use serde_json::{json, Value};
use crate::{Result, RuntimeError};
use super::super::{Tool, ToolContext};
use crate::runtime::subagent::SubagentStatus;
pub struct SubagentSteerTool;
#[async_trait::async_trait]
impl Tool for SubagentSteerTool {
fn name(&self) -> &str { "subagent_steer" }
fn description(&self) -> &str {
"Inject a guidance message into a running reactive subagent. Use this to \
correct course, provide new context, or impose constraints mid-run without \
stopping the subagent. Returns {\"acknowledged\": true} on success or an \
error payload if the subagent is no longer running."
}
fn parameters(&self) -> Value {
json!({
"type": "object",
"properties": {
"handle_id": {
"type": "string",
"description": "Handle ID returned by subagent_start (e.g. \"sa_3\")."
},
"message": {
"type": "string",
"description": "Guidance message to inject into the subagent's context. \
Keep it concise — the subagent sees this as a mid-run \
user message."
}
},
"required": ["handle_id", "message"]
})
}
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 message = params["message"].as_str()
.ok_or_else(|| RuntimeError::Tool("Missing 'message' 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)
))?;
if handle.status() != SubagentStatus::Running {
return Ok(json!({
"acknowledged": false,
"error": format!(
"Subagent '{}' is '{}' — steering is only possible while running.",
handle_id,
handle.status().as_str()
)
}).to_string());
}
match handle.steer(&message) {
Ok(()) => Ok(json!({ "acknowledged": true }).to_string()),
Err(e) => {
tracing::debug!(
"subagent_steer: steer failed for handle '{}': {}",
handle_id, e
);
Ok(json!({
"acknowledged": false,
"error": e
}).to_string())
}
}
}
}