@copilotkit/react-core 1.57.0 → 1.57.1-canary.1778272612

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 (86) hide show
  1. package/dist/{copilotkit-CPe2-340.mjs → copilotkit-3XTEoVQO.mjs} +1367 -1200
  2. package/dist/copilotkit-3XTEoVQO.mjs.map +1 -0
  3. package/dist/{copilotkit-DFaI4j2r.d.mts → copilotkit-BCJ2yvV6.d.mts} +68 -8
  4. package/dist/copilotkit-BCJ2yvV6.d.mts.map +1 -0
  5. package/dist/{copilotkit-Dg4r4Gi_.d.cts → copilotkit-CBbSvze0.d.cts} +68 -8
  6. package/dist/copilotkit-CBbSvze0.d.cts.map +1 -0
  7. package/dist/{copilotkit-DGbvw8n2.cjs → copilotkit-Dnj9pi4m.cjs} +1369 -1196
  8. package/dist/copilotkit-Dnj9pi4m.cjs.map +1 -0
  9. package/dist/index.cjs +2 -5
  10. package/dist/index.cjs.map +1 -1
  11. package/dist/index.d.cts +1 -1
  12. package/dist/index.d.mts +1 -1
  13. package/dist/index.mjs +2 -5
  14. package/dist/index.mjs.map +1 -1
  15. package/dist/index.umd.js +733 -610
  16. package/dist/index.umd.js.map +1 -1
  17. package/dist/v2/context.cjs +135 -0
  18. package/dist/v2/context.cjs.map +1 -0
  19. package/dist/v2/context.d.cts +148 -0
  20. package/dist/v2/context.d.cts.map +1 -0
  21. package/dist/v2/context.d.mts +148 -0
  22. package/dist/v2/context.d.mts.map +1 -0
  23. package/dist/v2/context.mjs +129 -0
  24. package/dist/v2/context.mjs.map +1 -0
  25. package/dist/v2/headless.cjs +1043 -0
  26. package/dist/v2/headless.cjs.map +1 -0
  27. package/dist/v2/headless.d.cts +605 -0
  28. package/dist/v2/headless.d.cts.map +1 -0
  29. package/dist/v2/headless.d.mts +512 -0
  30. package/dist/v2/headless.d.mts.map +1 -0
  31. package/dist/v2/headless.mjs +997 -0
  32. package/dist/v2/headless.mjs.map +1 -0
  33. package/dist/v2/index.cjs +2 -1
  34. package/dist/v2/index.css +1 -1
  35. package/dist/v2/index.d.cts +2 -2
  36. package/dist/v2/index.d.mts +2 -2
  37. package/dist/v2/index.mjs +2 -2
  38. package/dist/v2/index.umd.js +1385 -1204
  39. package/dist/v2/index.umd.js.map +1 -1
  40. package/package.json +14 -6
  41. package/src/hooks/__tests__/use-copilot-chat-internal-connect.test.tsx +5 -6
  42. package/src/hooks/use-copilot-chat_internal.ts +0 -1
  43. package/src/v2/components/chat/CopilotChat.tsx +2 -1
  44. package/src/v2/components/chat/CopilotChatMessageView.tsx +24 -9
  45. package/src/v2/components/chat/CopilotChatView.tsx +2 -2
  46. package/src/v2/components/chat/CopilotSidebar.tsx +5 -1
  47. package/src/v2/components/chat/CopilotSidebarView.tsx +24 -10
  48. package/src/v2/components/chat/__tests__/CopilotChat.welcomeGate.test.tsx +1 -3
  49. package/src/v2/components/chat/__tests__/CopilotChatActivityRendering.e2e.test.tsx +29 -25
  50. package/src/v2/components/chat/__tests__/CopilotSidebarView.position.test.tsx +159 -0
  51. package/src/v2/components/chat/__tests__/MCPAppsUiMessage.e2e.test.tsx +5 -60
  52. package/src/v2/components/index.ts +1 -0
  53. package/src/v2/components/intelligence-indicator/IntelligenceIndicator.tsx +286 -0
  54. package/src/v2/components/intelligence-indicator/__tests__/IntelligenceIndicator.e2e.test.tsx +464 -0
  55. package/src/v2/components/intelligence-indicator/index.ts +2 -0
  56. package/src/v2/context.ts +62 -0
  57. package/src/v2/headless.ts +42 -0
  58. package/src/v2/hooks/__tests__/standard-schema.test.tsx +2 -2
  59. package/src/v2/hooks/__tests__/use-agent-context.test.tsx +3 -3
  60. package/src/v2/hooks/__tests__/use-agent-stability.test.tsx +3 -3
  61. package/src/v2/hooks/__tests__/use-agent-throttle.test.tsx +85 -85
  62. package/src/v2/hooks/__tests__/use-interrupt.test.tsx +2 -2
  63. package/src/v2/hooks/__tests__/use-render-tool.test.tsx +2 -2
  64. package/src/v2/hooks/__tests__/use-threads.test.tsx +2 -2
  65. package/src/v2/hooks/__tests__/zod-regression.test.tsx +2 -2
  66. package/src/v2/hooks/use-agent-context.tsx +1 -1
  67. package/src/v2/hooks/use-agent.tsx +9 -118
  68. package/src/v2/hooks/use-configure-suggestions.tsx +1 -1
  69. package/src/v2/hooks/use-default-render-tool.tsx +18 -1
  70. package/src/v2/hooks/use-frontend-tool.tsx +2 -2
  71. package/src/v2/hooks/use-human-in-the-loop.tsx +1 -1
  72. package/src/v2/hooks/use-interrupt.tsx +1 -1
  73. package/src/v2/hooks/use-render-activity-message.tsx +3 -11
  74. package/src/v2/hooks/use-render-custom-messages.tsx +1 -6
  75. package/src/v2/hooks/use-render-tool-call.tsx +36 -6
  76. package/src/v2/hooks/use-render-tool.tsx +2 -2
  77. package/src/v2/hooks/use-suggestions.tsx +1 -1
  78. package/src/v2/hooks/use-threads.tsx +1 -1
  79. package/src/v2/providers/CopilotKitProvider.tsx +19 -59
  80. package/src/v2/styles/globals.css +118 -0
  81. package/tsdown.config.ts +75 -0
  82. package/dist/copilotkit-CPe2-340.mjs.map +0 -1
  83. package/dist/copilotkit-DFaI4j2r.d.mts.map +0 -1
  84. package/dist/copilotkit-DGbvw8n2.cjs.map +0 -1
  85. package/dist/copilotkit-Dg4r4Gi_.d.cts.map +0 -1
  86. package/src/v2/hooks/__tests__/use-agent-thread-isolation.test.tsx +0 -333
@@ -1295,351 +1295,842 @@ function useKatexStyles() {
1295
1295
  }
1296
1296
 
1297
1297
  //#endregion
1298
- //#region src/v2/components/CopilotKitInspector.tsx
1299
- const CopilotKitInspector = ({ core, ...rest }) => {
1300
- const [InspectorComponent, setInspectorComponent] = React$1.useState(null);
1301
- React$1.useEffect(() => {
1302
- let mounted = true;
1303
- import("@copilotkit/web-inspector").then((mod) => {
1304
- mod.defineWebInspector?.();
1305
- const Component = createComponent({
1306
- tagName: mod.WEB_INSPECTOR_TAG,
1307
- elementClass: mod.WebInspectorElement,
1308
- react: React$1
1298
+ //#region src/v2/lib/react-core.ts
1299
+ var CopilotKitCoreReact = class extends CopilotKitCore {
1300
+ constructor(config) {
1301
+ super(config);
1302
+ this._renderToolCalls = [];
1303
+ this._hookRenderToolCalls = /* @__PURE__ */ new Map();
1304
+ this._cachedMergedRenderToolCalls = null;
1305
+ this._renderCustomMessages = [];
1306
+ this._renderActivityMessages = [];
1307
+ this._interruptElement = null;
1308
+ this._renderToolCalls = config.renderToolCalls ?? [];
1309
+ this._renderCustomMessages = config.renderCustomMessages ?? [];
1310
+ this._renderActivityMessages = config.renderActivityMessages ?? [];
1311
+ }
1312
+ get renderCustomMessages() {
1313
+ return this._renderCustomMessages;
1314
+ }
1315
+ get renderActivityMessages() {
1316
+ return this._renderActivityMessages;
1317
+ }
1318
+ get renderToolCalls() {
1319
+ if (this._hookRenderToolCalls.size === 0) return this._renderToolCalls;
1320
+ if (this._cachedMergedRenderToolCalls) return this._cachedMergedRenderToolCalls;
1321
+ const merged = /* @__PURE__ */ new Map();
1322
+ for (const rc of this._renderToolCalls) merged.set(`${rc.agentId ?? ""}:${rc.name}`, rc);
1323
+ for (const [key, rc] of this._hookRenderToolCalls) merged.set(key, rc);
1324
+ this._cachedMergedRenderToolCalls = Array.from(merged.values());
1325
+ return this._cachedMergedRenderToolCalls;
1326
+ }
1327
+ setRenderActivityMessages(renderers) {
1328
+ this._renderActivityMessages = renderers;
1329
+ }
1330
+ setRenderCustomMessages(renderers) {
1331
+ this._renderCustomMessages = renderers;
1332
+ }
1333
+ setRenderToolCalls(renderToolCalls) {
1334
+ this._renderToolCalls = renderToolCalls;
1335
+ this._cachedMergedRenderToolCalls = null;
1336
+ this._notifyRenderToolCallsChanged();
1337
+ }
1338
+ addHookRenderToolCall(entry) {
1339
+ const key = `${entry.agentId ?? ""}:${entry.name}`;
1340
+ this._hookRenderToolCalls.set(key, entry);
1341
+ this._cachedMergedRenderToolCalls = null;
1342
+ this._notifyRenderToolCallsChanged();
1343
+ }
1344
+ removeHookRenderToolCall(name, agentId) {
1345
+ const key = `${agentId ?? ""}:${name}`;
1346
+ if (this._hookRenderToolCalls.delete(key)) {
1347
+ this._cachedMergedRenderToolCalls = null;
1348
+ this._notifyRenderToolCallsChanged();
1349
+ }
1350
+ }
1351
+ _notifyRenderToolCallsChanged() {
1352
+ this.notifySubscribers((subscriber) => {
1353
+ const reactSubscriber = subscriber;
1354
+ if (reactSubscriber.onRenderToolCallsChanged) reactSubscriber.onRenderToolCallsChanged({
1355
+ copilotkit: this,
1356
+ renderToolCalls: this.renderToolCalls
1309
1357
  });
1310
- if (mounted) setInspectorComponent(() => Component);
1311
- });
1312
- return () => {
1313
- mounted = false;
1314
- };
1315
- }, []);
1316
- if (!InspectorComponent) return null;
1317
- return /* @__PURE__ */ jsx(InspectorComponent, {
1318
- ...rest,
1319
- core: core ?? null
1320
- });
1358
+ }, "Subscriber onRenderToolCallsChanged error:");
1359
+ }
1360
+ get interruptElement() {
1361
+ return this._interruptElement;
1362
+ }
1363
+ setInterruptElement(element) {
1364
+ this._interruptElement = element;
1365
+ this.notifySubscribers((subscriber) => {
1366
+ subscriber.onInterruptElementChanged?.({
1367
+ copilotkit: this,
1368
+ interruptElement: this._interruptElement
1369
+ });
1370
+ }, "Subscriber onInterruptElementChanged error:");
1371
+ }
1372
+ subscribe(subscriber) {
1373
+ return super.subscribe(subscriber);
1374
+ }
1375
+ /**
1376
+ * Wait for pending React state updates before the follow-up agent run.
1377
+ *
1378
+ * When a frontend tool handler calls setState(), React 18 batches the update
1379
+ * and schedules a commit via its internal scheduler (MessageChannel). The
1380
+ * useAgentContext hook registers context via useLayoutEffect, which runs
1381
+ * synchronously after React commits that batch.
1382
+ *
1383
+ * Awaiting a zero-delay timeout yields to the macrotask queue. React's
1384
+ * MessageChannel task runs first, committing the pending state and running
1385
+ * useLayoutEffect (which updates the context store). The follow-up runAgent
1386
+ * call then reads fresh context.
1387
+ */
1388
+ async waitForPendingFrameworkUpdates() {
1389
+ await new Promise((resolve) => setTimeout(resolve, 0));
1390
+ }
1321
1391
  };
1322
- CopilotKitInspector.displayName = "CopilotKitInspector";
1323
1392
 
1324
1393
  //#endregion
1325
- //#region src/v2/components/license-warning-banner.tsx
1326
- const LICENSE_BANNER_OFFSET_PX = 52;
1327
- const LICENSE_BANNER_OFFSET_VAR = "--copilotkit-license-banner-offset";
1328
- const BANNER_STYLES = {
1329
- base: {
1330
- position: "fixed",
1331
- bottom: "8px",
1332
- left: "50%",
1333
- transform: "translateX(-50%)",
1334
- zIndex: 99999,
1335
- display: "inline-flex",
1336
- alignItems: "center",
1337
- gap: "12px",
1338
- whiteSpace: "nowrap",
1339
- padding: "8px 16px",
1340
- fontSize: "13px",
1341
- fontFamily: "-apple-system, BlinkMacSystemFont, 'Segoe UI', system-ui, sans-serif",
1342
- borderRadius: "6px",
1343
- boxShadow: "0 2px 8px rgba(0, 0, 0, 0.15)"
1344
- },
1345
- info: {
1346
- backgroundColor: "#eff6ff",
1347
- border: "1px solid #93c5fd",
1348
- color: "#1e40af"
1349
- },
1350
- warning: {
1351
- backgroundColor: "#fffbeb",
1352
- border: "1px solid #fbbf24",
1353
- color: "#92400e"
1354
- },
1355
- critical: {
1356
- backgroundColor: "#fef2f2",
1357
- border: "1px solid #fca5a5",
1358
- color: "#991b1b"
1359
- }
1360
- };
1361
- function getSeverityStyle(severity) {
1362
- switch (severity) {
1363
- case "warning": return BANNER_STYLES.warning;
1364
- case "critical": return BANNER_STYLES.critical;
1365
- default: return BANNER_STYLES.info;
1366
- }
1367
- }
1368
- function BannerShell({ severity, message, actionLabel, actionUrl, onDismiss }) {
1394
+ //#region src/v2/context.ts
1395
+ const CopilotKitContext = createContext(null);
1396
+ const useCopilotKit = () => {
1397
+ const context = useContext(CopilotKitContext);
1398
+ const [, forceUpdate] = useReducer((x) => x + 1, 0);
1399
+ if (!context) throw new Error("useCopilotKit must be used within CopilotKitProvider");
1369
1400
  useEffect(() => {
1370
- if (typeof document === "undefined") return;
1371
- const root = document.documentElement;
1372
- root.style.setProperty(LICENSE_BANNER_OFFSET_VAR, `${LICENSE_BANNER_OFFSET_PX}px`);
1401
+ const subscription = context.copilotkit.subscribe({ onRuntimeConnectionStatusChanged: () => {
1402
+ forceUpdate();
1403
+ } });
1373
1404
  return () => {
1374
- root.style.removeProperty(LICENSE_BANNER_OFFSET_VAR);
1405
+ subscription.unsubscribe();
1375
1406
  };
1376
1407
  }, []);
1377
- return /* @__PURE__ */ jsxs("div", {
1378
- style: {
1379
- ...BANNER_STYLES.base,
1380
- ...getSeverityStyle(severity)
1381
- },
1382
- children: [/* @__PURE__ */ jsx("span", { children: message }), /* @__PURE__ */ jsxs("div", {
1383
- style: {
1384
- display: "flex",
1385
- gap: "8px",
1386
- alignItems: "center"
1387
- },
1388
- children: [/* @__PURE__ */ jsx("a", {
1389
- href: actionUrl,
1390
- target: "_blank",
1391
- rel: "noopener noreferrer",
1392
- style: {
1393
- fontWeight: 600,
1394
- textDecoration: "underline",
1395
- color: "inherit"
1396
- },
1397
- children: actionLabel
1398
- }), onDismiss && /* @__PURE__ */ jsx("button", {
1399
- onClick: onDismiss,
1400
- style: {
1401
- background: "none",
1402
- border: "none",
1403
- cursor: "pointer",
1404
- color: "inherit",
1405
- fontSize: "16px"
1406
- },
1407
- children: "×"
1408
- })]
1409
- })]
1410
- });
1411
- }
1412
- function LicenseWarningBanner({ type, featureName, expiryDate, graceRemaining, onDismiss }) {
1413
- switch (type) {
1414
- case "no_license": return /* @__PURE__ */ jsx(BannerShell, {
1415
- severity: "info",
1416
- message: "Powered by CopilotKit",
1417
- actionLabel: "Get a license",
1418
- actionUrl: "https://copilotkit.ai/pricing",
1419
- onDismiss
1420
- });
1421
- case "feature_unlicensed": return /* @__PURE__ */ jsx(BannerShell, {
1422
- severity: "warning",
1423
- message: `⚠ The "${featureName}" feature requires a CopilotKit license.`,
1424
- actionLabel: "Get a license",
1425
- actionUrl: "https://copilotkit.ai/pricing",
1426
- onDismiss
1427
- });
1428
- case "expiring": return /* @__PURE__ */ jsx(BannerShell, {
1429
- severity: "warning",
1430
- message: `Your CopilotKit license expires in ${graceRemaining} day${graceRemaining !== 1 ? "s" : ""}. Please renew.`,
1431
- actionLabel: "Renew",
1432
- actionUrl: "https://cloud.copilotkit.ai",
1433
- onDismiss
1434
- });
1435
- case "expired": return /* @__PURE__ */ jsx(BannerShell, {
1436
- severity: "critical",
1437
- message: `Your CopilotKit license expired${expiryDate ? ` on ${expiryDate}` : ""}. Please renew at copilotkit.ai/pricing`,
1438
- actionLabel: "Renew now",
1439
- actionUrl: "https://copilotkit.ai/pricing",
1440
- onDismiss
1441
- });
1442
- case "invalid": return /* @__PURE__ */ jsx(BannerShell, {
1443
- severity: "critical",
1444
- message: "Invalid CopilotKit license token. Please check your configuration.",
1445
- actionLabel: "Get a license",
1446
- actionUrl: "https://copilotkit.ai/pricing",
1447
- onDismiss
1448
- });
1449
- default: return null;
1450
- }
1451
- }
1452
- function InlineFeatureWarning({ featureName }) {
1453
- return /* @__PURE__ */ jsxs("div", {
1454
- style: {
1455
- padding: "8px 12px",
1456
- backgroundColor: "#fffbeb",
1457
- border: "1px solid #fbbf24",
1458
- borderRadius: "6px",
1459
- fontSize: "13px",
1460
- color: "#92400e",
1461
- fontFamily: "-apple-system, BlinkMacSystemFont, 'Segoe UI', system-ui, sans-serif"
1462
- },
1463
- children: [
1464
- "⚠ The \"",
1465
- featureName,
1466
- "\" feature requires a CopilotKit license.",
1467
- " ",
1468
- /* @__PURE__ */ jsx("a", {
1469
- href: "https://copilotkit.ai/pricing",
1470
- target: "_blank",
1471
- rel: "noopener noreferrer",
1472
- style: {
1473
- color: "#b45309",
1474
- textDecoration: "underline"
1475
- },
1476
- children: "Get one at copilotkit.ai/pricing"
1477
- })
1478
- ]
1479
- });
1408
+ return context;
1409
+ };
1410
+ const LicenseContext = createContext({
1411
+ status: null,
1412
+ license: null,
1413
+ checkFeature: () => true,
1414
+ getLimit: () => null
1415
+ });
1416
+ const useLicenseContext = () => useContext(LicenseContext);
1417
+
1418
+ //#endregion
1419
+ //#region src/v2/types/defineToolCallRenderer.ts
1420
+ function defineToolCallRenderer(def) {
1421
+ const argsSchema = def.name === "*" && !def.args ? z.any() : def.args;
1422
+ return {
1423
+ name: def.name,
1424
+ args: argsSchema,
1425
+ render: def.render,
1426
+ ...def.agentId ? { agentId: def.agentId } : {}
1427
+ };
1480
1428
  }
1481
1429
 
1482
1430
  //#endregion
1483
- //#region src/v2/components/MCPAppsActivityRenderer.tsx
1484
- const PROTOCOL_VERSION = "2025-06-18";
1485
- function buildSandboxHTML(extraCspDomains) {
1486
- const baseScriptSrc = "'self' 'wasm-unsafe-eval' 'unsafe-inline' 'unsafe-eval' blob: data: http://localhost:* https://localhost:*";
1487
- const baseFrameSrc = "* blob: data: http://localhost:* https://localhost:*";
1488
- const extra = extraCspDomains?.length ? " " + extraCspDomains.join(" ") : "";
1489
- return `<!doctype html>
1490
- <html>
1491
- <head>
1492
- <meta charset="utf-8" />
1493
- <meta http-equiv="Content-Security-Policy" content="default-src 'self'; img-src * data: blob: 'unsafe-inline'; media-src * blob: data:; font-src * blob: data:; script-src ${baseScriptSrc + extra}; style-src * blob: data: 'unsafe-inline'; connect-src *; frame-src ${baseFrameSrc + extra}; base-uri 'self';" />
1494
- <style>html,body{margin:0;padding:0;height:100%;width:100%;overflow:hidden}*{box-sizing:border-box}iframe{background-color:transparent;border:none;padding:0;overflow:hidden;width:100%;height:100%}</style>
1495
- </head>
1496
- <body>
1497
- <script>
1498
- if(window.self===window.top){throw new Error("This file must be used in an iframe.")}
1499
- const inner=document.createElement("iframe");
1500
- inner.style="width:100%;height:100%;border:none;";
1501
- inner.setAttribute("sandbox","allow-scripts allow-same-origin allow-forms");
1502
- document.body.appendChild(inner);
1503
- window.addEventListener("message",async(event)=>{
1504
- if(event.source===window.parent){
1505
- if(event.data&&event.data.method==="ui/notifications/sandbox-resource-ready"){
1506
- const{html,sandbox}=event.data.params;
1507
- if(typeof sandbox==="string")inner.setAttribute("sandbox",sandbox);
1508
- if(typeof html==="string")inner.srcdoc=html;
1509
- }else if(inner&&inner.contentWindow){
1510
- inner.contentWindow.postMessage(event.data,"*");
1511
- }
1512
- }else if(event.source===inner.contentWindow){
1513
- window.parent.postMessage(event.data,"*");
1514
- }
1515
- });
1516
- window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-ready",params:{}},"*");
1517
- <\/script>
1518
- </body>
1519
- </html>`;
1520
- }
1431
+ //#region src/v2/hooks/use-render-tool.tsx
1432
+ const EMPTY_DEPS$1 = [];
1521
1433
  /**
1522
- * Queue for serializing MCP app requests to an agent.
1523
- * Ensures requests wait for the agent to stop running and are processed one at a time.
1434
+ * Registers a renderer entry in CopilotKit's `renderToolCalls` registry.
1435
+ *
1436
+ * Key behavior:
1437
+ * - deduplicates by `agentId:name` (latest registration wins),
1438
+ * - keeps renderer entries on cleanup so historical chat tool calls can still render,
1439
+ * - refreshes registration when `deps` change.
1440
+ *
1441
+ * @typeParam S - Schema type describing tool call parameters.
1442
+ * @param config - Renderer config for wildcard or named tools.
1443
+ * @param deps - Optional dependencies to refresh registration.
1444
+ *
1445
+ * @example
1446
+ * ```tsx
1447
+ * useRenderTool(
1448
+ * {
1449
+ * name: "searchDocs",
1450
+ * parameters: z.object({ query: z.string() }),
1451
+ * render: ({ status, parameters, result }) => {
1452
+ * if (status === "executing") return <div>Searching {parameters.query}</div>;
1453
+ * if (status === "complete") return <div>{result}</div>;
1454
+ * return <div>Preparing...</div>;
1455
+ * },
1456
+ * },
1457
+ * [],
1458
+ * );
1459
+ * ```
1460
+ *
1461
+ * @example
1462
+ * ```tsx
1463
+ * useRenderTool(
1464
+ * {
1465
+ * name: "summarize",
1466
+ * parameters: z.object({ text: z.string() }),
1467
+ * agentId: "research-agent",
1468
+ * render: ({ name, status }) => <div>{name}: {status}</div>,
1469
+ * },
1470
+ * [selectedAgentId],
1471
+ * );
1472
+ * ```
1524
1473
  */
1525
- var MCPAppsRequestQueue = class {
1526
- constructor() {
1527
- this.queues = /* @__PURE__ */ new Map();
1528
- this.processing = /* @__PURE__ */ new Map();
1529
- }
1530
- /**
1531
- * Add a request to the queue for a specific agent thread.
1532
- * Returns a promise that resolves when the request completes.
1533
- */
1534
- async enqueue(agent, request) {
1535
- const threadId = agent.threadId || "default";
1536
- return new Promise((resolve, reject) => {
1537
- let queue = this.queues.get(threadId);
1538
- if (!queue) {
1539
- queue = [];
1540
- this.queues.set(threadId, queue);
1541
- }
1542
- queue.push({
1543
- execute: request,
1544
- resolve,
1545
- reject
1546
- });
1547
- this.processQueue(threadId, agent);
1548
- });
1549
- }
1550
- async processQueue(threadId, agent) {
1551
- if (this.processing.get(threadId)) return;
1552
- this.processing.set(threadId, true);
1553
- try {
1554
- const queue = this.queues.get(threadId);
1555
- if (!queue) return;
1556
- while (queue.length > 0) {
1557
- const item = queue[0];
1558
- try {
1559
- await this.waitForAgentIdle(agent);
1560
- const result = await item.execute();
1561
- item.resolve(result);
1562
- } catch (error) {
1563
- item.reject(error instanceof Error ? error : new Error(String(error)));
1564
- }
1565
- queue.shift();
1566
- }
1567
- } finally {
1568
- this.processing.set(threadId, false);
1569
- }
1570
- }
1571
- waitForAgentIdle(agent) {
1572
- return new Promise((resolve) => {
1573
- if (!agent.isRunning) {
1574
- resolve();
1575
- return;
1576
- }
1577
- let done = false;
1578
- const finish = () => {
1579
- if (done) return;
1580
- done = true;
1581
- clearInterval(checkInterval);
1582
- sub.unsubscribe();
1583
- resolve();
1584
- };
1585
- const sub = agent.subscribe({
1586
- onRunFinalized: finish,
1587
- onRunFailed: finish
1588
- });
1589
- const checkInterval = setInterval(() => {
1590
- if (!agent.isRunning) finish();
1591
- }, 500);
1474
+ function useRenderTool(config, deps) {
1475
+ const { copilotkit } = useCopilotKit();
1476
+ const extraDeps = deps ?? EMPTY_DEPS$1;
1477
+ useEffect(() => {
1478
+ const renderer = config.name === "*" && !config.parameters ? defineToolCallRenderer({
1479
+ name: "*",
1480
+ render: (props) => config.render({
1481
+ ...props,
1482
+ parameters: props.args
1483
+ }),
1484
+ ...config.agentId ? { agentId: config.agentId } : {}
1485
+ }) : defineToolCallRenderer({
1486
+ name: config.name,
1487
+ args: config.parameters,
1488
+ render: (props) => config.render({
1489
+ ...props,
1490
+ parameters: props.args
1491
+ }),
1492
+ ...config.agentId ? { agentId: config.agentId } : {}
1592
1493
  });
1593
- }
1594
- };
1595
- const mcpAppsRequestQueue = new MCPAppsRequestQueue();
1596
- /**
1597
- * Activity type for MCP Apps events - must match the middleware's MCPAppsActivityType
1598
- */
1599
- const MCPAppsActivityType = "mcp-apps";
1600
- const MCPAppsActivityContentSchema = z.object({
1601
- result: z.object({
1602
- content: z.array(z.any()).optional(),
1603
- structuredContent: z.any().optional(),
1604
- isError: z.boolean().optional()
1605
- }),
1606
- resourceUri: z.string(),
1607
- serverHash: z.string(),
1608
- serverId: z.string().optional(),
1609
- toolInput: z.record(z.unknown()).optional()
1610
- });
1611
- function isRequest(msg) {
1612
- return "id" in msg && "method" in msg;
1613
- }
1614
- function isNotification(msg) {
1615
- return !("id" in msg) && "method" in msg;
1494
+ copilotkit.addHookRenderToolCall(renderer);
1495
+ }, [
1496
+ config.name,
1497
+ copilotkit,
1498
+ JSON.stringify(extraDeps)
1499
+ ]);
1616
1500
  }
1501
+
1502
+ //#endregion
1503
+ //#region src/v2/hooks/use-default-render-tool.tsx
1617
1504
  /**
1618
- * MCP Apps Extension Activity Renderer
1505
+ * Registers a wildcard (`"*"`) tool-call renderer via `useRenderTool`.
1619
1506
  *
1620
- * Renders MCP Apps UI in a sandboxed iframe with full protocol support.
1621
- * Fetches resource content on-demand via proxied MCP requests.
1622
- */
1623
- const MCPAppsActivityRenderer = function MCPAppsActivityRenderer({ content, agent }) {
1624
- const { copilotkit } = useCopilotKit();
1625
- const containerRef = useRef(null);
1626
- const iframeRef = useRef(null);
1627
- const [iframeReady, setIframeReady] = useState(false);
1628
- const [error, setError] = useState(null);
1629
- const [isLoading, setIsLoading] = useState(true);
1630
- const [iframeSize, setIframeSize] = useState({});
1631
- const [fetchedResource, setFetchedResource] = useState(null);
1632
- const contentRef = useRef(content);
1633
- contentRef.current = content;
1634
- const agentRef = useRef(agent);
1635
- agentRef.current = agent;
1636
- const fetchStateRef = useRef({
1637
- inProgress: false,
1638
- promise: null,
1639
- resourceUri: null
1640
- });
1641
- const sendToIframe = useCallback((msg) => {
1642
- if (iframeRef.current?.contentWindow) {
1507
+ * - Call with no config to use CopilotKit's built-in default tool-call card.
1508
+ * - Pass `config.render` to replace the default UI with your own fallback renderer.
1509
+ *
1510
+ * This is useful when you want a generic renderer for tools that do not have a
1511
+ * dedicated `useRenderTool({ name: "..." })` registration.
1512
+ *
1513
+ * @param config - Optional custom wildcard render function.
1514
+ * @param deps - Optional dependencies to refresh registration.
1515
+ *
1516
+ * @example
1517
+ * ```tsx
1518
+ * useDefaultRenderTool();
1519
+ * ```
1520
+ *
1521
+ * @example
1522
+ * ```tsx
1523
+ * useDefaultRenderTool({
1524
+ * render: ({ name, status }) => <div>{name}: {status}</div>,
1525
+ * });
1526
+ * ```
1527
+ *
1528
+ * @example
1529
+ * ```tsx
1530
+ * useDefaultRenderTool(
1531
+ * {
1532
+ * render: ({ name, result }) => (
1533
+ * <ToolEventRow title={name} payload={result} compact={compactMode} />
1534
+ * ),
1535
+ * },
1536
+ * [compactMode],
1537
+ * );
1538
+ * ```
1539
+ */
1540
+ function useDefaultRenderTool(config, deps) {
1541
+ useRenderTool({
1542
+ name: "*",
1543
+ render: config?.render ?? DefaultToolCallRenderer
1544
+ }, deps);
1545
+ }
1546
+ function DefaultToolCallRenderer({ name, parameters, status, result }) {
1547
+ const [isExpanded, setIsExpanded] = useState(false);
1548
+ const statusString = String(status);
1549
+ const isActive = statusString === "inProgress" || statusString === "executing";
1550
+ const isComplete = statusString === "complete";
1551
+ const statusLabel = isActive ? "Running" : isComplete ? "Done" : status;
1552
+ const dotColor = isActive ? "#f59e0b" : isComplete ? "#10b981" : "#a1a1aa";
1553
+ const badgeBg = isActive ? "#fef3c7" : isComplete ? "#d1fae5" : "#f4f4f5";
1554
+ const badgeColor = isActive ? "#92400e" : isComplete ? "#065f46" : "#3f3f46";
1555
+ return /* @__PURE__ */ jsx("div", {
1556
+ "data-testid": "copilot-tool-render",
1557
+ "data-tool-name": name,
1558
+ "data-status": statusString,
1559
+ "data-args": safeStringifyForAttr(parameters),
1560
+ "data-result": safeStringifyForAttr(result),
1561
+ style: {
1562
+ marginTop: "8px",
1563
+ paddingBottom: "8px"
1564
+ },
1565
+ children: /* @__PURE__ */ jsxs("div", {
1566
+ style: {
1567
+ borderRadius: "12px",
1568
+ border: "1px solid #e4e4e7",
1569
+ backgroundColor: "#fafafa",
1570
+ padding: "14px 16px"
1571
+ },
1572
+ children: [/* @__PURE__ */ jsxs("div", {
1573
+ onClick: () => setIsExpanded(!isExpanded),
1574
+ style: {
1575
+ display: "flex",
1576
+ alignItems: "center",
1577
+ justifyContent: "space-between",
1578
+ gap: "10px",
1579
+ cursor: "pointer",
1580
+ userSelect: "none"
1581
+ },
1582
+ children: [/* @__PURE__ */ jsxs("div", {
1583
+ style: {
1584
+ display: "flex",
1585
+ alignItems: "center",
1586
+ gap: "8px",
1587
+ minWidth: 0
1588
+ },
1589
+ children: [
1590
+ /* @__PURE__ */ jsx("svg", {
1591
+ style: {
1592
+ height: "14px",
1593
+ width: "14px",
1594
+ color: "#71717a",
1595
+ transition: "transform 0.15s",
1596
+ transform: isExpanded ? "rotate(90deg)" : "rotate(0deg)",
1597
+ flexShrink: 0
1598
+ },
1599
+ fill: "none",
1600
+ viewBox: "0 0 24 24",
1601
+ strokeWidth: 2,
1602
+ stroke: "currentColor",
1603
+ children: /* @__PURE__ */ jsx("path", {
1604
+ strokeLinecap: "round",
1605
+ strokeLinejoin: "round",
1606
+ d: "M8.25 4.5l7.5 7.5-7.5 7.5"
1607
+ })
1608
+ }),
1609
+ /* @__PURE__ */ jsx("span", { style: {
1610
+ display: "inline-block",
1611
+ height: "8px",
1612
+ width: "8px",
1613
+ borderRadius: "50%",
1614
+ backgroundColor: dotColor,
1615
+ flexShrink: 0
1616
+ } }),
1617
+ /* @__PURE__ */ jsx("span", {
1618
+ "data-testid": "copilot-tool-render-name",
1619
+ style: {
1620
+ fontSize: "13px",
1621
+ fontWeight: 600,
1622
+ color: "#18181b",
1623
+ overflow: "hidden",
1624
+ textOverflow: "ellipsis",
1625
+ whiteSpace: "nowrap"
1626
+ },
1627
+ children: name
1628
+ })
1629
+ ]
1630
+ }), /* @__PURE__ */ jsx("span", {
1631
+ "data-testid": "copilot-tool-render-status",
1632
+ style: {
1633
+ display: "inline-flex",
1634
+ alignItems: "center",
1635
+ borderRadius: "9999px",
1636
+ padding: "2px 8px",
1637
+ fontSize: "11px",
1638
+ fontWeight: 500,
1639
+ backgroundColor: badgeBg,
1640
+ color: badgeColor,
1641
+ flexShrink: 0
1642
+ },
1643
+ children: statusLabel
1644
+ })]
1645
+ }), isExpanded && /* @__PURE__ */ jsxs("div", {
1646
+ style: {
1647
+ marginTop: "12px",
1648
+ display: "grid",
1649
+ gap: "12px"
1650
+ },
1651
+ children: [/* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsx("div", {
1652
+ style: {
1653
+ fontSize: "10px",
1654
+ textTransform: "uppercase",
1655
+ letterSpacing: "0.05em",
1656
+ color: "#71717a"
1657
+ },
1658
+ children: "Arguments"
1659
+ }), /* @__PURE__ */ jsx("pre", {
1660
+ style: {
1661
+ marginTop: "6px",
1662
+ maxHeight: "200px",
1663
+ overflow: "auto",
1664
+ borderRadius: "6px",
1665
+ backgroundColor: "#f4f4f5",
1666
+ padding: "10px",
1667
+ fontSize: "11px",
1668
+ lineHeight: 1.6,
1669
+ color: "#27272a",
1670
+ whiteSpace: "pre-wrap",
1671
+ wordBreak: "break-word"
1672
+ },
1673
+ children: JSON.stringify(parameters ?? {}, null, 2)
1674
+ })] }), result !== void 0 && /* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsx("div", {
1675
+ style: {
1676
+ fontSize: "10px",
1677
+ textTransform: "uppercase",
1678
+ letterSpacing: "0.05em",
1679
+ color: "#71717a"
1680
+ },
1681
+ children: "Result"
1682
+ }), /* @__PURE__ */ jsx("pre", {
1683
+ style: {
1684
+ marginTop: "6px",
1685
+ maxHeight: "200px",
1686
+ overflow: "auto",
1687
+ borderRadius: "6px",
1688
+ backgroundColor: "#f4f4f5",
1689
+ padding: "10px",
1690
+ fontSize: "11px",
1691
+ lineHeight: 1.6,
1692
+ color: "#27272a",
1693
+ whiteSpace: "pre-wrap",
1694
+ wordBreak: "break-word"
1695
+ },
1696
+ children: typeof result === "string" ? result : JSON.stringify(result, null, 2)
1697
+ })] })]
1698
+ })]
1699
+ })
1700
+ });
1701
+ }
1702
+ function safeStringifyForAttr(value) {
1703
+ if (value === void 0 || value === null) return "";
1704
+ if (typeof value === "string") return value;
1705
+ try {
1706
+ return JSON.stringify(value);
1707
+ } catch {
1708
+ return String(value);
1709
+ }
1710
+ }
1711
+
1712
+ //#endregion
1713
+ //#region src/v2/hooks/use-render-tool-call.tsx
1714
+ /**
1715
+ * Memoized component that renders a single tool call.
1716
+ * This prevents unnecessary re-renders when parent components update
1717
+ * but the tool call data hasn't changed.
1718
+ */
1719
+ const ToolCallRenderer = React.memo(function ToolCallRenderer({ toolCall, toolMessage, RenderComponent, isExecuting }) {
1720
+ const args = useMemo(() => partialJSONParse(toolCall.function.arguments), [toolCall.function.arguments]);
1721
+ const toolName = toolCall.function.name;
1722
+ if (toolMessage) return /* @__PURE__ */ jsx(RenderComponent, {
1723
+ name: toolName,
1724
+ toolCallId: toolCall.id,
1725
+ args,
1726
+ status: ToolCallStatus.Complete,
1727
+ result: toolMessage.content
1728
+ });
1729
+ else if (isExecuting) return /* @__PURE__ */ jsx(RenderComponent, {
1730
+ name: toolName,
1731
+ toolCallId: toolCall.id,
1732
+ args,
1733
+ status: ToolCallStatus.Executing,
1734
+ result: void 0
1735
+ });
1736
+ else return /* @__PURE__ */ jsx(RenderComponent, {
1737
+ name: toolName,
1738
+ toolCallId: toolCall.id,
1739
+ args,
1740
+ status: ToolCallStatus.InProgress,
1741
+ result: void 0
1742
+ });
1743
+ }, (prevProps, nextProps) => {
1744
+ if (prevProps.toolCall.id !== nextProps.toolCall.id) return false;
1745
+ if (prevProps.toolCall.function.name !== nextProps.toolCall.function.name) return false;
1746
+ if (prevProps.toolCall.function.arguments !== nextProps.toolCall.function.arguments) return false;
1747
+ if (prevProps.toolMessage?.content !== nextProps.toolMessage?.content) return false;
1748
+ if (prevProps.isExecuting !== nextProps.isExecuting) return false;
1749
+ if (prevProps.RenderComponent !== nextProps.RenderComponent) return false;
1750
+ return true;
1751
+ });
1752
+ /**
1753
+ * Hook that returns a function to render tool calls based on the render functions
1754
+ * defined in CopilotKitProvider.
1755
+ *
1756
+ * @returns A function that takes a tool call and optional tool message and returns the rendered component
1757
+ */
1758
+ function useRenderToolCall() {
1759
+ const { copilotkit, executingToolCallIds } = useCopilotKit();
1760
+ const agentId = useCopilotChatConfiguration()?.agentId ?? DEFAULT_AGENT_ID;
1761
+ const renderToolCalls = useSyncExternalStore((callback) => {
1762
+ return copilotkit.subscribe({ onRenderToolCallsChanged: callback }).unsubscribe;
1763
+ }, () => copilotkit.renderToolCalls, () => copilotkit.renderToolCalls);
1764
+ return useCallback(({ toolCall, toolMessage }) => {
1765
+ const exactMatches = renderToolCalls.filter((rc) => rc.name === toolCall.function.name);
1766
+ return /* @__PURE__ */ jsx(ToolCallRenderer, {
1767
+ toolCall,
1768
+ toolMessage,
1769
+ RenderComponent: (exactMatches.find((rc) => rc.agentId === agentId) || exactMatches.find((rc) => !rc.agentId) || exactMatches[0] || renderToolCalls.find((rc) => rc.name === "*"))?.render ?? defaultToolCallRenderAdapter,
1770
+ isExecuting: executingToolCallIds.has(toolCall.id)
1771
+ }, toolCall.id);
1772
+ }, [
1773
+ renderToolCalls,
1774
+ executingToolCallIds,
1775
+ agentId
1776
+ ]);
1777
+ }
1778
+ function defaultToolCallRenderAdapter(props) {
1779
+ const status = props.status === ToolCallStatus.Complete ? "complete" : props.status === ToolCallStatus.Executing ? "executing" : "inProgress";
1780
+ return /* @__PURE__ */ jsx(DefaultToolCallRenderer, {
1781
+ name: props.name,
1782
+ parameters: props.args,
1783
+ status,
1784
+ result: props.result
1785
+ });
1786
+ }
1787
+
1788
+ //#endregion
1789
+ //#region src/v2/components/CopilotKitInspector.tsx
1790
+ const CopilotKitInspector = ({ core, ...rest }) => {
1791
+ const [InspectorComponent, setInspectorComponent] = React$1.useState(null);
1792
+ React$1.useEffect(() => {
1793
+ let mounted = true;
1794
+ import("@copilotkit/web-inspector").then((mod) => {
1795
+ mod.defineWebInspector?.();
1796
+ const Component = createComponent({
1797
+ tagName: mod.WEB_INSPECTOR_TAG,
1798
+ elementClass: mod.WebInspectorElement,
1799
+ react: React$1
1800
+ });
1801
+ if (mounted) setInspectorComponent(() => Component);
1802
+ });
1803
+ return () => {
1804
+ mounted = false;
1805
+ };
1806
+ }, []);
1807
+ if (!InspectorComponent) return null;
1808
+ return /* @__PURE__ */ jsx(InspectorComponent, {
1809
+ ...rest,
1810
+ core: core ?? null
1811
+ });
1812
+ };
1813
+ CopilotKitInspector.displayName = "CopilotKitInspector";
1814
+
1815
+ //#endregion
1816
+ //#region src/v2/components/license-warning-banner.tsx
1817
+ const LICENSE_BANNER_OFFSET_PX = 52;
1818
+ const LICENSE_BANNER_OFFSET_VAR = "--copilotkit-license-banner-offset";
1819
+ const BANNER_STYLES = {
1820
+ base: {
1821
+ position: "fixed",
1822
+ bottom: "8px",
1823
+ left: "50%",
1824
+ transform: "translateX(-50%)",
1825
+ zIndex: 99999,
1826
+ display: "inline-flex",
1827
+ alignItems: "center",
1828
+ gap: "12px",
1829
+ whiteSpace: "nowrap",
1830
+ padding: "8px 16px",
1831
+ fontSize: "13px",
1832
+ fontFamily: "-apple-system, BlinkMacSystemFont, 'Segoe UI', system-ui, sans-serif",
1833
+ borderRadius: "6px",
1834
+ boxShadow: "0 2px 8px rgba(0, 0, 0, 0.15)"
1835
+ },
1836
+ info: {
1837
+ backgroundColor: "#eff6ff",
1838
+ border: "1px solid #93c5fd",
1839
+ color: "#1e40af"
1840
+ },
1841
+ warning: {
1842
+ backgroundColor: "#fffbeb",
1843
+ border: "1px solid #fbbf24",
1844
+ color: "#92400e"
1845
+ },
1846
+ critical: {
1847
+ backgroundColor: "#fef2f2",
1848
+ border: "1px solid #fca5a5",
1849
+ color: "#991b1b"
1850
+ }
1851
+ };
1852
+ function getSeverityStyle(severity) {
1853
+ switch (severity) {
1854
+ case "warning": return BANNER_STYLES.warning;
1855
+ case "critical": return BANNER_STYLES.critical;
1856
+ default: return BANNER_STYLES.info;
1857
+ }
1858
+ }
1859
+ function BannerShell({ severity, message, actionLabel, actionUrl, onDismiss }) {
1860
+ useEffect(() => {
1861
+ if (typeof document === "undefined") return;
1862
+ const root = document.documentElement;
1863
+ root.style.setProperty(LICENSE_BANNER_OFFSET_VAR, `${LICENSE_BANNER_OFFSET_PX}px`);
1864
+ return () => {
1865
+ root.style.removeProperty(LICENSE_BANNER_OFFSET_VAR);
1866
+ };
1867
+ }, []);
1868
+ return /* @__PURE__ */ jsxs("div", {
1869
+ style: {
1870
+ ...BANNER_STYLES.base,
1871
+ ...getSeverityStyle(severity)
1872
+ },
1873
+ children: [/* @__PURE__ */ jsx("span", { children: message }), /* @__PURE__ */ jsxs("div", {
1874
+ style: {
1875
+ display: "flex",
1876
+ gap: "8px",
1877
+ alignItems: "center"
1878
+ },
1879
+ children: [/* @__PURE__ */ jsx("a", {
1880
+ href: actionUrl,
1881
+ target: "_blank",
1882
+ rel: "noopener noreferrer",
1883
+ style: {
1884
+ fontWeight: 600,
1885
+ textDecoration: "underline",
1886
+ color: "inherit"
1887
+ },
1888
+ children: actionLabel
1889
+ }), onDismiss && /* @__PURE__ */ jsx("button", {
1890
+ onClick: onDismiss,
1891
+ style: {
1892
+ background: "none",
1893
+ border: "none",
1894
+ cursor: "pointer",
1895
+ color: "inherit",
1896
+ fontSize: "16px"
1897
+ },
1898
+ children: "×"
1899
+ })]
1900
+ })]
1901
+ });
1902
+ }
1903
+ function LicenseWarningBanner({ type, featureName, expiryDate, graceRemaining, onDismiss }) {
1904
+ switch (type) {
1905
+ case "no_license": return /* @__PURE__ */ jsx(BannerShell, {
1906
+ severity: "info",
1907
+ message: "Powered by CopilotKit",
1908
+ actionLabel: "Get a license",
1909
+ actionUrl: "https://copilotkit.ai/pricing",
1910
+ onDismiss
1911
+ });
1912
+ case "feature_unlicensed": return /* @__PURE__ */ jsx(BannerShell, {
1913
+ severity: "warning",
1914
+ message: `⚠ The "${featureName}" feature requires a CopilotKit license.`,
1915
+ actionLabel: "Get a license",
1916
+ actionUrl: "https://copilotkit.ai/pricing",
1917
+ onDismiss
1918
+ });
1919
+ case "expiring": return /* @__PURE__ */ jsx(BannerShell, {
1920
+ severity: "warning",
1921
+ message: `Your CopilotKit license expires in ${graceRemaining} day${graceRemaining !== 1 ? "s" : ""}. Please renew.`,
1922
+ actionLabel: "Renew",
1923
+ actionUrl: "https://cloud.copilotkit.ai",
1924
+ onDismiss
1925
+ });
1926
+ case "expired": return /* @__PURE__ */ jsx(BannerShell, {
1927
+ severity: "critical",
1928
+ message: `Your CopilotKit license expired${expiryDate ? ` on ${expiryDate}` : ""}. Please renew at copilotkit.ai/pricing`,
1929
+ actionLabel: "Renew now",
1930
+ actionUrl: "https://copilotkit.ai/pricing",
1931
+ onDismiss
1932
+ });
1933
+ case "invalid": return /* @__PURE__ */ jsx(BannerShell, {
1934
+ severity: "critical",
1935
+ message: "Invalid CopilotKit license token. Please check your configuration.",
1936
+ actionLabel: "Get a license",
1937
+ actionUrl: "https://copilotkit.ai/pricing",
1938
+ onDismiss
1939
+ });
1940
+ default: return null;
1941
+ }
1942
+ }
1943
+ function InlineFeatureWarning({ featureName }) {
1944
+ return /* @__PURE__ */ jsxs("div", {
1945
+ style: {
1946
+ padding: "8px 12px",
1947
+ backgroundColor: "#fffbeb",
1948
+ border: "1px solid #fbbf24",
1949
+ borderRadius: "6px",
1950
+ fontSize: "13px",
1951
+ color: "#92400e",
1952
+ fontFamily: "-apple-system, BlinkMacSystemFont, 'Segoe UI', system-ui, sans-serif"
1953
+ },
1954
+ children: [
1955
+ "⚠ The \"",
1956
+ featureName,
1957
+ "\" feature requires a CopilotKit license.",
1958
+ " ",
1959
+ /* @__PURE__ */ jsx("a", {
1960
+ href: "https://copilotkit.ai/pricing",
1961
+ target: "_blank",
1962
+ rel: "noopener noreferrer",
1963
+ style: {
1964
+ color: "#b45309",
1965
+ textDecoration: "underline"
1966
+ },
1967
+ children: "Get one at copilotkit.ai/pricing"
1968
+ })
1969
+ ]
1970
+ });
1971
+ }
1972
+
1973
+ //#endregion
1974
+ //#region src/v2/components/MCPAppsActivityRenderer.tsx
1975
+ const PROTOCOL_VERSION = "2025-06-18";
1976
+ function buildSandboxHTML(extraCspDomains) {
1977
+ const baseScriptSrc = "'self' 'wasm-unsafe-eval' 'unsafe-inline' 'unsafe-eval' blob: data: http://localhost:* https://localhost:*";
1978
+ const baseFrameSrc = "* blob: data: http://localhost:* https://localhost:*";
1979
+ const extra = extraCspDomains?.length ? " " + extraCspDomains.join(" ") : "";
1980
+ return `<!doctype html>
1981
+ <html>
1982
+ <head>
1983
+ <meta charset="utf-8" />
1984
+ <meta http-equiv="Content-Security-Policy" content="default-src 'self'; img-src * data: blob: 'unsafe-inline'; media-src * blob: data:; font-src * blob: data:; script-src ${baseScriptSrc + extra}; style-src * blob: data: 'unsafe-inline'; connect-src *; frame-src ${baseFrameSrc + extra}; base-uri 'self';" />
1985
+ <style>html,body{margin:0;padding:0;height:100%;width:100%;overflow:hidden}*{box-sizing:border-box}iframe{background-color:transparent;border:none;padding:0;overflow:hidden;width:100%;height:100%}</style>
1986
+ </head>
1987
+ <body>
1988
+ <script>
1989
+ if(window.self===window.top){throw new Error("This file must be used in an iframe.")}
1990
+ const inner=document.createElement("iframe");
1991
+ inner.style="width:100%;height:100%;border:none;";
1992
+ inner.setAttribute("sandbox","allow-scripts allow-same-origin allow-forms");
1993
+ document.body.appendChild(inner);
1994
+ window.addEventListener("message",async(event)=>{
1995
+ if(event.source===window.parent){
1996
+ if(event.data&&event.data.method==="ui/notifications/sandbox-resource-ready"){
1997
+ const{html,sandbox}=event.data.params;
1998
+ if(typeof sandbox==="string")inner.setAttribute("sandbox",sandbox);
1999
+ if(typeof html==="string")inner.srcdoc=html;
2000
+ }else if(inner&&inner.contentWindow){
2001
+ inner.contentWindow.postMessage(event.data,"*");
2002
+ }
2003
+ }else if(event.source===inner.contentWindow){
2004
+ window.parent.postMessage(event.data,"*");
2005
+ }
2006
+ });
2007
+ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-ready",params:{}},"*");
2008
+ <\/script>
2009
+ </body>
2010
+ </html>`;
2011
+ }
2012
+ /**
2013
+ * Queue for serializing MCP app requests to an agent.
2014
+ * Ensures requests wait for the agent to stop running and are processed one at a time.
2015
+ */
2016
+ var MCPAppsRequestQueue = class {
2017
+ constructor() {
2018
+ this.queues = /* @__PURE__ */ new Map();
2019
+ this.processing = /* @__PURE__ */ new Map();
2020
+ }
2021
+ /**
2022
+ * Add a request to the queue for a specific agent thread.
2023
+ * Returns a promise that resolves when the request completes.
2024
+ */
2025
+ async enqueue(agent, request) {
2026
+ const threadId = agent.threadId || "default";
2027
+ return new Promise((resolve, reject) => {
2028
+ let queue = this.queues.get(threadId);
2029
+ if (!queue) {
2030
+ queue = [];
2031
+ this.queues.set(threadId, queue);
2032
+ }
2033
+ queue.push({
2034
+ execute: request,
2035
+ resolve,
2036
+ reject
2037
+ });
2038
+ this.processQueue(threadId, agent);
2039
+ });
2040
+ }
2041
+ async processQueue(threadId, agent) {
2042
+ if (this.processing.get(threadId)) return;
2043
+ this.processing.set(threadId, true);
2044
+ try {
2045
+ const queue = this.queues.get(threadId);
2046
+ if (!queue) return;
2047
+ while (queue.length > 0) {
2048
+ const item = queue[0];
2049
+ try {
2050
+ await this.waitForAgentIdle(agent);
2051
+ const result = await item.execute();
2052
+ item.resolve(result);
2053
+ } catch (error) {
2054
+ item.reject(error instanceof Error ? error : new Error(String(error)));
2055
+ }
2056
+ queue.shift();
2057
+ }
2058
+ } finally {
2059
+ this.processing.set(threadId, false);
2060
+ }
2061
+ }
2062
+ waitForAgentIdle(agent) {
2063
+ return new Promise((resolve) => {
2064
+ if (!agent.isRunning) {
2065
+ resolve();
2066
+ return;
2067
+ }
2068
+ let done = false;
2069
+ const finish = () => {
2070
+ if (done) return;
2071
+ done = true;
2072
+ clearInterval(checkInterval);
2073
+ sub.unsubscribe();
2074
+ resolve();
2075
+ };
2076
+ const sub = agent.subscribe({
2077
+ onRunFinalized: finish,
2078
+ onRunFailed: finish
2079
+ });
2080
+ const checkInterval = setInterval(() => {
2081
+ if (!agent.isRunning) finish();
2082
+ }, 500);
2083
+ });
2084
+ }
2085
+ };
2086
+ const mcpAppsRequestQueue = new MCPAppsRequestQueue();
2087
+ /**
2088
+ * Activity type for MCP Apps events - must match the middleware's MCPAppsActivityType
2089
+ */
2090
+ const MCPAppsActivityType = "mcp-apps";
2091
+ const MCPAppsActivityContentSchema = z.object({
2092
+ result: z.object({
2093
+ content: z.array(z.any()).optional(),
2094
+ structuredContent: z.any().optional(),
2095
+ isError: z.boolean().optional()
2096
+ }),
2097
+ resourceUri: z.string(),
2098
+ serverHash: z.string(),
2099
+ serverId: z.string().optional(),
2100
+ toolInput: z.record(z.unknown()).optional()
2101
+ });
2102
+ function isRequest(msg) {
2103
+ return "id" in msg && "method" in msg;
2104
+ }
2105
+ function isNotification(msg) {
2106
+ return !("id" in msg) && "method" in msg;
2107
+ }
2108
+ /**
2109
+ * MCP Apps Extension Activity Renderer
2110
+ *
2111
+ * Renders MCP Apps UI in a sandboxed iframe with full protocol support.
2112
+ * Fetches resource content on-demand via proxied MCP requests.
2113
+ */
2114
+ const MCPAppsActivityRenderer = function MCPAppsActivityRenderer({ content, agent }) {
2115
+ const { copilotkit } = useCopilotKit();
2116
+ const containerRef = useRef(null);
2117
+ const iframeRef = useRef(null);
2118
+ const [iframeReady, setIframeReady] = useState(false);
2119
+ const [error, setError] = useState(null);
2120
+ const [isLoading, setIsLoading] = useState(true);
2121
+ const [iframeSize, setIframeSize] = useState({});
2122
+ const [fetchedResource, setFetchedResource] = useState(null);
2123
+ const contentRef = useRef(content);
2124
+ contentRef.current = content;
2125
+ const agentRef = useRef(agent);
2126
+ agentRef.current = agent;
2127
+ const fetchStateRef = useRef({
2128
+ inProgress: false,
2129
+ promise: null,
2130
+ resourceUri: null
2131
+ });
2132
+ const sendToIframe = useCallback((msg) => {
2133
+ if (iframeRef.current?.contentWindow) {
1643
2134
  console.log("[MCPAppsRenderer] Sending to iframe:", msg);
1644
2135
  iframeRef.current.contentWindow.postMessage(msg, "*");
1645
2136
  }
@@ -2532,18 +3023,6 @@ function getOperationSurfaceId(operation) {
2532
3023
  return operation?.createSurface?.surfaceId ?? operation?.updateComponents?.surfaceId ?? operation?.updateDataModel?.surfaceId ?? operation?.deleteSurface?.surfaceId ?? null;
2533
3024
  }
2534
3025
 
2535
- //#endregion
2536
- //#region src/v2/types/defineToolCallRenderer.ts
2537
- function defineToolCallRenderer(def) {
2538
- const argsSchema = def.name === "*" && !def.args ? z.any() : def.args;
2539
- return {
2540
- name: def.name,
2541
- args: argsSchema,
2542
- render: def.render,
2543
- ...def.agentId ? { agentId: def.agentId } : {}
2544
- };
2545
- }
2546
-
2547
3026
  //#endregion
2548
3027
  //#region src/v2/a2ui/A2UIToolCallRenderer.tsx
2549
3028
  /**
@@ -2912,126 +3391,30 @@ function A2UICatalogContext({ catalog, includeSchema }) {
2912
3391
  useAgentContext({
2913
3392
  description: "A2UI catalog capabilities: available catalog IDs and custom component definitions the client can render.",
2914
3393
  value: buildCatalogContextValue(catalog)
2915
- });
2916
- const { copilotkit } = useCopilotKit();
2917
- const schemaValue = useMemo(() => includeSchema !== false ? JSON.stringify(extractCatalogComponentSchemas(catalog)) : null, [catalog, includeSchema]);
2918
- useLayoutEffect(() => {
2919
- if (!copilotkit || !schemaValue) return;
2920
- const ids = [];
2921
- ids.push(copilotkit.addContext({
2922
- description: A2UI_SCHEMA_CONTEXT_DESCRIPTION,
2923
- value: schemaValue
2924
- }));
2925
- ids.push(copilotkit.addContext({
2926
- description: "A2UI generation guidelines — protocol rules, tool arguments, path rules, data model format, and form/two-way-binding instructions.",
2927
- value: A2UI_DEFAULT_GENERATION_GUIDELINES
2928
- }));
2929
- ids.push(copilotkit.addContext({
2930
- description: "A2UI design guidelines — visual design rules, component hierarchy tips, and action handler patterns.",
2931
- value: A2UI_DEFAULT_DESIGN_GUIDELINES
2932
- }));
2933
- return () => {
2934
- for (const id of ids) copilotkit.removeContext(id);
2935
- };
2936
- }, [copilotkit, schemaValue]);
2937
- return null;
2938
- }
2939
-
2940
- //#endregion
2941
- //#region src/v2/lib/react-core.ts
2942
- var CopilotKitCoreReact = class extends CopilotKitCore {
2943
- constructor(config) {
2944
- super(config);
2945
- this._renderToolCalls = [];
2946
- this._hookRenderToolCalls = /* @__PURE__ */ new Map();
2947
- this._cachedMergedRenderToolCalls = null;
2948
- this._renderCustomMessages = [];
2949
- this._renderActivityMessages = [];
2950
- this._interruptElement = null;
2951
- this._renderToolCalls = config.renderToolCalls ?? [];
2952
- this._renderCustomMessages = config.renderCustomMessages ?? [];
2953
- this._renderActivityMessages = config.renderActivityMessages ?? [];
2954
- }
2955
- get renderCustomMessages() {
2956
- return this._renderCustomMessages;
2957
- }
2958
- get renderActivityMessages() {
2959
- return this._renderActivityMessages;
2960
- }
2961
- get renderToolCalls() {
2962
- if (this._hookRenderToolCalls.size === 0) return this._renderToolCalls;
2963
- if (this._cachedMergedRenderToolCalls) return this._cachedMergedRenderToolCalls;
2964
- const merged = /* @__PURE__ */ new Map();
2965
- for (const rc of this._renderToolCalls) merged.set(`${rc.agentId ?? ""}:${rc.name}`, rc);
2966
- for (const [key, rc] of this._hookRenderToolCalls) merged.set(key, rc);
2967
- this._cachedMergedRenderToolCalls = Array.from(merged.values());
2968
- return this._cachedMergedRenderToolCalls;
2969
- }
2970
- setRenderActivityMessages(renderers) {
2971
- this._renderActivityMessages = renderers;
2972
- }
2973
- setRenderCustomMessages(renderers) {
2974
- this._renderCustomMessages = renderers;
2975
- }
2976
- setRenderToolCalls(renderToolCalls) {
2977
- this._renderToolCalls = renderToolCalls;
2978
- this._cachedMergedRenderToolCalls = null;
2979
- this._notifyRenderToolCallsChanged();
2980
- }
2981
- addHookRenderToolCall(entry) {
2982
- const key = `${entry.agentId ?? ""}:${entry.name}`;
2983
- this._hookRenderToolCalls.set(key, entry);
2984
- this._cachedMergedRenderToolCalls = null;
2985
- this._notifyRenderToolCallsChanged();
2986
- }
2987
- removeHookRenderToolCall(name, agentId) {
2988
- const key = `${agentId ?? ""}:${name}`;
2989
- if (this._hookRenderToolCalls.delete(key)) {
2990
- this._cachedMergedRenderToolCalls = null;
2991
- this._notifyRenderToolCallsChanged();
2992
- }
2993
- }
2994
- _notifyRenderToolCallsChanged() {
2995
- this.notifySubscribers((subscriber) => {
2996
- const reactSubscriber = subscriber;
2997
- if (reactSubscriber.onRenderToolCallsChanged) reactSubscriber.onRenderToolCallsChanged({
2998
- copilotkit: this,
2999
- renderToolCalls: this.renderToolCalls
3000
- });
3001
- }, "Subscriber onRenderToolCallsChanged error:");
3002
- }
3003
- get interruptElement() {
3004
- return this._interruptElement;
3005
- }
3006
- setInterruptElement(element) {
3007
- this._interruptElement = element;
3008
- this.notifySubscribers((subscriber) => {
3009
- subscriber.onInterruptElementChanged?.({
3010
- copilotkit: this,
3011
- interruptElement: this._interruptElement
3012
- });
3013
- }, "Subscriber onInterruptElementChanged error:");
3014
- }
3015
- subscribe(subscriber) {
3016
- return super.subscribe(subscriber);
3017
- }
3018
- /**
3019
- * Wait for pending React state updates before the follow-up agent run.
3020
- *
3021
- * When a frontend tool handler calls setState(), React 18 batches the update
3022
- * and schedules a commit via its internal scheduler (MessageChannel). The
3023
- * useAgentContext hook registers context via useLayoutEffect, which runs
3024
- * synchronously after React commits that batch.
3025
- *
3026
- * Awaiting a zero-delay timeout yields to the macrotask queue. React's
3027
- * MessageChannel task runs first, committing the pending state and running
3028
- * useLayoutEffect (which updates the context store). The follow-up runAgent
3029
- * call then reads fresh context.
3030
- */
3031
- async waitForPendingFrameworkUpdates() {
3032
- await new Promise((resolve) => setTimeout(resolve, 0));
3033
- }
3034
- };
3394
+ });
3395
+ const { copilotkit } = useCopilotKit();
3396
+ const schemaValue = useMemo(() => includeSchema !== false ? JSON.stringify(extractCatalogComponentSchemas(catalog)) : null, [catalog, includeSchema]);
3397
+ useLayoutEffect(() => {
3398
+ if (!copilotkit || !schemaValue) return;
3399
+ const ids = [];
3400
+ ids.push(copilotkit.addContext({
3401
+ description: A2UI_SCHEMA_CONTEXT_DESCRIPTION,
3402
+ value: schemaValue
3403
+ }));
3404
+ ids.push(copilotkit.addContext({
3405
+ description: "A2UI generation guidelines — protocol rules, tool arguments, path rules, data model format, and form/two-way-binding instructions.",
3406
+ value: A2UI_DEFAULT_GENERATION_GUIDELINES
3407
+ }));
3408
+ ids.push(copilotkit.addContext({
3409
+ description: "A2UI design guidelines — visual design rules, component hierarchy tips, and action handler patterns.",
3410
+ value: A2UI_DEFAULT_DESIGN_GUIDELINES
3411
+ }));
3412
+ return () => {
3413
+ for (const id of ids) copilotkit.removeContext(id);
3414
+ };
3415
+ }, [copilotkit, schemaValue]);
3416
+ return null;
3417
+ }
3035
3418
 
3036
3419
  //#endregion
3037
3420
  //#region src/v2/providers/CopilotKitProvider.tsx
@@ -3048,12 +3431,6 @@ const DEFAULT_DESIGN_SKILL = `When generating UI with generateSandboxedUi, follo
3048
3431
  - Minimal transitions (150ms) for hover/focus states only. No decorative animations.
3049
3432
  - Keep the UI focused and dense — avoid excessive padding. Use compact spacing (8–12px gaps, 10–14px padding in controls).`;
3050
3433
  const GENERATE_SANDBOXED_UI_DESCRIPTION = "Generate sandboxed UI. IMPORTANT: The generated code runs in a sandboxed iframe WITHOUT same-origin access. Do NOT use localStorage, sessionStorage, document.cookie, IndexedDB, or fetch/XMLHttpRequest to same-origin URLs. To communicate with the host application, use Websandbox.connection.remote.<functionName>(args) which returns a Promise.\n\nYou CAN use external libraries from CDNs by including <script> or <link> tags in the HTML <head> (e.g., Chart.js, D3, Three.js, x-data-spreadsheet, etc.). CDN resources load normally inside the sandbox.\n\nPARAMETER ORDER IS CRITICAL — generate parameters in exactly this order:\n1. initialHeight + placeholderMessages (shown to user while generating)\n2. css (all styles FIRST — the user sees a placeholder until CSS is complete)\n3. html (streams in live — the user watches the UI build as HTML is generated)\n4. jsFunctions (reusable helper functions)\n5. jsExpressions (applied one-by-one — the user sees each expression take effect)";
3051
- const CopilotKitContext = createContext({
3052
- copilotkit: null,
3053
- executingToolCallIds: /* @__PURE__ */ new Set()
3054
- });
3055
- const LicenseContext = createContext(createLicenseContextValue(null));
3056
- const useLicenseContext = () => useContext(LicenseContext);
3057
3434
  function useStableArrayProp(prop, warningMessage, isMeaningfulChange) {
3058
3435
  const empty = useMemo(() => [], []);
3059
3436
  const value = prop ?? empty;
@@ -3275,13 +3652,9 @@ const CopilotKitProvider = ({ children, runtimeUrl, headers: headersProp = {}, c
3275
3652
  onErrorRef.current = onError;
3276
3653
  }, [onError]);
3277
3654
  useEffect(() => {
3278
- if (!onErrorRef.current) return;
3279
3655
  const subscription = copilotkit.subscribe({ onError: (event) => {
3280
- onErrorRef.current?.({
3281
- error: event.error,
3282
- code: event.code,
3283
- context: event.context
3284
- });
3656
+ if (onErrorRef.current) onErrorRef.current(event);
3657
+ else console.error(`[CopilotKit] Error (${event.code}):`, event.error, event.context ?? {});
3285
3658
  } });
3286
3659
  return () => {
3287
3660
  subscription.unsubscribe();
@@ -3351,297 +3724,51 @@ const CopilotKitProvider = ({ children, runtimeUrl, headers: headersProp = {}, c
3351
3724
  parameters: schemaToJsonSchema(fn.parameters, { zodToJsonSchema })
3352
3725
  })));
3353
3726
  }, [sandboxFunctionsList]);
3354
- useLayoutEffect(() => {
3355
- if (!copilotkit || !sandboxFunctionsDescriptors || !openGenUIActive) return;
3356
- const id = copilotkit.addContext({
3357
- description: "Sandbox functions available in generated sandboxed UI code. Call via: await Websandbox.connection.remote.<functionName>(args)",
3358
- value: sandboxFunctionsDescriptors
3359
- });
3360
- return () => {
3361
- copilotkit.removeContext(id);
3362
- };
3363
- }, [
3364
- copilotkit,
3365
- sandboxFunctionsDescriptors,
3366
- openGenUIActive
3367
- ]);
3368
- const contextValue = useMemo(() => ({
3369
- copilotkit,
3370
- executingToolCallIds
3371
- }), [copilotkit, executingToolCallIds]);
3372
- const licenseContextValue = useMemo(() => createLicenseContextValue(null), []);
3373
- return /* @__PURE__ */ jsx(SandboxFunctionsContext.Provider, {
3374
- value: sandboxFunctionsList,
3375
- children: /* @__PURE__ */ jsx(CopilotKitContext.Provider, {
3376
- value: contextValue,
3377
- children: /* @__PURE__ */ jsxs(LicenseContext.Provider, {
3378
- value: licenseContextValue,
3379
- children: [
3380
- runtimeA2UIEnabled && /* @__PURE__ */ jsx(A2UIBuiltInToolCallRenderer, {}),
3381
- runtimeA2UIEnabled && /* @__PURE__ */ jsx(A2UICatalogContext, {
3382
- catalog: a2ui?.catalog,
3383
- includeSchema: a2ui?.includeSchema
3384
- }),
3385
- children,
3386
- shouldRenderInspector ? /* @__PURE__ */ jsx(CopilotKitInspector, {
3387
- core: copilotkit,
3388
- defaultAnchor: inspectorDefaultAnchor
3389
- }) : null,
3390
- runtimeLicenseStatus === "none" && !resolvedPublicKey && /* @__PURE__ */ jsx(LicenseWarningBanner, { type: "no_license" }),
3391
- runtimeLicenseStatus === "expired" && /* @__PURE__ */ jsx(LicenseWarningBanner, { type: "expired" }),
3392
- runtimeLicenseStatus === "invalid" && /* @__PURE__ */ jsx(LicenseWarningBanner, { type: "invalid" }),
3393
- runtimeLicenseStatus === "expiring" && /* @__PURE__ */ jsx(LicenseWarningBanner, { type: "expiring" })
3394
- ]
3395
- })
3396
- })
3397
- });
3398
- };
3399
- const useCopilotKit = () => {
3400
- const context = useContext(CopilotKitContext);
3401
- const [, forceUpdate] = useReducer((x) => x + 1, 0);
3402
- if (!context) throw new Error("useCopilotKit must be used within CopilotKitProvider");
3403
- useEffect(() => {
3404
- const subscription = context.copilotkit.subscribe({ onRuntimeConnectionStatusChanged: () => {
3405
- forceUpdate();
3406
- } });
3407
- return () => {
3408
- subscription.unsubscribe();
3409
- };
3410
- }, []);
3411
- return context;
3412
- };
3413
-
3414
- //#endregion
3415
- //#region src/v2/hooks/use-render-tool-call.tsx
3416
- /**
3417
- * Memoized component that renders a single tool call.
3418
- * This prevents unnecessary re-renders when parent components update
3419
- * but the tool call data hasn't changed.
3420
- */
3421
- const ToolCallRenderer = React.memo(function ToolCallRenderer({ toolCall, toolMessage, RenderComponent, isExecuting }) {
3422
- const args = useMemo(() => partialJSONParse(toolCall.function.arguments), [toolCall.function.arguments]);
3423
- const toolName = toolCall.function.name;
3424
- if (toolMessage) return /* @__PURE__ */ jsx(RenderComponent, {
3425
- name: toolName,
3426
- toolCallId: toolCall.id,
3427
- args,
3428
- status: ToolCallStatus.Complete,
3429
- result: toolMessage.content
3430
- });
3431
- else if (isExecuting) return /* @__PURE__ */ jsx(RenderComponent, {
3432
- name: toolName,
3433
- toolCallId: toolCall.id,
3434
- args,
3435
- status: ToolCallStatus.Executing,
3436
- result: void 0
3437
- });
3438
- else return /* @__PURE__ */ jsx(RenderComponent, {
3439
- name: toolName,
3440
- toolCallId: toolCall.id,
3441
- args,
3442
- status: ToolCallStatus.InProgress,
3443
- result: void 0
3444
- });
3445
- }, (prevProps, nextProps) => {
3446
- if (prevProps.toolCall.id !== nextProps.toolCall.id) return false;
3447
- if (prevProps.toolCall.function.name !== nextProps.toolCall.function.name) return false;
3448
- if (prevProps.toolCall.function.arguments !== nextProps.toolCall.function.arguments) return false;
3449
- if (prevProps.toolMessage?.content !== nextProps.toolMessage?.content) return false;
3450
- if (prevProps.isExecuting !== nextProps.isExecuting) return false;
3451
- if (prevProps.RenderComponent !== nextProps.RenderComponent) return false;
3452
- return true;
3453
- });
3454
- /**
3455
- * Hook that returns a function to render tool calls based on the render functions
3456
- * defined in CopilotKitProvider.
3457
- *
3458
- * @returns A function that takes a tool call and optional tool message and returns the rendered component
3459
- */
3460
- function useRenderToolCall() {
3461
- const { copilotkit, executingToolCallIds } = useCopilotKit();
3462
- const agentId = useCopilotChatConfiguration()?.agentId ?? DEFAULT_AGENT_ID;
3463
- const renderToolCalls = useSyncExternalStore((callback) => {
3464
- return copilotkit.subscribe({ onRenderToolCallsChanged: callback }).unsubscribe;
3465
- }, () => copilotkit.renderToolCalls, () => copilotkit.renderToolCalls);
3466
- return useCallback(({ toolCall, toolMessage }) => {
3467
- const exactMatches = renderToolCalls.filter((rc) => rc.name === toolCall.function.name);
3468
- const renderConfig = exactMatches.find((rc) => rc.agentId === agentId) || exactMatches.find((rc) => !rc.agentId) || exactMatches[0] || renderToolCalls.find((rc) => rc.name === "*");
3469
- if (!renderConfig) return null;
3470
- const RenderComponent = renderConfig.render;
3471
- return /* @__PURE__ */ jsx(ToolCallRenderer, {
3472
- toolCall,
3473
- toolMessage,
3474
- RenderComponent,
3475
- isExecuting: executingToolCallIds.has(toolCall.id)
3476
- }, toolCall.id);
3477
- }, [
3478
- renderToolCalls,
3479
- executingToolCallIds,
3480
- agentId
3481
- ]);
3482
- }
3483
-
3484
- //#endregion
3485
- //#region src/v2/hooks/use-agent.tsx
3486
- let UseAgentUpdate = /* @__PURE__ */ function(UseAgentUpdate) {
3487
- UseAgentUpdate["OnMessagesChanged"] = "OnMessagesChanged";
3488
- UseAgentUpdate["OnStateChanged"] = "OnStateChanged";
3489
- UseAgentUpdate["OnRunStatusChanged"] = "OnRunStatusChanged";
3490
- return UseAgentUpdate;
3491
- }({});
3492
- const ALL_UPDATES = [
3493
- UseAgentUpdate.OnMessagesChanged,
3494
- UseAgentUpdate.OnStateChanged,
3495
- UseAgentUpdate.OnRunStatusChanged
3496
- ];
3497
- /**
3498
- * Clone a registry agent for per-thread isolation.
3499
- * Copies agent configuration (transport, headers, etc.) but resets conversation
3500
- * state (messages, threadId, state) so each thread starts fresh.
3501
- */
3502
- function cloneForThread(source, threadId, headers) {
3503
- const clone = source.clone();
3504
- if (clone === source) throw new Error(`useAgent: ${source.constructor.name}.clone() returned the same instance. clone() must return a new, independent object.`);
3505
- clone.threadId = threadId;
3506
- clone.setMessages([]);
3507
- clone.setState({});
3508
- if (clone instanceof HttpAgent) clone.headers = { ...headers };
3509
- return clone;
3510
- }
3511
- /**
3512
- * Module-level WeakMap: registryAgent → (threadId → clone).
3513
- * Shared across all useAgent() calls so that every component using the same
3514
- * (agentId, threadId) pair receives the same agent instance. Using WeakMap
3515
- * ensures the clone map is garbage-collected when the registry agent is
3516
- * replaced (e.g. after reconnect or hot-reload).
3517
- */
3518
- const globalThreadCloneMap = /* @__PURE__ */ new WeakMap();
3519
- /**
3520
- * Look up an existing per-thread clone without creating one.
3521
- * Returns undefined when no clone has been created yet for this pair.
3522
- */
3523
- function getThreadClone(registryAgent, threadId) {
3524
- if (!registryAgent || !threadId) return void 0;
3525
- return globalThreadCloneMap.get(registryAgent)?.get(threadId);
3526
- }
3527
- function getOrCreateThreadClone(existing, threadId, headers) {
3528
- let byThread = globalThreadCloneMap.get(existing);
3529
- if (!byThread) {
3530
- byThread = /* @__PURE__ */ new Map();
3531
- globalThreadCloneMap.set(existing, byThread);
3532
- }
3533
- const cached = byThread.get(threadId);
3534
- if (cached) return cached;
3535
- const clone = cloneForThread(existing, threadId, headers);
3536
- byThread.set(threadId, clone);
3537
- return clone;
3538
- }
3539
- function useAgent({ agentId, threadId, updates, throttleMs } = {}) {
3540
- agentId ??= DEFAULT_AGENT_ID;
3541
- const { copilotkit } = useCopilotKit();
3542
- const providerThrottleMs = copilotkit.defaultThrottleMs;
3543
- const chatConfig = useCopilotChatConfiguration();
3544
- threadId ??= chatConfig?.threadId;
3545
- const [, forceUpdate] = useReducer((x) => x + 1, 0);
3546
- const updateFlags = useMemo(() => updates ?? ALL_UPDATES, [JSON.stringify(updates)]);
3547
- const provisionalAgentCache = useRef(/* @__PURE__ */ new Map());
3548
- const agent = useMemo(() => {
3549
- const cacheKey = threadId ? `${agentId}:${threadId}` : agentId;
3550
- const existing = copilotkit.getAgent(agentId);
3551
- if (existing) {
3552
- provisionalAgentCache.current.delete(cacheKey);
3553
- provisionalAgentCache.current.delete(agentId);
3554
- if (!threadId) return existing;
3555
- return getOrCreateThreadClone(existing, threadId, copilotkit.headers);
3556
- }
3557
- const isRuntimeConfigured = copilotkit.runtimeUrl !== void 0;
3558
- const status = copilotkit.runtimeConnectionStatus;
3559
- if (isRuntimeConfigured && (status === CopilotKitCoreRuntimeConnectionStatus.Disconnected || status === CopilotKitCoreRuntimeConnectionStatus.Connecting)) {
3560
- const cached = provisionalAgentCache.current.get(cacheKey);
3561
- if (cached) {
3562
- cached.headers = { ...copilotkit.headers };
3563
- return cached;
3564
- }
3565
- const provisional = new ProxiedCopilotRuntimeAgent({
3566
- runtimeUrl: copilotkit.runtimeUrl,
3567
- agentId,
3568
- transport: copilotkit.runtimeTransport,
3569
- runtimeMode: "pending"
3570
- });
3571
- provisional.headers = { ...copilotkit.headers };
3572
- if (threadId) provisional.threadId = threadId;
3573
- provisionalAgentCache.current.set(cacheKey, provisional);
3574
- return provisional;
3575
- }
3576
- if (isRuntimeConfigured && status === CopilotKitCoreRuntimeConnectionStatus.Error) {
3577
- const cached = provisionalAgentCache.current.get(cacheKey);
3578
- if (cached) {
3579
- cached.headers = { ...copilotkit.headers };
3580
- return cached;
3581
- }
3582
- const provisional = new ProxiedCopilotRuntimeAgent({
3583
- runtimeUrl: copilotkit.runtimeUrl,
3584
- agentId,
3585
- transport: copilotkit.runtimeTransport,
3586
- runtimeMode: "pending"
3587
- });
3588
- provisional.headers = { ...copilotkit.headers };
3589
- if (threadId) provisional.threadId = threadId;
3590
- provisionalAgentCache.current.set(cacheKey, provisional);
3591
- return provisional;
3592
- }
3593
- const knownAgents = Object.keys(copilotkit.agents ?? {});
3594
- const runtimePart = isRuntimeConfigured ? `runtimeUrl=${copilotkit.runtimeUrl}` : "no runtimeUrl";
3595
- throw new Error(`useAgent: Agent '${agentId}' not found after runtime sync (${runtimePart}). ` + (knownAgents.length ? `Known agents: [${knownAgents.join(", ")}]` : "No agents registered.") + " Verify your runtime /info and/or agents__unsafe_dev_only.");
3596
- }, [
3597
- agentId,
3598
- threadId,
3599
- copilotkit.agents,
3600
- copilotkit.runtimeConnectionStatus,
3601
- copilotkit.runtimeUrl,
3602
- copilotkit.runtimeTransport,
3603
- JSON.stringify(copilotkit.headers)
3604
- ]);
3605
- useEffect(() => {
3606
- if (updateFlags.length === 0) return;
3607
- let active = true;
3608
- const handlers = {};
3609
- let batchScheduled = false;
3610
- const batchedForceUpdate = () => {
3611
- if (!active) return;
3612
- if (!batchScheduled) {
3613
- batchScheduled = true;
3614
- queueMicrotask(() => {
3615
- batchScheduled = false;
3616
- if (active) forceUpdate();
3617
- });
3618
- }
3619
- };
3620
- if (updateFlags.includes(UseAgentUpdate.OnMessagesChanged)) handlers.onMessagesChanged = forceUpdate;
3621
- if (updateFlags.includes(UseAgentUpdate.OnStateChanged)) handlers.onStateChanged = batchedForceUpdate;
3622
- if (updateFlags.includes(UseAgentUpdate.OnRunStatusChanged)) {
3623
- handlers.onRunInitialized = batchedForceUpdate;
3624
- handlers.onRunFinalized = batchedForceUpdate;
3625
- handlers.onRunFailed = batchedForceUpdate;
3626
- handlers.onRunErrorEvent = batchedForceUpdate;
3627
- }
3628
- const subscription = copilotkit.subscribeToAgentWithOptions(agent, handlers, { throttleMs });
3727
+ useLayoutEffect(() => {
3728
+ if (!copilotkit || !sandboxFunctionsDescriptors || !openGenUIActive) return;
3729
+ const id = copilotkit.addContext({
3730
+ description: "Sandbox functions available in generated sandboxed UI code. Call via: await Websandbox.connection.remote.<functionName>(args)",
3731
+ value: sandboxFunctionsDescriptors
3732
+ });
3629
3733
  return () => {
3630
- active = false;
3631
- subscription.unsubscribe();
3734
+ copilotkit.removeContext(id);
3632
3735
  };
3633
3736
  }, [
3634
- agent,
3635
- forceUpdate,
3636
- throttleMs,
3637
- providerThrottleMs,
3638
- updateFlags
3737
+ copilotkit,
3738
+ sandboxFunctionsDescriptors,
3739
+ openGenUIActive
3639
3740
  ]);
3640
- useEffect(() => {
3641
- if (agent instanceof HttpAgent) agent.headers = { ...copilotkit.headers };
3642
- }, [agent, JSON.stringify(copilotkit.headers)]);
3643
- return { agent };
3644
- }
3741
+ const contextValue = useMemo(() => ({
3742
+ copilotkit,
3743
+ executingToolCallIds
3744
+ }), [copilotkit, executingToolCallIds]);
3745
+ const licenseContextValue = useMemo(() => createLicenseContextValue(null), []);
3746
+ return /* @__PURE__ */ jsx(SandboxFunctionsContext.Provider, {
3747
+ value: sandboxFunctionsList,
3748
+ children: /* @__PURE__ */ jsx(CopilotKitContext.Provider, {
3749
+ value: contextValue,
3750
+ children: /* @__PURE__ */ jsxs(LicenseContext.Provider, {
3751
+ value: licenseContextValue,
3752
+ children: [
3753
+ runtimeA2UIEnabled && /* @__PURE__ */ jsx(A2UIBuiltInToolCallRenderer, {}),
3754
+ runtimeA2UIEnabled && /* @__PURE__ */ jsx(A2UICatalogContext, {
3755
+ catalog: a2ui?.catalog,
3756
+ includeSchema: a2ui?.includeSchema
3757
+ }),
3758
+ children,
3759
+ shouldRenderInspector ? /* @__PURE__ */ jsx(CopilotKitInspector, {
3760
+ core: copilotkit,
3761
+ defaultAnchor: inspectorDefaultAnchor
3762
+ }) : null,
3763
+ runtimeLicenseStatus === "none" && !resolvedPublicKey && /* @__PURE__ */ jsx(LicenseWarningBanner, { type: "no_license" }),
3764
+ runtimeLicenseStatus === "expired" && /* @__PURE__ */ jsx(LicenseWarningBanner, { type: "expired" }),
3765
+ runtimeLicenseStatus === "invalid" && /* @__PURE__ */ jsx(LicenseWarningBanner, { type: "invalid" }),
3766
+ runtimeLicenseStatus === "expiring" && /* @__PURE__ */ jsx(LicenseWarningBanner, { type: "expiring" })
3767
+ ]
3768
+ })
3769
+ })
3770
+ });
3771
+ };
3645
3772
 
3646
3773
  //#endregion
3647
3774
  //#region src/v2/hooks/use-render-custom-messages.tsx
@@ -3660,8 +3787,7 @@ function useRenderCustomMessages() {
3660
3787
  const { message, position } = params;
3661
3788
  const resolvedRunId = copilotkit.getRunIdForMessage(agentId, threadId, message.id) ?? copilotkit.getRunIdsForThread(agentId, threadId).slice(-1)[0];
3662
3789
  const runId = resolvedRunId ?? `missing-run-id:${message.id}`;
3663
- const registryAgent = copilotkit.getAgent(agentId);
3664
- const agent = getThreadClone(registryAgent, threadId) ?? registryAgent;
3790
+ const agent = copilotkit.getAgent(agentId);
3665
3791
  if (!agent) return null;
3666
3792
  const messagesIdsInRun = resolvedRunId ? agent.messages.filter((msg) => copilotkit.getRunIdForMessage(agentId, threadId, msg.id) === resolvedRunId).map((msg) => msg.id) : [message.id];
3667
3793
  const rawMessageIndex = agent.messages.findIndex((msg) => msg.id === message.id);
@@ -3669,429 +3795,162 @@ function useRenderCustomMessages() {
3669
3795
  const messageIndexInRun = resolvedRunId ? Math.max(messagesIdsInRun.indexOf(message.id), 0) : 0;
3670
3796
  const numberOfMessagesInRun = resolvedRunId ? messagesIdsInRun.length : 1;
3671
3797
  const stateSnapshot = resolvedRunId ? copilotkit.getStateByRun(agentId, threadId, resolvedRunId) : void 0;
3672
- let result = null;
3673
- for (const renderer of customMessageRenderers) {
3674
- if (!renderer.render) continue;
3675
- const Component = renderer.render;
3676
- result = /* @__PURE__ */ jsx(Component, {
3677
- message,
3678
- position,
3679
- runId,
3680
- messageIndex,
3681
- messageIndexInRun,
3682
- numberOfMessagesInRun,
3683
- agentId,
3684
- stateSnapshot
3685
- }, `${runId}-${message.id}-${position}`);
3686
- if (result) break;
3687
- }
3688
- return result;
3689
- };
3690
- }
3691
-
3692
- //#endregion
3693
- //#region src/v2/hooks/use-render-activity-message.tsx
3694
- function useRenderActivityMessage() {
3695
- const { copilotkit } = useCopilotKit();
3696
- const config = useCopilotChatConfiguration();
3697
- const agentId = config?.agentId ?? DEFAULT_AGENT_ID;
3698
- const renderers = copilotkit.renderActivityMessages;
3699
- const findRenderer = useCallback((activityType) => {
3700
- if (!renderers.length) return null;
3701
- const matches = renderers.filter((renderer) => renderer.activityType === activityType);
3702
- return matches.find((candidate) => candidate.agentId === agentId) ?? matches.find((candidate) => candidate.agentId === void 0) ?? renderers.find((candidate) => candidate.activityType === "*") ?? null;
3703
- }, [agentId, renderers]);
3704
- const renderActivityMessage = useCallback((message) => {
3705
- const renderer = findRenderer(message.activityType);
3706
- if (!renderer) return null;
3707
- const parseResult = renderer.content.safeParse(message.content);
3708
- if (!parseResult.success) {
3709
- console.warn(`Failed to parse content for activity message '${message.activityType}':`, parseResult.error);
3710
- return null;
3711
- }
3712
- const Component = renderer.render;
3713
- const registryAgent = copilotkit.getAgent(agentId);
3714
- const agent = getThreadClone(registryAgent, config?.threadId) ?? registryAgent;
3715
- return /* @__PURE__ */ jsx(Component, {
3716
- activityType: message.activityType,
3717
- content: parseResult.data,
3718
- message,
3719
- agent
3720
- }, message.id);
3721
- }, [
3722
- agentId,
3723
- config?.threadId,
3724
- copilotkit,
3725
- findRenderer
3726
- ]);
3727
- return useMemo(() => ({
3728
- renderActivityMessage,
3729
- findRenderer
3730
- }), [renderActivityMessage, findRenderer]);
3731
- }
3732
-
3733
- //#endregion
3734
- //#region src/v2/hooks/use-frontend-tool.tsx
3735
- const EMPTY_DEPS$1 = [];
3736
- function useFrontendTool(tool, deps) {
3737
- const { copilotkit } = useCopilotKit();
3738
- const extraDeps = deps ?? EMPTY_DEPS$1;
3739
- useEffect(() => {
3740
- const name = tool.name;
3741
- if (copilotkit.getTool({
3742
- toolName: name,
3743
- agentId: tool.agentId
3744
- })) {
3745
- console.warn(`Tool '${name}' already exists for agent '${tool.agentId || "global"}'. Overriding with latest registration.`);
3746
- copilotkit.removeTool(name, tool.agentId);
3747
- }
3748
- copilotkit.addTool(tool);
3749
- if (tool.render) copilotkit.addHookRenderToolCall({
3750
- name,
3751
- args: tool.parameters,
3752
- agentId: tool.agentId,
3753
- render: tool.render
3754
- });
3755
- return () => {
3756
- copilotkit.removeTool(name, tool.agentId);
3757
- };
3758
- }, [
3759
- tool.name,
3760
- tool.available,
3761
- copilotkit,
3762
- extraDeps.length,
3763
- ...extraDeps
3764
- ]);
3765
- }
3766
-
3767
- //#endregion
3768
- //#region src/v2/hooks/use-component.tsx
3769
- /**
3770
- * Registers a React component as a frontend tool renderer in chat.
3771
- *
3772
- * This hook is a convenience wrapper around `useFrontendTool` that:
3773
- * - builds a model-facing tool description,
3774
- * - forwards optional schema parameters (any Standard Schema V1 compatible library),
3775
- * - renders your component with tool call parameters.
3776
- *
3777
- * Use this when you want to display a typed visual component for a tool call
3778
- * without manually wiring a full frontend tool object.
3779
- *
3780
- * When `parameters` is provided, render props are inferred from the schema.
3781
- * When omitted, the render component may accept any props.
3782
- *
3783
- * @typeParam TSchema - Schema describing tool parameters, or `undefined` when no schema is given.
3784
- * @param config - Tool registration config.
3785
- * @param deps - Optional dependencies to refresh registration (same semantics as `useEffect`).
3786
- *
3787
- * @example
3788
- * ```tsx
3789
- * // Without parameters — render accepts any props
3790
- * useComponent({
3791
- * name: "showGreeting",
3792
- * render: ({ message }: { message: string }) => <div>{message}</div>,
3793
- * });
3794
- * ```
3795
- *
3796
- * @example
3797
- * ```tsx
3798
- * // With parameters — render props inferred from schema
3799
- * useComponent({
3800
- * name: "showWeatherCard",
3801
- * parameters: z.object({ city: z.string() }),
3802
- * render: ({ city }) => <div>{city}</div>,
3803
- * });
3804
- * ```
3805
- *
3806
- * @example
3807
- * ```tsx
3808
- * useComponent(
3809
- * {
3810
- * name: "renderProfile",
3811
- * parameters: z.object({ userId: z.string() }),
3812
- * render: ProfileCard,
3813
- * agentId: "support-agent",
3814
- * },
3815
- * [selectedAgentId],
3816
- * );
3817
- * ```
3818
- */
3819
- function useComponent(config, deps) {
3820
- const prefix = `Use this tool to display the "${config.name}" component in the chat. This tool renders a visual UI component for the user.`;
3821
- const fullDescription = config.description ? `${prefix}\n\n${config.description}` : prefix;
3822
- useFrontendTool({
3823
- name: config.name,
3824
- description: fullDescription,
3825
- parameters: config.parameters,
3826
- render: ({ args }) => {
3827
- const Component = config.render;
3828
- return /* @__PURE__ */ jsx(Component, { ...args });
3829
- },
3830
- agentId: config.agentId
3831
- }, deps);
3832
- }
3833
-
3834
- //#endregion
3835
- //#region src/v2/hooks/use-render-tool.tsx
3836
- const EMPTY_DEPS = [];
3837
- /**
3838
- * Registers a renderer entry in CopilotKit's `renderToolCalls` registry.
3839
- *
3840
- * Key behavior:
3841
- * - deduplicates by `agentId:name` (latest registration wins),
3842
- * - keeps renderer entries on cleanup so historical chat tool calls can still render,
3843
- * - refreshes registration when `deps` change.
3844
- *
3845
- * @typeParam S - Schema type describing tool call parameters.
3846
- * @param config - Renderer config for wildcard or named tools.
3847
- * @param deps - Optional dependencies to refresh registration.
3848
- *
3849
- * @example
3850
- * ```tsx
3851
- * useRenderTool(
3852
- * {
3853
- * name: "searchDocs",
3854
- * parameters: z.object({ query: z.string() }),
3855
- * render: ({ status, parameters, result }) => {
3856
- * if (status === "executing") return <div>Searching {parameters.query}</div>;
3857
- * if (status === "complete") return <div>{result}</div>;
3858
- * return <div>Preparing...</div>;
3859
- * },
3860
- * },
3861
- * [],
3862
- * );
3863
- * ```
3864
- *
3865
- * @example
3866
- * ```tsx
3867
- * useRenderTool(
3868
- * {
3869
- * name: "summarize",
3870
- * parameters: z.object({ text: z.string() }),
3871
- * agentId: "research-agent",
3872
- * render: ({ name, status }) => <div>{name}: {status}</div>,
3873
- * },
3874
- * [selectedAgentId],
3875
- * );
3876
- * ```
3877
- */
3878
- function useRenderTool(config, deps) {
3798
+ let result = null;
3799
+ for (const renderer of customMessageRenderers) {
3800
+ if (!renderer.render) continue;
3801
+ const Component = renderer.render;
3802
+ result = /* @__PURE__ */ jsx(Component, {
3803
+ message,
3804
+ position,
3805
+ runId,
3806
+ messageIndex,
3807
+ messageIndexInRun,
3808
+ numberOfMessagesInRun,
3809
+ agentId,
3810
+ stateSnapshot
3811
+ }, `${runId}-${message.id}-${position}`);
3812
+ if (result) break;
3813
+ }
3814
+ return result;
3815
+ };
3816
+ }
3817
+
3818
+ //#endregion
3819
+ //#region src/v2/hooks/use-render-activity-message.tsx
3820
+ function useRenderActivityMessage() {
3879
3821
  const { copilotkit } = useCopilotKit();
3880
- const extraDeps = deps ?? EMPTY_DEPS;
3881
- useEffect(() => {
3882
- const renderer = config.name === "*" && !config.parameters ? defineToolCallRenderer({
3883
- name: "*",
3884
- render: (props) => config.render({
3885
- ...props,
3886
- parameters: props.args
3887
- }),
3888
- ...config.agentId ? { agentId: config.agentId } : {}
3889
- }) : defineToolCallRenderer({
3890
- name: config.name,
3891
- args: config.parameters,
3892
- render: (props) => config.render({
3893
- ...props,
3894
- parameters: props.args
3895
- }),
3896
- ...config.agentId ? { agentId: config.agentId } : {}
3897
- });
3898
- copilotkit.addHookRenderToolCall(renderer);
3822
+ const agentId = useCopilotChatConfiguration()?.agentId ?? DEFAULT_AGENT_ID;
3823
+ const renderers = copilotkit.renderActivityMessages;
3824
+ const findRenderer = useCallback((activityType) => {
3825
+ if (!renderers.length) return null;
3826
+ const matches = renderers.filter((renderer) => renderer.activityType === activityType);
3827
+ return matches.find((candidate) => candidate.agentId === agentId) ?? matches.find((candidate) => candidate.agentId === void 0) ?? renderers.find((candidate) => candidate.activityType === "*") ?? null;
3828
+ }, [agentId, renderers]);
3829
+ const renderActivityMessage = useCallback((message) => {
3830
+ const renderer = findRenderer(message.activityType);
3831
+ if (!renderer) return null;
3832
+ const parseResult = renderer.content.safeParse(message.content);
3833
+ if (!parseResult.success) {
3834
+ console.warn(`Failed to parse content for activity message '${message.activityType}':`, parseResult.error);
3835
+ return null;
3836
+ }
3837
+ const Component = renderer.render;
3838
+ const agent = copilotkit.getAgent(agentId);
3839
+ return /* @__PURE__ */ jsx(Component, {
3840
+ activityType: message.activityType,
3841
+ content: parseResult.data,
3842
+ message,
3843
+ agent
3844
+ }, message.id);
3899
3845
  }, [
3900
- config.name,
3846
+ agentId,
3901
3847
  copilotkit,
3902
- extraDeps.length,
3903
- ...extraDeps
3848
+ findRenderer
3904
3849
  ]);
3905
- }
3906
-
3907
- //#endregion
3908
- //#region src/v2/hooks/use-default-render-tool.tsx
3909
- /**
3910
- * Registers a wildcard (`"*"`) tool-call renderer via `useRenderTool`.
3911
- *
3912
- * - Call with no config to use CopilotKit's built-in default tool-call card.
3913
- * - Pass `config.render` to replace the default UI with your own fallback renderer.
3914
- *
3915
- * This is useful when you want a generic renderer for tools that do not have a
3916
- * dedicated `useRenderTool({ name: "..." })` registration.
3917
- *
3918
- * @param config - Optional custom wildcard render function.
3919
- * @param deps - Optional dependencies to refresh registration.
3920
- *
3921
- * @example
3922
- * ```tsx
3923
- * useDefaultRenderTool();
3924
- * ```
3925
- *
3926
- * @example
3927
- * ```tsx
3928
- * useDefaultRenderTool({
3929
- * render: ({ name, status }) => <div>{name}: {status}</div>,
3930
- * });
3931
- * ```
3932
- *
3933
- * @example
3934
- * ```tsx
3935
- * useDefaultRenderTool(
3936
- * {
3937
- * render: ({ name, result }) => (
3938
- * <ToolEventRow title={name} payload={result} compact={compactMode} />
3939
- * ),
3940
- * },
3941
- * [compactMode],
3942
- * );
3943
- * ```
3944
- */
3945
- function useDefaultRenderTool(config, deps) {
3946
- useRenderTool({
3947
- name: "*",
3948
- render: config?.render ?? DefaultToolCallRenderer
3949
- }, deps);
3950
- }
3951
- function DefaultToolCallRenderer({ name, parameters, status, result }) {
3952
- const [isExpanded, setIsExpanded] = useState(false);
3953
- const statusString = String(status);
3954
- const isActive = statusString === "inProgress" || statusString === "executing";
3955
- const isComplete = statusString === "complete";
3956
- return /* @__PURE__ */ jsx("div", {
3957
- style: {
3958
- marginTop: "8px",
3959
- paddingBottom: "8px"
3960
- },
3961
- children: /* @__PURE__ */ jsxs("div", {
3962
- style: {
3963
- borderRadius: "12px",
3964
- border: "1px solid #e4e4e7",
3965
- backgroundColor: "#fafafa",
3966
- padding: "14px 16px"
3967
- },
3968
- children: [/* @__PURE__ */ jsxs("div", {
3969
- onClick: () => setIsExpanded(!isExpanded),
3970
- style: {
3971
- display: "flex",
3972
- alignItems: "center",
3973
- justifyContent: "space-between",
3974
- gap: "10px",
3975
- cursor: "pointer",
3976
- userSelect: "none"
3977
- },
3978
- children: [/* @__PURE__ */ jsxs("div", {
3979
- style: {
3980
- display: "flex",
3981
- alignItems: "center",
3982
- gap: "8px",
3983
- minWidth: 0
3984
- },
3985
- children: [
3986
- /* @__PURE__ */ jsx("svg", {
3987
- style: {
3988
- height: "14px",
3989
- width: "14px",
3990
- color: "#71717a",
3991
- transition: "transform 0.15s",
3992
- transform: isExpanded ? "rotate(90deg)" : "rotate(0deg)",
3993
- flexShrink: 0
3994
- },
3995
- fill: "none",
3996
- viewBox: "0 0 24 24",
3997
- strokeWidth: 2,
3998
- stroke: "currentColor",
3999
- children: /* @__PURE__ */ jsx("path", {
4000
- strokeLinecap: "round",
4001
- strokeLinejoin: "round",
4002
- d: "M8.25 4.5l7.5 7.5-7.5 7.5"
4003
- })
4004
- }),
4005
- /* @__PURE__ */ jsx("span", { style: {
4006
- display: "inline-block",
4007
- height: "8px",
4008
- width: "8px",
4009
- borderRadius: "50%",
4010
- backgroundColor: isActive ? "#f59e0b" : isComplete ? "#10b981" : "#a1a1aa",
4011
- flexShrink: 0
4012
- } }),
4013
- /* @__PURE__ */ jsx("span", {
4014
- style: {
4015
- fontSize: "13px",
4016
- fontWeight: 600,
4017
- color: "#18181b",
4018
- overflow: "hidden",
4019
- textOverflow: "ellipsis",
4020
- whiteSpace: "nowrap"
4021
- },
4022
- children: name
4023
- })
4024
- ]
4025
- }), /* @__PURE__ */ jsx("span", {
4026
- style: {
4027
- display: "inline-flex",
4028
- alignItems: "center",
4029
- borderRadius: "9999px",
4030
- padding: "2px 8px",
4031
- fontSize: "11px",
4032
- fontWeight: 500,
4033
- backgroundColor: isActive ? "#fef3c7" : isComplete ? "#d1fae5" : "#f4f4f5",
4034
- color: isActive ? "#92400e" : isComplete ? "#065f46" : "#3f3f46",
4035
- flexShrink: 0
4036
- },
4037
- children: isActive ? "Running" : isComplete ? "Done" : status
4038
- })]
4039
- }), isExpanded && /* @__PURE__ */ jsxs("div", {
4040
- style: {
4041
- marginTop: "12px",
4042
- display: "grid",
4043
- gap: "12px"
4044
- },
4045
- children: [/* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsx("div", {
4046
- style: {
4047
- fontSize: "10px",
4048
- textTransform: "uppercase",
4049
- letterSpacing: "0.05em",
4050
- color: "#71717a"
4051
- },
4052
- children: "Arguments"
4053
- }), /* @__PURE__ */ jsx("pre", {
4054
- style: {
4055
- marginTop: "6px",
4056
- maxHeight: "200px",
4057
- overflow: "auto",
4058
- borderRadius: "6px",
4059
- backgroundColor: "#f4f4f5",
4060
- padding: "10px",
4061
- fontSize: "11px",
4062
- lineHeight: 1.6,
4063
- color: "#27272a",
4064
- whiteSpace: "pre-wrap",
4065
- wordBreak: "break-word"
4066
- },
4067
- children: JSON.stringify(parameters ?? {}, null, 2)
4068
- })] }), result !== void 0 && /* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsx("div", {
4069
- style: {
4070
- fontSize: "10px",
4071
- textTransform: "uppercase",
4072
- letterSpacing: "0.05em",
4073
- color: "#71717a"
4074
- },
4075
- children: "Result"
4076
- }), /* @__PURE__ */ jsx("pre", {
4077
- style: {
4078
- marginTop: "6px",
4079
- maxHeight: "200px",
4080
- overflow: "auto",
4081
- borderRadius: "6px",
4082
- backgroundColor: "#f4f4f5",
4083
- padding: "10px",
4084
- fontSize: "11px",
4085
- lineHeight: 1.6,
4086
- color: "#27272a",
4087
- whiteSpace: "pre-wrap",
4088
- wordBreak: "break-word"
4089
- },
4090
- children: typeof result === "string" ? result : JSON.stringify(result, null, 2)
4091
- })] })]
4092
- })]
4093
- })
4094
- });
3850
+ return useMemo(() => ({
3851
+ renderActivityMessage,
3852
+ findRenderer
3853
+ }), [renderActivityMessage, findRenderer]);
3854
+ }
3855
+
3856
+ //#endregion
3857
+ //#region src/v2/hooks/use-frontend-tool.tsx
3858
+ const EMPTY_DEPS = [];
3859
+ function useFrontendTool(tool, deps) {
3860
+ const { copilotkit } = useCopilotKit();
3861
+ const extraDeps = deps ?? EMPTY_DEPS;
3862
+ useEffect(() => {
3863
+ const name = tool.name;
3864
+ if (copilotkit.getTool({
3865
+ toolName: name,
3866
+ agentId: tool.agentId
3867
+ })) {
3868
+ console.warn(`Tool '${name}' already exists for agent '${tool.agentId || "global"}'. Overriding with latest registration.`);
3869
+ copilotkit.removeTool(name, tool.agentId);
3870
+ }
3871
+ copilotkit.addTool(tool);
3872
+ if (tool.render) copilotkit.addHookRenderToolCall({
3873
+ name,
3874
+ args: tool.parameters,
3875
+ agentId: tool.agentId,
3876
+ render: tool.render
3877
+ });
3878
+ return () => {
3879
+ copilotkit.removeTool(name, tool.agentId);
3880
+ };
3881
+ }, [
3882
+ tool.name,
3883
+ tool.available,
3884
+ copilotkit,
3885
+ JSON.stringify(extraDeps)
3886
+ ]);
3887
+ }
3888
+
3889
+ //#endregion
3890
+ //#region src/v2/hooks/use-component.tsx
3891
+ /**
3892
+ * Registers a React component as a frontend tool renderer in chat.
3893
+ *
3894
+ * This hook is a convenience wrapper around `useFrontendTool` that:
3895
+ * - builds a model-facing tool description,
3896
+ * - forwards optional schema parameters (any Standard Schema V1 compatible library),
3897
+ * - renders your component with tool call parameters.
3898
+ *
3899
+ * Use this when you want to display a typed visual component for a tool call
3900
+ * without manually wiring a full frontend tool object.
3901
+ *
3902
+ * When `parameters` is provided, render props are inferred from the schema.
3903
+ * When omitted, the render component may accept any props.
3904
+ *
3905
+ * @typeParam TSchema - Schema describing tool parameters, or `undefined` when no schema is given.
3906
+ * @param config - Tool registration config.
3907
+ * @param deps - Optional dependencies to refresh registration (same semantics as `useEffect`).
3908
+ *
3909
+ * @example
3910
+ * ```tsx
3911
+ * // Without parameters — render accepts any props
3912
+ * useComponent({
3913
+ * name: "showGreeting",
3914
+ * render: ({ message }: { message: string }) => <div>{message}</div>,
3915
+ * });
3916
+ * ```
3917
+ *
3918
+ * @example
3919
+ * ```tsx
3920
+ * // With parameters — render props inferred from schema
3921
+ * useComponent({
3922
+ * name: "showWeatherCard",
3923
+ * parameters: z.object({ city: z.string() }),
3924
+ * render: ({ city }) => <div>{city}</div>,
3925
+ * });
3926
+ * ```
3927
+ *
3928
+ * @example
3929
+ * ```tsx
3930
+ * useComponent(
3931
+ * {
3932
+ * name: "renderProfile",
3933
+ * parameters: z.object({ userId: z.string() }),
3934
+ * render: ProfileCard,
3935
+ * agentId: "support-agent",
3936
+ * },
3937
+ * [selectedAgentId],
3938
+ * );
3939
+ * ```
3940
+ */
3941
+ function useComponent(config, deps) {
3942
+ const prefix = `Use this tool to display the "${config.name}" component in the chat. This tool renders a visual UI component for the user.`;
3943
+ const fullDescription = config.description ? `${prefix}\n\n${config.description}` : prefix;
3944
+ useFrontendTool({
3945
+ name: config.name,
3946
+ description: fullDescription,
3947
+ parameters: config.parameters,
3948
+ render: ({ args }) => {
3949
+ const Component = config.render;
3950
+ return /* @__PURE__ */ jsx(Component, { ...args });
3951
+ },
3952
+ agentId: config.agentId
3953
+ }, deps);
4095
3954
  }
4096
3955
 
4097
3956
  //#endregion
@@ -4160,6 +4019,118 @@ function useHumanInTheLoop(tool, deps) {
4160
4019
  ]);
4161
4020
  }
4162
4021
 
4022
+ //#endregion
4023
+ //#region src/v2/hooks/use-agent.tsx
4024
+ let UseAgentUpdate = /* @__PURE__ */ function(UseAgentUpdate) {
4025
+ UseAgentUpdate["OnMessagesChanged"] = "OnMessagesChanged";
4026
+ UseAgentUpdate["OnStateChanged"] = "OnStateChanged";
4027
+ UseAgentUpdate["OnRunStatusChanged"] = "OnRunStatusChanged";
4028
+ return UseAgentUpdate;
4029
+ }({});
4030
+ const ALL_UPDATES = [
4031
+ UseAgentUpdate.OnMessagesChanged,
4032
+ UseAgentUpdate.OnStateChanged,
4033
+ UseAgentUpdate.OnRunStatusChanged
4034
+ ];
4035
+ function useAgent({ agentId, updates, throttleMs } = {}) {
4036
+ agentId ??= DEFAULT_AGENT_ID;
4037
+ const { copilotkit } = useCopilotKit();
4038
+ const providerThrottleMs = copilotkit.defaultThrottleMs;
4039
+ const [, forceUpdate] = useReducer((x) => x + 1, 0);
4040
+ const updateFlags = useMemo(() => updates ?? ALL_UPDATES, [JSON.stringify(updates)]);
4041
+ const provisionalAgentCache = useRef(/* @__PURE__ */ new Map());
4042
+ const agent = useMemo(() => {
4043
+ const existing = copilotkit.getAgent(agentId);
4044
+ if (existing) {
4045
+ provisionalAgentCache.current.delete(agentId);
4046
+ return existing;
4047
+ }
4048
+ const isRuntimeConfigured = copilotkit.runtimeUrl !== void 0;
4049
+ const status = copilotkit.runtimeConnectionStatus;
4050
+ if (isRuntimeConfigured && (status === CopilotKitCoreRuntimeConnectionStatus.Disconnected || status === CopilotKitCoreRuntimeConnectionStatus.Connecting)) {
4051
+ const cached = provisionalAgentCache.current.get(agentId);
4052
+ if (cached) {
4053
+ cached.headers = { ...copilotkit.headers };
4054
+ return cached;
4055
+ }
4056
+ const provisional = new ProxiedCopilotRuntimeAgent({
4057
+ runtimeUrl: copilotkit.runtimeUrl,
4058
+ agentId,
4059
+ transport: copilotkit.runtimeTransport,
4060
+ runtimeMode: "pending"
4061
+ });
4062
+ provisional.headers = { ...copilotkit.headers };
4063
+ provisionalAgentCache.current.set(agentId, provisional);
4064
+ return provisional;
4065
+ }
4066
+ if (isRuntimeConfigured && status === CopilotKitCoreRuntimeConnectionStatus.Error) {
4067
+ const cached = provisionalAgentCache.current.get(agentId);
4068
+ if (cached) {
4069
+ cached.headers = { ...copilotkit.headers };
4070
+ return cached;
4071
+ }
4072
+ const provisional = new ProxiedCopilotRuntimeAgent({
4073
+ runtimeUrl: copilotkit.runtimeUrl,
4074
+ agentId,
4075
+ transport: copilotkit.runtimeTransport,
4076
+ runtimeMode: "pending"
4077
+ });
4078
+ provisional.headers = { ...copilotkit.headers };
4079
+ provisionalAgentCache.current.set(agentId, provisional);
4080
+ return provisional;
4081
+ }
4082
+ const knownAgents = Object.keys(copilotkit.agents ?? {});
4083
+ const runtimePart = isRuntimeConfigured ? `runtimeUrl=${copilotkit.runtimeUrl}` : "no runtimeUrl";
4084
+ throw new Error(`useAgent: Agent '${agentId}' not found after runtime sync (${runtimePart}). ` + (knownAgents.length ? `Known agents: [${knownAgents.join(", ")}]` : "No agents registered.") + " Verify your runtime /info and/or agents__unsafe_dev_only.");
4085
+ }, [
4086
+ agentId,
4087
+ copilotkit.agents,
4088
+ copilotkit.runtimeConnectionStatus,
4089
+ copilotkit.runtimeUrl,
4090
+ copilotkit.runtimeTransport,
4091
+ JSON.stringify(copilotkit.headers)
4092
+ ]);
4093
+ useEffect(() => {
4094
+ if (updateFlags.length === 0) return;
4095
+ let active = true;
4096
+ const handlers = {};
4097
+ let batchScheduled = false;
4098
+ const batchedForceUpdate = () => {
4099
+ if (!active) return;
4100
+ if (!batchScheduled) {
4101
+ batchScheduled = true;
4102
+ queueMicrotask(() => {
4103
+ batchScheduled = false;
4104
+ if (active) forceUpdate();
4105
+ });
4106
+ }
4107
+ };
4108
+ if (updateFlags.includes(UseAgentUpdate.OnMessagesChanged)) handlers.onMessagesChanged = batchedForceUpdate;
4109
+ if (updateFlags.includes(UseAgentUpdate.OnStateChanged)) handlers.onStateChanged = batchedForceUpdate;
4110
+ if (updateFlags.includes(UseAgentUpdate.OnRunStatusChanged)) {
4111
+ handlers.onRunInitialized = batchedForceUpdate;
4112
+ handlers.onRunFinalized = batchedForceUpdate;
4113
+ handlers.onRunFailed = batchedForceUpdate;
4114
+ handlers.onRunErrorEvent = batchedForceUpdate;
4115
+ }
4116
+ const subscription = copilotkit.subscribeToAgentWithOptions(agent, handlers, { throttleMs });
4117
+ return () => {
4118
+ active = false;
4119
+ subscription.unsubscribe();
4120
+ };
4121
+ }, [
4122
+ agent,
4123
+ forceUpdate,
4124
+ throttleMs,
4125
+ providerThrottleMs,
4126
+ updateFlags
4127
+ ]);
4128
+ useEffect(() => {
4129
+ if (agent instanceof HttpAgent) agent.headers = { ...copilotkit.headers };
4130
+ }, [agent, JSON.stringify(copilotkit.headers)]);
4131
+ return { agent };
4132
+ }
4133
+
4163
4134
  //#endregion
4164
4135
  //#region src/v2/hooks/use-capabilities.tsx
4165
4136
  /**
@@ -5625,6 +5596,190 @@ CopilotChatSuggestionView.displayName = "CopilotChatSuggestionView";
5625
5596
  */
5626
5597
  const ScrollElementContext = React.createContext(null);
5627
5598
 
5599
+ //#endregion
5600
+ //#region src/v2/components/intelligence-indicator/IntelligenceIndicator.tsx
5601
+ /**
5602
+ * Grace window before showing the spinner. A matching tool call must
5603
+ * remain unresolved (no `tool`-role result message in `agent.messages`)
5604
+ * for at least this long before the pill appears. This filters out
5605
+ * history-replay flashes — during `connectAgent` replay, tool calls and
5606
+ * their results arrive back-to-back in sub-millisecond bursts, so the
5607
+ * timer is cancelled before it fires. Live runs cross the threshold
5608
+ * easily because the tool actually has to execute.
5609
+ */
5610
+ const PENDING_THRESHOLD_MS = 100;
5611
+ /** Hold the checkmark briefly before fading out. */
5612
+ const CHECK_HOLD_MS = 800;
5613
+ /**
5614
+ * Duration of the fade-out animation. Must match
5615
+ * `cpk-intelligence-pill-fade-out` keyframes in `v2/styles/globals.css`.
5616
+ */
5617
+ const FADE_OUT_ANIMATION_MS = 480;
5618
+ /**
5619
+ * Tool-name regex patterns that trigger the indicator. Currently
5620
+ * hardcoded to the Intelligence MCP server's canonical tool name. If
5621
+ * we add per-instance customization later (e.g. a `CopilotKitProvider`
5622
+ * prop or a runtime-info field), this constant becomes the fallback.
5623
+ */
5624
+ const DEFAULT_TOOL_PATTERNS = [/^copilotkit_knowledge_base_shell$/];
5625
+ const isMatchingToolCallName = (name) => typeof name === "string" && DEFAULT_TOOL_PATTERNS.some((p) => p.test(name));
5626
+ /**
5627
+ * "Tool-call-like" messages do NOT count as a real follow-up: tool
5628
+ * result messages, assistant messages that carry tool calls, and
5629
+ * empty-content assistant messages (which some providers emit as a
5630
+ * standalone wrapper around a batch of tool calls). A real follow-up
5631
+ * is anything else — most importantly an assistant message with prose
5632
+ * content, or a fresh user message.
5633
+ */
5634
+ const isToolCallLikeMessage = (m) => {
5635
+ if (m.role === "tool") return true;
5636
+ if (m.role === "assistant") {
5637
+ if ((Array.isArray(m.toolCalls) ? m.toolCalls : []).length > 0) return true;
5638
+ const content = m.content;
5639
+ return typeof content !== "string" || content.trim().length === 0;
5640
+ }
5641
+ return false;
5642
+ };
5643
+ /**
5644
+ * The "Using CopilotKit Intelligence" pill. Auto-mounted by
5645
+ * `CopilotChatMessageView` for every message slot when
5646
+ * `copilotkit.intelligence` is configured — callers do not register
5647
+ * this themselves. Self-gates so only the canonical message renders a
5648
+ * pill.
5649
+ *
5650
+ * Render gates (all must hold):
5651
+ * 1. `copilotkit.intelligence !== undefined`
5652
+ * 2. The message is an assistant message with at least one tool call
5653
+ * whose name matches {@link DEFAULT_TOOL_PATTERNS}
5654
+ * 3. The message is the *latest* such matching-assistant message in
5655
+ * `agent.messages` — tool-result messages and prose-only assistant
5656
+ * messages don't invalidate the slot, so the pill stays
5657
+ * continuously through a multi-step tool chain.
5658
+ * 4. The phase machine is past `idle` (the pending-grace timer fired)
5659
+ * and not yet `hidden`.
5660
+ *
5661
+ * Phase machine (per-instance, all timers local):
5662
+ * - Starts in `idle` — nothing rendered.
5663
+ * - `idle → spinner` once a matching tool call has been pending
5664
+ * (no `tool`-role result with a matching `toolCallId`) for
5665
+ * {@link PENDING_THRESHOLD_MS}. Replay flashes (tool call + result
5666
+ * in the same tick) never cross this threshold.
5667
+ * - `spinner → check` as soon as EITHER `agent.isRunning` flips
5668
+ * false OR a non-tool-call-like message appears later in
5669
+ * `agent.messages` (i.e. the agent has produced a "real"
5670
+ * follow-up — prose answer or a new user turn).
5671
+ * - `check → fading` after {@link CHECK_HOLD_MS}.
5672
+ * - `fading → hidden` after {@link FADE_OUT_ANIMATION_MS}.
5673
+ *
5674
+ * Once `hidden`, the phase is sticky — a finished pill never re-spawns
5675
+ * on the same message. New runs mount fresh indicator instances on
5676
+ * their own assistant messages.
5677
+ *
5678
+ * The "exactly one pill at a time" guarantee is structural: only one
5679
+ * message satisfies the latest-matching-assistant gate at any moment.
5680
+ */
5681
+ function IntelligenceIndicator(props) {
5682
+ const { message, agentId, label = "Using CopilotKit Intelligence" } = props;
5683
+ const { copilotkit } = useCopilotKit();
5684
+ const config = useCopilotChatConfiguration();
5685
+ const { agent } = useAgent({
5686
+ agentId,
5687
+ updates: [UseAgentUpdate.OnRunStatusChanged, UseAgentUpdate.OnMessagesChanged]
5688
+ });
5689
+ const matchingToolCallIds = useMemo(() => {
5690
+ if (message.role !== "assistant") return [];
5691
+ const tcs = Array.isArray(message.toolCalls) ? message.toolCalls : [];
5692
+ const ids = [];
5693
+ for (const tc of tcs) if (isMatchingToolCallName(tc?.function?.name) && tc?.id) ids.push(tc.id);
5694
+ return ids;
5695
+ }, [message]);
5696
+ const hasPending = useMemo(() => {
5697
+ if (matchingToolCallIds.length === 0) return false;
5698
+ const resolved = /* @__PURE__ */ new Set();
5699
+ for (const m of agent.messages) if (m.role === "tool" && m.toolCallId) resolved.add(m.toolCallId);
5700
+ return matchingToolCallIds.some((id) => !resolved.has(id));
5701
+ }, [matchingToolCallIds, agent.messages]);
5702
+ const sawRealFollowup = useMemo(() => {
5703
+ const idx = agent.messages.findIndex((m) => m.id === message.id);
5704
+ if (idx < 0) return false;
5705
+ for (let i = idx + 1; i < agent.messages.length; i += 1) if (!isToolCallLikeMessage(agent.messages[i])) return true;
5706
+ return false;
5707
+ }, [agent.messages, message.id]);
5708
+ const [phase, setPhase] = useState("idle");
5709
+ useEffect(() => {
5710
+ if (phase !== "idle") return void 0;
5711
+ if (!hasPending) return void 0;
5712
+ const t = setTimeout(() => setPhase("spinner"), PENDING_THRESHOLD_MS);
5713
+ return () => clearTimeout(t);
5714
+ }, [phase, hasPending]);
5715
+ useEffect(() => {
5716
+ if (phase !== "spinner") return void 0;
5717
+ if (!agent.isRunning || sawRealFollowup) setPhase("check");
5718
+ }, [
5719
+ phase,
5720
+ agent.isRunning,
5721
+ sawRealFollowup
5722
+ ]);
5723
+ useEffect(() => {
5724
+ if (phase !== "check") return void 0;
5725
+ const t = setTimeout(() => setPhase("fading"), CHECK_HOLD_MS);
5726
+ return () => clearTimeout(t);
5727
+ }, [phase]);
5728
+ useEffect(() => {
5729
+ if (phase !== "fading") return void 0;
5730
+ const t = setTimeout(() => setPhase("hidden"), FADE_OUT_ANIMATION_MS);
5731
+ return () => clearTimeout(t);
5732
+ }, [phase]);
5733
+ if (copilotkit.intelligence === void 0) return null;
5734
+ if (!config) return null;
5735
+ if (phase === "idle" || phase === "hidden") return null;
5736
+ if (message.role !== "assistant") return null;
5737
+ if (!(Array.isArray(message.toolCalls) ? message.toolCalls : []).some((tc) => isMatchingToolCallName(tc?.function?.name))) return null;
5738
+ let latestMatchingAssistantId;
5739
+ for (let i = agent.messages.length - 1; i >= 0; i -= 1) {
5740
+ const m = agent.messages[i];
5741
+ if (m.role !== "assistant") continue;
5742
+ if ((Array.isArray(m.toolCalls) ? m.toolCalls : []).some((tc) => isMatchingToolCallName(tc?.function?.name))) {
5743
+ latestMatchingAssistantId = m.id;
5744
+ break;
5745
+ }
5746
+ }
5747
+ if (latestMatchingAssistantId !== message.id) return null;
5748
+ const showSpinner = phase === "spinner";
5749
+ const isFading = phase === "fading";
5750
+ return /* @__PURE__ */ jsxs("span", {
5751
+ className: "cpk-intelligence-pill" + (isFading ? " cpk-intelligence-pill--fading" : ""),
5752
+ role: "status",
5753
+ "aria-live": "polite",
5754
+ "aria-hidden": isFading || void 0,
5755
+ "data-testid": `cpk-intelligence-pill-${message.id}`,
5756
+ title: label,
5757
+ children: [/* @__PURE__ */ jsxs("svg", {
5758
+ className: "cpk-intelligence-pill__icon",
5759
+ viewBox: "0 0 24 24",
5760
+ width: "14",
5761
+ height: "14",
5762
+ "aria-hidden": "true",
5763
+ children: [/* @__PURE__ */ jsx("circle", {
5764
+ cx: "12",
5765
+ cy: "12",
5766
+ r: "9",
5767
+ fill: "none",
5768
+ strokeWidth: "2.5",
5769
+ strokeLinecap: "round",
5770
+ className: "cpk-intelligence-pill__ring" + (showSpinner ? "" : " cpk-intelligence-pill__ring--done")
5771
+ }), /* @__PURE__ */ jsx("path", {
5772
+ d: "M8 12.5l3 3 5-6",
5773
+ fill: "none",
5774
+ strokeWidth: "2.5",
5775
+ strokeLinecap: "round",
5776
+ strokeLinejoin: "round",
5777
+ className: "cpk-intelligence-pill__check" + (showSpinner ? "" : " cpk-intelligence-pill__check--shown")
5778
+ })]
5779
+ }), /* @__PURE__ */ jsx("span", { children: label })]
5780
+ });
5781
+ }
5782
+
5628
5783
  //#endregion
5629
5784
  //#region src/v2/components/chat/CopilotChatMessageView.tsx
5630
5785
  /**
@@ -5782,14 +5937,12 @@ function CopilotChatMessageView({ messages = [], assistantMessage, userMessage,
5782
5937
  const [, forceUpdate] = useReducer((x) => x + 1, 0);
5783
5938
  useEffect(() => {
5784
5939
  if (!config?.agentId) return;
5785
- const registryAgent = copilotkit.getAgent(config.agentId);
5786
- const agent = getThreadClone(registryAgent, config.threadId) ?? registryAgent;
5940
+ const agent = copilotkit.getAgent(config.agentId);
5787
5941
  if (!agent) return;
5788
5942
  const subscription = agent.subscribe({ onStateChanged: forceUpdate });
5789
5943
  return () => subscription.unsubscribe();
5790
5944
  }, [
5791
5945
  config?.agentId,
5792
- config?.threadId,
5793
5946
  copilotkit,
5794
5947
  forceUpdate
5795
5948
  ]);
@@ -5872,6 +6025,10 @@ function CopilotChatMessageView({ messages = [], assistantMessage, userMessage,
5872
6025
  renderCustomMessage,
5873
6026
  stateSnapshot
5874
6027
  }, `${message.id}-custom-after`));
6028
+ if (copilotkit.intelligence !== void 0 && message.role === "assistant") elements.push(/* @__PURE__ */ jsx(IntelligenceIndicator, {
6029
+ message,
6030
+ agentId: config?.agentId ?? DEFAULT_AGENT_ID
6031
+ }, `${message.id}-intelligence`));
5875
6032
  return elements.filter(Boolean);
5876
6033
  };
5877
6034
  const messageElements = shouldVirtualize ? [] : deduplicatedMessages.flatMap(renderMessageBlock);
@@ -6820,7 +6977,6 @@ function CopilotChat({ agentId, threadId, labels, chatView, isModalDefaultOpen,
6820
6977
  const hasExplicitThreadId = !!threadId || !!existingConfig?.hasExplicitThreadId;
6821
6978
  const { agent } = useAgent({
6822
6979
  agentId: resolvedAgentId,
6823
- threadId: resolvedThreadId,
6824
6980
  throttleMs
6825
6981
  });
6826
6982
  const { copilotkit } = useCopilotKit();
@@ -6862,6 +7018,7 @@ function CopilotChat({ agentId, threadId, labels, chatView, isModalDefaultOpen,
6862
7018
  let detached = false;
6863
7019
  const connectAbortController = new AbortController();
6864
7020
  if (agent instanceof HttpAgent) agent.abortController = connectAbortController;
7021
+ agent.threadId = resolvedThreadId;
6865
7022
  const connect = async (agent) => {
6866
7023
  try {
6867
7024
  await copilotkit.connectAgent({ agent });
@@ -7270,18 +7427,19 @@ CopilotModalHeader.CloseButton.displayName = "CopilotModalHeader.CloseButton";
7270
7427
  //#region src/v2/components/chat/CopilotSidebarView.tsx
7271
7428
  const DEFAULT_SIDEBAR_WIDTH = 480;
7272
7429
  const SIDEBAR_TRANSITION_MS = 260;
7273
- function CopilotSidebarView({ header, toggleButton, width, defaultOpen = true, ...props }) {
7430
+ function CopilotSidebarView({ header, toggleButton, width, defaultOpen = true, position = "right", ...props }) {
7274
7431
  return /* @__PURE__ */ jsx(CopilotChatConfigurationProvider, {
7275
7432
  isModalDefaultOpen: defaultOpen,
7276
7433
  children: /* @__PURE__ */ jsx(CopilotSidebarViewInternal, {
7277
7434
  header,
7278
7435
  toggleButton,
7279
7436
  width,
7437
+ position,
7280
7438
  ...props
7281
7439
  })
7282
7440
  });
7283
7441
  }
7284
- function CopilotSidebarViewInternal({ header, toggleButton, width, ...props }) {
7442
+ function CopilotSidebarViewInternal({ header, toggleButton, width, position = "right", ...props }) {
7285
7443
  const isSidebarOpen = useCopilotChatConfiguration()?.isModalOpen ?? false;
7286
7444
  const sidebarRef = useRef(null);
7287
7445
  const [sidebarWidth, setSidebarWidth] = useState(width ?? DEFAULT_SIDEBAR_WIDTH);
@@ -7314,26 +7472,33 @@ function CopilotSidebarViewInternal({ header, toggleButton, width, ...props }) {
7314
7472
  useLayoutEffect(() => {
7315
7473
  if (typeof window === "undefined" || typeof window.matchMedia !== "function") return;
7316
7474
  if (!window.matchMedia("(min-width: 768px)").matches) return;
7475
+ const marginStyleProp = position === "left" ? "marginInlineStart" : "marginInlineEnd";
7476
+ const transitionCssProp = position === "left" ? "margin-inline-start" : "margin-inline-end";
7317
7477
  if (isSidebarOpen) {
7318
- if (hasMounted.current) document.body.style.transition = `margin-inline-end ${SIDEBAR_TRANSITION_MS}ms ease`;
7319
- document.body.style.marginInlineEnd = widthToMargin(sidebarWidth);
7478
+ if (hasMounted.current) document.body.style.transition = `${transitionCssProp} ${SIDEBAR_TRANSITION_MS}ms ease`;
7479
+ document.body.style[marginStyleProp] = widthToMargin(sidebarWidth);
7320
7480
  } else if (hasMounted.current) {
7321
- document.body.style.transition = `margin-inline-end ${SIDEBAR_TRANSITION_MS}ms ease`;
7322
- document.body.style.marginInlineEnd = "";
7481
+ document.body.style.transition = `${transitionCssProp} ${SIDEBAR_TRANSITION_MS}ms ease`;
7482
+ document.body.style[marginStyleProp] = "";
7323
7483
  }
7324
7484
  hasMounted.current = true;
7325
7485
  return () => {
7326
- document.body.style.marginInlineEnd = "";
7486
+ document.body.style[marginStyleProp] = "";
7327
7487
  document.body.style.transition = "";
7328
7488
  };
7329
- }, [isSidebarOpen, sidebarWidth]);
7489
+ }, [
7490
+ isSidebarOpen,
7491
+ sidebarWidth,
7492
+ position
7493
+ ]);
7330
7494
  const headerElement = renderSlot(header, CopilotModalHeader, {});
7331
- return /* @__PURE__ */ jsxs(Fragment$1, { children: [renderSlot(toggleButton, CopilotChatToggleButton, {}), /* @__PURE__ */ jsx("aside", {
7495
+ return /* @__PURE__ */ jsxs(Fragment$1, { children: [renderSlot(toggleButton, CopilotChatToggleButton, position === "left" ? { className: "cpk:left-6 cpk:right-auto" } : {}), /* @__PURE__ */ jsx("aside", {
7332
7496
  ref: sidebarRef,
7333
7497
  "data-copilotkit": true,
7334
7498
  "data-testid": "copilot-sidebar",
7335
7499
  "data-copilot-sidebar": true,
7336
- className: cn("copilotKitSidebar copilotKitWindow", "cpk:fixed cpk:right-0 cpk:top-0 cpk:z-[1200] cpk:flex", "cpk:h-[100vh] cpk:h-[100dvh] cpk:max-h-screen", "cpk:w-full", "cpk:border-l cpk:border-border cpk:bg-background cpk:text-foreground cpk:shadow-xl", "cpk:transition-transform cpk:duration-300 cpk:ease-out", isSidebarOpen ? "cpk:translate-x-0" : "cpk:translate-x-full cpk:pointer-events-none"),
7500
+ "data-position": position,
7501
+ className: cn("copilotKitSidebar copilotKitWindow", "cpk:fixed cpk:top-0 cpk:z-[1200] cpk:flex", position === "left" ? "cpk:left-0" : "cpk:right-0", "cpk:h-[100vh] cpk:h-[100dvh] cpk:max-h-screen", "cpk:w-full", position === "left" ? "cpk:border-r" : "cpk:border-l", "cpk:border-border cpk:bg-background cpk:text-foreground cpk:shadow-xl", "cpk:transition-transform cpk:duration-300 cpk:ease-out", isSidebarOpen ? "cpk:translate-x-0" : position === "left" ? "cpk:-translate-x-full cpk:pointer-events-none" : "cpk:translate-x-full cpk:pointer-events-none"),
7337
7502
  style: {
7338
7503
  ["--sidebar-width"]: widthToCss(sidebarWidth),
7339
7504
  paddingTop: "env(safe-area-inset-top)",
@@ -7540,7 +7705,7 @@ var CopilotPopupView_default = CopilotPopupView;
7540
7705
 
7541
7706
  //#endregion
7542
7707
  //#region src/v2/components/chat/CopilotSidebar.tsx
7543
- function CopilotSidebar({ header, toggleButton, defaultOpen, width, ...chatProps }) {
7708
+ function CopilotSidebar({ header, toggleButton, defaultOpen, width, position, ...chatProps }) {
7544
7709
  const { checkFeature } = useLicenseContext();
7545
7710
  const isSidebarLicensed = checkFeature("sidebar");
7546
7711
  useEffect(() => {
@@ -7548,13 +7713,14 @@ function CopilotSidebar({ header, toggleButton, defaultOpen, width, ...chatProps
7548
7713
  }, [isSidebarLicensed]);
7549
7714
  const SidebarViewOverride = useMemo(() => {
7550
7715
  const Component = (viewProps) => {
7551
- const { header: viewHeader, toggleButton: viewToggleButton, width: viewWidth, defaultOpen: viewDefaultOpen, ...restProps } = viewProps;
7716
+ const { header: viewHeader, toggleButton: viewToggleButton, width: viewWidth, defaultOpen: viewDefaultOpen, position: viewPosition, ...restProps } = viewProps;
7552
7717
  return /* @__PURE__ */ jsx(CopilotSidebarView, {
7553
7718
  ...restProps,
7554
7719
  header: header ?? viewHeader,
7555
7720
  toggleButton: toggleButton ?? viewToggleButton,
7556
7721
  width: width ?? viewWidth,
7557
- defaultOpen: defaultOpen ?? viewDefaultOpen
7722
+ defaultOpen: defaultOpen ?? viewDefaultOpen,
7723
+ position: position ?? viewPosition
7558
7724
  });
7559
7725
  };
7560
7726
  return Object.assign(Component, CopilotChatView_default);
@@ -7562,7 +7728,8 @@ function CopilotSidebar({ header, toggleButton, defaultOpen, width, ...chatProps
7562
7728
  header,
7563
7729
  toggleButton,
7564
7730
  width,
7565
- defaultOpen
7731
+ defaultOpen,
7732
+ position
7566
7733
  ]);
7567
7734
  return /* @__PURE__ */ jsxs(Fragment$1, { children: [!isSidebarLicensed && /* @__PURE__ */ jsx(InlineFeatureWarning, { featureName: "Sidebar" }), /* @__PURE__ */ jsx(CopilotChat, {
7568
7735
  welcomeScreen: CopilotSidebarView.WelcomeScreen,
@@ -9802,5 +9969,5 @@ function validateProps(props) {
9802
9969
  }
9803
9970
 
9804
9971
  //#endregion
9805
- export { CopilotKitProvider as $, CopilotChatSuggestionView as A, useConfigureSuggestions as B, CopilotChatToggleButton as C, CopilotChatView_default as D, CopilotChat as E, CopilotChatAssistantMessage_default as F, useRenderTool as G, useCapabilities as H, CopilotChatToolCallsView as I, useRenderActivityMessage as J, useComponent as K, useAttachments as L, CopilotChatReasoningMessage_default as M, CopilotChatUserMessage_default as N, CopilotChatAttachmentQueue as O, CopilotChatAttachmentRenderer as P, useRenderToolCall as Q, useThreads$1 as R, CopilotModalHeader as S, DefaultOpenIcon as T, useHumanInTheLoop as U, useSuggestions as V, useDefaultRenderTool as W, UseAgentUpdate as X, useRenderCustomMessages as Y, useAgent as Z, WildcardToolCallRender as _, ThreadsProvider as a, SandboxFunctionsContext as at, CopilotPopupView as b, CoAgentStateRendersProvider as c, MCPAppsActivityRenderer as ct, shouldShowDevConsole as d, CopilotChatInput_default as dt, useCopilotKit as et, useToast as f, AudioRecorderError as ft, useCopilotContext as g, CopilotContext as h, useCopilotChatConfiguration as ht, ThreadsContext as i, createA2UIMessageRenderer as it, CopilotChatSuggestionPill as j, CopilotChatMessageView as k, useCoAgentStateRenders as l, MCPAppsActivityType as lt, useCopilotMessagesContext as m, CopilotChatConfigurationProvider as mt, defaultCopilotContextCategories as n, useAgentContext as nt, useThreads as o, useSandboxFunctions as ot, CopilotMessagesContext as p, CopilotChatAudioRecorder as pt, useFrontendTool as q, CoAgentStateRenderBridge as r, defineToolCallRenderer as rt, CoAgentStateRendersContext as s, MCPAppsActivityContentSchema as st, CopilotKit as t, CopilotKitCoreReact as tt, useAsyncCallback as u, CopilotKitInspector as ut, CopilotPopup as v, DefaultCloseIcon as w, CopilotSidebarView as x, CopilotSidebar as y, useInterrupt as z };
9806
- //# sourceMappingURL=copilotkit-CPe2-340.mjs.map
9972
+ 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 };
9973
+ //# sourceMappingURL=copilotkit-3XTEoVQO.mjs.map