Repository navigation
fix(sse): recognize bare delta.reasoning in combo streaming quality-gate peek (#13620) - #13806
Merged
diegosouzapw merged 2 commits intoSep 16, 2026
Merged
Conversation
…ate peek (#13620) hasOpenAICompatibleStreamValue() in open-sse/utils/streamHelpers.ts only recognized content, reasoning_content, reasoning_text, and tool_calls on an OpenAI-shape delta — not bare delta.reasoning (the field Ollama Cloud emits for deepseek-v4.1-flash, glm-5.3-flash, etc). Since this predicate is the only exit condition for the combo quality-gate's bounded SSE peek (validateQuality.ts), every reasoning delta was silently buffered until the first real content delta arrived, then replayed in one synchronous burst — and a stream that finished with reasoning-only content was misclassified as "streaming openai terminated with empty completion" and failed over. Fix: reuse the already-imported hasAnyReasoningSignal() helper (already used correctly in hasValuableContent() a few lines below) instead of the two hand-rolled string checks, aligning this predicate with the non-streaming validator, hasValuableContent(), and ensureStreamReadiness(), which already treat bare reasoning as real content. Regression test: tests/unit/issue-13620-combo-reasoning-only-sse-burst.test.ts
…urst (base-red fix #13747)
muhamadgalihsaputra
pushed a commit
to niyatna/NiyatnaRoute
that referenced
this pull request
Sep 27, 2026
…ate peek (cheaper-inference#13620) (cheaper-inference#13806) Merged in the 2026-09-16 sweep of the maintainer's own open PRs, at the owner's explicit instruction. No push was made to the PR branch: the merge took the head as the owning session left it (verified OPEN, non-draft and MERGEABLE against the release tip immediately before merging).
This was referenced Sep 29, 2026
Closed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #13620
Root cause (short)
hasOpenAICompatibleStreamValue()inopen-sse/utils/streamHelpers.ts— the solecontent-detection predicate for OpenAI-shape SSE chunks — recognized
content,reasoning_content,reasoning_text, andtool_calls, but not baredelta.reasoning(the field Ollama Cloud emits for reasoning-capable models like
deepseek-v4.1-flash,glm-5.3-flash,glm-5.3).This predicate is the only exit condition for the combo quality-gate's bounded SSE peek
(
open-sse/services/combo/validateQuality.ts), which every combo dispatch path runsbefore forwarding a stream to the client. Because bare
reasoningchunks neversatisfied it, the peek loop kept reading and buffering every reasoning delta until the
first real
contentdelta arrived, then replayed the entire buffered prefix in onesynchronous burst — the "dead silence, then a burst" the reporter measured (196s
silence, then 14,051 reasoning deltas in 1.24s). A stream that finished with only
reasoning deltas (no
content/tool_calls) was also misclassified as"streaming openai terminated with empty completion"and failed over unnecessarily.Non-combo (direct) requests were unaffected because they stream via
ensureStreamReadiness(), whose accept-list already includes barereasoning.Fix
Swap the two hand-rolled
reasoning_content/reasoning_textchecks inhasOpenAICompatibleStreamValue()for the already-importedhasAnyReasoningSignal()helper (
open-sse/utils/reasoningFields.ts), which is already used correctly a fewlines below in
hasValuableContent(). This aligns the streaming predicate with thenon-streaming validator,
hasValuableContent(), andensureStreamReadiness(), all ofwhich already treat bare
reasoningas real content. One-line, low-risk change —hasAnyReasoningSignal()already guards on non-empty strings, so no newfalse-positive risk from empty
reasoning: ""deltas.Regression test
tests/unit/issue-13620-combo-reasoning-only-sse-burst.test.ts— 3 tests:isKnownNonClaudeStreamPayload()recognizes baredelta.reasoning(root cause).to the first content delta (behavioral, counts physical stream chunks pulled).
finish_reason/[DONE]) isvalid: true, not rejected as an empty completion (secondary failure mode).RED (current release tip, before the fix):
GREEN (after the fix):
Note: the "behavioral" test's threshold is
<= 2physical chunks pulled rather thanexactly
1. The WHATWGReadableStreamspec itself speculatively pulls one extrachunk into its internal queue right after a
reader.read()resolves (defaulthighWaterMarkbackpressure refill), independent of application code — confirmed witha standalone repro against a plain
ReadableStream/Response. That prefetch isunrelated to the bug: the buggy code pulled 4-5 chunks (multiple logical reads inside
the peek loop), while the fixed code pulls at most 2 (one logical read + the engine's
own prefetch).
Gates run
npx eslint --suppressions-location config/quality/eslint-suppressions.json open-sse/utils/streamHelpers.ts tests/unit/issue-13620-combo-reasoning-only-sse-burst.test.ts— clean, exit 0.npm run check:open-sse-typecheck—openSseTypecheckErrors=0, OK (all within frozen baseline).node scripts/check/check-file-size.mjs— no violation on touched files (1 pre-existing violation onopen-sse/utils/stream.ts, a file this PR does not touch — confirmed identical line count onorigin/release/v3.8.51).node scripts/check/check-complexity.mjs— OK, 2824 violations vs baseline 3218 (no new violation).node scripts/check/check-cognitive-complexity.mjs— OK, 1276 violations vs baseline 1437 (no new violation).node scripts/check/check-test-discovery.mjs— OK, new test file discovered.DATA_DIR=$(mktemp -d) node --import tsx/esm --test --test-force-exit tests/unit/issue-13620-combo-reasoning-only-sse-burst.test.ts— 3/3 pass (RED→GREEN above).Existing tests aligned
None needed to change. Ran the existing coverage for the touched predicate/function to confirm no regression, all green:
tests/unit/combo-quality-validator-reasoning.test.ts— 16/16 pass (non-streaming reasoning acceptance, unaffected by this streaming-only change).tests/unit/combo-streaming-empty-completion-with-finish-reason-10404.test.ts— 2/2 pass (no-regression guard for thecontent-only/tool_calls-only truncation/empty-completion detection this PR shares a code path with).tests/unit/streamHelpers.test.ts— 35/35 pass (hasValuableContent(),unwrapGeminiChunk,appendBoundedText,hasActiveDeltaValue— none touched by this change).