{"version":3,"sources":["../src/index.ts"],"sourcesContent":["import type { OpenAI } from \"openai\";\nimport { z } from \"zod\";\nimport { zodToJsonSchema } from \"zod-to-json-schema\";\ninterface Steps<T = void, Omitted extends string = never> {\n  /**\n   * 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.\n   * @param s The schema for the input. Must be a `z.object({})`\n   * @returns A tool with the input schema set.\n   */\n  input<S extends z.AnyZodObject>(\n    schema: S,\n  ): Omit<Steps<z.infer<S>, Omitted | \"input\">, \"input\" | Omitted> &\n    InternalTool;\n  /**\n   * The function to run when the model calls the tool. This is the only required builder step.\n   * @param args The arguments for the `run()` function.\n   *   The type of the arguments will be inferred from the input schema. If there is no input schema, the type will be `void`.\n   * @returns A tool with the `run()` function set.\n   */\n  run(\n    func: (input: T extends void ? never : T) => unknown,\n  ): Omit<Steps<T, Omitted | \"run\">, \"run\" | \"input\" | Omitted> & InternalTool;\n  /**\n   * Adds a description to the tool. This will be provided to the model to aid in understanding the tool.\n   * @param d The description of the tool as a string.\n   *   It is good to explain what data the tool returns and what it does here.\n   * @returns A tool with the description set.\n   */\n  describe(\n    description: string,\n  ): Omit<Steps<T, Omitted | \"describe\">, Omitted | \"describe\"> & InternalTool;\n}\n\ntype CheckHasSetRun<T> = T extends { run: any } ? never : T;\n\ninterface Data {\n  func: (input: any) => unknown;\n  schema: z.AnyZodObject;\n  description: string | undefined;\n}\n\ninterface InternalTool {\n  _data: Data;\n  _parameters: OpenAI.Beta.FunctionTool[\"function\"][\"parameters\"];\n}\n\ntype OpenAIBuiltInTool = OpenAI.Beta.Assistant[\"tools\"][number];\n\nexport type Tool<T = void, O extends string = never> = Steps<T, O> &\n  InternalTool;\n\nfunction tool<T = void>(): Tool<T> {\n  const data: Data = {\n    schema: z.object({}),\n    func: () => {},\n    description: undefined,\n  };\n\n  return {\n    input<S extends z.AnyZodObject>(s: S) {\n      data.schema = s;\n      return this as Tool<z.infer<S>, \"input\">;\n    },\n    run(f) {\n      data.func = f;\n      return this;\n    },\n    describe(d) {\n      data.description = d;\n      return this;\n    },\n    /** @internal */\n    get _data() {\n      return data;\n    },\n    /** @internal */\n    get _parameters() {\n      const { $schema, ...parameters } = zodToJsonSchema(data.schema);\n      return parameters;\n    },\n  };\n}\n\n/**\n * Creates a tool for use with openai assistants\n * @example\n * ```ts\n * const getWeather = t\n *   .input(\n *     z.object({\n *       city: z.string(),\n *      }))\n *   .describe(\"Gets the weather\")\n *   .run(async ({ city }) => ({\n *     weather: \"sunny\",\n *   }));\n * ```\n */\nexport const t: Steps<void> & {\n  /**\n   * Alias to the `file_search` tool\n   * @see https://platform.openai.com/docs/assistants/tools/knowledge-retrieval\n   */\n  fileSearch: OpenAI.Beta.FileSearchTool;\n  /**\n   * Alias to the `code_interpreter` tool\n   * @see https://platform.openai.com/docs/assistants/tools/code-interpreter\n   */\n  codeInterpreter: OpenAI.Beta.CodeInterpreterTool;\n} = {\n  input<S extends z.AnyZodObject>(s: S) {\n    return tool().input<S>(s);\n  },\n  run(...args: Parameters<Tool[\"run\"]>) {\n    return tool().run(...args);\n  },\n  describe(d: string) {\n    return tool().describe(d);\n  },\n  codeInterpreter: { type: \"code_interpreter\" },\n  fileSearch: { type: \"file_search\" },\n};\n\n/**\n *\n * @param tools An object containing tools created with `t.run()`. Name them using the key.\n * @param onError A function that will be called when a tool throws an error. The error will be passed as the first argument.\n *  If this function returns a value, that value will be used as the output of the tool.\n *  If you do not provide a function, the error will be stringified and sent to the assistant.\n *  If the function returns `undefined` or `null`, the error will be sent to the assistant.\n * @returns An object containing the tools and a function to process actions.\n * @example\n * ```ts\n * const { t, processAssistantActions, processChatActions } = createTools({\n *   getWeather,  // These are created with `t.run()` and `t.input()`, see the example for `t`\n *   exponential,\n * });\n *\n * // Then use them like this:\n * const assistant = await openai.beta.assistants.create({\n *   tools,\n *   //...\n * });\n * ```\n */\nexport function createTools<T>(\n  tools: { [K in keyof T]: InternalTool & CheckHasSetRun<T[K]> },\n  onError?: (error: unknown) => any,\n) {\n  type _Tool = (typeof tools)[keyof T];\n\n  function _processActions(\n    data: (OpenAI.Beta.Threads.Runs.RequiredActionFunctionToolCall &\n      OpenAI.Chat.ChatCompletionMessageToolCall)[],\n  ) {\n    const results = Promise.all(\n      data.map(async ({ function: { arguments: args, name }, id }, i) => {\n        const tool = tools[name as keyof T];\n        let output;\n        try {\n          const input = await tool._data.schema.parseAsync(JSON.parse(args));\n          output = await tool._data.func(input);\n        } catch (error) {\n          error = onError?.(error) ?? error;\n          if (error instanceof Error) {\n            error = error.message;\n          }\n          output = { error };\n        }\n        return { id, output: JSON.stringify(output) };\n      }),\n    );\n    return results;\n  }\n\n  return {\n    tools: Object.entries<_Tool>(tools).map(\n      ([name, tool]): OpenAI.Beta.FunctionTool &\n        OpenAI.Chat.Completions.ChatCompletionTool => {\n        const parameters = tool._parameters;\n        return {\n          type: \"function\",\n          function: { name, description: tool._data.description, parameters },\n        };\n      },\n    ),\n    /**\n     * Process the actions from the chat completion.\n     * @param data The tool calls generated from the chat completion. (`message.tool_calls`)\n     * @returns The message which should be sent with the messages to generate the result based on the tool calls\n     */\n    async processChatActions(\n      data: OpenAI.Chat.ChatCompletionMessageToolCall[] = [],\n    ) {\n      return (await _processActions(data)).map(\n        ({ id, output }) =>\n          ({\n            tool_call_id: id,\n            role: \"tool\",\n            content: output,\n          }) as OpenAI.Chat.Completions.ChatCompletionToolMessageParam,\n      );\n    },\n    /**\n     * Process the actions from the assistant run.\n     * @param data The tool calls generated from the assistant run. (`run.required_action.submit_tool_outputs.tool_calls`)\n     * @returns The tool outputs which should be sent to `runs.submitToolOutputs()` to continue the run.\n     */\n    async processAssistantActions(\n      data: OpenAI.Beta.Threads.Runs.RequiredActionFunctionToolCall[] = [],\n    ) {\n      return (await _processActions(data)).map(\n        ({ id, output }) =>\n          ({\n            tool_call_id: id,\n            output,\n          }) as OpenAI.Beta.Threads.Runs.RunSubmitToolOutputsParams.ToolOutput,\n      );\n    },\n  };\n}\n\ntype CreateToolsOutput = ReturnType<typeof createTools>;\ntype AnyTool = ReturnType<typeof createTools> | OpenAIBuiltInTool;\n\n/**\n * Combine multiple tools into one object that can be used with an assistant.\n * @param tools All tools to combine. You can provide tools created with `createTools()` or built in tools from the OpenAI API (CodeInterpreter and Retrieval).\n * @returns The same object as `createTools()`, but with all tools combined.\n * @see https://platform.openai.com/docs/assistants/tools - for more information on the OpenAI API tools.\n * @example\n * ```ts\n * const { tools, processAssistantActions } = combineTools(\n *   createTools({\n *     getWeather,\n *     exponential,\n *   }),\n *   { type: \"code_interpreter\" },\n *   { type: \"retrieval\" },\n * );\n * ```\n */\nexport function combineTools(...tools: AnyTool[]): Omit<\n  CreateToolsOutput,\n  \"tools\"\n> & {\n  tools: OpenAIBuiltInTool[];\n} {\n  const customTools = tools.filter(\n    (t): t is Exclude<typeof t, OpenAIBuiltInTool> => \"tools\" in t,\n  );\n\n  const combinedCustomTools = {\n    tools: customTools.flatMap(t => t.tools),\n    async processChatActions(\n      data: OpenAI.Chat.ChatCompletionMessageToolCall[] = [],\n    ) {\n      return (\n        await Promise.all(customTools.map(t => t.processChatActions(data)))\n      ).flat();\n    },\n    async processAssistantActions(\n      data: OpenAI.Beta.Threads.Runs.RequiredActionFunctionToolCall[] = [],\n    ) {\n      return (\n        await Promise.all(customTools.map(t => t.processAssistantActions(data)))\n      ).flat();\n    },\n  };\n  const builtInTools = tools.filter((t): t is OpenAIBuiltInTool => \"type\" in t);\n\n  return {\n    tools: [...combinedCustomTools.tools, ...builtInTools],\n    processChatActions: combinedCustomTools.processChatActions,\n    processAssistantActions: combinedCustomTools.processAssistantActions,\n  };\n}\n"],"mappings":"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","names":["tool","t"]}