@copilotkit/react-core 1.74.0 → 1.75.1

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.
@@ -1635,7 +1635,7 @@ function useRenderToolCall() {
1635
1635
 
1636
1636
  //#endregion
1637
1637
  //#region package.json
1638
- var version = "1.74.0";
1638
+ var version = "1.75.1";
1639
1639
 
1640
1640
  //#endregion
1641
1641
  //#region src/v2/components/CopilotKitInspector.tsx
@@ -4665,6 +4665,7 @@ function useAgent({ agentId, threadId, runtimeAgentId, updates, throttleMs } = {
4665
4665
  if (updateFlags.includes(UseAgentUpdate.OnStateChanged)) handlers.onStateChanged = batchedForceUpdate;
4666
4666
  if (updateFlags.includes(UseAgentUpdate.OnRunStatusChanged)) {
4667
4667
  handlers.onRunInitialized = batchedForceUpdate;
4668
+ handlers.onRunStartedEvent = batchedForceUpdate;
4668
4669
  handlers.onRunFinalized = batchedForceUpdate;
4669
4670
  handlers.onRunFailed = batchedForceUpdate;
4670
4671
  handlers.onRunErrorEvent = batchedForceUpdate;
@@ -6364,7 +6365,7 @@ function BoundInspectorButton({ inspectorButton, messageId, openInspector, ...pr
6364
6365
  })
6365
6366
  });
6366
6367
  }
6367
- function CopilotChatAssistantMessage({ message, messages, isRunning, onThumbsUp, onThumbsDown, onReadAloud, onRegenerate, additionalToolbarItems, toolbarVisible = true, markdownRenderer, toolbar, copyButton, inspectorButton, thumbsUpButton, thumbsDownButton, readAloudButton, regenerateButton, toolCallsView, children, className, ...props }) {
6368
+ function CopilotChatAssistantMessage({ message, messages, isRunning, isLatest, onThumbsUp, onThumbsDown, onReadAloud, onRegenerate, additionalToolbarItems, toolbarVisible = true, markdownRenderer, toolbar, copyButton, inspectorButton, thumbsUpButton, thumbsDownButton, readAloudButton, regenerateButton, toolCallsView, children, className, ...props }) {
6368
6369
  useKatexStyles();
6369
6370
  const { isInspectorEnabled, openInspector } = useCopilotKitInspector();
6370
6371
  const shortcutsHidden = useInspectorShortcutsHidden();
@@ -6400,7 +6401,7 @@ function CopilotChatAssistantMessage({ message, messages, isRunning, onThumbsUp,
6400
6401
  messages
6401
6402
  });
6402
6403
  const hasContent = !!(message.content && message.content.trim().length > 0);
6403
- const isLatestAssistantMessage = message.role === "assistant" && messages?.[messages.length - 1]?.id === message.id;
6404
+ const isLatestAssistantMessage = message.role === "assistant" && (isLatest ?? messages?.[messages.length - 1]?.id === message.id);
6404
6405
  const shouldShowToolbar = toolbarVisible && (hasContent || showInspectorShortcut) && !(isRunning && isLatestAssistantMessage);
6405
6406
  if (children) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
6406
6407
  "data-copilotkit": true,
@@ -6914,8 +6915,8 @@ function formatDuration(seconds) {
6914
6915
  if (secs === 0) return `${mins} minute${mins > 1 ? "s" : ""}`;
6915
6916
  return `${mins}m ${secs}s`;
6916
6917
  }
6917
- function CopilotChatReasoningMessage({ message, messages, isRunning, header, contentView, toggle, children, className, ...props }) {
6918
- const isLatest = messages?.[messages.length - 1]?.id === message.id;
6918
+ function CopilotChatReasoningMessage({ message, messages, isRunning, isLatest: isLatestProp, header, contentView, toggle, children, className, ...props }) {
6919
+ const isLatest = isLatestProp ?? messages?.[messages.length - 1]?.id === message.id;
6919
6920
  const isStreaming = !!(isRunning && isLatest);
6920
6921
  const hasContent = !!(message.content && message.content.length > 0);
6921
6922
  const startTimeRef = (0, react.useRef)(null);
@@ -7310,24 +7311,31 @@ const INTELLIGENCE_TURN_HEAD = "__cpk_turn_head__";
7310
7311
  * emits exactly one `IntelligenceIndicator` per entry, keyed by the turn id and
7311
7312
  * positioned at the anchor; the per-turn key also lets every past turn keep its
7312
7313
  * own indicator in scroll-back.
7314
+ *
7315
+ * `visibleMessages` is what actually renders, when that differs from
7316
+ * `messages` (the chat's `transformMessages`). Turns are still read from the
7317
+ * full list, so hiding a user message does not merge its turn into the one
7318
+ * before it, and anchors are only chosen among visible messages. A message the
7319
+ * transform built itself joins the turn of the visible message before it.
7313
7320
  */
7314
- function getIntelligenceTurnAnchors(messages) {
7315
- const anchors = /* @__PURE__ */ new Map();
7321
+ function getIntelligenceTurnAnchors(messages, visibleMessages = messages) {
7322
+ const turnOfMessage = /* @__PURE__ */ new Map();
7316
7323
  let turnId = INTELLIGENCE_TURN_HEAD;
7317
- let anchorId = null;
7318
- const commit = () => {
7319
- if (anchorId !== null) anchors.set(anchorId, turnId);
7320
- anchorId = null;
7321
- };
7322
7324
  for (const m of messages) {
7323
- if (m.role === "user") {
7324
- commit();
7325
- turnId = m.id;
7326
- continue;
7325
+ if (m.role === "user") turnId = m.id;
7326
+ turnOfMessage.set(m.id, turnId);
7327
+ }
7328
+ const anchors = /* @__PURE__ */ new Map();
7329
+ const anchoredTurns = /* @__PURE__ */ new Set();
7330
+ let currentTurn = INTELLIGENCE_TURN_HEAD;
7331
+ for (const m of visibleMessages) {
7332
+ currentTurn = turnOfMessage.get(m.id) ?? currentTurn;
7333
+ if (m.role === "user") continue;
7334
+ if (!anchoredTurns.has(currentTurn) && messageHasMatchingToolCall(m)) {
7335
+ anchors.set(m.id, currentTurn);
7336
+ anchoredTurns.add(currentTurn);
7327
7337
  }
7328
- if (anchorId === null && messageHasMatchingToolCall(m)) anchorId = m.id;
7329
7338
  }
7330
- commit();
7331
7339
  return anchors;
7332
7340
  }
7333
7341
  /**
@@ -7473,11 +7481,12 @@ function resolveSlotComponent(slot, DefaultComponent) {
7473
7481
  /**
7474
7482
  * Memoized wrapper for assistant messages to prevent re-renders when other messages change.
7475
7483
  */
7476
- const MemoizedAssistantMessage = react.default.memo(function MemoizedAssistantMessage({ message, messages, isRunning, AssistantMessageComponent, slotProps }) {
7484
+ const MemoizedAssistantMessage = react.default.memo(function MemoizedAssistantMessage({ message, messages, isRunning, isLatest, AssistantMessageComponent, slotProps }) {
7477
7485
  return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(AssistantMessageComponent, {
7478
7486
  message,
7479
7487
  messages,
7480
7488
  isRunning,
7489
+ isLatest,
7481
7490
  ...slotProps
7482
7491
  });
7483
7492
  }, (prevProps, nextProps) => {
@@ -7499,7 +7508,7 @@ const MemoizedAssistantMessage = react.default.memo(function MemoizedAssistantMe
7499
7508
  if (prevToolResults.length !== nextToolResults.length) return false;
7500
7509
  for (let i = 0; i < prevToolResults.length; i++) if (prevToolResults[i].content !== nextToolResults[i].content) return false;
7501
7510
  }
7502
- if (nextProps.messages[nextProps.messages.length - 1]?.id === nextProps.message.id && prevProps.isRunning !== nextProps.isRunning) return false;
7511
+ if ((prevProps.isRunning && prevProps.isLatest) !== (nextProps.isRunning && nextProps.isLatest)) return false;
7503
7512
  if (prevProps.AssistantMessageComponent !== nextProps.AssistantMessageComponent) return false;
7504
7513
  if (prevProps.slotProps !== nextProps.slotProps) return false;
7505
7514
  return true;
@@ -7533,20 +7542,19 @@ const MemoizedActivityMessage = react.default.memo(function MemoizedActivityMess
7533
7542
  /**
7534
7543
  * Memoized wrapper for reasoning messages to prevent re-renders when other messages change.
7535
7544
  */
7536
- const MemoizedReasoningMessage = react.default.memo(function MemoizedReasoningMessage({ message, messages, isRunning, ReasoningMessageComponent, slotProps }) {
7545
+ const MemoizedReasoningMessage = react.default.memo(function MemoizedReasoningMessage({ message, messages, isRunning, isLatest, ReasoningMessageComponent, slotProps }) {
7537
7546
  return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ReasoningMessageComponent, {
7538
7547
  message,
7539
7548
  messages,
7540
7549
  isRunning,
7550
+ isLatest,
7541
7551
  ...slotProps
7542
7552
  });
7543
7553
  }, (prevProps, nextProps) => {
7544
7554
  if (prevProps.message.id !== nextProps.message.id) return false;
7545
7555
  if (prevProps.message.content !== nextProps.message.content) return false;
7546
- const prevIsLatest = prevProps.messages[prevProps.messages.length - 1]?.id === prevProps.message.id;
7547
- const nextIsLatest = nextProps.messages[nextProps.messages.length - 1]?.id === nextProps.message.id;
7548
- if (prevIsLatest !== nextIsLatest) return false;
7549
- if (nextIsLatest && prevProps.isRunning !== nextProps.isRunning) return false;
7556
+ if (prevProps.isLatest !== nextProps.isLatest) return false;
7557
+ if (nextProps.isLatest && prevProps.isRunning !== nextProps.isRunning) return false;
7550
7558
  if (prevProps.ReasoningMessageComponent !== nextProps.ReasoningMessageComponent) return false;
7551
7559
  if (prevProps.slotProps !== nextProps.slotProps) return false;
7552
7560
  return true;
@@ -7630,7 +7638,7 @@ function deduplicateMessages(messages) {
7630
7638
  return [...acc.values()];
7631
7639
  }
7632
7640
  const VIRTUALIZE_THRESHOLD = 50;
7633
- function CopilotChatMessageView({ messages = [], assistantMessage, userMessage, reasoningMessage, cursor, intelligenceIndicator, isRunning = false, children, className, ...props }) {
7641
+ function CopilotChatMessageView({ messages = [], assistantMessage, userMessage, reasoningMessage, cursor, intelligenceIndicator, isRunning = false, transformMessages, children, className, ...props }) {
7634
7642
  const isPinnedToBottom = (0, react.useContext)(ScrollPinnedContext);
7635
7643
  const renderCustomMessage = useRenderCustomMessages();
7636
7644
  const { renderActivityMessage } = useRenderActivityMessage();
@@ -7663,13 +7671,27 @@ function CopilotChatMessageView({ messages = [], assistantMessage, userMessage,
7663
7671
  return copilotkit.getStateByRun(config.agentId, config.threadId, resolvedRunId);
7664
7672
  };
7665
7673
  const deduplicatedMessages = (0, react.useMemo)(() => deduplicateMessages(messages), [messages]);
7674
+ const renderedMessages = (0, react.useMemo)(() => transformMessages ? transformMessages(deduplicatedMessages) : deduplicatedMessages, [deduplicatedMessages, transformMessages]);
7675
+ const latestRenderedId = renderedMessages[renderedMessages.length - 1]?.id;
7676
+ const transformDuplicateId = (0, react.useMemo)(() => {
7677
+ if (process.env.NODE_ENV === "production" || !transformMessages) return;
7678
+ const seen = /* @__PURE__ */ new Set();
7679
+ for (const message of renderedMessages) {
7680
+ if (seen.has(message.id)) return message.id;
7681
+ seen.add(message.id);
7682
+ }
7683
+ }, [renderedMessages, transformMessages]);
7684
+ (0, react.useEffect)(() => {
7685
+ if (transformDuplicateId === void 0) return;
7686
+ console.warn(`[CopilotKit] CopilotChatMessageView: \`transformMessages\` returned more than one message with id "${transformDuplicateId}". Return each id at most once; a message you create needs its own id, stable across renders.`);
7687
+ }, [transformDuplicateId]);
7666
7688
  const rowKeyStoreRef = (0, react.useRef)(null);
7667
7689
  rowKeyStoreRef.current ??= (0, _copilotkit_shared.createRowKeyStore)();
7668
7690
  const rowKeyStore = rowKeyStoreRef.current;
7669
- const rowRenderKeys = (0, react.useMemo)(() => (0, _copilotkit_shared.resolveRowRenderKeysById)(rowKeyStore, deduplicatedMessages), [rowKeyStore, deduplicatedMessages]);
7691
+ const rowRenderKeys = (0, react.useMemo)(() => (0, _copilotkit_shared.resolveRowRenderKeysById)(rowKeyStore, renderedMessages), [rowKeyStore, renderedMessages]);
7670
7692
  (0, react.useLayoutEffect)(() => {
7671
- (0, _copilotkit_shared.commitRowKeyStore)(rowKeyStore, deduplicatedMessages);
7672
- }, [rowKeyStore, deduplicatedMessages]);
7693
+ (0, _copilotkit_shared.commitRowKeyStore)(rowKeyStore, renderedMessages);
7694
+ }, [rowKeyStore, renderedMessages]);
7673
7695
  if (process.env.NODE_ENV === "development" && deduplicatedMessages.length < messages.length) console.warn(`CopilotChatMessageView: Merged ${messages.length - deduplicatedMessages.length} message(s) with duplicate IDs.`);
7674
7696
  const { Component: AssistantComponent, slotProps: assistantSlotProps } = (0, react.useMemo)(() => resolveSlotComponent(assistantMessage, CopilotChatAssistantMessage_default), [assistantMessage]);
7675
7697
  const agentId = config?.agentId;
@@ -7703,7 +7725,18 @@ function CopilotChatMessageView({ messages = [], assistantMessage, userMessage,
7703
7725
  (0, react.useEffect)(() => {
7704
7726
  if (process.env.NODE_ENV !== "production" && scrollElementFromCtx && scrollElementFromCtx.clientHeight === 0) console.warn("[CopilotKit] Chat scroll container has clientHeight=0 — virtualization disabled. Ensure the chat is rendered in a visible container with a non-zero height.");
7705
7727
  }, [scrollElementFromCtx]);
7706
- const shouldVirtualize = !!scrollElement && !children && deduplicatedMessages.length > VIRTUALIZE_THRESHOLD;
7728
+ const shouldVirtualize = !!scrollElement && !children && renderedMessages.length > VIRTUALIZE_THRESHOLD;
7729
+ const childrenDisabledVirtualization = !!children && !!scrollElement && renderedMessages.length > VIRTUALIZE_THRESHOLD;
7730
+ const warnedChildrenRef = (0, react.useRef)(false);
7731
+ (0, react.useEffect)(() => {
7732
+ if (process.env.NODE_ENV === "production" || !childrenDisabledVirtualization || warnedChildrenRef.current) return;
7733
+ warnedChildrenRef.current = true;
7734
+ console.warn(`[CopilotKit] CopilotChatMessageView: the \`children\` render prop disables virtualization, so all ${renderedMessages.length} messages are mounted. ` + (transformMessages ? "`transformMessages` keeps virtualization on by itself; drop `children` to use it." : "To reshape the list and keep virtualization, use `transformMessages` instead."));
7735
+ }, [
7736
+ childrenDisabledVirtualization,
7737
+ renderedMessages.length,
7738
+ transformMessages
7739
+ ]);
7707
7740
  const measuredRef = react.default.useRef({
7708
7741
  total: 0,
7709
7742
  sizes: /* @__PURE__ */ new Map()
@@ -7738,7 +7771,7 @@ function CopilotChatMessageView({ messages = [], assistantMessage, userMessage,
7738
7771
  return item.start < (instance.scrollOffset ?? 0) + scrollAdjustments;
7739
7772
  }, []);
7740
7773
  const virtualizer = (0, _tanstack_react_virtual.useVirtualizer)({
7741
- count: shouldVirtualize ? deduplicatedMessages.length : 0,
7774
+ count: shouldVirtualize ? renderedMessages.length : 0,
7742
7775
  getScrollElement: () => scrollElement,
7743
7776
  estimateSize: estimateRowSize,
7744
7777
  overscan: 5,
@@ -7751,10 +7784,10 @@ function CopilotChatMessageView({ messages = [], assistantMessage, userMessage,
7751
7784
  isPinnedToBottomRef.current = isPinnedToBottom;
7752
7785
  virtualizer.shouldAdjustScrollPositionOnItemSizeChange = shouldAdjustScrollOnResize;
7753
7786
  (0, react.useLayoutEffect)(() => {
7754
- if (!shouldVirtualize || !deduplicatedMessages.length) return;
7755
- virtualizer.scrollToIndex(deduplicatedMessages.length - 1, { align: "end" });
7787
+ if (!shouldVirtualize || !renderedMessages.length) return;
7788
+ virtualizer.scrollToIndex(renderedMessages.length - 1, { align: "end" });
7756
7789
  }, [shouldVirtualize, firstMessageId]);
7757
- const intelligenceTurnAnchors = (0, react.useMemo)(() => getIntelligenceTurnAnchors(deduplicatedMessages), [deduplicatedMessages]);
7790
+ const intelligenceTurnAnchors = (0, react.useMemo)(() => getIntelligenceTurnAnchors(deduplicatedMessages, renderedMessages), [deduplicatedMessages, renderedMessages]);
7758
7791
  const renderMessageBlock = (message) => {
7759
7792
  const elements = [];
7760
7793
  const stateSnapshot = renderCustomMessage ? getStateSnapshotForMessage(message.id) : void 0;
@@ -7769,6 +7802,7 @@ function CopilotChatMessageView({ messages = [], assistantMessage, userMessage,
7769
7802
  message,
7770
7803
  messages,
7771
7804
  isRunning,
7805
+ isLatest: message.id === latestRenderedId,
7772
7806
  AssistantMessageComponent: AssistantComponent,
7773
7807
  slotProps: assistantSlotPropsWithFeedback
7774
7808
  }, rowKey));
@@ -7785,6 +7819,7 @@ function CopilotChatMessageView({ messages = [], assistantMessage, userMessage,
7785
7819
  message,
7786
7820
  messages,
7787
7821
  isRunning,
7822
+ isLatest: message.id === latestRenderedId,
7788
7823
  ReasoningMessageComponent: ReasoningComponent,
7789
7824
  slotProps: reasoningSlotProps
7790
7825
  }, rowKey));
@@ -7802,7 +7837,7 @@ function CopilotChatMessageView({ messages = [], assistantMessage, userMessage,
7802
7837
  }, `intelligence-${intelligenceTurnId}`));
7803
7838
  return elements.filter(Boolean);
7804
7839
  };
7805
- const messageElements = shouldVirtualize ? [] : deduplicatedMessages.flatMap(renderMessageBlock);
7840
+ const messageElements = shouldVirtualize ? [] : renderedMessages.flatMap(renderMessageBlock);
7806
7841
  if (children) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
7807
7842
  "data-copilotkit": true,
7808
7843
  style: { display: "contents" },
@@ -7813,7 +7848,7 @@ function CopilotChatMessageView({ messages = [], assistantMessage, userMessage,
7813
7848
  interruptElement
7814
7849
  })
7815
7850
  });
7816
- const lastMessage = messages[messages.length - 1];
7851
+ const lastMessage = renderedMessages[renderedMessages.length - 1];
7817
7852
  const showCursor = isRunning && lastMessage?.role !== "reasoning";
7818
7853
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
7819
7854
  "data-copilotkit": true,
@@ -7827,7 +7862,7 @@ function CopilotChatMessageView({ messages = [], assistantMessage, userMessage,
7827
7862
  position: "relative"
7828
7863
  },
7829
7864
  children: virtualizer.getVirtualItems().map((virtualItem) => {
7830
- const message = deduplicatedMessages[virtualItem.index];
7865
+ const message = renderedMessages[virtualItem.index];
7831
7866
  return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
7832
7867
  "data-index": virtualItem.index,
7833
7868
  ref: virtualizer.measureElement,
@@ -13081,4 +13116,4 @@ Object.defineProperty(exports, 'useToast', {
13081
13116
  return useToast;
13082
13117
  }
13083
13118
  });
13084
- //# sourceMappingURL=copilotkit-C5FS3iDK.cjs.map
13119
+ //# sourceMappingURL=copilotkit-DIudpHkM.cjs.map