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 crate::llm::LlmProvider;
32use crate::tools::ToolRegistry;
33
34use super::{SubagentConfig, SubagentTool};
35
36/// Factory for creating subagents with shared resources.
37///
38/// The factory holds references to shared resources (provider, tool registries)
39/// and provides convenient methods to create subagents with common configurations.
40pub struct SubagentFactory<P>
41where
42    P: LlmProvider + 'static,
43{
44    provider: Arc<P>,
45    read_only_registry: Option<Arc<ToolRegistry<()>>>,
46    full_registry: Option<Arc<ToolRegistry<()>>>,
47}
48
49impl<P> SubagentFactory<P>
50where
51    P: LlmProvider + 'static,
52{
53    /// Creates a new factory with the given LLM provider.
54    #[must_use]
55    pub const fn new(provider: Arc<P>) -> Self {
56        Self {
57            provider,
58            read_only_registry: None,
59            full_registry: None,
60        }
61    }
62
63    /// Sets the read-only tool registry (typically glob, grep, read tools).
64    ///
65    /// This registry is used when creating read-only subagents.
66    #[must_use]
67    pub fn with_read_only_registry(mut self, registry: ToolRegistry<()>) -> Self {
68        self.read_only_registry = Some(Arc::new(registry));
69        self
70    }
71
72    /// Sets the full tool registry for full-access subagents.
73    #[must_use]
74    pub fn with_full_registry(mut self, registry: ToolRegistry<()>) -> Self {
75        self.full_registry = Some(Arc::new(registry));
76        self
77    }
78
79    /// Creates a read-only subagent with only read/search tools.
80    ///
81    /// This is useful for exploration, research, and investigation tasks
82    /// where the subagent should not modify any files.
83    ///
84    /// # Panics
85    ///
86    /// Panics if no read-only registry has been set.
87    #[must_use]
88    pub fn create_read_only(&self, config: SubagentConfig) -> SubagentTool<P> {
89        let registry = self
90            .read_only_registry
91            .as_ref()
92            .expect("read-only registry not set; call with_read_only_registry first");
93        SubagentTool::new(config, Arc::clone(&self.provider), Arc::clone(registry))
94    }
95
96    /// Creates a subagent with all available tools.
97    ///
98    /// # Panics
99    ///
100    /// Panics if no full registry has been set.
101    #[must_use]
102    pub fn create_full_access(&self, config: SubagentConfig) -> SubagentTool<P> {
103        let registry = self
104            .full_registry
105            .as_ref()
106            .expect("full registry not set; call with_full_registry first");
107        SubagentTool::new(config, Arc::clone(&self.provider), Arc::clone(registry))
108    }
109
110    /// Creates a subagent with a custom tool registry.
111    #[must_use]
112    pub fn create_with_registry(
113        &self,
114        config: SubagentConfig,
115        registry: Arc<ToolRegistry<()>>,
116    ) -> SubagentTool<P> {
117        SubagentTool::new(config, Arc::clone(&self.provider), registry)
118    }
119
120    /// Returns the provider for manual subagent construction.
121    #[must_use]
122    pub fn provider(&self) -> Arc<P> {
123        Arc::clone(&self.provider)
124    }
125}
126
127impl<P> Clone for SubagentFactory<P>
128where
129    P: LlmProvider + 'static,
130{
131    fn clone(&self) -> Self {
132        Self {
133            provider: Arc::clone(&self.provider),
134            read_only_registry: self.read_only_registry.clone(),
135            full_registry: self.full_registry.clone(),
136        }
137    }
138}
139
140#[cfg(test)]
141mod tests {
142    use super::*;
143
144    #[test]
145    fn test_subagent_config_builder() {
146        let config = SubagentConfig::new("test")
147            .with_system_prompt("You are a test agent")
148            .with_max_turns(5)
149            .with_timeout_ms(30000);
150
151        assert_eq!(config.name, "test");
152        assert_eq!(config.system_prompt, "You are a test agent");
153        assert_eq!(config.max_turns, 5);
154        assert_eq!(config.timeout_ms, Some(30000));
155    }
156}