Skip to main content

StateGraph

Struct StateGraph 

Source
pub struct StateGraph<S: State, I: IntoState<S> = S, O: FromState<S> = S> { /* private fields */ }
Expand description

Builder for constructing executable Juncture graphs

§Examples

use juncture_core::{StateGraph, State, IntoNode};

struct MyState;
impl State for MyState { type Update = MyStateUpdate; }
struct MyStateUpdate;

// Build a simple graph
let mut graph = StateGraph::<MyState>::new();
graph.add_node_simple("process", |state: MyState| async move {
    Ok(MyStateUpdate)
});
graph.set_entry_point("process");
graph.set_finish_point("process");

// Compile and validate
let compiled = graph.compile()?;

Implementations§

Source§

impl<S: State, I: IntoState<S>, O: FromState<S>> StateGraph<S, I, O>

Source

pub fn new() -> Self

Create a new empty graph

Source

pub fn add_node( &mut self, name: impl Into<String>, node: impl IntoNode<S>, defer: bool, metadata: Option<HashMap<String, Value>>, destinations: Option<Vec<String>>, retry_policies: Vec<RetryPolicy>, timeout_policies: Vec<TimeoutPolicy>, ) -> Result<&mut Self, TopologyError>

Add a node with full configuration options

Returns &mut Self on success for fluent builder chaining.

§Errors

Returns an error if a node with the same name already exists.

§Panics

Panics if the node name contains invalid characters for graph identifiers.

Source

pub fn add_node_simple( &mut self, name: impl Into<String>, node: impl IntoNode<S>, ) -> Result<&mut Self, TopologyError>

Add a node with default configuration options

This convenience method uses these defaults:

  • defer: false
  • metadata: None
  • destinations: None
  • retry_policies: empty
  • timeout_policies: empty

Returns &mut Self on success for fluent builder chaining.

§Errors

Returns an error if a node with the same name already exists.

Source

pub fn add_node_with_error_handler( &mut self, name: impl Into<String>, node: impl IntoNode<S>, handler: Arc<dyn Fn(NodeError<S>) -> Command<S> + Send + Sync>, ) -> Result<&mut Self, TopologyError>
where S: Clone,

Add a node with an error recovery handler

When the wrapped node returns an error, the handler is invoked to produce a fallback command instead of propagating the error.

The handler receives NodeError with detailed information (node name, error, state snapshot, attempt count) and returns a recovery command.

Returns &mut Self on success for fluent builder chaining.

§Arguments
  • name - Node name
  • node - The node to wrap
  • handler - Error recovery function receiving NodeError
§Errors

Returns an error if a node with the same name already exists.

Source

pub fn add_node_with_retry( &mut self, name: impl Into<String>, node: impl IntoNode<S>, policy: RetryPolicy, ) -> Result<&mut Self, TopologyError>
where S: Clone,

Add a node with automatic retry behavior

When the wrapped node fails, it is retried according to the provided retry policy with exponential backoff.

Returns &mut Self on success for fluent builder chaining.

§Arguments
  • name - Node name
  • node - The node to wrap
  • policy - Retry policy governing retry behavior
§Errors

Returns an error if a node with the same name already exists.

Source

pub fn add_node_with_circuit_breaker( &mut self, name: impl Into<String>, node: impl IntoNode<S>, config: CircuitBreakerConfig, ) -> Result<&mut Self, TopologyError>

Add a node with circuit breaker protection

When the circuit breaker’s failure threshold is reached, the node is skipped until the cooldown period expires. This prevents cascading failures from overwhelming downstream services.

Returns &mut Self on success for fluent builder chaining.

§Arguments
  • name - Node name
  • node - The node to protect
  • config - Circuit breaker configuration
§Errors

Returns an error if a node with the same name already exists.

Source

pub fn add_node_with_retry_and_circuit_breaker( &mut self, name: impl Into<String>, node: impl IntoNode<S>, retry_policy: RetryPolicy, circuit_breaker_config: CircuitBreakerConfig, ) -> Result<&mut Self, TopologyError>
where S: Clone,

Add a node with both retry and circuit breaker protection

The retry policy handles transient failures with exponential backoff, while the circuit breaker prevents repeated execution when the node is consistently failing.

Returns &mut Self on success for fluent builder chaining.

§Arguments
  • name - Node name
  • node - The node to protect
  • retry_policy - Retry policy for transient failures
  • circuit_breaker_config - Circuit breaker configuration
§Errors

Returns an error if a node with the same name already exists.

Source

pub fn add_node_with_fallback( &mut self, name: impl Into<String>, node: impl IntoNode<S>, fallback: impl Into<String>, ) -> Result<&mut Self, TopologyError>

Add a node with a fallback node for graceful degradation

When the primary node fails (after retries), the engine creates a recovery task targeting the fallback node instead of propagating the error. The fallback node receives the same state as the failed node.

Returns &mut Self on success for fluent builder chaining.

§Arguments
  • name - Node name
  • node - The node to protect
  • fallback - Name of the fallback node
§Errors

Returns an error if a node with the same name already exists.

Source

pub fn add_subgraph( &mut self, mount: SubgraphMount<S>, ) -> Result<&mut Self, TopologyError>

Add a compiled subgraph as a node in this graph

The subgraph is mounted with input/output mapping functions that transform state between the parent and child graph.

Returns &mut Self on success for fluent builder chaining.

§Arguments
  • mount - Subgraph mount containing the compiled graph and mapping functions
§Errors

Returns an error if a node with the same name as the subgraph already exists.

Source

pub fn add_subgraph_node<Sub>( &mut self, name: &str, subgraph: Arc<CompiledGraph<Sub>>, ) -> Result<&mut Self, TopologyError>
where Sub: StateSubset<S> + State + Clone + Serialize + for<'de> Deserialize<'de>, Sub::Update: Serialize, S: Clone,

Add a subgraph with shared state using StateSubset

This method adds a subgraph that shares state with its parent graph using the StateSubset trait for type-safe state transformation.

§Type Parameters
  • Sub - The subgraph’s state type, which must implement StateSubset<S>
§Arguments
  • name - The node name for the subgraph mount point
  • subgraph - The compiled subgraph to add
§Returns

A mutable reference to self for chaining

§Errors

Returns an error if a node with the same name already exists.

Source

pub fn add_subgraph_with_config<Sub>( &mut self, name: &str, subgraph: Arc<CompiledGraph<Sub>>, input_map: impl Fn(&S) -> Sub + Send + Sync + 'static, output_map: impl Fn(&Sub) -> S::Update + Send + Sync + 'static, config: SubgraphConfig, ) -> Result<&mut Self, TopologyError>
where Sub: State + Serialize + for<'de> Deserialize<'de>, Sub::Update: Serialize, S: Clone,

Add a subgraph with explicit state mapping and custom config

This method adds a subgraph with different state types than the parent, using explicit mapping functions to transform between state types.

§Type Parameters
  • Sub - The subgraph’s state type
§Arguments
  • name - The node name for the subgraph mount point
  • subgraph - The compiled subgraph to add
  • input_map - Function to transform parent state to subgraph input
  • output_map - Function to transform subgraph output to parent state update
  • config - Subgraph configuration options
§Returns

A mutable reference to self for chaining

§Errors

Returns an error if a node with the same name already exists.

Source

pub fn add_subgraph_explicit<Sub>( &mut self, name: &str, subgraph: Arc<CompiledGraph<Sub>>, input_map: impl Fn(&S) -> Sub + Send + Sync + 'static, output_map: impl Fn(&Sub) -> S::Update + Send + Sync + 'static, ) -> Result<&mut Self, TopologyError>
where Sub: State + Serialize + for<'de> Deserialize<'de>, Sub::Update: Serialize, S: Clone,

Add a subgraph with explicit state mapping using default config

Convenience overload for add_subgraph_with_config() that uses SubgraphConfig::default(). See that method for full documentation.

§Type Parameters
  • Sub - The subgraph’s state type
§Arguments
  • name - The node name for the subgraph mount point
  • subgraph - The compiled subgraph to add
  • input_map - Function to transform parent state to subgraph input
  • output_map - Function to transform subgraph output to parent state update
§Errors

Returns an error if a node with the same name already exists.

Source

pub fn add_edge(&mut self, from: impl Into<String>, to: impl Into<String>)

Add a fixed edge between two nodes

§Examples
graph.add_edge("node_a", "node_b")?;
§Errors

This method doesn’t validate node existence. Validation happens during compile.

Source

pub fn add_conditional_edges( &mut self, from: impl Into<String>, router: Arc<dyn Router<S>>, path_map: PathMap, )

Add a conditional edge with dynamic routing

§Examples
use juncture_core::edge::{PathMap, Router};
use std::sync::Arc;

let router = |state: &MyState| -> &str {
    if state.should_continue { "continue" } else { "stop" }
};

let path_map = PathMap::from(&[
    ("continue", "process_more"),
    ("stop", "finish"),
]);

graph.add_conditional_edges("decide", Arc::new(router), path_map)?;
§Errors

This method doesn’t validate node existence or path map targets. Validation happens during compile.

Source

pub fn set_entry_point(&mut self, node: impl Into<String>)

Set the entry point for the graph

This is equivalent to add_edge(START, node).

§Examples
graph.set_entry_point("start_node");
Source

pub fn set_finish_point(&mut self, node: impl Into<String>)

Set a finish point for the graph

This is equivalent to add_edge(node, END).

§Examples
graph.set_finish_point("end_node");
Source

pub fn add_sequence( &mut self, nodes: &[impl AsRef<str>], ) -> Result<&mut Self, TopologyError>

Add a sequence of nodes as a chain

Automatically adds edges between consecutive nodes and sets the first node as the entry point.

Returns &mut Self on success for fluent builder chaining.

§Examples
graph.add_sequence(&["step1", "step2", "step3"])?;
§Errors

Returns an error if any of the nodes don’t exist.

Source

pub fn validate_keys(&self) -> Result<(), TopologyError>

Validate that all state keys are present

Key validation ensures that all nodes can access their required state fields. This validates:

  • Node names are non-empty and contain no reserved characters
  • Entry point references an existing node
  • Finish points reference existing nodes
  • Reducer field indices are within bounds of the State type’s field count
§Errors

Returns TopologyError if:

  • A node name is empty or contains reserved characters (:, /, \)
  • Entry point references a non-existent node
  • A finish point references a non-existent node
  • A reducer field index exceeds the number of fields in the State type
Source

pub fn compile(&self) -> Result<CompiledGraph<S, I, O>, TopologyError>

Compile the graph into an executable form

Runs topology validation and builds the optimized execution structure using default compile configuration (no compile-time interrupts).

§Errors

Returns TopologyError if validation fails.

§Examples
let compiled = graph.compile()?;
Source

pub fn compile_with_config( &self, config: CompileConfig, ) -> Result<CompiledGraph<S, I, O>, TopologyError>

Compile the graph with explicit compile-time configuration

Like compile but accepts a CompileConfig that sets compile-time defaults for interrupt behavior. Runtime [RunnableConfig] values override these when present.

§Errors

Returns TopologyError if validation fails.

§Examples
use juncture_core::graph::CompileConfig;

let compiled = graph.compile_with_config(CompileConfig {
    interrupt_before: vec!["human_review".into()],
    interrupt_after: vec!["llm_call".into()],
    ..Default::default()
})?;
Source

pub fn compile_ephemeral(&self) -> Result<CompiledGraph<S, I, O>, TopologyError>

Compile the graph without persistence (dev/test)

Creates a compiled graph with no checkpointer attached. Useful for development and testing where persistence is not needed.

§Errors

Returns TopologyError if validation fails.

Source

pub fn compile_with_checkpointer( &self, checkpointer: Option<Arc<dyn CheckpointSaver>>, ) -> Result<CompiledGraph<S, I, O>, TopologyError>

Compile the graph with optional checkpointer

This is a forward-compatible method that accepts an optional checkpointer. Uses default compile configuration (no compile-time interrupts).

§Errors

Returns TopologyError if validation fails.

Trait Implementations§

Source§

impl<S: State, I: IntoState<S>, O: FromState<S>> Debug for StateGraph<S, I, O>

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl<S: State, I: IntoState<S>, O: FromState<S>> Default for StateGraph<S, I, O>

Source§

fn default() -> Self

Returns the “default value” for a type. Read more

Auto Trait Implementations§

§

impl<S, I = S, O = S> !RefUnwindSafe for StateGraph<S, I, O>

§

impl<S, I = S, O = S> !UnwindSafe for StateGraph<S, I, O>

§

impl<S, I, O> Freeze for StateGraph<S, I, O>

§

impl<S, I, O> Send for StateGraph<S, I, O>

§

impl<S, I, O> Sync for StateGraph<S, I, O>

§

impl<S, I, O> Unpin for StateGraph<S, I, O>
where I: Unpin, O: Unpin,

§

impl<S, I, O> UnsafeUnpin for StateGraph<S, I, O>

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

Source§

fn vzip(self) -> V

Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more