Skip to content

Commit a5aec32

Browse files
Bound edit mismatch scan work
1 parent d19707f commit a5aec32

2 files changed

Lines changed: 29 additions & 3 deletions

File tree

src/agents/sessions/tools/edit.test.ts

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,27 @@ describe("edit tool", () => {
183183
expect(message).not.toContain("tail-marker");
184184
});
185185

186+
it("does not scan past long unterminated lines for mismatch candidates", async () => {
187+
const longUnterminatedLine = `const hugeLine = ${"x".repeat(300_000)}`;
188+
const filePath = await createTempFile(`${longUnterminatedLine}\nconst nearbyNeedle = 1;`);
189+
const tool = createEditTool(tmpDir);
190+
191+
const message = await expectRejectedMessage(
192+
tool.execute(
193+
"call-1",
194+
{
195+
path: filePath,
196+
edits: [{ oldText: "const nearbyNeedle = 2;", newText: "const nearbyNeedle = 3;" }],
197+
},
198+
undefined,
199+
),
200+
);
201+
202+
expect(message).toContain("Closest candidate lines for oldText:");
203+
expect(message).not.toContain("- line 2:");
204+
expect(message).not.toContain('found: "const nearbyNeedle = 1;"');
205+
});
206+
186207
it("does not attach candidates from the wrong edit list for mixed no-op mismatches", async () => {
187208
const filePath = await createTempFile("const alpha = 1;\nconst beta = 2;\n");
188209
const tool = createEditTool(tmpDir);

src/agents/sessions/tools/edit.ts

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,8 @@ const EDIT_MISMATCH_SCAN_LINE_LIMIT = 2000;
8383
const EDIT_MISMATCH_LINE_DISPLAY_LIMIT = 140;
8484
// Keep one extra char so formatting can still show that the source line was truncated.
8585
const EDIT_MISMATCH_LINE_STORAGE_LIMIT = EDIT_MISMATCH_LINE_DISPLAY_LIMIT + 1;
86+
const EDIT_MISMATCH_SCAN_BYTE_LIMIT =
87+
EDIT_MISMATCH_SCAN_LINE_LIMIT * EDIT_MISMATCH_LINE_STORAGE_LIMIT;
8688
const EDIT_INDEXED_MISMATCH_RE = /\bCould not find edits\[\d+\] in /u;
8789

8890
/**
@@ -264,6 +266,7 @@ function findClosestMismatchLines(
264266
currentContent,
265267
EDIT_MISMATCH_SCAN_LINE_LIMIT,
266268
EDIT_MISMATCH_LINE_STORAGE_LIMIT,
269+
EDIT_MISMATCH_SCAN_BYTE_LIMIT,
267270
)
268271
.map((line, index) => ({
269272
lineNumber: index + 1,
@@ -279,11 +282,13 @@ function collectNormalizedLines(
279282
content: string,
280283
lineLimit: number,
281284
lineLengthLimit: number,
285+
scanByteLimit: number,
282286
): string[] {
283287
const lines: string[] = [];
284288
let lineStart = 0;
289+
const scanEnd = Math.min(content.length, scanByteLimit);
285290

286-
for (let index = 0; index < content.length && lines.length < lineLimit; index += 1) {
291+
for (let index = 0; index < scanEnd && lines.length < lineLimit; index += 1) {
287292
const char = content[index];
288293
if (char !== "\n" && char !== "\r") {
289294
continue;
@@ -296,8 +301,8 @@ function collectNormalizedLines(
296301
lineStart = index + 1;
297302
}
298303

299-
if (lines.length < lineLimit) {
300-
lines.push(content.slice(lineStart, lineStart + lineLengthLimit));
304+
if (lines.length < lineLimit && lineStart <= scanEnd) {
305+
lines.push(content.slice(lineStart, Math.min(scanEnd, lineStart + lineLengthLimit)));
301306
}
302307

303308
return lines;

0 commit comments

Comments
 (0)