lellm_agent/runtime/
builder.rs1use std::sync::Arc;
31
32use lellm_core::{Prompt, ReasoningConfig, ToolChoice};
33use lellm_provider::ResolvedModel;
34
35use super::config::{ToolCachePolicy, ToolUseConfig, ToolUseDeps};
36use super::context::ContextBudget;
37use super::fallback::FallbackStrategy;
38use super::request_opts::RequestOptions;
39use super::retry::RetryPolicy;
40use super::runtime::ToolUseLoop;
41use super::tools::{CompositeCatalog, StaticCatalog, ToolCatalog, ToolExecutor, ToolRegistration};
42
43pub struct AgentBuilder {
49 model: ResolvedModel,
50 static_tools: Vec<ToolRegistration>,
52 catalogs: Vec<Arc<dyn ToolCatalog>>,
54 config: ToolUseConfig,
55 deps: ToolUseDeps,
56}
57
58impl AgentBuilder {
59 pub fn new(model: ResolvedModel) -> Self {
61 Self {
62 model,
63 static_tools: Vec::new(),
64 catalogs: Vec::new(),
65 config: ToolUseConfig::default(),
66 deps: ToolUseDeps::default(),
67 }
68 }
69
70 pub fn tool(mut self, reg: ToolRegistration) -> Self {
72 self.static_tools.push(reg);
73 self
74 }
75
76 pub fn tools(mut self, registrations: impl IntoIterator<Item = ToolRegistration>) -> Self {
78 self.static_tools.extend(registrations);
79 self
80 }
81
82 pub fn catalog(mut self, catalog: Arc<dyn ToolCatalog>) -> Self {
100 self.catalogs.push(catalog);
101 self
102 }
103
104 pub fn max_iterations(mut self, max: usize) -> Self {
106 self.config.max_iterations = max;
107 self
108 }
109
110 pub fn max_output_tokens(mut self, max: u32) -> Self {
112 self.config.max_output_tokens = max;
113 self
114 }
115
116 pub fn max_total_output_tokens(mut self, max: u32) -> Self {
118 self.config.max_total_output_tokens = Some(max);
119 self
120 }
121
122 pub fn system(mut self, system: impl Into<Prompt>) -> Self {
147 self.config.system = Some(system.into());
148 self
149 }
150
151 #[deprecated(since = "0.5.0", note = "Use `.system()` instead")]
155 pub fn system_prompt(mut self, prompt: String) -> Self {
156 self.config.system = Some(prompt.into());
157 self
158 }
159
160 pub fn tool_cache_policy(mut self, policy: ToolCachePolicy) -> Self {
166 self.config.tool_cache_policy = policy;
167 self
168 }
169
170 pub fn request_options(mut self, opts: RequestOptions) -> Self {
174 self.config.request_options = opts;
175 self
176 }
177
178 pub fn temperature(mut self, t: f64) -> Self {
180 self.config.request_options.temperature = Some(t);
181 self
182 }
183
184 pub fn top_p(mut self, p: f64) -> Self {
186 self.config.request_options.top_p = Some(p);
187 self
188 }
189
190 pub fn seed(mut self, s: u64) -> Self {
192 self.config.request_options.seed = Some(s);
193 self
194 }
195
196 pub fn tool_choice(mut self, choice: ToolChoice) -> Self {
198 self.config.request_options.tool_choice = Some(choice);
199 self
200 }
201
202 pub fn stop_sequences(mut self, seqs: Vec<String>) -> Self {
204 self.config.request_options.stop_sequences = Some(seqs);
205 self
206 }
207
208 pub fn prefill(mut self, text: String) -> Self {
210 self.config.request_options.prefill = Some(text);
211 self
212 }
213
214 pub fn reasoning(mut self, r: ReasoningConfig) -> Self {
216 self.config.request_options.reasoning = Some(r);
217 self
218 }
219
220 pub fn stream_thinking(mut self, enable: bool) -> Self {
222 self.config.stream_thinking = enable;
223 self
224 }
225
226 pub fn reasoning_budget(mut self, max: u32) -> Self {
228 self.config.request_options.max_reasoning_tokens = Some(max);
229 self
230 }
231
232 pub fn max_total_reasoning_tokens(mut self, max: u32) -> Self {
234 self.config.max_total_reasoning_tokens = Some(max);
235 self
236 }
237
238 pub fn fallback(mut self, fallback: Arc<dyn FallbackStrategy>) -> Self {
240 self.deps.fallback = fallback;
241 self
242 }
243
244 pub fn retry_policy(mut self, policy: RetryPolicy) -> Self {
246 self.config.retry_policy = policy;
247 self
248 }
249
250 pub fn context_budget(mut self, budget: ContextBudget) -> Self {
253 self.config.context_budget = budget;
254 self
255 }
256
257 pub fn build(self) -> ToolUseLoop {
262 let mut sources: Vec<Arc<dyn ToolCatalog>> = Vec::new();
264
265 if !self.static_tools.is_empty() {
266 sources.push(Arc::new(StaticCatalog::from_tools(self.static_tools)));
267 }
268
269 sources.extend(self.catalogs);
270
271 let final_catalog: Arc<dyn ToolCatalog> = match sources.len() {
273 0 => Arc::new(StaticCatalog::empty()),
274 1 => sources.remove(0),
275 _ => Arc::new(CompositeCatalog::new(sources)),
276 };
277
278 let executor =
279 ToolExecutor::with_retry_policy(final_catalog, self.config.retry_policy.clone());
280 ToolUseLoop::new(self.model, executor, self.config, self.deps)
281 }
282}