feat(core/agents): enrich agent_wait responses with previews and agent_result hints\n\n- Single agent and sequential batch now include agent_result_hint and agent_result_params\n- Batch return_all:true now returns completed_summaries with per-agent preview + file\n- Update tool descriptions to clarify preview + file-path contract and agent_result usage

This commit is contained in:
James Peter
2025-10-03 07:22:33 +10:00
parent 698095a7ef
commit cdc833d94e
2 changed files with 57 additions and 3 deletions
+2 -3
View File
@@ -957,7 +957,7 @@ pub fn create_get_agent_result_tool() -> OpenAiTool {
OpenAiTool::Function(ResponsesApiTool {
name: "agent_result".to_string(),
description: "Get the final result of a completed agent.".to_string(),
description: "Get the final result of a completed agent. Returns a preview (first 500 lines) and a file path to the full output/error.".to_string(),
strict: false,
parameters: JsonSchema::Object {
properties,
@@ -1042,8 +1042,7 @@ pub fn create_wait_for_agent_tool() -> OpenAiTool {
OpenAiTool::Function(ResponsesApiTool {
name: "agent_wait".to_string(),
description: "Wait for a agent or any agent in a batch to complete, fail, or be cancelled."
.to_string(),
description: "Wait for an agent or any agent in a batch to complete, fail, or be cancelled. Returns status plus a preview (first 500 lines) and a file path to the full output/error. For batches, set return_all:true to receive per-agent summaries. Use agent_result with {\"agent_id\": \"...\"} to fetch after completion.".to_string(),
strict: false,
parameters: JsonSchema::Object {
properties,
+55
View File
@@ -7055,11 +7055,14 @@ async fn handle_wait_for_agent(sess: &Session, ctx: &ToolCallCtx, arguments: Str
_ => unreachable!(),
};
let hint = format!("agent_result {{\"agent_id\":\"{}\"}}", agent.id);
let mut response = serde_json::json!({
"agent_id": agent.id,
"status": agent.status,
"wait_time_seconds": start.elapsed().as_secs(),
"total_lines": total_lines,
"agent_result_hint": hint,
"agent_result_params": { "agent_id": agent.id },
});
if let Some(obj) = response.as_object_mut() {
obj.insert(preview_key.to_string(), serde_json::Value::String(preview));
@@ -7097,9 +7100,58 @@ async fn handle_wait_for_agent(sess: &Session, ctx: &ToolCallCtx, arguments: Str
if params.return_all.unwrap_or(false) {
// Wait for ALL agents in the batch to reach a terminal state
if !any_in_progress {
// Enriched response: include per-agent previews and file paths
let cwd = sess.get_cwd().to_path_buf();
let mut summaries: Vec<serde_json::Value> = Vec::new();
for a in &completed_agents {
let dir = ensure_agent_dir(&cwd, &a.id).unwrap_or_else(|_| cwd.clone());
let (preview_key, file_key, preview, file_path, total_lines) = match a.status {
AgentStatus::Completed => {
let text = a.result.clone().unwrap_or_default();
let (p, total) = preview_first_n_lines(&text, 500);
let fp = write_agent_file(&dir, "result.txt", &text)
.map(|p| p.display().to_string())
.unwrap_or_else(|e| format!("Failed to write result file: {}", e));
("output_preview", "output_file", p, fp, total)
}
AgentStatus::Failed => {
let text = a.error.clone().unwrap_or_else(|| "Unknown error".to_string());
let (p, total) = preview_first_n_lines(&text, 500);
let fp = write_agent_file(&dir, "error.txt", &text)
.map(|p| p.display().to_string())
.unwrap_or_else(|e| format!("Failed to write error file: {}", e));
("error_preview", "error_file", p, fp, total)
}
AgentStatus::Cancelled => {
let text = "Agent cancelled".to_string();
let (p, total) = preview_first_n_lines(&text, 500);
let fp = write_agent_file(&dir, "status.txt", &text)
.map(|p| p.display().to_string())
.unwrap_or_else(|e| format!("Failed to write status file: {}", e));
("status_preview", "status_file", p, fp, total)
}
_ => unreachable!(),
};
let hint = format!("agent_result {{\"agent_id\":\"{}\"}}", a.id);
let mut obj = serde_json::json!({
"agent_id": a.id,
"status": a.status,
"total_lines": total_lines,
"agent_result_hint": hint,
"agent_result_params": { "agent_id": a.id },
});
if let Some(map) = obj.as_object_mut() {
map.insert(preview_key.to_string(), serde_json::Value::String(preview));
map.insert(file_key.to_string(), serde_json::Value::String(file_path));
}
summaries.push(obj);
}
let response = serde_json::json!({
"batch_id": batch_id,
"completed_agents": completed_agents.iter().map(|t| t.id.clone()).collect::<Vec<_>>(),
"completed_summaries": summaries,
"wait_time_seconds": start.elapsed().as_secs(),
});
return ResponseInputItem::FunctionCallOutput {
@@ -7159,11 +7211,14 @@ async fn handle_wait_for_agent(sess: &Session, ctx: &ToolCallCtx, arguments: Str
_ => unreachable!(),
};
let hint = format!(r#"agent_result {{"agent_id":"{}"}}"#, unseen.id);
let mut response = serde_json::json!({
"agent_id": unseen.id,
"status": unseen.status,
"wait_time_seconds": start.elapsed().as_secs(),
"total_lines": total_lines,
"agent_result_hint": hint,
"agent_result_params": { "agent_id": unseen.id },
});
if let Some(obj) = response.as_object_mut() {
obj.insert(preview_key.to_string(), serde_json::Value::String(preview));