Skip to content
4 changes: 2 additions & 2 deletions langchain-core/src/output_parsers/tests/structured.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -210,7 +210,7 @@ describe("StructuredOutputParser.fromZodSchema", () => {

Here is the JSON Schema instance your output must adhere to. Include the enclosing markdown codeblock:
\`\`\`json
{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"answer":{"description":"answer to the user's question","type":"string"},"sources":{"description":"sources used to answer the question, should be websites.","type":"array","items":{"type":"string"}}},"required":["answer","sources"],"additionalProperties":false}
{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"answer":{"description":"answer to the user's question","type":"string"},"sources":{"type":"array","items":{"type":"string"},"description":"sources used to answer the question, should be websites."}},"required":["answer","sources"],"additionalProperties":false}
\`\`\`
"
`);
Expand Down Expand Up @@ -343,7 +343,7 @@ describe("StructuredOutputParser.fromZodSchema", () => {

Here is the JSON Schema instance your output must adhere to. Include the enclosing markdown codeblock:
\`\`\`json
{"$schema":"https://json-schema.org/draft/2020-12/schema","description":"Only One object","type":"object","properties":{"url":{"description":"A link to the resource","type":"string"},"title":{"description":"A title for the resource","type":"string"},"year":{"description":"The year the resource was created","type":"number"},"createdAt":{"description":"The date and time the resource was created","type":"string"},"createdAtDate":{"description":"The date the resource was created","type":"string"},"authors":{"type":"array","items":{"type":"object","properties":{"name":{"description":"The name of the author","type":"string"},"email":{"description":"The email of the author","type":"string"},"type":{"type":"string","enum":["author","editor"]},"address":{"description":"The address of the author","type":"string"},"stateProvince":{"description":"The state or province of the author","type":"string","enum":["AL","AK","AZ"]}},"required":["name","email"],"additionalProperties":false}}},"required":["url","title","year","createdAt","authors"],"additionalProperties":false}
{"$schema":"https://json-schema.org/draft/2020-12/schema","type":"object","properties":{"url":{"description":"A link to the resource","type":"string"},"title":{"description":"A title for the resource","type":"string"},"year":{"description":"The year the resource was created","type":"number"},"createdAt":{"description":"The date and time the resource was created","type":"string"},"createdAtDate":{"description":"The date the resource was created","type":"string"},"authors":{"type":"array","items":{"type":"object","properties":{"name":{"description":"The name of the author","type":"string"},"email":{"description":"The email of the author","type":"string"},"type":{"type":"string","enum":["author","editor"]},"address":{"description":"The address of the author","type":"string"},"stateProvince":{"description":"The state or province of the author","type":"string","enum":["AL","AK","AZ"]}},"required":["name","email"],"additionalProperties":false}}},"required":["url","title","year","createdAt","authors"],"additionalProperties":false,"description":"Only One object"}
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The zod 4 json schema serializer doesnt have stable key ordering

\`\`\`
"
`);
Expand Down
21 changes: 19 additions & 2 deletions langchain-core/src/utils/json_schema.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,15 @@
import { toJSONSchema } from "zod/v4/core";
import { type JsonSchema7Type, zodToJsonSchema } from "zod-to-json-schema";
import { dereference, type Schema } from "@cfworker/json-schema";
import { isZodSchemaV3, isZodSchemaV4, InteropZodType } from "./types/zod.js";
import {
isZodSchemaV3,
isZodSchemaV4,
InteropZodType,
interopZodObjectStrict,
isZodObjectV4,
ZodObjectV4,
interopZodTransformInputSchema,
} from "./types/zod.js";

export type JSONSchema = JsonSchema7Type;

Expand All @@ -14,7 +22,16 @@ export { deepCompareStrict, Validator } from "@cfworker/json-schema";
*/
export function toJsonSchema(schema: InteropZodType | JSONSchema): JSONSchema {
if (isZodSchemaV4(schema)) {
return toJSONSchema(schema);
const inputSchema = interopZodTransformInputSchema(schema);
if (isZodObjectV4(inputSchema)) {
const strictSchema = interopZodObjectStrict(
inputSchema,
true
) as ZodObjectV4;
return toJSONSchema(strictSchema);
} else {
return toJSONSchema(schema);
}
}
if (isZodSchemaV3(schema)) {
return zodToJsonSchema(schema);
Expand Down
34 changes: 34 additions & 0 deletions langchain-core/src/utils/tests/json_schema.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { describe, it, expect } from "@jest/globals";
import { z as z4 } from "zod/v4";
import { toJsonSchema } from "../json_schema.js";

describe("toJsonSchema", () => {
describe("with zod v4 schemas", () => {
// https://github.com/langchain-ai/langchainjs/issues/8367
it("should allow transformed v4 zod schemas", () => {
const schema = z4
.object({
name: z4.string(),
age: z4.number(),
})
.describe("Object description")
.transform((data) => ({
...data,
upperName: data.name.toUpperCase(),
doubledAge: data.age * 2,
}));
const jsonSchema = toJsonSchema(schema);
expect(jsonSchema).toEqual({
$schema: "https://json-schema.org/draft/2020-12/schema",
type: "object",
description: "Object description",
properties: {
name: { type: "string" },
age: { type: "number" },
},
required: ["name", "age"],
additionalProperties: false,
});
});
});
});
Loading
Loading