Skip to content

Commit e9fdf23

Browse files
committed
feat: Show checkpoint button on all subsequent messages instead of creating new checkpoints
- Modified ChatView to track the last checkpoint info - Updated ChatRow to display checkpoint UI on all messages after a checkpoint - Created ChatRowWithCheckpoint wrapper component to handle checkpoint display logic - Removed rendering of checkpoint_saved messages themselves This change improves the UI by showing a persistent checkpoint button on all messages after a checkpoint is created, rather than creating new checkpoint messages after each interaction.
1 parent 7a6e852 commit e9fdf23

File tree

2 files changed

+60
-10
lines changed

2 files changed

+60
-10
lines changed

webview-ui/src/components/chat/ChatRow.tsx

Lines changed: 44 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,11 @@ interface ChatRowProps {
6060
onFollowUpUnmount?: () => void
6161
isFollowUpAnswered?: boolean
6262
editable?: boolean
63+
lastCheckpointInfo?: {
64+
ts: number
65+
commitHash: string
66+
checkpoint?: Record<string, unknown>
67+
} | null
6368
}
6469

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

7580
const [chatrow, { height }] = useSize(
7681
<div className="px-[15px] py-[10px] pr-[6px]">
77-
<ChatRowContent {...props} />
82+
<ChatRowWithCheckpoint {...props} />
7883
</div>,
7984
)
8085

@@ -112,9 +117,10 @@ export const ChatRowContent = ({
112117
onBatchFileResponse,
113118
isFollowUpAnswered,
114119
editable,
120+
lastCheckpointInfo: _lastCheckpointInfo,
115121
}: ChatRowContentProps) => {
116122
const { t } = useTranslation()
117-
const { mcpServers, alwaysAllowMcp, currentCheckpoint, mode } = useExtensionState()
123+
const { mcpServers, alwaysAllowMcp, currentCheckpoint: _currentCheckpoint, mode } = useExtensionState()
118124
const [reasoningCollapsed, setReasoningCollapsed] = useState(true)
119125
const [isDiffErrorExpanded, setIsDiffErrorExpanded] = useState(false)
120126
const [showCopySuccess, setShowCopySuccess] = useState(false)
@@ -1157,14 +1163,8 @@ export const ChatRowContent = ({
11571163
case "shell_integration_warning":
11581164
return <CommandExecutionError />
11591165
case "checkpoint_saved":
1160-
return (
1161-
<CheckpointSaved
1162-
ts={message.ts!}
1163-
commitHash={message.text!}
1164-
currentHash={currentCheckpoint}
1165-
checkpoint={message.checkpoint}
1166-
/>
1167-
)
1166+
// Don't render the checkpoint_saved message itself
1167+
return null
11681168
case "condense_context":
11691169
if (message.partial) {
11701170
return <CondensingContextRow />
@@ -1345,4 +1345,38 @@ export const ChatRowContent = ({
13451345
return null
13461346
}
13471347
}
1348+
1349+
// Default return for messages that don't match any case
1350+
return null
1351+
}
1352+
1353+
// Create a wrapper component to handle the checkpoint UI
1354+
export const ChatRowWithCheckpoint: React.FC<ChatRowContentProps> = (props) => {
1355+
const { message, lastCheckpointInfo } = props
1356+
const { currentCheckpoint } = useExtensionState()
1357+
1358+
// Render the regular content
1359+
const content = <ChatRowContent {...props} lastCheckpointInfo={null} />
1360+
1361+
// Check if we should show checkpoint UI
1362+
const shouldShowCheckpoint =
1363+
lastCheckpointInfo && message.ts > lastCheckpointInfo.ts && message.say !== "checkpoint_saved"
1364+
1365+
if (shouldShowCheckpoint) {
1366+
return (
1367+
<>
1368+
{content}
1369+
<div className="mt-2">
1370+
<CheckpointSaved
1371+
ts={lastCheckpointInfo.ts}
1372+
commitHash={lastCheckpointInfo.commitHash}
1373+
currentHash={currentCheckpoint}
1374+
checkpoint={lastCheckpointInfo.checkpoint}
1375+
/>
1376+
</div>
1377+
</>
1378+
)
1379+
}
1380+
1381+
return content
13481382
}

webview-ui/src/components/chat/ChatView.tsx

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,20 @@ const ChatViewComponent: React.ForwardRefRenderFunction<ChatViewRef, ChatViewPro
145145
return getLatestTodo(messages)
146146
}, [messages])
147147

148+
// Track the last checkpoint message
149+
const lastCheckpointInfo = useMemo(() => {
150+
// Find the last checkpoint_saved message
151+
const checkpointMessages = messages.filter((msg) => msg.say === "checkpoint_saved")
152+
if (checkpointMessages.length === 0) return null
153+
154+
const lastCheckpoint = checkpointMessages[checkpointMessages.length - 1]
155+
return {
156+
ts: lastCheckpoint.ts,
157+
commitHash: lastCheckpoint.text || "",
158+
checkpoint: lastCheckpoint.checkpoint,
159+
}
160+
}, [messages])
161+
148162
const modifiedMessages = useMemo(() => combineApiRequests(combineCommandSequences(messages.slice(1))), [messages])
149163

150164
// Has to be after api_req_finished are all reduced into api_req_started messages.
@@ -1398,6 +1412,7 @@ const ChatViewComponent: React.ForwardRefRenderFunction<ChatViewRef, ChatViewPro
13981412
onBatchFileResponse={handleBatchFileResponse}
13991413
onFollowUpUnmount={handleFollowUpUnmount}
14001414
isFollowUpAnswered={messageOrGroup.ts === currentFollowUpTs}
1415+
lastCheckpointInfo={lastCheckpointInfo}
14011416
editable={
14021417
messageOrGroup.type === "ask" &&
14031418
messageOrGroup.ask === "tool" &&
@@ -1433,6 +1448,7 @@ const ChatViewComponent: React.ForwardRefRenderFunction<ChatViewRef, ChatViewPro
14331448
alwaysAllowUpdateTodoList,
14341449
enableButtons,
14351450
primaryButtonText,
1451+
lastCheckpointInfo,
14361452
],
14371453
)
14381454

0 commit comments

Comments
 (0)