diff --git a/src/core/tools/__tests__/writeToFileTool.spec.ts b/src/core/tools/__tests__/writeToFileTool.spec.ts index 78e60cbaa5..7ea99ffda1 100644 --- a/src/core/tools/__tests__/writeToFileTool.spec.ts +++ b/src/core/tools/__tests__/writeToFileTool.spec.ts @@ -6,7 +6,6 @@ import { fileExistsAtPath } 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" import { everyLineHasLineNumbers, stripLineNumbers } from "../../../integrations/misc/extract-text" import { ToolUse, ToolResponse } from "../../../shared/tools" import { writeToFileTool } from "../writeToFileTool" @@ -54,10 +53,6 @@ vi.mock("../../../utils/path", () => ({ getReadablePath: vi.fn().mockReturnValue("test/path.txt"), })) -vi.mock("../../../utils/text-normalization", () => ({ - unescapeHtmlEntities: vi.fn().mockImplementation((content) => content), -})) - vi.mock("../../../integrations/misc/extract-text", () => ({ everyLineHasLineNumbers: vi.fn().mockReturnValue(false), stripLineNumbers: vi.fn().mockImplementation((content) => content), @@ -104,7 +99,6 @@ describe("writeToFileTool", () => { const mockedDetectCodeOmission = detectCodeOmission as MockedFunction const mockedIsPathOutsideWorkspace = isPathOutsideWorkspace as MockedFunction const mockedGetReadablePath = getReadablePath as MockedFunction - const mockedUnescapeHtmlEntities = unescapeHtmlEntities as MockedFunction const mockedEveryLineHasLineNumbers = everyLineHasLineNumbers as MockedFunction const mockedStripLineNumbers = stripLineNumbers as MockedFunction const mockedPathResolve = path.resolve as MockedFunction @@ -124,7 +118,6 @@ describe("writeToFileTool", () => { mockedDetectCodeOmission.mockReturnValue(false) mockedIsPathOutsideWorkspace.mockReturnValue(false) mockedGetReadablePath.mockReturnValue("test/path.txt") - mockedUnescapeHtmlEntities.mockImplementation((content) => content) mockedEveryLineHasLineNumbers.mockReturnValue(false) mockedStripLineNumbers.mockImplementation((content) => content) @@ -288,20 +281,28 @@ describe("writeToFileTool", () => { expect(mockCline.diffViewProvider.update).toHaveBeenCalledWith("", true) }) - it("unescapes HTML entities for non-Claude models", async () => { - mockCline.api.getModel.mockReturnValue({ id: "gpt-4" }) + it("preserves C# generics and angle brackets in content", async () => { + const csharpContent = `public class Service where T : class +{ + public void Configure(TOptions options) + { + builder.Services.Configure(builder.Configuration.GetSection("BlazorServerSettings")); + } +}` - await executeWriteFileTool({ content: "<test>" }) + await executeWriteFileTool({ content: csharpContent, line_count: "7" }) - expect(mockedUnescapeHtmlEntities).toHaveBeenCalledWith("<test>") + // Verify the content is passed through unchanged (no HTML entity conversion) + expect(mockCline.diffViewProvider.update).toHaveBeenCalledWith(csharpContent, true) }) - it("skips HTML unescaping for Claude models", async () => { - mockCline.api.getModel.mockReturnValue({ id: "claude-3" }) + it("preserves HTML entities in content without unescaping", async () => { + const contentWithEntities = "This has <angle> brackets and & ampersand" - await executeWriteFileTool({ content: "<test>" }) + await executeWriteFileTool({ content: contentWithEntities }) - expect(mockedUnescapeHtmlEntities).not.toHaveBeenCalled() + // Verify the content is passed through with HTML entities preserved + expect(mockCline.diffViewProvider.update).toHaveBeenCalledWith(contentWithEntities, true) }) it("strips line numbers from numbered content", async () => { diff --git a/src/core/tools/writeToFileTool.ts b/src/core/tools/writeToFileTool.ts index e82eab92bc..8f22fd672e 100644 --- a/src/core/tools/writeToFileTool.ts +++ b/src/core/tools/writeToFileTool.ts @@ -13,7 +13,6 @@ import { stripLineNumbers, everyLineHasLineNumbers } from "../../integrations/mi 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" @@ -83,10 +82,6 @@ export async function writeToFileTool( newContent = newContent.split("\n").slice(0, -1).join("\n") } - if (!cline.api.getModel().id.includes("claude")) { - newContent = unescapeHtmlEntities(newContent) - } - // Determine if the path is outside the workspace const fullPath = relPath ? path.resolve(cline.cwd, removeClosingTag("path", relPath)) : "" const isOutsideWorkspace = isPathOutsideWorkspace(fullPath)