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

Co-authored-by: Roo Code <roomote@roocode.com>
This commit is contained in:
roomote[bot] 2025-12-03 13:20:22 -05:00 committed by GitHub
parent 23605bed93
commit 86edc01cb1
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 0 additions and 195 deletions

View file

@ -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)

View file

@ -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)

View file

@ -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)
})
})

View file

@ -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
}