@copilotkit/react-core 1.60.1 → 1.61.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 (40) hide show
  1. package/dist/{copilotkit-CV519nFv.mjs → copilotkit-BCxdKlMw.mjs} +60 -153
  2. package/dist/copilotkit-BCxdKlMw.mjs.map +1 -0
  3. package/dist/{copilotkit-C9ptuh-b.d.cts → copilotkit-CEdu_aie.d.cts} +29 -7
  4. package/dist/{copilotkit-DvbI8G0d.d.mts.map → copilotkit-CEdu_aie.d.cts.map} +1 -1
  5. package/dist/{copilotkit-BTHcCAVQ.cjs → copilotkit-DtPCrXXd.cjs} +60 -153
  6. package/dist/copilotkit-DtPCrXXd.cjs.map +1 -0
  7. package/dist/{copilotkit-DvbI8G0d.d.mts → copilotkit-M1FiciGd.d.mts} +29 -7
  8. package/dist/{copilotkit-C9ptuh-b.d.cts.map → copilotkit-M1FiciGd.d.mts.map} +1 -1
  9. package/dist/index.cjs +6 -6
  10. package/dist/index.cjs.map +1 -1
  11. package/dist/index.d.cts +3 -3
  12. package/dist/index.d.mts +3 -3
  13. package/dist/index.mjs +6 -6
  14. package/dist/index.mjs.map +1 -1
  15. package/dist/index.umd.js +61 -149
  16. package/dist/index.umd.js.map +1 -1
  17. package/dist/v2/context.cjs +8 -3
  18. package/dist/v2/context.cjs.map +1 -1
  19. package/dist/v2/context.d.cts.map +1 -1
  20. package/dist/v2/context.d.mts.map +1 -1
  21. package/dist/v2/context.mjs +8 -3
  22. package/dist/v2/context.mjs.map +1 -1
  23. package/dist/v2/headless.cjs +23 -12
  24. package/dist/v2/headless.cjs.map +1 -1
  25. package/dist/v2/headless.d.cts +25 -3
  26. package/dist/v2/headless.d.cts.map +1 -1
  27. package/dist/v2/headless.d.mts +25 -3
  28. package/dist/v2/headless.d.mts.map +1 -1
  29. package/dist/v2/headless.mjs +24 -13
  30. package/dist/v2/headless.mjs.map +1 -1
  31. package/dist/v2/index.cjs +1 -1
  32. package/dist/v2/index.css +1 -1
  33. package/dist/v2/index.d.cts +1 -1
  34. package/dist/v2/index.d.mts +1 -1
  35. package/dist/v2/index.mjs +1 -1
  36. package/dist/v2/index.umd.js +59 -152
  37. package/dist/v2/index.umd.js.map +1 -1
  38. package/package.json +6 -6
  39. package/dist/copilotkit-BTHcCAVQ.cjs.map +0 -1
  40. package/dist/copilotkit-CV519nFv.mjs.map +0 -1
@@ -1414,9 +1414,14 @@ _radix_ui_react_dropdown_menu = __toESM(_radix_ui_react_dropdown_menu);
1414
1414
  const [, forceUpdate] = (0, react.useReducer)((x) => x + 1, 0);
1415
1415
  if (!context) throw new Error("useCopilotKit must be used within CopilotKitProvider");
1416
1416
  (0, react.useEffect)(() => {
1417
- const subscription = context.copilotkit.subscribe({ onRuntimeConnectionStatusChanged: () => {
1418
- forceUpdate();
1419
- } });
1417
+ const subscription = context.copilotkit.subscribe({
1418
+ onRuntimeConnectionStatusChanged: () => {
1419
+ forceUpdate();
1420
+ },
1421
+ onHeadersChanged: () => {
1422
+ forceUpdate();
1423
+ }
1424
+ });
1420
1425
  return () => {
1421
1426
  subscription.unsubscribe();
1422
1427
  };
@@ -1623,9 +1628,8 @@ _radix_ui_react_dropdown_menu = __toESM(_radix_ui_react_dropdown_menu);
1623
1628
  const isActive = status === "inProgress" || status === "executing";
1624
1629
  const isComplete = status === "complete";
1625
1630
  const statusLabel = isActive ? "Running" : isComplete ? "Done" : status;
1626
- const dotColor = isActive ? "#f59e0b" : isComplete ? "#10b981" : "#a1a1aa";
1627
- const badgeBg = isActive ? "#fef3c7" : isComplete ? "#d1fae5" : "#f4f4f5";
1628
- const badgeColor = isActive ? "#92400e" : isComplete ? "#065f46" : "#3f3f46";
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";
1629
1633
  return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1630
1634
  "data-testid": "copilot-tool-render",
1631
1635
  "data-tool-name": name,
@@ -1633,54 +1637,20 @@ _radix_ui_react_dropdown_menu = __toESM(_radix_ui_react_dropdown_menu);
1633
1637
  "data-status": status,
1634
1638
  "data-args": safeStringifyForAttr(parameters),
1635
1639
  "data-result": safeStringifyForAttr(result),
1636
- style: {
1637
- marginTop: "8px",
1638
- paddingBottom: "8px"
1639
- },
1640
+ className: "cpk:mt-2 cpk:pb-2",
1640
1641
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1641
- style: {
1642
- borderRadius: "12px",
1643
- border: "1px solid #e4e4e7",
1644
- backgroundColor: "#fafafa",
1645
- padding: "14px 16px"
1646
- },
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",
1647
1643
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
1648
1644
  type: "button",
1649
1645
  "aria-expanded": isExpanded,
1650
1646
  onClick: () => setIsExpanded(!isExpanded),
1651
- style: {
1652
- display: "flex",
1653
- alignItems: "center",
1654
- justifyContent: "space-between",
1655
- gap: "10px",
1656
- cursor: "pointer",
1657
- userSelect: "none",
1658
- width: "100%",
1659
- border: "none",
1660
- padding: 0,
1661
- margin: 0,
1662
- background: "transparent",
1663
- textAlign: "left",
1664
- font: "inherit",
1665
- color: "inherit"
1666
- },
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" },
1667
1649
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1668
- style: {
1669
- display: "flex",
1670
- alignItems: "center",
1671
- gap: "8px",
1672
- minWidth: 0
1673
- },
1650
+ className: "cpk:flex cpk:min-w-0 cpk:items-center cpk:gap-2",
1674
1651
  children: [
1675
1652
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("svg", {
1676
- style: {
1677
- height: "14px",
1678
- width: "14px",
1679
- color: "#71717a",
1680
- transition: "transform 0.15s",
1681
- transform: isExpanded ? "rotate(90deg)" : "rotate(0deg)",
1682
- flexShrink: 0
1683
- },
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" : ""}`,
1684
1654
  fill: "none",
1685
1655
  viewBox: "0 0 24 24",
1686
1656
  strokeWidth: 2,
@@ -1691,93 +1661,31 @@ _radix_ui_react_dropdown_menu = __toESM(_radix_ui_react_dropdown_menu);
1691
1661
  d: "M8.25 4.5l7.5 7.5-7.5 7.5"
1692
1662
  })
1693
1663
  }),
1694
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { style: {
1695
- display: "inline-block",
1696
- height: "8px",
1697
- width: "8px",
1698
- borderRadius: "50%",
1699
- backgroundColor: dotColor,
1700
- flexShrink: 0
1701
- } }),
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}` }),
1702
1665
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1703
1666
  "data-testid": "copilot-tool-render-name",
1704
- style: {
1705
- fontSize: "13px",
1706
- fontWeight: 600,
1707
- color: "#18181b",
1708
- overflow: "hidden",
1709
- textOverflow: "ellipsis",
1710
- whiteSpace: "nowrap"
1711
- },
1667
+ className: "cpk:truncate cpk:text-[13px] cpk:font-semibold cpk:text-zinc-900 cpk:dark:text-zinc-100",
1712
1668
  children: name
1713
1669
  })
1714
1670
  ]
1715
1671
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1716
1672
  "data-testid": "copilot-tool-render-status",
1717
- style: {
1718
- display: "inline-flex",
1719
- alignItems: "center",
1720
- borderRadius: "9999px",
1721
- padding: "2px 8px",
1722
- fontSize: "11px",
1723
- fontWeight: 500,
1724
- backgroundColor: badgeBg,
1725
- color: badgeColor,
1726
- flexShrink: 0
1727
- },
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}`,
1728
1674
  children: statusLabel
1729
1675
  })]
1730
1676
  }), isExpanded && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1731
- style: {
1732
- marginTop: "12px",
1733
- display: "grid",
1734
- gap: "12px"
1735
- },
1677
+ className: "cpk:mt-3 cpk:grid cpk:gap-3",
1736
1678
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1737
- style: {
1738
- fontSize: "10px",
1739
- textTransform: "uppercase",
1740
- letterSpacing: "0.05em",
1741
- color: "#71717a"
1742
- },
1679
+ className: "cpk:text-[10px] cpk:uppercase cpk:text-zinc-500 cpk:dark:text-zinc-400",
1743
1680
  children: "Arguments"
1744
1681
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("pre", {
1745
- style: {
1746
- marginTop: "6px",
1747
- maxHeight: "200px",
1748
- overflow: "auto",
1749
- borderRadius: "6px",
1750
- backgroundColor: "#f4f4f5",
1751
- padding: "10px",
1752
- fontSize: "11px",
1753
- lineHeight: 1.6,
1754
- color: "#27272a",
1755
- whiteSpace: "pre-wrap",
1756
- wordBreak: "break-word"
1757
- },
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",
1758
1683
  children: safeStringifyForPre(parameters ?? {})
1759
1684
  })] }), result !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1760
- style: {
1761
- fontSize: "10px",
1762
- textTransform: "uppercase",
1763
- letterSpacing: "0.05em",
1764
- color: "#71717a"
1765
- },
1685
+ className: "cpk:text-[10px] cpk:uppercase cpk:text-zinc-500 cpk:dark:text-zinc-400",
1766
1686
  children: "Result"
1767
1687
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("pre", {
1768
- style: {
1769
- marginTop: "6px",
1770
- maxHeight: "200px",
1771
- overflow: "auto",
1772
- borderRadius: "6px",
1773
- backgroundColor: "#f4f4f5",
1774
- padding: "10px",
1775
- fontSize: "11px",
1776
- lineHeight: 1.6,
1777
- color: "#27272a",
1778
- whiteSpace: "pre-wrap",
1779
- wordBreak: "break-word"
1780
- },
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",
1781
1689
  children: typeof result === "string" ? result : safeStringifyForPre(result)
1782
1690
  })] })]
1783
1691
  })]
@@ -3720,6 +3628,10 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
3720
3628
  ...selfManagedAgents
3721
3629
  }), [agents, selfManagedAgents]);
3722
3630
  const hasLocalAgents = mergedAgents && Object.keys(mergedAgents).length > 0;
3631
+ const hasSelfManagedAgents = Object.keys(selfManagedAgents).length > 0;
3632
+ (0, react.useEffect)(() => {
3633
+ if (hasSelfManagedAgents && !resolvedPublicKey) console.warn("[CopilotKit] `selfManagedAgents` is part of CopilotKit's Enterprise Intelligence offering. Provide a `publicLicenseKey` for production use — contact the CopilotKit team about licensing.");
3634
+ }, [hasSelfManagedAgents, resolvedPublicKey]);
3723
3635
  const headers = typeof headersProp === "function" ? headersProp() : headersProp;
3724
3636
  const mergedHeaders = (0, react.useMemo)(() => {
3725
3637
  if (!resolvedPublicKey) return headers;
@@ -4197,36 +4109,40 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
4197
4109
  }, []);
4198
4110
  const RenderComponent = (0, react.useCallback)((props) => {
4199
4111
  const ToolComponent = tool.render;
4200
- if (props.status === "inProgress") {
4112
+ if (props.status === _copilotkit_core.ToolCallStatus.InProgress) {
4201
4113
  const enhancedProps = {
4202
4114
  ...props,
4203
4115
  name: tool.name,
4204
4116
  description: tool.description || "",
4117
+ agentId: tool.agentId,
4205
4118
  respond: void 0
4206
4119
  };
4207
4120
  return react.default.createElement(ToolComponent, enhancedProps);
4208
- } else if (props.status === "executing") {
4121
+ } else if (props.status === _copilotkit_core.ToolCallStatus.Executing) {
4209
4122
  const enhancedProps = {
4210
4123
  ...props,
4211
4124
  name: tool.name,
4212
4125
  description: tool.description || "",
4126
+ agentId: tool.agentId,
4213
4127
  respond
4214
4128
  };
4215
4129
  return react.default.createElement(ToolComponent, enhancedProps);
4216
- } else if (props.status === "complete") {
4130
+ } else if (props.status === _copilotkit_core.ToolCallStatus.Complete) {
4217
4131
  const enhancedProps = {
4218
4132
  ...props,
4219
4133
  name: tool.name,
4220
4134
  description: tool.description || "",
4135
+ agentId: tool.agentId,
4221
4136
  respond: void 0
4222
4137
  };
4223
4138
  return react.default.createElement(ToolComponent, enhancedProps);
4224
4139
  }
4225
- return react.default.createElement(ToolComponent, props);
4140
+ return props;
4226
4141
  }, [
4227
4142
  tool.render,
4228
4143
  tool.name,
4229
4144
  tool.description,
4145
+ tool.agentId,
4230
4146
  respond
4231
4147
  ]);
4232
4148
  useFrontendTool({
@@ -4717,18 +4633,25 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
4717
4633
  },
4718
4634
  onRunFailed: () => {
4719
4635
  localInterrupt = null;
4636
+ setPendingEvent(null);
4720
4637
  }
4721
4638
  });
4722
4639
  return () => subscription.unsubscribe();
4723
4640
  }, [agent]);
4724
- const resolve = (0, react.useCallback)((response) => {
4725
- copilotkit.runAgent({
4726
- agent,
4727
- forwardedProps: { command: {
4728
- resume: response,
4729
- interruptEvent: pendingEventRef.current?.value
4730
- } }
4731
- });
4641
+ const resolve = (0, react.useCallback)(async (response) => {
4642
+ try {
4643
+ return await copilotkit.runAgent({
4644
+ agent,
4645
+ forwardedProps: { command: {
4646
+ resume: response,
4647
+ interruptEvent: pendingEventRef.current?.value
4648
+ } }
4649
+ });
4650
+ } catch (err) {
4651
+ console.error("[CopilotKit] useInterrupt resolve: runAgent rejected; clearing pending + rethrowing", err);
4652
+ setPendingEvent(null);
4653
+ throw err;
4654
+ }
4732
4655
  }, [agent, copilotkit]);
4733
4656
  const renderRef = (0, react.useRef)(config.render);
4734
4657
  renderRef.current = config.render;
@@ -7097,7 +7020,6 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
7097
7020
  function usePinToSend({ scrollRef, contentRef, spacerRef, topOffset = 16 }) {
7098
7021
  const { id, sendNonce } = (0, react.useContext)(LastUserMessageContext);
7099
7022
  const lastNonceRef = (0, react.useRef)(-1);
7100
- const currentSpacerHeightRef = (0, react.useRef)(0);
7101
7023
  (0, react.useEffect)(() => {
7102
7024
  if (sendNonce === lastNonceRef.current) return;
7103
7025
  lastNonceRef.current = sendNonce;
@@ -7115,7 +7037,6 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
7115
7037
  const bubbleHeight = Math.max(0, userMessageHeight - paddingTop);
7116
7038
  const spacerHeight = Math.max(0, viewportHeight - bubbleHeight - topOffset);
7117
7039
  spacerEl.style.height = `${spacerHeight}px`;
7118
- currentSpacerHeightRef.current = spacerHeight;
7119
7040
  const raf = requestAnimationFrame(() => {
7120
7041
  const targetTop = computeOffsetTop(targetEl, scrollEl) + paddingTop - topOffset;
7121
7042
  scrollEl.scrollTo({
@@ -7127,10 +7048,7 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
7127
7048
  if (!contentEl || !spacerEl || !scrollEl) return;
7128
7049
  const consumedBelow = contentEl.getBoundingClientRect().height - computeOffsetTop(targetEl, contentEl) - userMessageHeight;
7129
7050
  const remaining = Math.max(0, spacerHeight - consumedBelow);
7130
- if (remaining < currentSpacerHeightRef.current) {
7131
- spacerEl.style.height = `${remaining}px`;
7132
- currentSpacerHeightRef.current = remaining;
7133
- }
7051
+ spacerEl.style.height = `${remaining}px`;
7134
7052
  });
7135
7053
  ro.observe(contentEl);
7136
7054
  return () => {
@@ -7424,7 +7342,7 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
7424
7342
  }, []);
7425
7343
  (0, react.useEffect)(() => {
7426
7344
  if (mode === "pin-to-bottom") return;
7427
- const scrollElement = scrollRef.current;
7345
+ const scrollElement = nonAutoScrollEl;
7428
7346
  if (!scrollElement) return;
7429
7347
  const checkScroll = () => {
7430
7348
  setShowScrollButton(!(scrollElement.scrollHeight - scrollElement.scrollTop - scrollElement.clientHeight < 10));
@@ -7437,7 +7355,7 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
7437
7355
  scrollElement.removeEventListener("scroll", checkScroll);
7438
7356
  resizeObserver.disconnect();
7439
7357
  };
7440
- }, [scrollRef, mode]);
7358
+ }, [nonAutoScrollEl, mode]);
7441
7359
  if (!hasMounted) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
7442
7360
  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",
7443
7361
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
@@ -10072,21 +9990,6 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
10072
9990
 
10073
9991
  //#endregion
10074
9992
  //#region src/components/copilot-provider/copilotkit.tsx
10075
- /**
10076
- * This component will typically wrap your entire application (or a sub-tree of your application where you want to have a copilot). It provides the copilot context to all other components and hooks.
10077
- *
10078
- * ## Example
10079
- *
10080
- * You can find more information about self-hosting CopilotKit [here](/guides/self-hosting).
10081
- *
10082
- * ```tsx
10083
- * import { CopilotKit } from "@copilotkit/react-core";
10084
- *
10085
- * <CopilotKit runtimeUrl="<your-runtime-url>">
10086
- * // ... your app ...
10087
- * </CopilotKit>
10088
- * ```
10089
- */
10090
9993
  function CopilotKit({ children, ...props }) {
10091
9994
  const enabled = shouldShowDevConsole(props.showDevConsole);
10092
9995
  const showInspector = shouldShowDevConsole(props.enableInspector);
@@ -10575,7 +10478,11 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
10575
10478
  function validateProps(props) {
10576
10479
  const cloudFeatures = Object.keys(props).filter((key) => key.endsWith("_c"));
10577
10480
  const hasApiKey = props.publicApiKey || props.publicLicenseKey;
10578
- if (!props.runtimeUrl && !hasApiKey) throw new _copilotkit_shared.ConfigurationError("Missing required prop: 'runtimeUrl' or 'publicApiKey' or 'publicLicenseKey'");
10481
+ const hasLocalAgents = Object.keys({
10482
+ ...props.agents__unsafe_dev_only,
10483
+ ...props.selfManagedAgents
10484
+ }).length > 0;
10485
+ if (!props.runtimeUrl && !hasApiKey && !hasLocalAgents) throw new _copilotkit_shared.ConfigurationError("Missing required prop: 'runtimeUrl' or 'publicApiKey' or 'publicLicenseKey'");
10579
10486
  if (cloudFeatures.length > 0 && !hasApiKey) throw new _copilotkit_shared.MissingPublicApiKeyError(`Missing required prop: 'publicApiKey' or 'publicLicenseKey' to use cloud features: ${cloudFeatures.map(formatFeatureName).join(", ")}`);
10580
10487
  }
10581
10488