From 659301ff83459e51e44e76f4e250b508e51f2eae Mon Sep 17 00:00:00 2001 From: Aishanee Shah Date: Mon, 2 Mar 2026 15:11:58 -0500 Subject: [PATCH] feat(core): centralize read_file limits and update gemini-3 description (#20619) --- .../tools/__snapshots__/read-file.test.ts.snap | 2 ++ .../coreToolsModelSnapshots.test.ts.snap | 2 +- .../definitions/model-family-sets/gemini-3.ts | 7 ++++++- packages/core/src/tools/read-file.test.ts | 8 ++++++++ packages/core/src/utils/constants.ts | 4 ++++ packages/core/src/utils/fileUtils.ts | 17 +++++++++-------- 6 files changed, 30 insertions(+), 10 deletions(-) diff --git a/packages/core/src/tools/__snapshots__/read-file.test.ts.snap b/packages/core/src/tools/__snapshots__/read-file.test.ts.snap index de36bd639e..36dbcf1572 100644 --- a/packages/core/src/tools/__snapshots__/read-file.test.ts.snap +++ b/packages/core/src/tools/__snapshots__/read-file.test.ts.snap @@ -1,5 +1,7 @@ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html +exports[`ReadFileTool > getSchema > should return the Gemini 3 schema when a Gemini 3 modelId is provided 1`] = `"Reads and returns the content of a specified file. To maintain context efficiency, you MUST use 'start_line' and 'end_line' for targeted, surgical reads of specific sections. For your safety, the tool will automatically truncate output exceeding 2000 lines, 2000 characters per line, or 20MB in size; however, triggering these limits is considered token-inefficient. Always retrieve only the minimum content necessary for your next step. Handles text, images (PNG, JPG, GIF, WEBP, SVG, BMP), audio files (MP3, WAV, AIFF, AAC, OGG, FLAC), and PDF files."`; + exports[`ReadFileTool > getSchema > should return the base schema when no modelId is provided 1`] = `"Reads and returns the content of a specified file. If the file is large, the content will be truncated. The tool's response will clearly indicate if truncation has occurred and will provide details on how to read more of the file using the 'start_line' and 'end_line' parameters. Handles text, images (PNG, JPG, GIF, WEBP, SVG, BMP), audio files (MP3, WAV, AIFF, AAC, OGG, FLAC), and PDF files. For text files, it can read specific line ranges."`; exports[`ReadFileTool > getSchema > should return the schema from the resolver when modelId is provided 1`] = `"Reads and returns the content of a specified file. If the file is large, the content will be truncated. The tool's response will clearly indicate if truncation has occurred and will provide details on how to read more of the file using the 'start_line' and 'end_line' parameters. Handles text, images (PNG, JPG, GIF, WEBP, SVG, BMP), audio files (MP3, WAV, AIFF, AAC, OGG, FLAC), and PDF files. For text files, it can read specific line ranges."`; diff --git a/packages/core/src/tools/definitions/__snapshots__/coreToolsModelSnapshots.test.ts.snap b/packages/core/src/tools/definitions/__snapshots__/coreToolsModelSnapshots.test.ts.snap index 70cf828d86..e3a80eddd7 100644 --- a/packages/core/src/tools/definitions/__snapshots__/coreToolsModelSnapshots.test.ts.snap +++ b/packages/core/src/tools/definitions/__snapshots__/coreToolsModelSnapshots.test.ts.snap @@ -1197,7 +1197,7 @@ exports[`coreTools snapshots for specific models > Model: gemini-3-pro-preview > exports[`coreTools snapshots for specific models > Model: gemini-3-pro-preview > snapshot for tool: read_file 1`] = ` { - "description": "Reads and returns the content of a specified file. If the file is large, the content will be truncated. The tool's response will clearly indicate if truncation has occurred and will provide details on how to read more of the file using the 'start_line' and 'end_line' parameters. Handles text, images (PNG, JPG, GIF, WEBP, SVG, BMP), audio files (MP3, WAV, AIFF, AAC, OGG, FLAC), and PDF files. For text files, it can read specific line ranges.", + "description": "Reads and returns the content of a specified file. To maintain context efficiency, you MUST use 'start_line' and 'end_line' for targeted, surgical reads of specific sections. For your safety, the tool will automatically truncate output exceeding 2000 lines, 2000 characters per line, or 20MB in size; however, triggering these limits is considered token-inefficient. Always retrieve only the minimum content necessary for your next step. Handles text, images (PNG, JPG, GIF, WEBP, SVG, BMP), audio files (MP3, WAV, AIFF, AAC, OGG, FLAC), and PDF files.", "name": "read_file", "parametersJsonSchema": { "properties": { diff --git a/packages/core/src/tools/definitions/model-family-sets/gemini-3.ts b/packages/core/src/tools/definitions/model-family-sets/gemini-3.ts index d879e4fd43..2c0375baa3 100644 --- a/packages/core/src/tools/definitions/model-family-sets/gemini-3.ts +++ b/packages/core/src/tools/definitions/model-family-sets/gemini-3.ts @@ -79,6 +79,11 @@ import { getExitPlanModeDeclaration, getActivateSkillDeclaration, } from '../dynamic-declaration-helpers.js'; +import { + DEFAULT_MAX_LINES_TEXT_FILE, + MAX_LINE_LENGTH_TEXT_FILE, + MAX_FILE_SIZE_MB, +} from '../../../utils/constants.js'; /** * Gemini 3 tool set. Initially a copy of the default legacy set. @@ -86,7 +91,7 @@ import { export const GEMINI_3_SET: CoreToolSet = { read_file: { name: READ_FILE_TOOL_NAME, - description: `Reads and returns the content of a specified file. If the file is large, the content will be truncated. The tool's response will clearly indicate if truncation has occurred and will provide details on how to read more of the file using the 'start_line' and 'end_line' parameters. Handles text, images (PNG, JPG, GIF, WEBP, SVG, BMP), audio files (MP3, WAV, AIFF, AAC, OGG, FLAC), and PDF files. For text files, it can read specific line ranges.`, + description: `Reads and returns the content of a specified file. To maintain context efficiency, you MUST use 'start_line' and 'end_line' for targeted, surgical reads of specific sections. For your safety, the tool will automatically truncate output exceeding ${DEFAULT_MAX_LINES_TEXT_FILE} lines, ${MAX_LINE_LENGTH_TEXT_FILE} characters per line, or ${MAX_FILE_SIZE_MB}MB in size; however, triggering these limits is considered token-inefficient. Always retrieve only the minimum content necessary for your next step. Handles text, images (PNG, JPG, GIF, WEBP, SVG, BMP), audio files (MP3, WAV, AIFF, AAC, OGG, FLAC), and PDF files.`, parametersJsonSchema: { type: 'object', properties: { diff --git a/packages/core/src/tools/read-file.test.ts b/packages/core/src/tools/read-file.test.ts index 5457b8337b..8f79bffe17 100644 --- a/packages/core/src/tools/read-file.test.ts +++ b/packages/core/src/tools/read-file.test.ts @@ -588,5 +588,13 @@ describe('ReadFileTool', () => { expect(schema.name).toBe(ReadFileTool.Name); expect(schema.description).toMatchSnapshot(); }); + + it('should return the Gemini 3 schema when a Gemini 3 modelId is provided', () => { + const modelId = 'gemini-3-pro-preview'; + const schema = tool.getSchema(modelId); + expect(schema.name).toBe(ReadFileTool.Name); + expect(schema.description).toMatchSnapshot(); + expect(schema.description).toContain('surgical reads'); + }); }); }); diff --git a/packages/core/src/utils/constants.ts b/packages/core/src/utils/constants.ts index e11cbb67c1..7c47f77d03 100644 --- a/packages/core/src/utils/constants.ts +++ b/packages/core/src/utils/constants.ts @@ -6,3 +6,7 @@ export const REFERENCE_CONTENT_START = '--- Content from referenced files ---'; export const REFERENCE_CONTENT_END = '--- End of content ---'; + +export const DEFAULT_MAX_LINES_TEXT_FILE = 2000; +export const MAX_LINE_LENGTH_TEXT_FILE = 2000; +export const MAX_FILE_SIZE_MB = 20; diff --git a/packages/core/src/utils/fileUtils.ts b/packages/core/src/utils/fileUtils.ts index 42119c3f18..2497439a63 100644 --- a/packages/core/src/utils/fileUtils.ts +++ b/packages/core/src/utils/fileUtils.ts @@ -15,6 +15,11 @@ import { ToolErrorType } from '../tools/tool-error.js'; import { BINARY_EXTENSIONS } from './ignorePatterns.js'; import { createRequire as createModuleRequire } from 'node:module'; import { debugLogger } from './debugLogger.js'; +import { + DEFAULT_MAX_LINES_TEXT_FILE, + MAX_LINE_LENGTH_TEXT_FILE, + MAX_FILE_SIZE_MB, +} from './constants.js'; const requireModule = createModuleRequire(import.meta.url); @@ -52,10 +57,6 @@ export async function loadWasmBinary( } } -// Constants for text file processing -export const DEFAULT_MAX_LINES_TEXT_FILE = 2000; -const MAX_LINE_LENGTH_TEXT_FILE = 2000; - // Default values for encoding and separator format export const DEFAULT_ENCODING: BufferEncoding = 'utf-8'; @@ -434,11 +435,11 @@ export async function processSingleFileContent( } const fileSizeInMB = stats.size / (1024 * 1024); - if (fileSizeInMB > 20) { + if (fileSizeInMB > MAX_FILE_SIZE_MB) { return { - llmContent: 'File size exceeds the 20MB limit.', - returnDisplay: 'File size exceeds the 20MB limit.', - error: `File size exceeds the 20MB limit: ${filePath} (${fileSizeInMB.toFixed(2)}MB)`, + llmContent: `File size exceeds the ${MAX_FILE_SIZE_MB}MB limit.`, + returnDisplay: `File size exceeds the ${MAX_FILE_SIZE_MB}MB limit.`, + error: `File size exceeds the ${MAX_FILE_SIZE_MB}MB limit: ${filePath} (${fileSizeInMB.toFixed(2)}MB)`, errorType: ToolErrorType.FILE_TOO_LARGE, }; }