swarm-engine-eval 0.1.6

Evaluation framework for SwarmEngine
Documentation
//! DependencyGraph Configuration
//!
//! 依存グラフの設定と関連する型の定義。

use serde::{Deserialize, Serialize};

// ============================================================================
// DependencyGraph Type
// ============================================================================

/// 依存グラフの種類
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(tag = "type", rename_all = "snake_case")]
pub enum DependencyGraphType {
    /// 組み込みパターンを使用
    Static {
        /// パターン名 (code_search, file_exploration)
        #[serde(default = "default_pattern")]
        pattern: String,
    },
    /// 明示的にグラフを定義
    Custom {
        /// 依存エッジ
        edges: Vec<DependencyEdgeConfig>,
        /// 開始ノード
        start: Vec<String>,
        /// 終端ノード
        terminal: Vec<String>,
        /// パラメータバリアント(action → (key, values))
        #[serde(default)]
        param_variants: Vec<ParamVariantConfig>,
    },
    /// LLM で動的生成(将来用)
    Llm {},
}

impl Default for DependencyGraphType {
    fn default() -> Self {
        Self::Static {
            pattern: default_pattern(),
        }
    }
}

fn default_pattern() -> String {
    "code_search".to_string()
}

// ============================================================================
// DependencyEdge Configuration
// ============================================================================

/// 依存エッジ設定
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct DependencyEdgeConfig {
    /// 元アクション
    pub from: String,
    /// 先アクション
    pub to: String,
    /// 確信度 (0.0-1.0)
    #[serde(default = "default_confidence")]
    pub confidence: f64,
}

fn default_confidence() -> f64 {
    0.9
}

// ============================================================================
// ParamVariant Configuration
// ============================================================================

/// パラメータバリアント設定
///
/// アクションごとのパラメータバリエーションを定義。
/// ExplorationSpace が後続ノード展開時に各バリアントごとにノードを生成する。
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ParamVariantConfig {
    /// アクション名(例: "Move")
    pub action: String,
    /// パラメータのキー名(例: "target")
    pub key: String,
    /// 取り得る値のリスト(例: ["north", "south", "east", "west"])
    pub values: Vec<String>,
}

// ============================================================================
// DependencyGraph Configuration
// ============================================================================

/// 依存グラフ設定
///
/// TOML で定義された依存グラフを Core の DependencyGraph に変換。
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct DependencyGraphConfig {
    /// 依存グラフの種類
    #[serde(flatten)]
    pub graph_type: DependencyGraphType,
}

impl DependencyGraphConfig {
    /// Core の DependencyGraph に変換
    pub fn to_core_graph(
        &self,
        available_actions: &[String],
    ) -> Option<swarm_engine_core::exploration::DependencyGraph> {
        use swarm_engine_core::exploration::{
            DependencyGraph, DependencyPlanner, StaticDependencyPlanner,
        };

        match &self.graph_type {
            DependencyGraphType::Static { pattern } => {
                let planner = match pattern.as_str() {
                    "code_search" => StaticDependencyPlanner::new().with_code_search_pattern(),
                    "file_exploration" => {
                        StaticDependencyPlanner::new().with_file_exploration_pattern()
                    }
                    _ => StaticDependencyPlanner::new().with_code_search_pattern(),
                };
                planner.plan("task", available_actions).ok()
            }
            DependencyGraphType::Custom {
                edges,
                start,
                terminal,
                param_variants,
            } => {
                let mut builder = DependencyGraph::builder()
                    .available_actions(available_actions.iter().cloned())
                    .start_nodes(start.iter().cloned())
                    .terminal_nodes(terminal.iter().cloned());

                for edge in edges {
                    builder = builder.edge(&edge.from, &edge.to, edge.confidence);
                }

                // パラメータバリアントを設定
                for pv in param_variants {
                    builder =
                        builder.param_variants(&pv.action, &pv.key, pv.values.iter().cloned());
                }

                Some(builder.build())
            }
            DependencyGraphType::Llm {} => {
                // LLM 生成は将来実装
                None
            }
        }
    }
}

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

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

    #[test]
    fn test_dependency_graph_type_default() {
        let graph_type = DependencyGraphType::default();
        match graph_type {
            DependencyGraphType::Static { pattern } => {
                assert_eq!(pattern, "code_search");
            }
            _ => panic!("Expected Static variant"),
        }
    }

    #[test]
    fn test_dependency_edge_config_default_confidence() {
        let toml_str = r#"
            from = "grep"
            to = "read"
        "#;
        let edge: DependencyEdgeConfig = toml::from_str(toml_str).unwrap();
        assert_eq!(edge.from, "grep");
        assert_eq!(edge.to, "read");
        assert!((edge.confidence - 0.9).abs() < 0.001);
    }

    #[test]
    fn test_dependency_graph_config_static() {
        let config = DependencyGraphConfig::default();
        let actions = vec!["grep".to_string(), "read".to_string(), "done".to_string()];
        let graph = config.to_core_graph(&actions);
        assert!(graph.is_some());
    }
}