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>
impl<S: State, I: IntoState<S>, O: FromState<S>> StateGraph<S, I, O>
Sourcepub 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>
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>
Sourcepub fn add_node_simple(
&mut self,
name: impl Into<String>,
node: impl IntoNode<S>,
) -> Result<&mut Self, TopologyError>
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:falsemetadata:Nonedestinations:Noneretry_policies: emptytimeout_policies: empty
Returns &mut Self on success for fluent builder chaining.
§Errors
Returns an error if a node with the same name already exists.
Sourcepub 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,
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 namenode- The node to wraphandler- Error recovery function receivingNodeError
§Errors
Returns an error if a node with the same name already exists.
Sourcepub fn add_node_with_retry(
&mut self,
name: impl Into<String>,
node: impl IntoNode<S>,
policy: RetryPolicy,
) -> Result<&mut Self, TopologyError>where
S: Clone,
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 namenode- The node to wrappolicy- Retry policy governing retry behavior
§Errors
Returns an error if a node with the same name already exists.
Sourcepub fn add_node_with_circuit_breaker(
&mut self,
name: impl Into<String>,
node: impl IntoNode<S>,
config: CircuitBreakerConfig,
) -> Result<&mut Self, TopologyError>
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 namenode- The node to protectconfig- Circuit breaker configuration
§Errors
Returns an error if a node with the same name already exists.
Sourcepub 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,
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 namenode- The node to protectretry_policy- Retry policy for transient failurescircuit_breaker_config- Circuit breaker configuration
§Errors
Returns an error if a node with the same name already exists.
Sourcepub fn add_node_with_fallback(
&mut self,
name: impl Into<String>,
node: impl IntoNode<S>,
fallback: impl Into<String>,
) -> Result<&mut Self, TopologyError>
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 namenode- The node to protectfallback- Name of the fallback node
§Errors
Returns an error if a node with the same name already exists.
Sourcepub fn add_subgraph(
&mut self,
mount: SubgraphMount<S>,
) -> Result<&mut Self, TopologyError>
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.
Sourcepub 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,
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 implementStateSubset<S>
§Arguments
name- The node name for the subgraph mount pointsubgraph- 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.
Sourcepub 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>
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>
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 pointsubgraph- The compiled subgraph to addinput_map- Function to transform parent state to subgraph inputoutput_map- Function to transform subgraph output to parent state updateconfig- Subgraph configuration options
§Returns
A mutable reference to self for chaining
§Errors
Returns an error if a node with the same name already exists.
Sourcepub 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>
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>
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 pointsubgraph- The compiled subgraph to addinput_map- Function to transform parent state to subgraph inputoutput_map- Function to transform subgraph output to parent state update
§Errors
Returns an error if a node with the same name already exists.
Sourcepub fn add_conditional_edges(
&mut self,
from: impl Into<String>,
router: Arc<dyn Router<S>>,
path_map: PathMap,
)
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.
Sourcepub fn set_entry_point(&mut self, node: impl Into<String>)
pub fn set_entry_point(&mut self, node: impl Into<String>)
Sourcepub fn set_finish_point(&mut self, node: impl Into<String>)
pub fn set_finish_point(&mut self, node: impl Into<String>)
Sourcepub fn add_sequence(
&mut self,
nodes: &[impl AsRef<str>],
) -> Result<&mut Self, TopologyError>
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.
Sourcepub fn validate_keys(&self) -> Result<(), TopologyError>
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
Sourcepub fn compile(&self) -> Result<CompiledGraph<S, I, O>, TopologyError>
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()?;Sourcepub fn compile_with_config(
&self,
config: CompileConfig,
) -> Result<CompiledGraph<S, I, O>, TopologyError>
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()
})?;Sourcepub fn compile_ephemeral(&self) -> Result<CompiledGraph<S, I, O>, TopologyError>
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.
Sourcepub fn compile_with_checkpointer(
&self,
checkpointer: Option<Arc<dyn CheckpointSaver>>,
) -> Result<CompiledGraph<S, I, O>, TopologyError>
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.