From 345b168befe2a51465b2a1e567db9cdcbc4718a8 Mon Sep 17 00:00:00 2001 From: LifeJiggy Date: Fri, 29 May 2026 12:47:39 +0100 Subject: [PATCH 1/2] fix(read): report MAX_BYTES cap independently when both MAX_LINES and MAX_BYTES are hit The finishMessage method used else-if chaining for the maxLinesReached, maxBytesReached, and end-of-file conditions. When a file exceeded both MAX_LINES and MAX_BYTES simultaneously, only the line cap was reported, silently hiding the byte cap from the model. Changed the conditions to independent if statements so both limits are reported when both are triggered. The EOF message now only appears when neither limit was reached. Fixes #94 --- .../agent-core/src/tools/builtin/file/read.ts | 6 ++++-- packages/agent-core/test/tools/read.test.ts | 17 +++++++++++++++++ 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/packages/agent-core/src/tools/builtin/file/read.ts b/packages/agent-core/src/tools/builtin/file/read.ts index 5c711007..bc374c33 100644 --- a/packages/agent-core/src/tools/builtin/file/read.ts +++ b/packages/agent-core/src/tools/builtin/file/read.ts @@ -435,9 +435,11 @@ export class ReadTool implements BuiltinTool { parts.push(`Total lines in file: ${String(input.totalLines)}.`); if (input.maxLinesReached) { parts.push(`Max ${String(MAX_LINES)} lines reached.`); - } else if (input.maxBytesReached) { + } + if (input.maxBytesReached) { parts.push(`Max ${String(MAX_BYTES)} bytes reached.`); - } else if (lineCount < input.requestedLines) { + } + if (!input.maxLinesReached && !input.maxBytesReached && lineCount < input.requestedLines) { parts.push('End of file reached.'); } if (input.truncatedLineNumbers.length > 0) { diff --git a/packages/agent-core/test/tools/read.test.ts b/packages/agent-core/test/tools/read.test.ts index 035b4dde..c14b34ee 100644 --- a/packages/agent-core/test/tools/read.test.ts +++ b/packages/agent-core/test/tools/read.test.ts @@ -597,6 +597,23 @@ describe('ReadTool', () => { expect(result.output).not.toContain(`${String(MAX_LINES + 1)}\tline ${String(MAX_LINES + 1)}`); }); + it('reports both MAX_LINES and MAX_BYTES when both caps are hit', async () => { + const lineCount = MAX_LINES + 5; + const lineContent = 'x'.repeat(105); + const content = Array.from({ length: lineCount }, (_, i) => `${lineContent} ${String(i + 1)}`).join( + '\n', + ); + const tool = toolWithContent(content); + + const result = await executeTool(tool, context({ path: '/tmp/both-caps.txt' })); + const output = toolContentString(result); + + expect(result.isError).toBeFalsy(); + expect(output).toContain(`Max ${String(MAX_LINES)} lines reached.`); + expect(output).toContain(`Max ${String(MAX_BYTES)} bytes reached.`); + expect(output).not.toContain('End of file reached.'); + }); + 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) => { From abc3b5342bd223b8abad3c4e9a7c7cf130978408 Mon Sep 17 00:00:00 2001 From: LifeJiggy Date: Fri, 29 May 2026 12:48:17 +0100 Subject: [PATCH 2/2] chore: add changeset for Read tool dual-cap fix --- .changeset/read-tool-dual-cap-message.md | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 .changeset/read-tool-dual-cap-message.md diff --git a/.changeset/read-tool-dual-cap-message.md b/.changeset/read-tool-dual-cap-message.md new file mode 100644 index 00000000..42908f69 --- /dev/null +++ b/.changeset/read-tool-dual-cap-message.md @@ -0,0 +1,6 @@ +--- +"@moonshot-ai/agent-core": patch +"@moonshot-ai/kimi-code": patch +--- + +Report both MAX_LINES and MAX_BYTES limits in Read tool status when both are reached.