@copilotkit/core 1.70.0 → 1.70.1

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/index.mjs CHANGED
@@ -2342,6 +2342,137 @@ function isForwardedToClientPlaceholder(content) {
2342
2342
  return normalizeToolResultContent(content) === FORWARDED_TO_CLIENT;
2343
2343
  }
2344
2344
 
2345
+ //#endregion
2346
+ //#region src/core/tool-schema.ts
2347
+ /**
2348
+ * Empty tool schema constant
2349
+ */
2350
+ const EMPTY_TOOL_SCHEMA = {
2351
+ type: "object",
2352
+ properties: {}
2353
+ };
2354
+ /**
2355
+ * Create a JSON schema from a tool's parameters
2356
+ */
2357
+ function createToolSchema(tool) {
2358
+ if (!tool.parameters) return { ...EMPTY_TOOL_SCHEMA };
2359
+ const rawSchema = schemaToJsonSchema(tool.parameters, { zodToJsonSchema: (schema, options) => zodToJsonSchema(schema, options) });
2360
+ if (!rawSchema || typeof rawSchema !== "object") return { ...EMPTY_TOOL_SCHEMA };
2361
+ const { $schema: _$schema, ...schema } = rawSchema;
2362
+ if (typeof schema.type !== "string") schema.type = "object";
2363
+ if (typeof schema.properties !== "object" || schema.properties === null) schema.properties = {};
2364
+ stripAdditionalProperties(schema);
2365
+ return schema;
2366
+ }
2367
+ /**
2368
+ * Remove every `additionalProperties` key from a JSON schema tree, in place.
2369
+ * Some LLM providers reject schemas that carry it.
2370
+ */
2371
+ function stripAdditionalProperties(schema) {
2372
+ if (!schema || typeof schema !== "object") return;
2373
+ if (Array.isArray(schema)) {
2374
+ schema.forEach(stripAdditionalProperties);
2375
+ return;
2376
+ }
2377
+ const record = schema;
2378
+ if (record.additionalProperties !== void 0) delete record.additionalProperties;
2379
+ for (const value of Object.values(record)) stripAdditionalProperties(value);
2380
+ }
2381
+
2382
+ //#endregion
2383
+ //#region src/core/webmcp.ts
2384
+ /**
2385
+ * Return the page's `document.modelContext`, or null when WebMCP is not
2386
+ * available (SSR, React Native, browsers without the API enabled).
2387
+ */
2388
+ function getWebMCPModelContext() {
2389
+ if (typeof document === "undefined") return null;
2390
+ return document.modelContext ?? null;
2391
+ }
2392
+ /**
2393
+ * Keeps a set of frontend tools registered on the page's WebMCP model context.
2394
+ *
2395
+ * `sync(desired)` reconciles the registrations with the desired set: tools that
2396
+ * are gone (or were re-registered with a new tool object) are unregistered by
2397
+ * aborting their registration signal, and new tools are registered with an
2398
+ * `execute` that delegates to the frontend tool's own handler.
2399
+ *
2400
+ * All WebMCP-API constraints live here so callers only supply the desired set:
2401
+ * a tool without a description is skipped with a warning (the spec rejects
2402
+ * empty descriptions), and failures from `registerTool` (duplicate name,
2403
+ * unsupported context, ...) are warned rather than thrown.
2404
+ */
2405
+ var WebMCPRegistry = class {
2406
+ entries = /* @__PURE__ */ new Map();
2407
+ warnedNames = /* @__PURE__ */ new Set();
2408
+ /** Names currently kept registered on the model context. */
2409
+ get registeredNames() {
2410
+ return [...this.entries.keys()];
2411
+ }
2412
+ /** Reconcile the registered tools with the desired set. */
2413
+ sync(desired) {
2414
+ const modelContext = getWebMCPModelContext();
2415
+ if (!modelContext) return;
2416
+ for (const [name, entry] of [...this.entries]) if (desired.get(name) !== entry.tool) {
2417
+ entry.controller.abort();
2418
+ this.entries.delete(name);
2419
+ }
2420
+ for (const [name, tool] of desired) {
2421
+ if (this.entries.has(name)) continue;
2422
+ if (!tool.description) {
2423
+ this.warnOnce(name, `Skipping WebMCP registration for tool '${name}': WebMCP requires a description.`);
2424
+ continue;
2425
+ }
2426
+ const controller = new AbortController();
2427
+ this.entries.set(name, {
2428
+ tool,
2429
+ controller
2430
+ });
2431
+ modelContext.registerTool(this.buildModelContextTool(tool), { signal: controller.signal }).catch((error) => {
2432
+ if (this.entries.get(name)?.controller !== controller) return;
2433
+ this.entries.delete(name);
2434
+ const message = error instanceof Error ? error.message : String(error);
2435
+ this.warnOnce(name, `WebMCP registration failed for tool '${name}': ${message}`);
2436
+ });
2437
+ }
2438
+ }
2439
+ /**
2440
+ * Build the WebMCP model-context tool for a frontend tool. The `execute`
2441
+ * callback delegates to the frontend tool's own handler, so a browser agent
2442
+ * call runs the same application code as an agent call.
2443
+ */
2444
+ buildModelContextTool(tool) {
2445
+ const annotations = typeof tool.webmcp === "object" ? tool.webmcp.annotations : void 0;
2446
+ return {
2447
+ name: tool.name,
2448
+ description: tool.description,
2449
+ inputSchema: createToolSchema(tool),
2450
+ execute: async (args, options) => {
2451
+ if (!tool.handler) return "";
2452
+ const toolCall = {
2453
+ id: randomUUID$1(),
2454
+ type: "function",
2455
+ function: {
2456
+ name: tool.name,
2457
+ arguments: JSON.stringify(args ?? {})
2458
+ }
2459
+ };
2460
+ return await tool.handler(args, {
2461
+ toolCall,
2462
+ signal: options?.signal
2463
+ });
2464
+ },
2465
+ ...annotations ? { annotations } : {}
2466
+ };
2467
+ }
2468
+ /** Log `message` once per tool name. Repeated syncs must not spam the log. */
2469
+ warnOnce(name, message) {
2470
+ if (this.warnedNames.has(name)) return;
2471
+ this.warnedNames.add(name);
2472
+ logger.warn(`[CopilotKit] ${message}`);
2473
+ }
2474
+ };
2475
+
2345
2476
  //#endregion
2346
2477
  //#region src/core/run-handler.ts
2347
2478
  /**
@@ -2424,6 +2555,12 @@ var RunHandler = class {
2424
2555
  */
2425
2556
  _runDepth = 0;
2426
2557
  /**
2558
+ * Keeps tools that opt in via `webmcp` registered on the page's WebMCP model
2559
+ * context (`document.modelContext`), in addition to the normal agent
2560
+ * registration. Reconciled on every tool registry mutation.
2561
+ */
2562
+ _webmcpRegistry = new WebMCPRegistry();
2563
+ /**
2427
2564
  * Tracks the threadId of the most recent `connectAgent` call so we
2428
2565
  * can distinguish a fresh thread restore (different threadId than
2429
2566
  * last time — chat is rebuilding state from scratch, must clear
@@ -2494,6 +2631,7 @@ var RunHandler = class {
2494
2631
  initialize(tools) {
2495
2632
  this._propTools = [...tools];
2496
2633
  this._cachedMergedTools = null;
2634
+ this.syncWebMCP();
2497
2635
  }
2498
2636
  /**
2499
2637
  * Add a tool to the registry. Survives provider re-syncs ({@link setTools}),
@@ -2507,6 +2645,7 @@ var RunHandler = class {
2507
2645
  }
2508
2646
  this._hookTools.set(key, tool);
2509
2647
  this._cachedMergedTools = null;
2648
+ this.syncWebMCP();
2510
2649
  }
2511
2650
  /**
2512
2651
  * Remove a tool by name and optionally by agentId
@@ -2518,6 +2657,7 @@ var RunHandler = class {
2518
2657
  return !(tool.name === id && !tool.agentId);
2519
2658
  });
2520
2659
  this._cachedMergedTools = null;
2660
+ this.syncWebMCP();
2521
2661
  }
2522
2662
  /**
2523
2663
  * Get a tool by name and optionally by agentId.
@@ -2540,6 +2680,7 @@ var RunHandler = class {
2540
2680
  setTools(tools) {
2541
2681
  this._propTools = [...tools];
2542
2682
  this._cachedMergedTools = null;
2683
+ this.syncWebMCP();
2543
2684
  }
2544
2685
  /**
2545
2686
  * Return the registered A2UI catalog components (readonly).
@@ -3061,6 +3202,7 @@ var RunHandler = class {
3061
3202
  const key = this.capabilityKey(name, agentId);
3062
3203
  if (enabled) this._disabledToolKeys.delete(key);
3063
3204
  else this._disabledToolKeys.add(key);
3205
+ this.syncWebMCP();
3064
3206
  }
3065
3207
  /** Whether a tool is currently enabled (not overridden off). Defaults true. */
3066
3208
  isToolEnabled(name, agentId) {
@@ -3077,6 +3219,32 @@ var RunHandler = class {
3077
3219
  }));
3078
3220
  }
3079
3221
  /**
3222
+ * Reconcile the WebMCP registrations with the current tool registry. Tools
3223
+ * opt in via `webmcp: true` or `webmcp: { annotations }`; the same
3224
+ * availability rules as `buildFrontendTools` apply. WebMCP tools are
3225
+ * page-level, so unlike the agent tool list they are not filtered by
3226
+ * agentId — a name collision across agentIds keeps the first registration.
3227
+ */
3228
+ syncWebMCP() {
3229
+ const desired = /* @__PURE__ */ new Map();
3230
+ const warnedCollisions = /* @__PURE__ */ new Set();
3231
+ for (const tool of this.tools) {
3232
+ if (!tool.webmcp) continue;
3233
+ if (tool.name === WILDCARD_TOOL_NAME) continue;
3234
+ if (tool.available === false || tool.available === "disabled") continue;
3235
+ if (!this.isToolEnabled(tool.name, tool.agentId)) continue;
3236
+ if (desired.has(tool.name)) {
3237
+ if (!warnedCollisions.has(tool.name)) {
3238
+ warnedCollisions.add(tool.name);
3239
+ logger.warn(`[CopilotKit] Multiple WebMCP tools share the name '${tool.name}'. Only the first registration is exposed to browser agents.`);
3240
+ }
3241
+ continue;
3242
+ }
3243
+ desired.set(tool.name, tool);
3244
+ }
3245
+ this._webmcpRegistry.sync(desired);
3246
+ }
3247
+ /**
3080
3248
  * Create an agent error subscriber
3081
3249
  */
3082
3250
  createAgentErrorSubscriber(agent) {
@@ -3109,36 +3277,6 @@ var RunHandler = class {
3109
3277
  }
3110
3278
  };
3111
3279
  /**
3112
- * Empty tool schema constant
3113
- */
3114
- const EMPTY_TOOL_SCHEMA = {
3115
- type: "object",
3116
- properties: {}
3117
- };
3118
- /**
3119
- * Create a JSON schema from a tool's parameters
3120
- */
3121
- function createToolSchema(tool) {
3122
- if (!tool.parameters) return { ...EMPTY_TOOL_SCHEMA };
3123
- const rawSchema = schemaToJsonSchema(tool.parameters, { zodToJsonSchema: (schema, options) => zodToJsonSchema(schema, options) });
3124
- if (!rawSchema || typeof rawSchema !== "object") return { ...EMPTY_TOOL_SCHEMA };
3125
- const { $schema: _$schema, ...schema } = rawSchema;
3126
- if (typeof schema.type !== "string") schema.type = "object";
3127
- if (typeof schema.properties !== "object" || schema.properties === null) schema.properties = {};
3128
- stripAdditionalProperties(schema);
3129
- return schema;
3130
- }
3131
- function stripAdditionalProperties(schema) {
3132
- if (!schema || typeof schema !== "object") return;
3133
- if (Array.isArray(schema)) {
3134
- schema.forEach(stripAdditionalProperties);
3135
- return;
3136
- }
3137
- const record = schema;
3138
- if (record.additionalProperties !== void 0) delete record.additionalProperties;
3139
- for (const value of Object.values(record)) stripAdditionalProperties(value);
3140
- }
3141
- /**
3142
3280
  * Ensures parsed tool arguments are a plain object.
3143
3281
  * Throws for non-object values so the caller's catch block can emit
3144
3282
  * a structured TOOL_ARGUMENT_PARSE_FAILED error.
@@ -6552,5 +6690,5 @@ function onInspectorViewThreadResult(handler) {
6552
6690
  }
6553
6691
 
6554
6692
  //#endregion
6555
- export { AgentRegistry, AgentThreadLockedError, ContextStore, CopilotKitCore, CopilotKitCoreErrorCode, CopilotKitCoreRuntimeConnectionStatus, INSPECTOR_THREAD_BRIDGE_PLUGIN_ID, IntelligenceAgent, MEMORY_ERROR_REGISTRY, MemoryError, ProxiedCopilotRuntimeAgent, RunHandler, StateManager, SuggestionEngine, ToolCallStatus, completePartialMarkdown, createActionGroup, createEffect, createInspectorThreadRequestId, createReducer, createSelector, createStore, emitInspectorActiveThread, emitInspectorStopViewing, emitInspectorViewThread, emitInspectorViewThreadResult, empty, ensureObjectArgs, isAbortError, isInspectorThreadBridgeEnabled, isRunCompletionAware, ofType, on, onInspectorActiveThread, onInspectorStopViewing, onInspectorViewThread, onInspectorViewThreadResult, parseToolArguments, props, select, ɵCOPILOTKIT_FEATURES, ɵInterruptState, ɵMAX_SOCKET_RETRIES, ɵRUNTIME_PROBE_TIMEOUT_MS, ɵTHREAD_REQUEST_TIMEOUT_MS, createMemoryStore as ɵcreateMemoryStore, ɵcreateThreadSelectors, createThreadStore as ɵcreateThreadStore, ɵisCopilotKitFeature, isRetryableStatus as ɵisRetryableMemoryStatus, ɵjoinPhoenixChannel$, ɵmapMemoryMetadataEvent, ɵmemoryAdapterEvents, ɵmemoryDomainEvents, ɵmemoryReducer, ɵmemoryRestEvents, ɵobservePhoenixEvent$, ɵobservePhoenixJoinOutcome$, ɵobservePhoenixSocketHealth$, ɵobservePhoenixSocketSignals$, ɵphoenixChannel$, ɵphoenixSocket$, ɵselectFetchMoreError, ɵselectHasNextPage, ɵselectIsFetchingNextPage, ɵselectIsMutating, ɵselectMemories, ɵselectMemoriesAvailable, ɵselectMemoriesError, ɵselectMemoriesIsLoading, ɵselectMemoriesIsMutating, ɵselectMemoriesRealtimeStatus, ɵselectThreads, ɵselectThreadsError, ɵselectThreadsIsLoading, ɵthreadAdapterEvents };
6693
+ export { AgentRegistry, AgentThreadLockedError, ContextStore, CopilotKitCore, CopilotKitCoreErrorCode, CopilotKitCoreRuntimeConnectionStatus, INSPECTOR_THREAD_BRIDGE_PLUGIN_ID, IntelligenceAgent, MEMORY_ERROR_REGISTRY, MemoryError, ProxiedCopilotRuntimeAgent, RunHandler, StateManager, SuggestionEngine, ToolCallStatus, WebMCPRegistry, completePartialMarkdown, createActionGroup, createEffect, createInspectorThreadRequestId, createReducer, createSelector, createStore, emitInspectorActiveThread, emitInspectorStopViewing, emitInspectorViewThread, emitInspectorViewThreadResult, empty, ensureObjectArgs, getWebMCPModelContext, isAbortError, isInspectorThreadBridgeEnabled, isRunCompletionAware, ofType, on, onInspectorActiveThread, onInspectorStopViewing, onInspectorViewThread, onInspectorViewThreadResult, parseToolArguments, props, select, ɵCOPILOTKIT_FEATURES, ɵInterruptState, ɵMAX_SOCKET_RETRIES, ɵRUNTIME_PROBE_TIMEOUT_MS, ɵTHREAD_REQUEST_TIMEOUT_MS, createMemoryStore as ɵcreateMemoryStore, ɵcreateThreadSelectors, createThreadStore as ɵcreateThreadStore, ɵisCopilotKitFeature, isRetryableStatus as ɵisRetryableMemoryStatus, ɵjoinPhoenixChannel$, ɵmapMemoryMetadataEvent, ɵmemoryAdapterEvents, ɵmemoryDomainEvents, ɵmemoryReducer, ɵmemoryRestEvents, ɵobservePhoenixEvent$, ɵobservePhoenixJoinOutcome$, ɵobservePhoenixSocketHealth$, ɵobservePhoenixSocketSignals$, ɵphoenixChannel$, ɵphoenixSocket$, ɵselectFetchMoreError, ɵselectHasNextPage, ɵselectIsFetchingNextPage, ɵselectIsMutating, ɵselectMemories, ɵselectMemoriesAvailable, ɵselectMemoriesError, ɵselectMemoriesIsLoading, ɵselectMemoriesIsMutating, ɵselectMemoriesRealtimeStatus, ɵselectThreads, ɵselectThreadsError, ɵselectThreadsIsLoading, ɵthreadAdapterEvents };
6556
6694
  //# sourceMappingURL=index.mjs.map