/** * ToolCallingAgent — Base class for agents that use a tool-calling loop. * * Adopts the proven pattern from Freebuff and Hermes: * LLM generates tool call → Agent executes tool → Result fed back → Loop * * KEY CONSTRAINT: This agent does NOT write to disk. Tools propose FileChange * objects in context.fileChanges. The Orchestrator applies them after the * agent returns. This preserves dry-run mode, rollback, and audit trail. * * Reference: * - Freebuff: packages/agent-runtime/src/run-agent-step.ts (tool-calling loop) * - Hermes: run_agent.py AIAgent.run_conversation() (tool dispatch loop) * * The tool-calling is prompt-based (not native function calling) because * the existing LLMCallFn interface doesn't support tool definitions. * The LLM is prompted to produce tool calls in a structured format, * and the agent parses and executes them. */ import { Agent, type AgentContext, type AgentResult, type LLMCallFn } from './agent.js'; /** A tool that the agent can call */ export interface AgentTool { /** Tool name (e.g. 'read_file', 'propose_change') */ name: string; /** Human-readable description */ description: string; /** JSON Schema for the tool's parameters */ parameters: Record; /** Execute the tool with the given arguments */ execute(args: Record, context: AgentContext): Promise; } /** Result of a tool execution */ export interface ToolResult { success: boolean; output: string; error?: string; } /** A tool call produced by the LLM */ export interface ToolCall { id: string; name: string; arguments: Record; } /** Parsed LLM response that may contain tool calls */ export interface ParsedResponse { /** Text response from the LLM */ text?: string; /** Tool calls the LLM wants to execute */ toolCalls?: ToolCall[]; /** Whether the LLM is done (no more tool calls needed) */ done: boolean; } /** * Base class for agents that use a tool-calling loop. * * The LLM is prompted to produce tool calls in a structured format. * The agent parses and executes them, feeding results back to the LLM. * The loop continues until the LLM produces a final text response (no tool calls). * * CRITICAL: This agent does NOT write to disk. Tools propose FileChange objects * in context.fileChanges. The Orchestrator applies them after the agent returns. * * Usage: * ```typescript * class MyAgent extends ToolCallingAgent { * readonly name = 'MyAgent'; * readonly description = 'Does something cool'; * * protected buildSystemPrompt(context: AgentContext): string { * return 'You are a helpful assistant...'; * } * * protected buildUserPrompt(context: AgentContext): string { * return `Task: ${context.goal}`; * } * * protected parseResponse(response: string): ParsedResponse { * // Parse tool calls from LLM response * } * } * ``` */ export declare abstract class ToolCallingAgent extends Agent { /** Get the tools available to this agent */ protected getTools(context: AgentContext): AgentTool[]; /** Build the system prompt for the LLM */ protected abstract buildSystemPrompt(context: AgentContext): string; /** Build the user prompt for the LLM */ protected abstract buildUserPrompt(context: AgentContext): string; /** Parse the LLM response to extract tool calls or final text */ protected abstract parseResponse(response: string): ParsedResponse; /** Build the tool definitions section of the prompt */ protected buildToolDefinitionsPrompt(tools: AgentTool[]): string; /** Execute the tool-calling loop */ execute(context: AgentContext, callLLM: LLMCallFn): Promise; /** * Build the follow-up prompt after a tool execution. * Appends the assistant's response and tool result to the conversation, * keeping the prompt bounded to prevent token explosion. */ private buildFollowUpPrompt; } //# sourceMappingURL=tool-calling-agent.d.ts.map