@tanstack/ai
Version:
Core TanStack AI library - Open source AI SDK
131 lines (130 loc) • 5.07 kB
TypeScript
import { CustomEvent, ModelMessage, RunFinishedEvent, Tool, ToolCall, ToolCallArgsEvent, ToolCallEndEvent, ToolCallStartEvent } from '../../../types.js';
import { AfterToolCallInfo, BeforeToolCallDecision } from '../middleware/types.js';
/**
* Optional middleware hooks for tool execution.
* When provided, these callbacks are invoked before/after each tool execution.
*/
export interface ToolExecutionMiddlewareHooks {
onBeforeToolCall?: (toolCall: ToolCall, tool: Tool | undefined, args: unknown) => Promise<BeforeToolCallDecision>;
onAfterToolCall?: (info: AfterToolCallInfo) => Promise<void>;
}
/**
* Error thrown when middleware decides to abort the chat run during tool execution.
*/
export declare class MiddlewareAbortError extends Error {
constructor(reason: string);
}
/**
* Manages tool call accumulation and execution for the chat() method's automatic tool execution loop.
*
* Responsibilities:
* - Accumulates streaming tool call events (ID, name, arguments)
* - Validates tool calls (filters out incomplete ones)
* - Executes tool `execute` functions with parsed arguments
* - Emits `TOOL_CALL_END` events for client visibility
* - Returns tool result messages for conversation history
*
* This class is used internally by the AI.chat() method to handle the automatic
* tool execution loop. It can also be used independently for custom tool execution logic.
*
* @example
* ```typescript
* const manager = new ToolCallManager(tools);
*
* // During streaming, accumulate tool calls
* for await (const chunk of stream) {
* if (chunk.type === 'TOOL_CALL_START') {
* manager.addToolCallStartEvent(chunk);
* } else if (chunk.type === 'TOOL_CALL_ARGS') {
* manager.addToolCallArgsEvent(chunk);
* }
* }
*
* // After stream completes, execute tools
* if (manager.hasToolCalls()) {
* const toolResults = yield* manager.executeTools(finishEvent);
* messages = [...messages, ...toolResults];
* manager.clear();
* }
* ```
*/
export declare class ToolCallManager {
private toolCallsMap;
private tools;
constructor(tools: ReadonlyArray<Tool>);
/**
* Add a TOOL_CALL_START event to begin tracking a tool call (AG-UI)
*/
addToolCallStartEvent(event: ToolCallStartEvent): void;
/**
* Add a TOOL_CALL_ARGS event to accumulate arguments (AG-UI)
*/
addToolCallArgsEvent(event: ToolCallArgsEvent): void;
/**
* Complete a tool call with its final input
* Called when TOOL_CALL_END is received
*/
completeToolCall(event: ToolCallEndEvent): void;
/**
* Check if there are any complete tool calls to execute
*/
hasToolCalls(): boolean;
/**
* Get all complete tool calls (filtered for valid ID and name)
*/
getToolCalls(): Array<ToolCall>;
/**
* Execute all tool calls and return tool result messages
* Yields TOOL_CALL_END events for streaming
* @param finishEvent - RUN_FINISHED event from the stream
*/
executeTools(finishEvent: RunFinishedEvent): AsyncGenerator<ToolCallEndEvent, Array<ModelMessage>, void>;
/**
* Clear the tool calls map for the next iteration
*/
clear(): void;
}
export interface ToolResult {
toolCallId: string;
toolName: string;
result: any;
state?: 'output-available' | 'output-error';
/** Duration of tool execution in milliseconds (only for server-executed tools) */
duration?: number;
}
export interface ApprovalRequest {
toolCallId: string;
toolName: string;
input: any;
approvalId: string;
}
export interface ClientToolRequest {
toolCallId: string;
toolName: string;
input: any;
}
interface ExecuteToolCallsResult {
/** Tool results ready to send to LLM */
results: Array<ToolResult>;
/** Tools that need user approval before execution */
needsApproval: Array<ApprovalRequest>;
/** Tools that need client-side execution */
needsClientExecution: Array<ClientToolRequest>;
}
/**
* Execute tool calls based on their configuration.
* Yields CustomEvent chunks during tool execution for real-time progress updates.
*
* Handles three cases:
* 1. Client tools (no execute) - request client to execute
* 2. Server tools with approval - check approval before executing
* 3. Normal server tools - execute immediately
*
* @param toolCalls - Tool calls from the LLM
* @param tools - Available tools with their configurations
* @param approvals - Map of approval decisions (approval.id -> approved boolean)
* @param clientResults - Map of client-side execution results (toolCallId -> result)
* @param createCustomEventChunk - Factory to create CustomEvent chunks (optional)
*/
export declare function executeToolCalls(toolCalls: Array<ToolCall>, tools: ReadonlyArray<Tool>, approvals?: Map<string, boolean>, clientResults?: Map<string, any>, createCustomEventChunk?: (eventName: string, value: Record<string, any>) => CustomEvent, middlewareHooks?: ToolExecutionMiddlewareHooks): AsyncGenerator<CustomEvent, ExecuteToolCallsResult, void>;
export {};