mirror of
https://github.com/QwenLM/qwen-code.git
synced 2025-12-19 09:33:53 +00:00
Fix linting errors in a number of core and tool files (partial)
- As part of this work I also started building out errors.ts which will be a cumulation of error helpers to better handle the challenging `catch (error: unknown)` requirement. - More changes are to come, this is truly a partial change in order to not disrupt as many people as possible. Part of https://b.corp.google.com/issues/411384603
This commit is contained in:
committed by
N. Taylor Mullen
parent
93fd6a9160
commit
7cd3b95317
@@ -25,9 +25,9 @@ import { GeminiEventType, GeminiStream } from './gemini-stream.js';
|
|||||||
type ToolExecutionOutcome = {
|
type ToolExecutionOutcome = {
|
||||||
callId: string;
|
callId: string;
|
||||||
name: string;
|
name: string;
|
||||||
args: Record<string, any>;
|
args: Record<string, never>;
|
||||||
result?: ToolResult;
|
result?: ToolResult;
|
||||||
error?: any;
|
error?: Error;
|
||||||
confirmationDetails?: ToolCallConfirmationDetails;
|
confirmationDetails?: ToolCallConfirmationDetails;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -126,7 +126,7 @@ ${folderStructure}
|
|||||||
let pendingToolCalls: Array<{
|
let pendingToolCalls: Array<{
|
||||||
callId: string;
|
callId: string;
|
||||||
name: string;
|
name: string;
|
||||||
args: Record<string, any>;
|
args: Record<string, never>;
|
||||||
}> = [];
|
}> = [];
|
||||||
let yieldedTextInTurn = false;
|
let yieldedTextInTurn = false;
|
||||||
const chunksForDebug = [];
|
const chunksForDebug = [];
|
||||||
@@ -148,7 +148,7 @@ ${folderStructure}
|
|||||||
call.id ??
|
call.id ??
|
||||||
`${call.name}-${Date.now()}-${Math.random().toString(16).slice(2)}`;
|
`${call.name}-${Date.now()}-${Math.random().toString(16).slice(2)}`;
|
||||||
const name = call.name || 'undefined_tool_name';
|
const name = call.name || 'undefined_tool_name';
|
||||||
const args = (call.args || {}) as Record<string, any>;
|
const args = (call.args || {}) as Record<string, never>;
|
||||||
|
|
||||||
pendingToolCalls.push({ callId, name, args });
|
pendingToolCalls.push({ callId, name, args });
|
||||||
const evtValue: ToolCallEvent = {
|
const evtValue: ToolCallEvent = {
|
||||||
@@ -281,7 +281,7 @@ ${folderStructure}
|
|||||||
(executedTool: ToolExecutionOutcome): Part => {
|
(executedTool: ToolExecutionOutcome): Part => {
|
||||||
const { name, result, error } = executedTool;
|
const { name, result, error } = executedTool;
|
||||||
const output = { output: result?.llmContent };
|
const output = { output: result?.llmContent };
|
||||||
let toolOutcomePayload: any;
|
let toolOutcomePayload: Record<string, unknown>;
|
||||||
|
|
||||||
if (error) {
|
if (error) {
|
||||||
const errorMessage = error?.message || String(error);
|
const errorMessage = error?.message || String(error);
|
||||||
@@ -445,11 +445,11 @@ Respond *only* in JSON format according to the following schema. Do not include
|
|||||||
async generateJson(
|
async generateJson(
|
||||||
contents: Content[],
|
contents: Content[],
|
||||||
schema: SchemaUnion,
|
schema: SchemaUnion,
|
||||||
): Promise<any> {
|
): Promise<Record<string, unknown>> {
|
||||||
const model = getModel();
|
const model = getModel();
|
||||||
try {
|
try {
|
||||||
const result = await this.ai.models.generateContent({
|
const result = await this.ai.models.generateContent({
|
||||||
model: model,
|
model,
|
||||||
config: {
|
config: {
|
||||||
...this.defaultHyperParameters,
|
...this.defaultHyperParameters,
|
||||||
systemInstruction: CoreSystemPrompt,
|
systemInstruction: CoreSystemPrompt,
|
||||||
|
|||||||
@@ -154,14 +154,14 @@ export const processGeminiStream = async ({
|
|||||||
if (signal.aborted) {
|
if (signal.aborted) {
|
||||||
throw new Error('Request cancelled by user');
|
throw new Error('Request cancelled by user');
|
||||||
}
|
}
|
||||||
} catch (error: any) {
|
} catch (error: unknown) {
|
||||||
if (renderTimeoutId) {
|
if (renderTimeoutId) {
|
||||||
// Ensure render loop stops on error
|
// Ensure render loop stops on error
|
||||||
clearTimeout(renderTimeoutId);
|
clearTimeout(renderTimeoutId);
|
||||||
renderTimeoutId = null;
|
renderTimeoutId = null;
|
||||||
}
|
}
|
||||||
// Delegate history update for error message
|
// Delegate history update for error message
|
||||||
addErrorMessageToHistory(error, setHistory, getNextMessageId);
|
addErrorMessageToHistory(error as (Error | DOMException), setHistory, getNextMessageId);
|
||||||
} finally {
|
} finally {
|
||||||
isStreamComplete = true; // Signal stream end for render loop completion
|
isStreamComplete = true; // Signal stream end for render loop completion
|
||||||
if (renderTimeoutId) {
|
if (renderTimeoutId) {
|
||||||
|
|||||||
@@ -178,7 +178,7 @@ export const handleToolCallChunk = (
|
|||||||
* it to the last non-user message or creating a new entry.
|
* it to the last non-user message or creating a new entry.
|
||||||
*/
|
*/
|
||||||
export const addErrorMessageToHistory = (
|
export const addErrorMessageToHistory = (
|
||||||
error: any,
|
error: DOMException | Error,
|
||||||
setHistory: React.Dispatch<React.SetStateAction<HistoryItem[]>>,
|
setHistory: React.Dispatch<React.SetStateAction<HistoryItem[]>>,
|
||||||
getNextMessageId: () => number,
|
getNextMessageId: () => number,
|
||||||
): void => {
|
): void => {
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import {
|
|||||||
import { makeRelative, shortenPath } from '../utils/paths.js';
|
import { makeRelative, shortenPath } from '../utils/paths.js';
|
||||||
import { ReadFileTool } from './read-file.tool.js';
|
import { ReadFileTool } from './read-file.tool.js';
|
||||||
import { WriteFileTool } from './write-file.tool.js';
|
import { WriteFileTool } from './write-file.tool.js';
|
||||||
|
import { isNodeError } from '../utils/errors.js';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parameters for the Edit tool
|
* Parameters for the Edit tool
|
||||||
@@ -37,11 +38,6 @@ export interface EditToolParams {
|
|||||||
expected_replacements?: number;
|
expected_replacements?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Result from the Edit tool
|
|
||||||
*/
|
|
||||||
export interface EditToolResult extends ToolResult {}
|
|
||||||
|
|
||||||
interface CalculatedEdit {
|
interface CalculatedEdit {
|
||||||
currentContent: string | null;
|
currentContent: string | null;
|
||||||
newContent: string;
|
newContent: string;
|
||||||
@@ -54,7 +50,7 @@ interface CalculatedEdit {
|
|||||||
* Implementation of the Edit tool that modifies files.
|
* Implementation of the Edit tool that modifies files.
|
||||||
* This tool maintains state for the "Always Edit" confirmation preference.
|
* This tool maintains state for the "Always Edit" confirmation preference.
|
||||||
*/
|
*/
|
||||||
export class EditTool extends BaseTool<EditToolParams, EditToolResult> {
|
export class EditTool extends BaseTool<EditToolParams, ToolResult> {
|
||||||
private shouldAlwaysEdit = false;
|
private shouldAlwaysEdit = false;
|
||||||
private readonly rootDirectory: string;
|
private readonly rootDirectory: string;
|
||||||
|
|
||||||
@@ -174,8 +170,8 @@ export class EditTool extends BaseTool<EditToolParams, EditToolResult> {
|
|||||||
try {
|
try {
|
||||||
currentContent = fs.readFileSync(params.file_path, 'utf8');
|
currentContent = fs.readFileSync(params.file_path, 'utf8');
|
||||||
fileExists = true;
|
fileExists = true;
|
||||||
} catch (err: any) {
|
} catch (err: unknown) {
|
||||||
if (err.code !== 'ENOENT') {
|
if (!isNodeError(err) || err.code !== 'ENOENT') {
|
||||||
throw err;
|
throw err;
|
||||||
}
|
}
|
||||||
fileExists = false;
|
fileExists = false;
|
||||||
@@ -300,7 +296,7 @@ export class EditTool extends BaseTool<EditToolParams, EditToolResult> {
|
|||||||
* @param params Parameters for the edit operation
|
* @param params Parameters for the edit operation
|
||||||
* @returns Result of the edit operation
|
* @returns Result of the edit operation
|
||||||
*/
|
*/
|
||||||
async execute(params: EditToolParams): Promise<EditToolResult> {
|
async execute(params: EditToolParams): Promise<ToolResult> {
|
||||||
if (!this.validateParams(params)) {
|
if (!this.validateParams(params)) {
|
||||||
return {
|
return {
|
||||||
llmContent: 'Invalid parameters for file edit operation',
|
llmContent: 'Invalid parameters for file edit operation',
|
||||||
|
|||||||
@@ -20,16 +20,11 @@ export interface GlobToolParams {
|
|||||||
path?: string;
|
path?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Result from the GlobTool
|
|
||||||
*/
|
|
||||||
export interface GlobToolResult extends ToolResult {}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Implementation of the GlobTool that finds files matching patterns,
|
* Implementation of the GlobTool that finds files matching patterns,
|
||||||
* sorted by modification time (newest first).
|
* sorted by modification time (newest first).
|
||||||
*/
|
*/
|
||||||
export class GlobTool extends BaseTool<GlobToolParams, GlobToolResult> {
|
export class GlobTool extends BaseTool<GlobToolParams, ToolResult> {
|
||||||
/**
|
/**
|
||||||
* The root directory that this tool is grounded in.
|
* The root directory that this tool is grounded in.
|
||||||
* All file operations will be restricted to this directory.
|
* All file operations will be restricted to this directory.
|
||||||
@@ -125,9 +120,9 @@ export class GlobTool extends BaseTool<GlobToolParams, GlobToolResult> {
|
|||||||
if (!fs.statSync(searchDirAbsolute).isDirectory()) {
|
if (!fs.statSync(searchDirAbsolute).isDirectory()) {
|
||||||
return `Search path is not a directory: ${shortenPath(makeRelative(searchDirAbsolute, this.rootDirectory))} (absolute: ${searchDirAbsolute})`;
|
return `Search path is not a directory: ${shortenPath(makeRelative(searchDirAbsolute, this.rootDirectory))} (absolute: ${searchDirAbsolute})`;
|
||||||
}
|
}
|
||||||
} catch (e: any) {
|
} catch (e: unknown) {
|
||||||
// Catch potential permission errors during sync checks
|
// Catch potential permission errors during sync checks
|
||||||
return `Error accessing search path: ${e.message}`;
|
return `Error accessing search path: ${e}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validate glob pattern (basic non-empty check)
|
// Validate glob pattern (basic non-empty check)
|
||||||
@@ -165,7 +160,7 @@ export class GlobTool extends BaseTool<GlobToolParams, GlobToolResult> {
|
|||||||
* @param params Parameters for the glob search
|
* @param params Parameters for the glob search
|
||||||
* @returns Result of the glob search
|
* @returns Result of the glob search
|
||||||
*/
|
*/
|
||||||
async execute(params: GlobToolParams): Promise<GlobToolResult> {
|
async execute(params: GlobToolParams): Promise<ToolResult> {
|
||||||
const validationError = this.invalidParams(params);
|
const validationError = this.invalidParams(params);
|
||||||
if (validationError) {
|
if (validationError) {
|
||||||
return {
|
return {
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import fastGlob from 'fast-glob'; // Used for JS fallback file searching
|
|||||||
import { BaseTool, ToolResult } from './tools.js';
|
import { BaseTool, ToolResult } from './tools.js';
|
||||||
import { SchemaValidator } from '../utils/schemaValidator.js';
|
import { SchemaValidator } from '../utils/schemaValidator.js';
|
||||||
import { makeRelative, shortenPath } from '../utils/paths.js';
|
import { makeRelative, shortenPath } from '../utils/paths.js';
|
||||||
|
import { getErrorMessage, isNodeError } from '../utils/errors.js';
|
||||||
|
|
||||||
// --- Interfaces (kept separate for clarity) ---
|
// --- Interfaces (kept separate for clarity) ---
|
||||||
|
|
||||||
@@ -39,17 +40,12 @@ interface GrepMatch {
|
|||||||
line: string;
|
line: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Result from the GrepTool
|
|
||||||
*/
|
|
||||||
export interface GrepToolResult extends ToolResult {}
|
|
||||||
|
|
||||||
// --- GrepTool Class ---
|
// --- GrepTool Class ---
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Implementation of the GrepTool that searches file contents using git grep, system grep, or JS fallback.
|
* Implementation of the GrepTool that searches file contents using git grep, system grep, or JS fallback.
|
||||||
*/
|
*/
|
||||||
export class GrepTool extends BaseTool<GrepToolParams, GrepToolResult> {
|
export class GrepTool extends BaseTool<GrepToolParams, ToolResult> {
|
||||||
private rootDirectory: string;
|
private rootDirectory: string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -114,12 +110,12 @@ export class GrepTool extends BaseTool<GrepToolParams, GrepToolResult> {
|
|||||||
if (!stats.isDirectory()) {
|
if (!stats.isDirectory()) {
|
||||||
throw new Error(`Path is not a directory: ${targetPath}`);
|
throw new Error(`Path is not a directory: ${targetPath}`);
|
||||||
}
|
}
|
||||||
} catch (err: any) {
|
} catch (error: unknown) {
|
||||||
if (err.code === 'ENOENT') {
|
if (isNodeError(error) && error.code !== 'ENOENT') {
|
||||||
throw new Error(`Path does not exist: ${targetPath}`);
|
throw new Error(`Path does not exist: ${targetPath}`);
|
||||||
}
|
}
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`Failed to access path stats for ${targetPath}: ${err.message}`,
|
`Failed to access path stats for ${targetPath}: ${error}`,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -164,7 +160,7 @@ export class GrepTool extends BaseTool<GrepToolParams, GrepToolResult> {
|
|||||||
* @param params Parameters for the grep search
|
* @param params Parameters for the grep search
|
||||||
* @returns Result of the grep search
|
* @returns Result of the grep search
|
||||||
*/
|
*/
|
||||||
async execute(params: GrepToolParams): Promise<GrepToolResult> {
|
async execute(params: GrepToolParams): Promise<ToolResult> {
|
||||||
const validationError = this.invalidParams(params);
|
const validationError = this.invalidParams(params);
|
||||||
if (validationError) {
|
if (validationError) {
|
||||||
console.error(`GrepTool Parameter Validation Failed: ${validationError}`);
|
console.error(`GrepTool Parameter Validation Failed: ${validationError}`);
|
||||||
@@ -253,7 +249,7 @@ export class GrepTool extends BaseTool<GrepToolParams, GrepToolResult> {
|
|||||||
});
|
});
|
||||||
child.on('close', (code) => resolve(code === 0));
|
child.on('close', (code) => resolve(code === 0));
|
||||||
child.on('error', () => resolve(false));
|
child.on('error', () => resolve(false));
|
||||||
} catch (e) {
|
} catch {
|
||||||
resolve(false);
|
resolve(false);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -277,10 +273,10 @@ export class GrepTool extends BaseTool<GrepToolParams, GrepToolResult> {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
} catch (err: any) {
|
} catch (error: unknown) {
|
||||||
if (err.code !== 'ENOENT') {
|
if (!isNodeError(error) || error.code !== 'ENOENT') {
|
||||||
console.error(
|
console.error(
|
||||||
`Error checking for .git in ${currentPath}: ${err.message}`,
|
`Error checking for .git in ${currentPath}: ${error}`,
|
||||||
);
|
);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -291,9 +287,9 @@ export class GrepTool extends BaseTool<GrepToolParams, GrepToolResult> {
|
|||||||
}
|
}
|
||||||
currentPath = path.dirname(currentPath);
|
currentPath = path.dirname(currentPath);
|
||||||
}
|
}
|
||||||
} catch (err: any) {
|
} catch (error: unknown) {
|
||||||
console.error(
|
console.error(
|
||||||
`Error traversing directory structure upwards from ${dirPath}: ${err instanceof Error ? err.message : String(err)}`,
|
`Error traversing directory structure upwards from ${dirPath}: ${error instanceof Error ? error.message : error}`,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
@@ -446,9 +442,9 @@ export class GrepTool extends BaseTool<GrepToolParams, GrepToolResult> {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
return this.parseGrepOutput(output, absolutePath);
|
return this.parseGrepOutput(output, absolutePath);
|
||||||
} catch (gitError: any) {
|
} catch (gitError: unknown) {
|
||||||
console.error(
|
console.error(
|
||||||
`GrepTool: git grep strategy failed: ${gitError.message}. Falling back...`,
|
`GrepTool: git grep strategy failed: ${getErrorMessage(gitError)}. Falling back...`,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -512,9 +508,9 @@ export class GrepTool extends BaseTool<GrepToolParams, GrepToolResult> {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
return this.parseGrepOutput(output, absolutePath);
|
return this.parseGrepOutput(output, absolutePath);
|
||||||
} catch (grepError: any) {
|
} catch (grepError: unknown) {
|
||||||
console.error(
|
console.error(
|
||||||
`GrepTool: System grep strategy failed: ${grepError.message}. Falling back...`,
|
`GrepTool: System grep strategy failed: ${getErrorMessage(grepError)}. Falling back...`,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -559,19 +555,19 @@ export class GrepTool extends BaseTool<GrepToolParams, GrepToolResult> {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} catch (readError: any) {
|
} catch (readError: unknown) {
|
||||||
if (readError.code !== 'ENOENT') {
|
if (!isNodeError(readError) || readError.code !== 'ENOENT') {
|
||||||
console.error(
|
console.error(
|
||||||
`GrepTool: Could not read or process file ${fileAbsolutePath}: ${readError.message}`,
|
`GrepTool: Could not read or process file ${fileAbsolutePath}: ${getErrorMessage(readError)}`,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return allMatches;
|
return allMatches;
|
||||||
} catch (error: any) {
|
} catch (error: unknown) {
|
||||||
console.error(
|
console.error(
|
||||||
`GrepTool: Error during performGrepSearch (Strategy: ${strategyUsed}): ${error.message}`,
|
`GrepTool: Error during performGrepSearch (Strategy: ${strategyUsed}): ${getErrorMessage(error)}`,
|
||||||
);
|
);
|
||||||
throw error; // Re-throw to be caught by the execute method's handler
|
throw error; // Re-throw to be caught by the execute method's handler
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,17 +24,12 @@ export interface ReadFileToolParams {
|
|||||||
limit?: number;
|
limit?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Standardized result from the ReadFile tool
|
|
||||||
*/
|
|
||||||
export interface ReadFileToolResult extends ToolResult {}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Implementation of the ReadFile tool that reads files from the filesystem
|
* Implementation of the ReadFile tool that reads files from the filesystem
|
||||||
*/
|
*/
|
||||||
export class ReadFileTool extends BaseTool<
|
export class ReadFileTool extends BaseTool<
|
||||||
ReadFileToolParams,
|
ReadFileToolParams,
|
||||||
ReadFileToolResult
|
ToolResult
|
||||||
> {
|
> {
|
||||||
static readonly Name: string = 'read_file';
|
static readonly Name: string = 'read_file';
|
||||||
|
|
||||||
@@ -166,7 +161,7 @@ export class ReadFileTool extends BaseTool<
|
|||||||
|
|
||||||
// If more than 30% are non-printable, likely binary
|
// If more than 30% are non-printable, likely binary
|
||||||
return nonPrintableCount / bytesRead > 0.3;
|
return nonPrintableCount / bytesRead > 0.3;
|
||||||
} catch (error) {
|
} catch {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -214,7 +209,7 @@ export class ReadFileTool extends BaseTool<
|
|||||||
* @param params Parameters for the file reading
|
* @param params Parameters for the file reading
|
||||||
* @returns Result with file contents
|
* @returns Result with file contents
|
||||||
*/
|
*/
|
||||||
async execute(params: ReadFileToolParams): Promise<ReadFileToolResult> {
|
async execute(params: ReadFileToolParams): Promise<ToolResult> {
|
||||||
const validationError = this.invalidParams(params);
|
const validationError = this.invalidParams(params);
|
||||||
const filePath = params.file_path;
|
const filePath = params.file_path;
|
||||||
if (validationError) {
|
if (validationError) {
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ export interface ToolCallEvent {
|
|||||||
status: ToolCallStatus;
|
status: ToolCallStatus;
|
||||||
callId: string;
|
callId: string;
|
||||||
name: string;
|
name: string;
|
||||||
args: Record<string, any>;
|
args: Record<string, never>;
|
||||||
resultDisplay: ToolResultDisplay | undefined;
|
resultDisplay: ToolResultDisplay | undefined;
|
||||||
confirmationDetails: ToolCallConfirmationDetails | undefined;
|
confirmationDetails: ToolCallConfirmationDetails | undefined;
|
||||||
}
|
}
|
||||||
|
|||||||
18
packages/cli/src/utils/errors.ts
Normal file
18
packages/cli/src/utils/errors.ts
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
export function isNodeError(error: unknown): error is NodeJS.ErrnoException {
|
||||||
|
return error instanceof Error && 'code' in error;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getErrorMessage(error: unknown): string {
|
||||||
|
if (error instanceof Error) {
|
||||||
|
return error.message;
|
||||||
|
} else {
|
||||||
|
// Attempt to convert the non-Error value to a string for logging
|
||||||
|
try {
|
||||||
|
const errorMessage = String(error);
|
||||||
|
return errorMessage;
|
||||||
|
} catch {
|
||||||
|
// If String() itself fails (highly unlikely)
|
||||||
|
return 'Failed to get error details';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user