1use super::api::{create_async_deep_agent_from_config, create_deep_agent_from_config};
7use super::config::{DeepAgentConfig, SubAgentConfig, SummarizationConfig};
8use super::runtime::DeepAgent;
9use crate::middleware::HitlPolicy;
10use crate::planner::LlmBackedPlanner;
11use crate::providers::{
12 AnthropicConfig, AnthropicMessagesModel, GeminiChatModel, GeminiConfig, OpenAiChatModel,
13 OpenAiConfig,
14};
15use agents_core::agent::PlannerHandle;
16use agents_core::llm::LanguageModel;
17use agents_core::persistence::Checkpointer;
18use agents_core::tools::ToolBox;
19use std::collections::{HashMap, HashSet};
20use std::sync::Arc;
21
22pub struct ConfigurableAgentBuilder {
25 instructions: String,
26 planner: Option<Arc<dyn PlannerHandle>>,
27 tools: Vec<ToolBox>,
28 subagents: Vec<SubAgentConfig>,
29 summarization: Option<SummarizationConfig>,
30 tool_interrupts: HashMap<String, HitlPolicy>,
31 builtin_tools: Option<HashSet<String>>,
32 auto_general_purpose: bool,
33 enable_prompt_caching: bool,
34 checkpointer: Option<Arc<dyn Checkpointer>>,
35 event_dispatcher: Option<Arc<agents_core::events::EventDispatcher>>,
36 enable_pii_sanitization: bool,
37}
38
39impl ConfigurableAgentBuilder {
40 pub fn new(instructions: impl Into<String>) -> Self {
41 Self {
42 instructions: instructions.into(),
43 planner: None,
44 tools: Vec::new(),
45 subagents: Vec::new(),
46 summarization: None,
47 tool_interrupts: HashMap::new(),
48 builtin_tools: None,
49 auto_general_purpose: true,
50 enable_prompt_caching: false,
51 checkpointer: None,
52 event_dispatcher: None,
53 enable_pii_sanitization: true, }
55 }
56
57 pub fn with_model(mut self, model: Arc<dyn LanguageModel>) -> Self {
59 let planner: Arc<dyn PlannerHandle> = Arc::new(LlmBackedPlanner::new(model));
60 self.planner = Some(planner);
61 self
62 }
63
64 pub fn with_planner(mut self, planner: Arc<dyn PlannerHandle>) -> Self {
66 self.planner = Some(planner);
67 self
68 }
69
70 pub fn with_openai_chat(self, config: OpenAiConfig) -> anyhow::Result<Self> {
72 let model = Arc::new(OpenAiChatModel::new(config)?);
73 Ok(self.with_model(model))
74 }
75
76 pub fn with_anthropic_messages(self, config: AnthropicConfig) -> anyhow::Result<Self> {
78 let model = Arc::new(AnthropicMessagesModel::new(config)?);
79 Ok(self.with_model(model))
80 }
81
82 pub fn with_gemini_chat(self, config: GeminiConfig) -> anyhow::Result<Self> {
84 let model = Arc::new(GeminiChatModel::new(config)?);
85 Ok(self.with_model(model))
86 }
87
88 pub fn with_tool(mut self, tool: ToolBox) -> Self {
90 self.tools.push(tool);
91 self
92 }
93
94 pub fn with_tools<I>(mut self, tools: I) -> Self
96 where
97 I: IntoIterator<Item = ToolBox>,
98 {
99 self.tools.extend(tools);
100 self
101 }
102
103 pub fn with_subagent_config<I>(mut self, cfgs: I) -> Self
104 where
105 I: IntoIterator<Item = SubAgentConfig>,
106 {
107 self.subagents.extend(cfgs);
108 self
109 }
110
111 pub fn with_subagent_tools<I>(mut self, tools: I) -> Self
114 where
115 I: IntoIterator<Item = ToolBox>,
116 {
117 for tool in tools {
118 let tool_name = tool.schema().name.clone();
119 let subagent_config = SubAgentConfig::new(
120 format!("{}-agent", tool_name),
121 format!("Specialized agent for {} operations", tool_name),
122 format!(
123 "You are a specialized agent. Use the {} tool to complete tasks efficiently.",
124 tool_name
125 ),
126 )
127 .with_tools(vec![tool]);
128 self.subagents.push(subagent_config);
129 }
130 self
131 }
132
133 pub fn with_summarization(mut self, config: SummarizationConfig) -> Self {
134 self.summarization = Some(config);
135 self
136 }
137
138 pub fn with_tool_interrupt(mut self, tool_name: impl Into<String>, policy: HitlPolicy) -> Self {
139 self.tool_interrupts.insert(tool_name.into(), policy);
140 self
141 }
142
143 pub fn with_builtin_tools<I, S>(mut self, names: I) -> Self
144 where
145 I: IntoIterator<Item = S>,
146 S: Into<String>,
147 {
148 self.builtin_tools = Some(names.into_iter().map(|s| s.into()).collect());
149 self
150 }
151
152 pub fn with_auto_general_purpose(mut self, enabled: bool) -> Self {
153 self.auto_general_purpose = enabled;
154 self
155 }
156
157 pub fn with_prompt_caching(mut self, enabled: bool) -> Self {
158 self.enable_prompt_caching = enabled;
159 self
160 }
161
162 pub fn with_checkpointer(mut self, checkpointer: Arc<dyn Checkpointer>) -> Self {
163 self.checkpointer = Some(checkpointer);
164 self
165 }
166
167 pub fn with_event_broadcaster(
174 mut self,
175 broadcaster: Arc<dyn agents_core::events::EventBroadcaster>,
176 ) -> Self {
177 if self.event_dispatcher.is_none() {
179 self.event_dispatcher = Some(Arc::new(agents_core::events::EventDispatcher::new()));
180 }
181
182 if let Some(dispatcher) = &self.event_dispatcher {
184 dispatcher.add_broadcaster(broadcaster);
185 }
186
187 self
188 }
189
190 pub fn with_event_broadcasters(
201 mut self,
202 broadcasters: Vec<Arc<dyn agents_core::events::EventBroadcaster>>,
203 ) -> Self {
204 if self.event_dispatcher.is_none() {
206 self.event_dispatcher = Some(Arc::new(agents_core::events::EventDispatcher::new()));
207 }
208
209 if let Some(dispatcher) = &self.event_dispatcher {
211 for broadcaster in broadcasters {
212 dispatcher.add_broadcaster(broadcaster);
213 }
214 }
215
216 self
217 }
218
219 pub fn with_event_dispatcher(
221 mut self,
222 dispatcher: Arc<agents_core::events::EventDispatcher>,
223 ) -> Self {
224 self.event_dispatcher = Some(dispatcher);
225 self
226 }
227
228 pub fn with_pii_sanitization(mut self, enabled: bool) -> Self {
254 self.enable_pii_sanitization = enabled;
255 self
256 }
257
258 pub fn build(self) -> anyhow::Result<DeepAgent> {
259 self.finalize(create_deep_agent_from_config)
260 }
261
262 pub fn build_async(self) -> anyhow::Result<DeepAgent> {
265 self.finalize(create_async_deep_agent_from_config)
266 }
267
268 fn finalize(self, ctor: fn(DeepAgentConfig) -> DeepAgent) -> anyhow::Result<DeepAgent> {
269 let Self {
270 instructions,
271 planner,
272 tools,
273 subagents,
274 summarization,
275 tool_interrupts,
276 builtin_tools,
277 auto_general_purpose,
278 enable_prompt_caching,
279 checkpointer,
280 event_dispatcher,
281 enable_pii_sanitization,
282 } = self;
283
284 let planner = planner
285 .ok_or_else(|| anyhow::anyhow!("model must be set (use with_model or with_*_chat)"))?;
286
287 let mut cfg = DeepAgentConfig::new(instructions, planner)
288 .with_auto_general_purpose(auto_general_purpose)
289 .with_prompt_caching(enable_prompt_caching)
290 .with_pii_sanitization(enable_pii_sanitization);
291
292 if let Some(ckpt) = checkpointer {
293 cfg = cfg.with_checkpointer(ckpt);
294 }
295 if let Some(dispatcher) = event_dispatcher {
296 cfg = cfg.with_event_dispatcher(dispatcher);
297 }
298 if let Some(sum) = summarization {
299 cfg = cfg.with_summarization(sum);
300 }
301 if let Some(selected) = builtin_tools {
302 cfg = cfg.with_builtin_tools(selected);
303 }
304 for (name, policy) in tool_interrupts {
305 cfg = cfg.with_tool_interrupt(name, policy);
306 }
307 for tool in tools {
308 cfg = cfg.with_tool(tool);
309 }
310 for sub_cfg in subagents {
311 cfg = cfg.with_subagent_config(sub_cfg);
312 }
313
314 Ok(ctor(cfg))
315 }
316}