agent_engine/tools/subagent/
status.rs1use serde_json::{json, Value};
8use crate::{Result, RuntimeError};
9use super::super::{Tool, ToolContext};
10
11pub struct SubagentStatusTool;
12
13#[async_trait::async_trait]
14impl Tool for SubagentStatusTool {
15 fn name(&self) -> &str { "subagent_status" }
16
17 fn description(&self) -> &str {
18 "Poll the current state of a reactive subagent. Returns status \
19 (running/completed/cancelled/timed_out/failed), the last 500 characters of output \
20 produced so far, elapsed time in seconds, and the number of tool calls \
21 made. If the status is 'failed', an 'error' field contains the failure reason. \
22 Non-blocking — returns immediately."
23 }
24
25 fn parameters(&self) -> Value {
26 json!({
27 "type": "object",
28 "properties": {
29 "handle_id": {
30 "type": "string",
31 "description": "Handle ID returned by subagent_start (e.g. \"sa_3\")."
32 }
33 },
34 "required": ["handle_id"]
35 })
36 }
37
38 async fn execute(&self, params: Value, ctx: ToolContext) -> Result<String> {
39 let handle_id = params["handle_id"].as_str()
40 .ok_or_else(|| RuntimeError::Tool("Missing 'handle_id' parameter".to_string()))?
41 .to_string();
42
43 let registry = ctx.capabilities.subagent_registry.as_ref()
46 .ok_or_else(|| RuntimeError::Tool(
47 "SubagentRegistry not available on this ToolContext".to_string()
48 ))?;
49
50 let reg = registry.lock().unwrap();
51
52 let handle = reg.get(&handle_id)
53 .ok_or_else(|| RuntimeError::Tool(
54 format!("No subagent found with handle_id '{}'", handle_id)
55 ))?;
56
57 let full: String = handle.partial_output();
60 let agent_name = handle.agent_name.clone();
61 let status = handle.status();
62 let status_str = status.as_str().to_string();
63 let elapsed = handle.elapsed_secs();
64 let tool_count = handle.tool_log().len();
65 let _ = handle;
66 drop(reg);
67
68 let char_count = full.chars().count();
69 let partial_output: String = if char_count > 500 {
70 full.chars().skip(char_count - 500).collect()
71 } else {
72 full
73 };
74
75 let mut resp = json!({
76 "handle_id": handle_id,
77 "agent_name": agent_name,
78 "status": status_str,
79 "partial_output": partial_output,
80 "elapsed_secs": (elapsed * 10.0).round() / 10.0,
81 "tool_count": tool_count
82 });
83 if let Some(reason) = status.failure_reason() {
84 resp["error"] = json!(reason);
85 }
86 Ok(resp.to_string())
87 }
88}