Skip to content

Commit ece9057

Browse files
Agents docs: Workers AI first, fix bugs, rewrite key pages (#28501)
* Migrate Agents docs to Workers AI examples Replace OpenAI-specific examples with Workers AI / AI SDK usage across Agents docs. Examples now use an Env AI binding, createWorkersAI / workers-ai-provider, and streamText/generateText from the ai SDK instead of direct OpenAI clients or API keys. Updated WebSocket/SSE streaming, long-running model examples, and SQL/state persistence to consume this.env.AI.run streams/responses. Updated Wrangler/config mentions to use the ai binding and clarified AI Gateway/model routing guidance. Files changed: browse-the-web.mdx, http-sse.mdx, store-and-sync-state.mdx, using-ai-models.mdx, index.mdx. * formatting * docs: clarify Agent class and add LLM patterns Revise agent-class.mdx to clarify the Agent/Server/DurableObject layering, tighten wording, fix small code snippets (ws.send, storage access, Response usage), standardize PartyKit/Server references, and add a new Layer 3 section describing AIChatAgent. Replace calling-llms.mdx with a complete rewrite that focuses on using LLMs inside stateful Agents: explains state-as-context, surviving disconnections, autonomous model calls, multi-model pipelines, and caching; adds multiple TypeScript examples and Next Steps link cards, and updates the page tag to "AI". * docs: fix MCP docs bugs and inconsistencies - authorization.mdx: remove orphaned <diagram> tag, fix broken anchor (#3 -> #2), fix "oAuth" -> "OAuth", add pcx_content_type, rewrite permission code to use correct MCP tool handler signature, replace MyMCPServer.Router with .serve(), remove unused DirectoryListing import - mcp-client-api.mdx: fix this.env bug in createMcpOAuthProvider (capture env before returning object literal), fix import path for error utils, remove dead code after return, replace OpenAI example with Workers AI - mcp-handler-api.mdx: fix misleading intro (stateless vs stateful, not SSE), fix storage.kv -> storage.get/put, fix {} as ExecutionContext, wrap global McpServer in factory function, fix "accessable" typo - remote-mcp-server.mdx: fix MyMCP.Router -> .serve(), fix Auth0/WorkOS anchors pointing to #stytch, fix https://localhost -> http://localhost, fix broken MCP client link - securing-mcp-server.mdx: fix apiHandlers -> apiRoute + apiHandler - test-remote-mcp-server.mdx: fix https -> http localhost, fix "lets you to test" typo, remove outdated claim about Claude Desktop - tools.mdx: add missing tags, add .js extension to import, remove unused Render import, fix stale repo link - governance.mdx: add pcx_content_type, remove empty import - index.mdx: fix http -> https links for Claude and Cursor - mcp-servers-for-cloudflare.mdx: fix "streamble-http" typo, remove unused Render import, fix link to source code -> docs - transport.mdx: remove unused Render/TabItem/Tabs imports - oauth-mcp-client.mdx: fix extends Agent -> Agent<Env> (5 instances) - connect-mcp-client.mdx: fix extends Agent -> Agent<Env> (3 instances) Co-authored-by: Cursor <cursoragent@cursor.com> * docs: rewrite MCP tools page, fix handler and authorization docs tools.mdx: Full rewrite from 36-line stub to comprehensive reference. Covers tool definitions, results, error handling, descriptions best practices, Zod input validation, and usage with both createMcpHandler and McpAgent. All examples use the factory function pattern. mcp-handler-api.mdx: Add missing State type definition in stateful example, fix onMcpRequest -> onRequest in Worker handler, remove unused Render import. authorization.mdx: Rewrite bottom half to show auth context usage for both McpAgent (this.props) and createMcpHandler (getMcpAuthContext), with proper type definitions. Clarify the two permission approaches (check inside handler vs conditional registration) and when to use each. Co-authored-by: Cursor <cursoragent@cursor.com> --------- Co-authored-by: Cursor <cursoragent@cursor.com>
1 parent 93e9135 commit ece9057

28 files changed

Lines changed: 970 additions & 599 deletions

src/content/docs/agents/api-reference/agents-api.mdx

Lines changed: 29 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -53,16 +53,16 @@ flowchart TD
5353
E --> F["onClose"]
5454
```
5555

56-
| Method | When it runs |
57-
| --------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
56+
| Method | When it runs |
57+
| --------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
5858
| `onStart(props?)` | When the instance starts, or wakes from hibernation. Receives optional [initialization props](/agents/api-reference/routing/#props) passed via `getAgentByName` or `routeAgentRequest`. |
59-
| `onRequest(request)` | For each HTTP request to the instance |
60-
| `onConnect(connection, ctx)` | When a WebSocket connection is established |
61-
| `onMessage(connection, message)` | For each WebSocket message received |
62-
| `onError(connection, error)` | When a WebSocket error occurs |
63-
| `onClose(connection, code, reason, wasClean)` | When a WebSocket connection closes |
64-
| `onEmail(email)` | When an email is routed to the instance |
65-
| `onStateChanged(state, source)` | When state changes (from server or client) |
59+
| `onRequest(request)` | For each HTTP request to the instance |
60+
| `onConnect(connection, ctx)` | When a WebSocket connection is established |
61+
| `onMessage(connection, message)` | For each WebSocket message received |
62+
| `onError(connection, error)` | When a WebSocket error occurs |
63+
| `onClose(connection, code, reason, wasClean)` | When a WebSocket connection closes |
64+
| `onEmail(email)` | When an email is routed to the instance |
65+
| `onStateChanged(state, source)` | When state changes (from server or client) |
6666

6767
## Core properties
6868

@@ -75,21 +75,21 @@ flowchart TD
7575

7676
## Server-side API reference
7777

78-
| Feature | Methods | Documentation |
79-
| -------------------- | --------------------------------------------------------------------- | ------------------------------------------------------------------- |
80-
| **State** | `setState()`, `onStateChanged()`, `initialState` | [Store and sync state](/agents/api-reference/store-and-sync-state/) |
81-
| **Callable methods** | `@callable()` decorator | [Callable methods](/agents/api-reference/callable-methods/) |
82-
| **Scheduling** | `schedule()`, `scheduleEvery()`, `getSchedules()`, `cancelSchedule()` | [Schedule tasks](/agents/api-reference/schedule-tasks/) |
83-
| **Queue** | `queue()`, `dequeue()`, `dequeueAll()`, `getQueue()` | [Queue tasks](/agents/api-reference/queue-tasks/) |
84-
| **WebSockets** | `onConnect()`, `onMessage()`, `onClose()`, `broadcast()` | [WebSockets](/agents/api-reference/websockets/) |
85-
| **HTTP/SSE** | `onRequest()` | [HTTP and SSE](/agents/api-reference/http-sse/) |
86-
| **Email** | `onEmail()`, `replyToEmail()` | [Email routing](/agents/api-reference/email/) |
87-
| **Workflows** | `runWorkflow()`, `waitForApproval()` | [Run Workflows](/agents/api-reference/run-workflows/) |
88-
| **MCP Client** | `addMcpServer()`, `removeMcpServer()`, `getMcpServers()` | [MCP Client API](/agents/api-reference/mcp-client-api/ ) |
89-
| **AI Models** | Workers AI, OpenAI, Anthropic bindings | [Using AI models](/agents/api-reference/using-ai-models/) |
90-
| **Protocol messages** | `shouldSendProtocolMessages()`, `isConnectionProtocolEnabled()` | [Protocol messages](/agents/api-reference/protocol-messages/) |
91-
| **Context** | `getCurrentAgent()` | [getCurrentAgent()](/agents/api-reference/get-current-agent/) |
92-
| **Observability** | `observability.emit()` | [Observability](/agents/api-reference/observability/) |
78+
| Feature | Methods | Documentation |
79+
| --------------------- | --------------------------------------------------------------------- | ------------------------------------------------------------------- |
80+
| **State** | `setState()`, `onStateChanged()`, `initialState` | [Store and sync state](/agents/api-reference/store-and-sync-state/) |
81+
| **Callable methods** | `@callable()` decorator | [Callable methods](/agents/api-reference/callable-methods/) |
82+
| **Scheduling** | `schedule()`, `scheduleEvery()`, `getSchedules()`, `cancelSchedule()` | [Schedule tasks](/agents/api-reference/schedule-tasks/) |
83+
| **Queue** | `queue()`, `dequeue()`, `dequeueAll()`, `getQueue()` | [Queue tasks](/agents/api-reference/queue-tasks/) |
84+
| **WebSockets** | `onConnect()`, `onMessage()`, `onClose()`, `broadcast()` | [WebSockets](/agents/api-reference/websockets/) |
85+
| **HTTP/SSE** | `onRequest()` | [HTTP and SSE](/agents/api-reference/http-sse/) |
86+
| **Email** | `onEmail()`, `replyToEmail()` | [Email routing](/agents/api-reference/email/) |
87+
| **Workflows** | `runWorkflow()`, `waitForApproval()` | [Run Workflows](/agents/api-reference/run-workflows/) |
88+
| **MCP Client** | `addMcpServer()`, `removeMcpServer()`, `getMcpServers()` | [MCP Client API](/agents/api-reference/mcp-client-api/) |
89+
| **AI Models** | Workers AI, OpenAI, Anthropic bindings | [Using AI models](/agents/api-reference/using-ai-models/) |
90+
| **Protocol messages** | `shouldSendProtocolMessages()`, `isConnectionProtocolEnabled()` | [Protocol messages](/agents/api-reference/protocol-messages/) |
91+
| **Context** | `getCurrentAgent()` | [getCurrentAgent()](/agents/api-reference/get-current-agent/) |
92+
| **Observability** | `observability.emit()` | [Observability](/agents/api-reference/observability/) |
9393

9494
## SQL API
9595

@@ -110,12 +110,12 @@ For state that needs to sync with clients, use the [State API](/agents/api-refer
110110

111111
## Client-side API reference
112112

113-
| Feature | Methods | Documentation |
114-
| -------------------- | ---------------- | ----------------------------------------------- |
115-
| **WebSocket client** | `AgentClient` | [Client SDK](/agents/api-reference/client-sdk/) |
113+
| Feature | Methods | Documentation |
114+
| -------------------- | ---------------- | ----------------------------------------------------------------------------- |
115+
| **WebSocket client** | `AgentClient` | [Client SDK](/agents/api-reference/client-sdk/) |
116116
| **HTTP client** | `agentFetch()` | [Client SDK](/agents/api-reference/client-sdk/#http-requests-with-agentfetch) |
117-
| **React hook** | `useAgent()` | [Client SDK](/agents/api-reference/client-sdk/#react) |
118-
| **Chat hook** | `useAgentChat()` | [Client SDK](/agents/api-reference/client-sdk/) |
117+
| **React hook** | `useAgent()` | [Client SDK](/agents/api-reference/client-sdk/#react) |
118+
| **Chat hook** | `useAgentChat()` | [Client SDK](/agents/api-reference/client-sdk/) |
119119

120120
### Quick example
121121

src/content/docs/agents/api-reference/browse-the-web.mdx

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -20,16 +20,17 @@ Agents can browse the web using the [Browser Rendering](/browser-rendering/) API
2020

2121
The [Browser Rendering](/browser-rendering/) allows you to spin up headless browser instances, render web pages, and interact with websites through your Agent.
2222

23-
You can define a method that uses Puppeteer to pull the content of a web page, parse the DOM, and extract relevant information by calling the OpenAI model:
23+
You can define a method that uses Puppeteer to pull the content of a web page, parse the DOM, and extract relevant information by calling a model via [Workers AI](/workers-ai/):
2424

2525
<TypeScriptExample>
2626

2727
```ts
2828
interface Env {
2929
BROWSER: Fetcher;
30+
AI: Ai;
3031
}
3132

32-
export class MyAgent extends Agent {
33+
export class MyAgent extends Agent<Env> {
3334
async browse(browserInstance: Fetcher, urls: string[]) {
3435
let responses = [];
3536
for (const url of urls) {
@@ -42,21 +43,14 @@ export class MyAgent extends Agent {
4243
"body",
4344
(element) => element.innerHTML,
4445
);
45-
const client = new OpenAI({
46-
apiKey: this.env.OPENAI_API_KEY,
47-
});
4846

49-
let resp = await client.chat.completions.create({
50-
model: this.env.MODEL,
47+
let resp = await this.env.AI.run("@cf/zai-org/glm-4.7-flash", {
5148
messages: [
5249
{
5350
role: "user",
5451
content: `Return a JSON object with the product names, prices and URLs with the following format: { "name": "Product Name", "price": "Price", "url": "URL" } from the website content below. <content>${bodyContent}</content>`,
5552
},
5653
],
57-
response_format: {
58-
type: "json_object",
59-
},
6054
});
6155

6256
responses.push(resp);
@@ -79,6 +73,9 @@ You'll also need to add install the `@cloudflare/puppeteer` package and add the
7973
```jsonc
8074
{
8175
// ...
76+
"ai": {
77+
"binding": "AI",
78+
},
8279
"browser": {
8380
"binding": "MYBROWSER",
8481
},

src/content/docs/agents/api-reference/chat-agents.mdx

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -675,11 +675,11 @@ export class ChatAgent extends AIChatAgent {
675675
676676
### Three patterns
677677
678-
| Pattern | How | Persisted? | Use case |
679-
| --- | --- | --- | --- |
680-
| **Reconciliation** | Same `type` + `id` → updates in-place | Yes | Progressive state (searching → found) |
681-
| **Append** | No `id`, or different `id` → appends | Yes | Log entries, multiple citations |
682-
| **Transient** | `transient: true` → not added to `message.parts` | No | Ephemeral status (thinking indicator) |
678+
| Pattern | How | Persisted? | Use case |
679+
| ------------------ | ------------------------------------------------ | ---------- | ------------------------------------- |
680+
| **Reconciliation** | Same `type` + `id` → updates in-place | Yes | Progressive state (searching → found) |
681+
| **Append** | No `id`, or different `id` → appends | Yes | Log entries, multiple citations |
682+
| **Transient** | `transient: true` → not added to `message.parts` | No | Ephemeral status (thinking indicator) |
683683
684684
Transient parts are broadcast to connected clients in real time but excluded from SQLite persistence and `message.parts`. Use the `onData` callback to consume them.
685685

src/content/docs/agents/api-reference/email.mdx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -316,9 +316,9 @@ When your agent sends emails and expects replies, use secure reply routing to pr
316316

317317
```jsonc
318318
{
319-
"vars": {
320-
"EMAIL_SECRET": "change-me-in-production",
321-
},
319+
"vars": {
320+
"EMAIL_SECRET": "change-me-in-production",
321+
},
322322
}
323323
```
324324

src/content/docs/agents/api-reference/http-sse.mdx

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -115,18 +115,20 @@ The [AI SDK](https://sdk.vercel.ai/) provides built-in SSE streaming:
115115
```ts
116116
import { Agent } from "agents";
117117
import { streamText } from "ai";
118-
import { createOpenAI } from "@ai-sdk/openai";
118+
import { createWorkersAI } from "workers-ai-provider";
119119

120-
export class ChatAgent extends Agent {
120+
interface Env {
121+
AI: Ai;
122+
}
123+
124+
export class ChatAgent extends Agent<Env> {
121125
async onRequest(request: Request): Promise<Response> {
122126
const { prompt } = await request.json<{ prompt: string }>();
123127

124-
const openai = createOpenAI({
125-
apiKey: this.env.OPENAI_API_KEY,
126-
});
128+
const workersai = createWorkersAI({ binding: this.env.AI });
127129

128130
const result = streamText({
129-
model: openai("gpt-4o"),
131+
model: workersai("@cf/zai-org/glm-4.7-flash"),
130132
prompt: prompt,
131133
});
132134

src/content/docs/agents/api-reference/mcp-agent-api.mdx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ You can use the APIs below in order to do so.
5555
| `state` | Current state object (persisted) |
5656
| `initialState` | Default state when instance starts |
5757
| `setState(state)` | Update and persist state |
58-
| `onStateChanged(state)` | Called when state changes |
58+
| `onStateChanged(state)` | Called when state changes |
5959
| `sql` | Execute SQL queries on embedded database |
6060
| `server` | The `McpServer` instance for registering tools |
6161
| `props` | User identity and tokens from OAuth authentication |

src/content/docs/agents/api-reference/mcp-client-api.mdx

Lines changed: 13 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -161,14 +161,8 @@ class MyAgent extends Agent {
161161
);
162162

163163
if (result.state === "authenticating") {
164-
// Option 1: Redirect the user
164+
// Redirect the user to the OAuth authorization page
165165
return Response.redirect(result.authUrl);
166-
167-
// Option 2: Return the URL for client-side redirect
168-
return Response.json({
169-
status: "needs_auth",
170-
authUrl: result.authUrl,
171-
});
172166
}
173167

174168
return Response.json({ status: "connected", id: result.id });
@@ -345,14 +339,15 @@ To use MCP tools with the Vercel AI SDK, use `this.mcp.getAITools()` which conve
345339

346340
```ts
347341
import { generateText } from "ai";
348-
import { openai } from "@ai-sdk/openai";
342+
import { createWorkersAI } from "workers-ai-provider";
349343

350-
export class MyAgent extends Agent {
344+
export class MyAgent extends Agent<Env> {
351345
async onRequest(request: Request) {
346+
const workersai = createWorkersAI({ binding: this.env.AI });
352347
const response = await generateText({
353-
model: openai("gpt-4"),
348+
model: workersai("@cf/zai-org/glm-4.7-flash"),
354349
prompt: "What's the weather in San Francisco?",
355-
tools: this.mcp.getAITools(), // Converts MCP tools to AI SDK format
350+
tools: this.mcp.getAITools(),
356351
});
357352

358353
return new Response(response.text);
@@ -633,26 +628,26 @@ The override is used for both new connections (`addMcpServer`) and restored conn
633628
import { Agent } from "agents";
634629
import type { AgentMcpOAuthProvider } from "agents";
635630

636-
export class MyAgent extends Agent {
631+
export class MyAgent extends Agent<Env> {
637632
createMcpOAuthProvider(callbackUrl: string): AgentMcpOAuthProvider {
633+
const env = this.env;
638634
return {
639635
get redirectUrl() {
640636
return callbackUrl;
641637
},
642638
get clientMetadata() {
643639
return {
644-
client_id: this.env.MCP_CLIENT_ID,
645-
client_secret: this.env.MCP_CLIENT_SECRET,
640+
client_id: env.MCP_CLIENT_ID,
641+
client_secret: env.MCP_CLIENT_SECRET,
646642
redirect_uris: [callbackUrl],
647643
};
648644
},
649645
clientInformation() {
650646
return {
651-
client_id: this.env.MCP_CLIENT_ID,
652-
client_secret: this.env.MCP_CLIENT_SECRET,
647+
client_id: env.MCP_CLIENT_ID,
648+
client_secret: env.MCP_CLIENT_SECRET,
653649
};
654650
},
655-
// ... implement other AgentMcpOAuthProvider methods
656651
};
657652
}
658653
}
@@ -831,7 +826,7 @@ Use error detection utilities to handle connection errors:
831826
<TypeScriptExample>
832827

833828
```ts
834-
import { isUnauthorized, isTransportNotImplemented } from "agents/mcp";
829+
import { isUnauthorized, isTransportNotImplemented } from "agents";
835830

836831
export class MyAgent extends Agent {
837832
async onRequest(request: Request) {

0 commit comments

Comments
 (0)