From 5100642ebbcc24d3636484787eab8d7124e1a38a Mon Sep 17 00:00:00 2001 From: InkshadeWoods <144514307+InkshadeWoods@users.noreply.github.com> Date: Thu, 20 Aug 2026 17:29:34 +0800 Subject: [PATCH] fix(sensenova): clamp max reasoning effort to xhigh (#10733) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Merged via merge-train (release/v3.8.50, batch1 2026-08-20) — static gates (typecheck/file-size/complexity/cognitive/changelog) green on the combined tree; test:unit reds observed in the boarded run were verified pre-existing on the pure release tip (unrelated flake), not caused by this PR. Thanks for the contribution! --- .../providers/registry/sensenova/index.ts | 2 ++ open-sse/executors/base/reasoningEffort.ts | 27 ++++++++++++++++++- tests/unit/sensenova-reasoning-effort.test.ts | 24 +++++++++++++++++ 3 files changed, 52 insertions(+), 1 deletion(-) create mode 100644 tests/unit/sensenova-reasoning-effort.test.ts diff --git a/open-sse/config/providers/registry/sensenova/index.ts b/open-sse/config/providers/registry/sensenova/index.ts index 37e95acc32..2e8b5822f9 100644 --- a/open-sse/config/providers/registry/sensenova/index.ts +++ b/open-sse/config/providers/registry/sensenova/index.ts @@ -27,6 +27,8 @@ export const sensenovaProvider: RegistryEntry = { contextLength: 1048576, maxOutputTokens: 65536, supportsReasoning: true, + supportedThinkingEfforts: ["none", "low", "medium", "high", "xhigh"], + supportsXHighEffort: true, interleavedField: "reasoning_content", }, { diff --git a/open-sse/executors/base/reasoningEffort.ts b/open-sse/executors/base/reasoningEffort.ts index f3d138bb79..9b8ffb1da0 100644 --- a/open-sse/executors/base/reasoningEffort.ts +++ b/open-sse/executors/base/reasoningEffort.ts @@ -6,6 +6,7 @@ import { supportsClaudeMaxEffort, supportsXHighEffort, getProviderModel, + getProviderModels, } from "../../config/providerModels.ts"; /** @@ -351,6 +352,31 @@ export function sanitizeReasoningEffortForProvider( // new models from being unusable for weeks until they're whitelisted (#8057). if (effortStr === "max") { if (supportsMax) return body; // explicitly known to accept max + + // A model that explicitly advertises its accepted tiers is safe to normalize. + // Keep the default pass-through for absent metadata: an unlisted model might + // support literal `max`, and #8057 deliberately avoids blocking such models. + const providerModelId = modelStr.startsWith(`${provider}/`) + ? modelStr.slice(provider.length + 1) + : modelStr; + // Do not fall back to a globally registered model here. Identical ids can + // have different upstream contracts across providers (for example, OpenCode + // and SenseNova both expose deepseek-v4-flash with different max support). + const explicitEfforts = getProviderModels(provider).find( + (entry) => entry.id === providerModelId || entry.aliases?.includes(providerModelId) + )?.supportedThinkingEfforts; + const maxFallback = + Array.isArray(explicitEfforts) && !explicitEfforts.includes("max") + ? ["xhigh", "high", "medium", "low"].find((tier) => explicitEfforts.includes(tier)) + : undefined; + if (maxFallback) { + log?.info?.( + "REASONING_SANITIZE", + `${provider}/${modelStr}: downgraded reasoning_effort max → ${maxFallback} (explicit model capability)` + ); + return writeEffortValue(b, maxFallback, c); + } + if (!supportsXHigh) { // Model is explicitly flagged as rejecting xhigh (and not in supportsMax) — // it likely only accepts standard tiers. Degrade to its highest: high. @@ -360,7 +386,6 @@ export function sanitizeReasoningEffortForProvider( ); return writeEffortValue(b, "high", c); } - // Default: pass max through unchanged — trust the upstream return body; } diff --git a/tests/unit/sensenova-reasoning-effort.test.ts b/tests/unit/sensenova-reasoning-effort.test.ts new file mode 100644 index 0000000000..d2d6f9142d --- /dev/null +++ b/tests/unit/sensenova-reasoning-effort.test.ts @@ -0,0 +1,24 @@ +import assert from "node:assert/strict"; +import test from "node:test"; + +import { sanitizeReasoningEffortForProvider } from "../../open-sse/executors/base/reasoningEffort.ts"; + +test("sensenova/deepseek-v4-flash maps max to its explicit xhigh ceiling", () => { + const result = sanitizeReasoningEffortForProvider( + { reasoning_effort: "max", messages: [] }, + "sensenova", + "deepseek-v4-flash" + ); + + assert.equal((result as Record).reasoning_effort, "xhigh"); +}); + +test("sensenova models without an explicit effort list keep max unchanged", () => { + const result = sanitizeReasoningEffortForProvider( + { reasoning_effort: "max", messages: [] }, + "sensenova", + "glm-5.2" + ); + + assert.equal((result as Record).reasoning_effort, "max"); +});