swarm-engine-eval 0.1.6

Evaluation framework for SwarmEngine
Documentation
//! Manager Configuration
//!
//! Manager の設定と関連する型の定義。

use serde::{Deserialize, Serialize};

use super::llm::default_true;

// ============================================================================
// Manager Configuration
// ============================================================================

/// Manager behavior configuration
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ManagerConfig {
    /// Process at every tick (overrides interval)
    #[serde(default)]
    pub process_every_tick: bool,

    /// Process interval in ticks
    #[serde(default = "default_process_interval_ticks")]
    pub process_interval_ticks: u64,

    /// Immediately respond to escalation events
    #[serde(default = "default_true")]
    pub immediate_on_escalation: bool,

    /// Minimum confidence threshold for accepting LLM decisions
    #[serde(default = "default_confidence_threshold")]
    pub confidence_threshold: f64,
}

fn default_process_interval_ticks() -> u64 {
    5
}

fn default_confidence_threshold() -> f64 {
    0.3
}

impl Default for ManagerConfig {
    fn default() -> Self {
        Self {
            process_every_tick: false,
            process_interval_ticks: default_process_interval_ticks(),
            immediate_on_escalation: default_true(),
            confidence_threshold: default_confidence_threshold(),
        }
    }
}

// ============================================================================
// BatchProcessor Configuration
// ============================================================================

/// Batch processor configuration
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct BatchProcessorConfig {
    /// Enable parallel processing
    #[serde(default = "default_true")]
    pub parallel: bool,

    /// Maximum concurrent requests
    #[serde(default = "default_max_concurrency")]
    pub max_concurrency: usize,
}

fn default_max_concurrency() -> usize {
    4
}

impl Default for BatchProcessorConfig {
    fn default() -> Self {
        Self {
            parallel: true,
            max_concurrency: default_max_concurrency(),
        }
    }
}

// ============================================================================
// Manager Template
// ============================================================================

/// Manager テンプレート
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ManagerTemplate {
    /// Manager ID (単一マネージャー用、id_pattern と排他)
    #[serde(default)]
    pub id: Option<String>,

    /// ID生成パターン (e.g., "manager_{i}"、複数マネージャー用)
    #[serde(default)]
    pub id_pattern: Option<String>,

    /// 生成数 (id_pattern 使用時のみ有効)
    #[serde(default = "default_manager_count")]
    pub count: usize,

    /// Manager 役割/タイプ (e.g., "llm_batch")
    #[serde(default)]
    pub role: String,

    /// アクティベーション設定
    #[serde(default)]
    pub activation: ManagerActivationConfig,

    /// Manager 固有設定
    #[serde(default)]
    pub config: serde_json::Value,
}

fn default_manager_count() -> usize {
    1
}

impl ManagerTemplate {
    /// Manager IDを生成
    pub fn generate_ids(&self) -> Vec<String> {
        if let Some(ref pattern) = self.id_pattern {
            (0..self.count)
                .map(|i| pattern.replace("{i}", &i.to_string()))
                .collect()
        } else if let Some(ref id) = self.id {
            vec![id.clone()]
        } else {
            vec!["manager_0".to_string()]
        }
    }
}

// ============================================================================
// Manager Activation Configuration
// ============================================================================

/// Manager アクティベーション設定
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(tag = "type", rename_all = "snake_case")]
pub enum ManagerActivationConfig {
    /// インターバルベース
    Interval {
        #[serde(default = "default_activation_interval")]
        interval: u64,
    },
    /// イベントトリガー
    Event {
        #[serde(default)]
        triggers: Vec<String>,
    },
    /// ハイブリッド
    Hybrid {
        #[serde(default = "default_activation_interval")]
        interval: u64,
        #[serde(default)]
        triggers: Vec<String>,
    },
}

fn default_activation_interval() -> u64 {
    10
}

impl Default for ManagerActivationConfig {
    fn default() -> Self {
        Self::Interval {
            interval: default_activation_interval(),
        }
    }
}

// ============================================================================
// Tests
// ============================================================================

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_manager_config_default() {
        let config = ManagerConfig::default();
        assert!(!config.process_every_tick);
        assert_eq!(config.process_interval_ticks, 5);
        assert!(config.immediate_on_escalation);
        assert!((config.confidence_threshold - 0.3).abs() < 0.001);
    }

    #[test]
    fn test_manager_config_deserialize_toml() {
        let toml_str = r#"
            process_every_tick = true
            process_interval_ticks = 10
            immediate_on_escalation = false
            confidence_threshold = 0.5
        "#;
        let config: ManagerConfig = toml::from_str(toml_str).unwrap();
        assert!(config.process_every_tick);
        assert_eq!(config.process_interval_ticks, 10);
        assert!(!config.immediate_on_escalation);
        assert!((config.confidence_threshold - 0.5).abs() < 0.001);
    }

    #[test]
    fn test_batch_processor_config_default() {
        let config = BatchProcessorConfig::default();
        assert!(config.parallel);
        assert_eq!(config.max_concurrency, 4);
    }

    #[test]
    fn test_batch_processor_config_deserialize_toml() {
        let toml_str = r#"
            parallel = false
            max_concurrency = 8
        "#;
        let config: BatchProcessorConfig = toml::from_str(toml_str).unwrap();
        assert!(!config.parallel);
        assert_eq!(config.max_concurrency, 8);
    }

    #[test]
    fn test_manager_template_generate_ids() {
        // Single ID
        let template = ManagerTemplate {
            id: Some("my_manager".to_string()),
            id_pattern: None,
            count: 1,
            role: "llm_batch".to_string(),
            activation: ManagerActivationConfig::default(),
            config: serde_json::Value::Null,
        };
        assert_eq!(template.generate_ids(), vec!["my_manager"]);

        // Pattern-based IDs
        let template = ManagerTemplate {
            id: None,
            id_pattern: Some("manager_{i}".to_string()),
            count: 3,
            role: "llm_batch".to_string(),
            activation: ManagerActivationConfig::default(),
            config: serde_json::Value::Null,
        };
        assert_eq!(
            template.generate_ids(),
            vec!["manager_0", "manager_1", "manager_2"]
        );
    }

    #[test]
    fn test_manager_activation_config_default() {
        let config = ManagerActivationConfig::default();
        match config {
            ManagerActivationConfig::Interval { interval } => {
                assert_eq!(interval, 10);
            }
            _ => panic!("Expected Interval variant"),
        }
    }
}