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