fix: accept string Responses structured-output tags - #617
Conversation
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
Castiron custom code✅ No new custom-code files detected. 47 mixed files remain; 0 existing customizations changed. Compared 47 existing customizations unchanged
7 more in the full report. A changed generated baseline means this report cannot reliably identify which handwritten lines changed. Inspect the custom-code diffDownload the exact patch produced by this run (requires repository access): gh run download 33896732065 --repo openai/openai-ruby \
--name castiron-custom-code-33896732065-1 --dir /tmp/castiron-custom-code-33896732065-1
git apply --stat /tmp/castiron-custom-code-33896732065-1/custom-code.patch
cat /tmp/castiron-custom-code-33896732065-1/custom-code.patchOr reproduce it from an SDK checkout containing the vendored reporter: git fetch --no-tags origin 59e0643dbb37e95b4746b24b38c1489dd2867e33 2bebb266b742f2c4b30d9dee9bab81c7d5dd592d
python3 scripts/castiron/custom_code_report.py report \
--base 59e0643dbb37e95b4746b24b38c1489dd2867e33 \
--head 2bebb266b742f2c4b30d9dee9bab81c7d5dd592d --fetch --require-head-hash --public \
--out /tmp/castiron-custom-code-2bebb266b742
cat /tmp/castiron-custom-code-2bebb266b742/custom-code.patchThis is the current full custom patch for mixed files, not an attribution of only the handwritten lines changed by this PR. |
sylvesterkaczmarek
left a comment
There was a problem hiding this comment.
Handling the string spellings at the two parser pattern boundaries is the right scope: it restores JSON-like request parity without globally coercing caller input. The wire-equality assertions plus typed parsed-result checks cover both serialization and model registration.
markstuart-oai
left a comment
There was a problem hiding this comment.
The parser now accepts both serialized and symbol forms at the two structured-output boundaries, and the focused request/response tests cover preservation and typed hydration across text and tools.
Problem
Responses structured-output preparation recognized symbol tags but missed the equivalent string tags for nested text JSON schema formats and flat function tools. A request such as
type: "json_schema"ortype: "function"with an OpenAI structured-output model serialized the Ruby class name instead of the model JSON schema, so returned text or tool calls had no typedparsedvalue.User impact
Applications that build request hashes from JSON-like configuration can use the documented existing Responses shapes with string tag values and receive the same schema serialization and typed parsing as symbol-tag callers.
Fix
Widen the two existing Responses parser pattern matches to accept the string spellings alongside their supported symbols:
text.format.type::json_schemaor"json_schema"type::functionor"function"No global coercion or request normalization was added. Existing name/default-name, strictness, sibling options, raw schema, mutation, and retrieval-hint behavior remain on their current paths.
Regression coverage
Added a network-disabled public
client.responses.createWebMock test file that inspects wire JSON and typed results for:The safe synthetic red probe showed symbol forms sending object schemas and returning typed values, while string forms sent class-name strings and returned nil parsed fields. After the fix, both forms send equivalent schemas and return typed values. No live API calls were made.
Scope and non-goals
Only
lib/openai/helpers/structured_output/response_parser.rband the new focused test file changed. This does not add public APIs, model features, Sorbet behavior, general transport coercion, strictness changes, streaming-state changes, generated-file edits, dependencies, schema caching, recursion work, or broader normalization.Validation
mise exec ruby@4.0.6 -- bundle exec ruby -Itest test/openai/helpers/responses_string_type_hints_test.rb— 4 runs, 22 assertions, 0 failuresmise exec ruby@4.0.6 -- bundle exec ruby -Itest test/openai/helpers/structured_output_api_names_test.rb— 40 runs, 133 assertions, 0 failuresmise exec ruby@4.0.6 -- bundle exec ruby -Itest test/openai/resources/responses/streaming_test.rb— 33 runs, 122 assertions, 0 failuresmise exec ruby@4.0.6 -- bundle exec rake lint— 2,870 RuboCop files clean; RBS validation and Sorbet examples cleanTEST_API_BASE_URL=... mise exec ruby@4.0.6 -- bundle exec rake test— 1,627 runs, 14,451 assertions, 0 failures, 0 errors, 1 skipReview and security
Two consecutive adversarial-review rounds completed on unchanged code, each with two new independent read-only reviewers; all four reviews were clean. A bounded security review found no new credential, transport, logging, dependency, or deserialization boundary: the change only recognizes existing request tags and uses the existing schema conversion and model-registration paths.
Limitations
The tests use safe synthetic WebMock responses and do not claim a live-server rejection or make live API requests.