Cloudflare Agents SDK
Your knowledge of the Agents SDK may be outdated. Prefer retrieval over pre-training for any Agents SDK task.
Retrieval Sources
Cloudflare docs: https://developers.cloudflare.com/agents/
| Topic | Docs URL | Use for |
|---|---|---|
| Getting started | Quick start | First agent, project setup |
| Adding to existing project | Add to existing project | Install into existing Workers app |
| Configuration | Configuration | wrangler.jsonc, bindings, assets, deployment |
| Agent class | Agents API | Agent lifecycle, patterns, pitfalls |
| State | Store and sync state | setState |
Capabilities
The Agents SDK provides:
- Persistent state — SQLite-backed, auto-synced to clients via
setState - Callable RPC —
@callable()methods invoked over WebSocket - Scheduling — One-time, recurring (
scheduleEvery), and cron tasks - Workflows — Durable multi-step background processing via
AgentWorkflow - Durable execution —
runFiber()/stash()for work that survives DO eviction - Queue — Built-in FIFO queue with retries via
queue() - Retries —
this.retry()with exponential backoff and jitter - MCP integration — Connect to MCP servers or build your own with
McpAgent - Email handling — Receive and reply to emails with secure routing
- Streaming chat —
AIChatAgentwith resumable streams, message persistence, tools - Server-driven messages —
saveMessages,waitUntilStable
FIRST: Verify Installation
npm ls agents # Should show agents packageIf not installed:
npm install agentsFor chat agents:
npm install agents @cloudflare/ai-chat ai @ai-sdk/reactWrangler Configuration
{
"compatibility_flags": ["nodejs_compat"],
"durable_objects": {
"bindings": [{ "name": "MyAgent", "class_name": "MyAgent" }]
},
"migrations": [{ "tag": "v1", "new_sqlite_classes": ["MyAgent"] }]
}Gotchas:
- Do NOT enable
experimentalDecoratorsin tsconfig (breaks@callable) - Never edit old migrations — always add new tags
- Each agent class needs its own DO binding + migration entry
- Add
"ai": { "binding": "AI" }for Workers AI
Agent Class
import { Agent, routeAgentRequest, callable } from "agents";
type State = { count: number };
export class Counter extends Agent<Env, State> {
initialState = { count: 0 };
validateStateChange(nextState: State, source: Connection | "server") {
if (nextState.count < 0) throw new Error("Count cannot be negative");
}
onStateUpdate(state: State, source: Connection | "server") {
console.log("State updated:", state);
}
@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 })
};Routing
Requests route to /agents/{agent-name}/{instance-name}:
| Class | URL |
|---|---|
Counter | /agents/counter/user-123 |
ChatRoom | /agents/chat-room/lobby |
Client: useAgent({ agent: "Counter", name: "user-123" })
Custom routing: use getAgentByName(env.MyAgent, "instance-id") then agent.fetch(request).
Core APIs
| Task | API |
|---|---|
| Read state | this.state.count |
| Write state | this.setState({ count: 1 }) |
| SQL query | this.sql`SELECT * FROM users WHERE id = ${id}` |
| Schedule (delay) | await this.schedule(60, "task", payload) |
| Schedule (cron) | await this.schedule("0 * * * *", "task", payload) |
| Schedule (interval) | await this.scheduleEvery(30, "poll") |
| RPC method | @callable() myMethod() { ... } |
| Streaming RPC | @callable({ streaming: true }) stream(res) { ... } |
| Start workflow | await this.runWorkflow("ProcessingWorkflow", params) |
React Client
import { useAgent } from "agents/react";
function App() {
const [state, setLocalState] = useState({ count: 0 });
const agent = useAgent({
agent: "Counter",
name: "my-instance",
onStateUpdate: (newState) => setLocalState(newState),
onIdentity: (name, agentType) => console.log(`Connected to ${name}`)
});
return (
<button onClick={() => agent.setState({ count: state.count + 1 })}>
Count: {state.count}
</button>
);
}References
Core
- [references/state-scheduling.md](references/state-scheduling.md) — State persistence, scheduling, SQL
- [references/callable.md](references/callable.md) — RPC methods, streaming, timeouts
- [references/routing.md](references/routing.md) — URL patterns, custom routing,
getAgentByName - [references/configuration.md](references/configuration.md) — Wrangler config, bindings, Vite setup
Chat & Streaming
- [references/streaming-chat.md](references/streaming-chat.md) — AIChatAgent, resumable streams, tools
- [references/client-sdk.md](references/client-sdk.md) —
useAgent,useAgentChat,AgentClient - [references/server-driven-messages.md](references/server-driven-messages.md) — Trigger patterns,
saveMessages - [references/human-in-the-loop.md](references/human-in-the-loop.md) — Approval flows,
needsApproval
Background Processing
- [references/workflows.md](references/workflows.md) — Durable Workflows integration
- [references/durable-execution.md](references/durable-execution.md) —
runFiber,stash, surviving eviction - [references/queue-retries.md](references/queue-retries.md) — Built-in queue, retry with backoff
Integrations
- [references/mcp.md](references/mcp.md) — MCP client and server, transports, securing
- [references/email.md](references/email.md) — Email routing and handling
- [references/webhooks-push.md](references/webhooks-push.md) — Webhooks, push notifications
- [references/observability.md](references/observability.md) — Diagnostics-channel events
Experimental
- [references/think.md](references/think.md) —
@cloudflare/thinkhigher-level chat agent - [references/voice.md](references/voice.md) —
@cloudflare/voiceSTT/TTS - [references/codemode.md](references/codemode.md) — Code Mode for tool orchestration
- [references/browse-the-web.md](references/browse-the-web.md) — CDP browser tools
