UNPKG

@techery/zod-to-openai-schema

Version:

Convert Zod schemas to OpenAI structured output compatible schemas

221 lines (169 loc) 5.63 kB
# zod-to-openai-schema [![npm version](https://badge.fury.io/js/@techery%2Fzod-to-openai-schema.svg)](https://www.npmjs.com/package/@techery/zod-to-openai-schema) ![CI Status](https://github.com/techery/zod-to-openai-schema/actions/workflows/pr-checks.yml/badge.svg?branch=main) Convert [Zod](https://github.com/colinhacks/zod) schemas to [OpenAI function calling](https://platform.openai.com/docs/guides/function-calling) compatible JSON Schema. This library helps you define your OpenAI function parameters using Zod's powerful schema definition system. Developed by [Techery](https://techery.io). ## Features - Convert Zod schemas to OpenAI-compatible JSON Schema - Preserves property descriptions and structure - Full TypeScript support - Zero dependencies (except Zod) ## Type Compatibility | Zod Type | OpenAI Schema Type | Notes | |----------|-------------------|-------| | `z.string()` | `string` | Basic string type | | `z.number()` | `number` | Floating point numbers | | `z.number().int()` | `integer` | Integer numbers | | `z.boolean()` | `boolean` | Boolean values | | `z.enum([...])` | `string` | With `enum: [...]` | | `z.object({...})` | `object` | With `properties` and `required` | | `z.array(...)` | `array` | With `items` schema | | `z.union([...])` | N/A | Converted to `anyOf: [...]` | | `z.discriminatedUnion(...)` | N/A | Converted to `anyOf: [...]` | | `z.literal(string)` | `string` | With `enum: [value]` | | `z.null()` | `string` | With `enum: [null]` | | `someSchema.nullable()` | Same as base | With `type: ['type', 'null']` | | `z.lazy(...)` | Supported | Using `$ref` and `$defs` | ## Installation ```bash npm install zod-to-openai-schema # or yarn add zod-to-openai-schema # or pnpm add zod-to-openai-schema ``` ## Usage ### Basic Example ```typescript import { z } from 'zod'; import { zodToOpenAISchema } from 'zod-to-openai-schema'; const schema = z.object({ name: z.string().describe('The name of the person'), age: z.number(), email: z.string().email(), }); const jsonSchema = zodToOpenAISchema(schema); // Resulting OpenAI schema: { type: "object", properties: { name: { type: "string", description: "The name of the person" }, age: { type: "number" }, email: { type: "string" } }, required: ["name", "age", "email"], additionalProperties: false } ``` ### Using with OpenAI Function Calling ```typescript import { z } from 'zod'; import { zodToOpenAISchema } from 'zod-to-openai-schema'; import OpenAI from 'openai'; const createTodoSchema = z.object({ title: z.string().describe('The title of the todo item'), priority: z.enum(['low', 'medium', 'high']).describe('Priority level'), dueDate: z.string().describe('Due date in ISO format'), }); const openai = new OpenAI(); const completion = await openai.chat.completions.create({ model: 'gpt-4', messages: [{ role: 'user', content: 'Create a high priority todo for reviewing code tomorrow' }], functions: [ { name: 'createTodo', description: 'Create a new todo item', parameters: zodToOpenAISchema(createTodoSchema), }, ], }); ``` ### Advanced Examples #### Recursive Types with References ```typescript import { z } from 'zod'; import { zodToOpenAISchema, definition } from 'zod-to-openai-schema'; // Define a recursive comment schema const commentSchema: z.ZodType<any> = z.lazy(() => z.object({ text: z.string(), replies: z.array(commentSchema) }) ); const schema = z.object({ post: z.object({ title: z.string(), content: z.string(), }), comments: z.array(commentSchema) }); const jsonSchema = zodToOpenAISchema(schema); // Resulting schema will use $ref and $defs for recursive types ``` #### Reusable Types with Named Definitions ```typescript const todoItemSchema = z.object({ name: z.string(), completed: z.boolean(), }); const schema = z.object({ pending: z.array(todoItemSchema), completed: z.array(todoItemSchema), }); const jsonSchema = zodToOpenAISchema(schema, { definitions: [definition('TodoItem', todoItemSchema)], }); // Resulting schema will use $ref: "#/$defs/TodoItem" ``` ## Supported Features - Basic Types: - `string` - `number` (with `int()` support) - `boolean` - Complex Types: - Objects (`z.object()`) - Arrays (`z.array()`) - Enums (`z.enum()`) - Unions (`z.union()`) - Discriminated Unions (`z.discriminatedUnion()`) - Literals (`z.literal()`) - Recursive types (using `z.lazy()`) - Modifiers: - Nullable fields (`nullable()`) - References (`$ref` and `$defs`) - Metadata: - Description preservation - Custom type definitions ## Limitations - Optional fields are not supported (OpenAI requires explicit handling of optional fields) - Some Zod types are not supported: - `z.any()` - `z.never()` - `z.intersection()` - `z.tuple()` - `z.record()` - Validation constraints (min, max, regex, etc.) are not included in the output schema ## API Reference ### `zodToOpenAISchema(schema: z.ZodTypeAny, config?: Config): OpenAIStructuredOutputSchema` Converts a Zod schema into an OpenAI-compatible JSON Schema. #### Config Options ```typescript interface Config { definitions?: Definition[]; } interface Definition { name: string; schema: z.ZodObject<any>; } ``` ### `definition(name: string, schema: z.ZodObject<any>): Definition` Helper function to create named type definitions for reuse. ## Contributing Contributions are welcome! Please feel free to submit a Pull Request. ## Authors - [Serge Zenchenko](https://github.com/sergezenchenko) - CTO at [Techery](https://techery.io) ## License MIT