Skip to content

feat(responses): parse structured outputs on retrieval - #532

Open
cjc0013 wants to merge 4 commits into
openai:mainfrom
cjc0013:issue-308-background-structured-outputs
Open

feat(responses): parse structured outputs on retrieval#532
cjc0013 wants to merge 4 commits into
openai:mainfrom
cjc0013:issue-308-background-structured-outputs

Conversation

@cjc0013

@cjc0013 cjc0013 commented Aug 26, 2026

Copy link
Copy Markdown

Summary

  • allow responses.retrieve to accept the same local text and tools structured-output models used when creating a background response
  • remove those local parsing hints before serializing retrieval query parameters, then reuse the existing Responses parser for returned text and function calls
  • preserve caller-owned tool arrays and nested hashes while extracting parser models
  • document the background create/retrieve flow

Closes #308.

Tests

  • Responses-related regression selection: 7 existing test files, 39 runs, 250 assertions, 0 failures, 0 errors, 0 skips
  • structured-output parser selection: 3 existing test files (including the 2 new retrieval tests), 22 runs, 161 assertions, 0 failures, 0 errors, 0 skips
  • rubyfmt 0.14.1 --check on the 2 modified Ruby files
  • rubocop on the 2 modified Ruby files: no offenses

@cjc0013
cjc0013 requested a review from a team as a code owner August 26, 2026 15:40

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: b8e9ee7797

ℹ️ 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".

# Retrieves a model response with the given ID.
#
# @overload retrieve(response_id, include: nil, include_obfuscation: nil, starting_after: nil, request_options: {})
# @overload retrieve(response_id, include: nil, include_obfuscation: nil, starting_after: nil, text: nil, tools: nil, request_options: {})

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Add retrieval hints to the shipped Sorbet signature

For Sorbet-typed consumers, the newly documented responses.retrieve(..., text: ..., tools: ...) call is rejected because rbi/openai/resources/responses.rbi still declares only include, include_obfuscation, starting_after, stream, and request_options for this method. Since the RBI files are shipped with the gem and the existing create signature already models JsonSchemaConverter, add text and tools to the retrieve signature so typed applications can use this feature.

Useful? React with 👍 / 👎.

@jbeckwith-oai jbeckwith-oai left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Thanks for tackling #308! This is a thoughtful improvement, and I especially appreciate the clear background-response example, the focused completed/in-progress coverage, and the quick follow-up adding both RBI and RBS signatures.

I reviewed the updated head and confirmed the type-signature concern is already addressed. Before merging, please address the four remaining compatibility/correctness issues in the inline comments:

  1. String-keyed local parsing hints currently leak into the HTTP query string.
  2. Existing ResponseRetrieveParams objects now fail before request conversion.
  3. Supported ResponseTextConfig instances that parse correctly during creation silently fail to parse during retrieval.
  4. Retrieval without parsing hints now runs the structured-output parser and can reject previously accepted partial function-call output.

The existing focused suites still pass (114 tests, 627 assertions), but targeted regression cases reproduce each of these four issues. Please add coverage for these cases, preserve the existing no-hints/request-model behavior, and request another review once they are fixed. Thanks again for moving this feature forward!

Comment thread lib/openai/resources/responses.rb Outdated
# @see OpenAI::Models::Responses::ResponseRetrieveParams
def retrieve(response_id, params = {})
parsed, options = OpenAI::Responses::ResponseRetrieveParams.dump_request(params)
structured_output_params = duplicate_structured_output_params(params.slice(:text, :tools))

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

[P1] Keep string-keyed parsing hints local.

The SDK normally accepts string-keyed parameter hashes and normalizes them in dump_request, but this extraction/deletion handles only symbol keys. I reproduced responses.retrieve(id, {"text" => CalendarEvent}) issuing GET /responses/<id>?text=CalendarEvent, which both leaks the supposedly local model name into the URL and sends an unsupported retrieval query parameter. Please normalize parameter keys before extracting/removing text and tools, and add regression coverage for both string-keyed hints.

Comment thread lib/openai/resources/responses.rb Outdated
# @see OpenAI::Models::Responses::ResponseRetrieveParams
def retrieve(response_id, params = {})
parsed, options = OpenAI::Responses::ResponseRetrieveParams.dump_request(params)
structured_output_params = duplicate_structured_output_params(params.slice(:text, :tools))

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

[P2] Preserve existing request-parameter model arguments.

responses.retrieve(id, OpenAI::Responses::ResponseRetrieveParams.new) succeeds on the current base branch because dump_request accepts SDK request-model instances. This new unconditional params.slice call instead raises NoMethodError: undefined method 'slice' before any request is made. Please coerce supported parameter objects to a hash before inspecting local hints, and add a backward-compatibility regression test.

raise ArgumentError.new(message)
end

model, tool_models = get_structured_output_models(structured_output_params)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

[P2] Support the same typed text configurations accepted by creation.

config = OpenAI::Responses::ResponseTextConfig.new(format_: CalendarEvent) correctly populates content.parsed when supplied to responses.create(..., text: config), but responses.retrieve(id, text: config) silently returns content.parsed == nil. Creation normalizes the model and translates format_ to format before extracting structured-output models; retrieval passes the unnormalized object straight into the parser. Please normalize supported typed configurations before model extraction and add a create/retrieve parity test.

Comment thread lib/openai/resources/responses.rb Outdated

model, tool_models = get_structured_output_models(structured_output_params)

unwrap = -> (raw) do

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

[P2] Preserve the no-hints retrieval path.

unwrap now invokes ResponseParser.parse! on every retrieval, including calls without text or tools. An in-progress response containing a partially populated {type: "function_call"} item succeeds on the base branch but now raises KeyError: key not found: :name, even though no tool parsing was requested. Please install the parser only when a usable text/tool model is present, and add a regression test showing ordinary retrieval remains backward-compatible.

@cjc0013

cjc0013 commented Aug 26, 2026

Copy link
Copy Markdown
Author

Addressed the four requested compatibility issues in 8b44e9c:

  • normalize retrieval params before extracting local string/symbol parsing hints
  • preserve ResponseRetrieveParams arguments
  • normalize typed ResponseTextConfig values for create/retrieve parity
  • skip structured-output parsing when retrieval has no usable hints

Added focused regressions for each case. Fresh verification: 26 runs, 171 assertions, 0 failures/errors; rubyfmt 0.14.1 clean; RuboCop clean. Ready for another review.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 8b44e9cfcb

ℹ️ 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".

Comment thread rbi/openai/resources/responses.rbi Outdated
include: T::Array[OpenAI::Responses::ResponseIncludable::OrSymbol],
include_obfuscation: T::Boolean,
starting_after: Integer,
text: T.nilable(OpenAI::StructuredOutput::JsonSchemaConverter::Input),

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Accept ResponseTextConfig in the retrieve RBI

When a Sorbet-typed caller passes an OpenAI::Responses::ResponseTextConfig to retrieve, the runtime supports it—as the new test_typed_text_config_has_create_and_retrieve_parity test demonstrates—but this signature accepts only JsonSchemaConverter::Input, so Sorbet rejects the call. Although retrieval hints were added to the RBI, the fresh typed-config test exposes this remaining mismatch; mirror the create signature by including ResponseTextConfig::OrHash alongside the converter type.

Useful? React with 👍 / 👎.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Parse structured outputs when retrieving background Responses

2 participants