use serde_json::{json, Value};
use crate::{Result, RuntimeError};
use super::super::{Tool, ToolContext};
use crate::runtime::subagent::SubagentStatus;
pub struct SubagentCollectTool;
#[async_trait::async_trait]
impl Tool for SubagentCollectTool {
fn name(&self) -> &str { "subagent_collect" }
fn description(&self) -> &str {
"Check if a reactive subagent is done and return its result. Non-blocking — \
returns immediately. If still running, returns status and partial output. \
If finished, returns the full result. Call repeatedly to poll for completion."
}
fn parameters(&self) -> Value {
json!({
"type": "object",
"properties": {
"handle_id": {
"type": "string",
"description": "Handle ID returned by subagent_start (e.g. \"sa_3\")."
}
},
"required": ["handle_id"]
})
}
async fn execute(&self, params: Value, ctx: ToolContext) -> Result<String> {
let handle_id = params["handle_id"].as_str()
.ok_or_else(|| RuntimeError::Tool("Missing 'handle_id' parameter".to_string()))?
.to_string();
let registry = ctx.capabilities.subagent_registry.as_ref()
.ok_or_else(|| RuntimeError::Tool(
"SubagentRegistry not available on this ToolContext".to_string()
))?;
let reg = registry.lock().unwrap();
let handle = reg.get(&handle_id)
.ok_or_else(|| RuntimeError::Tool(
format!("No subagent found with handle_id '{}'", handle_id)
))?;
let status = handle.status();
let output: String = handle.partial_output();
let elapsed = handle.elapsed_secs();
let _ = handle;
drop(reg);
if status == SubagentStatus::Running {
let char_count = output.chars().count();
let output_so_far: String = if char_count > 500 {
output.chars().skip(char_count - 500).collect()
} else {
output
};
return Ok(json!({
"handle_id": handle_id,
"status": "running",
"elapsed_secs": (elapsed * 10.0).round() / 10.0,
"output_so_far": output_so_far
}).to_string());
}
Ok(json!({
"handle_id": handle_id,
"status": status.as_str(),
"output": output
}).to_string())
}
}