fix(multi-edit): fall through to string match on line-range mismatch

When lineStart-anchored oldString doesn't match the adjusted range,
fall through to string-based matching instead of failing. Adjacent
edits in the same multi_edit batch can shift content, so the text
may still exist elsewhere in the evolved file.

Co-Authored-By: SoulForge <[email protected]>
This commit is contained in:
PouiiroandSoulForge committed 2026-04-10 11:03:44 +02:00
1 parent 6011c5572f
commit f3db97844c
2 files changed
+5 -12

No files matched your search

+3 -11
View File
@@ -120,17 +120,9 @@ export const multiEditTool = {
continue;
}
// oldString doesn't match range — FAIL instead of blindly applying.
// Applying by stale line numbers after formatting causes corruption.
const rangeSnippet = lines
.slice(start, end)
.map((l, idx) => `${String(start + idx + 1).padStart(4)} │ ${l}`)
.join("\n");
return {
success: false,
output: `Edit ${String(i + 1)}/${String(args.edits.length)} failed: oldString does not match lines ${String(edit.lineStart)}-${String((edit.lineStart ?? 0) + oldLineCount - 1)}. NO edits were applied (atomic rollback). Actual content at that range:\n${rangeSnippet}\nRe-read the file and retry ALL edits.`,
error: `edit ${String(i + 1)}: oldString mismatch at line range (0 edits applied)`,
};
// oldString doesn't match at the adjusted line range.
// Fall through to string-based matching — the content may still
// exist elsewhere in the evolved file (e.g. adjacent edits shifted it).
}
// Line range invalid — fall through to string-based matching
}
+2 -1
View File
@@ -331,7 +331,8 @@ describe("multi_edit tool: mismatch behavior", () => {
],
});
expect(result.success).toBe(false);
expect(result.output).toContain("oldString does not match");
expect(result.output).toContain("old_string not found");
expect(result.output).toContain("atomic rollback");
}, 30_000);
it("succeeds when all edits match exactly", async () => {