Skip to main content

vv_agent/
run_config.rs

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}