fix(zod): convert oneOf unions to anyOf#1904
Conversation
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 9cae2ab456
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
| // OpenAI strict schemas only support anyOf. | ||
| const oneOf = jsonSchema.oneOf; | ||
| if (Array.isArray(oneOf)) { | ||
| jsonSchema.anyOf = [...(jsonSchema.anyOf ?? []), ...oneOf]; |
There was a problem hiding this comment.
Preserve existing anyOf constraints when converting oneOf
When a schema node already has an anyOf, JSON Schema applies the existing anyOf and oneOf as separate constraints, but this merge turns all branches into alternatives. For callers of toStrictJsonSchema that pass a valid schema containing both keywords on the same node, values that satisfy only a former oneOf branch can now be accepted even if they fail the original anyOf constraint, broadening the response schema instead of preserving it.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Fixed in 8882406f: when a schema node already has anyOf, the converted oneOf is kept as a separate allOf constraint instead of merging branches into the existing anyOf. I also added a regression test covering the mixed anyOf + oneOf case.
9cae2ab to
9eee578
Compare
Summary
Fixes #1709.
Zod v4 emits
oneOffor discriminated unions, but OpenAI strict JSON schemas do not allowoneOf. The Zod v4 helper path already runs schemas throughtoStrictJsonSchema, so this convertsoneOfunions into strict-compatibleanyOfunions during that normalization pass.The regression test covers a Zod discriminated union through
zodResponseFormatand asserts the final schema no longer containsoneOf.Tests
npx --yes [email protected] test tests/helpers/zod.test.ts --runInBandnpx --yes [email protected] --check src/lib/transform.ts tests/helpers/zod.test.ts./node_modules/.bin/eslint src/lib/transform.ts tests/helpers/zod.test.tsgit diff --checkNote: I also ran
./node_modules/typescript/bin/tsc --noEmit; it surfaced missing optional example dependencies in this checkout (@azure/identity,express,next). The only PR-local type issue it reported was fixed before the checks above were rerun.