agents_runtime/agent/
builder.rs1use 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}
37
38impl ConfigurableAgentBuilder {
39 pub fn new(instructions: impl Into<String>) -> Self {
40 Self {
41 instructions: instructions.into(),
42 planner: None,
43 tools: Vec::new(),
44 subagents: Vec::new(),
45 summarization: None,
46 tool_interrupts: HashMap::new(),
47 builtin_tools: None,
48 auto_general_purpose: true,
49 enable_prompt_caching: false,
50 checkpointer: None,
51 event_dispatcher: None,
52 }
53 }
54
55 pub fn with_model(mut self, model: Arc<dyn LanguageModel>) -> Self {
57 let planner: Arc<dyn PlannerHandle> = Arc::new(LlmBackedPlanner::new(model));
58 self.planner = Some(planner);
59 self
60 }
61
62 pub fn with_planner(mut self, planner: Arc<dyn PlannerHandle>) -> Self {
64 self.planner = Some(planner);
65 self
66 }
67
68 pub fn with_openai_chat(self, config: OpenAiConfig) -> anyhow::Result<Self> {
70 let model = Arc::new(OpenAiChatModel::new(config)?);
71 Ok(self.with_model(model))
72 }
73
74 pub fn with_anthropic_messages(self, config: AnthropicConfig) -> anyhow::Result<Self> {
76 let model = Arc::new(AnthropicMessagesModel::new(config)?);
77 Ok(self.with_model(model))
78 }
79
80 pub fn with_gemini_chat(self, config: GeminiConfig) -> anyhow::Result<Self> {
82 let model = Arc::new(GeminiChatModel::new(config)?);
83 Ok(self.with_model(model))
84 }
85
86 pub fn with_tool(mut self, tool: ToolBox) -> Self {
88 self.tools.push(tool);
89 self
90 }
91
92 pub fn with_tools<I>(mut self, tools: I) -> Self
94 where
95 I: IntoIterator<Item = ToolBox>,
96 {
97 self.tools.extend(tools);
98 self
99 }
100
101 pub fn with_subagent_config<I>(mut self, cfgs: I) -> Self
102 where
103 I: IntoIterator<Item = SubAgentConfig>,
104 {
105 self.subagents.extend(cfgs);
106 self
107 }
108
109 pub fn with_subagent_tools<I>(mut self, tools: I) -> Self
112 where
113 I: IntoIterator<Item = ToolBox>,
114 {
115 for tool in tools {
116 let tool_name = tool.schema().name.clone();
117 let subagent_config = SubAgentConfig::new(
118 format!("{}-agent", tool_name),
119 format!("Specialized agent for {} operations", tool_name),
120 format!(
121 "You are a specialized agent. Use the {} tool to complete tasks efficiently.",
122 tool_name
123 ),
124 )
125 .with_tools(vec![tool]);
126 self.subagents.push(subagent_config);
127 }
128 self
129 }
130
131 pub fn with_summarization(mut self, config: SummarizationConfig) -> Self {
132 self.summarization = Some(config);
133 self
134 }
135
136 pub fn with_tool_interrupt(mut self, tool_name: impl Into<String>, policy: HitlPolicy) -> Self {
137 self.tool_interrupts.insert(tool_name.into(), policy);
138 self
139 }
140
141 pub fn with_builtin_tools<I, S>(mut self, names: I) -> Self
142 where
143 I: IntoIterator<Item = S>,
144 S: Into<String>,
145 {
146 self.builtin_tools = Some(names.into_iter().map(|s| s.into()).collect());
147 self
148 }
149
150 pub fn with_auto_general_purpose(mut self, enabled: bool) -> Self {
151 self.auto_general_purpose = enabled;
152 self
153 }
154
155 pub fn with_prompt_caching(mut self, enabled: bool) -> Self {
156 self.enable_prompt_caching = enabled;
157 self
158 }
159
160 pub fn with_checkpointer(mut self, checkpointer: Arc<dyn Checkpointer>) -> Self {
161 self.checkpointer = Some(checkpointer);
162 self
163 }
164
165 pub fn with_event_broadcaster(
172 mut self,
173 broadcaster: Arc<dyn agents_core::events::EventBroadcaster>,
174 ) -> Self {
175 if self.event_dispatcher.is_none() {
177 self.event_dispatcher = Some(Arc::new(agents_core::events::EventDispatcher::new()));
178 }
179
180 if let Some(dispatcher) = &self.event_dispatcher {
182 dispatcher.add_broadcaster(broadcaster);
183 }
184
185 self
186 }
187
188 pub fn with_event_broadcasters(
199 mut self,
200 broadcasters: Vec<Arc<dyn agents_core::events::EventBroadcaster>>,
201 ) -> Self {
202 if self.event_dispatcher.is_none() {
204 self.event_dispatcher = Some(Arc::new(agents_core::events::EventDispatcher::new()));
205 }
206
207 if let Some(dispatcher) = &self.event_dispatcher {
209 for broadcaster in broadcasters {
210 dispatcher.add_broadcaster(broadcaster);
211 }
212 }
213
214 self
215 }
216
217 pub fn with_event_dispatcher(
219 mut self,
220 dispatcher: Arc<agents_core::events::EventDispatcher>,
221 ) -> Self {
222 self.event_dispatcher = Some(dispatcher);
223 self
224 }
225
226 pub fn build(self) -> anyhow::Result<DeepAgent> {
227 self.finalize(create_deep_agent_from_config)
228 }
229
230 pub fn build_async(self) -> anyhow::Result<DeepAgent> {
233 self.finalize(create_async_deep_agent_from_config)
234 }
235
236 fn finalize(self, ctor: fn(DeepAgentConfig) -> DeepAgent) -> anyhow::Result<DeepAgent> {
237 let Self {
238 instructions,
239 planner,
240 tools,
241 subagents,
242 summarization,
243 tool_interrupts,
244 builtin_tools,
245 auto_general_purpose,
246 enable_prompt_caching,
247 checkpointer,
248 event_dispatcher,
249 } = self;
250
251 let planner = planner
252 .ok_or_else(|| anyhow::anyhow!("model must be set (use with_model or with_*_chat)"))?;
253
254 let mut cfg = DeepAgentConfig::new(instructions, planner)
255 .with_auto_general_purpose(auto_general_purpose)
256 .with_prompt_caching(enable_prompt_caching);
257
258 if let Some(ckpt) = checkpointer {
259 cfg = cfg.with_checkpointer(ckpt);
260 }
261 if let Some(dispatcher) = event_dispatcher {
262 cfg = cfg.with_event_dispatcher(dispatcher);
263 }
264 if let Some(sum) = summarization {
265 cfg = cfg.with_summarization(sum);
266 }
267 if let Some(selected) = builtin_tools {
268 cfg = cfg.with_builtin_tools(selected);
269 }
270 for (name, policy) in tool_interrupts {
271 cfg = cfg.with_tool_interrupt(name, policy);
272 }
273 for tool in tools {
274 cfg = cfg.with_tool(tool);
275 }
276 for sub_cfg in subagents {
277 cfg = cfg.with_subagent_config(sub_cfg);
278 }
279
280 Ok(ctor(cfg))
281 }
282}