From 2b15199176dc7f909c0b872571a6923663890c7b Mon Sep 17 00:00:00 2001 From: Ronald Koh Date: Thu, 4 Jun 2026 10:36:41 +0800 Subject: [PATCH] autoevals: support Zod v4 via peer dependency MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Move `zod` from a hard dependency (pinned to `^3.25.76`) to a peer dependency with range `^3.25.34 || ^4.0`, mirroring the pattern already used by the main `braintrust` TypeScript SDK (`braintrust/sdk/js/package.json:244-246`). Users on either Zod major version can now consume autoevals without needing to allow duplicate Zod installs or apply local patches. Adds `js/zod-utils.ts` with a small `zodToJsonSchema` shim that dispatches between Zod v3 (via `zod-to-json-schema`) and Zod v4 (via v4's native `z.toJSONSchema()`). The shim is a direct copy of the same pattern at `braintrust/sdk/js/src/zod/utils.ts`, so v3 and v4 schemas both produce JSON Schema output that's compatible with OpenAI tool parameters. Updates `js/ragas.ts` to import the shim instead of pulling `zod-to-json-schema` directly, so the same code works for users on either Zod major. `js/templates.ts` is unchanged — it only uses basic `z.object`, `z.string`, etc. APIs that exist in both Zod v3 and v4, so the exported `modelGradedSpecSchema` and `ModelGradedSpec` type resolve to whichever Zod version the consumer has installed. Picks up the work Caitlin started in #155 but takes a minimal approach off current main rather than carrying that branch's incidental drift. The internal integration test failures she flagged on 2026-01-13 in #155 still need to be re-validated against this change since they weren't reproducible from autoevals' public CI alone — flagging that explicitly in the PR description. Reported by Juicebox (Pylon #17165). Linear: BT-5495. Co-Authored-By: Claude Opus 4.7 (1M context) --- js/ragas.ts | 2 +- js/zod-utils.ts | 22 ++++++++++++++++++++++ package.json | 7 +++++-- 3 files changed, 28 insertions(+), 3 deletions(-) create mode 100644 js/zod-utils.ts diff --git a/js/ragas.ts b/js/ragas.ts index 2c89a975..553dda70 100644 --- a/js/ragas.ts +++ b/js/ragas.ts @@ -109,7 +109,7 @@ import OpenAI from "openai"; import { ListContains } from "./list"; import { EmbeddingSimilarity } from "./string"; import { z } from "zod"; -import zodToJsonSchema from "zod-to-json-schema"; +import { zodToJsonSchema } from "./zod-utils"; import { makePartial, ScorerWithPartial } from "./partial"; type RagasArgs = { diff --git a/js/zod-utils.ts b/js/zod-utils.ts new file mode 100644 index 00000000..3c11667c --- /dev/null +++ b/js/zod-utils.ts @@ -0,0 +1,22 @@ +import { zodToJsonSchema as zodToJsonSchemaV3 } from "zod-to-json-schema"; +import * as z3 from "zod/v3"; +import * as z4 from "zod/v4"; + +function isZodV4(zodObject: z3.ZodType | z4.ZodType): zodObject is z4.ZodType { + return ( + typeof zodObject === "object" && + zodObject !== null && + "_zod" in zodObject && + zodObject._zod !== undefined + ); +} + +export function zodToJsonSchema(schema: z4.ZodType | z3.ZodType) { + if (isZodV4(schema)) { + return z4.toJSONSchema(schema, { + target: "draft-7", + }); + } + + return zodToJsonSchemaV3(schema); +} diff --git a/package.json b/package.json index b7b42e0c..5de55294 100644 --- a/package.json +++ b/package.json @@ -55,7 +55,8 @@ "typedoc": "^0.25.13", "typedoc-plugin-markdown": "^3.17.1", "typescript": "^5.9.2", - "vitest": "^2.1.9" + "vitest": "^2.1.9", + "zod": "^3.25.34" }, "dependencies": { "ajv": "^8.17.1", @@ -65,8 +66,10 @@ "linear-sum-assignment": "^1.0.7", "mustache": "^4.2.0", "openai": "^6.3.0", - "zod": "^3.25.76", "zod-to-json-schema": "^3.24.6" }, + "peerDependencies": { + "zod": "^3.25.34 || ^4.0" + }, "packageManager": "pnpm@10.33.0" }