agents 0.26.0 → 0.27.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 +8 -9
- package/dist/{agent-routing-0DR0Tk2v.d.ts → agent-routing-Bhdbvf7s.d.ts} +13 -8
- package/dist/agent-routing.d.ts +1 -1
- package/dist/agent-tool-types.d.ts +1 -1
- package/dist/{agent-tools-YrATZJu2.d.ts → agent-tools-bJZwBMfq.d.ts} +2 -2
- package/dist/agent-tools.d.ts +1 -1
- package/dist/ai-sdk-OoGkFy3s.js +2444 -0
- package/dist/ai-sdk-OoGkFy3s.js.map +1 -0
- package/dist/apply-chunks-1FheRb9W.js +99 -0
- package/dist/apply-chunks-1FheRb9W.js.map +1 -0
- package/dist/broadcast-state-CEyI4uAK.js +69 -0
- package/dist/broadcast-state-CEyI4uAK.js.map +1 -0
- package/dist/browser/ai-sdk.d.ts +1 -1
- package/dist/browser/ai-sdk.js +2 -2
- package/dist/browser/ai-sdk.js.map +1 -1
- package/dist/browser/index.d.ts +1 -1
- package/dist/browser/tanstack-ai.d.ts +1 -1
- package/dist/browser/tanstack-ai.js +1 -1
- package/dist/{browser-DE3d-RLk.d.ts → browser-tmkcAAI3.d.ts} +2 -2
- package/dist/{browser-tool-DuNdlwZ9.d.ts → browser-tool-Bn-nzJQI.d.ts} +3 -3
- package/dist/{browser-tool-CQ10e6Kj.js → browser-tool-CBqs6hqa.js} +58 -18
- package/dist/browser-tool-CBqs6hqa.js.map +1 -0
- package/dist/capability-B4WbF81e.js.map +1 -1
- package/dist/{capability-runner-DBAnGr6L.d.ts → capability-runner-O5VbQzqg.d.ts} +9 -1
- package/dist/channel-Bak_6zDP.d.ts +333 -0
- package/dist/chat/index.d.ts +11 -9
- package/dist/chat/index.js +5 -194
- package/dist/chat/index.js.map +1 -1
- package/dist/chat/react.d.ts +2 -4
- package/dist/chat/react.js +3 -1
- package/dist/chat/react.js.map +1 -1
- package/dist/chat-sdk/index.d.ts +1 -1
- package/dist/chat-sdk/index.js +1 -1
- package/dist/cli.js +144 -0
- package/dist/{client-fyQrLGkD.js → client-1tEQ1Oqz.js} +27 -2
- package/dist/{client-fyQrLGkD.js.map → client-1tEQ1Oqz.js.map} +1 -1
- package/dist/{client-je3koD9Z.d.ts → client-DS3Dz9l0.d.ts} +2 -2
- package/dist/client-tools-aIBO0Fk7.d.ts +53 -0
- package/dist/client.d.ts +1 -1
- package/dist/conversations-DH0ut_8n.d.ts +192 -0
- package/dist/{current-agent-vAk_5JMt.d.ts → current-agent-C07C5o5Y.d.ts} +3 -3
- package/dist/daemon-core-Buubj-y1.js +481 -0
- package/dist/daemon-core-Buubj-y1.js.map +1 -0
- package/dist/daemon-core-CbohVPAu.d.ts +132 -0
- package/dist/{do-oauth-client-provider-Tmf1vgKz.d.ts → do-oauth-client-provider-DfsUcpc3.d.ts} +7 -1
- package/dist/{durable-object-lifecycle-HhgOMWq9.d.ts → durable-object-lifecycle-DRqp475_.d.ts} +2 -2
- package/dist/{channels/email.d.ts → experimental/channels/email/index.d.ts} +25 -12
- package/dist/{channels/email.js → experimental/channels/email/index.js} +13 -35
- package/dist/experimental/channels/email/index.js.map +1 -0
- package/dist/experimental/channels/index.d.ts +270 -0
- package/dist/experimental/channels/index.js +1186 -0
- package/dist/experimental/channels/index.js.map +1 -0
- package/dist/{channels/slack.d.ts → experimental/channels/slack/index.d.ts} +19 -9
- package/dist/experimental/channels/slack/index.js +267 -0
- package/dist/experimental/channels/slack/index.js.map +1 -0
- package/dist/{channels/telegram.d.ts → experimental/channels/telegram/index.d.ts} +19 -9
- package/dist/experimental/channels/telegram/index.js +198 -0
- package/dist/experimental/channels/telegram/index.js.map +1 -0
- package/dist/experimental/channels/web/ai-sdk.d.ts +55 -0
- package/dist/experimental/channels/web/ai-sdk.js +266 -0
- package/dist/experimental/channels/web/ai-sdk.js.map +1 -0
- package/dist/experimental/channels/web/client.d.ts +97 -0
- package/dist/experimental/channels/web/client.js +349 -0
- package/dist/experimental/channels/web/client.js.map +1 -0
- package/dist/experimental/channels/web/index.d.ts +189 -0
- package/dist/experimental/channels/web/index.js +332 -0
- package/dist/experimental/channels/web/index.js.map +1 -0
- package/dist/gateway-BDC07gYO.d.ts +100 -0
- package/dist/handle-zAzh0UW2.d.ts +460 -0
- package/dist/harness/ai-sdk/index.d.ts +175 -0
- package/dist/harness/ai-sdk/index.js +605 -0
- package/dist/harness/ai-sdk/index.js.map +1 -0
- package/dist/harness/container/daemon/index.d.ts +76 -0
- package/dist/harness/container/daemon/index.js +3 -0
- package/dist/harness/container/index.d.ts +740 -0
- package/dist/harness/container/index.js +2152 -0
- package/dist/harness/container/index.js.map +1 -0
- package/dist/harness/container/runtime/index.d.ts +144 -0
- package/dist/harness/container/runtime/index.js +1082 -0
- package/dist/harness/container/runtime/index.js.map +1 -0
- package/dist/harness/opencode/index.d.ts +369 -0
- package/dist/harness/opencode/index.js +1072 -0
- package/dist/harness/opencode/index.js.map +1 -0
- package/dist/harness/pi/index.d.ts +2 -1
- package/dist/harness/store/index.d.ts +24 -0
- package/dist/harness/store/index.js +2 -0
- package/dist/harness/think/index.d.ts +821 -0
- package/dist/harness/think/index.js +2529 -0
- package/dist/harness/think/index.js.map +1 -0
- package/dist/harness-B6B9S3rb.d.ts +203 -0
- package/dist/{images-iiTDSyRu.js → images-Ce9SCu3X.js} +2 -248
- package/dist/images-Ce9SCu3X.js.map +1 -0
- package/dist/{index-BreL0YrQ.d.ts → index-D0A5tbWu.d.ts} +2 -2
- package/dist/index-Ib_4dwOo.d.ts +200 -0
- package/dist/index.d.ts +5 -5
- package/dist/index.js +2 -2
- package/dist/ingress-EFbrS547.js +9 -0
- package/dist/ingress-EFbrS547.js.map +1 -0
- package/dist/input-schema-DNrpTu49.js +23 -0
- package/dist/input-schema-DNrpTu49.js.map +1 -0
- package/dist/internal-kmw70xwR.js +46 -0
- package/dist/internal-kmw70xwR.js.map +1 -0
- package/dist/internal_context.d.ts +1 -1
- package/dist/lifecycle/index.d.ts +3 -3
- package/dist/mcp/client/do-oauth-client-provider.d.ts +1 -1
- package/dist/mcp/client/do-oauth-client-provider.js +9 -0
- package/dist/mcp/client/do-oauth-client-provider.js.map +1 -1
- package/dist/mcp/client/index.d.ts +1 -1
- package/dist/mcp/client/index.js +1 -1
- package/dist/mcp/client/x402.d.ts +35 -4
- package/dist/mcp/client/x402.js +24 -3
- package/dist/mcp/client/x402.js.map +1 -1
- package/dist/mcp/index.d.ts +1 -1
- package/dist/mcp/index.js +2 -2
- package/dist/models/ai-sdk/index.d.ts +16 -14
- package/dist/models/ai-sdk/index.js +1 -2442
- package/dist/models/opencode/index.d.ts +65 -0
- package/dist/models/opencode/index.js +285 -0
- package/dist/models/opencode/index.js.map +1 -0
- package/dist/models/pi-ai/index.d.ts +9 -7
- package/dist/models/pi-ai/index.js +2 -1
- package/dist/models/pi-ai/index.js.map +1 -1
- package/dist/options-pwTNq9z6.d.ts +134 -0
- package/dist/protocol-BEgrJYC5.d.ts +331 -0
- package/dist/protocol-CukuI73M.d.ts +386 -0
- package/dist/protocol-cOklVBBD.js +227 -0
- package/dist/protocol-cOklVBBD.js.map +1 -0
- package/dist/{protocol-kHsr-f0X.js → protocol-eXeJxhgu.js} +2 -67
- package/dist/protocol-eXeJxhgu.js.map +1 -0
- package/dist/protocol-y2sSY584.js +148 -0
- package/dist/protocol-y2sSY584.js.map +1 -0
- package/dist/queue/index.d.ts +1 -1
- package/dist/react.d.ts +2 -2
- package/dist/routing/index.d.ts +2 -2
- package/dist/{scheduler-RdACNXDP.d.ts → scheduler-CrFCnv_J.d.ts} +2 -2
- package/dist/schedules/index.d.ts +1 -1
- package/dist/serializable.d.ts +1 -1
- package/dist/sessions/index.d.ts +11 -434
- package/dist/sessions/index.js +1 -2271
- package/dist/sessions-B9pNuxdT.js +2272 -0
- package/dist/sessions-B9pNuxdT.js.map +1 -0
- package/dist/settings-C45hDliX.js +253 -0
- package/dist/settings-C45hDliX.js.map +1 -0
- package/dist/{transport-PfFnt-Ld.d.ts → settings-NgGwF7Qt.d.ts} +14 -208
- package/dist/{src-BZeu-SCD.js → src-DgCbZtIR.js} +4 -4
- package/dist/{src-BZeu-SCD.js.map → src-DgCbZtIR.js.map} +1 -1
- package/dist/stall-watchdog-BpRF2uwG.js +195 -0
- package/dist/stall-watchdog-BpRF2uwG.js.map +1 -0
- package/dist/state/index.d.ts +1 -1
- package/dist/store-DLeqKuj3.d.ts +310 -0
- package/dist/store-vgcPYo8K.js +432 -0
- package/dist/store-vgcPYo8K.js.map +1 -0
- package/dist/streams/index.d.ts +1 -1
- package/dist/streams/index.js +1 -1
- package/dist/{streams-DW-UCOUc.js → streams-CITClVer.js} +16 -3
- package/dist/streams-CITClVer.js.map +1 -0
- package/dist/{streams-Cmkj9QfW.d.ts → streams-fbG61qM8.d.ts} +2 -2
- package/dist/sub-routing.d.ts +1 -1
- package/dist/tasks/index.d.ts +1 -1
- package/dist/tasks/index.js +1 -1
- package/dist/{tasks-68DESxf0.js → tasks-CkTZNaV1.js} +2 -1
- package/dist/tasks-CkTZNaV1.js.map +1 -0
- package/dist/{tasks-9YxYtByh.d.ts → tasks-PtlB4Uyn.d.ts} +2 -2
- package/dist/tool-3PA8xjB_.js +421 -0
- package/dist/tool-3PA8xjB_.js.map +1 -0
- package/dist/tool-BPJEbwaX.d.ts +278 -0
- package/dist/transport-k2mFrtL8.d.ts +200 -0
- package/dist/turns-DCV3ycDl.js +317 -0
- package/dist/turns-DCV3ycDl.js.map +1 -0
- package/dist/voice/client.js +1 -1
- package/dist/voice/index.d.ts +2 -2
- package/dist/voice/index.js +1 -1
- package/dist/websearch/index.d.ts +58 -0
- package/dist/websearch/index.js +2 -0
- package/dist/websearch/tools/ai-sdk.d.ts +77 -0
- package/dist/websearch/tools/ai-sdk.js +46 -0
- package/dist/websearch/tools/ai-sdk.js.map +1 -0
- package/dist/websearch/tools/pi.d.ts +82 -0
- package/dist/websearch/tools/pi.js +89 -0
- package/dist/websearch/tools/pi.js.map +1 -0
- package/dist/websearch/tools/tanstack-ai.d.ts +71 -0
- package/dist/websearch/tools/tanstack-ai.js +46 -0
- package/dist/websearch/tools/tanstack-ai.js.map +1 -0
- package/dist/websockets/index.d.ts +12 -296
- package/dist/websockets/index.js +1 -1
- package/dist/{websockets-Ci-LZFHH.js → websockets-CmENGb-Z.js} +18 -4
- package/dist/websockets-CmENGb-Z.js.map +1 -0
- package/dist/{wire-types-CrjKvDyi.d.ts → wire-types-Cv0iwjk5.d.ts} +3 -51
- 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 +3 -0
- package/docs/harnesses/think.md +215 -0
- package/docs/index.md +2 -1
- package/docs/lifecycle.md +40 -0
- package/docs/search-the-web.md +133 -0
- package/package.json +117 -38
- package/dist/browser-tool-CQ10e6Kj.js.map +0 -1
- package/dist/channel-Bnm4S7T2.d.ts +0 -491
- package/dist/channels/ai-sdk.d.ts +0 -46
- package/dist/channels/ai-sdk.js +0 -120
- package/dist/channels/ai-sdk.js.map +0 -1
- package/dist/channels/email.js.map +0 -1
- package/dist/channels/index.d.ts +0 -233
- package/dist/channels/index.js +0 -608
- package/dist/channels/index.js.map +0 -1
- package/dist/channels/slack.js +0 -614
- package/dist/channels/slack.js.map +0 -1
- package/dist/channels/tanstack-ai.d.ts +0 -39
- package/dist/channels/tanstack-ai.js +0 -17
- package/dist/channels/tanstack-ai.js.map +0 -1
- package/dist/channels/telegram.js +0 -427
- package/dist/channels/telegram.js.map +0 -1
- package/dist/channels/voice.d.ts +0 -45
- package/dist/channels/voice.js +0 -122
- package/dist/channels/voice.js.map +0 -1
- package/dist/images-iiTDSyRu.js.map +0 -1
- package/dist/index-BB0kqhIz.d.ts +0 -101
- package/dist/ingress-BfetZbMO.js +0 -83
- package/dist/ingress-BfetZbMO.js.map +0 -1
- package/dist/internal-CYlgHl1l.js +0 -59
- package/dist/internal-CYlgHl1l.js.map +0 -1
- package/dist/models/ai-sdk/index.js.map +0 -1
- package/dist/protocol-kHsr-f0X.js.map +0 -1
- package/dist/sessions/index.js.map +0 -1
- package/dist/streams-DW-UCOUc.js.map +0 -1
- package/dist/surface-bZZJqBka.js +0 -17
- package/dist/surface-bZZJqBka.js.map +0 -1
- package/dist/tasks-68DESxf0.js.map +0 -1
- package/dist/tool-schema-CBjGPrsQ.js +0 -31
- package/dist/tool-schema-CBjGPrsQ.js.map +0 -1
- package/dist/websockets-Ci-LZFHH.js.map +0 -1
- package/docs/channels.md +0 -323
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
# Search the Web (Beta)
|
|
2
|
+
|
|
3
|
+
`agents/websearch` gives a model a `web_search` tool over Cloudflare's [Web Search API](https://developers.cloudflare.com/web-search/), called through the `AI` binding and billed by the account's AI Gateway. The same tool is available for the pi harness, the AI SDK, and TanStack AI.
|
|
4
|
+
|
|
5
|
+
This page covers what the SDK adds on top of the API. For the binding, the providers, pricing, payment, and the error codes, see the [Web Search API docs](https://developers.cloudflare.com/web-search/).
|
|
6
|
+
|
|
7
|
+
> **Beta** — this feature may have breaking changes in future releases.
|
|
8
|
+
|
|
9
|
+
## Quick Start
|
|
10
|
+
|
|
11
|
+
You need:
|
|
12
|
+
|
|
13
|
+
- An `AI` binding: `"ai": { "binding": "AI" }` in `wrangler.jsonc`.
|
|
14
|
+
- workerd 1.20260924.1 or later, which is where `env.AI.websearch()` arrived. It ships with wrangler 4.141.0 and `@cloudflare/vite-plugin` 1.60.2.
|
|
15
|
+
- AI Gateway credits or a provider key on the gateway, in the account the Worker runs in. That account pays for every search. The `AI` binding always calls Cloudflare, so under `wrangler dev` searches run against, and bill, the account you are logged in to.
|
|
16
|
+
|
|
17
|
+
Then add the tool to your harness. Every adapter takes the same options; the TanStack AI adapter also takes `name`, because TanStack AI tools carry their name in the definition.
|
|
18
|
+
|
|
19
|
+
Pi harness:
|
|
20
|
+
|
|
21
|
+
```ts
|
|
22
|
+
import { webSearchTool } from "agents/websearch/pi";
|
|
23
|
+
|
|
24
|
+
this.registry.install({
|
|
25
|
+
name: "tools",
|
|
26
|
+
tools: [webSearchTool({ binding: this.env.AI, provider: "exa" })]
|
|
27
|
+
});
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
AI SDK:
|
|
31
|
+
|
|
32
|
+
```ts
|
|
33
|
+
import { webSearchTool } from "agents/websearch/ai-sdk";
|
|
34
|
+
|
|
35
|
+
const result = streamText({
|
|
36
|
+
model,
|
|
37
|
+
tools: { web_search: webSearchTool({ binding: this.env.AI }) },
|
|
38
|
+
messages
|
|
39
|
+
});
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
If you convert UI messages yourself, pass the same tools to `convertToModelMessages(messages, { tools })`. Without them, the AI SDK sends earlier search results back to the model as the full JSON response instead of the trimmed text. `AiSdkHarness` does this for you.
|
|
43
|
+
|
|
44
|
+
TanStack AI:
|
|
45
|
+
|
|
46
|
+
```ts
|
|
47
|
+
import { webSearchTool } from "agents/websearch/tanstack-ai";
|
|
48
|
+
|
|
49
|
+
const tools = [webSearchTool({ binding: this.env.AI })];
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
## Options
|
|
53
|
+
|
|
54
|
+
The model's input is `{ query, limit? }` and nothing else. The host fixes everything that affects cost or data handling. An invalid `limit`, `maxDescriptionChars`, `timeoutMs`, or `byokAlias` throws a `RangeError` when the tool is created:
|
|
55
|
+
|
|
56
|
+
| Option | Default | Notes |
|
|
57
|
+
| --------------------- | -------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
58
|
+
| `binding` | — | The `AI` binding. Or pass `source` instead (see [Other sources](#other-sources)). |
|
|
59
|
+
| `gateway` | `"default"` | AI Gateway id. |
|
|
60
|
+
| `provider` | platform default | `"ceramic"`, `"exa"`, or `"linkup"`. The model cannot choose or change it. |
|
|
61
|
+
| `byokAlias` | — | Bill a provider key stored on the gateway. Passed through as the API defines it. |
|
|
62
|
+
| `limit` | `5` | Results per search when the model does not ask for a count, and the most it gets when it asks for more. The tool description tells the model this number. |
|
|
63
|
+
| `maxDescriptionChars` | `600` | Per-result description length in the model's view. `Infinity` passes descriptions through whole. |
|
|
64
|
+
| `description` | built-in description | Replaces the tool description the model sees. |
|
|
65
|
+
| `timeoutMs` | `30000` | Give up on a search after this long, as a retryable `web_search_timeout` failure. |
|
|
66
|
+
|
|
67
|
+
## Model Interface
|
|
68
|
+
|
|
69
|
+
The model gets text: a numbered list of title, URL, and description, with descriptions trimmed to `maxDescriptionChars`. Some providers return descriptions of several thousand characters per result, so the default keeps a five-result search to a few kilobytes of context.
|
|
70
|
+
|
|
71
|
+
```
|
|
72
|
+
3 results for "cloudflare web search api":
|
|
73
|
+
|
|
74
|
+
1. Introducing the Web Search API
|
|
75
|
+
https://blog.cloudflare.com/introducing-web-search-api/
|
|
76
|
+
Today we are launching the Web Search API in open beta…
|
|
77
|
+
|
|
78
|
+
2. …
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
The host gets the full API response, without trimming, as `WebSearchToolOutput`: `items` with their whole descriptions and every documented field, `metadata` with `requestId` and `latencyMs`, plus `provider`. Items without a URL are dropped, a missing title falls back to the URL, and fields the API does not document are left out:
|
|
82
|
+
|
|
83
|
+
- **Pi**: in the tool result's `details`, as `{ ok: true, output }`. The tool is `replay: "safe"`: if a search is interrupted mid-call, for example by an eviction, pi runs it again when the session recovers, and that is a second billed search. Completed results are stored and not searched again.
|
|
84
|
+
- **AI SDK**: as the return value of `execute`, so `onFinish`, UI message parts, and logs see the full response. `toModelOutput` renders the text for the model.
|
|
85
|
+
- **TanStack AI**: the server tool returns the rendered text, so the host gets the same text the model does.
|
|
86
|
+
|
|
87
|
+
`renderWebSearchResults(output, { maxDescriptionChars })` from `agents/websearch` is the renderer, if you want the same text elsewhere.
|
|
88
|
+
|
|
89
|
+
The API has no pagination. The tool description tells the model to search again with a rephrased query when it wants more or different results.
|
|
90
|
+
|
|
91
|
+
## Failures
|
|
92
|
+
|
|
93
|
+
A failed search becomes a `WebSearchError` with `status`, `code`, `retryable`, and `requestId` (AI Gateway's id for the request, for the gateway log). Every error has a `code`: the API's own when it sends one, for example `web_search_payment_required`, otherwise one derived from the HTTP status, such as `web_search_rate_limited` or `web_search_unavailable`. On a runtime older than the one above, the binding has no `websearch()` and the search fails with code `web_search_unsupported_runtime`.
|
|
94
|
+
|
|
95
|
+
The error's `message` is written for you, and can say to top up credits or configure a key. The model gets different text that tells it what to do next: fix the query, retry once, or carry on without search.
|
|
96
|
+
|
|
97
|
+
- **Pi**: the tool returns an error result with the model's text, and `details` is `{ ok: false, message, status, code, retryable, requestId }`.
|
|
98
|
+
- **AI SDK** and **TanStack AI**: the tool throws a `WebSearchError`, which is how those frameworks report tool errors. Its `message` is the model's text, and its `cause` is the original error with the API's detail.
|
|
99
|
+
|
|
100
|
+
Every adapter entry point re-exports `WebSearchError`, so `instanceof` checks do not need a second import.
|
|
101
|
+
|
|
102
|
+
If the harness cancels the call, the search is aborted and the abort propagates instead of becoming a failed result.
|
|
103
|
+
|
|
104
|
+
## Other sources
|
|
105
|
+
|
|
106
|
+
`createAIWebSearch` and `createHTTPWebSearch` from `agents/websearch` return a `WebSearchSource`: an object whose `search({ query, limit? }, { signal? })` returns the API response (`limit` defaults to 5), with no model involved. Use them from scheduled jobs, or outside Workers:
|
|
107
|
+
|
|
108
|
+
```ts
|
|
109
|
+
import { createHTTPWebSearch } from "agents/websearch";
|
|
110
|
+
|
|
111
|
+
const search = createHTTPWebSearch({
|
|
112
|
+
accountId: env.CF_ACCOUNT_ID,
|
|
113
|
+
apiToken: env.CF_API_TOKEN,
|
|
114
|
+
provider: "linkup"
|
|
115
|
+
});
|
|
116
|
+
const { items } = await search.search({
|
|
117
|
+
query: "cloudflare agents sdk",
|
|
118
|
+
limit: 3
|
|
119
|
+
});
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
Any `WebSearchSource` can be passed to a tool as `source` instead of `binding`. That is how tests substitute a fake, and how you wrap a source with caching or logging. Spread the source you wrap so its `provider` is kept:
|
|
123
|
+
|
|
124
|
+
```ts
|
|
125
|
+
webSearchTool({
|
|
126
|
+
source: {
|
|
127
|
+
search: async ({ query }) => ({
|
|
128
|
+
items: [{ url: "https://example.com", title: query }],
|
|
129
|
+
metadata: { query, requestId: "test", latencyMs: 0 }
|
|
130
|
+
})
|
|
131
|
+
}
|
|
132
|
+
});
|
|
133
|
+
```
|
package/package.json
CHANGED
|
@@ -9,7 +9,10 @@
|
|
|
9
9
|
"durable objects"
|
|
10
10
|
],
|
|
11
11
|
"type": "module",
|
|
12
|
-
"
|
|
12
|
+
"bin": {
|
|
13
|
+
"agents": "./dist/cli.js"
|
|
14
|
+
},
|
|
15
|
+
"version": "0.27.0",
|
|
13
16
|
"license": "MIT",
|
|
14
17
|
"repository": {
|
|
15
18
|
"directory": "packages/agents",
|
|
@@ -42,10 +45,13 @@
|
|
|
42
45
|
"@cloudflare/codemode": "^0.5.3",
|
|
43
46
|
"@earendil-works/pi-ai": "^1.0.0",
|
|
44
47
|
"@earendil-works/pi-durable": "^1.0.0",
|
|
48
|
+
"@earendil-works/pi-tui": "1.0.0",
|
|
45
49
|
"@modelcontextprotocol/client": "2.0.0",
|
|
46
50
|
"@modelcontextprotocol/conformance-v2": "npm:@modelcontextprotocol/conformance@0.2.0-alpha.10",
|
|
47
51
|
"@modelcontextprotocol/sdk": "1.30.0",
|
|
48
52
|
"@modelcontextprotocol/server": "2.0.0",
|
|
53
|
+
"@opencode/plugin": "2.0.24",
|
|
54
|
+
"@opencode/sdk": "2.0.24",
|
|
49
55
|
"@tanstack/ai": "0.38.0",
|
|
50
56
|
"@types/react": "^19.2.17",
|
|
51
57
|
"@valibot/to-json-schema": "1.3.0",
|
|
@@ -54,6 +60,7 @@
|
|
|
54
60
|
"ai": "^7.0.0",
|
|
55
61
|
"chat": "^4.31.0",
|
|
56
62
|
"glob": "^13.0.6",
|
|
63
|
+
"highlight.js": "11.12.0",
|
|
57
64
|
"just-bash": "^3.0.2",
|
|
58
65
|
"react": "^19.2.7",
|
|
59
66
|
"teleproto": "^1.228.5",
|
|
@@ -69,6 +76,8 @@
|
|
|
69
76
|
"@modelcontextprotocol/client": "2.0.0",
|
|
70
77
|
"@modelcontextprotocol/sdk": "1.30.0",
|
|
71
78
|
"@modelcontextprotocol/server": "2.0.0",
|
|
79
|
+
"@opencode/plugin": "^2.0.24",
|
|
80
|
+
"@opencode/sdk": "^2.0.24",
|
|
72
81
|
"@tanstack/ai": ">=0.10.2 <1.0.0",
|
|
73
82
|
"@x402/core": "^2.0.0",
|
|
74
83
|
"@x402/evm": "^2.0.0",
|
|
@@ -95,6 +104,12 @@
|
|
|
95
104
|
"@earendil-works/pi-durable": {
|
|
96
105
|
"optional": true
|
|
97
106
|
},
|
|
107
|
+
"@opencode/plugin": {
|
|
108
|
+
"optional": true
|
|
109
|
+
},
|
|
110
|
+
"@opencode/sdk": {
|
|
111
|
+
"optional": true
|
|
112
|
+
},
|
|
98
113
|
"@tanstack/ai": {
|
|
99
114
|
"optional": true
|
|
100
115
|
},
|
|
@@ -167,11 +182,46 @@
|
|
|
167
182
|
"import": "./dist/lifecycle/index.js",
|
|
168
183
|
"require": "./dist/lifecycle/index.js"
|
|
169
184
|
},
|
|
185
|
+
"./harness/ai-sdk": {
|
|
186
|
+
"types": "./dist/harness/ai-sdk/index.d.ts",
|
|
187
|
+
"import": "./dist/harness/ai-sdk/index.js",
|
|
188
|
+
"require": "./dist/harness/ai-sdk/index.js"
|
|
189
|
+
},
|
|
190
|
+
"./harness/opencode": {
|
|
191
|
+
"types": "./dist/harness/opencode/index.d.ts",
|
|
192
|
+
"import": "./dist/harness/opencode/index.js",
|
|
193
|
+
"require": "./dist/harness/opencode/index.js"
|
|
194
|
+
},
|
|
170
195
|
"./harness/pi": {
|
|
171
196
|
"types": "./dist/harness/pi/index.d.ts",
|
|
172
197
|
"import": "./dist/harness/pi/index.js",
|
|
173
198
|
"require": "./dist/harness/pi/index.js"
|
|
174
199
|
},
|
|
200
|
+
"./harness/think": {
|
|
201
|
+
"types": "./dist/harness/think/index.d.ts",
|
|
202
|
+
"import": "./dist/harness/think/index.js",
|
|
203
|
+
"require": "./dist/harness/think/index.js"
|
|
204
|
+
},
|
|
205
|
+
"./harness/container": {
|
|
206
|
+
"types": "./dist/harness/container/index.d.ts",
|
|
207
|
+
"import": "./dist/harness/container/index.js",
|
|
208
|
+
"require": "./dist/harness/container/index.js"
|
|
209
|
+
},
|
|
210
|
+
"./harness/container/daemon": {
|
|
211
|
+
"types": "./dist/harness/container/daemon/index.d.ts",
|
|
212
|
+
"import": "./dist/harness/container/daemon/index.js",
|
|
213
|
+
"require": "./dist/harness/container/daemon/index.js"
|
|
214
|
+
},
|
|
215
|
+
"./harness/container/runtime": {
|
|
216
|
+
"types": "./dist/harness/container/runtime/index.d.ts",
|
|
217
|
+
"import": "./dist/harness/container/runtime/index.js",
|
|
218
|
+
"require": "./dist/harness/container/runtime/index.js"
|
|
219
|
+
},
|
|
220
|
+
"./harness/store": {
|
|
221
|
+
"types": "./dist/harness/store/index.d.ts",
|
|
222
|
+
"import": "./dist/harness/store/index.js",
|
|
223
|
+
"require": "./dist/harness/store/index.js"
|
|
224
|
+
},
|
|
175
225
|
"./agent-tools": {
|
|
176
226
|
"types": "./dist/agent-tools.d.ts",
|
|
177
227
|
"import": "./dist/agent-tools.js",
|
|
@@ -212,6 +262,11 @@
|
|
|
212
262
|
"import": "./dist/models/ai-sdk/index.js",
|
|
213
263
|
"require": "./dist/models/ai-sdk/index.js"
|
|
214
264
|
},
|
|
265
|
+
"./models/opencode": {
|
|
266
|
+
"types": "./dist/models/opencode/index.d.ts",
|
|
267
|
+
"import": "./dist/models/opencode/index.js",
|
|
268
|
+
"require": "./dist/models/opencode/index.js"
|
|
269
|
+
},
|
|
215
270
|
"./models/pi-ai": {
|
|
216
271
|
"types": "./dist/models/pi-ai/index.d.ts",
|
|
217
272
|
"import": "./dist/models/pi-ai/index.js",
|
|
@@ -337,6 +392,26 @@
|
|
|
337
392
|
"import": "./dist/browser/tanstack-ai.js",
|
|
338
393
|
"require": "./dist/browser/tanstack-ai.js"
|
|
339
394
|
},
|
|
395
|
+
"./websearch": {
|
|
396
|
+
"types": "./dist/websearch/index.d.ts",
|
|
397
|
+
"import": "./dist/websearch/index.js",
|
|
398
|
+
"require": "./dist/websearch/index.js"
|
|
399
|
+
},
|
|
400
|
+
"./websearch/pi": {
|
|
401
|
+
"types": "./dist/websearch/tools/pi.d.ts",
|
|
402
|
+
"import": "./dist/websearch/tools/pi.js",
|
|
403
|
+
"require": "./dist/websearch/tools/pi.js"
|
|
404
|
+
},
|
|
405
|
+
"./websearch/ai-sdk": {
|
|
406
|
+
"types": "./dist/websearch/tools/ai-sdk.d.ts",
|
|
407
|
+
"import": "./dist/websearch/tools/ai-sdk.js",
|
|
408
|
+
"require": "./dist/websearch/tools/ai-sdk.js"
|
|
409
|
+
},
|
|
410
|
+
"./websearch/tanstack-ai": {
|
|
411
|
+
"types": "./dist/websearch/tools/tanstack-ai.d.ts",
|
|
412
|
+
"import": "./dist/websearch/tools/tanstack-ai.js",
|
|
413
|
+
"require": "./dist/websearch/tools/tanstack-ai.js"
|
|
414
|
+
},
|
|
340
415
|
"./voice": {
|
|
341
416
|
"types": "./dist/voice/index.d.ts",
|
|
342
417
|
"import": "./dist/voice/index.js",
|
|
@@ -377,40 +452,40 @@
|
|
|
377
452
|
"import": "./dist/voice/text.js",
|
|
378
453
|
"require": "./dist/voice/text.js"
|
|
379
454
|
},
|
|
380
|
-
"./channels": {
|
|
381
|
-
"types": "./dist/channels/index.d.ts",
|
|
382
|
-
"import": "./dist/channels/index.js",
|
|
383
|
-
"require": "./dist/channels/index.js"
|
|
384
|
-
},
|
|
385
|
-
"./channels/email": {
|
|
386
|
-
"types": "./dist/channels/email.d.ts",
|
|
387
|
-
"import": "./dist/channels/email.js",
|
|
388
|
-
"require": "./dist/channels/email.js"
|
|
389
|
-
},
|
|
390
|
-
"./channels/slack": {
|
|
391
|
-
"types": "./dist/channels/slack.d.ts",
|
|
392
|
-
"import": "./dist/channels/slack.js",
|
|
393
|
-
"require": "./dist/channels/slack.js"
|
|
394
|
-
},
|
|
395
|
-
"./channels/telegram": {
|
|
396
|
-
"types": "./dist/channels/telegram.d.ts",
|
|
397
|
-
"import": "./dist/channels/telegram.js",
|
|
398
|
-
"require": "./dist/channels/telegram.js"
|
|
399
|
-
},
|
|
400
|
-
"./channels/
|
|
401
|
-
"types": "./dist/channels/
|
|
402
|
-
"import": "./dist/channels/
|
|
403
|
-
"require": "./dist/channels/
|
|
404
|
-
},
|
|
405
|
-
"./channels/
|
|
406
|
-
"types": "./dist/channels/
|
|
407
|
-
"import": "./dist/channels/
|
|
408
|
-
"require": "./dist/channels/
|
|
409
|
-
},
|
|
410
|
-
"./channels/
|
|
411
|
-
"types": "./dist/channels/
|
|
412
|
-
"import": "./dist/channels/
|
|
413
|
-
"require": "./dist/channels/
|
|
455
|
+
"./experimental/channels": {
|
|
456
|
+
"types": "./dist/experimental/channels/index.d.ts",
|
|
457
|
+
"import": "./dist/experimental/channels/index.js",
|
|
458
|
+
"require": "./dist/experimental/channels/index.js"
|
|
459
|
+
},
|
|
460
|
+
"./experimental/channels/email": {
|
|
461
|
+
"types": "./dist/experimental/channels/email/index.d.ts",
|
|
462
|
+
"import": "./dist/experimental/channels/email/index.js",
|
|
463
|
+
"require": "./dist/experimental/channels/email/index.js"
|
|
464
|
+
},
|
|
465
|
+
"./experimental/channels/slack": {
|
|
466
|
+
"types": "./dist/experimental/channels/slack/index.d.ts",
|
|
467
|
+
"import": "./dist/experimental/channels/slack/index.js",
|
|
468
|
+
"require": "./dist/experimental/channels/slack/index.js"
|
|
469
|
+
},
|
|
470
|
+
"./experimental/channels/telegram": {
|
|
471
|
+
"types": "./dist/experimental/channels/telegram/index.d.ts",
|
|
472
|
+
"import": "./dist/experimental/channels/telegram/index.js",
|
|
473
|
+
"require": "./dist/experimental/channels/telegram/index.js"
|
|
474
|
+
},
|
|
475
|
+
"./experimental/channels/web": {
|
|
476
|
+
"types": "./dist/experimental/channels/web/index.d.ts",
|
|
477
|
+
"import": "./dist/experimental/channels/web/index.js",
|
|
478
|
+
"require": "./dist/experimental/channels/web/index.js"
|
|
479
|
+
},
|
|
480
|
+
"./experimental/channels/web/client": {
|
|
481
|
+
"types": "./dist/experimental/channels/web/client.d.ts",
|
|
482
|
+
"import": "./dist/experimental/channels/web/client.js",
|
|
483
|
+
"require": "./dist/experimental/channels/web/client.js"
|
|
484
|
+
},
|
|
485
|
+
"./experimental/channels/web/ai-sdk": {
|
|
486
|
+
"types": "./dist/experimental/channels/web/ai-sdk.d.ts",
|
|
487
|
+
"import": "./dist/experimental/channels/web/ai-sdk.js",
|
|
488
|
+
"require": "./dist/experimental/channels/web/ai-sdk.js"
|
|
414
489
|
},
|
|
415
490
|
"./tsconfig": "./agents.tsconfig.json",
|
|
416
491
|
"./vite": {
|
|
@@ -453,7 +528,8 @@
|
|
|
453
528
|
],
|
|
454
529
|
"outputs": [
|
|
455
530
|
"{projectRoot}/dist",
|
|
456
|
-
"{projectRoot}/docs"
|
|
531
|
+
"{projectRoot}/docs",
|
|
532
|
+
"{projectRoot}/src/harness/container/daemon-source.generated.ts"
|
|
457
533
|
]
|
|
458
534
|
}
|
|
459
535
|
}
|
|
@@ -467,11 +543,12 @@
|
|
|
467
543
|
"test:voice:workers": "vitest --project voice-workers",
|
|
468
544
|
"test:voice:react": "vitest --project voice-react",
|
|
469
545
|
"test:channels": "vitest --project channels",
|
|
470
|
-
"test:channels:live": "vitest --run -c src/channels/vitest.live.config.ts",
|
|
471
546
|
"test:browser": "vitest run --config src/browser-tests/vitest.config.ts",
|
|
472
547
|
"test:workers": "vitest --project workers",
|
|
473
548
|
"test:chat": "vitest --project chat",
|
|
549
|
+
"test:harness:opencode": "vitest --project harness-opencode",
|
|
474
550
|
"test:harness:pi": "vitest --project harness-pi",
|
|
551
|
+
"test:harness:container": "vitest --project harness-container --project harness-container-runtime",
|
|
475
552
|
"test:webmcp": "vitest --project webmcp",
|
|
476
553
|
"test:x402": "vitest --project x402",
|
|
477
554
|
"test:e2e": "vitest --run -c src/e2e-tests/vitest.config.ts",
|
|
@@ -485,6 +562,8 @@
|
|
|
485
562
|
"test:conformance:server:mcp-agent": "bash conformance/run.sh server-mcp-agent",
|
|
486
563
|
"test:conformance:server:handler": "bash conformance/run.sh server-handler",
|
|
487
564
|
"test:conformance:server:handler:legacy-compat": "bash conformance/run.sh server-handler-legacy-compat",
|
|
488
|
-
"test:conformance:server:handler:legacy": "bash conformance/run.sh server-handler-legacy"
|
|
565
|
+
"test:conformance:server:handler:legacy": "bash conformance/run.sh server-handler-legacy",
|
|
566
|
+
"test:harness:think": "vitest --project harness-think",
|
|
567
|
+
"build:daemon": "tsx ./scripts/build-daemon.ts"
|
|
489
568
|
}
|
|
490
569
|
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"browser-tool-CQ10e6Kj.js","names":[],"sources":["../src/browser/session-connector.ts","../src/browser/browser-tool.ts"],"sourcesContent":["import {\n CodemodeConnector,\n type ConnectorTool,\n type ConnectorTools,\n type ToolExecuteContext\n} from \"@cloudflare/codemode\";\nimport { validateConnectorArgs } from \"./connector-validation\";\nimport {\n CDP_METHOD_NOT_FOUND,\n CdpProtocolError,\n type CdpConnection\n} from \"./cdp-connection\";\nimport type { BrowserConnection } from \"./browser\";\nimport type { SearchableCdpSpec } from \"./spec\";\n\n/**\n * Where a {@link BrowserSessionConnector} gets its browser. Usually a\n * `Browser` installed on the host's Lifecycle.\n */\nexport interface BrowserSource {\n /** The browser's name, for log messages. */\n readonly name: string;\n /** Reattach to the browser (or replace it) and open a CDP connection. */\n connect(): Promise<BrowserConnection>;\n}\n\nexport interface BrowserSessionConnectorOptions {\n /** The persistent browser this connector drives. */\n browser: BrowserSource;\n}\n\n/** A tab a page opened on its own during an execution. */\nexport interface BrowserNewTab {\n targetId: string;\n url?: string;\n title?: string;\n}\n\n/**\n * What happened to the browser during one execution, beyond the code's own\n * result — read by the tool after the run via\n * {@link BrowserSessionConnector.takeReport}.\n */\nexport interface BrowserExecutionReport {\n /** The browser was replaced before this run; earlier page state is gone. */\n restarted: boolean;\n /** Tabs the page opened itself (popups, `target=_blank`). */\n newTabs: BrowserNewTab[];\n}\n\n/** `sessionId` value that addresses the tab the agent is working in. */\nexport const ACTIVE_PAGE_SESSION = \"active\";\n\n/**\n * `cdp.attachToTarget` returns `{ sessionId: \"target:<targetId>\" }` — a\n * stable handle rather than a connection-scoped CDP session id, so replayed\n * code computes identical arguments. `send` resolves it on the live socket.\n */\nconst ATTACH_HANDLE_PREFIX = \"target:\";\n\n/** Chrome's JSON-RPC code for a CDP session id it doesn't know. */\nconst CDP_SESSION_NOT_FOUND = -32001;\n\n/** {@link BrowserSessionConnector} `#liveParams`: nothing to detach. */\nconst DETACHED = Symbol(\"detached\");\n\n/** Reports awaiting their tool call; bounded in case a caller never reads. */\nconst MAX_PENDING_REPORTS = 100;\n\n/**\n * Commands that would end the browser. The host owns its lifetime, so the\n * model can't close it out from under the agent (and lose its logins).\n */\nconst BROWSER_LIFETIME_COMMANDS = new Set([\n \"Browser.close\",\n \"Browser.crash\",\n \"Browser.crashGpuProcess\"\n]);\n\n/** A CDP target id — for this connector, a tab. */\ntype TargetId = string & { readonly __brand: \"TargetId\" };\n\n/** A CDP session id from `Target.attachToTarget`, valid on one socket only. */\ntype LiveSessionId = string & { readonly __brand: \"LiveSessionId\" };\n\n/** The stable `sessionId` handle `cdp.attachToTarget` gives the model. */\ntype AttachHandle = `${typeof ATTACH_HANDLE_PREFIX}${string}`;\n\ninterface TargetInfo {\n targetId: TargetId;\n type: string;\n url?: string;\n title?: string;\n /** The tab that opened this one (popups, `target=_blank` links). */\n openerId?: TargetId;\n}\n\n/** Per-execution state for one pass. Dropped when the pass ends. */\ninterface ExecutionState {\n connected: BrowserConnection;\n /** Live CDP session per target, valid on this socket only. */\n attached: Map<TargetId, LiveSessionId>;\n /** Page targets open when the pass connected. */\n initialPages: Set<TargetId>;\n /** The tab `\"active\"` resolves to — decided lazily on first use. */\n activeTargetId?: TargetId;\n /** Whether {@link activeTargetId} was decided (vs. never needed). */\n activeResolved: boolean;\n}\n\nconst INSTRUCTIONS = [\n \"This browser persists between executions: tabs, cookies, and logins you leave behind are still there next time. It is managed for you — there is nothing to start, close, or reset.\",\n \"The browser can still be replaced between runs (idle timeout, crash) — even between the passes of a run that paused for approval. The tool result then says restarted: true, and earlier tabs, cookies, and logins are gone. Don't assume a page from an earlier run is still there: check where you are before an action that matters (submitting a form, making a purchase).\",\n 'Page-scoped commands (Page.*, Runtime.*, DOM.*, Input.*, Network.*, Emulation.*) need sessionId: \"active\" — the tab you are working in, which stays the same across executions. Example: await cdp.send({ method: \"Page.navigate\", params: { url }, sessionId: \"active\" }).',\n \"Browser- and Target-scoped commands (Target.getTargets, Target.createTarget, Browser.getVersion) take no sessionId.\",\n 'Opening a tab with Target.createTarget makes it the active tab. To switch to another open tab, call cdp.attachToTarget({ targetId }): it becomes active, and the returned sessionId works like \"active\" for that tab, in this run and later ones. A raw Target.attachToTarget sent through cdp.send returns Chrome\\'s own sessionId, which only lasts for the current run.',\n \"Tabs a page opens on its own (popups, target=_blank links) do not become active; the tool result lists them as newTabs.\",\n \"cdp.send returns the CDP method result directly, not the JSON-RPC envelope: Target.createTarget returns { targetId }, Runtime.evaluate returns { result: { value } }, Page.captureScreenshot returns { data }.\",\n \"Issue CDP calls sequentially — never in parallel (no Promise.all): call order is recorded for durable replay.\",\n \"Page.navigate resolves before the page finishes loading. Poll Runtime.evaluate of document.readyState until it is 'complete' before reading the page.\",\n \"Use cdp.spec() to discover commands, events, and types when unsure. If a command fails or times out, check cdp.getDebugLog() for recent protocol traffic.\",\n \"Return small results. Write large page dumps to a file or workspace and pass references around.\"\n].join(\"\\n\");\n\n/**\n * Codemode connector exposing one host-named, persistent browser over the\n * Chrome DevTools Protocol as the `cdp` global.\n *\n * The model never manages sessions: every execution reattaches to the\n * browser (or gets a replacement, reported as `restarted`), and\n * `sessionId: \"active\"` addresses the tab it last worked in. The active tab\n * is stored on the browser's record, so it survives between executions for as\n * long as the tab does.\n *\n * The CDP socket is per pass: opened on the first call, closed when the pass\n * ends. The browser itself outlives the execution.\n */\nexport class BrowserSessionConnector extends CodemodeConnector {\n readonly #browser: BrowserSource;\n #states = new Map<string, ExecutionState>();\n #connecting = new Map<string, Promise<ExecutionState>>();\n /**\n * In memory, on this instance. An execution resumed after an approval\n * pause may run on a fresh connector, whose report starts over. Nothing\n * pauses today — the browser tool wires no approval tools — so reporting\n * across a resume is left for when approvals are added.\n *\n * The same goes for raw CDP session ids from `Target.attachToTarget` sent\n * through `send`: they belong to one pass's socket, so a replay after a\n * pause would reuse a dead id. The stable handles from `attachToTarget`\n * are the replay-safe path.\n */\n #reports = new Map<string, BrowserExecutionReport>();\n\n constructor(\n ctx: DurableObjectState | ExecutionContext,\n options: BrowserSessionConnectorOptions\n ) {\n super(ctx, {});\n this.#browser = options.browser;\n }\n\n name(): string {\n return \"cdp\";\n }\n\n protected instructions(): string {\n return INSTRUCTIONS;\n }\n\n protected override tool(name: string, tool: ConnectorTool): ConnectorTool {\n return validateConnectorArgs(this.name(), name, tool);\n }\n\n protected tools(): ConnectorTools {\n return {\n send: {\n description:\n 'Send a CDP command and return its method result directly. Pass sessionId: \"active\" for page-scoped commands; omit it for Browser/Target commands.',\n inputSchema: {\n type: \"object\",\n properties: {\n method: {\n type: \"string\",\n description: 'CDP method, e.g. \"Page.navigate\"'\n },\n params: {\n type: \"object\",\n description: \"CDP command parameters\"\n },\n sessionId: {\n type: \"string\",\n description:\n '\"active\" for the current tab, or a handle from attachToTarget. Omit for Browser/Target commands.'\n },\n timeoutMs: {\n type: \"number\",\n description: \"Per-command timeout override in milliseconds\"\n }\n },\n required: [\"method\"]\n },\n execute: async (args, ctx) => {\n const { method, params, sessionId, timeoutMs } = args as {\n method: string;\n params?: Record<string, unknown>;\n sessionId?: string;\n timeoutMs?: number;\n };\n if (BROWSER_LIFETIME_COMMANDS.has(method)) {\n throw new Error(\n `${method} is not available: this browser is managed for you ` +\n `and persists between runs. To close a tab, send ` +\n `Target.closeTarget with its targetId.`\n );\n }\n const state = await this.#state(this.#executionId(ctx));\n const live = await this.#resolveSessionId(state, sessionId);\n const liveParams = this.#liveParams(state, method, params);\n if (liveParams === DETACHED) return {};\n let result: unknown;\n try {\n result = await state.connected.cdp.send(method, liveParams, {\n sessionId: live,\n timeoutMs\n });\n } catch (error) {\n throw await this.#teach(state, error, method, sessionId);\n }\n this.#observe(state, method, liveParams, result);\n return result;\n }\n },\n\n attachToTarget: {\n description:\n \"Switch to an open tab: make it the active tab and return { sessionId } — a handle you can pass to page-scoped send calls for that tab.\",\n inputSchema: {\n type: \"object\",\n properties: {\n targetId: {\n type: \"string\",\n description: \"Target id from Target.getTargets/createTarget\"\n },\n timeoutMs: { type: \"number\" }\n },\n required: [\"targetId\"]\n },\n outputSchema: {\n type: \"object\",\n properties: {\n sessionId: {\n type: \"string\",\n description: \"Session handle for page-scoped send calls\"\n }\n },\n required: [\"sessionId\"]\n },\n execute: async (args, ctx) => {\n const { targetId, timeoutMs } = args as {\n targetId: TargetId;\n timeoutMs?: number;\n };\n const state = await this.#state(this.#executionId(ctx));\n await this.#attach(state, targetId, timeoutMs);\n this.#setActive(state, targetId);\n return { sessionId: attachHandle(targetId) };\n }\n },\n\n spec: {\n description:\n \"Return the searchable Chrome DevTools Protocol spec: domains with their commands, events, and types.\",\n replay: \"reexecute\",\n inputSchema: { type: \"object\", properties: {} },\n execute: async (_args, ctx): Promise<SearchableCdpSpec> => {\n const state = await this.#state(this.#executionId(ctx));\n return state.connected.spec();\n }\n },\n\n getDebugLog: {\n description:\n \"Return recent CDP protocol traffic (sends, receives, warnings) for this execution — useful to diagnose failures and timeouts.\",\n replay: \"reexecute\",\n inputSchema: {\n type: \"object\",\n properties: {\n limit: {\n type: \"number\",\n minimum: 1,\n description:\n \"Max entries to return, newest last (default 50; only the last 400 are kept)\"\n }\n }\n },\n execute: async (args, ctx) => {\n const { limit } = (args ?? {}) as { limit?: number };\n const state = await this.#state(this.#executionId(ctx));\n return state.connected.cdp.getDebugLog(limit);\n }\n },\n\n clearDebugLog: {\n description: \"Clear the CDP debug log for this execution.\",\n inputSchema: { type: \"object\", properties: {} },\n execute: async (_args, ctx) => {\n const state = await this.#state(this.#executionId(ctx));\n state.connected.cdp.clearDebugLog();\n return null;\n }\n }\n };\n }\n\n // ── Codemode execution hooks ─────────────────────────────────────────────\n\n /**\n * The pass is over: note tabs the page opened, save the active tab on the\n * browser's record, and drop the socket. The browser stays alive.\n */\n override async onPassEnd(executionId: string): Promise<void> {\n const state = this.#states.get(executionId);\n if (!state) return;\n this.#states.delete(executionId);\n try {\n const open = await this.#recordNewTabs(executionId, state);\n await this.#saveActiveTarget(state, open);\n } finally {\n state.connected.cdp.disconnect();\n }\n }\n\n /** Nothing per execution outlives the pass; the named browser persists. */\n override async disposeExecution(executionId: string): Promise<void> {\n const state = this.#states.get(executionId);\n if (!state) return;\n this.#states.delete(executionId);\n state.connected.cdp.disconnect();\n }\n\n /**\n * Take (and forget) what happened to the browser during an execution.\n * `undefined` when the execution never touched the browser. Covers the\n * passes this instance ran; see the note on `#reports`.\n */\n takeReport(executionId: string): BrowserExecutionReport | undefined {\n const report = this.#reports.get(executionId);\n this.#reports.delete(executionId);\n return report;\n }\n\n // ── Internals ────────────────────────────────────────────────────────────\n\n #executionId(ctx: ToolExecuteContext | undefined): string {\n if (!ctx?.executionId) {\n throw new Error(\"Browser tools must run inside a codemode execution\");\n }\n return ctx.executionId;\n }\n\n /**\n * Connect once per pass. Concurrent first calls (model code that uses\n * Promise.all despite the instructions) share one connect.\n */\n #state(executionId: string): Promise<ExecutionState> {\n const existing = this.#states.get(executionId);\n if (existing) return Promise.resolve(existing);\n const inFlight = this.#connecting.get(executionId);\n if (inFlight) return inFlight;\n const promise = this.#connect(executionId).finally(() => {\n this.#connecting.delete(executionId);\n });\n this.#connecting.set(executionId, promise);\n return promise;\n }\n\n async #connect(executionId: string): Promise<ExecutionState> {\n const connected = await this.#browser.connect();\n let initialPages: TargetInfo[];\n try {\n initialPages = await this.#pages(connected.cdp);\n } catch (error) {\n connected.cdp.disconnect();\n throw error;\n }\n const state: ExecutionState = {\n connected,\n attached: new Map(),\n initialPages: new Set(initialPages.map((page) => page.targetId)),\n activeResolved: false\n };\n this.#states.set(executionId, state);\n this.#report(executionId, connected.restarted);\n return state;\n }\n\n #report(executionId: string, restarted: boolean): BrowserExecutionReport {\n let report = this.#reports.get(executionId);\n if (!report) {\n report = { restarted, newTabs: [] };\n this.#reports.set(executionId, report);\n if (this.#reports.size > MAX_PENDING_REPORTS) {\n const oldest = this.#reports.keys().next().value;\n if (oldest !== undefined) this.#reports.delete(oldest);\n }\n }\n // A replacement on any pass means earlier page state is gone.\n report.restarted ||= restarted;\n return report;\n }\n\n /**\n * Add tabs the page opened this pass to the execution's report, and drop\n * earlier ones that have since closed: `newTabs` lists page-opened tabs\n * still open when the execution ends, across every pass. Returns the open\n * tabs, or `undefined` when the browser couldn't be asked.\n */\n async #recordNewTabs(\n executionId: string,\n state: ExecutionState\n ): Promise<Set<TargetId> | undefined> {\n let pages: TargetInfo[];\n try {\n pages = await this.#pages(state.connected.cdp);\n } catch (error) {\n this.#warn(\"list the open tabs\", error);\n return undefined;\n }\n const report = this.#report(executionId, state.connected.restarted);\n const opened = new Set<string>(report.newTabs.map((tab) => tab.targetId));\n for (const page of pages) {\n // Chrome sets openerId only on tabs a page opened, never on\n // Target.createTarget tabs — including ones another execution sharing\n // this browser created meanwhile.\n if (!state.initialPages.has(page.targetId) && page.openerId) {\n opened.add(page.targetId);\n }\n }\n report.newTabs = pages\n .filter((page) => opened.has(page.targetId))\n .map(({ targetId, url, title }) => ({ targetId, url, title }));\n return new Set(pages.map((page) => page.targetId));\n }\n\n /**\n * Save the tab this pass settled on, forgetting one that has since closed.\n * Without the list of open tabs, save the choice unchecked: the next\n * execution checks the stored tab is still open before using it.\n */\n async #saveActiveTarget(\n state: ExecutionState,\n open: Set<TargetId> | undefined\n ): Promise<void> {\n const stored = state.connected.activeTargetId as TargetId | undefined;\n const candidate = state.activeResolved ? state.activeTargetId : stored;\n const active =\n candidate && (!open || open.has(candidate)) ? candidate : undefined;\n if (active === stored) return;\n try {\n await state.connected.setActiveTarget(active);\n } catch (error) {\n this.#warn(\"save the active tab\", error);\n }\n }\n\n #warn(action: string, error: unknown): void {\n console.warn(\n `[agents/browser] Failed to ${action} for browser \"${this.#browser.name}\"`,\n error\n );\n }\n\n async #pages(cdp: CdpConnection): Promise<TargetInfo[]> {\n const result = (await cdp.send(\"Target.getTargets\")) as {\n targetInfos?: TargetInfo[];\n };\n return (result?.targetInfos ?? []).filter((info) => info.type === \"page\");\n }\n\n async #resolveSessionId(\n state: ExecutionState,\n sessionId: string | undefined\n ): Promise<LiveSessionId | undefined> {\n if (sessionId === ACTIVE_PAGE_SESSION) {\n return this.#attach(state, await this.#activeTarget(state));\n }\n if (isAttachHandle(sessionId)) {\n return this.#attach(state, targetOfHandle(sessionId));\n }\n // Omitted, or a raw CDP session id the model got from send().\n return sessionId as LiveSessionId | undefined;\n }\n\n /**\n * Decide which tab `\"active\"` means, once per pass: the stored tab if it\n * is still open, else the only open tab, else a new blank tab when none\n * are open, else the first listed tab.\n */\n async #activeTarget(state: ExecutionState): Promise<TargetId> {\n if (state.activeTargetId) return state.activeTargetId;\n const pages = await this.#pages(state.connected.cdp);\n const stored = state.connected.activeTargetId;\n let targetId = pages.find((page) => page.targetId === stored)?.targetId;\n if (!targetId && pages.length === 0) {\n const created = (await state.connected.cdp.send(\"Target.createTarget\", {\n url: \"about:blank\"\n })) as { targetId: TargetId };\n targetId = created.targetId;\n }\n targetId ??= pages[0].targetId;\n this.#setActive(state, targetId);\n return targetId;\n }\n\n #setActive(state: ExecutionState, targetId: TargetId | undefined): void {\n state.activeTargetId = targetId;\n state.activeResolved = true;\n }\n\n async #attach(\n state: ExecutionState,\n targetId: TargetId,\n timeoutMs?: number\n ): Promise<LiveSessionId> {\n const existing = state.attached.get(targetId);\n if (existing) return existing;\n const live = (await state.connected.cdp.attachToTarget(targetId, {\n timeoutMs\n })) as LiveSessionId;\n state.attached.set(targetId, live);\n return live;\n }\n\n /** Track tab changes the model makes through raw Target commands. */\n #observe(\n state: ExecutionState,\n method: string,\n params: Record<string, unknown> | undefined,\n result: unknown\n ): void {\n const targetId =\n typeof params?.targetId === \"string\"\n ? (params.targetId as TargetId)\n : undefined;\n if (method === \"Target.createTarget\") {\n const created = (result as { targetId?: unknown } | undefined)?.targetId;\n if (typeof created === \"string\") {\n this.#setActive(state, created as TargetId);\n }\n } else if (method === \"Target.attachToTarget\" && targetId) {\n this.#setActive(state, targetId);\n } else if (method === \"Target.closeTarget\" && targetId) {\n state.attached.delete(targetId);\n // The next \"active\" use picks a tab afresh.\n if (state.activeTargetId === targetId) state.activeTargetId = undefined;\n } else if (method === \"Target.detachFromTarget\") {\n // Forget a session the model detached, so the next use reattaches.\n for (const [target, live] of state.attached) {\n if (target === targetId || live === params?.sessionId) {\n state.attached.delete(target);\n }\n }\n }\n }\n\n /**\n * Swap a handle in `Target.detachFromTarget`'s `sessionId` param for the\n * live CDP session id. Returns {@link DETACHED} when the handle's tab isn't\n * attached on this socket, so there is nothing to detach.\n */\n #liveParams(\n state: ExecutionState,\n method: string,\n params: Record<string, unknown> | undefined\n ): Record<string, unknown> | undefined | typeof DETACHED {\n const handle = params?.sessionId;\n if (method !== \"Target.detachFromTarget\" || typeof handle !== \"string\") {\n return params;\n }\n if (!isAttachHandle(handle)) return params;\n const live = state.attached.get(targetOfHandle(handle));\n return live ? { ...params, sessionId: live } : DETACHED;\n }\n\n /**\n * Turn the common protocol mistakes into instructions: sending an\n * event as a command, and a page-scoped command without a session.\n */\n async #teach(\n state: ExecutionState,\n error: unknown,\n method: string,\n sessionId: string | undefined\n ): Promise<unknown> {\n if (!(error instanceof CdpProtocolError)) return error;\n if (\n error.code === CDP_SESSION_NOT_FOUND &&\n sessionId &&\n sessionId !== ACTIVE_PAGE_SESSION &&\n !isAttachHandle(sessionId)\n ) {\n return new Error(\n `${error.message}. CDP session ids don't carry over between runs. ` +\n `Use sessionId: \"active\" for the current tab, or the handle from ` +\n `cdp.attachToTarget({ targetId }) for another tab.`\n );\n }\n if (error.code !== CDP_METHOD_NOT_FOUND) return error;\n if (await this.#isEvent(state, method)) {\n return new Error(\n `${error.message}. '${method}' is a CDP *event*, not a command — it ` +\n `cannot be sent. To wait for page state, poll instead (e.g. ` +\n `Runtime.evaluate of document.readyState until \"complete\").`\n );\n }\n if (!sessionId) {\n return new Error(\n `${error.message}. '${method}' is page-scoped: pass sessionId: ` +\n `\"active\" to run it in the current tab — ` +\n `cdp.send({ method: \"${method}\", params, sessionId: \"active\" }).`\n );\n }\n return error;\n }\n\n async #isEvent(state: ExecutionState, method: string): Promise<boolean> {\n try {\n const spec = await state.connected.spec();\n const domain = method.split(\".\")[0];\n return spec.domains.some(\n (d) => d.name === domain && d.events.some((e) => e.event === method)\n );\n } catch {\n return false;\n }\n }\n}\n\nfunction attachHandle(targetId: TargetId): AttachHandle {\n return `${ATTACH_HANDLE_PREFIX}${targetId}`;\n}\n\nfunction isAttachHandle(\n sessionId: string | undefined\n): sessionId is AttachHandle {\n return sessionId?.startsWith(ATTACH_HANDLE_PREFIX) ?? false;\n}\n\nfunction targetOfHandle(handle: AttachHandle): TargetId {\n return handle.slice(ATTACH_HANDLE_PREFIX.length) as TargetId;\n}\n","/**\n * The harness-neutral core of `browserTool`, shared by the AI SDK\n * (`agents/browser/ai-sdk`) and TanStack AI (`agents/browser/tanstack-ai`)\n * adapters. Internal — not an entry point.\n */\nimport {\n createCodemodeRuntime,\n DynamicWorkerExecutor,\n type ProxyToolOutput\n} from \"@cloudflare/codemode\";\nimport {\n BrowserSessionConnector,\n type BrowserExecutionReport,\n type BrowserNewTab,\n type BrowserSource\n} from \"./session-connector\";\nimport { resolveCtx, transformBrowserResult } from \"./tool-helpers\";\n\nexport interface BrowserToolOptions {\n /**\n * The browser the tool drives — usually a `Browser` installed on the\n * host's Lifecycle. Tools built from the same `Browser` share it.\n */\n browser: BrowserSource;\n\n /**\n * WorkerLoader binding for sandboxed code execution.\n *\n * Requires `\"worker_loaders\": [{ \"binding\": \"LOADER\" }]` in wrangler.jsonc.\n */\n loader: WorkerLoader;\n\n /** Sandbox execution timeout in milliseconds. Defaults to 30000 (30s). */\n timeoutMs?: number;\n\n /**\n * Durable Object state for the codemode runtime facet. Optional inside an\n * Agent (resolved via `getCurrentAgent()`); pass it explicitly elsewhere.\n *\n * The worker must export the `CodemodeRuntime` class (the\n * `@cloudflare/codemode/vite` plugin does this automatically, or add\n * `export { CodemodeRuntime } from \"@cloudflare/codemode\"` to your entry).\n */\n ctx?: DurableObjectState;\n}\n\n/** The model's input to `browserTool`: JavaScript to run. */\nexport interface BrowserToolInput {\n code: string;\n}\n\n/**\n * The result of one `browserTool` run: the codemode execution result,\n * plus what happened to the browser.\n */\nexport type BrowserToolOutput = ProxyToolOutput & {\n /** The browser was replaced before this run; earlier tabs are gone. */\n restarted?: true;\n /** A sentence telling the model what `restarted` means for it. */\n notice?: string;\n /** Tabs the page opened itself (popups, `target=_blank` links). */\n newTabs?: BrowserNewTab[];\n};\n\nconst RESTARTED_NOTICE =\n \"The browser was restarted before this run (it expired or was closed): earlier tabs, logins, and page state are gone. Your code ran in a fresh browser — navigate again before relying on page state.\";\n\n/**\n * A codemode runtime name per browser. Browser names are host-chosen and\n * unrestricted; runtime names allow only `[a-zA-Z0-9_.-]`, so anything else\n * (including `.`, the escape) is hex-escaped.\n */\nfunction browserRuntimeName(name: string): string {\n const escaped = name.replace(\n /[^a-zA-Z0-9_-]/g,\n (char) => `.${char.codePointAt(0)?.toString(16)}.`\n );\n return `browser-tool_${escaped}`;\n}\n\n/** Add what happened to the browser to the codemode result. */\nfunction withBrowserReport(\n output: ProxyToolOutput,\n report: BrowserExecutionReport | undefined\n): BrowserToolOutput {\n if (!report) return output;\n return {\n ...output,\n ...(report.restarted\n ? { restarted: true as const, notice: RESTARTED_NOTICE }\n : {}),\n ...(report.newTabs.length > 0 ? { newTabs: report.newTabs } : {})\n };\n}\n\n/** Report sentences that must survive a screenshot's text summary. */\nexport function browserReportNotes(output: BrowserToolOutput): string[] {\n const notes: string[] = [];\n if (output.notice) notes.push(output.notice);\n if (output.newTabs?.length) {\n notes.push(\n `New tabs opened by the page: ${JSON.stringify(output.newTabs)}`\n );\n }\n return notes;\n}\n\n/**\n * Build the codemode runtime and connector for one `browserTool`, and wrap\n * `execute` so each result carries the browser report.\n */\nexport function createBrowserToolCore(\n options: BrowserToolOptions,\n adapter: {\n /** What the adapter does with screenshots, told to the model. */\n screenshotHint: string;\n }\n) {\n const ctx = resolveCtx(options);\n if (!ctx) {\n throw new Error(\n \"browserTool requires a Durable Object 'ctx' — pass it explicitly, or call from within an Agent so it can be resolved via getCurrentAgent()\"\n );\n }\n\n const connector = new BrowserSessionConnector(ctx, {\n browser: options.browser\n });\n const runtime = createCodemodeRuntime({\n ctx,\n executor: new DynamicWorkerExecutor({\n loader: options.loader,\n timeout: options.timeoutMs\n }),\n connectors: [connector],\n name: browserRuntimeName(options.browser.name),\n transformResult: transformBrowserResult\n });\n\n const codemodeTool = runtime.tool({\n connectorHints: {\n cdp: `A persistent browser over CDP — tabs and logins carry over between runs. Use sessionId: \"active\" for page commands. ${adapter.screenshotHint}`\n }\n });\n\n return {\n description: codemodeTool.description,\n inputSchema: codemodeTool.inputSchema,\n execute: async (\n input: BrowserToolInput,\n executeOptions?: unknown\n ): Promise<BrowserToolOutput> => {\n const output = await codemodeTool.execute(input, executeOptions);\n return withBrowserReport(\n output,\n connector.takeReport(output.executionId)\n );\n }\n };\n}\n"],"mappings":"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"}
|