swarm_engine_eval/scenario/
manager.rs1use serde::{Deserialize, Serialize};
6
7use super::llm::default_true;
8
9#[derive(Debug, Clone, Serialize, Deserialize)]
15pub struct ManagerConfig {
16 #[serde(default)]
18 pub process_every_tick: bool,
19
20 #[serde(default = "default_process_interval_ticks")]
22 pub process_interval_ticks: u64,
23
24 #[serde(default = "default_true")]
26 pub immediate_on_escalation: bool,
27
28 #[serde(default = "default_confidence_threshold")]
30 pub confidence_threshold: f64,
31}
32
33fn default_process_interval_ticks() -> u64 {
34 5
35}
36
37fn default_confidence_threshold() -> f64 {
38 0.3
39}
40
41impl Default for ManagerConfig {
42 fn default() -> Self {
43 Self {
44 process_every_tick: false,
45 process_interval_ticks: default_process_interval_ticks(),
46 immediate_on_escalation: default_true(),
47 confidence_threshold: default_confidence_threshold(),
48 }
49 }
50}
51
52#[derive(Debug, Clone, Serialize, Deserialize)]
58pub struct BatchProcessorConfig {
59 #[serde(default = "default_true")]
61 pub parallel: bool,
62
63 #[serde(default = "default_max_concurrency")]
65 pub max_concurrency: usize,
66}
67
68fn default_max_concurrency() -> usize {
69 4
70}
71
72impl Default for BatchProcessorConfig {
73 fn default() -> Self {
74 Self {
75 parallel: true,
76 max_concurrency: default_max_concurrency(),
77 }
78 }
79}
80
81#[derive(Debug, Clone, Serialize, Deserialize)]
87pub struct ManagerTemplate {
88 #[serde(default)]
90 pub id: Option<String>,
91
92 #[serde(default)]
94 pub id_pattern: Option<String>,
95
96 #[serde(default = "default_manager_count")]
98 pub count: usize,
99
100 #[serde(default)]
102 pub role: String,
103
104 #[serde(default)]
106 pub activation: ManagerActivationConfig,
107
108 #[serde(default)]
110 pub config: serde_json::Value,
111}
112
113fn default_manager_count() -> usize {
114 1
115}
116
117impl ManagerTemplate {
118 pub fn generate_ids(&self) -> Vec<String> {
120 if let Some(ref pattern) = self.id_pattern {
121 (0..self.count)
122 .map(|i| pattern.replace("{i}", &i.to_string()))
123 .collect()
124 } else if let Some(ref id) = self.id {
125 vec![id.clone()]
126 } else {
127 vec!["manager_0".to_string()]
128 }
129 }
130}
131
132#[derive(Debug, Clone, Serialize, Deserialize)]
138#[serde(tag = "type", rename_all = "snake_case")]
139pub enum ManagerActivationConfig {
140 Interval {
142 #[serde(default = "default_activation_interval")]
143 interval: u64,
144 },
145 Event {
147 #[serde(default)]
148 triggers: Vec<String>,
149 },
150 Hybrid {
152 #[serde(default = "default_activation_interval")]
153 interval: u64,
154 #[serde(default)]
155 triggers: Vec<String>,
156 },
157}
158
159fn default_activation_interval() -> u64 {
160 10
161}
162
163impl Default for ManagerActivationConfig {
164 fn default() -> Self {
165 Self::Interval {
166 interval: default_activation_interval(),
167 }
168 }
169}
170
171#[cfg(test)]
176mod tests {
177 use super::*;
178
179 #[test]
180 fn test_manager_config_default() {
181 let config = ManagerConfig::default();
182 assert!(!config.process_every_tick);
183 assert_eq!(config.process_interval_ticks, 5);
184 assert!(config.immediate_on_escalation);
185 assert!((config.confidence_threshold - 0.3).abs() < 0.001);
186 }
187
188 #[test]
189 fn test_manager_config_deserialize_toml() {
190 let toml_str = r#"
191 process_every_tick = true
192 process_interval_ticks = 10
193 immediate_on_escalation = false
194 confidence_threshold = 0.5
195 "#;
196 let config: ManagerConfig = toml::from_str(toml_str).unwrap();
197 assert!(config.process_every_tick);
198 assert_eq!(config.process_interval_ticks, 10);
199 assert!(!config.immediate_on_escalation);
200 assert!((config.confidence_threshold - 0.5).abs() < 0.001);
201 }
202
203 #[test]
204 fn test_batch_processor_config_default() {
205 let config = BatchProcessorConfig::default();
206 assert!(config.parallel);
207 assert_eq!(config.max_concurrency, 4);
208 }
209
210 #[test]
211 fn test_batch_processor_config_deserialize_toml() {
212 let toml_str = r#"
213 parallel = false
214 max_concurrency = 8
215 "#;
216 let config: BatchProcessorConfig = toml::from_str(toml_str).unwrap();
217 assert!(!config.parallel);
218 assert_eq!(config.max_concurrency, 8);
219 }
220
221 #[test]
222 fn test_manager_template_generate_ids() {
223 let template = ManagerTemplate {
225 id: Some("my_manager".to_string()),
226 id_pattern: None,
227 count: 1,
228 role: "llm_batch".to_string(),
229 activation: ManagerActivationConfig::default(),
230 config: serde_json::Value::Null,
231 };
232 assert_eq!(template.generate_ids(), vec!["my_manager"]);
233
234 let template = ManagerTemplate {
236 id: None,
237 id_pattern: Some("manager_{i}".to_string()),
238 count: 3,
239 role: "llm_batch".to_string(),
240 activation: ManagerActivationConfig::default(),
241 config: serde_json::Value::Null,
242 };
243 assert_eq!(
244 template.generate_ids(),
245 vec!["manager_0", "manager_1", "manager_2"]
246 );
247 }
248
249 #[test]
250 fn test_manager_activation_config_default() {
251 let config = ManagerActivationConfig::default();
252 match config {
253 ManagerActivationConfig::Interval { interval } => {
254 assert_eq!(interval, 10);
255 }
256 _ => panic!("Expected Interval variant"),
257 }
258 }
259}