Repository navigation
Forward the request's reasoning_effort to OpenAI-compatible providers - #185
Draft
adambalogh wants to merge 2 commits into
Draft
adambalogh wants to merge 2 commits into
adambalogh wants to merge 2 commits into
Conversation
Neither request carried a reasoning setting, so both ran at the
provider default: thinking on at effort "high". For V4 that is the
lowest effort there is (ModelArk only offers high/max), so a long
reasoning pass opened every reply. Off is the only way to tone it down.
A new registry flag, disable_thinking, becomes each provider's own off
switch: ModelArk `thinking: {"type": "disabled"}` (Flash) and OpenRouter
`reasoning: {"effort": "none"}` (Pro; reasoning is not mandatory on the
0813 slug and Phala lists `reasoning` as supported). A test pins the
flag to those two providers, since the others would silently ignore it.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SQvDLwdbHbxxCg4dGzeyh2
Replaces the disable_thinking registry flag: the request's own
reasoning_effort field (OpenAI's standard name) is now validated,
forwarded and signed, and the client decides per request. It is
translated once per provider, not per model:
- OpenAI, xAI, Z.ai, abliteration.ai, ModelArk: sent as-is (langchain
moves it into `reasoning` on the Responses API path).
- ModelArk "none": `thinking: {"type": "disabled"}` alone, since ModelArk
rejects reasoning_effort alongside it.
- OpenRouter: its `reasoning: {"effort": ...}` object.
- Anthropic, Google: not translated yet; the field is ignored.
Omitted sends nothing, so every existing request builds exactly as
before. An unknown value is a 400; a known value a model doesn't
support is the provider's 4xx, passed through. The field joins the
signed request hash only when sent, like aspect_ratio and resolution.
The OpenAPI enum (low/medium/high, default medium) would have refused
"none" at connexion's body validation, which the OHTTP inner request
also goes through; it now lists every accepted value and has no
default. The request model's own "medium" default is gone too, so an
unset field can never reach a provider or the hash.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SQvDLwdbHbxxCg4dGzeyh2
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.
Why
The gateway accepted a
reasoning_effortfield on chat requests but never sent it on to the provider, so every model ran at its provider's default. DeepSeek V4 thinks at efforthighby default and opened every reply with a long reasoning pass, and no client could turn that down.An earlier revision of this PR turned DeepSeek's thinking off with a per-model registry flag. This revision drops that flag: the client now chooses per request with the standard OpenAI field, and the gateway translates it once per provider, with no lists of models.
What
reasoning_effortis parsed, checked againstREASONING_EFFORTS(none,minimal,low,medium,high,xhigh,max; anything else is a 400) and passed toget_chat_model_cached, where it is part of the cache key.reasoning.effort."none": sendsthinking: {"type": "disabled"}instead, since ModelArk rejectsreasoning_effortalongside that switch.reasoning: {"effort": ...}. OpenRouter lists DeepSeek V4 Pro 0813 as acceptingnone/low/high/max, with reasoning not mandatory.lowon a model that only offershigh/max) comes back as the provider's 4xx, passed through unchanged.aspect_ratioandresolution.low/medium/high, defaultmedium) would have rejectednoneat connexion's body validation, which the OHTTP inner request also goes through. The enum now lists every accepted value and has no default. The request model's own"medium"default is removed too.Compatibility
A client that already sent
reasoning_effort(it was silently dropped until now) will see it reach the provider, and will find it in the signed request hash. A verifier that rebuilds the canonical request on its own has to add the field when it sends it. chat-app does that in its companion PR.Testing
pytest tee_gateway/test/ tests/test_pricing.py tests/test_opengradient_field.py: 512 passednonevs a level, OpenRouter, OpenAI) and omitted → nothing sent;"none"passes schema validation. Run against the oldopenapi.yaml, this test fails.ruff check,ruff format --check,mypy: cleanreasoning_effort: "none"should come back withreasoning_tokens: 0.Needs a new enclave image and PCR measurements and a redeploy. Deploy this before any client starts sending the field: an old gateway leaves it out of the signed hash, so a client that includes it would fail verification.
🤖 Generated with Claude Code
https://claude.ai/code/session_01SQvDLwdbHbxxCg4dGzeyh2