Skip to main content

wesichain_graph/
config.rs

1#[derive(Clone, Debug)]
2pub struct ExecutionConfig {
3    pub max_steps: Option<usize>,
4    pub max_duration: Option<std::time::Duration>,
5    pub node_timeout: Option<std::time::Duration>,
6    pub max_visits: Option<u32>,
7    pub max_loop_iterations: Option<u32>,
8    pub cycle_detection: bool,
9    pub cycle_window: usize,
10    pub interrupt_before: Vec<String>,
11    pub interrupt_after: Vec<String>,
12}
13
14impl Default for ExecutionConfig {
15    fn default() -> Self {
16        Self {
17            max_steps: Some(50),
18            max_duration: None,
19            node_timeout: None,
20            max_visits: Some(10),
21            max_loop_iterations: Some(15),
22            cycle_detection: true,
23            cycle_window: 20,
24            interrupt_before: Vec::new(),
25            interrupt_after: Vec::new(),
26        }
27    }
28}
29
30impl ExecutionConfig {
31    pub fn merge(&self, overrides: &ExecutionOptions) -> Self {
32        Self {
33            max_steps: overrides.max_steps.or(self.max_steps),
34            max_duration: overrides.max_duration.or(self.max_duration),
35            node_timeout: overrides.node_timeout.or(self.node_timeout),
36            max_visits: overrides.max_visits.or(self.max_visits),
37            max_loop_iterations: overrides.max_loop_iterations.or(self.max_loop_iterations),
38            cycle_detection: overrides.cycle_detection.unwrap_or(self.cycle_detection),
39            cycle_window: overrides.cycle_window.unwrap_or(self.cycle_window),
40            interrupt_before: if !overrides.interrupt_before.is_empty() {
41                overrides.interrupt_before.clone()
42            } else {
43                self.interrupt_before.clone()
44            },
45            interrupt_after: if !overrides.interrupt_after.is_empty() {
46                overrides.interrupt_after.clone()
47            } else {
48                self.interrupt_after.clone()
49            },
50        }
51    }
52}
53
54use std::sync::Arc;
55use tokio::sync::mpsc;
56use wesichain_core::{AgentEvent, RunConfig};
57
58use crate::Observer;
59
60#[derive(Clone, Default)]
61pub struct ExecutionOptions {
62    pub max_steps: Option<usize>,
63    pub max_duration: Option<std::time::Duration>,
64    pub node_timeout: Option<std::time::Duration>,
65    pub max_visits: Option<u32>,
66    pub max_loop_iterations: Option<u32>,
67    pub cycle_detection: Option<bool>,
68    pub cycle_window: Option<usize>,
69    pub interrupt_before: Vec<String>,
70    pub interrupt_after: Vec<String>,
71    pub initial_queue: Option<Vec<(String, u64)>>,
72    pub initial_step: Option<usize>,
73    pub checkpoint_thread_id: Option<String>,
74    pub auto_resume: bool,
75    pub run_config: Option<RunConfig>,
76    pub observer: Option<Arc<dyn Observer>>,
77    pub agent_event_sender: Option<mpsc::Sender<AgentEvent>>,
78    pub agent_event_thread_id: Option<String>,
79}
80
81impl std::fmt::Debug for ExecutionOptions {
82    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
83        f.debug_struct("ExecutionOptions")
84            .field("max_steps", &self.max_steps)
85            .field("max_duration", &self.max_duration)
86            .field("node_timeout", &self.node_timeout)
87            .field("max_visits", &self.max_visits)
88            .field("max_loop_iterations", &self.max_loop_iterations)
89            .field("cycle_detection", &self.cycle_detection)
90            .field("cycle_window", &self.cycle_window)
91            .field("interrupt_before", &self.interrupt_before)
92            .field("interrupt_after", &self.interrupt_after)
93            // Skip queue in debug output to avoid clutter, or summarize
94            .field(
95                "initial_queue_len",
96                &self.initial_queue.as_ref().map(|q| q.len()),
97            )
98            .field("checkpoint_thread_id", &self.checkpoint_thread_id)
99            .field("auto_resume", &self.auto_resume)
100            .field("run_config", &self.run_config.is_some())
101            .field("observer", &self.observer.is_some())
102            .field("agent_event_sender", &self.agent_event_sender.is_some())
103            .field("agent_event_thread_id", &self.agent_event_thread_id)
104            .finish()
105    }
106}