Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 40 additions & 10 deletions webview-ui/src/components/chat/ChatRow.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,11 @@ interface ChatRowProps {
onFollowUpUnmount?: () => void
isFollowUpAnswered?: boolean
editable?: boolean
lastCheckpointInfo?: {
ts: number
commitHash: string
checkpoint?: Record<string, unknown>
} | null
}

// eslint-disable-next-line @typescript-eslint/no-empty-object-type
Expand All @@ -74,7 +79,7 @@ const ChatRow = memo(

const [chatrow, { height }] = useSize(
<div className="px-[15px] py-[10px] pr-[6px]">
<ChatRowContent {...props} />
<ChatRowWithCheckpoint {...props} />
</div>,
)

Expand Down Expand Up @@ -114,7 +119,7 @@ export const ChatRowContent = ({
editable,
}: ChatRowContentProps) => {
const { t } = useTranslation()
const { mcpServers, alwaysAllowMcp, currentCheckpoint, mode } = useExtensionState()
const { mcpServers, alwaysAllowMcp, currentCheckpoint: _currentCheckpoint, mode } = useExtensionState()
const [reasoningCollapsed, setReasoningCollapsed] = useState(true)
const [isDiffErrorExpanded, setIsDiffErrorExpanded] = useState(false)
const [showCopySuccess, setShowCopySuccess] = useState(false)
Expand Down Expand Up @@ -1157,14 +1162,8 @@ export const ChatRowContent = ({
case "shell_integration_warning":
return <CommandExecutionError />
case "checkpoint_saved":
return (
<CheckpointSaved
ts={message.ts!}
commitHash={message.text!}
currentHash={currentCheckpoint}
checkpoint={message.checkpoint}
/>
)
// Don't render the checkpoint_saved message itself
return null
case "condense_context":
if (message.partial) {
return <CondensingContextRow />
Expand Down Expand Up @@ -1346,3 +1345,34 @@ export const ChatRowContent = ({
}
}
}

// Create a wrapper component to handle the checkpoint UI
export const ChatRowWithCheckpoint: React.FC<ChatRowContentProps> = (props) => {
const { message, lastCheckpointInfo } = props
const { currentCheckpoint } = useExtensionState()

// Render the regular content
const content = <ChatRowContent {...props} />

// Check if we should show checkpoint UI
const shouldShowCheckpoint =
lastCheckpointInfo && message.ts > lastCheckpointInfo.ts && message.say !== "checkpoint_saved"

if (shouldShowCheckpoint) {
return (
<>
{content}
<div className="mt-2">
<CheckpointSaved
ts={lastCheckpointInfo.ts}
commitHash={lastCheckpointInfo.commitHash}
currentHash={currentCheckpoint}
checkpoint={lastCheckpointInfo.checkpoint}
/>
</div>
</>
)
}

return content
}
15 changes: 15 additions & 0 deletions webview-ui/src/components/chat/ChatView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,19 @@ const ChatViewComponent: React.ForwardRefRenderFunction<ChatViewRef, ChatViewPro
return getLatestTodo(messages)
}, [messages])

// Track the last checkpoint message - optimized to only recalculate when checkpoint messages change
const checkpointMessages = useMemo(() => messages.filter((msg) => msg.say === "checkpoint_saved"), [messages])
const lastCheckpointInfo = useMemo(() => {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Performance consideration: This recalculates on every render when any message changes. Since checkpoint messages are relatively rare, could we optimize this by only recalculating when messages with are added? Perhaps we could track the last checkpoint info in a ref and only update it when needed?

if (checkpointMessages.length === 0) return null

const lastCheckpoint = checkpointMessages[checkpointMessages.length - 1]
return {
ts: lastCheckpoint.ts,
commitHash: lastCheckpoint.text || "",
checkpoint: lastCheckpoint.checkpoint,
}
}, [checkpointMessages])

const modifiedMessages = useMemo(() => combineApiRequests(combineCommandSequences(messages.slice(1))), [messages])

// Has to be after api_req_finished are all reduced into api_req_started messages.
Expand Down Expand Up @@ -1398,6 +1411,7 @@ const ChatViewComponent: React.ForwardRefRenderFunction<ChatViewRef, ChatViewPro
onBatchFileResponse={handleBatchFileResponse}
onFollowUpUnmount={handleFollowUpUnmount}
isFollowUpAnswered={messageOrGroup.ts === currentFollowUpTs}
lastCheckpointInfo={lastCheckpointInfo}
editable={
messageOrGroup.type === "ask" &&
messageOrGroup.ask === "tool" &&
Expand Down Expand Up @@ -1433,6 +1447,7 @@ const ChatViewComponent: React.ForwardRefRenderFunction<ChatViewRef, ChatViewPro
alwaysAllowUpdateTodoList,
enableButtons,
primaryButtonText,
lastCheckpointInfo,
],
)

Expand Down