Skip to content

fix: drop the redundant stream_options patch that OpenAI 2.13.0 rejects - #495

Merged
thomasluizon merged 2 commits into
mainfrom
fix/ticket-364-openai-streaming-regression
Aug 24, 2026
Merged

fix: drop the redundant stream_options patch that OpenAI 2.13.0 rejects#495
thomasluizon merged 2 commits into
mainfrom
fix/ticket-364-openai-streaming-regression

Conversation

@thomasluizon

@thomasluizon thomasluizon commented Aug 24, 2026

Copy link
Copy Markdown
Owner

Ticket: #364 in the ticket repository, https://github.com/thomasluizon/orbit-tickets/issues/364

main is red and this unblocks it. Every open pull request against this repository inherits the failure, including #494.

What broke

#479, the Dependabot nuget-minor-patch group, bumped OpenAI 2.12.0 to 2.13.0. Nine AiIntentServiceStreamingTests went red.

It was invisible on main because API Tests only ran on pull_request, so a red main surfaced as a single failing SonarCloud Analysis, whose "Test with Coverage" job is what actually runs the suite.

Root cause, traced rather than inferred

The streamed round asked for usage through the experimental SCME0001 JsonPatch API:

options.Patch.Set("$.stream_options.include_usage"u8, true);

In 2.13.0, ChatCompletionOptions gained a PropagateSet override for that path which dereferences a null internal StreamOptions, so it throws NullReferenceException. Measured directly against the installed 2.13.0 assembly:

patch result
$.foo (top-level bool) OK
$.a.b (arbitrary nested) OK
$.stream_options.include_usage NullReferenceException

So this is specific to stream_options, not a general JsonPatch break. ChatCompletionOptions.StreamOptions is internal in 2.13.0 and there is no public typed replacement, so Patch was the only documented route.

AiIntentService swallowed the NRE into Result.Failure(AiUnavailable), which is why every assertion only ever reported IsSuccess false with no cause. I surfaced it by temporarily rethrowing.

Why this deletes the call instead of pinning the package

The patch was never needed. The SDK already emits "stream_options":{"include_usage":true} for a streamed round on its own. Verified by dumping the outgoing request body with the call removed:

{"temperature":0.1,"messages":[...],"model":"gpt-test","max_completion_tokens":8192,
 "stream":true,"stream_options":{"include_usage":true}}

That holds on both 2.12.0 and 2.13.0.

So the options were: pin to 2.12.0 (2.13.0 is the latest on nuget.org, so there is no forward fix to take instead), or delete code that does nothing. Deleting is strictly better: we stay on the current SDK, we take no Dependabot ignore, and an experimental-API suppression leaves the codebase.

The new test is the guard for that reasoning

We no longer request usage ourselves, so we now depend on SDK behaviour. SendWithToolsAsync_Streaming_RequestsUsageInStreamOptions asserts the outgoing request carries stream_options.include_usage. If a future SDK stops emitting it, per-user token accounting would silently record nothing, and ORB-100's per-request cost bound would quietly stop working. This test fails instead.

API Tests now runs on push to main

arch-map.yml, guards.yml and codeql.yml already do. test.yml did not, which is the reason a red main was only visible as one confusingly-named failing check.

Verification

Full suite, locally:

project result
Orbit.Domain.Tests 547 passed, 0 failed
Orbit.Application.Tests 3208 passed, 0 failed
Orbit.Infrastructure.Tests 2169 passed, 0 failed
Orbit.Analyzers.Tests 32 passed, 0 failed

Production

The deployed API on 2.13.0 would fail every streamed Astra turn, because the NRE happens before the request is sent and the caller sees AiUnavailable. Confirm live chat after this deploys. Flagged on the ticket as the urgent half.

Nobody merged past a red gate

Worth stating, because it is the natural suspicion. #479 merged at 23:24:26Z, and the only Unit Tests run on that head started at 23:27:56Z, three and a half minutes later, failing at 23:30:03Z. The failure did not exist at merge time.

The missing push gate is the whole explanation: once the package was on main, nothing re-ran the suite there, and the only signal was a job called SonarCloud Analysis whose name gives no hint that it is what runs the tests.

orbit-api main was red. Nine AiIntentServiceStreamingTests failed after
#479 bumped OpenAI 2.12.0 to 2.13.0, and the failure was invisible on main
because API Tests only ran on pull_request.

Root cause, traced rather than inferred. The streamed round called
options.Patch.Set("$.stream_options.include_usage"u8, true) through the
experimental SCME0001 JsonPatch API. In 2.13.0 ChatCompletionOptions gained
a PropagateSet override for that path which dereferences a null internal
StreamOptions, so it throws NullReferenceException. Measured: an arbitrary
nested patch such as $.a.b still succeeds, and only $.stream_options.*
throws, so this is specific to that path and not a general JsonPatch break.
AiIntentService swallowed the NRE into Result.Failure(AiUnavailable), which
is why the assertion only ever reported IsSuccess false.

The patch was never needed. The SDK already emits
"stream_options":{"include_usage":true} for a streamed round on its own,
verified by dumping the outgoing request body with the call removed, on
both 2.12.0 and 2.13.0. So this deletes the call and its helper instead of
pinning the package backwards, which keeps us on the current SDK and drops
an experimental-API suppression.

A test now asserts the request carries stream_options.include_usage. We no
longer set it ourselves, so if a future SDK stops emitting it, per-user
token accounting would silently record nothing. This is the guard for that.

API Tests now also runs on push to main. Every other gate here already did,
which is why a red main showed up only as one failing SonarCloud Analysis.

Full suite: 547 domain, 3208 application, 2169 infrastructure, 32 analyzer,
all passing.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

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

Important

The new push trigger reaches pull request only jobs that use an unset github.base_ref, so API Tests will fail on every main push.

Reviewed changes I reviewed the OpenAI streaming regression fix, its request-shape coverage, and the expanded API test workflow trigger.

  • Streaming patch removal: Removes the redundant experimental JsonPatch call that OpenAI 2.13.0 rejects while retaining the SDK's emitted usage option.
  • Usage regression coverage: Adds an exact outbound JSON assertion for stream_options.include_usage so usage accounting cannot silently lose its SDK prerequisite.
  • Main branch test coverage: Adds push coverage for main, but currently exposes pull request only assumptions in two workflow jobs.

Pullfrog  | Fix all ➔Fix 👍s ➔View workflow run | Using GPT Sol𝕏

Comment thread .github/workflows/test.yml
…push

Adding the push trigger reached two jobs that diff HEAD against
github.base_ref, which GitHub leaves empty on a push event. Guard
Migrations and the OpenAPI Breaking-Change Gate would both have failed on
every push to main, turning the new gate into permanent noise.

Both are inherently base-relative, so they are scoped to pull_request
rather than taught a fallback base. Build, Unit Tests, Dependency Scan and
Guard Conventions read only the working tree and stay on both events,
which is the coverage the push trigger was added for.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

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

✅ No new issues found.

Reviewed changes I reviewed the workflow guards added since the prior Pullfrog review and checked them against the complete PR diff and the API Tests job dependency graph.

  • Push safe workflow: Scoped migration-guard and openapi-breaking to pull request events, preserving their github.base_ref comparisons while leaving build and unit tests active on pushes to main.

Pullfrog  | View workflow run | Using GPT Sol𝕏

@sonarqubecloud

Copy link
Copy Markdown

@thomasluizon
thomasluizon merged commit 578fba4 into main Aug 24, 2026
23 checks passed
@thomasluizon
thomasluizon deleted the fix/ticket-364-openai-streaming-regression branch August 24, 2026 19:26
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.

1 participant