Your knowledge of the Agents SDK may be outdated. Prefer retrieval over pre-training for any Agents SDK task.
Cloudflare docs: https://developers.cloudflare.com/agents/
TopicDocs URLUse forGetting startedQuick startFirst agent, project setupAdding to existing projectAdd to existing projectInstall into existing Workers appConfigurationConfigurationwrangler.jsonc, bindings, assets, deploymentAgent classAgents APIAgent lifecycle, patterns, pitfallsStateStore and sync statesetState, validateStateChange, persistenceRoutingRoutingURL patterns, routeAgentRequestCallable methodsCallable methods@callable, RPC, streaming, timeoutsSchedulingSchedule tasksschedule(), scheduleEvery(), cronWorkflowsRun workflowsAgentWorkflow, durable multi-step tasksHTTP/WebSocketsWebSocketsLifecycle hooks, hibernationChat agentsChat agentsAIChatAgent, streaming, tools, persistenceClient SDKClient SDKuseAgent, useAgentChat, React hooksClient toolsClient toolsClient-side tools, autoContinueAfterToolResultServer-driven messagesTrigger patternssaveMessages, waitUntilStable, server-initiated turnsResumable streamingResumable streamingStream recovery on disconnectEmailEmailEmail routing, secure reply resolverMCP clientMCP clientConnecting to MCP serversMCP serverMCP serverBuilding MCP servers with McpAgentMCP transportsMCP transportsStreamable HTTP, SSE, RPC transport optionsSecuring MCP serversSecuring MCPOAuth, proxy MCP, hardeningHuman-in-the-loopHuman-in-the-loopApproval flows, needsApproval, workflowsDurable executionDurable executionrunFiber(), stash(), surviving DO evictionQueueQueueBuilt-in FIFO queue, queue()RetriesRetriesthis.retry(), backoff/jitterObservabilityObservabilityDiagnostics-channel eventsPush notificationsPush notificationsWeb Push + VAPID from agentsWebhooksWebhooksReceiving external webhooksCross-domain authCross-domain authWebSocket auth, tokens, CORSReadonly connectionsReadonlyshouldConnectionBeReadonlyVoiceVoiceExperimental STT/TTS, withVoiceBrowse the webBrowser toolsExperimental CDP browser automationThinkThinkExperimental higher-level chat agent classMigrationsAI SDK v5, AI SDK v6Upgrading @cloudflare/ai-chat
The Agents SDK provides:
setState@callable() methods invoked over WebSocketscheduleEvery), and cron tasksAgentWorkflowrunFiber() / stash() for work that survives DO evictionqueue()this.retry() with exponential backoff and jitterMcpAgentAIChatAgent with resumable streams, message persistence, toolssaveMessages, waitUntilStable for proactive agent turnsuseAgent, useAgentChat for client appsdiagnostics_channel events for state, RPC, schedule, lifecycle@cloudflare/voiceagents/browser@cloudflare/thinkbash
npm ls agents # Should show agents package
If not installed:
bash
npm install agents
For chat agents:
bash
npm install agents @cloudflare/ai-chat ai @ai-sdk/react
jsonc
{
"compatibility_flags": ["nodejs_compat"],
"durable_objects": {
"bindings": [{ "name": "MyAgent", "class_name": "MyAgent" }]
},
"migrations": [{ "tag": "v1", "new_sqlite_classes": ["MyAgent"] }]
}
Gotchas:
experimentalDecorators in tsconfig (breaks @callable)"ai": { "binding": "AI" } for Workers AItypescript
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 })
};
Requests route to /agents/{agent-name}/{instance-name}:
ClassURLCounter``/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).
TaskAPIRead statethis.state.countWrite statethis.setState({ count: 1 })SQL querythis.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 workflowawait this.runWorkflow("ProcessingWorkflow", params)Durable fiberawait this.runFiber("name", async (ctx) => { ... })Enqueue workthis.queue("handler", payload)Retry with backoffawait this.retry(fn, { maxAttempts: 5 })Broadcast to clientsthis.broadcast(message)Get connectionsthis.getConnections(tag?)
tsx
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>
);
}
getAgentByNameuseAgent, useAgentChat, AgentClientsaveMessagesneedsApprovalrunFiber, stash, surviving eviction@cloudflare/think higher-level chat agent@cloudflare/voice STT/TTS