Skip to content

fix: preserve UTF-8 SSE stream boundaries - #623

Merged
jbeckwith-oai merged 1 commit into
mainfrom
codex/autoimprove-20260904-6-sse-utf8-boundary
Sep 4, 2026
Merged

fix: preserve UTF-8 SSE stream boundaries#623
jbeckwith-oai merged 1 commit into
mainfrom
codex/autoimprove-20260904-6-sse-utf8-boundary

Conversation

@jbeckwith-oai

Copy link
Copy Markdown
Contributor

Problem

Valid UTF-8 SSE streams could lose data at the decoder boundary when a supported custom OpenAI::HTTPClient returned ordinary Ruby String chunks instead of binary strings. A single leading UTF-8 BOM caused the first event to be ignored, and UTF-8-labeled fragmentation could drop later non-ASCII events and the terminal finish reason.

User impact

Applications using custom HTTP transports could receive incomplete raw or helper streams even when the wire bytes were valid SSE. For example, a stream containing 你好世界 end could return only 你好世界 with no stop finish reason, and a leading BOM could remove start from start end.

Fix

  • Reassemble line fragments through a binary internal buffer so delimiter scanning does not depend on each Ruby fragment's encoding label.
  • Preserve the transport's emitted line encoding and allow an initial US-ASCII prefix label to yield to later UTF-8 content.
  • Reuse already-binary transport chunks to preserve existing large-payload memory behavior.
  • Ignore exactly one UTF-8 BOM only at the start of SSE decoding; embedded and non-leading BOM content remains data.

Verification

  • Coordinator public probes, before: leading BOM lost start ; UTF-8 fragments lost end and stop.
  • Coordinator public probes, after: plain/whole-BOM/split-BOM raw and helper results match; binary and UTF-8 fragments both preserve 你好世界 end and stop.
  • mise exec ruby@4.0.6 -- bundle exec rake test TEST=test/openai/sse_utf8_boundary_test.rb — 5 runs, 8 assertions, 0 failures, 0 errors.
  • Selected util, streaming, helper, unknown-event, and large-payload tests — 156 runs, 758 assertions, 0 failures, 0 errors.
  • mise exec ruby@4.0.6 -- bundle exec rake lint — passed.
  • mise exec ruby@4.0.6 -- bundle exec rake typecheck — passed.
  • Serialized current-spec full suite with offline Steady mock — 1656 runs, 14670 assertions, 0 failures, 0 errors, 1 skip.
  • Dedicated bounded streaming/deserialization security scan — 0 findings.
  • Adversarial review — six fresh-context paired rounds; supported mixed-label and binary-copy findings were fixed; rounds 5 and 6 were consecutively clean on final code.
  • Trusted public custom-code budget — 3363 / 4000, 637 lines headroom.

Compatibility and scope

The change is limited to decode_lines/decode_sse and one focused regression test. It preserves LF/CRLF handling, ASCII/no-BOM streams, embedded BOM content, caller-owned fragment bytes and encodings, JSONL behavior, one-shot closing, and large-payload semantics. It does not change public APIs, charset policy, transport behavior, dependencies, generated files, SSE retry/event-ID semantics, EOF dispatch, [DONE], or reconnection behavior.

Limitations

Verification uses deterministic offline synthetic responses through the public custom transport path; no live API examples were run.

@jbeckwith-oai
jbeckwith-oai requested a review from a team as a code owner September 4, 2026 22:13
@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-04T22:15:22.922920Z 5c2e657 PR opened
🔒 Security Review Completed 2026-09-04T22:15:12.297353Z 5c2e657 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.

@openai-sdks

openai-sdks Bot commented Sep 4, 2026

Copy link
Copy Markdown
Contributor

OkTest Summary

237/237 SDK tests passed in 10.388s for Ruby SDK PR #623.

Test results — 42 files
Test Result Time
tests/chat-completions-complex-body.test.ts ✅ Passed 178ms
tests/chat-completions-create.test.ts ✅ Passed 325ms
tests/chat-completions-stream.test.ts ✅ Passed 141ms
tests/files-content-binary.test.ts ✅ Passed 145ms
tests/files-create-multipart.test.ts ✅ Passed 189ms
tests/files-list-pagination.test.ts ✅ Passed 155ms
tests/initialize-config.test.ts ✅ Passed 254ms
tests/instance-isolation.test.ts ✅ Passed 149ms
tests/models-list.test.ts ✅ Passed 252ms
tests/responses-background-lifecycle.test.ts ✅ Passed 206ms
tests/responses-body-method-errors.test.ts ✅ Passed 403ms
tests/responses-cancel-timeout.test.ts ✅ Passed 274ms
tests/responses-cancel.test.ts ✅ Passed 261ms
tests/responses-compact-retries.test.ts ✅ Passed 286ms
tests/responses-compact.test.ts ✅ Passed 221ms
tests/responses-create-advanced-stream.test.ts ✅ Passed 143ms
tests/responses-create-advanced.test.ts ✅ Passed 216ms
tests/responses-create-disconnect.test.ts ✅ Passed 974ms
tests/responses-create-errors.test.ts ✅ Passed 257ms
tests/responses-create-malformed-api-responses.test.ts ✅ Passed 151ms
tests/responses-create-retries.test.ts ✅ Passed 336ms
tests/responses-create-stream-failures.test.ts ✅ Passed 153ms
tests/responses-create-stream-timeout.test.ts ✅ Passed 252ms
tests/responses-create-stream-wire.test.ts ✅ Passed 2.496s
tests/responses-create-stream.test.ts ✅ Passed 197ms
tests/responses-create-terminal-states.test.ts ✅ Passed 280ms
tests/responses-create-timeout.test.ts ✅ Passed 283ms
tests/responses-create.test.ts ✅ Passed 342ms
tests/responses-delete.test.ts ✅ Passed 256ms
tests/responses-input-items-errors.test.ts ✅ Passed 186ms
tests/responses-input-items-list.test.ts ✅ Passed 194ms
tests/responses-input-items-options.test.ts ✅ Passed 228ms
tests/responses-input-tokens-count-timeout.test.ts ✅ Passed 260ms
tests/responses-input-tokens-count.test.ts ✅ Passed 244ms
tests/responses-malformed-inputs.test.ts ✅ Passed 2.259s
tests/responses-not-found-errors.test.ts ✅ Passed 325ms
tests/responses-parse.test.ts ✅ Passed 238ms
tests/responses-retrieve-retries.test.ts ✅ Passed 304ms
tests/responses-retrieve.test.ts ✅ Passed 266ms
tests/responses-stored-method-errors.test.ts ✅ Passed 739ms
tests/retry-behavior.test.ts ✅ Passed 3.295s
tests/sdk-error-shape.test.ts ✅ Passed 430ms

View OkTest run #33924562182

SDK merge (60fac4c6c7be) · head (5c2e65785775) · base (06e2c91dc349) · OkTest (2b1bdfd25e98)

@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 06e2c91dc3495c2e65785775. 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 33924590211 --repo openai/openai-ruby \
  --name castiron-custom-code-33924590211-1 --dir /tmp/castiron-custom-code-33924590211-1
git apply --stat /tmp/castiron-custom-code-33924590211-1/custom-code.patch
cat /tmp/castiron-custom-code-33924590211-1/custom-code.patch

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

git fetch --no-tags origin 06e2c91dc349ba36d12ece05bf0b0cbf1ba0e220 5c2e65785775c15352e79f6ec2539f62c44ef547
python3 scripts/castiron/custom_code_report.py report \
  --base 06e2c91dc349ba36d12ece05bf0b0cbf1ba0e220 \
  --head 5c2e65785775c15352e79f6ec2539f62c44ef547 --fetch --require-head-hash --public \
  --out /tmp/castiron-custom-code-5c2e65785775
cat /tmp/castiron-custom-code-5c2e65785775/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

@HAYDEN-OAI HAYDEN-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 both changed files and traced the SSE/JSONL decoders through the raw and helper streaming paths. The binary buffer keeps delimiter offsets consistent across UTF-8 fragments, and stripping one BOM after line reassembly preserves embedded and later BOMs. I found no substantive issues in the encoding-label handling, source-string ownership, CR/LF handling, cleanup, or existing binary large-payload path. Validation was static: Ruby is unavailable in this environment, so I could not independently run the regression suite.

@jbeckwith-oai
jbeckwith-oai added this pull request to the merge queue Sep 4, 2026
Merged via the queue into main with commit 6b9ee87 Sep 4, 2026
20 checks passed
@jbeckwith-oai
jbeckwith-oai deleted the codex/autoimprove-20260904-6-sse-utf8-boundary branch September 4, 2026 22:37
@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.

2 participants