Improve readability issues
This is only the first change of many changes. * Remove redundant autogenerated comments * Use the recommended file name style * Use camelCase for variable names * Don't introduce submodules for relevant types * Don't introduce constants like modules, these are implementation details * Remove empty files
This commit is contained in:
parent
898a83031c
commit
81ba61df7f
|
@ -1,22 +0,0 @@
|
||||||
import { ToolCallEvent } from "../ui/types.js";
|
|
||||||
|
|
||||||
export enum GeminiEventType {
|
|
||||||
Content,
|
|
||||||
ToolCallInfo,
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface GeminiContentEvent {
|
|
||||||
type: GeminiEventType.Content;
|
|
||||||
value: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface GeminiToolCallInfoEvent {
|
|
||||||
type: GeminiEventType.ToolCallInfo;
|
|
||||||
value: ToolCallEvent;
|
|
||||||
}
|
|
||||||
|
|
||||||
export type GeminiEvent =
|
|
||||||
| GeminiContentEvent
|
|
||||||
| GeminiToolCallInfoEvent;
|
|
||||||
|
|
||||||
export type GeminiStream = AsyncIterable<GeminiEvent>;
|
|
|
@ -1,4 +0,0 @@
|
||||||
export enum StreamingState {
|
|
||||||
Idle,
|
|
||||||
Responding,
|
|
||||||
}
|
|
|
@ -1 +0,0 @@
|
||||||
export const MEMORY_FILE_NAME = 'GEMINI.md';
|
|
|
@ -10,9 +10,9 @@ import { CoreSystemPrompt } from './prompts.js';
|
||||||
import { type ToolCallEvent, type ToolCallConfirmationDetails, ToolCallStatus } from '../ui/types.js';
|
import { type ToolCallEvent, type ToolCallConfirmationDetails, ToolCallStatus } from '../ui/types.js';
|
||||||
import process from 'node:process';
|
import process from 'node:process';
|
||||||
import { toolRegistry } from '../tools/tool-registry.js';
|
import { toolRegistry } from '../tools/tool-registry.js';
|
||||||
import { ToolResult } from '../tools/ToolResult.js';
|
import { ToolResult } from '../tools/tool.js';
|
||||||
import { getFolderStructure } from '../utils/getFolderStructure.js';
|
import { getFolderStructure } from '../utils/getFolderStructure.js';
|
||||||
import { GeminiEventType, GeminiStream } from './GeminiStream.js';
|
import { GeminiEventType, GeminiStream } from './gemini-stream.js';
|
||||||
|
|
||||||
type ToolExecutionOutcome = {
|
type ToolExecutionOutcome = {
|
||||||
callId: string;
|
callId: string;
|
||||||
|
@ -62,7 +62,7 @@ ${folderStructure}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const chat = this.ai.chats.create({
|
const chat = this.ai.chats.create({
|
||||||
model: 'gemini-2.5-pro-preview-03-25',//'gemini-2.0-flash',
|
model: 'gemini-2.0-flash',//'gemini-2.0-flash',
|
||||||
config: {
|
config: {
|
||||||
systemInstruction: CoreSystemPrompt,
|
systemInstruction: CoreSystemPrompt,
|
||||||
...this.defaultHyperParameters,
|
...this.defaultHyperParameters,
|
|
@ -1,7 +1,33 @@
|
||||||
|
import { ToolCallEvent } from "../ui/types.js";
|
||||||
import { Part } from '@google/genai';
|
import { Part } from '@google/genai';
|
||||||
import { HistoryItem } from '../ui/types.js';
|
import { HistoryItem } from '../ui/types.js';
|
||||||
import { GeminiEventType, GeminiStream } from './GeminiStream.js';
|
import { handleToolCallChunk, addErrorMessageToHistory } from './history-updater.js';
|
||||||
import { handleToolCallChunk, addErrorMessageToHistory } from './historyUpdater.js';
|
|
||||||
|
export enum GeminiEventType {
|
||||||
|
Content,
|
||||||
|
ToolCallInfo,
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface GeminiContentEvent {
|
||||||
|
type: GeminiEventType.Content;
|
||||||
|
value: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface GeminiToolCallInfoEvent {
|
||||||
|
type: GeminiEventType.ToolCallInfo;
|
||||||
|
value: ToolCallEvent;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type GeminiEvent =
|
||||||
|
| GeminiContentEvent
|
||||||
|
| GeminiToolCallInfoEvent;
|
||||||
|
|
||||||
|
export type GeminiStream = AsyncIterable<GeminiEvent>;
|
||||||
|
|
||||||
|
export enum StreamingState {
|
||||||
|
Idle,
|
||||||
|
Responding,
|
||||||
|
}
|
||||||
|
|
||||||
interface StreamProcessorParams {
|
interface StreamProcessorParams {
|
||||||
stream: GeminiStream;
|
stream: GeminiStream;
|
||||||
|
@ -104,7 +130,6 @@ export const processGeminiStream = async ({ // Renamed function for clarity
|
||||||
clearTimeout(renderTimeoutId);
|
clearTimeout(renderTimeoutId);
|
||||||
renderTimeoutId = null;
|
renderTimeoutId = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Flush any text buffer content.
|
// Flush any text buffer content.
|
||||||
render(textBuffer);
|
render(textBuffer);
|
||||||
currentGeminiMessageId = null; // End text message context
|
currentGeminiMessageId = null; // End text message context
|
|
@ -1,7 +1,7 @@
|
||||||
import { Part } from "@google/genai";
|
import { Part } from "@google/genai";
|
||||||
import { toolRegistry } from "../tools/tool-registry.js";
|
import { toolRegistry } from "../tools/tool-registry.js";
|
||||||
import { HistoryItem, IndividualToolCallDisplay, ToolCallEvent, ToolCallStatus, ToolConfirmationOutcome, ToolEditConfirmationDetails, ToolExecuteConfirmationDetails } from "../ui/types.js";
|
import { HistoryItem, IndividualToolCallDisplay, ToolCallEvent, ToolCallStatus, ToolConfirmationOutcome, ToolEditConfirmationDetails, ToolExecuteConfirmationDetails } from "../ui/types.js";
|
||||||
import { ToolResultDisplay } from "../tools/ToolResult.js";
|
import { ToolResultDisplay } from "../tools/tool.js";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Processes a tool call chunk and updates the history state accordingly.
|
* Processes a tool call chunk and updates the history state accordingly.
|
||||||
|
@ -46,13 +46,9 @@ export const handleToolCallChunk = (
|
||||||
if (!tool) {
|
if (!tool) {
|
||||||
throw new Error(`Tool "${chunk.name}" not found or is not registered.`);
|
throw new Error(`Tool "${chunk.name}" not found or is not registered.`);
|
||||||
}
|
}
|
||||||
|
|
||||||
handleToolCallChunk({ ...chunk, status: ToolCallStatus.Invoked, resultDisplay: "Executing...", confirmationDetails: undefined }, setHistory, submitQuery, getNextMessageId, currentToolGroupIdRef);
|
handleToolCallChunk({ ...chunk, status: ToolCallStatus.Invoked, resultDisplay: "Executing...", confirmationDetails: undefined }, setHistory, submitQuery, getNextMessageId, currentToolGroupIdRef);
|
||||||
|
|
||||||
const result = await tool.execute(chunk.args);
|
const result = await tool.execute(chunk.args);
|
||||||
|
|
||||||
handleToolCallChunk({ ...chunk, status: ToolCallStatus.Invoked, resultDisplay: result.returnDisplay, confirmationDetails: undefined }, setHistory, submitQuery, getNextMessageId, currentToolGroupIdRef);
|
handleToolCallChunk({ ...chunk, status: ToolCallStatus.Invoked, resultDisplay: result.returnDisplay, confirmationDetails: undefined }, setHistory, submitQuery, getNextMessageId, currentToolGroupIdRef);
|
||||||
|
|
||||||
const functionResponse: Part = {
|
const functionResponse: Part = {
|
||||||
functionResponse: {
|
functionResponse: {
|
||||||
name: chunk.name,
|
name: chunk.name,
|
||||||
|
@ -60,7 +56,6 @@ export const handleToolCallChunk = (
|
||||||
response: { "output": result.llmContent },
|
response: { "output": result.llmContent },
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
await submitQuery(functionResponse);
|
await submitQuery(functionResponse);
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,6 +1,7 @@
|
||||||
import { ReadFileTool } from "../tools/read-file.tool.js";
|
import { ReadFileTool } from "../tools/read-file.tool.js";
|
||||||
import { TerminalTool } from "../tools/terminal.tool.js";
|
import { TerminalTool } from "../tools/terminal.tool.js";
|
||||||
import { MEMORY_FILE_NAME } from "./constants.js";
|
|
||||||
|
const MEMORY_FILE_NAME = 'GEMINI.md';
|
||||||
|
|
||||||
const contactEmail = 'ntaylormullen@google.com';
|
const contactEmail = 'ntaylormullen@google.com';
|
||||||
export const CoreSystemPrompt = `
|
export const CoreSystemPrompt = `
|
||||||
|
|
|
@ -1,73 +0,0 @@
|
||||||
import type { FunctionDeclaration, Schema } from '@google/genai';
|
|
||||||
import { ToolResult } from './ToolResult.js';
|
|
||||||
import { Tool } from './Tool.js';
|
|
||||||
import { ToolCallConfirmationDetails } from '../ui/types.js';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Base implementation for tools with common functionality
|
|
||||||
*/
|
|
||||||
export abstract class BaseTool<TParams = unknown, TResult extends ToolResult = ToolResult> implements Tool<TParams, TResult> {
|
|
||||||
/**
|
|
||||||
* Creates a new instance of BaseTool
|
|
||||||
* @param name Internal name of the tool (used for API calls)
|
|
||||||
* @param displayName User-friendly display name of the tool
|
|
||||||
* @param description Description of what the tool does
|
|
||||||
* @param parameterSchema JSON Schema defining the parameters
|
|
||||||
*/
|
|
||||||
constructor(
|
|
||||||
public readonly name: string,
|
|
||||||
public readonly displayName: string,
|
|
||||||
public readonly description: string,
|
|
||||||
public readonly parameterSchema: Record<string, unknown>
|
|
||||||
) {}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Function declaration schema computed from name, description, and parameterSchema
|
|
||||||
*/
|
|
||||||
get schema(): FunctionDeclaration {
|
|
||||||
return {
|
|
||||||
name: this.name,
|
|
||||||
description: this.description,
|
|
||||||
parameters: this.parameterSchema as Schema
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Validates the parameters for the tool
|
|
||||||
* This is a placeholder implementation and should be overridden
|
|
||||||
* @param params Parameters to validate
|
|
||||||
* @returns An error message string if invalid, null otherwise
|
|
||||||
*/
|
|
||||||
invalidParams(params: TParams): string | null {
|
|
||||||
// Implementation would typically use a JSON Schema validator
|
|
||||||
// This is a placeholder that should be implemented by derived classes
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets a pre-execution description of the tool operation
|
|
||||||
* Default implementation that should be overridden by derived classes
|
|
||||||
* @param params Parameters for the tool execution
|
|
||||||
* @returns A markdown string describing what the tool will do
|
|
||||||
*/
|
|
||||||
getDescription(params: TParams): string {
|
|
||||||
return JSON.stringify(params);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Determines if the tool should prompt for confirmation before execution
|
|
||||||
* @param params Parameters for the tool execution
|
|
||||||
* @returns Whether or not execute should be confirmed by the user.
|
|
||||||
*/
|
|
||||||
shouldConfirmExecute(params: TParams): Promise<ToolCallConfirmationDetails | false> {
|
|
||||||
return Promise.resolve(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Abstract method to execute the tool with the given parameters
|
|
||||||
* Must be implemented by derived classes
|
|
||||||
* @param params Parameters for the tool execution
|
|
||||||
* @returns Result of the tool execution
|
|
||||||
*/
|
|
||||||
abstract execute(params: TParams): Promise<TResult>;
|
|
||||||
}
|
|
|
@ -1,5 +1,4 @@
|
||||||
import { FunctionDeclaration } from "@google/genai";
|
import { FunctionDeclaration, Schema } from "@google/genai";
|
||||||
import { ToolResult } from "./ToolResult.js";
|
|
||||||
import { ToolCallConfirmationDetails } from "../ui/types.js";
|
import { ToolCallConfirmationDetails } from "../ui/types.js";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -25,14 +24,14 @@ export interface Tool<TParams = unknown, TResult extends ToolResult = ToolResult
|
||||||
* Function declaration schema from @google/genai
|
* Function declaration schema from @google/genai
|
||||||
*/
|
*/
|
||||||
schema: FunctionDeclaration;
|
schema: FunctionDeclaration;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Validates the parameters for the tool
|
* Validates the parameters for the tool
|
||||||
* @param params Parameters to validate
|
* @param params Parameters to validate
|
||||||
* @returns An error message string if invalid, null otherwise
|
* @returns An error message string if invalid, null otherwise
|
||||||
*/
|
*/
|
||||||
invalidParams(params: TParams): string | null;
|
invalidParams(params: TParams): string | null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets a pre-execution description of the tool operation
|
* Gets a pre-execution description of the tool operation
|
||||||
* @param params Parameters for the tool execution
|
* @param params Parameters for the tool execution
|
||||||
|
@ -47,7 +46,7 @@ export interface Tool<TParams = unknown, TResult extends ToolResult = ToolResult
|
||||||
* @returns Whether execute should be confirmed.
|
* @returns Whether execute should be confirmed.
|
||||||
*/
|
*/
|
||||||
shouldConfirmExecute(params: TParams): Promise<ToolCallConfirmationDetails | false>;
|
shouldConfirmExecute(params: TParams): Promise<ToolCallConfirmationDetails | false>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Executes the tool with the given parameters
|
* Executes the tool with the given parameters
|
||||||
* @param params Parameters for the tool execution
|
* @param params Parameters for the tool execution
|
||||||
|
@ -55,3 +54,94 @@ export interface Tool<TParams = unknown, TResult extends ToolResult = ToolResult
|
||||||
*/
|
*/
|
||||||
execute(params: TParams): Promise<TResult>;
|
execute(params: TParams): Promise<TResult>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Base implementation for tools with common functionality
|
||||||
|
*/
|
||||||
|
export abstract class BaseTool<TParams = unknown, TResult extends ToolResult = ToolResult> implements Tool<TParams, TResult> {
|
||||||
|
/**
|
||||||
|
* Creates a new instance of BaseTool
|
||||||
|
* @param name Internal name of the tool (used for API calls)
|
||||||
|
* @param displayName User-friendly display name of the tool
|
||||||
|
* @param description Description of what the tool does
|
||||||
|
* @param parameterSchema JSON Schema defining the parameters
|
||||||
|
*/
|
||||||
|
constructor(
|
||||||
|
public readonly name: string,
|
||||||
|
public readonly displayName: string,
|
||||||
|
public readonly description: string,
|
||||||
|
public readonly parameterSchema: Record<string, unknown>
|
||||||
|
) {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function declaration schema computed from name, description, and parameterSchema
|
||||||
|
*/
|
||||||
|
get schema(): FunctionDeclaration {
|
||||||
|
return {
|
||||||
|
name: this.name,
|
||||||
|
description: this.description,
|
||||||
|
parameters: this.parameterSchema as Schema
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validates the parameters for the tool
|
||||||
|
* This is a placeholder implementation and should be overridden
|
||||||
|
* @param params Parameters to validate
|
||||||
|
* @returns An error message string if invalid, null otherwise
|
||||||
|
*/
|
||||||
|
invalidParams(params: TParams): string | null {
|
||||||
|
// Implementation would typically use a JSON Schema validator
|
||||||
|
// This is a placeholder that should be implemented by derived classes
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets a pre-execution description of the tool operation
|
||||||
|
* Default implementation that should be overridden by derived classes
|
||||||
|
* @param params Parameters for the tool execution
|
||||||
|
* @returns A markdown string describing what the tool will do
|
||||||
|
*/
|
||||||
|
getDescription(params: TParams): string {
|
||||||
|
return JSON.stringify(params);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determines if the tool should prompt for confirmation before execution
|
||||||
|
* @param params Parameters for the tool execution
|
||||||
|
* @returns Whether or not execute should be confirmed by the user.
|
||||||
|
*/
|
||||||
|
shouldConfirmExecute(params: TParams): Promise<ToolCallConfirmationDetails | false> {
|
||||||
|
return Promise.resolve(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Abstract method to execute the tool with the given parameters
|
||||||
|
* Must be implemented by derived classes
|
||||||
|
* @param params Parameters for the tool execution
|
||||||
|
* @returns Result of the tool execution
|
||||||
|
*/
|
||||||
|
abstract execute(params: TParams): Promise<TResult>;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export interface ToolResult {
|
||||||
|
/**
|
||||||
|
* Content meant to be included in LLM history.
|
||||||
|
* This should represent the factual outcome of the tool execution.
|
||||||
|
*/
|
||||||
|
llmContent: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Markdown string for user display.
|
||||||
|
* This provides a user-friendly summary or visualization of the result.
|
||||||
|
*/
|
||||||
|
returnDisplay: ToolResultDisplay;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type ToolResultDisplay = string | FileDiff;
|
||||||
|
|
||||||
|
export interface FileDiff {
|
||||||
|
fileDiff: string
|
||||||
|
}
|
||||||
|
|
|
@ -1,22 +0,0 @@
|
||||||
/**
|
|
||||||
* Standard tool result interface that all tools should implement
|
|
||||||
*/
|
|
||||||
export interface ToolResult {
|
|
||||||
/**
|
|
||||||
* Content meant to be included in LLM history.
|
|
||||||
* This should represent the factual outcome of the tool execution.
|
|
||||||
*/
|
|
||||||
llmContent: string;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Markdown string for user display.
|
|
||||||
* This provides a user-friendly summary or visualization of the result.
|
|
||||||
*/
|
|
||||||
returnDisplay: ToolResultDisplay;
|
|
||||||
}
|
|
||||||
|
|
||||||
export type ToolResultDisplay = string | FileDiff;
|
|
||||||
|
|
||||||
export interface FileDiff {
|
|
||||||
fileDiff: string
|
|
||||||
}
|
|
|
@ -2,8 +2,7 @@ import fs from 'fs';
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
import * as Diff from 'diff';
|
import * as Diff from 'diff';
|
||||||
import { SchemaValidator } from '../utils/schemaValidator.js';
|
import { SchemaValidator } from '../utils/schemaValidator.js';
|
||||||
import { ToolResult } from './ToolResult.js';
|
import { BaseTool, ToolResult } from './tool.js';
|
||||||
import { BaseTool } from './BaseTool.js';
|
|
||||||
import { ToolCallConfirmationDetails, ToolConfirmationOutcome, ToolEditConfirmationDetails } from '../ui/types.js';
|
import { ToolCallConfirmationDetails, ToolConfirmationOutcome, ToolEditConfirmationDetails } from '../ui/types.js';
|
||||||
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';
|
||||||
|
@ -67,7 +66,7 @@ export class EditTool extends BaseTool<EditToolParams, EditToolResult> {
|
||||||
`Replaces a SINGLE, UNIQUE occurrence of text within a file. Requires providing significant context around the change to ensure uniqueness. For moving/renaming files, use the Bash tool with \`mv\`. For replacing entire file contents or creating new files use the ${WriteFileTool.Name} tool. Always use the ${ReadFileTool.Name} tool to examine the file before using this tool.`,
|
`Replaces a SINGLE, UNIQUE occurrence of text within a file. Requires providing significant context around the change to ensure uniqueness. For moving/renaming files, use the Bash tool with \`mv\`. For replacing entire file contents or creating new files use the ${WriteFileTool.Name} tool. Always use the ${ReadFileTool.Name} tool to examine the file before using this tool.`,
|
||||||
{
|
{
|
||||||
properties: {
|
properties: {
|
||||||
file_path: {
|
filePath: {
|
||||||
description: 'The absolute path to the file to modify. Must start with /. When creating a new file, ensure the parent directory exists (use the `LS` tool to verify).',
|
description: 'The absolute path to the file to modify. Must start with /. When creating a new file, ensure the parent directory exists (use the `LS` tool to verify).',
|
||||||
type: 'string'
|
type: 'string'
|
||||||
},
|
},
|
||||||
|
|
|
@ -2,8 +2,7 @@ import fs from 'fs';
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
import fg from 'fast-glob';
|
import fg from 'fast-glob';
|
||||||
import { SchemaValidator } from '../utils/schemaValidator.js';
|
import { SchemaValidator } from '../utils/schemaValidator.js';
|
||||||
import { BaseTool } from './BaseTool.js';
|
import { BaseTool, ToolResult } from './tool.js';
|
||||||
import { ToolResult } from './ToolResult.js';
|
|
||||||
import { shortenPath, makeRelative } from '../utils/paths.js';
|
import { shortenPath, makeRelative } from '../utils/paths.js';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -4,8 +4,7 @@ import path from 'path';
|
||||||
import { EOL } from 'os'; // Used for parsing grep output lines
|
import { EOL } from 'os'; // Used for parsing grep output lines
|
||||||
import { spawn } from 'child_process'; // Used for git grep and system grep
|
import { spawn } from 'child_process'; // Used for git grep and system grep
|
||||||
import fastGlob from 'fast-glob'; // Used for JS fallback file searching
|
import fastGlob from 'fast-glob'; // Used for JS fallback file searching
|
||||||
import { ToolResult } from './ToolResult.js';
|
import { BaseTool, ToolResult } from './tool.js';
|
||||||
import { BaseTool } from './BaseTool.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';
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,7 @@
|
||||||
import fs from 'fs';
|
import fs from 'fs';
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
import { BaseTool } from './BaseTool.js';
|
import { BaseTool, ToolResult } from './tool.js';
|
||||||
import { SchemaValidator } from '../utils/schemaValidator.js';
|
import { SchemaValidator } from '../utils/schemaValidator.js';
|
||||||
import { ToolResult } from './ToolResult.js';
|
|
||||||
import { makeRelative, shortenPath } from '../utils/paths.js';
|
import { makeRelative, shortenPath } from '../utils/paths.js';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -13,7 +12,7 @@ export interface LSToolParams {
|
||||||
* The absolute path to the directory to list
|
* The absolute path to the directory to list
|
||||||
*/
|
*/
|
||||||
path: string;
|
path: string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* List of glob patterns to ignore
|
* List of glob patterns to ignore
|
||||||
*/
|
*/
|
||||||
|
@ -28,22 +27,22 @@ export interface FileEntry {
|
||||||
* Name of the file or directory
|
* Name of the file or directory
|
||||||
*/
|
*/
|
||||||
name: string;
|
name: string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Absolute path to the file or directory
|
* Absolute path to the file or directory
|
||||||
*/
|
*/
|
||||||
path: string;
|
path: string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether this entry is a directory
|
* Whether this entry is a directory
|
||||||
*/
|
*/
|
||||||
isDirectory: boolean;
|
isDirectory: boolean;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Size of the file in bytes (0 for directories)
|
* Size of the file in bytes (0 for directories)
|
||||||
*/
|
*/
|
||||||
size: number;
|
size: number;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Last modified timestamp
|
* Last modified timestamp
|
||||||
*/
|
*/
|
||||||
|
@ -58,12 +57,12 @@ export interface LSToolResult extends ToolResult {
|
||||||
* List of file entries
|
* List of file entries
|
||||||
*/
|
*/
|
||||||
entries: FileEntry[];
|
entries: FileEntry[];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The directory that was listed
|
* The directory that was listed
|
||||||
*/
|
*/
|
||||||
listedPath: string;
|
listedPath: string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Total number of entries found
|
* Total number of entries found
|
||||||
*/
|
*/
|
||||||
|
@ -120,15 +119,13 @@ export class LSTool extends BaseTool<LSToolParams, LSToolResult> {
|
||||||
private isWithinRoot(pathToCheck: string): boolean {
|
private isWithinRoot(pathToCheck: string): boolean {
|
||||||
const normalizedPath = path.normalize(pathToCheck);
|
const normalizedPath = path.normalize(pathToCheck);
|
||||||
const normalizedRoot = path.normalize(this.rootDirectory);
|
const normalizedRoot = path.normalize(this.rootDirectory);
|
||||||
|
|
||||||
// Ensure the normalizedRoot ends with a path separator for proper path comparison
|
// Ensure the normalizedRoot ends with a path separator for proper path comparison
|
||||||
const rootWithSep = normalizedRoot.endsWith(path.sep)
|
const rootWithSep = normalizedRoot.endsWith(path.sep)
|
||||||
? normalizedRoot
|
? normalizedRoot
|
||||||
: normalizedRoot + path.sep;
|
: normalizedRoot + path.sep;
|
||||||
|
|
||||||
return normalizedPath === normalizedRoot || normalizedPath.startsWith(rootWithSep);
|
return normalizedPath === normalizedRoot || normalizedPath.startsWith(rootWithSep);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Validates the parameters for the tool
|
* Validates the parameters for the tool
|
||||||
* @param params Parameters to validate
|
* @param params Parameters to validate
|
||||||
|
@ -138,7 +135,6 @@ export class LSTool extends BaseTool<LSToolParams, LSToolResult> {
|
||||||
if (this.schema.parameters && !SchemaValidator.validate(this.schema.parameters as Record<string, unknown>, params)) {
|
if (this.schema.parameters && !SchemaValidator.validate(this.schema.parameters as Record<string, unknown>, params)) {
|
||||||
return "Parameters failed schema validation.";
|
return "Parameters failed schema validation.";
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ensure path is absolute
|
// Ensure path is absolute
|
||||||
if (!path.isAbsolute(params.path)) {
|
if (!path.isAbsolute(params.path)) {
|
||||||
return `Path must be absolute: ${params.path}`;
|
return `Path must be absolute: ${params.path}`;
|
||||||
|
@ -148,10 +144,9 @@ export class LSTool extends BaseTool<LSToolParams, LSToolResult> {
|
||||||
if (!this.isWithinRoot(params.path)) {
|
if (!this.isWithinRoot(params.path)) {
|
||||||
return `Path must be within the root directory (${this.rootDirectory}): ${params.path}`;
|
return `Path must be within the root directory (${this.rootDirectory}): ${params.path}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks if a filename matches any of the ignore patterns
|
* Checks if a filename matches any of the ignore patterns
|
||||||
* @param filename Filename to check
|
* @param filename Filename to check
|
||||||
|
@ -162,26 +157,22 @@ export class LSTool extends BaseTool<LSToolParams, LSToolResult> {
|
||||||
if (!patterns || patterns.length === 0) {
|
if (!patterns || patterns.length === 0) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const pattern of patterns) {
|
for (const pattern of patterns) {
|
||||||
// Convert glob pattern to RegExp
|
// Convert glob pattern to RegExp
|
||||||
const regexPattern = pattern
|
const regexPattern = pattern
|
||||||
.replace(/[.+^${}()|[\]\\]/g, '\\$&')
|
.replace(/[.+^${}()|[\]\\]/g, '\\$&')
|
||||||
.replace(/\*/g, '.*')
|
.replace(/\*/g, '.*')
|
||||||
.replace(/\?/g, '.');
|
.replace(/\?/g, '.');
|
||||||
|
|
||||||
const regex = new RegExp(`^${regexPattern}$`);
|
const regex = new RegExp(`^${regexPattern}$`);
|
||||||
|
|
||||||
if (regex.test(filename)) {
|
if (regex.test(filename)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets a description of the file reading operation
|
* Gets a description of the file reading operation
|
||||||
* @param params Parameters for the file reading
|
* @param params Parameters for the file reading
|
||||||
* @returns A string describing the file being read
|
* @returns A string describing the file being read
|
||||||
*/
|
*/
|
||||||
|
@ -189,7 +180,7 @@ export class LSTool extends BaseTool<LSToolParams, LSToolResult> {
|
||||||
const relativePath = makeRelative(params.path, this.rootDirectory);
|
const relativePath = makeRelative(params.path, this.rootDirectory);
|
||||||
return shortenPath(relativePath);
|
return shortenPath(relativePath);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Executes the LS operation with the given parameters
|
* Executes the LS operation with the given parameters
|
||||||
* @param params Parameters for the LS operation
|
* @param params Parameters for the LS operation
|
||||||
|
@ -206,7 +197,7 @@ export class LSTool extends BaseTool<LSToolParams, LSToolResult> {
|
||||||
returnDisplay: "**Error:** Failed to execute tool."
|
returnDisplay: "**Error:** Failed to execute tool."
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Check if path exists
|
// Check if path exists
|
||||||
if (!fs.existsSync(params.path)) {
|
if (!fs.existsSync(params.path)) {
|
||||||
|
@ -218,7 +209,6 @@ export class LSTool extends BaseTool<LSToolParams, LSToolResult> {
|
||||||
returnDisplay: `Directory does not exist`
|
returnDisplay: `Directory does not exist`
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if path is a directory
|
// Check if path is a directory
|
||||||
const stats = fs.statSync(params.path);
|
const stats = fs.statSync(params.path);
|
||||||
if (!stats.isDirectory()) {
|
if (!stats.isDirectory()) {
|
||||||
|
@ -230,11 +220,10 @@ export class LSTool extends BaseTool<LSToolParams, LSToolResult> {
|
||||||
returnDisplay: `Path is not a directory`
|
returnDisplay: `Path is not a directory`
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read directory contents
|
// Read directory contents
|
||||||
const files = fs.readdirSync(params.path);
|
const files = fs.readdirSync(params.path);
|
||||||
const entries: FileEntry[] = [];
|
const entries: FileEntry[] = [];
|
||||||
|
|
||||||
if (files.length === 0) {
|
if (files.length === 0) {
|
||||||
return {
|
return {
|
||||||
entries: [],
|
entries: [],
|
||||||
|
@ -244,20 +233,16 @@ export class LSTool extends BaseTool<LSToolParams, LSToolResult> {
|
||||||
returnDisplay: `Directory is empty.`
|
returnDisplay: `Directory is empty.`
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// Process each entry
|
|
||||||
for (const file of files) {
|
for (const file of files) {
|
||||||
// Skip if the file matches ignore patterns
|
|
||||||
if (this.shouldIgnore(file, params.ignore)) {
|
if (this.shouldIgnore(file, params.ignore)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
const fullPath = path.join(params.path, file);
|
const fullPath = path.join(params.path, file);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const stats = fs.statSync(fullPath);
|
const stats = fs.statSync(fullPath);
|
||||||
const isDir = stats.isDirectory();
|
const isDir = stats.isDirectory();
|
||||||
|
|
||||||
entries.push({
|
entries.push({
|
||||||
name: file,
|
name: file,
|
||||||
path: fullPath,
|
path: fullPath,
|
||||||
|
@ -270,21 +255,21 @@ export class LSTool extends BaseTool<LSToolParams, LSToolResult> {
|
||||||
console.error(`Error accessing ${fullPath}: ${error}`);
|
console.error(`Error accessing ${fullPath}: ${error}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sort entries (directories first, then alphabetically)
|
// Sort entries (directories first, then alphabetically)
|
||||||
entries.sort((a, b) => {
|
entries.sort((a, b) => {
|
||||||
if (a.isDirectory && !b.isDirectory) return -1;
|
if (a.isDirectory && !b.isDirectory) return -1;
|
||||||
if (!a.isDirectory && b.isDirectory) return 1;
|
if (!a.isDirectory && b.isDirectory) return 1;
|
||||||
return a.name.localeCompare(b.name);
|
return a.name.localeCompare(b.name);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Create formatted content for display
|
// Create formatted content for display
|
||||||
const directoryContent = entries.map(entry => {
|
const directoryContent = entries.map(entry => {
|
||||||
const typeIndicator = entry.isDirectory ? 'd' : '-';
|
const typeIndicator = entry.isDirectory ? 'd' : '-';
|
||||||
const sizeInfo = entry.isDirectory ? '' : ` (${entry.size} bytes)`;
|
const sizeInfo = entry.isDirectory ? '' : ` (${entry.size} bytes)`;
|
||||||
return `${typeIndicator} ${entry.name}${sizeInfo}`;
|
return `${typeIndicator} ${entry.name}${sizeInfo}`;
|
||||||
}).join('\n');
|
}).join('\n');
|
||||||
|
|
||||||
return {
|
return {
|
||||||
entries,
|
entries,
|
||||||
listedPath: params.path,
|
listedPath: params.path,
|
||||||
|
|
|
@ -1,9 +1,8 @@
|
||||||
import fs from 'fs';
|
import fs from 'fs';
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
import { ToolResult } from './ToolResult.js';
|
|
||||||
import { BaseTool } from './BaseTool.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 { BaseTool, ToolResult } from './tool.js';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parameters for the ReadFile tool
|
* Parameters for the ReadFile tool
|
||||||
|
@ -36,7 +35,7 @@ export interface ReadFileToolResult extends ToolResult {
|
||||||
*/
|
*/
|
||||||
export class ReadFileTool extends BaseTool<ReadFileToolParams, ReadFileToolResult> {
|
export class ReadFileTool extends BaseTool<ReadFileToolParams, ReadFileToolResult> {
|
||||||
public static readonly Name: string = 'read_file';
|
public static readonly Name: string = 'read_file';
|
||||||
|
|
||||||
// Maximum number of lines to read by default
|
// Maximum number of lines to read by default
|
||||||
private static readonly DEFAULT_MAX_LINES = 2000;
|
private static readonly DEFAULT_MAX_LINES = 2000;
|
||||||
|
|
||||||
|
@ -108,26 +107,19 @@ export class ReadFileTool extends BaseTool<ReadFileToolParams, ReadFileToolResul
|
||||||
if (this.schema.parameters && !SchemaValidator.validate(this.schema.parameters as Record<string, unknown>, params)) {
|
if (this.schema.parameters && !SchemaValidator.validate(this.schema.parameters as Record<string, unknown>, params)) {
|
||||||
return "Parameters failed schema validation.";
|
return "Parameters failed schema validation.";
|
||||||
}
|
}
|
||||||
|
const filePath = params.file_path;
|
||||||
// Ensure path is absolute
|
if (!path.isAbsolute(filePath)) {
|
||||||
if (!path.isAbsolute(params.file_path)) {
|
return `File path must be absolute: ${filePath}`;
|
||||||
return `File path must be absolute: ${params.file_path}`;
|
|
||||||
}
|
}
|
||||||
|
if (!this.isWithinRoot(filePath)) {
|
||||||
// Ensure path is within the root directory
|
return `File path must be within the root directory (${this.rootDirectory}): ${filePath}`;
|
||||||
if (!this.isWithinRoot(params.file_path)) {
|
|
||||||
return `File path must be within the root directory (${this.rootDirectory}): ${params.file_path}`;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validate offset and limit if provided
|
|
||||||
if (params.offset !== undefined && params.offset < 0) {
|
if (params.offset !== undefined && params.offset < 0) {
|
||||||
return 'Offset must be a non-negative number';
|
return 'Offset must be a non-negative number';
|
||||||
}
|
}
|
||||||
|
|
||||||
if (params.limit !== undefined && params.limit <= 0) {
|
if (params.limit !== undefined && params.limit <= 0) {
|
||||||
return 'Limit must be a positive number';
|
return 'Limit must be a positive number';
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -208,6 +200,7 @@ export class ReadFileTool extends BaseTool<ReadFileToolParams, ReadFileToolResul
|
||||||
*/
|
*/
|
||||||
async execute(params: ReadFileToolParams): Promise<ReadFileToolResult> {
|
async execute(params: ReadFileToolParams): Promise<ReadFileToolResult> {
|
||||||
const validationError = this.invalidParams(params);
|
const validationError = this.invalidParams(params);
|
||||||
|
const filePath = params.file_path;
|
||||||
if (validationError) {
|
if (validationError) {
|
||||||
return {
|
return {
|
||||||
llmContent: `Error: Invalid parameters provided. Reason: ${validationError}`,
|
llmContent: `Error: Invalid parameters provided. Reason: ${validationError}`,
|
||||||
|
@ -216,51 +209,40 @@ export class ReadFileTool extends BaseTool<ReadFileToolParams, ReadFileToolResul
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Check if file exists
|
if (!fs.existsSync(filePath)) {
|
||||||
if (!fs.existsSync(params.file_path)) {
|
|
||||||
return {
|
return {
|
||||||
llmContent: `File not found: ${params.file_path}`,
|
llmContent: `File not found: ${filePath}`,
|
||||||
returnDisplay: `File not found.`,
|
returnDisplay: `File not found.`,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if it's a directory
|
const stats = fs.statSync(filePath);
|
||||||
const stats = fs.statSync(params.file_path);
|
|
||||||
if (stats.isDirectory()) {
|
if (stats.isDirectory()) {
|
||||||
return {
|
return {
|
||||||
llmContent: `Path is a directory, not a file: ${params.file_path}`,
|
llmContent: `Path is a directory, not a file: ${filePath}`,
|
||||||
returnDisplay: `File is directory.`,
|
returnDisplay: `File is directory.`,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// Detect file type
|
const fileType = this.detectFileType(filePath);
|
||||||
const fileType = this.detectFileType(params.file_path);
|
|
||||||
|
|
||||||
// Handle binary files differently
|
|
||||||
if (fileType !== 'text') {
|
if (fileType !== 'text') {
|
||||||
return {
|
return {
|
||||||
llmContent: `Binary file: ${params.file_path} (${fileType})`,
|
llmContent: `Binary file: ${filePath} (${fileType})`,
|
||||||
returnDisplay: ``,
|
returnDisplay: ``,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read and process text file
|
const content = fs.readFileSync(filePath, 'utf8');
|
||||||
const content = fs.readFileSync(params.file_path, 'utf8');
|
|
||||||
const lines = content.split('\n');
|
const lines = content.split('\n');
|
||||||
|
|
||||||
// Apply offset and limit
|
|
||||||
const startLine = params.offset || 0;
|
const startLine = params.offset || 0;
|
||||||
// Use the default max lines if no limit is provided
|
|
||||||
const endLine = params.limit
|
const endLine = params.limit
|
||||||
? startLine + params.limit
|
? startLine + params.limit
|
||||||
: Math.min(startLine + ReadFileTool.DEFAULT_MAX_LINES, lines.length);
|
: Math.min(startLine + ReadFileTool.DEFAULT_MAX_LINES, lines.length);
|
||||||
const selectedLines = lines.slice(startLine, endLine);
|
const selectedLines = lines.slice(startLine, endLine);
|
||||||
|
|
||||||
// Format with line numbers and handle line truncation
|
|
||||||
let truncated = false;
|
let truncated = false;
|
||||||
const formattedLines = selectedLines.map((line) => {
|
const formattedLines = selectedLines.map((line) => {
|
||||||
// Calculate actual line number (1-based)
|
|
||||||
// Truncate long lines
|
|
||||||
let processedLine = line;
|
let processedLine = line;
|
||||||
if (line.length > ReadFileTool.MAX_LINE_LENGTH) {
|
if (line.length > ReadFileTool.MAX_LINE_LENGTH) {
|
||||||
processedLine = line.substring(0, ReadFileTool.MAX_LINE_LENGTH) + '... [truncated]';
|
processedLine = line.substring(0, ReadFileTool.MAX_LINE_LENGTH) + '... [truncated]';
|
||||||
|
@ -270,10 +252,8 @@ export class ReadFileTool extends BaseTool<ReadFileToolParams, ReadFileToolResul
|
||||||
return processedLine;
|
return processedLine;
|
||||||
});
|
});
|
||||||
|
|
||||||
// Check if content was truncated due to line limit or max lines limit
|
|
||||||
const contentTruncated = (endLine < lines.length) || truncated;
|
const contentTruncated = (endLine < lines.length) || truncated;
|
||||||
|
|
||||||
// Create llmContent with truncation info if needed
|
|
||||||
let llmContent = '';
|
let llmContent = '';
|
||||||
if (contentTruncated) {
|
if (contentTruncated) {
|
||||||
llmContent += `[File truncated: showing lines ${startLine + 1}-${endLine} of ${lines.length} total lines. Use offset parameter to view more.]\n`;
|
llmContent += `[File truncated: showing lines ${startLine + 1}-${endLine} of ${lines.length} total lines. Use offset parameter to view more.]\n`;
|
||||||
|
@ -288,7 +268,7 @@ export class ReadFileTool extends BaseTool<ReadFileToolParams, ReadFileToolResul
|
||||||
const errorMsg = `Error reading file: ${error instanceof Error ? error.message : String(error)}`;
|
const errorMsg = `Error reading file: ${error instanceof Error ? error.message : String(error)}`;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
llmContent: `Error reading file ${params.file_path}: ${errorMsg}`,
|
llmContent: `Error reading file ${filePath}: ${errorMsg}`,
|
||||||
returnDisplay: `Failed to read file: ${errorMsg}`,
|
returnDisplay: `Failed to read file: ${errorMsg}`,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,13 +2,10 @@ import { spawn, SpawnOptions, ChildProcessWithoutNullStreams, exec } from 'child
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
import os from 'os';
|
import os from 'os';
|
||||||
import crypto from 'crypto';
|
import crypto from 'crypto';
|
||||||
import { promises as fs } from 'fs'; // Added fs.promises
|
import { promises as fs } from 'fs';
|
||||||
import { BaseTool } from './BaseTool.js'; // Adjust path as needed
|
import { BaseTool, ToolResult } from './tool.js';
|
||||||
import { ToolResult } from './ToolResult.js'; // Adjust path as needed
|
import { SchemaValidator } from '../utils/schemaValidator.js';
|
||||||
import { SchemaValidator } from '../utils/schemaValidator.js'; // Adjust path as needed
|
|
||||||
import { ToolCallConfirmationDetails, ToolConfirmationOutcome, ToolExecuteConfirmationDetails } from '../ui/types.js'; // Adjust path as needed
|
import { ToolCallConfirmationDetails, ToolConfirmationOutcome, ToolExecuteConfirmationDetails } from '../ui/types.js'; // Adjust path as needed
|
||||||
import { GeminiClient } from '../core/GeminiClient.js';
|
|
||||||
import { SchemaUnion, Type } from '@google/genai';
|
|
||||||
import { BackgroundTerminalAnalyzer } from '../utils/BackgroundTerminalAnalyzer.js';
|
import { BackgroundTerminalAnalyzer } from '../utils/BackgroundTerminalAnalyzer.js';
|
||||||
|
|
||||||
// --- Interfaces ---
|
// --- Interfaces ---
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
import { ToolListUnion, FunctionDeclaration } from '@google/genai';
|
import { ToolListUnion, FunctionDeclaration } from '@google/genai';
|
||||||
import { Tool } from './Tool.js';
|
import { Tool } from './tool.js';
|
||||||
import { ToolResult } from './ToolResult.js';
|
|
||||||
|
|
||||||
class ToolRegistry {
|
class ToolRegistry {
|
||||||
private tools: Map<string, Tool> = new Map();
|
private tools: Map<string, Tool> = new Map();
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
import fs from 'fs';
|
import fs from 'fs';
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
import { ToolResult } from './ToolResult.js';
|
import { BaseTool, ToolResult } from './tool.js';
|
||||||
import { BaseTool } from './BaseTool.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 { ToolCallConfirmationDetails, ToolConfirmationOutcome, ToolEditConfirmationDetails } from '../ui/types.js';
|
import { ToolCallConfirmationDetails, ToolConfirmationOutcome, ToolEditConfirmationDetails } from '../ui/types.js';
|
||||||
|
@ -52,7 +51,7 @@ export class WriteFileTool extends BaseTool<WriteFileToolParams, WriteFileToolRe
|
||||||
'Writes content to a specified file in the local filesystem.',
|
'Writes content to a specified file in the local filesystem.',
|
||||||
{
|
{
|
||||||
properties: {
|
properties: {
|
||||||
file_path: {
|
filePath: {
|
||||||
description: 'The absolute path to the file to write to (e.g., \'/home/user/project/file.txt\'). Relative paths are not supported.',
|
description: 'The absolute path to the file to write to (e.g., \'/home/user/project/file.txt\'). Relative paths are not supported.',
|
||||||
type: 'string'
|
type: 'string'
|
||||||
},
|
},
|
||||||
|
@ -61,7 +60,7 @@ export class WriteFileTool extends BaseTool<WriteFileToolParams, WriteFileToolRe
|
||||||
type: 'string'
|
type: 'string'
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
required: ['file_path', 'content'],
|
required: ['filePath', 'content'],
|
||||||
type: 'object'
|
type: 'object'
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
|
@ -9,7 +9,7 @@ import HistoryDisplay from './components/HistoryDisplay.js';
|
||||||
import LoadingIndicator from './components/LoadingIndicator.js';
|
import LoadingIndicator from './components/LoadingIndicator.js';
|
||||||
import InputPrompt from './components/InputPrompt.js';
|
import InputPrompt from './components/InputPrompt.js';
|
||||||
import Footer from './components/Footer.js';
|
import Footer from './components/Footer.js';
|
||||||
import { StreamingState } from '../core/StreamingState.js';
|
import { StreamingState } from '../core/gemini-stream.js';
|
||||||
import { PartListUnion } from '@google/genai';
|
import { PartListUnion } from '@google/genai';
|
||||||
|
|
||||||
interface AppProps {
|
interface AppProps {
|
||||||
|
|
|
@ -2,7 +2,7 @@ import React from 'react';
|
||||||
import { Box, Text } from 'ink';
|
import { Box, Text } from 'ink';
|
||||||
import Spinner from 'ink-spinner';
|
import Spinner from 'ink-spinner';
|
||||||
import { ToolCallStatus } from '../../types.js';
|
import { ToolCallStatus } from '../../types.js';
|
||||||
import { ToolResultDisplay } from '../../../tools/ToolResult.js';
|
import { ToolResultDisplay } from '../../../tools/tool.js';
|
||||||
import DiffRenderer from './DiffRenderer.js';
|
import DiffRenderer from './DiffRenderer.js';
|
||||||
import { MarkdownRenderer } from '../../utils/MarkdownRenderer.js';
|
import { MarkdownRenderer } from '../../utils/MarkdownRenderer.js';
|
||||||
|
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
import { useState, useRef, useCallback, useEffect } from 'react';
|
import { useState, useRef, useCallback, useEffect } from 'react';
|
||||||
import { useInput } from 'ink';
|
import { useInput } from 'ink';
|
||||||
import { GeminiClient } from '../../core/GeminiClient.js';
|
import { GeminiClient } from '../../core/gemini-client.js';
|
||||||
import { type Chat, type PartListUnion } from '@google/genai';
|
import { type Chat, type PartListUnion } from '@google/genai';
|
||||||
import { HistoryItem } from '../types.js';
|
import { HistoryItem } from '../types.js';
|
||||||
import { processGeminiStream } from '../../core/geminiStreamProcessor.js';
|
import { processGeminiStream } from '../../core/gemini-stream.js';
|
||||||
import { StreamingState } from '../../core/StreamingState.js';
|
import { StreamingState } from '../../core/gemini-stream.js';
|
||||||
|
|
||||||
const addHistoryItem = (
|
const addHistoryItem = (
|
||||||
setHistory: React.Dispatch<React.SetStateAction<HistoryItem[]>>,
|
setHistory: React.Dispatch<React.SetStateAction<HistoryItem[]>>,
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import { useState, useEffect, useRef } from 'react';
|
import { useState, useEffect, useRef } from 'react';
|
||||||
import { WITTY_LOADING_PHRASES, PHRASE_CHANGE_INTERVAL_MS } from '../constants.js';
|
import { WITTY_LOADING_PHRASES, PHRASE_CHANGE_INTERVAL_MS } from '../constants.js';
|
||||||
import { StreamingState } from '../../core/StreamingState.js';
|
import { StreamingState } from '../../core/gemini-stream.js';
|
||||||
|
|
||||||
export const useLoadingIndicator = (streamingState: StreamingState) => {
|
export const useLoadingIndicator = (streamingState: StreamingState) => {
|
||||||
const [elapsedTime, setElapsedTime] = useState(0);
|
const [elapsedTime, setElapsedTime] = useState(0);
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { ToolResultDisplay } from "../tools/ToolResult.js";
|
import { ToolResultDisplay } from '../tools/tool.js';
|
||||||
|
|
||||||
export enum ToolCallStatus {
|
export enum ToolCallStatus {
|
||||||
Pending,
|
Pending,
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import { promises as fs } from 'fs';
|
import { promises as fs } from 'fs';
|
||||||
import { SchemaUnion, Type } from "@google/genai"; // Assuming these types exist
|
import { SchemaUnion, Type } from "@google/genai"; // Assuming these types exist
|
||||||
import { GeminiClient } from "../core/GeminiClient.js"; // Assuming this path
|
import { GeminiClient } from "../core/gemini-client.js"; // Assuming this path
|
||||||
import { exec } from 'child_process'; // Needed for Windows process check
|
import { exec } from 'child_process'; // Needed for Windows process check
|
||||||
import { promisify } from 'util'; // To promisify exec
|
import { promisify } from 'util'; // To promisify exec
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue