@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.
Files changed (42) hide show
  1. package/dist/{copilotkit-UY-H6Kx7.mjs → copilotkit-BtRkFsNR.mjs} +1227 -599
  2. package/dist/copilotkit-BtRkFsNR.mjs.map +1 -0
  3. package/dist/{copilotkit-BCJDP8qd.cjs → copilotkit-CdpDZi3i.cjs} +1219 -585
  4. package/dist/copilotkit-CdpDZi3i.cjs.map +1 -0
  5. package/dist/{copilotkit-CEdu_aie.d.cts → copilotkit-Cga6AHO0.d.cts} +497 -209
  6. package/dist/copilotkit-Cga6AHO0.d.cts.map +1 -0
  7. package/dist/{copilotkit-M1FiciGd.d.mts → copilotkit-DnLpJ2Cl.d.mts} +497 -209
  8. package/dist/copilotkit-DnLpJ2Cl.d.mts.map +1 -0
  9. package/dist/index.cjs +1 -1
  10. package/dist/index.cjs.map +1 -1
  11. package/dist/index.d.cts +1 -1
  12. package/dist/index.d.cts.map +1 -1
  13. package/dist/index.d.mts +1 -1
  14. package/dist/index.d.mts.map +1 -1
  15. package/dist/index.mjs +1 -1
  16. package/dist/index.mjs.map +1 -1
  17. package/dist/index.umd.js +360 -270
  18. package/dist/index.umd.js.map +1 -1
  19. package/dist/v2/context.d.cts +5 -1
  20. package/dist/v2/context.d.cts.map +1 -1
  21. package/dist/v2/context.d.mts +5 -1
  22. package/dist/v2/context.d.mts.map +1 -1
  23. package/dist/v2/headless.cjs +323 -104
  24. package/dist/v2/headless.cjs.map +1 -1
  25. package/dist/v2/headless.d.cts +187 -69
  26. package/dist/v2/headless.d.cts.map +1 -1
  27. package/dist/v2/headless.d.mts +187 -69
  28. package/dist/v2/headless.d.mts.map +1 -1
  29. package/dist/v2/headless.mjs +325 -106
  30. package/dist/v2/headless.mjs.map +1 -1
  31. package/dist/v2/index.cjs +2 -1
  32. package/dist/v2/index.css +1 -1
  33. package/dist/v2/index.d.cts +2 -2
  34. package/dist/v2/index.d.mts +2 -2
  35. package/dist/v2/index.mjs +2 -2
  36. package/dist/v2/index.umd.js +1112 -484
  37. package/dist/v2/index.umd.js.map +1 -1
  38. package/package.json +8 -6
  39. package/dist/copilotkit-BCJDP8qd.cjs.map +0 -1
  40. package/dist/copilotkit-CEdu_aie.d.cts.map +0 -1
  41. package/dist/copilotkit-M1FiciGd.d.mts.map +0 -1
  42. package/dist/copilotkit-UY-H6Kx7.mjs.map +0 -1
@@ -1,10 +1,10 @@
1
1
  "use client";
2
2
 
3
3
  (function(global, factory) {
4
- typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('./index.css'), require('@copilotkit/core'), require('@ag-ui/client'), require('react'), require('tailwind-merge'), require('lucide-react'), require('@copilotkit/shared'), require('react/jsx-runtime'), require('@radix-ui/react-slot'), require('class-variance-authority'), require('clsx'), require('@radix-ui/react-tooltip'), require('@radix-ui/react-dropdown-menu'), require('streamdown'), require('zod'), require('@lit-labs/react'), require('@copilotkit/a2ui-renderer'), require('zod-to-json-schema'), require('react-dom'), require('@tanstack/react-virtual'), require('use-stick-to-bottom')) :
5
- typeof define === 'function' && define.amd ? define(['exports', './index.css', '@copilotkit/core', '@ag-ui/client', 'react', 'tailwind-merge', 'lucide-react', '@copilotkit/shared', 'react/jsx-runtime', '@radix-ui/react-slot', 'class-variance-authority', 'clsx', '@radix-ui/react-tooltip', '@radix-ui/react-dropdown-menu', 'streamdown', 'zod', '@lit-labs/react', '@copilotkit/a2ui-renderer', 'zod-to-json-schema', 'react-dom', '@tanstack/react-virtual', 'use-stick-to-bottom'], factory) :
6
- (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory((global.CopilotKitReactCoreV2 = {}), global.src_v2_index_css,global.CopilotKitCore,global.AgUIClient,global.React,global.tailwindMerge,global.lucideReact,global.CopilotKitShared,global.ReactJsxRuntime,global.RadixReactSlot,global.classVarianceAuthority,global.clsx,global.RadixReactTooltip,global.RadixReactDropdownMenu,global.streamdown,global.Zod,global.LitLabsReact,global.CopilotKitA2UIRenderer,global.zod_to_json_schema,global.ReactDOM,global._tanstack_react_virtual,global.useStickToBottom));
7
- })(this, function(exports, src_v2_index_css, _copilotkit_core, _ag_ui_client, react, tailwind_merge, lucide_react, _copilotkit_shared, react_jsx_runtime, _radix_ui_react_slot, class_variance_authority, clsx, _radix_ui_react_tooltip, _radix_ui_react_dropdown_menu, streamdown, zod, _lit_labs_react, _copilotkit_a2ui_renderer, zod_to_json_schema, react_dom, _tanstack_react_virtual, use_stick_to_bottom) {
4
+ typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('./index.css'), require('@copilotkit/core'), require('@ag-ui/client'), require('react'), require('tailwind-merge'), require('lucide-react'), require('@copilotkit/shared'), require('react/jsx-runtime'), require('@radix-ui/react-slot'), require('class-variance-authority'), require('clsx'), require('@radix-ui/react-tooltip'), require('@radix-ui/react-dropdown-menu'), require('streamdown'), require('zod'), require('@lit-labs/react'), require('@copilotkit/a2ui-renderer'), require('zod-to-json-schema'), require('react-dom'), require('@tanstack/react-virtual'), require('use-stick-to-bottom'), require('@copilotkit/web-components/threads-drawer')) :
5
+ typeof define === 'function' && define.amd ? define(['exports', './index.css', '@copilotkit/core', '@ag-ui/client', 'react', 'tailwind-merge', 'lucide-react', '@copilotkit/shared', 'react/jsx-runtime', '@radix-ui/react-slot', 'class-variance-authority', 'clsx', '@radix-ui/react-tooltip', '@radix-ui/react-dropdown-menu', 'streamdown', 'zod', '@lit-labs/react', '@copilotkit/a2ui-renderer', 'zod-to-json-schema', 'react-dom', '@tanstack/react-virtual', 'use-stick-to-bottom', '@copilotkit/web-components/threads-drawer'], factory) :
6
+ (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory((global.CopilotKitReactCoreV2 = {}), global.src_v2_index_css,global.CopilotKitCore,global.AgUIClient,global.React,global.tailwindMerge,global.lucideReact,global.CopilotKitShared,global.ReactJsxRuntime,global.RadixReactSlot,global.classVarianceAuthority,global.clsx,global.RadixReactTooltip,global.RadixReactDropdownMenu,global.streamdown,global.Zod,global.LitLabsReact,global.CopilotKitA2UIRenderer,global.zod_to_json_schema,global.ReactDOM,global._tanstack_react_virtual,global.useStickToBottom,global._copilotkit_web_components_threads_drawer));
7
+ })(this, function(exports, src_v2_index_css, _copilotkit_core, _ag_ui_client, react, tailwind_merge, lucide_react, _copilotkit_shared, react_jsx_runtime, _radix_ui_react_slot, class_variance_authority, clsx, _radix_ui_react_tooltip, _radix_ui_react_dropdown_menu, streamdown, zod, _lit_labs_react, _copilotkit_a2ui_renderer, zod_to_json_schema, react_dom, _tanstack_react_virtual, use_stick_to_bottom, _copilotkit_web_components_threads_drawer) {
8
8
  Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
9
9
  //#region \0rolldown/runtime.js
10
10
  var __create = Object.create;
@@ -160,6 +160,25 @@ _radix_ui_react_dropdown_menu = __toESM(_radix_ui_react_dropdown_menu);
160
160
  modalHeaderTitle: "CopilotKit Chat",
161
161
  welcomeMessageText: "How can I help you today?"
162
162
  };
163
+ /**
164
+ * Mobile breakpoint below which the chat modal and the thread-list drawer are
165
+ * mutually exclusive. At or above this width both surfaces may coexist. This
166
+ * mirrors the `(max-width: 767px)` / `(min-width: 768px)` split already used by
167
+ * CopilotChatInput and CopilotSidebarView.
168
+ */
169
+ const MOBILE_MAX_WIDTH_PX = 767;
170
+ /**
171
+ * Reports whether the current viewport is in the mobile range (`<768px`), where
172
+ * the chat modal and drawer must not be open simultaneously. SSR-safe and
173
+ * defensive against environments without `matchMedia` (treated as desktop, so
174
+ * no mutual-exclusion constraint is applied).
175
+ *
176
+ * @returns `true` when the viewport is mobile-width, `false` otherwise.
177
+ */
178
+ function isMobileViewport() {
179
+ if (typeof window === "undefined" || typeof window.matchMedia !== "function") return false;
180
+ return window.matchMedia(`(max-width: ${MOBILE_MAX_WIDTH_PX}px)`).matches;
181
+ }
163
182
  const CopilotChatConfiguration = (0, react.createContext)(null);
164
183
  const CopilotChatConfigurationProvider = ({ children, labels, agentId, threadId, hasExplicitThreadId, isModalDefaultOpen }) => {
165
184
  const parentConfig = (0, react.useContext)(CopilotChatConfiguration);
@@ -170,12 +189,22 @@ _radix_ui_react_dropdown_menu = __toESM(_radix_ui_react_dropdown_menu);
170
189
  ...stableLabels
171
190
  }), [stableLabels, parentConfig?.labels]);
172
191
  const resolvedAgentId = agentId ?? parentConfig?.agentId ?? _copilotkit_shared.DEFAULT_AGENT_ID;
192
+ const threadIdPropIsAuthoritative = threadId !== void 0 && hasExplicitThreadId !== false;
193
+ const isThreadIdControlled = threadIdPropIsAuthoritative;
194
+ const [activeThreadOverride, setActiveThreadOverride] = (0, react.useState)(null);
173
195
  const resolvedThreadId = (0, react.useMemo)(() => {
174
- if (threadId) return threadId;
196
+ if (threadIdPropIsAuthoritative) return threadId;
197
+ if (activeThreadOverride) return activeThreadOverride.threadId;
175
198
  if (parentConfig?.threadId) return parentConfig.threadId;
199
+ if (threadId) return threadId;
176
200
  return (0, _copilotkit_shared.randomUUID)();
177
- }, [threadId, parentConfig?.threadId]);
178
- const resolvedHasExplicitThreadId = (hasExplicitThreadId !== void 0 ? hasExplicitThreadId : !!threadId) || !!parentConfig?.hasExplicitThreadId;
201
+ }, [
202
+ threadIdPropIsAuthoritative,
203
+ threadId,
204
+ parentConfig?.threadId,
205
+ activeThreadOverride
206
+ ]);
207
+ const resolvedHasExplicitThreadId = (threadIdPropIsAuthoritative ? true : activeThreadOverride?.explicit ?? hasExplicitThreadId ?? false) || !!parentConfig?.hasExplicitThreadId;
179
208
  const [internalModalOpen, setInternalModalOpen] = (0, react.useState)(isModalDefaultOpen ?? true);
180
209
  const hasExplicitDefault = isModalDefaultOpen !== void 0;
181
210
  const setAndSync = (0, react.useCallback)((open) => {
@@ -194,20 +223,113 @@ _radix_ui_react_dropdown_menu = __toESM(_radix_ui_react_dropdown_menu);
194
223
  }, [parentConfig?.isModalOpen, hasExplicitDefault]);
195
224
  const resolvedIsModalOpen = hasExplicitDefault ? internalModalOpen : parentConfig?.isModalOpen ?? internalModalOpen;
196
225
  const resolvedSetModalOpen = hasExplicitDefault ? setAndSync : parentConfig?.setModalOpen ?? setInternalModalOpen;
226
+ const [ownDrawerOpen, setOwnDrawerOpen] = (0, react.useState)(false);
227
+ const [ownDrawerCount, setOwnDrawerCount] = (0, react.useState)(0);
228
+ const modalCloseRef = (0, react.useRef)(() => {});
229
+ modalCloseRef.current = resolvedSetModalOpen;
230
+ const registeredModalClosersRef = (0, react.useRef)([]);
231
+ const ownRegisterModalCloser = (0, react.useCallback)((closeModal) => {
232
+ registeredModalClosersRef.current.push(closeModal);
233
+ return () => {
234
+ registeredModalClosersRef.current = registeredModalClosersRef.current.filter((entry) => entry !== closeModal);
235
+ };
236
+ }, []);
237
+ const ownSetDrawerOpen = (0, react.useCallback)((open) => {
238
+ setOwnDrawerOpen(open);
239
+ if (open && isMobileViewport()) {
240
+ const registered = registeredModalClosersRef.current;
241
+ (registered.length > 0 ? registered[registered.length - 1] : modalCloseRef.current)(false);
242
+ }
243
+ }, []);
244
+ const ownRegisterDrawer = (0, react.useCallback)(() => {
245
+ setOwnDrawerCount((count) => count + 1);
246
+ return () => {
247
+ setOwnDrawerCount((count) => Math.max(0, count - 1));
248
+ };
249
+ }, []);
250
+ const resolvedDrawerOpen = parentConfig ? parentConfig.drawerOpen : ownDrawerOpen;
251
+ const resolvedSetDrawerOpen = parentConfig ? parentConfig.setDrawerOpen : ownSetDrawerOpen;
252
+ const resolvedDrawerRegistered = parentConfig ? parentConfig.drawerRegistered : ownDrawerCount > 0;
253
+ const resolvedRegisterDrawer = parentConfig ? parentConfig.registerDrawer : ownRegisterDrawer;
254
+ const resolvedRegisterModalCloser = parentConfig ? parentConfig.ɵregisterModalCloser : ownRegisterModalCloser;
255
+ (0, react.useEffect)(() => {
256
+ if (!hasExplicitDefault) return;
257
+ return resolvedRegisterModalCloser(resolvedSetModalOpen);
258
+ }, [
259
+ hasExplicitDefault,
260
+ resolvedRegisterModalCloser,
261
+ resolvedSetModalOpen
262
+ ]);
263
+ const isThreadIdControlledRef = (0, react.useRef)(isThreadIdControlled);
264
+ isThreadIdControlledRef.current = isThreadIdControlled;
265
+ const ownSetActiveThreadId = (0, react.useCallback)((id, options) => {
266
+ setActiveThreadOverride({
267
+ threadId: id,
268
+ explicit: options?.explicit ?? true
269
+ });
270
+ }, []);
271
+ const ownStartNewThread = (0, react.useCallback)(() => {
272
+ setActiveThreadOverride({
273
+ threadId: (0, _copilotkit_shared.randomUUID)(),
274
+ explicit: false
275
+ });
276
+ }, []);
277
+ const parentSetActiveThreadId = parentConfig?.setActiveThreadId;
278
+ const parentStartNewThread = parentConfig?.startNewThread;
279
+ const resolvedSetActiveThreadId = (0, react.useCallback)((id, options) => {
280
+ if (isThreadIdControlledRef.current) {
281
+ console.warn("[CopilotKit] Ignoring setActiveThreadId(): threadId is controlled via the `threadId` prop on CopilotChatConfigurationProvider.");
282
+ return;
283
+ }
284
+ if (parentSetActiveThreadId) {
285
+ parentSetActiveThreadId(id, options);
286
+ return;
287
+ }
288
+ ownSetActiveThreadId(id, options);
289
+ }, [parentSetActiveThreadId, ownSetActiveThreadId]);
290
+ const resolvedStartNewThread = (0, react.useCallback)(() => {
291
+ if (isThreadIdControlledRef.current) {
292
+ console.warn("[CopilotKit] Ignoring startNewThread(): threadId is controlled via the `threadId` prop on CopilotChatConfigurationProvider.");
293
+ return;
294
+ }
295
+ if (parentStartNewThread) {
296
+ parentStartNewThread();
297
+ return;
298
+ }
299
+ ownStartNewThread();
300
+ }, [parentStartNewThread, ownStartNewThread]);
301
+ const setModalOpenWithDrawerExclusion = (0, react.useCallback)((open) => {
302
+ if (open && isMobileViewport()) resolvedSetDrawerOpen(false);
303
+ resolvedSetModalOpen(open);
304
+ }, [resolvedSetModalOpen, resolvedSetDrawerOpen]);
197
305
  const configurationValue = (0, react.useMemo)(() => ({
198
306
  labels: mergedLabels,
199
307
  agentId: resolvedAgentId,
200
308
  threadId: resolvedThreadId,
201
309
  hasExplicitThreadId: resolvedHasExplicitThreadId,
202
310
  isModalOpen: resolvedIsModalOpen,
203
- setModalOpen: resolvedSetModalOpen
311
+ setModalOpen: setModalOpenWithDrawerExclusion,
312
+ drawerOpen: resolvedDrawerOpen,
313
+ setDrawerOpen: resolvedSetDrawerOpen,
314
+ drawerRegistered: resolvedDrawerRegistered,
315
+ registerDrawer: resolvedRegisterDrawer,
316
+ ɵregisterModalCloser: resolvedRegisterModalCloser,
317
+ setActiveThreadId: resolvedSetActiveThreadId,
318
+ startNewThread: resolvedStartNewThread
204
319
  }), [
205
320
  mergedLabels,
206
321
  resolvedAgentId,
207
322
  resolvedThreadId,
208
323
  resolvedHasExplicitThreadId,
209
324
  resolvedIsModalOpen,
210
- resolvedSetModalOpen
325
+ setModalOpenWithDrawerExclusion,
326
+ resolvedDrawerOpen,
327
+ resolvedSetDrawerOpen,
328
+ resolvedDrawerRegistered,
329
+ resolvedRegisterDrawer,
330
+ resolvedRegisterModalCloser,
331
+ resolvedSetActiveThreadId,
332
+ resolvedStartNewThread
211
333
  ]);
212
334
  return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(CopilotChatConfiguration.Provider, {
213
335
  value: configurationValue,
@@ -1128,7 +1250,7 @@ _radix_ui_react_dropdown_menu = __toESM(_radix_ui_react_dropdown_menu);
1128
1250
  },
1129
1251
  ...props,
1130
1252
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1131
- className: "cpk:max-w-3xl cpk:mx-auto cpk:py-0 cpk:px-4 cpk:sm:px-0 cpk:[div[data-sidebar-chat]_&]:px-8 cpk:[div[data-popup-chat]_&]:px-4 cpk:pointer-events-auto",
1253
+ className: "cpk:max-w-3xl cpk:mx-auto cpk:py-0 cpk:px-4 cpk:@3xl:px-0 cpk:[div[data-sidebar-chat]_&]:px-8 cpk:[div[data-popup-chat]_&]:px-4 cpk:pointer-events-auto",
1132
1254
  children: inputPill
1133
1255
  }), shouldShowDisclaimer && BoundDisclaimer]
1134
1256
  });
@@ -1396,317 +1518,45 @@ _radix_ui_react_dropdown_menu = __toESM(_radix_ui_react_dropdown_menu);
1396
1518
  * useAgentContext hook registers context via useLayoutEffect, which runs
1397
1519
  * synchronously after React commits that batch.
1398
1520
  *
1399
- * Awaiting a zero-delay timeout yields to the macrotask queue. React's
1400
- * MessageChannel task runs first, committing the pending state and running
1401
- * useLayoutEffect (which updates the context store). The follow-up runAgent
1402
- * call then reads fresh context.
1403
- */
1404
- async waitForPendingFrameworkUpdates() {
1405
- await new Promise((resolve) => setTimeout(resolve, 0));
1406
- }
1407
- };
1408
-
1409
- //#endregion
1410
- //#region src/v2/context.ts
1411
- const CopilotKitContext = (0, react.createContext)(null);
1412
- const useCopilotKit = () => {
1413
- const context = (0, react.useContext)(CopilotKitContext);
1414
- const [, forceUpdate] = (0, react.useReducer)((x) => x + 1, 0);
1415
- if (!context) throw new Error("useCopilotKit must be used within CopilotKitProvider");
1416
- (0, react.useEffect)(() => {
1417
- const subscription = context.copilotkit.subscribe({
1418
- onRuntimeConnectionStatusChanged: () => {
1419
- forceUpdate();
1420
- },
1421
- onHeadersChanged: () => {
1422
- forceUpdate();
1423
- }
1424
- });
1425
- return () => {
1426
- subscription.unsubscribe();
1427
- };
1428
- }, []);
1429
- return context;
1430
- };
1431
- const LicenseContext = (0, react.createContext)({
1432
- status: null,
1433
- license: null,
1434
- checkFeature: () => true,
1435
- getLimit: () => null
1436
- });
1437
- const useLicenseContext = () => (0, react.useContext)(LicenseContext);
1438
-
1439
- //#endregion
1440
- //#region src/v2/types/defineToolCallRenderer.ts
1441
- function defineToolCallRenderer(def) {
1442
- const argsSchema = def.name === "*" && !def.args ? zod.z.any() : def.args;
1443
- return {
1444
- name: def.name,
1445
- args: argsSchema,
1446
- render: def.render,
1447
- ...def.agentId ? { agentId: def.agentId } : {}
1448
- };
1449
- }
1450
-
1451
- //#endregion
1452
- //#region src/v2/hooks/use-render-tool.tsx
1453
- const EMPTY_DEPS$1 = [];
1454
- /**
1455
- * Registers a renderer entry in CopilotKit's `renderToolCalls` registry.
1456
- *
1457
- * Key behavior:
1458
- * - deduplicates by `agentId:name` (latest registration wins),
1459
- * - keeps renderer entries on cleanup so historical chat tool calls can still render,
1460
- * - refreshes registration when `deps` change.
1461
- *
1462
- * @typeParam S - Schema type describing tool call parameters.
1463
- * @param config - Renderer config for wildcard or named tools.
1464
- * @param deps - Optional dependencies to refresh registration.
1465
- *
1466
- * @example
1467
- * ```tsx
1468
- * useRenderTool(
1469
- * {
1470
- * name: "searchDocs",
1471
- * parameters: z.object({ query: z.string() }),
1472
- * render: ({ status, parameters, result }) => {
1473
- * if (status === "executing") return <div>Searching {parameters.query}</div>;
1474
- * if (status === "complete") return <div>{result}</div>;
1475
- * return <div>Preparing...</div>;
1476
- * },
1477
- * },
1478
- * [],
1479
- * );
1480
- * ```
1481
- *
1482
- * @example
1483
- * ```tsx
1484
- * useRenderTool(
1485
- * {
1486
- * name: "summarize",
1487
- * parameters: z.object({ text: z.string() }),
1488
- * agentId: "research-agent",
1489
- * render: ({ name, status }) => <div>{name}: {status}</div>,
1490
- * },
1491
- * [selectedAgentId],
1492
- * );
1493
- * ```
1494
- */
1495
- function useRenderTool(config, deps) {
1496
- const { copilotkit } = useCopilotKit();
1497
- const extraDeps = deps ?? EMPTY_DEPS$1;
1498
- (0, react.useEffect)(() => {
1499
- const renderer = config.name === "*" && !config.parameters ? defineToolCallRenderer({
1500
- name: "*",
1501
- render: (props) => config.render({
1502
- ...props,
1503
- parameters: props.args
1504
- }),
1505
- ...config.agentId ? { agentId: config.agentId } : {}
1506
- }) : defineToolCallRenderer({
1507
- name: config.name,
1508
- args: config.parameters,
1509
- render: (props) => config.render({
1510
- ...props,
1511
- parameters: props.args
1512
- }),
1513
- ...config.agentId ? { agentId: config.agentId } : {}
1514
- });
1515
- copilotkit.addHookRenderToolCall(renderer);
1516
- }, [
1517
- config.name,
1518
- copilotkit,
1519
- JSON.stringify(extraDeps)
1520
- ]);
1521
- }
1522
-
1523
- //#endregion
1524
- //#region src/v2/hooks/use-default-render-tool.tsx
1525
- /**
1526
- * Module-level dedup set so an unknown status value only emits a console
1527
- * warning the FIRST time we encounter it. Otherwise a stuck/unmapped status
1528
- * would log on every re-render (potentially many per second).
1529
- */
1530
- const warnedUnknownStatuses = /* @__PURE__ */ new Set();
1531
- /**
1532
- * Map a {@link ToolCallStatus} enum value to the documented string-union
1533
- * status the {@link DefaultRenderProps} contract exposes. Unknown / future
1534
- * enum members log a warning (once per distinct value) and fall back to
1535
- * `"inProgress"`.
1536
- */
1537
- function mapToolCallStatus(status) {
1538
- switch (status) {
1539
- case _copilotkit_core.ToolCallStatus.Complete: return "complete";
1540
- case _copilotkit_core.ToolCallStatus.Executing: return "executing";
1541
- case _copilotkit_core.ToolCallStatus.InProgress: return "inProgress";
1542
- default: {
1543
- const key = String(status);
1544
- if (!warnedUnknownStatuses.has(key)) {
1545
- warnedUnknownStatuses.add(key);
1546
- console.warn(`[CopilotKit] Unknown ToolCallStatus "${key}" in default tool-call renderer; falling back to "inProgress".`);
1547
- }
1548
- return "inProgress";
1549
- }
1550
- }
1551
- }
1552
- /**
1553
- * Convert the framework-internal renderer props (`args`, enum status) into
1554
- * the documented {@link DefaultRenderProps} shape (`parameters`, string-union
1555
- * status) so a user `config.render` always sees the documented contract.
1556
- */
1557
- function adaptRendererProps(props) {
1558
- return {
1559
- name: props.name,
1560
- toolCallId: props.toolCallId,
1561
- parameters: props.args,
1562
- status: mapToolCallStatus(props.status),
1563
- result: props.result
1564
- };
1565
- }
1566
- /**
1567
- * Registers a wildcard (`"*"`) tool-call renderer via `useRenderTool`.
1568
- *
1569
- * - Call with no config to use CopilotKit's built-in default tool-call card.
1570
- * - Pass `config.render` to replace the default UI with your own fallback renderer.
1571
- *
1572
- * This is useful when you want a generic renderer for tools that do not have a
1573
- * dedicated `useRenderTool({ name: "..." })` registration.
1574
- *
1575
- * @param config - Optional custom wildcard render function.
1576
- * @param deps - Optional dependencies to refresh registration.
1577
- *
1578
- * @example
1579
- * ```tsx
1580
- * useDefaultRenderTool();
1581
- * ```
1582
- *
1583
- * @example
1584
- * ```tsx
1585
- * useDefaultRenderTool({
1586
- * render: ({ name, status }) => <div>{name}: {status}</div>,
1587
- * });
1588
- * ```
1589
- *
1590
- * @example
1591
- * ```tsx
1592
- * useDefaultRenderTool(
1593
- * {
1594
- * render: ({ name, result }) => (
1595
- * <ToolEventRow title={name} payload={result} compact={compactMode} />
1596
- * ),
1597
- * },
1598
- * [compactMode],
1599
- * );
1600
- * ```
1601
- */
1602
- function useDefaultRenderTool(config, deps) {
1603
- const userRender = config?.render;
1604
- useRenderTool({
1605
- name: "*",
1606
- render: userRender ? (raw) => userRender(adaptRendererProps(raw)) : (raw) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(DefaultToolCallRenderer, { ...adaptRendererProps(raw) })
1607
- }, deps);
1608
- }
1609
- /**
1610
- * Guarded JSON.stringify used inside the expanded `<pre>` blocks. A circular
1611
- * reference would otherwise crash the entire React tree on render.
1612
- */
1613
- function safeStringifyForPre(value) {
1614
- try {
1615
- return JSON.stringify(value, null, 2);
1616
- } catch (err) {
1617
- console.warn("[CopilotKit] Failed to JSON.stringify tool-call payload for default renderer; falling back to String():", err);
1618
- try {
1619
- return String(value);
1620
- } catch (innerErr) {
1621
- console.warn("[CopilotKit] safeStringifyForPre: value could not be stringified:", innerErr);
1622
- return "[unserializable]";
1623
- }
1624
- }
1625
- }
1626
- function DefaultToolCallRenderer({ name, toolCallId, parameters, status, result }) {
1627
- const [isExpanded, setIsExpanded] = (0, react.useState)(false);
1628
- const isActive = status === "inProgress" || status === "executing";
1629
- const isComplete = status === "complete";
1630
- const statusLabel = isActive ? "Running" : isComplete ? "Done" : status;
1631
- const dotClassName = isActive ? "cpk:bg-amber-500" : isComplete ? "cpk:bg-emerald-500" : "cpk:bg-zinc-400";
1632
- 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";
1633
- return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1634
- "data-testid": "copilot-tool-render",
1635
- "data-tool-name": name,
1636
- "data-tool-call-id": toolCallId,
1637
- "data-status": status,
1638
- "data-args": safeStringifyForAttr(parameters),
1639
- "data-result": safeStringifyForAttr(result),
1640
- className: "cpk:mt-2 cpk:pb-2",
1641
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1642
- 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",
1643
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
1644
- type: "button",
1645
- "aria-expanded": isExpanded,
1646
- onClick: () => setIsExpanded(!isExpanded),
1647
- 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",
1648
- style: { font: "inherit" },
1649
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1650
- className: "cpk:flex cpk:min-w-0 cpk:items-center cpk:gap-2",
1651
- children: [
1652
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("svg", {
1653
- 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" : ""}`,
1654
- fill: "none",
1655
- viewBox: "0 0 24 24",
1656
- strokeWidth: 2,
1657
- stroke: "currentColor",
1658
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", {
1659
- strokeLinecap: "round",
1660
- strokeLinejoin: "round",
1661
- d: "M8.25 4.5l7.5 7.5-7.5 7.5"
1662
- })
1663
- }),
1664
- /* @__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}` }),
1665
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1666
- "data-testid": "copilot-tool-render-name",
1667
- className: "cpk:truncate cpk:text-[13px] cpk:font-semibold cpk:text-zinc-900 cpk:dark:text-zinc-100",
1668
- children: name
1669
- })
1670
- ]
1671
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1672
- "data-testid": "copilot-tool-render-status",
1673
- 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}`,
1674
- children: statusLabel
1675
- })]
1676
- }), isExpanded && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1677
- className: "cpk:mt-3 cpk:grid cpk:gap-3",
1678
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1679
- className: "cpk:text-[10px] cpk:uppercase cpk:text-zinc-500 cpk:dark:text-zinc-400",
1680
- children: "Arguments"
1681
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("pre", {
1682
- 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",
1683
- children: safeStringifyForPre(parameters ?? {})
1684
- })] }), result !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1685
- className: "cpk:text-[10px] cpk:uppercase cpk:text-zinc-500 cpk:dark:text-zinc-400",
1686
- children: "Result"
1687
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("pre", {
1688
- 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",
1689
- children: typeof result === "string" ? result : safeStringifyForPre(result)
1690
- })] })]
1691
- })]
1692
- })
1693
- });
1694
- }
1695
- function safeStringifyForAttr(value) {
1696
- if (value === void 0 || value === null) return "";
1697
- if (typeof value === "string") return value;
1698
- try {
1699
- return JSON.stringify(value);
1700
- } catch (err) {
1701
- console.warn("[CopilotKit] Failed to JSON.stringify tool-call payload for data-* attribute; falling back to String():", err);
1702
- try {
1703
- return String(value);
1704
- } catch (innerErr) {
1705
- console.warn("[CopilotKit] safeStringifyForAttr: value could not be stringified:", innerErr);
1706
- return "";
1707
- }
1521
+ * Awaiting a zero-delay timeout yields to the macrotask queue. React's
1522
+ * MessageChannel task runs first, committing the pending state and running
1523
+ * useLayoutEffect (which updates the context store). The follow-up runAgent
1524
+ * call then reads fresh context.
1525
+ */
1526
+ async waitForPendingFrameworkUpdates() {
1527
+ await new Promise((resolve) => setTimeout(resolve, 0));
1708
1528
  }
1709
- }
1529
+ };
1530
+
1531
+ //#endregion
1532
+ //#region src/v2/context.ts
1533
+ const CopilotKitContext = (0, react.createContext)(null);
1534
+ const useCopilotKit = () => {
1535
+ const context = (0, react.useContext)(CopilotKitContext);
1536
+ const [, forceUpdate] = (0, react.useReducer)((x) => x + 1, 0);
1537
+ if (!context) throw new Error("useCopilotKit must be used within CopilotKitProvider");
1538
+ (0, react.useEffect)(() => {
1539
+ const subscription = context.copilotkit.subscribe({
1540
+ onRuntimeConnectionStatusChanged: () => {
1541
+ forceUpdate();
1542
+ },
1543
+ onHeadersChanged: () => {
1544
+ forceUpdate();
1545
+ }
1546
+ });
1547
+ return () => {
1548
+ subscription.unsubscribe();
1549
+ };
1550
+ }, []);
1551
+ return context;
1552
+ };
1553
+ const LicenseContext = (0, react.createContext)({
1554
+ status: null,
1555
+ license: null,
1556
+ checkFeature: () => true,
1557
+ getLimit: () => null
1558
+ });
1559
+ const useLicenseContext = () => (0, react.useContext)(LicenseContext);
1710
1560
 
1711
1561
  //#endregion
1712
1562
  //#region src/v2/hooks/use-render-tool-call.tsx
@@ -1762,10 +1612,13 @@ _radix_ui_react_dropdown_menu = __toESM(_radix_ui_react_dropdown_menu);
1762
1612
  }, () => copilotkit.renderToolCalls, () => copilotkit.renderToolCalls);
1763
1613
  return (0, react.useCallback)(({ toolCall, toolMessage }) => {
1764
1614
  const exactMatches = renderToolCalls.filter((rc) => rc.name === toolCall.function.name);
1615
+ const renderConfig = exactMatches.find((rc) => rc.agentId === agentId) || exactMatches.find((rc) => !rc.agentId) || exactMatches[0] || renderToolCalls.find((rc) => rc.name === "*");
1616
+ if (!renderConfig) return null;
1617
+ const RenderComponent = renderConfig.render;
1765
1618
  return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ToolCallRenderer, {
1766
1619
  toolCall,
1767
1620
  toolMessage,
1768
- RenderComponent: (exactMatches.find((rc) => rc.agentId === agentId) || exactMatches.find((rc) => !rc.agentId) || exactMatches[0] || renderToolCalls.find((rc) => rc.name === "*"))?.render ?? defaultToolCallRenderAdapter,
1621
+ RenderComponent,
1769
1622
  isExecuting: executingToolCallIds.has(toolCall.id)
1770
1623
  }, toolCall.id);
1771
1624
  }, [
@@ -1774,15 +1627,6 @@ _radix_ui_react_dropdown_menu = __toESM(_radix_ui_react_dropdown_menu);
1774
1627
  agentId
1775
1628
  ]);
1776
1629
  }
1777
- function defaultToolCallRenderAdapter(props) {
1778
- return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(DefaultToolCallRenderer, {
1779
- name: props.name,
1780
- toolCallId: props.toolCallId,
1781
- parameters: props.args,
1782
- status: mapToolCallStatus(props.status),
1783
- result: props.result
1784
- });
1785
- }
1786
1630
 
1787
1631
  //#endregion
1788
1632
  //#region src/v2/components/CopilotKitInspector.tsx
@@ -3264,7 +3108,7 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
3264
3108
  ...A2UILifecycleFields
3265
3109
  }).passthrough();
3266
3110
  function createA2UIMessageRenderer(options) {
3267
- const { theme, catalog, loadingComponent, recovery } = options;
3111
+ const { theme, catalog, loadingComponent, recovery, onAction } = options;
3268
3112
  const showAfterMs = recovery?.showAfterMs ?? 2e3;
3269
3113
  const showAfterAttempts = recovery?.showAfterAttempts ?? 2;
3270
3114
  const optionDebugExposure = recovery?.debugExposure ?? "collapsed";
@@ -3340,6 +3184,7 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
3340
3184
  agent,
3341
3185
  copilotkit,
3342
3186
  catalog,
3187
+ onAction,
3343
3188
  onReady: markSurfaceReady
3344
3189
  }, surfaceId))
3345
3190
  });
@@ -3360,29 +3205,60 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
3360
3205
  };
3361
3206
  }
3362
3207
  /**
3208
+ * Orchestrates a single A2UI user action: runs the optional `onAction`
3209
+ * interceptor first, then forwards to the agent unless the interceptor
3210
+ * suppressed it (returned `null`). Exported for unit testing; the wiring lives
3211
+ * in {@link ReactSurfaceHost}.
3212
+ */
3213
+ async function runA2UIAction({ message, agent, copilotkit, onAction }) {
3214
+ if (!agent) return;
3215
+ const action = message.userAction;
3216
+ const forward = async (forwardAction) => {
3217
+ const a2uiAction = forwardAction !== void 0 ? {
3218
+ ...message,
3219
+ userAction: forwardAction
3220
+ } : message;
3221
+ try {
3222
+ copilotkit.setProperties({
3223
+ ...copilotkit.properties,
3224
+ a2uiAction
3225
+ });
3226
+ await copilotkit.runAgent({ agent });
3227
+ } finally {
3228
+ if (copilotkit.properties) {
3229
+ const { a2uiAction: _omit, ...rest } = copilotkit.properties;
3230
+ copilotkit.setProperties(rest);
3231
+ }
3232
+ }
3233
+ };
3234
+ if (onAction && action) {
3235
+ const result = await onAction(action, forward);
3236
+ if (result === null) return;
3237
+ if (result) {
3238
+ await forward(result);
3239
+ return;
3240
+ }
3241
+ }
3242
+ await forward();
3243
+ }
3244
+ /**
3363
3245
  * Renders a single A2UI surface using the React renderer.
3364
3246
  * Wraps A2UIProvider + A2UIRenderer and bridges actions back to CopilotKit.
3365
3247
  */
3366
- function ReactSurfaceHost({ surfaceId, operations, theme, agent, copilotkit, catalog, onReady }) {
3248
+ function ReactSurfaceHost({ surfaceId, operations, theme, agent, copilotkit, catalog, onAction, onReady }) {
3367
3249
  return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
3368
3250
  className: "cpk:flex cpk:w-full cpk:flex-none cpk:flex-col cpk:gap-4",
3369
3251
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_copilotkit_a2ui_renderer.A2UIProvider, {
3370
- onAction: (0, react.useCallback)(async (message) => {
3371
- if (!agent) return;
3372
- message.userAction;
3373
- try {
3374
- copilotkit.setProperties({
3375
- ...copilotkit.properties,
3376
- a2uiAction: message
3377
- });
3378
- await copilotkit.runAgent({ agent });
3379
- } finally {
3380
- if (copilotkit.properties) {
3381
- const { a2uiAction, ...rest } = copilotkit.properties;
3382
- copilotkit.setProperties(rest);
3383
- }
3384
- }
3385
- }, [agent, copilotkit]),
3252
+ onAction: (0, react.useCallback)((message) => runA2UIAction({
3253
+ message,
3254
+ agent,
3255
+ copilotkit,
3256
+ onAction
3257
+ }), [
3258
+ agent,
3259
+ copilotkit,
3260
+ onAction
3261
+ ]),
3386
3262
  theme,
3387
3263
  catalog,
3388
3264
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(SurfaceMessageProcessor, {
@@ -3453,6 +3329,18 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
3453
3329
  return operation?.createSurface?.surfaceId ?? operation?.updateComponents?.surfaceId ?? operation?.updateDataModel?.surfaceId ?? operation?.deleteSurface?.surfaceId ?? null;
3454
3330
  }
3455
3331
 
3332
+ //#endregion
3333
+ //#region src/v2/types/defineToolCallRenderer.ts
3334
+ function defineToolCallRenderer(def) {
3335
+ const argsSchema = def.name === "*" && !def.args ? zod.z.any() : def.args;
3336
+ return {
3337
+ name: def.name,
3338
+ args: argsSchema,
3339
+ render: def.render,
3340
+ ...def.agentId ? { agentId: def.agentId } : {}
3341
+ };
3342
+ }
3343
+
3456
3344
  //#endregion
3457
3345
  //#region src/v2/a2ui/A2UIToolCallRenderer.tsx
3458
3346
  /**
@@ -3547,6 +3435,10 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
3547
3435
 
3548
3436
  //#endregion
3549
3437
  //#region src/v2/providers/CopilotKitProvider.tsx
3438
+ const zodToJsonSchemaAdapter = (schema, options) => {
3439
+ const refStrategy = options?.$refStrategy;
3440
+ return (0, zod_to_json_schema.zodToJsonSchema)(schema, refStrategy === "root" || refStrategy === "relative" || refStrategy === "none" || refStrategy === "seen" ? { $refStrategy: refStrategy } : {});
3441
+ };
3550
3442
  const HEADER_NAME = "X-CopilotCloud-Public-Api-Key";
3551
3443
  const COPILOT_CLOUD_CHAT_URL$1 = "https://api.cloud.copilotkit.ai/copilotkit/v1";
3552
3444
  const EMPTY_HEADERS = Object.freeze({});
@@ -3577,6 +3469,8 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
3577
3469
  const [runtimeA2UIEnabled, setRuntimeA2UIEnabled] = (0, react.useState)(false);
3578
3470
  const [runtimeOpenGenUIEnabled, setRuntimeOpenGenUIEnabled] = (0, react.useState)(false);
3579
3471
  const openGenUIActive = runtimeOpenGenUIEnabled || !!openGenerativeUI;
3472
+ const a2uiCatalogProvided = !!a2ui?.catalog;
3473
+ const a2uiActive = runtimeA2UIEnabled || a2uiCatalogProvided;
3580
3474
  const [runtimeLicenseStatus, setRuntimeLicenseStatus] = (0, react.useState)(void 0);
3581
3475
  (0, react.useEffect)(() => {
3582
3476
  if (typeof window === "undefined") return;
@@ -3607,7 +3501,7 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
3607
3501
  content: OpenGenerativeUIContentSchema,
3608
3502
  render: OpenGenerativeUIActivityRenderer
3609
3503
  });
3610
- if (runtimeA2UIEnabled) renderers.unshift(createA2UIMessageRenderer({
3504
+ if (a2uiActive) renderers.unshift(createA2UIMessageRenderer({
3611
3505
  theme: a2ui?.theme ?? _copilotkit_a2ui_renderer.viewerTheme,
3612
3506
  catalog: a2ui?.catalog,
3613
3507
  loadingComponent: a2ui?.loadingComponent,
@@ -3615,7 +3509,7 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
3615
3509
  }));
3616
3510
  return renderers;
3617
3511
  }, [
3618
- runtimeA2UIEnabled,
3512
+ a2uiActive,
3619
3513
  openGenUIActive,
3620
3514
  a2ui
3621
3515
  ]);
@@ -3802,7 +3696,10 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
3802
3696
  copilotkit.setRuntimeTransport(useSingleEndpoint === true ? "single" : useSingleEndpoint === false ? "rest" : "auto");
3803
3697
  copilotkit.setHeaders(mergedHeaders);
3804
3698
  copilotkit.setCredentials(credentials);
3805
- copilotkit.setProperties(properties);
3699
+ copilotkit.setProperties(a2uiCatalogProvided ? {
3700
+ ...properties,
3701
+ a2uiCatalogAvailable: true
3702
+ } : properties);
3806
3703
  copilotkit.setAgents__unsafe_dev_only(mergedAgents);
3807
3704
  copilotkit.setDebug(debug);
3808
3705
  }, [
@@ -3811,6 +3708,7 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
3811
3708
  mergedHeaders,
3812
3709
  credentials,
3813
3710
  properties,
3711
+ a2uiCatalogProvided,
3814
3712
  mergedAgents,
3815
3713
  useSingleEndpoint,
3816
3714
  debug
@@ -3858,7 +3756,7 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
3858
3756
  return JSON.stringify(sandboxFunctionsList.map((fn) => ({
3859
3757
  name: fn.name,
3860
3758
  description: fn.description,
3861
- parameters: (0, _copilotkit_shared.schemaToJsonSchema)(fn.parameters, { zodToJsonSchema: zod_to_json_schema.zodToJsonSchema })
3759
+ parameters: (0, _copilotkit_shared.schemaToJsonSchema)(fn.parameters, { zodToJsonSchema: zodToJsonSchemaAdapter })
3862
3760
  })));
3863
3761
  }, [sandboxFunctionsList]);
3864
3762
  (0, react.useLayoutEffect)(() => {
@@ -3879,7 +3777,7 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
3879
3777
  copilotkit,
3880
3778
  executingToolCallIds
3881
3779
  }), [copilotkit, executingToolCallIds]);
3882
- const licenseContextValue = (0, react.useMemo)(() => (0, _copilotkit_shared.createLicenseContextValue)(null), []);
3780
+ const licenseContextValue = (0, react.useMemo)(() => (0, _copilotkit_shared.createLicenseContextValue)(runtimeLicenseStatus), [runtimeLicenseStatus]);
3883
3781
  return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(SandboxFunctionsContext.Provider, {
3884
3782
  value: sandboxFunctionsList,
3885
3783
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(CopilotKitContext.Provider, {
@@ -3887,8 +3785,8 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
3887
3785
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(LicenseContext.Provider, {
3888
3786
  value: licenseContextValue,
3889
3787
  children: [
3890
- runtimeA2UIEnabled && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(A2UIBuiltInToolCallRenderer, {}),
3891
- runtimeA2UIEnabled && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(A2UICatalogContext, {
3788
+ a2uiActive && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(A2UIBuiltInToolCallRenderer, {}),
3789
+ a2uiActive && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(A2UICatalogContext, {
3892
3790
  catalog: a2ui?.catalog,
3893
3791
  includeSchema: a2ui?.includeSchema
3894
3792
  }),
@@ -3966,16 +3864,20 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
3966
3864
  const renderActivityMessage = (0, react.useCallback)((message) => {
3967
3865
  const renderer = findRenderer(message.activityType);
3968
3866
  if (!renderer) return null;
3969
- const parseResult = renderer.content.safeParse(message.content);
3970
- if (!parseResult.success) {
3971
- console.warn(`Failed to parse content for activity message '${message.activityType}':`, parseResult.error);
3867
+ const parseResult = renderer.content["~standard"].validate(message.content);
3868
+ if (parseResult instanceof Promise) {
3869
+ console.warn(`Async content validation is not supported for activity message '${message.activityType}'`);
3870
+ return null;
3871
+ }
3872
+ if (parseResult.issues) {
3873
+ console.warn(`Failed to parse content for activity message '${message.activityType}':`, parseResult.issues);
3972
3874
  return null;
3973
3875
  }
3974
3876
  const Component = renderer.render;
3975
3877
  const agent = copilotkit.getAgent(agentId);
3976
3878
  return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Component, {
3977
3879
  activityType: message.activityType,
3978
- content: parseResult.data,
3880
+ content: parseResult.value,
3979
3881
  message,
3980
3882
  agent
3981
3883
  }, message.id);
@@ -3992,10 +3894,10 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
3992
3894
 
3993
3895
  //#endregion
3994
3896
  //#region src/v2/hooks/use-frontend-tool.tsx
3995
- const EMPTY_DEPS = [];
3897
+ const EMPTY_DEPS$1 = [];
3996
3898
  function useFrontendTool(tool, deps) {
3997
3899
  const { copilotkit } = useCopilotKit();
3998
- const extraDeps = deps ?? EMPTY_DEPS;
3900
+ const extraDeps = deps ?? EMPTY_DEPS$1;
3999
3901
  (0, react.useEffect)(() => {
4000
3902
  const name = tool.name;
4001
3903
  if (copilotkit.getTool({
@@ -4075,21 +3977,291 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
4075
3977
  * );
4076
3978
  * ```
4077
3979
  */
4078
- function useComponent(config, deps) {
4079
- const prefix = `Use this tool to display the "${config.name}" component in the chat. This tool renders a visual UI component for the user.`;
4080
- const fullDescription = config.description ? `${prefix}\n\n${config.description}` : prefix;
4081
- useFrontendTool({
4082
- name: config.name,
4083
- description: fullDescription,
4084
- parameters: config.parameters,
4085
- render: ({ args }) => {
4086
- const Component = config.render;
4087
- return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Component, { ...args });
4088
- },
4089
- agentId: config.agentId,
4090
- followUp: config.followUp
3980
+ function useComponent(config, deps) {
3981
+ const prefix = `Use this tool to display the "${config.name}" component in the chat. This tool renders a visual UI component for the user.`;
3982
+ const fullDescription = config.description ? `${prefix}\n\n${config.description}` : prefix;
3983
+ useFrontendTool({
3984
+ name: config.name,
3985
+ description: fullDescription,
3986
+ parameters: config.parameters,
3987
+ render: ({ args }) => {
3988
+ const Component = config.render;
3989
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Component, { ...args });
3990
+ },
3991
+ agentId: config.agentId,
3992
+ followUp: config.followUp
3993
+ }, deps);
3994
+ }
3995
+
3996
+ //#endregion
3997
+ //#region src/v2/hooks/use-render-tool.tsx
3998
+ const EMPTY_DEPS = [];
3999
+ /**
4000
+ * Registers a renderer entry in CopilotKit's `renderToolCalls` registry.
4001
+ *
4002
+ * Key behavior:
4003
+ * - deduplicates by `agentId:name` (latest registration wins),
4004
+ * - keeps renderer entries on cleanup so historical chat tool calls can still render,
4005
+ * - refreshes registration when `deps` change.
4006
+ *
4007
+ * @typeParam S - Schema type describing tool call parameters.
4008
+ * @param config - Renderer config for wildcard or named tools.
4009
+ * @param deps - Optional dependencies to refresh registration.
4010
+ *
4011
+ * @example
4012
+ * ```tsx
4013
+ * useRenderTool(
4014
+ * {
4015
+ * name: "searchDocs",
4016
+ * parameters: z.object({ query: z.string() }),
4017
+ * render: ({ status, parameters, result }) => {
4018
+ * if (status === "executing") return <div>Searching {parameters.query}</div>;
4019
+ * if (status === "complete") return <div>{result}</div>;
4020
+ * return <div>Preparing...</div>;
4021
+ * },
4022
+ * },
4023
+ * [],
4024
+ * );
4025
+ * ```
4026
+ *
4027
+ * @example
4028
+ * ```tsx
4029
+ * useRenderTool(
4030
+ * {
4031
+ * name: "summarize",
4032
+ * parameters: z.object({ text: z.string() }),
4033
+ * agentId: "research-agent",
4034
+ * render: ({ name, status }) => <div>{name}: {status}</div>,
4035
+ * },
4036
+ * [selectedAgentId],
4037
+ * );
4038
+ * ```
4039
+ */
4040
+ function useRenderTool(config, deps) {
4041
+ const { copilotkit } = useCopilotKit();
4042
+ const extraDeps = deps ?? EMPTY_DEPS;
4043
+ (0, react.useEffect)(() => {
4044
+ const renderer = config.name === "*" && !config.parameters ? defineToolCallRenderer({
4045
+ name: "*",
4046
+ render: (props) => config.render({
4047
+ ...props,
4048
+ parameters: props.args
4049
+ }),
4050
+ ...config.agentId ? { agentId: config.agentId } : {}
4051
+ }) : defineToolCallRenderer({
4052
+ name: config.name,
4053
+ args: config.parameters,
4054
+ render: (props) => {
4055
+ if (props.status === _copilotkit_core.ToolCallStatus.InProgress) return config.render({
4056
+ ...props,
4057
+ parameters: props.args
4058
+ });
4059
+ if (props.status === _copilotkit_core.ToolCallStatus.Executing) return config.render({
4060
+ ...props,
4061
+ parameters: props.args
4062
+ });
4063
+ return config.render({
4064
+ ...props,
4065
+ parameters: props.args
4066
+ });
4067
+ },
4068
+ ...config.agentId ? { agentId: config.agentId } : {}
4069
+ });
4070
+ copilotkit.addHookRenderToolCall(renderer);
4071
+ }, [
4072
+ config.name,
4073
+ copilotkit,
4074
+ JSON.stringify(extraDeps)
4075
+ ]);
4076
+ }
4077
+
4078
+ //#endregion
4079
+ //#region src/v2/hooks/use-default-render-tool.tsx
4080
+ /**
4081
+ * Module-level dedup set so an unknown status value only emits a console
4082
+ * warning the FIRST time we encounter it. Otherwise a stuck/unmapped status
4083
+ * would log on every re-render (potentially many per second).
4084
+ */
4085
+ const warnedUnknownStatuses = /* @__PURE__ */ new Set();
4086
+ /**
4087
+ * Map a {@link ToolCallStatus} enum value to the documented string-union
4088
+ * status the {@link DefaultRenderProps} contract exposes. Unknown / future
4089
+ * enum members log a warning (once per distinct value) and fall back to
4090
+ * `"inProgress"`.
4091
+ */
4092
+ function mapToolCallStatus(status) {
4093
+ switch (status) {
4094
+ case _copilotkit_core.ToolCallStatus.Complete: return "complete";
4095
+ case _copilotkit_core.ToolCallStatus.Executing: return "executing";
4096
+ case _copilotkit_core.ToolCallStatus.InProgress: return "inProgress";
4097
+ default: {
4098
+ const key = String(status);
4099
+ if (!warnedUnknownStatuses.has(key)) {
4100
+ warnedUnknownStatuses.add(key);
4101
+ console.warn(`[CopilotKit] Unknown ToolCallStatus "${key}" in default tool-call renderer; falling back to "inProgress".`);
4102
+ }
4103
+ return "inProgress";
4104
+ }
4105
+ }
4106
+ }
4107
+ /**
4108
+ * Convert the framework-internal renderer props (`args`, enum status) into
4109
+ * the documented {@link DefaultRenderProps} shape (`parameters`, string-union
4110
+ * status) so a user `config.render` always sees the documented contract.
4111
+ */
4112
+ function adaptRendererProps(props) {
4113
+ return {
4114
+ name: props.name,
4115
+ toolCallId: props.toolCallId,
4116
+ parameters: props.args,
4117
+ status: mapToolCallStatus(props.status),
4118
+ result: props.result
4119
+ };
4120
+ }
4121
+ /**
4122
+ * Registers a wildcard (`"*"`) tool-call renderer via `useRenderTool`.
4123
+ *
4124
+ * - Call with no config to use CopilotKit's built-in default tool-call card.
4125
+ * - Pass `config.render` to replace the default UI with your own fallback renderer.
4126
+ *
4127
+ * This is useful when you want a generic renderer for tools that do not have a
4128
+ * dedicated `useRenderTool({ name: "..." })` registration.
4129
+ *
4130
+ * @param config - Optional custom wildcard render function.
4131
+ * @param deps - Optional dependencies to refresh registration.
4132
+ *
4133
+ * @example
4134
+ * ```tsx
4135
+ * useDefaultRenderTool();
4136
+ * ```
4137
+ *
4138
+ * @example
4139
+ * ```tsx
4140
+ * useDefaultRenderTool({
4141
+ * render: ({ name, status }) => <div>{name}: {status}</div>,
4142
+ * });
4143
+ * ```
4144
+ *
4145
+ * @example
4146
+ * ```tsx
4147
+ * useDefaultRenderTool(
4148
+ * {
4149
+ * render: ({ name, result }) => (
4150
+ * <ToolEventRow title={name} payload={result} compact={compactMode} />
4151
+ * ),
4152
+ * },
4153
+ * [compactMode],
4154
+ * );
4155
+ * ```
4156
+ */
4157
+ function useDefaultRenderTool(config, deps) {
4158
+ const userRender = config?.render;
4159
+ useRenderTool({
4160
+ name: "*",
4161
+ render: userRender ? (raw) => userRender(adaptRendererProps(raw)) : (raw) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(DefaultToolCallRenderer, { ...adaptRendererProps(raw) })
4091
4162
  }, deps);
4092
4163
  }
4164
+ /**
4165
+ * Guarded JSON.stringify used inside the expanded `<pre>` blocks. A circular
4166
+ * reference would otherwise crash the entire React tree on render.
4167
+ */
4168
+ function safeStringifyForPre(value) {
4169
+ try {
4170
+ return JSON.stringify(value, null, 2);
4171
+ } catch (err) {
4172
+ console.warn("[CopilotKit] Failed to JSON.stringify tool-call payload for default renderer; falling back to String():", err);
4173
+ try {
4174
+ return String(value);
4175
+ } catch (innerErr) {
4176
+ console.warn("[CopilotKit] safeStringifyForPre: value could not be stringified:", innerErr);
4177
+ return "[unserializable]";
4178
+ }
4179
+ }
4180
+ }
4181
+ function DefaultToolCallRenderer({ name, toolCallId, parameters, status, result }) {
4182
+ const [isExpanded, setIsExpanded] = (0, react.useState)(false);
4183
+ const isActive = status === "inProgress" || status === "executing";
4184
+ const isComplete = status === "complete";
4185
+ const statusLabel = isActive ? "Running" : isComplete ? "Done" : status;
4186
+ const dotClassName = isActive ? "cpk:bg-amber-500" : isComplete ? "cpk:bg-emerald-500" : "cpk:bg-zinc-400";
4187
+ 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";
4188
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
4189
+ "data-testid": "copilot-tool-render",
4190
+ "data-tool-name": name,
4191
+ "data-tool-call-id": toolCallId,
4192
+ "data-status": status,
4193
+ "data-args": safeStringifyForAttr(parameters),
4194
+ "data-result": safeStringifyForAttr(result),
4195
+ className: "cpk:mt-2 cpk:pb-2",
4196
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
4197
+ 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",
4198
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
4199
+ type: "button",
4200
+ "aria-expanded": isExpanded,
4201
+ onClick: () => setIsExpanded(!isExpanded),
4202
+ 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",
4203
+ style: { font: "inherit" },
4204
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
4205
+ className: "cpk:flex cpk:min-w-0 cpk:items-center cpk:gap-2",
4206
+ children: [
4207
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("svg", {
4208
+ 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" : ""}`,
4209
+ fill: "none",
4210
+ viewBox: "0 0 24 24",
4211
+ strokeWidth: 2,
4212
+ stroke: "currentColor",
4213
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", {
4214
+ strokeLinecap: "round",
4215
+ strokeLinejoin: "round",
4216
+ d: "M8.25 4.5l7.5 7.5-7.5 7.5"
4217
+ })
4218
+ }),
4219
+ /* @__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}` }),
4220
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
4221
+ "data-testid": "copilot-tool-render-name",
4222
+ className: "cpk:truncate cpk:text-[13px] cpk:font-semibold cpk:text-zinc-900 cpk:dark:text-zinc-100",
4223
+ children: name
4224
+ })
4225
+ ]
4226
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
4227
+ "data-testid": "copilot-tool-render-status",
4228
+ 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}`,
4229
+ children: statusLabel
4230
+ })]
4231
+ }), isExpanded && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
4232
+ className: "cpk:mt-3 cpk:grid cpk:gap-3",
4233
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
4234
+ className: "cpk:text-[10px] cpk:uppercase cpk:text-zinc-500 cpk:dark:text-zinc-400",
4235
+ children: "Arguments"
4236
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("pre", {
4237
+ 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",
4238
+ children: safeStringifyForPre(parameters ?? {})
4239
+ })] }), result !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
4240
+ className: "cpk:text-[10px] cpk:uppercase cpk:text-zinc-500 cpk:dark:text-zinc-400",
4241
+ children: "Result"
4242
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("pre", {
4243
+ 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",
4244
+ children: typeof result === "string" ? result : safeStringifyForPre(result)
4245
+ })] })]
4246
+ })]
4247
+ })
4248
+ });
4249
+ }
4250
+ function safeStringifyForAttr(value) {
4251
+ if (value === void 0 || value === null) return "";
4252
+ if (typeof value === "string") return value;
4253
+ try {
4254
+ return JSON.stringify(value);
4255
+ } catch (err) {
4256
+ console.warn("[CopilotKit] Failed to JSON.stringify tool-call payload for data-* attribute; falling back to String():", err);
4257
+ try {
4258
+ return String(value);
4259
+ } catch (innerErr) {
4260
+ console.warn("[CopilotKit] safeStringifyForAttr: value could not be stringified:", innerErr);
4261
+ return "";
4262
+ }
4263
+ }
4264
+ }
4093
4265
 
4094
4266
  //#endregion
4095
4267
  //#region src/v2/hooks/use-human-in-the-loop.tsx
@@ -4211,7 +4383,7 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
4211
4383
  if (isRuntimeConfigured && (status === _copilotkit_core.CopilotKitCoreRuntimeConnectionStatus.Disconnected || status === _copilotkit_core.CopilotKitCoreRuntimeConnectionStatus.Connecting)) {
4212
4384
  const cached = provisionalAgentCache.current.get(agentId);
4213
4385
  if (cached) {
4214
- cached.headers = { ...copilotkit.headers };
4386
+ copilotkit.applyHeadersToAgent(cached);
4215
4387
  return cached;
4216
4388
  }
4217
4389
  const provisional = new _copilotkit_core.ProxiedCopilotRuntimeAgent({
@@ -4220,14 +4392,14 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
4220
4392
  transport: copilotkit.runtimeTransport,
4221
4393
  runtimeMode: "pending"
4222
4394
  });
4223
- provisional.headers = { ...copilotkit.headers };
4395
+ copilotkit.applyHeadersToAgent(provisional);
4224
4396
  provisionalAgentCache.current.set(agentId, provisional);
4225
4397
  return provisional;
4226
4398
  }
4227
4399
  if (isRuntimeConfigured && status === _copilotkit_core.CopilotKitCoreRuntimeConnectionStatus.Error) {
4228
4400
  const cached = provisionalAgentCache.current.get(agentId);
4229
4401
  if (cached) {
4230
- cached.headers = { ...copilotkit.headers };
4402
+ copilotkit.applyHeadersToAgent(cached);
4231
4403
  return cached;
4232
4404
  }
4233
4405
  const provisional = new _copilotkit_core.ProxiedCopilotRuntimeAgent({
@@ -4236,7 +4408,7 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
4236
4408
  transport: copilotkit.runtimeTransport,
4237
4409
  runtimeMode: "pending"
4238
4410
  });
4239
- provisional.headers = { ...copilotkit.headers };
4411
+ copilotkit.applyHeadersToAgent(provisional);
4240
4412
  provisionalAgentCache.current.set(agentId, provisional);
4241
4413
  return provisional;
4242
4414
  }
@@ -4287,7 +4459,7 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
4287
4459
  updateFlags
4288
4460
  ]);
4289
4461
  (0, react.useEffect)(() => {
4290
- if (agent instanceof _ag_ui_client.HttpAgent) agent.headers = { ...copilotkit.headers };
4462
+ if (agent instanceof _ag_ui_client.HttpAgent) copilotkit.applyHeadersToAgent(agent);
4291
4463
  }, [agent, JSON.stringify(copilotkit.headers)]);
4292
4464
  const chatConfig = useCopilotChatConfiguration();
4293
4465
  const configThreadId = chatConfig?.threadId;
@@ -4564,114 +4736,165 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
4564
4736
  function isPromiseLike(value) {
4565
4737
  return (typeof value === "object" || typeof value === "function") && value !== null && typeof Reflect.get(value, "then") === "function";
4566
4738
  }
4739
+ /** Derive the legacy-compatible `event` for any pending interrupt. */
4740
+ function toLegacyEvent(pending) {
4741
+ if (pending.kind === "legacy") return pending.event;
4742
+ return {
4743
+ name: INTERRUPT_EVENT_NAME,
4744
+ value: pending.interrupts[0]
4745
+ };
4746
+ }
4567
4747
  /**
4568
- * Handles agent interrupts (`on_interrupt`) with optional filtering, preprocessing, and resume behavior.
4569
- *
4570
- * The hook listens to custom events on the active agent, stores interrupt payloads per run,
4571
- * and surfaces a render callback once the run finalizes. Call `resolve` from your UI to resume
4572
- * execution with user-provided data.
4573
- *
4574
- * - `renderInChat: true` (default): the element is published into `<CopilotChat>` and this hook returns `void`.
4575
- * - `renderInChat: false`: the hook returns the interrupt element so you can place it anywhere in your component tree.
4576
- *
4577
- * `event.value` is typed as `any` since the interrupt payload shape depends on your agent.
4578
- * Type-narrow it in your callbacks (e.g. `handler`, `enabled`, `render`) as needed.
4579
- *
4580
- * @typeParam TResult - Inferred from `handler` return type. Exposed as `result` in `render`.
4581
- * @param config - Interrupt configuration (renderer, optional handler/filter, and render mode).
4582
- * @returns When `renderInChat` is `false`, returns the interrupt element (or `null` when idle).
4583
- * Otherwise returns `void` and publishes the element into chat. In `render`, `result` is always
4584
- * either the handler's resolved return value or `null` (including when no handler is provided,
4585
- * when filtering skips the interrupt, or when handler execution fails).
4586
- *
4587
- * @example
4588
- * ```tsx
4589
- * import { useInterrupt } from "@copilotkit/react-core/v2";
4748
+ * Handles agent interrupts with optional filtering, preprocessing, and resume behavior.
4590
4749
  *
4591
- * function InterruptUI() {
4592
- * useInterrupt({
4593
- * render: ({ event, resolve }) => (
4594
- * <div>
4595
- * <p>{event.value.question}</p>
4596
- * <button onClick={() => resolve({ approved: true })}>Approve</button>
4597
- * <button onClick={() => resolve({ approved: false })}>Reject</button>
4598
- * </div>
4599
- * ),
4600
- * });
4750
+ * Supports both the AG-UI standard interrupt flow (`RUN_FINISHED` with
4751
+ * `outcome.type === "interrupt"`) and the legacy custom-event flow
4752
+ * (`on_interrupt`). For standard interrupts, `render` receives `interrupt`
4753
+ * (the primary one) and `interrupts` (the full open set); call `resolve(payload)`
4754
+ * to resume or `cancel()` to cancel. Resuming addresses the targeted interrupt
4755
+ * and, once every open interrupt is addressed, submits a single spec `resume`
4756
+ * array via `copilotkit.runAgent`.
4601
4757
  *
4602
- * return null;
4603
- * }
4604
- * ```
4758
+ * - `renderInChat: true` (default): the element is published into `<CopilotChat>`; returns `void`.
4759
+ * - `renderInChat: false`: the hook returns the interrupt element for manual placement.
4605
4760
  *
4606
4761
  * @example
4607
4762
  * ```tsx
4608
- * import { useInterrupt } from "@copilotkit/react-core/v2";
4609
- *
4610
- * function CustomPanel() {
4611
- * const interruptElement = useInterrupt({
4612
- * renderInChat: false,
4613
- * enabled: (event) => event.value.startsWith("approval:"),
4614
- * handler: async ({ event }) => ({ label: event.value.toUpperCase() }),
4615
- * render: ({ event, result, resolve }) => (
4616
- * <aside>
4617
- * <strong>{result?.label ?? ""}</strong>
4618
- * <button onClick={() => resolve({ value: event.value })}>Continue</button>
4619
- * </aside>
4620
- * ),
4621
- * });
4622
- *
4623
- * return <>{interruptElement}</>;
4624
- * }
4763
+ * useInterrupt({
4764
+ * render: ({ interrupt, resolve, cancel }) => (
4765
+ * <div>
4766
+ * <p>{interrupt?.message}</p>
4767
+ * <button onClick={() => resolve({ approved: true })}>Approve</button>
4768
+ * <button onClick={() => cancel()}>Cancel</button>
4769
+ * </div>
4770
+ * ),
4771
+ * });
4625
4772
  * ```
4626
4773
  */
4627
4774
  function useInterrupt(config) {
4628
4775
  const { copilotkit } = useCopilotKit();
4629
4776
  const { agent } = useAgent({ agentId: config.agentId });
4630
- const [pendingEvent, setPendingEvent] = (0, react.useState)(null);
4631
- const pendingEventRef = (0, react.useRef)(pendingEvent);
4632
- pendingEventRef.current = pendingEvent;
4777
+ const [pending, setPending] = (0, react.useState)(null);
4778
+ const pendingRef = (0, react.useRef)(pending);
4779
+ pendingRef.current = pending;
4633
4780
  const [handlerResult, setHandlerResult] = (0, react.useState)(null);
4781
+ const responsesRef = (0, react.useRef)({});
4634
4782
  (0, react.useEffect)(() => {
4635
- let localInterrupt = null;
4783
+ let localLegacy = null;
4784
+ let localStandard = null;
4636
4785
  const subscription = agent.subscribe({
4637
4786
  onCustomEvent: ({ event }) => {
4638
- if (event.name === INTERRUPT_EVENT_NAME) localInterrupt = {
4787
+ if (event.name === INTERRUPT_EVENT_NAME) localLegacy = {
4639
4788
  name: event.name,
4640
4789
  value: event.value
4641
4790
  };
4642
4791
  },
4792
+ onRunFinishedEvent: (params) => {
4793
+ if (params.outcome === "interrupt") localStandard = params.interrupts;
4794
+ },
4643
4795
  onRunStartedEvent: () => {
4644
- localInterrupt = null;
4645
- setPendingEvent(null);
4796
+ localLegacy = null;
4797
+ localStandard = null;
4798
+ responsesRef.current = {};
4799
+ setPending(null);
4646
4800
  },
4647
4801
  onRunFinalized: () => {
4648
- if (localInterrupt) {
4649
- setPendingEvent(localInterrupt);
4650
- localInterrupt = null;
4651
- }
4802
+ if (localStandard && localStandard.length > 0) setPending({
4803
+ kind: "standard",
4804
+ interrupts: localStandard
4805
+ });
4806
+ else if (localLegacy) setPending({
4807
+ kind: "legacy",
4808
+ event: localLegacy
4809
+ });
4810
+ localLegacy = null;
4811
+ localStandard = null;
4652
4812
  },
4653
4813
  onRunFailed: () => {
4654
- localInterrupt = null;
4655
- setPendingEvent(null);
4814
+ localLegacy = null;
4815
+ localStandard = null;
4816
+ responsesRef.current = {};
4817
+ setPending(null);
4656
4818
  }
4657
4819
  });
4658
4820
  return () => subscription.unsubscribe();
4659
4821
  }, [agent]);
4660
- const resolve = (0, react.useCallback)(async (response) => {
4822
+ const submitStandardIfComplete = (0, react.useCallback)(async (interrupts) => {
4823
+ if (!interrupts.every((i) => responsesRef.current[i.id])) return;
4824
+ const expired = interrupts.find((i) => (0, _ag_ui_client.isInterruptExpired)(i));
4825
+ if (expired) {
4826
+ console.error(`[CopilotKit] useInterrupt: interrupt ${expired.id} expired at ${expired.expiresAt}; not resuming.`);
4827
+ responsesRef.current = {};
4828
+ setPending(null);
4829
+ return;
4830
+ }
4831
+ const resume = (0, _ag_ui_client.buildResumeArray)(interrupts, responsesRef.current);
4832
+ for (const i of interrupts) {
4833
+ if (!i.toolCallId) continue;
4834
+ const response = responsesRef.current[i.id];
4835
+ const content = response.status === "cancelled" ? { status: "cancelled" } : response.payload ?? { status: "resolved" };
4836
+ agent.addMessage({
4837
+ id: (0, _ag_ui_client.randomUUID)(),
4838
+ role: "tool",
4839
+ toolCallId: i.toolCallId,
4840
+ content: JSON.stringify(content)
4841
+ });
4842
+ }
4843
+ responsesRef.current = {};
4661
4844
  try {
4845
+ return await copilotkit.runAgent({
4846
+ agent,
4847
+ resume
4848
+ });
4849
+ } catch (err) {
4850
+ console.error("[CopilotKit] useInterrupt resolve: runAgent rejected; clearing pending + rethrowing", err);
4851
+ setPending(null);
4852
+ throw err;
4853
+ }
4854
+ }, [agent, copilotkit]);
4855
+ const resolve = (0, react.useCallback)(async (payload, interruptId) => {
4856
+ const current = pendingRef.current;
4857
+ if (!current) return;
4858
+ if (current.kind === "legacy") try {
4662
4859
  return await copilotkit.runAgent({
4663
4860
  agent,
4664
4861
  forwardedProps: { command: {
4665
- resume: response,
4666
- interruptEvent: pendingEventRef.current?.value
4862
+ resume: payload,
4863
+ interruptEvent: current.event.value
4667
4864
  } }
4668
4865
  });
4669
4866
  } catch (err) {
4670
4867
  console.error("[CopilotKit] useInterrupt resolve: runAgent rejected; clearing pending + rethrowing", err);
4671
- setPendingEvent(null);
4868
+ setPending(null);
4672
4869
  throw err;
4673
4870
  }
4674
- }, [agent, copilotkit]);
4871
+ 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.`);
4872
+ const id = interruptId ?? current.interrupts[0]?.id;
4873
+ if (!id) return;
4874
+ responsesRef.current[id] = {
4875
+ status: "resolved",
4876
+ payload
4877
+ };
4878
+ return submitStandardIfComplete(current.interrupts);
4879
+ }, [
4880
+ agent,
4881
+ copilotkit,
4882
+ submitStandardIfComplete
4883
+ ]);
4884
+ const cancel = (0, react.useCallback)(async (interruptId) => {
4885
+ const current = pendingRef.current;
4886
+ if (!current) return;
4887
+ if (current.kind === "legacy") {
4888
+ console.warn("[CopilotKit] useInterrupt: cancel() is not supported for legacy on_interrupt interrupts; dismissing.");
4889
+ setPending(null);
4890
+ return;
4891
+ }
4892
+ 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.`);
4893
+ const id = interruptId ?? current.interrupts[0]?.id;
4894
+ if (!id) return;
4895
+ responsesRef.current[id] = { status: "cancelled" };
4896
+ return submitStandardIfComplete(current.interrupts);
4897
+ }, [submitStandardIfComplete]);
4675
4898
  const renderRef = (0, react.useRef)(config.render);
4676
4899
  renderRef.current = config.render;
4677
4900
  const enabledRef = (0, react.useRef)(config.enabled);
@@ -4680,6 +4903,8 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
4680
4903
  handlerRef.current = config.handler;
4681
4904
  const resolveRef = (0, react.useRef)(resolve);
4682
4905
  resolveRef.current = resolve;
4906
+ const cancelRef = (0, react.useRef)(cancel);
4907
+ cancelRef.current = cancel;
4683
4908
  const isEnabled = (event) => {
4684
4909
  const predicate = enabledRef.current;
4685
4910
  if (!predicate) return true;
@@ -4691,11 +4916,12 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
4691
4916
  }
4692
4917
  };
4693
4918
  (0, react.useEffect)(() => {
4694
- if (!pendingEvent) {
4919
+ if (!pending) {
4695
4920
  setHandlerResult(null);
4696
4921
  return;
4697
4922
  }
4698
- if (!isEnabled(pendingEvent)) {
4923
+ const legacyEvent = toLegacyEvent(pending);
4924
+ if (!isEnabled(legacyEvent)) {
4699
4925
  setHandlerResult(null);
4700
4926
  return;
4701
4927
  }
@@ -4708,8 +4934,11 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
4708
4934
  let maybePromise;
4709
4935
  try {
4710
4936
  maybePromise = handler({
4711
- event: pendingEvent,
4712
- resolve: resolveRef.current
4937
+ event: legacyEvent,
4938
+ interrupt: pending.kind === "standard" ? pending.interrupts[0] : null,
4939
+ interrupts: pending.kind === "standard" ? pending.interrupts : [],
4940
+ resolve: resolveRef.current,
4941
+ cancel: cancelRef.current
4713
4942
  });
4714
4943
  } catch (err) {
4715
4944
  console.error("[CopilotKit] useInterrupt handler threw; result will be null:", err);
@@ -4728,19 +4957,24 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
4728
4957
  return () => {
4729
4958
  cancelled = true;
4730
4959
  };
4731
- }, [pendingEvent]);
4960
+ }, [pending]);
4732
4961
  const element = (0, react.useMemo)(() => {
4733
- if (!pendingEvent) return null;
4734
- if (!isEnabled(pendingEvent)) return null;
4962
+ if (!pending) return null;
4963
+ const legacyEvent = toLegacyEvent(pending);
4964
+ if (!isEnabled(legacyEvent)) return null;
4735
4965
  return renderRef.current({
4736
- event: pendingEvent,
4966
+ event: legacyEvent,
4967
+ interrupt: pending.kind === "standard" ? pending.interrupts[0] : null,
4968
+ interrupts: pending.kind === "standard" ? pending.interrupts : [],
4737
4969
  result: handlerResult,
4738
- resolve
4970
+ resolve,
4971
+ cancel
4739
4972
  });
4740
4973
  }, [
4741
- pendingEvent,
4974
+ pending,
4742
4975
  handlerResult,
4743
- resolve
4976
+ resolve,
4977
+ cancel
4744
4978
  ]);
4745
4979
  (0, react.useEffect)(() => {
4746
4980
  if (config.renderInChat === false) return;
@@ -4765,7 +4999,7 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
4765
4999
  return (0, react.useSyncExternalStore)((0, react.useCallback)((onStoreChange) => {
4766
5000
  const subscription = store.select(selector).subscribe(onStoreChange);
4767
5001
  return () => subscription.unsubscribe();
4768
- }, [store, selector]), () => selector(store.getState()));
5002
+ }, [store, selector]), () => selector(store.getState()), () => selector(store.getServerState()));
4769
5003
  }
4770
5004
  /**
4771
5005
  * React hook for listing and managing Intelligence platform threads.
@@ -4776,9 +5010,9 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
4776
5010
  * current without polling — thread creates, renames, archives, and deletes
4777
5011
  * from any client are reflected immediately.
4778
5012
  *
4779
- * Mutation methods (`renameThread`, `archiveThread`, `deleteThread`) return
4780
- * promises that resolve once the platform confirms the operation and reject
4781
- * with an `Error` on failure.
5013
+ * Mutation methods (`renameThread`, `archiveThread`, `unarchiveThread`,
5014
+ * `deleteThread`) return promises that resolve once the platform confirms the
5015
+ * operation and reject with an `Error` on failure.
4782
5016
  *
4783
5017
  * @param input - Agent identifier and optional list controls.
4784
5018
  * @returns Thread list state and stable mutation callbacks.
@@ -4808,7 +5042,7 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
4808
5042
  * }
4809
5043
  * ```
4810
5044
  */
4811
- function useThreads({ agentId, includeArchived, limit }) {
5045
+ function useThreads({ agentId, includeArchived, limit, enabled = true }) {
4812
5046
  const { copilotkit } = useCopilotKit();
4813
5047
  const [store] = (0, react.useState)(() => (0, _copilotkit_core.ɵcreateThreadStore)({ fetch: globalThis.fetch }));
4814
5048
  const coreThreads = useThreadStoreSelector(store, _copilotkit_core.ɵselectThreads);
@@ -4825,6 +5059,7 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
4825
5059
  const storeError = useThreadStoreSelector(store, _copilotkit_core.ɵselectThreadsError);
4826
5060
  const hasMoreThreads = useThreadStoreSelector(store, _copilotkit_core.ɵselectHasNextPage);
4827
5061
  const isFetchingMoreThreads = useThreadStoreSelector(store, _copilotkit_core.ɵselectIsFetchingNextPage);
5062
+ const isMutating = useThreadStoreSelector(store, _copilotkit_core.ɵselectIsMutating);
4828
5063
  const headersKey = (0, react.useMemo)(() => {
4829
5064
  return JSON.stringify(Object.entries(copilotkit.headers ?? {}).sort(([left], [right]) => left.localeCompare(right)));
4830
5065
  }, [copilotkit.headers]);
@@ -4845,9 +5080,16 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
4845
5080
  return /* @__PURE__ */ new Error("Thread mutations are not available on this CopilotKit runtime");
4846
5081
  }, [threadMutationsSupported]);
4847
5082
  const [hasDispatchedContext, setHasDispatchedContext] = (0, react.useState)(false);
4848
- const preConnectLoading = !!copilotkit.runtimeUrl && !threadEndpointsUnavailable && !hasDispatchedContext;
4849
- const isLoading = runtimeError || threadEndpointsError ? false : preConnectLoading || storeIsLoading;
4850
- const error = runtimeError ?? threadEndpointsError ?? storeError;
5083
+ const preConnectLoading = enabled && !!copilotkit.runtimeUrl && !threadEndpointsUnavailable && !hasDispatchedContext;
5084
+ const [configErrorDismissed, setConfigErrorDismissed] = (0, react.useState)(false);
5085
+ (0, react.useEffect)(() => {
5086
+ setConfigErrorDismissed(false);
5087
+ }, [runtimeError, threadEndpointsError]);
5088
+ const activeRuntimeError = configErrorDismissed ? null : runtimeError;
5089
+ const activeThreadEndpointsError = configErrorDismissed ? null : threadEndpointsError;
5090
+ const isLoading = activeRuntimeError || activeThreadEndpointsError ? false : preConnectLoading || storeIsLoading;
5091
+ const error = activeRuntimeError ?? activeThreadEndpointsError ?? storeError;
5092
+ const listError = storeError;
4851
5093
  (0, react.useEffect)(() => {
4852
5094
  store.start();
4853
5095
  return () => {
@@ -4855,6 +5097,7 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
4855
5097
  };
4856
5098
  }, [store]);
4857
5099
  (0, react.useEffect)(() => {
5100
+ if (!enabled) return;
4858
5101
  copilotkit.registerThreadStore(agentId, store);
4859
5102
  return () => {
4860
5103
  copilotkit.unregisterThreadStore(agentId);
@@ -4862,9 +5105,15 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
4862
5105
  }, [
4863
5106
  copilotkit,
4864
5107
  agentId,
4865
- store
5108
+ store,
5109
+ enabled
4866
5110
  ]);
4867
5111
  (0, react.useEffect)(() => {
5112
+ if (!enabled) {
5113
+ store.setContext(null);
5114
+ setHasDispatchedContext(false);
5115
+ return;
5116
+ }
4868
5117
  if (!copilotkit.runtimeUrl) {
4869
5118
  store.setContext(null);
4870
5119
  setHasDispatchedContext(false);
@@ -4888,6 +5137,7 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
4888
5137
  setHasDispatchedContext(true);
4889
5138
  }, [
4890
5139
  store,
5140
+ enabled,
4891
5141
  copilotkit.runtimeUrl,
4892
5142
  runtimeStatus,
4893
5143
  headersKey,
@@ -4905,16 +5155,25 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
4905
5155
  }, [threadMutationsError]);
4906
5156
  const renameThread = (0, react.useMemo)(() => guardMutation((threadId, name) => store.renameThread(threadId, name)), [store, guardMutation]);
4907
5157
  const archiveThread = (0, react.useMemo)(() => guardMutation((threadId) => store.archiveThread(threadId)), [store, guardMutation]);
5158
+ const unarchiveThread = (0, react.useMemo)(() => guardMutation((threadId) => store.unarchiveThread(threadId)), [store, guardMutation]);
4908
5159
  const deleteThread = (0, react.useMemo)(() => guardMutation((threadId) => store.deleteThread(threadId)), [store, guardMutation]);
4909
5160
  return {
4910
5161
  threads,
4911
5162
  isLoading,
4912
5163
  error,
5164
+ listError,
4913
5165
  hasMoreThreads,
4914
5166
  isFetchingMoreThreads,
5167
+ isMutating,
4915
5168
  fetchMoreThreads: (0, react.useCallback)(() => store.fetchNextPage(), [store]),
5169
+ refetchThreads: (0, react.useCallback)(() => store.refetchThreads(), [store]),
5170
+ startNewThread: (0, react.useCallback)(() => {
5171
+ setConfigErrorDismissed(true);
5172
+ store.startNewThread();
5173
+ }, [store]),
4916
5174
  renameThread,
4917
5175
  archiveThread,
5176
+ unarchiveThread,
4918
5177
  deleteThread
4919
5178
  };
4920
5179
  }
@@ -6098,7 +6357,7 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
6098
6357
  ref,
6099
6358
  "data-copilotkit": true,
6100
6359
  "data-testid": "copilot-suggestions",
6101
- className: cn("cpk:flex cpk:flex-wrap cpk:items-center cpk:gap-1.5 cpk:sm:gap-2 cpk:pl-0 cpk:pr-4 cpk:sm:px-0 cpk:pointer-events-none", className),
6360
+ className: cn("cpk:flex cpk:flex-wrap cpk:items-center cpk:gap-1.5 cpk:sm:gap-2 cpk:pl-0 cpk:pr-4 cpk:@3xl:px-0 cpk:pointer-events-none", className),
6102
6361
  ...props
6103
6362
  });
6104
6363
  });
@@ -7203,7 +7462,7 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
7203
7462
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
7204
7463
  className: "cpk:max-w-3xl cpk:mx-auto",
7205
7464
  children: [BoundMessageView, hasSuggestions ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
7206
- className: "cpk:pl-0 cpk:pr-4 cpk:sm:px-0 cpk:mt-4",
7465
+ className: "cpk:pl-0 cpk:pr-4 cpk:@3xl:px-0 cpk:mt-4",
7207
7466
  children: BoundSuggestionView
7208
7467
  }) : null]
7209
7468
  })
@@ -7246,7 +7505,7 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
7246
7505
  onDragOver,
7247
7506
  onDragLeave,
7248
7507
  onDrop,
7249
- className: cn("copilotKitChat cpk:relative cpk:h-full cpk:flex cpk:flex-col", className),
7508
+ className: cn("copilotKitChat cpk:@container cpk:relative cpk:h-full cpk:flex cpk:flex-col", className),
7250
7509
  ...props,
7251
7510
  children: [dragOver && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(DropOverlay, {}), BoundWelcomeScreen]
7252
7511
  });
@@ -7268,7 +7527,7 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
7268
7527
  onDragOver,
7269
7528
  onDragLeave,
7270
7529
  onDrop,
7271
- className: cn("copilotKitChat cpk:relative cpk:h-full cpk:flex cpk:flex-col", className),
7530
+ className: cn("copilotKitChat cpk:@container cpk:relative cpk:h-full cpk:flex cpk:flex-col", className),
7272
7531
  ...props,
7273
7532
  children: [
7274
7533
  dragOver && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(DropOverlay, {}),
@@ -7307,7 +7566,7 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
7307
7566
  minHeight: 0
7308
7567
  },
7309
7568
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
7310
- className: "cpk:px-4 cpk:sm:px-0 cpk:[div[data-sidebar-chat]_&]:px-8 cpk:[div[data-popup-chat]_&]:px-6",
7569
+ className: "cpk:px-4 cpk:@3xl:px-0 cpk:[div[data-sidebar-chat]_&]:px-8 cpk:[div[data-popup-chat]_&]:px-6",
7311
7570
  children
7312
7571
  })
7313
7572
  }),
@@ -7340,7 +7599,7 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
7340
7599
  ...props,
7341
7600
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
7342
7601
  ref: contentRef,
7343
- className: "cpk:px-4 cpk:sm:px-0 cpk:[div[data-sidebar-chat]_&]:px-8 cpk:[div[data-popup-chat]_&]:px-6",
7602
+ className: "cpk:px-4 cpk:@3xl:px-0 cpk:[div[data-sidebar-chat]_&]:px-8 cpk:[div[data-popup-chat]_&]:px-6",
7344
7603
  children
7345
7604
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
7346
7605
  ref: spacerRef,
@@ -7402,7 +7661,7 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
7402
7661
  if (!hasMounted) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
7403
7662
  className: "cpk:h-full cpk:max-h-full cpk:flex cpk:flex-col cpk:min-h-0 cpk:overflow-y-auto cpk:overflow-x-hidden",
7404
7663
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
7405
- className: "cpk:px-4 cpk:sm:px-0 cpk:[div[data-sidebar-chat]_&]:px-8 cpk:[div[data-popup-chat]_&]:px-6",
7664
+ className: "cpk:px-4 cpk:@3xl:px-0 cpk:[div[data-sidebar-chat]_&]:px-8 cpk:[div[data-popup-chat]_&]:px-6",
7406
7665
  children
7407
7666
  })
7408
7667
  });
@@ -7417,7 +7676,7 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
7417
7676
  children: [
7418
7677
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
7419
7678
  ref: contentRef,
7420
- className: "cpk:px-4 cpk:sm:px-0 cpk:[div[data-sidebar-chat]_&]:px-8 cpk:[div[data-popup-chat]_&]:px-6",
7679
+ className: "cpk:px-4 cpk:@3xl:px-0 cpk:[div[data-sidebar-chat]_&]:px-8 cpk:[div[data-popup-chat]_&]:px-6",
7421
7680
  children
7422
7681
  }),
7423
7682
  BoundFeather,
@@ -7681,9 +7940,17 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
7681
7940
  const { messageView: providedMessageView, suggestionView: providedSuggestionView, onStop: providedStopHandler, ...restProps } = props;
7682
7941
  const [lastConnectedThreadId, setLastConnectedThreadId] = (0, react.useState)(null);
7683
7942
  const isConnecting = hasExplicitThreadId && lastConnectedThreadId !== resolvedThreadId;
7943
+ const previousThreadIdRef = (0, react.useRef)(null);
7944
+ const hasExplicitThreadIdRef = (0, react.useRef)(hasExplicitThreadId);
7945
+ hasExplicitThreadIdRef.current = hasExplicitThreadId;
7684
7946
  (0, react.useEffect)(() => {
7947
+ const threadChanged = previousThreadIdRef.current !== resolvedThreadId;
7948
+ previousThreadIdRef.current = resolvedThreadId;
7685
7949
  agent.threadId = resolvedThreadId;
7686
- if (!hasExplicitThreadId) return;
7950
+ if (!hasExplicitThreadId) {
7951
+ if (threadChanged && agent.messages.length > 0) agent.setMessages([]);
7952
+ return;
7953
+ }
7687
7954
  let detached = false;
7688
7955
  const connectAbortController = new AbortController();
7689
7956
  if (agent instanceof _ag_ui_client.HttpAgent) agent.abortController = connectAbortController;
@@ -7697,6 +7964,7 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
7697
7964
  if (!detached) (typeof requestAnimationFrame === "function" ? requestAnimationFrame : (cb) => setTimeout(cb, 16))(() => {
7698
7965
  if (!detached) setLastConnectedThreadId(resolvedThreadId);
7699
7966
  });
7967
+ else if (!hasExplicitThreadIdRef.current) agentToConnect.setMessages([]);
7700
7968
  }
7701
7969
  };
7702
7970
  connect(agent);
@@ -7712,8 +7980,10 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
7712
7980
  hasExplicitThreadId
7713
7981
  ]);
7714
7982
  const waitForActiveRunToSettle = (0, react.useCallback)(async () => {
7715
- if (agent.isRunning && (0, _copilotkit_core.isRunCompletionAware)(agent) && agent.activeRunCompletionPromise) try {
7716
- await agent.activeRunCompletionPromise;
7983
+ const maybeAware = agent;
7984
+ const activeRunCompletionPromise = (0, _copilotkit_core.isRunCompletionAware)(maybeAware) ? maybeAware.activeRunCompletionPromise : void 0;
7985
+ if (agent.isRunning && activeRunCompletionPromise) try {
7986
+ await activeRunCompletionPromise;
7717
7987
  } catch (error) {
7718
7988
  console.error("CopilotChat: in-flight run rejected while queuing send", error);
7719
7989
  }
@@ -8045,18 +8315,46 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
8045
8315
 
8046
8316
  //#endregion
8047
8317
  //#region src/v2/components/chat/CopilotModalHeader.tsx
8048
- function CopilotModalHeader({ title, titleContent, closeButton, children, className, ...rest }) {
8318
+ /**
8319
+ * Reactively tracks whether the viewport is in the mobile range (≤767px) — the
8320
+ * same breakpoint the drawer + chat coordination use. SSR-safe: starts `false`
8321
+ * (desktop) so the server render and first client render agree, then syncs on
8322
+ * mount and on resize.
8323
+ */
8324
+ function useIsMobileViewport() {
8325
+ const [isMobile, setIsMobile] = (0, react.useState)(false);
8326
+ (0, react.useEffect)(() => {
8327
+ if (typeof window === "undefined" || typeof window.matchMedia !== "function") return;
8328
+ const mql = window.matchMedia("(max-width: 767px)");
8329
+ const update = () => setIsMobile(mql.matches);
8330
+ update();
8331
+ mql.addEventListener("change", update);
8332
+ return () => mql.removeEventListener("change", update);
8333
+ }, []);
8334
+ return isMobile;
8335
+ }
8336
+ function CopilotModalHeader({ title, titleContent, closeButton, drawerLauncher, children, className, ...rest }) {
8049
8337
  const configuration = useCopilotChatConfiguration();
8050
8338
  const fallbackTitle = configuration?.labels.modalHeaderTitle ?? CopilotChatDefaultLabels.modalHeaderTitle;
8051
8339
  const resolvedTitle = title ?? fallbackTitle;
8340
+ const isMobile = useIsMobileViewport();
8341
+ const drawerRegistered = (configuration?.drawerRegistered ?? false) && isMobile;
8052
8342
  const handleClose = (0, react.useCallback)(() => {
8053
8343
  configuration?.setModalOpen?.(false);
8054
8344
  }, [configuration]);
8345
+ const handleToggleDrawer = (0, react.useCallback)(() => {
8346
+ configuration?.setDrawerOpen?.(!configuration.drawerOpen);
8347
+ }, [configuration]);
8055
8348
  const BoundTitle = renderSlot(titleContent, CopilotModalHeader.Title, { children: resolvedTitle });
8056
8349
  const BoundCloseButton = renderSlot(closeButton, CopilotModalHeader.CloseButton, { onClick: handleClose });
8350
+ const BoundDrawerLauncher = drawerRegistered ? renderSlot(drawerLauncher, CopilotModalHeader.DrawerLauncher, {
8351
+ onClick: handleToggleDrawer,
8352
+ "aria-expanded": configuration?.drawerOpen ?? false
8353
+ }) : null;
8057
8354
  if (children) return children({
8058
8355
  titleContent: BoundTitle,
8059
8356
  closeButton: BoundCloseButton,
8357
+ drawerLauncher: BoundDrawerLauncher,
8060
8358
  title: resolvedTitle,
8061
8359
  ...rest
8062
8360
  });
@@ -8069,8 +8367,8 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
8069
8367
  className: "cpk:flex cpk:w-full cpk:items-center cpk:gap-2",
8070
8368
  children: [
8071
8369
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
8072
- className: "cpk:flex-1",
8073
- "aria-hidden": "true"
8370
+ className: "cpk:flex cpk:flex-1 cpk:justify-start",
8371
+ children: BoundDrawerLauncher ?? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { "aria-hidden": "true" })
8074
8372
  }),
8075
8373
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
8076
8374
  className: "cpk:flex cpk:flex-1 cpk:justify-center cpk:text-center",
@@ -8103,9 +8401,21 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
8103
8401
  "aria-hidden": "true"
8104
8402
  })
8105
8403
  });
8404
+ _CopilotModalHeader.DrawerLauncher = ({ className, ...props }) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
8405
+ type: "button",
8406
+ "data-testid": "copilot-threads-drawer-launcher",
8407
+ className: cn("cpk:inline-flex cpk:size-8 cpk:items-center cpk:justify-center cpk:rounded-full cpk:text-muted-foreground cpk:transition cpk:cursor-pointer", "cpk:hover:bg-muted cpk:hover:text-foreground cpk:focus-visible:outline-none cpk:focus-visible:ring-2 cpk:focus-visible:ring-ring", className),
8408
+ "aria-label": "Open threads",
8409
+ ...props,
8410
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(lucide_react.PanelLeftOpen, {
8411
+ className: "cpk:h-4 cpk:w-4",
8412
+ "aria-hidden": "true"
8413
+ })
8414
+ });
8106
8415
  })(CopilotModalHeader || (CopilotModalHeader = {}));
8107
8416
  CopilotModalHeader.Title.displayName = "CopilotModalHeader.Title";
8108
8417
  CopilotModalHeader.CloseButton.displayName = "CopilotModalHeader.CloseButton";
8418
+ CopilotModalHeader.DrawerLauncher.displayName = "CopilotModalHeader.DrawerLauncher";
8109
8419
 
8110
8420
  //#endregion
8111
8421
  //#region src/v2/components/chat/CopilotSidebarView.tsx
@@ -8463,6 +8773,322 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
8463
8773
  }
8464
8774
  CopilotPopup.displayName = "CopilotPopup";
8465
8775
 
8776
+ //#endregion
8777
+ //#region src/v2/components/chat/CopilotThreadsDrawer.tsx
8778
+ /**
8779
+ * Maps a {@link Thread} from {@link useThreads} to the element's
8780
+ * {@link DrawerThread} view shape. The shapes are structurally compatible; this
8781
+ * narrows to exactly the fields the element renders so the element never sees
8782
+ * platform-internal fields.
8783
+ */
8784
+ function toDrawerThread(thread) {
8785
+ return {
8786
+ id: thread.id,
8787
+ name: thread.name,
8788
+ archived: thread.archived,
8789
+ createdAt: thread.createdAt,
8790
+ updatedAt: thread.updatedAt,
8791
+ ...thread.lastRunAt !== void 0 ? { lastRunAt: thread.lastRunAt } : {}
8792
+ };
8793
+ }
8794
+ /** The chat input textarea's documented `data-testid`. */
8795
+ const CHAT_INPUT_TESTID = "copilot-chat-textarea";
8796
+ /** The chat view container's documented `data-testid`. */
8797
+ const CHAT_CONTAINER_TESTID = "copilot-chat";
8798
+ /**
8799
+ * Returns the chat input element for focus-return after a thread is selected.
8800
+ *
8801
+ * Best-effort and SCOPED: walks up from the drawer element looking for an
8802
+ * ancestor that contains a chat-view container (`data-testid="copilot-chat"`),
8803
+ * then returns the chat input within that subtree. This avoids focusing the
8804
+ * wrong composer on a page hosting more than one chat (multi-chat dashboards),
8805
+ * where a document-global lookup would grab whichever input appears first in
8806
+ * DOM order rather than the one this drawer drives.
8807
+ *
8808
+ * Falls back to a document-global lookup when no scoping ancestor is found
8809
+ * (e.g. the drawer and chat share no common container, or headless usage),
8810
+ * and returns `null` when there is no chat input at all.
8811
+ *
8812
+ * @param origin - The drawer element to scope the search from.
8813
+ */
8814
+ function findChatInput(origin) {
8815
+ if (typeof document === "undefined") return null;
8816
+ const container = origin?.closest?.(`[data-testid="${CHAT_CONTAINER_TESTID}"]`);
8817
+ if (container) {
8818
+ const scoped = container.querySelector(`[data-testid="${CHAT_INPUT_TESTID}"]`);
8819
+ if (scoped) return scoped;
8820
+ }
8821
+ return document.querySelector(`[data-testid="${CHAT_INPUT_TESTID}"]`);
8822
+ }
8823
+ /**
8824
+ * React wrapper for the shadow-DOM `<copilotkit-threads-drawer>` threads drawer.
8825
+ *
8826
+ * Responsibilities:
8827
+ * - Registers the custom element on the client (SSR-safe; nothing renders
8828
+ * during prerender to avoid hydration mismatch).
8829
+ * - Feeds the element domain data: `threads`, `loading`, `error`,
8830
+ * `activeThreadId`, `licensed`, fetch-more state.
8831
+ * - Routes the element's nine outbound events to core thread operations
8832
+ * ({@link useThreads}) and chat-configuration changes.
8833
+ * - Registers with the surrounding chat configuration so the header
8834
+ * thread-list launcher appears, and binds the element `open` state to the
8835
+ * configuration's `drawerOpen`.
8836
+ *
8837
+ * License gating is two-pronged: the locked view shows when no license is configured
8838
+ * (the runtime reported no license status) OR the `threads` feature is
8839
+ * explicitly unlicensed. While unlicensed, the thread fetch is skipped entirely
8840
+ * so an unlicensed drawer issues no network requests.
8841
+ *
8842
+ * Thread switching needs no host wiring: when `onThreadSelect`/`onNewThread`
8843
+ * are omitted, the wrapper drives the surrounding chat configuration directly
8844
+ * ({@link CopilotChatConfigurationValue.setActiveThreadId} /
8845
+ * {@link CopilotChatConfigurationValue.startNewThread}), so a bare drawer
8846
+ * connects to the picked thread and shows the welcome screen on "+ New". Pass
8847
+ * the callbacks only to take control yourself.
8848
+ *
8849
+ * @example
8850
+ * ```tsx
8851
+ * // Callback-free: the drawer drives the chat configuration itself.
8852
+ * <CopilotKitProvider runtimeUrl="/api/copilotkit" publicLicenseKey="ck_pub_...">
8853
+ * <CopilotChat />
8854
+ * <CopilotThreadsDrawer />
8855
+ * </CopilotKitProvider>
8856
+ * ```
8857
+ */
8858
+ function CopilotThreadsDrawer({ agentId, onThreadSelect, onNewThread, onLicensed, licenseUrl, renderRow, label, limit, "data-testid": dataTestId = "copilot-threads-drawer" }) {
8859
+ const configuration = useCopilotChatConfiguration();
8860
+ const { status, checkFeature } = useLicenseContext();
8861
+ const licensePresent = status === "valid" || status === "expiring";
8862
+ const featureLicensed = checkFeature("threads");
8863
+ const licensed = licensePresent && featureLicensed;
8864
+ const licensePending = status === null;
8865
+ const resolvedAgentId = agentId ?? configuration?.agentId ?? "default";
8866
+ const activeThreadId = configuration?.threadId ?? null;
8867
+ const { threads, isLoading, listError, hasMoreThreads, isFetchingMoreThreads, archiveThread, unarchiveThread, deleteThread, fetchMoreThreads, refetchThreads, startNewThread } = useThreads({
8868
+ agentId: resolvedAgentId,
8869
+ includeArchived: true,
8870
+ enabled: licensed,
8871
+ ...limit !== void 0 ? { limit } : {}
8872
+ });
8873
+ const drawerThreads = (0, react.useMemo)(() => threads.map(toDrawerThread), [threads]);
8874
+ const elementRef = (0, react.useRef)(null);
8875
+ const [mounted, setMounted] = (0, react.useState)(false);
8876
+ (0, react.useEffect)(() => {
8877
+ (0, _copilotkit_web_components_threads_drawer.defineCopilotKitThreadsDrawer)();
8878
+ setMounted(true);
8879
+ }, []);
8880
+ const registerDrawer = configuration?.registerDrawer;
8881
+ (0, react.useEffect)(() => {
8882
+ if (!registerDrawer) return;
8883
+ return registerDrawer();
8884
+ }, [registerDrawer]);
8885
+ const [localDrawerOpen, setLocalDrawerOpen] = (0, react.useState)(false);
8886
+ const drawerOpen = configuration ? configuration.drawerOpen : localDrawerOpen;
8887
+ const setDrawerOpen = configuration ? configuration.setDrawerOpen : setLocalDrawerOpen;
8888
+ const setActiveThreadId = configuration?.setActiveThreadId;
8889
+ const startNewThreadConfig = configuration?.startNewThread;
8890
+ const handleThreadSelected = (0, react.useCallback)((threadId) => {
8891
+ if (onThreadSelect) onThreadSelect(threadId);
8892
+ else setActiveThreadId?.(threadId, { explicit: true });
8893
+ findChatInput(elementRef.current)?.focus();
8894
+ }, [onThreadSelect, setActiveThreadId]);
8895
+ const handleNewThread = (0, react.useCallback)(() => {
8896
+ startNewThread();
8897
+ if (onNewThread) onNewThread();
8898
+ else startNewThreadConfig?.();
8899
+ }, [
8900
+ startNewThread,
8901
+ onNewThread,
8902
+ startNewThreadConfig
8903
+ ]);
8904
+ const handleArchive = (0, react.useCallback)((threadId) => {
8905
+ archiveThread(threadId).catch((err) => {
8906
+ console.error("CopilotThreadsDrawer: archiveThread failed", err);
8907
+ });
8908
+ }, [archiveThread]);
8909
+ const handleUnarchive = (0, react.useCallback)((threadId) => {
8910
+ unarchiveThread(threadId).catch((err) => {
8911
+ console.error("CopilotThreadsDrawer: unarchiveThread failed", err);
8912
+ });
8913
+ }, [unarchiveThread]);
8914
+ const handleDelete = (0, react.useCallback)((threadId) => {
8915
+ const isActive = threadId === activeThreadId;
8916
+ deleteThread(threadId).then(() => {
8917
+ if (isActive) {
8918
+ startNewThread();
8919
+ if (onNewThread) onNewThread();
8920
+ else startNewThreadConfig?.();
8921
+ }
8922
+ }).catch((err) => {
8923
+ console.error("CopilotThreadsDrawer: deleteThread failed", err);
8924
+ });
8925
+ }, [
8926
+ deleteThread,
8927
+ activeThreadId,
8928
+ startNewThread,
8929
+ onNewThread,
8930
+ startNewThreadConfig
8931
+ ]);
8932
+ const handleFilterChange = (0, react.useCallback)(() => {
8933
+ refetchThreads();
8934
+ }, [refetchThreads]);
8935
+ const handleRetry = (0, react.useCallback)((scope) => {
8936
+ if (scope === "fetch-more") fetchMoreThreads();
8937
+ else refetchThreads();
8938
+ }, [fetchMoreThreads, refetchThreads]);
8939
+ const handleOpenChange = (0, react.useCallback)((open) => {
8940
+ setDrawerOpen(open);
8941
+ }, [setDrawerOpen]);
8942
+ const handleLicensed = (0, react.useCallback)(() => {
8943
+ onLicensed?.();
8944
+ }, [onLicensed]);
8945
+ const handleLoadMore = (0, react.useCallback)(() => {
8946
+ fetchMoreThreads();
8947
+ }, [fetchMoreThreads]);
8948
+ const handlersRef = (0, react.useRef)({
8949
+ handleThreadSelected,
8950
+ handleNewThread,
8951
+ handleArchive,
8952
+ handleUnarchive,
8953
+ handleDelete,
8954
+ handleFilterChange,
8955
+ handleRetry,
8956
+ handleOpenChange,
8957
+ handleLicensed,
8958
+ handleLoadMore
8959
+ });
8960
+ handlersRef.current = {
8961
+ handleThreadSelected,
8962
+ handleNewThread,
8963
+ handleArchive,
8964
+ handleUnarchive,
8965
+ handleDelete,
8966
+ handleFilterChange,
8967
+ handleRetry,
8968
+ handleOpenChange,
8969
+ handleLicensed,
8970
+ handleLoadMore
8971
+ };
8972
+ (0, react.useEffect)(() => {
8973
+ const el = elementRef.current;
8974
+ if (!el) return;
8975
+ const onThreadSelected = (event) => {
8976
+ const detail = event.detail;
8977
+ handlersRef.current.handleThreadSelected(detail.threadId);
8978
+ };
8979
+ const onNewThreadEvent = () => handlersRef.current.handleNewThread();
8980
+ const onArchive = (event) => {
8981
+ const detail = event.detail;
8982
+ handlersRef.current.handleArchive(detail.threadId);
8983
+ };
8984
+ const onUnarchive = (event) => {
8985
+ const detail = event.detail;
8986
+ handlersRef.current.handleUnarchive(detail.threadId);
8987
+ };
8988
+ const onDelete = (event) => {
8989
+ const detail = event.detail;
8990
+ handlersRef.current.handleDelete(detail.threadId);
8991
+ };
8992
+ const onFilterChange = (_event) => {
8993
+ handlersRef.current.handleFilterChange();
8994
+ };
8995
+ const onOpenChangeEvent = (event) => {
8996
+ const detail = event.detail;
8997
+ handlersRef.current.handleOpenChange(detail.open);
8998
+ };
8999
+ const onRetry = (event) => {
9000
+ const detail = event.detail;
9001
+ handlersRef.current.handleRetry(detail.scope);
9002
+ };
9003
+ const onLicensedEvent = () => handlersRef.current.handleLicensed();
9004
+ const onLoadMore = () => handlersRef.current.handleLoadMore();
9005
+ el.addEventListener("thread-selected", onThreadSelected);
9006
+ el.addEventListener("new-thread", onNewThreadEvent);
9007
+ el.addEventListener("archive", onArchive);
9008
+ el.addEventListener("unarchive", onUnarchive);
9009
+ el.addEventListener("delete", onDelete);
9010
+ el.addEventListener("filter-change", onFilterChange);
9011
+ el.addEventListener("open-change", onOpenChangeEvent);
9012
+ el.addEventListener("retry", onRetry);
9013
+ el.addEventListener("licensed", onLicensedEvent);
9014
+ el.addEventListener("load-more", onLoadMore);
9015
+ return () => {
9016
+ el.removeEventListener("thread-selected", onThreadSelected);
9017
+ el.removeEventListener("new-thread", onNewThreadEvent);
9018
+ el.removeEventListener("archive", onArchive);
9019
+ el.removeEventListener("unarchive", onUnarchive);
9020
+ el.removeEventListener("delete", onDelete);
9021
+ el.removeEventListener("filter-change", onFilterChange);
9022
+ el.removeEventListener("open-change", onOpenChangeEvent);
9023
+ el.removeEventListener("retry", onRetry);
9024
+ el.removeEventListener("licensed", onLicensedEvent);
9025
+ el.removeEventListener("load-more", onLoadMore);
9026
+ };
9027
+ }, [mounted]);
9028
+ (0, react.useEffect)(() => {
9029
+ const el = elementRef.current;
9030
+ if (!el) return;
9031
+ el.threads = drawerThreads;
9032
+ }, [drawerThreads, mounted]);
9033
+ (0, react.useEffect)(() => {
9034
+ const el = elementRef.current;
9035
+ if (!el) return;
9036
+ el.loading = isLoading || licensePending;
9037
+ el.error = listError ? listError.message : null;
9038
+ el.activeThreadId = activeThreadId;
9039
+ el.licensed = licensed || licensePending;
9040
+ el.hasMore = hasMoreThreads;
9041
+ el.fetchingMore = isFetchingMoreThreads;
9042
+ }, [
9043
+ isLoading,
9044
+ listError,
9045
+ activeThreadId,
9046
+ licensed,
9047
+ licensePending,
9048
+ hasMoreThreads,
9049
+ isFetchingMoreThreads,
9050
+ mounted
9051
+ ]);
9052
+ (0, react.useEffect)(() => {
9053
+ const el = elementRef.current;
9054
+ if (!el) return;
9055
+ el.open = drawerOpen;
9056
+ }, [drawerOpen, mounted]);
9057
+ (0, react.useEffect)(() => {
9058
+ const el = elementRef.current;
9059
+ if (!el) return;
9060
+ if (label !== void 0) el.label = label;
9061
+ }, [label, mounted]);
9062
+ (0, react.useEffect)(() => {
9063
+ const el = elementRef.current;
9064
+ if (!el) return;
9065
+ if (licenseUrl !== void 0) el.licenseUrl = licenseUrl;
9066
+ }, [licenseUrl, mounted]);
9067
+ const rowChildren = (0, react.useMemo)(() => {
9068
+ if (!renderRow) return null;
9069
+ return drawerThreads.map((drawerThread) => {
9070
+ const fullThread = threads.find((t) => t.id === drawerThread.id);
9071
+ if (!fullThread) return null;
9072
+ const content = renderRow(fullThread);
9073
+ if (content === null || content === void 0) return null;
9074
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
9075
+ slot: `row:${drawerThread.id}`,
9076
+ children: content
9077
+ }, drawerThread.id);
9078
+ });
9079
+ }, [
9080
+ renderRow,
9081
+ drawerThreads,
9082
+ threads
9083
+ ]);
9084
+ if (!mounted) return null;
9085
+ return react.default.createElement(_copilotkit_web_components_threads_drawer.COPILOTKIT_THREADS_DRAWER_TAG, {
9086
+ ref: elementRef,
9087
+ "data-testid": dataTestId
9088
+ }, rowChildren);
9089
+ }
9090
+ CopilotThreadsDrawer.displayName = "CopilotThreadsDrawer";
9091
+
8466
9092
  //#endregion
8467
9093
  //#region src/v2/components/WildcardToolCallRender.tsx
8468
9094
  const WildcardToolCallRender = defineToolCallRenderer({
@@ -10038,6 +10664,7 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
10038
10664
  const showInspector = shouldShowDevConsole(props.enableInspector);
10039
10665
  const publicApiKey = props.publicApiKey || props.publicLicenseKey;
10040
10666
  const renderArr = (0, react.useMemo)(() => [{ render: CoAgentStateRenderBridge }], []);
10667
+ const { onError: _onError, ...v2Props } = props;
10041
10668
  return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ToastProvider, {
10042
10669
  enabled,
10043
10670
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(CopilotErrorBoundary, {
@@ -10046,7 +10673,7 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
10046
10673
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ThreadsProvider, {
10047
10674
  threadId: props.threadId,
10048
10675
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(CopilotKitProvider, {
10049
- ...props,
10676
+ ...v2Props,
10050
10677
  showDevConsole: showInspector,
10051
10678
  renderCustomMessages: renderArr,
10052
10679
  useSingleEndpoint: props.useSingleEndpoint ?? true,
@@ -10577,6 +11204,7 @@ Object.defineProperty(exports, 'CopilotSidebarView', {
10577
11204
  return CopilotSidebarView;
10578
11205
  }
10579
11206
  });
11207
+ exports.CopilotThreadsDrawer = CopilotThreadsDrawer;
10580
11208
  exports.INTELLIGENCE_TURN_HEAD = INTELLIGENCE_TURN_HEAD;
10581
11209
  exports.IntelligenceIndicator = IntelligenceIndicator;
10582
11210
  exports.IntelligenceIndicatorView = IntelligenceIndicatorView;