Skip to main content

Graph

Struct Graph 

Source
pub struct Graph<T: State> { /* private fields */ }
Expand description

The execution graph for the agent

A graph represents the complete workflow structure:

  • Which nodes exist and what they do
  • How nodes are connected (edges)
  • Which nodes are entry and exit points
  • Optional: Loop configurations for repeated execution

§Performance Features

  • Adjacency List Cache: Maintains HashMap<NodeId, Vec> for O(1) edge lookups
  • Lazy Evaluation: Validation deferred until explicitly called
  • Memory Efficient: Single edge vec with indexed access

Implementations§

Source§

impl<T: State> Graph<T>

Source

pub fn new() -> Self

Create a new empty graph. Cycles are allowed by default. Call set_allow_cycles(false) to enforce strict DAG mode.

Source

pub fn with_loops() -> Self

Create a new graph that allows loops (cycles)

Use this for workflows where nodes can intentionally feed back to earlier nodes. Remember to configure set_max_loop_iterations() to prevent infinite loops.

§Example
use flowgentra_ai::core::graph::Graph;

let mut graph = Graph::with_loops();
graph.set_max_loop_iterations(5);
// graph allows cycles up to 5 iterations
Source

pub fn add_node(&mut self, node: Node<T>)

Add a node to the graph

Nodes should be added before edges are created that reference them.

§Arguments
  • node - The node to add to the graph
Source

pub fn add_edge(&mut self, edge: Edge<T>)

Add an edge to the graph and update adjacency list cache

Both the source and target nodes should already exist in the graph. The adjacency list is automatically updated for O(1) future lookups.

§Arguments
  • edge - The edge to add to the graph
Source

pub fn set_start_nodes(&mut self, nodes: Vec<NodeId>)

Set the entry nodes (those connected from START)

§Arguments
  • nodes - Vector of node IDs that act as entry points
Source

pub fn set_end_nodes(&mut self, nodes: Vec<NodeId>)

Set the exit nodes (those connected to END)

§Arguments
  • nodes - Vector of node IDs that act as exit points
Source

pub fn set_allow_cycles(&mut self, allow: bool) -> &mut Self

Enable or disable loop support (allow cycles in the graph)

When enabled, the graph validation will not enforce DAG property. You should configure set_max_loop_iterations() to prevent infinite loops.

§Arguments
  • allow - Whether to allow cycles in the graph
§Returns
  • &mut Self - For builder pattern chaining
Source

pub fn allows_cycles(&self) -> bool

Check if cycles are allowed in this graph

§Returns
  • true if the graph allows cycles, false if it enforces DAG property
Source

pub fn allow_loops(&mut self, allow: bool) -> &mut Self

👎Deprecated since 0.2.0:

Use set_max_loop_iterations instead

Set maximum iterations for loops (builder-style, deprecated name)

⚠️ Deprecated: Use set_max_loop_iterations() instead. This method is kept for backwards compatibility.

Source

pub fn loops_allowed(&self) -> bool

👎Deprecated since 0.2.0:

Use allows_cycles instead

Check if loops are allowed (deprecated name)

⚠️ Deprecated: Use allows_cycles() instead. This method is kept for backwards compatibility.

Source

pub fn set_max_loop_iterations(&mut self, max: usize) -> &mut Self

Set maximum iterations for loops

This prevents infinite loops by limiting the number of iterations the runtime will execute for any loop structure.

§Arguments
  • max - Maximum number of loop iterations (0 = unlimited)
§Returns
  • &mut Self - For builder pattern chaining
§Example
use flowgentra_ai::core::graph::Graph;

let mut graph = Graph::with_loops();
graph.set_max_loop_iterations(5); // Allow max 5 iterations
Source

pub fn max_loop_iterations(&self) -> usize

Get maximum iterations for loops

Source

pub fn get_node(&self, id: &str) -> Option<&Node<T>>

Get a specific node by ID (borrowed reference)

§Arguments
  • id - The node ID (name)
§Returns
  • Some(&Node) if the node exists, None otherwise
Source

pub fn nodes(&self) -> &HashMap<NodeId, Node<T>>

Get all nodes in the graph

Source

pub fn edges(&self) -> &[Edge<T>]

Get all edges in the graph

Source

pub fn start_nodes(&self) -> &[NodeId]

Get the entry nodes (START nodes)

Source

pub fn end_nodes(&self) -> &[NodeId]

Get the exit nodes (END nodes)

Source

pub fn get_next_nodes(&self, node_id: &str) -> Vec<&Edge<T>>

Get all outgoing edges from a node (O(1) average case using adjacency list)

§Arguments
  • node_id - ID of the source node (borrowed reference)
§Returns
  • Vector of references to edges originating from this node
§Performance
  • Time: O(1) average case + O(k) where k is number of outgoing edges to copy vec refs
  • Space: O(k) for the returned vector
§Example
let edges = graph.get_next_nodes("my_node");
for edge in edges {
    println!("Can go to: {}", edge.to);
}
Source

pub fn get_reachable_node_ids(&self, from: &str) -> Vec<String>

Get the IDs of nodes reachable in one step from the given node

Returns unique target node names from outgoing edges (includes “END” if present).

§Arguments
  • from - ID of the source node
§Returns
  • Vector of unique target node IDs
§Performance
  • Time: O(k) where k is the number of outgoing edges
  • Space: O(k) for result vector + O(k) for HashSet
Source

pub fn get_prev_nodes(&self, node_id: &str) -> Vec<&Edge<T>>

Get all incoming edges to a node (O(E) linear scan - consider caching if frequently used)

§Arguments
  • node_id - ID of the target node
§Returns
  • Vector of references to edges ending at this node
§Performance
  • Time: O(E) where E is total number of edges
  • Space: O(k) where k is number of incoming edges
§Note

If this operation is called frequently, consider maintaining a reverse adjacency list.

Source

pub fn validate(&self) -> Result<()>

Validate the graph structure for correctness

Checks:

  • No cycles exist (DAG property) - unless loops are explicitly allowed
  • All referenced nodes exist
  • START and END nodes are properly connected
  • No orphaned nodes
§Errors

Returns FlowgentraError if validation fails with detailed reason

§Performance
  • Time: O(V + E) for cycle detection using iterative DFS
  • Additional O(E) for edge validation
§Example
let mut graph = Graph::new();
// ... add nodes and edges ...
graph.validate()?; // Will return Err if graph is invalid
Source

pub fn topological_sort(&self) -> Result<Vec<NodeId>>

Topological sort of the graph

Returns nodes in execution order (respecting dependencies). Useful for analysis, optimization, and execution planning.

§Algorithm

Uses Kahn’s algorithm (BFS-based):

  1. Compute in-degree for each node
  2. Enqueue all nodes with in-degree 0
  3. Dequeue node, add to result, decrement in-degree of neighbors
  4. Repeat until queue empty
  5. If result size != nodes size, graph has cycles
§Returns
  • Ok(Vec<NodeId>) - Nodes in topological order
  • Err(FlowgentraError::CycleDetected) - If graph has cycles
§Performance
  • Time: O(V + E)
  • Space: O(V)
§Example
let sorted = graph.topological_sort()?;
println!("Execution order: {:?}", sorted);

Trait Implementations§

Source§

impl<T: State + Default> Default for Graph<T>

Source§

fn default() -> Self

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

Auto Trait Implementations§

§

impl<T> Freeze for Graph<T>

§

impl<T> !RefUnwindSafe for Graph<T>

§

impl<T> Send for Graph<T>

§

impl<T> Sync for Graph<T>

§

impl<T> Unpin for Graph<T>

§

impl<T> UnsafeUnpin for Graph<T>

§

impl<T> !UnwindSafe for Graph<T>

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> Same for T

Source§

type Output = T

Should always be Self
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<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
Source§

impl<A, B, T> HttpServerConnExec<A, B> for T
where B: Body,