cloudflare-agents
Cloudflare Agents provides a comprehensive framework for building stateful AI agents that persist, think, and evolve at the edge. Built on Cloudflare's Durable Objects, it enables agents to maintain p
Cloudflare Agents
Cloudflare Agents provides a comprehensive framework for building stateful AI agents that persist, think, and evolve at the edge. Built on Cloudflare's Durable Objects, it enables agents to maintain persistent state across sessions, communicate via WebSockets and HTTP, integrate with LLMs through the AI SDK, and execute scheduled tasks—all with global scale and automatic hibernation for cost efficiency.
Quick References
| File | Purpose |
|---|---|
packages/agents/src/index.ts | Main Agent class and core framework |
packages/agents/src/index.ts | Public API exports and core abstractions |
packages/ai-chat/src/index.ts | AIChatAgent for chat-enabled agents |
packages/hono-agents/src/index.ts | Hono middleware for agent routing |
README.md | Official documentation and overview |
Packages
| Package | npm name | Description |
|---|---|---|
packages/agents | agents | Core agent framework with state management, RPC, scheduling, and MCP client |
packages/ai-chat | @cloudflare/ai-chat | AI chat agent with automatic message persistence and AI SDK v6 integration |
packages/codemode | @cloudflare/codemode | Code mode for LLM-generated executable tool code |
packages/hono-agents | hono-agents | Hono middleware for integrating agents into Hono apps |
When to Use
- Stateful AI Chatbots: Build chatbots that remember conversation history across sessions and connections
- Multi-user Collaborative Agents: Create agents with shared state synchronized across multiple clients in real-time
- Scheduled Task Automation: Implement agents that execute scheduled workflows via cron, delayed execution, or one-time events
- Human-in-the-Loop Workflows: Request human approval before executing sensitive operations
- Tool-Enabled AI Agents: Connect AI agents to external tools via Model Context Protocol (MCP)
- Email-Responsive Agents: Handle incoming emails and reply programmatically
- Event-Driven Automation: React to external events and take autonomous actions
Installation
# Core agents framework
npm install agents
# AI chat functionality
npm install @cloudflare/ai-chat ai react
# Hono integration
npm install hono-agents hono
# Code mode for LLM-generated tools
npm install @cloudflare/codemode
Best Practices
-
Always define SQL migrations in wrangler.jsonc: Agents require SQLite storage for state persistence. Add your agent class to
new_sqlite_classesin the migrations section. -
Use the
@callabledecorator for RPC methods: Mark public methods with@callable()to expose them via WebSocket RPC. Optionally enable streaming responses with@callable({ streaming: true }). -
Initialize agent state with
initialState: Set default state in theinitialStateproperty to avoidundefinedstate values on first access. -
Use
getCurrentAgent()for context access: AsyncLocalStorage provides access to the current agent, connection, request, and email from anywhere in your code without passing parameters. -
Batch SQL operations when possible: For multiple database writes, consider batching them to reduce transaction overhead.
-
Use
schedule()instead ofsetAlarm()directly: Agent'sschedule()method handles multiple schedules internally using a single alarm. -
Handle errors in
onError(): Override theonError()method to gracefully handle connection and server errors. -
Clean up with
destroy()when needed: Callawait this.destroy()to wipe all tables, clear storage, and remove alarms when an agent should be terminated.
Common Patterns
Basic Agent with HTTP Handler:
import { Agent } from "agents";
export class MyAgent extends Agent<{ OPENAI_API_KEY: string }> {
initialState = { count: 0 };
async onRequest(request: Request) {
return Response.json({ count: this.state.count });
}
increment() {
this.setState({ count: this.state.count + 1 });
}
}
Agent with WebSocket RPC:
import { Agent, callable } from "agents";
export class CalculatorAgent extends Agent {
@callable({ description: "Add two numbers" })
async add(a: number, b: number) {
return a + b;
}
@callable({ description: "Multiply two numbers" })
async multiply(a: number, b: number) {
return a * b;
}
}
Agent with Scheduled Tasks:
export class ScheduledAgent extends Agent {
async onStart() {
// Run daily at midnight
this.schedule("0 0 * * *", "dailyCleanup", { type: "logs" });
// Run in 10 seconds
this.schedule(10, "quickCheck");
// Run at specific date
this.schedule(new Date("2025-12-25"), "holidayMessage");
}
async dailyCleanup(payload: { type: string }) {
console.log(`Cleaning up ${payload.type}`);
}
}
Agent with Queue:
export class QueueAgent extends Agent {
async onConnect() {
this.queue("process", { userId: "123" });
}
async process(payload: { userId: string }) {
console.log(`Processing user ${payload.userId}`);
await this.dequeue();
}
}
AI Chat Agent:
import { AIChatAgent } from "@cloudflare/ai-chat";
import { streamText } from "ai";
import { openai } from "@ai-sdk/openai";
export class ChatBot extends AIChatAgent<{ OPENAI_API_KEY: string }> {
async onChatMessage(onFinish) {
return streamText({
model: openai("gpt-4"),
messages: this.messages,
onFinish
}).toDataStreamResponse();
}
}
React Client Connection:
import { useAgent } from "agents/react";
function Component() {
const agent = useAgent({
agent: "my-agent",
name: "user-123"
});
const increment = () => agent.call("increment");
return <button onClick={increment}>Increment</button>;
}
React Chat Interface:
import { useAgentChat } from "@cloudflare/ai-chat/react";
function ChatInterface() {
const agent = useAgent({ agent: "chatbot", name: "session-1" });
const { messages, sendMessage } = useAgentChat({ agent });
return (
<div>
{messages.map(m => <p key={m.id}>{m.content}</p>)}
<button onClick={() => sendMessage("Hello!")}>Send</button>
</div>
);
}
Human-in-the-Loop Approval:
export class ApprovalAgent extends AIChatAgent {
async onChatMessage(onFinish) {
// Use needsApproval on tools to require human confirmation
return streamText({
model: openai("gpt-4"),
messages: this.messages,
tools: {
dangerousAction: tool({
description: "Execute dangerous action",
inputSchema: z.object({}),
needsApproval: true
})
},
onFinish
}).toDataStreamResponse();
}
}
MCP Integration:
import { McpAgent } from "agents/mcp";
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
export class MyMcp extends McpAgent {
server = new McpServer({ name: "demo", version: "1.0.0" });
async init() {
this.server.registerTool(
"getData",
{ description: "Fetch data", inputSchema: z.object({ id: z.string() }) },
async ({ id }) => ({ content: [{ type: "text", text: `Data for ${id}` }] })
);
}
}
API Quick Reference
| Export | Type | Description |
|---|---|---|
Agent | Class | Base class for creating agents with state persistence, RPC, scheduling, and WebSocket support |
AIChatAgent | Class | Extension of Agent with AI chat capabilities and automatic message persistence |
McpAgent | Class | Agent extension for creating MCP servers with tool registration |
@callable | Decorator | Marks methods as callable via WebSocket RPC |
callable() | Function | Decorator factory for callable methods |
useAgent | Hook | React hook for connecting to an agent with WebSocket support |
useAgentChat | Hook | React hook for AI chat interfaces with message persistence |
AgentClient | Class | WebSocket client for agent communication |
agentFetch | Function | Make HTTP requests to an agent |
routeAgentRequest | Function | Route HTTP/WebSocket requests to the appropriate agent |
getAgentByName | Function | Get an agent stub by name |
getCurrentAgent | Function | Access current agent, connection, request, and email context |
SqlError | Class | Error class for SQL query failures |
Agent Class Methods
| Method | Returns | Description |
|---|---|---|
setState(state) | void | Update agent state and persist to storage |
onStateUpdate(state, source) | void | Called when state is updated (override in subclass) |
schedule(when, callback, payload?) | Promise<Schedule> | Schedule a one-time, delayed, or recurring task |
cancelSchedule(id) | Promise<boolean> | Cancel a scheduled task |
getSchedule(id) | Promise<Schedule|undefined> | Get a specific scheduled task |
getSchedules(criteria?) | Schedule[] | Get scheduled tasks matching criteria |
queue(callback, payload) | Promise<string> | Queue a task for deferred execution |
dequeue(id) | void | Remove a specific queued task |
dequeueAll() | void | Remove all queued tasks |
getQueue(id) | Promise<QueueItem|undefined> | Get a specific queued task |
getQueues(key, value) | Promise<QueueItem[]> | Get queued tasks by key/value filter |
destroy() | Promise<void> | Destroy the agent, dropping all tables and clearing storage |
replyToEmail(email, options) | Promise<void> | Reply to an incoming email |
runWorkflow(name, params, options?) | Promise<string> | Start a Cloudflare Workflow and track it |
sendWorkflowEvent(name, id, event) | Promise<void> | Send an event to a running workflow |
approveWorkflow(id, data?) | Promise<void> | Approve a waiting workflow |
rejectWorkflow(id, data?) | Promise<void> | Reject a waiting workflow |
Agent Lifecycle Hooks
| Hook | Parameters | Description |
|---|---|---|
onStart(props?) | Props | Called when the agent starts up |
onRequest(request) | Request | Handle HTTP requests to the agent |
onConnect(connection, ctx) | Connection, ConnectionContext | Called when a WebSocket connects |
onMessage(connection, message) | Connection, WSMessage | Handle incoming WebSocket messages |
onClose(connection, code, reason, wasClean) | Connection, number, string, boolean | Called when a WebSocket closes |
onEmail(email) | AgentEmail | Handle incoming emails |
Hono Integration
| Export | Type | Description |
|---|---|---|
agentsMiddleware | Function | Create Hono middleware for handling agent WebSocket and HTTP requests |
MCP Integration
| Export | Type | Description |
|---|---|---|
McpAgent | Class | Base class for creating MCP servers |
MCPClientManager | Class | Client for connecting to MCP servers |
Utility Types
| Type | Description |
|---|---|
QueueItem<T> | Type for a queued task with payload, callback, and timestamp |
Schedule<T> | Type for a scheduled task with type (scheduled/delayed/cron), time, and payload |
AgentContext | Type for agent constructor context |
AgentEmail | Type for incoming email messages |
Connection | Type for WebSocket connection (from partyserver) |
ConnectionContext | Type for connection context with request |