@copilotkit/react-core 1.55.0-next.7 → 1.55.0-next.9

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 (42) hide show
  1. package/CHANGELOG.md +23 -0
  2. package/dist/{copilotkit-B3Mb1yVE.cjs → copilotkit-BDNjFNmk.cjs} +156 -92
  3. package/dist/copilotkit-BDNjFNmk.cjs.map +1 -0
  4. package/dist/{copilotkit-Dy5w3qEV.d.mts → copilotkit-BqcyhQjT.d.mts} +3 -1
  5. package/dist/{copilotkit-Dy5w3qEV.d.mts.map → copilotkit-BqcyhQjT.d.mts.map} +1 -1
  6. package/dist/{copilotkit-DNYSFuz5.mjs → copilotkit-DeOzjPsb.mjs} +157 -93
  7. package/dist/copilotkit-DeOzjPsb.mjs.map +1 -0
  8. package/dist/{copilotkit-DBzgOMby.d.cts → copilotkit-l-IBF4Xp.d.cts} +3 -1
  9. package/dist/{copilotkit-DBzgOMby.d.cts.map → copilotkit-l-IBF4Xp.d.cts.map} +1 -1
  10. package/dist/index.cjs +9 -4
  11. package/dist/index.cjs.map +1 -1
  12. package/dist/index.d.cts +1 -1
  13. package/dist/index.d.mts +1 -1
  14. package/dist/index.mjs +9 -4
  15. package/dist/index.mjs.map +1 -1
  16. package/dist/index.umd.js +160 -94
  17. package/dist/index.umd.js.map +1 -1
  18. package/dist/v2/index.cjs +1 -1
  19. package/dist/v2/index.d.cts +1 -1
  20. package/dist/v2/index.d.mts +1 -1
  21. package/dist/v2/index.mjs +1 -1
  22. package/dist/v2/index.umd.js +160 -94
  23. package/dist/v2/index.umd.js.map +1 -1
  24. package/package.json +6 -6
  25. package/src/components/copilot-provider/__tests__/copilot-messages-key.test.tsx +92 -0
  26. package/src/components/copilot-provider/copilotkit.tsx +3 -3
  27. package/src/hooks/__tests__/use-copilot-chat-internal-connect.test.tsx +27 -16
  28. package/src/hooks/use-copilot-chat_internal.ts +15 -4
  29. package/src/v2/__tests__/utils/test-helpers.tsx +40 -7
  30. package/src/v2/components/chat/CopilotChat.tsx +4 -2
  31. package/src/v2/components/chat/CopilotChatMessageView.tsx +7 -2
  32. package/src/v2/components/chat/__tests__/CopilotChatToolRendering.e2e.test.tsx +5 -2
  33. package/src/v2/components/chat/__tests__/CopilotChatToolRerenders.e2e.test.tsx +5 -2
  34. package/src/v2/components/chat/__tests__/MCPAppsActivityRenderer.e2e.test.tsx +17 -1
  35. package/src/v2/hooks/__tests__/use-agent-context-timing.e2e.test.tsx +8 -0
  36. package/src/v2/hooks/__tests__/use-agent-thread-isolation.test.tsx +327 -0
  37. package/src/v2/hooks/__tests__/use-agent.e2e.test.tsx +13 -2
  38. package/src/v2/hooks/__tests__/use-frontend-tool.e2e.test.tsx +23 -4
  39. package/src/v2/hooks/use-agent.tsx +126 -6
  40. package/src/v2/hooks/use-render-custom-messages.tsx +6 -1
  41. package/dist/copilotkit-B3Mb1yVE.cjs.map +0 -1
  42. package/dist/copilotkit-DNYSFuz5.mjs.map +0 -1
package/dist/index.umd.js CHANGED
@@ -1327,6 +1327,154 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
1327
1327
  ]);
1328
1328
  }
1329
1329
 
1330
+ //#endregion
1331
+ //#region src/v2/hooks/use-agent.tsx
1332
+ let UseAgentUpdate = /* @__PURE__ */ function(UseAgentUpdate) {
1333
+ UseAgentUpdate["OnMessagesChanged"] = "OnMessagesChanged";
1334
+ UseAgentUpdate["OnStateChanged"] = "OnStateChanged";
1335
+ UseAgentUpdate["OnRunStatusChanged"] = "OnRunStatusChanged";
1336
+ return UseAgentUpdate;
1337
+ }({});
1338
+ const ALL_UPDATES = [
1339
+ UseAgentUpdate.OnMessagesChanged,
1340
+ UseAgentUpdate.OnStateChanged,
1341
+ UseAgentUpdate.OnRunStatusChanged
1342
+ ];
1343
+ /**
1344
+ * Clone a registry agent for per-thread isolation.
1345
+ * Copies agent configuration (transport, headers, etc.) but resets conversation
1346
+ * state (messages, threadId, state) so each thread starts fresh.
1347
+ */
1348
+ function cloneForThread(source, threadId, headers) {
1349
+ const clone = source.clone();
1350
+ if (clone === source) throw new Error(`useAgent: ${source.constructor.name}.clone() returned the same instance. clone() must return a new, independent object.`);
1351
+ clone.threadId = threadId;
1352
+ clone.setMessages([]);
1353
+ clone.setState({});
1354
+ if (clone instanceof _ag_ui_client.HttpAgent) clone.headers = { ...headers };
1355
+ return clone;
1356
+ }
1357
+ /**
1358
+ * Module-level WeakMap: registryAgent → (threadId → clone).
1359
+ * Shared across all useAgent() calls so that every component using the same
1360
+ * (agentId, threadId) pair receives the same agent instance. Using WeakMap
1361
+ * ensures the clone map is garbage-collected when the registry agent is
1362
+ * replaced (e.g. after reconnect or hot-reload).
1363
+ */
1364
+ const globalThreadCloneMap = /* @__PURE__ */ new WeakMap();
1365
+ /**
1366
+ * Look up an existing per-thread clone without creating one.
1367
+ * Returns undefined when no clone has been created yet for this pair.
1368
+ */
1369
+ function getThreadClone(registryAgent, threadId) {
1370
+ var _globalThreadCloneMap;
1371
+ if (!registryAgent || !threadId) return void 0;
1372
+ return (_globalThreadCloneMap = globalThreadCloneMap.get(registryAgent)) === null || _globalThreadCloneMap === void 0 ? void 0 : _globalThreadCloneMap.get(threadId);
1373
+ }
1374
+ function getOrCreateThreadClone(existing, threadId, headers) {
1375
+ let byThread = globalThreadCloneMap.get(existing);
1376
+ if (!byThread) {
1377
+ byThread = /* @__PURE__ */ new Map();
1378
+ globalThreadCloneMap.set(existing, byThread);
1379
+ }
1380
+ const cached = byThread.get(threadId);
1381
+ if (cached) return cached;
1382
+ const clone = cloneForThread(existing, threadId, headers);
1383
+ byThread.set(threadId, clone);
1384
+ return clone;
1385
+ }
1386
+ function useAgent({ agentId, threadId, updates } = {}) {
1387
+ var _agentId, _threadId;
1388
+ (_agentId = agentId) !== null && _agentId !== void 0 || (agentId = _copilotkit_shared.DEFAULT_AGENT_ID);
1389
+ const { copilotkit } = useCopilotKit();
1390
+ const chatConfig = useCopilotChatConfiguration();
1391
+ (_threadId = threadId) !== null && _threadId !== void 0 || (threadId = chatConfig === null || chatConfig === void 0 ? void 0 : chatConfig.threadId);
1392
+ const [, forceUpdate] = (0, react.useReducer)((x) => x + 1, 0);
1393
+ const updateFlags = (0, react.useMemo)(() => updates !== null && updates !== void 0 ? updates : ALL_UPDATES, [JSON.stringify(updates)]);
1394
+ const provisionalAgentCache = (0, react.useRef)(/* @__PURE__ */ new Map());
1395
+ const agent = (0, react.useMemo)(() => {
1396
+ var _copilotkit$agents;
1397
+ const cacheKey = threadId ? `${agentId}:${threadId}` : agentId;
1398
+ const existing = copilotkit.getAgent(agentId);
1399
+ if (existing) {
1400
+ provisionalAgentCache.current.delete(cacheKey);
1401
+ provisionalAgentCache.current.delete(agentId);
1402
+ if (!threadId) return existing;
1403
+ return getOrCreateThreadClone(existing, threadId, copilotkit.headers);
1404
+ }
1405
+ const isRuntimeConfigured = copilotkit.runtimeUrl !== void 0;
1406
+ const status = copilotkit.runtimeConnectionStatus;
1407
+ if (isRuntimeConfigured && (status === _copilotkit_core.CopilotKitCoreRuntimeConnectionStatus.Disconnected || status === _copilotkit_core.CopilotKitCoreRuntimeConnectionStatus.Connecting)) {
1408
+ const cached = provisionalAgentCache.current.get(cacheKey);
1409
+ if (cached) {
1410
+ cached.headers = { ...copilotkit.headers };
1411
+ return cached;
1412
+ }
1413
+ const provisional = new _copilotkit_core.ProxiedCopilotRuntimeAgent({
1414
+ runtimeUrl: copilotkit.runtimeUrl,
1415
+ agentId,
1416
+ transport: copilotkit.runtimeTransport,
1417
+ runtimeMode: "pending"
1418
+ });
1419
+ provisional.headers = { ...copilotkit.headers };
1420
+ if (threadId) provisional.threadId = threadId;
1421
+ provisionalAgentCache.current.set(cacheKey, provisional);
1422
+ return provisional;
1423
+ }
1424
+ if (isRuntimeConfigured && status === _copilotkit_core.CopilotKitCoreRuntimeConnectionStatus.Error) {
1425
+ const cached = provisionalAgentCache.current.get(cacheKey);
1426
+ if (cached) {
1427
+ cached.headers = { ...copilotkit.headers };
1428
+ return cached;
1429
+ }
1430
+ const provisional = new _copilotkit_core.ProxiedCopilotRuntimeAgent({
1431
+ runtimeUrl: copilotkit.runtimeUrl,
1432
+ agentId,
1433
+ transport: copilotkit.runtimeTransport,
1434
+ runtimeMode: "pending"
1435
+ });
1436
+ provisional.headers = { ...copilotkit.headers };
1437
+ if (threadId) provisional.threadId = threadId;
1438
+ provisionalAgentCache.current.set(cacheKey, provisional);
1439
+ return provisional;
1440
+ }
1441
+ const knownAgents = Object.keys((_copilotkit$agents = copilotkit.agents) !== null && _copilotkit$agents !== void 0 ? _copilotkit$agents : {});
1442
+ const runtimePart = isRuntimeConfigured ? `runtimeUrl=${copilotkit.runtimeUrl}` : "no runtimeUrl";
1443
+ 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.");
1444
+ }, [
1445
+ agentId,
1446
+ threadId,
1447
+ copilotkit.agents,
1448
+ copilotkit.runtimeConnectionStatus,
1449
+ copilotkit.runtimeUrl,
1450
+ copilotkit.runtimeTransport,
1451
+ JSON.stringify(copilotkit.headers)
1452
+ ]);
1453
+ (0, react.useEffect)(() => {
1454
+ if (updateFlags.length === 0) return;
1455
+ const handlers = {};
1456
+ if (updateFlags.includes(UseAgentUpdate.OnMessagesChanged)) handlers.onMessagesChanged = () => {
1457
+ forceUpdate();
1458
+ };
1459
+ if (updateFlags.includes(UseAgentUpdate.OnStateChanged)) handlers.onStateChanged = forceUpdate;
1460
+ if (updateFlags.includes(UseAgentUpdate.OnRunStatusChanged)) {
1461
+ handlers.onRunInitialized = forceUpdate;
1462
+ handlers.onRunFinalized = forceUpdate;
1463
+ handlers.onRunFailed = forceUpdate;
1464
+ }
1465
+ const subscription = agent.subscribe(handlers);
1466
+ return () => subscription.unsubscribe();
1467
+ }, [
1468
+ agent,
1469
+ forceUpdate,
1470
+ JSON.stringify(updateFlags)
1471
+ ]);
1472
+ (0, react.useEffect)(() => {
1473
+ if (agent instanceof _ag_ui_client.HttpAgent) agent.headers = { ...copilotkit.headers };
1474
+ }, [agent, JSON.stringify(copilotkit.headers)]);
1475
+ return { agent };
1476
+ }
1477
+
1330
1478
  //#endregion
1331
1479
  //#region src/v2/hooks/use-render-custom-messages.tsx
1332
1480
  function useRenderCustomMessages() {
@@ -1340,12 +1488,13 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
1340
1488
  return aHasAgent ? -1 : 1;
1341
1489
  });
1342
1490
  return function(params) {
1343
- var _copilotkit$getRunIdF;
1491
+ var _copilotkit$getRunIdF, _getThreadClone;
1344
1492
  if (!customMessageRenderers.length) return null;
1345
1493
  const { message, position } = params;
1346
1494
  const resolvedRunId = (_copilotkit$getRunIdF = copilotkit.getRunIdForMessage(agentId, threadId, message.id)) !== null && _copilotkit$getRunIdF !== void 0 ? _copilotkit$getRunIdF : copilotkit.getRunIdsForThread(agentId, threadId).slice(-1)[0];
1347
1495
  const runId = resolvedRunId !== null && resolvedRunId !== void 0 ? resolvedRunId : `missing-run-id:${message.id}`;
1348
- const agent = copilotkit.getAgent(agentId);
1496
+ const registryAgent = copilotkit.getAgent(agentId);
1497
+ const agent = (_getThreadClone = getThreadClone(registryAgent, threadId)) !== null && _getThreadClone !== void 0 ? _getThreadClone : registryAgent;
1349
1498
  if (!agent) throw new Error("Agent not found");
1350
1499
  const messagesIdsInRun = resolvedRunId ? agent.messages.filter((msg) => copilotkit.getRunIdForMessage(agentId, threadId, msg.id) === resolvedRunId).map((msg) => msg.id) : [message.id];
1351
1500
  const rawMessageIndex = agent.messages.findIndex((msg) => msg.id === message.id);
@@ -1485,94 +1634,6 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
1485
1634
  ]);
1486
1635
  }
1487
1636
 
1488
- //#endregion
1489
- //#region src/v2/hooks/use-agent.tsx
1490
- let UseAgentUpdate = /* @__PURE__ */ function(UseAgentUpdate) {
1491
- UseAgentUpdate["OnMessagesChanged"] = "OnMessagesChanged";
1492
- UseAgentUpdate["OnStateChanged"] = "OnStateChanged";
1493
- UseAgentUpdate["OnRunStatusChanged"] = "OnRunStatusChanged";
1494
- return UseAgentUpdate;
1495
- }({});
1496
- const ALL_UPDATES = [
1497
- UseAgentUpdate.OnMessagesChanged,
1498
- UseAgentUpdate.OnStateChanged,
1499
- UseAgentUpdate.OnRunStatusChanged
1500
- ];
1501
- function useAgent({ agentId, updates } = {}) {
1502
- var _agentId;
1503
- (_agentId = agentId) !== null && _agentId !== void 0 || (agentId = _copilotkit_shared.DEFAULT_AGENT_ID);
1504
- const { copilotkit } = useCopilotKit();
1505
- const [, forceUpdate] = (0, react.useReducer)((x) => x + 1, 0);
1506
- const updateFlags = (0, react.useMemo)(() => updates !== null && updates !== void 0 ? updates : ALL_UPDATES, [JSON.stringify(updates)]);
1507
- const provisionalAgentCache = (0, react.useRef)(/* @__PURE__ */ new Map());
1508
- const agent = (0, react.useMemo)(() => {
1509
- var _copilotkit$agents;
1510
- const existing = copilotkit.getAgent(agentId);
1511
- if (existing) {
1512
- provisionalAgentCache.current.delete(agentId);
1513
- return existing;
1514
- }
1515
- const isRuntimeConfigured = copilotkit.runtimeUrl !== void 0;
1516
- const status = copilotkit.runtimeConnectionStatus;
1517
- if (isRuntimeConfigured && (status === _copilotkit_core.CopilotKitCoreRuntimeConnectionStatus.Disconnected || status === _copilotkit_core.CopilotKitCoreRuntimeConnectionStatus.Connecting)) {
1518
- const cached = provisionalAgentCache.current.get(agentId);
1519
- if (cached) {
1520
- cached.headers = { ...copilotkit.headers };
1521
- return cached;
1522
- }
1523
- const provisional = new _copilotkit_core.ProxiedCopilotRuntimeAgent({
1524
- runtimeUrl: copilotkit.runtimeUrl,
1525
- agentId,
1526
- transport: copilotkit.runtimeTransport,
1527
- runtimeMode: "pending"
1528
- });
1529
- provisional.headers = { ...copilotkit.headers };
1530
- provisionalAgentCache.current.set(agentId, provisional);
1531
- return provisional;
1532
- }
1533
- if (isRuntimeConfigured && status === _copilotkit_core.CopilotKitCoreRuntimeConnectionStatus.Error) {
1534
- const provisional = new _copilotkit_core.ProxiedCopilotRuntimeAgent({
1535
- runtimeUrl: copilotkit.runtimeUrl,
1536
- agentId,
1537
- transport: copilotkit.runtimeTransport,
1538
- runtimeMode: "pending"
1539
- });
1540
- provisional.headers = { ...copilotkit.headers };
1541
- return provisional;
1542
- }
1543
- const knownAgents = Object.keys((_copilotkit$agents = copilotkit.agents) !== null && _copilotkit$agents !== void 0 ? _copilotkit$agents : {});
1544
- const runtimePart = isRuntimeConfigured ? `runtimeUrl=${copilotkit.runtimeUrl}` : "no runtimeUrl";
1545
- 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.");
1546
- }, [
1547
- agentId,
1548
- copilotkit.agents,
1549
- copilotkit.runtimeConnectionStatus,
1550
- copilotkit.runtimeUrl,
1551
- copilotkit.runtimeTransport,
1552
- JSON.stringify(copilotkit.headers)
1553
- ]);
1554
- (0, react.useEffect)(() => {
1555
- if (updateFlags.length === 0) return;
1556
- const handlers = {};
1557
- if (updateFlags.includes(UseAgentUpdate.OnMessagesChanged)) handlers.onMessagesChanged = () => {
1558
- forceUpdate();
1559
- };
1560
- if (updateFlags.includes(UseAgentUpdate.OnStateChanged)) handlers.onStateChanged = forceUpdate;
1561
- if (updateFlags.includes(UseAgentUpdate.OnRunStatusChanged)) {
1562
- handlers.onRunInitialized = forceUpdate;
1563
- handlers.onRunFinalized = forceUpdate;
1564
- handlers.onRunFailed = forceUpdate;
1565
- }
1566
- const subscription = agent.subscribe(handlers);
1567
- return () => subscription.unsubscribe();
1568
- }, [
1569
- agent,
1570
- forceUpdate,
1571
- JSON.stringify(updateFlags)
1572
- ]);
1573
- return { agent };
1574
- }
1575
-
1576
1637
  //#endregion
1577
1638
  //#region src/v2/hooks/use-suggestions.tsx
1578
1639
  function useSuggestions({ agentId } = {}) {
@@ -3967,7 +4028,7 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
3967
4028
  children: [
3968
4029
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)(CopilotListeners, {}),
3969
4030
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)(CopilotKitErrorBridge, {}),
3970
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(CoAgentStateRendersProvider, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(MessagesTapProvider, { children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(CopilotMessages, { children: [memoizedChildren, /* @__PURE__ */ (0, react_jsx_runtime.jsx)(RegisteredActionsRenderer, {})] }) }), bannerError && showDevConsole && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(UsageBanner, {
4031
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(CoAgentStateRendersProvider, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(MessagesTapProvider, { children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(CopilotMessages, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(react.default.Fragment, { children: memoizedChildren }, "children"), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(RegisteredActionsRenderer, {}, "actions")] }) }), bannerError && showDevConsole && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(UsageBanner, {
3971
4032
  severity: bannerError.severity,
3972
4033
  message: bannerError.message,
3973
4034
  onClose: () => setBannerError(null),
@@ -4037,7 +4098,11 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
4037
4098
  const existingConfig = useCopilotChatConfiguration();
4038
4099
  const [agentAvailable, setAgentAvailable] = (0, react.useState)(false);
4039
4100
  const resolvedAgentId = (_existingConfig$agent = existingConfig === null || existingConfig === void 0 ? void 0 : existingConfig.agentId) !== null && _existingConfig$agent !== void 0 ? _existingConfig$agent : "default";
4040
- const { agent } = useAgent({ agentId: resolvedAgentId });
4101
+ const { agent } = useAgent({
4102
+ agentId: resolvedAgentId,
4103
+ threadId: existingConfig === null || existingConfig === void 0 ? void 0 : existingConfig.threadId
4104
+ });
4105
+ const lastConnectedAgentRef = (0, react.useRef)(null);
4041
4106
  (0, react.useEffect)(() => {
4042
4107
  let detached = false;
4043
4108
  const connectAbortController = new AbortController();
@@ -4052,11 +4117,12 @@ window.parent.postMessage({jsonrpc:"2.0",method:"ui/notifications/sandbox-proxy-
4052
4117
  if (error instanceof _ag_ui_client.AGUIConnectNotImplementedError) {} else console.error("CopilotChat: connectAgent failed", error);
4053
4118
  }
4054
4119
  };
4055
- if (agent && (existingConfig === null || existingConfig === void 0 ? void 0 : existingConfig.threadId) && agent.threadId !== existingConfig.threadId && copilotkit.runtimeConnectionStatus === _copilotkit_core.CopilotKitCoreRuntimeConnectionStatus.Connected) {
4056
- agent.threadId = existingConfig.threadId;
4120
+ if (agent && agent !== lastConnectedAgentRef.current && copilotkit.runtimeConnectionStatus === _copilotkit_core.CopilotKitCoreRuntimeConnectionStatus.Connected) {
4121
+ lastConnectedAgentRef.current = agent;
4057
4122
  connect(agent);
4058
4123
  }
4059
4124
  return () => {
4125
+ lastConnectedAgentRef.current = null;
4060
4126
  detached = true;
4061
4127
  connectAbortController.abort();
4062
4128
  agent === null || agent === void 0 || agent.detachActiveRun();