1use std::path::PathBuf;
2use std::sync::Arc;
3use std::time::Duration;
4
5use serde_json::Value;
6
7use crate::approval::{ApprovalBroker, ApprovalProvider};
8use crate::budget::{HostCostMeter, RunBudgetLimits};
9use crate::checkpoint::{CheckpointConfig, CheckpointExtension, ReconciliationProvider};
10use crate::context_providers::ContextProvider;
11use crate::event_store::RunEventStore;
12use crate::execution_mode::ExecutionMode;
13use crate::llm::LlmStreamCallback;
14use crate::memory::MemoryProvider;
15use crate::model::{ModelProvider, ModelRef};
16use crate::model_settings::ModelSettings;
17use crate::runtime::backends::RuntimeExecutionBackend;
18use crate::runtime::{
19 BeforeCycleMessageProvider, CancellationToken, InterruptionMessageProvider,
20 RuntimeEventHandler, RuntimeHook, SubTaskManager,
21};
22use crate::sessions::Session;
23use crate::tools::{ToolPolicy, ToolRegistry};
24use crate::tracing::TraceSink;
25use crate::types::{Message, Metadata, NoToolPolicy};
26use crate::workspace::WorkspaceBackend;
27
28pub type ToolRegistryFactory = Arc<dyn Fn() -> ToolRegistry + Send + Sync + 'static>;
29
30pub(crate) const INITIAL_BUDGET_USAGE_METADATA_KEY: &str = "_vv_agent_initial_budget_usage";
31
32pub(crate) const MAX_CYCLES_RANGE_ERROR: &str = "max_cycles must be between 1 and 4294967295";
33
34pub(crate) fn validate_max_cycles(max_cycles: u32) -> Result<u32, String> {
35 if max_cycles == 0 {
36 return Err(MAX_CYCLES_RANGE_ERROR.to_string());
37 }
38 Ok(max_cycles)
39}
40
41#[derive(Clone, Default)]
42pub struct RunConfig {
43 pub model: Option<ModelRef>,
44 pub model_provider: Option<Arc<dyn ModelProvider>>,
45 pub model_settings: Option<ModelSettings>,
46 pub workspace: Option<PathBuf>,
47 pub workspace_backend: Option<Arc<dyn WorkspaceBackend>>,
48 pub session: Option<Arc<dyn Session>>,
49 pub initial_messages: Option<Vec<Message>>,
50 pub max_cycles: Option<u32>,
51 pub max_handoffs: Option<u32>,
52 pub no_tool_policy: Option<NoToolPolicy>,
53 pub tool_policy: ToolPolicy,
54 pub execution_backend: Option<RuntimeExecutionBackend>,
55 pub cancellation_token: Option<CancellationToken>,
56 pub hooks: Vec<Arc<dyn RuntimeHook>>,
57 pub trace_sink: Option<Arc<dyn TraceSink>>,
58 pub trace_id: Option<String>,
59 pub workflow_name: Option<String>,
60 pub event_store: Option<Arc<dyn RunEventStore>>,
61 pub event_store_fail_closed: bool,
62 pub approval_provider: Option<Arc<dyn ApprovalProvider>>,
63 pub approval_timeout: Option<Duration>,
64 pub approval_broker: Option<ApprovalBroker>,
65 pub context_providers: Vec<Arc<dyn ContextProvider>>,
66 pub max_context_chars: Option<usize>,
67 pub memory_providers: Vec<Arc<dyn MemoryProvider>>,
68 pub app_state: Option<Arc<dyn std::any::Any + Send + Sync>>,
69 pub initial_shared_state: Metadata,
70 pub tool_registry_factory: Option<ToolRegistryFactory>,
71 pub log_preview_chars: Option<usize>,
72 pub debug_dump_dir: Option<PathBuf>,
73 pub before_cycle_messages: Option<BeforeCycleMessageProvider>,
74 pub interruption_messages: Option<InterruptionMessageProvider>,
75 pub sub_task_manager: Option<SubTaskManager>,
76 pub runtime_log_handler: Option<RuntimeEventHandler>,
77 pub runtime_stream_callback: Option<LlmStreamCallback>,
78 pub budget_limits: Option<RunBudgetLimits>,
79 pub host_cost_meter: Option<Arc<dyn HostCostMeter>>,
80 pub checkpoint_config: Option<CheckpointConfig>,
81 pub checkpoint_extensions: Vec<Arc<dyn CheckpointExtension>>,
82 pub reconciliation_provider: Option<Arc<dyn ReconciliationProvider>>,
83 pub metadata: Metadata,
84}
85
86impl RunConfig {
87 pub fn builder() -> RunConfigBuilder {
88 RunConfigBuilder::default()
89 }
90
91 pub(crate) fn for_background_child(&self, shared_state: Metadata) -> Self {
92 let mut child = self.clone();
93 child.model = None;
94 child.model_settings = None;
95 child.session = None;
96 child.initial_messages = None;
97 child.cancellation_token = self
98 .cancellation_token
99 .as_ref()
100 .map(CancellationToken::child);
101 child.initial_shared_state = shared_state;
102 child.before_cycle_messages = None;
103 child.interruption_messages = None;
104 child.sub_task_manager = None;
105 child.runtime_log_handler = None;
106 child.runtime_stream_callback = None;
107 child.host_cost_meter = None;
108 child.checkpoint_config = None;
109 child.checkpoint_extensions.clear();
110 child.reconciliation_provider = None;
111 child.metadata.remove(INITIAL_BUDGET_USAGE_METADATA_KEY);
112 child
113 }
114}
115
116#[derive(Default)]
117pub struct RunConfigBuilder {
118 config: RunConfig,
119}
120
121impl RunConfigBuilder {
122 pub fn model(mut self, model: ModelRef) -> Self {
123 self.config.model = Some(model);
124 self
125 }
126
127 pub fn model_provider(mut self, provider: impl ModelProvider + 'static) -> Self {
128 self.config.model_provider = Some(Arc::new(provider));
129 self
130 }
131
132 pub fn model_provider_arc(mut self, provider: Arc<dyn ModelProvider>) -> Self {
133 self.config.model_provider = Some(provider);
134 self
135 }
136
137 pub fn model_settings(mut self, settings: ModelSettings) -> Self {
138 self.config.model_settings = Some(settings);
139 self
140 }
141
142 pub fn workspace(mut self, workspace: impl Into<PathBuf>) -> Self {
143 self.config.workspace = Some(workspace.into());
144 self
145 }
146
147 pub fn workspace_backend(mut self, backend: Arc<dyn WorkspaceBackend>) -> Self {
148 self.config.workspace_backend = Some(backend);
149 self
150 }
151
152 pub fn session(mut self, session: impl Session + 'static) -> Self {
153 self.config.session = Some(Arc::new(session));
154 self
155 }
156
157 pub fn session_arc(mut self, session: Arc<dyn Session>) -> Self {
158 self.config.session = Some(session);
159 self
160 }
161
162 pub fn initial_messages(mut self, messages: Vec<Message>) -> Self {
163 self.config.initial_messages = Some(messages);
164 self
165 }
166
167 pub fn max_cycles(mut self, max_cycles: u32) -> Self {
168 self.config.max_cycles = Some(max_cycles);
169 self
170 }
171
172 pub fn max_handoffs(mut self, max_handoffs: u32) -> Self {
173 self.config.max_handoffs = Some(max_handoffs);
174 self
175 }
176
177 pub fn no_tool_policy(mut self, policy: NoToolPolicy) -> Self {
178 self.config.no_tool_policy = Some(policy);
179 self
180 }
181
182 pub fn tool_policy(mut self, tool_policy: ToolPolicy) -> Self {
183 self.config.tool_policy = tool_policy;
184 self
185 }
186
187 pub fn execution_backend(mut self, execution_backend: RuntimeExecutionBackend) -> Self {
188 self.config.execution_backend = Some(execution_backend);
189 self
190 }
191
192 pub fn execution_mode(mut self, execution_mode: ExecutionMode) -> Self {
193 self.config.execution_backend = Some(execution_mode.into());
194 self
195 }
196
197 pub fn cancellation_token(mut self, cancellation_token: CancellationToken) -> Self {
198 self.config.cancellation_token = Some(cancellation_token);
199 self
200 }
201
202 pub fn hook(mut self, hook: Arc<dyn RuntimeHook>) -> Self {
203 self.config.hooks.push(hook);
204 self
205 }
206
207 pub fn trace_sink(mut self, sink: Arc<dyn TraceSink>) -> Self {
208 self.config.trace_sink = Some(sink);
209 self
210 }
211
212 pub fn trace_id(mut self, trace_id: impl Into<String>) -> Self {
213 self.config.trace_id = Some(trace_id.into());
214 self
215 }
216
217 pub fn workflow_name(mut self, workflow_name: impl Into<String>) -> Self {
218 self.config.workflow_name = Some(workflow_name.into());
219 self
220 }
221
222 pub fn event_store(mut self, store: Arc<dyn RunEventStore>) -> Self {
223 self.config.event_store = Some(store);
224 self
225 }
226
227 pub fn event_store_fail_closed(mut self, fail_closed: bool) -> Self {
228 self.config.event_store_fail_closed = fail_closed;
229 self
230 }
231
232 pub fn approval_provider(mut self, provider: Arc<dyn ApprovalProvider>) -> Self {
233 self.config.approval_provider = Some(provider);
234 self
235 }
236
237 pub fn approval_timeout(mut self, timeout: Duration) -> Self {
238 self.config.approval_timeout = Some(timeout);
239 self
240 }
241
242 pub fn approval_broker(mut self, broker: ApprovalBroker) -> Self {
243 self.config.approval_broker = Some(broker);
244 self
245 }
246
247 pub fn context_provider(mut self, provider: Arc<dyn ContextProvider>) -> Self {
248 self.config.context_providers.push(provider);
249 self
250 }
251
252 pub fn max_context_chars(mut self, max_chars: usize) -> Self {
253 self.config.max_context_chars = Some(max_chars);
254 self
255 }
256
257 pub fn memory_provider(mut self, provider: Arc<dyn MemoryProvider>) -> Self {
258 self.config.memory_providers.push(provider);
259 self
260 }
261
262 pub fn app_state<T>(mut self, app_state: T) -> Self
263 where
264 T: Send + Sync + 'static,
265 {
266 self.config.app_state = Some(Arc::new(app_state));
267 self
268 }
269
270 pub fn app_state_arc(mut self, app_state: Arc<dyn std::any::Any + Send + Sync>) -> Self {
271 self.config.app_state = Some(app_state);
272 self
273 }
274
275 pub fn initial_shared_state(mut self, shared_state: Metadata) -> Self {
276 self.config.initial_shared_state = shared_state;
277 self
278 }
279
280 pub fn shared_state(self, shared_state: Metadata) -> Self {
281 self.initial_shared_state(shared_state)
282 }
283
284 pub fn tool_registry_factory(
285 mut self,
286 factory: impl Fn() -> ToolRegistry + Send + Sync + 'static,
287 ) -> Self {
288 self.config.tool_registry_factory = Some(Arc::new(factory));
289 self
290 }
291
292 pub fn tool_registry_factory_arc(mut self, factory: ToolRegistryFactory) -> Self {
293 self.config.tool_registry_factory = Some(factory);
294 self
295 }
296
297 pub fn log_preview_chars(mut self, max_chars: usize) -> Self {
298 self.config.log_preview_chars = Some(max_chars);
299 self
300 }
301
302 pub fn debug_dump_dir(mut self, path: impl Into<PathBuf>) -> Self {
303 self.config.debug_dump_dir = Some(path.into());
304 self
305 }
306
307 pub fn before_cycle_messages(
308 mut self,
309 provider: impl Fn(u32, &[Message], &Metadata) -> Vec<Message> + Send + Sync + 'static,
310 ) -> Self {
311 self.config.before_cycle_messages = Some(Arc::new(provider));
312 self
313 }
314
315 pub fn before_cycle_messages_arc(mut self, provider: BeforeCycleMessageProvider) -> Self {
316 self.config.before_cycle_messages = Some(provider);
317 self
318 }
319
320 pub fn interruption_messages(
321 mut self,
322 provider: impl Fn() -> Vec<Message> + Send + Sync + 'static,
323 ) -> Self {
324 self.config.interruption_messages = Some(Arc::new(provider));
325 self
326 }
327
328 pub fn interruption_messages_arc(mut self, provider: InterruptionMessageProvider) -> Self {
329 self.config.interruption_messages = Some(provider);
330 self
331 }
332
333 pub fn sub_task_manager(mut self, manager: SubTaskManager) -> Self {
334 self.config.sub_task_manager = Some(manager);
335 self
336 }
337
338 pub fn runtime_log_handler(
339 mut self,
340 handler: impl Fn(&str, &Metadata) + Send + Sync + 'static,
341 ) -> Self {
342 self.config.runtime_log_handler = Some(Arc::new(handler));
343 self
344 }
345
346 pub fn runtime_log_handler_arc(mut self, handler: RuntimeEventHandler) -> Self {
347 self.config.runtime_log_handler = Some(handler);
348 self
349 }
350
351 pub fn runtime_stream_callback(
352 mut self,
353 callback: impl Fn(&Metadata) + Send + Sync + 'static,
354 ) -> Self {
355 self.config.runtime_stream_callback = Some(Arc::new(callback));
356 self
357 }
358
359 pub fn runtime_stream_callback_arc(mut self, callback: LlmStreamCallback) -> Self {
360 self.config.runtime_stream_callback = Some(callback);
361 self
362 }
363
364 pub fn budget_limits(mut self, limits: RunBudgetLimits) -> Self {
365 self.config.budget_limits = Some(limits);
366 self
367 }
368
369 pub fn host_cost_meter(mut self, meter: impl HostCostMeter + 'static) -> Self {
370 self.config.host_cost_meter = Some(Arc::new(meter));
371 self
372 }
373
374 pub fn host_cost_meter_arc(mut self, meter: Arc<dyn HostCostMeter>) -> Self {
375 self.config.host_cost_meter = Some(meter);
376 self
377 }
378
379 pub fn checkpoint_config(mut self, checkpoint_config: CheckpointConfig) -> Self {
380 self.config.checkpoint_config = Some(checkpoint_config);
381 self
382 }
383
384 pub fn checkpoint_extension(mut self, extension: impl CheckpointExtension + 'static) -> Self {
385 self.config.checkpoint_extensions.push(Arc::new(extension));
386 self
387 }
388
389 pub fn checkpoint_extension_arc(mut self, extension: Arc<dyn CheckpointExtension>) -> Self {
390 self.config.checkpoint_extensions.push(extension);
391 self
392 }
393
394 pub fn reconciliation_provider(
395 mut self,
396 provider: impl ReconciliationProvider + 'static,
397 ) -> Self {
398 self.config.reconciliation_provider = Some(Arc::new(provider));
399 self
400 }
401
402 pub fn reconciliation_provider_arc(
403 mut self,
404 provider: Arc<dyn ReconciliationProvider>,
405 ) -> Self {
406 self.config.reconciliation_provider = Some(provider);
407 self
408 }
409
410 pub fn metadata(mut self, key: impl Into<String>, value: Value) -> Self {
411 self.config.metadata.insert(key.into(), value);
412 self
413 }
414
415 pub fn build(self) -> RunConfig {
416 self.config
417 }
418}