diff --git a/packages/ui/src/components/chat/ChatMessage.tsx b/packages/ui/src/components/chat/ChatMessage.tsx index df9b1431..28e3e812 100644 --- a/packages/ui/src/components/chat/ChatMessage.tsx +++ b/packages/ui/src/components/chat/ChatMessage.tsx @@ -30,7 +30,6 @@ import type { TurnGroupingContext } from './lib/turns/types'; import { copyTextToClipboard } from '@/lib/clipboard'; import { FadeInOnReveal } from './message/FadeInOnReveal'; import { streamPerfCount } from '@/stores/utils/streamDebug'; -import { areOptionalRenderRelevantMessagesEqual, areRelevantTurnGroupingContextsEqual, areRenderRelevantMessageInfoEqual, areRenderRelevantPartsEqual } from './message/renderCompare'; const ToolOutputDialog = React.lazy(() => import('./message/ToolOutputDialog')); @@ -1128,18 +1127,4 @@ const ChatMessage: React.FC = ({ ); }; -export default React.memo(ChatMessage, (prev, next) => { - const prevRole = deriveMessageRole(prev.message.info); - - return areRenderRelevantMessageInfoEqual(prev.message.info, next.message.info) - && areRenderRelevantPartsEqual(prev.message.parts, next.message.parts) - && areOptionalRenderRelevantMessagesEqual(prev.previousMessage, next.previousMessage) - && areOptionalRenderRelevantMessagesEqual(prev.nextMessage, next.nextMessage) - && prev.onContentChange === next.onContentChange - && areRelevantTurnGroupingContextsEqual(prev.turnGroupingContext, next.turnGroupingContext, prev.message.info.id, prevRole.isUser) - && prev.assistantHeaderMessageId === next.assistantHeaderMessageId - && prev.isInActiveTurn === next.isInActiveTurn - && prev.activeStreamingPhase === next.activeStreamingPhase - && prev.animateUserOnMount === next.animateUserOnMount - && prev.onUserAnimationConsumed === next.onUserAnimationConsumed; -}); +export default ChatMessage; diff --git a/packages/ui/src/components/chat/MessageList.tsx b/packages/ui/src/components/chat/MessageList.tsx index 01ba1ca0..db72b459 100644 --- a/packages/ui/src/components/chat/MessageList.tsx +++ b/packages/ui/src/components/chat/MessageList.tsx @@ -797,7 +797,7 @@ interface UngroupedMessageRowProps { activeStreamingPhase?: StreamPhase | null; } -const UngroupedMessageRow: React.FC = React.memo(({ +const UngroupedMessageRow: React.FC = ({ message, previousMessage, nextMessage, @@ -823,18 +823,7 @@ const UngroupedMessageRow: React.FC = React.memo(({ activeStreamingPhase={message.info.id === activeStreamingMessageId ? activeStreamingPhase : null} /> ); -}, (prev, next) => { - return areRenderRelevantMessagesEqual(prev.message, next.message) - && areOptionalRenderRelevantMessagesEqual(prev.previousMessage, next.previousMessage) - && areOptionalRenderRelevantMessagesEqual(prev.nextMessage, next.nextMessage) - && prev.onMessageContentChange === next.onMessageContentChange - && prev.getAnimationHandlers === next.getAnimationHandlers - && prev.scrollToBottom === next.scrollToBottom - && prev.shouldAnimateUserMessage === next.shouldAnimateUserMessage - && prev.onUserAnimationConsumed === next.onUserAnimationConsumed - && prev.activeStreamingMessageId === next.activeStreamingMessageId - && prev.activeStreamingPhase === next.activeStreamingPhase; -}); +}; UngroupedMessageRow.displayName = 'UngroupedMessageRow'; @@ -867,7 +856,7 @@ const turnContainsMessageId = (turn: TurnRecord, messageId: string | null | unde return turn.assistantMessages.some((assistant) => assistant.info.id === messageId); }; -const MessageListEntry: React.FC = React.memo(({ +const MessageListEntry: React.FC = ({ entry, onMessageContentChange, getAnimationHandlers, @@ -919,96 +908,10 @@ const MessageListEntry: React.FC = React.memo(({ stickyUserHeader={stickyUserHeader} /> ); -}, areMessageListEntryPropsEqual); +}; MessageListEntry.displayName = 'MessageListEntry'; -function areMessageListEntryPropsEqual(prevProps: MessageListEntryProps, nextProps: MessageListEntryProps): boolean { - if (prevProps.stickyUserHeader !== nextProps.stickyUserHeader) return false; - if (prevProps.chatRenderMode !== nextProps.chatRenderMode) return false; - if (prevProps.shouldAnimateUserMessage !== nextProps.shouldAnimateUserMessage) return false; - - const prevEntry = prevProps.entry; - const nextEntry = nextProps.entry; - if (prevEntry.kind !== nextEntry.kind) return false; - if (prevEntry.key !== nextEntry.key) return false; - - if (prevEntry.kind === 'turn' && nextEntry.kind === 'turn') { - if (prevEntry.turn !== nextEntry.turn || prevEntry.isLastTurn !== nextEntry.isLastTurn) { - return false; - } - - const prevExpanded = (prevProps.turnUiStates.get(prevEntry.turn.turnId) ?? { isExpanded: prevProps.defaultActivityExpanded }).isExpanded; - const nextExpanded = (nextProps.turnUiStates.get(nextEntry.turn.turnId) ?? { isExpanded: nextProps.defaultActivityExpanded }).isExpanded; - if (prevExpanded !== nextExpanded) { - return false; - } - - if (prevEntry.isLastTurn && prevProps.sessionIsWorking !== nextProps.sessionIsWorking) { - return false; - } - - if (prevProps.activeStreamingMessageId !== nextProps.activeStreamingMessageId) { - const prevAffected = turnContainsMessageId(prevEntry.turn, prevProps.activeStreamingMessageId); - const nextAffected = turnContainsMessageId(nextEntry.turn, nextProps.activeStreamingMessageId); - if (prevAffected || nextAffected) { - return false; - } - } - - if (prevProps.activeStreamingPhase !== nextProps.activeStreamingPhase) { - const prevAffected = turnContainsMessageId(prevEntry.turn, prevProps.activeStreamingMessageId); - const nextAffected = turnContainsMessageId(nextEntry.turn, nextProps.activeStreamingMessageId); - if (prevAffected || nextAffected) { - return false; - } - } - - if (prevProps.activeStreamingPhase !== nextProps.activeStreamingPhase) { - const prevAffected = turnContainsMessageId(prevEntry.turn, prevProps.activeStreamingMessageId); - const nextAffected = turnContainsMessageId(nextEntry.turn, nextProps.activeStreamingMessageId); - if (prevAffected || nextAffected) { - return false; - } - } - - return true; - } - - if (prevEntry.kind === 'ungrouped' && nextEntry.kind === 'ungrouped') { - if (prevProps.activeStreamingMessageId !== nextProps.activeStreamingMessageId) { - const messageId = prevEntry.message.info.id; - const prevActive = prevProps.activeStreamingMessageId === messageId; - const nextActive = nextProps.activeStreamingMessageId === messageId; - if (prevActive !== nextActive) { - return false; - } - } - - if (prevProps.activeStreamingPhase !== nextProps.activeStreamingPhase) { - const messageId = prevEntry.message.info.id; - if (prevProps.activeStreamingMessageId === messageId || nextProps.activeStreamingMessageId === messageId) { - return false; - } - } - - if (prevProps.activeStreamingPhase !== nextProps.activeStreamingPhase) { - const messageId = prevEntry.message.info.id; - if (prevProps.activeStreamingMessageId === messageId || nextProps.activeStreamingMessageId === messageId) { - return false; - } - } - - return ( - areRenderRelevantMessagesEqual(prevEntry.message, nextEntry.message) - && areOptionalRenderRelevantMessagesEqual(prevEntry.previousMessage, nextEntry.previousMessage) - && areOptionalRenderRelevantMessagesEqual(prevEntry.nextMessage, nextEntry.nextMessage) - ); - } - - return false; -} - // Inner component that renders staged turn entries. const StaticHistoryList: React.FC<{ entries: RenderEntry[]; @@ -1028,7 +931,7 @@ const StaticHistoryList: React.FC<{ shouldAnimateUserMessage: (message: ChatMessageEntry) => boolean; onUserAnimationConsumed: (messageId: string) => void; activeStreamingPhase?: StreamPhase | null; -}> = React.memo(({ entries, shouldVirtualize, virtualRows, totalSize, measureElement, contentRef, onMessageContentChange, getAnimationHandlers, scrollToBottom, stickyUserHeader, defaultActivityExpanded, turnUiStates, onToggleTurnGroup, chatRenderMode, shouldAnimateUserMessage, onUserAnimationConsumed, activeStreamingPhase }) => { +}> = ({ entries, shouldVirtualize, virtualRows, totalSize, measureElement, contentRef, onMessageContentChange, getAnimationHandlers, scrollToBottom, stickyUserHeader, defaultActivityExpanded, turnUiStates, onToggleTurnGroup, chatRenderMode, shouldAnimateUserMessage, onUserAnimationConsumed, activeStreamingPhase }) => { const renderEntry = React.useCallback((entry: RenderEntry) => { return ( 0 ? ); -}, (prevProps, nextProps) => { - return prevProps.entries === nextProps.entries - && prevProps.shouldVirtualize === nextProps.shouldVirtualize - && prevProps.virtualRows === nextProps.virtualRows - && prevProps.totalSize === nextProps.totalSize - && prevProps.measureElement === nextProps.measureElement - && prevProps.contentRef === nextProps.contentRef - && prevProps.onMessageContentChange === nextProps.onMessageContentChange - && prevProps.getAnimationHandlers === nextProps.getAnimationHandlers - && prevProps.scrollToBottom === nextProps.scrollToBottom - && prevProps.stickyUserHeader === nextProps.stickyUserHeader - && prevProps.defaultActivityExpanded === nextProps.defaultActivityExpanded - && prevProps.turnUiStates === nextProps.turnUiStates - && prevProps.onToggleTurnGroup === nextProps.onToggleTurnGroup - && prevProps.chatRenderMode === nextProps.chatRenderMode - && prevProps.shouldAnimateUserMessage === nextProps.shouldAnimateUserMessage - && prevProps.onUserAnimationConsumed === nextProps.onUserAnimationConsumed - && prevProps.activeStreamingPhase === nextProps.activeStreamingPhase; -}); +}; StaticHistoryList.displayName = 'StaticHistoryList'; @@ -1133,7 +1018,7 @@ const StreamingTailContent: React.FC<{ onUserAnimationConsumed: (messageId: string) => void; activeStreamingMessageId?: string | null; activeStreamingPhase?: StreamPhase | null; -}> = React.memo(({ +}> = ({ entry, onMessageContentChange, getAnimationHandlers, @@ -1167,22 +1052,7 @@ const StreamingTailContent: React.FC<{ activeStreamingPhase={activeStreamingPhase} /> ); -}, (prev, next) => { - return prev.entry === next.entry - && prev.onMessageContentChange === next.onMessageContentChange - && prev.getAnimationHandlers === next.getAnimationHandlers - && prev.scrollToBottom === next.scrollToBottom - && prev.stickyUserHeader === next.stickyUserHeader - && prev.sessionIsWorking === next.sessionIsWorking - && prev.defaultActivityExpanded === next.defaultActivityExpanded - && prev.turnUiStates === next.turnUiStates - && prev.onToggleTurnGroup === next.onToggleTurnGroup - && prev.chatRenderMode === next.chatRenderMode - && prev.shouldAnimateUserMessage === next.shouldAnimateUserMessage - && prev.onUserAnimationConsumed === next.onUserAnimationConsumed - && prev.activeStreamingMessageId === next.activeStreamingMessageId - && prev.activeStreamingPhase === next.activeStreamingPhase; -}); +}; StreamingTailContent.displayName = 'StreamingTailContent'; diff --git a/packages/ui/src/components/chat/message/MessageBody.tsx b/packages/ui/src/components/chat/message/MessageBody.tsx index 93e1bb1f..d8d5bea0 100644 --- a/packages/ui/src/components/chat/message/MessageBody.tsx +++ b/packages/ui/src/components/chat/message/MessageBody.tsx @@ -35,7 +35,6 @@ import { ToolRevealOnMount } from './parts/ToolRevealOnMount'; import { StaticToolRow } from './parts/ProgressiveGroup'; import { isExpandableTool, isStandaloneTool } from './parts/toolRenderUtils'; import TurnActivity from '../components/TurnActivity'; -import { areRenderRelevantPartsEqual } from './renderCompare'; type SubtaskPartLike = Part & { type: 'subtask'; @@ -1549,37 +1548,4 @@ const MessageBody: React.FC = ({ isUser, ...props }) => { return ; }; -export default React.memo(MessageBody, (prev, next) => { - return prev.sessionId === next.sessionId - && prev.messageId === next.messageId - && prev.isUser === next.isUser - && areRenderRelevantPartsEqual(prev.parts, next.parts) - && prev.isMessageCompleted === next.isMessageCompleted - && prev.messageFinish === next.messageFinish - && prev.messageCompletedAt === next.messageCompletedAt - && prev.messageCreatedAt === next.messageCreatedAt - && prev.syntaxTheme === next.syntaxTheme - && prev.isMobile === next.isMobile - && prev.hasTouchInput === next.hasTouchInput - && prev.copiedCode === next.copiedCode - && prev.expandedTools === next.expandedTools - && prev.streamPhase === next.streamPhase - && prev.allowAnimation === next.allowAnimation - && prev.shouldShowHeader === next.shouldShowHeader - && prev.hasTextContent === next.hasTextContent - && prev.copiedMessage === next.copiedMessage - && prev.showReasoningTraces === next.showReasoningTraces - && prev.agentMention === next.agentMention - && prev.turnGroupingContext === next.turnGroupingContext - && prev.errorMessage === next.errorMessage - && prev.userActionsMode === next.userActionsMode - && prev.stickyUserHeaderEnabled === next.stickyUserHeaderEnabled - && prev.onCopyCode === next.onCopyCode - && prev.onToggleTool === next.onToggleTool - && prev.onShowPopup === next.onShowPopup - && prev.onContentChange === next.onContentChange - && prev.onCopyMessage === next.onCopyMessage - && prev.onAuxiliaryContentComplete === next.onAuxiliaryContentComplete - && prev.onRevert === next.onRevert - && prev.onFork === next.onFork; -}); +export default MessageBody;