1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
use serde::{Deserialize, Serialize};
use serde_json::Value;
use std::collections::HashMap;
/// Output from a node execution.
#[derive(Debug, Clone)]
pub enum NodeOutput {
/// Standard completion - node modified state directly, follow normal edges
Done,
/// Command - state update + navigation instruction
Command(Command),
}
/// A command that combines state updates with navigation instructions.
#[derive(Debug, Clone)]
pub struct Command {
/// Optional state updates to apply
pub update: Option<HashMap<String, Value>>,
/// Navigation instruction
pub goto: Navigation,
}
/// Navigation instructions for graph traversal.
#[derive(Debug, Clone)]
pub enum Navigation {
/// Go to a specific node
Node(String),
/// Fan-out to multiple nodes simultaneously
Nodes(Vec<String>),
/// Terminate execution
End,
/// Dynamic fan-out with per-branch state
Send(Vec<SendOp>),
/// Follow normal edges (default behavior)
Default,
}
/// A send operation for dynamic fan-out with custom state per branch.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SendOp {
/// Target node name
pub node: String,
/// Custom state values for this branch
pub state: HashMap<String, Value>,
}
impl Command {
/// Create a command that navigates to a specific node
pub fn goto(node: impl Into<String>) -> Self {
Self {
update: None,
goto: Navigation::Node(node.into()),
}
}
/// Create a command that ends execution
pub fn end() -> Self {
Self {
update: None,
goto: Navigation::End,
}
}
/// Create a command with state updates and default navigation
pub fn update(updates: HashMap<String, Value>) -> Self {
Self {
update: Some(updates),
goto: Navigation::Default,
}
}
/// Add state updates to this command
pub fn with_update(mut self, updates: HashMap<String, Value>) -> Self {
self.update = Some(updates);
self
}
/// Set the navigation for this command
pub fn with_goto(mut self, goto: Navigation) -> Self {
self.goto = goto;
self
}
}
impl NodeOutput {
/// Create a command that navigates to a specific node
pub fn goto(node: impl Into<String>) -> Self {
NodeOutput::Command(Command::goto(node))
}
/// Create a command that ends execution
pub fn end() -> Self {
NodeOutput::Command(Command::end())
}
}
impl From<()> for NodeOutput {
fn from((): ()) -> Self {
NodeOutput::Done
}
}