graph-flow
A high-performance, type-safe framework for building stateful, multi-agent LLM workflows in Rust — inspired by LangGraph, integrated with Rig.
Features
- Type-Safe Workflows: Compile-time guarantees, validated graph construction
- Flexible Execution: Step-by-step, fire-and-forget, or mixed in one graph
- Built-in Persistence: PostgreSQL and in-memory session storage with optimistic locking
- LLM Integration: Optional Rig integration (
rigfeature) with built-in chat history - Human-in-the-Loop: Pause on
WaitForInput, resume when the user answers - Parallel Blocks:
FanOutTaskruns multiple tasks concurrently inside a single node
Quick Start
[]
= { = "0.6", = ["rig"] } # drop "rig" if you don't need LLM helpers
Migrating from 0.5? See the 0.5 → 0.6 migration guide.
Define a task
use async_trait;
use ;
;
Context methods are synchronous and thread-safe; set is fallible (JSON serialization can fail).
Build a graph
use GraphBuilder;
use Arc;
let graph = new;
Execute with sessions
use ;
use Arc;
let storage = new;
let runner = new;
let session = new_from_task;
session.context.set?;
storage.save.await?;
loop
Failures are returned as Err(GraphError). Sessions carry an optimistic-locking version: concurrent saves of the same session fail with GraphError::SessionConflict instead of losing updates.
Execution control
Each task returns a NextAction:
| Variant | Behavior |
|---|---|
Continue |
Advance one edge, return control to the caller |
ContinueAndExecute |
Advance and keep executing until something pauses |
WaitForInput |
Park the workflow until new input arrives |
GoTo(task_id) |
Jump to a specific task |
End |
Complete the workflow |
Guard rails: GraphBuilder::with_task_timeout(duration) bounds each task (default 5 min); with_max_execution_steps(n) turns a ContinueAndExecute cycle into an error instead of an infinite loop.
LLM integration (feature rig)
let chat_history = context.get_rig_messages;
let response = agent.chat.await?;
context.add_user_message;
context.add_assistant_message;
Chat history is a capped ring buffer (default 1000 messages) and serializes with the session.
Storage
// Development
let storage = new;
// Production (session ids are free-form TEXT)
let storage = new;
// Custom pool configuration
let storage = new;
Both implement the same SessionStorage trait.
More
Full documentation, runnable examples, and complete service implementations (insurance claims workflow, RAG recommendation service) live in the repository.
License
MIT