fix(ai): honor provider reasoning effort maps (#112632)

This commit is contained in:
Peter Steinberger
2026-07-22 06:11:03 -07:00
committed by GitHub
parent cf2f591161
commit 1c70136472
2 changed files with 59 additions and 24 deletions
@@ -228,6 +228,34 @@ describe("OpenAI-compatible completions params", () => {
expect(mockOpenAIOptionsRef.payloads[0]).not.toHaveProperty("reasoning_effort");
});
it.each([
{ name: "model compat mapping", reasoningEffort: "low", expected: "high" },
{ name: "thinkingLevelMap fallback", reasoningEffort: "medium", expected: "xhigh" },
{ name: "requested effort fallback", reasoningEffort: "high", expected: "high" },
] as const)(
"uses $name in the emitted reasoning_effort payload",
async ({ reasoningEffort, expected }) => {
mockChunksRef.chunks = [makeTextChunk("ok"), makeFinishChunk("stop")];
const compatibleModel = {
...reasoningModel,
provider: "custom-openai-compatible",
baseUrl: "https://third-party.test/v1",
thinkingLevelMap: { low: "medium", medium: "xhigh" },
compat: {
supportsReasoningEffort: true,
reasoningEffortMap: { low: "high" },
},
} as unknown as Model<"openai-completions">;
await streamOpenAICompletions(compatibleModel, context, {
apiKey: "sk-test",
reasoningEffort,
}).result();
expect(mockOpenAIOptionsRef.payloads[0]).toMatchObject({ reasoning_effort: expected });
},
);
it("configures the OpenAI SDK client with the host-built model fetch", async () => {
mockOpenAIOptionsRef.options = [];
mockChunksRef.chunks = [makeTextChunk("ok"), makeFinishChunk("stop")];
+31 -24
View File
@@ -18,6 +18,7 @@ import {
calculateCost,
clampThinkingLevel,
} from "../model-utils.js";
import { resolveOpenAIReasoningEffortMap } from "../transports/openai-reasoning-compat.js";
import type {
AssistantMessage,
CacheRetention,
@@ -814,51 +815,57 @@ function buildParams(
}
}
// Provider compat is authoritative; keep model-level and literal values as fallbacks
// for catalogs that have not adopted reasoningEffortMap.
const reasoningEffortMap = resolveOpenAIReasoningEffortMap(model);
const reasoningEffort =
options?.reasoningEffort === undefined
? undefined
: (reasoningEffortMap[options.reasoningEffort] ??
model.thinkingLevelMap?.[options.reasoningEffort] ??
options.reasoningEffort);
const reasoningEnabled = reasoningEffort !== undefined;
const offReasoningEffort = reasoningEffortMap.off ?? model.thinkingLevelMap?.off;
if (compat.thinkingFormat === "zai" && model.reasoning) {
params.thinking = options?.reasoningEffort
params.thinking = reasoningEnabled
? { type: "enabled", clear_thinking: false }
: { type: "disabled" };
} else if (compat.thinkingFormat === "qwen" && model.reasoning) {
params.enable_thinking = Boolean(options?.reasoningEffort);
params.enable_thinking = reasoningEnabled;
} else if (compat.thinkingFormat === "qwen-chat-template" && model.reasoning) {
params.chat_template_kwargs = {
enable_thinking: Boolean(options?.reasoningEffort),
enable_thinking: reasoningEnabled,
preserve_thinking: true,
};
} else if (compat.thinkingFormat === "deepseek" && model.reasoning) {
params.thinking = { type: options?.reasoningEffort ? "enabled" : "disabled" };
if (options?.reasoningEffort && compat.supportsReasoningEffort) {
params.reasoning_effort =
model.thinkingLevelMap?.[options.reasoningEffort] ?? options.reasoningEffort;
params.thinking = { type: reasoningEnabled ? "enabled" : "disabled" };
if (reasoningEnabled && compat.supportsReasoningEffort) {
params.reasoning_effort = reasoningEffort;
}
} else if (compat.thinkingFormat === "openrouter" && model.reasoning) {
// OpenRouter normalizes reasoning across providers via a nested reasoning object.
const openRouterParams = params as typeof params & { reasoning?: { effort?: string } };
if (options?.reasoningEffort) {
openRouterParams.reasoning = {
effort: model.thinkingLevelMap?.[options.reasoningEffort] ?? options.reasoningEffort,
};
} else if (model.thinkingLevelMap?.off !== null) {
openRouterParams.reasoning = { effort: model.thinkingLevelMap?.off ?? "none" };
if (reasoningEnabled) {
openRouterParams.reasoning = { effort: reasoningEffort };
} else if (offReasoningEffort !== null) {
openRouterParams.reasoning = { effort: offReasoningEffort ?? "none" };
}
} else if (compat.thinkingFormat === "together" && model.reasoning) {
const togetherParams = params as Omit<typeof params, "reasoning_effort"> & {
reasoning?: { enabled: boolean };
reasoning_effort?: string;
};
togetherParams.reasoning = { enabled: Boolean(options?.reasoningEffort) };
if (options?.reasoningEffort && compat.supportsReasoningEffort) {
togetherParams.reasoning_effort =
model.thinkingLevelMap?.[options.reasoningEffort] ?? options.reasoningEffort;
togetherParams.reasoning = { enabled: reasoningEnabled };
if (reasoningEnabled && compat.supportsReasoningEffort) {
togetherParams.reasoning_effort = reasoningEffort;
}
} else if (options?.reasoningEffort && model.reasoning && compat.supportsReasoningEffort) {
} else if (reasoningEnabled && model.reasoning && compat.supportsReasoningEffort) {
// OpenAI-style reasoning_effort
params.reasoning_effort =
model.thinkingLevelMap?.[options.reasoningEffort] ?? options.reasoningEffort;
} else if (!options?.reasoningEffort && model.reasoning && compat.supportsReasoningEffort) {
const offValue = model.thinkingLevelMap?.off;
if (typeof offValue === "string") {
params.reasoning_effort = offValue;
params.reasoning_effort = reasoningEffort;
} else if (model.reasoning && compat.supportsReasoningEffort) {
if (typeof offReasoningEffort === "string") {
params.reasoning_effort = offReasoningEffort;
}
}