use crate::types::*;
pub const AGENT_TOOL_NAME: &str = "Agent";
pub struct AgentTool;
impl AgentTool {
pub fn new() -> Self {
Self
}
#[allow(dead_code)]
fn input_schema(&self) -> ToolInputSchema {
ToolInputSchema {
schema_type: "object".to_string(),
properties: serde_json::json!({
"description": {
"type": "string",
"description": "A short description (3-5 words) summarizing what the agent will do"
},
"subagent_type": {
"type": "string",
"description": "The type of subagent to use (e.g., 'general-purpose', 'code-reviewer', 'test-runner'). If omitted, uses the general-purpose agent."
},
"prompt": {
"type": "string",
"description": "The task prompt for the subagent to execute"
},
"model": {
"type": "string",
"description": "Optional model override for this subagent"
},
"max_turns": {
"type": "number",
"description": "Maximum number of turns for this subagent (default: 10)"
},
"run_in_background": {
"type": "boolean",
"description": "Whether to run the agent in the background (default: false)"
},
"isolation": {
"type": "string",
"enum": ["worktree", "remote"],
"description": "Isolation mode: 'worktree' for git worktree, 'remote' for remote CCR"
}
}),
required: Some(vec!["description".to_string(), "prompt".to_string()]),
}
}
pub async fn execute(&self, input: serde_json::Value, _context: &ToolContext) -> Result<ToolResult, crate::error::AgentError> {
let description = input["description"]
.as_str()
.ok_or_else(|| crate::error::AgentError::Tool("description is required".to_string()))?;
let subagent_type = input["subagent_type"].as_str();
let prompt = input["prompt"]
.as_str()
.ok_or_else(|| crate::error::AgentError::Tool("prompt is required".to_string()))?;
let model = input["model"].as_str().map(|s| s.to_string());
let max_turns = input["max_turns"].as_u64().unwrap_or(10) as u32;
let run_in_background = input["run_in_background"].as_bool().unwrap_or(false);
let isolation = input["isolation"].as_str();
let subagent_model = model.unwrap_or_else(|| "claude-sonnet-4-6".to_string());
let mut response = format!("Launching subagent: {}\n", description);
if let Some(t) = subagent_type {
response.push_str(&format!("Type: {}\n", t));
}
response.push_str(&format!("Prompt: {}\n", prompt));
response.push_str(&format!("Model: {}\n", subagent_model));
response.push_str(&format!("Max turns: {}\n", max_turns));
if run_in_background {
response.push_str("Mode: background\n");
}
if let Some(iso) = isolation {
response.push_str(&format!("Isolation: {}\n", iso));
}
response.push_str("\nNote: Full subagent implementation would spawn a new agent process here.");
Ok(ToolResult {
result_type: "text".to_string(),
tool_use_id: "agent_tool".to_string(),
content: response,
is_error: Some(false),
})
}
}
impl Default for AgentTool {
fn default() -> Self {
Self::new()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_agent_tool_schema() {
let tool = AgentTool::new();
let schema = tool.input_schema();
assert_eq!(schema.schema_type, "object");
let props = &schema.properties;
assert!(props.get("description").is_some());
assert!(props.get("prompt").is_some());
let required = schema.required.as_ref().unwrap();
assert!(required.contains(&"description".to_string()));
assert!(required.contains(&"prompt".to_string()));
}
}