diff options
Diffstat (limited to 'packages/core/src/tools/tools.ts')
| -rw-r--r-- | packages/core/src/tools/tools.ts | 235 |
1 files changed, 235 insertions, 0 deletions
diff --git a/packages/core/src/tools/tools.ts b/packages/core/src/tools/tools.ts new file mode 100644 index 00000000..a2e7fa06 --- /dev/null +++ b/packages/core/src/tools/tools.ts @@ -0,0 +1,235 @@ +/** + * @license + * Copyright 2025 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +import { FunctionDeclaration, PartListUnion, Schema } from '@google/genai'; + +/** + * Interface representing the base Tool functionality + */ +export interface Tool< + TParams = unknown, + TResult extends ToolResult = ToolResult, +> { + /** + * The internal name of the tool (used for API calls) + */ + name: string; + + /** + * The user-friendly display name of the tool + */ + displayName: string; + + /** + * Description of what the tool does + */ + description: string; + + /** + * Function declaration schema from @google/genai + */ + schema: FunctionDeclaration; + + /** + * Whether the tool's output should be rendered as markdown + */ + isOutputMarkdown: boolean; + + /** + * Whether the tool supports live (streaming) output + */ + canUpdateOutput: boolean; + + /** + * Validates the parameters for the tool + * Should be called from both `shouldConfirmExecute` and `execute` + * `shouldConfirmExecute` should return false immediately if invalid + * @param params Parameters to validate + * @returns An error message string if invalid, null otherwise + */ + validateToolParams(params: TParams): string | null; + + /** + * Gets a pre-execution description of the tool operation + * @param params Parameters for the tool execution + * @returns A markdown string describing what the tool will do + * Optional for backward compatibility + */ + getDescription(params: TParams): string; + + /** + * Determines if the tool should prompt for confirmation before execution + * @param params Parameters for the tool execution + * @returns Whether execute should be confirmed. + */ + shouldConfirmExecute( + params: TParams, + abortSignal: AbortSignal, + ): Promise<ToolCallConfirmationDetails | false>; + + /** + * Executes the tool with the given parameters + * @param params Parameters for the tool execution + * @returns Result of the tool execution + */ + execute( + params: TParams, + signal: AbortSignal, + updateOutput?: (output: string) => void, + ): 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 isOutputMarkdown Whether the tool's output should be rendered as markdown + * @param canUpdateOutput Whether the tool supports live (streaming) output + * @param parameterSchema JSON Schema defining the parameters + */ + constructor( + readonly name: string, + readonly displayName: string, + readonly description: string, + readonly parameterSchema: Record<string, unknown>, + readonly isOutputMarkdown: boolean = true, + readonly canUpdateOutput: boolean = false, + ) {} + + /** + * 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 + * Should be called from both `shouldConfirmExecute` and `execute` + * `shouldConfirmExecute` should return false immediately if invalid + * @param params Parameters to validate + * @returns An error message string if invalid, null otherwise + */ + // eslint-disable-next-line @typescript-eslint/no-unused-vars + validateToolParams(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( + // eslint-disable-next-line @typescript-eslint/no-unused-vars + params: TParams, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + abortSignal: AbortSignal, + ): 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 + * @param signal AbortSignal for tool cancellation + * @returns Result of the tool execution + */ + abstract execute( + params: TParams, + signal: AbortSignal, + updateOutput?: (output: string) => void, + ): Promise<TResult>; +} + +export interface ToolResult { + /** + * Content meant to be included in LLM history. + * This should represent the factual outcome of the tool execution. + */ + llmContent: PartListUnion; + + /** + * Markdown string for user display. + * This provides a user-friendly summary or visualization of the result. + * NOTE: This might also be considered UI-specific and could potentially be + * removed or modified in a further refactor if the server becomes purely API-driven. + * For now, we keep it as the core logic in ReadFileTool currently produces it. + */ + returnDisplay: ToolResultDisplay; +} + +export type ToolResultDisplay = string | FileDiff; + +export interface FileDiff { + fileDiff: string; + fileName: string; +} + +export interface ToolEditConfirmationDetails { + type: 'edit'; + title: string; + onConfirm: (outcome: ToolConfirmationOutcome) => Promise<void>; + fileName: string; + fileDiff: string; +} + +export interface ToolExecuteConfirmationDetails { + type: 'exec'; + title: string; + onConfirm: (outcome: ToolConfirmationOutcome) => Promise<void>; + command: string; + rootCommand: string; +} + +export interface ToolMcpConfirmationDetails { + type: 'mcp'; + title: string; + serverName: string; + toolName: string; + toolDisplayName: string; + onConfirm: (outcome: ToolConfirmationOutcome) => Promise<void> | void; +} + +export type ToolCallConfirmationDetails = + | ToolEditConfirmationDetails + | ToolExecuteConfirmationDetails + | ToolMcpConfirmationDetails; + +export enum ToolConfirmationOutcome { + ProceedOnce = 'proceed_once', + ProceedAlways = 'proceed_always', + ProceedAlwaysServer = 'proceed_always_server', + ProceedAlwaysTool = 'proceed_always_tool', + Cancel = 'cancel', +} |
