Skip to content

Commit d93ea64

Browse files
committed
style(read-file): format paging green and its tests
1 parent 7f836db commit d93ea64

4 files changed

Lines changed: 87 additions & 82 deletions

File tree

‎src/agent/posix-tool-plugins.test.ts‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -124,9 +124,9 @@ describe("buildCorePosixToolPlugins", () => {
124124
// path+offset continuation, not only by grep.
125125
expect(String(allowed.content)).not.toContain("line truncated");
126126
expect(String(allowed.content)).toContain("to continue");
127-
expect(Buffer.byteLength(String(allowed.content), "utf8")).toBeLessThanOrEqual(
128-
50 * 1024,
129-
);
127+
expect(
128+
Buffer.byteLength(String(allowed.content), "utf8"),
129+
).toBeLessThanOrEqual(50 * 1024);
130130
} finally {
131131
await rm(cwd, { recursive: true, force: true });
132132
}

‎src/plugins/read-file-guard-plugin.test.ts‎

Lines changed: 66 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -359,82 +359,74 @@ describe("CL-8979 large-file pagination", () => {
359359
expect(String(res.content)).not.toContain("scan limit");
360360
});
361361

362-
test(
363-
"chains plain path+offset continuation on one path through to the last line",
364-
async () => {
365-
const name = "cl8979-chain.txt";
366-
await bigFixture(name);
367-
const run = chainRunner();
368-
const collected: string[] = [];
369-
let offset = 0;
370-
let hops = 0;
371-
for (;;) {
372-
const result = await run(`chain-${hops}`, {
373-
path: name,
374-
limit: 200,
375-
offset,
376-
});
377-
hops += 1;
378-
const content = String(result.content);
379-
expect(result.isError).toBeFalsy();
380-
expect(content).not.toContain("scan limit");
381-
collected.push(...bodyRows(content));
382-
const next = continueOffset(content);
383-
if (next === null) break;
384-
offset = next;
385-
expect(hops).toBeLessThan(2000);
386-
}
387-
expect(hops).toBeGreaterThan(1);
388-
expect(collected.length).toBe(BIG_LINES);
389-
expect(collected).toEqual(
390-
Array.from({ length: BIG_LINES }, (_, i) => bigRow(i)),
391-
);
392-
},
393-
120_000,
394-
);
395-
396-
test(
397-
"chains cursor resumption on a blob past the scan ceiling without re-scanning",
398-
async () => {
399-
const rows = Array.from({ length: BIG_LINES }, (_, i) => bigRow(i));
400-
const bytes = new TextEncoder().encode(`${rows.join("\n")}\n`);
401-
const run = blobChainRunner(async (key) => {
402-
if (key === "cl8979-blob") return bytes;
403-
throw new Error(`missing ${key}`);
362+
test("chains plain path+offset continuation on one path through to the last line", async () => {
363+
const name = "cl8979-chain.txt";
364+
await bigFixture(name);
365+
const run = chainRunner();
366+
const collected: string[] = [];
367+
let offset = 0;
368+
let hops = 0;
369+
for (;;) {
370+
const result = await run(`chain-${hops}`, {
371+
path: name,
372+
limit: 200,
373+
offset,
404374
});
405-
const collected: string[] = [];
406-
let path = "tool-output:///cl8979-blob";
407-
let hops = 0;
408-
let sawOffsetFooter = false;
409-
let sawCursorAlias = false;
410-
for (;;) {
411-
const result = await run(`blob-${hops}`, { path, limit: 200 });
412-
hops += 1;
413-
const content = String(result.content);
414-
expect(result.isError).toBeFalsy();
415-
expect(content).not.toContain("scan limit");
416-
collected.push(...bodyRows(content));
417-
const cursor = /Use path="(tool-output:\/\/\/[^"]+)"/.exec(content);
418-
const offset = continueOffset(content);
419-
if (offset !== null) {
420-
sawOffsetFooter = true;
421-
path = "tool-output:///cl8979-blob";
422-
}
423-
if (cursor !== null) {
424-
sawCursorAlias = true;
425-
path = cursor[1] as string;
426-
}
427-
if (offset === null && cursor === null) break;
428-
expect(hops).toBeLessThan(2000);
375+
hops += 1;
376+
const content = String(result.content);
377+
expect(result.isError).toBeFalsy();
378+
expect(content).not.toContain("scan limit");
379+
collected.push(...bodyRows(content));
380+
const next = continueOffset(content);
381+
if (next === null) break;
382+
offset = next;
383+
expect(hops).toBeLessThan(2000);
384+
}
385+
expect(hops).toBeGreaterThan(1);
386+
expect(collected.length).toBe(BIG_LINES);
387+
expect(collected).toEqual(
388+
Array.from({ length: BIG_LINES }, (_, i) => bigRow(i)),
389+
);
390+
}, 120_000);
391+
392+
test("chains cursor resumption on a blob past the scan ceiling without re-scanning", async () => {
393+
const rows = Array.from({ length: BIG_LINES }, (_, i) => bigRow(i));
394+
const bytes = new TextEncoder().encode(`${rows.join("\n")}\n`);
395+
const run = blobChainRunner(async (key) => {
396+
if (key === "cl8979-blob") return bytes;
397+
throw new Error(`missing ${key}`);
398+
});
399+
const collected: string[] = [];
400+
let path = "tool-output:///cl8979-blob";
401+
let hops = 0;
402+
let sawOffsetFooter = false;
403+
let sawCursorAlias = false;
404+
for (;;) {
405+
const result = await run(`blob-${hops}`, { path, limit: 200 });
406+
hops += 1;
407+
const content = String(result.content);
408+
expect(result.isError).toBeFalsy();
409+
expect(content).not.toContain("scan limit");
410+
collected.push(...bodyRows(content));
411+
const cursor = /Use path="(tool-output:\/\/\/[^"]+)"/.exec(content);
412+
const offset = continueOffset(content);
413+
if (offset !== null) {
414+
sawOffsetFooter = true;
415+
path = "tool-output:///cl8979-blob";
429416
}
430-
expect(hops).toBeGreaterThan(1);
431-
expect(sawOffsetFooter).toBe(true);
432-
expect(sawCursorAlias).toBe(true);
433-
expect(collected.length).toBe(BIG_LINES);
434-
expect(collected[BIG_LINES - 1]).toBe(bigRow(BIG_LINES - 1));
435-
},
436-
120_000,
437-
);
417+
if (cursor !== null) {
418+
sawCursorAlias = true;
419+
path = cursor[1] as string;
420+
}
421+
if (offset === null && cursor === null) break;
422+
expect(hops).toBeLessThan(2000);
423+
}
424+
expect(hops).toBeGreaterThan(1);
425+
expect(sawOffsetFooter).toBe(true);
426+
expect(sawCursorAlias).toBe(true);
427+
expect(collected.length).toBe(BIG_LINES);
428+
expect(collected[BIG_LINES - 1]).toBe(bigRow(BIG_LINES - 1));
429+
}, 120_000);
438430

439431
test("windows an overlong single file line so the tail is reachable", async () => {
440432
const payload = `HEAD-${"y".repeat(100_000)}-TAIL`;

‎src/plugins/read-file-guard-plugin.ts‎

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,11 @@ function mintCursor(
118118
// survives downstream layers byte-identical. Consumed cursors stay retired:
119119
// only the stale-replay message may name them.
120120
for (const [id, cursor] of cursors) {
121-
if (!cursor.consumed && cursor.offset === offset && sameCursorSource(cursor, source)) {
121+
if (
122+
!cursor.consumed &&
123+
cursor.offset === offset &&
124+
sameCursorSource(cursor, source)
125+
) {
122126
const alias = cursorAlias(id);
123127
if (LINE_LIMIT_NOTICE_RE.test(content)) {
124128
return content.replace(CONTINUE_OFFSET_RE, alias);
@@ -219,8 +223,11 @@ function readStreamBounded(
219223
} = {},
220224
): Promise<BoundedRead> {
221225
return new Promise<BoundedRead>((resolveP, rejectP) => {
222-
const { mapStreamError, wrapLongLines = false, windowHugeLines = false } =
223-
options;
226+
const {
227+
mapStreamError,
228+
wrapLongLines = false,
229+
windowHugeLines = false,
230+
} = options;
224231
const decoder = new StringDecoder("utf8");
225232
const contentBudget = READ_FILE_MAX_BYTES - NOTICE_RESERVE_BYTES;
226233

@@ -339,7 +346,12 @@ function readStreamBounded(
339346
emitWrapped(pending, true);
340347
return;
341348
}
342-
if (!pendingOverflow && !scanCapped && windowHugeLines && pending.length > contentBudget) {
349+
if (
350+
!pendingOverflow &&
351+
!scanCapped &&
352+
windowHugeLines &&
353+
pending.length > contentBudget
354+
) {
343355
emitWrapped(pending, true);
344356
return;
345357
}

‎src/plugins/result-truncation-plugin.ts‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -298,7 +298,8 @@ export async function applyToolResultTruncation(
298298
// the 10k leisure cap would slice the footer off the page boundary and strand
299299
// the pagination chain, so footer-bearing read_file pages pass through intact.
300300
// Pages without a footer take the normal path.
301-
const READ_FILE_CONTINUATION_RE = /Use offset=\d+ to continue\.|Use path="tool-output:\/\/\//;
301+
const READ_FILE_CONTINUATION_RE =
302+
/Use offset=\d+ to continue\.|Use path="tool-output:\/\/\//;
302303

303304
function isPagedReadFilePage(
304305
toolName: string | undefined,

0 commit comments

Comments
 (0)