Why Chatbot and Callbot Loops Need a State Machine

If a conversation is driven by prompts alone, nothing in the code knows whether the current session is in entry, waiting on a tool call, or mid-handoff. That's why LangGraph describes itself as a "low-level orchestration framework" and puts checkpoint-based durable execution at the center of its pitch: you can only resume exactly where a failure happened if the state was explicitly named first. Framework choice aside, every session should sit in exactly one of six states — entry, listening, processing, speaking, transition, close — and that value has to travel with the log and the store, not live only in memory.

Checkpoints: An Unsaved State Can't Be Recovered

A checkpoint isn't the state value itself; it's a snapshot of context taken right before entering a state. Without checkpoints, a dropped call in a callbot loop means restarting the entire conversation from zero. With checkpoints that fire on the wrong schedule — out of sync with state transitions — the caller gets greeted by a half-restored session instead. Tying the save point exactly to the transition event is the hard constraint this design has to satisfy.

Handoff Is a State Transition Too

LiveKit Agents' multi-agent examples pass control to the next agent by returning a handoff tuple while keeping the shared userdata intact. That treats a switch to a human agent or a specialized bot as one more transition inside the state machine, not a separate exception-handling path.

Build Roadmap and Pitfalls: Putting a Session State Machine Into a Real Loop

The first step in designing a state machine is fixing the state names in a document before they exist in code. Entry, Listening, Processing, Speaking, Handoff, Checkpoint, Close, and Orphaned — eight states are enough to describe most chatbot and callbot loops. A reasonable starting point for target metrics: state-transition failure rate under 0.5%, checkpoint save latency under 200ms, and orphaned sessions auto-cleaned within 90 seconds of going idle.

Without wiring these metrics into a deploy gate, the state machine stays a diagram. Log an event on every transition, and add a pre-deploy scenario test that walks through all eight states at least once — that's the only way to confirm the running code still matches the design.

Failures tend to start in two places. Keep the state value only in the session object instead of persistent storage, and a process restart erases which state that session was in, with no trace left behind. Handoff transitions that forward only part of the prior state's context to the new agent or human rep are just as common — without a field list fixed in code, a different field goes missing every time.

Save checkpoints on a fixed timer (say, every five seconds) rather than on transitions, and a call that drops within that five-second window loses everything since the last save. Skip orphaned-session cleanup, and abnormally terminated sessions keep holding resources. Recovery branches should differ by state: a drop during Listening or Processing resumes from the last checkpoint, while a drop during Handoff re-routes from scratch instead of resuming, to avoid stitching together mismatched context.

The operations checklist starts by cross-checking the state diagram against actual logs. Every transition event should carry four required fields — session ID, previous state, next state, transition reason, timestamp — and logs from the Processing state, where PII tends to mix in, need their own masking rule. Before deploying, reproduce three scenarios — a mid-call drop, simultaneous barge-in, and a failed handoff to a human agent — and confirm the state machine always lands on one of its defined states.

Track the orphaned-session rate on its own dashboard panel. If sessions transitioning into Orphaned exceed 2% of total sessions, treat it as a sign that some transition rule is missing from the state machine and prioritize the investigation.

Aggregating transition-failure logs weekly by state pair (previous → next) surfaces the pattern where one transition accounts for most of the failures. Narrowing the fix to that single transition — moving up the checkpoint save point or adding a recovery branch — moves the metric faster than redesigning the whole state machine. When the state definitions themselves change, bump a version field too, so old checkpoints never get mixed in with new ones.

Takeaways

Fix eight state names in a document first, save checkpoints only at transition events, and lock the handoff field list in code — those three habits alone move a session state machine from a diagram into running operations. Wire a state-transition failure rate under 0.5% and an orphaned-session rate under 2% into the deploy gate, and every improvement after that can be scoped down to a single transition pair.

References

LangGraph — durable execution and checkpointing (GitHub)

LiveKit Agents — AgentSession lifecycle and multi-agent handoff (GitHub)