From 1895c2feafc07a22bf69af4325c2841cdf8659d0 Mon Sep 17 00:00:00 2001 From: qer Date: Mon, 15 Jun 2026 18:38:20 +0800 Subject: [PATCH] fix(read): report maxLinesReached in tail mode When reading from the tail with line_offset=-MAX_LINES, the Read tool never reported maxLinesReached even though it hit the cap. This made tail mode inconsistent with forward mode. - Set maxLinesReached in readTail when effectiveLimit >= MAX_LINES and entries.length >= effectiveLimit. - Add regression test ensuring tail mode reports the cap. --- .../agent-core/src/tools/builtin/file/read.ts | 2 +- packages/agent-core/test/tools/read.test.ts | 16 ++++++++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/packages/agent-core/src/tools/builtin/file/read.ts b/packages/agent-core/src/tools/builtin/file/read.ts index 252eef3af..7daf07c4e 100644 --- a/packages/agent-core/src/tools/builtin/file/read.ts +++ b/packages/agent-core/src/tools/builtin/file/read.ts @@ -412,7 +412,7 @@ export class ReadTool implements BuiltinTool { return this.finishReadResult({ renderedLines, truncatedLineNumbers, - maxLinesReached: false, + maxLinesReached: effectiveLimit >= MAX_LINES && entries.length >= effectiveLimit, maxBytesReached, lineEndingStyle, startLine: renderedCandidates[0]?.entry.lineNo ?? 0, diff --git a/packages/agent-core/test/tools/read.test.ts b/packages/agent-core/test/tools/read.test.ts index 4ab97c1bb..34826b9a6 100644 --- a/packages/agent-core/test/tools/read.test.ts +++ b/packages/agent-core/test/tools/read.test.ts @@ -622,6 +622,22 @@ describe('ReadTool', () => { expect(result.output).not.toContain(`${String(MAX_LINES + 1)}\tline ${String(MAX_LINES + 1)}`); }); + it('caps tail reads at MAX_LINES', async () => { + const content = Array.from({ length: MAX_LINES + 5 }, (_, i) => `line ${String(i + 1)}`).join( + '\n', + ); + const tool = toolWithContent(content); + + const result = await executeTool( + tool, + context({ path: '/tmp/tail-big.txt', line_offset: -MAX_LINES }), + ); + + expect(result.output).toContain(`Max ${String(MAX_LINES)} lines reached.`); + expect(result.output).toContain(`${String(MAX_LINES + 5)}\tline ${String(MAX_LINES + 5)}`); + expect(result.output).toMatch(/^6\tline 6/); + }); + it('tail byte truncation keeps the newest lines closest to EOF', async () => { const numLines = Math.floor(MAX_BYTES / 1001) + 20; const content = Array.from({ length: numLines }, (_, i) => {