zod-to-openai-tool
Version:
Easily create tools from zod schemas to use with OpenAI Assistants and Chat Completions
133 lines • 3.67 kB
JavaScript
// src/index.ts
import { z } from "zod";
import { zodToJsonSchema } from "zod-to-json-schema";
function tool() {
const data = {
schema: z.object({}),
func: () => {
},
description: void 0
};
return {
input(s) {
data.schema = s;
return this;
},
run(f) {
data.func = f;
return this;
},
describe(d) {
data.description = d;
return this;
},
/** @internal */
get _data() {
return data;
},
/** @internal */
get _parameters() {
const { $schema, ...parameters } = zodToJsonSchema(data.schema);
return parameters;
}
};
}
var t = {
input(s) {
return tool().input(s);
},
run(...args) {
return tool().run(...args);
},
describe(d) {
return tool().describe(d);
},
codeInterpreter: { type: "code_interpreter" },
fileSearch: { type: "file_search" }
};
function createTools(tools, onError) {
function _processActions(data) {
const results = Promise.all(
data.map(async ({ function: { arguments: args, name }, id }, i) => {
const tool2 = tools[name];
let output;
try {
const input = await tool2._data.schema.parseAsync(JSON.parse(args));
output = await tool2._data.func(input);
} catch (error) {
error = onError?.(error) ?? error;
if (error instanceof Error) {
error = error.message;
}
output = { error };
}
return { id, output: JSON.stringify(output) };
})
);
return results;
}
return {
tools: Object.entries(tools).map(
([name, tool2]) => {
const parameters = tool2._parameters;
return {
type: "function",
function: { name, description: tool2._data.description, parameters }
};
}
),
/**
* 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
*/
async processChatActions(data = []) {
return (await _processActions(data)).map(
({ id, output }) => ({
tool_call_id: id,
role: "tool",
content: output
})
);
},
/**
* 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.
*/
async processAssistantActions(data = []) {
return (await _processActions(data)).map(
({ id, output }) => ({
tool_call_id: id,
output
})
);
}
};
}
function combineTools(...tools) {
const customTools = tools.filter(
(t2) => "tools" in t2
);
const combinedCustomTools = {
tools: customTools.flatMap((t2) => t2.tools),
async processChatActions(data = []) {
return (await Promise.all(customTools.map((t2) => t2.processChatActions(data)))).flat();
},
async processAssistantActions(data = []) {
return (await Promise.all(customTools.map((t2) => t2.processAssistantActions(data)))).flat();
}
};
const builtInTools = tools.filter((t2) => "type" in t2);
return {
tools: [...combinedCustomTools.tools, ...builtInTools],
processChatActions: combinedCustomTools.processChatActions,
processAssistantActions: combinedCustomTools.processAssistantActions
};
}
export {
combineTools,
createTools,
t
};
//# sourceMappingURL=index.js.map