mirror of
https://github.com/RooVetGit/Roo-Code.git
synced 2026-08-28 05:27:24 +00:00
reduce checkpoint changes
This commit is contained in:
parent
ab46f94c26
commit
7baefefec6
6 changed files with 85 additions and 116 deletions
|
|
@ -181,7 +181,6 @@ export class Task extends EventEmitter<ClineEvents> {
|
|||
// LLM Messages & Chat Messages
|
||||
apiConversationHistory: ApiMessage[] = []
|
||||
clineMessages: ClineMessage[] = []
|
||||
public pendingUserMessageCheckpoint?: Record<string, unknown>
|
||||
|
||||
// Ask
|
||||
private askResponse?: ClineAskResponse
|
||||
|
|
@ -718,17 +717,13 @@ export class Task extends EventEmitter<ClineEvents> {
|
|||
}
|
||||
|
||||
if (type === "user_feedback") {
|
||||
// Automatically use and clear the pending checkpoint for user_feedback messages
|
||||
const feedbackCheckpoint = checkpoint || this.pendingUserMessageCheckpoint
|
||||
this.pendingUserMessageCheckpoint = undefined // Clear it after use
|
||||
|
||||
await this.addToClineMessages({
|
||||
ts: sayTs,
|
||||
type: "say",
|
||||
say: type,
|
||||
text,
|
||||
images,
|
||||
checkpoint: feedbackCheckpoint,
|
||||
checkpoint,
|
||||
contextCondense,
|
||||
})
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -87,7 +87,6 @@ interface PendingEditOperation {
|
|||
images?: string[]
|
||||
messageIndex: number
|
||||
apiConversationHistoryIndex: number
|
||||
originalCheckpoint: { hash: string }
|
||||
timeoutId: NodeJS.Timeout
|
||||
createdAt: number
|
||||
}
|
||||
|
|
@ -268,7 +267,6 @@ export class ClineProvider
|
|||
images?: string[]
|
||||
messageIndex: number
|
||||
apiConversationHistoryIndex: number
|
||||
originalCheckpoint: { hash: string }
|
||||
},
|
||||
): void {
|
||||
// Clear any existing operation with the same ID
|
||||
|
|
@ -720,11 +718,6 @@ export class ClineProvider
|
|||
)
|
||||
}
|
||||
|
||||
// If there was an original checkpoint, preserve it for the new message
|
||||
if (pendingEdit.originalCheckpoint) {
|
||||
cline.pendingUserMessageCheckpoint = pendingEdit.originalCheckpoint
|
||||
}
|
||||
|
||||
// Process the edited message
|
||||
await cline.handleWebviewAskResponse(
|
||||
"messageResponse",
|
||||
|
|
|
|||
|
|
@ -134,7 +134,6 @@ describe("checkpointRestoreHandler", () => {
|
|||
images: ["image1.png"],
|
||||
messageIndex: 2,
|
||||
apiConversationHistoryIndex: 2,
|
||||
originalCheckpoint: { hash: "abc123" },
|
||||
})
|
||||
|
||||
// Verify checkpoint restore was called with edit operation
|
||||
|
|
|
|||
|
|
@ -27,21 +27,14 @@ describe("webviewMessageHandler - checkpoint operations", () => {
|
|||
taskId: "test-task-123",
|
||||
clineMessages: [
|
||||
{ ts: 1, type: "user", say: "user", text: "First message" },
|
||||
{ ts: 2, type: "assistant", say: "assistant", text: "Response" },
|
||||
{
|
||||
ts: 3,
|
||||
type: "user",
|
||||
say: "user",
|
||||
text: "Checkpoint message",
|
||||
checkpoint: { hash: "abc123" },
|
||||
},
|
||||
{ ts: 4, type: "assistant", say: "assistant", text: "After checkpoint" },
|
||||
{ ts: 2, type: "assistant", say: "checkpoint_saved", text: "abc123" },
|
||||
{ ts: 3, type: "user", say: "user", text: "Message to delete" },
|
||||
{ ts: 4, type: "assistant", say: "assistant", text: "After message" },
|
||||
],
|
||||
apiConversationHistory: [
|
||||
{ ts: 1, role: "user", content: [{ type: "text", text: "First message" }] },
|
||||
{ ts: 2, role: "assistant", content: [{ type: "text", text: "Response" }] },
|
||||
{ ts: 3, role: "user", content: [{ type: "text", text: "Checkpoint message" }] },
|
||||
{ ts: 4, role: "assistant", content: [{ type: "text", text: "After checkpoint" }] },
|
||||
{ ts: 3, role: "user", content: [{ type: "text", text: "Message to delete" }] },
|
||||
{ ts: 4, role: "assistant", content: [{ type: "text", text: "After message" }] },
|
||||
],
|
||||
checkpointRestore: vi.fn(),
|
||||
overwriteClineMessages: vi.fn(),
|
||||
|
|
@ -130,7 +123,7 @@ describe("webviewMessageHandler - checkpoint operations", () => {
|
|||
editData: {
|
||||
editedContent: "Edited checkpoint message",
|
||||
images: undefined,
|
||||
apiConversationHistoryIndex: 2,
|
||||
apiConversationHistoryIndex: 1,
|
||||
},
|
||||
})
|
||||
})
|
||||
|
|
|
|||
|
|
@ -51,7 +51,6 @@ export async function handleCheckpointRestoreOperation(config: CheckpointRestore
|
|||
images: editData.images,
|
||||
messageIndex: config.messageIndex,
|
||||
apiConversationHistoryIndex: editData.apiConversationHistoryIndex,
|
||||
originalCheckpoint: checkpoint,
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -102,18 +102,18 @@ export const webviewMessageHandler = async (
|
|||
* Handles message deletion operations with user confirmation
|
||||
*/
|
||||
const handleDeleteOperation = async (messageTs: number): Promise<void> => {
|
||||
// Check if the message has a checkpoint
|
||||
// Check if there's a checkpoint before this message
|
||||
const currentCline = provider.getCurrentCline()
|
||||
let hasCheckpoint = false
|
||||
if (currentCline) {
|
||||
const { messageIndex } = findMessageIndices(messageTs, currentCline)
|
||||
if (messageIndex !== -1) {
|
||||
const targetMessage = currentCline.clineMessages[messageIndex]
|
||||
hasCheckpoint = !!(
|
||||
targetMessage?.checkpoint &&
|
||||
typeof targetMessage.checkpoint === "object" &&
|
||||
"hash" in targetMessage.checkpoint
|
||||
)
|
||||
// Find the last checkpoint before this message
|
||||
const checkpoints = currentCline.clineMessages
|
||||
.filter((msg) => msg.say === "checkpoint_saved" && msg.ts < messageTs)
|
||||
.sort((a, b) => b.ts - a.ts)
|
||||
|
||||
hasCheckpoint = checkpoints.length > 0
|
||||
} else {
|
||||
console.log("[webviewMessageHandler] Message not found! Looking for ts:", messageTs)
|
||||
}
|
||||
|
|
@ -149,16 +149,29 @@ export const webviewMessageHandler = async (
|
|||
try {
|
||||
const targetMessage = currentCline.clineMessages[messageIndex]
|
||||
|
||||
// If checkpoint restoration is requested, restore to the checkpoint first
|
||||
if (restoreCheckpoint && hasValidCheckpoint(targetMessage)) {
|
||||
await handleCheckpointRestoreOperation({
|
||||
provider,
|
||||
currentCline,
|
||||
messageTs: targetMessage.ts!,
|
||||
messageIndex,
|
||||
checkpoint: targetMessage.checkpoint as ValidCheckpoint,
|
||||
operation: "delete",
|
||||
})
|
||||
// If checkpoint restoration is requested, find and restore to the last checkpoint before this message
|
||||
if (restoreCheckpoint) {
|
||||
// Find the last checkpoint before this message
|
||||
const checkpoints = currentCline.clineMessages
|
||||
.filter((msg) => msg.say === "checkpoint_saved" && msg.ts < messageTs)
|
||||
.sort((a, b) => b.ts - a.ts)
|
||||
|
||||
const lastCheckpoint = checkpoints[0]
|
||||
|
||||
if (lastCheckpoint && lastCheckpoint.text) {
|
||||
await handleCheckpointRestoreOperation({
|
||||
provider,
|
||||
currentCline,
|
||||
messageTs: targetMessage.ts!,
|
||||
messageIndex,
|
||||
checkpoint: { hash: lastCheckpoint.text },
|
||||
operation: "delete",
|
||||
})
|
||||
} else {
|
||||
// No checkpoint found before this message
|
||||
console.log("[handleDeleteMessageConfirm] No checkpoint found before message")
|
||||
vscode.window.showWarningMessage("No checkpoint found before this message")
|
||||
}
|
||||
} else {
|
||||
// For non-checkpoint deletes, preserve checkpoint associations for remaining messages
|
||||
// Store checkpoints from messages that will be preserved
|
||||
|
|
@ -200,43 +213,33 @@ export const webviewMessageHandler = async (
|
|||
* Handles message editing operations with user confirmation
|
||||
*/
|
||||
const handleEditOperation = async (messageTs: number, editedContent: string, images?: string[]): Promise<void> => {
|
||||
// Always check if the message has a checkpoint first
|
||||
// Check if there's a checkpoint before this message
|
||||
const currentCline = provider.getCurrentCline()
|
||||
let hasCheckpoint = false
|
||||
if (currentCline) {
|
||||
const { messageIndex } = findMessageIndices(messageTs, currentCline)
|
||||
if (messageIndex !== -1) {
|
||||
const targetMessage = currentCline.clineMessages[messageIndex]
|
||||
hasCheckpoint = !!(
|
||||
targetMessage?.checkpoint &&
|
||||
typeof targetMessage.checkpoint === "object" &&
|
||||
"hash" in targetMessage.checkpoint
|
||||
)
|
||||
// Find the last checkpoint before this message
|
||||
const checkpoints = currentCline.clineMessages
|
||||
.filter((msg) => msg.say === "checkpoint_saved" && msg.ts < messageTs)
|
||||
.sort((a, b) => b.ts - a.ts)
|
||||
|
||||
hasCheckpoint = checkpoints.length > 0
|
||||
} else {
|
||||
console.log("[webviewMessageHandler] Edit - Message not found in clineMessages!")
|
||||
}
|
||||
} else {
|
||||
console.log("[webviewMessageHandler] Edit - No currentCline available!")
|
||||
}
|
||||
// If there's a checkpoint, show the checkpoint dialog even when skipping confirmation
|
||||
if (hasCheckpoint) {
|
||||
await provider.postMessageToWebview({
|
||||
type: "showEditMessageDialog",
|
||||
messageTs,
|
||||
text: editedContent,
|
||||
hasCheckpoint,
|
||||
images,
|
||||
})
|
||||
} else {
|
||||
// Send message to webview to show edit confirmation dialog
|
||||
await provider.postMessageToWebview({
|
||||
type: "showEditMessageDialog",
|
||||
messageTs,
|
||||
text: editedContent,
|
||||
hasCheckpoint,
|
||||
images,
|
||||
})
|
||||
}
|
||||
|
||||
// Send message to webview to show edit confirmation dialog
|
||||
await provider.postMessageToWebview({
|
||||
type: "showEditMessageDialog",
|
||||
messageTs,
|
||||
text: editedContent,
|
||||
hasCheckpoint,
|
||||
images,
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -267,27 +270,38 @@ export const webviewMessageHandler = async (
|
|||
try {
|
||||
const targetMessage = currentCline.clineMessages[messageIndex]
|
||||
|
||||
// Preserve the original checkpoint data for the edited message
|
||||
const originalCheckpoint = targetMessage?.checkpoint
|
||||
// If checkpoint restoration is requested, find and restore to the last checkpoint before this message
|
||||
if (restoreCheckpoint) {
|
||||
// Find the last checkpoint before this message
|
||||
const checkpoints = currentCline.clineMessages
|
||||
.filter((msg) => msg.say === "checkpoint_saved" && msg.ts < messageTs)
|
||||
.sort((a, b) => b.ts - a.ts)
|
||||
|
||||
// If checkpoint restoration is requested, restore to the checkpoint first
|
||||
if (restoreCheckpoint && hasValidCheckpoint(targetMessage)) {
|
||||
await handleCheckpointRestoreOperation({
|
||||
provider,
|
||||
currentCline,
|
||||
messageTs: targetMessage.ts!,
|
||||
messageIndex,
|
||||
checkpoint: targetMessage.checkpoint as ValidCheckpoint,
|
||||
operation: "edit",
|
||||
editData: {
|
||||
editedContent,
|
||||
images,
|
||||
apiConversationHistoryIndex,
|
||||
},
|
||||
})
|
||||
// The task will be cancelled and reinitialized by checkpointRestore
|
||||
// The pending edit will be processed in the reinitialized task
|
||||
return
|
||||
const lastCheckpoint = checkpoints[0]
|
||||
|
||||
if (lastCheckpoint && lastCheckpoint.text) {
|
||||
await handleCheckpointRestoreOperation({
|
||||
provider,
|
||||
currentCline,
|
||||
messageTs: targetMessage.ts!,
|
||||
messageIndex,
|
||||
checkpoint: { hash: lastCheckpoint.text },
|
||||
operation: "edit",
|
||||
editData: {
|
||||
editedContent,
|
||||
images,
|
||||
apiConversationHistoryIndex,
|
||||
},
|
||||
})
|
||||
// The task will be cancelled and reinitialized by checkpointRestore
|
||||
// The pending edit will be processed in the reinitialized task
|
||||
return
|
||||
} else {
|
||||
// No checkpoint found before this message
|
||||
console.log("[handleEditMessageConfirm] No checkpoint found before message")
|
||||
vscode.window.showWarningMessage("No checkpoint found before this message")
|
||||
// Continue with non-checkpoint edit
|
||||
}
|
||||
}
|
||||
|
||||
// For non-checkpoint edits, preserve checkpoint associations for remaining messages
|
||||
|
|
@ -319,12 +333,6 @@ export const webviewMessageHandler = async (
|
|||
})
|
||||
|
||||
// Process the edited message as a regular user message
|
||||
// Preserve the original checkpoint for the new message
|
||||
if (originalCheckpoint) {
|
||||
// Store the checkpoint to be attached to the new message
|
||||
currentCline.pendingUserMessageCheckpoint = originalCheckpoint
|
||||
}
|
||||
|
||||
webviewMessageHandler(provider, {
|
||||
type: "askResponse",
|
||||
askResponse: "messageResponse",
|
||||
|
|
@ -495,25 +503,7 @@ export const webviewMessageHandler = async (
|
|||
await provider.postStateToWebview()
|
||||
break
|
||||
case "askResponse":
|
||||
// Save checkpoint BEFORE processing the user message if checkpoints are enabled
|
||||
const currentCline = provider.getCurrentCline()
|
||||
if (currentCline && currentCline.enableCheckpoints && message.askResponse === "messageResponse") {
|
||||
try {
|
||||
const checkpointResult = await currentCline.checkpointSave(true) // Force checkpoint save
|
||||
if (checkpointResult?.commit) {
|
||||
// Store checkpoint data temporarily to be used when creating the user_feedback message
|
||||
currentCline.pendingUserMessageCheckpoint = {
|
||||
hash: checkpointResult.commit,
|
||||
timestamp: Date.now(),
|
||||
type: "user_message",
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("[webviewMessageHandler] Failed to save checkpoint before user message:", error)
|
||||
}
|
||||
}
|
||||
|
||||
currentCline?.handleWebviewAskResponse(message.askResponse!, message.text, message.images)
|
||||
provider.getCurrentCline()?.handleWebviewAskResponse(message.askResponse!, message.text, message.images)
|
||||
break
|
||||
case "autoCondenseContext":
|
||||
await updateGlobalState("autoCondenseContext", message.bool)
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue