import { JSONValue } from '@ai-sdk/provider'; import { FlexibleSchema } from '../schema'; import { ToolResultOutput } from './content-part'; import { ModelMessage } from './model-message'; import { ProviderOptions } from './provider-options'; /** * Additional options that are sent into each tool call. */ export interface ToolExecutionOptions { /** * The ID of the tool call. You can use it e.g. when sending tool-call related information with stream data. */ toolCallId: string; /** * Messages that were sent to the language model to initiate the response that contained the tool call. * The messages **do not** include the system prompt nor the assistant response that contained the tool call. */ messages: ModelMessage[]; /** * An optional abort signal that indicates that the overall operation should be aborted. */ abortSignal?: AbortSignal; /** * User-defined context. * * Treat the context object as immutable inside tools. * Mutating the context object can lead to race conditions and unexpected results * when tools are called in parallel. * * If you need to mutate the context, analyze the tool calls and results * in `prepareStep` and update it there. * * Experimental (can break in patch releases). */ experimental_context?: unknown; } /** * Function that is called to determine if the tool needs approval before it can be executed. */ export type ToolNeedsApprovalFunction = ( input: INPUT, options: { /** * The ID of the tool call. You can use it e.g. when sending tool-call related information with stream data. */ toolCallId: string; /** * Messages that were sent to the language model to initiate the response that contained the tool call. * The messages **do not** include the system prompt nor the assistant response that contained the tool call. */ messages: ModelMessage[]; /** * Additional context. * * Experimental (can break in patch releases). */ experimental_context?: unknown; }, ) => boolean | PromiseLike; export type ToolExecuteFunction = ( input: INPUT, options: ToolExecutionOptions, ) => AsyncIterable | PromiseLike | OUTPUT; // 0 extends 1 & N checks for any // [N] extends [never] checks for never type NeverOptional = 0 extends 1 & N ? Partial : [N] extends [never] ? Partial> : T; type ToolOutputProperties = NeverOptional< OUTPUT, | { /** * An async function that is called with the arguments from the tool call and produces a result. * If not provided, the tool will not be executed automatically. * * @args is the input of the tool call. * @options.abortSignal is a signal that can be used to abort the tool call. */ execute: ToolExecuteFunction; outputSchema?: FlexibleSchema; } | { outputSchema: FlexibleSchema; execute?: never; } >; /** * A tool contains the description and the schema of the input that the tool expects. * This enables the language model to generate the input. * * The tool can also contain an optional execute function for the actual execution function of the tool. */ export type Tool< INPUT extends JSONValue | unknown | never = any, OUTPUT extends JSONValue | unknown | never = any, > = { /** * An optional description of what the tool does. * Will be used by the language model to decide whether to use the tool. * Not used for provider-defined tools. */ description?: string; /** * An optional title of the tool. */ title?: string; /** * Additional provider-specific metadata. They are passed through * to the provider from the AI SDK and enable provider-specific * functionality that can be fully encapsulated in the provider. */ providerOptions?: ProviderOptions; /** * The schema of the input that the tool expects. * The language model will use this to generate the input. * It is also used to validate the output of the language model. * * You can use descriptions on the schema properties to make the input understandable for the language model. */ inputSchema: FlexibleSchema; /** * An optional list of input examples that show the language * model what the input should look like. */ inputExamples?: Array<{ input: NoInfer }>; /** * Whether the tool needs approval before it can be executed. */ needsApproval?: | boolean | ToolNeedsApprovalFunction<[INPUT] extends [never] ? unknown : INPUT>; /** * Strict mode setting for the tool. * * Providers that support strict mode will use this setting to determine * how the input should be generated. Strict mode will always produce * valid inputs, but it might limit what input schemas are supported. */ strict?: boolean; /** * Optional function that is called when the argument streaming starts. * Only called when the tool is used in a streaming context. */ onInputStart?: (options: ToolExecutionOptions) => void | PromiseLike; /** * Optional function that is called when an argument streaming delta is available. * Only called when the tool is used in a streaming context. */ onInputDelta?: ( options: { inputTextDelta: string } & ToolExecutionOptions, ) => void | PromiseLike; /** * Optional function that is called when a tool call can be started, * even if the execute function is not provided. */ onInputAvailable?: ( options: { input: [INPUT] extends [never] ? unknown : INPUT; } & ToolExecutionOptions, ) => void | PromiseLike; } & ToolOutputProperties & { /** * Optional conversion function that maps the tool result to an output that can be used by the language model. * * If not provided, the tool result will be sent as a JSON object. */ toModelOutput?: (options: { /** * The ID of the tool call. You can use it e.g. when sending tool-call related information with stream data. */ toolCallId: string; /** * The input of the tool call. */ input: [INPUT] extends [never] ? unknown : INPUT; /** * The output of the tool call. */ output: 0 extends 1 & OUTPUT ? any : [OUTPUT] extends [never] ? any : NoInfer; }) => ToolResultOutput | PromiseLike; } & ( | { /** * Tool with user-defined input and output schemas. */ type?: undefined | 'function'; } | { /** * Tool that is defined at runtime (e.g. an MCP tool). * The types of input and output are not known at development time. */ type: 'dynamic'; } | { /** * Tool with provider-defined input and output schemas. */ type: 'provider'; /** * The ID of the tool. Must follow the format `.`. */ id: `${string}.${string}`; /** * The arguments for configuring the tool. Must match the expected arguments defined by the provider for this tool. */ args: Record; /** * Whether this provider-executed tool supports deferred results. * * When true, the tool result may not be returned in the same turn as the * tool call (e.g., when using programmatic tool calling where a server tool * triggers a client-executed tool, and the server tool's result is deferred * until the client tool is resolved). * * This flag allows the AI SDK to handle tool results that arrive without * a matching tool call in the current response. * * @default false */ supportsDeferredResults?: boolean; } ); /** * Infer the input type of a tool. */ export type InferToolInput = TOOL extends Tool ? INPUT : never; /** * Infer the output type of a tool. */ export type InferToolOutput = TOOL extends Tool ? OUTPUT : never; /** * Helper function for inferring the execute args of a tool. */ // Note: overload order is important for auto-completion export function tool( tool: Tool, ): Tool; export function tool(tool: Tool): Tool; export function tool(tool: Tool): Tool; export function tool(tool: Tool): Tool; export function tool(tool: any): any { return tool; } /** * Defines a dynamic tool. */ export function dynamicTool(tool: { description?: string; title?: string; providerOptions?: ProviderOptions; inputSchema: FlexibleSchema; execute: ToolExecuteFunction; /** * Optional conversion function that maps the tool result to an output that can be used by the language model. * * If not provided, the tool result will be sent as a JSON object. */ toModelOutput?: (options: { /** * The ID of the tool call. You can use it e.g. when sending tool-call related information with stream data. */ toolCallId: string; /** * The input of the tool call. */ input: unknown; /** * The output of the tool call. */ output: unknown; }) => ToolResultOutput | PromiseLike; /** * Whether the tool needs approval before it can be executed. */ needsApproval?: boolean | ToolNeedsApprovalFunction; }): Tool & { type: 'dynamic'; } { return { ...tool, type: 'dynamic' }; }