diff --git a/packages/ui/src/components/chat/MessageList.tsx b/packages/ui/src/components/chat/MessageList.tsx index 8e4f9531..bef3cbcf 100644 --- a/packages/ui/src/components/chat/MessageList.tsx +++ b/packages/ui/src/components/chat/MessageList.tsx @@ -3,6 +3,7 @@ import type { Part } from '@opencode-ai/sdk/v2'; import { LegendList, type LegendListRef } from '@legendapp/list/react'; import ChatMessage from './ChatMessage'; +import { filterVisibleParts, isEmptyTextPart } from './message/partUtils'; import { areOptionalRenderRelevantMessagesEqual, areRelevantTurnGroupingContextsEqual, areRenderRelevantMessagesEqual } from './message/renderCompare'; import TurnItem from './components/TurnItem'; import type { ChatMessageEntry, TurnRecord, TurnGroupingContext } from './lib/turns/types'; @@ -637,6 +638,9 @@ const TurnBlock = React.memo(({ activityOwnerMessageId, isFirstAssistantInTurn: isFirstAssistant, isLastAssistantInTurn: isLastAssistant, + hasEarlierAssistantText: chatRenderMode === 'live' && isLastAssistant && visibleAssistantMessages.some((assistant, index) => ( + index < assistantIndex && filterVisibleParts(assistant.parts).some((part) => part.type === 'text' && !isEmptyTextPart(part)) + )), isLatestTurn: isLastTurn, isWorking: isLastTurn && sessionIsWorking && ( chatRenderMode === 'sorted' diff --git a/packages/ui/src/components/chat/lib/turns/types.ts b/packages/ui/src/components/chat/lib/turns/types.ts index 1084c30b..67d837a9 100644 --- a/packages/ui/src/components/chat/lib/turns/types.ts +++ b/packages/ui/src/components/chat/lib/turns/types.ts @@ -115,6 +115,7 @@ export interface TurnGroupingContext { activityOwnerMessageId?: string; isFirstAssistantInTurn: boolean; isLastAssistantInTurn: boolean; + hasEarlierAssistantText?: boolean; isLatestTurn: boolean; summaryBody?: string; activityParts?: TurnActivityRecord[]; diff --git a/packages/ui/src/components/chat/message/MessageBody.tsx b/packages/ui/src/components/chat/message/MessageBody.tsx index 3d066526..beb09f6e 100644 --- a/packages/ui/src/components/chat/message/MessageBody.tsx +++ b/packages/ui/src/components/chat/message/MessageBody.tsx @@ -1730,6 +1730,17 @@ const AssistantMessageBody = React.memo(({ const renderedParts = React.useMemo(() => { const rendered: React.ReactNode[] = []; + let hasRenderedAnswerText = false; + const isFinalLiveAnswer = chatRenderMode === 'live' && isLastAssistantInTurn && hasStopFinish; + const hasEarlierVisibleActivity = isFinalLiveAnswer && Boolean(turnGroupingContext?.activityParts?.some((activity) => { + if (activity.messageId === messageId) { + return false; + } + if (activity.part.type === 'tool') { + return shouldShowTool(activity.part); + } + return (activity.kind !== 'reasoning' || showReasoningTraces) && !isEmptyTextPart(activity.part); + })); const renderSegmentBlock = (segment: TurnActivityGroup): React.ReactNode | null => { if (!shouldRenderActivityGroup || !toggleActivityGroup) { @@ -1820,6 +1831,16 @@ const AssistantMessageBody = React.memo(({ i += 1; continue; } + if (isFinalLiveAnswer && !hasRenderedAnswerText && (rendered.length > 0 || hasEarlierVisibleActivity || turnGroupingContext?.hasEarlierAssistantText)) { + rendered.push( +