Skip to main content

swarm_engine_eval/scenario/
manager.rs

1//! Manager Configuration
2//!
3//! Manager の設定と関連する型の定義。
4
5use serde::{Deserialize, Serialize};
6
7use super::llm::default_true;
8
9// ============================================================================
10// Manager Configuration
11// ============================================================================
12
13/// Manager behavior configuration
14#[derive(Debug, Clone, Serialize, Deserialize)]
15pub struct ManagerConfig {
16    /// Process at every tick (overrides interval)
17    #[serde(default)]
18    pub process_every_tick: bool,
19
20    /// Process interval in ticks
21    #[serde(default = "default_process_interval_ticks")]
22    pub process_interval_ticks: u64,
23
24    /// Immediately respond to escalation events
25    #[serde(default = "default_true")]
26    pub immediate_on_escalation: bool,
27
28    /// Minimum confidence threshold for accepting LLM decisions
29    #[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// ============================================================================
53// BatchProcessor Configuration
54// ============================================================================
55
56/// Batch processor configuration
57#[derive(Debug, Clone, Serialize, Deserialize)]
58pub struct BatchProcessorConfig {
59    /// Enable parallel processing
60    #[serde(default = "default_true")]
61    pub parallel: bool,
62
63    /// Maximum concurrent requests
64    #[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// ============================================================================
82// Manager Template
83// ============================================================================
84
85/// Manager テンプレート
86#[derive(Debug, Clone, Serialize, Deserialize)]
87pub struct ManagerTemplate {
88    /// Manager ID (単一マネージャー用、id_pattern と排他)
89    #[serde(default)]
90    pub id: Option<String>,
91
92    /// ID生成パターン (e.g., "manager_{i}"、複数マネージャー用)
93    #[serde(default)]
94    pub id_pattern: Option<String>,
95
96    /// 生成数 (id_pattern 使用時のみ有効)
97    #[serde(default = "default_manager_count")]
98    pub count: usize,
99
100    /// Manager 役割/タイプ (e.g., "llm_batch")
101    #[serde(default)]
102    pub role: String,
103
104    /// アクティベーション設定
105    #[serde(default)]
106    pub activation: ManagerActivationConfig,
107
108    /// Manager 固有設定
109    #[serde(default)]
110    pub config: serde_json::Value,
111}
112
113fn default_manager_count() -> usize {
114    1
115}
116
117impl ManagerTemplate {
118    /// Manager IDを生成
119    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// ============================================================================
133// Manager Activation Configuration
134// ============================================================================
135
136/// Manager アクティベーション設定
137#[derive(Debug, Clone, Serialize, Deserialize)]
138#[serde(tag = "type", rename_all = "snake_case")]
139pub enum ManagerActivationConfig {
140    /// インターバルベース
141    Interval {
142        #[serde(default = "default_activation_interval")]
143        interval: u64,
144    },
145    /// イベントトリガー
146    Event {
147        #[serde(default)]
148        triggers: Vec<String>,
149    },
150    /// ハイブリッド
151    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// ============================================================================
172// Tests
173// ============================================================================
174
175#[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        // Single ID
224        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        // Pattern-based IDs
235        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}