UNPKG

zod-to-openai-tool

Version:

Easily create tools from zod schemas to use with OpenAI Assistants and Chat Completions

130 lines (127 loc) 5.57 kB
import { OpenAI } from 'openai'; import { z } from 'zod'; interface Steps<T = void, Omitted extends string = never> { /** * Adds a schema for the tool. This will be used to validate the input and to infer the type of the input in the `run()` function. * @param s The schema for the input. Must be a `z.object({})` * @returns A tool with the input schema set. */ input<S extends z.AnyZodObject>(schema: S): Omit<Steps<z.infer<S>, Omitted | "input">, "input" | Omitted> & InternalTool; /** * The function to run when the model calls the tool. This is the only required builder step. * @param args The arguments for the `run()` function. * The type of the arguments will be inferred from the input schema. If there is no input schema, the type will be `void`. * @returns A tool with the `run()` function set. */ run(func: (input: T extends void ? never : T) => unknown): Omit<Steps<T, Omitted | "run">, "run" | "input" | Omitted> & InternalTool; /** * Adds a description to the tool. This will be provided to the model to aid in understanding the tool. * @param d The description of the tool as a string. * It is good to explain what data the tool returns and what it does here. * @returns A tool with the description set. */ describe(description: string): Omit<Steps<T, Omitted | "describe">, Omitted | "describe"> & InternalTool; } type CheckHasSetRun<T> = T extends { run: any; } ? never : T; interface Data { func: (input: any) => unknown; schema: z.AnyZodObject; description: string | undefined; } interface InternalTool { _data: Data; _parameters: OpenAI.Beta.FunctionTool["function"]["parameters"]; } type OpenAIBuiltInTool = OpenAI.Beta.Assistant["tools"][number]; type Tool<T = void, O extends string = never> = Steps<T, O> & InternalTool; /** * Creates a tool for use with openai assistants * @example * ```ts * const getWeather = t * .input( * z.object({ * city: z.string(), * })) * .describe("Gets the weather") * .run(async ({ city }) => ({ * weather: "sunny", * })); * ``` */ declare const t: Steps<void> & { /** * Alias to the `file_search` tool * @see https://platform.openai.com/docs/assistants/tools/knowledge-retrieval */ fileSearch: OpenAI.Beta.FileSearchTool; /** * Alias to the `code_interpreter` tool * @see https://platform.openai.com/docs/assistants/tools/code-interpreter */ codeInterpreter: OpenAI.Beta.CodeInterpreterTool; }; /** * * @param tools An object containing tools created with `t.run()`. Name them using the key. * @param onError A function that will be called when a tool throws an error. The error will be passed as the first argument. * If this function returns a value, that value will be used as the output of the tool. * If you do not provide a function, the error will be stringified and sent to the assistant. * If the function returns `undefined` or `null`, the error will be sent to the assistant. * @returns An object containing the tools and a function to process actions. * @example * ```ts * const { t, processAssistantActions, processChatActions } = createTools({ * getWeather, // These are created with `t.run()` and `t.input()`, see the example for `t` * exponential, * }); * * // Then use them like this: * const assistant = await openai.beta.assistants.create({ * tools, * //... * }); * ``` */ declare function createTools<T>(tools: { [K in keyof T]: InternalTool & CheckHasSetRun<T[K]>; }, onError?: (error: unknown) => any): { tools: (OpenAI.Beta.Assistants.FunctionTool & OpenAI.Chat.Completions.ChatCompletionTool)[]; /** * Process the actions from the chat completion. * @param data The tool calls generated from the chat completion. (`message.tool_calls`) * @returns The message which should be sent with the messages to generate the result based on the tool calls */ processChatActions(data?: OpenAI.Chat.ChatCompletionMessageToolCall[]): Promise<OpenAI.Chat.Completions.ChatCompletionToolMessageParam[]>; /** * Process the actions from the assistant run. * @param data The tool calls generated from the assistant run. (`run.required_action.submit_tool_outputs.tool_calls`) * @returns The tool outputs which should be sent to `runs.submitToolOutputs()` to continue the run. */ processAssistantActions(data?: OpenAI.Beta.Threads.Runs.RequiredActionFunctionToolCall[]): Promise<OpenAI.Beta.Threads.Runs.RunSubmitToolOutputsParams.ToolOutput[]>; }; type CreateToolsOutput = ReturnType<typeof createTools>; type AnyTool = ReturnType<typeof createTools> | OpenAIBuiltInTool; /** * Combine multiple tools into one object that can be used with an assistant. * @param tools All tools to combine. You can provide tools created with `createTools()` or built in tools from the OpenAI API (CodeInterpreter and Retrieval). * @returns The same object as `createTools()`, but with all tools combined. * @see https://platform.openai.com/docs/assistants/tools - for more information on the OpenAI API tools. * @example * ```ts * const { tools, processAssistantActions } = combineTools( * createTools({ * getWeather, * exponential, * }), * { type: "code_interpreter" }, * { type: "retrieval" }, * ); * ``` */ declare function combineTools(...tools: AnyTool[]): Omit<CreateToolsOutput, "tools"> & { tools: OpenAIBuiltInTool[]; }; export { type Tool, combineTools, createTools, t };