fix(files): reject no-op edits

This commit is contained in:
chengyongru
2026-08-10 21:39:00 +08:00
committed by chengyongru
parent c281e090d0
commit b3b0517611
2 changed files with 16 additions and 2 deletions
+6 -2
View File
@@ -827,7 +827,8 @@ class EditFileTool(_FsTool):
def description(self) -> str:
return (
"Perform a small, exact replacement in one file by replacing "
"old_text with new_text. Use this for narrow text substitutions "
"old_text with new_text. When replacing text in an existing file, "
"old_text and new_text must be different. Use this for narrow text substitutions "
"with old_text copied from read_file. For multi-file, structural, "
"or generated code edits, prefer apply_patch. If old_text matches "
"multiple times, provide more context or set occurrence, line_hint, "
@@ -862,9 +863,12 @@ class EditFileTool(_FsTool):
return ToolResult.error("Error: expected_replacements must be >= 1.")
fp = self._resolve_write(path)
file_exists = fp.exists()
if file_exists and old_text == new_text:
return ToolResult.error("Error: new_text must be different from old_text.")
# Create-file semantics: old_text='' + file doesn't exist → create
if not fp.exists():
if not file_exists:
if old_text == "":
fp.parent.mkdir(parents=True, exist_ok=True)
fp.write_text(new_text, encoding="utf-8")
+10
View File
@@ -133,6 +133,16 @@ class TestEditFileTool:
assert "Successfully" in result
assert f.read_text() == "hello earth"
@pytest.mark.asyncio
async def test_identical_replacement_returns_clear_error(self, tool, tmp_path):
f = tmp_path / "a.py"
f.write_text("hello world", encoding="utf-8")
result = await tool.execute(path=str(f), old_text="world", new_text="world")
assert result == "Error: new_text must be different from old_text."
assert f.read_text(encoding="utf-8") == "hello world"
@pytest.mark.asyncio
async def test_crlf_normalisation(self, tool, tmp_path):
f = tmp_path / "crlf.py"