Skip to content

fix: encode multipart array and nested fields - #348

Merged
jbeckwith-oai merged 1 commit into
mainfrom
codex/fix-multipart-form-encoding
Aug 10, 2026
Merged

fix: encode multipart array and nested fields#348
jbeckwith-oai merged 1 commit into
mainfrom
codex/fix-multipart-form-encoding

Conversation

@jbeckwith-oai

Copy link
Copy Markdown
Contributor

Summary

  • encode multipart arrays recursively as field[], including both primitive and file arrays
  • flatten nested multipart objects with bracket notation, including arrays of nested objects
  • preserve scalar field names and streaming file behavior
  • escape both name and filename Content-Disposition parameters
  • keep the fix entirely in the openai-ruby runtime; no generated model, OpenAPI, or Castiron changes are needed

Root cause

The shared multipart writer repeated top-level primitive and file arrays using the scalar field name and serialized nested hashes as JSON parts. The API's form parser expects the same global brackets format used by openai-python and by the transformed OpenAPI examples.

Before:

  • timestamp_granularities=word and timestamp_granularities=segment
  • duplicate scalar image file parts
  • one JSON expires_after part

After:

  • timestamp_granularities[]=word and timestamp_granularities[]=segment
  • duplicate image[] file parts, while a single image remains image
  • expires_after[anchor]=created_at and expires_after[seconds]=3600

The implementation replaces the old top-level array special case with one recursive field writer. It preserves insertion order, array order, duplicate values, and streaming file contents without materializing a flattened body.

This consolidates and supersedes #249, #311, and #339.

Fixes #201.
Fixes #212.
Fixes #253.

Validation

  • mise exec ruby@4.0.6 -- bundle exec ruby -Itest test/openai/internal/util_test.rb — 45 runs, 178 assertions
  • mise exec ruby@4.0.6 -- ./scripts/test — 522 runs, 1,709 assertions
  • mise exec ruby@4.0.6 -- bundle exec rake lint — 2,596 files, no RuboCop offenses; Sorbet clean; 1,211 RBS files valid
  • mise exec ruby@4.0.6 -- bundle exec rake build:gem — built openai-0.78.0.gem
  • RBI and RBS formatting plus git diff --check
  • thermo-nuclear maintainability review and a separate correctness/readability/architecture/security/performance review, repeated after findings until clean

@jbeckwith-oai
jbeckwith-oai requested a review from a team as a code owner August 9, 2026 19:58
@openai-sdks

openai-sdks Bot commented Aug 9, 2026

Copy link
Copy Markdown
Contributor

OkTest Summary

237/237 SDK tests passed in 8.488s for Ruby SDK PR #348.

Test results — 42 files
Test Result Time
tests/chat-completions-complex-body.test.ts ✅ Passed 163ms
tests/chat-completions-create.test.ts ✅ Passed 236ms
tests/chat-completions-stream.test.ts ✅ Passed 129ms
tests/files-content-binary.test.ts ✅ Passed 225ms
tests/files-create-multipart.test.ts ✅ Passed 242ms
tests/files-list-pagination.test.ts ✅ Passed 171ms
tests/initialize-config.test.ts ✅ Passed 153ms
tests/instance-isolation.test.ts ✅ Passed 239ms
tests/models-list.test.ts ✅ Passed 173ms
tests/responses-background-lifecycle.test.ts ✅ Passed 207ms
tests/responses-body-method-errors.test.ts ✅ Passed 448ms
tests/responses-cancel-timeout.test.ts ✅ Passed 207ms
tests/responses-cancel.test.ts ✅ Passed 231ms
tests/responses-compact-retries.test.ts ✅ Passed 228ms
tests/responses-compact.test.ts ✅ Passed 227ms
tests/responses-create-advanced-stream.test.ts ✅ Passed 135ms
tests/responses-create-advanced.test.ts ✅ Passed 205ms
tests/responses-create-disconnect.test.ts ✅ Passed 160ms
tests/responses-create-errors.test.ts ✅ Passed 264ms
tests/responses-create-malformed-api-responses.test.ts ✅ Passed 130ms
tests/responses-create-retries.test.ts ✅ Passed 275ms
tests/responses-create-stream-failures.test.ts ✅ Passed 139ms
tests/responses-create-stream-timeout.test.ts ✅ Passed 218ms
tests/responses-create-stream-wire.test.ts ✅ Passed 1.973s
tests/responses-create-stream.test.ts ✅ Passed 84ms
tests/responses-create-terminal-states.test.ts ✅ Passed 304ms
tests/responses-create-timeout.test.ts ✅ Passed 218ms
tests/responses-create.test.ts ✅ Passed 290ms
tests/responses-delete.test.ts ✅ Passed 234ms
tests/responses-input-items-errors.test.ts ✅ Passed 188ms
tests/responses-input-items-list.test.ts ✅ Passed 188ms
tests/responses-input-items-options.test.ts ✅ Passed 251ms
tests/responses-input-tokens-count-timeout.test.ts ✅ Passed 290ms
tests/responses-input-tokens-count.test.ts ✅ Passed 261ms
tests/responses-malformed-inputs.test.ts ✅ Passed 2.128s
tests/responses-not-found-errors.test.ts ✅ Passed 323ms
tests/responses-parse.test.ts ✅ Passed 182ms
tests/responses-retrieve-retries.test.ts ✅ Passed 257ms
tests/responses-retrieve.test.ts ✅ Passed 268ms
tests/responses-stored-method-errors.test.ts ✅ Passed 616ms
tests/retry-behavior.test.ts ✅ Passed 1.952s
tests/sdk-error-shape.test.ts ✅ Passed 331ms

View OkTest run #31335329567

SDK merge (85ffda68ff94) · head (9d04855c556e) · base (20fbb0942991) · OkTest (91635c6a2723)

@jbeckwith-oai jbeckwith-oai added the generator Touches generated SDK files label Aug 9, 2026
Encode arrays and nested objects recursively with bracket notation while preserving scalar multipart fields. Escape all Content-Disposition parameters and cover generated request models for transcription, image editing, and file expiration.
@jbeckwith-oai jbeckwith-oai changed the title Fix multipart array and nested field encoding fix: encode multipart array and nested fields Aug 9, 2026
@jbeckwith-oai
jbeckwith-oai force-pushed the codex/fix-multipart-form-encoding branch from 8ba6ba2 to 9d04855 Compare August 9, 2026 20:51
@jbeckwith-oai
jbeckwith-oai added this pull request to the merge queue Aug 10, 2026
Merged via the queue into main with commit 1c71a1e Aug 10, 2026
14 checks passed
@jbeckwith-oai
jbeckwith-oai deleted the codex/fix-multipart-form-encoding branch August 10, 2026 18:59
@openai-sdks openai-sdks Bot mentioned this pull request Aug 10, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

generator Touches generated SDK files

Projects

None yet

2 participants