@copilotkit/react-core 1.59.1 → 1.59.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.
@@ -1502,6 +1502,47 @@ function useRenderTool(config, deps) {
1502
1502
  //#endregion
1503
1503
  //#region src/v2/hooks/use-default-render-tool.tsx
1504
1504
  /**
1505
+ * Module-level dedup set so an unknown status value only emits a console
1506
+ * warning the FIRST time we encounter it. Otherwise a stuck/unmapped status
1507
+ * would log on every re-render (potentially many per second).
1508
+ */
1509
+ const warnedUnknownStatuses = /* @__PURE__ */ new Set();
1510
+ /**
1511
+ * Map a {@link ToolCallStatus} enum value to the documented string-union
1512
+ * status the {@link DefaultRenderProps} contract exposes. Unknown / future
1513
+ * enum members log a warning (once per distinct value) and fall back to
1514
+ * `"inProgress"`.
1515
+ */
1516
+ function mapToolCallStatus(status) {
1517
+ switch (status) {
1518
+ case ToolCallStatus.Complete: return "complete";
1519
+ case ToolCallStatus.Executing: return "executing";
1520
+ case ToolCallStatus.InProgress: return "inProgress";
1521
+ default: {
1522
+ const key = String(status);
1523
+ if (!warnedUnknownStatuses.has(key)) {
1524
+ warnedUnknownStatuses.add(key);
1525
+ console.warn(`[CopilotKit] Unknown ToolCallStatus "${key}" in default tool-call renderer; falling back to "inProgress".`);
1526
+ }
1527
+ return "inProgress";
1528
+ }
1529
+ }
1530
+ }
1531
+ /**
1532
+ * Convert the framework-internal renderer props (`args`, enum status) into
1533
+ * the documented {@link DefaultRenderProps} shape (`parameters`, string-union
1534
+ * status) so a user `config.render` always sees the documented contract.
1535
+ */
1536
+ function adaptRendererProps(props) {
1537
+ return {
1538
+ name: props.name,
1539
+ toolCallId: props.toolCallId,
1540
+ parameters: props.args,
1541
+ status: mapToolCallStatus(props.status),
1542
+ result: props.result
1543
+ };
1544
+ }
1545
+ /**
1505
1546
  * Registers a wildcard (`"*"`) tool-call renderer via `useRenderTool`.
1506
1547
  *
1507
1548
  * - Call with no config to use CopilotKit's built-in default tool-call card.
@@ -1538,16 +1579,33 @@ function useRenderTool(config, deps) {
1538
1579
  * ```
1539
1580
  */
1540
1581
  function useDefaultRenderTool(config, deps) {
1582
+ const userRender = config?.render;
1541
1583
  useRenderTool({
1542
1584
  name: "*",
1543
- render: config?.render ?? DefaultToolCallRenderer
1585
+ render: userRender ? (raw) => userRender(adaptRendererProps(raw)) : (raw) => /* @__PURE__ */ jsx(DefaultToolCallRenderer, { ...adaptRendererProps(raw) })
1544
1586
  }, deps);
1545
1587
  }
1546
- function DefaultToolCallRenderer({ name, parameters, status, result }) {
1588
+ /**
1589
+ * Guarded JSON.stringify used inside the expanded `<pre>` blocks. A circular
1590
+ * reference would otherwise crash the entire React tree on render.
1591
+ */
1592
+ function safeStringifyForPre(value) {
1593
+ try {
1594
+ return JSON.stringify(value, null, 2);
1595
+ } catch (err) {
1596
+ console.warn("[CopilotKit] Failed to JSON.stringify tool-call payload for default renderer; falling back to String():", err);
1597
+ try {
1598
+ return String(value);
1599
+ } catch (innerErr) {
1600
+ console.warn("[CopilotKit] safeStringifyForPre: value could not be stringified:", innerErr);
1601
+ return "[unserializable]";
1602
+ }
1603
+ }
1604
+ }
1605
+ function DefaultToolCallRenderer({ name, toolCallId, parameters, status, result }) {
1547
1606
  const [isExpanded, setIsExpanded] = useState(false);
1548
- const statusString = String(status);
1549
- const isActive = statusString === "inProgress" || statusString === "executing";
1550
- const isComplete = statusString === "complete";
1607
+ const isActive = status === "inProgress" || status === "executing";
1608
+ const isComplete = status === "complete";
1551
1609
  const statusLabel = isActive ? "Running" : isComplete ? "Done" : status;
1552
1610
  const dotColor = isActive ? "#f59e0b" : isComplete ? "#10b981" : "#a1a1aa";
1553
1611
  const badgeBg = isActive ? "#fef3c7" : isComplete ? "#d1fae5" : "#f4f4f5";
@@ -1555,7 +1613,8 @@ function DefaultToolCallRenderer({ name, parameters, status, result }) {
1555
1613
  return /* @__PURE__ */ jsx("div", {
1556
1614
  "data-testid": "copilot-tool-render",
1557
1615
  "data-tool-name": name,
1558
- "data-status": statusString,
1616
+ "data-tool-call-id": toolCallId,
1617
+ "data-status": status,
1559
1618
  "data-args": safeStringifyForAttr(parameters),
1560
1619
  "data-result": safeStringifyForAttr(result),
1561
1620
  style: {
@@ -1569,7 +1628,9 @@ function DefaultToolCallRenderer({ name, parameters, status, result }) {
1569
1628
  backgroundColor: "#fafafa",
1570
1629
  padding: "14px 16px"
1571
1630
  },
1572
- children: [/* @__PURE__ */ jsxs("div", {
1631
+ children: [/* @__PURE__ */ jsxs("button", {
1632
+ type: "button",
1633
+ "aria-expanded": isExpanded,
1573
1634
  onClick: () => setIsExpanded(!isExpanded),
1574
1635
  style: {
1575
1636
  display: "flex",
@@ -1577,7 +1638,15 @@ function DefaultToolCallRenderer({ name, parameters, status, result }) {
1577
1638
  justifyContent: "space-between",
1578
1639
  gap: "10px",
1579
1640
  cursor: "pointer",
1580
- userSelect: "none"
1641
+ userSelect: "none",
1642
+ width: "100%",
1643
+ border: "none",
1644
+ padding: 0,
1645
+ margin: 0,
1646
+ background: "transparent",
1647
+ textAlign: "left",
1648
+ font: "inherit",
1649
+ color: "inherit"
1581
1650
  },
1582
1651
  children: [/* @__PURE__ */ jsxs("div", {
1583
1652
  style: {
@@ -1670,7 +1739,7 @@ function DefaultToolCallRenderer({ name, parameters, status, result }) {
1670
1739
  whiteSpace: "pre-wrap",
1671
1740
  wordBreak: "break-word"
1672
1741
  },
1673
- children: JSON.stringify(parameters ?? {}, null, 2)
1742
+ children: safeStringifyForPre(parameters ?? {})
1674
1743
  })] }), result !== void 0 && /* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsx("div", {
1675
1744
  style: {
1676
1745
  fontSize: "10px",
@@ -1693,7 +1762,7 @@ function DefaultToolCallRenderer({ name, parameters, status, result }) {
1693
1762
  whiteSpace: "pre-wrap",
1694
1763
  wordBreak: "break-word"
1695
1764
  },
1696
- children: typeof result === "string" ? result : JSON.stringify(result, null, 2)
1765
+ children: typeof result === "string" ? result : safeStringifyForPre(result)
1697
1766
  })] })]
1698
1767
  })]
1699
1768
  })
@@ -1704,8 +1773,14 @@ function safeStringifyForAttr(value) {
1704
1773
  if (typeof value === "string") return value;
1705
1774
  try {
1706
1775
  return JSON.stringify(value);
1707
- } catch {
1708
- return String(value);
1776
+ } catch (err) {
1777
+ console.warn("[CopilotKit] Failed to JSON.stringify tool-call payload for data-* attribute; falling back to String():", err);
1778
+ try {
1779
+ return String(value);
1780
+ } catch (innerErr) {
1781
+ console.warn("[CopilotKit] safeStringifyForAttr: value could not be stringified:", innerErr);
1782
+ return "";
1783
+ }
1709
1784
  }
1710
1785
  }
1711
1786
 
@@ -1776,11 +1851,11 @@ function useRenderToolCall() {
1776
1851
  ]);
1777
1852
  }
1778
1853
  function defaultToolCallRenderAdapter(props) {
1779
- const status = props.status === ToolCallStatus.Complete ? "complete" : props.status === ToolCallStatus.Executing ? "executing" : "inProgress";
1780
1854
  return /* @__PURE__ */ jsx(DefaultToolCallRenderer, {
1781
1855
  name: props.name,
1856
+ toolCallId: props.toolCallId,
1782
1857
  parameters: props.args,
1783
- status,
1858
+ status: mapToolCallStatus(props.status),
1784
1859
  result: props.result
1785
1860
  });
1786
1861
  }
@@ -4475,7 +4550,6 @@ function useInterrupt(config) {
4475
4550
  return () => subscription.unsubscribe();
4476
4551
  }, [agent]);
4477
4552
  const resolve = useCallback((response) => {
4478
- setPendingEvent(null);
4479
4553
  copilotkit.runAgent({
4480
4554
  agent,
4481
4555
  forwardedProps: { command: {
@@ -4484,44 +4558,67 @@ function useInterrupt(config) {
4484
4558
  } }
4485
4559
  });
4486
4560
  }, [agent, copilotkit]);
4561
+ const renderRef = useRef(config.render);
4562
+ renderRef.current = config.render;
4563
+ const enabledRef = useRef(config.enabled);
4564
+ enabledRef.current = config.enabled;
4565
+ const handlerRef = useRef(config.handler);
4566
+ handlerRef.current = config.handler;
4567
+ const resolveRef = useRef(resolve);
4568
+ resolveRef.current = resolve;
4569
+ const isEnabled = (event) => {
4570
+ const predicate = enabledRef.current;
4571
+ if (!predicate) return true;
4572
+ try {
4573
+ return predicate(event);
4574
+ } catch (err) {
4575
+ console.error("[CopilotKit] useInterrupt enabled predicate threw; treating interrupt as disabled:", err);
4576
+ return false;
4577
+ }
4578
+ };
4487
4579
  useEffect(() => {
4488
4580
  if (!pendingEvent) {
4489
4581
  setHandlerResult(null);
4490
4582
  return;
4491
4583
  }
4492
- if (config.enabled && !config.enabled(pendingEvent)) {
4584
+ if (!isEnabled(pendingEvent)) {
4493
4585
  setHandlerResult(null);
4494
4586
  return;
4495
4587
  }
4496
- const handler = config.handler;
4588
+ const handler = handlerRef.current;
4497
4589
  if (!handler) {
4498
4590
  setHandlerResult(null);
4499
4591
  return;
4500
4592
  }
4501
4593
  let cancelled = false;
4502
- const maybePromise = handler({
4503
- event: pendingEvent,
4504
- resolve
4505
- });
4594
+ let maybePromise;
4595
+ try {
4596
+ maybePromise = handler({
4597
+ event: pendingEvent,
4598
+ resolve: resolveRef.current
4599
+ });
4600
+ } catch (err) {
4601
+ console.error("[CopilotKit] useInterrupt handler threw; result will be null:", err);
4602
+ if (!cancelled) setHandlerResult(null);
4603
+ return () => {
4604
+ cancelled = true;
4605
+ };
4606
+ }
4506
4607
  if (isPromiseLike(maybePromise)) Promise.resolve(maybePromise).then((resolved) => {
4507
4608
  if (!cancelled) setHandlerResult(resolved);
4508
- }).catch(() => {
4609
+ }).catch((err) => {
4610
+ console.error("[CopilotKit] useInterrupt handler rejected; result will be null:", err);
4509
4611
  if (!cancelled) setHandlerResult(null);
4510
4612
  });
4511
4613
  else setHandlerResult(maybePromise);
4512
4614
  return () => {
4513
4615
  cancelled = true;
4514
4616
  };
4515
- }, [
4516
- pendingEvent,
4517
- config.enabled,
4518
- config.handler,
4519
- resolve
4520
- ]);
4617
+ }, [pendingEvent]);
4521
4618
  const element = useMemo(() => {
4522
4619
  if (!pendingEvent) return null;
4523
- if (config.enabled && !config.enabled(pendingEvent)) return null;
4524
- return config.render({
4620
+ if (!isEnabled(pendingEvent)) return null;
4621
+ return renderRef.current({
4525
4622
  event: pendingEvent,
4526
4623
  result: handlerResult,
4527
4624
  resolve
@@ -4529,19 +4626,22 @@ function useInterrupt(config) {
4529
4626
  }, [
4530
4627
  pendingEvent,
4531
4628
  handlerResult,
4532
- config.enabled,
4533
- config.render,
4534
4629
  resolve
4535
4630
  ]);
4536
4631
  useEffect(() => {
4537
4632
  if (config.renderInChat === false) return;
4538
4633
  copilotkit.setInterruptElement(element);
4539
- return () => copilotkit.setInterruptElement(null);
4540
4634
  }, [
4541
4635
  element,
4542
4636
  config.renderInChat,
4543
4637
  copilotkit
4544
4638
  ]);
4639
+ useEffect(() => {
4640
+ if (config.renderInChat === false) return;
4641
+ return () => {
4642
+ copilotkit.setInterruptElement(null);
4643
+ };
4644
+ }, []);
4545
4645
  if (config.renderInChat === false) return element;
4546
4646
  }
4547
4647
 
@@ -8190,6 +8290,7 @@ function BannerErrorDisplay({ bannerError, onDismiss }) {
8190
8290
  const details = bannerError.details;
8191
8291
  const link = extractUrl(bannerError.message);
8192
8292
  return /* @__PURE__ */ jsxs("div", {
8293
+ "data-testid": "copilot-error-banner",
8193
8294
  style: {
8194
8295
  position: "fixed",
8195
8296
  bottom: "20px",
@@ -8390,7 +8491,7 @@ function ToastProvider({ enabled, children }) {
8390
8491
  }, []);
8391
8492
  const addToast = useCallback((toast) => {
8392
8493
  if (!enabled) return;
8393
- const id = toast.id ?? Math.random().toString(36).substring(2, 9);
8494
+ const id = toast.id ?? Math.random().toString(36).slice(2, 9);
8394
8495
  setToasts((currentToasts) => {
8395
8496
  if (currentToasts.find((toast) => toast.id === id)) return currentToasts;
8396
8497
  return [...currentToasts, {
@@ -8747,6 +8848,7 @@ function UsageBanner({ severity = Severity.CRITICAL, message = "", onClose, acti
8747
8848
  }
8748
8849
  ` }), /* @__PURE__ */ jsx("div", {
8749
8850
  className: "usage-banner",
8851
+ "data-testid": "copilot-error-banner",
8750
8852
  children: /* @__PURE__ */ jsxs("div", {
8751
8853
  className: "banner-content",
8752
8854
  children: [
@@ -9985,4 +10087,4 @@ function validateProps(props) {
9985
10087
 
9986
10088
  //#endregion
9987
10089
  export { createA2UIMessageRenderer as $, IntelligenceIndicator as A, useInterrupt as B, CopilotChatToggleButton as C, CopilotChatView_default as D, CopilotChat as E, CopilotChatAttachmentRenderer as F, useAgent as G, useSuggestions as H, CopilotChatAssistantMessage_default as I, useFrontendTool as J, useHumanInTheLoop as K, CopilotChatToolCallsView as L, CopilotChatSuggestionPill as M, CopilotChatReasoningMessage_default as N, CopilotChatAttachmentQueue as O, CopilotChatUserMessage_default as P, useAgentContext as Q, useAttachments as R, CopilotModalHeader as S, DefaultOpenIcon as T, useCapabilities as U, useConfigureSuggestions as V, UseAgentUpdate as W, useRenderCustomMessages as X, useRenderActivityMessage as Y, CopilotKitProvider as Z, WildcardToolCallRender as _, ThreadsProvider as a, CopilotKitInspector as at, CopilotPopupView as b, CoAgentStateRendersProvider as c, useRenderTool as ct, shouldShowDevConsole as d, CopilotKitCoreReact as dt, SandboxFunctionsContext as et, useToast as f, CopilotChatInput_default as ft, useCopilotContext as g, useCopilotChatConfiguration as gt, CopilotContext as h, CopilotChatConfigurationProvider as ht, ThreadsContext as i, MCPAppsActivityType as it, CopilotChatSuggestionView as j, CopilotChatMessageView as k, useCoAgentStateRenders as l, defineToolCallRenderer as lt, useCopilotMessagesContext as m, CopilotChatAudioRecorder as mt, defaultCopilotContextCategories as n, MCPAppsActivityContentSchema as nt, useThreads as o, useRenderToolCall as ot, CopilotMessagesContext as p, AudioRecorderError as pt, useComponent as q, CoAgentStateRenderBridge as r, MCPAppsActivityRenderer as rt, CoAgentStateRendersContext as s, useDefaultRenderTool as st, CopilotKit as t, useSandboxFunctions as tt, useAsyncCallback as u, useCopilotKit as ut, CopilotPopup as v, DefaultCloseIcon as w, CopilotSidebarView as x, CopilotSidebar as y, useThreads$1 as z };
9988
- //# sourceMappingURL=copilotkit-CDK5ny-e.mjs.map
10090
+ //# sourceMappingURL=copilotkit-B5RsC6la.mjs.map