| 548 | } |
| 549 | |
| 550 | fn render_script_output( |
| 551 | result: &serde_json::Value, |
| 552 | records: &[ScriptCallRecord], |
| 553 | stderr: &str, |
| 554 | ) -> String { |
| 555 | let mut output = String::from("Program script completed."); |
| 556 | if let Some(summary) = result.get("summary").and_then(|value| value.as_str()) { |
| 557 | output.push('\n'); |
| 558 | output.push_str(summary); |
| 559 | } |
| 560 | |
| 561 | output.push_str(&format!("\n\nTool calls: {}", records.len())); |
| 562 | for (index, record) in records.iter().enumerate() { |
| 563 | output.push_str(&format!( |
| 564 | "\n{}. {} ({}, exit_code={}, output_bytes={})", |
| 565 | index + 1, |
| 566 | record.tool_name, |
| 567 | if record.success { "ok" } else { "failed" }, |
| 568 | record.exit_code, |
| 569 | record.output_bytes |
| 570 | )); |
| 571 | } |
| 572 | |
| 573 | output.push_str("\n\nResult:\n"); |
| 574 | output.push_str(&serde_json::to_string_pretty(result).unwrap_or_else(|_| result.to_string())); |
| 575 | |
| 576 | if !stderr.is_empty() { |
| 577 | output.push_str("\n\nstderr:\n"); |
| 578 | output.push_str(stderr); |
| 579 | } |
| 580 | |
| 581 | output |
| 582 | } |
| 583 | |
| 584 | #[cfg(test)] |
| 585 | mod tests { |