1 unstable release
Uses new Rust 2024
new 0.1.0 | May 7, 2025 |
---|
#471 in Web programming
2MB
1K
SLoC
A Rust implementation of PocketFlow, a minimalist flow-based programming framework.
Features
- Type-safe state transitions using enums
- Macro-based flow construction
- Async node execution and post-processing
- Batch flow support
- Custom state management
- Extensible node system
Quick Start
0. Setup
cargo add pocketflow_rs
1. Define Custom States
use pocketflow_rs::ProcessState;
#[derive(Debug, Clone, PartialEq)]
pub enum MyState {
Success,
Failure,
Default,
}
impl ProcessState for MyState {
fn is_default(&self) -> bool {
matches!(self, MyState::Default)
}
fn to_condition(&self) -> String {
match self {
MyState::Success => "success".to_string(),
MyState::Failure => "failure".to_string(),
MyState::Default => "default".to_string(),
}
}
}
impl Default for MyState {
fn default() -> Self {
MyState::Default
}
}
2. Implement Nodes
use pocketflow_rs::{Node, ProcessResult, Context};
use anyhow::Result;
use async_trait::async_trait;
struct MyNode;
#[async_trait]
impl Node for MyNode {
type State = MyState;
async fn execute(&self, context: &Context) -> Result<serde_json::Value> {
// Your node logic here
Ok(serde_json::json!({"data": 42}))
}
async fn post_process(
&self,
context: &mut Context,
result: &Result<serde_json::Value>,
) -> Result<ProcessResult<MyState>> {
// Your post-processing logic here
Ok(ProcessResult::new(MyState::Success, "success".to_string()))
}
}
3. Build Flows
use pocketflow_rs::{build_flow, Context};
let node1 = MyNode;
let node2 = MyNode;
let flow = build_flow!(
start: ("start", node1),
nodes: [("next", node2)],
edges: [
("start", "next", MyState::Success)
]
);
let context = Context::new();
let result = flow.run(context).await?;
4. Batch Processing
use pocketflow_rs::build_batch_flow;
let batch_flow = build_batch_flow!(
start: ("start", node1),
nodes: [("next", node2)],
edges: [
("start", "next", MyState::Success)
],
batch_size: 10
);
let contexts = vec![Context::new(); 10];
batch_flow.run_batch(contexts).await?;
Advanced Usage
Custom State Management
Define your own states to control flow transitions:
#[derive(Debug, Clone, PartialEq)]
pub enum WorkflowState {
Initialized,
Processing,
Completed,
Error,
Default,
}
impl ProcessState for WorkflowState {
fn is_default(&self) -> bool {
matches!(self, WorkflowState::Default)
}
fn to_condition(&self) -> String {
match self {
WorkflowState::Initialized => "initialized".to_string(),
WorkflowState::Processing => "processing".to_string(),
WorkflowState::Completed => "completed".to_string(),
WorkflowState::Error => "error".to_string(),
WorkflowState::Default => "default".to_string(),
}
}
}
Complex Flow Construction
Build complex workflows with multiple nodes and state transitions:
let flow = build_flow!(
start: ("start", node1),
nodes: [
("process", node2),
("validate", node3),
("complete", node4)
],
edges: [
("start", "process", WorkflowState::Initialized),
("process", "validate", WorkflowState::Processing),
("validate", "process", WorkflowState::Error),
("validate", "complete", WorkflowState::Completed)
]
);
Available Features
The following features are available: (feature for utility_function)
openai
(default): Enable OpenAI API integration for LLM capabilitieswebsearch
: Enable web search functionality using Google Custom Search APIqdrant
: Enable vector database integration using Qdrantdebug
: Enable additional debug logging and information
To use specific features, add them to your Cargo.toml
:
[dependencies]
pocketflow_rs = { version = "0.1.0", features = ["openai", "websearch"] }
Or use them in the command line:
cargo add pocketflow_rs --features "openai websearch"
Examples
Check out the examples/
directory for more detailed examples:
- basic.rs: Basic flow with custom states
- text2sql: Text-to-SQL workflow example
- pocketflow-rs-rag: Retrieval-Augmented Generation (RAG) workflow example
License
MIT
Dependencies
~6–21MB
~285K SLoC