lellm_agent/runtime/
builder.rs1use std::sync::Arc;
18
19use lellm_core::{ReasoningConfig, ToolChoice};
20use lellm_provider::ResolvedModel;
21
22use super::config::{ToolUseConfig, ToolUseDeps};
23use super::context::ContextBudget;
24use super::fallback::FallbackStrategy;
25use super::request_opts::RequestOptions;
26use super::retry::RetryPolicy;
27use super::runtime::ToolUseLoop;
28use super::tools::{CompositeCatalog, StaticCatalog, ToolCatalog, ToolExecutor, ToolRegistration};
29
30pub struct AgentBuilder {
36 model: ResolvedModel,
37 static_tools: Vec<ToolRegistration>,
39 catalogs: Vec<Arc<dyn ToolCatalog>>,
41 config: ToolUseConfig,
42 deps: ToolUseDeps,
43}
44
45impl AgentBuilder {
46 pub fn new(model: ResolvedModel) -> Self {
48 Self {
49 model,
50 static_tools: Vec::new(),
51 catalogs: Vec::new(),
52 config: ToolUseConfig::default(),
53 deps: ToolUseDeps::default(),
54 }
55 }
56
57 pub fn tool(mut self, reg: ToolRegistration) -> Self {
59 self.static_tools.push(reg);
60 self
61 }
62
63 pub fn tools(mut self, registrations: impl IntoIterator<Item = ToolRegistration>) -> Self {
65 self.static_tools.extend(registrations);
66 self
67 }
68
69 pub fn catalog(mut self, catalog: Arc<dyn ToolCatalog>) -> Self {
87 self.catalogs.push(catalog);
88 self
89 }
90
91 pub fn max_iterations(mut self, max: usize) -> Self {
93 self.config.max_iterations = max;
94 self
95 }
96
97 pub fn max_output_tokens(mut self, max: u32) -> Self {
99 self.config.max_output_tokens = max;
100 self
101 }
102
103 pub fn max_total_output_tokens(mut self, max: u32) -> Self {
105 self.config.max_total_output_tokens = Some(max);
106 self
107 }
108
109 pub fn system_prompt(mut self, prompt: String) -> Self {
111 self.config.system_prompt = Some(prompt);
112 self
113 }
114
115 pub fn request_options(mut self, opts: RequestOptions) -> Self {
119 self.config.request_options = opts;
120 self
121 }
122
123 pub fn temperature(mut self, t: f64) -> Self {
125 self.config.request_options.temperature = Some(t);
126 self
127 }
128
129 pub fn top_p(mut self, p: f64) -> Self {
131 self.config.request_options.top_p = Some(p);
132 self
133 }
134
135 pub fn seed(mut self, s: u64) -> Self {
137 self.config.request_options.seed = Some(s);
138 self
139 }
140
141 pub fn tool_choice(mut self, choice: ToolChoice) -> Self {
143 self.config.request_options.tool_choice = Some(choice);
144 self
145 }
146
147 pub fn stop_sequences(mut self, seqs: Vec<String>) -> Self {
149 self.config.request_options.stop_sequences = Some(seqs);
150 self
151 }
152
153 pub fn prefill(mut self, text: String) -> Self {
155 self.config.request_options.prefill = Some(text);
156 self
157 }
158
159 pub fn reasoning(mut self, r: ReasoningConfig) -> Self {
161 self.config.request_options.reasoning = Some(r);
162 self
163 }
164
165 pub fn stream_thinking(mut self, enable: bool) -> Self {
167 self.config.stream_thinking = enable;
168 self
169 }
170
171 pub fn reasoning_budget(mut self, max: u32) -> Self {
173 self.config.request_options.max_reasoning_tokens = Some(max);
174 self
175 }
176
177 pub fn max_total_reasoning_tokens(mut self, max: u32) -> Self {
179 self.config.max_total_reasoning_tokens = Some(max);
180 self
181 }
182
183 pub fn fallback(mut self, fallback: Arc<dyn FallbackStrategy>) -> Self {
185 self.deps.fallback = fallback;
186 self
187 }
188
189 pub fn retry_policy(mut self, policy: RetryPolicy) -> Self {
191 self.config.retry_policy = policy;
192 self
193 }
194
195 pub fn context_budget(mut self, budget: ContextBudget) -> Self {
198 self.config.context_budget = budget;
199 self
200 }
201
202 pub fn build(self) -> ToolUseLoop {
207 let mut sources: Vec<Arc<dyn ToolCatalog>> = Vec::new();
209
210 if !self.static_tools.is_empty() {
211 sources.push(Arc::new(StaticCatalog::from_tools(self.static_tools)));
212 }
213
214 sources.extend(self.catalogs);
215
216 let final_catalog: Arc<dyn ToolCatalog> = match sources.len() {
218 0 => Arc::new(StaticCatalog::empty()),
219 1 => sources.remove(0),
220 _ => Arc::new(CompositeCatalog::new(sources)),
221 };
222
223 let executor =
224 ToolExecutor::with_retry_policy(final_catalog, self.config.retry_policy.clone());
225 ToolUseLoop::new(self.model, executor, self.config, self.deps)
226 }
227}