UNPKG

@techery/zod-to-vertex-schema

Version:

Convert Zod schemas to Vertex AI/Gemini compatible schemas

396 lines (331 loc) 11.1 kB
# zod-to-vertex-schema [![npm version](https://badge.fury.io/js/@techery%2Fzod-to-vertex-schema.svg)](https://www.npmjs.com/package/@techery/zod-to-vertex-schema) ![CI Status](https://github.com/techery/zod-to-vertex-schema/actions/workflows/pr-checks.yml/badge.svg?branch=main) Convert [Zod](https://github.com/colinhacks/zod) schemas to [Vertex AI/Gemini](https://cloud.google.com/vertex-ai) compatible schemas and back. This library helps you define your Vertex AI/Gemini function parameters using Zod's powerful schema definition system. Developed by [Techery](https://techery.io). ## Features - Two-way conversion between Zod and Vertex AI schemas - Preserves property ordering and descriptions - Full TypeScript support - Zero dependencies (except Zod) ## Type Compatibility | Zod Type | Vertex AI Schema Type | Notes | |----------|---------------------|-------| | `z.string()` | `STRING` | Basic string type | | `z.string().datetime()` | `STRING` | With `format: "date-time"` | | `z.string().date()` | `STRING` | With `format: "date"` | | `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`, `required`, and `propertyOrdering` matching Zod field order | | `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 `nullable: true` | | `someSchema.optional()` | Same as base | Field removed from `required` | | `someSchema.nullable()` | Same as base | With `nullable: true` | | `z.lazy(...)` | N/A | Not supported - Vertex AI schema doesn't support recursive definitions | ## Installation ```bash npm install zod-to-vertex-schema ``` ## Usage ### Converting Zod to Vertex AI Schema ```typescript import { z } from 'zod'; import { zodToVertexSchema } from 'zod-to-vertex-schema'; // Define your Zod schema const userSchema = z.object({ name: z.string(), age: z.number().int().min(0), email: z.string().email(), roles: z.array(z.enum(['admin', 'user'])), }); // Convert to Vertex AI schema const vertexSchema = zodToVertexSchema(userSchema); ``` ### Converting Vertex AI Schema to Zod ```typescript import { vertexSchemaToZod } from 'zod-to-vertex-schema'; import { SchemaType } from 'zod-to-vertex-schema'; // Your Vertex AI schema const vertexSchema = { type: SchemaType.OBJECT, properties: { name: { type: SchemaType.STRING }, age: { type: SchemaType.INTEGER, minimum: 0 }, email: { type: SchemaType.STRING }, roles: { type: SchemaType.ARRAY, items: { type: SchemaType.STRING, enum: ["admin", "user"] } } }, required: ["name", "age", "email", "roles"], propertyOrdering: ["name", "age", "email", "roles"] }; // Convert back to Zod schema const zodSchema = vertexSchemaToZod(vertexSchema); // Now you can use it for validation const validUser = { name: "John", age: 30, email: "john@example.com", roles: ["admin"] }; const result = zodSchema.safeParse(validUser); console.log(result.success); // true ``` ### Basic Example ```typescript import { z } from 'zod'; import { zodToVertexSchema } from 'zod-to-vertex-schema'; // Define your Zod schema const userSchema = z.object({ name: z.string(), age: z.number().int().min(0), email: z.string().email(), roles: z.array(z.enum(['admin', 'user'])), }); // Convert to Vertex AI schema const vertexSchema = zodToVertexSchema(userSchema); // Resulting Vertex AI schema: { type: "OBJECT", properties: { name: { type: "STRING" }, age: { type: "INTEGER", minimum: 0 }, email: { type: "STRING" }, roles: { type: "ARRAY", items: { type: "STRING", enum: ["admin", "user"] } } }, required: ["name", "age", "email", "roles"], propertyOrdering: ["name", "age", "email", "roles"] } ``` ### Advanced Examples #### Optional and Nullable Fields ```typescript const profileSchema = z.object({ username: z.string(), displayName: z.string().optional(), // Will be marked as not required bio: z.string().nullable(), // Will be marked as nullable lastSeen: z.date().optional().nullable(), // Both optional and nullable }); const vertexProfileSchema = zodToVertexSchema(profileSchema); // Resulting Vertex AI schema: { type: "OBJECT", properties: { username: { type: "STRING" }, displayName: { type: "STRING" }, bio: { type: "STRING", nullable: true }, lastSeen: { type: "STRING", format: "date", nullable: true } }, required: ["username"], propertyOrdering: ["username", "displayName", "bio", "lastSeen"] } ``` #### Complex Nested Objects ```typescript const addressSchema = z.object({ street: z.string(), city: z.string(), country: z.string(), postalCode: z.string(), }); const orderSchema = z.object({ orderId: z.string(), customer: z.object({ id: z.string(), name: z.string(), addresses: z.array(addressSchema), }), items: z.array(z.object({ productId: z.string(), quantity: z.number().int().min(1), price: z.number().min(0), })), status: z.enum(['pending', 'processing', 'shipped', 'delivered']), createdAt: z.date(), }); const vertexOrderSchema = zodToVertexSchema(orderSchema); // Resulting Vertex AI schema: { type: "OBJECT", properties: { orderId: { type: "STRING" }, customer: { type: "OBJECT", properties: { id: { type: "STRING" }, name: { type: "STRING" }, addresses: { type: "ARRAY", items: { type: "OBJECT", properties: { street: { type: "STRING" }, city: { type: "STRING" }, country: { type: "STRING" }, postalCode: { type: "STRING" } }, required: ["street", "city", "country", "postalCode"], propertyOrdering: ["street", "city", "country", "postalCode"] } } }, required: ["id", "name", "addresses"], propertyOrdering: ["id", "name", "addresses"] }, items: { type: "ARRAY", items: { type: "OBJECT", properties: { productId: { type: "STRING" }, quantity: { type: "INTEGER", minimum: 1 }, price: { type: "NUMBER", minimum: 0 } }, required: ["productId", "quantity", "price"], propertyOrdering: ["productId", "quantity", "price"] } }, status: { type: "STRING", enum: ["pending", "processing", "shipped", "delivered"] }, createdAt: { type: "STRING", format: "date" } }, required: ["orderId", "customer", "items", "status", "createdAt"], propertyOrdering: ["orderId", "customer", "items", "status", "createdAt"] } ``` #### Unions and Discriminated Unions ```typescript // Simple union const resultSchema = z.union([ z.object({ success: z.literal(true), data: z.string() }), z.object({ success: z.literal(false), error: z.string() }), ]); // Discriminated union const shapeSchema = z.discriminatedUnion('type', [ z.object({ type: z.literal('circle'), radius: z.number() }), z.object({ type: z.literal('rectangle'), width: z.number(), height: z.number() }), ]); const vertexResultSchema = zodToVertexSchema(resultSchema); const vertexShapeSchema = zodToVertexSchema(shapeSchema); // Resulting Vertex AI schemas: // For resultSchema: { anyOf: [ { type: "OBJECT", properties: { success: { type: "STRING", enum: ["true"] }, data: { type: "STRING" } }, required: ["success", "data"], propertyOrdering: ["success", "data"] }, { type: "OBJECT", properties: { success: { type: "STRING", enum: ["false"] }, error: { type: "STRING" } }, required: ["success", "error"], propertyOrdering: ["success", "error"] } ] } // For shapeSchema: { anyOf: [ { type: "OBJECT", properties: { type: { type: "STRING", enum: ["circle"] }, radius: { type: "NUMBER" } }, required: ["type", "radius"], propertyOrdering: ["type", "radius"] }, { type: "OBJECT", properties: { type: { type: "STRING", enum: ["rectangle"] }, width: { type: "NUMBER" }, height: { type: "NUMBER" } }, required: ["type", "width", "height"], propertyOrdering: ["type", "width", "height"] } ] } ``` #### Date and Format Validation ```typescript const eventSchema = z.object({ title: z.string(), startDate: z.date(), // Will be converted to date format endDate: z.date(), createdAt: z.string().datetime(), // Will be converted to date-time format }); const vertexEventSchema = zodToVertexSchema(eventSchema); // Resulting Vertex AI schema: { type: "OBJECT", properties: { title: { type: "STRING" }, startDate: { type: "STRING", format: "date" }, endDate: { type: "STRING", format: "date" }, createdAt: { type: "STRING", format: "date-time" } }, required: ["title", "startDate", "endDate", "createdAt"], propertyOrdering: ["title", "startDate", "endDate", "createdAt"] } ``` ## Supported Features - Basic Types: - `string` - `number` (with `int()` support) - `boolean` - `date` - Complex Types: - Objects (`z.object()`) - Arrays (`z.array()`) - Enums (`z.enum()`) - Unions (`z.union()`) - Discriminated Unions (`z.discriminatedUnion()`) - Literals (`z.literal()`) for strings - Modifiers: - Optional fields (`optional()`) - Nullable fields (`nullable()`) - String formats (`date()`, `datetime()`) - Number constraints (`min()`, `max()`) - Metadata: - Description preservation - Property ordering in objects (preserves the exact order of fields as defined in your Zod schema) ## API Reference ### `zodToVertexSchema(schema: z.ZodTypeAny): VertexSchema` Converts any Zod schema into a Vertex AI/Gemini-compatible schema. ### `vertexSchemaToZod(schema: VertexSchema): z.ZodTypeAny` Converts a Vertex AI/Gemini schema back into a Zod schema. Supports all features that are available in the Vertex AI schema format. ### `zodDynamicEnum(values: string[]): z.ZodEnum` Helper function to create an enum schema from a dynamic array of strings. ```typescript const roles = ['admin', 'user', 'guest']; const roleSchema = zodDynamicEnum(roles); ``` ## Notes - Default values are intentionally ignored in the conversion process - Recursive schemas (using `z.lazy()`) are not supported because Vertex AI schema format doesn't support schema definitions or recursive references - Some Zod features like transformers, refinements, and custom validators are not supported - Non-string literals are not supported in the current version ## 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