agents 0.3.6 → 0.3.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +303 -314
- package/dist/ai-types.js +1 -1
- package/dist/{client-0lfEZpSQ.js → client-6CeOh-EV.js} +7 -3
- package/dist/client-6CeOh-EV.js.map +1 -0
- package/dist/{client-Cxno-5sH.d.ts → client-DGpERepg.d.ts} +8 -14
- package/dist/client.d.ts +80 -24
- package/dist/client.js +184 -2
- package/dist/client.js.map +1 -0
- package/dist/{do-oauth-client-provider-BH9zFtSy.d.ts → do-oauth-client-provider-BqnOQzjy.d.ts} +1 -1
- package/dist/{do-oauth-client-provider-BfPFgQU0.js → do-oauth-client-provider-DDg8QrEA.js} +1 -1
- package/dist/{do-oauth-client-provider-BfPFgQU0.js.map → do-oauth-client-provider-DDg8QrEA.js.map} +1 -1
- package/dist/email-8ljcpvwV.d.ts +157 -0
- package/dist/email-XHsSYsTO.js +223 -0
- package/dist/email-XHsSYsTO.js.map +1 -0
- package/dist/email.d.ts +30 -0
- package/dist/email.js +3 -0
- package/dist/{index-B7Ny-XfU.d.ts → index-N6791tVt.d.ts} +18 -3
- package/dist/index.d.ts +543 -87
- package/dist/index.js +6 -6
- package/dist/{internal_context-neg89p5n.d.ts → internal_context-CEu5ji80.d.ts} +8 -3
- package/dist/{internal_context-oN047Id3.js → internal_context-D9eKFth1.js} +1 -1
- package/dist/internal_context-D9eKFth1.js.map +1 -0
- package/dist/internal_context.d.ts +1 -1
- package/dist/internal_context.js +1 -1
- package/dist/mcp/client.d.ts +1 -1
- package/dist/mcp/client.js +2 -2
- package/dist/mcp/do-oauth-client-provider.d.ts +1 -1
- package/dist/mcp/do-oauth-client-provider.js +1 -1
- package/dist/mcp/index.d.ts +4 -2
- package/dist/mcp/index.js +35 -35
- package/dist/mcp/index.js.map +1 -1
- package/dist/mcp/x402.d.ts +0 -1
- package/dist/mcp/x402.js.map +1 -1
- package/dist/{mcp-AK39tq6H.d.ts → mcp-BwPscEiF.d.ts} +1 -1
- package/dist/observability/index.d.ts +1 -1
- package/dist/observability/index.js +5 -5
- package/dist/react.d.ts +70 -26
- package/dist/react.js +83 -21
- package/dist/react.js.map +1 -1
- package/dist/schedule.d.ts +23 -2
- package/dist/schedule.js +23 -1
- package/dist/schedule.js.map +1 -1
- package/dist/serializable.d.ts +68 -3
- package/dist/src-BFP4sOQ4.js +2146 -0
- package/dist/src-BFP4sOQ4.js.map +1 -0
- package/dist/types-BITaDFf-.js +16 -0
- package/dist/{types-4b5tlB0u.js.map → types-BITaDFf-.js.map} +1 -1
- package/dist/{types-C5vR2Gzv.d.ts → types-DSSHBW6w.d.ts} +2 -1
- package/dist/types.d.ts +1 -1
- package/dist/types.js +1 -1
- package/dist/utils-B49TmLCI.js +16 -0
- package/dist/utils-B49TmLCI.js.map +1 -0
- package/dist/utils.d.ts +10 -0
- package/dist/utils.js +3 -0
- package/dist/workflow-types-Z_Oem1FJ.d.ts +260 -0
- package/dist/workflow-types.d.ts +48 -0
- package/dist/workflow-types.js +16 -0
- package/dist/workflow-types.js.map +1 -0
- package/dist/workflows.d.ts +163 -0
- package/dist/workflows.js +240 -0
- package/dist/workflows.js.map +1 -0
- package/package.json +22 -12
- package/dist/client-0lfEZpSQ.js.map +0 -1
- package/dist/client-CEO0P7vN.js +0 -117
- package/dist/client-CEO0P7vN.js.map +0 -1
- package/dist/internal_context-oN047Id3.js.map +0 -1
- package/dist/src-C_iKczoR.js +0 -1191
- package/dist/src-C_iKczoR.js.map +0 -1
- package/dist/types-4b5tlB0u.js +0 -15
package/README.md
CHANGED
|
@@ -1,465 +1,454 @@
|
|
|
1
|
-
|
|
1
|
+
# agents
|
|
2
2
|
|
|
3
3
|

|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
**Build software that thinks and does.**
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
Persistent AI agents on Cloudflare's global network. They remember context, reason through problems, schedule their own work, and take action—all without you managing servers.
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
- **Persistence**: Maintains its state and knowledge across time
|
|
14
|
-
- **Agency**: Acts autonomously within its defined purpose
|
|
15
|
-
- **Connection**: Communicates through multiple channels with both humans and other agents
|
|
16
|
-
- **Growth**: Learns and adapts through its interactions
|
|
17
|
-
|
|
18
|
-
Built on Cloudflare's global network, this framework provides agents with a reliable, distributed foundation where they can operate continuously and effectively.
|
|
9
|
+
```sh
|
|
10
|
+
npm create cloudflare@latest -- --template cloudflare/agents-starter
|
|
11
|
+
```
|
|
19
12
|
|
|
20
|
-
|
|
13
|
+
Or add to an existing project:
|
|
21
14
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
4. **Global Distribution**: Leverage Cloudflare's network for worldwide presence
|
|
26
|
-
5. **Resource Harmony**: Efficient hibernation and awakening as needed
|
|
15
|
+
```sh
|
|
16
|
+
npm install agents
|
|
17
|
+
```
|
|
27
18
|
|
|
28
19
|
---
|
|
29
20
|
|
|
30
|
-
|
|
21
|
+
## Why Agents, Why Now
|
|
31
22
|
|
|
32
|
-
|
|
23
|
+
LLMs can reason, plan, and use tools—but they need infrastructure that matches their capabilities. Traditional serverless is stateless and ephemeral. Agents are persistent and purposeful.
|
|
33
24
|
|
|
34
|
-
```sh
|
|
35
|
-
# Create a new project
|
|
36
|
-
npm create cloudflare@latest -- --template cloudflare/agents-starter
|
|
37
|
-
|
|
38
|
-
# Or enhance an existing one
|
|
39
|
-
npm install agents
|
|
40
25
|
```
|
|
26
|
+
From request handlers → to autonomous entities
|
|
27
|
+
From stateless functions → to persistent intelligence
|
|
41
28
|
|
|
42
|
-
|
|
29
|
+
Traditional serverless: Request → Response → Gone
|
|
30
|
+
Agents: Thinking, remembering, acting — continuously
|
|
31
|
+
```
|
|
43
32
|
|
|
44
|
-
|
|
33
|
+
**Pay only when active.** Agents hibernate between requests. You can have millions of agents—one per user, per session, per game room—each costs nothing when idle.
|
|
45
34
|
|
|
46
|
-
|
|
47
|
-
import { Agent } from "agents";
|
|
35
|
+
Built on Cloudflare Durable Objects, agents run globally, close to your users, with persistent state that survives restarts.
|
|
48
36
|
|
|
49
|
-
|
|
50
|
-
async onRequest(request) {
|
|
51
|
-
// Transform intention into response
|
|
52
|
-
return new Response("Ready to assist.");
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
```
|
|
37
|
+
---
|
|
56
38
|
|
|
57
|
-
|
|
39
|
+
## Quick Example
|
|
58
40
|
|
|
59
|
-
|
|
41
|
+
A counter agent with real-time state sync and callable methods:
|
|
60
42
|
|
|
61
|
-
```
|
|
62
|
-
|
|
63
|
-
import {
|
|
43
|
+
```typescript
|
|
44
|
+
// server.ts
|
|
45
|
+
import { Agent, callable } from "agents";
|
|
64
46
|
|
|
65
|
-
|
|
66
|
-
async onRequest(request) {
|
|
67
|
-
// Connect with AI capabilities
|
|
68
|
-
const ai = new OpenAI({
|
|
69
|
-
apiKey: this.env.OPENAI_API_KEY
|
|
70
|
-
});
|
|
47
|
+
type State = { count: number };
|
|
71
48
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
model: "gpt-4",
|
|
75
|
-
messages: [{ role: "user", content: await request.text() }]
|
|
76
|
-
});
|
|
49
|
+
export class CounterAgent extends Agent<Env, State> {
|
|
50
|
+
initialState: State = { count: 0 };
|
|
77
51
|
|
|
78
|
-
|
|
52
|
+
@callable()
|
|
53
|
+
increment() {
|
|
54
|
+
this.setState({ count: this.state.count + 1 });
|
|
55
|
+
return this.state.count;
|
|
79
56
|
}
|
|
80
57
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
58
|
+
@callable()
|
|
59
|
+
decrement() {
|
|
60
|
+
this.setState({ count: this.state.count - 1 });
|
|
61
|
+
return this.state.count;
|
|
85
62
|
}
|
|
86
63
|
}
|
|
87
64
|
```
|
|
88
65
|
|
|
89
|
-
|
|
66
|
+
```tsx
|
|
67
|
+
// client.tsx
|
|
68
|
+
import { useAgent } from "agents/react";
|
|
69
|
+
import { useState } from "react";
|
|
90
70
|
|
|
91
|
-
|
|
71
|
+
function Counter() {
|
|
72
|
+
const [count, setCount] = useState(0);
|
|
92
73
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
// Mandatory for the Agent to store state
|
|
107
|
-
"new_sqlite_classes": ["AIAgent"]
|
|
108
|
-
}
|
|
109
|
-
]
|
|
74
|
+
const agent = useAgent<State>({
|
|
75
|
+
agent: "counter-agent",
|
|
76
|
+
name: "my-counter",
|
|
77
|
+
onStateUpdate: (state) => setCount(state.count)
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
return (
|
|
81
|
+
<div>
|
|
82
|
+
<span>{count}</span>
|
|
83
|
+
<button onClick={() => agent.stub.increment()}>+</button>
|
|
84
|
+
<button onClick={() => agent.stub.decrement()}>-</button>
|
|
85
|
+
</div>
|
|
86
|
+
);
|
|
110
87
|
}
|
|
111
88
|
```
|
|
112
89
|
|
|
113
|
-
|
|
90
|
+
State changes sync to all connected clients automatically. Call methods like they're local functions.
|
|
91
|
+
|
|
92
|
+
---
|
|
114
93
|
|
|
115
|
-
|
|
94
|
+
## What You Can Build
|
|
116
95
|
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
96
|
+
| Use Case | Why Agents |
|
|
97
|
+
| ---------------------- | ----------------------------------------------------- |
|
|
98
|
+
| Multiplayer game rooms | Per-room state, real-time sync, hibernates when empty |
|
|
99
|
+
| Customer support bots | Remembers conversation history, escalates to humans |
|
|
100
|
+
| Collaborative editors | Presence, cursors, document state |
|
|
101
|
+
| Approval workflows | Long-running, pauses for human input, durable |
|
|
102
|
+
| Personal AI assistants | Per-user memory, tool access via MCP |
|
|
103
|
+
| Notification systems | Scheduled delivery, user preferences, retry logic |
|
|
121
104
|
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
context: "incoming_data",
|
|
126
|
-
parameters: initialConfig
|
|
127
|
-
});
|
|
105
|
+
---
|
|
106
|
+
|
|
107
|
+
## Features
|
|
128
108
|
|
|
129
|
-
|
|
130
|
-
|
|
109
|
+
```
|
|
110
|
+
Core State sync · Routing · HTTP & WebSockets · @callable RPC
|
|
111
|
+
Clients React hook · Vanilla JS · Real-time state sync
|
|
112
|
+
Channels WebSocket · HTTP · Email · (coming: SMS, Voice, Messengers)
|
|
113
|
+
Background Queue · Scheduling · Workflows · Human-in-the-loop
|
|
114
|
+
AI Chat agents · Tool calling · MCP servers & clients
|
|
115
|
+
Platform Observability · Cross-domain auth · Resumable streams
|
|
131
116
|
```
|
|
132
117
|
|
|
133
|
-
###
|
|
118
|
+
### State Management
|
|
134
119
|
|
|
135
|
-
|
|
120
|
+
State persists across requests and syncs to all connected clients:
|
|
136
121
|
|
|
137
|
-
|
|
122
|
+
```typescript
|
|
123
|
+
export class MyAgent extends Agent<Env, { items: string[] }> {
|
|
124
|
+
initialState = { items: [] };
|
|
138
125
|
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
126
|
+
@callable()
|
|
127
|
+
addItem(item: string) {
|
|
128
|
+
this.setState({ items: [...this.state.items, item] });
|
|
129
|
+
}
|
|
143
130
|
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
moment: Date.now()
|
|
147
|
-
});
|
|
131
|
+
onStateUpdate(state: State, source: Connection | "server") {
|
|
132
|
+
// Called when state changes from any source
|
|
148
133
|
}
|
|
149
134
|
}
|
|
150
135
|
```
|
|
151
136
|
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
Maintain ongoing dialogues through WebSocket:
|
|
137
|
+
### Callable Methods
|
|
155
138
|
|
|
156
|
-
|
|
157
|
-
export class DialogueAgent extends Agent {
|
|
158
|
-
async onConnect(connection) {
|
|
159
|
-
await this.initiate(connection);
|
|
160
|
-
}
|
|
139
|
+
Expose methods to clients with the `@callable()` decorator:
|
|
161
140
|
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
141
|
+
```typescript
|
|
142
|
+
@callable()
|
|
143
|
+
async processOrder(orderId: string, items: Item[]) {
|
|
144
|
+
// Full type safety - clients call this like a local function
|
|
145
|
+
const result = await this.validateAndProcess(orderId, items);
|
|
146
|
+
return result;
|
|
166
147
|
}
|
|
167
148
|
```
|
|
168
149
|
|
|
169
|
-
|
|
150
|
+
```typescript
|
|
151
|
+
// Client
|
|
152
|
+
const result = await agent.stub.processOrder("order-123", items);
|
|
153
|
+
```
|
|
170
154
|
|
|
171
|
-
|
|
155
|
+
### Scheduling
|
|
172
156
|
|
|
173
|
-
|
|
174
|
-
import { AgentClient } from "agents/client";
|
|
157
|
+
Run tasks later, on intervals, or with cron expressions:
|
|
175
158
|
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
});
|
|
159
|
+
```typescript
|
|
160
|
+
// In 60 seconds
|
|
161
|
+
this.schedule(60, "sendReminder", { userId: "123" });
|
|
180
162
|
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
});
|
|
163
|
+
// Every hour
|
|
164
|
+
this.scheduleEvery(3600, "syncData");
|
|
184
165
|
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
);
|
|
166
|
+
// Daily at 9am UTC
|
|
167
|
+
this.schedule("0 9 * * *", "dailyReport");
|
|
168
|
+
|
|
169
|
+
// At a specific date
|
|
170
|
+
this.schedule(new Date("2025-12-31"), "yearEndTask");
|
|
191
171
|
```
|
|
192
172
|
|
|
193
|
-
|
|
173
|
+
### Background Tasks
|
|
194
174
|
|
|
195
|
-
|
|
175
|
+
Queue immediate background work:
|
|
196
176
|
|
|
197
|
-
```
|
|
198
|
-
|
|
177
|
+
```typescript
|
|
178
|
+
await this.queue("processUpload", { fileId: "abc" });
|
|
179
|
+
// Returns immediately, task runs in background
|
|
180
|
+
```
|
|
199
181
|
|
|
200
|
-
|
|
201
|
-
const connection = useAgent({
|
|
202
|
-
agent: "dialogue-agent",
|
|
203
|
-
name: "insight-seeker",
|
|
204
|
-
onMessage: (message) => {
|
|
205
|
-
console.log("Understanding received:", message.data);
|
|
206
|
-
},
|
|
207
|
-
onOpen: () => console.log("Connection established"),
|
|
208
|
-
onClose: () => console.log("Connection closed")
|
|
209
|
-
});
|
|
182
|
+
### WebSocket Connections
|
|
210
183
|
|
|
211
|
-
|
|
212
|
-
connection.send(
|
|
213
|
-
JSON.stringify({
|
|
214
|
-
type: "inquiry",
|
|
215
|
-
content: "What insights have you gathered?"
|
|
216
|
-
})
|
|
217
|
-
);
|
|
218
|
-
};
|
|
184
|
+
Handle real-time communication:
|
|
219
185
|
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
</div>
|
|
224
|
-
);
|
|
186
|
+
```typescript
|
|
187
|
+
async onConnect(connection: Connection) {
|
|
188
|
+
console.log(`Client ${connection.id} connected`);
|
|
225
189
|
}
|
|
226
|
-
```
|
|
227
190
|
|
|
228
|
-
|
|
191
|
+
async onMessage(connection: Connection, message: unknown) {
|
|
192
|
+
// Handle incoming messages
|
|
193
|
+
connection.send(JSON.stringify({ received: true }));
|
|
194
|
+
}
|
|
229
195
|
|
|
230
|
-
|
|
196
|
+
async onClose(connection: Connection) {
|
|
197
|
+
console.log(`Client ${connection.id} disconnected`);
|
|
198
|
+
}
|
|
199
|
+
```
|
|
231
200
|
|
|
232
|
-
|
|
233
|
-
export class ThinkingAgent extends Agent {
|
|
234
|
-
async evolve(newInsight) {
|
|
235
|
-
this.setState({
|
|
236
|
-
...this.state,
|
|
237
|
-
insights: [...(this.state.insights || []), newInsight],
|
|
238
|
-
understanding: this.state.understanding + 1
|
|
239
|
-
});
|
|
240
|
-
}
|
|
201
|
+
### Email
|
|
241
202
|
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
203
|
+
Agents can receive and respond to emails:
|
|
204
|
+
|
|
205
|
+
```typescript
|
|
206
|
+
async onEmail(email: EmailMessage) {
|
|
207
|
+
const from = email.from;
|
|
208
|
+
const subject = email.headers.get("subject");
|
|
209
|
+
// Process incoming email
|
|
248
210
|
}
|
|
249
211
|
```
|
|
250
212
|
|
|
251
|
-
|
|
213
|
+
---
|
|
214
|
+
|
|
215
|
+
## Client SDK
|
|
216
|
+
|
|
217
|
+
### React
|
|
252
218
|
|
|
253
219
|
```tsx
|
|
254
|
-
import { useState } from "react";
|
|
255
220
|
import { useAgent } from "agents/react";
|
|
221
|
+
import { useState } from "react";
|
|
256
222
|
|
|
257
|
-
function
|
|
258
|
-
const [state, setState] = useState
|
|
223
|
+
function App() {
|
|
224
|
+
const [state, setState] = useState<MyState | null>(null);
|
|
259
225
|
|
|
260
|
-
const agent = useAgent({
|
|
261
|
-
agent: "
|
|
226
|
+
const agent = useAgent<MyState>({
|
|
227
|
+
agent: "my-agent",
|
|
228
|
+
name: "instance-name",
|
|
262
229
|
onStateUpdate: (newState) => setState(newState)
|
|
263
230
|
});
|
|
264
231
|
|
|
265
|
-
const increment = () => {
|
|
266
|
-
agent.setState({ counter: state.counter + 1 });
|
|
267
|
-
};
|
|
268
|
-
|
|
269
232
|
return (
|
|
270
233
|
<div>
|
|
271
|
-
<
|
|
272
|
-
<button onClick={
|
|
234
|
+
<pre>{JSON.stringify(state, null, 2)}</pre>
|
|
235
|
+
<button onClick={() => agent.stub.doSomething()}>Call Agent</button>
|
|
273
236
|
</div>
|
|
274
237
|
);
|
|
275
238
|
}
|
|
276
239
|
```
|
|
277
240
|
|
|
278
|
-
|
|
241
|
+
### Vanilla JavaScript
|
|
279
242
|
|
|
280
|
-
|
|
243
|
+
```typescript
|
|
244
|
+
import { AgentClient } from "agents/client";
|
|
281
245
|
|
|
282
|
-
|
|
246
|
+
const client = new AgentClient({
|
|
247
|
+
agent: "my-agent",
|
|
248
|
+
name: "instance-name",
|
|
249
|
+
onStateUpdate: (state) => console.log("State:", state)
|
|
250
|
+
});
|
|
283
251
|
|
|
284
|
-
|
|
252
|
+
// Call methods
|
|
253
|
+
const result = await client.call("processData", [payload]);
|
|
285
254
|
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
- Tool support - Both server and client-side tool execution
|
|
290
|
-
- AI SDK v6 integration - Built on the latest AI SDK
|
|
255
|
+
// Or use the stub
|
|
256
|
+
const result = await client.stub.processData(payload);
|
|
257
|
+
```
|
|
291
258
|
|
|
292
|
-
|
|
259
|
+
---
|
|
260
|
+
|
|
261
|
+
## Workflows Integration
|
|
293
262
|
|
|
294
|
-
|
|
263
|
+
For durable, multi-step tasks that survive failures and can pause for human approval, integrate with [Cloudflare Workflows](https://developers.cloudflare.com/workflows/):
|
|
295
264
|
|
|
296
|
-
```
|
|
297
|
-
|
|
298
|
-
async initialize() {
|
|
299
|
-
// Quick reflection
|
|
300
|
-
this.schedule(10, "quickInsight", { focus: "patterns" });
|
|
265
|
+
```typescript
|
|
266
|
+
import { AgentWorkflow } from "agents";
|
|
301
267
|
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
268
|
+
export class OrderWorkflow extends AgentWorkflow<OrderAgent, OrderParams> {
|
|
269
|
+
async run(event, step) {
|
|
270
|
+
// Step 1: Validate (retries automatically on failure)
|
|
271
|
+
const validated = await step.do("validate", async () => {
|
|
272
|
+
return validateOrder(event.payload);
|
|
305
273
|
});
|
|
306
274
|
|
|
307
|
-
//
|
|
308
|
-
this.
|
|
309
|
-
|
|
275
|
+
// Step 2: Wait for human approval
|
|
276
|
+
await this.reportProgress({ step: "approval", status: "pending" });
|
|
277
|
+
const approval = await this.waitForApproval(step, { timeout: "7 days" });
|
|
310
278
|
|
|
311
|
-
|
|
312
|
-
await
|
|
279
|
+
// Step 3: Process the approved order
|
|
280
|
+
await step.do("process", async () => {
|
|
281
|
+
return processOrder(validated, approval);
|
|
282
|
+
});
|
|
313
283
|
}
|
|
284
|
+
}
|
|
285
|
+
```
|
|
314
286
|
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
287
|
+
Workflows provide:
|
|
288
|
+
|
|
289
|
+
- **Durable execution** — steps retry automatically, state persists across failures
|
|
290
|
+
- **Human-in-the-loop** — pause for approval with `waitForApproval()`
|
|
291
|
+
- **Long-running tasks** — run for days or weeks
|
|
292
|
+
- **Progress tracking** — report status back to the agent
|
|
318
293
|
|
|
319
|
-
|
|
320
|
-
|
|
294
|
+
See [Workflows](./docs/workflows.md) and [Human in the Loop](./docs/human-in-the-loop.md).
|
|
295
|
+
|
|
296
|
+
---
|
|
297
|
+
|
|
298
|
+
## AI Chat Integration
|
|
299
|
+
|
|
300
|
+
For AI-powered chat experiences with persistent conversations, streaming responses, and tool support, see [`@cloudflare/ai-chat`](../ai-chat/README.md).
|
|
301
|
+
|
|
302
|
+
```typescript
|
|
303
|
+
import { AIChatAgent } from "@cloudflare/ai-chat";
|
|
304
|
+
|
|
305
|
+
export class ChatAgent extends AIChatAgent<Env> {
|
|
306
|
+
async onChatMessage(onFinish) {
|
|
307
|
+
return streamText({
|
|
308
|
+
model: openai("gpt-4o"),
|
|
309
|
+
messages: this.messages,
|
|
310
|
+
tools: this.tools,
|
|
311
|
+
onFinish
|
|
312
|
+
});
|
|
321
313
|
}
|
|
322
314
|
}
|
|
323
315
|
```
|
|
324
316
|
|
|
325
|
-
|
|
317
|
+
```tsx
|
|
318
|
+
// Client
|
|
319
|
+
import { useAgentChat } from "@cloudflare/ai-chat/react";
|
|
326
320
|
|
|
327
|
-
|
|
321
|
+
const { messages, input, handleSubmit } = useAgentChat({
|
|
322
|
+
agent: useAgent({ agent: "chat-agent" })
|
|
323
|
+
});
|
|
324
|
+
```
|
|
328
325
|
|
|
329
|
-
|
|
326
|
+
Features:
|
|
327
|
+
|
|
328
|
+
- Automatic message persistence
|
|
329
|
+
- Resumable streaming (survives disconnections)
|
|
330
|
+
- Server and client-side tool execution
|
|
331
|
+
- Human-in-the-loop approval for sensitive tools
|
|
332
|
+
|
|
333
|
+
---
|
|
334
|
+
|
|
335
|
+
## MCP (Model Context Protocol)
|
|
336
|
+
|
|
337
|
+
Agents integrate with MCP to act as servers (providing tools to AI assistants) or clients (using tools from other services).
|
|
338
|
+
|
|
339
|
+
### Creating an MCP Server
|
|
330
340
|
|
|
331
341
|
```typescript
|
|
332
342
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
333
343
|
import { McpAgent } from "agents/mcp";
|
|
334
|
-
import { z } from "zod";
|
|
335
|
-
|
|
336
|
-
type Env = {
|
|
337
|
-
MyMCP: DurableObjectNamespace<MyMCP>;
|
|
338
|
-
};
|
|
339
|
-
|
|
340
|
-
type State = { counter: number };
|
|
341
344
|
|
|
342
345
|
export class MyMCP extends McpAgent<Env, State, {}> {
|
|
343
|
-
server = new McpServer({
|
|
344
|
-
name: "Demo",
|
|
345
|
-
version: "1.0.0"
|
|
346
|
-
});
|
|
347
|
-
|
|
348
|
-
initialState: State = {
|
|
349
|
-
counter: 1
|
|
350
|
-
};
|
|
346
|
+
server = new McpServer({ name: "my-tools", version: "1.0.0" });
|
|
351
347
|
|
|
352
348
|
async init() {
|
|
353
|
-
this.server.resource("counter", "mcp://resource/counter", (uri) => {
|
|
354
|
-
return {
|
|
355
|
-
contents: [{ text: String(this.state.counter), uri: uri.href }]
|
|
356
|
-
};
|
|
357
|
-
});
|
|
358
|
-
|
|
359
349
|
this.server.registerTool(
|
|
360
|
-
"
|
|
361
|
-
{
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
async ({ a }) => {
|
|
366
|
-
this.setState({ ...this.state, counter: this.state.counter + a });
|
|
367
|
-
|
|
368
|
-
return {
|
|
369
|
-
content: [
|
|
370
|
-
{
|
|
371
|
-
text: String(`Added ${a}, total is now ${this.state.counter}`),
|
|
372
|
-
type: "text"
|
|
373
|
-
}
|
|
374
|
-
]
|
|
375
|
-
};
|
|
350
|
+
"lookup",
|
|
351
|
+
{ description: "Look up data", inputSchema: { query: z.string() } },
|
|
352
|
+
async ({ query }) => {
|
|
353
|
+
const result = await this.search(query);
|
|
354
|
+
return { content: [{ type: "text", text: result }] };
|
|
376
355
|
}
|
|
377
356
|
);
|
|
378
357
|
}
|
|
379
|
-
|
|
380
|
-
onStateUpdate(state: State) {
|
|
381
|
-
console.log({ stateUpdate: state });
|
|
382
|
-
}
|
|
383
358
|
}
|
|
384
359
|
|
|
385
|
-
|
|
386
|
-
export default MyMCP.serve("/mcp", {
|
|
387
|
-
binding: "MyMCP"
|
|
388
|
-
});
|
|
389
|
-
|
|
390
|
-
// Or SSE transport for legacy compatibility
|
|
391
|
-
// export default MyMCP.serveSSE("/mcp", { binding: "MyMCP" });
|
|
360
|
+
export default MyMCP.serve("/mcp", { binding: "MyMCP" });
|
|
392
361
|
```
|
|
393
362
|
|
|
394
|
-
|
|
363
|
+
### Using MCP Tools
|
|
395
364
|
|
|
396
365
|
```typescript
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
366
|
+
// Connect to external MCP servers
|
|
367
|
+
await this.addMcpServer(
|
|
368
|
+
"weather-service",
|
|
369
|
+
"https://weather-mcp.example.com/mcp",
|
|
370
|
+
{
|
|
371
|
+
transport: { type: "streamable-http" }
|
|
372
|
+
}
|
|
373
|
+
);
|
|
400
374
|
|
|
401
|
-
//
|
|
402
|
-
await
|
|
403
|
-
|
|
375
|
+
// Use with AI SDK
|
|
376
|
+
const result = await generateText({
|
|
377
|
+
model: openai("gpt-4o"),
|
|
378
|
+
tools: this.mcp.getTools(),
|
|
379
|
+
prompt: "What's the weather in Tokyo?"
|
|
404
380
|
});
|
|
381
|
+
```
|
|
405
382
|
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
383
|
+
---
|
|
384
|
+
|
|
385
|
+
## Configuration
|
|
386
|
+
|
|
387
|
+
Add your agent to `wrangler.jsonc`:
|
|
388
|
+
|
|
389
|
+
```jsonc
|
|
390
|
+
{
|
|
391
|
+
"durable_objects": {
|
|
392
|
+
"bindings": [{ "name": "MyAgent", "class_name": "MyAgent" }]
|
|
393
|
+
},
|
|
394
|
+
"migrations": [{ "tag": "v1", "new_sqlite_classes": ["MyAgent"] }]
|
|
395
|
+
}
|
|
412
396
|
```
|
|
413
397
|
|
|
414
|
-
|
|
398
|
+
Route requests to your agent:
|
|
415
399
|
|
|
416
400
|
```typescript
|
|
417
|
-
import {
|
|
401
|
+
import { routeAgentRequest } from "agents";
|
|
418
402
|
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
403
|
+
export default {
|
|
404
|
+
async fetch(request: Request, env: Env) {
|
|
405
|
+
return (
|
|
406
|
+
(await routeAgentRequest(request, env)) ??
|
|
407
|
+
new Response("Not found", { status: 404 })
|
|
408
|
+
);
|
|
409
|
+
}
|
|
410
|
+
};
|
|
425
411
|
```
|
|
426
412
|
|
|
427
|
-
|
|
413
|
+
---
|
|
428
414
|
|
|
429
|
-
|
|
430
|
-
- **HTTP Streamable**: Best performance, batch requests, session management
|
|
431
|
-
- **SSE**: Simple setup, legacy compatibility
|
|
415
|
+
## Coming Soon
|
|
432
416
|
|
|
433
|
-
|
|
417
|
+
- **Browse the Web** — Headless browser for web scraping and automation
|
|
418
|
+
- **Cloudflare Sandboxes** — Isolated environments for code execution
|
|
419
|
+
- **SMS, Voice, Messengers** — Multi-channel communication
|
|
434
420
|
|
|
435
|
-
|
|
421
|
+
---
|
|
436
422
|
|
|
437
|
-
|
|
423
|
+
## Learn More
|
|
438
424
|
|
|
439
|
-
-
|
|
440
|
-
|
|
441
|
-
|
|
425
|
+
[Getting Started](./docs/getting-started.md) ·
|
|
426
|
+
[State Management](./docs/state.md) ·
|
|
427
|
+
[Scheduling](./docs/scheduling.md) ·
|
|
428
|
+
[Callable Methods](./docs/callable-methods.md) ·
|
|
429
|
+
[MCP Integration](./docs/mcp-client.md) ·
|
|
430
|
+
[Full Documentation](./docs/index.md)
|
|
442
431
|
|
|
443
|
-
|
|
432
|
+
---
|
|
444
433
|
|
|
445
|
-
|
|
446
|
-
- **Clear Sight**: Deep visibility into agent processes
|
|
447
|
-
- **Private Realms**: Complete self-hosting guide
|
|
434
|
+
## Contributing
|
|
448
435
|
|
|
449
|
-
|
|
436
|
+
Contributions are welcome, especially when:
|
|
450
437
|
|
|
451
|
-
|
|
438
|
+
- You've opened an issue as an RFC to discuss your proposal
|
|
439
|
+
- The contribution isn't "AI slop" — LLMs are tools, but vibe-coded PRs won't meet the quality bar
|
|
440
|
+
- You're open to feedback to ensure changes fit the SDK's goals
|
|
452
441
|
|
|
453
|
-
|
|
442
|
+
Small fixes, type bugs, and documentation improvements can be raised directly as PRs.
|
|
454
443
|
|
|
455
|
-
|
|
444
|
+
---
|
|
456
445
|
|
|
457
|
-
|
|
458
|
-
- Not "AI slop": LLMs are powerful tools, but contributions entirely authored by vibe coding are unlikely to meet the quality bar, and will be rejected.
|
|
459
|
-
- You're willing to accept feedback and make sure the changes fit the goals of the `agents` SDK. Not everything will, and that's OK.
|
|
446
|
+
## License
|
|
460
447
|
|
|
461
|
-
|
|
448
|
+
MIT licensed. See the [LICENSE](../../LICENSE) file for details.
|
|
462
449
|
|
|
463
|
-
|
|
450
|
+
---
|
|
464
451
|
|
|
465
|
-
|
|
452
|
+
<p align="center">
|
|
453
|
+
<i>Build something that thinks. Ship something that does.</i>
|
|
454
|
+
</p>
|