agents 0.11.2 → 0.11.4
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/dist/browser/ai.js +1 -1
- package/dist/browser/index.js +1 -1
- package/dist/browser/tanstack-ai.js +1 -1
- package/dist/{classPrivateFieldGet2-BVdP0e3Z.js → classPrivateFieldGet2-DAZNVUKb.js} +5 -5
- package/dist/{client-PEDsNnfY.js → client-B_xdiZbn.js} +4 -3
- package/dist/{client-PEDsNnfY.js.map → client-B_xdiZbn.js.map} +1 -1
- package/dist/client.d.ts +1 -1
- package/dist/client.js +7 -7
- package/dist/client.js.map +1 -1
- package/dist/experimental/memory/session/index.js +3 -3
- package/dist/experimental/memory/session/index.js.map +1 -1
- package/dist/experimental/webmcp.d.ts +212 -0
- package/dist/experimental/webmcp.js +298 -0
- package/dist/experimental/webmcp.js.map +1 -0
- package/dist/{index-BBh8iKgk.d.ts → index-D9qo_Inc.d.ts} +38 -10
- package/dist/index.d.ts +1 -1
- package/dist/index.js +57 -34
- package/dist/index.js.map +1 -1
- package/dist/mcp/client.d.ts +1 -1
- package/dist/mcp/client.js +1 -1
- package/dist/mcp/index.d.ts +1 -1
- package/dist/mcp/index.js +5 -5
- package/dist/mcp/index.js.map +1 -1
- package/dist/react.d.ts +1 -1
- package/dist/react.js +8 -8
- package/dist/react.js.map +1 -1
- package/dist/{shared-BtPEbm_U.js → shared-BovR6hRc.js} +3 -3
- package/dist/{shared-BtPEbm_U.js.map → shared-BovR6hRc.js.map} +1 -1
- package/dist/workflows.d.ts +1 -1
- package/package.json +11 -4
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
//#region src/experimental/webmcp.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
|
4
|
+
* !! WARNING: EXPERIMENTAL — DO NOT USE IN PRODUCTION !!
|
|
5
|
+
* !! !!
|
|
6
|
+
* !! This API is under active development and WILL break between !!
|
|
7
|
+
* !! releases. Google's WebMCP API (navigator.modelContext) is still !!
|
|
8
|
+
* !! in early preview and subject to change. !!
|
|
9
|
+
* !! !!
|
|
10
|
+
* !! If you use this, pin your agents version and expect to rewrite !!
|
|
11
|
+
* !! your code when upgrading. !!
|
|
12
|
+
* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
|
13
|
+
*
|
|
14
|
+
* WebMCP adapter for Cloudflare Agents SDK.
|
|
15
|
+
*
|
|
16
|
+
* Bridges tools registered on an McpAgent server to Chrome's native
|
|
17
|
+
* navigator.modelContext API, so browser-native agents can discover
|
|
18
|
+
* and call them without extra infrastructure.
|
|
19
|
+
*
|
|
20
|
+
* @example Bridge a remote McpAgent endpoint into the page
|
|
21
|
+
* ```ts
|
|
22
|
+
* import { registerWebMcp } from "agents/experimental/webmcp";
|
|
23
|
+
*
|
|
24
|
+
* const handle = await registerWebMcp({ url: "/mcp" });
|
|
25
|
+
*
|
|
26
|
+
* // Later, to clean up:
|
|
27
|
+
* await handle.dispose();
|
|
28
|
+
* ```
|
|
29
|
+
*
|
|
30
|
+
* @example Mix in-page tools with bridged tools (recommended pattern)
|
|
31
|
+
* ```ts
|
|
32
|
+
* import { registerWebMcp } from "agents/experimental/webmcp";
|
|
33
|
+
*
|
|
34
|
+
* // 1. Register page-local tools — things only the page can do
|
|
35
|
+
* navigator.modelContext?.registerTool({
|
|
36
|
+
* name: "scroll_to_section",
|
|
37
|
+
* description: "Scroll the page to a named section",
|
|
38
|
+
* inputSchema: {
|
|
39
|
+
* type: "object",
|
|
40
|
+
* properties: { id: { type: "string" } },
|
|
41
|
+
* required: ["id"]
|
|
42
|
+
* },
|
|
43
|
+
* async execute({ id }) {
|
|
44
|
+
* document.getElementById(String(id))?.scrollIntoView({ behavior: "smooth" });
|
|
45
|
+
* return "ok";
|
|
46
|
+
* }
|
|
47
|
+
* });
|
|
48
|
+
*
|
|
49
|
+
* // 2. Bridge server tools — things that need durable storage / auth / DB access
|
|
50
|
+
* const handle = await registerWebMcp({
|
|
51
|
+
* url: "/mcp",
|
|
52
|
+
* prefix: "remote.", // optional namespace to avoid collisions
|
|
53
|
+
* getHeaders: async () => ({ Authorization: `Bearer ${await getToken()}` })
|
|
54
|
+
* });
|
|
55
|
+
*
|
|
56
|
+
* // The browser AI sees both kinds of tools side by side.
|
|
57
|
+
* ```
|
|
58
|
+
*
|
|
59
|
+
* @experimental This API is not yet stable and may change.
|
|
60
|
+
*/
|
|
61
|
+
interface ModelContextToolAnnotations {
|
|
62
|
+
readOnlyHint?: boolean;
|
|
63
|
+
}
|
|
64
|
+
interface ModelContextClient {
|
|
65
|
+
requestUserInteraction(callback: () => Promise<unknown>): Promise<unknown>;
|
|
66
|
+
}
|
|
67
|
+
interface ModelContextTool {
|
|
68
|
+
name: string;
|
|
69
|
+
description: string;
|
|
70
|
+
inputSchema?: Record<string, unknown>;
|
|
71
|
+
execute: (input: Record<string, unknown>, client: ModelContextClient) => Promise<unknown>;
|
|
72
|
+
annotations?: ModelContextToolAnnotations;
|
|
73
|
+
}
|
|
74
|
+
interface ModelContextRegisterToolOptions {
|
|
75
|
+
signal?: AbortSignal;
|
|
76
|
+
}
|
|
77
|
+
interface ModelContext {
|
|
78
|
+
registerTool(tool: ModelContextTool, options?: ModelContextRegisterToolOptions): void;
|
|
79
|
+
}
|
|
80
|
+
declare global {
|
|
81
|
+
interface Navigator {
|
|
82
|
+
modelContext?: ModelContext;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
interface McpTool {
|
|
86
|
+
name: string;
|
|
87
|
+
description?: string;
|
|
88
|
+
inputSchema?: Record<string, unknown>;
|
|
89
|
+
annotations?: {
|
|
90
|
+
readOnlyHint?: boolean;
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Logger interface for adapter diagnostics. Defaults to `console`.
|
|
95
|
+
* Pass a no-op implementation (or `quiet: true`) to silence output.
|
|
96
|
+
*/
|
|
97
|
+
interface WebMcpLogger {
|
|
98
|
+
info(...args: unknown[]): void;
|
|
99
|
+
warn(...args: unknown[]): void;
|
|
100
|
+
error(...args: unknown[]): void;
|
|
101
|
+
}
|
|
102
|
+
interface WebMcpOptions {
|
|
103
|
+
/** URL of the MCP endpoint (absolute or relative, e.g. `"/mcp"`). */
|
|
104
|
+
url: string;
|
|
105
|
+
/**
|
|
106
|
+
* Additional headers to include in every request to the MCP server.
|
|
107
|
+
* Useful for static authentication (e.g. `{ Authorization: "Bearer <token>" }`).
|
|
108
|
+
*/
|
|
109
|
+
headers?: Record<string, string>;
|
|
110
|
+
/**
|
|
111
|
+
* Async function that returns headers for each request.
|
|
112
|
+
* Called before every request, useful for tokens that refresh.
|
|
113
|
+
* If both `headers` and `getHeaders` are provided, they are merged
|
|
114
|
+
* with `getHeaders` values taking precedence.
|
|
115
|
+
*/
|
|
116
|
+
getHeaders?: () => Promise<Record<string, string>> | Record<string, string>;
|
|
117
|
+
/**
|
|
118
|
+
* If true, listen for `tools/list_changed` notifications and re-sync
|
|
119
|
+
* tools with `navigator.modelContext`. The adapter opens an SSE GET to
|
|
120
|
+
* the MCP endpoint to receive notifications; servers that don't support
|
|
121
|
+
* server-initiated streams (e.g. respond `405` on GET) gracefully degrade.
|
|
122
|
+
* @default true
|
|
123
|
+
*/
|
|
124
|
+
watch?: boolean;
|
|
125
|
+
/**
|
|
126
|
+
* Optional namespace prefix prepended to every tool name registered with
|
|
127
|
+
* `navigator.modelContext`. Useful when bridging multiple MCP servers, or
|
|
128
|
+
* when the page also registers in-page tools and you want to avoid
|
|
129
|
+
* collisions. The original (unprefixed) name is still used on the wire
|
|
130
|
+
* when calling the server.
|
|
131
|
+
*
|
|
132
|
+
* @example `prefix: "remote."` turns `search` into `remote.search`.
|
|
133
|
+
*/
|
|
134
|
+
prefix?: string;
|
|
135
|
+
/**
|
|
136
|
+
* Per-request timeout (in milliseconds) applied to `tools/list` and
|
|
137
|
+
* `tools/call`. If the server doesn't respond in time, the request is
|
|
138
|
+
* aborted and the resulting error is surfaced through the normal error
|
|
139
|
+
* paths (`onError` for sync, rejection for tool execution).
|
|
140
|
+
*/
|
|
141
|
+
timeoutMs?: number;
|
|
142
|
+
/**
|
|
143
|
+
* Custom logger. Defaults to `console` with a `[webmcp-adapter]` prefix.
|
|
144
|
+
* Pass `{ info: () => {}, warn: () => {}, error: () => {} }` to silence.
|
|
145
|
+
*/
|
|
146
|
+
logger?: WebMcpLogger;
|
|
147
|
+
/** Convenience shortcut for `logger: SILENT_LOGGER`. @default false */
|
|
148
|
+
quiet?: boolean;
|
|
149
|
+
/**
|
|
150
|
+
* Called whenever the adapter performs a successful sync (initial load
|
|
151
|
+
* and on `tools/list_changed`). Receives the tools as the server returned
|
|
152
|
+
* them (with their original, unprefixed names).
|
|
153
|
+
*/
|
|
154
|
+
onSync?: (tools: McpTool[]) => void;
|
|
155
|
+
/**
|
|
156
|
+
* Called when an error occurs during background work that the caller
|
|
157
|
+
* cannot otherwise observe — specifically: a watch-mode re-sync failure.
|
|
158
|
+
*
|
|
159
|
+
* **Not** called for:
|
|
160
|
+
* - Initialization failures (those reject the `registerWebMcp` promise).
|
|
161
|
+
* - Per-tool execution failures (those reject the `execute` promise the
|
|
162
|
+
* browser host awaits; Chrome surfaces them to the AI).
|
|
163
|
+
*/
|
|
164
|
+
onError?: (error: Error) => void;
|
|
165
|
+
}
|
|
166
|
+
interface WebMcpHandle {
|
|
167
|
+
/**
|
|
168
|
+
* Currently registered tool names (with `prefix` applied). Returns a fresh
|
|
169
|
+
* snapshot on each access — safe to mutate.
|
|
170
|
+
*/
|
|
171
|
+
readonly tools: ReadonlyArray<string>;
|
|
172
|
+
/**
|
|
173
|
+
* Re-fetch the tool list from the server and re-register everything.
|
|
174
|
+
* If a sync is already in flight (from a `tools/list_changed` notification
|
|
175
|
+
* or a previous `refresh()` call), returns the in-flight promise rather
|
|
176
|
+
* than starting a second sync.
|
|
177
|
+
*/
|
|
178
|
+
refresh(): Promise<void>;
|
|
179
|
+
/**
|
|
180
|
+
* Unregister all tools, signal any in-flight work to abort, and close the
|
|
181
|
+
* MCP connection. Safe to call multiple times.
|
|
182
|
+
*/
|
|
183
|
+
dispose(): Promise<void>;
|
|
184
|
+
/** True after `dispose()` has been called at least once. */
|
|
185
|
+
readonly disposed: boolean;
|
|
186
|
+
}
|
|
187
|
+
/**
|
|
188
|
+
* Discovers tools from a Cloudflare McpAgent endpoint and registers them
|
|
189
|
+
* with Chrome's native `navigator.modelContext` API.
|
|
190
|
+
*
|
|
191
|
+
* On browsers without `navigator.modelContext` (everything except recent
|
|
192
|
+
* Chrome with the relevant flags), this function is a no-op and returns a
|
|
193
|
+
* handle with an empty tools array. No network request is made.
|
|
194
|
+
*
|
|
195
|
+
* @example
|
|
196
|
+
* ```ts
|
|
197
|
+
* import { registerWebMcp } from "agents/experimental/webmcp";
|
|
198
|
+
*
|
|
199
|
+
* const handle = await registerWebMcp({ url: "/mcp" });
|
|
200
|
+
* console.log("Registered tools:", handle.tools);
|
|
201
|
+
*
|
|
202
|
+
* // Clean up when done (e.g. in a React effect cleanup)
|
|
203
|
+
* await handle.dispose();
|
|
204
|
+
* ```
|
|
205
|
+
*
|
|
206
|
+
* See the JSDoc on the module itself for the recommended "in-page tools +
|
|
207
|
+
* remote tools" composition pattern.
|
|
208
|
+
*/
|
|
209
|
+
declare function registerWebMcp(options: WebMcpOptions): Promise<WebMcpHandle>;
|
|
210
|
+
//#endregion
|
|
211
|
+
export { WebMcpHandle, WebMcpLogger, WebMcpOptions, registerWebMcp };
|
|
212
|
+
//# sourceMappingURL=webmcp.d.ts.map
|
|
@@ -0,0 +1,298 @@
|
|
|
1
|
+
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
|
|
2
|
+
import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";
|
|
3
|
+
import { ToolListChangedNotificationSchema } from "@modelcontextprotocol/sdk/types.js";
|
|
4
|
+
//#region src/experimental/webmcp.ts
|
|
5
|
+
/**
|
|
6
|
+
* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
|
7
|
+
* !! WARNING: EXPERIMENTAL — DO NOT USE IN PRODUCTION !!
|
|
8
|
+
* !! !!
|
|
9
|
+
* !! This API is under active development and WILL break between !!
|
|
10
|
+
* !! releases. Google's WebMCP API (navigator.modelContext) is still !!
|
|
11
|
+
* !! in early preview and subject to change. !!
|
|
12
|
+
* !! !!
|
|
13
|
+
* !! If you use this, pin your agents version and expect to rewrite !!
|
|
14
|
+
* !! your code when upgrading. !!
|
|
15
|
+
* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
|
16
|
+
*
|
|
17
|
+
* WebMCP adapter for Cloudflare Agents SDK.
|
|
18
|
+
*
|
|
19
|
+
* Bridges tools registered on an McpAgent server to Chrome's native
|
|
20
|
+
* navigator.modelContext API, so browser-native agents can discover
|
|
21
|
+
* and call them without extra infrastructure.
|
|
22
|
+
*
|
|
23
|
+
* @example Bridge a remote McpAgent endpoint into the page
|
|
24
|
+
* ```ts
|
|
25
|
+
* import { registerWebMcp } from "agents/experimental/webmcp";
|
|
26
|
+
*
|
|
27
|
+
* const handle = await registerWebMcp({ url: "/mcp" });
|
|
28
|
+
*
|
|
29
|
+
* // Later, to clean up:
|
|
30
|
+
* await handle.dispose();
|
|
31
|
+
* ```
|
|
32
|
+
*
|
|
33
|
+
* @example Mix in-page tools with bridged tools (recommended pattern)
|
|
34
|
+
* ```ts
|
|
35
|
+
* import { registerWebMcp } from "agents/experimental/webmcp";
|
|
36
|
+
*
|
|
37
|
+
* // 1. Register page-local tools — things only the page can do
|
|
38
|
+
* navigator.modelContext?.registerTool({
|
|
39
|
+
* name: "scroll_to_section",
|
|
40
|
+
* description: "Scroll the page to a named section",
|
|
41
|
+
* inputSchema: {
|
|
42
|
+
* type: "object",
|
|
43
|
+
* properties: { id: { type: "string" } },
|
|
44
|
+
* required: ["id"]
|
|
45
|
+
* },
|
|
46
|
+
* async execute({ id }) {
|
|
47
|
+
* document.getElementById(String(id))?.scrollIntoView({ behavior: "smooth" });
|
|
48
|
+
* return "ok";
|
|
49
|
+
* }
|
|
50
|
+
* });
|
|
51
|
+
*
|
|
52
|
+
* // 2. Bridge server tools — things that need durable storage / auth / DB access
|
|
53
|
+
* const handle = await registerWebMcp({
|
|
54
|
+
* url: "/mcp",
|
|
55
|
+
* prefix: "remote.", // optional namespace to avoid collisions
|
|
56
|
+
* getHeaders: async () => ({ Authorization: `Bearer ${await getToken()}` })
|
|
57
|
+
* });
|
|
58
|
+
*
|
|
59
|
+
* // The browser AI sees both kinds of tools side by side.
|
|
60
|
+
* ```
|
|
61
|
+
*
|
|
62
|
+
* @experimental This API is not yet stable and may change.
|
|
63
|
+
*/
|
|
64
|
+
const DEFAULT_LOGGER = {
|
|
65
|
+
info: (...args) => console.info("[webmcp-adapter]", ...args),
|
|
66
|
+
warn: (...args) => console.warn("[webmcp-adapter]", ...args),
|
|
67
|
+
error: (...args) => console.error("[webmcp-adapter]", ...args)
|
|
68
|
+
};
|
|
69
|
+
const SILENT_LOGGER = {
|
|
70
|
+
info: () => {},
|
|
71
|
+
warn: () => {},
|
|
72
|
+
error: () => {}
|
|
73
|
+
};
|
|
74
|
+
var McpHttpClient = class {
|
|
75
|
+
constructor(url, headers, getHeaders, timeoutMs) {
|
|
76
|
+
const resolvedUrl = new URL(url, globalThis.location?.origin);
|
|
77
|
+
this._timeoutMs = timeoutMs;
|
|
78
|
+
const transportOptions = { requestInit: { headers: headers ?? {} } };
|
|
79
|
+
if (getHeaders) transportOptions.fetch = async (input, init) => {
|
|
80
|
+
const dynamic = await getHeaders();
|
|
81
|
+
const merged = new Headers(init?.headers);
|
|
82
|
+
for (const [k, v] of Object.entries(dynamic)) merged.set(k, v);
|
|
83
|
+
return globalThis.fetch(input, {
|
|
84
|
+
...init,
|
|
85
|
+
headers: merged
|
|
86
|
+
});
|
|
87
|
+
};
|
|
88
|
+
this._transport = new StreamableHTTPClientTransport(resolvedUrl, transportOptions);
|
|
89
|
+
this._client = new Client({
|
|
90
|
+
name: "webmcp-adapter",
|
|
91
|
+
version: "0.1.0"
|
|
92
|
+
}, { capabilities: {} });
|
|
93
|
+
}
|
|
94
|
+
async initialize(signal) {
|
|
95
|
+
await this._client.connect(this._transport);
|
|
96
|
+
this._client.setNotificationHandler(ToolListChangedNotificationSchema, async () => {
|
|
97
|
+
if (signal?.aborted) return;
|
|
98
|
+
this._onToolsChanged?.();
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
async listTools(signal) {
|
|
102
|
+
const allTools = [];
|
|
103
|
+
let cursor;
|
|
104
|
+
do {
|
|
105
|
+
if (signal?.aborted) throw new DOMException("Aborted", "AbortError");
|
|
106
|
+
const result = await this._client.listTools(cursor ? { cursor } : void 0, {
|
|
107
|
+
signal,
|
|
108
|
+
timeout: this._timeoutMs
|
|
109
|
+
});
|
|
110
|
+
for (const t of result.tools) allTools.push({
|
|
111
|
+
name: t.name,
|
|
112
|
+
description: t.description,
|
|
113
|
+
inputSchema: t.inputSchema,
|
|
114
|
+
annotations: t.annotations ? { readOnlyHint: t.annotations.readOnlyHint } : void 0
|
|
115
|
+
});
|
|
116
|
+
cursor = result.nextCursor;
|
|
117
|
+
} while (cursor);
|
|
118
|
+
return allTools;
|
|
119
|
+
}
|
|
120
|
+
async callTool(name, args, signal) {
|
|
121
|
+
const result = await this._client.callTool({
|
|
122
|
+
name,
|
|
123
|
+
arguments: args
|
|
124
|
+
}, void 0, {
|
|
125
|
+
signal,
|
|
126
|
+
timeout: this._timeoutMs
|
|
127
|
+
});
|
|
128
|
+
if ("content" in result) return {
|
|
129
|
+
content: result.content.map((c) => ({
|
|
130
|
+
type: c.type,
|
|
131
|
+
text: "text" in c ? c.text : void 0,
|
|
132
|
+
data: "data" in c ? c.data : void 0,
|
|
133
|
+
mimeType: "mimeType" in c ? c.mimeType : void 0
|
|
134
|
+
})),
|
|
135
|
+
isError: "isError" in result ? result.isError : false
|
|
136
|
+
};
|
|
137
|
+
return {
|
|
138
|
+
content: [],
|
|
139
|
+
isError: false
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
listenForChanges(onToolsChanged) {
|
|
143
|
+
this._onToolsChanged = onToolsChanged;
|
|
144
|
+
}
|
|
145
|
+
async close() {
|
|
146
|
+
try {
|
|
147
|
+
await this._client.close();
|
|
148
|
+
} catch {}
|
|
149
|
+
}
|
|
150
|
+
};
|
|
151
|
+
/**
|
|
152
|
+
* Discovers tools from a Cloudflare McpAgent endpoint and registers them
|
|
153
|
+
* with Chrome's native `navigator.modelContext` API.
|
|
154
|
+
*
|
|
155
|
+
* On browsers without `navigator.modelContext` (everything except recent
|
|
156
|
+
* Chrome with the relevant flags), this function is a no-op and returns a
|
|
157
|
+
* handle with an empty tools array. No network request is made.
|
|
158
|
+
*
|
|
159
|
+
* @example
|
|
160
|
+
* ```ts
|
|
161
|
+
* import { registerWebMcp } from "agents/experimental/webmcp";
|
|
162
|
+
*
|
|
163
|
+
* const handle = await registerWebMcp({ url: "/mcp" });
|
|
164
|
+
* console.log("Registered tools:", handle.tools);
|
|
165
|
+
*
|
|
166
|
+
* // Clean up when done (e.g. in a React effect cleanup)
|
|
167
|
+
* await handle.dispose();
|
|
168
|
+
* ```
|
|
169
|
+
*
|
|
170
|
+
* See the JSDoc on the module itself for the recommended "in-page tools +
|
|
171
|
+
* remote tools" composition pattern.
|
|
172
|
+
*/
|
|
173
|
+
async function registerWebMcp(options) {
|
|
174
|
+
const { url, headers, getHeaders, watch = true, prefix = "", timeoutMs, logger: userLogger, quiet = false, onSync, onError } = options;
|
|
175
|
+
const logger = quiet ? SILENT_LOGGER : userLogger ?? DEFAULT_LOGGER;
|
|
176
|
+
const registeredTools = [];
|
|
177
|
+
const toolControllers = /* @__PURE__ */ new Map();
|
|
178
|
+
const lifecycleController = new AbortController();
|
|
179
|
+
let disposed = false;
|
|
180
|
+
let inflightSync = null;
|
|
181
|
+
if (!navigator.modelContext) {
|
|
182
|
+
logger.info("navigator.modelContext not available — skipping registration. This is expected on non-Chrome browsers.");
|
|
183
|
+
onSync?.([]);
|
|
184
|
+
return {
|
|
185
|
+
get tools() {
|
|
186
|
+
return [];
|
|
187
|
+
},
|
|
188
|
+
get disposed() {
|
|
189
|
+
return disposed;
|
|
190
|
+
},
|
|
191
|
+
refresh: async () => {},
|
|
192
|
+
dispose: async () => {
|
|
193
|
+
disposed = true;
|
|
194
|
+
}
|
|
195
|
+
};
|
|
196
|
+
}
|
|
197
|
+
const modelContext = navigator.modelContext;
|
|
198
|
+
const client = new McpHttpClient(url, headers, getHeaders, timeoutMs);
|
|
199
|
+
function unregisterAll() {
|
|
200
|
+
for (const controller of toolControllers.values()) controller.abort();
|
|
201
|
+
toolControllers.clear();
|
|
202
|
+
registeredTools.length = 0;
|
|
203
|
+
}
|
|
204
|
+
function registerTools(tools) {
|
|
205
|
+
for (const tool of tools) {
|
|
206
|
+
const registeredName = `${prefix}${tool.name}`;
|
|
207
|
+
const toolDef = {
|
|
208
|
+
name: registeredName,
|
|
209
|
+
description: tool.description ?? tool.name,
|
|
210
|
+
...tool.inputSchema ? { inputSchema: tool.inputSchema } : {},
|
|
211
|
+
...tool.annotations ? { annotations: { readOnlyHint: tool.annotations.readOnlyHint } } : {},
|
|
212
|
+
execute: async (input) => {
|
|
213
|
+
if (disposed) throw new Error("WebMCP adapter has been disposed");
|
|
214
|
+
const result = await client.callTool(tool.name, input, lifecycleController.signal);
|
|
215
|
+
if (result.isError) {
|
|
216
|
+
const errorText = result.content.map((c) => c.text ?? "").join("\n");
|
|
217
|
+
throw new Error(errorText || "Tool execution failed");
|
|
218
|
+
}
|
|
219
|
+
const parts = [];
|
|
220
|
+
let sawUnsupported = false;
|
|
221
|
+
for (const c of result.content) if (c.type === "text" && c.text) parts.push(c.text);
|
|
222
|
+
else if (c.type === "image" && c.data) parts.push(`data:${c.mimeType ?? "image/png"};base64,${c.data}`);
|
|
223
|
+
else if (c.data) {
|
|
224
|
+
parts.push(c.data);
|
|
225
|
+
sawUnsupported = true;
|
|
226
|
+
} else sawUnsupported = true;
|
|
227
|
+
if (sawUnsupported) logger.warn(`Tool "${tool.name}" returned content type(s) the adapter cannot fully represent as a string.`);
|
|
228
|
+
return parts.join("\n");
|
|
229
|
+
}
|
|
230
|
+
};
|
|
231
|
+
try {
|
|
232
|
+
const controller = new AbortController();
|
|
233
|
+
modelContext.registerTool(toolDef, { signal: controller.signal });
|
|
234
|
+
toolControllers.set(registeredName, controller);
|
|
235
|
+
registeredTools.push(registeredName);
|
|
236
|
+
} catch (err) {
|
|
237
|
+
logger.warn(`Failed to register tool "${registeredName}":`, err);
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
function syncTools() {
|
|
242
|
+
if (disposed) return Promise.resolve();
|
|
243
|
+
if (inflightSync) return inflightSync;
|
|
244
|
+
inflightSync = (async () => {
|
|
245
|
+
try {
|
|
246
|
+
const tools = await client.listTools(lifecycleController.signal);
|
|
247
|
+
if (disposed) return;
|
|
248
|
+
unregisterAll();
|
|
249
|
+
registerTools(tools);
|
|
250
|
+
onSync?.(tools);
|
|
251
|
+
} finally {
|
|
252
|
+
inflightSync = null;
|
|
253
|
+
}
|
|
254
|
+
})();
|
|
255
|
+
return inflightSync;
|
|
256
|
+
}
|
|
257
|
+
try {
|
|
258
|
+
await client.initialize(lifecycleController.signal);
|
|
259
|
+
await syncTools();
|
|
260
|
+
if (watch) client.listenForChanges(() => {
|
|
261
|
+
if (disposed) return;
|
|
262
|
+
syncTools().catch((err) => {
|
|
263
|
+
if (disposed) return;
|
|
264
|
+
const error = err instanceof Error ? err : new Error(String(err));
|
|
265
|
+
logger.warn("Watch-mode sync failed:", error);
|
|
266
|
+
onError?.(error);
|
|
267
|
+
});
|
|
268
|
+
});
|
|
269
|
+
} catch (err) {
|
|
270
|
+
const error = err instanceof Error ? err : new Error(String(err));
|
|
271
|
+
logger.error("Initialization failed:", error);
|
|
272
|
+
await client.close();
|
|
273
|
+
throw error;
|
|
274
|
+
}
|
|
275
|
+
return {
|
|
276
|
+
get tools() {
|
|
277
|
+
return [...registeredTools];
|
|
278
|
+
},
|
|
279
|
+
get disposed() {
|
|
280
|
+
return disposed;
|
|
281
|
+
},
|
|
282
|
+
refresh: syncTools,
|
|
283
|
+
async dispose() {
|
|
284
|
+
if (disposed) return;
|
|
285
|
+
disposed = true;
|
|
286
|
+
lifecycleController.abort();
|
|
287
|
+
unregisterAll();
|
|
288
|
+
try {
|
|
289
|
+
await inflightSync;
|
|
290
|
+
} catch {}
|
|
291
|
+
await client.close();
|
|
292
|
+
}
|
|
293
|
+
};
|
|
294
|
+
}
|
|
295
|
+
//#endregion
|
|
296
|
+
export { registerWebMcp };
|
|
297
|
+
|
|
298
|
+
//# sourceMappingURL=webmcp.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"webmcp.js","names":[],"sources":["../../src/experimental/webmcp.ts"],"sourcesContent":["/**\n * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n * !! WARNING: EXPERIMENTAL — DO NOT USE IN PRODUCTION !!\n * !! !!\n * !! This API is under active development and WILL break between !!\n * !! releases. Google's WebMCP API (navigator.modelContext) is still !!\n * !! in early preview and subject to change. !!\n * !! !!\n * !! If you use this, pin your agents version and expect to rewrite !!\n * !! your code when upgrading. !!\n * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n *\n * WebMCP adapter for Cloudflare Agents SDK.\n *\n * Bridges tools registered on an McpAgent server to Chrome's native\n * navigator.modelContext API, so browser-native agents can discover\n * and call them without extra infrastructure.\n *\n * @example Bridge a remote McpAgent endpoint into the page\n * ```ts\n * import { registerWebMcp } from \"agents/experimental/webmcp\";\n *\n * const handle = await registerWebMcp({ url: \"/mcp\" });\n *\n * // Later, to clean up:\n * await handle.dispose();\n * ```\n *\n * @example Mix in-page tools with bridged tools (recommended pattern)\n * ```ts\n * import { registerWebMcp } from \"agents/experimental/webmcp\";\n *\n * // 1. Register page-local tools — things only the page can do\n * navigator.modelContext?.registerTool({\n * name: \"scroll_to_section\",\n * description: \"Scroll the page to a named section\",\n * inputSchema: {\n * type: \"object\",\n * properties: { id: { type: \"string\" } },\n * required: [\"id\"]\n * },\n * async execute({ id }) {\n * document.getElementById(String(id))?.scrollIntoView({ behavior: \"smooth\" });\n * return \"ok\";\n * }\n * });\n *\n * // 2. Bridge server tools — things that need durable storage / auth / DB access\n * const handle = await registerWebMcp({\n * url: \"/mcp\",\n * prefix: \"remote.\", // optional namespace to avoid collisions\n * getHeaders: async () => ({ Authorization: `Bearer ${await getToken()}` })\n * });\n *\n * // The browser AI sees both kinds of tools side by side.\n * ```\n *\n * @experimental This API is not yet stable and may change.\n */\n\nimport { Client } from \"@modelcontextprotocol/sdk/client/index.js\";\nimport { StreamableHTTPClientTransport } from \"@modelcontextprotocol/sdk/client/streamableHttp.js\";\nimport { ToolListChangedNotificationSchema } from \"@modelcontextprotocol/sdk/types.js\";\n\n// ── WebMCP browser API surface (Chrome's navigator.modelContext) ─────\n\ninterface ModelContextToolAnnotations {\n readOnlyHint?: boolean;\n}\n\ninterface ModelContextClient {\n requestUserInteraction(callback: () => Promise<unknown>): Promise<unknown>;\n}\n\ninterface ModelContextTool {\n name: string;\n description: string;\n inputSchema?: Record<string, unknown>;\n execute: (\n input: Record<string, unknown>,\n client: ModelContextClient\n ) => Promise<unknown>;\n annotations?: ModelContextToolAnnotations;\n}\n\ninterface ModelContextRegisterToolOptions {\n signal?: AbortSignal;\n}\n\ninterface ModelContext {\n registerTool(\n tool: ModelContextTool,\n options?: ModelContextRegisterToolOptions\n ): void;\n}\n\ndeclare global {\n interface Navigator {\n modelContext?: ModelContext;\n }\n}\n\n// ── Internal types ───────────────────────────────────────────────────\n\ninterface McpTool {\n name: string;\n description?: string;\n inputSchema?: Record<string, unknown>;\n annotations?: { readOnlyHint?: boolean };\n}\n\ninterface McpToolCallResult {\n content: Array<{\n type: string;\n text?: string;\n data?: string;\n mimeType?: string;\n }>;\n isError?: boolean;\n}\n\n/**\n * Logger interface for adapter diagnostics. Defaults to `console`.\n * Pass a no-op implementation (or `quiet: true`) to silence output.\n */\nexport interface WebMcpLogger {\n info(...args: unknown[]): void;\n warn(...args: unknown[]): void;\n error(...args: unknown[]): void;\n}\n\nconst DEFAULT_LOGGER: WebMcpLogger = {\n info: (...args) => console.info(\"[webmcp-adapter]\", ...args),\n warn: (...args) => console.warn(\"[webmcp-adapter]\", ...args),\n error: (...args) => console.error(\"[webmcp-adapter]\", ...args)\n};\n\nconst SILENT_LOGGER: WebMcpLogger = {\n info: () => {},\n warn: () => {},\n error: () => {}\n};\n\n// ── MCP transport wrapper ────────────────────────────────────────────\n\nclass McpHttpClient {\n private _client: Client;\n private _transport: StreamableHTTPClientTransport;\n private _onToolsChanged?: () => void;\n private _timeoutMs?: number;\n\n constructor(\n url: string,\n headers?: Record<string, string>,\n getHeaders?: () => Promise<Record<string, string>> | Record<string, string>,\n timeoutMs?: number\n ) {\n const resolvedUrl = new URL(url, globalThis.location?.origin);\n this._timeoutMs = timeoutMs;\n\n const transportOptions: ConstructorParameters<\n typeof StreamableHTTPClientTransport\n >[1] = {\n requestInit: { headers: headers ?? {} }\n };\n\n if (getHeaders) {\n transportOptions.fetch = async (input, init) => {\n const dynamic = await getHeaders();\n const merged = new Headers(init?.headers);\n for (const [k, v] of Object.entries(dynamic)) {\n merged.set(k, v);\n }\n return globalThis.fetch(input, {\n ...init,\n headers: merged\n });\n };\n }\n\n this._transport = new StreamableHTTPClientTransport(\n resolvedUrl,\n transportOptions\n );\n\n this._client = new Client(\n { name: \"webmcp-adapter\", version: \"0.1.0\" },\n { capabilities: {} }\n );\n }\n\n async initialize(signal?: AbortSignal): Promise<void> {\n await this._client.connect(this._transport);\n\n this._client.setNotificationHandler(\n ToolListChangedNotificationSchema,\n async () => {\n if (signal?.aborted) return;\n this._onToolsChanged?.();\n }\n );\n }\n\n async listTools(signal?: AbortSignal): Promise<McpTool[]> {\n const allTools: McpTool[] = [];\n let cursor: string | undefined;\n do {\n if (signal?.aborted) throw new DOMException(\"Aborted\", \"AbortError\");\n const result = await this._client.listTools(\n cursor ? { cursor } : undefined,\n { signal, timeout: this._timeoutMs }\n );\n for (const t of result.tools) {\n allTools.push({\n name: t.name,\n description: t.description,\n inputSchema: t.inputSchema as Record<string, unknown> | undefined,\n annotations: t.annotations\n ? { readOnlyHint: t.annotations.readOnlyHint }\n : undefined\n });\n }\n cursor = result.nextCursor;\n } while (cursor);\n return allTools;\n }\n\n async callTool(\n name: string,\n args: Record<string, unknown>,\n signal?: AbortSignal\n ): Promise<McpToolCallResult> {\n const result = await this._client.callTool(\n { name, arguments: args },\n undefined,\n { signal, timeout: this._timeoutMs }\n );\n if (\"content\" in result) {\n return {\n content: (\n result.content as Array<{\n type: string;\n text?: string;\n data?: string;\n }>\n ).map((c) => ({\n type: c.type,\n text: \"text\" in c ? (c.text as string) : undefined,\n data: \"data\" in c ? (c.data as string) : undefined,\n mimeType: \"mimeType\" in c ? (c.mimeType as string) : undefined\n })),\n isError: \"isError\" in result ? (result.isError as boolean) : false\n };\n }\n return { content: [], isError: false };\n }\n\n listenForChanges(onToolsChanged: () => void): void {\n this._onToolsChanged = onToolsChanged;\n }\n\n async close(): Promise<void> {\n try {\n await this._client.close();\n } catch {\n // Closing a never-connected or already-closed client is fine.\n }\n }\n}\n\n// ── Public API ───────────────────────────────────────────────────────\n\nexport interface WebMcpOptions {\n /** URL of the MCP endpoint (absolute or relative, e.g. `\"/mcp\"`). */\n url: string;\n /**\n * Additional headers to include in every request to the MCP server.\n * Useful for static authentication (e.g. `{ Authorization: \"Bearer <token>\" }`).\n */\n headers?: Record<string, string>;\n /**\n * Async function that returns headers for each request.\n * Called before every request, useful for tokens that refresh.\n * If both `headers` and `getHeaders` are provided, they are merged\n * with `getHeaders` values taking precedence.\n */\n getHeaders?: () => Promise<Record<string, string>> | Record<string, string>;\n /**\n * If true, listen for `tools/list_changed` notifications and re-sync\n * tools with `navigator.modelContext`. The adapter opens an SSE GET to\n * the MCP endpoint to receive notifications; servers that don't support\n * server-initiated streams (e.g. respond `405` on GET) gracefully degrade.\n * @default true\n */\n watch?: boolean;\n /**\n * Optional namespace prefix prepended to every tool name registered with\n * `navigator.modelContext`. Useful when bridging multiple MCP servers, or\n * when the page also registers in-page tools and you want to avoid\n * collisions. The original (unprefixed) name is still used on the wire\n * when calling the server.\n *\n * @example `prefix: \"remote.\"` turns `search` into `remote.search`.\n */\n prefix?: string;\n /**\n * Per-request timeout (in milliseconds) applied to `tools/list` and\n * `tools/call`. If the server doesn't respond in time, the request is\n * aborted and the resulting error is surfaced through the normal error\n * paths (`onError` for sync, rejection for tool execution).\n */\n timeoutMs?: number;\n /**\n * Custom logger. Defaults to `console` with a `[webmcp-adapter]` prefix.\n * Pass `{ info: () => {}, warn: () => {}, error: () => {} }` to silence.\n */\n logger?: WebMcpLogger;\n /** Convenience shortcut for `logger: SILENT_LOGGER`. @default false */\n quiet?: boolean;\n /**\n * Called whenever the adapter performs a successful sync (initial load\n * and on `tools/list_changed`). Receives the tools as the server returned\n * them (with their original, unprefixed names).\n */\n onSync?: (tools: McpTool[]) => void;\n /**\n * Called when an error occurs during background work that the caller\n * cannot otherwise observe — specifically: a watch-mode re-sync failure.\n *\n * **Not** called for:\n * - Initialization failures (those reject the `registerWebMcp` promise).\n * - Per-tool execution failures (those reject the `execute` promise the\n * browser host awaits; Chrome surfaces them to the AI).\n */\n onError?: (error: Error) => void;\n}\n\nexport interface WebMcpHandle {\n /**\n * Currently registered tool names (with `prefix` applied). Returns a fresh\n * snapshot on each access — safe to mutate.\n */\n readonly tools: ReadonlyArray<string>;\n /**\n * Re-fetch the tool list from the server and re-register everything.\n * If a sync is already in flight (from a `tools/list_changed` notification\n * or a previous `refresh()` call), returns the in-flight promise rather\n * than starting a second sync.\n */\n refresh(): Promise<void>;\n /**\n * Unregister all tools, signal any in-flight work to abort, and close the\n * MCP connection. Safe to call multiple times.\n */\n dispose(): Promise<void>;\n /** True after `dispose()` has been called at least once. */\n readonly disposed: boolean;\n}\n\n/**\n * Discovers tools from a Cloudflare McpAgent endpoint and registers them\n * with Chrome's native `navigator.modelContext` API.\n *\n * On browsers without `navigator.modelContext` (everything except recent\n * Chrome with the relevant flags), this function is a no-op and returns a\n * handle with an empty tools array. No network request is made.\n *\n * @example\n * ```ts\n * import { registerWebMcp } from \"agents/experimental/webmcp\";\n *\n * const handle = await registerWebMcp({ url: \"/mcp\" });\n * console.log(\"Registered tools:\", handle.tools);\n *\n * // Clean up when done (e.g. in a React effect cleanup)\n * await handle.dispose();\n * ```\n *\n * See the JSDoc on the module itself for the recommended \"in-page tools +\n * remote tools\" composition pattern.\n */\nexport async function registerWebMcp(\n options: WebMcpOptions\n): Promise<WebMcpHandle> {\n const {\n url,\n headers,\n getHeaders,\n watch = true,\n prefix = \"\",\n timeoutMs,\n logger: userLogger,\n quiet = false,\n onSync,\n onError\n } = options;\n\n const logger = quiet ? SILENT_LOGGER : (userLogger ?? DEFAULT_LOGGER);\n\n const registeredTools: string[] = [];\n const toolControllers = new Map<string, AbortController>();\n const lifecycleController = new AbortController();\n let disposed = false;\n let inflightSync: Promise<void> | null = null;\n\n if (!navigator.modelContext) {\n logger.info(\n \"navigator.modelContext not available — skipping registration. \" +\n \"This is expected on non-Chrome browsers.\"\n );\n onSync?.([]);\n return {\n get tools() {\n return [];\n },\n get disposed() {\n return disposed;\n },\n refresh: async () => {},\n dispose: async () => {\n disposed = true;\n }\n };\n }\n\n const modelContext: ModelContext = navigator.modelContext;\n const client = new McpHttpClient(url, headers, getHeaders, timeoutMs);\n\n function unregisterAll(): void {\n for (const controller of toolControllers.values()) {\n controller.abort();\n }\n toolControllers.clear();\n registeredTools.length = 0;\n }\n\n function registerTools(tools: McpTool[]): void {\n for (const tool of tools) {\n const registeredName = `${prefix}${tool.name}`;\n const toolDef: ModelContextTool = {\n name: registeredName,\n description: tool.description ?? tool.name,\n ...(tool.inputSchema ? { inputSchema: tool.inputSchema } : {}),\n ...(tool.annotations\n ? { annotations: { readOnlyHint: tool.annotations.readOnlyHint } }\n : {}),\n execute: async (input: Record<string, unknown>) => {\n if (disposed) {\n throw new Error(\"WebMCP adapter has been disposed\");\n }\n const result = await client.callTool(\n tool.name,\n input,\n lifecycleController.signal\n );\n\n if (result.isError) {\n const errorText = result.content\n .map((c) => c.text ?? \"\")\n .join(\"\\n\");\n throw new Error(errorText || \"Tool execution failed\");\n }\n\n const parts: string[] = [];\n let sawUnsupported = false;\n for (const c of result.content) {\n if (c.type === \"text\" && c.text) {\n parts.push(c.text);\n } else if (c.type === \"image\" && c.data) {\n parts.push(`data:${c.mimeType ?? \"image/png\"};base64,${c.data}`);\n } else if (c.data) {\n parts.push(c.data);\n sawUnsupported = true;\n } else {\n sawUnsupported = true;\n }\n }\n if (sawUnsupported) {\n logger.warn(\n `Tool \"${tool.name}\" returned content type(s) the adapter` +\n \" cannot fully represent as a string.\"\n );\n }\n return parts.join(\"\\n\");\n }\n };\n\n try {\n const controller = new AbortController();\n modelContext.registerTool(toolDef, { signal: controller.signal });\n toolControllers.set(registeredName, controller);\n registeredTools.push(registeredName);\n } catch (err) {\n logger.warn(`Failed to register tool \"${registeredName}\":`, err);\n }\n }\n }\n\n // Serialize syncs: if one is already running, share its promise. This\n // prevents the unregister/listTools/registerTools sequence from\n // interleaving when both `refresh()` and a `tools/list_changed`\n // notification fire concurrently.\n function syncTools(): Promise<void> {\n if (disposed) return Promise.resolve();\n if (inflightSync) return inflightSync;\n inflightSync = (async () => {\n try {\n const tools = await client.listTools(lifecycleController.signal);\n if (disposed) return;\n unregisterAll();\n registerTools(tools);\n onSync?.(tools);\n } finally {\n inflightSync = null;\n }\n })();\n return inflightSync;\n }\n\n try {\n await client.initialize(lifecycleController.signal);\n await syncTools();\n\n if (watch) {\n client.listenForChanges(() => {\n if (disposed) return;\n syncTools().catch((err: unknown) => {\n if (disposed) return;\n const error = err instanceof Error ? err : new Error(String(err));\n logger.warn(\"Watch-mode sync failed:\", error);\n onError?.(error);\n });\n });\n }\n } catch (err) {\n const error = err instanceof Error ? err : new Error(String(err));\n logger.error(\"Initialization failed:\", error);\n // Best-effort cleanup so a failed init doesn't leak the transport.\n await client.close();\n throw error;\n }\n\n return {\n get tools() {\n return [...registeredTools];\n },\n get disposed() {\n return disposed;\n },\n refresh: syncTools,\n async dispose() {\n if (disposed) return;\n disposed = true;\n lifecycleController.abort();\n unregisterAll();\n // Wait for any in-flight sync to settle so callers can rely on\n // a quiet adapter after `await handle.dispose()`.\n try {\n await inflightSync;\n } catch {\n // Already surfaced via onError or thrown to the original caller.\n }\n await client.close();\n }\n };\n}\n"],"mappings":"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"}
|
|
@@ -729,7 +729,7 @@ declare class MCPClientConnection {
|
|
|
729
729
|
*/
|
|
730
730
|
getTransport(
|
|
731
731
|
transportType: BaseTransportType
|
|
732
|
-
):
|
|
732
|
+
): RPCClientTransport | SSEClientTransport | StreamableHTTPClientTransport;
|
|
733
733
|
private tryConnect;
|
|
734
734
|
private _capabilityErrorHandler;
|
|
735
735
|
}
|
|
@@ -1640,6 +1640,11 @@ type FiberRecoveryContext = {
|
|
|
1640
1640
|
/** Fiber ID. */ id: string /** Name passed to `runFiber`. */;
|
|
1641
1641
|
name: string /** Last checkpoint data from `stash()`, or null if never stashed. */;
|
|
1642
1642
|
snapshot: unknown | null;
|
|
1643
|
+
/**
|
|
1644
|
+
* Epoch milliseconds when the fiber row was inserted (when `runFiber`
|
|
1645
|
+
* started). Use `Date.now() - createdAt` to gate stale recoveries.
|
|
1646
|
+
*/
|
|
1647
|
+
createdAt: number;
|
|
1643
1648
|
[key: string]: unknown;
|
|
1644
1649
|
};
|
|
1645
1650
|
/**
|
|
@@ -1898,6 +1903,18 @@ declare class Agent<
|
|
|
1898
1903
|
* @param excludeIds Additional connection IDs to exclude (e.g. the source)
|
|
1899
1904
|
*/
|
|
1900
1905
|
private _broadcastProtocol;
|
|
1906
|
+
/**
|
|
1907
|
+
* When running as a facet, the parent DO owns the WebSocket registry
|
|
1908
|
+
* (`ctx.getWebSockets()`). Iterating from the child isolate throws
|
|
1909
|
+
* "Cannot perform I/O on behalf of a different Durable Object".
|
|
1910
|
+
* Downstream callers (e.g. chat-streaming paths) invoke
|
|
1911
|
+
* `this.broadcast()` directly, bypassing `_broadcastProtocol`'s
|
|
1912
|
+
* guard, so override at the base to catch every path.
|
|
1913
|
+
*/
|
|
1914
|
+
broadcast(
|
|
1915
|
+
msg: string | ArrayBuffer | ArrayBufferView,
|
|
1916
|
+
without?: string[]
|
|
1917
|
+
): void;
|
|
1901
1918
|
private _setStateInternal;
|
|
1902
1919
|
/**
|
|
1903
1920
|
* Update the Agent's state
|
|
@@ -2369,12 +2386,23 @@ declare class Agent<
|
|
|
2369
2386
|
*/
|
|
2370
2387
|
alarm(): Promise<void>;
|
|
2371
2388
|
/**
|
|
2372
|
-
*
|
|
2373
|
-
*
|
|
2374
|
-
*
|
|
2375
|
-
*
|
|
2389
|
+
* Initialize this agent as a facet in a single RPC.
|
|
2390
|
+
*
|
|
2391
|
+
* Runs entirely inside the child's isolate, so every storage write
|
|
2392
|
+
* and `onStart()` I/O is owned by the child DO. This replaces the
|
|
2393
|
+
* previous "construct a Request in the parent DO and `stub.fetch()`
|
|
2394
|
+
* it on the child" handshake, whose native I/O was tied to the
|
|
2395
|
+
* parent and triggered "Cannot perform I/O on behalf of a different
|
|
2396
|
+
* Durable Object" on the child.
|
|
2397
|
+
*
|
|
2398
|
+
* Order matters: set `_isFacet` BEFORE triggering initialization, so
|
|
2399
|
+
* the first `onStart()` run (which calls `broadcastMcpServers`) sees
|
|
2400
|
+
* the flag and skips broadcasts that would touch the parent DO's
|
|
2401
|
+
* WebSocket registry.
|
|
2402
|
+
*
|
|
2403
|
+
* @internal Called by {@link subAgent}.
|
|
2376
2404
|
*/
|
|
2377
|
-
|
|
2405
|
+
_cf_initAsFacet(name: string): Promise<void>;
|
|
2378
2406
|
/**
|
|
2379
2407
|
* Get or create a named sub-agent — a child Durable Object (facet)
|
|
2380
2408
|
* with its own isolated SQLite storage running on the same machine.
|
|
@@ -2383,7 +2411,7 @@ declare class Agent<
|
|
|
2383
2411
|
* entry point. The first call for a given name triggers the child's
|
|
2384
2412
|
* `onStart()`. Subsequent calls return the existing instance.
|
|
2385
2413
|
*
|
|
2386
|
-
* @experimental
|
|
2414
|
+
* @experimental The API surface may change before stabilizing.
|
|
2387
2415
|
*
|
|
2388
2416
|
* @param cls The Agent subclass (must be exported from the worker)
|
|
2389
2417
|
* @param name Unique name for this child instance
|
|
@@ -2405,7 +2433,7 @@ declare class Agent<
|
|
|
2405
2433
|
* Pending RPC calls receive the reason as an error.
|
|
2406
2434
|
* Transitively aborts the child's own children.
|
|
2407
2435
|
*
|
|
2408
|
-
* @experimental
|
|
2436
|
+
* @experimental The API surface may change before stabilizing.
|
|
2409
2437
|
*
|
|
2410
2438
|
* @param cls The Agent subclass used when creating the child
|
|
2411
2439
|
* @param name Name of the child to abort
|
|
@@ -2416,7 +2444,7 @@ declare class Agent<
|
|
|
2416
2444
|
* Delete a sub-agent: abort it if running, then permanently wipe its
|
|
2417
2445
|
* storage. Transitively deletes the child's own children.
|
|
2418
2446
|
*
|
|
2419
|
-
* @experimental
|
|
2447
|
+
* @experimental The API surface may change before stabilizing.
|
|
2420
2448
|
*
|
|
2421
2449
|
* @param cls The Agent subclass used when creating the child
|
|
2422
2450
|
* @param name Name of the child to delete
|
|
@@ -3080,4 +3108,4 @@ export {
|
|
|
3080
3108
|
QueueItem as y,
|
|
3081
3109
|
MCPClientOAuthResult as z
|
|
3082
3110
|
};
|
|
3083
|
-
//# sourceMappingURL=index-
|
|
3111
|
+
//# sourceMappingURL=index-D9qo_Inc.d.ts.map
|