Skip to content

fix: honor raw StringIO request cursors - #621

Merged
jbeckwith-oai merged 1 commit into
mainfrom
codex/autoimprove-20260904-8-stringio-cursors
Sep 4, 2026
Merged

fix: honor raw StringIO request cursors#621
jbeckwith-oai merged 1 commit into
mainfrom
codex/autoimprove-20260904-8-stringio-cursors

Conversation

@jbeckwith-oai

Copy link
Copy Markdown
Contributor

Problem

The generic OpenAI::Client#request path did not honor a caller-owned StringIO cursor for raw request bodies. A direct StringIO at byte position 3 sent the full abcdef buffer, while a StringIO wrapped in OpenAI::FilePart could be consumed by the first transport attempt and send an empty retry body.

Fix

At the existing raw encode_content dispatch boundary, snapshot only the bytes remaining from the current StringIO#pos for both direct raw StringIO and raw FilePart(StringIO) bodies. The snapshot uses byte slicing and does not read, rewind, close, or otherwise mutate the caller-owned object. The guarded FilePart branch keeps non-StringIO payloads on their existing path and deliberately does not recursively re-encode raw string content as JSON.

User-visible behavior

For a buffer containing abcdef:

  • byte position 0 sends abcdef
  • byte position 3 sends def
  • EOF and beyond EOF send an empty body
  • a retryable 500→200 request replays the same remaining bytes on both attempts

The regression also checks a UTF-8 byte cursor (éx positioned after é) and preserves caller content, position, encoding, and open ownership.

Compatibility and scope

This is limited to raw StringIO normalization in lib/openai/internal/util.rb plus a focused public-client regression. It does not change retry eligibility or callbacks, IO stream behavior, multipart encoding, headers, Pathname, String, JSON, JSONL, non-StringIO FilePart, generated resources, signatures, dependencies, or public APIs.

Verification

  • mise exec ruby@4.0.6 -- bundle exec ruby -Itest test/openai/raw_stringio_request_test.rb — 3 runs, 70 assertions
  • mise exec ruby@4.0.6 -- bundle exec ruby -Itest test/openai/file_part_serialization_cursor_test.rb — 2 runs, 30 assertions
  • mise exec ruby@4.0.6 -- bundle exec ruby -Itest test/openai/net_http_client_stringio_length_test.rb — 3 runs, 38 assertions
  • mise exec ruby@4.0.6 -- bundle exec ruby -Itest test/openai/internal/util_test.rb — 63 runs, 287 assertions
  • mise exec ruby@4.0.6 -- bundle exec ruby -Itest test/openai/http_client_test.rb — 36 runs, 158 assertions
  • mise exec ruby@4.0.6 -- bundle exec rake lint — 2,875 files, no offenses; RBS validation and Sorbet examples typecheck passed
  • TEST_API_BASE_URL=<coordinator mock> mise exec ruby@4.0.6 -- bundle exec rake test — 1,637 runs, 14,583 assertions, 0 failures, 0 errors, 1 skip
  • trusted current-main public custom-code budget check — 3,363 / 4,000 custom lines, 637 lines headroom

Review and security

Two consecutive fresh adversarial-review rounds completed with two independent read-only reviewers per round and no unresolved in-scope findings. A bounded transport/file security review found no new disclosure, mutation, logging, header, redirect, retry-eligibility, or multipart risk; the change reduces accidental prefix transmission for cursor-positioned raw bodies.

Limitations

The full suite retains its existing single skipped test and emits existing dependency warnings; neither is introduced by this change.

@jbeckwith-oai
jbeckwith-oai requested a review from a team as a code owner September 4, 2026 18:07
@jbeckwith-oai jbeckwith-oai added codex-maintenance Low-risk maintenance changes created by Codex autoimprove Automated repository-health improvements labels Sep 4, 2026
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Sep 4, 2026

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review Completed 2026-09-04T18:09:42.124052Z 38f956a PR opened
🔒 Security Review Completed 2026-09-04T18:12:13.088486Z 38f956a PR opened
ℹ️ About Codex in GitHub

Your team has set up Codex to 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" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@github-actions

github-actions Bot commented Sep 4, 2026

Copy link
Copy Markdown
Contributor

Castiron custom code

✅ No new custom-code files detected.

47 mixed files remain; 0 existing customizations changed.

Compared 4322e076e57b38f956abb1dc. Generated baselines verified.

47 existing customizations unchanged
  • lib/openai.rb
  • lib/openai/client.rb
  • lib/openai/models/chat/chat_completion_message.rb
  • lib/openai/models/chat/chat_completion_message_function_tool_call.rb
  • lib/openai/models/chat/completion_create_params.rb
  • lib/openai/models/response_format_json_schema.rb
  • lib/openai/models/responses/function_tool.rb
  • lib/openai/models/responses/response.rb
  • lib/openai/models/responses/response_create_params.rb
  • lib/openai/models/responses/response_format_text_config.rb
  • lib/openai/models/responses/response_format_text_json_schema_config.rb
  • lib/openai/models/responses/response_function_tool_call.rb
  • lib/openai/models/responses/response_function_web_search.rb
  • lib/openai/models/responses/response_output_text.rb
  • lib/openai/models/responses/tool.rb
  • lib/openai/resources/beta/threads.rb
  • lib/openai/resources/chat/completions.rb
  • lib/openai/resources/files.rb
  • lib/openai/resources/responses.rb
  • lib/openai/resources/vector_stores/file_batches.rb
  • lib/openai/resources/vector_stores/files.rb
  • lib/openai/resources/webhooks.rb
  • rbi/openai/client.rbi
  • rbi/openai/models/chat/chat_completion_message.rbi
  • rbi/openai/models/chat/chat_completion_message_function_tool_call.rbi
  • rbi/openai/models/chat/completion_create_params.rbi
  • rbi/openai/models/response_format_json_schema.rbi
  • rbi/openai/models/responses/response.rbi
  • rbi/openai/models/responses/response_create_params.rbi
  • rbi/openai/models/responses/response_function_tool_call.rbi
  • rbi/openai/models/responses/response_function_web_search.rbi
  • rbi/openai/models/responses/response_output_text.rbi
  • rbi/openai/resources/chat/completions.rbi
  • rbi/openai/resources/files.rbi
  • rbi/openai/resources/responses.rbi
  • rbi/openai/resources/vector_stores/file_batches.rbi
  • rbi/openai/resources/vector_stores/files.rbi
  • scripts/castiron/README.md
  • scripts/castiron/custom_code_report.py
  • scripts/castiron/test_custom_code_report.py

7 more in the full report.

A changed generated baseline means this report cannot reliably identify which handwritten lines changed.

Inspect the custom-code diff

Download the exact patch produced by this run (requires repository access):

gh run download 33904252106 --repo openai/openai-ruby \
  --name castiron-custom-code-33904252106-1 --dir /tmp/castiron-custom-code-33904252106-1
git apply --stat /tmp/castiron-custom-code-33904252106-1/custom-code.patch
cat /tmp/castiron-custom-code-33904252106-1/custom-code.patch

Or reproduce it from an SDK checkout containing the vendored reporter:

git fetch --no-tags origin 4322e076e57b769d619175006307763e3c630cfb 38f956abb1dc7518367b4c376b5a6239897ab9d2
python3 scripts/castiron/custom_code_report.py report \
  --base 4322e076e57b769d619175006307763e3c630cfb \
  --head 38f956abb1dc7518367b4c376b5a6239897ab9d2 --fetch --require-head-hash --public \
  --out /tmp/castiron-custom-code-38f956abb1dc
cat /tmp/castiron-custom-code-38f956abb1dc/custom-code.patch

This is the current full custom patch for mixed files, not an attribution of only the handwritten lines changed by this PR.

Full report and patch

@openai-sdks

openai-sdks Bot commented Sep 4, 2026

Copy link
Copy Markdown
Contributor

OkTest Summary

237/237 SDK tests passed in 8.006s for Ruby SDK PR #621.

Test results — 42 files
Test Result Time
tests/chat-completions-complex-body.test.ts ✅ Passed 116ms
tests/chat-completions-create.test.ts ✅ Passed 225ms
tests/chat-completions-stream.test.ts ✅ Passed 103ms
tests/files-content-binary.test.ts ✅ Passed 136ms
tests/files-create-multipart.test.ts ✅ Passed 209ms
tests/files-list-pagination.test.ts ✅ Passed 105ms
tests/initialize-config.test.ts ✅ Passed 109ms
tests/instance-isolation.test.ts ✅ Passed 119ms
tests/models-list.test.ts ✅ Passed 258ms
tests/responses-background-lifecycle.test.ts ✅ Passed 100ms
tests/responses-body-method-errors.test.ts ✅ Passed 263ms
tests/responses-cancel-timeout.test.ts ✅ Passed 206ms
tests/responses-cancel.test.ts ✅ Passed 141ms
tests/responses-compact-retries.test.ts ✅ Passed 198ms
tests/responses-compact.test.ts ✅ Passed 194ms
tests/responses-create-advanced-stream.test.ts ✅ Passed 96ms
tests/responses-create-advanced.test.ts ✅ Passed 136ms
tests/responses-create-disconnect.test.ts ✅ Passed 1.004s
tests/responses-create-errors.test.ts ✅ Passed 303ms
tests/responses-create-malformed-api-responses.test.ts ✅ Passed 98ms
tests/responses-create-retries.test.ts ✅ Passed 310ms
tests/responses-create-stream-failures.test.ts ✅ Passed 106ms
tests/responses-create-stream-timeout.test.ts ✅ Passed 214ms
tests/responses-create-stream-wire.test.ts ✅ Passed 1.974s
tests/responses-create-stream.test.ts ✅ Passed 73ms
tests/responses-create-terminal-states.test.ts ✅ Passed 196ms
tests/responses-create-timeout.test.ts ✅ Passed 197ms
tests/responses-create.test.ts ✅ Passed 115ms
tests/responses-delete.test.ts ✅ Passed 140ms
tests/responses-input-items-errors.test.ts ✅ Passed 117ms
tests/responses-input-items-list.test.ts ✅ Passed 170ms
tests/responses-input-items-options.test.ts ✅ Passed 82ms
tests/responses-input-tokens-count-timeout.test.ts ✅ Passed 225ms
tests/responses-input-tokens-count.test.ts ✅ Passed 175ms
tests/responses-malformed-inputs.test.ts ✅ Passed 1.745s
tests/responses-not-found-errors.test.ts ✅ Passed 195ms
tests/responses-parse.test.ts ✅ Passed 138ms
tests/responses-retrieve-retries.test.ts ✅ Passed 153ms
tests/responses-retrieve.test.ts ✅ Passed 196ms
tests/responses-stored-method-errors.test.ts ✅ Passed 552ms
tests/retry-behavior.test.ts ✅ Passed 3.218s
tests/sdk-error-shape.test.ts ✅ Passed 337ms

View OkTest run #33904214638

SDK merge (ce1d5796d052) · head (38f956abb1dc) · base (4322e076e57b) · OkTest (2b1bdfd25e98)

@sylvesterkaczmarek sylvesterkaczmarek 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.

Snapshotting the remaining bytes at encode_content is the right replay boundary: retries need an immutable body without consuming, rewinding, or closing caller-owned StringIO. Using byteslice also correctly treats StringIO#pos as a byte offset, which the multibyte regression pins. Handling FilePart(StringIO) at the same dispatch point avoids the first transport attempt consuming state that a retry would otherwise inherit.

@markstuart-oai markstuart-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.

Reviewed the raw StringIO normalization and public-client regression coverage. The change preserves the caller’s cursor and ownership while allowing both raw forms to replay without transport consumption. Verified passing Ruby 3.3, 3.4, and 4.0 CI suites on the exact head/base merge, plus lint and type checks.

@jbeckwith-oai
jbeckwith-oai added this pull request to the merge queue Sep 4, 2026
Merged via the queue into main with commit 8e6abfd Sep 4, 2026
20 checks passed
@jbeckwith-oai
jbeckwith-oai deleted the codex/autoimprove-20260904-8-stringio-cursors branch September 4, 2026 20:05
@openai-sdks openai-sdks Bot mentioned this pull request Sep 4, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

autoimprove Automated repository-health improvements codex-maintenance Low-risk maintenance changes created by Codex

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants