Repository navigation
fix!: send reasoning_effort as reasoning.effort on flex Responses requests - #54
Merged
Merged
Conversation
…uests
Flex text calls are submitted to /v1/responses. responses.create(reasoning_effort=...)
was forwarded as a top-level reasoning_effort, and extra_body thinking fields
(chat_template_kwargs, thinking, thinking_token_budget) were forwarded as-is.
Doubleword ignores these on /v1/responses today and will refuse them with a 400.
Map reasoning_effort into reasoning.effort (merging with any other reasoning
fields, and refusing a conflicting reasoning.effort), and raise a ValueError /
Error naming the field for the native thinking fields on both the chat and
Responses flex paths. Same change in the Python and TypeScript SDKs.
BREAKING CHANGE: flex chat.completions.create and responses.create now raise
before submitting when the request carries chat_template_kwargs, thinking or
thinking_token_budget, or a reasoning_effort that conflicts with
reasoning.effort. These were previously sent and silently ignored. Use
reasoning_effort (chat) or reasoning={"effort": ...} (Responses) instead.
Crown421
force-pushed
the
claude/flex-reasoning-effort-33dcc6
branch
from
October 21, 2026 15:24
054cdf9 to
b51b6a0
Compare
Merged
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.
What
Since 0.11.0 (#48), text calls without
completion_window="24h"go to flex/v1/responses. Two kinds of reasoning control were forwarded in a shape that/v1/responsesdoesn't accept:responses.create(reasoning_effort=...), top-level or inextra_body, went out as a top-levelreasoning_effort. A test asserted this as a supported extension.chat_template_kwargs,thinkingandthinking_token_budgetinextra_bodywere copied onto the Responses request from bothchat.completions.createandresponses.create.Today the gateway ignores these on
/v1/responses, so the caller's reasoning setting is silently lost. control-layer#1999 (DW-974) makes the gateway refuse all four with400 unsupported_parameter("use 'reasoning.effort'"). The refused list comes fromonwards/src/reasoning.rs(ApiSurface::Responses).Change (Python and TypeScript, same behaviour)
reasoning_efforton the Responses flex path now becomesreasoning: {"effort": ...}. It merges with otherreasoningfields (e.g.summary). Ifreasoning.effortis also set to a different value, the call raises instead of picking one. Chat calls already mappedreasoning_effortthis way. A new end-to-end test covers that.chat_template_kwargs,thinkingandthinking_token_budgetnow raise client-side (ValueError/Error) before anything is submitted. The error names the field and points toreasoning_effort(chat) orreasoning={"effort": ...}(Responses).Why raise, not translate
Mapping
enable_thinking: falsetoreasoning.effort: "none"would be faithful for that one key.chat_template_kwargscan hold arbitrary template keys, though, andthinking/thinking_token_budgethave no exactreasoning.effortequivalent. Translating only some of them means guessing effort levels, which changes behaviour silently. Raising is simpler and matches the gateway everywhere else:/v1/chat/completionsalready returns a 400 for these fields;The difference is that the error comes before a background job is created, and it names the replacement. Callers who already use
reasoning_effortare unaffected.The 24h batch path is unchanged.
Breaking change
Flex calls (any text call without
completion_window="24h") now raise before submitting in two cases:chat_template_kwargs,thinkingorthinking_token_budget;reasoning_effortconflicts withreasoning.effort.Before this change, these requests were sent and the fields were silently ignored. After control-layer#1999 they'd fail with a 400 anyway.
bump-minor-pre-majoris set, so release-please bumps the minor version: Python 0.12.0 and TypeScript 0.7.0.Tests
python/tests/test_flex_polling.py):reasoning_effortinextra_bodynow checks that the other extensions still go throughextra_body.TestFlexReasoningControls, using publiccreate()with only the upstreamresponses.createmocked:extra_bodyand mergedreasoning_effortall becomereasoning;reasoning.effortraises;reasoning_effortreaches the submitted Responses request asreasoning.effort.typescript/test/client.test.ts): the same cases.Run locally:
pytest tests/test_flex_polling.py tests/test_responses.py: 59 passed (Python 3.11, openai latest).ty check: clean.npm test: 57 passed.npm run typecheck: clean.Python 3.12 and the openai-version matrix are left to CI.
Known follow-ups (not in this PR; tracked in DW-981)
descriptionget a 400. dwctl's Responses tool type requiresdescription: String(dwctl/src/inference/translation/responses/types.rs:557), but Chat Completions accepts tools without one. This is the default path for the PydanticAI, Agno, Microsoft Agent Framework, Agents SDK and Arize recipes. Confirmed in source, not run against a gateway.cache_controlon content parts and assistantreasoning_contenton the flex path. Neither translator references them. As a result, thecache_controloption onChatDoublewordAsync/DoublewordLLMAsynchas no effect, and interleaved reasoning isn't replayed on tool turns.BatchOpenAI()withoutcompletion_window="24h""submits batch jobs", but it runs as flex. This came from a docs read on 21 Oct; I didn't re-check it here.