Building Cloudflare Agents
Your knowledge of the Agents SDK may be outdated. Prefer retrieval over pre-training for any agent-building task.
Retrieval Sources
| Source | How to retrieve | Use for |
|---|---|---|
| Agents SDK docs | https://github.com/cloudflare/agents/tree/main/docs | SDK API, state, routing, scheduling |
| Cloudflare Agents docs | https://developers.cloudflare.com/agents/ | Platform integration, deployment |
| Workers docs | Search tool or https://developers.cloudflare.com/workers/ | Runtime APIs, bindings, config |
When to Use
- User wants to build an AI agent or chatbot
- User needs stateful, real-time AI interactions
- User asks about the Cloudflare Agents SDK
- User wants scheduled tasks or background AI work
- User needs WebSocket-based AI communication
Prerequisites
- Cloudflare account with Workers enabled
- Node.js 18+ and npm/pnpm/yarn
- Wrangler CLI (
npm install -g wrangler)
Quick Start
bash1npm create cloudflare@latest -- my-agent --template=cloudflare/agents-starter 2cd my-agent 3npm start
Agent runs at http://localhost:8787
Core Concepts
What is an Agent?
An Agent is a stateful, persistent AI service that:
- Maintains state across requests and reconnections
- Communicates via WebSockets or HTTP
- Runs on Cloudflare's edge via Durable Objects
- Can schedule tasks and call tools
- Scales horizontally (each user/session gets own instance)
Agent Lifecycle
Client connects → Agent.onConnect() → Agent processes messages
→ Agent.onMessage()
→ Agent.setState() (persists + syncs)
Client disconnects → State persists → Client reconnects → State restored
Basic Agent Structure
typescript1import { Agent, Connection } from "agents"; 2 3interface Env { 4 AI: Ai; // Workers AI binding 5} 6 7interface State { 8 messages: Array<{ role: string; content: string }>; 9 preferences: Record<string, string>; 10} 11 12export class MyAgent extends Agent<Env, State> { 13 // Initial state for new instances 14 initialState: State = { 15 messages: [], 16 preferences: {}, 17 }; 18 19 // Called when agent starts or resumes 20 async onStart() { 21 console.log("Agent started with state:", this.state); 22 } 23 24 // Handle WebSocket connections 25 async onConnect(connection: Connection) { 26 connection.send(JSON.stringify({ 27 type: "welcome", 28 history: this.state.messages, 29 })); 30 } 31 32 // Handle incoming messages 33 async onMessage(connection: Connection, message: string) { 34 const data = JSON.parse(message); 35 36 if (data.type === "chat") { 37 await this.handleChat(connection, data.content); 38 } 39 } 40 41 // Handle disconnections 42 async onClose(connection: Connection) { 43 console.log("Client disconnected"); 44 } 45 46 // React to state changes 47 onStateUpdate(state: State, source: string) { 48 console.log("State updated by:", source); 49 } 50 51 private async handleChat(connection: Connection, userMessage: string) { 52 // Add user message to history 53 const messages = [ 54 ...this.state.messages, 55 { role: "user", content: userMessage }, 56 ]; 57 58 // Call AI 59 const response = await this.env.AI.run("@cf/meta/llama-3-8b-instruct", { 60 messages, 61 }); 62 63 // Update state (persists and syncs to all clients) 64 this.setState({ 65 ...this.state, 66 messages: [ 67 ...messages, 68 { role: "assistant", content: response.response }, 69 ], 70 }); 71 72 // Send response 73 connection.send(JSON.stringify({ 74 type: "response", 75 content: response.response, 76 })); 77 } 78}
Entry Point Configuration
typescript1// src/index.ts 2import { routeAgentRequest } from "agents"; 3import { MyAgent } from "./agent"; 4 5export default { 6 async fetch(request: Request, env: Env) { 7 // routeAgentRequest handles routing to /agents/:class/:name 8 return ( 9 (await routeAgentRequest(request, env)) || 10 new Response("Not found", { status: 404 }) 11 ); 12 }, 13}; 14 15export { MyAgent };
Clients connect via: wss://my-agent.workers.dev/agents/MyAgent/session-id
Wrangler Configuration
toml1name = "my-agent" 2main = "src/index.ts" 3compatibility_date = "2024-12-01" 4 5[ai] 6binding = "AI" 7 8[durable_objects] 9bindings = [{ name = "AGENT", class_name = "MyAgent" }] 10 11[[migrations]] 12tag = "v1" 13new_classes = ["MyAgent"]
State Management
Reading State
typescript1// Current state is always available 2const currentMessages = this.state.messages; 3const userPrefs = this.state.preferences;
Updating State
typescript1// setState persists AND syncs to all connected clients 2this.setState({ 3 ...this.state, 4 messages: [...this.state.messages, newMessage], 5}); 6 7// Partial updates work too 8this.setState({ 9 preferences: { ...this.state.preferences, theme: "dark" }, 10});
SQL Storage
For complex queries, use the embedded SQLite database:
typescript1// Create tables 2await this.sql` 3 CREATE TABLE IF NOT EXISTS documents ( 4 id INTEGER PRIMARY KEY AUTOINCREMENT, 5 title TEXT NOT NULL, 6 content TEXT, 7 created_at DATETIME DEFAULT CURRENT_TIMESTAMP 8 ) 9`; 10 11// Insert 12await this.sql` 13 INSERT INTO documents (title, content) 14 VALUES (${title}, ${content}) 15`; 16 17// Query 18const docs = await this.sql` 19 SELECT * FROM documents WHERE title LIKE ${`%${search}%`} 20`;
Scheduled Tasks
Agents can schedule future work:
typescript1async onMessage(connection: Connection, message: string) { 2 const data = JSON.parse(message); 3 4 if (data.type === "schedule_reminder") { 5 // Schedule task for 1 hour from now 6 const { id } = await this.schedule(3600, "sendReminder", { 7 message: data.reminderText, 8 userId: data.userId, 9 }); 10 11 connection.send(JSON.stringify({ type: "scheduled", taskId: id })); 12 } 13} 14 15// Called when scheduled task fires 16async sendReminder(data: { message: string; userId: string }) { 17 // Send notification, email, etc. 18 console.log(`Reminder for ${data.userId}: ${data.message}`); 19 20 // Can also update state 21 this.setState({ 22 ...this.state, 23 lastReminder: new Date().toISOString(), 24 }); 25}
Schedule Options
typescript1// Delay in seconds 2await this.schedule(60, "taskMethod", { data }); 3 4// Specific date 5await this.schedule(new Date("2025-01-01T00:00:00Z"), "taskMethod", { data }); 6 7// Cron expression (recurring) 8await this.schedule("0 9 * * *", "dailyTask", {}); // 9 AM daily 9await this.schedule("*/5 * * * *", "everyFiveMinutes", {}); // Every 5 min 10 11// Manage schedules 12const schedules = await this.getSchedules(); 13await this.cancelSchedule(taskId);
Chat Agent (AI-Powered)
For chat-focused agents, extend AIChatAgent:
typescript1import { AIChatAgent } from "agents/ai-chat-agent"; 2 3export class ChatBot extends AIChatAgent<Env> { 4 // Called for each user message 5 async onChatMessage(message: string) { 6 const response = await this.env.AI.run("@cf/meta/llama-3-8b-instruct", { 7 messages: [ 8 { role: "system", content: "You are a helpful assistant." }, 9 ...this.messages, // Automatic history management 10 { role: "user", content: message }, 11 ], 12 stream: true, 13 }); 14 15 // Stream response back to client 16 return response; 17 } 18}
Features included:
- Automatic message history
- Resumable streaming (survives disconnects)
- Built-in
saveMessages()for persistence
Client Integration
React Hook
tsx1import { useAgent } from "agents/react"; 2 3function Chat() { 4 const { state, send, connected } = useAgent({ 5 agent: "my-agent", 6 name: userId, // Agent instance ID 7 }); 8 9 const sendMessage = (text: string) => { 10 send(JSON.stringify({ type: "chat", content: text })); 11 }; 12 13 return ( 14 <div> 15 {state.messages.map((msg, i) => ( 16 <div key={i}>{msg.role}: {msg.content}</div> 17 ))} 18 <input onKeyDown={(e) => e.key === "Enter" && sendMessage(e.target.value)} /> 19 </div> 20 ); 21}
Vanilla JavaScript
javascript1const ws = new WebSocket("wss://my-agent.workers.dev/agents/MyAgent/user123"); 2 3ws.onopen = () => { 4 console.log("Connected to agent"); 5}; 6 7ws.onmessage = (event) => { 8 const data = JSON.parse(event.data); 9 console.log("Received:", data); 10}; 11 12ws.send(JSON.stringify({ type: "chat", content: "Hello!" }));
Common Patterns
See references/agent-patterns.md for:
- Tool calling and function execution
- Multi-agent orchestration
- RAG (Retrieval Augmented Generation)
- Human-in-the-loop workflows
Deployment
bash1# Deploy 2npx wrangler deploy 3 4# View logs 5wrangler tail 6 7# Test endpoint 8curl https://my-agent.workers.dev/agents/MyAgent/test-user
Troubleshooting
See references/troubleshooting.md for common issues.
References
- references/examples.md — Official templates and production examples
- references/agent-patterns.md — Advanced patterns
- references/state-patterns.md — State management strategies
- references/troubleshooting.md — Error solutions