@copilotkit/react-core 1.55.1 → 1.55.2-canary.test-01

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 (34) hide show
  1. package/CHANGELOG.md +34 -0
  2. package/dist/copilotkit-BuhSUZHb.d.mts.map +1 -1
  3. package/dist/{copilotkit-BY5S1-0P.mjs → copilotkit-Cd-NrDyp.mjs} +46 -16
  4. package/dist/copilotkit-Cd-NrDyp.mjs.map +1 -0
  5. package/dist/{copilotkit-Bz5-ImDl.cjs → copilotkit-Dgdpbqjt.cjs} +46 -16
  6. package/dist/copilotkit-Dgdpbqjt.cjs.map +1 -0
  7. package/dist/copilotkit-dwDWYpya.d.cts.map +1 -1
  8. package/dist/index.cjs +6 -3
  9. package/dist/index.cjs.map +1 -1
  10. package/dist/index.mjs +6 -3
  11. package/dist/index.mjs.map +1 -1
  12. package/dist/index.umd.js +28 -29
  13. package/dist/index.umd.js.map +1 -1
  14. package/dist/v2/index.cjs +1 -1
  15. package/dist/v2/index.mjs +1 -1
  16. package/dist/v2/index.umd.js +52 -28
  17. package/dist/v2/index.umd.js.map +1 -1
  18. package/package.json +7 -7
  19. package/src/components/copilot-provider/copilotkit.tsx +2 -2
  20. package/src/hooks/use-agent-nodename.ts +3 -0
  21. package/src/hooks/use-coagent-state-render-bridge.helpers.ts +2 -1
  22. package/src/hooks/use-coagent-state-render-registry.ts +6 -6
  23. package/src/hooks/use-copilot-chat_internal.ts +1 -1
  24. package/src/lib/copilot-task.ts +1 -1
  25. package/src/utils/utils.ts +0 -2
  26. package/src/v2/a2ui/A2UIMessageRenderer.tsx +1 -1
  27. package/src/v2/components/MCPAppsActivityRenderer.tsx +32 -2
  28. package/src/v2/components/chat/CopilotChatMessageView.tsx +41 -5
  29. package/src/v2/components/chat/__tests__/CopilotChatMessageView.test.tsx +192 -82
  30. package/src/v2/components/chat/__tests__/MCPAppsProxy.e2e.test.tsx +589 -0
  31. package/src/v2/components/chat/__tests__/MCPAppsUiMessage.e2e.test.tsx +458 -0
  32. package/src/v2/providers/CopilotChatConfigurationProvider.tsx +2 -2
  33. package/dist/copilotkit-BY5S1-0P.mjs.map +0 -1
  34. package/dist/copilotkit-Bz5-ImDl.cjs.map +0 -1
@@ -180,8 +180,8 @@ const CopilotChatConfigurationProvider = ({ children, labels, agentId, threadId,
180
180
  const stableLabels = useShallowStableRef(labels);
181
181
  const mergedLabels = (0, react.useMemo)(() => ({
182
182
  ...CopilotChatDefaultLabels,
183
- ...parentConfig?.labels ?? {},
184
- ...stableLabels ?? {}
183
+ ...parentConfig?.labels,
184
+ ...stableLabels
185
185
  }), [stableLabels, parentConfig?.labels]);
186
186
  const resolvedAgentId = agentId ?? parentConfig?.agentId ?? _copilotkit_shared.DEFAULT_AGENT_ID;
187
187
  const resolvedThreadId = (0, react.useMemo)(() => {
@@ -1630,6 +1630,7 @@ function isNotification(msg) {
1630
1630
  * Fetches resource content on-demand via proxied MCP requests.
1631
1631
  */
1632
1632
  const MCPAppsActivityRenderer = function MCPAppsActivityRenderer({ content, agent }) {
1633
+ const { copilotkit } = useCopilotKit();
1633
1634
  const containerRef = (0, react.useRef)(null);
1634
1635
  const iframeRef = (0, react.useRef)(null);
1635
1636
  const [iframeReady, setIframeReady] = (0, react.useState)(false);
@@ -1803,13 +1804,15 @@ const MCPAppsActivityRenderer = function MCPAppsActivityRenderer({ content, agen
1803
1804
  }
1804
1805
  try {
1805
1806
  const params = msg.params;
1807
+ const role = params.role || "user";
1806
1808
  const textContent = params.content?.filter((c) => c.type === "text" && c.text).map((c) => c.text).join("\n") || "";
1807
1809
  if (textContent) currentAgent.addMessage({
1808
1810
  id: crypto.randomUUID(),
1809
- role: params.role || "user",
1811
+ role,
1810
1812
  content: textContent
1811
1813
  });
1812
1814
  sendResponse(msg.id, { isError: false });
1815
+ if ((params.followUp ?? role === "user") && textContent) mcpAppsRequestQueue.enqueue(currentAgent, () => copilotkit.runAgent({ agent: currentAgent })).catch((err) => console.error("[MCPAppsRenderer] ui/message agent run failed:", err));
1813
1816
  } catch (err) {
1814
1817
  console.error("[MCPAppsRenderer] ui/message error:", err);
1815
1818
  sendResponse(msg.id, { isError: true });
@@ -2435,7 +2438,7 @@ function ReactSurfaceHost({ surfaceId, operations, theme, agent, copilotkit, cat
2435
2438
  message.userAction;
2436
2439
  try {
2437
2440
  copilotkit.setProperties({
2438
- ...copilotkit.properties ?? {},
2441
+ ...copilotkit.properties,
2439
2442
  a2uiAction: message
2440
2443
  });
2441
2444
  await copilotkit.runAgent({ agent });
@@ -5617,6 +5620,33 @@ const MemoizedCustomMessage = react.default.memo(function MemoizedCustomMessage(
5617
5620
  if (JSON.stringify(prevProps.stateSnapshot) !== JSON.stringify(nextProps.stateSnapshot)) return false;
5618
5621
  return true;
5619
5622
  });
5623
+ /**
5624
+ * Deduplicates messages by ID. For assistant messages, merges occurrences:
5625
+ * recovers non-empty content from any earlier occurrence if the latest wiped it
5626
+ * (empty string means the streaming update cleared the field, not blank text),
5627
+ * and similarly recovers toolCalls from earlier occurrences if the latest is
5628
+ * undefined (an empty array [] is treated as intentional and kept as-is).
5629
+ * For all other roles, keeps the last entry.
5630
+ *
5631
+ * @internal Exported for unit testing only — not part of the public API.
5632
+ */
5633
+ function deduplicateMessages(messages) {
5634
+ const acc = /* @__PURE__ */ new Map();
5635
+ for (const message of messages) {
5636
+ const existing = acc.get(message.id);
5637
+ if (existing && message.role === "assistant" && existing.role === "assistant") {
5638
+ const content = message.content || existing.content;
5639
+ const toolCalls = message.toolCalls ?? existing.toolCalls;
5640
+ acc.set(message.id, {
5641
+ ...existing,
5642
+ ...message,
5643
+ content,
5644
+ toolCalls
5645
+ });
5646
+ } else acc.set(message.id, message);
5647
+ }
5648
+ return [...acc.values()];
5649
+ }
5620
5650
  const VIRTUALIZE_THRESHOLD = 50;
5621
5651
  function CopilotChatMessageView({ messages = [], assistantMessage, userMessage, reasoningMessage, cursor, isRunning = false, children, className, ...props }) {
5622
5652
  const renderCustomMessage = useRenderCustomMessages();
@@ -5651,8 +5681,8 @@ function CopilotChatMessageView({ messages = [], assistantMessage, userMessage,
5651
5681
  if (!resolvedRunId) return void 0;
5652
5682
  return copilotkit.getStateByRun(config.agentId, config.threadId, resolvedRunId);
5653
5683
  };
5654
- const deduplicatedMessages = (0, react.useMemo)(() => [...new Map(messages.map((m) => [m.id, m])).values()], [messages]);
5655
- if (process.env.NODE_ENV === "development" && deduplicatedMessages.length < messages.length) console.warn(`CopilotChatMessageView: Deduplicated ${messages.length - deduplicatedMessages.length} message(s) with duplicate IDs.`);
5684
+ const deduplicatedMessages = (0, react.useMemo)(() => deduplicateMessages(messages), [messages]);
5685
+ if (process.env.NODE_ENV === "development" && deduplicatedMessages.length < messages.length) console.warn(`CopilotChatMessageView: Merged ${messages.length - deduplicatedMessages.length} message(s) with duplicate IDs.`);
5656
5686
  const { Component: AssistantComponent, slotProps: assistantSlotProps } = (0, react.useMemo)(() => resolveSlotComponent(assistantMessage, CopilotChatAssistantMessage_default), [assistantMessage]);
5657
5687
  const { Component: UserComponent, slotProps: userSlotProps } = (0, react.useMemo)(() => resolveSlotComponent(userMessage, CopilotChatUserMessage_default), [userMessage]);
5658
5688
  const { Component: ReasoningComponent, slotProps: reasoningSlotProps } = (0, react.useMemo)(() => resolveSlotComponent(reasoningMessage, CopilotChatReasoningMessage_default), [reasoningMessage]);
@@ -8699,7 +8729,7 @@ function resolveClaim({ claims, context, stateSnapshot }) {
8699
8729
  * 5) last cached snapshot for stateRenderId
8700
8730
  */
8701
8731
  function selectSnapshot({ messageId, messageName, allowLiveState, skipLatestCache, stateRenderId, effectiveRunId, stateSnapshotProp, agentState, agentMessages, existingClaim, caches }) {
8702
- const lastAssistantId = agentMessages ? [...agentMessages].reverse().find((msg) => msg.role === "assistant")?.id : void 0;
8732
+ const lastAssistantId = agentMessages ? [...agentMessages].toReversed().find((msg) => msg.role === "assistant")?.id : void 0;
8703
8733
  const latestSnapshot = stateRenderId !== void 0 ? caches.byStateRenderAndRun[`${stateRenderId}::latest`] : void 0;
8704
8734
  const messageIndex = agentMessages ? agentMessages.findIndex((msg) => msg.id === messageId) : -1;
8705
8735
  const messageRole = messageIndex >= 0 && agentMessages ? agentMessages[messageIndex]?.role : void 0;
@@ -8761,12 +8791,12 @@ function useStateRenderRegistry({ agentId, stateRenderId, message, messageIndex,
8761
8791
  return () => {
8762
8792
  const existingClaim = claimsRef.current[message.id];
8763
8793
  if (existingClaim?.stateSnapshot && Object.keys(existingClaim.stateSnapshot).length > 0) {
8764
- const snapshotCache = { ...store[LAST_SNAPSHOTS_BY_RENDER_AND_RUN] ?? {} };
8794
+ const snapshotCache = { ...store[LAST_SNAPSHOTS_BY_RENDER_AND_RUN] };
8765
8795
  const cacheKey = `${existingClaim.stateRenderId}::${existingClaim.runId ?? "pending"}`;
8766
8796
  snapshotCache[cacheKey] = existingClaim.stateSnapshot;
8767
8797
  snapshotCache[`${existingClaim.stateRenderId}::latest`] = existingClaim.stateSnapshot;
8768
8798
  store[LAST_SNAPSHOTS_BY_RENDER_AND_RUN] = snapshotCache;
8769
- const messageCache = { ...store[LAST_SNAPSHOTS_BY_MESSAGE] ?? {} };
8799
+ const messageCache = { ...store[LAST_SNAPSHOTS_BY_MESSAGE] };
8770
8800
  messageCache[message.id] = {
8771
8801
  snapshot: existingClaim.stateSnapshot,
8772
8802
  runId: existingClaim.runId ?? effectiveRunId
@@ -8822,12 +8852,12 @@ function useStateRenderRegistry({ agentId, stateRenderId, message, messageIndex,
8822
8852
  if (snapshot && (stateSnapshot || hasSnapshotKeys || allowEmptySnapshot) && (!claimsRef.current[message.id].locked || snapshotChanged)) {
8823
8853
  if (!claimsRef.current[message.id].locked || snapshotChanged) {
8824
8854
  claimsRef.current[message.id].stateSnapshot = snapshot;
8825
- const snapshotCache = { ...store[LAST_SNAPSHOTS_BY_RENDER_AND_RUN] ?? {} };
8855
+ const snapshotCache = { ...store[LAST_SNAPSHOTS_BY_RENDER_AND_RUN] };
8826
8856
  const cacheKey = `${stateRenderId}::${effectiveRunId}`;
8827
8857
  snapshotCache[cacheKey] = snapshot;
8828
8858
  snapshotCache[`${stateRenderId}::latest`] = snapshot;
8829
8859
  store[LAST_SNAPSHOTS_BY_RENDER_AND_RUN] = snapshotCache;
8830
- const messageCache = { ...store[LAST_SNAPSHOTS_BY_MESSAGE] ?? {} };
8860
+ const messageCache = { ...store[LAST_SNAPSHOTS_BY_MESSAGE] };
8831
8861
  messageCache[message.id] = {
8832
8862
  snapshot,
8833
8863
  runId: effectiveRunId
@@ -8838,12 +8868,12 @@ function useStateRenderRegistry({ agentId, stateRenderId, message, messageIndex,
8838
8868
  } else if (snapshotForClaim) {
8839
8869
  if (!claimsRef.current[message.id].stateSnapshot) {
8840
8870
  claimsRef.current[message.id].stateSnapshot = snapshotForClaim;
8841
- const snapshotCache = { ...store[LAST_SNAPSHOTS_BY_RENDER_AND_RUN] ?? {} };
8871
+ const snapshotCache = { ...store[LAST_SNAPSHOTS_BY_RENDER_AND_RUN] };
8842
8872
  const cacheKey = `${stateRenderId}::${effectiveRunId}`;
8843
8873
  snapshotCache[cacheKey] = snapshotForClaim;
8844
8874
  snapshotCache[`${stateRenderId}::latest`] = snapshotForClaim;
8845
8875
  store[LAST_SNAPSHOTS_BY_RENDER_AND_RUN] = snapshotCache;
8846
- const messageCache = { ...store[LAST_SNAPSHOTS_BY_MESSAGE] ?? {} };
8876
+ const messageCache = { ...store[LAST_SNAPSHOTS_BY_MESSAGE] };
8847
8877
  messageCache[message.id] = {
8848
8878
  snapshot: snapshotForClaim,
8849
8879
  runId: effectiveRunId
@@ -9184,7 +9214,7 @@ function CopilotKitInternal(cpkProps) {
9184
9214
  return acc;
9185
9215
  }, {});
9186
9216
  return {
9187
- ...copilotApiConfig.headers || {},
9217
+ ...copilotApiConfig.headers,
9188
9218
  ...copilotApiConfig.publicApiKey ? { [_copilotkit_shared.COPILOT_CLOUD_PUBLIC_API_KEY_HEADER]: copilotApiConfig.publicApiKey } : {},
9189
9219
  ...authHeaders
9190
9220
  };
@@ -9268,7 +9298,7 @@ function CopilotKitInternal(cpkProps) {
9268
9298
  return {
9269
9299
  ...prev,
9270
9300
  [action.id]: {
9271
- ...prev[action.id] ?? {},
9301
+ ...prev[action.id],
9272
9302
  ...action
9273
9303
  }
9274
9304
  };
@@ -9916,4 +9946,4 @@ Object.defineProperty(exports, 'useToast', {
9916
9946
  return useToast;
9917
9947
  }
9918
9948
  });
9919
- //# sourceMappingURL=copilotkit-Bz5-ImDl.cjs.map
9949
+ //# sourceMappingURL=copilotkit-Dgdpbqjt.cjs.map