Model chat sessions at different architectural layers to control state ownership and handle interruptions.
Chat sessions in AI agents can be modeled at different layers of your architecture. The choice affects state ownership and how you handle interruptions and reconnections.
While there are many ways to model chat sessions, the two most common categories are single-turn and multi-turn.
Each user message triggers a new workflow run. The client or API route owns the conversation history and sends the full message array with each request.
This is the pattern used in the Building Durable AI Agents guide.
In this pattern, the client owns conversation state, with the latest turn managed by the AI SDK's useChat, and past turns persisted to a user-managed database.
Persisting the turn is usually done through either:
- A step on the workflow that runs after
agent.stream()and takes the message history from the agent return value (eithermessages: ModelMessage[]oruiMessages: UIMessage[]) - A hook on
useChatin the client that calls an API to persist state (or localStorage, etc.), either on every new message, oronFinish - The resumable stream attached to the workflow (see Resumable Streams)
- Note that user messages are not persisted to the stream by default, and need to be explicitly persisted separately
A single workflow handles the entire conversation session across multiple turns, and owns the current conversation state. The clients/API routes inject new messages via hooks. The workflow run ID serves as the session identifier.
For a full example of an agent using multi-turn workflows, check out the Flight Booking App example in the Workflow Examples repository.
A key challenge in multi-turn workflows is ensuring user messages appear in the correct order when replaying the stream (e.g., after a page refresh). Since the stream primarily contains AI responses, user messages must be explicitly marked in the stream so the client can reconstruct the full conversation.
In this pattern, the workflow owns the entire conversation session. All messages are persisted in the workflow, and follow-up messages are injected via hooks. The workflow writes user message markers to the stream using data-workflow chunks, which allows the client to reconstruct the full conversation in the correct order when replaying the stream (e.g., after a page refresh).
The client hook processes these markers by:
- Iterating through message parts in order
- When a
user-messagemarker is found, flushing any accumulated assistant content and inserting the user message - Deduplicating against optimistic sends from the initial message
This ensures the conversation displays as User → AI → User → AI regardless of whether viewing live or replaying from the stream.
| Consideration | Single-Turn | Multi-Turn |
|---|---|---|
| State ownership | Client or API route | Workflow |
| Message injection from backend | Requires stitching together runs | Native via hooks |
| Workflow complexity | Lower | Higher |
| Workflow time horizon | Minutes | Hours to indefinitely |
| Observability scope | Per-turn traces | Full session traces |
Multi-turn is recommended for most production use-cases. If you're starting fresh, go with multi-turn. It's more flexible and grows with your requirements. You don't need to maintain the chat history yourself and can offload all that to the workflow's built in persistence. It also enables native message injection and full session observability, which becomes increasingly valuable as your agent matures.
Single-turn works well when adapting existing architectures. If you already have a system for managing message state, and want to adopt durable agents incrementally, single-turn workflows slot in with minimal changes. Each turn maps cleanly to an independent workflow run.
The multi-turn pattern also easily enables multi-player chat sessions. New messages can come from system events, external services, and other users. Since a hook injects messages into workflow at any point, and the entire history is a single stream that clients can reconnect to, it doesn't matter where the injected messages come from. Here are different use-cases for multi-player chat sessions:
- Building Durable AI Agents - Foundation guide for durable agents
- Message Queueing - Queueing messages during tool execution
defineHook()API Reference - Hook configuration optionsDurableAgentAPI Reference - Full API documentation









