fix(sensenova): clamp max reasoning effort to xhigh (#10733)

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!
This commit is contained in:
InkshadeWoods
2026-08-20 17:29:34 +08:00
committed by GitHub
parent 2eb6d59ebc
commit 5100642ebb
3 changed files with 52 additions and 1 deletions

View File

@@ -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",
},
{

View File

@@ -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;
}

View File

@@ -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<string, unknown>).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<string, unknown>).reasoning_effort, "max");
});