agents 0.0.0-804e02e → 0.0.0-80a8fbd0

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.
Files changed (217) hide show
  1. package/README.md +373 -481
  2. package/agents.tsconfig.json +18 -0
  3. package/dist/agent-tool-types-DEBXD2Ta.d.ts +6169 -0
  4. package/dist/agent-tool-types.d.ts +54 -0
  5. package/dist/agent-tool-types.js +20 -0
  6. package/dist/agent-tool-types.js.map +1 -0
  7. package/dist/agent-tools-krZpfAix.d.ts +133 -0
  8. package/dist/agent-tools-y7zLfw4Q.js +304 -0
  9. package/dist/agent-tools-y7zLfw4Q.js.map +1 -0
  10. package/dist/agent-tools.d.ts +70 -0
  11. package/dist/agent-tools.js +60 -0
  12. package/dist/agent-tools.js.map +1 -0
  13. package/dist/ai-chat-agent.d.ts +1 -85
  14. package/dist/ai-chat-agent.js +4 -358
  15. package/dist/ai-chat-agent.js.map +1 -1
  16. package/dist/ai-chat-v5-migration.d.ts +1 -152
  17. package/dist/ai-chat-v5-migration.js +5 -19
  18. package/dist/ai-chat-v5-migration.js.map +1 -1
  19. package/dist/ai-react.d.ts +1 -98
  20. package/dist/ai-react.js +4 -354
  21. package/dist/ai-react.js.map +1 -1
  22. package/dist/ai-types.d.ts +1 -92
  23. package/dist/ai-types.js +5 -7
  24. package/dist/ai-types.js.map +1 -1
  25. package/dist/browser/ai.d.ts +235 -0
  26. package/dist/browser/ai.js +265 -0
  27. package/dist/browser/ai.js.map +1 -0
  28. package/dist/browser/index.d.ts +146 -0
  29. package/dist/browser/index.js +3 -0
  30. package/dist/browser/tanstack-ai.d.ts +41 -0
  31. package/dist/browser/tanstack-ai.js +57 -0
  32. package/dist/browser/tanstack-ai.js.map +1 -0
  33. package/dist/chat/index.d.ts +3392 -0
  34. package/dist/chat/index.js +3408 -0
  35. package/dist/chat/index.js.map +1 -0
  36. package/dist/chat/react.d.ts +602 -0
  37. package/dist/chat/react.js +1517 -0
  38. package/dist/chat/react.js.map +1 -0
  39. package/dist/chat-sdk/index.d.ts +135 -0
  40. package/dist/chat-sdk/index.js +453 -0
  41. package/dist/chat-sdk/index.js.map +1 -0
  42. package/dist/classPrivateFieldGet2-DZBYAB34.js +27 -0
  43. package/dist/classPrivateMethodInitSpec-qMjJ6sHQ.js +7 -0
  44. package/dist/cli/index.d.ts +1 -0
  45. package/dist/cli/index.js +26 -0
  46. package/dist/cli/index.js.map +1 -0
  47. package/dist/client-D8tz8bn3.js +2233 -0
  48. package/dist/client-D8tz8bn3.js.map +1 -0
  49. package/dist/client-invoker-BNSZxAkv.d.ts +20 -0
  50. package/dist/client-invoker-oF0lZZtP.js +57 -0
  51. package/dist/client-invoker-oF0lZZtP.js.map +1 -0
  52. package/dist/client-tools-aIBO0Fk7.d.ts +53 -0
  53. package/dist/client.d.ts +248 -44
  54. package/dist/client.js +272 -11
  55. package/dist/client.js.map +1 -1
  56. package/dist/codemode/ai.d.ts +1 -0
  57. package/dist/codemode/ai.js +6 -0
  58. package/dist/codemode/ai.js.map +1 -0
  59. package/dist/compaction-helpers-iiKMr2TQ.js +340 -0
  60. package/dist/compaction-helpers-iiKMr2TQ.js.map +1 -0
  61. package/dist/compaction-helpers-wUz6M3us.d.ts +621 -0
  62. package/dist/connector-CdldGF3h.js +1291 -0
  63. package/dist/connector-CdldGF3h.js.map +1 -0
  64. package/dist/connector-v2M1zlZp.d.ts +659 -0
  65. package/dist/do-oauth-client-provider-VTZj2VtM.d.ts +110 -0
  66. package/dist/email-CL27preh.d.ts +157 -0
  67. package/dist/email.d.ts +30 -0
  68. package/dist/email.js +222 -0
  69. package/dist/email.js.map +1 -0
  70. package/dist/experimental/memory/session/index.d.ts +670 -0
  71. package/dist/experimental/memory/session/index.js +2374 -0
  72. package/dist/experimental/memory/session/index.js.map +1 -0
  73. package/dist/experimental/memory/utils/index.d.ts +96 -0
  74. package/dist/experimental/memory/utils/index.js +79 -0
  75. package/dist/experimental/memory/utils/index.js.map +1 -0
  76. package/dist/experimental/webmcp.d.ts +218 -0
  77. package/dist/experimental/webmcp.js +298 -0
  78. package/dist/experimental/webmcp.js.map +1 -0
  79. package/dist/index-BRnybD6X.d.ts +947 -0
  80. package/dist/index.d.ts +180 -558
  81. package/dist/index.js +7151 -30
  82. package/dist/index.js.map +1 -1
  83. package/dist/internal_context-Dg4Cgjcu.d.ts +37 -0
  84. package/dist/internal_context.d.ts +6 -0
  85. package/dist/internal_context.js +11 -0
  86. package/dist/internal_context.js.map +1 -0
  87. package/dist/mcp/client.d.ts +38 -11
  88. package/dist/mcp/client.js +2 -10
  89. package/dist/mcp/do-oauth-client-provider.d.ts +10 -50
  90. package/dist/mcp/do-oauth-client-provider.js +290 -6
  91. package/dist/mcp/do-oauth-client-provider.js.map +1 -1
  92. package/dist/mcp/index.d.ts +82 -78
  93. package/dist/mcp/index.js +2045 -1085
  94. package/dist/mcp/index.js.map +1 -1
  95. package/dist/mcp/x402.d.ts +110 -22
  96. package/dist/mcp/x402.js +254 -3189
  97. package/dist/mcp/x402.js.map +1 -1
  98. package/dist/message-builder-BymO4N_D.js +386 -0
  99. package/dist/message-builder-BymO4N_D.js.map +1 -0
  100. package/dist/observability/index.d.ts +15 -45
  101. package/dist/observability/index.js +86 -10
  102. package/dist/observability/index.js.map +1 -1
  103. package/dist/react.d.ts +202 -75
  104. package/dist/react.js +478 -114
  105. package/dist/react.js.map +1 -1
  106. package/dist/retries-CAvxtG9d.d.ts +127 -0
  107. package/dist/retries.d.ts +22 -0
  108. package/dist/retries.js +229 -0
  109. package/dist/retries.js.map +1 -0
  110. package/dist/schedule.d.ts +91 -85
  111. package/dist/schedule.js +68 -33
  112. package/dist/schedule.js.map +1 -1
  113. package/dist/serializable.d.ts +115 -6
  114. package/dist/serializable.js +1 -1
  115. package/dist/skills/compile.d.ts +40 -0
  116. package/dist/skills/compile.js +65 -0
  117. package/dist/skills/compile.js.map +1 -0
  118. package/dist/skills/index.d.ts +244 -0
  119. package/dist/skills/index.js +1323 -0
  120. package/dist/skills/index.js.map +1 -0
  121. package/dist/sub-routing.d.ts +14 -0
  122. package/dist/sub-routing.js +177 -0
  123. package/dist/sub-routing.js.map +1 -0
  124. package/dist/tool-output-truncation-CNnnGZQ3.js +98 -0
  125. package/dist/tool-output-truncation-CNnnGZQ3.js.map +1 -0
  126. package/dist/types-6Zo2zfoO.d.ts +17 -0
  127. package/dist/types.d.ts +2 -0
  128. package/dist/types.js +19 -0
  129. package/dist/types.js.map +1 -0
  130. package/dist/utils-CGtGDSgA.d.ts +34 -0
  131. package/dist/utils.d.ts +6 -0
  132. package/dist/utils.js +51 -0
  133. package/dist/utils.js.map +1 -0
  134. package/dist/vite.d.ts +25 -0
  135. package/dist/vite.js +310 -0
  136. package/dist/vite.js.map +1 -0
  137. package/dist/wire-types-nflOzNuU.js +240 -0
  138. package/dist/wire-types-nflOzNuU.js.map +1 -0
  139. package/dist/workflow-types-Baz_PO5v.d.ts +280 -0
  140. package/dist/workflow-types.d.ts +52 -0
  141. package/dist/workflow-types.js +16 -0
  142. package/dist/workflow-types.js.map +1 -0
  143. package/dist/workflows.d.ts +198 -0
  144. package/dist/workflows.js +343 -0
  145. package/dist/workflows.js.map +1 -0
  146. package/docs/adding-to-existing-project.md +450 -0
  147. package/docs/agent-class.md +503 -0
  148. package/docs/agent-tools.md +552 -0
  149. package/docs/browse-the-web.md +430 -0
  150. package/docs/callable-methods.md +627 -0
  151. package/docs/chat-agents.md +1696 -0
  152. package/docs/chat-sdk.md +181 -0
  153. package/docs/client-sdk.md +520 -0
  154. package/docs/client-tools-continuation.md +177 -0
  155. package/docs/codemode.md +440 -0
  156. package/docs/configuration.md +795 -0
  157. package/docs/cross-domain-authentication.md +171 -0
  158. package/docs/durable-execution.md +537 -0
  159. package/docs/email.md +663 -0
  160. package/docs/get-current-agent.md +204 -0
  161. package/docs/getting-started.md +305 -0
  162. package/docs/http-websockets.md +668 -0
  163. package/docs/human-in-the-loop.md +661 -0
  164. package/docs/index.md +151 -0
  165. package/docs/long-running-agents.md +730 -0
  166. package/docs/mcp-client.md +683 -0
  167. package/docs/mcp-servers.md +548 -0
  168. package/docs/mcp-transports.md +308 -0
  169. package/docs/migration-to-ai-sdk-v5.md +96 -0
  170. package/docs/migration-to-ai-sdk-v6.md +163 -0
  171. package/docs/observability.md +261 -0
  172. package/docs/push-notifications.md +367 -0
  173. package/docs/queue.md +329 -0
  174. package/docs/readonly-connections.md +278 -0
  175. package/docs/resumable-streaming.md +127 -0
  176. package/docs/retries.md +444 -0
  177. package/docs/routing.md +749 -0
  178. package/docs/scheduling.md +898 -0
  179. package/docs/securing-mcp-servers.md +362 -0
  180. package/docs/server-driven-messages.md +477 -0
  181. package/docs/sessions.md +1024 -0
  182. package/docs/state.md +512 -0
  183. package/docs/sub-agents.md +389 -0
  184. package/docs/webhooks.md +604 -0
  185. package/docs/workflows.md +877 -0
  186. package/package.json +238 -56
  187. package/skills-module.d.ts +22 -0
  188. package/dist/_esm-LV5FJ3HK.js +0 -3922
  189. package/dist/_esm-LV5FJ3HK.js.map +0 -1
  190. package/dist/ccip-CMBYN64O.js +0 -15
  191. package/dist/ccip-CMBYN64O.js.map +0 -1
  192. package/dist/chunk-5Y6BEZDY.js +0 -276
  193. package/dist/chunk-5Y6BEZDY.js.map +0 -1
  194. package/dist/chunk-BER7KXUJ.js +0 -18
  195. package/dist/chunk-BER7KXUJ.js.map +0 -1
  196. package/dist/chunk-JJBFIGUC.js +0 -5202
  197. package/dist/chunk-JJBFIGUC.js.map +0 -1
  198. package/dist/chunk-PR4QN5HX.js +0 -43
  199. package/dist/chunk-PR4QN5HX.js.map +0 -1
  200. package/dist/chunk-QEPGNUG6.js +0 -650
  201. package/dist/chunk-QEPGNUG6.js.map +0 -1
  202. package/dist/chunk-QEVM4BVL.js +0 -116
  203. package/dist/chunk-QEVM4BVL.js.map +0 -1
  204. package/dist/chunk-RS5OCNEQ.js +0 -1323
  205. package/dist/chunk-RS5OCNEQ.js.map +0 -1
  206. package/dist/chunk-TYAY6AU6.js +0 -159
  207. package/dist/chunk-TYAY6AU6.js.map +0 -1
  208. package/dist/chunk-UJVEAURM.js +0 -150
  209. package/dist/chunk-UJVEAURM.js.map +0 -1
  210. package/dist/chunk-XFS5ERG3.js +0 -127
  211. package/dist/chunk-XFS5ERG3.js.map +0 -1
  212. package/dist/client-BohGLma8.d.ts +0 -5041
  213. package/dist/mcp/client.js.map +0 -1
  214. package/dist/secp256k1-M22GZP2U.js +0 -2193
  215. package/dist/secp256k1-M22GZP2U.js.map +0 -1
  216. package/dist/serializable.js.map +0 -1
  217. package/src/index.ts +0 -1987
package/README.md CHANGED
@@ -1,656 +1,548 @@
1
- ### 🧠 `agents` - A Framework for Digital Intelligence
1
+ # agents
2
2
 
3
3
  ![npm install agents](../../assets/npm-install-agents.svg)
4
4
 
5
- Welcome to a new chapter in software development, where AI agents persist, think, and act with purpose. The `agents` framework creates an environment where artificial intelligence can flourish - maintaining state, engaging in meaningful interactions, and evolving over time.
5
+ **Build software that thinks and does.**
6
6
 
7
- _This project is in active development. Join us in shaping the future of intelligent agents._
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
- #### The Nature of Agents
9
+ ```sh
10
+ npm create cloudflare@latest -- --template cloudflare/agents-starter
11
+ ```
10
12
 
11
- An AI agent transcends traditional software boundaries. It's an entity that:
13
+ Or add to an existing project:
12
14
 
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
15
+ ```sh
16
+ npm install agents
17
+ ```
17
18
 
18
- Built on Cloudflare's global network, this framework provides agents with a reliable, distributed foundation where they can operate continuously and effectively.
19
+ ---
20
+
21
+ ## Why Agents, Why Now
22
+
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.
24
+
25
+ ```
26
+ From request handlers → to autonomous entities
27
+ From stateless functions → to persistent intelligence
28
+
29
+ Traditional serverless: Request → Response → Gone
30
+ Agents: Thinking, remembering, acting — continuously
31
+ ```
19
32
 
20
- #### 💫 Core Principles
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.
21
34
 
22
- 1. **Stateful Existence**: Each agent maintains its own persistent reality
23
- 2. **Long-lived Presence**: Agents can run for extended periods, resting when idle
24
- 3. **Natural Communication**: Interact through HTTP, WebSockets, or direct calls
25
- 4. **Global Distribution**: Leverage Cloudflare's network for worldwide presence
26
- 5. **Resource Harmony**: Efficient hibernation and awakening as needed
35
+ Built on Cloudflare Durable Objects, agents run globally, close to your users, with persistent state that survives restarts.
27
36
 
28
37
  ---
29
38
 
30
- ### 🌱 Beginning the Journey
39
+ ## Quick Example
31
40
 
32
- Start with a complete environment:
41
+ A counter agent with real-time state sync and callable methods:
33
42
 
34
- ```sh
35
- # Create a new project
36
- npm create cloudflare@latest -- --template cloudflare/agents-starter
43
+ ```typescript
44
+ // server.ts
45
+ import { Agent, callable } from "agents";
37
46
 
38
- # Or enhance an existing one
39
- npm install agents
47
+ type State = { count: number };
48
+
49
+ export class CounterAgent extends Agent<Env, State> {
50
+ initialState: State = { count: 0 };
51
+
52
+ @callable()
53
+ increment() {
54
+ this.setState({ count: this.state.count + 1 });
55
+ return this.state.count;
56
+ }
57
+
58
+ @callable()
59
+ decrement() {
60
+ this.setState({ count: this.state.count - 1 });
61
+ return this.state.count;
62
+ }
63
+ }
40
64
  ```
41
65
 
42
- ### 📝 Your First Agent
66
+ ```tsx
67
+ // client.tsx
68
+ import { useAgent } from "agents/react";
69
+ import { useState } from "react";
43
70
 
44
- Create an agent that bridges thought and action:
71
+ function Counter() {
72
+ const [count, setCount] = useState(0);
45
73
 
46
- ```ts
47
- import { Agent } from "agents";
74
+ const agent = useAgent<State>({
75
+ agent: "counter-agent",
76
+ name: "my-counter",
77
+ onStateUpdate: (state) => setCount(state.count)
78
+ });
48
79
 
49
- export class IntelligentAgent extends Agent {
50
- async onRequest(request) {
51
- // Transform intention into response
52
- return new Response("Ready to assist.");
53
- }
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
+ );
54
87
  }
55
88
  ```
56
89
 
57
- ### 🎭 Patterns of Intelligence
90
+ State changes sync to all connected clients automatically. Call methods like they're local functions.
58
91
 
59
- Agents can manifest various forms of understanding:
92
+ ---
60
93
 
61
- ```ts
62
- import { Agent } from "agents";
63
- import { OpenAI } from "openai";
94
+ ## What You Can Build
64
95
 
65
- export class AIAgent extends Agent {
66
- async onRequest(request) {
67
- // Connect with AI capabilities
68
- const ai = new OpenAI({
69
- apiKey: this.env.OPENAI_API_KEY
70
- });
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 |
71
104
 
72
- // Process and understand
73
- const response = await ai.chat.completions.create({
74
- model: "gpt-4",
75
- messages: [{ role: "user", content: await request.text() }]
76
- });
105
+ ---
77
106
 
78
- return new Response(response.choices[0].message.content);
107
+ ## Features
108
+
109
+ ```
110
+ Core State sync · Routing · HTTP & WebSockets · @callable RPC · Sub-agents (facets)
111
+ Clients React hook · Vanilla JS · Real-time state sync
112
+ Channels WebSocket · HTTP · Email · (coming: SMS, Voice, Messengers)
113
+ Background Queue · Scheduling · Managed fibers · Workflows · Human-in-the-loop
114
+ AI Chat agents · Agent tools · Tool calling · MCP servers & clients
115
+ Platform Observability · Cross-domain auth · Resumable streams
116
+ ```
117
+
118
+ ### State Management
119
+
120
+ State persists across requests and syncs to all connected clients:
121
+
122
+ ```typescript
123
+ export class MyAgent extends Agent<Env, { items: string[] }> {
124
+ initialState = { items: [] };
125
+
126
+ @callable()
127
+ addItem(item: string) {
128
+ this.setState({ items: [...this.state.items, item] });
79
129
  }
80
130
 
81
- async processTask(task) {
82
- await this.understand(task);
83
- await this.act();
84
- await this.reflect();
131
+ onStateChanged(state: State, source: Connection | "server") {
132
+ // Called after state is persisted and broadcast
85
133
  }
86
134
  }
87
135
  ```
88
136
 
89
- ### 🏰 Creating Space
137
+ ### Callable Methods
90
138
 
91
- Define your agent's domain:
139
+ Expose methods to clients with the `@callable()` decorator:
92
140
 
93
- ```jsonc
94
- {
95
- "durable_objects": {
96
- "bindings": [
97
- {
98
- "name": "AIAgent",
99
- "class_name": "AIAgent"
100
- }
101
- ]
102
- },
103
- "migrations": [
104
- {
105
- "tag": "v1",
106
- // Mandatory for the Agent to store state
107
- "new_sqlite_classes": ["AIAgent"]
108
- }
109
- ]
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;
110
147
  }
111
148
  ```
112
149
 
113
- ### 🌐 Lifecycle
150
+ ```typescript
151
+ // Client
152
+ const result = await agent.stub.processOrder("order-123", items);
153
+ ```
114
154
 
115
- Bring your agent into being:
155
+ ### Scheduling
116
156
 
117
- ```ts
118
- // Create a new instance
119
- const id = env.AIAgent.newUniqueId();
120
- const agent = env.AIAgent.get(id);
157
+ Run tasks later, on intervals, or with cron expressions:
121
158
 
122
- // Initialize with purpose
123
- await agent.processTask({
124
- type: "analysis",
125
- context: "incoming_data",
126
- parameters: initialConfig
127
- });
159
+ ```typescript
160
+ // In 60 seconds
161
+ this.schedule(60, "sendReminder", { userId: "123" });
128
162
 
129
- // Or reconnect with an existing one
130
- const existingAgent = await getAgentByName(env.AIAgent, "data-analyzer");
131
- ```
163
+ // Every hour
164
+ this.scheduleEvery(3600, "syncData");
132
165
 
133
- ### 🔄 Paths of Communication
166
+ // Daily at 9am UTC
167
+ this.schedule("0 9 * * *", "dailyReport");
134
168
 
135
- #### HTTP Understanding
169
+ // At a specific date
170
+ this.schedule(new Date("2025-12-31"), "yearEndTask");
171
+ ```
136
172
 
137
- Process and respond to direct requests:
173
+ ### Background Tasks
138
174
 
139
- ```ts
140
- export class APIAgent extends Agent {
141
- async onRequest(request) {
142
- const data = await request.json();
175
+ Queue immediate background work:
143
176
 
144
- return Response.json({
145
- insight: await this.process(data),
146
- moment: Date.now()
147
- });
148
- }
149
- }
177
+ ```typescript
178
+ await this.queue("processUpload", { fileId: "abc" });
179
+ // Returns immediately, task runs in background
150
180
  ```
151
181
 
152
- #### Persistent Connections
182
+ ### Sub-agents
153
183
 
154
- Maintain ongoing dialogues through WebSocket:
184
+ Spawn child Durable Objects (facets) from a parent agent. Each child has
185
+ its own SQLite storage and runs in parallel, but is addressed under the
186
+ parent's URL:
187
+
188
+ ```typescript
189
+ export class Inbox extends Agent {
190
+ @callable()
191
+ async createChat() {
192
+ const id = crypto.randomUUID();
193
+ await this.subAgent(Chat, id);
194
+ return id;
195
+ }
155
196
 
156
- ```ts
157
- export class DialogueAgent extends Agent {
158
- async onConnect(connection) {
159
- await this.initiate(connection);
197
+ override async onBeforeSubAgent(_req, { className, name }) {
198
+ if (!this.hasSubAgent(className, name)) {
199
+ return new Response("Not found", { status: 404 });
200
+ }
160
201
  }
202
+ }
161
203
 
162
- async onMessage(connection, message) {
163
- const understanding = await this.comprehend(message);
164
- await this.respond(connection, understanding);
204
+ export class Chat extends Agent {
205
+ async writePreview(text: string) {
206
+ const inbox = await this.parentAgent(Inbox);
207
+ await inbox.savePreview(this.name, text);
165
208
  }
166
209
  }
167
210
  ```
168
211
 
169
- #### Client Communication
212
+ Client-side, connect to a child with `useAgent({ sub: [...] })`:
170
213
 
171
- For direct connection to your agent:
214
+ ```tsx
215
+ const inbox = useAgent({ agent: "Inbox", name: userId });
216
+ const chat = useAgent({
217
+ agent: "Inbox",
218
+ name: userId,
219
+ sub: [{ agent: "Chat", name: chatId }]
220
+ });
221
+ ```
172
222
 
173
- ```ts
174
- import { AgentClient } from "agents/client";
223
+ The routed URL becomes `/agents/inbox/{userId}/sub/chat/{chatId}`.
175
224
 
176
- const connection = new AgentClient({
177
- agent: "dialogue-agent",
178
- name: "insight-seeker"
179
- });
225
+ Child WebSocket clients can use the same URL shape. The parent remains the
226
+ public address, while child agents still receive `onConnect`, `onMessage`,
227
+ `onClose`, `broadcast()`, and `getConnections()` calls scoped to their own
228
+ clients. Parent broadcasts do not leak to child-targeted sockets, and child
229
+ connection tags, readonly state, and protocol-message settings are preserved
230
+ when a connection is resumed from hibernation.
180
231
 
181
- connection.addEventListener("message", (event) => {
182
- console.log("Received:", event.data);
183
- });
232
+ Nested sub-agent URLs are supported using repeated `/sub/{agent}/{name}`
233
+ segments, subject to the platform's current facet nesting limits.
184
234
 
185
- connection.send(
186
- JSON.stringify({
187
- type: "inquiry",
188
- content: "What patterns do you see?"
189
- })
190
- );
235
+ ### Agent Tools
236
+
237
+ Run chat-capable sub-agents as tools from a parent chat agent. Think agents and
238
+ `AIChatAgent` subclasses are supported. The child keeps its own messages, tools,
239
+ SQLite storage, and resumable stream, while the parent broadcasts
240
+ `agent-tool-event` frames so the UI can render the child timeline inline.
241
+
242
+ ```typescript
243
+ import { Think } from "@cloudflare/think";
244
+ import { agentTool } from "agents/agent-tools";
245
+ import { z } from "zod";
246
+
247
+ export class Researcher extends Think<Env> {
248
+ getSystemPrompt() {
249
+ return "Research the requested topic and end with a concise summary.";
250
+ }
251
+ }
252
+
253
+ export class Assistant extends Think<Env> {
254
+ getTools() {
255
+ return {
256
+ research: agentTool(Researcher, {
257
+ description: "Research one topic in depth.",
258
+ inputSchema: z.object({ query: z.string().min(3) })
259
+ })
260
+ };
261
+ }
262
+ }
191
263
  ```
192
264
 
193
- #### React Integration
265
+ For deterministic fan-out, call `this.runAgentTool(Researcher, { input })`
266
+ directly. Parent recovery reconciles stale child rows after restarts and marks
267
+ unrecoverable runs `interrupted` instead of hanging. In React, use
268
+ `useAgentToolEvents({ agent })` to render retained and replayed child timelines.
269
+ AIChatAgent children run headlessly, so browser client tools require a separate
270
+ bridge; server-side tools work normally. See the full
271
+ [Agent Tools guide](../../docs/agents/agent-tools.md).
194
272
 
195
- For harmonious integration with React:
273
+ ### WebSocket Connections
196
274
 
197
- ```tsx
198
- import { useAgent } from "agents/react";
275
+ Handle real-time communication:
199
276
 
200
- function AgentInterface() {
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
- });
277
+ ```typescript
278
+ async onConnect(connection: Connection) {
279
+ console.log(`Client ${connection.id} connected`);
280
+ }
210
281
 
211
- const inquire = () => {
212
- connection.send(
213
- JSON.stringify({
214
- type: "inquiry",
215
- content: "What insights have you gathered?"
216
- })
217
- );
218
- };
282
+ async onMessage(connection: Connection, message: unknown) {
283
+ // Handle incoming messages
284
+ connection.send(JSON.stringify({ received: true }));
285
+ }
219
286
 
220
- return (
221
- <div className="agent-interface">
222
- <button onClick={inquire}>Seek Understanding</button>
223
- </div>
224
- );
287
+ async onClose(connection: Connection) {
288
+ console.log(`Client ${connection.id} disconnected`);
225
289
  }
226
290
  ```
227
291
 
228
- ### 🌊 Flow of State
229
-
230
- Maintain and evolve your agent's understanding:
292
+ ### Email
231
293
 
232
- ```ts
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
- }
294
+ Agents can receive and respond to emails:
241
295
 
242
- onStateUpdate(state, source) {
243
- console.log("Understanding deepened:", {
244
- newState: state,
245
- origin: source
246
- });
247
- }
296
+ ```typescript
297
+ async onEmail(email: EmailMessage) {
298
+ const from = email.from;
299
+ const subject = email.headers.get("subject");
300
+ // Process incoming email
248
301
  }
249
302
  ```
250
303
 
251
- Connect to your agent's state from React:
304
+ ---
305
+
306
+ ## Client SDK
307
+
308
+ ### React
252
309
 
253
310
  ```tsx
254
- import { useState } from "react";
255
311
  import { useAgent } from "agents/react";
312
+ import { useState } from "react";
256
313
 
257
- function StateInterface() {
258
- const [state, setState] = useState({ counter: 0 });
314
+ function App() {
315
+ const [state, setState] = useState<MyState | null>(null);
259
316
 
260
- const agent = useAgent({
261
- agent: "thinking-agent",
317
+ const agent = useAgent<MyState>({
318
+ agent: "my-agent",
319
+ name: "instance-name",
262
320
  onStateUpdate: (newState) => setState(newState)
263
321
  });
264
322
 
265
- const increment = () => {
266
- agent.setState({ counter: state.counter + 1 });
267
- };
268
-
269
323
  return (
270
324
  <div>
271
- <div>Count: {state.counter}</div>
272
- <button onClick={increment}>Increment</button>
325
+ <pre>{JSON.stringify(state, null, 2)}</pre>
326
+ <button onClick={() => agent.stub.doSomething()}>Call Agent</button>
273
327
  </div>
274
328
  );
275
329
  }
276
330
  ```
277
331
 
278
- This creates a synchronized state that automatically updates across all connected clients.
279
-
280
- ### ⏳ Temporal Patterns
332
+ ### Vanilla JavaScript
281
333
 
282
- Schedule moments of action and reflection:
334
+ ```typescript
335
+ import { AgentClient } from "agents/client";
283
336
 
284
- ```ts
285
- export class TimeAwareAgent extends Agent {
286
- async initialize() {
287
- // Quick reflection
288
- this.schedule(10, "quickInsight", { focus: "patterns" });
337
+ const client = new AgentClient({
338
+ agent: "my-agent",
339
+ name: "instance-name",
340
+ onStateUpdate: (state) => console.log("State:", state)
341
+ });
289
342
 
290
- // Daily synthesis
291
- this.schedule("0 0 * * *", "dailySynthesis", {
292
- depth: "comprehensive"
293
- });
343
+ // Call methods
344
+ const result = await client.call("processData", [payload]);
294
345
 
295
- // Milestone review
296
- this.schedule(new Date("2024-12-31"), "yearlyAnalysis");
297
- }
346
+ // Or use the stub
347
+ const result = await client.stub.processData(payload);
348
+ ```
298
349
 
299
- async quickInsight(data) {
300
- await this.analyze(data.focus);
301
- }
350
+ ---
302
351
 
303
- async dailySynthesis(data) {
304
- await this.synthesize(data.depth);
305
- }
352
+ ## Workflows Integration
306
353
 
307
- async yearlyAnalysis() {
308
- await this.analyze();
309
- }
310
- }
311
- ```
354
+ For durable, multi-step tasks that survive failures and can pause for human approval, integrate with [Cloudflare Workflows](https://developers.cloudflare.com/workflows/):
312
355
 
313
- ### 💬 AI Dialogue
356
+ ```typescript
357
+ import { AgentWorkflow } from "agents";
314
358
 
315
- Create meaningful conversations with intelligence:
359
+ export class OrderWorkflow extends AgentWorkflow<OrderAgent, OrderParams> {
360
+ async run(event, step) {
361
+ // Step 1: Validate (retries automatically on failure)
362
+ const validated = await step.do("validate", async () => {
363
+ return validateOrder(event.payload);
364
+ });
316
365
 
317
- ```ts
318
- import { AIChatAgent } from "agents/ai-chat-agent";
319
- import { openai } from "@ai-sdk/openai";
320
- import { streamText, generateText, createDataStreamResponse } from "ai";
366
+ // Step 2: Wait for human approval
367
+ await this.reportProgress({ step: "approval", status: "pending" });
368
+ const approval = await this.waitForApproval(step, { timeout: "7 days" });
321
369
 
322
- export class DialogueAgent extends AIChatAgent {
323
- async onChatMessage(onFinish) {
324
- // Option 1: Streaming responses (recommended for real-time interaction)
325
- return createDataStreamResponse({
326
- execute: async (dataStream) => {
327
- const stream = streamText({
328
- model: openai("gpt-4o"),
329
- messages: this.messages,
330
- // Optional: onFinish is invoked by the AI SDK when generation completes.
331
- // Persistence is handled automatically by AIChatAgent after streaming completes.
332
- onFinish
333
- });
334
-
335
- stream.mergeIntoDataStream(dataStream);
336
- }
370
+ // Step 3: Process the approved order
371
+ await step.do("process", async () => {
372
+ return processOrder(validated, approval);
337
373
  });
338
-
339
- // Option 2: Non-streaming responses (simpler, but no real-time updates)
340
- // const result = await generateText({
341
- // model: openai("gpt-4o"),
342
- // messages: this.messages,
343
- // });
344
- //
345
- // // For non-streaming with metadata, use toUIMessage:
346
- // const message = result.toUIMessage({
347
- // metadata: {
348
- // model: 'gpt-4o',
349
- // totalTokens: result.usage?.totalTokens,
350
- // }
351
- // });
352
- //
353
- // return new Response(JSON.stringify(message), {
354
- // headers: { 'Content-Type': 'application/json' }
355
- // });
356
374
  }
357
375
  }
358
376
  ```
359
377
 
360
- #### Metadata Support
378
+ Workflows provide:
361
379
 
362
- The AI SDK provides native support for message metadata through the `messageMetadata` callback. This allows you to attach custom information to messages at the message level.
380
+ - **Durable execution** steps retry automatically, state persists across failures
381
+ - **Human-in-the-loop** — pause for approval with `waitForApproval()`
382
+ - **Long-running tasks** — run for days or weeks
383
+ - **Progress tracking** — report status back to the agent
384
+
385
+ See [Workflows](../../docs/agents/workflows.md) and [Human in the Loop](../../docs/agents/human-in-the-loop.md).
386
+
387
+ ---
363
388
 
364
- ##### AIChatAgent Integration
389
+ ## AI Chat Integration
365
390
 
366
- In the context of `AIChatAgent`, you can use metadata like this:
391
+ For AI-powered chat experiences with persistent conversations, streaming responses, and tool support, see [`@cloudflare/ai-chat`](../ai-chat/README.md).
367
392
 
368
393
  ```typescript
369
- import { AIChatAgent } from "agents/ai-chat-agent";
370
- import { streamText } from "ai";
371
- import { openai } from "@ai-sdk/openai";
394
+ import { AIChatAgent } from "@cloudflare/ai-chat";
372
395
 
373
- export class MyAgent extends AIChatAgent<Env> {
396
+ export class ChatAgent extends AIChatAgent<Env> {
374
397
  async onChatMessage(onFinish) {
375
- const startTime = Date.now();
376
-
377
- const result = streamText({
398
+ return streamText({
378
399
  model: openai("gpt-4o"),
379
400
  messages: this.messages,
401
+ tools: this.tools,
380
402
  onFinish
381
403
  });
382
-
383
- return result.toUIMessageStreamResponse({
384
- messageMetadata: ({ part }) => {
385
- if (part.type === "start") {
386
- return {
387
- model: "gpt-4o",
388
- createdAt: Date.now(),
389
- messageCount: this.messages.length
390
- };
391
- }
392
- if (part.type === "finish") {
393
- return {
394
- responseTime: Date.now() - startTime,
395
- totalTokens: part.totalUsage?.totalTokens
396
- };
397
- }
398
- }
399
- });
400
404
  }
401
405
  }
402
406
  ```
403
407
 
404
- ##### Accessing Metadata on the Client
405
-
406
- Access metadata through the `message.metadata` property:
407
-
408
- ```typescript
409
- 'use client';
410
-
411
- import { useChat } from '@ai-sdk/react';
412
- import { DefaultChatTransport } from 'ai';
413
- import type { MyUIMessage } from '@/types';
414
-
415
- export default function Chat() {
416
- const { messages } = useChat<MyUIMessage>({
417
- transport: new DefaultChatTransport({
418
- api: '/api/chat',
419
- }),
420
- });
421
-
422
- return (
423
- <div>
424
- {messages.map(message => (
425
- <div key={message.id}>
426
- <div>
427
- {message.role === 'user' ? 'User: ' : 'AI: '}
428
- {message.metadata?.createdAt && (
429
- <span className="text-sm text-gray-500">
430
- {new Date(message.metadata.createdAt).toLocaleTimeString()}
431
- </span>
432
- )}
433
- </div>
434
- {/* Render message content */}
435
- {message.parts.map((part, index) =>
436
- part.type === 'text' ? <div key={index}>{part.text}</div> : null,
437
- )}
438
- {/* Display additional metadata */}
439
- {message.metadata?.totalTokens && (
440
- <div className="text-xs text-gray-400">
441
- {message.metadata.totalTokens} tokens
442
- </div>
443
- )}
444
- </div>
445
- ))}
446
- </div>
447
- );
448
- }
449
- ```
450
-
451
- For more details, see the [AI SDK Message Metadata documentation](https://ai-sdk.dev/docs/ai-sdk-ui/message-metadata).
452
-
453
- #### Creating the Interface
454
-
455
- Connect with your agent through a React interface:
456
-
457
408
  ```tsx
458
- import { useAgent } from "agents/react";
459
- import { useAgentChat } from "agents/ai-react";
409
+ // Client
410
+ import { useAgentChat } from "@cloudflare/ai-chat/react";
460
411
 
461
- function ChatInterface() {
462
- // Connect to the agent
463
- const agent = useAgent({
464
- agent: "dialogue-agent"
465
- });
466
-
467
- // Set up the chat interaction
468
- const { messages, input, handleInputChange, handleSubmit, clearHistory } =
469
- useAgentChat({
470
- agent,
471
- maxSteps: 5
472
- });
473
-
474
- return (
475
- <div className="chat-interface">
476
- {/* Message History */}
477
- <div className="message-flow">
478
- {messages.map((message) => (
479
- <div key={message.id} className="message">
480
- <div className="role">{message.role}</div>
481
- <div className="content">
482
- {message.parts.map((part, i) => {
483
- if (part.type === "text")
484
- return <span key={i}>{part.text}</span>;
485
- // Render other part types (e.g., files, tool calls) as desired
486
- return null;
487
- })}
488
- </div>
489
- </div>
490
- ))}
491
- </div>
492
-
493
- {/* Input Area */}
494
- <form onSubmit={handleSubmit} className="input-area">
495
- <input
496
- value={input}
497
- onChange={handleInputChange}
498
- placeholder="Type your message..."
499
- className="message-input"
500
- />
501
- </form>
502
-
503
- <button onClick={clearHistory} className="clear-button">
504
- Clear Chat
505
- </button>
506
- </div>
507
- );
508
- }
412
+ const { messages, input, handleSubmit } = useAgentChat({
413
+ agent: useAgent({ agent: "chat-agent" })
414
+ });
509
415
  ```
510
416
 
511
- This creates:
417
+ Features:
512
418
 
513
- - Real-time message streaming
514
- - Simple message history
515
- - Intuitive input handling
516
- - Easy conversation reset
419
+ - Automatic message persistence
420
+ - Resumable streaming (survives disconnections)
421
+ - Server and client-side tool execution
422
+ - Human-in-the-loop approval for sensitive tools
517
423
 
518
- ### 🔗 MCP (Model Context Protocol) Integration
424
+ ---
519
425
 
520
- Agents can seamlessly integrate with the Model Context Protocol, allowing them to act as both MCP servers (providing tools to AI assistants) and MCP clients (using tools from other services).
426
+ ## MCP (Model Context Protocol)
521
427
 
522
- #### Creating an MCP Server
428
+ Agents integrate with MCP to act as servers (providing tools to AI assistants) or clients (using tools from other services).
429
+
430
+ ### Creating an MCP Server
523
431
 
524
432
  ```typescript
525
433
  import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
526
434
  import { McpAgent } from "agents/mcp";
527
- import { z } from "zod";
528
-
529
- type Env = {
530
- MyMCP: DurableObjectNamespace<MyMCP>;
531
- };
532
-
533
- type State = { counter: number };
534
435
 
535
436
  export class MyMCP extends McpAgent<Env, State, {}> {
536
- server = new McpServer({
537
- name: "Demo",
538
- version: "1.0.0"
539
- });
540
-
541
- initialState: State = {
542
- counter: 1
543
- };
437
+ server = new McpServer({ name: "my-tools", version: "1.0.0" });
544
438
 
545
439
  async init() {
546
- this.server.resource("counter", "mcp://resource/counter", (uri) => {
547
- return {
548
- contents: [{ text: String(this.state.counter), uri: uri.href }]
549
- };
550
- });
551
-
552
- this.server.tool(
553
- "add",
554
- "Add to the counter, stored in the MCP",
555
- { a: z.number() },
556
- async ({ a }) => {
557
- this.setState({ ...this.state, counter: this.state.counter + a });
558
-
559
- return {
560
- content: [
561
- {
562
- text: String(`Added ${a}, total is now ${this.state.counter}`),
563
- type: "text"
564
- }
565
- ]
566
- };
440
+ this.server.registerTool(
441
+ "lookup",
442
+ { description: "Look up data", inputSchema: { query: z.string() } },
443
+ async ({ query }) => {
444
+ const result = await this.search(query);
445
+ return { content: [{ type: "text", text: result }] };
567
446
  }
568
447
  );
569
448
  }
570
-
571
- onStateUpdate(state: State) {
572
- console.log({ stateUpdate: state });
573
- }
574
449
  }
575
450
 
576
- // HTTP Streamable transport (recommended)
577
- export default MyMCP.serve("/mcp", {
578
- binding: "MyMCP"
579
- });
580
-
581
- // Or SSE transport for legacy compatibility
582
- // export default MyMCP.serveSSE("/mcp", { binding: "MyMCP" });
451
+ export default MyMCP.serve("/mcp", { binding: "MyMCP" });
583
452
  ```
584
453
 
585
- #### Using MCP Tools
454
+ ### Using MCP Tools
586
455
 
587
456
  ```typescript
588
- import { MCPClientManager } from "agents/mcp";
589
-
590
- const client = new MCPClientManager("my-app", "1.0.0");
457
+ // Connect to external MCP servers
458
+ await this.addMcpServer(
459
+ "weather-service",
460
+ "https://weather-mcp.example.com/mcp",
461
+ {
462
+ transport: { type: "streamable-http" }
463
+ }
464
+ );
591
465
 
592
- // Connect to an MCP server
593
- await client.connect("https://weather-service.com/mcp", {
594
- transport: { type: "streamable-http" }
466
+ // Use with AI SDK
467
+ const result = await generateText({
468
+ model: openai("gpt-4o"),
469
+ tools: this.mcp.getTools(),
470
+ prompt: "What's the weather in Tokyo?"
595
471
  });
472
+ ```
596
473
 
597
- // Use tools from the server
598
- const weather = await client.callTool({
599
- serverId: "weather-service",
600
- name: "getWeather",
601
- arguments: { location: "San Francisco" }
602
- });
474
+ ---
475
+
476
+ ## Configuration
477
+
478
+ Add your agent to `wrangler.jsonc`:
479
+
480
+ ```jsonc
481
+ {
482
+ "durable_objects": {
483
+ "bindings": [{ "name": "MyAgent", "class_name": "MyAgent" }]
484
+ },
485
+ "migrations": [{ "tag": "v1", "new_sqlite_classes": ["MyAgent"] }]
486
+ }
603
487
  ```
604
488
 
605
- #### AI SDK Integration
489
+ Route requests to your agent:
606
490
 
607
491
  ```typescript
608
- import { generateText } from "ai";
492
+ import { routeAgentRequest } from "agents";
609
493
 
610
- // Convert MCP tools for AI use
611
- const result = await generateText({
612
- model: openai("gpt-4"),
613
- tools: client.getAITools(),
614
- prompt: "What's the weather in Tokyo?"
615
- });
494
+ export default {
495
+ async fetch(request: Request, env: Env) {
496
+ return (
497
+ (await routeAgentRequest(request, env)) ??
498
+ new Response("Not found", { status: 404 })
499
+ );
500
+ }
501
+ };
616
502
  ```
617
503
 
618
- **Transport Options:**
504
+ ---
505
+
506
+ ## Coming Soon
619
507
 
620
- - **Auto**: Automatically determine the correct transport
621
- - **HTTP Streamable**: Best performance, batch requests, session management
622
- - **SSE**: Simple setup, legacy compatibility
508
+ - **Browse the Web** Headless browser for web scraping and automation
509
+ - **Cloudflare Sandboxes** Isolated environments for code execution
510
+ - **SMS, Voice, Messengers** — Multi-channel communication
623
511
 
624
- ### 💬 The Path Forward
512
+ ---
625
513
 
626
- We're developing new dimensions of agent capability:
514
+ ## Learn More
627
515
 
628
- #### Enhanced Understanding
516
+ The published package includes the complete documentation tree at
517
+ `docs/index.md`.
629
518
 
630
- - **WebRTC Perception**: Audio and video communication channels
631
- - **Email Discourse**: Automated email interaction and response
632
- - **Deep Memory**: Long-term context and relationship understanding
519
+ [Getting Started](../../docs/agents/getting-started.md) ·
520
+ [State Management](../../docs/agents/state.md) ·
521
+ [Scheduling](../../docs/agents/scheduling.md) ·
522
+ [Callable Methods](../../docs/agents/callable-methods.md) ·
523
+ [MCP Integration](../../docs/agents/mcp-client.md) ·
524
+ [Full Documentation](../../docs/agents/index.md)
633
525
 
634
- #### Development Insights
526
+ ---
635
527
 
636
- - **Evaluation Framework**: Understanding agent effectiveness
637
- - **Clear Sight**: Deep visibility into agent processes
638
- - **Private Realms**: Complete self-hosting guide
528
+ ## Contributing
639
529
 
640
- These capabilities will expand your agents' potential while maintaining their reliability and purpose.
530
+ Contributions are welcome, especially when:
641
531
 
642
- Welcome to the future of intelligent agents. Create something meaningful. 🌟
532
+ - You've opened an issue as an RFC to discuss your proposal
533
+ - The contribution isn't "AI slop" — LLMs are tools, but vibe-coded PRs won't meet the quality bar
534
+ - You're open to feedback to ensure changes fit the SDK's goals
643
535
 
644
- ### Contributing
536
+ Small fixes, type bugs, and documentation improvements can be raised directly as PRs.
645
537
 
646
- Contributions are welcome, but are especially welcome when:
538
+ ---
647
539
 
648
- - You have opened an issue as a Request for Comment (RFC) to discuss your proposal, show your thinking, and iterate together.
649
- - 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.
650
- - 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.
540
+ ## License
651
541
 
652
- Small fixes, type bugs, and documentation improvements can be raised directly as PRs.
542
+ MIT licensed. See the [LICENSE](../../LICENSE) file for details.
653
543
 
654
- ### License
544
+ ---
655
545
 
656
- MIT licensed. See the LICENSE file at the root of this repository for details.
546
+ <p align="center">
547
+ <i>Build something that thinks. Ship something that does.</i>
548
+ </p>