A declarative Finite State Machine engine for multi-turn conversational AI that uses YAML to define states, typed slots, and per-state model selection.
https://github.com/davidbmar/flowstate · public · shipped
flowstate is a Python library that structures complex conversations as deterministic state machines. Instead of relying on long chat histories and fragile system prompts, it breaks conversations into discrete states with specific goals and typed data contracts (slots). Each state can use a different LLM optimized for its specific task, ensuring context isolation, debuggability, and reliable data extraction.
pip install flowstate python scripts/demo_real_pizza.py
flowchart TD
User[User Input] --> Engine[flowstate Engine]
Engine --> Context[FlowContext]
Context --> Router[ModelRouter]
Router --> Adapter[Model Adapter]
Adapter --> LLM[External LLM]
LLM --> Adapter
Adapter --> Engine
Engine --> Tools[Tool Registry]
Tools --> External[External Systems]
External --> Tools
Engine --> NextState[Next State Decision]
The core is a Python engine that loads YAML flow definitions. It uses a `ModelRouter` to dispatch requests to specific `ModelAdapter` implementations (Anthropic, Gemini, MLX, or Fake). The engine maintains a `FlowContext` tracking the current state and filled slots, executing a `step()` function that calls the adapter, parses structured JSON responses, updates slots, and evaluates transition conditions to move to the next state.
sequenceDiagram
participant App as Application
participant Eng as flowstate Engine
participant Ctx as FlowContext
participant Rtr as ModelRouter
participant Adp as ModelAdapter
participant LLM as LLM Provider
App->>Eng: step(input, ctx)
Eng->>Ctx: get_current_state()
Ctx-->>Eng: state_config
Eng->>Rtr: get_adapter(state.model)
Rtr-->>Eng: adapter_instance
Eng->>Adp: complete(prompt, slots)
Adp->>LLM: generate_response()
LLM-->>Adp: raw_text/json
Adp-->>Eng: AdapterResponse(slots, tool_calls)
Eng->>Eng: update_slots(ctx)
Eng->>Eng: evaluate_transitions()
Eng-->>App: StepResult(next_state, updated_ctx)
Define your conversation logic in a YAML file specifying states, goals, required slots, and transitions. Instantiate a `FlowContext` and load the flow using `load_flow()`. Use the `step()` function in your application loop, passing user input and the current context. Integrate specific LLM adapters via the `ModelRouter` to handle actual generation.
✓ all on main — nothing unmerged.