From 90fba74c49271d53b71bb90f7167f8beb9e6587c Mon Sep 17 00:00:00 2001 From: Ammar Date: Fri, 1 May 2026 20:42:55 -0500 Subject: [PATCH] =?UTF-8?q?=F0=9F=A4=96=20feat:=20allow=20guardless=20inse?= =?UTF-8?q?rts=20on=20empty=20existing=20files?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit file_edit_insert previously required insert_before/insert_after guards whenever the target existed, even when the file was empty (and so had no content to anchor against). Empty files now behave like missing files: the provided content simply populates them. --- _Generated with `mux` • Model: `anthropic:claude-opus-4-7` • Thinking: `medium` • Cost: `$0.20`_ --- src/common/utils/tools/toolDefinitions.ts | 2 +- src/node/services/tools/file_edit_insert.test.ts | 14 ++++++++++++++ src/node/services/tools/file_edit_insert.ts | 9 +++++++++ 3 files changed, 24 insertions(+), 1 deletion(-) diff --git a/src/common/utils/tools/toolDefinitions.ts b/src/common/utils/tools/toolDefinitions.ts index 4ed7e585cb..c0cdc2ec71 100644 --- a/src/common/utils/tools/toolDefinitions.ts +++ b/src/common/utils/tools/toolDefinitions.ts @@ -1271,7 +1271,7 @@ export const TOOL_DEFINITIONS = { description: "Insert content into a file using substring guards. " + "Provide exactly one of insert_before or insert_after to anchor the operation when editing an existing file. " + - "When the file does not exist, it is created automatically without guards. " + + "When the file does not exist or is empty, it is populated automatically without guards. " + "Optional before/after substrings must uniquely match surrounding content. " + "Avoid short guards like `}` or `}\\n` that match multiple locations — " + `use longer patterns like full function signatures or unique comments. ${TOOL_EDIT_WARNING}`, diff --git a/src/node/services/tools/file_edit_insert.test.ts b/src/node/services/tools/file_edit_insert.test.ts index 32adbd8a33..7173edbd8f 100644 --- a/src/node/services/tools/file_edit_insert.test.ts +++ b/src/node/services/tools/file_edit_insert.test.ts @@ -142,6 +142,20 @@ describe("file_edit_insert tool", () => { expect(await fs.readFile(newFile, "utf-8")).toBe("Hello world!\n"); }); + it("populates an empty existing file without requiring guards", async () => { + const emptyFile = path.join(testDir, "empty.txt"); + await fs.writeFile(emptyFile, ""); + const tool = createTestTool(testDir); + const args: FileEditInsertToolArgs = { + path: path.relative(testDir, emptyFile), + content: "Hello empty!\n", + }; + + const result = (await tool.execute!(args, mockToolCallOptions)) as FileEditInsertToolResult; + expect(result.success).toBe(true); + expect(await fs.readFile(emptyFile, "utf-8")).toBe("Hello empty!\n"); + }); + it("fails when no guards are provided", async () => { const tool = createTestTool(testDir); const args: FileEditInsertToolArgs = { diff --git a/src/node/services/tools/file_edit_insert.ts b/src/node/services/tools/file_edit_insert.ts index 31d69f1a09..fd0354b2b2 100644 --- a/src/node/services/tools/file_edit_insert.ts +++ b/src/node/services/tools/file_edit_insert.ts @@ -149,6 +149,15 @@ function insertContent( } if (insert_before == null && insert_after == null) { + // Empty existing files have no anchors to match against, so allow guardless + // inserts that simply populate the file (mirrors the create-on-missing path). + if (originalContent.length === 0) { + return { + success: true, + newContent: contentToInsert, + metadata: {}, + }; + } return guardFailure( "Provide either insert_before or insert_after guard when editing existing files." );