Cloudflare Agents SDK
Build persistent, stateful AI agents on Cloudflare Workers using the agents npm package.
FIRST: Verify Installation npm install agents
Agents require a binding in wrangler.jsonc:
{ "durable_objects": { // "class_name" must match your Agent class name exactly "bindings": [{ "name": "Counter", "class_name": "Counter" }] }, "migrations": [ // Required: list all Agent classes for SQLite storage { "tag": "v1", "new_sqlite_classes": ["Counter"] } ] }
Choosing an Agent Type
Use Case Base Class Package
Custom state + RPC, no chat Agent agents
Chat with message persistence AIChatAgent @cloudflare/ai-chat
Building an MCP server McpAgent agents/mcp
Key Concepts
Agent base class provides state, scheduling, RPC, MCP, and email capabilities
AIChatAgent adds streaming chat with automatic message persistence and resumable streams
Code Mode generates executable code instead of tool calls—reduces token usage significantly
this.state / this.setState() - automatic persistence to SQLite, broadcasts to clients
this.schedule() - schedule tasks at Date, delay (seconds), or cron expression
@callable decorator - expose methods to clients via WebSocket RPC
Quick Reference
Task API
Persist state this.setState({ count: 1 })
Read state this.state.count
Schedule task this.schedule(60, "taskMethod", payload)
Schedule cron this.schedule("0 * * * *", "hourlyTask")
Cancel schedule this.cancelSchedule(id)
Queue task this.queue("processItem", payload)
SQL query this.sqlSELECT * FROM users WHERE id = ${id}
RPC method @callable() async myMethod() { ... }
Streaming RPC @callable({ streaming: true }) async stream(res) { ... }
Minimal Agent
import { Agent, routeAgentRequest, callable } from "agents";
type State = { count: number };
export class Counter extends Agent
@callable() increment() { this.setState({ count: this.state.count + 1 }); return this.state.count; } }
export default { fetch: (req, env) => routeAgentRequest(req, env) ?? new Response("Not found", { status: 404 }) };
Streaming Chat Agent
Use AIChatAgent for chat with automatic message persistence and resumable streaming.
Install additional dependencies first:
npm install @cloudflare/ai-chat ai @ai-sdk/openai
Add wrangler.jsonc config (same pattern as base Agent):
{ "durable_objects": { "bindings": [{ "name": "Chat", "class_name": "Chat" }] }, "migrations": [{ "tag": "v1", "new_sqlite_classes": ["Chat"] }] }
import { AIChatAgent } from "@cloudflare/ai-chat"; import { routeAgentRequest } from "agents"; import { streamText, convertToModelMessages } from "ai"; import { openai } from "@ai-sdk/openai";
export class Chat extends AIChatAgent
export default { fetch: (req, env) => routeAgentRequest(req, env) ?? new Response("Not found", { status: 404 }) };
Client (React):
import { useAgent } from "agents/react"; import { useAgentChat } from "@cloudflare/ai-chat/react";
const agent = useAgent({ agent: "Chat", name: "my-chat" }); const { messages, input, handleSubmit } = useAgentChat({ agent });
Detailed References references/state-scheduling.md - State persistence, scheduling, queues references/streaming-chat.md - AIChatAgent, resumable streams, UI patterns references/codemode.md - Generate code instead of tool calls (token savings) references/mcp.md - MCP server integration references/email.md - Email routing and handling When to Use Code Mode
Code Mode generates executable JavaScript instead of making individual tool calls. Use it when:
Chaining multiple tool calls in sequence Complex conditional logic across tools MCP server orchestration (multiple servers) Token budget is constrained
See references/codemode.md for setup and examples.
Best Practices
Prefer streaming: Use streamText and toUIMessageStreamResponse() for chat
Use AIChatAgent for chat: Handles message persistence and resumable streams automatically
Type your state: Agent