mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-08 11:01:24 +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
@@ -202,6 +202,58 @@ describe("applyExtraParamsToAgent", () => {
|
||||
return calls[0]?.headers;
|
||||
}
|
||||
|
||||
it("does not inject reasoning when thinkingLevel is off (default) for OpenRouter", () => {
|
||||
// Regression: "off" is a truthy string, so the old code injected
|
||||
// reasoning: { effort: "none" }, causing a 400 on models that require
|
||||
// reasoning (e.g. deepseek/deepseek-r1).
|
||||
const payloads: Record<string, unknown>[] = [];
|
||||
const baseStreamFn: StreamFn = (_model, _context, options) => {
|
||||
const payload: Record<string, unknown> = { model: "deepseek/deepseek-r1" };
|
||||
options?.onPayload?.(payload);
|
||||
payloads.push(payload);
|
||||
return {} as ReturnType<StreamFn>;
|
||||
};
|
||||
const agent = { streamFn: baseStreamFn };
|
||||
|
||||
applyExtraParamsToAgent(agent, undefined, "openrouter", "deepseek/deepseek-r1", undefined, "off");
|
||||
|
||||
const model = {
|
||||
api: "openai-completions",
|
||||
provider: "openrouter",
|
||||
id: "deepseek/deepseek-r1",
|
||||
} as Model<"openai-completions">;
|
||||
const context: Context = { messages: [] };
|
||||
void agent.streamFn?.(model, context, {});
|
||||
|
||||
expect(payloads).toHaveLength(1);
|
||||
expect(payloads[0]).not.toHaveProperty("reasoning");
|
||||
expect(payloads[0]).not.toHaveProperty("reasoning_effort");
|
||||
});
|
||||
|
||||
it("injects reasoning.effort when thinkingLevel is non-off for OpenRouter", () => {
|
||||
const payloads: Record<string, unknown>[] = [];
|
||||
const baseStreamFn: StreamFn = (_model, _context, options) => {
|
||||
const payload: Record<string, unknown> = {};
|
||||
options?.onPayload?.(payload);
|
||||
payloads.push(payload);
|
||||
return {} as ReturnType<StreamFn>;
|
||||
};
|
||||
const agent = { streamFn: baseStreamFn };
|
||||
|
||||
applyExtraParamsToAgent(agent, undefined, "openrouter", "openrouter/auto", undefined, "low");
|
||||
|
||||
const model = {
|
||||
api: "openai-completions",
|
||||
provider: "openrouter",
|
||||
id: "openrouter/auto",
|
||||
} as Model<"openai-completions">;
|
||||
const context: Context = { messages: [] };
|
||||
void agent.streamFn?.(model, context, {});
|
||||
|
||||
expect(payloads).toHaveLength(1);
|
||||
expect(payloads[0]?.reasoning).toEqual({ effort: "low" });
|
||||
});
|
||||
|
||||
it("adds OpenRouter attribution headers to stream options", () => {
|
||||
const { calls, agent } = createOptionsCaptureAgent();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user