Commit 1a7af76
fix: make optional fields nullable in strict-mode schemas (#55)
Option<T> was unsound under strict structured outputs. Option<T>::schema()
deliberately returns the inner type's schema with no null union, expressing
optionality via the struct-level required array. But prepare_strict_schema
overwrites required with ALL property keys, as OpenAI strict mode demands.
The combination made optional fields both required AND non-nullable, so
under OpenAI/Grok/Anthropic constrained decoding the model was grammatically
forced to fabricate values for Option fields instead of omitting them.
Fix, in add_additional_properties_false: before overwriting required,
capture the ORIGINAL required list (the derive macro emits only truly
required fields there) and rewrite every property NOT in it to also admit
null:
- scalar "type" becomes a [type, "null"] union
- existing type unions get "null" appended if absent
- enum arrays also get null appended (enum constrains values independently
of type)
- anyOf/oneOf unions get a {"type": "null"} branch if none exists
- bare $ref (emitted for self-referential structs) is wrapped as
anyOf: [{$ref}, {"type": "null"}]
- an absent required array treats ALL properties as optional
The capture happens per object level inside the existing recursion, so
nested objects and array item objects resolve optionality against their
own required arrays. Option<T>::schema() is unchanged: non-strict mode
still relies on its transparency. Serde already maps null to None, so
deserialization is unaffected.
Covers all prepare_strict_schema callers (OpenAI, Grok, Anthropic
materialize/streaming paths and Toolbox tool-arg schemas). Adds unit
tests for the scalar/union/enum/anyOf/oneOf/$ref transformations, nested
object and array cases, the absent-required case, and null-to-None serde
round-trip; updates the two tests that asserted the old behavior.
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>1 parent 6ffcffc commit 1a7af76
1 file changed
Lines changed: 438 additions & 17 deletions
0 commit comments