Remove unnecessary FileErrorType. (#6697)

This commit is contained in:
Tommaso Sciortino 2025-08-20 16:13:29 -07:00 committed by GitHub
parent 6eb6560d42
commit 0193ce77dd
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 23 additions and 62 deletions

View File

@ -219,7 +219,7 @@ describe('ReadFileTool', () => {
returnDisplay: 'Path is a directory.', returnDisplay: 'Path is a directory.',
error: { error: {
message: `Path is a directory, not a file: ${dirPath}`, message: `Path is a directory, not a file: ${dirPath}`,
type: ToolErrorType.INVALID_TOOL_PARAMS, type: ToolErrorType.TARGET_IS_DIRECTORY,
}, },
}); });
}); });

View File

@ -14,7 +14,7 @@ import {
ToolLocation, ToolLocation,
ToolResult, ToolResult,
} from './tools.js'; } from './tools.js';
import { ToolErrorType } from './tool-error.js';
import { PartUnion } from '@google/genai'; import { PartUnion } from '@google/genai';
import { import {
processSingleFileContent, processSingleFileContent,
@ -79,44 +79,12 @@ class ReadFileToolInvocation extends BaseToolInvocation<
); );
if (result.error) { if (result.error) {
// Map error messages to ToolErrorType
let errorType: ToolErrorType;
let llmContent: string;
// Check error message patterns to determine error type
if (
result.error.includes('File not found') ||
result.error.includes('does not exist') ||
result.error.includes('ENOENT')
) {
errorType = ToolErrorType.FILE_NOT_FOUND;
llmContent =
'Could not read file because no file was found at the specified path.';
} else if (
result.error.includes('is a directory') ||
result.error.includes('EISDIR')
) {
errorType = ToolErrorType.INVALID_TOOL_PARAMS;
llmContent =
'Could not read file because the provided path is a directory, not a file.';
} else if (
result.error.includes('too large') ||
result.error.includes('File size exceeds')
) {
errorType = ToolErrorType.FILE_TOO_LARGE;
llmContent = `Could not read file. ${result.error}`;
} else {
// Other read errors map to READ_CONTENT_FAILURE
errorType = ToolErrorType.READ_CONTENT_FAILURE;
llmContent = `Could not read file. ${result.error}`;
}
return { return {
llmContent, llmContent: result.llmContent,
returnDisplay: result.returnDisplay || 'Error reading file', returnDisplay: result.returnDisplay || 'Error reading file',
error: { error: {
message: result.error, message: result.error,
type: errorType, type: result.errorType,
}, },
}; };
} }

View File

@ -21,6 +21,7 @@ import {
processSingleFileContent, processSingleFileContent,
DEFAULT_ENCODING, DEFAULT_ENCODING,
getSpecificMimeType, getSpecificMimeType,
ProcessedFileReadResult,
} from '../utils/fileUtils.js'; } from '../utils/fileUtils.js';
import { PartListUnion } from '@google/genai'; import { PartListUnion } from '@google/genai';
import { Config, DEFAULT_FILE_FILTERING_OPTIONS } from '../config/config.js'; import { Config, DEFAULT_FILE_FILTERING_OPTIONS } from '../config/config.js';
@ -84,9 +85,7 @@ type FileProcessingResult =
success: true; success: true;
filePath: string; filePath: string;
relativePathForDisplay: string; relativePathForDisplay: string;
fileReadResult: NonNullable< fileReadResult: ProcessedFileReadResult;
Awaited<ReturnType<typeof processSingleFileContent>>
>;
reason?: undefined; reason?: undefined;
} }
| { | {

View File

@ -9,6 +9,7 @@ import path from 'node:path';
import { PartUnion } from '@google/genai'; import { PartUnion } from '@google/genai';
import mime from 'mime-types'; import mime from 'mime-types';
import { FileSystemService } from '../services/fileSystemService.js'; import { FileSystemService } from '../services/fileSystemService.js';
import { ToolErrorType } from '../tools/tool-error.js';
// Constants for text file processing // Constants for text file processing
const DEFAULT_MAX_LINES_TEXT_FILE = 2000; const DEFAULT_MAX_LINES_TEXT_FILE = 2000;
@ -196,18 +197,11 @@ export async function detectFileType(
return 'text'; return 'text';
} }
export enum FileErrorType {
FILE_NOT_FOUND = 'FILE_NOT_FOUND',
IS_DIRECTORY = 'IS_DIRECTORY',
FILE_TOO_LARGE = 'FILE_TOO_LARGE',
READ_ERROR = 'READ_ERROR',
}
export interface ProcessedFileReadResult { export interface ProcessedFileReadResult {
llmContent: PartUnion; // string for text, Part for image/pdf/unreadable binary llmContent: PartUnion; // string for text, Part for image/pdf/unreadable binary
returnDisplay: string; returnDisplay: string;
error?: string; // Optional error message for the LLM if file processing failed error?: string; // Optional error message for the LLM if file processing failed
errorType?: FileErrorType; // Structured error type using enum errorType?: ToolErrorType; // Structured error type
isTruncated?: boolean; // For text files, indicates if content was truncated isTruncated?: boolean; // For text files, indicates if content was truncated
originalLineCount?: number; // For text files originalLineCount?: number; // For text files
linesShown?: [number, number]; // For text files [startLine, endLine] (1-based for display) linesShown?: [number, number]; // For text files [startLine, endLine] (1-based for display)
@ -232,33 +226,32 @@ export async function processSingleFileContent(
if (!fs.existsSync(filePath)) { if (!fs.existsSync(filePath)) {
// Sync check is acceptable before async read // Sync check is acceptable before async read
return { return {
llmContent: '', llmContent:
'Could not read file because no file was found at the specified path.',
returnDisplay: 'File not found.', returnDisplay: 'File not found.',
error: `File not found: ${filePath}`, error: `File not found: ${filePath}`,
errorType: FileErrorType.FILE_NOT_FOUND, errorType: ToolErrorType.FILE_NOT_FOUND,
}; };
} }
const stats = await fs.promises.stat(filePath); const stats = await fs.promises.stat(filePath);
if (stats.isDirectory()) { if (stats.isDirectory()) {
return { return {
llmContent: '', llmContent:
'Could not read file because the provided path is a directory, not a file.',
returnDisplay: 'Path is a directory.', returnDisplay: 'Path is a directory.',
error: `Path is a directory, not a file: ${filePath}`, error: `Path is a directory, not a file: ${filePath}`,
errorType: FileErrorType.IS_DIRECTORY, errorType: ToolErrorType.TARGET_IS_DIRECTORY,
}; };
} }
const fileSizeInBytes = stats.size; const fileSizeInMB = stats.size / (1024 * 1024);
// 20MB limit if (fileSizeInMB > 20) {
const maxFileSize = 20 * 1024 * 1024; return {
llmContent: 'File size exceeds the 20MB limit.',
if (fileSizeInBytes > maxFileSize) { returnDisplay: 'File size exceeds the 20MB limit.',
throw new Error( error: `File size exceeds the 20MB limit: ${filePath} (${fileSizeInMB.toFixed(2)}MB)`,
`File size exceeds the 20MB limit: ${filePath} (${( errorType: ToolErrorType.FILE_TOO_LARGE,
fileSizeInBytes / };
(1024 * 1024)
).toFixed(2)}MB)`,
);
} }
const fileType = await detectFileType(filePath); const fileType = await detectFileType(filePath);
@ -373,6 +366,7 @@ export async function processSingleFileContent(
llmContent: `Error reading file ${displayPath}: ${errorMessage}`, llmContent: `Error reading file ${displayPath}: ${errorMessage}`,
returnDisplay: `Error reading file ${displayPath}: ${errorMessage}`, returnDisplay: `Error reading file ${displayPath}: ${errorMessage}`,
error: `Error reading file ${filePath}: ${errorMessage}`, error: `Error reading file ${filePath}: ${errorMessage}`,
errorType: ToolErrorType.READ_CONTENT_FAILURE,
}; };
} }
} }