@copilotkit/react-core 1.61.1 → 1.62.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{copilotkit-UY-H6Kx7.mjs → copilotkit-BtRkFsNR.mjs} +1227 -599
- package/dist/copilotkit-BtRkFsNR.mjs.map +1 -0
- package/dist/{copilotkit-BCJDP8qd.cjs → copilotkit-CdpDZi3i.cjs} +1219 -585
- package/dist/copilotkit-CdpDZi3i.cjs.map +1 -0
- package/dist/{copilotkit-CEdu_aie.d.cts → copilotkit-Cga6AHO0.d.cts} +497 -209
- package/dist/copilotkit-Cga6AHO0.d.cts.map +1 -0
- package/dist/{copilotkit-M1FiciGd.d.mts → copilotkit-DnLpJ2Cl.d.mts} +497 -209
- package/dist/copilotkit-DnLpJ2Cl.d.mts.map +1 -0
- package/dist/index.cjs +1 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1 -1
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.mts +1 -1
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +1 -1
- package/dist/index.mjs.map +1 -1
- package/dist/index.umd.js +360 -270
- package/dist/index.umd.js.map +1 -1
- package/dist/v2/context.d.cts +5 -1
- package/dist/v2/context.d.cts.map +1 -1
- package/dist/v2/context.d.mts +5 -1
- package/dist/v2/context.d.mts.map +1 -1
- package/dist/v2/headless.cjs +323 -104
- package/dist/v2/headless.cjs.map +1 -1
- package/dist/v2/headless.d.cts +187 -69
- package/dist/v2/headless.d.cts.map +1 -1
- package/dist/v2/headless.d.mts +187 -69
- package/dist/v2/headless.d.mts.map +1 -1
- package/dist/v2/headless.mjs +325 -106
- package/dist/v2/headless.mjs.map +1 -1
- package/dist/v2/index.cjs +2 -1
- package/dist/v2/index.css +1 -1
- package/dist/v2/index.d.cts +2 -2
- package/dist/v2/index.d.mts +2 -2
- package/dist/v2/index.mjs +2 -2
- package/dist/v2/index.umd.js +1112 -484
- package/dist/v2/index.umd.js.map +1 -1
- package/package.json +8 -6
- package/dist/copilotkit-BCJDP8qd.cjs.map +0 -1
- package/dist/copilotkit-CEdu_aie.d.cts.map +0 -1
- package/dist/copilotkit-M1FiciGd.d.mts.map +0 -1
- package/dist/copilotkit-UY-H6Kx7.mjs.map +0 -1
package/dist/index.umd.js
CHANGED
|
@@ -144,6 +144,25 @@ react_markdown = __toESM(react_markdown);
|
|
|
144
144
|
modalHeaderTitle: "CopilotKit Chat",
|
|
145
145
|
welcomeMessageText: "How can I help you today?"
|
|
146
146
|
};
|
|
147
|
+
/**
|
|
148
|
+
* Mobile breakpoint below which the chat modal and the thread-list drawer are
|
|
149
|
+
* mutually exclusive. At or above this width both surfaces may coexist. This
|
|
150
|
+
* mirrors the `(max-width: 767px)` / `(min-width: 768px)` split already used by
|
|
151
|
+
* CopilotChatInput and CopilotSidebarView.
|
|
152
|
+
*/
|
|
153
|
+
const MOBILE_MAX_WIDTH_PX = 767;
|
|
154
|
+
/**
|
|
155
|
+
* Reports whether the current viewport is in the mobile range (`<768px`), where
|
|
156
|
+
* the chat modal and drawer must not be open simultaneously. SSR-safe and
|
|
157
|
+
* defensive against environments without `matchMedia` (treated as desktop, so
|
|
158
|
+
* no mutual-exclusion constraint is applied).
|
|
159
|
+
*
|
|
160
|
+
* @returns `true` when the viewport is mobile-width, `false` otherwise.
|
|
161
|
+
*/
|
|
162
|
+
function isMobileViewport() {
|
|
163
|
+
if (typeof window === "undefined" || typeof window.matchMedia !== "function") return false;
|
|
164
|
+
return window.matchMedia(`(max-width: ${MOBILE_MAX_WIDTH_PX}px)`).matches;
|
|
165
|
+
}
|
|
147
166
|
const CopilotChatConfiguration = (0, react.createContext)(null);
|
|
148
167
|
const CopilotChatConfigurationProvider = ({ children, labels, agentId, threadId, hasExplicitThreadId, isModalDefaultOpen }) => {
|
|
149
168
|
const parentConfig = (0, react.useContext)(CopilotChatConfiguration);
|
|
@@ -154,12 +173,22 @@ react_markdown = __toESM(react_markdown);
|
|
|
154
173
|
...stableLabels
|
|
155
174
|
}), [stableLabels, parentConfig?.labels]);
|
|
156
175
|
const resolvedAgentId = agentId ?? parentConfig?.agentId ?? _copilotkit_shared.DEFAULT_AGENT_ID;
|
|
176
|
+
const threadIdPropIsAuthoritative = threadId !== void 0 && hasExplicitThreadId !== false;
|
|
177
|
+
const isThreadIdControlled = threadIdPropIsAuthoritative;
|
|
178
|
+
const [activeThreadOverride, setActiveThreadOverride] = (0, react.useState)(null);
|
|
157
179
|
const resolvedThreadId = (0, react.useMemo)(() => {
|
|
158
|
-
if (
|
|
180
|
+
if (threadIdPropIsAuthoritative) return threadId;
|
|
181
|
+
if (activeThreadOverride) return activeThreadOverride.threadId;
|
|
159
182
|
if (parentConfig?.threadId) return parentConfig.threadId;
|
|
183
|
+
if (threadId) return threadId;
|
|
160
184
|
return (0, _copilotkit_shared.randomUUID)();
|
|
161
|
-
}, [
|
|
162
|
-
|
|
185
|
+
}, [
|
|
186
|
+
threadIdPropIsAuthoritative,
|
|
187
|
+
threadId,
|
|
188
|
+
parentConfig?.threadId,
|
|
189
|
+
activeThreadOverride
|
|
190
|
+
]);
|
|
191
|
+
const resolvedHasExplicitThreadId = (threadIdPropIsAuthoritative ? true : activeThreadOverride?.explicit ?? hasExplicitThreadId ?? false) || !!parentConfig?.hasExplicitThreadId;
|
|
163
192
|
const [internalModalOpen, setInternalModalOpen] = (0, react.useState)(isModalDefaultOpen ?? true);
|
|
164
193
|
const hasExplicitDefault = isModalDefaultOpen !== void 0;
|
|
165
194
|
const setAndSync = (0, react.useCallback)((open) => {
|
|
@@ -178,20 +207,113 @@ react_markdown = __toESM(react_markdown);
|
|
|
178
207
|
}, [parentConfig?.isModalOpen, hasExplicitDefault]);
|
|
179
208
|
const resolvedIsModalOpen = hasExplicitDefault ? internalModalOpen : parentConfig?.isModalOpen ?? internalModalOpen;
|
|
180
209
|
const resolvedSetModalOpen = hasExplicitDefault ? setAndSync : parentConfig?.setModalOpen ?? setInternalModalOpen;
|
|
210
|
+
const [ownDrawerOpen, setOwnDrawerOpen] = (0, react.useState)(false);
|
|
211
|
+
const [ownDrawerCount, setOwnDrawerCount] = (0, react.useState)(0);
|
|
212
|
+
const modalCloseRef = (0, react.useRef)(() => {});
|
|
213
|
+
modalCloseRef.current = resolvedSetModalOpen;
|
|
214
|
+
const registeredModalClosersRef = (0, react.useRef)([]);
|
|
215
|
+
const ownRegisterModalCloser = (0, react.useCallback)((closeModal) => {
|
|
216
|
+
registeredModalClosersRef.current.push(closeModal);
|
|
217
|
+
return () => {
|
|
218
|
+
registeredModalClosersRef.current = registeredModalClosersRef.current.filter((entry) => entry !== closeModal);
|
|
219
|
+
};
|
|
220
|
+
}, []);
|
|
221
|
+
const ownSetDrawerOpen = (0, react.useCallback)((open) => {
|
|
222
|
+
setOwnDrawerOpen(open);
|
|
223
|
+
if (open && isMobileViewport()) {
|
|
224
|
+
const registered = registeredModalClosersRef.current;
|
|
225
|
+
(registered.length > 0 ? registered[registered.length - 1] : modalCloseRef.current)(false);
|
|
226
|
+
}
|
|
227
|
+
}, []);
|
|
228
|
+
const ownRegisterDrawer = (0, react.useCallback)(() => {
|
|
229
|
+
setOwnDrawerCount((count) => count + 1);
|
|
230
|
+
return () => {
|
|
231
|
+
setOwnDrawerCount((count) => Math.max(0, count - 1));
|
|
232
|
+
};
|
|
233
|
+
}, []);
|
|
234
|
+
const resolvedDrawerOpen = parentConfig ? parentConfig.drawerOpen : ownDrawerOpen;
|
|
235
|
+
const resolvedSetDrawerOpen = parentConfig ? parentConfig.setDrawerOpen : ownSetDrawerOpen;
|
|
236
|
+
const resolvedDrawerRegistered = parentConfig ? parentConfig.drawerRegistered : ownDrawerCount > 0;
|
|
237
|
+
const resolvedRegisterDrawer = parentConfig ? parentConfig.registerDrawer : ownRegisterDrawer;
|
|
238
|
+
const resolvedRegisterModalCloser = parentConfig ? parentConfig.ɵregisterModalCloser : ownRegisterModalCloser;
|
|
239
|
+
(0, react.useEffect)(() => {
|
|
240
|
+
if (!hasExplicitDefault) return;
|
|
241
|
+
return resolvedRegisterModalCloser(resolvedSetModalOpen);
|
|
242
|
+
}, [
|
|
243
|
+
hasExplicitDefault,
|
|
244
|
+
resolvedRegisterModalCloser,
|
|
245
|
+
resolvedSetModalOpen
|
|
246
|
+
]);
|
|
247
|
+
const isThreadIdControlledRef = (0, react.useRef)(isThreadIdControlled);
|
|
248
|
+
isThreadIdControlledRef.current = isThreadIdControlled;
|
|
249
|
+
const ownSetActiveThreadId = (0, react.useCallback)((id, options) => {
|
|
250
|
+
setActiveThreadOverride({
|
|
251
|
+
threadId: id,
|
|
252
|
+
explicit: options?.explicit ?? true
|
|
253
|
+
});
|
|
254
|
+
}, []);
|
|
255
|
+
const ownStartNewThread = (0, react.useCallback)(() => {
|
|
256
|
+
setActiveThreadOverride({
|
|
257
|
+
threadId: (0, _copilotkit_shared.randomUUID)(),
|
|
258
|
+
explicit: false
|
|
259
|
+
});
|
|
260
|
+
}, []);
|
|
261
|
+
const parentSetActiveThreadId = parentConfig?.setActiveThreadId;
|
|
262
|
+
const parentStartNewThread = parentConfig?.startNewThread;
|
|
263
|
+
const resolvedSetActiveThreadId = (0, react.useCallback)((id, options) => {
|
|
264
|
+
if (isThreadIdControlledRef.current) {
|
|
265
|
+
console.warn("[CopilotKit] Ignoring setActiveThreadId(): threadId is controlled via the `threadId` prop on CopilotChatConfigurationProvider.");
|
|
266
|
+
return;
|
|
267
|
+
}
|
|
268
|
+
if (parentSetActiveThreadId) {
|
|
269
|
+
parentSetActiveThreadId(id, options);
|
|
270
|
+
return;
|
|
271
|
+
}
|
|
272
|
+
ownSetActiveThreadId(id, options);
|
|
273
|
+
}, [parentSetActiveThreadId, ownSetActiveThreadId]);
|
|
274
|
+
const resolvedStartNewThread = (0, react.useCallback)(() => {
|
|
275
|
+
if (isThreadIdControlledRef.current) {
|
|
276
|
+
console.warn("[CopilotKit] Ignoring startNewThread(): threadId is controlled via the `threadId` prop on CopilotChatConfigurationProvider.");
|
|
277
|
+
return;
|
|
278
|
+
}
|
|
279
|
+
if (parentStartNewThread) {
|
|
280
|
+
parentStartNewThread();
|
|
281
|
+
return;
|
|
282
|
+
}
|
|
283
|
+
ownStartNewThread();
|
|
284
|
+
}, [parentStartNewThread, ownStartNewThread]);
|
|
285
|
+
const setModalOpenWithDrawerExclusion = (0, react.useCallback)((open) => {
|
|
286
|
+
if (open && isMobileViewport()) resolvedSetDrawerOpen(false);
|
|
287
|
+
resolvedSetModalOpen(open);
|
|
288
|
+
}, [resolvedSetModalOpen, resolvedSetDrawerOpen]);
|
|
181
289
|
const configurationValue = (0, react.useMemo)(() => ({
|
|
182
290
|
labels: mergedLabels,
|
|
183
291
|
agentId: resolvedAgentId,
|
|
184
292
|
threadId: resolvedThreadId,
|
|
185
293
|
hasExplicitThreadId: resolvedHasExplicitThreadId,
|
|
186
294
|
isModalOpen: resolvedIsModalOpen,
|
|
187
|
-
setModalOpen:
|
|
295
|
+
setModalOpen: setModalOpenWithDrawerExclusion,
|
|
296
|
+
drawerOpen: resolvedDrawerOpen,
|
|
297
|
+
setDrawerOpen: resolvedSetDrawerOpen,
|
|
298
|
+
drawerRegistered: resolvedDrawerRegistered,
|
|
299
|
+
registerDrawer: resolvedRegisterDrawer,
|
|
300
|
+
ɵregisterModalCloser: resolvedRegisterModalCloser,
|
|
301
|
+
setActiveThreadId: resolvedSetActiveThreadId,
|
|
302
|
+
startNewThread: resolvedStartNewThread
|
|
188
303
|
}), [
|
|
189
304
|
mergedLabels,
|
|
190
305
|
resolvedAgentId,
|
|
191
306
|
resolvedThreadId,
|
|
192
307
|
resolvedHasExplicitThreadId,
|
|
193
308
|
resolvedIsModalOpen,
|
|
194
|
-
|
|
309
|
+
setModalOpenWithDrawerExclusion,
|
|
310
|
+
resolvedDrawerOpen,
|
|
311
|
+
resolvedSetDrawerOpen,
|
|
312
|
+
resolvedDrawerRegistered,
|
|
313
|
+
resolvedRegisterDrawer,
|
|
314
|
+
resolvedRegisterModalCloser,
|
|
315
|
+
resolvedSetActiveThreadId,
|
|
316
|
+
resolvedStartNewThread
|
|
195
317
|
]);
|
|
196
318
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(CopilotChatConfiguration.Provider, {
|
|
197
319
|
value: configurationValue,
|
|
@@ -327,149 +449,6 @@ react_markdown = __toESM(react_markdown);
|
|
|
327
449
|
getLimit: () => null
|
|
328
450
|
});
|
|
329
451
|
|
|
330
|
-
//#endregion
|
|
331
|
-
//#region src/v2/types/defineToolCallRenderer.ts
|
|
332
|
-
function defineToolCallRenderer(def) {
|
|
333
|
-
const argsSchema = def.name === "*" && !def.args ? zod.z.any() : def.args;
|
|
334
|
-
return {
|
|
335
|
-
name: def.name,
|
|
336
|
-
args: argsSchema,
|
|
337
|
-
render: def.render,
|
|
338
|
-
...def.agentId ? { agentId: def.agentId } : {}
|
|
339
|
-
};
|
|
340
|
-
}
|
|
341
|
-
|
|
342
|
-
//#endregion
|
|
343
|
-
//#region src/v2/hooks/use-default-render-tool.tsx
|
|
344
|
-
/**
|
|
345
|
-
* Module-level dedup set so an unknown status value only emits a console
|
|
346
|
-
* warning the FIRST time we encounter it. Otherwise a stuck/unmapped status
|
|
347
|
-
* would log on every re-render (potentially many per second).
|
|
348
|
-
*/
|
|
349
|
-
const warnedUnknownStatuses = /* @__PURE__ */ new Set();
|
|
350
|
-
/**
|
|
351
|
-
* Map a {@link ToolCallStatus} enum value to the documented string-union
|
|
352
|
-
* status the {@link DefaultRenderProps} contract exposes. Unknown / future
|
|
353
|
-
* enum members log a warning (once per distinct value) and fall back to
|
|
354
|
-
* `"inProgress"`.
|
|
355
|
-
*/
|
|
356
|
-
function mapToolCallStatus(status) {
|
|
357
|
-
switch (status) {
|
|
358
|
-
case _copilotkit_core.ToolCallStatus.Complete: return "complete";
|
|
359
|
-
case _copilotkit_core.ToolCallStatus.Executing: return "executing";
|
|
360
|
-
case _copilotkit_core.ToolCallStatus.InProgress: return "inProgress";
|
|
361
|
-
default: {
|
|
362
|
-
const key = String(status);
|
|
363
|
-
if (!warnedUnknownStatuses.has(key)) {
|
|
364
|
-
warnedUnknownStatuses.add(key);
|
|
365
|
-
console.warn(`[CopilotKit] Unknown ToolCallStatus "${key}" in default tool-call renderer; falling back to "inProgress".`);
|
|
366
|
-
}
|
|
367
|
-
return "inProgress";
|
|
368
|
-
}
|
|
369
|
-
}
|
|
370
|
-
}
|
|
371
|
-
/**
|
|
372
|
-
* Guarded JSON.stringify used inside the expanded `<pre>` blocks. A circular
|
|
373
|
-
* reference would otherwise crash the entire React tree on render.
|
|
374
|
-
*/
|
|
375
|
-
function safeStringifyForPre(value) {
|
|
376
|
-
try {
|
|
377
|
-
return JSON.stringify(value, null, 2);
|
|
378
|
-
} catch (err) {
|
|
379
|
-
console.warn("[CopilotKit] Failed to JSON.stringify tool-call payload for default renderer; falling back to String():", err);
|
|
380
|
-
try {
|
|
381
|
-
return String(value);
|
|
382
|
-
} catch (innerErr) {
|
|
383
|
-
console.warn("[CopilotKit] safeStringifyForPre: value could not be stringified:", innerErr);
|
|
384
|
-
return "[unserializable]";
|
|
385
|
-
}
|
|
386
|
-
}
|
|
387
|
-
}
|
|
388
|
-
function DefaultToolCallRenderer({ name, toolCallId, parameters, status, result }) {
|
|
389
|
-
const [isExpanded, setIsExpanded] = (0, react.useState)(false);
|
|
390
|
-
const isActive = status === "inProgress" || status === "executing";
|
|
391
|
-
const isComplete = status === "complete";
|
|
392
|
-
const statusLabel = isActive ? "Running" : isComplete ? "Done" : status;
|
|
393
|
-
const dotClassName = isActive ? "cpk:bg-amber-500" : isComplete ? "cpk:bg-emerald-500" : "cpk:bg-zinc-400";
|
|
394
|
-
const badgeClassName = isActive ? "cpk:bg-amber-100 cpk:text-amber-800 cpk:dark:bg-amber-500/15 cpk:dark:text-amber-400" : isComplete ? "cpk:bg-emerald-100 cpk:text-emerald-800 cpk:dark:bg-emerald-500/15 cpk:dark:text-emerald-400" : "cpk:bg-zinc-100 cpk:text-zinc-800 cpk:dark:bg-zinc-700/40 cpk:dark:text-zinc-300";
|
|
395
|
-
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
396
|
-
"data-testid": "copilot-tool-render",
|
|
397
|
-
"data-tool-name": name,
|
|
398
|
-
"data-tool-call-id": toolCallId,
|
|
399
|
-
"data-status": status,
|
|
400
|
-
"data-args": safeStringifyForAttr(parameters),
|
|
401
|
-
"data-result": safeStringifyForAttr(result),
|
|
402
|
-
className: "cpk:mt-2 cpk:pb-2",
|
|
403
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
404
|
-
className: "cpk:rounded-xl cpk:border cpk:border-zinc-200/60 cpk:bg-white/70 cpk:p-4 cpk:shadow-sm cpk:backdrop-blur cpk:dark:border-zinc-800/60 cpk:dark:bg-zinc-900/50",
|
|
405
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
406
|
-
type: "button",
|
|
407
|
-
"aria-expanded": isExpanded,
|
|
408
|
-
onClick: () => setIsExpanded(!isExpanded),
|
|
409
|
-
className: "cpk:flex cpk:w-full cpk:cursor-pointer cpk:select-none cpk:items-center cpk:justify-between cpk:gap-2.5 cpk:border-none cpk:bg-transparent cpk:p-0 cpk:m-0 cpk:text-left cpk:text-inherit",
|
|
410
|
-
style: { font: "inherit" },
|
|
411
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
412
|
-
className: "cpk:flex cpk:min-w-0 cpk:items-center cpk:gap-2",
|
|
413
|
-
children: [
|
|
414
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("svg", {
|
|
415
|
-
className: `cpk:h-3.5 cpk:w-3.5 cpk:flex-shrink-0 cpk:text-zinc-500 cpk:transition-transform cpk:dark:text-zinc-400 ${isExpanded ? "cpk:rotate-90" : ""}`,
|
|
416
|
-
fill: "none",
|
|
417
|
-
viewBox: "0 0 24 24",
|
|
418
|
-
strokeWidth: 2,
|
|
419
|
-
stroke: "currentColor",
|
|
420
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", {
|
|
421
|
-
strokeLinecap: "round",
|
|
422
|
-
strokeLinejoin: "round",
|
|
423
|
-
d: "M8.25 4.5l7.5 7.5-7.5 7.5"
|
|
424
|
-
})
|
|
425
|
-
}),
|
|
426
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { className: `cpk:inline-block cpk:h-2 cpk:w-2 cpk:flex-shrink-0 cpk:rounded-full ${dotClassName}` }),
|
|
427
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
428
|
-
"data-testid": "copilot-tool-render-name",
|
|
429
|
-
className: "cpk:truncate cpk:text-[13px] cpk:font-semibold cpk:text-zinc-900 cpk:dark:text-zinc-100",
|
|
430
|
-
children: name
|
|
431
|
-
})
|
|
432
|
-
]
|
|
433
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
434
|
-
"data-testid": "copilot-tool-render-status",
|
|
435
|
-
className: `cpk:inline-flex cpk:flex-shrink-0 cpk:items-center cpk:rounded-full cpk:px-2 cpk:py-0.5 cpk:text-[11px] cpk:font-medium ${badgeClassName}`,
|
|
436
|
-
children: statusLabel
|
|
437
|
-
})]
|
|
438
|
-
}), isExpanded && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
439
|
-
className: "cpk:mt-3 cpk:grid cpk:gap-3",
|
|
440
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
441
|
-
className: "cpk:text-[10px] cpk:uppercase cpk:text-zinc-500 cpk:dark:text-zinc-400",
|
|
442
|
-
children: "Arguments"
|
|
443
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("pre", {
|
|
444
|
-
className: "cpk:mt-1.5 cpk:max-h-[200px] cpk:overflow-auto cpk:rounded-md cpk:bg-zinc-100 cpk:p-2.5 cpk:text-[11px] cpk:leading-relaxed cpk:text-zinc-800 cpk:whitespace-pre-wrap cpk:break-words cpk:dark:bg-zinc-800/60 cpk:dark:text-zinc-200",
|
|
445
|
-
children: safeStringifyForPre(parameters ?? {})
|
|
446
|
-
})] }), result !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
447
|
-
className: "cpk:text-[10px] cpk:uppercase cpk:text-zinc-500 cpk:dark:text-zinc-400",
|
|
448
|
-
children: "Result"
|
|
449
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("pre", {
|
|
450
|
-
className: "cpk:mt-1.5 cpk:max-h-[200px] cpk:overflow-auto cpk:rounded-md cpk:bg-zinc-100 cpk:p-2.5 cpk:text-[11px] cpk:leading-relaxed cpk:text-zinc-800 cpk:whitespace-pre-wrap cpk:break-words cpk:dark:bg-zinc-800/60 cpk:dark:text-zinc-200",
|
|
451
|
-
children: typeof result === "string" ? result : safeStringifyForPre(result)
|
|
452
|
-
})] })]
|
|
453
|
-
})]
|
|
454
|
-
})
|
|
455
|
-
});
|
|
456
|
-
}
|
|
457
|
-
function safeStringifyForAttr(value) {
|
|
458
|
-
if (value === void 0 || value === null) return "";
|
|
459
|
-
if (typeof value === "string") return value;
|
|
460
|
-
try {
|
|
461
|
-
return JSON.stringify(value);
|
|
462
|
-
} catch (err) {
|
|
463
|
-
console.warn("[CopilotKit] Failed to JSON.stringify tool-call payload for data-* attribute; falling back to String():", err);
|
|
464
|
-
try {
|
|
465
|
-
return String(value);
|
|
466
|
-
} catch (innerErr) {
|
|
467
|
-
console.warn("[CopilotKit] safeStringifyForAttr: value could not be stringified:", innerErr);
|
|
468
|
-
return "";
|
|
469
|
-
}
|
|
470
|
-
}
|
|
471
|
-
}
|
|
472
|
-
|
|
473
452
|
//#endregion
|
|
474
453
|
//#region src/v2/hooks/use-render-tool-call.tsx
|
|
475
454
|
/**
|
|
@@ -524,10 +503,13 @@ react_markdown = __toESM(react_markdown);
|
|
|
524
503
|
}, () => copilotkit.renderToolCalls, () => copilotkit.renderToolCalls);
|
|
525
504
|
return (0, react.useCallback)(({ toolCall, toolMessage }) => {
|
|
526
505
|
const exactMatches = renderToolCalls.filter((rc) => rc.name === toolCall.function.name);
|
|
506
|
+
const renderConfig = exactMatches.find((rc) => rc.agentId === agentId) || exactMatches.find((rc) => !rc.agentId) || exactMatches[0] || renderToolCalls.find((rc) => rc.name === "*");
|
|
507
|
+
if (!renderConfig) return null;
|
|
508
|
+
const RenderComponent = renderConfig.render;
|
|
527
509
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ToolCallRenderer, {
|
|
528
510
|
toolCall,
|
|
529
511
|
toolMessage,
|
|
530
|
-
RenderComponent
|
|
512
|
+
RenderComponent,
|
|
531
513
|
isExecuting: executingToolCallIds.has(toolCall.id)
|
|
532
514
|
}, toolCall.id);
|
|
533
515
|
}, [
|
|
@@ -536,15 +518,6 @@ react_markdown = __toESM(react_markdown);
|
|
|
536
518
|
agentId
|
|
537
519
|
]);
|
|
538
520
|
}
|
|
539
|
-
function defaultToolCallRenderAdapter(props) {
|
|
540
|
-
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(DefaultToolCallRenderer, {
|
|
541
|
-
name: props.name,
|
|
542
|
-
toolCallId: props.toolCallId,
|
|
543
|
-
parameters: props.args,
|
|
544
|
-
status: mapToolCallStatus(props.status),
|
|
545
|
-
result: props.result
|
|
546
|
-
});
|
|
547
|
-
}
|
|
548
521
|
|
|
549
522
|
//#endregion
|
|
550
523
|
//#region src/v2/components/CopilotKitInspector.tsx
|
|
@@ -1997,7 +1970,7 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
|
|
|
1997
1970
|
...A2UILifecycleFields
|
|
1998
1971
|
}).passthrough();
|
|
1999
1972
|
function createA2UIMessageRenderer(options) {
|
|
2000
|
-
const { theme, catalog, loadingComponent, recovery } = options;
|
|
1973
|
+
const { theme, catalog, loadingComponent, recovery, onAction } = options;
|
|
2001
1974
|
const showAfterMs = recovery?.showAfterMs ?? 2e3;
|
|
2002
1975
|
const showAfterAttempts = recovery?.showAfterAttempts ?? 2;
|
|
2003
1976
|
const optionDebugExposure = recovery?.debugExposure ?? "collapsed";
|
|
@@ -2073,6 +2046,7 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
|
|
|
2073
2046
|
agent,
|
|
2074
2047
|
copilotkit,
|
|
2075
2048
|
catalog,
|
|
2049
|
+
onAction,
|
|
2076
2050
|
onReady: markSurfaceReady
|
|
2077
2051
|
}, surfaceId))
|
|
2078
2052
|
});
|
|
@@ -2093,29 +2067,60 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
|
|
|
2093
2067
|
};
|
|
2094
2068
|
}
|
|
2095
2069
|
/**
|
|
2070
|
+
* Orchestrates a single A2UI user action: runs the optional `onAction`
|
|
2071
|
+
* interceptor first, then forwards to the agent unless the interceptor
|
|
2072
|
+
* suppressed it (returned `null`). Exported for unit testing; the wiring lives
|
|
2073
|
+
* in {@link ReactSurfaceHost}.
|
|
2074
|
+
*/
|
|
2075
|
+
async function runA2UIAction({ message, agent, copilotkit, onAction }) {
|
|
2076
|
+
if (!agent) return;
|
|
2077
|
+
const action = message.userAction;
|
|
2078
|
+
const forward = async (forwardAction) => {
|
|
2079
|
+
const a2uiAction = forwardAction !== void 0 ? {
|
|
2080
|
+
...message,
|
|
2081
|
+
userAction: forwardAction
|
|
2082
|
+
} : message;
|
|
2083
|
+
try {
|
|
2084
|
+
copilotkit.setProperties({
|
|
2085
|
+
...copilotkit.properties,
|
|
2086
|
+
a2uiAction
|
|
2087
|
+
});
|
|
2088
|
+
await copilotkit.runAgent({ agent });
|
|
2089
|
+
} finally {
|
|
2090
|
+
if (copilotkit.properties) {
|
|
2091
|
+
const { a2uiAction: _omit, ...rest } = copilotkit.properties;
|
|
2092
|
+
copilotkit.setProperties(rest);
|
|
2093
|
+
}
|
|
2094
|
+
}
|
|
2095
|
+
};
|
|
2096
|
+
if (onAction && action) {
|
|
2097
|
+
const result = await onAction(action, forward);
|
|
2098
|
+
if (result === null) return;
|
|
2099
|
+
if (result) {
|
|
2100
|
+
await forward(result);
|
|
2101
|
+
return;
|
|
2102
|
+
}
|
|
2103
|
+
}
|
|
2104
|
+
await forward();
|
|
2105
|
+
}
|
|
2106
|
+
/**
|
|
2096
2107
|
* Renders a single A2UI surface using the React renderer.
|
|
2097
2108
|
* Wraps A2UIProvider + A2UIRenderer and bridges actions back to CopilotKit.
|
|
2098
2109
|
*/
|
|
2099
|
-
function ReactSurfaceHost({ surfaceId, operations, theme, agent, copilotkit, catalog, onReady }) {
|
|
2110
|
+
function ReactSurfaceHost({ surfaceId, operations, theme, agent, copilotkit, catalog, onAction, onReady }) {
|
|
2100
2111
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
2101
2112
|
className: "cpk:flex cpk:w-full cpk:flex-none cpk:flex-col cpk:gap-4",
|
|
2102
2113
|
children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_copilotkit_a2ui_renderer.A2UIProvider, {
|
|
2103
|
-
onAction: (0, react.useCallback)(
|
|
2104
|
-
|
|
2105
|
-
|
|
2106
|
-
|
|
2107
|
-
|
|
2108
|
-
|
|
2109
|
-
|
|
2110
|
-
|
|
2111
|
-
|
|
2112
|
-
|
|
2113
|
-
if (copilotkit.properties) {
|
|
2114
|
-
const { a2uiAction, ...rest } = copilotkit.properties;
|
|
2115
|
-
copilotkit.setProperties(rest);
|
|
2116
|
-
}
|
|
2117
|
-
}
|
|
2118
|
-
}, [agent, copilotkit]),
|
|
2114
|
+
onAction: (0, react.useCallback)((message) => runA2UIAction({
|
|
2115
|
+
message,
|
|
2116
|
+
agent,
|
|
2117
|
+
copilotkit,
|
|
2118
|
+
onAction
|
|
2119
|
+
}), [
|
|
2120
|
+
agent,
|
|
2121
|
+
copilotkit,
|
|
2122
|
+
onAction
|
|
2123
|
+
]),
|
|
2119
2124
|
theme,
|
|
2120
2125
|
catalog,
|
|
2121
2126
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(SurfaceMessageProcessor, {
|
|
@@ -2186,6 +2191,18 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
|
|
|
2186
2191
|
return operation?.createSurface?.surfaceId ?? operation?.updateComponents?.surfaceId ?? operation?.updateDataModel?.surfaceId ?? operation?.deleteSurface?.surfaceId ?? null;
|
|
2187
2192
|
}
|
|
2188
2193
|
|
|
2194
|
+
//#endregion
|
|
2195
|
+
//#region src/v2/types/defineToolCallRenderer.ts
|
|
2196
|
+
function defineToolCallRenderer(def) {
|
|
2197
|
+
const argsSchema = def.name === "*" && !def.args ? zod.z.any() : def.args;
|
|
2198
|
+
return {
|
|
2199
|
+
name: def.name,
|
|
2200
|
+
args: argsSchema,
|
|
2201
|
+
render: def.render,
|
|
2202
|
+
...def.agentId ? { agentId: def.agentId } : {}
|
|
2203
|
+
};
|
|
2204
|
+
}
|
|
2205
|
+
|
|
2189
2206
|
//#endregion
|
|
2190
2207
|
//#region src/v2/a2ui/A2UIToolCallRenderer.tsx
|
|
2191
2208
|
/**
|
|
@@ -2280,6 +2297,10 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
|
|
|
2280
2297
|
|
|
2281
2298
|
//#endregion
|
|
2282
2299
|
//#region src/v2/providers/CopilotKitProvider.tsx
|
|
2300
|
+
const zodToJsonSchemaAdapter = (schema, options) => {
|
|
2301
|
+
const refStrategy = options?.$refStrategy;
|
|
2302
|
+
return (0, zod_to_json_schema.zodToJsonSchema)(schema, refStrategy === "root" || refStrategy === "relative" || refStrategy === "none" || refStrategy === "seen" ? { $refStrategy: refStrategy } : {});
|
|
2303
|
+
};
|
|
2283
2304
|
const HEADER_NAME = "X-CopilotCloud-Public-Api-Key";
|
|
2284
2305
|
const COPILOT_CLOUD_CHAT_URL$1 = "https://api.cloud.copilotkit.ai/copilotkit/v1";
|
|
2285
2306
|
const EMPTY_HEADERS = Object.freeze({});
|
|
@@ -2310,6 +2331,8 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
|
|
|
2310
2331
|
const [runtimeA2UIEnabled, setRuntimeA2UIEnabled] = (0, react.useState)(false);
|
|
2311
2332
|
const [runtimeOpenGenUIEnabled, setRuntimeOpenGenUIEnabled] = (0, react.useState)(false);
|
|
2312
2333
|
const openGenUIActive = runtimeOpenGenUIEnabled || !!openGenerativeUI;
|
|
2334
|
+
const a2uiCatalogProvided = !!a2ui?.catalog;
|
|
2335
|
+
const a2uiActive = runtimeA2UIEnabled || a2uiCatalogProvided;
|
|
2313
2336
|
const [runtimeLicenseStatus, setRuntimeLicenseStatus] = (0, react.useState)(void 0);
|
|
2314
2337
|
(0, react.useEffect)(() => {
|
|
2315
2338
|
if (typeof window === "undefined") return;
|
|
@@ -2340,7 +2363,7 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
|
|
|
2340
2363
|
content: OpenGenerativeUIContentSchema,
|
|
2341
2364
|
render: OpenGenerativeUIActivityRenderer
|
|
2342
2365
|
});
|
|
2343
|
-
if (
|
|
2366
|
+
if (a2uiActive) renderers.unshift(createA2UIMessageRenderer({
|
|
2344
2367
|
theme: a2ui?.theme ?? _copilotkit_a2ui_renderer.viewerTheme,
|
|
2345
2368
|
catalog: a2ui?.catalog,
|
|
2346
2369
|
loadingComponent: a2ui?.loadingComponent,
|
|
@@ -2348,7 +2371,7 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
|
|
|
2348
2371
|
}));
|
|
2349
2372
|
return renderers;
|
|
2350
2373
|
}, [
|
|
2351
|
-
|
|
2374
|
+
a2uiActive,
|
|
2352
2375
|
openGenUIActive,
|
|
2353
2376
|
a2ui
|
|
2354
2377
|
]);
|
|
@@ -2535,7 +2558,10 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
|
|
|
2535
2558
|
copilotkit.setRuntimeTransport(useSingleEndpoint === true ? "single" : useSingleEndpoint === false ? "rest" : "auto");
|
|
2536
2559
|
copilotkit.setHeaders(mergedHeaders);
|
|
2537
2560
|
copilotkit.setCredentials(credentials);
|
|
2538
|
-
copilotkit.setProperties(
|
|
2561
|
+
copilotkit.setProperties(a2uiCatalogProvided ? {
|
|
2562
|
+
...properties,
|
|
2563
|
+
a2uiCatalogAvailable: true
|
|
2564
|
+
} : properties);
|
|
2539
2565
|
copilotkit.setAgents__unsafe_dev_only(mergedAgents);
|
|
2540
2566
|
copilotkit.setDebug(debug);
|
|
2541
2567
|
}, [
|
|
@@ -2544,6 +2570,7 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
|
|
|
2544
2570
|
mergedHeaders,
|
|
2545
2571
|
credentials,
|
|
2546
2572
|
properties,
|
|
2573
|
+
a2uiCatalogProvided,
|
|
2547
2574
|
mergedAgents,
|
|
2548
2575
|
useSingleEndpoint,
|
|
2549
2576
|
debug
|
|
@@ -2591,7 +2618,7 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
|
|
|
2591
2618
|
return JSON.stringify(sandboxFunctionsList.map((fn) => ({
|
|
2592
2619
|
name: fn.name,
|
|
2593
2620
|
description: fn.description,
|
|
2594
|
-
parameters: (0, _copilotkit_shared.schemaToJsonSchema)(fn.parameters, { zodToJsonSchema:
|
|
2621
|
+
parameters: (0, _copilotkit_shared.schemaToJsonSchema)(fn.parameters, { zodToJsonSchema: zodToJsonSchemaAdapter })
|
|
2595
2622
|
})));
|
|
2596
2623
|
}, [sandboxFunctionsList]);
|
|
2597
2624
|
(0, react.useLayoutEffect)(() => {
|
|
@@ -2612,7 +2639,7 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
|
|
|
2612
2639
|
copilotkit,
|
|
2613
2640
|
executingToolCallIds
|
|
2614
2641
|
}), [copilotkit, executingToolCallIds]);
|
|
2615
|
-
const licenseContextValue = (0, react.useMemo)(() => (0, _copilotkit_shared.createLicenseContextValue)(
|
|
2642
|
+
const licenseContextValue = (0, react.useMemo)(() => (0, _copilotkit_shared.createLicenseContextValue)(runtimeLicenseStatus), [runtimeLicenseStatus]);
|
|
2616
2643
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(SandboxFunctionsContext.Provider, {
|
|
2617
2644
|
value: sandboxFunctionsList,
|
|
2618
2645
|
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(CopilotKitContext.Provider, {
|
|
@@ -2620,8 +2647,8 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
|
|
|
2620
2647
|
children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(LicenseContext.Provider, {
|
|
2621
2648
|
value: licenseContextValue,
|
|
2622
2649
|
children: [
|
|
2623
|
-
|
|
2624
|
-
|
|
2650
|
+
a2uiActive && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(A2UIBuiltInToolCallRenderer, {}),
|
|
2651
|
+
a2uiActive && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(A2UICatalogContext, {
|
|
2625
2652
|
catalog: a2ui?.catalog,
|
|
2626
2653
|
includeSchema: a2ui?.includeSchema
|
|
2627
2654
|
}),
|
|
@@ -2838,7 +2865,7 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
|
|
|
2838
2865
|
if (isRuntimeConfigured && (status === _copilotkit_core.CopilotKitCoreRuntimeConnectionStatus.Disconnected || status === _copilotkit_core.CopilotKitCoreRuntimeConnectionStatus.Connecting)) {
|
|
2839
2866
|
const cached = provisionalAgentCache.current.get(agentId);
|
|
2840
2867
|
if (cached) {
|
|
2841
|
-
|
|
2868
|
+
copilotkit.applyHeadersToAgent(cached);
|
|
2842
2869
|
return cached;
|
|
2843
2870
|
}
|
|
2844
2871
|
const provisional = new _copilotkit_core.ProxiedCopilotRuntimeAgent({
|
|
@@ -2847,14 +2874,14 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
|
|
|
2847
2874
|
transport: copilotkit.runtimeTransport,
|
|
2848
2875
|
runtimeMode: "pending"
|
|
2849
2876
|
});
|
|
2850
|
-
|
|
2877
|
+
copilotkit.applyHeadersToAgent(provisional);
|
|
2851
2878
|
provisionalAgentCache.current.set(agentId, provisional);
|
|
2852
2879
|
return provisional;
|
|
2853
2880
|
}
|
|
2854
2881
|
if (isRuntimeConfigured && status === _copilotkit_core.CopilotKitCoreRuntimeConnectionStatus.Error) {
|
|
2855
2882
|
const cached = provisionalAgentCache.current.get(agentId);
|
|
2856
2883
|
if (cached) {
|
|
2857
|
-
|
|
2884
|
+
copilotkit.applyHeadersToAgent(cached);
|
|
2858
2885
|
return cached;
|
|
2859
2886
|
}
|
|
2860
2887
|
const provisional = new _copilotkit_core.ProxiedCopilotRuntimeAgent({
|
|
@@ -2863,7 +2890,7 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
|
|
|
2863
2890
|
transport: copilotkit.runtimeTransport,
|
|
2864
2891
|
runtimeMode: "pending"
|
|
2865
2892
|
});
|
|
2866
|
-
|
|
2893
|
+
copilotkit.applyHeadersToAgent(provisional);
|
|
2867
2894
|
provisionalAgentCache.current.set(agentId, provisional);
|
|
2868
2895
|
return provisional;
|
|
2869
2896
|
}
|
|
@@ -2914,7 +2941,7 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
|
|
|
2914
2941
|
updateFlags
|
|
2915
2942
|
]);
|
|
2916
2943
|
(0, react.useEffect)(() => {
|
|
2917
|
-
if (agent instanceof _ag_ui_client.HttpAgent)
|
|
2944
|
+
if (agent instanceof _ag_ui_client.HttpAgent) copilotkit.applyHeadersToAgent(agent);
|
|
2918
2945
|
}, [agent, JSON.stringify(copilotkit.headers)]);
|
|
2919
2946
|
const chatConfig = useCopilotChatConfiguration();
|
|
2920
2947
|
const configThreadId = chatConfig?.threadId;
|
|
@@ -3148,114 +3175,165 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
|
|
|
3148
3175
|
function isPromiseLike(value) {
|
|
3149
3176
|
return (typeof value === "object" || typeof value === "function") && value !== null && typeof Reflect.get(value, "then") === "function";
|
|
3150
3177
|
}
|
|
3178
|
+
/** Derive the legacy-compatible `event` for any pending interrupt. */
|
|
3179
|
+
function toLegacyEvent(pending) {
|
|
3180
|
+
if (pending.kind === "legacy") return pending.event;
|
|
3181
|
+
return {
|
|
3182
|
+
name: INTERRUPT_EVENT_NAME,
|
|
3183
|
+
value: pending.interrupts[0]
|
|
3184
|
+
};
|
|
3185
|
+
}
|
|
3151
3186
|
/**
|
|
3152
|
-
* Handles agent interrupts
|
|
3187
|
+
* Handles agent interrupts with optional filtering, preprocessing, and resume behavior.
|
|
3153
3188
|
*
|
|
3154
|
-
*
|
|
3155
|
-
*
|
|
3156
|
-
*
|
|
3189
|
+
* Supports both the AG-UI standard interrupt flow (`RUN_FINISHED` with
|
|
3190
|
+
* `outcome.type === "interrupt"`) and the legacy custom-event flow
|
|
3191
|
+
* (`on_interrupt`). For standard interrupts, `render` receives `interrupt`
|
|
3192
|
+
* (the primary one) and `interrupts` (the full open set); call `resolve(payload)`
|
|
3193
|
+
* to resume or `cancel()` to cancel. Resuming addresses the targeted interrupt
|
|
3194
|
+
* and, once every open interrupt is addressed, submits a single spec `resume`
|
|
3195
|
+
* array via `copilotkit.runAgent`.
|
|
3157
3196
|
*
|
|
3158
|
-
* - `renderInChat: true` (default): the element is published into `<CopilotChat
|
|
3159
|
-
* - `renderInChat: false`: the hook returns the interrupt element
|
|
3160
|
-
*
|
|
3161
|
-
* `event.value` is typed as `any` since the interrupt payload shape depends on your agent.
|
|
3162
|
-
* Type-narrow it in your callbacks (e.g. `handler`, `enabled`, `render`) as needed.
|
|
3163
|
-
*
|
|
3164
|
-
* @typeParam TResult - Inferred from `handler` return type. Exposed as `result` in `render`.
|
|
3165
|
-
* @param config - Interrupt configuration (renderer, optional handler/filter, and render mode).
|
|
3166
|
-
* @returns When `renderInChat` is `false`, returns the interrupt element (or `null` when idle).
|
|
3167
|
-
* Otherwise returns `void` and publishes the element into chat. In `render`, `result` is always
|
|
3168
|
-
* either the handler's resolved return value or `null` (including when no handler is provided,
|
|
3169
|
-
* when filtering skips the interrupt, or when handler execution fails).
|
|
3170
|
-
*
|
|
3171
|
-
* @example
|
|
3172
|
-
* ```tsx
|
|
3173
|
-
* import { useInterrupt } from "@copilotkit/react-core/v2";
|
|
3174
|
-
*
|
|
3175
|
-
* function InterruptUI() {
|
|
3176
|
-
* useInterrupt({
|
|
3177
|
-
* render: ({ event, resolve }) => (
|
|
3178
|
-
* <div>
|
|
3179
|
-
* <p>{event.value.question}</p>
|
|
3180
|
-
* <button onClick={() => resolve({ approved: true })}>Approve</button>
|
|
3181
|
-
* <button onClick={() => resolve({ approved: false })}>Reject</button>
|
|
3182
|
-
* </div>
|
|
3183
|
-
* ),
|
|
3184
|
-
* });
|
|
3185
|
-
*
|
|
3186
|
-
* return null;
|
|
3187
|
-
* }
|
|
3188
|
-
* ```
|
|
3197
|
+
* - `renderInChat: true` (default): the element is published into `<CopilotChat>`; returns `void`.
|
|
3198
|
+
* - `renderInChat: false`: the hook returns the interrupt element for manual placement.
|
|
3189
3199
|
*
|
|
3190
3200
|
* @example
|
|
3191
3201
|
* ```tsx
|
|
3192
|
-
*
|
|
3193
|
-
*
|
|
3194
|
-
*
|
|
3195
|
-
*
|
|
3196
|
-
*
|
|
3197
|
-
*
|
|
3198
|
-
*
|
|
3199
|
-
*
|
|
3200
|
-
*
|
|
3201
|
-
* <strong>{result?.label ?? ""}</strong>
|
|
3202
|
-
* <button onClick={() => resolve({ value: event.value })}>Continue</button>
|
|
3203
|
-
* </aside>
|
|
3204
|
-
* ),
|
|
3205
|
-
* });
|
|
3206
|
-
*
|
|
3207
|
-
* return <>{interruptElement}</>;
|
|
3208
|
-
* }
|
|
3202
|
+
* useInterrupt({
|
|
3203
|
+
* render: ({ interrupt, resolve, cancel }) => (
|
|
3204
|
+
* <div>
|
|
3205
|
+
* <p>{interrupt?.message}</p>
|
|
3206
|
+
* <button onClick={() => resolve({ approved: true })}>Approve</button>
|
|
3207
|
+
* <button onClick={() => cancel()}>Cancel</button>
|
|
3208
|
+
* </div>
|
|
3209
|
+
* ),
|
|
3210
|
+
* });
|
|
3209
3211
|
* ```
|
|
3210
3212
|
*/
|
|
3211
3213
|
function useInterrupt(config) {
|
|
3212
3214
|
const { copilotkit } = useCopilotKit();
|
|
3213
3215
|
const { agent } = useAgent({ agentId: config.agentId });
|
|
3214
|
-
const [
|
|
3215
|
-
const
|
|
3216
|
-
|
|
3216
|
+
const [pending, setPending] = (0, react.useState)(null);
|
|
3217
|
+
const pendingRef = (0, react.useRef)(pending);
|
|
3218
|
+
pendingRef.current = pending;
|
|
3217
3219
|
const [handlerResult, setHandlerResult] = (0, react.useState)(null);
|
|
3220
|
+
const responsesRef = (0, react.useRef)({});
|
|
3218
3221
|
(0, react.useEffect)(() => {
|
|
3219
|
-
let
|
|
3222
|
+
let localLegacy = null;
|
|
3223
|
+
let localStandard = null;
|
|
3220
3224
|
const subscription = agent.subscribe({
|
|
3221
3225
|
onCustomEvent: ({ event }) => {
|
|
3222
|
-
if (event.name === INTERRUPT_EVENT_NAME)
|
|
3226
|
+
if (event.name === INTERRUPT_EVENT_NAME) localLegacy = {
|
|
3223
3227
|
name: event.name,
|
|
3224
3228
|
value: event.value
|
|
3225
3229
|
};
|
|
3226
3230
|
},
|
|
3231
|
+
onRunFinishedEvent: (params) => {
|
|
3232
|
+
if (params.outcome === "interrupt") localStandard = params.interrupts;
|
|
3233
|
+
},
|
|
3227
3234
|
onRunStartedEvent: () => {
|
|
3228
|
-
|
|
3229
|
-
|
|
3235
|
+
localLegacy = null;
|
|
3236
|
+
localStandard = null;
|
|
3237
|
+
responsesRef.current = {};
|
|
3238
|
+
setPending(null);
|
|
3230
3239
|
},
|
|
3231
3240
|
onRunFinalized: () => {
|
|
3232
|
-
if (
|
|
3233
|
-
|
|
3234
|
-
|
|
3235
|
-
}
|
|
3241
|
+
if (localStandard && localStandard.length > 0) setPending({
|
|
3242
|
+
kind: "standard",
|
|
3243
|
+
interrupts: localStandard
|
|
3244
|
+
});
|
|
3245
|
+
else if (localLegacy) setPending({
|
|
3246
|
+
kind: "legacy",
|
|
3247
|
+
event: localLegacy
|
|
3248
|
+
});
|
|
3249
|
+
localLegacy = null;
|
|
3250
|
+
localStandard = null;
|
|
3236
3251
|
},
|
|
3237
3252
|
onRunFailed: () => {
|
|
3238
|
-
|
|
3239
|
-
|
|
3253
|
+
localLegacy = null;
|
|
3254
|
+
localStandard = null;
|
|
3255
|
+
responsesRef.current = {};
|
|
3256
|
+
setPending(null);
|
|
3240
3257
|
}
|
|
3241
3258
|
});
|
|
3242
3259
|
return () => subscription.unsubscribe();
|
|
3243
3260
|
}, [agent]);
|
|
3244
|
-
const
|
|
3261
|
+
const submitStandardIfComplete = (0, react.useCallback)(async (interrupts) => {
|
|
3262
|
+
if (!interrupts.every((i) => responsesRef.current[i.id])) return;
|
|
3263
|
+
const expired = interrupts.find((i) => (0, _ag_ui_client.isInterruptExpired)(i));
|
|
3264
|
+
if (expired) {
|
|
3265
|
+
console.error(`[CopilotKit] useInterrupt: interrupt ${expired.id} expired at ${expired.expiresAt}; not resuming.`);
|
|
3266
|
+
responsesRef.current = {};
|
|
3267
|
+
setPending(null);
|
|
3268
|
+
return;
|
|
3269
|
+
}
|
|
3270
|
+
const resume = (0, _ag_ui_client.buildResumeArray)(interrupts, responsesRef.current);
|
|
3271
|
+
for (const i of interrupts) {
|
|
3272
|
+
if (!i.toolCallId) continue;
|
|
3273
|
+
const response = responsesRef.current[i.id];
|
|
3274
|
+
const content = response.status === "cancelled" ? { status: "cancelled" } : response.payload ?? { status: "resolved" };
|
|
3275
|
+
agent.addMessage({
|
|
3276
|
+
id: (0, _ag_ui_client.randomUUID)(),
|
|
3277
|
+
role: "tool",
|
|
3278
|
+
toolCallId: i.toolCallId,
|
|
3279
|
+
content: JSON.stringify(content)
|
|
3280
|
+
});
|
|
3281
|
+
}
|
|
3282
|
+
responsesRef.current = {};
|
|
3245
3283
|
try {
|
|
3284
|
+
return await copilotkit.runAgent({
|
|
3285
|
+
agent,
|
|
3286
|
+
resume
|
|
3287
|
+
});
|
|
3288
|
+
} catch (err) {
|
|
3289
|
+
console.error("[CopilotKit] useInterrupt resolve: runAgent rejected; clearing pending + rethrowing", err);
|
|
3290
|
+
setPending(null);
|
|
3291
|
+
throw err;
|
|
3292
|
+
}
|
|
3293
|
+
}, [agent, copilotkit]);
|
|
3294
|
+
const resolve = (0, react.useCallback)(async (payload, interruptId) => {
|
|
3295
|
+
const current = pendingRef.current;
|
|
3296
|
+
if (!current) return;
|
|
3297
|
+
if (current.kind === "legacy") try {
|
|
3246
3298
|
return await copilotkit.runAgent({
|
|
3247
3299
|
agent,
|
|
3248
3300
|
forwardedProps: { command: {
|
|
3249
|
-
resume:
|
|
3250
|
-
interruptEvent:
|
|
3301
|
+
resume: payload,
|
|
3302
|
+
interruptEvent: current.event.value
|
|
3251
3303
|
} }
|
|
3252
3304
|
});
|
|
3253
3305
|
} catch (err) {
|
|
3254
3306
|
console.error("[CopilotKit] useInterrupt resolve: runAgent rejected; clearing pending + rethrowing", err);
|
|
3255
|
-
|
|
3307
|
+
setPending(null);
|
|
3256
3308
|
throw err;
|
|
3257
3309
|
}
|
|
3258
|
-
|
|
3310
|
+
if (current.interrupts.length > 1 && interruptId === void 0) console.warn(`[CopilotKit] useInterrupt: resolve()/cancel() called without an interruptId while ${current.interrupts.length} interrupts are open; defaulting to the first. Pass an interruptId to address a specific interrupt.`);
|
|
3311
|
+
const id = interruptId ?? current.interrupts[0]?.id;
|
|
3312
|
+
if (!id) return;
|
|
3313
|
+
responsesRef.current[id] = {
|
|
3314
|
+
status: "resolved",
|
|
3315
|
+
payload
|
|
3316
|
+
};
|
|
3317
|
+
return submitStandardIfComplete(current.interrupts);
|
|
3318
|
+
}, [
|
|
3319
|
+
agent,
|
|
3320
|
+
copilotkit,
|
|
3321
|
+
submitStandardIfComplete
|
|
3322
|
+
]);
|
|
3323
|
+
const cancel = (0, react.useCallback)(async (interruptId) => {
|
|
3324
|
+
const current = pendingRef.current;
|
|
3325
|
+
if (!current) return;
|
|
3326
|
+
if (current.kind === "legacy") {
|
|
3327
|
+
console.warn("[CopilotKit] useInterrupt: cancel() is not supported for legacy on_interrupt interrupts; dismissing.");
|
|
3328
|
+
setPending(null);
|
|
3329
|
+
return;
|
|
3330
|
+
}
|
|
3331
|
+
if (current.interrupts.length > 1 && interruptId === void 0) console.warn(`[CopilotKit] useInterrupt: resolve()/cancel() called without an interruptId while ${current.interrupts.length} interrupts are open; defaulting to the first. Pass an interruptId to address a specific interrupt.`);
|
|
3332
|
+
const id = interruptId ?? current.interrupts[0]?.id;
|
|
3333
|
+
if (!id) return;
|
|
3334
|
+
responsesRef.current[id] = { status: "cancelled" };
|
|
3335
|
+
return submitStandardIfComplete(current.interrupts);
|
|
3336
|
+
}, [submitStandardIfComplete]);
|
|
3259
3337
|
const renderRef = (0, react.useRef)(config.render);
|
|
3260
3338
|
renderRef.current = config.render;
|
|
3261
3339
|
const enabledRef = (0, react.useRef)(config.enabled);
|
|
@@ -3264,6 +3342,8 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
|
|
|
3264
3342
|
handlerRef.current = config.handler;
|
|
3265
3343
|
const resolveRef = (0, react.useRef)(resolve);
|
|
3266
3344
|
resolveRef.current = resolve;
|
|
3345
|
+
const cancelRef = (0, react.useRef)(cancel);
|
|
3346
|
+
cancelRef.current = cancel;
|
|
3267
3347
|
const isEnabled = (event) => {
|
|
3268
3348
|
const predicate = enabledRef.current;
|
|
3269
3349
|
if (!predicate) return true;
|
|
@@ -3275,11 +3355,12 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
|
|
|
3275
3355
|
}
|
|
3276
3356
|
};
|
|
3277
3357
|
(0, react.useEffect)(() => {
|
|
3278
|
-
if (!
|
|
3358
|
+
if (!pending) {
|
|
3279
3359
|
setHandlerResult(null);
|
|
3280
3360
|
return;
|
|
3281
3361
|
}
|
|
3282
|
-
|
|
3362
|
+
const legacyEvent = toLegacyEvent(pending);
|
|
3363
|
+
if (!isEnabled(legacyEvent)) {
|
|
3283
3364
|
setHandlerResult(null);
|
|
3284
3365
|
return;
|
|
3285
3366
|
}
|
|
@@ -3292,8 +3373,11 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
|
|
|
3292
3373
|
let maybePromise;
|
|
3293
3374
|
try {
|
|
3294
3375
|
maybePromise = handler({
|
|
3295
|
-
event:
|
|
3296
|
-
|
|
3376
|
+
event: legacyEvent,
|
|
3377
|
+
interrupt: pending.kind === "standard" ? pending.interrupts[0] : null,
|
|
3378
|
+
interrupts: pending.kind === "standard" ? pending.interrupts : [],
|
|
3379
|
+
resolve: resolveRef.current,
|
|
3380
|
+
cancel: cancelRef.current
|
|
3297
3381
|
});
|
|
3298
3382
|
} catch (err) {
|
|
3299
3383
|
console.error("[CopilotKit] useInterrupt handler threw; result will be null:", err);
|
|
@@ -3312,19 +3396,24 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
|
|
|
3312
3396
|
return () => {
|
|
3313
3397
|
cancelled = true;
|
|
3314
3398
|
};
|
|
3315
|
-
}, [
|
|
3399
|
+
}, [pending]);
|
|
3316
3400
|
const element = (0, react.useMemo)(() => {
|
|
3317
|
-
if (!
|
|
3318
|
-
|
|
3401
|
+
if (!pending) return null;
|
|
3402
|
+
const legacyEvent = toLegacyEvent(pending);
|
|
3403
|
+
if (!isEnabled(legacyEvent)) return null;
|
|
3319
3404
|
return renderRef.current({
|
|
3320
|
-
event:
|
|
3405
|
+
event: legacyEvent,
|
|
3406
|
+
interrupt: pending.kind === "standard" ? pending.interrupts[0] : null,
|
|
3407
|
+
interrupts: pending.kind === "standard" ? pending.interrupts : [],
|
|
3321
3408
|
result: handlerResult,
|
|
3322
|
-
resolve
|
|
3409
|
+
resolve,
|
|
3410
|
+
cancel
|
|
3323
3411
|
});
|
|
3324
3412
|
}, [
|
|
3325
|
-
|
|
3413
|
+
pending,
|
|
3326
3414
|
handlerResult,
|
|
3327
|
-
resolve
|
|
3415
|
+
resolve,
|
|
3416
|
+
cancel
|
|
3328
3417
|
]);
|
|
3329
3418
|
(0, react.useEffect)(() => {
|
|
3330
3419
|
if (config.renderInChat === false) return;
|
|
@@ -4982,6 +5071,7 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
|
|
|
4982
5071
|
const showInspector = shouldShowDevConsole(props.enableInspector);
|
|
4983
5072
|
const publicApiKey = props.publicApiKey || props.publicLicenseKey;
|
|
4984
5073
|
const renderArr = (0, react.useMemo)(() => [{ render: CoAgentStateRenderBridge }], []);
|
|
5074
|
+
const { onError: _onError, ...v2Props } = props;
|
|
4985
5075
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ToastProvider, {
|
|
4986
5076
|
enabled,
|
|
4987
5077
|
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(CopilotErrorBoundary, {
|
|
@@ -4990,7 +5080,7 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
|
|
|
4990
5080
|
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ThreadsProvider, {
|
|
4991
5081
|
threadId: props.threadId,
|
|
4992
5082
|
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(CopilotKitProvider, {
|
|
4993
|
-
...
|
|
5083
|
+
...v2Props,
|
|
4994
5084
|
showDevConsole: showInspector,
|
|
4995
5085
|
renderCustomMessages: renderArr,
|
|
4996
5086
|
useSingleEndpoint: props.useSingleEndpoint ?? true,
|