use agent_base::{RunOutcome, RuntimeEvent};
use super::watcher::ChildReport;
use crate::multi_agent::mailbox::{MailboxResult, MailboxStatus, MailboxTask};
pub(super) fn build_child_input(task: &MailboxTask) -> String {
if task.pending_messages.is_empty() {
task.task.clone()
} else {
let mut parts: Vec<String> = Vec::new();
for msg in &task.pending_messages {
parts.push(format!("[Message]: {}", msg));
}
parts.push(format!("[Task]: {}", task.task));
parts.join("\n\n")
}
}
pub(super) fn summarize_outcome(outcome: &RunOutcome) -> String {
match outcome {
RunOutcome::Completed => "task completed".to_string(),
RunOutcome::Continuing => "continuing".to_string(),
RunOutcome::Failed { error } => format!("task failed: {}", error),
RunOutcome::MaxTurnsExceeded { turns } => {
format!("max turns exceeded ({} turns)", turns)
}
RunOutcome::Cancelled => "cancelled".to_string(),
}
}
pub(super) fn extract_last_assistant_message(events: &[RuntimeEvent]) -> String {
let start = events
.iter()
.rposition(|e| matches!(e, RuntimeEvent::ToolCallStarted { .. }))
.map(|i| i + 1)
.unwrap_or(0);
let mut text = String::new();
for event in &events[start..] {
if let RuntimeEvent::TextDelta {
text: delta,
agent_id,
..
} = event
&& agent_id.is_none()
{
text.push_str(delta);
}
}
text
}
pub(super) fn collect_denied_tools(events: &[RuntimeEvent]) -> Vec<String> {
events
.iter()
.filter_map(|e| match e {
RuntimeEvent::ToolCallFinished {
tool_name,
denied: true,
agent_id: None,
..
} => Some(tool_name.clone()),
_ => None,
})
.collect()
}
pub(super) fn build_child_result(outcome: &RunOutcome, events: &[RuntimeEvent]) -> String {
match outcome {
RunOutcome::Completed => {
let text = extract_last_assistant_message(events);
if text.trim().is_empty() {
summarize_outcome(outcome)
} else {
text
}
}
_ => summarize_outcome(outcome),
}
}
pub fn format_child_result(result: &MailboxResult) -> ChildReport {
let status_str = match &result.status {
MailboxStatus::Ok => "ok",
MailboxStatus::Error => "error",
MailboxStatus::Closed => "closed",
};
let result_text = result.result.as_deref().unwrap_or("");
let path = result.agent_path.to_string();
let message = match &result.status {
MailboxStatus::Ok => {
if result_text.is_empty() {
format!("[子 agent {} 已完成]", path)
} else {
format!("[子 agent {} 已完成]\n{}", path, result_text)
}
}
MailboxStatus::Error => {
if result_text.is_empty() {
format!("[子 agent {} 执行出错]", path)
} else {
format!("[子 agent {} 执行出错]\n{}", path, result_text)
}
}
MailboxStatus::Closed => {
format!("[子 agent {} 已关闭]", path)
}
};
ChildReport {
agent_path: path,
status: status_str.to_string(),
result: result.result.clone(),
message,
}
}