use petgraph::graph::{DiGraph, NodeIndex};
use serde_json::Value;
use std::collections::{HashMap, HashSet};
use std::sync::Arc;
#[derive(Debug, Clone)]
pub struct Action {
pub name: String,
pub params: HashMap<String, String>,
}
#[derive(Debug, Clone)]
pub enum NodeType {
Task(Action),
Assert(String),
AssignCall {
var: String,
action: Action,
},
Foreach {
item: String,
list: String,
body: Box<WorkflowGraph>,
parallel: bool,
},
Literal(Value),
Loop {
condition: String,
body: Box<WorkflowGraph>,
},
_ExternalCall {
call_path: String,
args: Vec<String>,
kwargs: HashMap<String, String>,
},
NewInstance {
class_name: String,
args: HashMap<String, String>,
},
#[allow(dead_code)]
MethodCall {
instance_path: String,
method_name: String,
args: HashMap<String, String>,
},
ReturnErr(Value),
Yield(String),
}
#[derive(Debug, Clone)]
pub struct Node {
pub id: String,
pub node_type: NodeType,
}
#[derive(Debug, Clone)]
pub struct SwitchCase {
pub value: Option<String>,
pub target: String,
pub is_ok: bool,
pub is_err: bool,
pub err_kind: Option<String>,
}
#[derive(Debug, Clone)]
pub struct SwitchRoute {
pub subject: String,
pub cases: Vec<SwitchCase>,
}
#[derive(Debug, Clone, Default)]
pub struct Edge {
pub condition: Option<String>,
pub is_error_path: bool,
pub switch_case: Option<String>,
}
#[derive(Debug, Clone)]
pub struct WorkflowGraph {
pub slug: String,
pub name: String,
pub version: String,
pub description: String,
pub graph: DiGraph<Node, Edge>,
pub node_map: HashMap<String, NodeIndex>,
pub entry_node: String,
pub libs: Vec<String>,
pub prompt_patterns: Vec<String>,
pub tool_patterns: Vec<String>,
pub python_imports: Vec<String>,
pub switch_routes: HashMap<String, SwitchRoute>,
pub flow_imports: HashMap<String, String>,
pub pending_edges: Vec<(String, String, Edge)>,
pub pending_wildcard_edges: Vec<(String, String, Edge)>,
pub functions: HashMap<String, FunctionDef>,
pub lib_imports: HashMap<String, String>,
pub lib_auto_namespaces: HashSet<String>,
pub classes: HashMap<String, Arc<ClassDef>>,
pub pending_methods: Vec<(String, String, FunctionDef)>,
pub decorator_applications: Vec<DecoratorApplication>,
}
#[derive(Debug, Clone, Default)]
pub struct Manifest {
pub slug: String,
pub name: String,
pub version: String,
pub source: String,
pub author: String,
pub description: String,
pub is_public: Option<bool>,
pub schedule: Option<String>,
pub entry_node: String,
pub exit_nodes: Vec<String>,
pub libs: Vec<String>,
pub lib_imports: HashMap<String, String>,
pub lib_auto_namespaces: HashSet<String>,
pub prompt_patterns: Vec<String>,
pub tool_patterns: Vec<String>,
pub python_imports: Vec<String>,
pub flow_imports: HashMap<String, String>,
}
impl Manifest {
pub fn apply_to(&self, wf: &mut WorkflowGraph) {
if !self.slug.is_empty() {
wf.slug = self.slug.clone();
}
if !self.name.is_empty() {
wf.name = self.name.clone();
}
if !self.version.is_empty() {
wf.version = self.version.clone();
}
if !self.description.is_empty() {
wf.description = self.description.clone();
}
if !self.libs.is_empty() {
wf.libs = self.libs.clone();
wf.lib_imports = self.lib_imports.clone();
wf.lib_auto_namespaces = self.lib_auto_namespaces.clone();
}
if !self.entry_node.is_empty() {
wf.entry_node = self.entry_node.clone();
}
if !self.prompt_patterns.is_empty() {
wf.prompt_patterns = self.prompt_patterns.clone();
}
if !self.tool_patterns.is_empty() {
wf.tool_patterns = self.tool_patterns.clone();
}
}
}
#[derive(Debug, Clone)]
pub struct FunctionDef {
pub params: Vec<String>,
pub body: Arc<WorkflowGraph>,
#[allow(dead_code)]
pub annotations: HashMap<String, Value>,
}
#[derive(Debug, Clone)]
pub struct DecoratorApplication {
pub decorator_fn: String,
pub args: Vec<String>,
pub target_node_id: String,
}
#[derive(Debug, Clone)]
#[allow(dead_code)]
pub struct GraphFragment {
pub id: String,
pub params: Vec<String>,
pub body: Arc<WorkflowGraph>,
pub annotations: HashMap<String, Value>,
}
#[derive(Debug, Clone)]
#[allow(dead_code)]
pub struct ClassField {
pub name: String,
pub type_hint: Option<String>,
pub default: Option<String>,
}
#[derive(Debug, Clone)]
pub struct ClassDef {
pub fields: Vec<ClassField>,
pub methods: HashMap<String, FunctionDef>,
pub field_index: HashMap<String, usize>,
}
impl ClassDef {
pub fn new(fields: Vec<ClassField>, methods: HashMap<String, FunctionDef>) -> Self {
let field_index = fields
.iter()
.enumerate()
.map(|(i, f)| (f.name.clone(), i))
.collect();
Self {
fields,
methods,
field_index,
}
}
}
impl WorkflowGraph {
#[allow(dead_code)]
pub fn empty() -> Self {
Self::default()
}
}
pub fn is_test_node_id(id: &str) -> bool {
id.starts_with("test_")
}
impl Default for WorkflowGraph {
fn default() -> Self {
WorkflowGraph {
slug: String::new(),
name: String::new(),
version: String::new(),
description: String::new(),
graph: DiGraph::new(),
node_map: HashMap::new(),
entry_node: String::new(),
libs: Vec::new(),
prompt_patterns: Vec::new(),
tool_patterns: Vec::new(),
python_imports: Vec::new(),
switch_routes: HashMap::new(),
flow_imports: HashMap::new(),
pending_edges: Vec::new(),
pending_wildcard_edges: Vec::new(),
functions: HashMap::new(),
lib_imports: HashMap::new(),
lib_auto_namespaces: HashSet::new(),
classes: HashMap::new(),
pending_methods: Vec::new(),
decorator_applications: Vec::new(),
}
}
}