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
|
// LLM Messages & Chat Messages
|
||||||
apiConversationHistory: ApiMessage[] = []
|
apiConversationHistory: ApiMessage[] = []
|
||||||
clineMessages: ClineMessage[] = []
|
clineMessages: ClineMessage[] = []
|
||||||
public pendingUserMessageCheckpoint?: Record<string, unknown>
|
|
||||||
|
|
||||||
// Ask
|
// Ask
|
||||||
private askResponse?: ClineAskResponse
|
private askResponse?: ClineAskResponse
|
||||||
|
|
@ -718,17 +717,13 @@ export class Task extends EventEmitter<ClineEvents> {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (type === "user_feedback") {
|
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({
|
await this.addToClineMessages({
|
||||||
ts: sayTs,
|
ts: sayTs,
|
||||||
type: "say",
|
type: "say",
|
||||||
say: type,
|
say: type,
|
||||||
text,
|
text,
|
||||||
images,
|
images,
|
||||||
checkpoint: feedbackCheckpoint,
|
checkpoint,
|
||||||
contextCondense,
|
contextCondense,
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
|
|
|
||||||
|
|
@ -87,7 +87,6 @@ interface PendingEditOperation {
|
||||||
images?: string[]
|
images?: string[]
|
||||||
messageIndex: number
|
messageIndex: number
|
||||||
apiConversationHistoryIndex: number
|
apiConversationHistoryIndex: number
|
||||||
originalCheckpoint: { hash: string }
|
|
||||||
timeoutId: NodeJS.Timeout
|
timeoutId: NodeJS.Timeout
|
||||||
createdAt: number
|
createdAt: number
|
||||||
}
|
}
|
||||||
|
|
@ -268,7 +267,6 @@ export class ClineProvider
|
||||||
images?: string[]
|
images?: string[]
|
||||||
messageIndex: number
|
messageIndex: number
|
||||||
apiConversationHistoryIndex: number
|
apiConversationHistoryIndex: number
|
||||||
originalCheckpoint: { hash: string }
|
|
||||||
},
|
},
|
||||||
): void {
|
): void {
|
||||||
// Clear any existing operation with the same ID
|
// 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
|
// Process the edited message
|
||||||
await cline.handleWebviewAskResponse(
|
await cline.handleWebviewAskResponse(
|
||||||
"messageResponse",
|
"messageResponse",
|
||||||
|
|
|
||||||
|
|
@ -134,7 +134,6 @@ describe("checkpointRestoreHandler", () => {
|
||||||
images: ["image1.png"],
|
images: ["image1.png"],
|
||||||
messageIndex: 2,
|
messageIndex: 2,
|
||||||
apiConversationHistoryIndex: 2,
|
apiConversationHistoryIndex: 2,
|
||||||
originalCheckpoint: { hash: "abc123" },
|
|
||||||
})
|
})
|
||||||
|
|
||||||
// Verify checkpoint restore was called with edit operation
|
// Verify checkpoint restore was called with edit operation
|
||||||
|
|
|
||||||
|
|
@ -27,21 +27,14 @@ describe("webviewMessageHandler - checkpoint operations", () => {
|
||||||
taskId: "test-task-123",
|
taskId: "test-task-123",
|
||||||
clineMessages: [
|
clineMessages: [
|
||||||
{ ts: 1, type: "user", say: "user", text: "First message" },
|
{ ts: 1, type: "user", say: "user", text: "First message" },
|
||||||
{ ts: 2, type: "assistant", say: "assistant", text: "Response" },
|
{ ts: 2, type: "assistant", say: "checkpoint_saved", text: "abc123" },
|
||||||
{
|
{ ts: 3, type: "user", say: "user", text: "Message to delete" },
|
||||||
ts: 3,
|
{ ts: 4, type: "assistant", say: "assistant", text: "After message" },
|
||||||
type: "user",
|
|
||||||
say: "user",
|
|
||||||
text: "Checkpoint message",
|
|
||||||
checkpoint: { hash: "abc123" },
|
|
||||||
},
|
|
||||||
{ ts: 4, type: "assistant", say: "assistant", text: "After checkpoint" },
|
|
||||||
],
|
],
|
||||||
apiConversationHistory: [
|
apiConversationHistory: [
|
||||||
{ ts: 1, role: "user", content: [{ type: "text", text: "First message" }] },
|
{ 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: "Message to delete" }] },
|
||||||
{ ts: 3, role: "user", content: [{ type: "text", text: "Checkpoint message" }] },
|
{ ts: 4, role: "assistant", content: [{ type: "text", text: "After message" }] },
|
||||||
{ ts: 4, role: "assistant", content: [{ type: "text", text: "After checkpoint" }] },
|
|
||||||
],
|
],
|
||||||
checkpointRestore: vi.fn(),
|
checkpointRestore: vi.fn(),
|
||||||
overwriteClineMessages: vi.fn(),
|
overwriteClineMessages: vi.fn(),
|
||||||
|
|
@ -130,7 +123,7 @@ describe("webviewMessageHandler - checkpoint operations", () => {
|
||||||
editData: {
|
editData: {
|
||||||
editedContent: "Edited checkpoint message",
|
editedContent: "Edited checkpoint message",
|
||||||
images: undefined,
|
images: undefined,
|
||||||
apiConversationHistoryIndex: 2,
|
apiConversationHistoryIndex: 1,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
|
||||||
|
|
@ -51,7 +51,6 @@ export async function handleCheckpointRestoreOperation(config: CheckpointRestore
|
||||||
images: editData.images,
|
images: editData.images,
|
||||||
messageIndex: config.messageIndex,
|
messageIndex: config.messageIndex,
|
||||||
apiConversationHistoryIndex: editData.apiConversationHistoryIndex,
|
apiConversationHistoryIndex: editData.apiConversationHistoryIndex,
|
||||||
originalCheckpoint: checkpoint,
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -102,18 +102,18 @@ export const webviewMessageHandler = async (
|
||||||
* Handles message deletion operations with user confirmation
|
* Handles message deletion operations with user confirmation
|
||||||
*/
|
*/
|
||||||
const handleDeleteOperation = async (messageTs: number): Promise<void> => {
|
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()
|
const currentCline = provider.getCurrentCline()
|
||||||
let hasCheckpoint = false
|
let hasCheckpoint = false
|
||||||
if (currentCline) {
|
if (currentCline) {
|
||||||
const { messageIndex } = findMessageIndices(messageTs, currentCline)
|
const { messageIndex } = findMessageIndices(messageTs, currentCline)
|
||||||
if (messageIndex !== -1) {
|
if (messageIndex !== -1) {
|
||||||
const targetMessage = currentCline.clineMessages[messageIndex]
|
// Find the last checkpoint before this message
|
||||||
hasCheckpoint = !!(
|
const checkpoints = currentCline.clineMessages
|
||||||
targetMessage?.checkpoint &&
|
.filter((msg) => msg.say === "checkpoint_saved" && msg.ts < messageTs)
|
||||||
typeof targetMessage.checkpoint === "object" &&
|
.sort((a, b) => b.ts - a.ts)
|
||||||
"hash" in targetMessage.checkpoint
|
|
||||||
)
|
hasCheckpoint = checkpoints.length > 0
|
||||||
} else {
|
} else {
|
||||||
console.log("[webviewMessageHandler] Message not found! Looking for ts:", messageTs)
|
console.log("[webviewMessageHandler] Message not found! Looking for ts:", messageTs)
|
||||||
}
|
}
|
||||||
|
|
@ -149,16 +149,29 @@ export const webviewMessageHandler = async (
|
||||||
try {
|
try {
|
||||||
const targetMessage = currentCline.clineMessages[messageIndex]
|
const targetMessage = currentCline.clineMessages[messageIndex]
|
||||||
|
|
||||||
// If checkpoint restoration is requested, restore to the checkpoint first
|
// If checkpoint restoration is requested, find and restore to the last checkpoint before this message
|
||||||
if (restoreCheckpoint && hasValidCheckpoint(targetMessage)) {
|
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({
|
await handleCheckpointRestoreOperation({
|
||||||
provider,
|
provider,
|
||||||
currentCline,
|
currentCline,
|
||||||
messageTs: targetMessage.ts!,
|
messageTs: targetMessage.ts!,
|
||||||
messageIndex,
|
messageIndex,
|
||||||
checkpoint: targetMessage.checkpoint as ValidCheckpoint,
|
checkpoint: { hash: lastCheckpoint.text },
|
||||||
operation: "delete",
|
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 {
|
} else {
|
||||||
// For non-checkpoint deletes, preserve checkpoint associations for remaining messages
|
// For non-checkpoint deletes, preserve checkpoint associations for remaining messages
|
||||||
// Store checkpoints from messages that will be preserved
|
// Store checkpoints from messages that will be preserved
|
||||||
|
|
@ -200,34 +213,25 @@ export const webviewMessageHandler = async (
|
||||||
* Handles message editing operations with user confirmation
|
* Handles message editing operations with user confirmation
|
||||||
*/
|
*/
|
||||||
const handleEditOperation = async (messageTs: number, editedContent: string, images?: string[]): Promise<void> => {
|
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()
|
const currentCline = provider.getCurrentCline()
|
||||||
let hasCheckpoint = false
|
let hasCheckpoint = false
|
||||||
if (currentCline) {
|
if (currentCline) {
|
||||||
const { messageIndex } = findMessageIndices(messageTs, currentCline)
|
const { messageIndex } = findMessageIndices(messageTs, currentCline)
|
||||||
if (messageIndex !== -1) {
|
if (messageIndex !== -1) {
|
||||||
const targetMessage = currentCline.clineMessages[messageIndex]
|
// Find the last checkpoint before this message
|
||||||
hasCheckpoint = !!(
|
const checkpoints = currentCline.clineMessages
|
||||||
targetMessage?.checkpoint &&
|
.filter((msg) => msg.say === "checkpoint_saved" && msg.ts < messageTs)
|
||||||
typeof targetMessage.checkpoint === "object" &&
|
.sort((a, b) => b.ts - a.ts)
|
||||||
"hash" in targetMessage.checkpoint
|
|
||||||
)
|
hasCheckpoint = checkpoints.length > 0
|
||||||
} else {
|
} else {
|
||||||
console.log("[webviewMessageHandler] Edit - Message not found in clineMessages!")
|
console.log("[webviewMessageHandler] Edit - Message not found in clineMessages!")
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
console.log("[webviewMessageHandler] Edit - No currentCline available!")
|
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
|
// Send message to webview to show edit confirmation dialog
|
||||||
await provider.postMessageToWebview({
|
await provider.postMessageToWebview({
|
||||||
type: "showEditMessageDialog",
|
type: "showEditMessageDialog",
|
||||||
|
|
@ -237,7 +241,6 @@ export const webviewMessageHandler = async (
|
||||||
images,
|
images,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handles confirmed message editing from webview dialog
|
* Handles confirmed message editing from webview dialog
|
||||||
|
|
@ -267,17 +270,22 @@ export const webviewMessageHandler = async (
|
||||||
try {
|
try {
|
||||||
const targetMessage = currentCline.clineMessages[messageIndex]
|
const targetMessage = currentCline.clineMessages[messageIndex]
|
||||||
|
|
||||||
// Preserve the original checkpoint data for the edited message
|
// If checkpoint restoration is requested, find and restore to the last checkpoint before this message
|
||||||
const originalCheckpoint = targetMessage?.checkpoint
|
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
|
const lastCheckpoint = checkpoints[0]
|
||||||
if (restoreCheckpoint && hasValidCheckpoint(targetMessage)) {
|
|
||||||
|
if (lastCheckpoint && lastCheckpoint.text) {
|
||||||
await handleCheckpointRestoreOperation({
|
await handleCheckpointRestoreOperation({
|
||||||
provider,
|
provider,
|
||||||
currentCline,
|
currentCline,
|
||||||
messageTs: targetMessage.ts!,
|
messageTs: targetMessage.ts!,
|
||||||
messageIndex,
|
messageIndex,
|
||||||
checkpoint: targetMessage.checkpoint as ValidCheckpoint,
|
checkpoint: { hash: lastCheckpoint.text },
|
||||||
operation: "edit",
|
operation: "edit",
|
||||||
editData: {
|
editData: {
|
||||||
editedContent,
|
editedContent,
|
||||||
|
|
@ -288,6 +296,12 @@ export const webviewMessageHandler = async (
|
||||||
// The task will be cancelled and reinitialized by checkpointRestore
|
// The task will be cancelled and reinitialized by checkpointRestore
|
||||||
// The pending edit will be processed in the reinitialized task
|
// The pending edit will be processed in the reinitialized task
|
||||||
return
|
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
|
// 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
|
// 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, {
|
webviewMessageHandler(provider, {
|
||||||
type: "askResponse",
|
type: "askResponse",
|
||||||
askResponse: "messageResponse",
|
askResponse: "messageResponse",
|
||||||
|
|
@ -495,25 +503,7 @@ export const webviewMessageHandler = async (
|
||||||
await provider.postStateToWebview()
|
await provider.postStateToWebview()
|
||||||
break
|
break
|
||||||
case "askResponse":
|
case "askResponse":
|
||||||
// Save checkpoint BEFORE processing the user message if checkpoints are enabled
|
provider.getCurrentCline()?.handleWebviewAskResponse(message.askResponse!, message.text, message.images)
|
||||||
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)
|
|
||||||
break
|
break
|
||||||
case "autoCondenseContext":
|
case "autoCondenseContext":
|
||||||
await updateGlobalState("autoCondenseContext", message.bool)
|
await updateGlobalState("autoCondenseContext", message.bool)
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue