mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-08 19:18:26 +00:00
fix: don't inject reasoning: { effort: "none" } for OpenRouter when thinking is off
"off" is a truthy string, so the existing guard `if (thinkingLevel && ...)`
was always entering the injection block and sending `reasoning: { effort: "none" }`
to every OpenRouter request — even when thinking wasn't enabled. Models that
require reasoning (e.g. deepseek/deepseek-r1) reject this with:
400 Reasoning is mandatory for this endpoint and cannot be disabled.
Fix: skip the reasoning injection entirely when thinkingLevel is "off".
The reasoning_effort flat-field cleanup still runs. Omitting the reasoning
field lets each model use its own default behavior.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
committed by
Peter Steinberger
parent
69a541c3f0
commit
3e974dc93f
@@ -435,24 +435,31 @@ function createOpenRouterWrapper(
|
||||
// only the nested one is sent.
|
||||
delete payloadObj.reasoning_effort;
|
||||
|
||||
const existingReasoning = payloadObj.reasoning;
|
||||
// When thinking is "off", do not inject reasoning at all.
|
||||
// Some models (e.g. deepseek/deepseek-r1) require reasoning and reject
|
||||
// { effort: "none" } with "Reasoning is mandatory for this endpoint and
|
||||
// cannot be disabled." Omitting the field lets each model use its own
|
||||
// default reasoning behavior.
|
||||
if (thinkingLevel !== "off") {
|
||||
const existingReasoning = payloadObj.reasoning;
|
||||
|
||||
// OpenRouter treats reasoning.effort and reasoning.max_tokens as
|
||||
// alternative controls. If max_tokens is already present, do not
|
||||
// inject effort and do not overwrite caller-supplied reasoning.
|
||||
if (
|
||||
existingReasoning &&
|
||||
typeof existingReasoning === "object" &&
|
||||
!Array.isArray(existingReasoning)
|
||||
) {
|
||||
const reasoningObj = existingReasoning as Record<string, unknown>;
|
||||
if (!("max_tokens" in reasoningObj) && !("effort" in reasoningObj)) {
|
||||
reasoningObj.effort = mapThinkingLevelToOpenRouterReasoningEffort(thinkingLevel);
|
||||
// OpenRouter treats reasoning.effort and reasoning.max_tokens as
|
||||
// alternative controls. If max_tokens is already present, do not
|
||||
// inject effort and do not overwrite caller-supplied reasoning.
|
||||
if (
|
||||
existingReasoning &&
|
||||
typeof existingReasoning === "object" &&
|
||||
!Array.isArray(existingReasoning)
|
||||
) {
|
||||
const reasoningObj = existingReasoning as Record<string, unknown>;
|
||||
if (!("max_tokens" in reasoningObj) && !("effort" in reasoningObj)) {
|
||||
reasoningObj.effort = mapThinkingLevelToOpenRouterReasoningEffort(thinkingLevel);
|
||||
}
|
||||
} else if (!existingReasoning) {
|
||||
payloadObj.reasoning = {
|
||||
effort: mapThinkingLevelToOpenRouterReasoningEffort(thinkingLevel),
|
||||
};
|
||||
}
|
||||
} else if (!existingReasoning) {
|
||||
payloadObj.reasoning = {
|
||||
effort: mapThinkingLevelToOpenRouterReasoningEffort(thinkingLevel),
|
||||
};
|
||||
}
|
||||
}
|
||||
onPayload?.(payload);
|
||||
|
||||
Reference in New Issue
Block a user