use std::collections::HashMap; use serde::{Deserialize, Serialize}; use super::script::{ScriptPrimitive, WorkflowScript}; static FINDINGS: std::sync::Mutex> = std::sync::Mutex::new(Vec::new()); #[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)] pub enum AgentState { Idle, Running, Completed, Failed, } #[derive(Debug, Clone, Serialize, Deserialize)] pub struct AgentStatus { pub state: AgentState, pub started_at: Option, pub completed_at: Option, pub error: Option, } impl AgentStatus { pub fn new() -> Self { AgentStatus { state: AgentState::Idle, started_at: None, completed_at: None, error: None, } } } #[derive(Debug, Clone, Serialize, Deserialize)] pub struct WorkflowAgent { pub id: String, pub name: String, pub status: AgentStatus, } impl WorkflowAgent { pub fn new(id: String, name: String) -> Self { WorkflowAgent { id, name, status: AgentStatus::new(), } } } #[derive(Debug, Clone)] pub struct WorkflowEngine { pub agents: Vec, pub concurrency_cap: usize, pub findings: Vec, } impl WorkflowEngine { pub fn new() -> Self { WorkflowEngine { agents: Vec::new(), concurrency_cap: 5, findings: Vec::new(), } } pub fn with_concurrency_cap(mut self, cap: usize) -> Self { self.concurrency_cap = cap; self } pub fn add_agent(&mut self, agent: WorkflowAgent) { self.agents.push(agent); } } pub fn execute_primitive(primitive: &ScriptPrimitive, args: &HashMap) -> anyhow::Result<()> { match primitive { ScriptPrimitive::Agent(name) => { let _agent_name = name; let _args = args; Ok(()) } ScriptPrimitive::Parallel(scripts) => { for script in scripts { execute_primitive(script, args)?; } Ok(()) } ScriptPrimitive::Pipeline(scripts) => { for script in scripts { execute_primitive(script, args)?; } Ok(()) } ScriptPrimitive::Phase { name: _name, script } => { execute_primitive(script, args) } } } pub fn run_workflow(script: &WorkflowScript, args: &HashMap) -> anyhow::Result { let concurrency_cap = if script.options.max_concurrency > 0 { script.options.max_concurrency.min(5) } else { 5 }; let _cap = concurrency_cap; execute_primitive(&script.script, args)?; Ok("workflow completed".to_string()) } #[expect(dead_code)] pub fn push_finding(engine: &mut WorkflowEngine, text: &str) { engine.findings.push(text.to_string()); } pub fn note_finding(text: &str) { if let Ok(mut findings) = FINDINGS.lock() { findings.push(text.to_string()); } } #[expect(dead_code)] pub fn current_findings() -> Vec { if let Ok(findings) = FINDINGS.lock() { findings.clone() } else { Vec::new() } } #[expect(dead_code)] pub fn clear_findings() { if let Ok(mut findings) = FINDINGS.lock() { findings.clear(); } }