diff --git a/packages/core/src/tools/grep-utils.ts b/packages/core/src/tools/grep-utils.ts index 6dd2cdc83e..2191588301 100644 --- a/packages/core/src/tools/grep-utils.ts +++ b/packages/core/src/tools/grep-utils.ts @@ -6,6 +6,7 @@ import fsPromises from 'node:fs/promises'; import { debugLogger } from '../utils/debugLogger.js'; +import { MAX_LINE_LENGTH_TEXT_FILE } from '../utils/constants.js'; /** * Result object for a single grep match @@ -198,7 +199,14 @@ export async function formatGrepResults( // If isContext is undefined, assume it's a match (false) const separator = match.isContext ? '-' : ':'; // trimEnd to avoid double newlines if line has them, but we want to preserve indentation - llmContent += `L${match.lineNumber}${separator} ${match.line.trimEnd()}\n`; + let lineContent = match.line.trimEnd(); + const graphemes = Array.from(lineContent); + if (graphemes.length > MAX_LINE_LENGTH_TEXT_FILE) { + lineContent = + graphemes.slice(0, MAX_LINE_LENGTH_TEXT_FILE).join('') + + '... [truncated]'; + } + llmContent += `L${match.lineNumber}${separator} ${lineContent}\n`; }); llmContent += '---\n'; } diff --git a/packages/core/src/tools/grep.test.ts b/packages/core/src/tools/grep.test.ts index 508ae7775b..1f0a8ee98f 100644 --- a/packages/core/src/tools/grep.test.ts +++ b/packages/core/src/tools/grep.test.ts @@ -562,6 +562,22 @@ describe('GrepTool', () => { // Verify context after expect(result.llmContent).toContain('L60- Line 60'); }); + + it('should truncate excessively long lines', async () => { + const longString = 'a'.repeat(3000); + await fs.writeFile( + path.join(tempRootDir, 'longline.txt'), + `Target match ${longString}`, + ); + + const params: GrepToolParams = { pattern: 'Target match' }; + const invocation = grepTool.build(params); + const result = await invocation.execute(abortSignal); + + // MAX_LINE_LENGTH_TEXT_FILE is 2000. It should be truncated. + expect(result.llmContent).toContain('... [truncated]'); + expect(result.llmContent).not.toContain(longString); + }); }); describe('getDescription', () => { diff --git a/packages/core/src/tools/ripGrep.test.ts b/packages/core/src/tools/ripGrep.test.ts index 265bb8e53c..a1b155fb7a 100644 --- a/packages/core/src/tools/ripGrep.test.ts +++ b/packages/core/src/tools/ripGrep.test.ts @@ -2028,6 +2028,32 @@ describe('RipGrepTool', () => { expect(result.llmContent).not.toContain('fileB.txt'); expect(result.llmContent).toContain('Copyright 2025 Google LLC'); }); + + it('should truncate excessively long lines', async () => { + const longString = 'a'.repeat(3000); + mockSpawn.mockImplementation( + createMockSpawn({ + outputData: + JSON.stringify({ + type: 'match', + data: { + path: { text: 'longline.txt' }, + line_number: 1, + lines: { text: `Target match ${longString}\n` }, + }, + }) + '\n', + exitCode: 0, + }), + ); + + const params: RipGrepToolParams = { pattern: 'Target match', context: 0 }; + const invocation = grepTool.build(params); + const result = await invocation.execute(abortSignal); + + // MAX_LINE_LENGTH_TEXT_FILE is 2000. It should be truncated. + expect(result.llmContent).toContain('... [truncated]'); + expect(result.llmContent).not.toContain(longString); + }); }); });