Return auto-formatting in file edit responses to avoid invalid diff edit operations

This commit is contained in:
Saoud Rizwan 2024-12-31 16:06:41 -08:00
parent 66aaf646be
commit 69311f013c
3 changed files with 35 additions and 10 deletions

View file

@ -1168,7 +1168,7 @@ export class Cline {
pushToolResult(
formatResponse.toolError(
`${(error as Error)?.message}\n\n` +
`This is likely because the SEARCH block content doesn't match exactly with what's in the file.\n\n` +
`This is likely because the SEARCH block content doesn't match exactly with what's in the file, or if you used multiple SEARCH/REPLACE blocks they may not have been in the order they appear in the file.\n\n` +
`The file was reverted to its original state:\n\n` +
`<file_content path="${relPath.toPosix()}">\n${this.diffViewProvider.originalContent}\n</file_content>\n\n` +
`Try again with a more precise SEARCH block.\n(If you keep running into this error, you may use the write_to_file tool as a workaround.)`,
@ -1292,7 +1292,7 @@ export class Cline {
}
}
const { newProblemsMessage, userEdits, finalContent } =
const { newProblemsMessage, userEdits, autoFormattingEdits, finalContent } =
await this.diffViewProvider.saveChanges()
this.didEditFile = true // used to determine if we should wait for busy terminal to update before sending api request
if (userEdits) {
@ -1306,7 +1306,10 @@ export class Cline {
)
pushToolResult(
`The user made the following updates to your content:\n\n${userEdits}\n\n` +
`The updated content, which includes both your original modifications and the user's edits, has been successfully saved to ${relPath.toPosix()}. Here is the full, updated content of the file:\n\n` +
(autoFormattingEdits
? `The user's editor also applied the following auto-formatting to your content:\n\n${autoFormattingEdits}\n\n(Note: Pay close attention to changes such as single quotes being converted to double quotes, semicolons being removed or added, long lines being broken into multiple lines, adjusting indentation style, adding/removing trailing commas, etc. This will help you ensure future SEARCH/REPLACE operations to this file are accurate.)\n\n`
: "") +
`The updated content, which includes both your original modifications and the additional edits, has been successfully saved to ${relPath.toPosix()}. Here is the full, updated content of the file that was saved:\n\n` +
`<final_file_content path="${relPath.toPosix()}">\n${finalContent}\n</final_file_content>\n\n` +
`Please note:\n` +
`1. You do not need to re-write the file with these changes, as they have already been applied.\n` +
@ -1318,7 +1321,10 @@ export class Cline {
} else {
pushToolResult(
`The content was successfully saved to ${relPath.toPosix()}.\n\n` +
`Here is the full, updated content of the file:\n\n` +
(autoFormattingEdits
? `Along with your edits, the user's editor applied the following auto-formatting to your content:\n\n${autoFormattingEdits}\n\n(Note: Pay close attention to changes such as single quotes being converted to double quotes, semicolons being removed or added, long lines being broken into multiple lines, adjusting indentation style, adding/removing trailing commas, etc. This will help you ensure future SEARCH/REPLACE operations to this file are accurate.)\n\n`
: "") +
`Here is the full, updated content of the file that was saved:\n\n` +
`<final_file_content path="${relPath.toPosix()}">\n${finalContent}\n</final_file_content>\n\n` +
`IMPORTANT: For any future changes to this file, use the final_file_content shown above as your reference. This content reflects the current state of the file, including any auto-formatting (e.g., if you used single quotes but the formatter converted them to double quotes). Always base your SEARCH/REPLACE operations on this final version to ensure accuracy.\n\n` +
`${newProblemsMessage}`,

View file

@ -795,9 +795,8 @@ You have access to two tools for working with files: **write_to_file** and **rep
- After using either write_to_file or replace_in_file, the user's editor may automatically format the file
- This auto-formatting may modify the file contents, for example:
- Breaking single lines into multiple lines (e.g. long function declarations, object literals, array definitions)
- Breaking single lines into multiple lines
- Adjusting indentation to match project style (e.g. 2 spaces vs 4 spaces vs tabs)
- Standardizing spacing and line endings (e.g. removing extra whitespace, ensuring consistent newlines)
- Converting single quotes to double quotes (or vice versa based on project preferences)
- Organizing imports (e.g. sorting, grouping by type)
- Adding/removing trailing commas in objects and arrays

View file

@ -141,10 +141,16 @@ export class DiffViewProvider {
async saveChanges(): Promise<{
newProblemsMessage: string | undefined
userEdits: string | undefined
autoFormattingEdits: string | undefined
finalContent: string | undefined
}> {
if (!this.relPath || !this.newContent || !this.activeDiffEditor) {
return { newProblemsMessage: undefined, userEdits: undefined, finalContent: undefined }
return {
newProblemsMessage: undefined,
userEdits: undefined,
autoFormattingEdits: undefined,
finalContent: undefined,
}
}
const absolutePath = path.resolve(this.cwd, this.relPath)
const updatedDocument = this.activeDiffEditor.document
@ -197,18 +203,32 @@ export class DiffViewProvider {
const normalizedPostSaveContent = postSaveContent.replace(/\r\n|\n/g, newContentEOL).trimEnd() + newContentEOL // this is the final content we return to the model to use as the new baseline for future edits
// just in case the new content has a mix of varying EOL characters
const normalizedNewContent = this.newContent.replace(/\r\n|\n/g, newContentEOL).trimEnd() + newContentEOL
let userEdits: string | undefined
if (normalizedPreSaveContent !== normalizedNewContent) {
// user made changes before approving edit. let the model know about user made changes (not including post-save auto-formatting changes)
const userEdits = formatResponse.createPrettyPatch(
userEdits = formatResponse.createPrettyPatch(
this.relPath.toPosix(),
normalizedNewContent,
normalizedPreSaveContent,
)
return { newProblemsMessage, userEdits, finalContent: normalizedPostSaveContent }
// return { newProblemsMessage, userEdits, finalContent: normalizedPostSaveContent }
} else {
// no changes to cline's edits
return { newProblemsMessage, userEdits: undefined, finalContent: normalizedPostSaveContent }
// return { newProblemsMessage, userEdits: undefined, finalContent: normalizedPostSaveContent }
}
let autoFormattingEdits: string | undefined
if (normalizedPreSaveContent !== normalizedPostSaveContent) {
// auto-formatting was done by the editor
autoFormattingEdits = formatResponse.createPrettyPatch(
this.relPath.toPosix(),
normalizedPreSaveContent,
normalizedPostSaveContent,
)
}
return { newProblemsMessage, userEdits, autoFormattingEdits, finalContent: normalizedPostSaveContent }
}
async revertChanges(): Promise<void> {