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::agent::ToolHandle;
17use agents_core::llm::LanguageModel;
18use agents_core::persistence::Checkpointer;
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<Arc<dyn ToolHandle>>,
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}
36
37impl ConfigurableAgentBuilder {
38 pub fn new(instructions: impl Into<String>) -> Self {
39 Self {
40 instructions: instructions.into(),
41 planner: None,
42 tools: Vec::new(),
43 subagents: Vec::new(),
44 summarization: None,
45 tool_interrupts: HashMap::new(),
46 builtin_tools: None,
47 auto_general_purpose: true,
48 enable_prompt_caching: false,
49 checkpointer: None,
50 }
51 }
52
53 pub fn with_model(mut self, model: Arc<dyn LanguageModel>) -> Self {
55 let planner: Arc<dyn PlannerHandle> = Arc::new(LlmBackedPlanner::new(model));
56 self.planner = Some(planner);
57 self
58 }
59
60 pub fn with_planner(mut self, planner: Arc<dyn PlannerHandle>) -> Self {
62 self.planner = Some(planner);
63 self
64 }
65
66 pub fn with_openai_chat(self, config: OpenAiConfig) -> anyhow::Result<Self> {
68 let model = Arc::new(OpenAiChatModel::new(config)?);
69 Ok(self.with_model(model))
70 }
71
72 pub fn with_anthropic_messages(self, config: AnthropicConfig) -> anyhow::Result<Self> {
74 let model = Arc::new(AnthropicMessagesModel::new(config)?);
75 Ok(self.with_model(model))
76 }
77
78 pub fn with_gemini_chat(self, config: GeminiConfig) -> anyhow::Result<Self> {
80 let model = Arc::new(GeminiChatModel::new(config)?);
81 Ok(self.with_model(model))
82 }
83
84 pub fn with_tool(mut self, tool: Arc<dyn ToolHandle>) -> Self {
85 self.tools.push(tool);
86 self
87 }
88
89 pub fn with_tools<I>(mut self, tools: I) -> Self
90 where
91 I: IntoIterator<Item = Arc<dyn ToolHandle>>,
92 {
93 self.tools.extend(tools);
94 self
95 }
96
97 pub fn with_subagent_config<I>(mut self, cfgs: I) -> Self
98 where
99 I: IntoIterator<Item = SubAgentConfig>,
100 {
101 self.subagents.extend(cfgs);
102 self
103 }
104
105 pub fn with_subagent_tools<I>(mut self, tools: I) -> Self
108 where
109 I: IntoIterator<Item = Arc<dyn ToolHandle>>,
110 {
111 for tool in tools {
112 let tool_name = tool.name();
113 let subagent_config = SubAgentConfig {
114 name: format!("{}-agent", tool_name),
115 description: format!("Specialized agent for {} operations", tool_name),
116 instructions: format!(
117 "You are a specialized agent. Use the {} tool to complete tasks efficiently.",
118 tool_name
119 ),
120 tools: Some(vec![tool]),
121 planner: None, };
123 self.subagents.push(subagent_config);
124 }
125 self
126 }
127
128 pub fn with_summarization(mut self, config: SummarizationConfig) -> Self {
129 self.summarization = Some(config);
130 self
131 }
132
133 pub fn with_tool_interrupt(mut self, tool_name: impl Into<String>, policy: HitlPolicy) -> Self {
134 self.tool_interrupts.insert(tool_name.into(), policy);
135 self
136 }
137
138 pub fn with_builtin_tools<I, S>(mut self, names: I) -> Self
139 where
140 I: IntoIterator<Item = S>,
141 S: Into<String>,
142 {
143 self.builtin_tools = Some(names.into_iter().map(|s| s.into()).collect());
144 self
145 }
146
147 pub fn with_auto_general_purpose(mut self, enabled: bool) -> Self {
148 self.auto_general_purpose = enabled;
149 self
150 }
151
152 pub fn with_prompt_caching(mut self, enabled: bool) -> Self {
153 self.enable_prompt_caching = enabled;
154 self
155 }
156
157 pub fn with_checkpointer(mut self, checkpointer: Arc<dyn Checkpointer>) -> Self {
158 self.checkpointer = Some(checkpointer);
159 self
160 }
161
162 pub fn build(self) -> anyhow::Result<DeepAgent> {
163 self.finalize(create_deep_agent_from_config)
164 }
165
166 pub fn build_async(self) -> anyhow::Result<DeepAgent> {
169 self.finalize(create_async_deep_agent_from_config)
170 }
171
172 fn finalize(self, ctor: fn(DeepAgentConfig) -> DeepAgent) -> anyhow::Result<DeepAgent> {
173 let Self {
174 instructions,
175 planner,
176 tools,
177 subagents,
178 summarization,
179 tool_interrupts,
180 builtin_tools,
181 auto_general_purpose,
182 enable_prompt_caching,
183 checkpointer,
184 } = self;
185
186 let planner = planner
187 .ok_or_else(|| anyhow::anyhow!("model must be set (use with_model or with_*_chat)"))?;
188
189 let mut cfg = DeepAgentConfig::new(instructions, planner)
190 .with_auto_general_purpose(auto_general_purpose)
191 .with_prompt_caching(enable_prompt_caching);
192
193 if let Some(ckpt) = checkpointer {
194 cfg = cfg.with_checkpointer(ckpt);
195 }
196 if let Some(sum) = summarization {
197 cfg = cfg.with_summarization(sum);
198 }
199 if let Some(selected) = builtin_tools {
200 cfg = cfg.with_builtin_tools(selected);
201 }
202 for (name, policy) in tool_interrupts {
203 cfg = cfg.with_tool_interrupt(name, policy);
204 }
205 for tool in tools {
206 cfg = cfg.with_tool(tool);
207 }
208 for sub_cfg in subagents {
209 cfg = cfg.with_subagent_config(sub_cfg);
210 }
211
212 Ok(ctor(cfg))
213 }
214}