2026-07-11 13:16:10 +07:00
|
|
|
use std::collections::HashMap;
|
|
|
|
|
use serde::{Deserialize, Serialize};
|
|
|
|
|
use super::script::{ScriptPrimitive, WorkflowScript};
|
|
|
|
|
|
2026-07-11 18:23:01 +07:00
|
|
|
static FINDINGS: std::sync::Mutex<Vec<String>> = std::sync::Mutex::new(Vec::new());
|
|
|
|
|
|
2026-07-11 13:16:10 +07:00
|
|
|
#[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<i64>,
|
|
|
|
|
pub completed_at: Option<i64>,
|
|
|
|
|
pub error: Option<String>,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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<WorkflowAgent>,
|
|
|
|
|
pub concurrency_cap: usize,
|
|
|
|
|
pub findings: Vec<String>,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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<String, String>) -> 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<String, String>) -> anyhow::Result<String> {
|
|
|
|
|
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())
|
|
|
|
|
}
|
|
|
|
|
|
2026-07-11 18:23:01 +07:00
|
|
|
#[expect(dead_code)]
|
|
|
|
|
pub fn push_finding(engine: &mut WorkflowEngine, text: &str) {
|
|
|
|
|
engine.findings.push(text.to_string());
|
|
|
|
|
}
|
|
|
|
|
|
2026-07-11 13:16:10 +07:00
|
|
|
pub fn note_finding(text: &str) {
|
2026-07-11 18:23:01 +07:00
|
|
|
if let Ok(mut findings) = FINDINGS.lock() {
|
|
|
|
|
findings.push(text.to_string());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[expect(dead_code)]
|
|
|
|
|
pub fn current_findings() -> Vec<String> {
|
|
|
|
|
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();
|
|
|
|
|
}
|
2026-07-11 13:16:10 +07:00
|
|
|
}
|