A Rust implementation of PocketFlow, a minimalist flow-based programming framework.
📋 Get started quickly with our template →
- 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
cargo add pocketflow_rsuse 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 } }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())) } }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?;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?;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(), } } }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) ] );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"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
Fork the PocketFlow-Template-Rust repository and use it as a template for your own project.
MIT
