Skip to main content

ai_agent/tools/agent/
built_in.rs

1//! Built-in agents - ported from ~/claudecode/openclaudecode/src/tools/AgentTool/builtInAgents.ts
2//!
3//! This module provides built-in agent definitions that ship with the SDK.
4
5use crate::constants::env::ai;
6use crate::skills::loader::HooksSettings;
7
8/// Built-in agent type
9#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
10#[serde(rename_all = "kebab-case")]
11pub enum BuiltInAgentType {
12    GeneralPurpose,
13    Explore,
14    Plan,
15    Verification,
16    CodeGuide,
17    StatuslineSetup,
18}
19
20impl BuiltInAgentType {
21    pub fn as_str(&self) -> &'static str {
22        match self {
23            BuiltInAgentType::GeneralPurpose => "general-purpose",
24            BuiltInAgentType::Explore => "explore",
25            BuiltInAgentType::Plan => "plan",
26            BuiltInAgentType::Verification => "verification",
27            BuiltInAgentType::CodeGuide => "code-guide",
28            BuiltInAgentType::StatuslineSetup => "statusline-setup",
29        }
30    }
31}
32
33/// Agent definition for built-in agents
34#[derive(Debug, Clone)]
35pub struct BuiltInAgent {
36    /// Unique agent type identifier
37    pub agent_type: BuiltInAgentType,
38    /// Human-readable name
39    pub name: String,
40    /// Description
41    pub description: String,
42    /// System prompt
43    pub get_system_prompt: fn() -> String,
44    /// Optional skills to preload
45    pub skills: Option<Vec<String>>,
46    /// Optional hooks
47    pub hooks: Option<HooksSettings>,
48    /// Optional MCP servers
49    pub mcp_servers: Option<Vec<String>>,
50    /// Maximum turns (None = use default)
51    pub max_turns: Option<u32>,
52    /// Whether to omit AI.md
53    pub omit_claude_md: bool,
54}
55
56impl BuiltInAgent {
57    /// Get the system prompt for this agent
58    pub fn get_system_prompt(&self) -> String {
59        (self.get_system_prompt)()
60    }
61}
62
63/// General Purpose Agent system prompt
64fn general_purpose_system_prompt() -> String {
65    r#"You are a general-purpose AI assistant helping with software development tasks.
66
67Your goal is to assist the user with whatever task they present, combining your abilities as a coding, reasoning, and command-line assistant.
68
69When working on code:
70- Write clean, maintainable code
71- Follow best practices for the language/framework
72- Consider edge cases and error handling
73- Write tests when appropriate
74
75When you need more information to complete a task, ask the user clarifying questions.
76
77Use the available tools to explore the codebase, read and write files, run commands, and accomplish the user's goals."#.to_string()
78}
79
80/// Explore Agent system prompt
81fn explore_system_prompt() -> String {
82    r#"You are an exploration agent. Your goal is to thoroughly investigate a codebase or problem area.
83
84Your approach:
851. Start by understanding the overall structure
862. Identify key files and their purposes
873. Trace through important code paths
884. Look for patterns and conventions
895. Document your findings clearly
90
91Be systematic and thorough. Use Glob, Grep, and Read tools to explore comprehensively.
92
93Provide detailed findings with file paths and line numbers to help the user understand the codebase."#.to_string()
94}
95
96/// Plan Agent system prompt
97fn plan_system_prompt() -> String {
98    r#"You are a planning agent. Your goal is to design implementation plans for complex tasks.
99
100Your approach:
1011. Understand the requirements thoroughly
1022. Break down into discrete steps
1033. Identify dependencies and potential issues
1044. Consider alternatives and trade-offs
1055. Create a clear, actionable plan
106
107When planning:
108- Think step by step
109- Consider edge cases
110- Identify what needs to be tested
111- Make sure the plan is practical and achievable
112
113Present your plan in a clear format with numbered steps."#
114        .to_string()
115}
116
117/// Verification Agent system prompt
118fn verification_system_prompt() -> String {
119    r#"You are a verification agent. Your goal is to verify that work is complete and correct.
120
121Your approach:
1221. Understand what was supposed to be accomplished
1232. Check that all requirements are met
1243. Run tests and verify they pass
1254. Look for potential issues or bugs
1265. Verify code quality and best practices
127
128Be thorough - don't just check that code compiles, verify it actually works correctly.
129
130When you find issues, be specific about what's wrong and suggest fixes."#
131        .to_string()
132}
133
134/// Code Guide Agent system prompt
135fn code_guide_system_prompt() -> String {
136    r#"You are a code guide agent. Your goal is to help users understand and navigate Claude Code.
137
138Your approach:
1391. Answer questions about Claude Code features
1402. Explain how to use tools effectively
1413. Help with debugging and troubleshooting
1424. Provide guidance on best practices
1435. Explain Claude Code concepts and workflows
144
145Be helpful and informative. Draw on your knowledge of Claude Code to assist users."#
146        .to_string()
147}
148
149/// Statusline Setup Agent system prompt
150fn statusline_setup_system_prompt() -> String {
151    r#"You are a statusline setup agent. Your goal is to help configure the Claude Code statusline.
152
153Your approach:
1541. Check current statusline configuration
1552. Understand available components
1563. Help customize the statusline to user preferences
1574. Ensure configuration is valid
158
159Provide clear guidance on statusline options and help users get their ideal setup."#
160        .to_string()
161}
162
163/// All built-in agents
164pub fn get_built_in_agents() -> Vec<BuiltInAgent> {
165    vec![
166        BuiltInAgent {
167            agent_type: BuiltInAgentType::GeneralPurpose,
168            name: "General Purpose".to_string(),
169            description: "A general-purpose agent for any task".to_string(),
170            get_system_prompt: general_purpose_system_prompt,
171            skills: None,
172            hooks: None,
173            mcp_servers: None,
174            max_turns: Some(50),
175            omit_claude_md: false,
176        },
177        BuiltInAgent {
178            agent_type: BuiltInAgentType::Explore,
179            name: "Explore".to_string(),
180            description: "Explore and understand a codebase".to_string(),
181            get_system_prompt: explore_system_prompt,
182            skills: Some(vec!["superpowers:brainstorming".to_string()]),
183            hooks: None,
184            mcp_servers: None,
185            max_turns: Some(20),
186            omit_claude_md: false,
187        },
188        BuiltInAgent {
189            agent_type: BuiltInAgentType::Plan,
190            name: "Plan".to_string(),
191            description: "Create implementation plans".to_string(),
192            get_system_prompt: plan_system_prompt,
193            skills: Some(vec!["superpowers:writing-plans".to_string()]),
194            hooks: None,
195            mcp_servers: None,
196            max_turns: Some(15),
197            omit_claude_md: false,
198        },
199        BuiltInAgent {
200            agent_type: BuiltInAgentType::Verification,
201            name: "Verification".to_string(),
202            description: "Verify work is complete and correct".to_string(),
203            get_system_prompt: verification_system_prompt,
204            skills: Some(vec![
205                "superpowers:verification-before-completion".to_string(),
206                "simplify".to_string(),
207            ]),
208            hooks: None,
209            mcp_servers: None,
210            max_turns: Some(25),
211            omit_claude_md: false,
212        },
213        BuiltInAgent {
214            agent_type: BuiltInAgentType::CodeGuide,
215            name: "Code Guide".to_string(),
216            description: "Help with Claude Code features".to_string(),
217            get_system_prompt: code_guide_system_prompt,
218            skills: None,
219            hooks: None,
220            mcp_servers: None,
221            max_turns: Some(10),
222            omit_claude_md: true,
223        },
224        BuiltInAgent {
225            agent_type: BuiltInAgentType::StatuslineSetup,
226            name: "Statusline Setup".to_string(),
227            description: "Configure Claude Code statusline".to_string(),
228            get_system_prompt: statusline_setup_system_prompt,
229            skills: None,
230            hooks: None,
231            mcp_servers: None,
232            max_turns: Some(5),
233            omit_claude_md: true,
234        },
235    ]
236}
237
238/// Get a built-in agent by type
239pub fn get_built_in_agent(agent_type: BuiltInAgentType) -> Option<BuiltInAgent> {
240    get_built_in_agents()
241        .into_iter()
242        .find(|a| a.agent_type == agent_type)
243}
244
245/// Get agent by type name (e.g., "general-purpose", "explore")
246pub fn get_agent_by_type_name(type_name: &str) -> Option<BuiltInAgent> {
247    let agent_type = match type_name {
248        "general-purpose" | "general" => Some(BuiltInAgentType::GeneralPurpose),
249        "explore" => Some(BuiltInAgentType::Explore),
250        "plan" => Some(BuiltInAgentType::Plan),
251        "verification" | "verify" => Some(BuiltInAgentType::Verification),
252        "code-guide" | "guide" => Some(BuiltInAgentType::CodeGuide),
253        "statusline-setup" | "statusline" => Some(BuiltInAgentType::StatuslineSetup),
254        _ => None,
255    };
256    agent_type.and_then(get_built_in_agent)
257}
258
259/// Check if Explore/Plan agents are enabled (feature-gated in TypeScript)
260pub fn are_explore_plan_agents_enabled() -> bool {
261    // In Rust SDK, always enabled by default
262    // Can be disabled via environment variable in production use
263    std::env::var(ai::DISABLE_EXPLORE_PLAN_AGENTS)
264        .map(|v| v != "true")
265        .unwrap_or(true)
266}
267
268/// Get all enabled built-in agents
269pub fn get_enabled_built_in_agents() -> Vec<BuiltInAgent> {
270    let mut agents = get_built_in_agents();
271
272    // Filter based on feature flags
273    if !are_explore_plan_agents_enabled() {
274        agents.retain(|a| {
275            a.agent_type != BuiltInAgentType::Explore && a.agent_type != BuiltInAgentType::Plan
276        });
277    }
278
279    agents
280}
281
282#[cfg(test)]
283mod tests {
284    use super::*;
285
286    #[test]
287    fn test_get_built_in_agents() {
288        let agents = get_built_in_agents();
289        assert!(!agents.is_empty());
290    }
291
292    #[test]
293    fn test_get_agent_by_type_name() {
294        let agent = get_agent_by_type_name("explore");
295        assert!(agent.is_some());
296        assert_eq!(agent.unwrap().agent_type, BuiltInAgentType::Explore);
297    }
298
299    #[test]
300    fn test_get_nonexistent_agent() {
301        let agent = get_agent_by_type_name("nonexistent");
302        assert!(agent.is_none());
303    }
304
305    #[test]
306    fn test_agent_system_prompt() {
307        let agent = get_built_in_agent(BuiltInAgentType::Explore).unwrap();
308        let prompt = agent.get_system_prompt();
309        assert!(!prompt.is_empty());
310    }
311
312    #[test]
313    fn test_are_explore_plan_agents_enabled_default() {
314        // By default should be enabled
315        assert!(are_explore_plan_agents_enabled());
316    }
317}