@copilotkit/react-core 1.57.0-canary.1778078321 → 1.57.0-canary.1778116520

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 (84) hide show
  1. package/dist/{copilotkit-XGd8L2jL.cjs → copilotkit-BLlkMAjx.cjs} +368 -502
  2. package/dist/copilotkit-BLlkMAjx.cjs.map +1 -0
  3. package/dist/{copilotkit-BNlJq5UO.d.mts → copilotkit-BYnbIBN5.d.mts} +10 -62
  4. package/dist/copilotkit-BYnbIBN5.d.mts.map +1 -0
  5. package/dist/{copilotkit-DhuXdtE1.mjs → copilotkit-N0YiBG5S.mjs} +369 -497
  6. package/dist/copilotkit-N0YiBG5S.mjs.map +1 -0
  7. package/dist/{copilotkit-DgC5oCFO.d.cts → copilotkit-vx_R9p-O.d.cts} +10 -62
  8. package/dist/copilotkit-vx_R9p-O.d.cts.map +1 -0
  9. package/dist/index.cjs +5 -2
  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 +5 -2
  14. package/dist/index.mjs.map +1 -1
  15. package/dist/index.umd.js +409 -347
  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 +1085 -0
  26. package/dist/v2/headless.cjs.map +1 -0
  27. package/dist/v2/headless.d.cts +607 -0
  28. package/dist/v2/headless.d.cts.map +1 -0
  29. package/dist/v2/headless.d.mts +514 -0
  30. package/dist/v2/headless.d.mts.map +1 -0
  31. package/dist/v2/headless.mjs +1039 -0
  32. package/dist/v2/headless.mjs.map +1 -0
  33. package/dist/v2/index.cjs +1 -2
  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 +387 -523
  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 +6 -5
  42. package/src/hooks/use-copilot-chat_internal.ts +1 -0
  43. package/src/v2/components/MCPAppsActivityRenderer.tsx +9 -3
  44. package/src/v2/components/chat/CopilotChat.tsx +1 -2
  45. package/src/v2/components/chat/CopilotChatMessageView.tsx +9 -24
  46. package/src/v2/components/chat/CopilotChatView.tsx +2 -2
  47. package/src/v2/components/chat/__tests__/CopilotChat.welcomeGate.test.tsx +3 -1
  48. package/src/v2/components/chat/__tests__/CopilotChatActivityRendering.e2e.test.tsx +25 -29
  49. package/src/v2/components/chat/__tests__/MCPAppsActivityRenderer.e2e.test.tsx +102 -0
  50. package/src/v2/components/chat/__tests__/MCPAppsUiMessage.e2e.test.tsx +60 -5
  51. package/src/v2/components/index.ts +0 -1
  52. package/src/v2/context.ts +62 -0
  53. package/src/v2/headless.ts +42 -0
  54. package/src/v2/hooks/__tests__/standard-schema.test.tsx +2 -2
  55. package/src/v2/hooks/__tests__/use-agent-context.test.tsx +3 -3
  56. package/src/v2/hooks/__tests__/use-agent-stability.test.tsx +3 -3
  57. package/src/v2/hooks/__tests__/use-agent-thread-isolation.test.tsx +333 -0
  58. package/src/v2/hooks/__tests__/use-agent-throttle.test.tsx +85 -85
  59. package/src/v2/hooks/__tests__/use-interrupt.test.tsx +2 -2
  60. package/src/v2/hooks/__tests__/use-render-tool.test.tsx +2 -2
  61. package/src/v2/hooks/__tests__/use-threads.test.tsx +2 -2
  62. package/src/v2/hooks/__tests__/zod-regression.test.tsx +2 -2
  63. package/src/v2/hooks/use-agent-context.tsx +1 -1
  64. package/src/v2/hooks/use-agent.tsx +118 -9
  65. package/src/v2/hooks/use-configure-suggestions.tsx +1 -1
  66. package/src/v2/hooks/use-frontend-tool.tsx +2 -2
  67. package/src/v2/hooks/use-human-in-the-loop.tsx +1 -1
  68. package/src/v2/hooks/use-interrupt.tsx +1 -1
  69. package/src/v2/hooks/use-render-activity-message.tsx +11 -3
  70. package/src/v2/hooks/use-render-custom-messages.tsx +6 -1
  71. package/src/v2/hooks/use-render-tool-call.tsx +1 -1
  72. package/src/v2/hooks/use-render-tool.tsx +2 -2
  73. package/src/v2/hooks/use-suggestions.tsx +1 -1
  74. package/src/v2/hooks/use-threads.tsx +1 -1
  75. package/src/v2/providers/CopilotKitProvider.tsx +19 -59
  76. package/src/v2/styles/globals.css +0 -118
  77. package/tsdown.config.ts +75 -0
  78. package/dist/copilotkit-BNlJq5UO.d.mts.map +0 -1
  79. package/dist/copilotkit-DgC5oCFO.d.cts.map +0 -1
  80. package/dist/copilotkit-DhuXdtE1.mjs.map +0 -1
  81. package/dist/copilotkit-XGd8L2jL.cjs.map +0 -1
  82. package/src/v2/components/intelligence-indicator/IntelligenceIndicator.tsx +0 -284
  83. package/src/v2/components/intelligence-indicator/__tests__/IntelligenceIndicator.e2e.test.tsx +0 -464
  84. package/src/v2/components/intelligence-indicator/index.ts +0 -2
@@ -1324,6 +1324,197 @@ function useKatexStyles() {
1324
1324
  }, []);
1325
1325
  }
1326
1326
 
1327
+ //#endregion
1328
+ //#region src/v2/lib/react-core.ts
1329
+ var CopilotKitCoreReact = class extends _copilotkit_core.CopilotKitCore {
1330
+ constructor(config) {
1331
+ super(config);
1332
+ this._renderToolCalls = [];
1333
+ this._hookRenderToolCalls = /* @__PURE__ */ new Map();
1334
+ this._cachedMergedRenderToolCalls = null;
1335
+ this._renderCustomMessages = [];
1336
+ this._renderActivityMessages = [];
1337
+ this._interruptElement = null;
1338
+ this._renderToolCalls = config.renderToolCalls ?? [];
1339
+ this._renderCustomMessages = config.renderCustomMessages ?? [];
1340
+ this._renderActivityMessages = config.renderActivityMessages ?? [];
1341
+ }
1342
+ get renderCustomMessages() {
1343
+ return this._renderCustomMessages;
1344
+ }
1345
+ get renderActivityMessages() {
1346
+ return this._renderActivityMessages;
1347
+ }
1348
+ get renderToolCalls() {
1349
+ if (this._hookRenderToolCalls.size === 0) return this._renderToolCalls;
1350
+ if (this._cachedMergedRenderToolCalls) return this._cachedMergedRenderToolCalls;
1351
+ const merged = /* @__PURE__ */ new Map();
1352
+ for (const rc of this._renderToolCalls) merged.set(`${rc.agentId ?? ""}:${rc.name}`, rc);
1353
+ for (const [key, rc] of this._hookRenderToolCalls) merged.set(key, rc);
1354
+ this._cachedMergedRenderToolCalls = Array.from(merged.values());
1355
+ return this._cachedMergedRenderToolCalls;
1356
+ }
1357
+ setRenderActivityMessages(renderers) {
1358
+ this._renderActivityMessages = renderers;
1359
+ }
1360
+ setRenderCustomMessages(renderers) {
1361
+ this._renderCustomMessages = renderers;
1362
+ }
1363
+ setRenderToolCalls(renderToolCalls) {
1364
+ this._renderToolCalls = renderToolCalls;
1365
+ this._cachedMergedRenderToolCalls = null;
1366
+ this._notifyRenderToolCallsChanged();
1367
+ }
1368
+ addHookRenderToolCall(entry) {
1369
+ const key = `${entry.agentId ?? ""}:${entry.name}`;
1370
+ this._hookRenderToolCalls.set(key, entry);
1371
+ this._cachedMergedRenderToolCalls = null;
1372
+ this._notifyRenderToolCallsChanged();
1373
+ }
1374
+ removeHookRenderToolCall(name, agentId) {
1375
+ const key = `${agentId ?? ""}:${name}`;
1376
+ if (this._hookRenderToolCalls.delete(key)) {
1377
+ this._cachedMergedRenderToolCalls = null;
1378
+ this._notifyRenderToolCallsChanged();
1379
+ }
1380
+ }
1381
+ _notifyRenderToolCallsChanged() {
1382
+ this.notifySubscribers((subscriber) => {
1383
+ const reactSubscriber = subscriber;
1384
+ if (reactSubscriber.onRenderToolCallsChanged) reactSubscriber.onRenderToolCallsChanged({
1385
+ copilotkit: this,
1386
+ renderToolCalls: this.renderToolCalls
1387
+ });
1388
+ }, "Subscriber onRenderToolCallsChanged error:");
1389
+ }
1390
+ get interruptElement() {
1391
+ return this._interruptElement;
1392
+ }
1393
+ setInterruptElement(element) {
1394
+ this._interruptElement = element;
1395
+ this.notifySubscribers((subscriber) => {
1396
+ subscriber.onInterruptElementChanged?.({
1397
+ copilotkit: this,
1398
+ interruptElement: this._interruptElement
1399
+ });
1400
+ }, "Subscriber onInterruptElementChanged error:");
1401
+ }
1402
+ subscribe(subscriber) {
1403
+ return super.subscribe(subscriber);
1404
+ }
1405
+ /**
1406
+ * Wait for pending React state updates before the follow-up agent run.
1407
+ *
1408
+ * When a frontend tool handler calls setState(), React 18 batches the update
1409
+ * and schedules a commit via its internal scheduler (MessageChannel). The
1410
+ * useAgentContext hook registers context via useLayoutEffect, which runs
1411
+ * synchronously after React commits that batch.
1412
+ *
1413
+ * Awaiting a zero-delay timeout yields to the macrotask queue. React's
1414
+ * MessageChannel task runs first, committing the pending state and running
1415
+ * useLayoutEffect (which updates the context store). The follow-up runAgent
1416
+ * call then reads fresh context.
1417
+ */
1418
+ async waitForPendingFrameworkUpdates() {
1419
+ await new Promise((resolve) => setTimeout(resolve, 0));
1420
+ }
1421
+ };
1422
+
1423
+ //#endregion
1424
+ //#region src/v2/context.ts
1425
+ const CopilotKitContext = (0, react.createContext)(null);
1426
+ const useCopilotKit = () => {
1427
+ const context = (0, react.useContext)(CopilotKitContext);
1428
+ const [, forceUpdate] = (0, react.useReducer)((x) => x + 1, 0);
1429
+ if (!context) throw new Error("useCopilotKit must be used within CopilotKitProvider");
1430
+ (0, react.useEffect)(() => {
1431
+ const subscription = context.copilotkit.subscribe({ onRuntimeConnectionStatusChanged: () => {
1432
+ forceUpdate();
1433
+ } });
1434
+ return () => {
1435
+ subscription.unsubscribe();
1436
+ };
1437
+ }, []);
1438
+ return context;
1439
+ };
1440
+ const LicenseContext = (0, react.createContext)({
1441
+ status: null,
1442
+ license: null,
1443
+ checkFeature: () => true,
1444
+ getLimit: () => null
1445
+ });
1446
+ const useLicenseContext = () => (0, react.useContext)(LicenseContext);
1447
+
1448
+ //#endregion
1449
+ //#region src/v2/hooks/use-render-tool-call.tsx
1450
+ /**
1451
+ * Memoized component that renders a single tool call.
1452
+ * This prevents unnecessary re-renders when parent components update
1453
+ * but the tool call data hasn't changed.
1454
+ */
1455
+ const ToolCallRenderer = react.default.memo(function ToolCallRenderer({ toolCall, toolMessage, RenderComponent, isExecuting }) {
1456
+ const args = (0, react.useMemo)(() => (0, _copilotkit_shared.partialJSONParse)(toolCall.function.arguments), [toolCall.function.arguments]);
1457
+ const toolName = toolCall.function.name;
1458
+ if (toolMessage) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(RenderComponent, {
1459
+ name: toolName,
1460
+ toolCallId: toolCall.id,
1461
+ args,
1462
+ status: _copilotkit_core.ToolCallStatus.Complete,
1463
+ result: toolMessage.content
1464
+ });
1465
+ else if (isExecuting) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(RenderComponent, {
1466
+ name: toolName,
1467
+ toolCallId: toolCall.id,
1468
+ args,
1469
+ status: _copilotkit_core.ToolCallStatus.Executing,
1470
+ result: void 0
1471
+ });
1472
+ else return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(RenderComponent, {
1473
+ name: toolName,
1474
+ toolCallId: toolCall.id,
1475
+ args,
1476
+ status: _copilotkit_core.ToolCallStatus.InProgress,
1477
+ result: void 0
1478
+ });
1479
+ }, (prevProps, nextProps) => {
1480
+ if (prevProps.toolCall.id !== nextProps.toolCall.id) return false;
1481
+ if (prevProps.toolCall.function.name !== nextProps.toolCall.function.name) return false;
1482
+ if (prevProps.toolCall.function.arguments !== nextProps.toolCall.function.arguments) return false;
1483
+ if (prevProps.toolMessage?.content !== nextProps.toolMessage?.content) return false;
1484
+ if (prevProps.isExecuting !== nextProps.isExecuting) return false;
1485
+ if (prevProps.RenderComponent !== nextProps.RenderComponent) return false;
1486
+ return true;
1487
+ });
1488
+ /**
1489
+ * Hook that returns a function to render tool calls based on the render functions
1490
+ * defined in CopilotKitProvider.
1491
+ *
1492
+ * @returns A function that takes a tool call and optional tool message and returns the rendered component
1493
+ */
1494
+ function useRenderToolCall() {
1495
+ const { copilotkit, executingToolCallIds } = useCopilotKit();
1496
+ const agentId = useCopilotChatConfiguration()?.agentId ?? _copilotkit_shared.DEFAULT_AGENT_ID;
1497
+ const renderToolCalls = (0, react.useSyncExternalStore)((callback) => {
1498
+ return copilotkit.subscribe({ onRenderToolCallsChanged: callback }).unsubscribe;
1499
+ }, () => copilotkit.renderToolCalls, () => copilotkit.renderToolCalls);
1500
+ return (0, react.useCallback)(({ toolCall, toolMessage }) => {
1501
+ const exactMatches = renderToolCalls.filter((rc) => rc.name === toolCall.function.name);
1502
+ const renderConfig = exactMatches.find((rc) => rc.agentId === agentId) || exactMatches.find((rc) => !rc.agentId) || exactMatches[0] || renderToolCalls.find((rc) => rc.name === "*");
1503
+ if (!renderConfig) return null;
1504
+ const RenderComponent = renderConfig.render;
1505
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ToolCallRenderer, {
1506
+ toolCall,
1507
+ toolMessage,
1508
+ RenderComponent,
1509
+ isExecuting: executingToolCallIds.has(toolCall.id)
1510
+ }, toolCall.id);
1511
+ }, [
1512
+ renderToolCalls,
1513
+ executingToolCallIds,
1514
+ agentId
1515
+ ]);
1516
+ }
1517
+
1327
1518
  //#endregion
1328
1519
  //#region src/v2/components/CopilotKitInspector.tsx
1329
1520
  const CopilotKitInspector = ({ core, ...rest }) => {
@@ -1668,6 +1859,7 @@ const MCPAppsActivityRenderer = function MCPAppsActivityRenderer({ content, agen
1668
1859
  promise: null,
1669
1860
  resourceUri: null
1670
1861
  });
1862
+ const { resourceUri, serverHash, serverId } = content;
1671
1863
  const sendToIframe = (0, react.useCallback)((msg) => {
1672
1864
  if (iframeRef.current?.contentWindow) {
1673
1865
  console.log("[MCPAppsRenderer] Sending to iframe:", msg);
@@ -1699,7 +1891,6 @@ const MCPAppsActivityRenderer = function MCPAppsActivityRenderer({ content, agen
1699
1891
  });
1700
1892
  }, [sendToIframe]);
1701
1893
  (0, react.useEffect)(() => {
1702
- const { resourceUri, serverHash, serverId } = content;
1703
1894
  if (fetchStateRef.current.inProgress && fetchStateRef.current.resourceUri === resourceUri) {
1704
1895
  fetchStateRef.current.promise?.then((resource) => {
1705
1896
  if (resource) {
@@ -1746,7 +1937,12 @@ const MCPAppsActivityRenderer = function MCPAppsActivityRenderer({ content, agen
1746
1937
  setError(err instanceof Error ? err : new Error(String(err)));
1747
1938
  setIsLoading(false);
1748
1939
  });
1749
- }, [agent, content]);
1940
+ }, [
1941
+ agent,
1942
+ resourceUri,
1943
+ serverHash,
1944
+ serverId
1945
+ ]);
1750
1946
  (0, react.useEffect)(() => {
1751
1947
  if (isLoading || !fetchedResource) return;
1752
1948
  const container = containerRef.current;
@@ -2967,102 +3163,6 @@ function A2UICatalogContext({ catalog, includeSchema }) {
2967
3163
  return null;
2968
3164
  }
2969
3165
 
2970
- //#endregion
2971
- //#region src/v2/lib/react-core.ts
2972
- var CopilotKitCoreReact = class extends _copilotkit_core.CopilotKitCore {
2973
- constructor(config) {
2974
- super(config);
2975
- this._renderToolCalls = [];
2976
- this._hookRenderToolCalls = /* @__PURE__ */ new Map();
2977
- this._cachedMergedRenderToolCalls = null;
2978
- this._renderCustomMessages = [];
2979
- this._renderActivityMessages = [];
2980
- this._interruptElement = null;
2981
- this._renderToolCalls = config.renderToolCalls ?? [];
2982
- this._renderCustomMessages = config.renderCustomMessages ?? [];
2983
- this._renderActivityMessages = config.renderActivityMessages ?? [];
2984
- }
2985
- get renderCustomMessages() {
2986
- return this._renderCustomMessages;
2987
- }
2988
- get renderActivityMessages() {
2989
- return this._renderActivityMessages;
2990
- }
2991
- get renderToolCalls() {
2992
- if (this._hookRenderToolCalls.size === 0) return this._renderToolCalls;
2993
- if (this._cachedMergedRenderToolCalls) return this._cachedMergedRenderToolCalls;
2994
- const merged = /* @__PURE__ */ new Map();
2995
- for (const rc of this._renderToolCalls) merged.set(`${rc.agentId ?? ""}:${rc.name}`, rc);
2996
- for (const [key, rc] of this._hookRenderToolCalls) merged.set(key, rc);
2997
- this._cachedMergedRenderToolCalls = Array.from(merged.values());
2998
- return this._cachedMergedRenderToolCalls;
2999
- }
3000
- setRenderActivityMessages(renderers) {
3001
- this._renderActivityMessages = renderers;
3002
- }
3003
- setRenderCustomMessages(renderers) {
3004
- this._renderCustomMessages = renderers;
3005
- }
3006
- setRenderToolCalls(renderToolCalls) {
3007
- this._renderToolCalls = renderToolCalls;
3008
- this._cachedMergedRenderToolCalls = null;
3009
- this._notifyRenderToolCallsChanged();
3010
- }
3011
- addHookRenderToolCall(entry) {
3012
- const key = `${entry.agentId ?? ""}:${entry.name}`;
3013
- this._hookRenderToolCalls.set(key, entry);
3014
- this._cachedMergedRenderToolCalls = null;
3015
- this._notifyRenderToolCallsChanged();
3016
- }
3017
- removeHookRenderToolCall(name, agentId) {
3018
- const key = `${agentId ?? ""}:${name}`;
3019
- if (this._hookRenderToolCalls.delete(key)) {
3020
- this._cachedMergedRenderToolCalls = null;
3021
- this._notifyRenderToolCallsChanged();
3022
- }
3023
- }
3024
- _notifyRenderToolCallsChanged() {
3025
- this.notifySubscribers((subscriber) => {
3026
- const reactSubscriber = subscriber;
3027
- if (reactSubscriber.onRenderToolCallsChanged) reactSubscriber.onRenderToolCallsChanged({
3028
- copilotkit: this,
3029
- renderToolCalls: this.renderToolCalls
3030
- });
3031
- }, "Subscriber onRenderToolCallsChanged error:");
3032
- }
3033
- get interruptElement() {
3034
- return this._interruptElement;
3035
- }
3036
- setInterruptElement(element) {
3037
- this._interruptElement = element;
3038
- this.notifySubscribers((subscriber) => {
3039
- subscriber.onInterruptElementChanged?.({
3040
- copilotkit: this,
3041
- interruptElement: this._interruptElement
3042
- });
3043
- }, "Subscriber onInterruptElementChanged error:");
3044
- }
3045
- subscribe(subscriber) {
3046
- return super.subscribe(subscriber);
3047
- }
3048
- /**
3049
- * Wait for pending React state updates before the follow-up agent run.
3050
- *
3051
- * When a frontend tool handler calls setState(), React 18 batches the update
3052
- * and schedules a commit via its internal scheduler (MessageChannel). The
3053
- * useAgentContext hook registers context via useLayoutEffect, which runs
3054
- * synchronously after React commits that batch.
3055
- *
3056
- * Awaiting a zero-delay timeout yields to the macrotask queue. React's
3057
- * MessageChannel task runs first, committing the pending state and running
3058
- * useLayoutEffect (which updates the context store). The follow-up runAgent
3059
- * call then reads fresh context.
3060
- */
3061
- async waitForPendingFrameworkUpdates() {
3062
- await new Promise((resolve) => setTimeout(resolve, 0));
3063
- }
3064
- };
3065
-
3066
3166
  //#endregion
3067
3167
  //#region src/v2/providers/CopilotKitProvider.tsx
3068
3168
  const HEADER_NAME = "X-CopilotCloud-Public-Api-Key";
@@ -3078,12 +3178,6 @@ const DEFAULT_DESIGN_SKILL = `When generating UI with generateSandboxedUi, follo
3078
3178
  - Minimal transitions (150ms) for hover/focus states only. No decorative animations.
3079
3179
  - Keep the UI focused and dense — avoid excessive padding. Use compact spacing (8–12px gaps, 10–14px padding in controls).`;
3080
3180
  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)";
3081
- const CopilotKitContext = (0, react.createContext)({
3082
- copilotkit: null,
3083
- executingToolCallIds: /* @__PURE__ */ new Set()
3084
- });
3085
- const LicenseContext = (0, react.createContext)((0, _copilotkit_shared.createLicenseContextValue)(null));
3086
- const useLicenseContext = () => (0, react.useContext)(LicenseContext);
3087
3181
  function useStableArrayProp(prop, warningMessage, isMeaningfulChange) {
3088
3182
  const empty = (0, react.useMemo)(() => [], []);
3089
3183
  const value = prop ?? empty;
@@ -3305,13 +3399,9 @@ const CopilotKitProvider = ({ children, runtimeUrl, headers: headersProp = {}, c
3305
3399
  onErrorRef.current = onError;
3306
3400
  }, [onError]);
3307
3401
  (0, react.useEffect)(() => {
3308
- if (!onErrorRef.current) return;
3309
3402
  const subscription = copilotkit.subscribe({ onError: (event) => {
3310
- onErrorRef.current?.({
3311
- error: event.error,
3312
- code: event.code,
3313
- context: event.context
3314
- });
3403
+ if (onErrorRef.current) onErrorRef.current(event);
3404
+ else console.error(`[CopilotKit] Error (${event.code}):`, event.error, event.context ?? {});
3315
3405
  } });
3316
3406
  return () => {
3317
3407
  subscription.unsubscribe();
@@ -3426,89 +3516,167 @@ const CopilotKitProvider = ({ children, runtimeUrl, headers: headersProp = {}, c
3426
3516
  })
3427
3517
  });
3428
3518
  };
3429
- const useCopilotKit = () => {
3430
- const context = (0, react.useContext)(CopilotKitContext);
3519
+
3520
+ //#endregion
3521
+ //#region src/v2/hooks/use-agent.tsx
3522
+ let UseAgentUpdate = /* @__PURE__ */ function(UseAgentUpdate) {
3523
+ UseAgentUpdate["OnMessagesChanged"] = "OnMessagesChanged";
3524
+ UseAgentUpdate["OnStateChanged"] = "OnStateChanged";
3525
+ UseAgentUpdate["OnRunStatusChanged"] = "OnRunStatusChanged";
3526
+ return UseAgentUpdate;
3527
+ }({});
3528
+ const ALL_UPDATES = [
3529
+ UseAgentUpdate.OnMessagesChanged,
3530
+ UseAgentUpdate.OnStateChanged,
3531
+ UseAgentUpdate.OnRunStatusChanged
3532
+ ];
3533
+ /**
3534
+ * Clone a registry agent for per-thread isolation.
3535
+ * Copies agent configuration (transport, headers, etc.) but resets conversation
3536
+ * state (messages, threadId, state) so each thread starts fresh.
3537
+ */
3538
+ function cloneForThread(source, threadId, headers) {
3539
+ const clone = source.clone();
3540
+ if (clone === source) throw new Error(`useAgent: ${source.constructor.name}.clone() returned the same instance. clone() must return a new, independent object.`);
3541
+ clone.threadId = threadId;
3542
+ clone.setMessages([]);
3543
+ clone.setState({});
3544
+ if (clone instanceof _ag_ui_client.HttpAgent) clone.headers = { ...headers };
3545
+ return clone;
3546
+ }
3547
+ /**
3548
+ * Module-level WeakMap: registryAgent → (threadId → clone).
3549
+ * Shared across all useAgent() calls so that every component using the same
3550
+ * (agentId, threadId) pair receives the same agent instance. Using WeakMap
3551
+ * ensures the clone map is garbage-collected when the registry agent is
3552
+ * replaced (e.g. after reconnect or hot-reload).
3553
+ */
3554
+ const globalThreadCloneMap = /* @__PURE__ */ new WeakMap();
3555
+ /**
3556
+ * Look up an existing per-thread clone without creating one.
3557
+ * Returns undefined when no clone has been created yet for this pair.
3558
+ */
3559
+ function getThreadClone(registryAgent, threadId) {
3560
+ if (!registryAgent || !threadId) return void 0;
3561
+ return globalThreadCloneMap.get(registryAgent)?.get(threadId);
3562
+ }
3563
+ function getOrCreateThreadClone(existing, threadId, headers) {
3564
+ let byThread = globalThreadCloneMap.get(existing);
3565
+ if (!byThread) {
3566
+ byThread = /* @__PURE__ */ new Map();
3567
+ globalThreadCloneMap.set(existing, byThread);
3568
+ }
3569
+ const cached = byThread.get(threadId);
3570
+ if (cached) return cached;
3571
+ const clone = cloneForThread(existing, threadId, headers);
3572
+ byThread.set(threadId, clone);
3573
+ return clone;
3574
+ }
3575
+ function useAgent({ agentId, threadId, updates, throttleMs } = {}) {
3576
+ agentId ??= _copilotkit_shared.DEFAULT_AGENT_ID;
3577
+ const { copilotkit } = useCopilotKit();
3578
+ const providerThrottleMs = copilotkit.defaultThrottleMs;
3579
+ const chatConfig = useCopilotChatConfiguration();
3580
+ threadId ??= chatConfig?.threadId;
3431
3581
  const [, forceUpdate] = (0, react.useReducer)((x) => x + 1, 0);
3432
- if (!context) throw new Error("useCopilotKit must be used within CopilotKitProvider");
3582
+ const updateFlags = (0, react.useMemo)(() => updates ?? ALL_UPDATES, [JSON.stringify(updates)]);
3583
+ const provisionalAgentCache = (0, react.useRef)(/* @__PURE__ */ new Map());
3584
+ const agent = (0, react.useMemo)(() => {
3585
+ const cacheKey = threadId ? `${agentId}:${threadId}` : agentId;
3586
+ const existing = copilotkit.getAgent(agentId);
3587
+ if (existing) {
3588
+ provisionalAgentCache.current.delete(cacheKey);
3589
+ provisionalAgentCache.current.delete(agentId);
3590
+ if (!threadId) return existing;
3591
+ return getOrCreateThreadClone(existing, threadId, copilotkit.headers);
3592
+ }
3593
+ const isRuntimeConfigured = copilotkit.runtimeUrl !== void 0;
3594
+ const status = copilotkit.runtimeConnectionStatus;
3595
+ if (isRuntimeConfigured && (status === _copilotkit_core.CopilotKitCoreRuntimeConnectionStatus.Disconnected || status === _copilotkit_core.CopilotKitCoreRuntimeConnectionStatus.Connecting)) {
3596
+ const cached = provisionalAgentCache.current.get(cacheKey);
3597
+ if (cached) {
3598
+ cached.headers = { ...copilotkit.headers };
3599
+ return cached;
3600
+ }
3601
+ const provisional = new _copilotkit_core.ProxiedCopilotRuntimeAgent({
3602
+ runtimeUrl: copilotkit.runtimeUrl,
3603
+ agentId,
3604
+ transport: copilotkit.runtimeTransport,
3605
+ runtimeMode: "pending"
3606
+ });
3607
+ provisional.headers = { ...copilotkit.headers };
3608
+ if (threadId) provisional.threadId = threadId;
3609
+ provisionalAgentCache.current.set(cacheKey, provisional);
3610
+ return provisional;
3611
+ }
3612
+ if (isRuntimeConfigured && status === _copilotkit_core.CopilotKitCoreRuntimeConnectionStatus.Error) {
3613
+ const cached = provisionalAgentCache.current.get(cacheKey);
3614
+ if (cached) {
3615
+ cached.headers = { ...copilotkit.headers };
3616
+ return cached;
3617
+ }
3618
+ const provisional = new _copilotkit_core.ProxiedCopilotRuntimeAgent({
3619
+ runtimeUrl: copilotkit.runtimeUrl,
3620
+ agentId,
3621
+ transport: copilotkit.runtimeTransport,
3622
+ runtimeMode: "pending"
3623
+ });
3624
+ provisional.headers = { ...copilotkit.headers };
3625
+ if (threadId) provisional.threadId = threadId;
3626
+ provisionalAgentCache.current.set(cacheKey, provisional);
3627
+ return provisional;
3628
+ }
3629
+ const knownAgents = Object.keys(copilotkit.agents ?? {});
3630
+ const runtimePart = isRuntimeConfigured ? `runtimeUrl=${copilotkit.runtimeUrl}` : "no runtimeUrl";
3631
+ 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.");
3632
+ }, [
3633
+ agentId,
3634
+ threadId,
3635
+ copilotkit.agents,
3636
+ copilotkit.runtimeConnectionStatus,
3637
+ copilotkit.runtimeUrl,
3638
+ copilotkit.runtimeTransport,
3639
+ JSON.stringify(copilotkit.headers)
3640
+ ]);
3433
3641
  (0, react.useEffect)(() => {
3434
- const subscription = context.copilotkit.subscribe({ onRuntimeConnectionStatusChanged: () => {
3435
- forceUpdate();
3436
- } });
3642
+ if (updateFlags.length === 0) return;
3643
+ let active = true;
3644
+ const handlers = {};
3645
+ let batchScheduled = false;
3646
+ const batchedForceUpdate = () => {
3647
+ if (!active) return;
3648
+ if (!batchScheduled) {
3649
+ batchScheduled = true;
3650
+ queueMicrotask(() => {
3651
+ batchScheduled = false;
3652
+ if (active) forceUpdate();
3653
+ });
3654
+ }
3655
+ };
3656
+ if (updateFlags.includes(UseAgentUpdate.OnMessagesChanged)) handlers.onMessagesChanged = batchedForceUpdate;
3657
+ if (updateFlags.includes(UseAgentUpdate.OnStateChanged)) handlers.onStateChanged = batchedForceUpdate;
3658
+ if (updateFlags.includes(UseAgentUpdate.OnRunStatusChanged)) {
3659
+ handlers.onRunInitialized = batchedForceUpdate;
3660
+ handlers.onRunFinalized = batchedForceUpdate;
3661
+ handlers.onRunFailed = batchedForceUpdate;
3662
+ handlers.onRunErrorEvent = batchedForceUpdate;
3663
+ }
3664
+ const subscription = copilotkit.subscribeToAgentWithOptions(agent, handlers, { throttleMs });
3437
3665
  return () => {
3666
+ active = false;
3438
3667
  subscription.unsubscribe();
3439
3668
  };
3440
- }, []);
3441
- return context;
3442
- };
3443
-
3444
- //#endregion
3445
- //#region src/v2/hooks/use-render-tool-call.tsx
3446
- /**
3447
- * Memoized component that renders a single tool call.
3448
- * This prevents unnecessary re-renders when parent components update
3449
- * but the tool call data hasn't changed.
3450
- */
3451
- const ToolCallRenderer = react.default.memo(function ToolCallRenderer({ toolCall, toolMessage, RenderComponent, isExecuting }) {
3452
- const args = (0, react.useMemo)(() => (0, _copilotkit_shared.partialJSONParse)(toolCall.function.arguments), [toolCall.function.arguments]);
3453
- const toolName = toolCall.function.name;
3454
- if (toolMessage) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(RenderComponent, {
3455
- name: toolName,
3456
- toolCallId: toolCall.id,
3457
- args,
3458
- status: _copilotkit_core.ToolCallStatus.Complete,
3459
- result: toolMessage.content
3460
- });
3461
- else if (isExecuting) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(RenderComponent, {
3462
- name: toolName,
3463
- toolCallId: toolCall.id,
3464
- args,
3465
- status: _copilotkit_core.ToolCallStatus.Executing,
3466
- result: void 0
3467
- });
3468
- else return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(RenderComponent, {
3469
- name: toolName,
3470
- toolCallId: toolCall.id,
3471
- args,
3472
- status: _copilotkit_core.ToolCallStatus.InProgress,
3473
- result: void 0
3474
- });
3475
- }, (prevProps, nextProps) => {
3476
- if (prevProps.toolCall.id !== nextProps.toolCall.id) return false;
3477
- if (prevProps.toolCall.function.name !== nextProps.toolCall.function.name) return false;
3478
- if (prevProps.toolCall.function.arguments !== nextProps.toolCall.function.arguments) return false;
3479
- if (prevProps.toolMessage?.content !== nextProps.toolMessage?.content) return false;
3480
- if (prevProps.isExecuting !== nextProps.isExecuting) return false;
3481
- if (prevProps.RenderComponent !== nextProps.RenderComponent) return false;
3482
- return true;
3483
- });
3484
- /**
3485
- * Hook that returns a function to render tool calls based on the render functions
3486
- * defined in CopilotKitProvider.
3487
- *
3488
- * @returns A function that takes a tool call and optional tool message and returns the rendered component
3489
- */
3490
- function useRenderToolCall() {
3491
- const { copilotkit, executingToolCallIds } = useCopilotKit();
3492
- const agentId = useCopilotChatConfiguration()?.agentId ?? _copilotkit_shared.DEFAULT_AGENT_ID;
3493
- const renderToolCalls = (0, react.useSyncExternalStore)((callback) => {
3494
- return copilotkit.subscribe({ onRenderToolCallsChanged: callback }).unsubscribe;
3495
- }, () => copilotkit.renderToolCalls, () => copilotkit.renderToolCalls);
3496
- return (0, react.useCallback)(({ toolCall, toolMessage }) => {
3497
- const exactMatches = renderToolCalls.filter((rc) => rc.name === toolCall.function.name);
3498
- const renderConfig = exactMatches.find((rc) => rc.agentId === agentId) || exactMatches.find((rc) => !rc.agentId) || exactMatches[0] || renderToolCalls.find((rc) => rc.name === "*");
3499
- if (!renderConfig) return null;
3500
- const RenderComponent = renderConfig.render;
3501
- return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ToolCallRenderer, {
3502
- toolCall,
3503
- toolMessage,
3504
- RenderComponent,
3505
- isExecuting: executingToolCallIds.has(toolCall.id)
3506
- }, toolCall.id);
3507
3669
  }, [
3508
- renderToolCalls,
3509
- executingToolCallIds,
3510
- agentId
3670
+ agent,
3671
+ forceUpdate,
3672
+ throttleMs,
3673
+ providerThrottleMs,
3674
+ updateFlags
3511
3675
  ]);
3676
+ (0, react.useEffect)(() => {
3677
+ if (agent instanceof _ag_ui_client.HttpAgent) agent.headers = { ...copilotkit.headers };
3678
+ }, [agent, JSON.stringify(copilotkit.headers)]);
3679
+ return { agent };
3512
3680
  }
3513
3681
 
3514
3682
  //#endregion
@@ -3528,7 +3696,8 @@ function useRenderCustomMessages() {
3528
3696
  const { message, position } = params;
3529
3697
  const resolvedRunId = copilotkit.getRunIdForMessage(agentId, threadId, message.id) ?? copilotkit.getRunIdsForThread(agentId, threadId).slice(-1)[0];
3530
3698
  const runId = resolvedRunId ?? `missing-run-id:${message.id}`;
3531
- const agent = copilotkit.getAgent(agentId);
3699
+ const registryAgent = copilotkit.getAgent(agentId);
3700
+ const agent = getThreadClone(registryAgent, threadId) ?? registryAgent;
3532
3701
  if (!agent) return null;
3533
3702
  const messagesIdsInRun = resolvedRunId ? agent.messages.filter((msg) => copilotkit.getRunIdForMessage(agentId, threadId, msg.id) === resolvedRunId).map((msg) => msg.id) : [message.id];
3534
3703
  const rawMessageIndex = agent.messages.findIndex((msg) => msg.id === message.id);
@@ -3560,7 +3729,8 @@ function useRenderCustomMessages() {
3560
3729
  //#region src/v2/hooks/use-render-activity-message.tsx
3561
3730
  function useRenderActivityMessage() {
3562
3731
  const { copilotkit } = useCopilotKit();
3563
- const agentId = useCopilotChatConfiguration()?.agentId ?? _copilotkit_shared.DEFAULT_AGENT_ID;
3732
+ const config = useCopilotChatConfiguration();
3733
+ const agentId = config?.agentId ?? _copilotkit_shared.DEFAULT_AGENT_ID;
3564
3734
  const renderers = copilotkit.renderActivityMessages;
3565
3735
  const findRenderer = (0, react.useCallback)((activityType) => {
3566
3736
  if (!renderers.length) return null;
@@ -3576,7 +3746,8 @@ function useRenderActivityMessage() {
3576
3746
  return null;
3577
3747
  }
3578
3748
  const Component = renderer.render;
3579
- const agent = copilotkit.getAgent(agentId);
3749
+ const registryAgent = copilotkit.getAgent(agentId);
3750
+ const agent = getThreadClone(registryAgent, config?.threadId) ?? registryAgent;
3580
3751
  return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Component, {
3581
3752
  activityType: message.activityType,
3582
3753
  content: parseResult.data,
@@ -3585,6 +3756,7 @@ function useRenderActivityMessage() {
3585
3756
  }, message.id);
3586
3757
  }, [
3587
3758
  agentId,
3759
+ config?.threadId,
3588
3760
  copilotkit,
3589
3761
  findRenderer
3590
3762
  ]);
@@ -3623,8 +3795,7 @@ function useFrontendTool(tool, deps) {
3623
3795
  tool.name,
3624
3796
  tool.available,
3625
3797
  copilotkit,
3626
- extraDeps.length,
3627
- ...extraDeps
3798
+ JSON.stringify(extraDeps)
3628
3799
  ]);
3629
3800
  }
3630
3801
 
@@ -3763,8 +3934,7 @@ function useRenderTool(config, deps) {
3763
3934
  }, [
3764
3935
  config.name,
3765
3936
  copilotkit,
3766
- extraDeps.length,
3767
- ...extraDeps
3937
+ JSON.stringify(extraDeps)
3768
3938
  ]);
3769
3939
  }
3770
3940
 
@@ -4024,118 +4194,6 @@ function useHumanInTheLoop(tool, deps) {
4024
4194
  ]);
4025
4195
  }
4026
4196
 
4027
- //#endregion
4028
- //#region src/v2/hooks/use-agent.tsx
4029
- let UseAgentUpdate = /* @__PURE__ */ function(UseAgentUpdate) {
4030
- UseAgentUpdate["OnMessagesChanged"] = "OnMessagesChanged";
4031
- UseAgentUpdate["OnStateChanged"] = "OnStateChanged";
4032
- UseAgentUpdate["OnRunStatusChanged"] = "OnRunStatusChanged";
4033
- return UseAgentUpdate;
4034
- }({});
4035
- const ALL_UPDATES = [
4036
- UseAgentUpdate.OnMessagesChanged,
4037
- UseAgentUpdate.OnStateChanged,
4038
- UseAgentUpdate.OnRunStatusChanged
4039
- ];
4040
- function useAgent({ agentId, updates, throttleMs } = {}) {
4041
- agentId ??= _copilotkit_shared.DEFAULT_AGENT_ID;
4042
- const { copilotkit } = useCopilotKit();
4043
- const providerThrottleMs = copilotkit.defaultThrottleMs;
4044
- const [, forceUpdate] = (0, react.useReducer)((x) => x + 1, 0);
4045
- const updateFlags = (0, react.useMemo)(() => updates ?? ALL_UPDATES, [JSON.stringify(updates)]);
4046
- const provisionalAgentCache = (0, react.useRef)(/* @__PURE__ */ new Map());
4047
- const agent = (0, react.useMemo)(() => {
4048
- const existing = copilotkit.getAgent(agentId);
4049
- if (existing) {
4050
- provisionalAgentCache.current.delete(agentId);
4051
- return existing;
4052
- }
4053
- const isRuntimeConfigured = copilotkit.runtimeUrl !== void 0;
4054
- const status = copilotkit.runtimeConnectionStatus;
4055
- if (isRuntimeConfigured && (status === _copilotkit_core.CopilotKitCoreRuntimeConnectionStatus.Disconnected || status === _copilotkit_core.CopilotKitCoreRuntimeConnectionStatus.Connecting)) {
4056
- const cached = provisionalAgentCache.current.get(agentId);
4057
- if (cached) {
4058
- cached.headers = { ...copilotkit.headers };
4059
- return cached;
4060
- }
4061
- const provisional = new _copilotkit_core.ProxiedCopilotRuntimeAgent({
4062
- runtimeUrl: copilotkit.runtimeUrl,
4063
- agentId,
4064
- transport: copilotkit.runtimeTransport,
4065
- runtimeMode: "pending"
4066
- });
4067
- provisional.headers = { ...copilotkit.headers };
4068
- provisionalAgentCache.current.set(agentId, provisional);
4069
- return provisional;
4070
- }
4071
- if (isRuntimeConfigured && status === _copilotkit_core.CopilotKitCoreRuntimeConnectionStatus.Error) {
4072
- const cached = provisionalAgentCache.current.get(agentId);
4073
- if (cached) {
4074
- cached.headers = { ...copilotkit.headers };
4075
- return cached;
4076
- }
4077
- const provisional = new _copilotkit_core.ProxiedCopilotRuntimeAgent({
4078
- runtimeUrl: copilotkit.runtimeUrl,
4079
- agentId,
4080
- transport: copilotkit.runtimeTransport,
4081
- runtimeMode: "pending"
4082
- });
4083
- provisional.headers = { ...copilotkit.headers };
4084
- provisionalAgentCache.current.set(agentId, provisional);
4085
- return provisional;
4086
- }
4087
- const knownAgents = Object.keys(copilotkit.agents ?? {});
4088
- const runtimePart = isRuntimeConfigured ? `runtimeUrl=${copilotkit.runtimeUrl}` : "no runtimeUrl";
4089
- 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.");
4090
- }, [
4091
- agentId,
4092
- copilotkit.agents,
4093
- copilotkit.runtimeConnectionStatus,
4094
- copilotkit.runtimeUrl,
4095
- copilotkit.runtimeTransport,
4096
- JSON.stringify(copilotkit.headers)
4097
- ]);
4098
- (0, react.useEffect)(() => {
4099
- if (updateFlags.length === 0) return;
4100
- let active = true;
4101
- const handlers = {};
4102
- let batchScheduled = false;
4103
- const batchedForceUpdate = () => {
4104
- if (!active) return;
4105
- if (!batchScheduled) {
4106
- batchScheduled = true;
4107
- queueMicrotask(() => {
4108
- batchScheduled = false;
4109
- if (active) forceUpdate();
4110
- });
4111
- }
4112
- };
4113
- if (updateFlags.includes(UseAgentUpdate.OnMessagesChanged)) handlers.onMessagesChanged = forceUpdate;
4114
- if (updateFlags.includes(UseAgentUpdate.OnStateChanged)) handlers.onStateChanged = batchedForceUpdate;
4115
- if (updateFlags.includes(UseAgentUpdate.OnRunStatusChanged)) {
4116
- handlers.onRunInitialized = batchedForceUpdate;
4117
- handlers.onRunFinalized = batchedForceUpdate;
4118
- handlers.onRunFailed = batchedForceUpdate;
4119
- handlers.onRunErrorEvent = batchedForceUpdate;
4120
- }
4121
- const subscription = copilotkit.subscribeToAgentWithOptions(agent, handlers, { throttleMs });
4122
- return () => {
4123
- active = false;
4124
- subscription.unsubscribe();
4125
- };
4126
- }, [
4127
- agent,
4128
- forceUpdate,
4129
- throttleMs,
4130
- providerThrottleMs,
4131
- updateFlags
4132
- ]);
4133
- (0, react.useEffect)(() => {
4134
- if (agent instanceof _ag_ui_client.HttpAgent) agent.headers = { ...copilotkit.headers };
4135
- }, [agent, JSON.stringify(copilotkit.headers)]);
4136
- return { agent };
4137
- }
4138
-
4139
4197
  //#endregion
4140
4198
  //#region src/v2/hooks/use-capabilities.tsx
4141
4199
  /**
@@ -5601,190 +5659,6 @@ CopilotChatSuggestionView.displayName = "CopilotChatSuggestionView";
5601
5659
  */
5602
5660
  const ScrollElementContext = react.default.createContext(null);
5603
5661
 
5604
- //#endregion
5605
- //#region src/v2/components/intelligence-indicator/IntelligenceIndicator.tsx
5606
- /**
5607
- * Grace window before showing the spinner. A matching tool call must
5608
- * remain unresolved (no `tool`-role result message in `agent.messages`)
5609
- * for at least this long before the pill appears. This filters out
5610
- * history-replay flashes — during `connectAgent` replay, tool calls and
5611
- * their results arrive back-to-back in sub-millisecond bursts, so the
5612
- * timer is cancelled before it fires. Live runs cross the threshold
5613
- * easily because the tool actually has to execute.
5614
- */
5615
- const PENDING_THRESHOLD_MS = 100;
5616
- /** Hold the checkmark briefly before fading out. */
5617
- const CHECK_HOLD_MS = 800;
5618
- /**
5619
- * Duration of the fade-out animation. Must match
5620
- * `cpk-intelligence-pill-fade-out` keyframes in `v2/styles/globals.css`.
5621
- */
5622
- const FADE_OUT_ANIMATION_MS = 480;
5623
- /**
5624
- * Tool-name regex patterns that trigger the indicator. Currently
5625
- * hardcoded to the Intelligence MCP server's canonical tool name. If
5626
- * we add per-instance customization later (e.g. a `CopilotKitProvider`
5627
- * prop or a runtime-info field), this constant becomes the fallback.
5628
- */
5629
- const DEFAULT_TOOL_PATTERNS = [/^bash$/];
5630
- const isMatchingToolCallName = (name) => typeof name === "string" && DEFAULT_TOOL_PATTERNS.some((p) => p.test(name));
5631
- /**
5632
- * "Tool-call-like" messages do NOT count as a real follow-up: tool
5633
- * result messages, assistant messages that carry tool calls, and
5634
- * empty-content assistant messages (which some providers emit as a
5635
- * standalone wrapper around a batch of tool calls). A real follow-up
5636
- * is anything else — most importantly an assistant message with prose
5637
- * content, or a fresh user message.
5638
- */
5639
- const isToolCallLikeMessage = (m) => {
5640
- if (m.role === "tool") return true;
5641
- if (m.role === "assistant") {
5642
- if ((Array.isArray(m.toolCalls) ? m.toolCalls : []).length > 0) return true;
5643
- const content = m.content;
5644
- return typeof content !== "string" || content.trim().length === 0;
5645
- }
5646
- return false;
5647
- };
5648
- /**
5649
- * The "Using CopilotKit Intelligence" pill. Auto-mounted by
5650
- * `CopilotChatMessageView` for every message slot when
5651
- * `copilotkit.intelligence` is configured — callers do not register
5652
- * this themselves. Self-gates so only the canonical message renders a
5653
- * pill.
5654
- *
5655
- * Render gates (all must hold):
5656
- * 1. `copilotkit.intelligence !== undefined`
5657
- * 2. The message is an assistant message with at least one tool call
5658
- * whose name matches {@link DEFAULT_TOOL_PATTERNS}
5659
- * 3. The message is the *latest* such matching-assistant message in
5660
- * `agent.messages` — tool-result messages and prose-only assistant
5661
- * messages don't invalidate the slot, so the pill stays
5662
- * continuously through a multi-step tool chain.
5663
- * 4. The phase machine is past `idle` (the pending-grace timer fired)
5664
- * and not yet `hidden`.
5665
- *
5666
- * Phase machine (per-instance, all timers local):
5667
- * - Starts in `idle` — nothing rendered.
5668
- * - `idle → spinner` once a matching tool call has been pending
5669
- * (no `tool`-role result with a matching `toolCallId`) for
5670
- * {@link PENDING_THRESHOLD_MS}. Replay flashes (tool call + result
5671
- * in the same tick) never cross this threshold.
5672
- * - `spinner → check` as soon as EITHER `agent.isRunning` flips
5673
- * false OR a non-tool-call-like message appears later in
5674
- * `agent.messages` (i.e. the agent has produced a "real"
5675
- * follow-up — prose answer or a new user turn).
5676
- * - `check → fading` after {@link CHECK_HOLD_MS}.
5677
- * - `fading → hidden` after {@link FADE_OUT_ANIMATION_MS}.
5678
- *
5679
- * Once `hidden`, the phase is sticky — a finished pill never re-spawns
5680
- * on the same message. New runs mount fresh indicator instances on
5681
- * their own assistant messages.
5682
- *
5683
- * The "exactly one pill at a time" guarantee is structural: only one
5684
- * message satisfies the latest-matching-assistant gate at any moment.
5685
- */
5686
- function IntelligenceIndicator(props) {
5687
- const { message, agentId, label = "Using CopilotKit Intelligence" } = props;
5688
- const { copilotkit } = useCopilotKit();
5689
- const config = useCopilotChatConfiguration();
5690
- const { agent } = useAgent({
5691
- agentId,
5692
- updates: [UseAgentUpdate.OnRunStatusChanged, UseAgentUpdate.OnMessagesChanged]
5693
- });
5694
- const matchingToolCallIds = (0, react.useMemo)(() => {
5695
- if (message.role !== "assistant") return [];
5696
- const tcs = Array.isArray(message.toolCalls) ? message.toolCalls : [];
5697
- const ids = [];
5698
- for (const tc of tcs) if (isMatchingToolCallName(tc?.function?.name) && tc?.id) ids.push(tc.id);
5699
- return ids;
5700
- }, [message]);
5701
- const hasPending = (0, react.useMemo)(() => {
5702
- if (matchingToolCallIds.length === 0) return false;
5703
- const resolved = /* @__PURE__ */ new Set();
5704
- for (const m of agent.messages) if (m.role === "tool" && m.toolCallId) resolved.add(m.toolCallId);
5705
- return matchingToolCallIds.some((id) => !resolved.has(id));
5706
- }, [matchingToolCallIds, agent.messages]);
5707
- const sawRealFollowup = (0, react.useMemo)(() => {
5708
- const idx = agent.messages.findIndex((m) => m.id === message.id);
5709
- if (idx < 0) return false;
5710
- for (let i = idx + 1; i < agent.messages.length; i += 1) if (!isToolCallLikeMessage(agent.messages[i])) return true;
5711
- return false;
5712
- }, [agent.messages, message.id]);
5713
- const [phase, setPhase] = (0, react.useState)("idle");
5714
- (0, react.useEffect)(() => {
5715
- if (phase !== "idle") return void 0;
5716
- if (!hasPending) return void 0;
5717
- const t = setTimeout(() => setPhase("spinner"), PENDING_THRESHOLD_MS);
5718
- return () => clearTimeout(t);
5719
- }, [phase, hasPending]);
5720
- (0, react.useEffect)(() => {
5721
- if (phase !== "spinner") return void 0;
5722
- if (!agent.isRunning || sawRealFollowup) setPhase("check");
5723
- }, [
5724
- phase,
5725
- agent.isRunning,
5726
- sawRealFollowup
5727
- ]);
5728
- (0, react.useEffect)(() => {
5729
- if (phase !== "check") return void 0;
5730
- const t = setTimeout(() => setPhase("fading"), CHECK_HOLD_MS);
5731
- return () => clearTimeout(t);
5732
- }, [phase]);
5733
- (0, react.useEffect)(() => {
5734
- if (phase !== "fading") return void 0;
5735
- const t = setTimeout(() => setPhase("hidden"), FADE_OUT_ANIMATION_MS);
5736
- return () => clearTimeout(t);
5737
- }, [phase]);
5738
- if (copilotkit.intelligence === void 0) return null;
5739
- if (!config) return null;
5740
- if (phase === "idle" || phase === "hidden") return null;
5741
- if (message.role !== "assistant") return null;
5742
- if (!(Array.isArray(message.toolCalls) ? message.toolCalls : []).some((tc) => isMatchingToolCallName(tc?.function?.name))) return null;
5743
- let latestMatchingAssistantId;
5744
- for (let i = agent.messages.length - 1; i >= 0; i -= 1) {
5745
- const m = agent.messages[i];
5746
- if (m.role !== "assistant") continue;
5747
- if ((Array.isArray(m.toolCalls) ? m.toolCalls : []).some((tc) => isMatchingToolCallName(tc?.function?.name))) {
5748
- latestMatchingAssistantId = m.id;
5749
- break;
5750
- }
5751
- }
5752
- if (latestMatchingAssistantId !== message.id) return null;
5753
- const showSpinner = phase === "spinner";
5754
- const isFading = phase === "fading";
5755
- return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
5756
- className: "cpk-intelligence-pill" + (isFading ? " cpk-intelligence-pill--fading" : ""),
5757
- role: "status",
5758
- "aria-live": "polite",
5759
- "aria-hidden": isFading || void 0,
5760
- "data-testid": `cpk-intelligence-pill-${message.id}`,
5761
- title: label,
5762
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("svg", {
5763
- className: "cpk-intelligence-pill__icon",
5764
- viewBox: "0 0 24 24",
5765
- width: "14",
5766
- height: "14",
5767
- "aria-hidden": "true",
5768
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("circle", {
5769
- cx: "12",
5770
- cy: "12",
5771
- r: "9",
5772
- fill: "none",
5773
- strokeWidth: "2.5",
5774
- strokeLinecap: "round",
5775
- className: "cpk-intelligence-pill__ring" + (showSpinner ? "" : " cpk-intelligence-pill__ring--done")
5776
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", {
5777
- d: "M8 12.5l3 3 5-6",
5778
- fill: "none",
5779
- strokeWidth: "2.5",
5780
- strokeLinecap: "round",
5781
- strokeLinejoin: "round",
5782
- className: "cpk-intelligence-pill__check" + (showSpinner ? "" : " cpk-intelligence-pill__check--shown")
5783
- })]
5784
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: label })]
5785
- });
5786
- }
5787
-
5788
5662
  //#endregion
5789
5663
  //#region src/v2/components/chat/CopilotChatMessageView.tsx
5790
5664
  /**
@@ -5942,12 +5816,14 @@ function CopilotChatMessageView({ messages = [], assistantMessage, userMessage,
5942
5816
  const [, forceUpdate] = (0, react.useReducer)((x) => x + 1, 0);
5943
5817
  (0, react.useEffect)(() => {
5944
5818
  if (!config?.agentId) return;
5945
- const agent = copilotkit.getAgent(config.agentId);
5819
+ const registryAgent = copilotkit.getAgent(config.agentId);
5820
+ const agent = getThreadClone(registryAgent, config.threadId) ?? registryAgent;
5946
5821
  if (!agent) return;
5947
5822
  const subscription = agent.subscribe({ onStateChanged: forceUpdate });
5948
5823
  return () => subscription.unsubscribe();
5949
5824
  }, [
5950
5825
  config?.agentId,
5826
+ config?.threadId,
5951
5827
  copilotkit,
5952
5828
  forceUpdate
5953
5829
  ]);
@@ -6030,10 +5906,6 @@ function CopilotChatMessageView({ messages = [], assistantMessage, userMessage,
6030
5906
  renderCustomMessage,
6031
5907
  stateSnapshot
6032
5908
  }, `${message.id}-custom-after`));
6033
- if (copilotkit.intelligence !== void 0 && message.role === "assistant") elements.push(/* @__PURE__ */ (0, react_jsx_runtime.jsx)(IntelligenceIndicator, {
6034
- message,
6035
- agentId: config?.agentId ?? _copilotkit_shared.DEFAULT_AGENT_ID
6036
- }, `${message.id}-intelligence`));
6037
5909
  return elements.filter(Boolean);
6038
5910
  };
6039
5911
  const messageElements = shouldVirtualize ? [] : deduplicatedMessages.flatMap(renderMessageBlock);
@@ -6982,6 +6854,7 @@ function CopilotChat({ agentId, threadId, labels, chatView, isModalDefaultOpen,
6982
6854
  const hasExplicitThreadId = !!threadId || !!existingConfig?.hasExplicitThreadId;
6983
6855
  const { agent } = useAgent({
6984
6856
  agentId: resolvedAgentId,
6857
+ threadId: resolvedThreadId,
6985
6858
  throttleMs
6986
6859
  });
6987
6860
  const { copilotkit } = useCopilotKit();
@@ -7023,7 +6896,6 @@ function CopilotChat({ agentId, threadId, labels, chatView, isModalDefaultOpen,
7023
6896
  let detached = false;
7024
6897
  const connectAbortController = new AbortController();
7025
6898
  if (agent instanceof _ag_ui_client.HttpAgent) agent.abortController = connectAbortController;
7026
- agent.threadId = resolvedThreadId;
7027
6899
  const connect = async (agent) => {
7028
6900
  try {
7029
6901
  await copilotkit.connectAgent({ agent });
@@ -10156,12 +10028,6 @@ Object.defineProperty(exports, 'DefaultOpenIcon', {
10156
10028
  return DefaultOpenIcon;
10157
10029
  }
10158
10030
  });
10159
- Object.defineProperty(exports, 'IntelligenceIndicator', {
10160
- enumerable: true,
10161
- get: function () {
10162
- return IntelligenceIndicator;
10163
- }
10164
- });
10165
10031
  Object.defineProperty(exports, 'MCPAppsActivityContentSchema', {
10166
10032
  enumerable: true,
10167
10033
  get: function () {
@@ -10390,4 +10256,4 @@ Object.defineProperty(exports, 'useToast', {
10390
10256
  return useToast;
10391
10257
  }
10392
10258
  });
10393
- //# sourceMappingURL=copilotkit-XGd8L2jL.cjs.map
10259
+ //# sourceMappingURL=copilotkit-BLlkMAjx.cjs.map