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}