mirror of
https://github.com/openclaw/openclaw.git
synced 2026-08-28 05:16:23 -06:00
fix(ai): honor provider reasoning effort maps (#112632)
This commit is contained in:
committed by
GitHub
parent
cf2f591161
commit
1c70136472
@@ -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")];
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user