Skip to content
Open
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
5 changes: 5 additions & 0 deletions .changeset/zod-v4-json-schema-fallback.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@browserbasehq/stagehand": patch
---

Use the Zod v4 subpath JSON schema converter when root zod does not expose `toJSONSchema`.
18 changes: 11 additions & 7 deletions packages/core/lib/v3/zodCompat.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { z } from "zod";
import { z as zodV4 } from "zod/v4";
import type {
ZodObject as Zod4Object,
ZodRawShape as Zod4RawShape,
Expand Down Expand Up @@ -35,15 +36,18 @@ export function toJsonSchema(schema: StagehandZodSchema): JsonSchemaDocument {
return zodToJsonSchema(schema);
}

// For v4 schemas, use built-in z.toJSONSchema() method
const zodWithJsonSchema = z as typeof z & {
toJSONSchema?: (schema: Zod4TypeAny) => JsonSchemaDocument;
};
const converters = [zodV4, z] as Array<
typeof z & {
toJSONSchema?: (schema: Zod4TypeAny) => JsonSchemaDocument;
}
>;

if (zodWithJsonSchema.toJSONSchema) {
return zodWithJsonSchema.toJSONSchema(schema as Zod4TypeAny);
for (const zodWithJsonSchema of converters) {
if (zodWithJsonSchema.toJSONSchema) {
return zodWithJsonSchema.toJSONSchema(schema as Zod4TypeAny);
}
}

// This should never happen with Zod v4.1+
// This should never happen with Zod v4.1+ or transitional Zod v3.25+ packages.
throw new Error("Zod v4 toJSONSchema method not found");
}
28 changes: 28 additions & 0 deletions packages/core/tests/unit/zod-compat.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { afterEach, describe, expect, it, vi } from "vitest";

describe("zodCompat", () => {
afterEach(() => {
vi.resetModules();
vi.doUnmock("zod");
vi.doUnmock("zod/v4");
vi.doUnmock("zod-to-json-schema");
});

it("uses zod/v4 JSON schema conversion when root zod lacks toJSONSchema", async () => {
const schema = { _zod: { def: { type: "object" } } };
const jsonSchema = {
type: "object",
properties: { ok: { type: "boolean" } },
};
const toJSONSchema = vi.fn(() => jsonSchema);

vi.doMock("zod", () => ({ z: {} }));
vi.doMock("zod/v4", () => ({ z: { toJSONSchema } }));
vi.doMock("zod-to-json-schema", () => ({ default: vi.fn() }));

const { toJsonSchema } = await import("../../lib/v3/zodCompat.js");

expect(toJsonSchema(schema as never)).toBe(jsonSchema);
expect(toJSONSchema).toHaveBeenCalledWith(schema);
});
});
Loading