Skip to main content

synaptic_graph/
command.rs

1use std::sync::Arc;
2
3use tokio::sync::Mutex;
4
5/// A graph execution command that can override normal edge routing.
6///
7/// Commands provide dynamic control flow within graph nodes, allowing
8/// nodes to redirect execution to specific nodes or end the graph
9/// without relying solely on edge definitions.
10#[derive(Debug, Clone)]
11pub enum GraphCommand {
12    /// Go to a specific node next, overriding normal routing.
13    Goto(String),
14    /// End the graph execution immediately.
15    End,
16}
17
18/// A context that nodes can use to issue graph execution commands.
19///
20/// The `GraphContext` is shared between the graph execution loop and
21/// individual nodes. Nodes call `goto()` or `end()` to signal the
22/// desired control flow, and the compiled graph checks for these
23/// commands after each node execution.
24///
25/// # Example
26///
27/// ```ignore
28/// use synaptic_graph::GraphContext;
29///
30/// async fn my_node_logic(ctx: &GraphContext) {
31///     // Skip normal routing and go directly to "summary" node
32///     ctx.goto("summary").await;
33/// }
34/// ```
35#[derive(Clone)]
36pub struct GraphContext {
37    command: Arc<Mutex<Option<GraphCommand>>>,
38}
39
40impl GraphContext {
41    /// Create a new `GraphContext`.
42    pub fn new() -> Self {
43        Self {
44            command: Arc::new(Mutex::new(None)),
45        }
46    }
47
48    /// Signal the graph to go to a specific node next, overriding normal routing.
49    pub async fn goto(&self, node: impl Into<String>) {
50        *self.command.lock().await = Some(GraphCommand::Goto(node.into()));
51    }
52
53    /// Signal the graph to end execution immediately.
54    pub async fn end(&self) {
55        *self.command.lock().await = Some(GraphCommand::End);
56    }
57
58    /// Take the current command (if any), clearing it from the slot.
59    ///
60    /// This is used internally by `CompiledGraph` after each node execution.
61    pub(crate) async fn take_command(&self) -> Option<GraphCommand> {
62        self.command.lock().await.take()
63    }
64}
65
66impl Default for GraphContext {
67    fn default() -> Self {
68        Self::new()
69    }
70}
71
72impl std::fmt::Debug for GraphContext {
73    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
74        f.debug_struct("GraphContext").finish()
75    }
76}