diff --git a/AIClasses/AIFunctionCall.ts b/AIClasses/AIToolCall.ts similarity index 74% rename from AIClasses/AIFunctionCall.ts rename to AIClasses/AIToolCall.ts index 52325c4..eb66d51 100644 --- a/AIClasses/AIFunctionCall.ts +++ b/AIClasses/AIToolCall.ts @@ -1,13 +1,13 @@ -import { AIFunction } from "Enums/AIFunction"; +import { AITool } from "Enums/AITool"; // platform agnostic function call class used to execute the requested function -export class AIFunctionCall { - public readonly name: AIFunction; +export class AIToolCall { + public readonly name: AITool; public readonly arguments: Record; public readonly toolId?: string; public readonly thoughtSignature?: string; - constructor(name: AIFunction, args: Record, toolId?: string, thoughtSignature?: string) { + constructor(name: AITool, args: Record, toolId?: string, thoughtSignature?: string) { this.name = name; this.arguments = args; this.toolId = toolId; diff --git a/AIClasses/BaseAIClass.ts b/AIClasses/BaseAIClass.ts index 9b55f88..5864fa5 100644 --- a/AIClasses/BaseAIClass.ts +++ b/AIClasses/BaseAIClass.ts @@ -4,18 +4,18 @@ import type { IAIClass } from "AIClasses/IAIClass"; import { type IStreamChunk } from "Services/StreamingService"; import type { Conversation } from "Conversations/Conversation"; import type { AIProvider } from "Enums/ApiProvider"; -import type { IAIFunctionDefinition } from "AIClasses/FunctionDefinitions/IAIFunctionDefinition"; +import type { IAIToolDefinition } from "AIClasses/FunctionDefinitions/IAIToolDefinition"; import type { ConversationContent } from "Conversations/ConversationContent"; import type { Attachment } from "Conversations/Attachment"; import type { SettingsService } from "Services/SettingsService"; import type { StreamingService } from "Services/StreamingService"; -import type { StoredFunctionCall, StoredFunctionResponse } from "AIClasses/Schemas/AIFunctionTypes"; +import type { StoredFunctionCall, StoredFunctionResponse } from "AIClasses/Schemas/AIToolTypes"; import { Exception } from "Helpers/Exception"; import { ApiError, ApiErrorType } from "Types/ApiError"; import type { AbortService } from "Services/AbortService"; import type { IAIFileService } from "./IAIFileService"; import { AgentType } from "Enums/AgentType"; -import { AIFunctionUsageMode } from "Enums/AIFunctionUsageMode"; +import { AIToolUsageMode } from "Enums/AIToolUsageMode"; export abstract class BaseAIClass implements IAIClass { @@ -29,8 +29,8 @@ export abstract class BaseAIClass implements IAIClass { private _systemPrompt: string = ""; private _userInstruction: string = ""; private _agentType: AgentType = AgentType.Main; - private _aiFunctionDefinitions: IAIFunctionDefinition[] = []; - private _aiFunctionUsageMode: AIFunctionUsageMode = AIFunctionUsageMode.Auto; + private _aiToolDefinitions: IAIToolDefinition[] = []; + private _aiToolUsageMode: AIToolUsageMode = AIToolUsageMode.Auto; protected constructor(provider: AIProvider) { this.provider = provider; @@ -62,12 +62,12 @@ export abstract class BaseAIClass implements IAIClass { return this._userInstruction; } - public get aiFunctionDefinitions(): IAIFunctionDefinition[] { - return this._aiFunctionDefinitions; + public get aiToolDefinitions(): IAIToolDefinition[] { + return this._aiToolDefinitions; } - public set aiFunctionDefinitions(aiFunctionDefinitions: IAIFunctionDefinition[]) { - this._aiFunctionDefinitions = aiFunctionDefinitions; + public set aiToolDefinitions(aiToolDefinitions: IAIToolDefinition[]) { + this._aiToolDefinitions = aiToolDefinitions; } public get agentType() { @@ -78,12 +78,12 @@ export abstract class BaseAIClass implements IAIClass { this._agentType = agentType; } - public get aiFunctionUsageMode(): AIFunctionUsageMode { - return this._aiFunctionUsageMode; + public get aiToolUsageMode(): AIToolUsageMode { + return this._aiToolUsageMode; } - public set aiFunctionUsageMode(mode: AIFunctionUsageMode) { - this._aiFunctionUsageMode = mode; + public set aiToolUsageMode(mode: AIToolUsageMode) { + this._aiToolUsageMode = mode; } public abstract streamRequest(conversation: Conversation): AsyncGenerator; @@ -92,7 +92,7 @@ export abstract class BaseAIClass implements IAIClass { protected abstract parseStreamChunk(chunk: string): IStreamChunk; protected abstract extractContents(conversationContent: ConversationContent[]): unknown; - protected abstract mapFunctionDefinitions(aiFunctionDefinitions: IAIFunctionDefinition[]): object; + protected abstract mapFunctionDefinitions(aiToolDefinitions: IAIToolDefinition[]): object; protected model(): string { switch (this._agentType) { diff --git a/AIClasses/Claude/Claude.ts b/AIClasses/Claude/Claude.ts index 1116ab8..3be3e9b 100644 --- a/AIClasses/Claude/Claude.ts +++ b/AIClasses/Claude/Claude.ts @@ -3,9 +3,9 @@ import type { IStreamChunk } from "Services/StreamingService"; import type { Conversation } from "Conversations/Conversation"; import type { Attachment } from "Conversations/Attachment"; import { AIProvider, AIProviderURL } from "Enums/ApiProvider"; -import { AIFunctionCall } from "AIClasses/AIFunctionCall"; -import { fromString as aiFunctionFromString } from "Enums/AIFunction"; -import type { IAIFunctionDefinition } from "AIClasses/FunctionDefinitions/IAIFunctionDefinition"; +import { AIToolCall } from "AIClasses/AIToolCall"; +import { fromString as aiToolFromString } from "Enums/AITool"; +import type { IAIToolDefinition } from "AIClasses/FunctionDefinitions/IAIToolDefinition"; import type { ConversationContent } from "Conversations/ConversationContent"; import { Role } from "Enums/Role"; import type { RawMessageStreamEvent, ContentBlockParam, Tool, TextBlockParam, ToolUnion, WebSearchTool20250305 } from '@anthropic-ai/sdk/resources/messages'; @@ -15,7 +15,7 @@ import { isTextFile } from "Enums/FileType"; import { MimeTypeToFileTypes } from "Enums/FileTypeMimeTypeMapping"; import { ApiError, ApiErrorType } from "Types/ApiError"; import { parseFunctionCall, parseFunctionResponse } from "Helpers/ResponseHelper"; -import { AIFunctionUsageMode } from "Enums/AIFunctionUsageMode"; +import { AIToolUsageMode } from "Enums/AIToolUsageMode"; export class Claude extends BaseAIClass { @@ -69,7 +69,7 @@ export class Claude extends BaseAIClass { }; const tools: ToolUnion[] = this.addCacheControlToTools([ - webSearchTool, ...this.mapFunctionDefinitions(this.aiFunctionDefinitions)]); + webSearchTool, ...this.mapFunctionDefinitions(this.aiToolDefinitions)]); const requestBody = { model: this.model(), @@ -103,7 +103,7 @@ export class Claude extends BaseAIClass { const data = JSON.parse(chunk) as RawMessageStreamEvent; let text = ""; - let functionCall: AIFunctionCall | undefined = undefined; + let functionCall: AIToolCall | undefined = undefined; let isComplete = false; let shouldContinue = false; @@ -135,8 +135,8 @@ export class Claude extends BaseAIClass { if (this.accumulatedFunctionName && this.accumulatedFunctionArgs) { try { const args = JSON.parse(this.accumulatedFunctionArgs) as Record; - functionCall = new AIFunctionCall( - aiFunctionFromString(this.accumulatedFunctionName), + functionCall = new AIToolCall( + aiToolFromString(this.accumulatedFunctionName), args as Record, this.accumulatedFunctionId || undefined, undefined // thoughtSignature not used by Claude @@ -268,8 +268,8 @@ export class Claude extends BaseAIClass { return results.filter(message => message.content.length > 0); } - protected mapFunctionDefinitions(aiFunctionDefinitions: IAIFunctionDefinition[]): Tool[] { - return aiFunctionDefinitions.map((functionDefinition) => ({ + protected mapFunctionDefinitions(aiToolDefinitions: IAIToolDefinition[]): Tool[] { + return aiToolDefinitions.map((functionDefinition) => ({ name: functionDefinition.name, description: functionDefinition.description, input_schema: { @@ -369,16 +369,16 @@ export class Claude extends BaseAIClass { private buildClaudeToolChoice(): { type: string } { // If no tools defined, fall back to auto - if (this.aiFunctionDefinitions.length === 0) { + if (this.aiToolDefinitions.length === 0) { return { type: "auto" }; } - switch (this.aiFunctionUsageMode) { - case AIFunctionUsageMode.Auto: + switch (this.aiToolUsageMode) { + case AIToolUsageMode.Auto: return { type: "auto" }; - case AIFunctionUsageMode.Enabled: + case AIToolUsageMode.Enabled: return { type: "any" }; - case AIFunctionUsageMode.Disabled: + case AIToolUsageMode.Disabled: return { type: "none" }; } } diff --git a/AIClasses/FunctionDefinitions/AIFunctionDefinitions.ts b/AIClasses/FunctionDefinitions/AIToolDefinitions.ts similarity index 86% rename from AIClasses/FunctionDefinitions/AIFunctionDefinitions.ts rename to AIClasses/FunctionDefinitions/AIToolDefinitions.ts index 1953abb..3c7c2a6 100644 --- a/AIClasses/FunctionDefinitions/AIFunctionDefinitions.ts +++ b/AIClasses/FunctionDefinitions/AIToolDefinitions.ts @@ -1,4 +1,4 @@ -import type { IAIFunctionDefinition } from "./IAIFunctionDefinition"; +import type { IAIToolDefinition } from "./IAIToolDefinition"; import { SearchVaultFiles } from "./Functions/SearchVaultFiles"; import { ReadVaultFiles } from "./Functions/ReadVaultFiles"; import { WriteVaultFile } from "./Functions/WriteVaultFile"; @@ -15,14 +15,14 @@ import { CompletePlan } from "./Functions/CompletePlan"; import { CompleteTask } from "./Functions/CompleteTask"; import { ExecuteWorkflow } from "./Functions/ExecuteWorkflow"; -export abstract class AIFunctionDefinitions { +export abstract class AIToolDefinitions { public static isGated: boolean = false; // Definitions list provides a list of function definitions that does not include any planning functions (used as reference in planning agent prompt) private static readonly definitionsList = [SearchVaultFiles, ReadVaultFiles, ListVaultFiles, WriteVaultFile, PatchVaultFile, DeleteVaultFiles, MoveVaultFiles]; - public static agentDefinitions(destructive: boolean, planning: boolean): IAIFunctionDefinition[] { + public static agentDefinitions(destructive: boolean, planning: boolean): IAIToolDefinition[] { this.isGated = false; if (planning) { @@ -47,15 +47,15 @@ export abstract class AIFunctionDefinitions { return actions; } - public static orchestrationAgentDefinitions(): IAIFunctionDefinition[] { + public static orchestrationAgentDefinitions(): IAIToolDefinition[] { return [CompleteStep, Replan, CancelPlan, CompletePlan]; } - public static planningAgentDefinitions(): IAIFunctionDefinition[] { + public static planningAgentDefinitions(): IAIToolDefinition[] { return [SearchVaultFiles, ReadVaultFiles, ListVaultFiles, AskUserQuestionPlanning, SubmitPlan]; } - public static executionAgentDefinitions(): IAIFunctionDefinition[] { + public static executionAgentDefinitions(): IAIToolDefinition[] { return [...this.agentDefinitions(true, false), CompleteTask]; } diff --git a/AIClasses/FunctionDefinitions/AIFunctionResponse.ts b/AIClasses/FunctionDefinitions/AIToolResponse.ts similarity index 90% rename from AIClasses/FunctionDefinitions/AIFunctionResponse.ts rename to AIClasses/FunctionDefinitions/AIToolResponse.ts index 467c1ea..2141a76 100644 --- a/AIClasses/FunctionDefinitions/AIFunctionResponse.ts +++ b/AIClasses/FunctionDefinitions/AIToolResponse.ts @@ -1,10 +1,10 @@ // Platform agnostic class for function responses -import type { AIFunction } from "Enums/AIFunction"; +import type { AITool } from "Enums/AITool"; // Used by AI providers to format function execution results for API calls -export class AIFunctionResponse { - public readonly name: AIFunction; +export class AIToolResponse { + public readonly name: AITool; public readonly response: object; public readonly toolId?: string; @@ -29,7 +29,7 @@ export class AIFunctionResponse { **User's Suggestion:**`; - constructor(name: AIFunction, response: object, toolId?: string) { + constructor(name: AITool, response: object, toolId?: string) { this.name = name; this.response = response; this.toolId = toolId; diff --git a/AIClasses/FunctionDefinitions/Functions/AskUserQuestionExecution.ts b/AIClasses/FunctionDefinitions/Functions/AskUserQuestionExecution.ts index f706f1c..35921c8 100644 --- a/AIClasses/FunctionDefinitions/Functions/AskUserQuestionExecution.ts +++ b/AIClasses/FunctionDefinitions/Functions/AskUserQuestionExecution.ts @@ -1,8 +1,8 @@ -import { AIFunction } from "Enums/AIFunction"; -import type { IAIFunctionDefinition } from "../IAIFunctionDefinition"; +import { AITool } from "Enums/AITool"; +import type { IAIToolDefinition } from "../IAIToolDefinition"; -export const AskUserQuestionExecution: IAIFunctionDefinition = { - name: AIFunction.AskUserQuestionExecution, +export const AskUserQuestionExecution: IAIToolDefinition = { + name: AITool.AskUserQuestionExecution, description: `Asks the user a question during plan execution and waits for their response. Use this function to resolve ambiguity at the point of discovery rather than reporting uncertain outcomes. diff --git a/AIClasses/FunctionDefinitions/Functions/AskUserQuestionPlanning.ts b/AIClasses/FunctionDefinitions/Functions/AskUserQuestionPlanning.ts index 406725e..aff1a46 100644 --- a/AIClasses/FunctionDefinitions/Functions/AskUserQuestionPlanning.ts +++ b/AIClasses/FunctionDefinitions/Functions/AskUserQuestionPlanning.ts @@ -1,8 +1,8 @@ -import { AIFunction } from "Enums/AIFunction"; -import type { IAIFunctionDefinition } from "../IAIFunctionDefinition"; +import { AITool } from "Enums/AITool"; +import type { IAIToolDefinition } from "../IAIToolDefinition"; -export const AskUserQuestionPlanning: IAIFunctionDefinition = { - name: AIFunction.AskUserQuestionPlanning, +export const AskUserQuestionPlanning: IAIToolDefinition = { + name: AITool.AskUserQuestionPlanning, description: `Asks the user a question during the planning phase and waits for their response. This allows interactive planning where user feedback shapes the plan before it's submitted. diff --git a/AIClasses/FunctionDefinitions/Functions/CancelPlan.ts b/AIClasses/FunctionDefinitions/Functions/CancelPlan.ts index d789aaa..b8ee4ba 100644 --- a/AIClasses/FunctionDefinitions/Functions/CancelPlan.ts +++ b/AIClasses/FunctionDefinitions/Functions/CancelPlan.ts @@ -1,8 +1,8 @@ -import { AIFunction } from "Enums/AIFunction"; -import type { IAIFunctionDefinition } from "../IAIFunctionDefinition"; +import { AITool } from "Enums/AITool"; +import type { IAIToolDefinition } from "../IAIToolDefinition"; -export const CancelPlan: IAIFunctionDefinition = { - name: AIFunction.CancelPlan, +export const CancelPlan: IAIToolDefinition = { + name: AITool.CancelPlan, description: `Terminates the current plan execution immediately and returns control to the main conversation loop. Use this function when plan execution cannot or should not continue. diff --git a/AIClasses/FunctionDefinitions/Functions/CompletePlan.ts b/AIClasses/FunctionDefinitions/Functions/CompletePlan.ts index f34fdbd..5d20318 100644 --- a/AIClasses/FunctionDefinitions/Functions/CompletePlan.ts +++ b/AIClasses/FunctionDefinitions/Functions/CompletePlan.ts @@ -1,8 +1,8 @@ -import { AIFunction } from "Enums/AIFunction"; -import type { IAIFunctionDefinition } from "../IAIFunctionDefinition"; +import { AITool } from "Enums/AITool"; +import type { IAIToolDefinition } from "../IAIToolDefinition"; -export const CompletePlan: IAIFunctionDefinition = { - name: AIFunction.CompletePlan, +export const CompletePlan: IAIToolDefinition = { + name: AITool.CompletePlan, description: `Marks the current execution plan as fully completed. Use this function when all steps in the plan have been successfully executed and diff --git a/AIClasses/FunctionDefinitions/Functions/CompleteStep.ts b/AIClasses/FunctionDefinitions/Functions/CompleteStep.ts index 97ffed2..b6064af 100644 --- a/AIClasses/FunctionDefinitions/Functions/CompleteStep.ts +++ b/AIClasses/FunctionDefinitions/Functions/CompleteStep.ts @@ -1,8 +1,8 @@ -import { AIFunction } from "Enums/AIFunction"; -import type { IAIFunctionDefinition } from "../IAIFunctionDefinition"; +import { AITool } from "Enums/AITool"; +import type { IAIToolDefinition } from "../IAIToolDefinition"; -export const CompleteStep: IAIFunctionDefinition = { - name: AIFunction.CompleteStep, +export const CompleteStep: IAIToolDefinition = { + name: AITool.CompleteStep, description: `Signals that plan execution should proceed to the next step without modification. Call this function: diff --git a/AIClasses/FunctionDefinitions/Functions/CompleteTask.ts b/AIClasses/FunctionDefinitions/Functions/CompleteTask.ts index 3d474a8..2f42863 100644 --- a/AIClasses/FunctionDefinitions/Functions/CompleteTask.ts +++ b/AIClasses/FunctionDefinitions/Functions/CompleteTask.ts @@ -1,8 +1,8 @@ -import { AIFunction } from "Enums/AIFunction"; -import type { IAIFunctionDefinition } from "../IAIFunctionDefinition"; +import { AITool } from "Enums/AITool"; +import type { IAIToolDefinition } from "../IAIToolDefinition"; -export const CompleteTask: IAIFunctionDefinition = { - name: AIFunction.CompleteTask, +export const CompleteTask: IAIToolDefinition = { + name: AITool.CompleteTask, description: `Signals that you have finished executing all of your assigned instructions. This function MUST be called exactly once, only after you have fully completed or can no longer make progress on everything you were asked to do. diff --git a/AIClasses/FunctionDefinitions/Functions/ContinuePlanExecution.ts b/AIClasses/FunctionDefinitions/Functions/ContinuePlanExecution.ts index da80000..ada1b5b 100644 --- a/AIClasses/FunctionDefinitions/Functions/ContinuePlanExecution.ts +++ b/AIClasses/FunctionDefinitions/Functions/ContinuePlanExecution.ts @@ -1,8 +1,8 @@ -import { AIFunction } from "Enums/AIFunction"; -import type { IAIFunctionDefinition } from "../IAIFunctionDefinition"; +import { AITool } from "Enums/AITool"; +import type { IAIToolDefinition } from "../IAIToolDefinition"; -export const ContinuePlanExecution: IAIFunctionDefinition = { - name: AIFunction.ContinuePlanExecution, +export const ContinuePlanExecution: IAIToolDefinition = { + name: AITool.ContinuePlanExecution, description: `Signals that you need to perform additional actions to complete the current step. Call this function: diff --git a/AIClasses/FunctionDefinitions/Functions/DeleteVaultFiles.ts b/AIClasses/FunctionDefinitions/Functions/DeleteVaultFiles.ts index 3bdca1b..ea1f01c 100644 --- a/AIClasses/FunctionDefinitions/Functions/DeleteVaultFiles.ts +++ b/AIClasses/FunctionDefinitions/Functions/DeleteVaultFiles.ts @@ -1,8 +1,8 @@ -import { AIFunction } from "Enums/AIFunction"; -import type { IAIFunctionDefinition } from "../IAIFunctionDefinition"; +import { AITool } from "Enums/AITool"; +import type { IAIToolDefinition } from "../IAIToolDefinition"; -export const DeleteVaultFiles: IAIFunctionDefinition = { - name: AIFunction.DeleteVaultFiles, +export const DeleteVaultFiles: IAIToolDefinition = { + name: AITool.DeleteVaultFiles, description: `Permanently removes files and folders from the vault. IMPORTANT: This action is irreversible - always confirm the exact file path(s) before deletion. diff --git a/AIClasses/FunctionDefinitions/Functions/ExecuteWorkflow.ts b/AIClasses/FunctionDefinitions/Functions/ExecuteWorkflow.ts index 5c448ef..c6d192c 100644 --- a/AIClasses/FunctionDefinitions/Functions/ExecuteWorkflow.ts +++ b/AIClasses/FunctionDefinitions/Functions/ExecuteWorkflow.ts @@ -1,8 +1,8 @@ -import { AIFunction } from "Enums/AIFunction"; -import type { IAIFunctionDefinition } from "../IAIFunctionDefinition"; +import { AITool } from "Enums/AITool"; +import type { IAIToolDefinition } from "../IAIToolDefinition"; -export const ExecuteWorkflow: IAIFunctionDefinition = { - name: AIFunction.ExecuteWorkflow, +export const ExecuteWorkflow: IAIToolDefinition = { + name: AITool.ExecuteWorkflow, description: `Delegates a complex goal to a specialized workflow system that will autonomously plan, execute, and return the completed result. When called, this tool hands off the goal to a planning and execution engine that operates independently. The system will analyze the goal, create a detailed plan, execute each step programmatically, handle any necessary replanning if steps fail, and return the final outcome. You do not need to manage or monitor the execution — the result will be returned to you once the workflow completes or if it fails irrecoverably. diff --git a/AIClasses/FunctionDefinitions/Functions/ListVaultFiles.ts b/AIClasses/FunctionDefinitions/Functions/ListVaultFiles.ts index 5185d8e..22b4de3 100644 --- a/AIClasses/FunctionDefinitions/Functions/ListVaultFiles.ts +++ b/AIClasses/FunctionDefinitions/Functions/ListVaultFiles.ts @@ -1,8 +1,8 @@ -import { AIFunction } from "Enums/AIFunction"; -import type { IAIFunctionDefinition } from "../IAIFunctionDefinition"; +import { AITool } from "Enums/AITool"; +import type { IAIToolDefinition } from "../IAIToolDefinition"; -export const ListVaultFiles: IAIFunctionDefinition = { - name: AIFunction.ListVaultFiles, +export const ListVaultFiles: IAIToolDefinition = { + name: AITool.ListVaultFiles, description: `Lists files and directories in the vault's directory structure. Returns a structured view of the vault's organization including file names, paths, and directory hierarchy. diff --git a/AIClasses/FunctionDefinitions/Functions/MoveVaultFiles.ts b/AIClasses/FunctionDefinitions/Functions/MoveVaultFiles.ts index abf3b59..f7b04bc 100644 --- a/AIClasses/FunctionDefinitions/Functions/MoveVaultFiles.ts +++ b/AIClasses/FunctionDefinitions/Functions/MoveVaultFiles.ts @@ -1,8 +1,8 @@ -import { AIFunction } from "Enums/AIFunction"; -import type { IAIFunctionDefinition } from "../IAIFunctionDefinition"; +import { AITool } from "Enums/AITool"; +import type { IAIToolDefinition } from "../IAIToolDefinition"; -export const MoveVaultFiles: IAIFunctionDefinition = { - name: AIFunction.MoveVaultFiles, +export const MoveVaultFiles: IAIToolDefinition = { + name: AITool.MoveVaultFiles, description: `Moves or renames one or more files within the vault to new locations. This operation preserves file content while updating paths and names. diff --git a/AIClasses/FunctionDefinitions/Functions/PatchVaultFile.ts b/AIClasses/FunctionDefinitions/Functions/PatchVaultFile.ts index 17cc940..9bdce0a 100644 --- a/AIClasses/FunctionDefinitions/Functions/PatchVaultFile.ts +++ b/AIClasses/FunctionDefinitions/Functions/PatchVaultFile.ts @@ -1,8 +1,8 @@ -import { AIFunction } from "Enums/AIFunction"; -import type { IAIFunctionDefinition } from "../IAIFunctionDefinition"; +import { AITool } from "Enums/AITool"; +import type { IAIToolDefinition } from "../IAIToolDefinition"; -export const PatchVaultFile: IAIFunctionDefinition = { - name: AIFunction.PatchVaultFile, +export const PatchVaultFile: IAIToolDefinition = { + name: AITool.PatchVaultFile, description: `Apply targeted changes to an existing file in the vault by finding and replacing specific content. This tool modifies specific sections of a file by matching exact content and replacing it with new content. It works by performing a direct string match and replace operation. diff --git a/AIClasses/FunctionDefinitions/Functions/ReadVaultFiles.ts b/AIClasses/FunctionDefinitions/Functions/ReadVaultFiles.ts index 259f736..7089473 100644 --- a/AIClasses/FunctionDefinitions/Functions/ReadVaultFiles.ts +++ b/AIClasses/FunctionDefinitions/Functions/ReadVaultFiles.ts @@ -1,8 +1,8 @@ -import { AIFunction } from "Enums/AIFunction"; -import type { IAIFunctionDefinition } from "../IAIFunctionDefinition"; +import { AITool } from "Enums/AITool"; +import type { IAIToolDefinition } from "../IAIToolDefinition"; -export const ReadVaultFiles: IAIFunctionDefinition = { - name: AIFunction.ReadVaultFiles, +export const ReadVaultFiles: IAIToolDefinition = { + name: AITool.ReadVaultFiles, description: `Reads and returns the complete content of one or more files from the vault. **IMPORTANT: This function gives you the ability to SEE and ANALYZE images diff --git a/AIClasses/FunctionDefinitions/Functions/Replan.ts b/AIClasses/FunctionDefinitions/Functions/Replan.ts index f9a8105..1a5a481 100644 --- a/AIClasses/FunctionDefinitions/Functions/Replan.ts +++ b/AIClasses/FunctionDefinitions/Functions/Replan.ts @@ -1,8 +1,8 @@ -import { AIFunction } from "Enums/AIFunction"; -import type { IAIFunctionDefinition } from "../IAIFunctionDefinition"; +import { AITool } from "Enums/AITool"; +import type { IAIToolDefinition } from "../IAIToolDefinition"; -export const Replan: IAIFunctionDefinition = { - name: AIFunction.Replan, +export const Replan: IAIToolDefinition = { + name: AITool.Replan, description: `Signals that the current plan needs to be revised before execution can continue. Call this function: diff --git a/AIClasses/FunctionDefinitions/Functions/SearchVaultFiles.ts b/AIClasses/FunctionDefinitions/Functions/SearchVaultFiles.ts index 60ebca3..d41b709 100644 --- a/AIClasses/FunctionDefinitions/Functions/SearchVaultFiles.ts +++ b/AIClasses/FunctionDefinitions/Functions/SearchVaultFiles.ts @@ -1,8 +1,8 @@ -import { AIFunction } from "Enums/AIFunction"; -import type { IAIFunctionDefinition } from "../IAIFunctionDefinition"; +import { AITool } from "Enums/AITool"; +import type { IAIToolDefinition } from "../IAIToolDefinition"; -export const SearchVaultFiles: IAIFunctionDefinition = { - name: AIFunction.SearchVaultFiles, +export const SearchVaultFiles: IAIToolDefinition = { + name: AITool.SearchVaultFiles, description: `Searches the content of all vault files using regex pattern matching. Returns files containing any of the search terms with contextual snippets showing where matches appear. diff --git a/AIClasses/FunctionDefinitions/Functions/SubmitPlan.ts b/AIClasses/FunctionDefinitions/Functions/SubmitPlan.ts index 6f91912..b522430 100644 --- a/AIClasses/FunctionDefinitions/Functions/SubmitPlan.ts +++ b/AIClasses/FunctionDefinitions/Functions/SubmitPlan.ts @@ -1,8 +1,8 @@ -import { AIFunction } from "Enums/AIFunction"; -import type { IAIFunctionDefinition } from "../IAIFunctionDefinition"; +import { AITool } from "Enums/AITool"; +import type { IAIToolDefinition } from "../IAIToolDefinition"; -export const SubmitPlan: IAIFunctionDefinition = { - name: AIFunction.SubmitPlan, +export const SubmitPlan: IAIToolDefinition = { + name: AITool.SubmitPlan, description: `Submits an execution plan with ordered, actionable steps. Call this function: diff --git a/AIClasses/FunctionDefinitions/Functions/WriteVaultFile.ts b/AIClasses/FunctionDefinitions/Functions/WriteVaultFile.ts index c92cdfa..6aa6dce 100644 --- a/AIClasses/FunctionDefinitions/Functions/WriteVaultFile.ts +++ b/AIClasses/FunctionDefinitions/Functions/WriteVaultFile.ts @@ -1,8 +1,8 @@ -import { AIFunction } from "Enums/AIFunction"; -import type { IAIFunctionDefinition } from "../IAIFunctionDefinition"; +import { AITool } from "Enums/AITool"; +import type { IAIToolDefinition } from "../IAIToolDefinition"; -export const WriteVaultFile: IAIFunctionDefinition = { - name: AIFunction.WriteVaultFile, +export const WriteVaultFile: IAIToolDefinition = { + name: AITool.WriteVaultFile, description: `Writes content to a file, creating it if it doesn't exist or replacing its contents if it does. Call this function: diff --git a/AIClasses/FunctionDefinitions/IAIFunctionDefinition.ts b/AIClasses/FunctionDefinitions/IAIToolDefinition.ts similarity index 56% rename from AIClasses/FunctionDefinitions/IAIFunctionDefinition.ts rename to AIClasses/FunctionDefinitions/IAIToolDefinition.ts index 2730740..9bc0cc1 100644 --- a/AIClasses/FunctionDefinitions/IAIFunctionDefinition.ts +++ b/AIClasses/FunctionDefinitions/IAIToolDefinition.ts @@ -1,9 +1,9 @@ -import type { AIFunction } from "Enums/AIFunction"; -import type { JSONSchemaProperty } from "../Schemas/AIFunctionTypes"; +import type { AITool } from "Enums/AITool"; +import type { JSONSchemaProperty } from "../Schemas/AIToolTypes"; // platform agnostic function definition used to present function calls in an API call -export interface IAIFunctionDefinition { - name: AIFunction; +export interface IAIToolDefinition { + name: AITool; description: string; parameters: { type: string; diff --git a/AIClasses/Gemini/Gemini.ts b/AIClasses/Gemini/Gemini.ts index f14af9f..0341fff 100644 --- a/AIClasses/Gemini/Gemini.ts +++ b/AIClasses/Gemini/Gemini.ts @@ -4,9 +4,9 @@ import type { Conversation } from "Conversations/Conversation"; import type { Attachment } from "Conversations/Attachment"; import { Role } from "Enums/Role"; import { AIProvider, AIProviderURL } from "Enums/ApiProvider"; -import { AIFunctionCall } from "AIClasses/AIFunctionCall"; -import { fromString as aiFunctionFromString } from "Enums/AIFunction"; -import type { IAIFunctionDefinition } from "AIClasses/FunctionDefinitions/IAIFunctionDefinition"; +import { AIToolCall } from "AIClasses/AIToolCall"; +import { fromString as aiToolFromString } from "Enums/AITool"; +import type { IAIToolDefinition } from "AIClasses/FunctionDefinitions/IAIToolDefinition"; import type { ConversationContent } from "Conversations/ConversationContent"; import type { Candidate, Part, FunctionDeclaration } from "@google/genai"; import { FinishReason } from "@google/genai"; @@ -17,7 +17,7 @@ import { Exception } from "Helpers/Exception"; import { ApiError, ApiErrorType } from "Types/ApiError"; import { parseFunctionCall, parseFunctionResponse } from "Helpers/ResponseHelper"; import type { GeminiRetryInfo, GeminiErrorResponse } from "./GeminiTypes"; -import { AIFunctionUsageMode } from "Enums/AIFunctionUsageMode"; +import { AIToolUsageMode } from "Enums/AIToolUsageMode"; export class Gemini extends BaseAIClass { @@ -104,7 +104,7 @@ export class Gemini extends BaseAIClass { information, recent events, news, or facts that may have changed. After calling this, you will be able to perform web searches.`, }, - ...this.mapFunctionDefinitions(this.aiFunctionDefinitions), + ...this.mapFunctionDefinitions(this.aiToolDefinitions), ] } @@ -157,7 +157,7 @@ export class Gemini extends BaseAIClass { const data = JSON.parse(chunk) as { candidates?: Candidate[] }; let text = ""; - let functionCall: AIFunctionCall | undefined = undefined; + let functionCall: AIToolCall | undefined = undefined; const candidate = data.candidates?.[0]; if (candidate) { @@ -199,8 +199,8 @@ export class Gemini extends BaseAIClass { // If streaming is complete and we have accumulated a function call, return it if (isComplete && this.accumulatedFunctionName) { - functionCall = new AIFunctionCall( - aiFunctionFromString(this.accumulatedFunctionName), + functionCall = new AIToolCall( + aiToolFromString(this.accumulatedFunctionName), this.accumulatedFunctionArgs as Record, undefined, // toolId not used by Gemini this.accumulatedThoughtSignature || undefined @@ -317,8 +317,8 @@ export class Gemini extends BaseAIClass { return results.filter(message => message.parts.length > 0); } - protected mapFunctionDefinitions(aiFunctionDefinitions: IAIFunctionDefinition[]): FunctionDeclaration[] { - return aiFunctionDefinitions.map((functionDefinition) => ({ + protected mapFunctionDefinitions(aiToolDefinitions: IAIToolDefinition[]): FunctionDeclaration[] { + return aiToolDefinitions.map((functionDefinition) => ({ name: functionDefinition.name, description: functionDefinition.description, parameters: functionDefinition.parameters as FunctionDeclaration['parameters'] @@ -362,16 +362,16 @@ export class Gemini extends BaseAIClass { private buildGeminiToolConfig(): { function_calling_config: { mode: string } } { // If no tools defined, fall back to auto - if (this.aiFunctionDefinitions.length === 0) { + if (this.aiToolDefinitions.length === 0) { return { function_calling_config: { mode: "AUTO" } }; } - switch (this.aiFunctionUsageMode) { - case AIFunctionUsageMode.Auto: + switch (this.aiToolUsageMode) { + case AIToolUsageMode.Auto: return { function_calling_config: { mode: "AUTO" } }; - case AIFunctionUsageMode.Enabled: + case AIToolUsageMode.Enabled: return { function_calling_config: { mode: "ANY" } }; - case AIFunctionUsageMode.Disabled: + case AIToolUsageMode.Disabled: return { function_calling_config: { mode: "NONE" } }; } } diff --git a/AIClasses/IAIClass.ts b/AIClasses/IAIClass.ts index 90550d5..4313942 100644 --- a/AIClasses/IAIClass.ts +++ b/AIClasses/IAIClass.ts @@ -1,18 +1,18 @@ import type { IStreamChunk } from "Services/StreamingService"; import type { Conversation } from "Conversations/Conversation"; import type { Attachment } from "Conversations/Attachment"; -import type { IAIFunctionDefinition } from "./FunctionDefinitions/IAIFunctionDefinition"; +import type { IAIToolDefinition } from "./FunctionDefinitions/IAIToolDefinition"; import type { AIProvider } from "Enums/ApiProvider"; import type { AgentType } from "Enums/AgentType"; -import type { AIFunctionUsageMode } from "Enums/AIFunctionUsageMode"; +import type { AIToolUsageMode } from "Enums/AIToolUsageMode"; export interface IAIClass { get currentProvider(): AIProvider; set agentType(agentType: AgentType); set systemPrompt(systemPrompt: string); set userInstruction(userInstruction: string); - set aiFunctionDefinitions(aiFunctionDefinitions: IAIFunctionDefinition[]); - set aiFunctionUsageMode(mode: AIFunctionUsageMode); + set aiToolDefinitions(aiToolDefinitions: IAIToolDefinition[]); + set aiToolUsageMode(mode: AIToolUsageMode); streamRequest(conversation: Conversation): AsyncGenerator; formatBinaryFiles(attachments: Attachment[]): string; diff --git a/AIClasses/OpenAI/OpenAI.ts b/AIClasses/OpenAI/OpenAI.ts index 4a8ccd7..3425182 100644 --- a/AIClasses/OpenAI/OpenAI.ts +++ b/AIClasses/OpenAI/OpenAI.ts @@ -4,17 +4,17 @@ import type { Conversation } from "Conversations/Conversation"; import type { ConversationContent } from "Conversations/ConversationContent"; import type { Attachment } from "Conversations/Attachment"; import { AIProvider, AIProviderURL } from "Enums/ApiProvider"; -import { AIFunctionCall } from "AIClasses/AIFunctionCall"; -import { fromString as aiFunctionFromString } from "Enums/AIFunction"; -import type { IAIFunctionDefinition } from "AIClasses/FunctionDefinitions/IAIFunctionDefinition"; -import type { ResponseEvent, ResponseOutputTextDelta, ResponseOutputItemDone, ResponseErrorEvent, ResponseFailedEvent, OpenAIFunctionTool, ResponsesAPIInput } from "./OpenAITypes"; +import { AIToolCall } from "AIClasses/AIToolCall"; +import { fromString as aiToolFromString } from "Enums/AITool"; +import type { IAIToolDefinition } from "AIClasses/FunctionDefinitions/IAIToolDefinition"; +import type { ResponseEvent, ResponseOutputTextDelta, ResponseOutputItemDone, ResponseErrorEvent, ResponseFailedEvent, OpenAIToolTool, ResponsesAPIInput } from "./OpenAITypes"; import { Exception } from "Helpers/Exception"; import { ApiError, ApiErrorType } from "Types/ApiError"; import { MimeType, toMimeType } from "Enums/MimeType"; import { isTextFile } from "Enums/FileType"; import { MimeTypeToFileTypes } from "Enums/FileTypeMimeTypeMapping"; import { parseFunctionCall, parseFunctionResponse } from "Helpers/ResponseHelper"; -import { AIFunctionUsageMode } from "Enums/AIFunctionUsageMode"; +import { AIToolUsageMode } from "Enums/AIToolUsageMode"; export class OpenAI extends BaseAIClass { @@ -43,7 +43,7 @@ export class OpenAI extends BaseAIClass { const tools = [{ type: "web_search" - }, ...this.mapFunctionDefinitions(this.aiFunctionDefinitions)]; + }, ...this.mapFunctionDefinitions(this.aiToolDefinitions)]; const requestBody = { model: this.model(), @@ -78,7 +78,7 @@ export class OpenAI extends BaseAIClass { const event = JSON.parse(chunk) as ResponseEvent; let text = ""; - let functionCall: AIFunctionCall | undefined = undefined; + let functionCall: AIToolCall | undefined = undefined; let isComplete = false; let shouldContinue = false; @@ -148,8 +148,8 @@ export class OpenAI extends BaseAIClass { itemDoneEvent.item.arguments) { try { const args = JSON.parse(itemDoneEvent.item.arguments) as Record; - functionCall = new AIFunctionCall( - aiFunctionFromString(itemDoneEvent.item.name), + functionCall = new AIToolCall( + aiToolFromString(itemDoneEvent.item.name), args as Record, itemDoneEvent.item.call_id || itemDoneEvent.item_id, undefined // thoughtSignature not used by OpenAI @@ -305,8 +305,8 @@ export class OpenAI extends BaseAIClass { return results; } - protected mapFunctionDefinitions(aiFunctionDefinitions: IAIFunctionDefinition[]): OpenAIFunctionTool[] { - return aiFunctionDefinitions.map((functionDefinition) => ({ + protected mapFunctionDefinitions(aiToolDefinitions: IAIToolDefinition[]): OpenAIToolTool[] { + return aiToolDefinitions.map((functionDefinition) => ({ type: "function", name: functionDefinition.name, description: functionDefinition.description, @@ -354,16 +354,16 @@ export class OpenAI extends BaseAIClass { private buildOpenAIToolChoice(): string { // If no tools defined, fall back to auto - if (this.aiFunctionDefinitions.length === 0) { + if (this.aiToolDefinitions.length === 0) { return "auto"; } - switch (this.aiFunctionUsageMode) { - case AIFunctionUsageMode.Auto: + switch (this.aiToolUsageMode) { + case AIToolUsageMode.Auto: return "auto"; - case AIFunctionUsageMode.Enabled: + case AIToolUsageMode.Enabled: return "required"; - case AIFunctionUsageMode.Disabled: + case AIToolUsageMode.Disabled: return "none"; } } diff --git a/AIClasses/OpenAI/OpenAITypes.ts b/AIClasses/OpenAI/OpenAITypes.ts index e73fc46..d2f6cff 100644 --- a/AIClasses/OpenAI/OpenAITypes.ts +++ b/AIClasses/OpenAI/OpenAITypes.ts @@ -1,4 +1,4 @@ -import type { IAIFunctionDefinition } from "AIClasses/FunctionDefinitions/IAIFunctionDefinition"; +import type { IAIToolDefinition } from "AIClasses/FunctionDefinitions/IAIToolDefinition"; /* SDK types are a bit complicated and verbose so define simpler interfaces */ @@ -73,11 +73,11 @@ export interface ResponseFailedEvent extends ResponseEvent { }; } -export interface OpenAIFunctionTool { +export interface OpenAIToolTool { type: "function"; name: string; description: string; - parameters: IAIFunctionDefinition["parameters"]; + parameters: IAIToolDefinition["parameters"]; } /** diff --git a/AIClasses/Schemas/AIFunctionSchemas.ts b/AIClasses/Schemas/AIToolSchemas.ts similarity index 100% rename from AIClasses/Schemas/AIFunctionSchemas.ts rename to AIClasses/Schemas/AIToolSchemas.ts diff --git a/AIClasses/Schemas/AIFunctionTypes.ts b/AIClasses/Schemas/AIToolTypes.ts similarity index 100% rename from AIClasses/Schemas/AIFunctionTypes.ts rename to AIClasses/Schemas/AIToolTypes.ts diff --git a/AIPrompts/PlanningPrompt.ts b/AIPrompts/PlanningPrompt.ts index a13fb93..e4d88ec 100644 --- a/AIPrompts/PlanningPrompt.ts +++ b/AIPrompts/PlanningPrompt.ts @@ -1,4 +1,4 @@ -import { AIFunctionDefinitions } from "AIClasses/FunctionDefinitions/AIFunctionDefinitions"; +import { AIToolDefinitions } from "AIClasses/FunctionDefinitions/AIToolDefinitions"; export const PlanningPrompt: string = ` # Obsidian Vault Planning Agent @@ -229,7 +229,7 @@ If extensive searching yields nothing: The main agent has access to the following vault operation capabilities: -${AIFunctionDefinitions.compactSummaryForPlanningAgent()} +${AIToolDefinitions.compactSummaryForPlanningAgent()} **Important**: - Design your plan steps around these capabilities diff --git a/Conversations/Conversation.ts b/Conversations/Conversation.ts index 7ac5d42..3c9384d 100644 --- a/Conversations/Conversation.ts +++ b/Conversations/Conversation.ts @@ -1,9 +1,9 @@ import { StringTools } from "Helpers/StringTools"; import { ConversationContent } from "./ConversationContent"; import { Attachment } from "./Attachment"; -import type { AIFunctionResponse } from "AIClasses/FunctionDefinitions/AIFunctionResponse"; +import type { AIToolResponse } from "AIClasses/FunctionDefinitions/AIToolResponse"; import { Role } from "Enums/Role"; -import { AIFunction } from "Enums/AIFunction"; +import { AITool } from "Enums/AITool"; import { isTextFile, toFileType } from "Enums/FileType"; import { FileTypeToMimeType } from "Enums/FileTypeMimeTypeMapping"; @@ -27,8 +27,8 @@ export class Conversation { return this.contents.some(c => c.attachments.length > 0); } - public addFunctionResponse(functionResponse: AIFunctionResponse): void { - if (functionResponse.name !== AIFunction.ReadVaultFiles) { + public addFunctionResponse(functionResponse: AIToolResponse): void { + if (functionResponse.name !== AITool.ReadVaultFiles) { const functionResponseString = functionResponse.toConversationString(); this.contents.push(new ConversationContent({ role: Role.User, diff --git a/Enums/AIFunction.ts b/Enums/AITool.ts similarity index 69% rename from Enums/AIFunction.ts rename to Enums/AITool.ts index 2a97de3..dadd8bc 100644 --- a/Enums/AIFunction.ts +++ b/Enums/AITool.ts @@ -1,4 +1,4 @@ -export enum AIFunction { +export enum AITool { SearchVaultFiles = "search_vault_files", ReadVaultFiles = "read_vault_files", WriteVaultFile = "write_vault_file", @@ -25,14 +25,14 @@ export enum AIFunction { Unknown = "unknown" } -export function fromString(functionName: string): AIFunction { - const enumValue = Object.values(AIFunction).find((value: string) => value === functionName); +export function fromString(functionName: string): AITool { + const enumValue = Object.values(AITool).find((value: string) => value === functionName); if (enumValue) { - return enumValue as AIFunction; + return enumValue as AITool; } - return AIFunction.Unknown; + return AITool.Unknown; } -export function isAIFunction(value: unknown, aiFunction: AIFunction): value is AIFunction { - return value === aiFunction; +export function isAITool(value: unknown, aiTool: AITool): value is AITool { + return value === aiTool; } \ No newline at end of file diff --git a/Enums/AIFunctionUsageMode.ts b/Enums/AIToolUsageMode.ts similarity index 67% rename from Enums/AIFunctionUsageMode.ts rename to Enums/AIToolUsageMode.ts index 890482c..5a75136 100644 --- a/Enums/AIFunctionUsageMode.ts +++ b/Enums/AIToolUsageMode.ts @@ -1,4 +1,4 @@ -export enum AIFunctionUsageMode { +export enum AIToolUsageMode { Auto = "auto", Enabled = "enabled", Disabled = "disabled" diff --git a/Helpers/ResponseHelper.ts b/Helpers/ResponseHelper.ts index 9046de5..f919f30 100644 --- a/Helpers/ResponseHelper.ts +++ b/Helpers/ResponseHelper.ts @@ -1,10 +1,10 @@ -import type { AIFunctionCall } from "AIClasses/AIFunctionCall"; -import type { StoredFunctionCall, StoredFunctionResponse } from "AIClasses/Schemas/AIFunctionTypes"; +import type { AIToolCall } from "AIClasses/AIToolCall"; +import type { StoredFunctionCall, StoredFunctionResponse } from "AIClasses/Schemas/AIToolTypes"; import { StringTools } from "./StringTools"; import { Exception } from "./Exception"; // handle the rare event where a function call is also included in content (gemini sometimes does this) -export function sanitizeFunctionCallContent(content: string, functionCall: AIFunctionCall | null): string { +export function sanitizeFunctionCallContent(content: string, functionCall: AIToolCall | null): string { // Early returns for simple cases if (!functionCall || !content.trim()) { return content; diff --git a/Services/AIServices/AIFunctionService.ts b/Services/AIServices/AIToolService.ts similarity index 70% rename from Services/AIServices/AIFunctionService.ts rename to Services/AIServices/AIToolService.ts index 085d490..a4eb1a4 100644 --- a/Services/AIServices/AIFunctionService.ts +++ b/Services/AIServices/AIToolService.ts @@ -1,9 +1,9 @@ import { Resolve } from "../DependencyService"; import { Services } from "../Services"; import type { FileSystemService } from "../FileSystemService"; -import { AIFunction, fromString } from "Enums/AIFunction"; -import { AIFunctionResponse } from "AIClasses/FunctionDefinitions/AIFunctionResponse"; -import type { AIFunctionCall } from "AIClasses/AIFunctionCall"; +import { AITool, fromString } from "Enums/AITool"; +import { AIToolResponse } from "AIClasses/FunctionDefinitions/AIToolResponse"; +import type { AIToolCall } from "AIClasses/AIToolCall"; import type { ISearchMatch } from "../../Types/SearchTypes"; import { AbortService } from "../AbortService"; import { normalizePath, TAbstractFile, TFile } from "obsidian"; @@ -17,9 +17,9 @@ import { MoveVaultFilesArgsSchema, ListVaultFilesArgsSchema, PatchVaultFileArgsSchema -} from "AIClasses/Schemas/AIFunctionSchemas"; +} from "AIClasses/Schemas/AIToolSchemas"; -export class AIFunctionService { +export class AIToolService { private readonly fileSystemService: FileSystemService; private readonly abortService: AbortService; @@ -29,122 +29,122 @@ export class AIFunctionService { this.abortService = Resolve(Services.AbortService); } - public async performAIFunction(functionCall: AIFunctionCall): Promise { + public async performAITool(functionCall: AIToolCall): Promise { return await this.abortService.abortableOperation(async () => { switch (functionCall.name) { - case AIFunction.SearchVaultFiles: { + case AITool.SearchVaultFiles: { const parseResult = SearchVaultFilesArgsSchema.safeParse(functionCall.arguments); if (!parseResult.success) { - return new AIFunctionResponse( + return new AIToolResponse( functionCall.name, - { error: `Invalid arguments for ${AIFunction.SearchVaultFiles}: ${parseResult.error.message}` }, + { error: `Invalid arguments for ${AITool.SearchVaultFiles}: ${parseResult.error.message}` }, functionCall.toolId ); } - return new AIFunctionResponse(functionCall.name, await this.searchVaultFiles(parseResult.data.search_terms), functionCall.toolId); + return new AIToolResponse(functionCall.name, await this.searchVaultFiles(parseResult.data.search_terms), functionCall.toolId); } - case AIFunction.ReadVaultFiles: { + case AITool.ReadVaultFiles: { const parseResult = ReadVaultFilesArgsSchema.safeParse(functionCall.arguments); if (!parseResult.success) { - return new AIFunctionResponse( + return new AIToolResponse( functionCall.name, - { error: `Invalid arguments for ${AIFunction.ReadVaultFiles}: ${parseResult.error.message}` }, + { error: `Invalid arguments for ${AITool.ReadVaultFiles}: ${parseResult.error.message}` }, functionCall.toolId ); } - return new AIFunctionResponse(functionCall.name, await this.readVaultFiles(parseResult.data.file_paths), functionCall.toolId); + return new AIToolResponse(functionCall.name, await this.readVaultFiles(parseResult.data.file_paths), functionCall.toolId); } - case AIFunction.WriteVaultFile: { + case AITool.WriteVaultFile: { const parseResult = WriteVaultFileArgsSchema.safeParse(functionCall.arguments); if (!parseResult.success) { - return new AIFunctionResponse( + return new AIToolResponse( functionCall.name, - { error: `Invalid arguments for ${AIFunction.WriteVaultFile}: ${parseResult.error.message}` }, + { error: `Invalid arguments for ${AITool.WriteVaultFile}: ${parseResult.error.message}` }, functionCall.toolId ); } - return new AIFunctionResponse(functionCall.name, await this.writeVaultFile(parseResult.data.file_path, parseResult.data.content), functionCall.toolId); + return new AIToolResponse(functionCall.name, await this.writeVaultFile(parseResult.data.file_path, parseResult.data.content), functionCall.toolId); } - case AIFunction.PatchVaultFile: { + case AITool.PatchVaultFile: { const parseResult = PatchVaultFileArgsSchema.safeParse(functionCall.arguments); if (!parseResult.success) { - return new AIFunctionResponse( + return new AIToolResponse( functionCall.name, - { error: `Invalid arguments for ${AIFunction.PatchVaultFile}: ${parseResult.error.message}` }, + { error: `Invalid arguments for ${AITool.PatchVaultFile}: ${parseResult.error.message}` }, functionCall.toolId ); } - return new AIFunctionResponse(functionCall.name, await this.patchVaultFile(parseResult.data.file_path, parseResult.data.oldContent, parseResult.data.newContent), functionCall.toolId); + return new AIToolResponse(functionCall.name, await this.patchVaultFile(parseResult.data.file_path, parseResult.data.oldContent, parseResult.data.newContent), functionCall.toolId); } - case AIFunction.DeleteVaultFiles: { + case AITool.DeleteVaultFiles: { const parseResult = DeleteVaultFilesArgsSchema.safeParse(functionCall.arguments); if (!parseResult.success) { - return new AIFunctionResponse( + return new AIToolResponse( functionCall.name, - { error: `Invalid arguments for ${AIFunction.DeleteVaultFiles}: ${parseResult.error.message}` }, + { error: `Invalid arguments for ${AITool.DeleteVaultFiles}: ${parseResult.error.message}` }, functionCall.toolId ); } - return new AIFunctionResponse(functionCall.name, await this.deleteVaultFiles(parseResult.data.file_paths, parseResult.data.confirm_deletion), functionCall.toolId); + return new AIToolResponse(functionCall.name, await this.deleteVaultFiles(parseResult.data.file_paths, parseResult.data.confirm_deletion), functionCall.toolId); } - case AIFunction.MoveVaultFiles: { + case AITool.MoveVaultFiles: { const parseResult = MoveVaultFilesArgsSchema.safeParse(functionCall.arguments); if (!parseResult.success) { - return new AIFunctionResponse( + return new AIToolResponse( functionCall.name, - { error: `Invalid arguments for ${AIFunction.MoveVaultFiles}: ${parseResult.error.message}` }, + { error: `Invalid arguments for ${AITool.MoveVaultFiles}: ${parseResult.error.message}` }, functionCall.toolId ); } - return new AIFunctionResponse(functionCall.name, await this.moveVaultFiles(parseResult.data.source_paths, parseResult.data.destination_paths), functionCall.toolId); + return new AIToolResponse(functionCall.name, await this.moveVaultFiles(parseResult.data.source_paths, parseResult.data.destination_paths), functionCall.toolId); } - case AIFunction.ListVaultFiles: { + case AITool.ListVaultFiles: { const parseResult = ListVaultFilesArgsSchema.safeParse(functionCall.arguments); if (!parseResult.success) { - return new AIFunctionResponse( + return new AIToolResponse( functionCall.name, - { error: `Invalid arguments for ${AIFunction.ListVaultFiles}: ${parseResult.error.message}` }, + { error: `Invalid arguments for ${AITool.ListVaultFiles}: ${parseResult.error.message}` }, functionCall.toolId ); } - return new AIFunctionResponse(functionCall.name, await this.ListVaultFiles(parseResult.data.path, parseResult.data.recursive), functionCall.toolId); + return new AIToolResponse(functionCall.name, await this.ListVaultFiles(parseResult.data.path, parseResult.data.recursive), functionCall.toolId); } // This is only used by gemini - case AIFunction.RequestWebSearch: - return new AIFunctionResponse(functionCall.name, {}, functionCall.toolId) + case AITool.RequestWebSearch: + return new AIToolResponse(functionCall.name, {}, functionCall.toolId) // multi-agent functions are handled elsewhere - this shouldn't really ever get hit - case AIFunction.ExecuteWorkflow: - case AIFunction.ContinuePlanExecution: - case AIFunction.Replan: - case AIFunction.SubmitPlan: - case AIFunction.AskUserQuestionPlanning: - case AIFunction.AskUserQuestionExecution: - case AIFunction.CompleteTask: - case AIFunction.CompleteStep: - case AIFunction.CompletePlan: - case AIFunction.CancelPlan: { - Exception.log(`Multi-agent function ${functionCall.name} should not be handled by AIFunctionService`); - return new AIFunctionResponse( + case AITool.ExecuteWorkflow: + case AITool.ContinuePlanExecution: + case AITool.Replan: + case AITool.SubmitPlan: + case AITool.AskUserQuestionPlanning: + case AITool.AskUserQuestionExecution: + case AITool.CompleteTask: + case AITool.CompleteStep: + case AITool.CompletePlan: + case AITool.CancelPlan: { + Exception.log(`Multi-agent function ${functionCall.name} should not be handled by AIToolService`); + return new AIToolResponse( functionCall.name, { error: `Failed to execute ${functionCall.name}.` }, functionCall.toolId ); } - case AIFunction.Unknown: + case AITool.Unknown: default: { const functionCallName = fromString(functionCall.name); const error = `Unknown function request ${functionCallName}` Exception.log(error); - return new AIFunctionResponse( + return new AIToolResponse( functionCallName, { error: error }, functionCall.toolId diff --git a/Services/AIServices/BaseAgent.ts b/Services/AIServices/BaseAgent.ts index 93b2e45..bd0ae4c 100644 --- a/Services/AIServices/BaseAgent.ts +++ b/Services/AIServices/BaseAgent.ts @@ -1,4 +1,4 @@ -import type { AIFunctionCall } from "AIClasses/AIFunctionCall"; +import type { AIToolCall } from "AIClasses/AIToolCall"; import type { IAIClass } from "AIClasses/IAIClass"; import type { IPrompt } from "AIPrompts/IPrompt"; import type { Conversation } from "Conversations/Conversation"; @@ -10,24 +10,24 @@ import { sanitizeFunctionCallContent } from "Helpers/ResponseHelper"; import type { IChatServiceCallbacks } from "Services/ChatService"; import { Resolve, TryResolve } from "Services/DependencyService"; import { Services } from "Services/Services"; -import type { AIFunctionService } from "./AIFunctionService"; +import type { AIToolService } from "./AIToolService"; import type { DebugService } from "Services/DebugService"; import { DebugColor } from "Enums/DebugColor"; import { Exception } from "Helpers/Exception"; -import { AIFunctionUsageMode } from "Enums/AIFunctionUsageMode"; +import { AIToolUsageMode } from "Enums/AIToolUsageMode"; export abstract class BaseAgent { protected ai: IAIClass | undefined; protected readonly aiPrompt: IPrompt; - protected readonly aiFunctionService: AIFunctionService; + protected readonly aiToolService: AIToolService; protected readonly debugService: DebugService | undefined; private onSaveConversation?: (conversation: Conversation) => Promise; public constructor() { this.aiPrompt = Resolve(Services.IPrompt); - this.aiFunctionService = Resolve(Services.AIFunctionService); + this.aiToolService = Resolve(Services.AIToolService); this.debugService = TryResolve(Services.DebugService); this.setDebugColor(); } @@ -41,7 +41,7 @@ export abstract class BaseAgent { } protected async runAgentLoop(agentType: AgentType, conversation: Conversation, callbacks: IChatServiceCallbacks, - handleFunctionCall: (functionCall: AIFunctionCall) => Promise<{ shouldExit: boolean }> + handleFunctionCall: (functionCall: AIToolCall) => Promise<{ shouldExit: boolean }> ): Promise { this.debugService?.log("AgentLoop", `Starting ${agentType} agent loop`); let response = await this.streamRequestResponse(agentType, this.ensureCorrectConversationStructure(conversation), callbacks); @@ -86,7 +86,7 @@ export abstract class BaseAgent { }); } - protected updateThought(functionCall: AIFunctionCall | null, callbacks: IChatServiceCallbacks) { + protected updateThought(functionCall: AIToolCall | null, callbacks: IChatServiceCallbacks) { const userMessage = functionCall?.arguments.user_message; if (userMessage && typeof userMessage === "string") { callbacks.onThoughtUpdate(userMessage); @@ -117,7 +117,7 @@ export abstract class BaseAgent { } private async streamRequestResponse(agentType: AgentType, conversation: Conversation, callbacks: IChatServiceCallbacks - ): Promise<{ functionCall: AIFunctionCall | null, shouldContinue: boolean }> { + ): Promise<{ functionCall: AIToolCall | null, shouldContinue: boolean }> { if (!this.ai) { // this should never happen return { functionCall: null, shouldContinue: false }; } @@ -126,7 +126,7 @@ export abstract class BaseAgent { conversation.contents.push(conversationContent); let accumulatedContent = ""; - let capturedFunctionCall: AIFunctionCall | null = null; + let capturedFunctionCall: AIToolCall | null = null; let capturedShouldContinue = false; for await (const chunk of this.ai.streamRequest(conversation)) { @@ -191,12 +191,12 @@ export abstract class BaseAgent { Exception.throw("Error: No AI provider has been set!"); } - const aiFunctionUsageMode = this.ai.aiFunctionUsageMode; - this.ai.aiFunctionUsageMode = AIFunctionUsageMode.Disabled; + const aiToolUsageMode = this.ai.aiToolUsageMode; + this.ai.aiToolUsageMode = AIToolUsageMode.Disabled; const result = await callback(); - this.ai.aiFunctionUsageMode = aiFunctionUsageMode; + this.ai.aiToolUsageMode = aiToolUsageMode; return result; } } \ No newline at end of file diff --git a/Services/AIServices/ExecutionAgent.ts b/Services/AIServices/ExecutionAgent.ts index 4806ebf..b282fca 100644 --- a/Services/AIServices/ExecutionAgent.ts +++ b/Services/AIServices/ExecutionAgent.ts @@ -5,14 +5,14 @@ import { Conversation } from "Conversations/Conversation"; import type { IChatServiceCallbacks } from "Services/ChatService"; import { ConversationContent } from "Conversations/ConversationContent"; import { Role } from "Enums/Role"; -import { AIFunction, isAIFunction } from "Enums/AIFunction"; -import { CompleteTaskArgsSchema, type CompleteTaskArgs } from "AIClasses/Schemas/AIFunctionSchemas"; -import { AIFunctionResponse } from "AIClasses/FunctionDefinitions/AIFunctionResponse"; +import { AITool, isAITool } from "Enums/AITool"; +import { CompleteTaskArgsSchema, type CompleteTaskArgs } from "AIClasses/Schemas/AIToolSchemas"; +import { AIToolResponse } from "AIClasses/FunctionDefinitions/AIToolResponse"; import { Exception } from "Helpers/Exception"; -import { AIFunctionDefinitions } from "AIClasses/FunctionDefinitions/AIFunctionDefinitions"; +import { AIToolDefinitions } from "AIClasses/FunctionDefinitions/AIToolDefinitions"; import { Copy, replaceCopy } from "Enums/Copy"; import { DebugColor } from "Enums/DebugColor"; -import { AIFunctionUsageMode } from "Enums/AIFunctionUsageMode"; +import { AIToolUsageMode } from "Enums/AIToolUsageMode"; export class ExecutionAgent extends BaseAgent { @@ -48,12 +48,12 @@ export class ExecutionAgent extends BaseAgent { await this.runAgentLoop(AgentType.Execution, this.conversation, callbacks, async functionCall => { const functionCallName = functionCall.name; - if (isAIFunction(functionCallName, AIFunction.CompleteTask)) { + if (isAITool(functionCallName, AITool.CompleteTask)) { const parseResult = CompleteTaskArgsSchema.safeParse(functionCall.arguments); if (!parseResult.success) { - this.conversation.addFunctionResponse(new AIFunctionResponse( + this.conversation.addFunctionResponse(new AIToolResponse( functionCallName, - { error: `Invalid arguments for ${AIFunction.CompleteTask}: ${parseResult.error.message}` }, + { error: `Invalid arguments for ${AITool.CompleteTask}: ${parseResult.error.message}` }, functionCall.toolId )); return { shouldExit: false }; @@ -66,7 +66,7 @@ export class ExecutionAgent extends BaseAgent { this.debugService?.log("ExecutionAgent", `Executing function: ${functionCall.name}`); this.updateThought(functionCall, callbacks); - const functionResponse = await this.aiFunctionService.performAIFunction(functionCall); + const functionResponse = await this.aiToolService.performAITool(functionCall); this.conversation.addFunctionResponse(functionResponse); return { shouldExit: false }; }); @@ -87,10 +87,10 @@ export class ExecutionAgent extends BaseAgent { Exception.throw("Error: No AI provider has been set!"); } this.ai.agentType = AgentType.Execution; - this.ai.aiFunctionUsageMode = AIFunctionUsageMode.Enabled; + this.ai.aiToolUsageMode = AIToolUsageMode.Enabled; this.ai.systemPrompt = this.aiPrompt.executionInstruction(); this.ai.userInstruction = ""; // do not include user instruction for execution agent - this.ai.aiFunctionDefinitions = AIFunctionDefinitions.executionAgentDefinitions(); + this.ai.aiToolDefinitions = AIToolDefinitions.executionAgentDefinitions(); } protected override setDebugColor(): void { diff --git a/Services/AIServices/MainAgent.ts b/Services/AIServices/MainAgent.ts index 51ca3a5..c961075 100644 --- a/Services/AIServices/MainAgent.ts +++ b/Services/AIServices/MainAgent.ts @@ -1,18 +1,18 @@ import type { Conversation } from "Conversations/Conversation"; import type { IChatServiceCallbacks } from "../ChatService"; -import { AIFunctionDefinitions } from "AIClasses/FunctionDefinitions/AIFunctionDefinitions"; +import { AIToolDefinitions } from "AIClasses/FunctionDefinitions/AIToolDefinitions"; import { Exception } from "Helpers/Exception"; -import { AIFunction, isAIFunction } from "Enums/AIFunction"; +import { AITool, isAITool } from "Enums/AITool"; import { AgentType } from "Enums/AgentType"; import { BaseAgent } from "./BaseAgent"; -import { ExecuteWorkflowArgsSchema, type ExecuteWorkflowArgs } from "AIClasses/Schemas/AIFunctionSchemas"; -import { AIFunctionResponse } from "AIClasses/FunctionDefinitions/AIFunctionResponse"; -import type { AIFunctionCall } from "AIClasses/AIFunctionCall"; +import { ExecuteWorkflowArgsSchema, type ExecuteWorkflowArgs } from "AIClasses/Schemas/AIToolSchemas"; +import { AIToolResponse } from "AIClasses/FunctionDefinitions/AIToolResponse"; +import type { AIToolCall } from "AIClasses/AIToolCall"; import { OrchestrationAgent } from "./OrchestrationAgent"; import { ConversationContent } from "Conversations/ConversationContent"; import { Role } from "Enums/Role"; import { DebugColor } from "Enums/DebugColor"; -import { AIFunctionUsageMode } from "Enums/AIFunctionUsageMode"; +import { AIToolUsageMode } from "Enums/AIToolUsageMode"; export class MainAgent extends BaseAgent { @@ -38,7 +38,7 @@ export class MainAgent extends BaseAgent { const workflowResult = await orchestrationAgent.runPlannedWorkflow(result.planRequest, callbacks); this.debugService?.log("MainAgent", "OrchestrationAgent workflow completed"); - conversation.addFunctionResponse(new AIFunctionResponse( + conversation.addFunctionResponse(new AIToolResponse( result.functionCall.name, workflowResult, result.functionCall.toolId @@ -51,20 +51,20 @@ export class MainAgent extends BaseAgent { // the main agent loop - may return an execution plan if the agent has requested a planned workflow private async runMainAgentLoop(conversation: Conversation, callbacks: IChatServiceCallbacks - ): Promise<{ planRequest: ExecuteWorkflowArgs | undefined, functionCall: AIFunctionCall | undefined }> { + ): Promise<{ planRequest: ExecuteWorkflowArgs | undefined, functionCall: AIToolCall | undefined }> { let planRequest: ExecuteWorkflowArgs | undefined; - let planFunctionCall: AIFunctionCall | undefined; + let planFunctionCall: AIToolCall | undefined; await this.runAgentLoop(AgentType.Main, conversation, callbacks, async functionCall => { const functionCallName = functionCall.name; - if (isAIFunction(functionCallName, AIFunction.ExecuteWorkflow)) { + if (isAITool(functionCallName, AITool.ExecuteWorkflow)) { this.debugService?.log("MainAgent", "ExecuteWorkflow function detected - transitioning to orchestration"); const parseResult = ExecuteWorkflowArgsSchema.safeParse(functionCall.arguments); if (!parseResult.success) { - conversation.addFunctionResponse(new AIFunctionResponse( + conversation.addFunctionResponse(new AIToolResponse( functionCallName, - { error: `Invalid arguments for ${AIFunction.ExecuteWorkflow}: ${parseResult.error.message}` }, + { error: `Invalid arguments for ${AITool.ExecuteWorkflow}: ${parseResult.error.message}` }, functionCall.toolId )); return { shouldExit: false }; @@ -77,7 +77,7 @@ export class MainAgent extends BaseAgent { this.debugService?.log("MainAgent", `Executing function: ${functionCall.name}`); this.updateThought(functionCall, callbacks); - const functionResponse = await this.aiFunctionService.performAIFunction(functionCall); + const functionResponse = await this.aiToolService.performAITool(functionCall); conversation.addFunctionResponse(functionResponse); return { shouldExit: false }; }); @@ -89,10 +89,10 @@ export class MainAgent extends BaseAgent { Exception.throw("Error: No AI provider has been set!"); } this.ai.agentType = AgentType.Main; - this.ai.aiFunctionUsageMode = AIFunctionUsageMode.Auto; + this.ai.aiToolUsageMode = AIToolUsageMode.Auto; this.ai.systemPrompt = this.aiPrompt.systemInstruction(); this.ai.userInstruction = await this.aiPrompt.userInstruction(); - this.ai.aiFunctionDefinitions = AIFunctionDefinitions.agentDefinitions(allowDestructiveActions, planningMode); + this.ai.aiToolDefinitions = AIToolDefinitions.agentDefinitions(allowDestructiveActions, planningMode); } protected override setDebugColor(): void { diff --git a/Services/AIServices/OrchestrationAgent.ts b/Services/AIServices/OrchestrationAgent.ts index 82f6d9e..a5c4c9b 100644 --- a/Services/AIServices/OrchestrationAgent.ts +++ b/Services/AIServices/OrchestrationAgent.ts @@ -1,4 +1,4 @@ -import { CancelPlanArgsSchema, CompletePlanArgsSchema, CompleteStepArgsSchema, ReplanArgsSchema, type ExecuteWorkflowArgs } from "AIClasses/Schemas/AIFunctionSchemas"; +import { CancelPlanArgsSchema, CompletePlanArgsSchema, CompleteStepArgsSchema, ReplanArgsSchema, type ExecuteWorkflowArgs } from "AIClasses/Schemas/AIToolSchemas"; import { BaseAgent } from "./BaseAgent"; import { ConversationContent } from "Conversations/ConversationContent"; import { Role } from "Enums/Role"; @@ -8,13 +8,13 @@ import { Copy, replaceCopy } from "Enums/Copy"; import { Conversation } from "Conversations/Conversation"; import { PlanningAgent } from "./PlanningAgent"; import { Exception } from "Helpers/Exception"; -import { AIFunctionDefinitions } from "AIClasses/FunctionDefinitions/AIFunctionDefinitions"; +import { AIToolDefinitions } from "AIClasses/FunctionDefinitions/AIToolDefinitions"; import { OrchestrationResult } from "Types/OrchestrationResult"; import { AgentType } from "Enums/AgentType"; -import { AIFunction, isAIFunction } from "Enums/AIFunction"; -import { AIFunctionResponse } from "AIClasses/FunctionDefinitions/AIFunctionResponse"; +import { AITool, isAITool } from "Enums/AITool"; +import { AIToolResponse } from "AIClasses/FunctionDefinitions/AIToolResponse"; import { DebugColor } from "Enums/DebugColor"; -import { AIFunctionUsageMode } from "Enums/AIFunctionUsageMode"; +import { AIToolUsageMode } from "Enums/AIToolUsageMode"; export class OrchestrationAgent extends BaseAgent { @@ -142,9 +142,9 @@ export class OrchestrationAgent extends BaseAgent { await this.runAgentLoop(AgentType.Orchestration, planningConversation, callbacks, async functionCall => { const functionCallName = functionCall.name; - if (!AIFunctionDefinitions.orchestrationAgentDefinitions().some(definition => isAIFunction(functionCallName, definition.name))) { + if (!AIToolDefinitions.orchestrationAgentDefinitions().some(definition => isAITool(functionCallName, definition.name))) { this.debugService?.log("Orchestration", `Invalid tool call denied: ${functionCallName}`); - planningConversation.addFunctionResponse(new AIFunctionResponse( + planningConversation.addFunctionResponse(new AIToolResponse( functionCallName, { message: Copy.OrchestrationToolDenial }, functionCall.toolId @@ -152,18 +152,18 @@ export class OrchestrationAgent extends BaseAgent { return Promise.resolve({ shouldExit: false }); } - if (isAIFunction(functionCallName, AIFunction.CompleteStep)) { + if (isAITool(functionCallName, AITool.CompleteStep)) { const parseResult = CompleteStepArgsSchema.safeParse(functionCall.arguments); if (!parseResult.success) { - planningConversation.addFunctionResponse(new AIFunctionResponse( + planningConversation.addFunctionResponse(new AIToolResponse( functionCallName, - { error: `Invalid arguments for ${AIFunction.CompleteStep}: ${parseResult.error.message}` }, + { error: `Invalid arguments for ${AITool.CompleteStep}: ${parseResult.error.message}` }, functionCall.toolId )); return Promise.resolve({ shouldExit: false }); } if (!parseResult.data.confirm_completion) { - planningConversation.addFunctionResponse(new AIFunctionResponse( + planningConversation.addFunctionResponse(new AIToolResponse( functionCallName, { error: "Confirmation was false, no action taken" }, functionCall.toolId @@ -172,7 +172,7 @@ export class OrchestrationAgent extends BaseAgent { } this.debugService?.log("Orchestration", `CompleteStep called (confirmed: ${parseResult.data.confirm_completion})`); this.updateThought(functionCall, callbacks); - planningConversation.addFunctionResponse(new AIFunctionResponse( + planningConversation.addFunctionResponse(new AIToolResponse( functionCallName, { message: "Step Completed" }, functionCall.toolId @@ -181,18 +181,18 @@ export class OrchestrationAgent extends BaseAgent { return Promise.resolve({ shouldExit: true }); } - if (isAIFunction(functionCallName, AIFunction.CompletePlan)) { + if (isAITool(functionCallName, AITool.CompletePlan)) { const parseResult = CompletePlanArgsSchema.safeParse(functionCall.arguments); if (!parseResult.success) { - planningConversation.addFunctionResponse(new AIFunctionResponse( + planningConversation.addFunctionResponse(new AIToolResponse( functionCallName, - { error: `Invalid arguments for ${AIFunction.CompletePlan}: ${parseResult.error.message}` }, + { error: `Invalid arguments for ${AITool.CompletePlan}: ${parseResult.error.message}` }, functionCall.toolId )); return Promise.resolve({ shouldExit: false }); } if (!parseResult.data.confirm_completion) { - planningConversation.addFunctionResponse(new AIFunctionResponse( + planningConversation.addFunctionResponse(new AIToolResponse( functionCallName, { error: "Confirmation was false, no action taken" }, functionCall.toolId @@ -201,7 +201,7 @@ export class OrchestrationAgent extends BaseAgent { } this.debugService?.log("Orchestration", `CompletePlan called (confirmed: ${parseResult.data.confirm_completion})`); this.updateThought(functionCall, callbacks); - planningConversation.addFunctionResponse(new AIFunctionResponse( + planningConversation.addFunctionResponse(new AIToolResponse( functionCallName, { message: "Plan Completed" }, functionCall.toolId @@ -210,19 +210,19 @@ export class OrchestrationAgent extends BaseAgent { return Promise.resolve({ shouldExit: true }); } - if (isAIFunction(functionCallName, AIFunction.Replan)) { + if (isAITool(functionCallName, AITool.Replan)) { const parseResult = ReplanArgsSchema.safeParse(functionCall.arguments); if (!parseResult.success) { - planningConversation.addFunctionResponse(new AIFunctionResponse( + planningConversation.addFunctionResponse(new AIToolResponse( functionCallName, - { error: `Invalid arguments for ${AIFunction.Replan}: ${parseResult.error.message}` }, + { error: `Invalid arguments for ${AITool.Replan}: ${parseResult.error.message}` }, functionCall.toolId )); return Promise.resolve({ shouldExit: false }); } this.debugService?.log("Orchestration", `Replan requested: ${parseResult.data.context}`); this.updateThought(functionCall, callbacks); - planningConversation.addFunctionResponse(new AIFunctionResponse( + planningConversation.addFunctionResponse(new AIToolResponse( functionCallName, { message: "Replan Requested" }, functionCall.toolId @@ -231,19 +231,19 @@ export class OrchestrationAgent extends BaseAgent { return Promise.resolve({ shouldExit: false }); } - if (isAIFunction(functionCallName, AIFunction.CancelPlan)) { + if (isAITool(functionCallName, AITool.CancelPlan)) { const parseResult = CancelPlanArgsSchema.safeParse(functionCall.arguments); if (!parseResult.success) { - planningConversation.addFunctionResponse(new AIFunctionResponse( + planningConversation.addFunctionResponse(new AIToolResponse( functionCallName, - { error: `Invalid arguments for ${AIFunction.CancelPlan}: ${parseResult.error.message}` }, + { error: `Invalid arguments for ${AITool.CancelPlan}: ${parseResult.error.message}` }, functionCall.toolId )); return Promise.resolve({ shouldExit: false }); } this.debugService?.log("Orchestration", `Plan cancellation requested: ${parseResult.data.context}`); this.updateThought(functionCall, callbacks); - planningConversation.addFunctionResponse(new AIFunctionResponse( + planningConversation.addFunctionResponse(new AIToolResponse( functionCallName, { message: "Plan Cancelled" }, functionCall.toolId @@ -276,10 +276,10 @@ export class OrchestrationAgent extends BaseAgent { Exception.throw("Error: No AI provider has been set!"); } this.ai.agentType = AgentType.Orchestration; - this.ai.aiFunctionUsageMode = AIFunctionUsageMode.Enabled; + this.ai.aiToolUsageMode = AIToolUsageMode.Enabled; this.ai.systemPrompt = this.aiPrompt.orchestrationInstruction(); this.ai.userInstruction = ""; // do not include user instruction for orchestration agent - this.ai.aiFunctionDefinitions = AIFunctionDefinitions.orchestrationAgentDefinitions(); + this.ai.aiToolDefinitions = AIToolDefinitions.orchestrationAgentDefinitions(); } protected override setDebugColor(): void { diff --git a/Services/AIServices/PlanningAgent.ts b/Services/AIServices/PlanningAgent.ts index c50f254..60610b8 100644 --- a/Services/AIServices/PlanningAgent.ts +++ b/Services/AIServices/PlanningAgent.ts @@ -1,18 +1,18 @@ import { Conversation } from "Conversations/Conversation"; import { BaseAgent } from "./BaseAgent"; -import { AskUserQuestionPlanningArgsSchema, SubmitPlanArgsSchema } from "AIClasses/Schemas/AIFunctionSchemas"; +import { AskUserQuestionPlanningArgsSchema, SubmitPlanArgsSchema } from "AIClasses/Schemas/AIToolSchemas"; import { Exception } from "Helpers/Exception"; import type { IChatServiceCallbacks } from "Services/ChatService"; import { AgentType } from "Enums/AgentType"; -import { AIFunction, isAIFunction } from "Enums/AIFunction"; -import { AIFunctionResponse } from "AIClasses/FunctionDefinitions/AIFunctionResponse"; +import { AITool, isAITool } from "Enums/AITool"; +import { AIToolResponse } from "AIClasses/FunctionDefinitions/AIToolResponse"; import { ExecutionPlan } from "Types/ExecutionPlan"; -import { AIFunctionDefinitions } from "AIClasses/FunctionDefinitions/AIFunctionDefinitions"; +import { AIToolDefinitions } from "AIClasses/FunctionDefinitions/AIToolDefinitions"; import { Copy } from "Enums/Copy"; import { ConversationContent } from "Conversations/ConversationContent"; import { Role } from "Enums/Role"; import { DebugColor } from "Enums/DebugColor"; -import { AIFunctionUsageMode } from "Enums/AIFunctionUsageMode"; +import { AIToolUsageMode } from "Enums/AIToolUsageMode"; export class PlanningAgent extends BaseAgent { @@ -35,9 +35,9 @@ export class PlanningAgent extends BaseAgent { await this.runAgentLoop(AgentType.Planning, conversation, callbacks, async (functionCall) => { const functionCallName = functionCall.name; - if (!AIFunctionDefinitions.planningAgentDefinitions().some(definition => isAIFunction(functionCallName, definition.name))) { + if (!AIToolDefinitions.planningAgentDefinitions().some(definition => isAITool(functionCallName, definition.name))) { this.debugService?.log("PlanningAgent", `Invalid tool call denied: ${functionCallName}`); - conversation.addFunctionResponse(new AIFunctionResponse( + conversation.addFunctionResponse(new AIToolResponse( functionCallName, { message: Copy.PlanningToolDenial }, functionCall.toolId @@ -45,12 +45,12 @@ export class PlanningAgent extends BaseAgent { return { shouldExit: false }; } - if (isAIFunction(functionCallName, AIFunction.AskUserQuestionPlanning)) { + if (isAITool(functionCallName, AITool.AskUserQuestionPlanning)) { const parseResult = AskUserQuestionPlanningArgsSchema.safeParse(functionCall.arguments); if (!parseResult.success) { - conversation.addFunctionResponse(new AIFunctionResponse( + conversation.addFunctionResponse(new AIToolResponse( functionCallName, - { error: `Invalid arguments for ${AIFunction.AskUserQuestionPlanning}: ${parseResult.error.message}` }, + { error: `Invalid arguments for ${AITool.AskUserQuestionPlanning}: ${parseResult.error.message}` }, functionCall.toolId )); return { shouldExit: false }; @@ -59,7 +59,7 @@ export class PlanningAgent extends BaseAgent { this.updateThought(functionCall, callbacks); const answer = await callbacks.onUserQuestion(parseResult.data.question); this.debugService?.log("PlanningAgent", "User answer received"); - conversation.addFunctionResponse(new AIFunctionResponse( + conversation.addFunctionResponse(new AIToolResponse( functionCallName, { answer: answer }, functionCall.toolId @@ -67,19 +67,19 @@ export class PlanningAgent extends BaseAgent { return { shouldExit: false }; } - if (isAIFunction(functionCallName, AIFunction.SubmitPlan)) { + if (isAITool(functionCallName, AITool.SubmitPlan)) { const parseResult = SubmitPlanArgsSchema.safeParse(functionCall.arguments); if (!parseResult.success) { - conversation.addFunctionResponse(new AIFunctionResponse( + conversation.addFunctionResponse(new AIToolResponse( functionCallName, - { error: `Invalid arguments for ${AIFunction.SubmitPlan}: ${parseResult.error.message}` }, + { error: `Invalid arguments for ${AITool.SubmitPlan}: ${parseResult.error.message}` }, functionCall.toolId )); return { shouldExit: false }; } this.debugService?.log("PlanningAgent", `Plan submitted successfully with ${parseResult.data.steps.length} steps`); capturedPlan = new ExecutionPlan(parseResult.data, isReplan); - conversation.addFunctionResponse(new AIFunctionResponse( + conversation.addFunctionResponse(new AIToolResponse( functionCallName, { message: Copy.PlanReceived }, functionCall.toolId @@ -88,7 +88,7 @@ export class PlanningAgent extends BaseAgent { } this.updateThought(functionCall, callbacks); - const functionResponse = await this.aiFunctionService.performAIFunction(functionCall); + const functionResponse = await this.aiToolService.performAITool(functionCall); conversation.addFunctionResponse(functionResponse); return { shouldExit: false }; }); @@ -111,10 +111,10 @@ export class PlanningAgent extends BaseAgent { Exception.throw("Error: No AI provider has been set!"); } this.ai.agentType = AgentType.Planning; - this.ai.aiFunctionUsageMode = AIFunctionUsageMode.Enabled; + this.ai.aiToolUsageMode = AIToolUsageMode.Enabled; this.ai.systemPrompt = this.aiPrompt.planningInstruction(); this.ai.userInstruction = await this.aiPrompt.userInstruction(); - this.ai.aiFunctionDefinitions = AIFunctionDefinitions.planningAgentDefinitions(); + this.ai.aiToolDefinitions = AIToolDefinitions.planningAgentDefinitions(); } protected override setDebugColor(): void { diff --git a/Services/ServiceRegistration.ts b/Services/ServiceRegistration.ts index aad5e60..ffc6010 100644 --- a/Services/ServiceRegistration.ts +++ b/Services/ServiceRegistration.ts @@ -11,7 +11,7 @@ import { StreamingMarkdownService } from "./StreamingMarkdownService"; import { FileSystemService } from "./FileSystemService"; import { ConversationFileSystemService } from "./ConversationFileSystemService"; import { ConversationHistoryModal } from "Modals/ConversationHistoryModal"; -import { AIFunctionService } from "./AIServices/AIFunctionService"; +import { AIToolService } from "./AIServices/AIToolService"; import { StreamingService } from "./StreamingService"; import { WorkSpaceService } from "./WorkSpaceService"; import { ChatService } from "./ChatService"; @@ -67,7 +67,7 @@ export function RegisterDependencies() { RegisterSingleton(Services.ConversationNamingService, new ConversationNamingService()); RegisterSingleton(Services.IPrompt, new AIPrompt()); - RegisterSingleton(Services.AIFunctionService, new AIFunctionService()); + RegisterSingleton(Services.AIToolService, new AIToolService()); RegisterSingleton(Services.MainAgent, new MainAgent()); RegisterSingleton(Services.StreamingService, new StreamingService()); RegisterSingleton(Services.ChatService, new ChatService()); diff --git a/Services/Services.ts b/Services/Services.ts index 0ddcf0c..3a84165 100644 --- a/Services/Services.ts +++ b/Services/Services.ts @@ -14,7 +14,7 @@ export class Services { static StreamingService = Symbol("StreamingService"); static MarkdownService = Symbol("MarkdownService"); static StreamingMarkdownService = Symbol("StreamingMarkdownService"); - static AIFunctionService = Symbol("AIFunctionService"); + static AIToolService = Symbol("AIToolService"); static MainAgent = Symbol("MainAgent"); static ChatService = Symbol("ChatService"); static SanitiserService = Symbol("SanitiserService"); diff --git a/Services/StreamingService.ts b/Services/StreamingService.ts index 95964b2..2aa88e6 100644 --- a/Services/StreamingService.ts +++ b/Services/StreamingService.ts @@ -1,4 +1,4 @@ -import type { AIFunctionCall } from "AIClasses/AIFunctionCall"; +import type { AIToolCall } from "AIClasses/AIToolCall"; import { Event } from "Enums/Event"; import { Exception } from "Helpers/Exception"; import { ApiError, ApiErrorType } from "Types/ApiError"; @@ -13,7 +13,7 @@ export interface IStreamChunk { isComplete: boolean; error?: string; errorType?: ApiErrorType; - functionCall?: AIFunctionCall; + functionCall?: AIToolCall; shouldContinue?: boolean; } diff --git a/Services/VaultService.ts b/Services/VaultService.ts index 9f0482c..f624f21 100644 --- a/Services/VaultService.ts +++ b/Services/VaultService.ts @@ -15,7 +15,7 @@ import { DiffService } from "./DiffService"; import * as path from "path-browserify"; import { Event } from "Enums/Event"; import { AbortService } from "./AbortService"; -import { AIFunctionResponse } from "AIClasses/FunctionDefinitions/AIFunctionResponse"; +import { AIToolResponse } from "AIClasses/FunctionDefinitions/AIToolResponse"; import { FileType, isBinaryFile, isFileType } from "Enums/FileType"; import { readPDF } from "Helpers/PDFHelper"; @@ -524,9 +524,9 @@ export class VaultService { return await performChange(); } - let response = AIFunctionResponse.UserRejectionMessage; + let response = AIToolResponse.UserRejectionMessage; if (result.suggestion) { - response = `${AIFunctionResponse.UserSuggestionMessage}\n${result.suggestion}`; + response = `${AIToolResponse.UserSuggestionMessage}\n${result.suggestion}`; } return Exception.new(response); } catch (error) { diff --git a/Types/ExecutionPlan.ts b/Types/ExecutionPlan.ts index 317982a..7e2322a 100644 --- a/Types/ExecutionPlan.ts +++ b/Types/ExecutionPlan.ts @@ -1,5 +1,5 @@ import type { ExecutionStep } from "./ExecutionStep"; -import type { SubmitPlanArgs } from "AIClasses/Schemas/AIFunctionSchemas"; +import type { SubmitPlanArgs } from "AIClasses/Schemas/AIToolSchemas"; export class ExecutionPlan { diff --git a/__tests__/AIClasses/AIFunctionCall.test.ts b/__tests__/AIClasses/AIToolCall.test.ts similarity index 73% rename from __tests__/AIClasses/AIFunctionCall.test.ts rename to __tests__/AIClasses/AIToolCall.test.ts index 59875e1..73531bf 100644 --- a/__tests__/AIClasses/AIFunctionCall.test.ts +++ b/__tests__/AIClasses/AIToolCall.test.ts @@ -1,29 +1,29 @@ import { describe, it, expect } from 'vitest'; -import { AIFunctionCall } from '../../AIClasses/AIFunctionCall'; -import { AIFunction } from '../../Enums/AIFunction'; +import { AIToolCall } from '../../AIClasses/AIToolCall'; +import { AITool } from '../../Enums/AITool'; -describe('AIFunctionCall', () => { +describe('AIToolCall', () => { describe('constructor', () => { it('should create instance with name and arguments only', () => { - const functionCall = new AIFunctionCall( - AIFunction.SearchVaultFiles, + const functionCall = new AIToolCall( + AITool.SearchVaultFiles, { query: 'test' } ); - expect(functionCall.name).toBe(AIFunction.SearchVaultFiles); + expect(functionCall.name).toBe(AITool.SearchVaultFiles); expect(functionCall.arguments).toEqual({ query: 'test' }); expect(functionCall.toolId).toBeUndefined(); expect(functionCall.thoughtSignature).toBeUndefined(); }); it('should create instance with name, arguments, and toolId', () => { - const functionCall = new AIFunctionCall( - AIFunction.ReadVaultFiles, + const functionCall = new AIToolCall( + AITool.ReadVaultFiles, { path: 'test.md' }, 'tool-123' ); - expect(functionCall.name).toBe(AIFunction.ReadVaultFiles); + expect(functionCall.name).toBe(AITool.ReadVaultFiles); expect(functionCall.arguments).toEqual({ path: 'test.md' }); expect(functionCall.toolId).toBe('tool-123'); expect(functionCall.thoughtSignature).toBeUndefined(); @@ -31,14 +31,14 @@ describe('AIFunctionCall', () => { it('should create instance with all four parameters including thoughtSignature', () => { const signature = 'base64EncodedSignature=='; - const functionCall = new AIFunctionCall( - AIFunction.SearchVaultFiles, + const functionCall = new AIToolCall( + AITool.SearchVaultFiles, { query: 'notes' }, undefined, signature ); - expect(functionCall.name).toBe(AIFunction.SearchVaultFiles); + expect(functionCall.name).toBe(AITool.SearchVaultFiles); expect(functionCall.arguments).toEqual({ query: 'notes' }); expect(functionCall.toolId).toBeUndefined(); expect(functionCall.thoughtSignature).toBe(signature); @@ -46,26 +46,26 @@ describe('AIFunctionCall', () => { it('should create instance with toolId and thoughtSignature', () => { const signature = 'aGVsbG8gd29ybGQ='; - const functionCall = new AIFunctionCall( - AIFunction.WriteVaultFile, + const functionCall = new AIToolCall( + AITool.WriteVaultFile, { path: 'note.md', content: 'Hello' }, 'tool-456', signature ); - expect(functionCall.name).toBe(AIFunction.WriteVaultFile); + expect(functionCall.name).toBe(AITool.WriteVaultFile); expect(functionCall.arguments).toEqual({ path: 'note.md', content: 'Hello' }); expect(functionCall.toolId).toBe('tool-456'); expect(functionCall.thoughtSignature).toBe(signature); }); it('should handle empty arguments object', () => { - const functionCall = new AIFunctionCall( - AIFunction.SearchVaultFiles, + const functionCall = new AIToolCall( + AITool.SearchVaultFiles, {} ); - expect(functionCall.name).toBe(AIFunction.SearchVaultFiles); + expect(functionCall.name).toBe(AITool.SearchVaultFiles); expect(functionCall.arguments).toEqual({}); }); @@ -78,8 +78,8 @@ describe('AIFunctionCall', () => { limit: 10 }; - const functionCall = new AIFunctionCall( - AIFunction.SearchVaultFiles, + const functionCall = new AIToolCall( + AITool.SearchVaultFiles, complexArgs ); @@ -89,8 +89,8 @@ describe('AIFunctionCall', () => { describe('toConversationString', () => { it('should serialize to JSON with only name and args when no optional fields', () => { - const functionCall = new AIFunctionCall( - AIFunction.SearchVaultFiles, + const functionCall = new AIToolCall( + AITool.SearchVaultFiles, { query: 'test' } ); @@ -99,7 +99,7 @@ describe('AIFunctionCall', () => { expect(parsed).toEqual({ functionCall: { - name: AIFunction.SearchVaultFiles, + name: AITool.SearchVaultFiles, args: { query: 'test' }, id: undefined, thoughtSignature: undefined @@ -108,8 +108,8 @@ describe('AIFunctionCall', () => { }); it('should serialize with toolId when present', () => { - const functionCall = new AIFunctionCall( - AIFunction.ReadVaultFiles, + const functionCall = new AIToolCall( + AITool.ReadVaultFiles, { path: 'note.md' }, 'tool-789' ); @@ -119,7 +119,7 @@ describe('AIFunctionCall', () => { expect(parsed).toEqual({ functionCall: { - name: AIFunction.ReadVaultFiles, + name: AITool.ReadVaultFiles, args: { path: 'note.md' }, id: 'tool-789', thoughtSignature: undefined @@ -129,8 +129,8 @@ describe('AIFunctionCall', () => { it('should serialize with thoughtSignature when present', () => { const signature = 'dGVzdFNpZ25hdHVyZQ=='; - const functionCall = new AIFunctionCall( - AIFunction.SearchVaultFiles, + const functionCall = new AIToolCall( + AITool.SearchVaultFiles, { query: 'notes' }, undefined, signature @@ -141,7 +141,7 @@ describe('AIFunctionCall', () => { expect(parsed).toEqual({ functionCall: { - name: AIFunction.SearchVaultFiles, + name: AITool.SearchVaultFiles, args: { query: 'notes' }, id: undefined, thoughtSignature: signature @@ -151,8 +151,8 @@ describe('AIFunctionCall', () => { it('should serialize with both toolId and thoughtSignature when present', () => { const signature = 'YW5vdGhlclNpZ25hdHVyZQ=='; - const functionCall = new AIFunctionCall( - AIFunction.WriteVaultFile, + const functionCall = new AIToolCall( + AITool.WriteVaultFile, { path: 'file.md', content: 'content' }, 'tool-999', signature @@ -163,7 +163,7 @@ describe('AIFunctionCall', () => { expect(parsed).toEqual({ functionCall: { - name: AIFunction.WriteVaultFile, + name: AITool.WriteVaultFile, args: { path: 'file.md', content: 'content' }, id: 'tool-999', thoughtSignature: signature @@ -172,8 +172,8 @@ describe('AIFunctionCall', () => { }); it('should produce valid JSON string', () => { - const functionCall = new AIFunctionCall( - AIFunction.SearchVaultFiles, + const functionCall = new AIToolCall( + AITool.SearchVaultFiles, { query: 'test' }, 'tool-123', 'c2lnbmF0dXJl' @@ -185,8 +185,8 @@ describe('AIFunctionCall', () => { }); it('should handle special characters in arguments', () => { - const functionCall = new AIFunctionCall( - AIFunction.SearchVaultFiles, + const functionCall = new AIToolCall( + AITool.SearchVaultFiles, { query: 'test "quotes" and \'apostrophes\' and\nnewlines' } ); @@ -197,8 +197,8 @@ describe('AIFunctionCall', () => { }); it('should handle empty string thoughtSignature', () => { - const functionCall = new AIFunctionCall( - AIFunction.SearchVaultFiles, + const functionCall = new AIToolCall( + AITool.SearchVaultFiles, { query: 'test' }, undefined, '' @@ -213,19 +213,19 @@ describe('AIFunctionCall', () => { describe('properties', () => { it('should have immutable name property', () => { - const functionCall = new AIFunctionCall( - AIFunction.SearchVaultFiles, + const functionCall = new AIToolCall( + AITool.SearchVaultFiles, { query: 'test' } ); // Readonly is enforced at TypeScript compile time // At runtime, the properties are accessible - expect(functionCall.name).toBe(AIFunction.SearchVaultFiles); + expect(functionCall.name).toBe(AITool.SearchVaultFiles); }); it('should have immutable arguments property', () => { - const functionCall = new AIFunctionCall( - AIFunction.SearchVaultFiles, + const functionCall = new AIToolCall( + AITool.SearchVaultFiles, { query: 'test' } ); @@ -233,8 +233,8 @@ describe('AIFunctionCall', () => { }); it('should have immutable toolId property', () => { - const functionCall = new AIFunctionCall( - AIFunction.SearchVaultFiles, + const functionCall = new AIToolCall( + AITool.SearchVaultFiles, { query: 'test' }, 'tool-123' ); @@ -243,8 +243,8 @@ describe('AIFunctionCall', () => { }); it('should have immutable thoughtSignature property', () => { - const functionCall = new AIFunctionCall( - AIFunction.SearchVaultFiles, + const functionCall = new AIToolCall( + AITool.SearchVaultFiles, { query: 'test' }, undefined, 'signature' @@ -257,8 +257,8 @@ describe('AIFunctionCall', () => { describe('edge cases', () => { it('should handle very long thoughtSignature (realistic base64)', () => { const longSignature = 'A'.repeat(10000); - const functionCall = new AIFunctionCall( - AIFunction.SearchVaultFiles, + const functionCall = new AIToolCall( + AITool.SearchVaultFiles, { query: 'test' }, undefined, longSignature @@ -270,8 +270,8 @@ describe('AIFunctionCall', () => { it('should handle thoughtSignature with base64 special characters', () => { const base64Signature = 'SGVsbG8gV29ybGQ+Pz8/Pz8+Pg=='; - const functionCall = new AIFunctionCall( - AIFunction.SearchVaultFiles, + const functionCall = new AIToolCall( + AITool.SearchVaultFiles, { query: 'test' }, undefined, base64Signature @@ -281,8 +281,8 @@ describe('AIFunctionCall', () => { }); it('should handle undefined toolId and defined thoughtSignature', () => { - const functionCall = new AIFunctionCall( - AIFunction.SearchVaultFiles, + const functionCall = new AIToolCall( + AITool.SearchVaultFiles, { query: 'test' }, undefined, 'signature' @@ -293,8 +293,8 @@ describe('AIFunctionCall', () => { }); it('should handle defined toolId and undefined thoughtSignature', () => { - const functionCall = new AIFunctionCall( - AIFunction.SearchVaultFiles, + const functionCall = new AIToolCall( + AITool.SearchVaultFiles, { query: 'test' }, 'tool-123', undefined diff --git a/__tests__/AIClasses/Claude.test.ts b/__tests__/AIClasses/Claude.test.ts index e447f6d..987a5c4 100644 --- a/__tests__/AIClasses/Claude.test.ts +++ b/__tests__/AIClasses/Claude.test.ts @@ -5,7 +5,7 @@ import { Services } from '../../Services/Services'; import { StreamingService } from '../../Services/StreamingService'; import type { IPrompt } from '../../AIPrompts/IPrompt'; import type VaultkeeperAIPlugin from '../../main'; -import { AIFunctionDefinitions } from '../../AIClasses/FunctionDefinitions/AIFunctionDefinitions'; +import { AIToolDefinitions } from '../../AIClasses/FunctionDefinitions/AIToolDefinitions'; import { Conversation } from '../../Conversations/Conversation'; import { ConversationContent } from '../../Conversations/ConversationContent'; import { Role } from '../../Enums/Role'; @@ -118,7 +118,7 @@ describe('Claude', () => { expect(plugin).toBe(mockPlugin); expect(settingsService).toBe(mockSettingsService); expect(streaming).toBe(mockStreamingService); - expect(AIFunctionDefinitions.agentDefinitions).toBeDefined(); + expect(AIToolDefinitions.agentDefinitions).toBeDefined(); }); }); @@ -1157,7 +1157,7 @@ describe('Claude', () => { // Set system prompts before calling streamRequest claude.systemPrompt = 'System instruction'; claude.userInstruction = 'User instruction'; - claude.aiFunctionDefinitions = []; + claude.aiToolDefinitions = []; mockStreamingService.streamRequest.mockImplementation(async function* () { yield { content: 'response', isComplete: true }; diff --git a/__tests__/AIClasses/CrossProviderIntegration.test.ts b/__tests__/AIClasses/CrossProviderIntegration.test.ts index 683c0cb..3381bfd 100644 --- a/__tests__/AIClasses/CrossProviderIntegration.test.ts +++ b/__tests__/AIClasses/CrossProviderIntegration.test.ts @@ -100,7 +100,7 @@ describe('Cross-Provider Integration - Thought Signature Support', () => { displayContent: '', functionCall: JSON.stringify({ functionCall: { - id: 'call_abc123', // AIFunctionCall.toConversationString() includes id in JSON + id: 'call_abc123', // AIToolCall.toConversationString() includes id in JSON name: 'search_vault_files', args: { query: 'meeting notes' } } @@ -122,13 +122,13 @@ describe('Cross-Provider Integration - Thought Signature Support', () => { it('should convert OpenAI function call (no thoughtSignature) to legacy text format', async () => { // Simulate a conversation started with OpenAI - const openaiFunctionCall = new ConversationContent({ + const openaiToolCall = new ConversationContent({ role: Role.Assistant, content: '', displayContent: '', functionCall: JSON.stringify({ functionCall: { - id: 'call_xyz789', // AIFunctionCall.toConversationString() includes id in JSON + id: 'call_xyz789', // AIToolCall.toConversationString() includes id in JSON name: 'read_file', args: { path: 'project.md' } } @@ -138,7 +138,7 @@ describe('Cross-Provider Integration - Thought Signature Support', () => { toolId: 'call_xyz789' }); - const result = await (gemini as any).extractContents([openaiFunctionCall]); + const result = await (gemini as any).extractContents([openaiToolCall]); expect(result[0].parts[0].text).toContain('