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
bash
1npm 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
typescript
1import { 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
typescript
1// 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
jsonc
1{
2 "name": "my-agent",
3 "main": "src/index.ts",
4 "compatibility_date": "2024-12-01",
5 "ai": { "binding": "AI" },
6 "durable_objects": {
7 "bindings": [{ "name": "AGENT", "class_name": "MyAgent" }]
8 },
9 "migrations": [{ "tag": "v1", "new_sqlite_classes": ["MyAgent"] }]
10}
State Management
Reading State
typescript
1// Current state is always available
2const currentMessages = this.state.messages;
3const userPrefs = this.state.preferences;
Updating State
typescript
1// 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:
typescript
1// 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:
typescript
1async 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
typescript
1// 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:
typescript
1import { 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
tsx
1import { 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
javascript
1const 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
bash
1# 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