Skip to content

fix(reasoning): preserve mixed plaintext and drop incompatible state (#10949, #10959) - #10961

Merged
diegosouzapw merged 86 commits into
cheaper-inference:release/v3.8.50from
jackjinke:fix/10949-mixed-reasoning-plaintext
Aug 23, 2026
Merged

diegosouzapw merged 86 commits into
cheaper-inference:release/v3.8.50from
jackjinke:fix/10949-mixed-reasoning-plaintext

Conversation

@jackjinke

@jackjinke jackjinke commented Aug 21, 2026 •

Copy link
Copy Markdown
Contributor

Summary

OpenCode Go can return a single Responses API reasoning item that contains both explicit plaintext (content[].type === "reasoning_text") and non-empty opaque state (encrypted_content). The extractor treated any opaque companion as a veto and dropped the portable plaintext, so the next DeepSeek tool-call continuation failed with:

400: The `reasoning_text` in the thinking mode must be passed back to the API.

Opaque-only reasoning from a previous provider could also hard-fail a direct cross-model replay instead of being dropped when the selected target could not transport it.

Fixes #10949 and #10959. Related: #10550, #10574.

Change

  • extractReplayableResponsesReasoningText() (open-sse/services/reasoningInputPolicy.ts): explicit plaintext now wins over a coexisting opaque companion; opaque-only items are still never converted or exposed.
  • applyReasoningInputPolicy(): mixed input is projected onto the target transport, and incompatible reasoning is dropped by default. Combos retain the explicit Skip strategy to fall through without mutating the request.
  • Responses → Chat request translator: mixed items replay their plaintext companion; opaque-only items are dropped instead of throwing.
  • Combo advanced settings retain Drop/Skip, with Drop as the default and without the warning text.

Test Plan

New regressions:

  • Non-streaming extraction: mixed item preserves reasoning_content and caches for replay (tests/unit/reasoning-cache.test.ts)
  • Streaming response.output_item.done: mixed item replays plaintext; opaque-only still emits nothing fabricated (tests/unit/translator-resp-openai-responses.test.ts)
  • Policy projection: mixed input follows the target transport instead of rejecting, both directions (tests/unit/strip-reasoning-blobs-agentic-context-1599.test.ts)
  • Request translator: mixed item replays its plaintext companion (tests/unit/translator-openai-responses-req.test.ts)
  • Direct Responses and Chat replay drops incompatible opaque reasoning by default; Combo Skip still rejects the attempt for target fallthrough (tests/unit/chatcore-translation-paths.test.ts)

Legacy tests locking in the old direct mixed/opaque rejection behavior were flipped to the new contract.

Commands run:

# focused suites (all green)
npx cross-env DISABLE_SQLITE_AUTO_BACKUP=true node --import tsx/esm --import ./open-sse/utils/setupPolyfill.ts --import ./tests/_setup/isolateDataDir.ts --test --test-force-exit --test-concurrency=1 \
  tests/unit/reasoning-cache.test.ts \
  tests/unit/strip-reasoning-blobs-agentic-context-1599.test.ts \
  tests/unit/translator-resp-openai-responses.test.ts \
  tests/unit/translator-openai-responses-req.test.ts
# plus chatcore/combo/translator neighbor suites (all green)

# #10959 follow-up: 155 pass
npx cross-env DISABLE_SQLITE_AUTO_BACKUP=true node --import tsx/esm --import ./open-sse/utils/setupPolyfill.ts --import ./tests/_setup/isolateDataDir.ts --test --test-force-exit --test-concurrency=1 tests/unit/strip-reasoning-blobs-agentic-context-1599.test.ts tests/unit/translator-openai-responses-req.test.ts tests/unit/chatcore-translation-paths.test.ts tests/unit/combo-attempt-body-isolation-7847.test.ts

# full gate, excluding tests/unit/cli-serve-stop-command.test.ts per ~/OMNIROUTE_TESTS_SKIP_20128.txt
npm run test:coverage

Final coverage result (gate requires ≥60% each):

Metric Result
Statements 84.02%
Branches 79.06%
Functions 87.25%
Lines 84.02%

Note: two pre-existing failures in vision-bridge-maxchars.test.ts / vision-compression-authoritative-capability-7237.test.ts are unrelated to this change (vision modality bridge settings, untouched here); coverage gate passed regardless.

@jackjinke
jackjinke force-pushed the fix/10949-mixed-reasoning-plaintext branch from 5eea5fa to cae3135 Compare August 21, 2026 08:15
@jackjinke
jackjinke marked this pull request as ready for review August 21, 2026 08:22
@jackjinke
jackjinke force-pushed the fix/10949-mixed-reasoning-plaintext branch 4 times, most recently from c79a471 to 1f18c4b Compare August 21, 2026 14:10
@jackjinke jackjinke changed the title fix(reasoning): preserve plaintext from mixed reasoning items (#10949) fix(reasoning): preserve mixed plaintext and drop incompatible state (#10949, #10959) Aug 21, 2026
…r-inference#10949)

OpenCode Go can return a single Responses reasoning item containing both
explicit reasoning_text and non-empty encrypted_content. The extractor
treated any opaque companion as a veto and dropped the portable plaintext,
so DeepSeek continuations failed with 400 (reasoning_text must be passed
back).

- extractReplayableResponsesReasoningText: explicit plaintext wins over a
  coexisting opaque companion; opaque-only items are still never converted
- applyReasoningInputPolicy: mixed plaintext + opaque input is projected
  onto the target transport instead of rejected (plaintext targets keep
  the text, opaque targets keep provider state)
- Responses -> Chat request translator: only opaque-only items throw;
  mixed items replay their plaintext companion

Regressions cover non-streaming extraction, streaming output_item.done,
and per-target projection. Legacy mixed-rejection tests flipped to the
new contract.
@jackjinke
jackjinke force-pushed the fix/10949-mixed-reasoning-plaintext branch from ae55845 to b8e4e88 Compare August 21, 2026 18:14
@diegosouzapw

Copy link
Copy Markdown
Collaborator

Nice, tightly-scoped fix. I verified the mixed plaintext+opaque projection and the new drop-by-default flow: the reasoning tests pass locally (strip-reasoning 16/16, reasoning-cache + both Responses translators 140/140, and chatcore-translation-paths 75/75 on a clean run). One optional nit: the docstring on extractReplayableResponsesReasoningText (open-sse/services/reasoningInputPolicy.ts, before line 94) still says "a record carrying opaque state is never cross-converted," which now contradicts the #10949 behavior you're shipping (mixed plaintext IS projected and replayed). Consider rewording the first sentence so future readers don't misread the intent. No mandatory items from my review.

diegosouzapw and others added 18 commits August 21, 2026 20:27
…form signal (cheaper-inference#10028) (cheaper-inference#11068)

⭐5 — Fix do dono com TDD. Estado committed+pushed limpo (hold-vivo cedido por instrução direta do operador).
…heaper-inference#10990) (cheaper-inference#11066)

⭐5 — Fix do dono com TDD. Estado committed+pushed limpo (hold-vivo cedido por instrução direta do operador).
…ndpoint (cheaper-inference#11002) (cheaper-inference#11065)

⭐5 — Fix do dono com TDD. Estado committed+pushed limpo (hold-vivo cedido por instrução direta do operador).
…form no longer forces a fake API key (cheaper-inference#8864) (cheaper-inference#11064)

⭐5 — Fix do dono com TDD. Estado committed+pushed limpo (hold-vivo cedido por instrução direta do operador).
…ext-delta (cheaper-inference#10986) (cheaper-inference#11063)

⭐5 — Fix do dono com TDD. Estado committed+pushed limpo (hold-vivo cedido por instrução direta do operador).
…aper-inference#9123) (cheaper-inference#11062)

⭐5 — Fix do dono com TDD. Estado committed+pushed limpo (hold-vivo cedido por instrução direta do operador).
…rts to stop order-dependent flake (cheaper-inference#10523) (cheaper-inference#11061)

⭐5 — Fix do dono com TDD. Estado committed+pushed limpo (hold-vivo cedido por instrução direta do operador).
…ngs) (cheaper-inference#11040)

⭐5 — Fecha 11 achados restantes das advisories de segurança do v3.8.50 (batch 2), TDD. UNSTABLE é o base-red cheaper-inference#9985 já rastreado.
…provider docs, orphaned suppressions (cheaper-inference#11038)

⭐5 — Drain de base-reds v3.8.50 (cheaper-inference#9985): corrige build-break do cheaper-inference#10939 (import fantasma @/lib/db/connections → reroteado por getProviderConnectionById real), headers Anthropic no fallback GLM, fallthrough do reject de listing CC-compatible, no-auth leak no auto-combo, retry de mesmo-account nos combo live tests, pin onnxruntime-node ~1.24.3; + alignments de teste + gates (env-doc, docs-counts 347→348, openapi floor, i18n vi/pt-BR).

Reconciliado com o tip: 5 conflitos de contagem gerada (SVGs + PROVIDER_REFERENCE — HEAD já em 348, branch em 347 stale) resolvidos ficando com o HEAD. typecheck limpo, gates verdes, 5/5 testes focados (cheaper-inference#10939 regressão + utilização), lint limpo nos tocados.

Também rebaselined neste turno via push direto ao tip: config/quality/file-size-baseline.json modelCapabilities.ts 1016→1072 (drift de PRs ja mergeadas, ex: cheaper-inference#11034), com changelog fragment — tip estava vermelho nesse gate e travava esta PR.
… alias (cheaper-inference#11047)

⭐5 — OpencodeExecutor buscava targetFormat com o id bruto do provider em vez do alias público ("oc"), caindo em default openai → corpo Responses no URL chat/completions (400). resolveOpencodeTargetFormat resolve via PROVIDER_ID_TO_ALIAS. TDD 4/4 + 32/32 irmãos, lint/tsc limpos. Fecha cheaper-inference#11046. Base-red cheaper-inference#9985 inherited.
… collisions (cheaper-inference#11043)

⭐5 — Providers que não bumpam index/id em tool calls repetidas do mesmo nome colam N arguments JSON num só ({...}{...}{...}); leitores a jusante pegam só o primeiro e dropam o resto em silêncio. Detecta N objetos concatenados e divide de volta em N tool_calls. TDD 20/20 + 86/86 irmãos. Fecha cheaper-inference#11044. Base-red cheaper-inference#9985 inherited.
…per-inference#11050)

⭐5 — Remove 3 webhook events declarados mas nunca emitidos (provider.error/recovered, combo.switched): union 7→4, z.enum com 400 em ghost values (era z.string pass-through). Breaking intencional + testado. TDD 3/3, i18n B-pattern (42 __MISSING__). Base-red cheaper-inference#9985 inherited.
… too (cheaper-inference#11049)

⭐5 — Muse Spark responde só na Responses API; cheaper-inference#10874 corrigiu só o provider `opencode`, mas `opencode-zen` (faltava targetFormat em 2 entries) e `opencode-go` (6 entries effort-tier) nunca receberam. Espelha a declaração. freebuff NÃO tocado (backend codebuff.com /chat/completions distinto, verificado). TDD 2/2 + 18/18 irmãos. Fecha cheaper-inference#11048. Base-red cheaper-inference#9985 inherited.
…entries (cheaper-inference#11051)

⭐5 — Dedupe dos 3 entries byte-idênticos (kimi-k2.7-code, qwen3.5-plus, qwen3.6-plus) entre opencode-zen e opencode-go via OPENCODE_ZEN_GO_SHARED_MODELS (padrão GLM_SHARED_MODELS), frozen e testado por deep-equal. Pure move, sem mudança de comportamento; check:provider-consistency OK (267 entries, 348 providers). TDD 3/3. Follow-up de cheaper-inference#11049/cheaper-inference#11048. Base-red cheaper-inference#9985 inherited.
…e bind (cheaper-inference#11059)

⭐5 — LIMIT negativo = "sem limite" no SQLite: ?limit=-1 retornava a leaderboard inteira em endpoint management autenticado; ceil por Math.min só no upper. Duas camadas: route rejeita não-inteiro/fora de range com 400 (mesmo contrato de parseListLimit), getTopN clampeia como backstop defense-in-depth + exporta LEADERBOARD_MAX_LIMIT. TDD red→green, 5 casos novos, 84/84 suíte gamification. Fecha cheaper-inference#11058.
…chema_version seed (cheaper-inference#10906)

⭐5 — Preenche os 3 test.skip com asserções reais (resetDbInstance troca o singleton preservando a linha no disco, journal_mode WAL, schema_version=1). Além do valor pretendido, o autor redesenhou o setup()/cleanup() do arquivo corrigindo um bug de isolamento pré-existente que eu apontei em review: DATA_DIR/SQLITE_FILE são const de topo de módulo; o cleanup() usava require() CJS que nunca resetava a instância ESM-importada, então os testes 1-4 passavam "por acidente" contra a conexão nunca fechada. Agora: tempDir compartilhado definido antes do primeiro import, resetDbInstance importado via ESM uma vez, handle fechado antes de cada reopen, e o catch{} silencioso removido. 7/7 verdes no arquivo inteiro.
…verwrite (cheaper-inference#11033) (cheaper-inference#11067)

⭐5 — computeConnectionDefaultName aceita array de nomes existentes e acha o próximo não-conflitante, evitando overwrite de nome de conexão. TDD. Fecha cheaper-inference#11033.
rqzbeh and others added 24 commits August 22, 2026 20:13
…dal Enter handler (cheaper-inference#10995) (cheaper-inference#11156)

Cherry-picked onto the current tip (authorship preserved), generated-count noise stripped. Pre-merge: file-size baseline rebaselined 1080→1082 with dated annotation (the +2 lines are the Enter-handler isCheckDisabled mirror — owner-requested cheaper-inference#11056 polish; rest is Prettier reflow). Gate green; vitest add-api-key-modal-enter-key 2/2 (jsdom render test). Thank you @rqzbeh!
… oauth start (cheaper-inference#11164) (cheaper-inference#11173)

Cherry-picked onto the current tip (authorship preserved), noise stripped. Focused: oauth-device-flow-11164 green + 9474-claude-code-oauth-mismap neighbor suite green. Device-code endpoint is tried first, camelCase/snake_case fallbacks normalized, no more blank code / 'Visit: undefined'. Fixes cheaper-inference#11164. Thank you @rqzbeh!
… providers (cheaper-inference#11100) (cheaper-inference#11155)

Cherry-picked onto the current tip (authorship preserved), generated-count noise stripped. Two pre-merge adjustments: (1) dropped the unrelated localDb.ts re-export hunk (nothing in this PR uses those symbols); (2) automated security review flagged the blocked-provider list resolving once at server creation — the handler now rebuilds the schema per invocation via the resolver (advertised tools/list schema stays a creation-time snapshot, which is inherent to MCP). Vitest: new runtime-blocked-schema suite 3/3, full MCP __tests__ 118/118; contract suites (mcp-web-search-provider-enum-contract, search-blocked-providers-11100) 6/6; typecheck clean. This closes the residual gap noted when cheaper-inference#11120 was closed. Thank you @rqzbeh!
…antiation (cheaper-inference#11039) (cheaper-inference#11163)

Cherry-picked onto the current tip (authorship preserved), noise stripped. Validated on BOTH runtimes: bun test tests/unit/db-adapters/ 44/44 under the pinned Bun 1.3.14 (native bun:sqlite path), and node --test on the same suite 52 pass / 0 fail / 1 skip (Bun-only adapter skips under Node, as designed). Dockerfile.bun entrypoint now matches the standalone runner shape. Follow-up to cheaper-inference#11039. Thank you @rqzbeh!
…workflow (cheaper-inference#11039) (cheaper-inference#11168)

Cherry-picked onto the current tip (authorship preserved, Dockerfile.bun conflict with the just-merged cheaper-inference#11163 resolved additively — runner-web stage after the new entrypoint). Three pre-merge fixes on the branch: (1) generated-count noise stripped; (2) runner-web stage now returns to the non-root bun user after the apt install (mirrors the Node Dockerfile runner-web re-asserting USER node — the stage previously ended as root); (3) the 6 new build/manifest steps SHA-pinned so the zizmor ratchet stays at 191<=192 findings instead of regressing to 197 (actionlint clean). Workflow YAML parses; runner-base/runner-web targets cross-checked against the Dockerfile stages. Thank you @rqzbeh!
…nference#11122) (cheaper-inference#11154)

Validated on a worktree over the current tip: the red it fixes reproduced exactly as described (media-page-client-browser-bundle red since cheaper-inference#11122 — providerRegistry became reachable from the dashboard client bundle via node:net). Post-fix: bundle test 2/2 green, new ip-parity suite + is-local-provider 7/7, all 7 outboundUrlGuard consumer suites 76/76 (the moved normalizeHost/isPrivateHost keep their re-exports; routing behavior untouched). Thank you @yourspraveen — clean surgical extraction with a pure-JS ipVersion mirroring Node's own regexes.
… test (cheaper-inference#11160)

Validated against code before merge: 159 migration files on disk, 56 free-forever (Hack Club removal), 40 pools — counts verified, not trusted. check:docs-counts exit 0 (HARD failures drained; the 2 remaining soft executors-count notes are pre-existing on the tip) and check:test-discovery OK (orphan moved into the collected tree). These reds came from cheaper-inference#11103/cheaper-inference#11123 merging without the count regen — thanks for sweeping them @yourspraveen!
…-inference#11071) (cheaper-inference#11165)

Validated on a worktree over the current tip: account-fallback-service 91/91 plus the five sibling lockout suites 24/24. The measurement in the body (40 of 111 passthroughModels providers uncovered on this branch) is the clincher — one lookup via getProviderById().passthroughModels beside the existing checks, closing the cheaper-inference#11071 remainder for shared-registry gateways (port of cheaper-inference#11075 which had only landed on main). Thank you @yourspraveen!
… confirmed) (cheaper-inference#11114)

Validated on the combined batch board over tip 92ef3c7: static gates clean (changelog, file-size, complexity 2624<=2774, cognitive 1182<=1223, dead-code 411<=416), typecheck:core clean, focused tests green.

Companion to cheaper-inference#11113 (consumer side): tokenrouter joins BUILTIN_PROVIDERS_SYSTEM_MUST_BE_FIRST — memory-system-first-6135 suite green. Live-confirmed 400 class documented in the body. Thank you @ggdayup!
…inference#11162)

Validated on the combined batch board over tip 92ef3c7: static gates clean (changelog, file-size, complexity 2624<=2774, cognitive 1182<=1223, dead-code 411<=416), typecheck:core clean, focused tests green.

Combo without models is now refused at the schema boundary (API 400), the CLI flags it, and openapi.yaml matches the real contract (phantom props removed). combo-* suites + cli-combo-create-models green on the board. Closes cheaper-inference#10954. Thank you @maxmad64bis!
…e) (cheaper-inference#11158)

Validated on the combined batch board over tip 92ef3c7: static gates clean (changelog, file-size, complexity 2624<=2774, cognitive 1182<=1223, dead-code 411<=416), typecheck:core clean, focused tests green.

Empty-envelope 400 (no error field, empty content, finish_reason null) now rotates/retries instead of propagating as success; 200/streaming path never buffered; real-error 400s untouched. account-rotation + new rotation suite 34/34 on the board. Thank you @maxmad64bis!
…stem message (cheaper-inference#11113)

Validated on the combined batch board: purify-system-first suite 4/4, typecheck clean. Pre-merge: file-size baseline gained a frozen entry for contextManager.ts at 1001 (+1, this PR's merge-into-leading-system branch) with a dated annotation — the gate caps unlisted files at 1000. Producer side of the live-confirmed TokenRouter 400 class: no internal path emits a mid-array system message anymore. Thank you @ggdayup — the call-log evidence made this airtight!
…ly output (cheaper-inference#11151)

Merged after conflict resolution against the tip's cheaper-inference#11109 (per-call tool_call tracking): scanOpenAiSseText keeps the per-call finish_reason special-case AND gains reasoningText + literal finishReason; canContinue uses the in-flight predicate with the new reasoning-only-clean-stop escape. One integration fix on the branch: the PR's hallucinatedEmptyStop referenced emittedToolCall, which cheaper-inference#11109 had renamed — the branch now tracks emittedSawToolCall at the emitted level (any tool_call delta, complete or not), preserving the PR's don't-recover-after-tool-calls intent. Chain suites green: stream-continuation-wiring + stream-continuation + stream-recovery-toolcall 29/29. Thank you @maxmad64bis!
…f concatenating it raw (cheaper-inference#11152)

Merged after sibling cheaper-inference#11151 landed: streamRecovery.ts auto-merged byte-identical to the validated combined board; the test-file conflict (both PRs added suites at the same anchor) resolved keeping all 11 tests — cheaper-inference#11151's four clean-stop cases plus this PR's three threshold cases, with the PR's updated partial-tail fixture for the pre-existing overlap test. Full chain green: 32/32 (wiring + continuation + toolcall regression). The documented 8-char overlap threshold ends the silent mid-word gluing. Thank you @maxmad64bis!
cheaper-inference#11190)

* feat(api): structured ?format=json for the self-service usage endpoint

GET /api/usage/om-usage already let any key read its own usage — personal
daily/weekly USD limits and the provider quota snapshot — but only as
text/plain, which a UI cannot parse safely. OmniCopilot issue cheaper-inference#8 asks exactly
for this surface.

Adds ?format=json, returning the ApiKeyUsageLimitStatus + UsageSnapshot the
text is rendered from. Text and JSON share the same collectors
(collectUsageSnapshots, getApiKeyUsageLimitStatus), so the two can never
disagree about a number. The response is a discriminated union: a key without
allowUsageCommand (403) or an invalid key (401) returns
{ allowed:false, error:{message} }, distinct from allowed:true with empty
sections — the state a panel must render as "nothing learned yet", not a
refusal. Text form unchanged; without ?format the contract is untouched.

The endpoint was previously missing from API_REFERENCE.md; it now has a
section documenting both forms, the allowUsageCommand gate, and the
self-service auth model (caller's own key, not requireManagementAuth).

Regression guards in tests/unit/usage-command-json-format.test.ts (4 tests:
json shape, text default preserved, structured 403, sanitized 401 with no
stack trace). Existing internal-usage-command suite still 12/12.

* chore(changelog): correct the fragment to the real PR number (cheaper-inference#11190)

---------

Co-authored-by: Xiangzhe <bakryun0718@proton.me>
…-usage json (cheaper-inference#11192)

* feat(api): structured ?format=json for the self-service usage endpoint

GET /api/usage/om-usage already let any key read its own usage — personal
daily/weekly USD limits and the provider quota snapshot — but only as
text/plain, which a UI cannot parse safely. OmniCopilot issue cheaper-inference#8 asks exactly
for this surface.

Adds ?format=json, returning the ApiKeyUsageLimitStatus + UsageSnapshot the
text is rendered from. Text and JSON share the same collectors
(collectUsageSnapshots, getApiKeyUsageLimitStatus), so the two can never
disagree about a number. The response is a discriminated union: a key without
allowUsageCommand (403) or an invalid key (401) returns
{ allowed:false, error:{message} }, distinct from allowed:true with empty
sections — the state a panel must render as "nothing learned yet", not a
refusal. Text form unchanged; without ?format the contract is untouched.

The endpoint was previously missing from API_REFERENCE.md; it now has a
section documenting both forms, the allowUsageCommand gate, and the
self-service auth model (caller's own key, not requireManagementAuth).

Regression guards in tests/unit/usage-command-json-format.test.ts (4 tests:
json shape, text default preserved, structured 403, sanitized 401 with no
stack trace). Existing internal-usage-command suite still 12/12.

* chore(changelog): correct the fragment to the real PR number (cheaper-inference#11190)

* feat(api): return every connection's snapshot under providers[] in om-usage json

Closes cheaper-inference#11191. buildUsageCommandJson picked a single snapshot via selectUsageSnapshot, so a panel could only ever show one provider. The collector already had them all — the single-pick is a presentation choice for a terminal. The JSON form now also returns the full UsageSnapshot[] alongside the selected provider, so a UI can render Codex / Claude / OpenCode side by side. The text form is untouched.

---------

Co-authored-by: Xiangzhe <bakryun0718@proton.me>
… links through the shortener (cheaper-inference#11196)

- New CheaperInferenceSponsorBanner on the dashboard home, same size/shape as
  KimiSponsorBanner, no version gate (durable partnership). Uses the
  cheaperinference ProviderIcon and the brand green (#31f889) with the dark
  ink CTA (contrast, per colors.ts token).
- CTA points at https://link.omniroute.online/cheaper — the branded short
  link — so clicks land in our Kutt metrics.
- VscodeCopilotBanner CTA now points at https://link.omniroute.online/vsx
  instead of the raw Marketplace URL, for the same reason.
- i18n strings in en + pt (en is the namespace-level fallback for the other
  41 locales).
- Tests: new cheaperInferenceSponsorBanner.test.tsx (render, CTA href, dismiss
  persistence); vscodeCopilotBanner.test.tsx updated to the new CTA URL.

Co-authored-by: Xiangzhe <bakryun0718@proton.me>
… response quality validation (cheaper-inference#11036)

SSE comment lines (OpenRouter keep-alives) and leading whitespace no longer fail the combo quality gate's JSON fallback. First contribution — clean minimal fix with test. Thank you @asorourx, welcome aboard!
…rence#11041)

Compaction-V2 output now counts as real model output (no synthetic response.failed after response.completed), the Codex SSE filter handles CRLF framing, and terminal detection runs before scan-state bounding. 88/88 stream/readiness suites on the board. Thank you @jackjinke!
…11020)

Validated on the combined batch board + this branch alone: chat-body-admission + authz/pipeline 65/65, file-size gate green with a dated frozen entry (chatBodyAdmission 1005→1009 — the +4 lease/drain wiring lines, owner-authorized rebaseline). trackRequest was never called, so SIGTERM waitForDrain saw zero in-flight and killed live SSE; leases now hold the drain counter for the stream's lifetime, and the 503 carries Retry-After. Closes cheaper-inference#11015. Thank you @RaviTharuma!
… retrieve tool (cheaper-inference#11084)

Validated on the combined batch board + this branch: ccr-non-mcp-full-prompt-loss + ccr-retrieval-ramp 20/20, file-size gate green with the ccr/index listing (1024, dated annotation — owner-authorized). The callerSupportsCcrRetrieve gate now skips the whole engine for callers whose tools[] cannot reach omniroute_ccr_retrieve — no more 15KB prompt arriving upstream as 112 tokens. Production-measured root cause, textbook TDD. Thank you @HouMinXi!
…0963)

Merged after conflict resolution in modelMetadataRegistry.ts: the tip's effortTiers chain (declared efforts → declared tiers → undefined-if-thinking-declared → codex extension) now carries this PR's GLM guard as the final-fallback override — GLM-family models without a provider-declared contract get the authoritative empty tier list instead of generic OpenAI tiers. GLM/ZCode suites 40/40 on the resolved branch. Closes cheaper-inference#10962. Thank you @xz-dev!
@diegosouzapw
diegosouzapw merged commit 9689dce into cheaper-inference:release/v3.8.50 Aug 23, 2026
4 of 7 checks passed
diegosouzapw pushed a commit to adevwithpurpose/OmniRoute that referenced this pull request Aug 23, 2026
diegosouzapw pushed a commit that referenced this pull request Aug 23, 2026
…entic replay (#10959) (#11178)

Merged after conflict resolution onto the post-#10961 tip (verified no clobber of today's plaintext-wins work — the resolver functions were appended and the chatCore call-site swapped; a first --theirs attempt was caught reverting #10961 and redone hunk-by-hunk). resolveIncompatibleReasoningAction now defaults single-target incompatible reasoning to drop while combos keep their explicit strategy, with the x-omniroute-reasoning-fallback header override. 21/21 reasoning suites green, typecheck clean. Fixes #10959. Thank you @adevwithpurpose!
muhamadgalihsaputra pushed a commit to niyatna/NiyatnaRoute that referenced this pull request Sep 27, 2026
…heaper-inference#10949, cheaper-inference#10959) (cheaper-inference#10961)

Validated on the combined batch board + this branch: 231/231 across chatcore-translation-paths, reasoning-cache, strip-reasoning-blobs, and both Responses translator suites. Pre-merge: propagated the cheaper-inference#11110/cheaper-inference#11129 summary:[] defaults into five assertions here (each commented with its PR) — without it this branch red against the tip, and as a bonus the merge drains the 4 reasoning reds that were live on the tip from those merges. Plaintext now wins over a coexisting opaque companion; opaque-only drops cleanly for plaintext targets; combos keep explicit Skip. Fixes cheaper-inference#10949 and cheaper-inference#10959. Thank you @jackjinke!
muhamadgalihsaputra pushed a commit to niyatna/NiyatnaRoute that referenced this pull request Sep 27, 2026
…entic replay (cheaper-inference#10959) (cheaper-inference#11178)

Merged after conflict resolution onto the post-cheaper-inference#10961 tip (verified no clobber of today's plaintext-wins work — the resolver functions were appended and the chatCore call-site swapped; a first --theirs attempt was caught reverting cheaper-inference#10961 and redone hunk-by-hunk). resolveIncompatibleReasoningAction now defaults single-target incompatible reasoning to drop while combos keep their explicit strategy, with the x-omniroute-reasoning-fallback header override. 21/21 reasoning suites green, typecheck clean. Fixes cheaper-inference#10959. Thank you @adevwithpurpose!
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.

[BUG] OpenCode Go mixed reasoning item drops plaintext continuation