From 2f6da5d20054211ffacd87d98b42c09d4e944374 Mon Sep 17 00:00:00 2001 From: Roo Code Date: Wed, 3 Dec 2025 18:04:45 +0000 Subject: [PATCH] fix: remove omission detection logic to fix false positives Removes the detectCodeOmission function and all its usages as per discussion in issue #9785. The omission detection was causing false positives with legitimate documentation comments in markdown files and other file types. With modern models having larger context windows and max output tokens, this validation is no longer necessary. Fixes #9785 --- src/core/tools/WriteToFileTool.ts | 55 ------------- .../tools/__tests__/writeToFileTool.spec.ts | 7 -- .../editor/__tests__/detect-omission.spec.ts | 80 ------------------- src/integrations/editor/detect-omission.ts | 53 ------------ 4 files changed, 195 deletions(-) delete mode 100644 src/integrations/editor/__tests__/detect-omission.spec.ts delete mode 100644 src/integrations/editor/detect-omission.ts diff --git a/src/core/tools/WriteToFileTool.ts b/src/core/tools/WriteToFileTool.ts index f1bae7ff2fc..7caaeb6d55d 100644 --- a/src/core/tools/WriteToFileTool.ts +++ b/src/core/tools/WriteToFileTool.ts @@ -11,7 +11,6 @@ import { fileExistsAtPath, createDirectoriesForFile } from "../../utils/fs" import { stripLineNumbers, everyLineHasLineNumbers } from "../../integrations/misc/extract-text" import { getReadablePath } from "../../utils/path" import { isPathOutsideWorkspace } from "../../utils/pathUtils" -import { detectCodeOmission } from "../../integrations/editor/detect-omission" import { unescapeHtmlEntities } from "../../utils/text-normalization" import { DEFAULT_WRITE_DELAY_MS } from "@roo-code/types" import { EXPERIMENT_IDS, experiments } from "../../shared/experiments" @@ -125,32 +124,6 @@ export class WriteToFileTool extends BaseTool<"write_to_file"> { task.diffViewProvider.originalContent = "" } - if (detectCodeOmission(task.diffViewProvider.originalContent || "", newContent)) { - if (task.diffStrategy) { - pushToolResult( - formatResponse.toolError( - `Content appears to contain comments indicating omitted code (e.g., '// rest of code unchanged', '/* previous code */'). Please provide the complete file content without any omissions if possible, or otherwise use the 'apply_diff' tool to apply the diff to the original file.`, - ), - ) - return - } else { - vscode.window - .showWarningMessage( - "Potential code truncation detected. This happens when the AI reaches its max output limit.", - "Follow guide to fix the issue", - ) - .then((selection) => { - if (selection === "Follow guide to fix the issue") { - vscode.env.openExternal( - vscode.Uri.parse( - "https://github.com/cline/cline/wiki/Troubleshooting-%E2%80%90-Cline-Deleting-Code-with-%22Rest-of-Code-Here%22-Comments", - ), - ) - } - }) - } - } - let unified = fileExists ? formatResponse.createPrettyPatch(relPath, task.diffViewProvider.originalContent, newContent) : convertNewFileToUnifiedDiff(newContent, relPath) @@ -183,34 +156,6 @@ export class WriteToFileTool extends BaseTool<"write_to_file"> { await delay(300) task.diffViewProvider.scrollToFirstDiff() - if (detectCodeOmission(task.diffViewProvider.originalContent || "", newContent)) { - if (task.diffStrategy) { - await task.diffViewProvider.revertChanges() - - pushToolResult( - formatResponse.toolError( - `Content appears to contain comments indicating omitted code (e.g., '// rest of code unchanged', '/* previous code */'). Please provide the complete file content without any omissions if possible, or otherwise use the 'apply_diff' tool to apply the diff to the original file.`, - ), - ) - return - } else { - vscode.window - .showWarningMessage( - "Potential code truncation detected. This happens when the AI reaches its max output limit.", - "Follow guide to fix the issue", - ) - .then((selection) => { - if (selection === "Follow guide to fix the issue") { - vscode.env.openExternal( - vscode.Uri.parse( - "https://github.com/cline/cline/wiki/Troubleshooting-%E2%80%90-Cline-Deleting-Code-with-%22Rest-of-Code-Here%22-Comments", - ), - ) - } - }) - } - } - let unified = fileExists ? formatResponse.createPrettyPatch(relPath, task.diffViewProvider.originalContent, newContent) : convertNewFileToUnifiedDiff(newContent, relPath) diff --git a/src/core/tools/__tests__/writeToFileTool.spec.ts b/src/core/tools/__tests__/writeToFileTool.spec.ts index ff9ad76dade..3970a99f066 100644 --- a/src/core/tools/__tests__/writeToFileTool.spec.ts +++ b/src/core/tools/__tests__/writeToFileTool.spec.ts @@ -3,7 +3,6 @@ import * as path from "path" import type { MockedFunction } from "vitest" import { fileExistsAtPath, createDirectoriesForFile } from "../../../utils/fs" -import { detectCodeOmission } from "../../../integrations/editor/detect-omission" import { isPathOutsideWorkspace } from "../../../utils/pathUtils" import { getReadablePath } from "../../../utils/path" import { unescapeHtmlEntities } from "../../../utils/text-normalization" @@ -40,10 +39,6 @@ vi.mock("../../prompts/responses", () => ({ }, })) -vi.mock("../../../integrations/editor/detect-omission", () => ({ - detectCodeOmission: vi.fn().mockReturnValue(false), -})) - vi.mock("../../../utils/pathUtils", () => ({ isPathOutsideWorkspace: vi.fn().mockReturnValue(false), })) @@ -100,7 +95,6 @@ describe("writeToFileTool", () => { // Mocked functions with correct types const mockedFileExistsAtPath = fileExistsAtPath as MockedFunction const mockedCreateDirectoriesForFile = createDirectoriesForFile as MockedFunction - const mockedDetectCodeOmission = detectCodeOmission as MockedFunction const mockedIsPathOutsideWorkspace = isPathOutsideWorkspace as MockedFunction const mockedGetReadablePath = getReadablePath as MockedFunction const mockedUnescapeHtmlEntities = unescapeHtmlEntities as MockedFunction @@ -120,7 +114,6 @@ describe("writeToFileTool", () => { mockedPathResolve.mockReturnValue(absoluteFilePath) mockedFileExistsAtPath.mockResolvedValue(false) - mockedDetectCodeOmission.mockReturnValue(false) mockedIsPathOutsideWorkspace.mockReturnValue(false) mockedGetReadablePath.mockReturnValue("test/path.txt") mockedUnescapeHtmlEntities.mockImplementation((content) => content) diff --git a/src/integrations/editor/__tests__/detect-omission.spec.ts b/src/integrations/editor/__tests__/detect-omission.spec.ts deleted file mode 100644 index 6ff31c390a5..00000000000 --- a/src/integrations/editor/__tests__/detect-omission.spec.ts +++ /dev/null @@ -1,80 +0,0 @@ -import { detectCodeOmission } from "../detect-omission" - -describe("detectCodeOmission", () => { - const originalContent = `function example() { - // Some code - const x = 1; - const y = 2; - return x + y; -}` - - // Generate content with a specified number of lines (100+ lines triggers detection) - const generateLongContent = (commentLine: string, length: number = 110) => { - return `${commentLine} - ${Array.from({ length }, (_, i) => `const x${i} = ${i};`).join("\n")} - const y = 2;` - } - - it("should skip comment checks for files under 100 lines", () => { - const newContent = `// Lines 1-50 remain unchanged -const z = 3;` - expect(detectCodeOmission(originalContent, newContent)).toBe(false) - }) - - it("should not detect regular comments without omission keywords", () => { - const newContent = generateLongContent("// Adding new functionality") - expect(detectCodeOmission(originalContent, newContent)).toBe(false) - }) - - it("should not detect when comment is part of original content", () => { - const originalWithComment = `// Content remains unchanged -${originalContent}` - const newContent = generateLongContent("// Content remains unchanged") - expect(detectCodeOmission(originalWithComment, newContent)).toBe(false) - }) - - it("should not detect code that happens to contain omission keywords", () => { - const newContent = generateLongContent(`const remains = 'some value'; -const unchanged = true;`) - expect(detectCodeOmission(originalContent, newContent)).toBe(false) - }) - - it("should detect suspicious single-line comment for files with 100+ lines", () => { - const newContent = generateLongContent("// Previous content remains here\nconst x = 1;") - expect(detectCodeOmission(originalContent, newContent)).toBe(true) - }) - - it("should detect suspicious Python-style comment for files with 100+ lines", () => { - const newContent = generateLongContent("# Previous content remains here\nconst x = 1;") - expect(detectCodeOmission(originalContent, newContent)).toBe(true) - }) - - it("should detect suspicious multi-line comment for files with 100+ lines", () => { - const newContent = generateLongContent("/* Previous content remains the same */\nconst x = 1;") - expect(detectCodeOmission(originalContent, newContent)).toBe(true) - }) - - it("should detect suspicious JSX comment for files with 100+ lines", () => { - const newContent = generateLongContent("{/* Rest of the code remains the same */}\nconst x = 1;") - expect(detectCodeOmission(originalContent, newContent)).toBe(true) - }) - - it("should detect suspicious HTML comment for files with 100+ lines", () => { - const newContent = generateLongContent("\nconst x = 1;") - expect(detectCodeOmission(originalContent, newContent)).toBe(true) - }) - - it("should detect suspicious square bracket notation for files with 100+ lines", () => { - const newContent = generateLongContent( - "[Previous content from line 1-305 remains exactly the same]\nconst x = 1;", - ) - expect(detectCodeOmission(originalContent, newContent)).toBe(true) - }) - - it("should not flag legitimate comments in files with 100+ lines when in original", () => { - const originalWithComment = `// This is a legitimate comment that remains here -${originalContent}` - const newContent = generateLongContent("// This is a legitimate comment that remains here") - expect(detectCodeOmission(originalWithComment, newContent)).toBe(false) - }) -}) diff --git a/src/integrations/editor/detect-omission.ts b/src/integrations/editor/detect-omission.ts deleted file mode 100644 index d55acd4183c..00000000000 --- a/src/integrations/editor/detect-omission.ts +++ /dev/null @@ -1,53 +0,0 @@ -/** - * Detects potential AI-generated code omissions in the given file content. - * Looks for comments containing omission keywords that weren't in the original file. - * @param originalFileContent The original content of the file. - * @param newFileContent The new content of the file to check. - * @returns True if a potential omission is detected, false otherwise. - */ -export function detectCodeOmission(originalFileContent: string, newFileContent: string): boolean { - const actualLineCount = newFileContent.split("\n").length - - // Skip checks for small files (less than 100 lines) - if (actualLineCount < 100) { - return false - } - - const originalLines = originalFileContent.split("\n") - const newLines = newFileContent.split("\n") - const omissionKeywords = [ - "remain", - "remains", - "unchanged", - "rest", - "previous", - "existing", - "content", - "same", - "...", - ] - - const commentPatterns = [ - /^\s*\/\//, // Single-line comment for most languages - /^\s*#/, // Single-line comment for Python, Ruby, etc. - /^\s*\/\*/, // Multi-line comment opening - /^\s*{\s*\/\*/, // JSX comment opening - /^\s*