Skip to main content

agent_sdk/subagent/
factory.rs

1//! Factory for creating subagents with common configurations.
2//!
3//! This module provides a convenient API for creating subagents with
4//! pre-configured tool registries and common patterns.
5//!
6//! # Example
7//!
8//! ```ignore
9//! use agent_sdk::subagent::{SubagentFactory, SubagentConfig};
10//! use agent_sdk::ToolRegistry;
11//!
12//! // Create tool registries for different access levels
13//! let mut read_tools = ToolRegistry::new();
14//! read_tools.register(glob_tool);
15//! read_tools.register(grep_tool);
16//! read_tools.register(read_tool);
17//!
18//! let factory = SubagentFactory::new(provider.clone())
19//!     .with_read_only_registry(read_tools);
20//!
21//! // Create a read-only subagent for exploration
22//! let explorer = factory.create_read_only(
23//!     SubagentConfig::new("explorer")
24//!         .with_system_prompt("You explore codebases...")
25//!         .with_max_turns(20)
26//! );
27//! ```
28
29use std::sync::Arc;
30
31use anyhow::{Context, Result};
32
33use crate::llm::LlmProvider;
34use crate::tools::ToolRegistry;
35
36use super::{SubagentConfig, SubagentTool};
37
38/// Factory for creating subagents with shared resources.
39///
40/// The factory holds references to shared resources (provider, tool registries)
41/// and provides convenient methods to create subagents with common configurations.
42pub struct SubagentFactory<P>
43where
44    P: LlmProvider + 'static,
45{
46    provider: Arc<P>,
47    read_only_registry: Option<Arc<ToolRegistry<()>>>,
48    full_registry: Option<Arc<ToolRegistry<()>>>,
49}
50
51impl<P> SubagentFactory<P>
52where
53    P: LlmProvider + 'static,
54{
55    /// Creates a new factory with the given LLM provider.
56    #[must_use]
57    pub const fn new(provider: Arc<P>) -> Self {
58        Self {
59            provider,
60            read_only_registry: None,
61            full_registry: None,
62        }
63    }
64
65    /// Sets the read-only tool registry (typically glob, grep, read tools).
66    ///
67    /// This registry is used when creating read-only subagents.
68    #[must_use]
69    pub fn with_read_only_registry(mut self, registry: ToolRegistry<()>) -> Self {
70        self.read_only_registry = Some(Arc::new(registry));
71        self
72    }
73
74    /// Sets the full tool registry for full-access subagents.
75    #[must_use]
76    pub fn with_full_registry(mut self, registry: ToolRegistry<()>) -> Self {
77        self.full_registry = Some(Arc::new(registry));
78        self
79    }
80
81    /// Creates a read-only subagent with only read/search tools.
82    ///
83    /// This is useful for exploration, research, and investigation tasks
84    /// where the subagent should not modify any files.
85    ///
86    /// # Errors
87    ///
88    /// Returns an error if no read-only registry has been set.
89    pub fn create_read_only(&self, config: SubagentConfig) -> Result<SubagentTool<P>> {
90        let registry = self
91            .read_only_registry
92            .as_ref()
93            .context("read-only registry not set; call with_read_only_registry first")?;
94        Ok(SubagentTool::new(
95            config,
96            Arc::clone(&self.provider),
97            Arc::clone(registry),
98        ))
99    }
100
101    /// Creates a subagent with all available tools.
102    ///
103    /// # Errors
104    ///
105    /// Returns an error if no full registry has been set.
106    pub fn create_full_access(&self, config: SubagentConfig) -> Result<SubagentTool<P>> {
107        let registry = self
108            .full_registry
109            .as_ref()
110            .context("full registry not set; call with_full_registry first")?;
111        Ok(SubagentTool::new(
112            config,
113            Arc::clone(&self.provider),
114            Arc::clone(registry),
115        ))
116    }
117
118    /// Creates a subagent with a custom tool registry.
119    #[must_use]
120    pub fn create_with_registry(
121        &self,
122        config: SubagentConfig,
123        registry: Arc<ToolRegistry<()>>,
124    ) -> SubagentTool<P> {
125        SubagentTool::new(config, Arc::clone(&self.provider), registry)
126    }
127
128    /// Returns the provider for manual subagent construction.
129    #[must_use]
130    pub fn provider(&self) -> Arc<P> {
131        Arc::clone(&self.provider)
132    }
133}
134
135impl<P> Clone for SubagentFactory<P>
136where
137    P: LlmProvider + 'static,
138{
139    fn clone(&self) -> Self {
140        Self {
141            provider: Arc::clone(&self.provider),
142            read_only_registry: self.read_only_registry.clone(),
143            full_registry: self.full_registry.clone(),
144        }
145    }
146}
147
148#[cfg(test)]
149mod tests {
150    use super::*;
151
152    #[test]
153    fn test_subagent_config_builder() {
154        let config = SubagentConfig::new("test")
155            .with_system_prompt("You are a test agent")
156            .with_max_turns(5)
157            .with_timeout_ms(30000);
158
159        assert_eq!(config.name, "test");
160        assert_eq!(config.system_prompt, "You are a test agent");
161        assert_eq!(config.max_turns, Some(5));
162        assert_eq!(config.timeout_ms, Some(30000));
163    }
164}