subagent_tool.rs

  1use agent_client_protocol as acp;
  2use anyhow::Result;
  3use gpui::{App, SharedString, Task};
  4use schemars::JsonSchema;
  5use serde::{Deserialize, Serialize};
  6use std::sync::Arc;
  7
  8use crate::{AgentTool, ToolCallEventStream};
  9
 10/// Spawns a subagent with its own context window to perform a delegated task.
 11///
 12/// Use this tool when you need to:
 13/// - Perform research that would consume too many tokens in the main context
 14/// - Execute a complex subtask independently
 15/// - Run multiple parallel investigations
 16///
 17/// You control what the subagent does by providing:
 18/// 1. A task prompt describing what the subagent should do
 19/// 2. A summary prompt that tells the subagent how to summarize its work when done
 20/// 3. A "context running out" prompt for when the subagent is low on tokens
 21///
 22/// The subagent has access to the same tools you do. You can optionally restrict
 23/// which tools the subagent can use.
 24///
 25/// IMPORTANT:
 26/// - Maximum 8 subagents can be spawned per turn
 27/// - Subagents cannot use tools you don't have access to
 28/// - If spawning multiple subagents that might write to the filesystem, provide
 29///   guidance on how to avoid conflicts (e.g., assign each to different directories)
 30/// - Instruct subagents to be concise in their summaries to conserve your context
 31#[derive(Debug, Serialize, Deserialize, JsonSchema)]
 32pub struct SubagentToolInput {
 33    /// Short label displayed in the UI while the subagent runs (e.g., "Researching alternatives")
 34    pub label: String,
 35
 36    /// The initial prompt that tells the subagent what task to perform.
 37    /// Be specific about what you want the subagent to accomplish.
 38    pub task_prompt: String,
 39
 40    /// The prompt sent to the subagent when it completes its task, asking it
 41    /// to summarize what it did and return results. This summary becomes the
 42    /// tool result you receive.
 43    ///
 44    /// Example: "Summarize what you found, listing the top 3 alternatives with pros/cons."
 45    pub summary_prompt: String,
 46
 47    /// The prompt sent if the subagent is running low on context (25% remaining).
 48    /// Should instruct it to stop and summarize progress so far, plus what's left undone.
 49    ///
 50    /// Example: "Context is running low. Stop and summarize your progress so far,
 51    /// and list what remains to be investigated."
 52    pub context_low_prompt: String,
 53
 54    /// Optional: Maximum runtime in milliseconds. If exceeded, the subagent is
 55    /// asked to summarize and return. No timeout by default.
 56    #[serde(default)]
 57    pub timeout_ms: Option<u64>,
 58
 59    /// Optional: List of tool names the subagent is allowed to use.
 60    /// If not provided, the subagent can use all tools available to the parent.
 61    /// Tools listed here must be a subset of the parent's available tools.
 62    #[serde(default)]
 63    pub allowed_tools: Option<Vec<String>>,
 64}
 65
 66pub struct SubagentTool;
 67
 68impl SubagentTool {
 69    pub fn new() -> Self {
 70        Self
 71    }
 72}
 73
 74impl AgentTool for SubagentTool {
 75    type Input = SubagentToolInput;
 76    type Output = String;
 77
 78    fn name() -> &'static str {
 79        "subagent"
 80    }
 81
 82    fn kind() -> acp::ToolKind {
 83        acp::ToolKind::Other
 84    }
 85
 86    fn initial_title(
 87        &self,
 88        input: Result<Self::Input, serde_json::Value>,
 89        _cx: &mut App,
 90    ) -> SharedString {
 91        match input {
 92            Ok(input) => format!("Subagent: {}", input.label).into(),
 93            Err(_) => "Subagent".into(),
 94        }
 95    }
 96
 97    fn run(
 98        self: Arc<Self>,
 99        input: Self::Input,
100        event_stream: ToolCallEventStream,
101        _cx: &mut App,
102    ) -> Task<Result<String>> {
103        event_stream.update_fields(
104            acp::ToolCallUpdateFields::new()
105                .content(vec![format!("Starting subagent: {}", input.label).into()]),
106        );
107        Task::ready(Ok("Subagent tool not yet implemented.".to_string()))
108    }
109}