@copilotkit/react-core 1.61.0 → 1.61.2

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-BCxdKlMw.mjs → copilotkit-Be-o2UaU.mjs} +262 -128
  2. package/dist/copilotkit-Be-o2UaU.mjs.map +1 -0
  3. package/dist/{copilotkit-M1FiciGd.d.mts → copilotkit-Bpt1c_-q.d.mts} +79 -71
  4. package/dist/copilotkit-Bpt1c_-q.d.mts.map +1 -0
  5. package/dist/{copilotkit-DtPCrXXd.cjs → copilotkit-CTCjVxkH.cjs} +251 -117
  6. package/dist/copilotkit-CTCjVxkH.cjs.map +1 -0
  7. package/dist/{copilotkit-CEdu_aie.d.cts → copilotkit-ClqbUuGX.d.cts} +79 -71
  8. package/dist/copilotkit-ClqbUuGX.d.cts.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 +188 -96
  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 +219 -102
  24. package/dist/v2/headless.cjs.map +1 -1
  25. package/dist/v2/headless.d.cts +76 -68
  26. package/dist/v2/headless.d.cts.map +1 -1
  27. package/dist/v2/headless.d.mts +76 -68
  28. package/dist/v2/headless.d.mts.map +1 -1
  29. package/dist/v2/headless.mjs +220 -103
  30. package/dist/v2/headless.mjs.map +1 -1
  31. package/dist/v2/index.cjs +1 -1
  32. package/dist/v2/index.d.cts +2 -2
  33. package/dist/v2/index.d.mts +2 -2
  34. package/dist/v2/index.mjs +1 -1
  35. package/dist/v2/index.umd.js +250 -116
  36. package/dist/v2/index.umd.js.map +1 -1
  37. package/package.json +6 -6
  38. package/skills/react-core/references/provider-setup.md +20 -2
  39. package/dist/copilotkit-BCxdKlMw.mjs.map +0 -1
  40. package/dist/copilotkit-CEdu_aie.d.cts.map +0 -1
  41. package/dist/copilotkit-DtPCrXXd.cjs.map +0 -1
  42. package/dist/copilotkit-M1FiciGd.d.mts.map +0 -1
package/dist/v2/index.mjs CHANGED
@@ -1,6 +1,6 @@
1
1
  "use client";
2
2
 
3
- import { $ as useAgent, A as INTELLIGENCE_TURN_HEAD, B as CopilotChatToolCallsView, C as CopilotChatToggleButton, Ct as useCopilotChatConfiguration, D as CopilotChatView_default, E as CopilotChat, F as CopilotChatSuggestionPill, G as useLearnFromUserAction, H as useLearningContainers, I as CopilotChatReasoningMessage_default, J as useConfigureSuggestions, K as useThreads, L as CopilotChatUserMessage_default, M as getIntelligenceTurnAnchors, N as IntelligenceIndicatorView, O as CopilotChatAttachmentQueue, P as CopilotChatSuggestionView, Q as UseAgentUpdate, R as CopilotChatAttachmentRenderer, S as CopilotModalHeader, St as CopilotChatConfigurationProvider, T as DefaultOpenIcon, U as useAttachments, V as useLearningContainersInCurrentThread, W as useLearnFromUserActionInCurrentThread, X as useAgentContext, Y as useSuggestions, Z as useCapabilities, _ as WildcardToolCallRender, _t as useCopilotKit, at as CopilotKitProvider, b as CopilotPopupView, bt as AudioRecorderError, ct as useSandboxFunctions, dt as MCPAppsActivityType, et as useHumanInTheLoop, ft as CopilotKitInspector, gt as defineToolCallRenderer, ht as useRenderTool, it as useRenderCustomMessages, j as IntelligenceIndicator, k as CopilotChatMessageView, lt as MCPAppsActivityContentSchema, mt as useDefaultRenderTool, nt as useFrontendTool, ot as createA2UIMessageRenderer, pt as useRenderToolCall, q as useInterrupt, rt as useRenderActivityMessage, st as SandboxFunctionsContext, t as CopilotKit, tt as useComponent, ut as MCPAppsActivityRenderer, v as CopilotPopup, vt as CopilotKitCoreReact, w as DefaultCloseIcon, x as CopilotSidebarView, xt as CopilotChatAudioRecorder, y as CopilotSidebar, yt as CopilotChatInput_default, z as CopilotChatAssistantMessage_default } from "../copilotkit-BCxdKlMw.mjs";
3
+ import { $ as useAgent, A as INTELLIGENCE_TURN_HEAD, B as CopilotChatToolCallsView, C as CopilotChatToggleButton, Ct as useCopilotChatConfiguration, D as CopilotChatView_default, E as CopilotChat, F as CopilotChatSuggestionPill, G as useLearnFromUserAction, H as useLearningContainers, I as CopilotChatReasoningMessage_default, J as useConfigureSuggestions, K as useThreads, L as CopilotChatUserMessage_default, M as getIntelligenceTurnAnchors, N as IntelligenceIndicatorView, O as CopilotChatAttachmentQueue, P as CopilotChatSuggestionView, Q as UseAgentUpdate, R as CopilotChatAttachmentRenderer, S as CopilotModalHeader, St as CopilotChatConfigurationProvider, T as DefaultOpenIcon, U as useAttachments, V as useLearningContainersInCurrentThread, W as useLearnFromUserActionInCurrentThread, X as useAgentContext, Y as useSuggestions, Z as useCapabilities, _ as WildcardToolCallRender, _t as useCopilotKit, at as CopilotKitProvider, b as CopilotPopupView, bt as AudioRecorderError, ct as useSandboxFunctions, dt as MCPAppsActivityType, et as useHumanInTheLoop, ft as CopilotKitInspector, gt as defineToolCallRenderer, ht as useRenderTool, it as useRenderCustomMessages, j as IntelligenceIndicator, k as CopilotChatMessageView, lt as MCPAppsActivityContentSchema, mt as useDefaultRenderTool, nt as useFrontendTool, ot as createA2UIMessageRenderer, pt as useRenderToolCall, q as useInterrupt, rt as useRenderActivityMessage, st as SandboxFunctionsContext, t as CopilotKit, tt as useComponent, ut as MCPAppsActivityRenderer, v as CopilotPopup, vt as CopilotKitCoreReact, w as DefaultCloseIcon, x as CopilotSidebarView, xt as CopilotChatAudioRecorder, y as CopilotSidebar, yt as CopilotChatInput_default, z as CopilotChatAssistantMessage_default } from "../copilotkit-Be-o2UaU.mjs";
4
4
  import "./index.css";
5
5
  import { defaultTheme as a2uiDefaultTheme } from "@copilotkit/a2ui-renderer";
6
6
 
@@ -1506,10 +1506,20 @@ _radix_ui_react_dropdown_menu = __toESM(_radix_ui_react_dropdown_menu);
1506
1506
  }) : defineToolCallRenderer({
1507
1507
  name: config.name,
1508
1508
  args: config.parameters,
1509
- render: (props) => config.render({
1510
- ...props,
1511
- parameters: props.args
1512
- }),
1509
+ render: (props) => {
1510
+ if (props.status === _copilotkit_core.ToolCallStatus.InProgress) return config.render({
1511
+ ...props,
1512
+ parameters: props.args
1513
+ });
1514
+ if (props.status === _copilotkit_core.ToolCallStatus.Executing) return config.render({
1515
+ ...props,
1516
+ parameters: props.args
1517
+ });
1518
+ return config.render({
1519
+ ...props,
1520
+ parameters: props.args
1521
+ });
1522
+ },
1513
1523
  ...config.agentId ? { agentId: config.agentId } : {}
1514
1524
  });
1515
1525
  copilotkit.addHookRenderToolCall(renderer);
@@ -3547,6 +3557,10 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
3547
3557
 
3548
3558
  //#endregion
3549
3559
  //#region src/v2/providers/CopilotKitProvider.tsx
3560
+ const zodToJsonSchemaAdapter = (schema, options) => {
3561
+ const refStrategy = options?.$refStrategy;
3562
+ return (0, zod_to_json_schema.zodToJsonSchema)(schema, refStrategy === "root" || refStrategy === "relative" || refStrategy === "none" || refStrategy === "seen" ? { $refStrategy: refStrategy } : {});
3563
+ };
3550
3564
  const HEADER_NAME = "X-CopilotCloud-Public-Api-Key";
3551
3565
  const COPILOT_CLOUD_CHAT_URL$1 = "https://api.cloud.copilotkit.ai/copilotkit/v1";
3552
3566
  const EMPTY_HEADERS = Object.freeze({});
@@ -3577,6 +3591,8 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
3577
3591
  const [runtimeA2UIEnabled, setRuntimeA2UIEnabled] = (0, react.useState)(false);
3578
3592
  const [runtimeOpenGenUIEnabled, setRuntimeOpenGenUIEnabled] = (0, react.useState)(false);
3579
3593
  const openGenUIActive = runtimeOpenGenUIEnabled || !!openGenerativeUI;
3594
+ const a2uiCatalogProvided = !!a2ui?.catalog;
3595
+ const a2uiActive = runtimeA2UIEnabled || a2uiCatalogProvided;
3580
3596
  const [runtimeLicenseStatus, setRuntimeLicenseStatus] = (0, react.useState)(void 0);
3581
3597
  (0, react.useEffect)(() => {
3582
3598
  if (typeof window === "undefined") return;
@@ -3607,7 +3623,7 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
3607
3623
  content: OpenGenerativeUIContentSchema,
3608
3624
  render: OpenGenerativeUIActivityRenderer
3609
3625
  });
3610
- if (runtimeA2UIEnabled) renderers.unshift(createA2UIMessageRenderer({
3626
+ if (a2uiActive) renderers.unshift(createA2UIMessageRenderer({
3611
3627
  theme: a2ui?.theme ?? _copilotkit_a2ui_renderer.viewerTheme,
3612
3628
  catalog: a2ui?.catalog,
3613
3629
  loadingComponent: a2ui?.loadingComponent,
@@ -3615,7 +3631,7 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
3615
3631
  }));
3616
3632
  return renderers;
3617
3633
  }, [
3618
- runtimeA2UIEnabled,
3634
+ a2uiActive,
3619
3635
  openGenUIActive,
3620
3636
  a2ui
3621
3637
  ]);
@@ -3802,7 +3818,10 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
3802
3818
  copilotkit.setRuntimeTransport(useSingleEndpoint === true ? "single" : useSingleEndpoint === false ? "rest" : "auto");
3803
3819
  copilotkit.setHeaders(mergedHeaders);
3804
3820
  copilotkit.setCredentials(credentials);
3805
- copilotkit.setProperties(properties);
3821
+ copilotkit.setProperties(a2uiCatalogProvided ? {
3822
+ ...properties,
3823
+ a2uiCatalogAvailable: true
3824
+ } : properties);
3806
3825
  copilotkit.setAgents__unsafe_dev_only(mergedAgents);
3807
3826
  copilotkit.setDebug(debug);
3808
3827
  }, [
@@ -3811,6 +3830,7 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
3811
3830
  mergedHeaders,
3812
3831
  credentials,
3813
3832
  properties,
3833
+ a2uiCatalogProvided,
3814
3834
  mergedAgents,
3815
3835
  useSingleEndpoint,
3816
3836
  debug
@@ -3858,7 +3878,7 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
3858
3878
  return JSON.stringify(sandboxFunctionsList.map((fn) => ({
3859
3879
  name: fn.name,
3860
3880
  description: fn.description,
3861
- parameters: (0, _copilotkit_shared.schemaToJsonSchema)(fn.parameters, { zodToJsonSchema: zod_to_json_schema.zodToJsonSchema })
3881
+ parameters: (0, _copilotkit_shared.schemaToJsonSchema)(fn.parameters, { zodToJsonSchema: zodToJsonSchemaAdapter })
3862
3882
  })));
3863
3883
  }, [sandboxFunctionsList]);
3864
3884
  (0, react.useLayoutEffect)(() => {
@@ -3879,7 +3899,7 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
3879
3899
  copilotkit,
3880
3900
  executingToolCallIds
3881
3901
  }), [copilotkit, executingToolCallIds]);
3882
- const licenseContextValue = (0, react.useMemo)(() => (0, _copilotkit_shared.createLicenseContextValue)(null), []);
3902
+ const licenseContextValue = (0, react.useMemo)(() => (0, _copilotkit_shared.createLicenseContextValue)(runtimeLicenseStatus), [runtimeLicenseStatus]);
3883
3903
  return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(SandboxFunctionsContext.Provider, {
3884
3904
  value: sandboxFunctionsList,
3885
3905
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(CopilotKitContext.Provider, {
@@ -3887,8 +3907,8 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
3887
3907
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(LicenseContext.Provider, {
3888
3908
  value: licenseContextValue,
3889
3909
  children: [
3890
- runtimeA2UIEnabled && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(A2UIBuiltInToolCallRenderer, {}),
3891
- runtimeA2UIEnabled && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(A2UICatalogContext, {
3910
+ a2uiActive && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(A2UIBuiltInToolCallRenderer, {}),
3911
+ a2uiActive && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(A2UICatalogContext, {
3892
3912
  catalog: a2ui?.catalog,
3893
3913
  includeSchema: a2ui?.includeSchema
3894
3914
  }),
@@ -3966,16 +3986,20 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
3966
3986
  const renderActivityMessage = (0, react.useCallback)((message) => {
3967
3987
  const renderer = findRenderer(message.activityType);
3968
3988
  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);
3989
+ const parseResult = renderer.content["~standard"].validate(message.content);
3990
+ if (parseResult instanceof Promise) {
3991
+ console.warn(`Async content validation is not supported for activity message '${message.activityType}'`);
3992
+ return null;
3993
+ }
3994
+ if (parseResult.issues) {
3995
+ console.warn(`Failed to parse content for activity message '${message.activityType}':`, parseResult.issues);
3972
3996
  return null;
3973
3997
  }
3974
3998
  const Component = renderer.render;
3975
3999
  const agent = copilotkit.getAgent(agentId);
3976
4000
  return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Component, {
3977
4001
  activityType: message.activityType,
3978
- content: parseResult.data,
4002
+ content: parseResult.value,
3979
4003
  message,
3980
4004
  agent
3981
4005
  }, message.id);
@@ -4096,15 +4120,34 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
4096
4120
  function useHumanInTheLoop(tool, deps) {
4097
4121
  const { copilotkit } = useCopilotKit();
4098
4122
  const resolvePromiseRef = (0, react.useRef)(null);
4123
+ const cleanupAbortRef = (0, react.useRef)(null);
4099
4124
  const respond = (0, react.useCallback)(async (result) => {
4100
4125
  if (resolvePromiseRef.current) {
4126
+ cleanupAbortRef.current?.();
4127
+ cleanupAbortRef.current = null;
4101
4128
  resolvePromiseRef.current(result);
4102
4129
  resolvePromiseRef.current = null;
4103
4130
  }
4104
4131
  }, []);
4105
- const handler = (0, react.useCallback)(async () => {
4106
- return new Promise((resolve) => {
4132
+ const handler = (0, react.useCallback)(async (_args, context) => {
4133
+ const signal = context?.signal;
4134
+ return new Promise((resolve, reject) => {
4135
+ if (signal?.aborted) {
4136
+ reject(/* @__PURE__ */ new Error("Human-in-the-loop interaction aborted"));
4137
+ return;
4138
+ }
4107
4139
  resolvePromiseRef.current = resolve;
4140
+ if (signal) {
4141
+ const onAbort = () => {
4142
+ cleanupAbortRef.current = null;
4143
+ resolvePromiseRef.current = null;
4144
+ reject(/* @__PURE__ */ new Error("Human-in-the-loop interaction aborted"));
4145
+ };
4146
+ signal.addEventListener("abort", onAbort, { once: true });
4147
+ cleanupAbortRef.current = () => {
4148
+ signal.removeEventListener("abort", onAbort);
4149
+ };
4150
+ }
4108
4151
  });
4109
4152
  }, []);
4110
4153
  const RenderComponent = (0, react.useCallback)((props) => {
@@ -4192,7 +4235,7 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
4192
4235
  if (isRuntimeConfigured && (status === _copilotkit_core.CopilotKitCoreRuntimeConnectionStatus.Disconnected || status === _copilotkit_core.CopilotKitCoreRuntimeConnectionStatus.Connecting)) {
4193
4236
  const cached = provisionalAgentCache.current.get(agentId);
4194
4237
  if (cached) {
4195
- cached.headers = { ...copilotkit.headers };
4238
+ copilotkit.applyHeadersToAgent(cached);
4196
4239
  return cached;
4197
4240
  }
4198
4241
  const provisional = new _copilotkit_core.ProxiedCopilotRuntimeAgent({
@@ -4201,14 +4244,14 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
4201
4244
  transport: copilotkit.runtimeTransport,
4202
4245
  runtimeMode: "pending"
4203
4246
  });
4204
- provisional.headers = { ...copilotkit.headers };
4247
+ copilotkit.applyHeadersToAgent(provisional);
4205
4248
  provisionalAgentCache.current.set(agentId, provisional);
4206
4249
  return provisional;
4207
4250
  }
4208
4251
  if (isRuntimeConfigured && status === _copilotkit_core.CopilotKitCoreRuntimeConnectionStatus.Error) {
4209
4252
  const cached = provisionalAgentCache.current.get(agentId);
4210
4253
  if (cached) {
4211
- cached.headers = { ...copilotkit.headers };
4254
+ copilotkit.applyHeadersToAgent(cached);
4212
4255
  return cached;
4213
4256
  }
4214
4257
  const provisional = new _copilotkit_core.ProxiedCopilotRuntimeAgent({
@@ -4217,7 +4260,7 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
4217
4260
  transport: copilotkit.runtimeTransport,
4218
4261
  runtimeMode: "pending"
4219
4262
  });
4220
- provisional.headers = { ...copilotkit.headers };
4263
+ copilotkit.applyHeadersToAgent(provisional);
4221
4264
  provisionalAgentCache.current.set(agentId, provisional);
4222
4265
  return provisional;
4223
4266
  }
@@ -4268,7 +4311,7 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
4268
4311
  updateFlags
4269
4312
  ]);
4270
4313
  (0, react.useEffect)(() => {
4271
- if (agent instanceof _ag_ui_client.HttpAgent) agent.headers = { ...copilotkit.headers };
4314
+ if (agent instanceof _ag_ui_client.HttpAgent) copilotkit.applyHeadersToAgent(agent);
4272
4315
  }, [agent, JSON.stringify(copilotkit.headers)]);
4273
4316
  const chatConfig = useCopilotChatConfiguration();
4274
4317
  const configThreadId = chatConfig?.threadId;
@@ -4545,114 +4588,165 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
4545
4588
  function isPromiseLike(value) {
4546
4589
  return (typeof value === "object" || typeof value === "function") && value !== null && typeof Reflect.get(value, "then") === "function";
4547
4590
  }
4591
+ /** Derive the legacy-compatible `event` for any pending interrupt. */
4592
+ function toLegacyEvent(pending) {
4593
+ if (pending.kind === "legacy") return pending.event;
4594
+ return {
4595
+ name: INTERRUPT_EVENT_NAME,
4596
+ value: pending.interrupts[0]
4597
+ };
4598
+ }
4548
4599
  /**
4549
- * Handles agent interrupts (`on_interrupt`) with optional filtering, preprocessing, and resume behavior.
4600
+ * Handles agent interrupts with optional filtering, preprocessing, and resume behavior.
4550
4601
  *
4551
- * The hook listens to custom events on the active agent, stores interrupt payloads per run,
4552
- * and surfaces a render callback once the run finalizes. Call `resolve` from your UI to resume
4553
- * execution with user-provided data.
4602
+ * Supports both the AG-UI standard interrupt flow (`RUN_FINISHED` with
4603
+ * `outcome.type === "interrupt"`) and the legacy custom-event flow
4604
+ * (`on_interrupt`). For standard interrupts, `render` receives `interrupt`
4605
+ * (the primary one) and `interrupts` (the full open set); call `resolve(payload)`
4606
+ * to resume or `cancel()` to cancel. Resuming addresses the targeted interrupt
4607
+ * and, once every open interrupt is addressed, submits a single spec `resume`
4608
+ * array via `copilotkit.runAgent`.
4554
4609
  *
4555
- * - `renderInChat: true` (default): the element is published into `<CopilotChat>` and this hook returns `void`.
4556
- * - `renderInChat: false`: the hook returns the interrupt element so you can place it anywhere in your component tree.
4557
- *
4558
- * `event.value` is typed as `any` since the interrupt payload shape depends on your agent.
4559
- * Type-narrow it in your callbacks (e.g. `handler`, `enabled`, `render`) as needed.
4560
- *
4561
- * @typeParam TResult - Inferred from `handler` return type. Exposed as `result` in `render`.
4562
- * @param config - Interrupt configuration (renderer, optional handler/filter, and render mode).
4563
- * @returns When `renderInChat` is `false`, returns the interrupt element (or `null` when idle).
4564
- * Otherwise returns `void` and publishes the element into chat. In `render`, `result` is always
4565
- * either the handler's resolved return value or `null` (including when no handler is provided,
4566
- * when filtering skips the interrupt, or when handler execution fails).
4610
+ * - `renderInChat: true` (default): the element is published into `<CopilotChat>`; returns `void`.
4611
+ * - `renderInChat: false`: the hook returns the interrupt element for manual placement.
4567
4612
  *
4568
4613
  * @example
4569
4614
  * ```tsx
4570
- * import { useInterrupt } from "@copilotkit/react-core/v2";
4571
- *
4572
- * function InterruptUI() {
4573
- * useInterrupt({
4574
- * render: ({ event, resolve }) => (
4575
- * <div>
4576
- * <p>{event.value.question}</p>
4577
- * <button onClick={() => resolve({ approved: true })}>Approve</button>
4578
- * <button onClick={() => resolve({ approved: false })}>Reject</button>
4579
- * </div>
4580
- * ),
4581
- * });
4582
- *
4583
- * return null;
4584
- * }
4585
- * ```
4586
- *
4587
- * @example
4588
- * ```tsx
4589
- * import { useInterrupt } from "@copilotkit/react-core/v2";
4590
- *
4591
- * function CustomPanel() {
4592
- * const interruptElement = useInterrupt({
4593
- * renderInChat: false,
4594
- * enabled: (event) => event.value.startsWith("approval:"),
4595
- * handler: async ({ event }) => ({ label: event.value.toUpperCase() }),
4596
- * render: ({ event, result, resolve }) => (
4597
- * <aside>
4598
- * <strong>{result?.label ?? ""}</strong>
4599
- * <button onClick={() => resolve({ value: event.value })}>Continue</button>
4600
- * </aside>
4601
- * ),
4602
- * });
4603
- *
4604
- * return <>{interruptElement}</>;
4605
- * }
4615
+ * useInterrupt({
4616
+ * render: ({ interrupt, resolve, cancel }) => (
4617
+ * <div>
4618
+ * <p>{interrupt?.message}</p>
4619
+ * <button onClick={() => resolve({ approved: true })}>Approve</button>
4620
+ * <button onClick={() => cancel()}>Cancel</button>
4621
+ * </div>
4622
+ * ),
4623
+ * });
4606
4624
  * ```
4607
4625
  */
4608
4626
  function useInterrupt(config) {
4609
4627
  const { copilotkit } = useCopilotKit();
4610
4628
  const { agent } = useAgent({ agentId: config.agentId });
4611
- const [pendingEvent, setPendingEvent] = (0, react.useState)(null);
4612
- const pendingEventRef = (0, react.useRef)(pendingEvent);
4613
- pendingEventRef.current = pendingEvent;
4629
+ const [pending, setPending] = (0, react.useState)(null);
4630
+ const pendingRef = (0, react.useRef)(pending);
4631
+ pendingRef.current = pending;
4614
4632
  const [handlerResult, setHandlerResult] = (0, react.useState)(null);
4633
+ const responsesRef = (0, react.useRef)({});
4615
4634
  (0, react.useEffect)(() => {
4616
- let localInterrupt = null;
4635
+ let localLegacy = null;
4636
+ let localStandard = null;
4617
4637
  const subscription = agent.subscribe({
4618
4638
  onCustomEvent: ({ event }) => {
4619
- if (event.name === INTERRUPT_EVENT_NAME) localInterrupt = {
4639
+ if (event.name === INTERRUPT_EVENT_NAME) localLegacy = {
4620
4640
  name: event.name,
4621
4641
  value: event.value
4622
4642
  };
4623
4643
  },
4644
+ onRunFinishedEvent: (params) => {
4645
+ if (params.outcome === "interrupt") localStandard = params.interrupts;
4646
+ },
4624
4647
  onRunStartedEvent: () => {
4625
- localInterrupt = null;
4626
- setPendingEvent(null);
4648
+ localLegacy = null;
4649
+ localStandard = null;
4650
+ responsesRef.current = {};
4651
+ setPending(null);
4627
4652
  },
4628
4653
  onRunFinalized: () => {
4629
- if (localInterrupt) {
4630
- setPendingEvent(localInterrupt);
4631
- localInterrupt = null;
4632
- }
4654
+ if (localStandard && localStandard.length > 0) setPending({
4655
+ kind: "standard",
4656
+ interrupts: localStandard
4657
+ });
4658
+ else if (localLegacy) setPending({
4659
+ kind: "legacy",
4660
+ event: localLegacy
4661
+ });
4662
+ localLegacy = null;
4663
+ localStandard = null;
4633
4664
  },
4634
4665
  onRunFailed: () => {
4635
- localInterrupt = null;
4636
- setPendingEvent(null);
4666
+ localLegacy = null;
4667
+ localStandard = null;
4668
+ responsesRef.current = {};
4669
+ setPending(null);
4637
4670
  }
4638
4671
  });
4639
4672
  return () => subscription.unsubscribe();
4640
4673
  }, [agent]);
4641
- const resolve = (0, react.useCallback)(async (response) => {
4674
+ const submitStandardIfComplete = (0, react.useCallback)(async (interrupts) => {
4675
+ if (!interrupts.every((i) => responsesRef.current[i.id])) return;
4676
+ const expired = interrupts.find((i) => (0, _ag_ui_client.isInterruptExpired)(i));
4677
+ if (expired) {
4678
+ console.error(`[CopilotKit] useInterrupt: interrupt ${expired.id} expired at ${expired.expiresAt}; not resuming.`);
4679
+ responsesRef.current = {};
4680
+ setPending(null);
4681
+ return;
4682
+ }
4683
+ const resume = (0, _ag_ui_client.buildResumeArray)(interrupts, responsesRef.current);
4684
+ for (const i of interrupts) {
4685
+ if (!i.toolCallId) continue;
4686
+ const response = responsesRef.current[i.id];
4687
+ const content = response.status === "cancelled" ? { status: "cancelled" } : response.payload ?? { status: "resolved" };
4688
+ agent.addMessage({
4689
+ id: (0, _ag_ui_client.randomUUID)(),
4690
+ role: "tool",
4691
+ toolCallId: i.toolCallId,
4692
+ content: JSON.stringify(content)
4693
+ });
4694
+ }
4695
+ responsesRef.current = {};
4642
4696
  try {
4697
+ return await copilotkit.runAgent({
4698
+ agent,
4699
+ resume
4700
+ });
4701
+ } catch (err) {
4702
+ console.error("[CopilotKit] useInterrupt resolve: runAgent rejected; clearing pending + rethrowing", err);
4703
+ setPending(null);
4704
+ throw err;
4705
+ }
4706
+ }, [agent, copilotkit]);
4707
+ const resolve = (0, react.useCallback)(async (payload, interruptId) => {
4708
+ const current = pendingRef.current;
4709
+ if (!current) return;
4710
+ if (current.kind === "legacy") try {
4643
4711
  return await copilotkit.runAgent({
4644
4712
  agent,
4645
4713
  forwardedProps: { command: {
4646
- resume: response,
4647
- interruptEvent: pendingEventRef.current?.value
4714
+ resume: payload,
4715
+ interruptEvent: current.event.value
4648
4716
  } }
4649
4717
  });
4650
4718
  } catch (err) {
4651
4719
  console.error("[CopilotKit] useInterrupt resolve: runAgent rejected; clearing pending + rethrowing", err);
4652
- setPendingEvent(null);
4720
+ setPending(null);
4653
4721
  throw err;
4654
4722
  }
4655
- }, [agent, copilotkit]);
4723
+ 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.`);
4724
+ const id = interruptId ?? current.interrupts[0]?.id;
4725
+ if (!id) return;
4726
+ responsesRef.current[id] = {
4727
+ status: "resolved",
4728
+ payload
4729
+ };
4730
+ return submitStandardIfComplete(current.interrupts);
4731
+ }, [
4732
+ agent,
4733
+ copilotkit,
4734
+ submitStandardIfComplete
4735
+ ]);
4736
+ const cancel = (0, react.useCallback)(async (interruptId) => {
4737
+ const current = pendingRef.current;
4738
+ if (!current) return;
4739
+ if (current.kind === "legacy") {
4740
+ console.warn("[CopilotKit] useInterrupt: cancel() is not supported for legacy on_interrupt interrupts; dismissing.");
4741
+ setPending(null);
4742
+ return;
4743
+ }
4744
+ 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.`);
4745
+ const id = interruptId ?? current.interrupts[0]?.id;
4746
+ if (!id) return;
4747
+ responsesRef.current[id] = { status: "cancelled" };
4748
+ return submitStandardIfComplete(current.interrupts);
4749
+ }, [submitStandardIfComplete]);
4656
4750
  const renderRef = (0, react.useRef)(config.render);
4657
4751
  renderRef.current = config.render;
4658
4752
  const enabledRef = (0, react.useRef)(config.enabled);
@@ -4661,6 +4755,8 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
4661
4755
  handlerRef.current = config.handler;
4662
4756
  const resolveRef = (0, react.useRef)(resolve);
4663
4757
  resolveRef.current = resolve;
4758
+ const cancelRef = (0, react.useRef)(cancel);
4759
+ cancelRef.current = cancel;
4664
4760
  const isEnabled = (event) => {
4665
4761
  const predicate = enabledRef.current;
4666
4762
  if (!predicate) return true;
@@ -4672,11 +4768,12 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
4672
4768
  }
4673
4769
  };
4674
4770
  (0, react.useEffect)(() => {
4675
- if (!pendingEvent) {
4771
+ if (!pending) {
4676
4772
  setHandlerResult(null);
4677
4773
  return;
4678
4774
  }
4679
- if (!isEnabled(pendingEvent)) {
4775
+ const legacyEvent = toLegacyEvent(pending);
4776
+ if (!isEnabled(legacyEvent)) {
4680
4777
  setHandlerResult(null);
4681
4778
  return;
4682
4779
  }
@@ -4689,8 +4786,11 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
4689
4786
  let maybePromise;
4690
4787
  try {
4691
4788
  maybePromise = handler({
4692
- event: pendingEvent,
4693
- resolve: resolveRef.current
4789
+ event: legacyEvent,
4790
+ interrupt: pending.kind === "standard" ? pending.interrupts[0] : null,
4791
+ interrupts: pending.kind === "standard" ? pending.interrupts : [],
4792
+ resolve: resolveRef.current,
4793
+ cancel: cancelRef.current
4694
4794
  });
4695
4795
  } catch (err) {
4696
4796
  console.error("[CopilotKit] useInterrupt handler threw; result will be null:", err);
@@ -4709,19 +4809,24 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
4709
4809
  return () => {
4710
4810
  cancelled = true;
4711
4811
  };
4712
- }, [pendingEvent]);
4812
+ }, [pending]);
4713
4813
  const element = (0, react.useMemo)(() => {
4714
- if (!pendingEvent) return null;
4715
- if (!isEnabled(pendingEvent)) return null;
4814
+ if (!pending) return null;
4815
+ const legacyEvent = toLegacyEvent(pending);
4816
+ if (!isEnabled(legacyEvent)) return null;
4716
4817
  return renderRef.current({
4717
- event: pendingEvent,
4818
+ event: legacyEvent,
4819
+ interrupt: pending.kind === "standard" ? pending.interrupts[0] : null,
4820
+ interrupts: pending.kind === "standard" ? pending.interrupts : [],
4718
4821
  result: handlerResult,
4719
- resolve
4822
+ resolve,
4823
+ cancel
4720
4824
  });
4721
4825
  }, [
4722
- pendingEvent,
4826
+ pending,
4723
4827
  handlerResult,
4724
- resolve
4828
+ resolve,
4829
+ cancel
4725
4830
  ]);
4726
4831
  (0, react.useEffect)(() => {
4727
4832
  if (config.renderInChat === false) return;
@@ -4757,9 +4862,9 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
4757
4862
  * current without polling — thread creates, renames, archives, and deletes
4758
4863
  * from any client are reflected immediately.
4759
4864
  *
4760
- * Mutation methods (`renameThread`, `archiveThread`, `deleteThread`) return
4761
- * promises that resolve once the platform confirms the operation and reject
4762
- * with an `Error` on failure.
4865
+ * Mutation methods (`renameThread`, `archiveThread`, `unarchiveThread`,
4866
+ * `deleteThread`) return promises that resolve once the platform confirms the
4867
+ * operation and reject with an `Error` on failure.
4763
4868
  *
4764
4869
  * @param input - Agent identifier and optional list controls.
4765
4870
  * @returns Thread list state and stable mutation callbacks.
@@ -4809,21 +4914,32 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
4809
4914
  const headersKey = (0, react.useMemo)(() => {
4810
4915
  return JSON.stringify(Object.entries(copilotkit.headers ?? {}).sort(([left], [right]) => left.localeCompare(right)));
4811
4916
  }, [copilotkit.headers]);
4917
+ const runtimeStatus = copilotkit.runtimeConnectionStatus;
4918
+ const threadListEndpointSupported = copilotkit.threadEndpoints?.list !== false;
4919
+ const threadMutationsSupported = copilotkit.threadEndpoints?.mutations !== false;
4920
+ const threadEndpointsUnavailable = !!copilotkit.runtimeUrl && runtimeStatus === _copilotkit_core.CopilotKitCoreRuntimeConnectionStatus.Connected && !threadListEndpointSupported;
4812
4921
  const runtimeError = (0, react.useMemo)(() => {
4813
4922
  if (copilotkit.runtimeUrl) return null;
4814
4923
  return /* @__PURE__ */ new Error("Runtime URL is not configured");
4815
4924
  }, [copilotkit.runtimeUrl]);
4925
+ const threadEndpointsError = (0, react.useMemo)(() => {
4926
+ if (!threadEndpointsUnavailable) return null;
4927
+ return /* @__PURE__ */ new Error("Thread endpoints are not available on this CopilotKit runtime");
4928
+ }, [threadEndpointsUnavailable]);
4929
+ const threadMutationsError = (0, react.useMemo)(() => {
4930
+ if (threadMutationsSupported) return null;
4931
+ return /* @__PURE__ */ new Error("Thread mutations are not available on this CopilotKit runtime");
4932
+ }, [threadMutationsSupported]);
4816
4933
  const [hasDispatchedContext, setHasDispatchedContext] = (0, react.useState)(false);
4817
- const preConnectLoading = !!copilotkit.runtimeUrl && !hasDispatchedContext;
4818
- const isLoading = runtimeError ? false : preConnectLoading || storeIsLoading;
4819
- const error = runtimeError ?? storeError;
4934
+ const preConnectLoading = !!copilotkit.runtimeUrl && !threadEndpointsUnavailable && !hasDispatchedContext;
4935
+ const isLoading = runtimeError || threadEndpointsError ? false : preConnectLoading || storeIsLoading;
4936
+ const error = runtimeError ?? threadEndpointsError ?? storeError;
4820
4937
  (0, react.useEffect)(() => {
4821
4938
  store.start();
4822
4939
  return () => {
4823
4940
  store.stop();
4824
4941
  };
4825
4942
  }, [store]);
4826
- const runtimeStatus = copilotkit.runtimeConnectionStatus;
4827
4943
  (0, react.useEffect)(() => {
4828
4944
  copilotkit.registerThreadStore(agentId, store);
4829
4945
  return () => {
@@ -4837,9 +4953,15 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
4837
4953
  (0, react.useEffect)(() => {
4838
4954
  if (!copilotkit.runtimeUrl) {
4839
4955
  store.setContext(null);
4956
+ setHasDispatchedContext(false);
4840
4957
  return;
4841
4958
  }
4842
4959
  if (runtimeStatus !== _copilotkit_core.CopilotKitCoreRuntimeConnectionStatus.Connected) return;
4960
+ if (!threadListEndpointSupported) {
4961
+ store.setContext(null);
4962
+ setHasDispatchedContext(false);
4963
+ return;
4964
+ }
4843
4965
  const context = {
4844
4966
  runtimeUrl: copilotkit.runtimeUrl,
4845
4967
  headers: { ...copilotkit.headers },
@@ -4856,13 +4978,21 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
4856
4978
  runtimeStatus,
4857
4979
  headersKey,
4858
4980
  copilotkit.intelligence?.wsUrl,
4981
+ threadListEndpointSupported,
4859
4982
  agentId,
4860
4983
  includeArchived,
4861
4984
  limit
4862
4985
  ]);
4863
- const renameThread = (0, react.useCallback)((threadId, name) => store.renameThread(threadId, name), [store]);
4864
- const archiveThread = (0, react.useCallback)((threadId) => store.archiveThread(threadId), [store]);
4865
- const deleteThread = (0, react.useCallback)((threadId) => store.deleteThread(threadId), [store]);
4986
+ const guardMutation = (0, react.useCallback)((mutation) => {
4987
+ return (...args) => {
4988
+ if (threadMutationsError) return Promise.reject(threadMutationsError);
4989
+ return mutation(...args);
4990
+ };
4991
+ }, [threadMutationsError]);
4992
+ const renameThread = (0, react.useMemo)(() => guardMutation((threadId, name) => store.renameThread(threadId, name)), [store, guardMutation]);
4993
+ const archiveThread = (0, react.useMemo)(() => guardMutation((threadId) => store.archiveThread(threadId)), [store, guardMutation]);
4994
+ const unarchiveThread = (0, react.useMemo)(() => guardMutation((threadId) => store.unarchiveThread(threadId)), [store, guardMutation]);
4995
+ const deleteThread = (0, react.useMemo)(() => guardMutation((threadId) => store.deleteThread(threadId)), [store, guardMutation]);
4866
4996
  return {
4867
4997
  threads,
4868
4998
  isLoading,
@@ -4872,6 +5002,7 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
4872
5002
  fetchMoreThreads: (0, react.useCallback)(() => store.fetchNextPage(), [store]),
4873
5003
  renameThread,
4874
5004
  archiveThread,
5005
+ unarchiveThread,
4875
5006
  deleteThread
4876
5007
  };
4877
5008
  }
@@ -7669,8 +7800,10 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
7669
7800
  hasExplicitThreadId
7670
7801
  ]);
7671
7802
  const waitForActiveRunToSettle = (0, react.useCallback)(async () => {
7672
- if (agent.isRunning && (0, _copilotkit_core.isRunCompletionAware)(agent) && agent.activeRunCompletionPromise) try {
7673
- await agent.activeRunCompletionPromise;
7803
+ const maybeAware = agent;
7804
+ const activeRunCompletionPromise = (0, _copilotkit_core.isRunCompletionAware)(maybeAware) ? maybeAware.activeRunCompletionPromise : void 0;
7805
+ if (agent.isRunning && activeRunCompletionPromise) try {
7806
+ await activeRunCompletionPromise;
7674
7807
  } catch (error) {
7675
7808
  console.error("CopilotChat: in-flight run rejected while queuing send", error);
7676
7809
  }
@@ -9995,6 +10128,7 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
9995
10128
  const showInspector = shouldShowDevConsole(props.enableInspector);
9996
10129
  const publicApiKey = props.publicApiKey || props.publicLicenseKey;
9997
10130
  const renderArr = (0, react.useMemo)(() => [{ render: CoAgentStateRenderBridge }], []);
10131
+ const { onError: _onError, ...v2Props } = props;
9998
10132
  return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ToastProvider, {
9999
10133
  enabled,
10000
10134
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(CopilotErrorBoundary, {
@@ -10003,7 +10137,7 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
10003
10137
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ThreadsProvider, {
10004
10138
  threadId: props.threadId,
10005
10139
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(CopilotKitProvider, {
10006
- ...props,
10140
+ ...v2Props,
10007
10141
  showDevConsole: showInspector,
10008
10142
  renderCustomMessages: renderArr,
10009
10143
  useSingleEndpoint: props.useSingleEndpoint ?? true,