agents 0.13.2 → 0.14.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.
Files changed (74) hide show
  1. package/README.md +6 -4
  2. package/dist/{agent-tool-types-Dn9n-3SI.d.ts → agent-tool-types-LInzZfLo.d.ts} +511 -124
  3. package/dist/agent-tool-types.d.ts +13 -11
  4. package/dist/{agent-tools-B1ttU-pq.d.ts → agent-tools-BE9xosUG.d.ts} +2 -2
  5. package/dist/agent-tools.d.ts +14 -20
  6. package/dist/agent-tools.js +10 -6
  7. package/dist/agent-tools.js.map +1 -1
  8. package/dist/browser/ai.d.ts +1 -1
  9. package/dist/browser/ai.js +1 -1
  10. package/dist/browser/index.d.ts +1 -1
  11. package/dist/browser/index.js +1 -1
  12. package/dist/browser/tanstack-ai.d.ts +1 -1
  13. package/dist/browser/tanstack-ai.js +1 -1
  14. package/dist/chat/index.d.ts +194 -22
  15. package/dist/chat/index.js +144 -11
  16. package/dist/chat/index.js.map +1 -1
  17. package/dist/chat-sdk/index.d.ts +4 -4
  18. package/dist/classPrivateMethodInitSpec-bG0tD96O.js +7 -0
  19. package/dist/{client-D1kFXo80.js → client-NradHZZz.js} +206 -75
  20. package/dist/client-NradHZZz.js.map +1 -0
  21. package/dist/client.d.ts +1 -1
  22. package/dist/{compaction-helpers-DvcZnvQ1.js → compaction-helpers-BjT2NKRZ.js} +37 -9
  23. package/dist/compaction-helpers-BjT2NKRZ.js.map +1 -0
  24. package/dist/{compaction-helpers-DAe-xiVY.d.ts → compaction-helpers-DpP_XP9J.d.ts} +86 -29
  25. package/dist/{do-oauth-client-provider-4OKQU9rT.d.ts → do-oauth-client-provider-CPm9rK5I.d.ts} +1 -1
  26. package/dist/{email-J0GGS3sa.d.ts → email-1fTSJwPm.d.ts} +1 -1
  27. package/dist/email.d.ts +2 -2
  28. package/dist/experimental/memory/session/index.d.ts +58 -23
  29. package/dist/experimental/memory/session/index.js +98 -9
  30. package/dist/experimental/memory/session/index.js.map +1 -1
  31. package/dist/experimental/memory/utils/index.d.ts +13 -11
  32. package/dist/experimental/memory/utils/index.js +2 -2
  33. package/dist/{index-DKey3P4s.d.ts → index-Brdu5nMI.d.ts} +270 -1
  34. package/dist/index.d.ts +74 -67
  35. package/dist/index.js +607 -97
  36. package/dist/index.js.map +1 -1
  37. package/dist/{internal_context-BZrMS0B5.d.ts → internal_context-CcZy2Em7.d.ts} +1 -1
  38. package/dist/internal_context.d.ts +1 -1
  39. package/dist/mcp/client.d.ts +17 -13
  40. package/dist/mcp/client.js +2 -2
  41. package/dist/mcp/do-oauth-client-provider.d.ts +1 -1
  42. package/dist/mcp/index.d.ts +35 -27
  43. package/dist/mcp/index.js +402 -69
  44. package/dist/mcp/index.js.map +1 -1
  45. package/dist/observability/index.d.ts +1 -1
  46. package/dist/observability/index.js +15 -1
  47. package/dist/observability/index.js.map +1 -1
  48. package/dist/react.d.ts +3 -3
  49. package/dist/{retries-BVdRl5ZE.d.ts → retries-ClWwxADl.d.ts} +1 -1
  50. package/dist/retries.d.ts +1 -1
  51. package/dist/serializable.d.ts +1 -1
  52. package/dist/{shared-Cvj92byG.d.ts → shared-CpY1FLvm.d.ts} +1 -1
  53. package/dist/{shared-CiKaIK4h.js → shared-DdOn6sp4.js} +3 -7
  54. package/dist/{shared-CiKaIK4h.js.map → shared-DdOn6sp4.js.map} +1 -1
  55. package/dist/skills/index.d.ts +236 -0
  56. package/dist/skills/index.js +1326 -0
  57. package/dist/skills/index.js.map +1 -0
  58. package/dist/sub-routing.d.ts +6 -6
  59. package/dist/{tool-output-truncation-CH-khbZ3.js → tool-output-truncation-BF4AZQlw.js} +1 -1
  60. package/dist/{tool-output-truncation-CH-khbZ3.js.map → tool-output-truncation-BF4AZQlw.js.map} +1 -1
  61. package/dist/{types-_JjKmv-l.d.ts → types-B0GymtN_.d.ts} +1 -1
  62. package/dist/types.d.ts +1 -1
  63. package/dist/vite.d.ts +1 -1
  64. package/dist/vite.js +248 -2
  65. package/dist/vite.js.map +1 -1
  66. package/dist/{workflow-types-Dkzg4hAx.d.ts → workflow-types-DPkuBi--.d.ts} +1 -1
  67. package/dist/workflow-types.d.ts +1 -1
  68. package/dist/workflows.d.ts +13 -3
  69. package/dist/workflows.js +10 -1
  70. package/dist/workflows.js.map +1 -1
  71. package/package.json +21 -3
  72. package/skills-module.d.ts +22 -0
  73. package/dist/client-D1kFXo80.js.map +0 -1
  74. package/dist/compaction-helpers-DvcZnvQ1.js.map +0 -1
@@ -7,7 +7,7 @@ import { z } from "zod";
7
7
  import { Client } from "@modelcontextprotocol/sdk/client/index.js";
8
8
  import { SSEClientTransport } from "@modelcontextprotocol/sdk/client/sse.js";
9
9
  import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";
10
- import { ElicitRequestSchema, JSONRPCMessageSchema, PromptListChangedNotificationSchema, ResourceListChangedNotificationSchema, ToolListChangedNotificationSchema } from "@modelcontextprotocol/sdk/types.js";
10
+ import { ElicitRequestSchema, JSONRPCMessageSchema, PromptListChangedNotificationSchema, ResourceListChangedNotificationSchema, ToolListChangedNotificationSchema, isJSONRPCErrorResponse, isJSONRPCResultResponse } from "@modelcontextprotocol/sdk/types.js";
11
11
  //#region src/core/events.ts
12
12
  function toDisposable(fn) {
13
13
  return { dispose: fn };
@@ -121,8 +121,8 @@ var RPCClientTransport = class {
121
121
  var RPCServerTransport = class {
122
122
  constructor(options) {
123
123
  this._started = false;
124
- this._pendingResponse = null;
125
- this._responseResolver = null;
124
+ this._pendingRequests = /* @__PURE__ */ new Map();
125
+ this._pendingContinuations = [];
126
126
  this._timeout = options?.timeout ?? 6e4;
127
127
  }
128
128
  setProtocolVersion(version) {
@@ -138,109 +138,146 @@ var RPCServerTransport = class {
138
138
  async close() {
139
139
  this._started = false;
140
140
  this.onclose?.();
141
- if (this._responseResolver) {
142
- this._responseResolver();
143
- this._responseResolver = null;
141
+ const error = /* @__PURE__ */ new Error("Transport closed");
142
+ for (const pending of this._pendingRequests.values()) {
143
+ clearTimeout(pending.timeoutId);
144
+ pending.reject(error);
144
145
  }
146
+ this._pendingRequests.clear();
147
+ for (const pending of this._pendingContinuations) {
148
+ clearTimeout(pending.timeoutId);
149
+ pending.reject(error);
150
+ }
151
+ this._pendingContinuations = [];
152
+ }
153
+ _makeTimeout(onTimeout) {
154
+ return setTimeout(onTimeout, this._timeout);
155
+ }
156
+ _appendPending(pending, message) {
157
+ pending.messages.push(message);
158
+ }
159
+ _completePending(pending, message) {
160
+ pending.messages.push(message);
161
+ clearTimeout(pending.timeoutId);
162
+ const messages = pending.messages;
163
+ queueMicrotask(() => {
164
+ pending.resolve(messages.length === 1 ? messages[0] : messages);
165
+ });
166
+ }
167
+ _completeRequest(key, message) {
168
+ const pending = this._pendingRequests.get(key);
169
+ if (!pending) return false;
170
+ this._pendingRequests.delete(key);
171
+ this._completePending(pending, message);
172
+ return true;
145
173
  }
146
- async send(message, _options) {
174
+ _appendRequest(key, message) {
175
+ const pending = this._pendingRequests.get(key);
176
+ if (!pending) return false;
177
+ this._appendPending(pending, message);
178
+ return true;
179
+ }
180
+ _completeContinuation(message) {
181
+ const pending = this._pendingContinuations.shift();
182
+ if (!pending) return false;
183
+ this._completePending(pending, message);
184
+ return true;
185
+ }
186
+ _appendContinuation(message) {
187
+ const pending = this._pendingContinuations[0];
188
+ if (!pending) return false;
189
+ this._appendPending(pending, message);
190
+ return true;
191
+ }
192
+ async send(message, options) {
147
193
  if (!this._started) throw new Error("Transport not started");
148
- if (!this._pendingResponse) this._pendingResponse = message;
149
- else if (Array.isArray(this._pendingResponse)) this._pendingResponse.push(message);
150
- else this._pendingResponse = [this._pendingResponse, message];
151
- if (this._responseResolver) {
152
- const resolver = this._responseResolver;
153
- queueMicrotask(() => resolver());
194
+ if (isJSONRPCResultResponse(message) || isJSONRPCErrorResponse(message)) {
195
+ const id = message.id;
196
+ if (id === void 0) {
197
+ this.onerror?.(/* @__PURE__ */ new Error(`RPC response missing id: ${JSON.stringify(message)}`));
198
+ return;
199
+ }
200
+ if (this._completeRequest(id.toString(), message)) return;
201
+ if (this._completeContinuation(message)) return;
202
+ this.onerror?.(/* @__PURE__ */ new Error(`No pending RPC request found for response: ${JSON.stringify(message)}`));
203
+ return;
204
+ }
205
+ const relatedRequestId = options?.relatedRequestId?.toString();
206
+ const expectsResponse = "id" in message;
207
+ if (relatedRequestId) {
208
+ if (expectsResponse) {
209
+ if (this._completeRequest(relatedRequestId, message)) return;
210
+ } else if (this._appendRequest(relatedRequestId, message)) return;
154
211
  }
212
+ if (expectsResponse) {
213
+ if (this._completeContinuation(message)) return;
214
+ } else if (this._appendContinuation(message)) return;
215
+ this.onerror?.(/* @__PURE__ */ new Error(`No pending RPC request found for message: ${JSON.stringify(message)}`));
155
216
  }
156
217
  /**
157
218
  * @internal Called by McpAgent.handleMcpMessage() — not for external use.
158
219
  *
159
- * Wait for the next send() call and return whatever it produces.
220
+ * Wait for the next unmatched send() call that expects a client response or
221
+ * completes a resumed tool call.
160
222
  *
161
- * Used after resolving an elicitation response: the tool handler is still
162
- * running and will eventually call send() with either another elicitation
163
- * request or the final tool result. This method captures that send() using
164
- * the same _responseResolver / _pendingResponse / timeout mechanism as
165
- * handle().
223
+ * Used after resolving an elicitation response: the original tool call has
224
+ * already returned the elicitation request to the RPC client, and the resumed
225
+ * tool handler will eventually send the final tool result. That final response
226
+ * has the original tool request id, so there is no active handle() waiter left
227
+ * for id-based routing; this continuation waiter receives it instead.
166
228
  */
167
229
  async _awaitPendingResponse() {
168
230
  if (!this._started) throw new Error("Transport not started");
169
- this._pendingResponse = null;
170
- let timeoutId = null;
171
- const responsePromise = new Promise((resolve, reject) => {
172
- timeoutId = setTimeout(() => {
173
- this._responseResolver = null;
174
- reject(/* @__PURE__ */ new Error(`Request timeout: No response received within ${this._timeout}ms`));
175
- }, this._timeout);
176
- this._responseResolver = () => {
177
- if (timeoutId) {
178
- clearTimeout(timeoutId);
179
- timeoutId = null;
180
- }
181
- this._responseResolver = null;
182
- resolve();
231
+ return await new Promise((resolve, reject) => {
232
+ const pending = {
233
+ messages: [],
234
+ resolve,
235
+ reject,
236
+ timeoutId: this._makeTimeout(() => {
237
+ const index = this._pendingContinuations.indexOf(pending);
238
+ if (index !== -1) this._pendingContinuations.splice(index, 1);
239
+ reject(/* @__PURE__ */ new Error(`Request timeout: No response received within ${this._timeout}ms`));
240
+ })
183
241
  };
242
+ this._pendingContinuations.push(pending);
184
243
  });
185
- try {
186
- await responsePromise;
187
- } catch (error) {
188
- this._pendingResponse = null;
189
- this._responseResolver = null;
190
- throw error;
191
- }
192
- const response = this._pendingResponse;
193
- this._pendingResponse = null;
194
- return response ?? void 0;
195
244
  }
196
245
  async handle(message) {
197
246
  if (!this._started) throw new Error("Transport not started");
198
247
  if (Array.isArray(message)) {
199
248
  validateBatch(message);
200
- const responses = [];
201
- for (const msg of message) {
202
- const response = await this.handle(msg);
203
- if (response !== void 0) if (Array.isArray(response)) responses.push(...response);
204
- else responses.push(response);
205
- }
206
- return responses.length === 0 ? void 0 : responses;
249
+ const flattened = (await Promise.all(message.map((msg) => this.handle(msg)))).flatMap((response) => {
250
+ if (response === void 0) return [];
251
+ return Array.isArray(response) ? response : [response];
252
+ });
253
+ return flattened.length === 0 ? void 0 : flattened;
207
254
  }
208
255
  try {
209
256
  JSONRPCMessageSchema.parse(message);
210
257
  } catch {
211
258
  return makeInvalidRequestError(typeof message === "object" && message !== null && "id" in message ? message.id : null);
212
259
  }
213
- this._pendingResponse = null;
214
260
  if (!("id" in message)) {
215
261
  this.onmessage?.(message);
216
262
  return;
217
263
  }
218
- let timeoutId = null;
264
+ const id = message.id?.toString();
265
+ if (!id) return makeInvalidRequestError(message.id);
266
+ if (this._pendingRequests.has(id)) throw new Error(`Duplicate pending RPC request id: ${id}`);
219
267
  const responsePromise = new Promise((resolve, reject) => {
220
- timeoutId = setTimeout(() => {
221
- this._responseResolver = null;
222
- reject(/* @__PURE__ */ new Error(`Request timeout: No response received within ${this._timeout}ms`));
223
- }, this._timeout);
224
- this._responseResolver = () => {
225
- if (timeoutId) {
226
- clearTimeout(timeoutId);
227
- timeoutId = null;
228
- }
229
- this._responseResolver = null;
230
- resolve();
268
+ const pending = {
269
+ messages: [],
270
+ resolve,
271
+ reject,
272
+ timeoutId: this._makeTimeout(() => {
273
+ this._pendingRequests.delete(id);
274
+ reject(/* @__PURE__ */ new Error(`Request timeout: No response received within ${this._timeout}ms`));
275
+ })
231
276
  };
277
+ this._pendingRequests.set(id, pending);
232
278
  });
233
279
  this.onmessage?.(message);
234
- try {
235
- await responsePromise;
236
- } catch (error) {
237
- this._pendingResponse = null;
238
- this._responseResolver = null;
239
- throw error;
240
- }
241
- const response = this._pendingResponse;
242
- this._pendingResponse = null;
243
- return response ?? void 0;
280
+ return await responsePromise;
244
281
  }
245
282
  };
246
283
  //#endregion
@@ -711,6 +748,37 @@ var MCPClientConnection = class {
711
748
  //#endregion
712
749
  //#region src/mcp/client.ts
713
750
  const defaultClientOptions = { jsonSchemaValidator: new CfWorkerJsonSchemaValidator() };
751
+ /** Maximum length of a normalized MCP server id. */
752
+ const MCP_SERVER_ID_MAX_LENGTH = 64;
753
+ /**
754
+ * Normalize a caller-supplied MCP server id into a stable, storage- and
755
+ * tool-name-safe form.
756
+ *
757
+ * The id is surfaced in several places where the character set matters:
758
+ * - as the primary key in the `cf_agents_mcp_servers` SQLite table
759
+ * - embedded in AI SDK tool names as `` `tool_${id.replace(/-/g, "")}_${tool}` ``
760
+ * (tool names must match `/^[A-Za-z0-9_]+$/`)
761
+ * - as a key on the `mcpConnections` map and OAuth provider storage
762
+ *
763
+ * Rules:
764
+ * 1. Lowercase.
765
+ * 2. Replace any run of disallowed characters with a single `-`.
766
+ * 3. Collapse repeated `-` and trim leading/trailing `-`/`_`.
767
+ * 4. Prefix with `id-` if the result is empty or doesn't start with a letter.
768
+ * 5. Truncate to {@link MCP_SERVER_ID_MAX_LENGTH} characters.
769
+ *
770
+ * @example
771
+ * normalizeServerId("my-supplied-id"); // "my-supplied-id"
772
+ * normalizeServerId("GitHub MCP!"); // "github-mcp"
773
+ * normalizeServerId("42-things"); // "id-42-things"
774
+ */
775
+ function normalizeServerId(input) {
776
+ if (typeof input !== "string") throw new TypeError(`normalizeServerId: expected string, got ${typeof input}`);
777
+ let id = input.toLowerCase().replace(/[^a-z0-9_-]+/g, "-").replace(/-+/g, "-").replace(/^[-_]+|[-_]+$/g, "");
778
+ if (id.length === 0 || !/^[a-z]/.test(id)) id = `id-${id}`.replace(/-+$/g, "");
779
+ if (id.length > 64) id = id.slice(0, 64).replace(/-+$/g, "");
780
+ return id;
781
+ }
714
782
  /**
715
783
  * Blocked hostname patterns for SSRF protection.
716
784
  * Prevents MCP client from connecting to internal/private network addresses
@@ -838,6 +906,69 @@ var MCPClientManager = class {
838
906
  removeServerFromStorage(serverId) {
839
907
  this.sql("DELETE FROM cf_agents_mcp_servers WHERE id = ?", serverId);
840
908
  }
909
+ /**
910
+ * Rename a server's id, in-place, across every place the id is used as a
911
+ * key. Used to JIT-migrate servers that were originally registered under an
912
+ * auto-generated nanoid to a caller-supplied stable id (see
913
+ * `Agent.addMcpServer`'s `{ id }` option).
914
+ *
915
+ * Migrates:
916
+ * - the `cf_agents_mcp_servers` row (primary key)
917
+ * - the in-memory `mcpConnections` map key
918
+ * - the connection disposables map key
919
+ * - the attached `authProvider.serverId`, if any
920
+ * - OAuth-related storage keys under `/{clientName}/{oldId}/...`
921
+ *
922
+ * Safe to call when no OAuth keys exist (RPC / bearer-token HTTP servers).
923
+ * If `oldId === newId` this is a no-op. If a row already exists under
924
+ * `newId`, throws — the caller is expected to have verified uniqueness.
925
+ *
926
+ * @internal Exposed for `Agent.addMcpServer` JIT-migration.
927
+ */
928
+ async migrateServerId(oldId, newId, clientName) {
929
+ if (oldId === newId) return;
930
+ if (this.sql("SELECT id FROM cf_agents_mcp_servers WHERE id = ?", oldId).length === 0) {
931
+ this._renameInMemoryConnection(oldId, newId);
932
+ return;
933
+ }
934
+ if (this.sql("SELECT id FROM cf_agents_mcp_servers WHERE id = ?", newId).length > 0) throw new Error(`Cannot migrate MCP server id "${oldId}" → "${newId}": new id is already in use.`);
935
+ this.sql("UPDATE cf_agents_mcp_servers SET id = ? WHERE id = ?", newId, oldId);
936
+ const oldPrefix = `/${clientName}/${oldId}/`;
937
+ const newPrefix = `/${clientName}/${newId}/`;
938
+ try {
939
+ const keys = await this._storage.list({ prefix: oldPrefix });
940
+ if (keys.size > 0) {
941
+ const writes = {};
942
+ const deletes = [];
943
+ for (const [oldKey, value] of keys) {
944
+ const newKey = newPrefix + oldKey.slice(oldPrefix.length);
945
+ writes[newKey] = value;
946
+ deletes.push(oldKey);
947
+ }
948
+ await this._storage.put(writes);
949
+ await this._storage.delete(deletes);
950
+ }
951
+ } catch (error) {
952
+ console.warn(`[MCPClientManager] OAuth key migration ${oldPrefix} → ${newPrefix} failed:`, error);
953
+ }
954
+ this._renameInMemoryConnection(oldId, newId);
955
+ this._onServerStateChanged.fire();
956
+ }
957
+ _renameInMemoryConnection(oldId, newId) {
958
+ if (oldId === newId) return;
959
+ const conn = this.mcpConnections[oldId];
960
+ if (conn) {
961
+ this.mcpConnections[newId] = conn;
962
+ delete this.mcpConnections[oldId];
963
+ const authProvider = conn.options.transport.authProvider;
964
+ if (authProvider) authProvider.serverId = newId;
965
+ }
966
+ const disposables = this._connectionDisposables.get(oldId);
967
+ if (disposables) {
968
+ this._connectionDisposables.set(newId, disposables);
969
+ this._connectionDisposables.delete(oldId);
970
+ }
971
+ }
841
972
  getServersFromStorage() {
842
973
  return this.sql("SELECT id, name, server_url, client_id, auth_url, callback_url, server_options FROM cf_agents_mcp_servers");
843
974
  }
@@ -1623,6 +1754,6 @@ function getNamespacedData(mcpClients, type) {
1623
1754
  });
1624
1755
  }
1625
1756
  //#endregion
1626
- export { RPCServerTransport as a, RPCClientTransport as i, getNamespacedData as n, RPC_DO_PREFIX as o, MCPConnectionState as r, DisposableStore as s, MCPClientManager as t };
1757
+ export { MCPConnectionState as a, RPC_DO_PREFIX as c, normalizeServerId as i, DisposableStore as l, MCP_SERVER_ID_MAX_LENGTH as n, RPCClientTransport as o, getNamespacedData as r, RPCServerTransport as s, MCPClientManager as t };
1627
1758
 
1628
- //# sourceMappingURL=client-D1kFXo80.js.map
1759
+ //# sourceMappingURL=client-NradHZZz.js.map