agents 0.30.0 → 0.31.0
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 +4 -2
- package/dist/{agent-routing-CDbpVjYq.d.ts → agent-routing-wS1TimZ_.d.ts} +64 -603
- package/dist/agent-routing.d.ts +1 -1
- package/dist/agent-tool-types.d.ts +1 -1
- package/dist/{agent-tools-C8DH8Yii.d.ts → agent-tools-Bamxxb6Y.d.ts} +2 -2
- package/dist/agent-tools.d.ts +1 -1
- package/dist/{ai-iXw0uOGj.d.ts → ai-CDn3Abax.d.ts} +30 -4
- package/dist/{ai-sdk-DRPh2rRa.js → ai-sdk-Kon40i0q.js} +2 -36
- package/dist/ai-sdk-Kon40i0q.js.map +1 -0
- package/dist/ai-sdk-hW3vntnk.d.ts +72 -0
- package/dist/browser/ai.d.ts +1 -1
- package/dist/browser/ai.js +16 -3
- package/dist/browser/ai.js.map +1 -1
- package/dist/browser/index.d.ts +64 -16
- package/dist/browser/index.js +4 -4
- package/dist/browser/tools/ai-sdk.d.ts +7 -70
- package/dist/browser/tools/ai-sdk.js +4 -4
- package/dist/browser/tools/ai-sdk.js.map +1 -1
- package/dist/browser/tools/pi.d.ts +9 -15
- package/dist/browser/tools/pi.js +6 -14
- package/dist/browser/tools/pi.js.map +1 -1
- package/dist/browser/tools/tanstack-ai.d.ts +46 -23
- package/dist/browser/tools/tanstack-ai.js +8 -4
- package/dist/browser/tools/tanstack-ai.js.map +1 -1
- package/dist/{browser-DccPw_wW.js → browser-1eUbPvC2.js} +413 -14
- package/dist/browser-1eUbPvC2.js.map +1 -0
- package/dist/{browser-DlXhSAdf.d.ts → browser-D9RNpJuT.d.ts} +254 -20
- package/dist/browser-tool-BhjCcNVE.d.ts +71 -0
- package/dist/browser-tool-lGnvEBLJ.js +497 -0
- package/dist/browser-tool-lGnvEBLJ.js.map +1 -0
- package/dist/capability-id-B3J8Nok_.js +13 -0
- package/dist/capability-id-B3J8Nok_.js.map +1 -0
- package/dist/chat/index.d.ts +2 -2
- package/dist/chat-sdk/index.d.ts +3 -3
- package/dist/chat-sdk/index.js +1 -1
- package/dist/client-4OlMIJx-.js.map +1 -1
- package/dist/{client-BnYbNT3z.js → client-DMWujQJ1.js} +68 -244
- package/dist/client-DMWujQJ1.js.map +1 -0
- package/dist/{client-C27CtRZr.d.ts → client-wn4-yqGz.d.ts} +9 -7
- package/dist/client.d.ts +1 -1
- package/dist/{connector-DAXBOIIi.js → connector-CM-uuxKM.js} +96 -8
- package/dist/connector-CM-uuxKM.js.map +1 -0
- package/dist/{connector-20DJ6p4k.d.ts → connector-DZ71EjE-.d.ts} +109 -9
- package/dist/experimental/webmcp.js +1 -1
- package/dist/{handler-stateless-Bly_nSH3.js → handler-stateless-B5hU3dxK.js} +35 -2
- package/dist/handler-stateless-B5hU3dxK.js.map +1 -0
- package/dist/{handler-stateless-DxYpJ_XF.d.ts → handler-stateless-C90kD5_R.d.ts} +3 -47
- package/dist/harness/container/index.d.ts +15 -15
- package/dist/harness/opencode/index.js.map +1 -1
- package/dist/harness/pi/index.d.ts +7 -3
- package/dist/harness/pi/index.js +46 -15
- package/dist/harness/pi/index.js.map +1 -1
- package/dist/harness/think/index.d.ts +2 -1
- package/dist/{images-xaDv2Fqe.js → images-CfuRCjwq.js} +1 -5
- package/dist/images-CfuRCjwq.js.map +1 -0
- package/dist/{index-DCxk3OSJ.d.ts → index-8k4qsX1T.d.ts} +2 -28
- package/dist/index.d.ts +14 -14
- package/dist/index.js +2 -2
- package/dist/internal-hosts-Kfp5A392.d.ts +230 -0
- package/dist/internal-kmw70xwR.js.map +1 -1
- package/dist/invoker-BC1SZ3q1.js +26 -0
- package/dist/invoker-BC1SZ3q1.js.map +1 -0
- package/dist/invoker-DoLFPJZV.d.ts +21 -0
- package/dist/mcp/client/index.d.ts +15 -1
- package/dist/mcp/client/index.js +2 -2
- package/dist/mcp/client/x402.d.ts +7 -5
- package/dist/mcp/client/x402.js +34 -1
- package/dist/mcp/client/x402.js.map +1 -1
- package/dist/mcp/index.d.ts +561 -27
- package/dist/mcp/index.js +180 -3
- package/dist/mcp/index.js.map +1 -1
- package/dist/mcp/server/index.d.ts +1 -1
- package/dist/mcp/server/index.js +1 -1
- package/dist/models/ai-sdk/index.d.ts +2 -2
- package/dist/models/ai-sdk/index.js +1 -1
- package/dist/models/opencode/index.d.ts +2 -2
- package/dist/models/opencode/index.js +1 -1
- package/dist/models/pi-ai/index.d.ts +3 -28
- package/dist/models/pi-ai/index.js +31 -16
- package/dist/models/pi-ai/index.js.map +1 -1
- package/dist/protocol-BEgrJYC5.d.ts +29 -29
- package/dist/react.d.ts +2 -2
- package/dist/routing/index.d.ts +1 -1
- package/dist/serializable.d.ts +1 -1
- package/dist/{session-store-yvwq1f9x.js → session-7CDgVE0z.js} +455 -33
- package/dist/session-7CDgVE0z.js.map +1 -0
- package/dist/{session-store-_IK6dV-w.d.ts → session-store-B7Ca-u1t.d.ts} +8 -1
- package/dist/settings-Dk2il2Hf.js.map +1 -1
- package/dist/{src-DfLzdwlK.js → src-BGolXG_H.js} +18 -2
- package/dist/src-BGolXG_H.js.map +1 -0
- package/dist/sub-routing.d.ts +12 -12
- package/dist/tool-CTp72Jb_.d.ts +10 -10
- package/dist/tool-DoVberpN.d.ts +22 -22
- package/dist/tool-helpers-BodWi4gd.js +256 -0
- package/dist/tool-helpers-BodWi4gd.js.map +1 -0
- package/dist/{transport-CPh7YGiw.d.ts → transport-5moD2pW5.d.ts} +1 -43
- package/dist/types-D2naO3rA.d.ts +49 -0
- package/dist/voice/index.d.ts +1 -1
- package/dist/workflow-types.d.ts +1 -1
- package/dist/workflows.d.ts +1 -1
- package/dist/workflows.js +1 -1
- package/docs/browse-the-web.md +247 -413
- package/docs/get-current-agent.md +4 -7
- package/docs/harnesses/pi.md +28 -28
- package/docs/human-in-the-loop.md +3 -7
- package/docs/index.md +6 -6
- package/docs/mcp-client.md +4 -28
- package/docs/mcp-servers.md +137 -411
- package/docs/mcp-transports.md +30 -289
- package/docs/models-pi-ai.md +9 -11
- package/docs/models.md +1 -8
- package/docs/routing.md +0 -2
- package/docs/securing-mcp-servers.md +120 -304
- package/package.json +8 -3
- package/dist/ai-sdk-DRPh2rRa.js.map +0 -1
- package/dist/browser-DccPw_wW.js.map +0 -1
- package/dist/browser-tool-B1mhifin.js +0 -616
- package/dist/browser-tool-B1mhifin.js.map +0 -1
- package/dist/browser-tool-Cxjk5sgG.d.ts +0 -92
- package/dist/client-BnYbNT3z.js.map +0 -1
- package/dist/connector-DAXBOIIi.js.map +0 -1
- package/dist/handler-stateless-Bly_nSH3.js.map +0 -1
- package/dist/images-xaDv2Fqe.js.map +0 -1
- package/dist/invoker-CG0_p_Wq.d.ts +0 -20
- package/dist/invoker-CHMnoxIA.js +0 -57
- package/dist/invoker-CHMnoxIA.js.map +0 -1
- package/dist/session-store-yvwq1f9x.js.map +0 -1
- package/dist/src-DfLzdwlK.js.map +0 -1
- package/dist/tool-helpers-O5BDVEAY.js +0 -58
- package/dist/tool-helpers-O5BDVEAY.js.map +0 -1
|
@@ -142,9 +142,10 @@ context:
|
|
|
142
142
|
|
|
143
143
|
```typescript
|
|
144
144
|
import { RpcTarget } from "cloudflare:workers";
|
|
145
|
+
import { Agent, getCurrentAgent } from "agents";
|
|
145
146
|
|
|
146
147
|
class HostCallbackBridge extends RpcTarget {
|
|
147
|
-
constructor(private agent:
|
|
148
|
+
constructor(private agent: MyAgent) {
|
|
148
149
|
super();
|
|
149
150
|
}
|
|
150
151
|
|
|
@@ -155,9 +156,9 @@ class HostCallbackBridge extends RpcTarget {
|
|
|
155
156
|
}
|
|
156
157
|
}
|
|
157
158
|
|
|
158
|
-
export class
|
|
159
|
+
export class MyAgent extends Agent {
|
|
159
160
|
async handleSandboxCallback() {
|
|
160
|
-
const { agent } = getCurrentAgent<
|
|
161
|
+
const { agent } = getCurrentAgent<MyAgent>();
|
|
161
162
|
// `agent` is available again.
|
|
162
163
|
}
|
|
163
164
|
}
|
|
@@ -166,10 +167,6 @@ export class MyMcpAgent extends McpAgent {
|
|
|
166
167
|
Context restored this way has `connection`, `request`, and `email` unset. It
|
|
167
168
|
is not tied to live client I/O.
|
|
168
169
|
|
|
169
|
-
Server-initiated MCP requests (`elicitInput`, `createMessage`, and `listRoots`)
|
|
170
|
-
on `McpAgent` do not require this indirection because the MCP transport retains
|
|
171
|
-
its owning agent.
|
|
172
|
-
|
|
173
170
|
## API reference
|
|
174
171
|
|
|
175
172
|
The agents package exports one main function for context management:
|
package/docs/harnesses/pi.md
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
---
|
|
2
|
-
title: Pi harness
|
|
2
|
+
title: Pi harness
|
|
3
3
|
pcx_content_type: get-started
|
|
4
|
-
description: Host pi-durable sessions in a Durable Object with the
|
|
4
|
+
description: Host pi-durable sessions in a Durable Object with the PiHarness lifecycle capability. Connect a pi-ai model, add tools and skills, and keep sessions running across eviction.
|
|
5
5
|
---
|
|
6
6
|
|
|
7
|
-
`PiHarness` hosts [pi-durable](https://github.com/earendil-works/pi/tree/main/packages/durable) in a Durable Object. It opens Pi over the object's SQLite database and connects Pi's sessions to the Agents SDK lifecycle, which wakes sessions with work after eviction.
|
|
7
|
+
`PiHarness` hosts [pi-durable](https://github.com/earendil-works/pi/tree/main/packages/durable) in a Durable Object. It opens Pi over the object's SQLite database and connects Pi's sessions to the Agents SDK lifecycle, which wakes sessions with work after eviction.
|
|
8
8
|
|
|
9
9
|
Pi owns everything about a run: the transcript, the inbox of steers and follow-ups, generation, tool calls, retries, and crash recovery. `PiHarness` supplies the storage and the wake. It does not provide a chat protocol or user interface. Your application chooses how clients reach sessions, such as WebSockets, HTTP, or RPC.
|
|
10
10
|
|
|
@@ -21,13 +21,14 @@ The three Pi packages are optional peer dependencies of `agents`, at `~1.4.0`. p
|
|
|
21
21
|
`PiHarness` uses a factory function to construct Pi's `Harness` so it can be instantiated lazily:
|
|
22
22
|
|
|
23
23
|
```ts
|
|
24
|
+
import { DurableObject } from "cloudflare:workers";
|
|
24
25
|
import { createModels } from "@earendil-works/pi-ai/models";
|
|
25
26
|
import { createRegistry, Harness } from "@earendil-works/pi-durable";
|
|
26
|
-
import { Agent } from "agents";
|
|
27
27
|
import { PiHarness } from "agents/harness/pi";
|
|
28
|
+
import { Lifecycle } from "agents/lifecycle";
|
|
28
29
|
import { createAI } from "agents/models/pi-ai";
|
|
29
30
|
|
|
30
|
-
export class Assistant extends
|
|
31
|
+
export class Assistant extends DurableObject<Env> {
|
|
31
32
|
ai = createAI({ binding: this.env.AI });
|
|
32
33
|
registry = createRegistry();
|
|
33
34
|
|
|
@@ -42,15 +43,12 @@ export class Assistant extends Agent<Env> {
|
|
|
42
43
|
);
|
|
43
44
|
},
|
|
44
45
|
defaults: {
|
|
45
|
-
model: this.ai("@cf/zai-org/glm-
|
|
46
|
+
model: this.ai("@cf/zai-org/glm-5.3-flash"),
|
|
46
47
|
thinkingLevel: "low"
|
|
47
48
|
}
|
|
48
49
|
});
|
|
49
50
|
|
|
50
|
-
|
|
51
|
-
super(ctx, env);
|
|
52
|
-
this.lifecycle.use(this.harness);
|
|
53
|
-
}
|
|
51
|
+
lifecycle = Lifecycle.install(this).use(this.harness);
|
|
54
52
|
|
|
55
53
|
async ask(prompt: string) {
|
|
56
54
|
return (await this.harness.prompt(prompt)).text;
|
|
@@ -58,6 +56,8 @@ export class Assistant extends Agent<Env> {
|
|
|
58
56
|
}
|
|
59
57
|
```
|
|
60
58
|
|
|
59
|
+
`PiHarness` is a Lifecycle capability, so it runs on a plain Durable Object. `Lifecycle.install(this)` gives the object its startup, alarms and job queue, and `.use(this.harness)` installs the harness on it. The object needs a SQLite migration in your Wrangler configuration, like any Durable Object that uses SQLite storage. To use it from an `Agent`, which already has a lifecycle, call `this.lifecycle.use(this.harness)` in the constructor instead.
|
|
60
|
+
|
|
61
61
|
| Option | What it is |
|
|
62
62
|
| ---------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
63
63
|
| `harness` | Required. Receives `{ storage, context, onWake }` and returns Pi's `Harness`, usually from `Harness.open`. Pass `onWake` to `Harness.open`, so the object can hibernate while Pi's tasks sleep (see [How recovery works](#how-recovery-works)). Models, the registry, `settings`, `env` and `onReport` are all yours to build here. |
|
|
@@ -149,7 +149,7 @@ harness: async ({ storage, context, onWake }) => {
|
|
|
149
149
|
this.registry.install({
|
|
150
150
|
name: "browser",
|
|
151
151
|
tools: [
|
|
152
|
-
browserTool({
|
|
152
|
+
browserTool({ browser: this.browser, loader: this.env.LOADER })
|
|
153
153
|
]
|
|
154
154
|
});
|
|
155
155
|
return Harness.open(
|
|
@@ -162,7 +162,7 @@ harness: async ({ storage, context, onWake }) => {
|
|
|
162
162
|
readonly lifecycle = Lifecycle.install(this).use(this.browser).use(this.harness);
|
|
163
163
|
```
|
|
164
164
|
|
|
165
|
-
It needs a `browser` binding, a `LOADER` Worker Loader binding, and `
|
|
165
|
+
It needs a `browser` binding, a `LOADER` Worker Loader binding, and `@cloudflare/codemode` installed (only until the deprecated codemode browser APIs are removed from `agents/browser`). Screenshots come back as images, and each conversation works in its own tab. Refer to [Persistent browser](../browse-the-web.md#persistent-browser) for how it behaves.
|
|
166
166
|
|
|
167
167
|
## Work with sessions
|
|
168
168
|
|
|
@@ -174,7 +174,7 @@ const { text } = await this.harness.prompt("What is 47 × 19?");
|
|
|
174
174
|
|
|
175
175
|
// Another session, on a cheaper model.
|
|
176
176
|
const session = await this.harness.sessions.create();
|
|
177
|
-
await session.setModel(this.ai("@cf/zai-org/glm-
|
|
177
|
+
await session.setModel(this.ai("@cf/zai-org/glm-5.3-flash"));
|
|
178
178
|
|
|
179
179
|
// Durable once it returns; the same operation id twice is one submission.
|
|
180
180
|
const receipt = await session.submit("Summarize the latest report", {
|
|
@@ -183,20 +183,20 @@ const receipt = await session.submit("Summarize the latest report", {
|
|
|
183
183
|
const result = await session.wait(receipt.operationId);
|
|
184
184
|
```
|
|
185
185
|
|
|
186
|
-
| Call | What it does
|
|
187
|
-
| ------------------------------------------------- |
|
|
188
|
-
| `prompt(input)` | Submits and waits: the answer, and the transcript after it.
|
|
189
|
-
| `submit(input, { operationId, whenBusy, entry })` | Hands the input to Pi and returns as soon as Pi has saved it, without waiting for the model. If the session is already working, the input waits until that work finishes. With `whenBusy: "steer"`, it joins the running work instead, after the current round of tool calls. `entry` records where the input came from (see below). |
|
|
190
|
-
| `wait(operationId, signal?)` | The operation's result once Pi settles it. Aborting `signal` stops only the wait, not the work.
|
|
191
|
-
| `steer(input)` | `submit` with `whenBusy: "steer"`.
|
|
192
|
-
| `abort(operationId?)` | Withdraws a queued operation, or with no id, stops everything running in the session.
|
|
193
|
-
| `pending()` | Operations Pi has not settled yet: queued, part of the running work, or `parked` (see [How recovery works](#how-recovery-works)).
|
|
194
|
-
| `retry()` | Runs again the tasks Pi's restart limit parked in the session's work. Resolves `false` when nothing was parked.
|
|
195
|
-
| `messages()` | Pi's transcript entries since the newest reset.
|
|
196
|
-
| `events()` | Pi's agent events: a `snapshot`, then one batch per commit.
|
|
197
|
-
| `reset(handoff?)` | Starts a new context, optionally from a handoff note.
|
|
198
|
-
| `setModel(model)` | Changes this session's model.
|
|
199
|
-
| `busy()` | Whether a run is going.
|
|
186
|
+
| Call | What it does |
|
|
187
|
+
| ------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
188
|
+
| `prompt(input)` | Submits and waits: the answer, and the transcript after it. |
|
|
189
|
+
| `submit(input, { operationId, whenBusy, entry })` | Hands the input to Pi and returns as soon as Pi has saved it, without waiting for the model. If the session is already working, the input waits until that work finishes. With `whenBusy: "steer"`, it joins the running work instead, after the current round of tool calls. With `whenBusy: "reject"`, it is not admitted: `submit` rejects with Pi's `ConversationBusy` and nothing is saved, so the same `operationId` can be submitted again later. `entry` records where the input came from (see below). |
|
|
190
|
+
| `wait(operationId, signal?)` | The operation's result once Pi settles it. Aborting `signal` stops only the wait, not the work. |
|
|
191
|
+
| `steer(input)` | `submit` with `whenBusy: "steer"`. |
|
|
192
|
+
| `abort(operationId?)` | Withdraws a queued operation, or with no id, stops everything running in the session. |
|
|
193
|
+
| `pending()` | Operations Pi has not settled yet: queued, part of the running work, or `parked` (see [How recovery works](#how-recovery-works)). |
|
|
194
|
+
| `retry()` | Runs again the tasks Pi's restart limit parked in the session's work. Resolves `false` when nothing was parked. |
|
|
195
|
+
| `messages()` | Pi's transcript entries since the newest reset. |
|
|
196
|
+
| `events()` | Pi's agent events: a `snapshot`, then one batch per commit. |
|
|
197
|
+
| `reset(handoff?)` | Starts a new context, optionally from a handoff note. |
|
|
198
|
+
| `setModel(model)` | Changes this session's model. |
|
|
199
|
+
| `busy()` | Whether a run is going. |
|
|
200
200
|
|
|
201
201
|
`harness.prompt()`, `submit()`, `wait()`, `abort()`, `retry()`, `messages()` and `pending()` act on the root session, or on `{ session }`. `harness.sessions` has `create()`, `fork(from)`, `get(id)` and `list()`, which includes sessions subagents created. `ROOT_SESSION` is the root's id.
|
|
202
202
|
|
|
@@ -246,7 +246,7 @@ With `keep`, the kept inputs are not work to Pi: its `wake()` counts tasks, not
|
|
|
246
246
|
|
|
247
247
|
## How recovery works
|
|
248
248
|
|
|
249
|
-
The harness schedules one lifecycle job, driven by Pi's `wake()`. While Pi has work running, the job waits on it and refreshes itself as a heartbeat. While Pi's tasks sleep, such as a retry backoff, the job is due when the first one wakes. Pi says when through the `onWake` the factory passes to `Harness.open`, and sets no in-memory timer of its own, so the object can hibernate until then. Without `onWake` the harness still works, but Pi's timer keeps the object in memory, and billed, while a task sleeps, and the harness logs a warning. When Pi has nothing to do, the job completes. If the object is evicted or crashes, the job is still due, so its alarm restarts the object. Pi reopens its stored state and resumes the session's work: a replay-safe tool call runs again, and an unsafe one is reported to the model as interrupted.
|
|
249
|
+
The harness schedules one lifecycle job, driven by Pi's `wake()`. While Pi has work running, the job waits on it and refreshes itself as a heartbeat. While Pi's tasks sleep, such as a retry backoff, the job is due when the first one wakes. Pi says when through the `onWake` the factory passes to `Harness.open`, and sets no in-memory timer of its own, so the object can hibernate until then. A task that sleeps while other work runs, such as a compaction retry during a generation, is resumed from the job's wait when it is due. Without `onWake` the harness still works, but Pi's timer keeps the object in memory, and billed, while a task sleeps, and the harness logs a warning. When Pi has nothing to do, the job completes. If the object is evicted or crashes, the job is still due, so its alarm restarts the object. Pi reopens its stored state and resumes the session's work: a replay-safe tool call runs again, and an unsafe one is reported to the model as interrupted.
|
|
250
250
|
|
|
251
251
|
A task that keeps crashing the object would restart it forever, so Pi parks a task cut off by a crash or eviction `settings.restartLimit` times in a row (default 5) without progress. A parked task is not work: the job completes and the object can hibernate. Its operations show as `parked` in `pending()`, and `wait()` keeps waiting. If your factory passes `onReport` to `Harness.open`, Pi reports it there as `task_parked`. Once you have dealt with the cause, `session.retry()` runs it again and wakes the harness; `session.abort()` gives up on it instead.
|
|
252
252
|
|
|
@@ -32,7 +32,6 @@ Agents SDK supports multiple human-in-the-loop patterns. Choose based on your us
|
|
|
32
32
|
| OpenAI Agents SDK | `needsApproval` | Using OpenAI's agent SDK with conditional approval | [openai-sdk/human-in-the-loop/](https://github.com/cloudflare/agents/tree/main/openai-sdk/human-in-the-loop) |
|
|
33
33
|
| Client-side tools | `onToolCall` | Tools that need browser APIs or user interaction | Pattern below |
|
|
34
34
|
| Stateless servers | Stateless Elicitation | Current MCP tools requesting structured input | [examples/mcp-elicitation-mrtr/](https://github.com/cloudflare/agents/tree/main/examples/mcp-elicitation-mrtr) |
|
|
35
|
-
| Legacy servers | Legacy Elicitation | Existing sessionful MCP deployments | [examples/mcp-elicitation/](https://github.com/cloudflare/agents/tree/main/examples/mcp-elicitation) |
|
|
36
35
|
|
|
37
36
|
### Decision Guide
|
|
38
37
|
|
|
@@ -40,7 +39,7 @@ Agents SDK supports multiple human-in-the-loop patterns. Choose based on your us
|
|
|
40
39
|
Is this part of a multi-step workflow?
|
|
41
40
|
├── Yes → Use Workflow Approval (waitForApproval)
|
|
42
41
|
└── No → Are you building an MCP server?
|
|
43
|
-
├── Yes → Use MCP Elicitation (
|
|
42
|
+
├── Yes → Use MCP Elicitation (inputRequired)
|
|
44
43
|
└── No → Is this an AI chat interaction?
|
|
45
44
|
├── Yes → Does the tool need browser APIs?
|
|
46
45
|
│ ├── Yes → Use onToolCall (client-side execution)
|
|
@@ -460,7 +459,7 @@ See the complete example: [openai-sdk/human-in-the-loop/](https://github.com/clo
|
|
|
460
459
|
|
|
461
460
|
### MCP Elicitation
|
|
462
461
|
|
|
463
|
-
|
|
462
|
+
MCP servers built with `createMcpHandler` use multi-round-trip requests (MRTR) for elicitation. A handler returns `inputRequired(...)`; the client gathers the requested input and retries with SDK-managed state. No Worker remains suspended while the user responds.
|
|
464
463
|
|
|
465
464
|
```typescript
|
|
466
465
|
import {
|
|
@@ -517,8 +516,6 @@ The MCP client renders the JSON Schema form and the original operation remains p
|
|
|
517
516
|
|
|
518
517
|
See the [Stateless Elicitation example](https://github.com/cloudflare/agents/tree/main/examples/mcp-elicitation-mrtr).
|
|
519
518
|
|
|
520
|
-
**Legacy Elicitation** in existing Legacy deployments uses pushed `elicitation/create` requests over a stateful transport. See the explicitly legacy [examples/mcp-elicitation/](https://github.com/cloudflare/agents/tree/main/examples/mcp-elicitation) example when retaining `McpAgent` or `createLegacyMcpHandler` with `WorkerTransport`.
|
|
521
|
-
|
|
522
519
|
## State Patterns for Approvals
|
|
523
520
|
|
|
524
521
|
Track pending approvals in agent state for UI rendering and persistence:
|
|
@@ -640,10 +637,9 @@ async submitForApproval(request: ApprovalRequest): Promise<string> {
|
|
|
640
637
|
| AIChatAgent tools | [guides/human-in-the-loop/](https://github.com/cloudflare/agents/tree/main/guides/human-in-the-loop) | Chat tool approval with needsApproval + onToolCall |
|
|
641
638
|
| OpenAI Agents SDK | [openai-sdk/human-in-the-loop/](https://github.com/cloudflare/agents/tree/main/openai-sdk/human-in-the-loop) | Conditional tool approval with modal |
|
|
642
639
|
| Stateless Elicitation | [examples/mcp-elicitation-mrtr/](https://github.com/cloudflare/agents/tree/main/examples/mcp-elicitation-mrtr) | Stateless multi-round input |
|
|
643
|
-
| Legacy Elicitation | [examples/mcp-elicitation/](https://github.com/cloudflare/agents/tree/main/examples/mcp-elicitation) | Stateful pushed input requests |
|
|
644
640
|
|
|
645
641
|
For detailed API documentation, see:
|
|
646
642
|
|
|
647
643
|
- [Workflows](./workflows.md) - `waitForApproval()`, `approveWorkflow()`, `rejectWorkflow()`
|
|
648
|
-
- [MCP Servers](./mcp-servers.md) - `inputRequired()`
|
|
644
|
+
- [MCP Servers](./mcp-servers.md) - `inputRequired()` elicitation
|
|
649
645
|
- [Callable Methods](./callable-methods.md) - `@callable()` decorator for approval endpoints
|
package/docs/index.md
CHANGED
|
@@ -49,7 +49,7 @@ The Lifecycle runs startup, routes requests to capabilities, and owns the object
|
|
|
49
49
|
|
|
50
50
|
## Harnesses
|
|
51
51
|
|
|
52
|
-
- [Pi harness
|
|
52
|
+
- [Pi harness](./harnesses/pi.md) - Host pi-durable sessions in a Durable Object with durable storage and lifecycle wakeups
|
|
53
53
|
- [Think harness (Experimental)](./harnesses/think.md) - Run Think's agent loop as a Lifecycle capability, with transcripts in Sessions, output in Streams, and turns that survive eviction
|
|
54
54
|
- [Think (Experimental)](https://github.com/cloudflare/agents/blob/main/docs/think/index.md) - Opinionated chat agent with built-in memory, tools, and streaming. Extends `Think`, which builds on `Agent`.
|
|
55
55
|
|
|
@@ -136,12 +136,12 @@ Building your own harness? Sessions stores the conversation, Streams holds durab
|
|
|
136
136
|
- TODO: [AI SDK Integration](./ai-sdk.md) - Using Vercel AI SDK with agents
|
|
137
137
|
- TODO: [TanStack Integration](./tanstack.md) - Using TanStack AI with agents
|
|
138
138
|
- TODO: [Using AI Models](./using-ai-models.md) - OpenAI, Anthropic, Workers AI, and other providers
|
|
139
|
-
- [Models
|
|
140
|
-
- [Models for pi-ai
|
|
139
|
+
- [Models](./models.md) - `createAI` — one AI SDK provider for Workers AI and third-party catalog models, same string space
|
|
140
|
+
- [Models for pi-ai](./models-pi-ai.md) - `createAI` for pi-ai: Workers AI ids and third-party models through AI Gateway, as a pi-ai provider
|
|
141
141
|
- [Context (Experimental)](./context.md) - System-prompt blocks, frozen prompts, writable/searchable/loadable providers, and their tools
|
|
142
142
|
- [Workspace (Experimental)](https://github.com/cloudflare/agents/blob/main/docs/shell/index.md) - Durable virtual filesystem backed by SQLite + R2
|
|
143
143
|
- [Codemode (Experimental)](./codemode.md) - LLM-generated executable code for tool orchestration
|
|
144
|
-
- [Browse the Web
|
|
144
|
+
- [Browse the Web](./browse-the-web.md) - Full CDP access for web inspection, scraping, and debugging
|
|
145
145
|
- [Search the Web (Beta)](./search-the-web.md) - A `websearch` tool over Cloudflare's Web Search API for the pi harness, the AI SDK, and TanStack AI
|
|
146
146
|
- [Fetch the Web (Beta)](./fetch-the-web.md) - A `web_fetch` tool that reads a URL as Markdown, JSON, or text, with a host-controlled URL policy, for the pi harness, the AI SDK, TanStack AI, and Think
|
|
147
147
|
- TODO: [Cloudflare Sandboxes](./sandboxes.md) - Isolated environments for coding agents, ffmpeg, and heavy compute
|
|
@@ -149,10 +149,10 @@ Building your own harness? Sessions stores the conversation, Streams holds durab
|
|
|
149
149
|
|
|
150
150
|
## MCP (Model Context Protocol)
|
|
151
151
|
|
|
152
|
-
- [Creating MCP Servers](./mcp-servers.md) - Build MCP servers with `
|
|
152
|
+
- [Creating MCP Servers](./mcp-servers.md) - Build stateless MCP servers with `createMcpHandler`
|
|
153
153
|
- [Securing MCP Servers](./securing-mcp-servers.md) - OAuth and authentication for MCP
|
|
154
154
|
- [Connecting to MCP Servers](./mcp-client.md) - `MCPClientManager` on a Durable Object, or `addMcpServer()` on an Agent
|
|
155
|
-
- [MCP Transports](./mcp-transports.md) -
|
|
155
|
+
- [MCP Transports](./mcp-transports.md) - Streamable HTTP on the server, and the transports an Agent can connect with
|
|
156
156
|
|
|
157
157
|
## Operations
|
|
158
158
|
|
package/docs/mcp-client.md
CHANGED
|
@@ -51,19 +51,6 @@ callback URL to `registerServer()` and route that request to the same named
|
|
|
51
51
|
Durable Object. The manager persists the URL and only intercepts a callback
|
|
52
52
|
whose origin and pathname match it.
|
|
53
53
|
|
|
54
|
-
An HTTP-only manager does not need `env`. Pass the Durable Object environment
|
|
55
|
-
when the catalog can contain RPC servers so persisted binding names can be
|
|
56
|
-
resolved after a wake:
|
|
57
|
-
|
|
58
|
-
```ts
|
|
59
|
-
readonly mcp = new MCPClientManager("my-object", "1.0.0", {
|
|
60
|
-
env: this.env
|
|
61
|
-
});
|
|
62
|
-
```
|
|
63
|
-
|
|
64
|
-
If an RPC row exists without `env`, startup logs a warning identifying the
|
|
65
|
-
server and does not recreate that connection.
|
|
66
|
-
|
|
67
54
|
`Agent` installs this same capability object directly. Existing `this.mcp`,
|
|
68
55
|
`addMcpServer()`, `removeMcpServer()`, and `getMcpServers()` APIs remain
|
|
69
56
|
available.
|
|
@@ -76,6 +63,8 @@ Install the exact MCP client peer used by this Agents release:
|
|
|
76
63
|
pnpm add agents @modelcontextprotocol/client@2.3.1
|
|
77
64
|
```
|
|
78
65
|
|
|
66
|
+
The MCP client does not need `@modelcontextprotocol/sdk` or `@modelcontextprotocol/server`. Those packages are optional peers used only by the MCP server APIs.
|
|
67
|
+
|
|
79
68
|
```typescript
|
|
80
69
|
import { Agent } from "agents";
|
|
81
70
|
|
|
@@ -188,7 +177,7 @@ These options are persisted and used when reconnecting after hibernation or afte
|
|
|
188
177
|
|
|
189
178
|
### Protocol negotiation and elicitation
|
|
190
179
|
|
|
191
|
-
Agents uses the MCP v2 client and automatically negotiates the protocol version for every connection. It uses `server/discover` with Stateless servers and falls back to the `initialize` handshake on the same connection for Legacy Streamable HTTP
|
|
180
|
+
Agents uses the MCP v2 client and automatically negotiates the protocol version for every connection. It uses `server/discover` with Stateless servers and falls back to the `initialize` handshake on the same connection for Legacy Streamable HTTP and SSE servers.
|
|
192
181
|
|
|
193
182
|
MCP servers can request input from the client during `callTool`, `getPrompt`, or `readResource`. Stateless Elicitation returns an `input_required` result and completes through MRTR: the MCP SDK invokes the configured `elicitation/create` handler, sends its response, and continues the original request. Agents does not expose an intermediate continuation; the original call stays pending while human input is collected and eventually resolves to the ordinary tool, prompt, or resource result. Legacy Elicitation on Legacy servers continues to use pushed `elicitation/create` requests. Both generations share the same handlers.
|
|
194
183
|
|
|
@@ -243,8 +232,6 @@ MCP server URLs are validated before connection to prevent Server-Side Request F
|
|
|
243
232
|
|
|
244
233
|
Loopback development URLs such as `localhost`, `127.0.0.1`, and `::1` are allowed.
|
|
245
234
|
|
|
246
|
-
If you need to connect to another internal MCP server, use the [RPC transport](./mcp-transports.md) with a Durable Object binding instead of HTTP.
|
|
247
|
-
|
|
248
235
|
### Return Value
|
|
249
236
|
|
|
250
237
|
`addMcpServer()` returns the connection state:
|
|
@@ -666,17 +653,6 @@ async addMcpServer(
|
|
|
666
653
|
| { id: string; state: "authenticating"; authUrl: string }
|
|
667
654
|
>
|
|
668
655
|
|
|
669
|
-
// RPC transport (Durable Object binding — no HTTP overhead)
|
|
670
|
-
async addMcpServer(
|
|
671
|
-
name: string,
|
|
672
|
-
binding: DurableObjectNamespace,
|
|
673
|
-
options?: {
|
|
674
|
-
props?: Record<string, unknown>; // passed to the McpAgent's onStart(props)
|
|
675
|
-
client?: ClientOptions;
|
|
676
|
-
retry?: RetryOptions;
|
|
677
|
-
}
|
|
678
|
-
): Promise<{ id: string; state: "ready" }>
|
|
679
|
-
|
|
680
656
|
// Legacy signature (still supported)
|
|
681
657
|
async addMcpServer(
|
|
682
658
|
name: string,
|
|
@@ -689,7 +665,7 @@ async addMcpServer(
|
|
|
689
665
|
|
|
690
666
|
Add and connect to an MCP server. Throws if connection or discovery fails.
|
|
691
667
|
|
|
692
|
-
`callbackHost` is automatically derived from the incoming HTTP request or WebSocket connection URI — you almost never need to set it explicitly. It is only needed when the auto-detected host does not match your desired OAuth callback origin (for example, behind a reverse proxy).
|
|
668
|
+
`callbackHost` is automatically derived from the incoming HTTP request or WebSocket connection URI — you almost never need to set it explicitly. It is only needed when the auto-detected host does not match your desired OAuth callback origin (for example, behind a reverse proxy). See [MCP Transports](./mcp-transports.md) for the transport options.
|
|
693
669
|
|
|
694
670
|
Calling `addMcpServer` is idempotent when both the server name **and** URL match an existing active connection — the existing connection is returned without creating a duplicate. This makes it safe to call in `onStart()` without worrying about duplicate connections on restart.
|
|
695
671
|
|