Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .release-please-manifest.json
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
{
".": "6.6.0"
".": "6.7.0"
}
4 changes: 2 additions & 2 deletions .stats.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
configured_endpoints: 135
openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-812a10f8fb54c584efc914422b574cb3f43dc238b5733b13f6a0b2308b7d9910.yml
openapi_spec_hash: 0222041ba12a5ff6b94924a834fa91a2
openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-a3c45d9bd3bb25bf4eaa49b7fb473a00038293dec659ffaa44f624ded884abf4.yml
openapi_spec_hash: 9c20aaf786a0700dabd13d9865481c9e
config_hash: 50ee3382a63c021a9f821a935950e926
13 changes: 13 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,18 @@
# Changelog

## 6.7.0 (2025-10-24)

Full Changelog: [v6.6.0...v6.7.0](https://github.com/openai/openai-node/compare/v6.6.0...v6.7.0)

### Features

* add support for zod@4 schemas ([#1666](https://github.com/openai/openai-node/issues/1666)) ([10ef7ff](https://github.com/openai/openai-node/commit/10ef7ff4cb4aefeaa831b239943118ff52872f5c))


### Bug Fixes

* **api:** docs updates ([2591c21](https://github.com/openai/openai-node/commit/2591c211bce29d078579445d9a3b45d8de453ec3))

## 6.6.0 (2025-10-20)

Full Changelog: [v6.5.0...v6.6.0](https://github.com/openai/openai-node/compare/v6.5.0...v6.6.0)
Expand Down
2 changes: 1 addition & 1 deletion examples/parsing-run-tools.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import OpenAI from 'openai';
import z from 'zod/v3';
import z from 'zod/v4'; // Also works for 'zod/v3'
import { zodFunction } from 'openai/helpers/zod';

const Table = z.enum(['orders', 'customers', 'products']);
Expand Down
2 changes: 1 addition & 1 deletion examples/parsing-stream.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { zodResponseFormat } from 'openai/helpers/zod';
import OpenAI from 'openai/index';
import { z } from 'zod/v3';
import { z } from 'zod/v4'; // Also works for 'zod/v3'

const Step = z.object({
explanation: z.string(),
Expand Down
2 changes: 1 addition & 1 deletion examples/parsing-tools-stream.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { zodFunction } from 'openai/helpers/zod';
import OpenAI from 'openai/index';
import { z } from 'zod/v3';
import { z } from 'zod/v4'; // Also works for 'zod/v3'

const GetWeatherArgs = z.object({
city: z.string(),
Expand Down
2 changes: 1 addition & 1 deletion examples/parsing-tools.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { zodFunction } from 'openai/helpers/zod';
import OpenAI from 'openai/index';
import { z } from 'zod/v3';
import { z } from 'zod/v4'; // Also works for 'zod/v3'

const Table = z.enum(['orders', 'customers', 'products']);

Expand Down
2 changes: 1 addition & 1 deletion examples/parsing.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { zodResponseFormat } from 'openai/helpers/zod';
import OpenAI from 'openai/index';
import { z } from 'zod/v3';
import { z } from 'zod/v4'; // Also works for 'zod/v3'

const Step = z.object({
explanation: z.string(),
Expand Down
2 changes: 1 addition & 1 deletion examples/responses/streaming-tools.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import { OpenAI } from 'openai';
import { zodResponsesFunction } from 'openai/helpers/zod';
import { z } from 'zod/v3';
import { z } from 'zod/v4'; // Also works for 'zod/v3'

const Table = z.enum(['orders', 'customers', 'products']);
const Column = z.enum([
Expand Down
2 changes: 1 addition & 1 deletion examples/responses/structured-outputs-tools.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import { OpenAI } from 'openai';
import { zodResponsesFunction } from 'openai/helpers/zod';
import { z } from 'zod/v3';
import { z } from 'zod/v4'; // Also works for 'zod/v3'

const Table = z.enum(['orders', 'customers', 'products']);
const Column = z.enum([
Expand Down
2 changes: 1 addition & 1 deletion examples/responses/structured-outputs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import { OpenAI } from 'openai';
import { zodTextFormat } from 'openai/helpers/zod';
import { z } from 'zod/v3';
import { z } from 'zod/v4'; // Also works for 'zod/v3'

const Step = z.object({
explanation: z.string(),
Expand Down
2 changes: 1 addition & 1 deletion examples/tool-call-helpers-zod.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import OpenAI from 'openai';
import { zodFunction } from 'openai/helpers/zod';
import { z } from 'zod/v3';
import { z } from 'zod/v4'; // Also works for 'zod/v3'

// gets API Key from environment variable OPENAI_API_KEY
const openai = new OpenAI();
Expand Down
2 changes: 1 addition & 1 deletion examples/ui-generation.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import OpenAI from 'openai';
import { z } from 'zod/v3';
import { z } from 'zod/v4'; // Also works for 'zod/v3'
import { zodResponseFormat } from 'openai/helpers/zod';

const openai = new OpenAI();
Expand Down
2 changes: 1 addition & 1 deletion jsr.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@openai/openai",
"version": "6.6.0",
"version": "6.7.0",
"exports": {
".": "./index.ts",
"./helpers/zod": "./helpers/zod.ts",
Expand Down
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "openai",
"version": "6.6.0",
"version": "6.7.0",
"description": "The official TypeScript library for the OpenAI API",
"author": "OpenAI <[email protected]>",
"types": "dist/index.d.ts",
Expand Down Expand Up @@ -36,6 +36,7 @@
"@types/node": "^20.17.6",
"@typescript-eslint/eslint-plugin": "8.31.1",
"@typescript-eslint/parser": "8.31.1",
"deep-object-diff": "^1.1.9",
"eslint": "^9.20.1",
"eslint-plugin-prettier": "^5.4.1",
"eslint-plugin-unused-imports": "^4.1.4",
Expand Down
58 changes: 42 additions & 16 deletions src/helpers/zod.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { ResponseFormatJSONSchema } from '../resources/index';
import type { infer as zodInfer, ZodType } from 'zod/v3';
import { z as z3 } from 'zod/v3';
import { z as z4 } from 'zod/v4';
import {
AutoParseableResponseFormat,
AutoParseableTextFormat,
Expand All @@ -11,8 +12,15 @@ import {
import { zodToJsonSchema as _zodToJsonSchema } from '../_vendor/zod-to-json-schema';
import { AutoParseableResponseTool, makeParseableResponseTool } from '../lib/ResponsesParser';
import { type ResponseFormatTextJSONSchemaConfig } from '../resources/responses/responses';
import { toStrictJsonSchema } from '../lib/transform';
import { JSONSchema } from '../lib/jsonschema';

function zodToJsonSchema(schema: ZodType, options: { name: string }): Record<string, unknown> {
type InferZodType<T> =
T extends z4.ZodType ? z4.infer<T>
: T extends z3.ZodType ? z3.infer<T>
: never;

function zodV3ToJsonSchema(schema: z3.ZodType, options: { name: string }): Record<string, unknown> {
return _zodToJsonSchema(schema, {
openaiStrictMode: true,
name: options.name,
Expand All @@ -22,6 +30,18 @@ function zodToJsonSchema(schema: ZodType, options: { name: string }): Record<str
});
}

function zodV4ToJsonSchema(schema: z4.ZodType): Record<string, unknown> {
return toStrictJsonSchema(
z4.toJSONSchema(schema, {
target: 'draft-7',
}) as JSONSchema,
) as Record<string, unknown>;
}

function isZodV4(zodObject: z3.ZodType | z4.ZodType): zodObject is z4.ZodType {
return '_zod' in zodObject;
}

/**
* Creates a chat completion `JSONSchema` response format object from
* the given Zod schema.
Expand Down Expand Up @@ -59,37 +79,37 @@ function zodToJsonSchema(schema: ZodType, options: { name: string }): Record<str
* This can be passed directly to the `.create()` method but will not
* result in any automatic parsing, you'll have to parse the response yourself.
*/
export function zodResponseFormat<ZodInput extends ZodType>(
export function zodResponseFormat<ZodInput extends z3.ZodType | z4.ZodType>(
zodObject: ZodInput,
name: string,
props?: Omit<ResponseFormatJSONSchema.JSONSchema, 'schema' | 'strict' | 'name'>,
): AutoParseableResponseFormat<zodInfer<ZodInput>> {
): AutoParseableResponseFormat<InferZodType<ZodInput>> {
return makeParseableResponseFormat(
{
type: 'json_schema',
json_schema: {
...props,
name,
strict: true,
schema: zodToJsonSchema(zodObject, { name }),
schema: isZodV4(zodObject) ? zodV4ToJsonSchema(zodObject) : zodV3ToJsonSchema(zodObject, { name }),
},
},
(content) => zodObject.parse(JSON.parse(content)),
);
}

export function zodTextFormat<ZodInput extends ZodType>(
export function zodTextFormat<ZodInput extends z3.ZodType | z4.ZodType>(
zodObject: ZodInput,
name: string,
props?: Omit<ResponseFormatTextJSONSchemaConfig, 'schema' | 'type' | 'strict' | 'name'>,
): AutoParseableTextFormat<zodInfer<ZodInput>> {
): AutoParseableTextFormat<InferZodType<ZodInput>> {
return makeParseableTextFormat(
{
type: 'json_schema',
...props,
name,
strict: true,
schema: zodToJsonSchema(zodObject, { name }),
schema: isZodV4(zodObject) ? zodV4ToJsonSchema(zodObject) : zodV3ToJsonSchema(zodObject, { name }),
},
(content) => zodObject.parse(JSON.parse(content)),
);
Expand All @@ -100,23 +120,26 @@ export function zodTextFormat<ZodInput extends ZodType>(
* automatically by the chat completion `.runTools()` method or automatically
* parsed by `.parse()` / `.stream()`.
*/
export function zodFunction<Parameters extends ZodType>(options: {
export function zodFunction<Parameters extends z3.ZodType | z4.ZodType>(options: {
name: string;
parameters: Parameters;
function?: ((args: zodInfer<Parameters>) => unknown | Promise<unknown>) | undefined;
function?: ((args: InferZodType<Parameters>) => unknown | Promise<unknown>) | undefined;
description?: string | undefined;
}): AutoParseableTool<{
arguments: Parameters;
name: string;
function: (args: zodInfer<Parameters>) => unknown;
function: (args: InferZodType<Parameters>) => unknown;
}> {
// @ts-expect-error TODO
return makeParseableTool<any>(
{
type: 'function',
function: {
name: options.name,
parameters: zodToJsonSchema(options.parameters, { name: options.name }),
parameters:
isZodV4(options.parameters) ?
zodV4ToJsonSchema(options.parameters)
: zodV3ToJsonSchema(options.parameters, { name: options.name }),
strict: true,
...(options.description ? { description: options.description } : undefined),
},
Expand All @@ -128,21 +151,24 @@ export function zodFunction<Parameters extends ZodType>(options: {
);
}

export function zodResponsesFunction<Parameters extends ZodType>(options: {
export function zodResponsesFunction<Parameters extends z3.ZodType | z4.ZodType>(options: {
name: string;
parameters: Parameters;
function?: ((args: zodInfer<Parameters>) => unknown | Promise<unknown>) | undefined;
function?: ((args: InferZodType<Parameters>) => unknown | Promise<unknown>) | undefined;
description?: string | undefined;
}): AutoParseableResponseTool<{
arguments: Parameters;
name: string;
function: (args: zodInfer<Parameters>) => unknown;
function: (args: InferZodType<Parameters>) => unknown;
}> {
return makeParseableResponseTool<any>(
{
type: 'function',
name: options.name,
parameters: zodToJsonSchema(options.parameters, { name: options.name }),
parameters:
isZodV4(options.parameters) ?
zodV4ToJsonSchema(options.parameters)
: zodV3ToJsonSchema(options.parameters, { name: options.name }),
strict: true,
...(options.description ? { description: options.description } : undefined),
},
Expand Down
24 changes: 24 additions & 0 deletions src/lib/jsonschema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,30 @@ export interface JSONSchema {
oneOf?: JSONSchemaDefinition[] | undefined;
not?: JSONSchemaDefinition | undefined;

/**
* @see https://json-schema.org/draft/2020-12/json-schema-core.html#section-8.2.4
*/
$defs?:
| {
[key: string]: JSONSchemaDefinition;
}
| undefined;

/**
* @deprecated Use $defs instead (draft 2019-09+)
* @see https://tools.ietf.org/doc/html/draft-handrews-json-schema-validation-01#page-22
*/
definitions?:
| {
[key: string]: JSONSchemaDefinition;
}
| undefined;

/**
* @see https://json-schema.org/draft/2020-12/json-schema-core#ref
*/
$ref?: string | undefined;

/**
* @see https://tools.ietf.org/html/draft-handrews-json-schema-validation-01#section-7
*/
Expand Down
Loading