Repository navigation
fix(stream): send full disable signals when thinking is off - #40
Conversation
The off path only sent `enable_thinking: false`, but goder's gateway still routes the reasoning model as reasoning-enabled because `model_config.is_reasoning` stayed `true`. qodercli disables thinking by emitting three signals together: `enable_thinking: false`, `reasoning effort: "none"`, and `is_reasoning: false`. Normalize every host's "off" signal into one `explicitlyOff` flag pi and OMP both omit `reasoning` (resolve "off" to `undefined`), OMP's fork additionally sets `disableReasoning` / `forceReasoningOff` - so off is never clamped back up to a concrete level, then emit all three disable signals consistently keyed off `reasoningLevel`.
…ed branch Live verification of #40 against the real gateway: models whose catalog has no disabled branch (e.g. Sonus, backed by an upstream that only accepts low/medium/high/xhigh/max) reject reasoning_effort "none" with a 400, and the omitted-reasoning path hits the same branch. Only send the effort signal when the catalog does not positively show the branch is missing (thinking_config efforts without disabled, or thinkingLevelMap off: null); enable_thinking:false and is_reasoning: false still go out, and models with a disabled branch are unchanged. Adds two regression tests seeding the model cache for both catalog shapes; Sonus no longer errors live and Ultimate still fully disables.
|
Hi @fredtanxo — thanks for this PR! It has been merged as-is (squash: Before cutting a release, I ran your change against the real Qoder gateway (a reasoning-bait prompt, thinking
I've landed a small follow-up on Two regression tests seeding the model cache for both catalog shapes were added alongside; the suite is at 367 passing and CI is green. This will ship in v0.6.3. Thanks again for the careful reverse-engineering and the thorough PR description — it made the live verification straightforward. |
Problem
Turning thinking off still leaves the model reasoning. The off path only sent
parameters.enable_thinking: false, but the request keptmodel_config.is_reasoning: true(andchat_context.extra.modelConfig.is_reasoning), so Qoder's gateway still routed the model as reasoning-enabled.@qoder-ai/qoderclidisables thinking with three signals together (reverse-engineered from its published bundle):i.e.
enable_thinking: false+reasoning_effort: "none"+is_reasoning: false.Fix
"off"toreasoning: undefined; OMP's fork additionally setsdisableReasoning/forceReasoningOff;false/"off"cover older hosts.clampThinkingLevelcould lift"off"to the model's lowest effort).reasoningLevel === undefined):enable_thinking: false, (reasoning_effort: "none",is_reasoning: false(bothchat_contextandmodel_config).Tests
Three regression cases assert the request body when thinking is off:
reasoning: 'off",disableReasoning: true(OMP), and omittedreasoning(pi's off signal).Notes
disableReasoning/forceReasoningOffare OMP-fork fields not present in@earendil-works/pi-ai'sSimpleStreamOptions; they are read through a type assertion, same as the existingreasoning !== false && reasoning !== "off"guard.disabledbranch (Kimi-K3, GLM-5.3, Sonus, Cantus, ...), off now still sendsreasoning_effort: "none". qodercli hides the "none" option for those models, so the gateway may accept or ignore it - but the request is at least self-consistent now, no longer "disable + is_reasoning: true".