diff --git a/core/config/types.ts b/core/config/types.ts index 6048cf4d30c..0b76419df6d 100644 --- a/core/config/types.ts +++ b/core/config/types.ts @@ -1061,6 +1061,7 @@ declare global { filepath?: string; fileContent?: string; originalFileContent?: string; + autoFormattingDiff?: string; } export interface RangeInFileWithContents { diff --git a/core/index.d.ts b/core/index.d.ts index 6e80bc5d374..5ac6796a1cf 100644 --- a/core/index.d.ts +++ b/core/index.d.ts @@ -1387,6 +1387,7 @@ export interface ApplyState { fileContent?: string; originalFileContent?: string; toolCallId?: string; + autoFormattingDiff?: string; } export interface StreamDiffLinesPayload { diff --git a/extensions/vscode/src/diff/processDiff.ts b/extensions/vscode/src/diff/processDiff.ts index f350e12b4d3..cbff6f4a363 100644 --- a/extensions/vscode/src/diff/processDiff.ts +++ b/extensions/vscode/src/diff/processDiff.ts @@ -1,8 +1,11 @@ import { Core } from "core/core"; import { DataLogger } from "core/data/log"; +import { myersDiff } from "core/diff/myers"; + import { ContinueGUIWebviewViewProvider } from "../ContinueGUIWebviewViewProvider"; import { editOutcomeTracker } from "../extension/EditOutcomeTracker"; import { VsCodeIde } from "../VsCodeIde"; + import { VerticalDiffManager } from "./vertical/manager"; export async function processDiff( @@ -42,7 +45,8 @@ export async function processDiff( } if (streamId) { - const fileContent = await ide.readFile(newOrCurrentUri); + // Capture file content before save to detect autoformatting + const preSaveContent = await ide.readFile(newOrCurrentUri); // Record the edit outcome before updating the apply state await editOutcomeTracker.recordEditOutcome( @@ -51,16 +55,45 @@ export async function processDiff( DataLogger.getInstance(), ); + // Save the file + await ide.saveFile(newOrCurrentUri); + + // Capture file content after save to detect autoformatting + const postSaveContent = await ide.readFile(newOrCurrentUri); + + // Detect autoformatting by comparing normalized content + let autoFormattingDiff: string | undefined; + const normalizedPreSave = preSaveContent.trim(); + const normalizedPostSave = postSaveContent.trim(); + + if (normalizedPreSave !== normalizedPostSave) { + // Auto-formatting was applied by the editor + const diffLines = myersDiff(preSaveContent, postSaveContent); + autoFormattingDiff = diffLines + .map((line) => { + switch (line.type) { + case "old": + return `-${line.line}`; + case "new": + return `+${line.line}`; + case "same": + return ` ${line.line}`; + } + }) + .join("\n"); + } + await sidebar.webviewProtocol.request("updateApplyState", { - fileContent, + fileContent: postSaveContent, // Use post-save content filepath: newOrCurrentUri, streamId, status: "closed", numDiffs: 0, toolCallId, + autoFormattingDiff, // Include autoformatting diff }); + } else { + // Save the file even if no streamId + await ide.saveFile(newOrCurrentUri); } - - // Save the file - await ide.saveFile(newOrCurrentUri); } diff --git a/gui/src/redux/thunks/handleApplyStateUpdate.ts b/gui/src/redux/thunks/handleApplyStateUpdate.ts index 25532e75079..8d7c1bec043 100644 --- a/gui/src/redux/thunks/handleApplyStateUpdate.ts +++ b/gui/src/redux/thunks/handleApplyStateUpdate.ts @@ -83,6 +83,24 @@ export const handleApplyStateUpdate = createAsyncThunk< } if (accepted) { + // Add autoformatting diff to tool output if present + if (applyState.autoFormattingDiff) { + dispatch( + updateToolCallOutput({ + toolCallId: applyState.toolCallId, + contextItems: [ + { + icon: "info", + name: "Auto-formatting Applied", + description: "Editor auto-formatting changes", + content: `Along with your edits, the editor applied the following auto-formatting:\n\n${applyState.autoFormattingDiff}\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.)`, + hidden: false, + }, + ], + }), + ); + } + if (toolCallState.status !== "errored") { dispatch( acceptToolCall({ @@ -98,7 +116,6 @@ export const handleApplyStateUpdate = createAsyncThunk< ); } } - // TODO return output from edit tools so the model knows the result } } }