AIChatAgent and useAgentChat. Messages are automatically persisted to SQLite, streams resume on disconnect, and tool calls work across server and client.
Overview
@cloudflare/ai-chat provides two main exports:
Built on the AI SDK and Cloudflare Durable Objects, you get:
- Automatic message persistence — conversations stored in SQLite, survive restarts
- Resumable streaming — disconnected clients resume mid-stream without data loss
- Real-time sync — messages broadcast to all connected clients via WebSocket
- Tool support — server-side, client-side, and human-in-the-loop tool patterns
- Data parts — attach typed JSON (citations, progress, usage) to messages alongside text
- Row size protection — automatic compaction when messages approach SQLite limits
Quick Start
1
Install dependencies
2
Create server agent
3
Create client UI
4
Configure Wrangler
wrangler.jsonc
The
new_sqlite_classes migration is required — AIChatAgent uses SQLite for message persistence and stream chunk buffering.How It Works
1
Client sends message
The client sends a message via WebSocket
2
Agent persists and calls handler
AIChatAgent persists messages to SQLite and calls your onChatMessage method3
Stream response
Your method returns a streaming
Response (typically from streamText)4
Real-time chunks
Chunks stream back over WebSocket in real-time
5
Broadcast final message
When the stream completes, the final message is persisted and broadcast to all connections
Server API
AIChatAgent
ExtendsAgent from the agents package. Manages conversation state, persistence, and streaming.
onChatMessage
This is the main method you override. It receives the conversation context and should return aResponse.
this.messages
The current conversation history, loaded from SQLite. This is an array ofUIMessage objects from the AI SDK. Messages are automatically persisted after each interaction.
maxPersistedMessages
Cap the number of messages stored in SQLite. When the limit is exceeded, the oldest messages are deleted. This controls storage only — it does not affect what is sent to the LLM.pruneMessages():
waitForMcpConnections
Controls whetherAIChatAgent waits for MCP server connections to settle before calling onChatMessage. This ensures this.mcp.getAITools() returns the full set of tools, especially after Durable Object hibernation when connections are being restored in the background.
Request Cancellation
When a user clicks “stop” in the chat UI, the client sends aCF_AGENT_CHAT_REQUEST_CANCEL message. The server propagates this to the abortSignal in options:
Client API
useAgentChat
React hook that connects to anAIChatAgent over WebSocket. Wraps the AI SDK’s useChat with a native WebSocket transport.
Options
Return Values
Tools
AIChatAgent supports three tool patterns, all using the AI SDK’s tool() function:
Server-Side Tools
Tools with anexecute function run automatically on the server:
Client-Side Tools
Define a tool on the server withoutexecute, then handle it on the client with onToolCall. Use this for tools that need browser APIs:
getLocation, the stream pauses. The onToolCall callback fires, your code provides the output, and the conversation continues.
Dynamic Client Tools
For SDKs and platforms where tools are defined dynamically by the embedding application at runtime, use thetools option on useAgentChat and createToolsFromClientSchemas() on the server:
For most apps, server-side tools with
tool() and onToolCall are simpler and provide full Zod type safety. Use dynamic client tools when the server does not know the tool surface at deploy time.Tool Approval (Human-in-the-Loop)
UseneedsApproval for tools that require user confirmation before executing:
Data Parts
Data parts let you attach typed JSON to messages alongside text — progress indicators, source citations, token usage, or any structured data your UI needs.Writing Data Parts (Server)
UsecreateUIMessageStream with writer.write() to send data parts from the server:
Three Patterns
Reading Data Parts (Client)
Non-transient data parts appear inmessage.parts. Use the UIMessage generic to type them:
Resumable Streaming
Streams automatically resume when a client disconnects and reconnects. No configuration is needed — it works out of the box. When streaming is active:- All chunks are buffered in SQLite as they are generated
- If the client disconnects, the server continues streaming and buffering
- When the client reconnects, it receives all buffered chunks and resumes live streaming
resume: false:
Storage Management
Row Size Protection
SQLite rows have a maximum size of 2 MB. When a message approaches this limit (for example, a tool returning a very large output),AIChatAgent automatically compacts the message:
- Tool output compaction — Large tool outputs are replaced with an LLM-friendly summary that instructs the model to suggest re-running the tool
- Text truncation — If the message is still too large after tool compaction, text parts are truncated with a note
metadata.compactedToolOutputs so clients can detect and display this gracefully.
Controlling LLM Context vs Storage
Storage (maxPersistedMessages) and LLM context are independent:
Using Different AI Providers
AIChatAgent works with any AI SDK-compatible provider. The server code determines which model to use — the client does not need to change.
Multi-Client Sync
When multiple clients connect to the same agent instance, messages are automatically broadcast to all connections. If one client sends a message, all other connected clients receive the updated message list.CF_AGENT_CHAT_MESSAGES broadcast.
Related Documentation
- Resumable Streaming — How stream resumption works
- Client Tools Continuation — Advanced client-side tool patterns
- Codemode — Let LLMs write code to orchestrate tools