fix(ollama-cloud): map xhigh reasoning effort to max (#10160)

This commit is contained in:
Chewji
2026-08-13 10:48:35 +07:00
committed by GitHub
parent e21f6acaab
commit f2d94957c8
3 changed files with 69 additions and 2 deletions

View File

@@ -27,7 +27,20 @@ export const ollama_cloudProvider: RegistryEntry = {
{ id: "deepseek-v4-pro", name: "DeepSeek V4 Pro", supportsReasoning: true },
{ id: "deepseek-v4-flash", name: "DeepSeek V4 Flash", supportsReasoning: true },
{ id: "kimi-k2.6", name: "Kimi K2.6" },
{ id: "glm-5.1", name: "GLM 5.1" },
// Ollama Cloud accepts low|medium|high|max|none and rejects xhigh, so the
// explicit supportsXHighEffort:false makes the sanitizer map xhigh → max.
{
id: "glm-5.1",
name: "GLM 5.1",
supportsReasoning: true,
supportsXHighEffort: false,
},
{
id: "glm-5.2",
name: "GLM 5.2",
supportsReasoning: true,
supportsXHighEffort: false,
},
// #3110: MiniMax M3 via Ollama
{ id: "minimax-m3", name: "MiniMax M3", contextLength: 1048576, supportsVision: true },
{ id: "minimax-m2.7", name: "MiniMax M2.7" },

View File

@@ -154,7 +154,8 @@ export function supportsMaxEffortForProvider(provider: string, model: string): b
// upstream. Scoped to opencode-go deliberately: OpenRouter's DeepSeek path
// (pi#4055) is the documented inverse and expects xhigh, not max.
// Ollama Cloud also accepts literal max (for example GLM 5.2 supports
// low|medium|high|max|none) and rejects xhigh.
// low|medium|high|max|none) and rejects xhigh; xhigh is mapped to max by the
// provider guard in sanitizeReasoningEffortForProvider.
const isOpencodeGoDeepSeek =
(provider === "opencode-go" || provider === "opencode-zen") &&
resolvedModelId.toLowerCase().includes("deepseek");
@@ -284,6 +285,18 @@ export function sanitizeReasoningEffortForProvider(
return writeEffortValue(b, "max", c);
}
// Ollama Cloud accepts low|medium|high|max|none and rejects xhigh. Map
// xhigh → max (its literal top tier) before the generic xhigh handling so
// passthrough (unregistered) models are covered too — the registry opt-out
// only covers known models.
if (provider === "ollama-cloud" && effortStr === "xhigh") {
log?.info?.(
"REASONING_SANITIZE",
`${provider}/${modelStr}: mapped reasoning_effort xhigh → max`
);
return writeEffortValue(b, "max", c);
}
// Native DeepSeek (api.deepseek.com) — V4 thinking mode uses the native
// {low, high, max} vocabulary on Flash and {high, max} on Pro. OmniRoute's
// internal top tier xhigh maps to DeepSeek's literal max. Pro's unsupported

View File

@@ -118,6 +118,47 @@ test("sanitizeReasoningEffortForProvider: Ollama Cloud preserves nested max", ()
assert.equal((result as Record<string, unknown>).reasoning.summary, "auto");
});
test("sanitizeReasoningEffortForProvider: Ollama Cloud maps registry model xhigh → max", () => {
const log = makeLog();
const body = {
model: "glm-5.2",
reasoning_effort: "xhigh",
messages: [{ role: "user", content: "hi" }],
};
const result = sanitizeReasoningEffortForProvider(body, "ollama-cloud", "glm-5.2", log) as Record<
string,
unknown
>;
assert.notEqual(result, body, "must return a new object when mutating");
assert.equal(result.reasoning_effort, "max");
assert.equal(result.model, "glm-5.2", "other fields preserved");
assert.ok(
log.messages.some(([tag, m]) => tag === "REASONING_SANITIZE" && /xhigh → max/.test(m)),
"logs the xhigh → max mapping"
);
});
test("sanitizeReasoningEffortForProvider: Ollama Cloud maps passthrough unknown model xhigh → max", () => {
const log = makeLog();
const body = {
model: "some-future-glm-model",
reasoning_effort: "xhigh",
messages: [{ role: "user", content: "hi" }],
};
const result = sanitizeReasoningEffortForProvider(
body,
"ollama-cloud",
"some-future-glm-model",
log
) as Record<string, unknown>;
assert.notEqual(result, body, "must return a new object when mutating");
assert.equal(result.reasoning_effort, "max");
assert.ok(
log.messages.some(([tag, m]) => tag === "REASONING_SANITIZE" && /xhigh → max/.test(m)),
"logs the xhigh → max mapping"
);
});
test("sanitizeReasoningEffortForProvider: OpenRouter DeepSeek passes max through (new default)", () => {
const log = makeLog();
const body = {