Browse Source

fix: remove omission detection logic to fix false positives (#9787)

Co-authored-by: Roo Code <[email protected]>
roomote[bot] 1 month ago
parent
commit
86edc01cb1

+ 0 - 55
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)

+ 0 - 7
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<typeof fileExistsAtPath>
 	const mockedCreateDirectoriesForFile = createDirectoriesForFile as MockedFunction<typeof createDirectoriesForFile>
-	const mockedDetectCodeOmission = detectCodeOmission as MockedFunction<typeof detectCodeOmission>
 	const mockedIsPathOutsideWorkspace = isPathOutsideWorkspace as MockedFunction<typeof isPathOutsideWorkspace>
 	const mockedGetReadablePath = getReadablePath as MockedFunction<typeof getReadablePath>
 	const mockedUnescapeHtmlEntities = unescapeHtmlEntities as MockedFunction<typeof unescapeHtmlEntities>
@@ -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)

+ 0 - 80
src/integrations/editor/__tests__/detect-omission.spec.ts

@@ -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("<!-- Existing content unchanged -->\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)
-	})
-})

+ 0 - 53
src/integrations/editor/detect-omission.ts

@@ -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*<!--/, // HTML comment opening
-		/^\s*\[/, // Square bracket notation
-	]
-
-	// Consider comments as suspicious if they weren't in the original file
-	// and contain omission keywords
-	for (const line of newLines) {
-		if (commentPatterns.some((pattern) => pattern.test(line))) {
-			const words = line.toLowerCase().split(/\s+/)
-			if (omissionKeywords.some((keyword) => words.includes(keyword))) {
-				if (!originalLines.includes(line)) {
-					return true
-				}
-			}
-		}
-	}
-
-	return false
-}