@copilotkit/react-core 1.55.3 → 1.56.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (53) hide show
  1. package/dist/{copilotkit-dwDWYpya.d.cts → copilotkit-BtP7w7cT.d.cts} +56 -10
  2. package/dist/copilotkit-BtP7w7cT.d.cts.map +1 -0
  3. package/dist/{copilotkit-BuhSUZHb.d.mts → copilotkit-CCbxm6JM.d.mts} +56 -10
  4. package/dist/copilotkit-CCbxm6JM.d.mts.map +1 -0
  5. package/dist/{copilotkit-Dgdpbqjt.cjs → copilotkit-CSJw5BG8.cjs} +129 -58
  6. package/dist/copilotkit-CSJw5BG8.cjs.map +1 -0
  7. package/dist/{copilotkit-Cd-NrDyp.mjs → copilotkit-Cj2ZIxVr.mjs} +125 -60
  8. package/dist/copilotkit-Cj2ZIxVr.mjs.map +1 -0
  9. package/dist/index.cjs +1 -1
  10. package/dist/index.d.cts +1 -1
  11. package/dist/index.d.mts +1 -1
  12. package/dist/index.mjs +1 -1
  13. package/dist/index.umd.js +55 -23
  14. package/dist/index.umd.js.map +1 -1
  15. package/dist/v2/index.cjs +2 -1
  16. package/dist/v2/index.d.cts +2 -2
  17. package/dist/v2/index.d.mts +2 -2
  18. package/dist/v2/index.mjs +2 -2
  19. package/dist/v2/index.umd.js +124 -59
  20. package/dist/v2/index.umd.js.map +1 -1
  21. package/package.json +6 -6
  22. package/src/components/CopilotListeners.tsx +15 -4
  23. package/src/components/__tests__/CopilotListeners.test.tsx +38 -0
  24. package/src/components/copilot-provider/__tests__/error-visibility-prod.test.tsx +70 -0
  25. package/src/components/copilot-provider/copilot-messages.tsx +39 -24
  26. package/src/components/copilot-provider/copilotkit-props.tsx +26 -6
  27. package/src/components/copilot-provider/copilotkit.tsx +4 -1
  28. package/src/v2/components/chat/CopilotChatAssistantMessage.tsx +22 -19
  29. package/src/v2/components/chat/CopilotChatInput.tsx +21 -2
  30. package/src/v2/components/chat/CopilotChatReasoningMessage.tsx +17 -4
  31. package/src/v2/components/chat/CopilotChatUserMessage.tsx +13 -10
  32. package/src/v2/components/chat/__tests__/CopilotChat.e2e.test.tsx +131 -5
  33. package/src/v2/components/chat/__tests__/CopilotChatAssistantMessage.test.tsx +1 -1
  34. package/src/v2/components/chat/__tests__/CopilotChatAssistantMessage.thumbs.test.tsx +72 -0
  35. package/src/v2/components/chat/__tests__/CopilotChatCopyButton.clipboard.test.tsx +241 -0
  36. package/src/v2/components/chat/__tests__/CopilotChatInput.test.tsx +38 -0
  37. package/src/v2/components/ui/button.tsx +12 -11
  38. package/src/v2/hooks/__tests__/use-agent-throttle.test.tsx +10 -10
  39. package/src/v2/hooks/__tests__/use-capabilities.test.tsx +76 -0
  40. package/src/v2/hooks/__tests__/use-render-custom-messages.test.tsx +55 -0
  41. package/src/v2/hooks/index.ts +1 -0
  42. package/src/v2/hooks/use-agent.tsx +23 -4
  43. package/src/v2/hooks/use-capabilities.tsx +25 -0
  44. package/src/v2/hooks/use-render-custom-messages.tsx +1 -1
  45. package/src/v2/hooks/use-render-tool-call.tsx +3 -0
  46. package/src/v2/hooks/use-render-tool.tsx +3 -0
  47. package/src/v2/providers/CopilotKitProvider.tsx +15 -2
  48. package/src/v2/types/defineToolCallRenderer.ts +3 -0
  49. package/src/v2/types/react-tool-call-renderer.ts +3 -0
  50. package/dist/copilotkit-BuhSUZHb.d.mts.map +0 -1
  51. package/dist/copilotkit-Cd-NrDyp.mjs.map +0 -1
  52. package/dist/copilotkit-Dgdpbqjt.cjs.map +0 -1
  53. package/dist/copilotkit-dwDWYpya.d.cts.map +0 -1
@@ -299,8 +299,9 @@ const buttonVariants = (0, class_variance_authority.cva)("cpk:inline-flex cpk:it
299
299
  size: "default"
300
300
  }
301
301
  });
302
- function Button({ className, variant, size, asChild = false, ...props }) {
302
+ const Button = react.forwardRef(function Button({ className, variant, size, asChild = false, ...props }, ref) {
303
303
  return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(asChild ? _radix_ui_react_slot.Slot : "button", {
304
+ ref,
304
305
  "data-slot": "button",
305
306
  className: cn(buttonVariants({
306
307
  variant,
@@ -309,7 +310,7 @@ function Button({ className, variant, size, asChild = false, ...props }) {
309
310
  })),
310
311
  ...props
311
312
  });
312
- }
313
+ });
313
314
 
314
315
  //#endregion
315
316
  //#region src/v2/components/ui/tooltip.tsx
@@ -751,6 +752,7 @@ function CopilotChatInput({ mode = "input", onSubmitMessage, onStop, isRunning =
751
752
  });
752
753
  }, [clearInputValue]);
753
754
  const handleKeyDown = (e) => {
755
+ if (e.nativeEvent.isComposing || e.keyCode === 229) return;
754
756
  if (commandQuery !== null && mode === "input") {
755
757
  if (e.key === "ArrowDown") {
756
758
  if (filteredCommands.length > 0) {
@@ -798,10 +800,8 @@ function CopilotChatInput({ mode = "input", onSubmitMessage, onStop, isRunning =
798
800
  const trimmed = resolvedValue.trim();
799
801
  if (!trimmed) return;
800
802
  onSubmitMessage(trimmed);
801
- if (!isControlled) {
802
- setInternalValue("");
803
- onChange?.("");
804
- }
803
+ if (!isControlled) setInternalValue("");
804
+ onChange?.("");
805
805
  if (inputRef.current) inputRef.current.focus();
806
806
  };
807
807
  const BoundTextArea = renderSlot(textArea, CopilotChatInput.TextArea, {
@@ -809,6 +809,12 @@ function CopilotChatInput({ mode = "input", onSubmitMessage, onStop, isRunning =
809
809
  value: resolvedValue,
810
810
  onChange: handleChange,
811
811
  onKeyDown: handleKeyDown,
812
+ onCompositionStart: () => {
813
+ isComposingRef.current = true;
814
+ },
815
+ onCompositionEnd: () => {
816
+ isComposingRef.current = false;
817
+ },
812
818
  autoFocus,
813
819
  className: (0, tailwind_merge.twMerge)("cpk:w-full cpk:py-3", isExpanded ? "cpk:px-5" : "cpk:pr-5")
814
820
  });
@@ -883,9 +889,10 @@ function CopilotChatInput({ mode = "input", onSubmitMessage, onStop, isRunning =
883
889
  const target = e.target;
884
890
  if (target.tagName !== "BUTTON" && !target.closest("button") && inputRef.current && mode === "input") inputRef.current.focus();
885
891
  };
892
+ const isComposingRef = (0, react.useRef)(false);
886
893
  const ensureMeasurements = (0, react.useCallback)(() => {
887
894
  const textarea = inputRef.current;
888
- if (!textarea) return;
895
+ if (!textarea || isComposingRef.current) return;
889
896
  const previousValue = textarea.value;
890
897
  const previousHeight = textarea.style.height;
891
898
  textarea.style.height = "auto";
@@ -3072,7 +3079,7 @@ function useStableArrayProp(prop, warningMessage, isMeaningfulChange) {
3072
3079
  }, [value, warningMessage]);
3073
3080
  return value;
3074
3081
  }
3075
- const CopilotKitProvider = ({ children, runtimeUrl, headers = {}, credentials, publicApiKey, publicLicenseKey, licenseToken, properties = {}, agents__unsafe_dev_only: agents = {}, selfManagedAgents = {}, renderToolCalls, renderActivityMessages, renderCustomMessages, frontendTools, humanInTheLoop, openGenerativeUI, showDevConsole = false, useSingleEndpoint, onError, a2ui, defaultThrottleMs, inspectorDefaultAnchor }) => {
3082
+ const CopilotKitProvider = ({ children, runtimeUrl, headers: headersProp = {}, credentials, publicApiKey, publicLicenseKey, licenseToken, properties = {}, agents__unsafe_dev_only: agents = {}, selfManagedAgents = {}, renderToolCalls, renderActivityMessages, renderCustomMessages, frontendTools, humanInTheLoop, openGenerativeUI, showDevConsole = false, useSingleEndpoint, onError, a2ui, defaultThrottleMs, inspectorDefaultAnchor, debug }) => {
3076
3083
  const [shouldRenderInspector, setShouldRenderInspector] = (0, react.useState)(false);
3077
3084
  const [runtimeA2UIEnabled, setRuntimeA2UIEnabled] = (0, react.useState)(false);
3078
3085
  const [runtimeOpenGenUIEnabled, setRuntimeOpenGenUIEnabled] = (0, react.useState)(false);
@@ -3127,6 +3134,7 @@ const CopilotKitProvider = ({ children, runtimeUrl, headers = {}, credentials, p
3127
3134
  ...selfManagedAgents
3128
3135
  }), [agents, selfManagedAgents]);
3129
3136
  const hasLocalAgents = mergedAgents && Object.keys(mergedAgents).length > 0;
3137
+ const headers = typeof headersProp === "function" ? headersProp() : headersProp;
3130
3138
  const mergedHeaders = (0, react.useMemo)(() => {
3131
3139
  if (!resolvedPublicKey) return headers;
3132
3140
  if (headers[HEADER_NAME]) return headers;
@@ -3228,7 +3236,8 @@ const CopilotKitProvider = ({ children, runtimeUrl, headers = {}, credentials, p
3228
3236
  tools: allTools,
3229
3237
  renderToolCalls: allRenderToolCalls,
3230
3238
  renderActivityMessages: allActivityRenderers,
3231
- renderCustomMessages: renderCustomMessagesList
3239
+ renderCustomMessages: renderCustomMessagesList,
3240
+ debug
3232
3241
  });
3233
3242
  if (defaultThrottleMs !== void 0) copilotkitRef.current.setDefaultThrottleMs(defaultThrottleMs);
3234
3243
  }
@@ -3301,6 +3310,7 @@ const CopilotKitProvider = ({ children, runtimeUrl, headers = {}, credentials, p
3301
3310
  copilotkit.setCredentials(credentials);
3302
3311
  copilotkit.setProperties(properties);
3303
3312
  copilotkit.setAgents__unsafe_dev_only(mergedAgents);
3313
+ copilotkit.setDebug(debug);
3304
3314
  }, [
3305
3315
  copilotkit,
3306
3316
  chatApiEndpoint,
@@ -3308,7 +3318,8 @@ const CopilotKitProvider = ({ children, runtimeUrl, headers = {}, credentials, p
3308
3318
  credentials,
3309
3319
  properties,
3310
3320
  mergedAgents,
3311
- useSingleEndpoint
3321
+ useSingleEndpoint,
3322
+ debug
3312
3323
  ]);
3313
3324
  const didMountRef = (0, react.useRef)(false);
3314
3325
  (0, react.useEffect)(() => {
@@ -3429,18 +3440,21 @@ const ToolCallRenderer = react.default.memo(function ToolCallRenderer({ toolCall
3429
3440
  const toolName = toolCall.function.name;
3430
3441
  if (toolMessage) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(RenderComponent, {
3431
3442
  name: toolName,
3443
+ toolCallId: toolCall.id,
3432
3444
  args,
3433
3445
  status: _copilotkit_core.ToolCallStatus.Complete,
3434
3446
  result: toolMessage.content
3435
3447
  });
3436
3448
  else if (isExecuting) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(RenderComponent, {
3437
3449
  name: toolName,
3450
+ toolCallId: toolCall.id,
3438
3451
  args,
3439
3452
  status: _copilotkit_core.ToolCallStatus.Executing,
3440
3453
  result: void 0
3441
3454
  });
3442
3455
  else return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(RenderComponent, {
3443
3456
  name: toolName,
3457
+ toolCallId: toolCall.id,
3444
3458
  args,
3445
3459
  status: _copilotkit_core.ToolCallStatus.InProgress,
3446
3460
  result: void 0
@@ -3619,6 +3633,17 @@ function useAgent({ agentId, threadId, updates, throttleMs } = {}) {
3619
3633
  const handlers = {};
3620
3634
  let timerId = null;
3621
3635
  let active = true;
3636
+ let batchScheduled = false;
3637
+ const batchedForceUpdate = () => {
3638
+ if (!active) return;
3639
+ if (!batchScheduled) {
3640
+ batchScheduled = true;
3641
+ queueMicrotask(() => {
3642
+ batchScheduled = false;
3643
+ if (active) forceUpdate();
3644
+ });
3645
+ }
3646
+ };
3622
3647
  if (updateFlags.includes(UseAgentUpdate.OnMessagesChanged)) {
3623
3648
  const ms = effectiveThrottleMs;
3624
3649
  if (ms > 0) {
@@ -3643,11 +3668,11 @@ function useAgent({ agentId, threadId, updates, throttleMs } = {}) {
3643
3668
  handlers.onMessagesChanged = throttledNotify;
3644
3669
  } else handlers.onMessagesChanged = forceUpdate;
3645
3670
  }
3646
- if (updateFlags.includes(UseAgentUpdate.OnStateChanged)) handlers.onStateChanged = forceUpdate;
3671
+ if (updateFlags.includes(UseAgentUpdate.OnStateChanged)) handlers.onStateChanged = batchedForceUpdate;
3647
3672
  if (updateFlags.includes(UseAgentUpdate.OnRunStatusChanged)) {
3648
- handlers.onRunInitialized = forceUpdate;
3649
- handlers.onRunFinalized = forceUpdate;
3650
- handlers.onRunFailed = forceUpdate;
3673
+ handlers.onRunInitialized = batchedForceUpdate;
3674
+ handlers.onRunFinalized = batchedForceUpdate;
3675
+ handlers.onRunFailed = batchedForceUpdate;
3651
3676
  }
3652
3677
  const subscription = agent.subscribe(handlers);
3653
3678
  return () => {
@@ -3686,7 +3711,7 @@ function useRenderCustomMessages() {
3686
3711
  const runId = resolvedRunId ?? `missing-run-id:${message.id}`;
3687
3712
  const registryAgent = copilotkit.getAgent(agentId);
3688
3713
  const agent = getThreadClone(registryAgent, threadId) ?? registryAgent;
3689
- if (!agent) throw new Error("Agent not found");
3714
+ if (!agent) return null;
3690
3715
  const messagesIdsInRun = resolvedRunId ? agent.messages.filter((msg) => copilotkit.getRunIdForMessage(agentId, threadId, msg.id) === resolvedRunId).map((msg) => msg.id) : [message.id];
3691
3716
  const rawMessageIndex = agent.messages.findIndex((msg) => msg.id === message.id);
3692
3717
  const messageIndex = rawMessageIndex >= 0 ? rawMessageIndex : 0;
@@ -4184,6 +4209,24 @@ function useHumanInTheLoop(tool, deps) {
4184
4209
  ]);
4185
4210
  }
4186
4211
 
4212
+ //#endregion
4213
+ //#region src/v2/hooks/use-capabilities.tsx
4214
+ /**
4215
+ * Returns the capabilities declared by the given agent (or the default agent).
4216
+ * Capabilities are populated from the runtime `/info` response at connection
4217
+ * time. The hook reads them synchronously from the agent instance — there is
4218
+ * no separate loading state, but the value will be `undefined` until the
4219
+ * runtime handshake completes.
4220
+ *
4221
+ * @param agentId - Optional agent ID. If omitted, uses the default agent.
4222
+ * @returns The agent's capabilities, or `undefined` if the agent doesn't
4223
+ * declare capabilities.
4224
+ */
4225
+ function useCapabilities(agentId) {
4226
+ const { agent } = useAgent({ agentId });
4227
+ if (agent && "capabilities" in agent) return agent.capabilities;
4228
+ }
4229
+
4187
4230
  //#endregion
4188
4231
  //#region src/v2/hooks/use-suggestions.tsx
4189
4232
  function useSuggestions({ agentId } = {}) {
@@ -4835,16 +4878,13 @@ function CopilotChatAssistantMessage({ message, messages, isRunning, onThumbsUp,
4835
4878
  useKatexStyles();
4836
4879
  const boundMarkdownRenderer = renderSlot(markdownRenderer, CopilotChatAssistantMessage.MarkdownRenderer, { content: message.content || "" });
4837
4880
  const boundCopyButton = renderSlot(copyButton, CopilotChatAssistantMessage.CopyButton, { onClick: async () => {
4838
- if (message.content) try {
4839
- await navigator.clipboard.writeText(message.content);
4840
- } catch (err) {
4841
- console.error("Failed to copy message:", err);
4842
- }
4881
+ if (message.content) return await (0, _copilotkit_shared.copyToClipboard)(message.content);
4882
+ return false;
4843
4883
  } });
4844
- const boundThumbsUpButton = renderSlot(thumbsUpButton, CopilotChatAssistantMessage.ThumbsUpButton, { onClick: onThumbsUp });
4845
- const boundThumbsDownButton = renderSlot(thumbsDownButton, CopilotChatAssistantMessage.ThumbsDownButton, { onClick: onThumbsDown });
4846
- const boundReadAloudButton = renderSlot(readAloudButton, CopilotChatAssistantMessage.ReadAloudButton, { onClick: onReadAloud });
4847
- const boundRegenerateButton = renderSlot(regenerateButton, CopilotChatAssistantMessage.RegenerateButton, { onClick: onRegenerate });
4884
+ const boundThumbsUpButton = renderSlot(thumbsUpButton, CopilotChatAssistantMessage.ThumbsUpButton, { onClick: onThumbsUp ? () => onThumbsUp(message) : void 0 });
4885
+ const boundThumbsDownButton = renderSlot(thumbsDownButton, CopilotChatAssistantMessage.ThumbsDownButton, { onClick: onThumbsDown ? () => onThumbsDown(message) : void 0 });
4886
+ const boundReadAloudButton = renderSlot(readAloudButton, CopilotChatAssistantMessage.ReadAloudButton, { onClick: onReadAloud ? () => onReadAloud(message) : void 0 });
4887
+ const boundRegenerateButton = renderSlot(regenerateButton, CopilotChatAssistantMessage.RegenerateButton, { onClick: onRegenerate ? () => onRegenerate(message) : void 0 });
4848
4888
  const boundToolbar = renderSlot(toolbar, CopilotChatAssistantMessage.Toolbar, { children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
4849
4889
  className: "cpk:flex cpk:items-center cpk:gap-1",
4850
4890
  children: [
@@ -4937,14 +4977,17 @@ function CopilotChatAssistantMessage({ message, messages, isRunning, onThumbsUp,
4937
4977
  if (timerRef.current !== null) clearTimeout(timerRef.current);
4938
4978
  };
4939
4979
  }, []);
4940
- const handleClick = (event) => {
4941
- setCopied(true);
4942
- if (timerRef.current !== null) clearTimeout(timerRef.current);
4943
- timerRef.current = setTimeout(() => {
4944
- timerRef.current = null;
4945
- setCopied(false);
4946
- }, 2e3);
4947
- if (onClick) onClick(event);
4980
+ const handleClick = async (event) => {
4981
+ let success = false;
4982
+ if (onClick) success = await Promise.resolve(onClick(event)) === true;
4983
+ if (success) {
4984
+ setCopied(true);
4985
+ if (timerRef.current !== null) clearTimeout(timerRef.current);
4986
+ timerRef.current = setTimeout(() => {
4987
+ timerRef.current = null;
4988
+ setCopied(false);
4989
+ }, 2e3);
4990
+ }
4948
4991
  };
4949
4992
  return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ToolbarButton, {
4950
4993
  "data-testid": "copilot-copy-button",
@@ -5097,11 +5140,8 @@ function CopilotChatUserMessage({ message, onEditMessage, branchIndex, numberOfB
5097
5140
  const mediaParts = (0, react.useMemo)(() => getMediaParts(message.content), [message.content]);
5098
5141
  const BoundMessageRenderer = renderSlot(messageRenderer, CopilotChatUserMessage.MessageRenderer, { content: flattenedContent });
5099
5142
  const BoundCopyButton = renderSlot(copyButton, CopilotChatUserMessage.CopyButton, { onClick: async () => {
5100
- if (flattenedContent) try {
5101
- await navigator.clipboard.writeText(flattenedContent);
5102
- } catch (err) {
5103
- console.error("Failed to copy message:", err);
5104
- }
5143
+ if (flattenedContent) return await (0, _copilotkit_shared.copyToClipboard)(flattenedContent);
5144
+ return false;
5105
5145
  } });
5106
5146
  const BoundEditButton = renderSlot(editButton, CopilotChatUserMessage.EditButton, { onClick: () => onEditMessage?.({ message }) });
5107
5147
  const BoundBranchNavigation = renderSlot(branchNavigation, CopilotChatUserMessage.BranchNavigation, {
@@ -5189,10 +5229,13 @@ function CopilotChatUserMessage({ message, onEditMessage, branchIndex, numberOfB
5189
5229
  _CopilotChatUserMessage.CopyButton = ({ className, title, onClick, ...props }) => {
5190
5230
  const labels = useCopilotChatConfiguration()?.labels ?? CopilotChatDefaultLabels;
5191
5231
  const [copied, setCopied] = (0, react.useState)(false);
5192
- const handleClick = (event) => {
5193
- setCopied(true);
5194
- setTimeout(() => setCopied(false), 2e3);
5195
- if (onClick) onClick(event);
5232
+ const handleClick = async (event) => {
5233
+ let success = false;
5234
+ if (onClick) success = await Promise.resolve(onClick(event)) === true;
5235
+ if (success) {
5236
+ setCopied(true);
5237
+ setTimeout(() => setCopied(false), 2e3);
5238
+ }
5196
5239
  };
5197
5240
  return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ToolbarButton, {
5198
5241
  "data-testid": "copilot-user-copy-button",
@@ -5299,17 +5342,24 @@ function CopilotChatReasoningMessage({ message, messages, isRunning, header, con
5299
5342
  return () => clearInterval(timer);
5300
5343
  }, [isStreaming]);
5301
5344
  const [isOpen, setIsOpen] = (0, react.useState)(isStreaming);
5345
+ const userToggledRef = (0, react.useRef)(false);
5302
5346
  (0, react.useEffect)(() => {
5303
- if (isStreaming) setIsOpen(true);
5304
- else setIsOpen(false);
5347
+ if (isStreaming) {
5348
+ userToggledRef.current = false;
5349
+ setIsOpen(true);
5350
+ } else if (!userToggledRef.current) setIsOpen(false);
5305
5351
  }, [isStreaming]);
5352
+ const handleToggle = hasContent ? () => {
5353
+ userToggledRef.current = true;
5354
+ setIsOpen((prev) => !prev);
5355
+ } : void 0;
5306
5356
  const label = isStreaming ? "Thinking…" : `Thought for ${formatDuration(elapsed)}`;
5307
5357
  const boundHeader = renderSlot(header, CopilotChatReasoningMessage.Header, {
5308
5358
  isOpen,
5309
5359
  label,
5310
5360
  hasContent,
5311
5361
  isStreaming,
5312
- onClick: hasContent ? () => setIsOpen((prev) => !prev) : void 0
5362
+ onClick: handleToggle
5313
5363
  });
5314
5364
  const boundContent = renderSlot(contentView, CopilotChatReasoningMessage.Content, {
5315
5365
  isStreaming,
@@ -8013,6 +8063,20 @@ function shouldShowDevConsole(showDevConsole) {
8013
8063
  /**
8014
8064
  * An internal context to separate the messages state (which is constantly changing) from the rest of CopilotKit context
8015
8065
  */
8066
+ /**
8067
+ * Determine whether a GraphQL error should be suppressed based on its visibility
8068
+ * and whether the dev console is active.
8069
+ *
8070
+ * Returns `null` when the error should be surfaced to the UI, or a log prefix
8071
+ * string when the error should be suppressed (logged to console only).
8072
+ *
8073
+ * Exported for unit testing.
8074
+ */
8075
+ function getErrorSuppression(visibility, isDev) {
8076
+ if (visibility === _copilotkit_shared.ErrorVisibility.SILENT) return "CopilotKit Silent Error:";
8077
+ if (!isDev && visibility === _copilotkit_shared.ErrorVisibility.DEV_ONLY) return "CopilotKit Error (hidden in production):";
8078
+ return null;
8079
+ }
8016
8080
  const MessagesTapContext = (0, react.createContext)(null);
8017
8081
  function useMessagesTap() {
8018
8082
  const tap = (0, react.useContext)(MessagesTapContext);
@@ -8096,12 +8160,9 @@ function CopilotMessages({ children }) {
8096
8160
  const graphQLErrors = error.graphQLErrors;
8097
8161
  const routeError = (gqlError) => {
8098
8162
  const visibility = gqlError.extensions?.visibility;
8099
- if (!shouldShowDevConsole(showDevConsole)) {
8100
- console.error("CopilotKit Error (hidden in production):", gqlError.message);
8101
- return;
8102
- }
8103
- if (visibility === _copilotkit_shared.ErrorVisibility.SILENT) {
8104
- console.error("CopilotKit Silent Error:", gqlError.message);
8163
+ const suppression = getErrorSuppression(visibility, shouldShowDevConsole(showDevConsole));
8164
+ if (suppression) {
8165
+ console.error(suppression, gqlError.message);
8105
8166
  return;
8106
8167
  }
8107
8168
  const ckError = createStructuredError(gqlError);
@@ -8118,8 +8179,7 @@ function CopilotMessages({ children }) {
8118
8179
  }
8119
8180
  };
8120
8181
  graphQLErrors.forEach(routeError);
8121
- } else if (!shouldShowDevConsole(showDevConsole)) console.error("CopilotKit Error (hidden in production):", error);
8122
- else {
8182
+ } else {
8123
8183
  const fallbackError = new _copilotkit_shared.CopilotKitError({
8124
8184
  message: error?.message || String(error),
8125
8185
  code: _copilotkit_shared.CopilotKitErrorCode.UNKNOWN
@@ -8993,12 +9053,17 @@ const usePredictStateSubscription = (agent) => {
8993
9053
  };
8994
9054
  }, [agent, getSubscriber]);
8995
9055
  };
8996
- function CopilotListeners() {
8997
- const { copilotkit } = useCopilotKit();
9056
+ function CopilotListenersAgentSubscription() {
8998
9057
  const resolvedAgentId = useCopilotChatConfiguration()?.agentId;
8999
- const { setBannerError } = useToast();
9000
9058
  const { agent } = useAgent({ agentId: resolvedAgentId });
9001
9059
  usePredictStateSubscription(agent);
9060
+ return null;
9061
+ }
9062
+ function CopilotListeners() {
9063
+ const { copilotkit } = useCopilotKit();
9064
+ const { setBannerError } = useToast();
9065
+ const hasAgents = Object.keys(copilotkit.agents ?? {}).length > 0;
9066
+ const hasRuntime = copilotkit.runtimeUrl !== void 0;
9002
9067
  (0, react.useEffect)(() => {
9003
9068
  const subscription = copilotkit.subscribe({ onError: ({ error, code, context }) => {
9004
9069
  if (error.name === "AbortError" || error.message === "Fetch is aborted" || error.message === "signal is aborted without reason" || error.message === "component unmounted" || !error.message) return;
@@ -9020,7 +9085,7 @@ function CopilotListeners() {
9020
9085
  subscription.unsubscribe();
9021
9086
  };
9022
9087
  }, [copilotkit?.subscribe]);
9023
- return null;
9088
+ return hasAgents || hasRuntime ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(CopilotListenersAgentSubscription, {}) : null;
9024
9089
  }
9025
9090
 
9026
9091
  //#endregion
@@ -9186,7 +9251,7 @@ function CopilotKitInternal(cpkProps) {
9186
9251
  publicApiKey,
9187
9252
  ...cloud ? { cloud } : {},
9188
9253
  chatApiEndpoint,
9189
- headers: props.headers || {},
9254
+ headers: typeof props.headers === "function" ? props.headers() : props.headers || {},
9190
9255
  properties: props.properties || {},
9191
9256
  transcribeAudioUrl: props.transcribeAudioUrl,
9192
9257
  textToSpeechUrl: props.textToSpeechUrl,
@@ -9826,6 +9891,12 @@ Object.defineProperty(exports, 'useAttachments', {
9826
9891
  return useAttachments;
9827
9892
  }
9828
9893
  });
9894
+ Object.defineProperty(exports, 'useCapabilities', {
9895
+ enumerable: true,
9896
+ get: function () {
9897
+ return useCapabilities;
9898
+ }
9899
+ });
9829
9900
  Object.defineProperty(exports, 'useCoAgentStateRenders', {
9830
9901
  enumerable: true,
9831
9902
  get: function () {
@@ -9946,4 +10017,4 @@ Object.defineProperty(exports, 'useToast', {
9946
10017
  return useToast;
9947
10018
  }
9948
10019
  });
9949
- //# sourceMappingURL=copilotkit-Dgdpbqjt.cjs.map
10020
+ //# sourceMappingURL=copilotkit-CSJw5BG8.cjs.map