fix(ai): use OpenRouter reasoning payload (#2298)
* fix(ai): use OpenRouter reasoning payload * fix(coding-agent): stop updating packages on startup closes #1963 * fix(ai): add openrouter thinkingFormat compat --------- Co-authored-by: Mario Zechner <badlogicgames@gmail.com>
This commit is contained in:
@@ -408,6 +408,12 @@ function buildParams(model: Model<"openai-completions">, context: Context, optio
|
||||
(params as any).enable_thinking = !!options?.reasoningEffort;
|
||||
} else if (compat.thinkingFormat === "qwen-chat-template" && model.reasoning) {
|
||||
(params as any).chat_template_kwargs = { enable_thinking: !!options?.reasoningEffort };
|
||||
} else if (compat.thinkingFormat === "openrouter" && options?.reasoningEffort && model.reasoning) {
|
||||
// OpenRouter normalizes reasoning across providers via a nested reasoning object.
|
||||
const openRouterParams = params as typeof params & { reasoning?: { effort?: string } };
|
||||
openRouterParams.reasoning = {
|
||||
effort: mapReasoningEffort(options.reasoningEffort, compat.reasoningEffortMap),
|
||||
};
|
||||
} else if (options?.reasoningEffort && model.reasoning && compat.supportsReasoningEffort) {
|
||||
// OpenAI-style reasoning_effort
|
||||
(params as any).reasoning_effort = mapReasoningEffort(options.reasoningEffort, compat.reasoningEffortMap);
|
||||
@@ -816,7 +822,11 @@ function detectCompat(model: Model<"openai-completions">): Required<OpenAIComple
|
||||
requiresToolResultName: false,
|
||||
requiresAssistantAfterToolResult: false,
|
||||
requiresThinkingAsText: false,
|
||||
thinkingFormat: isZai ? "zai" : "openai",
|
||||
thinkingFormat: isZai
|
||||
? "zai"
|
||||
: provider === "openrouter" || baseUrl.includes("openrouter.ai")
|
||||
? "openrouter"
|
||||
: "openai",
|
||||
openRouterRouting: {},
|
||||
vercelGatewayRouting: {},
|
||||
supportsStrictMode: true,
|
||||
|
||||
@@ -271,8 +271,8 @@ export interface OpenAICompletionsCompat {
|
||||
requiresAssistantAfterToolResult?: boolean;
|
||||
/** Whether thinking blocks must be converted to text blocks with <thinking> delimiters. Default: auto-detected from URL. */
|
||||
requiresThinkingAsText?: boolean;
|
||||
/** Format for reasoning/thinking parameter. "openai" uses reasoning_effort, "zai" uses top-level enable_thinking: boolean, "qwen" uses top-level enable_thinking: boolean, and "qwen-chat-template" uses chat_template_kwargs.enable_thinking. Default: "openai". */
|
||||
thinkingFormat?: "openai" | "zai" | "qwen" | "qwen-chat-template";
|
||||
/** Format for reasoning/thinking parameter. "openai" uses reasoning_effort, "openrouter" uses reasoning: { effort }, "zai" uses top-level enable_thinking: boolean, "qwen" uses top-level enable_thinking: boolean, and "qwen-chat-template" uses chat_template_kwargs.enable_thinking. Default: "openai". */
|
||||
thinkingFormat?: "openai" | "openrouter" | "zai" | "qwen" | "qwen-chat-template";
|
||||
/** OpenRouter-specific routing preferences. Only used when baseUrl points to OpenRouter. */
|
||||
openRouterRouting?: OpenRouterRouting;
|
||||
/** Vercel AI Gateway routing preferences. Only used when baseUrl points to Vercel AI Gateway. */
|
||||
|
||||
@@ -233,4 +233,36 @@ describe("openai-completions tool_choice", () => {
|
||||
expect(response.stopReason).toBe("error");
|
||||
expect(response.errorMessage).toBe("Provider finish_reason: network_error");
|
||||
});
|
||||
|
||||
it("uses OpenRouter reasoning object instead of reasoning_effort", async () => {
|
||||
const model = getModel("openrouter", "deepseek/deepseek-r1")!;
|
||||
let payload: unknown;
|
||||
|
||||
await streamSimple(
|
||||
model,
|
||||
{
|
||||
messages: [
|
||||
{
|
||||
role: "user",
|
||||
content: "Hi",
|
||||
timestamp: Date.now(),
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
apiKey: "test",
|
||||
reasoning: "high",
|
||||
onPayload: (params: unknown) => {
|
||||
payload = params;
|
||||
},
|
||||
},
|
||||
).result();
|
||||
|
||||
const params = (payload ?? mockState.lastParams) as {
|
||||
reasoning?: { effort?: string };
|
||||
reasoning_effort?: string;
|
||||
};
|
||||
expect(params.reasoning).toEqual({ effort: "high" });
|
||||
expect(params.reasoning_effort).toBeUndefined();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -63,6 +63,7 @@ const OpenAICompletionsCompatSchema = Type.Object({
|
||||
thinkingFormat: Type.Optional(
|
||||
Type.Union([
|
||||
Type.Literal("openai"),
|
||||
Type.Literal("openrouter"),
|
||||
Type.Literal("zai"),
|
||||
Type.Literal("qwen"),
|
||||
Type.Literal("qwen-chat-template"),
|
||||
|
||||
Reference in New Issue
Block a user