@@ -15,6 +15,7 @@ import { calculateCost, clampThinkingLevel } from "../models.ts";
|
||||
import type {
|
||||
AssistantMessage,
|
||||
CacheRetention,
|
||||
ChatTemplateKwargValue,
|
||||
Context,
|
||||
ImageContent,
|
||||
Message,
|
||||
@@ -91,6 +92,8 @@ type ResolvedOpenAICompletionsCompat = Omit<Required<OpenAICompletionsCompat>, "
|
||||
cacheControlFormat?: OpenAICompletionsCompat["cacheControlFormat"];
|
||||
};
|
||||
|
||||
type ResolvedChatTemplateKwargValue = string | number | boolean | null;
|
||||
|
||||
type ChatCompletionInstructionMessageParam = ChatCompletionDeveloperMessageParam | ChatCompletionSystemMessageParam;
|
||||
|
||||
type ChatCompletionTextPartWithCacheControl = ChatCompletionContentPartText & {
|
||||
@@ -585,6 +588,11 @@ function buildParams(
|
||||
enable_thinking: !!options?.reasoningEffort,
|
||||
preserve_thinking: true,
|
||||
};
|
||||
} else if (compat.thinkingFormat === "chat-template" && model.reasoning) {
|
||||
const chatTemplateKwargs = buildChatTemplateKwargs(model, options, compat);
|
||||
if (chatTemplateKwargs) {
|
||||
(params as any).chat_template_kwargs = chatTemplateKwargs;
|
||||
}
|
||||
} else if (compat.thinkingFormat === "deepseek" && model.reasoning) {
|
||||
if (options?.reasoningEffort) {
|
||||
(params as any).thinking = { type: "enabled" };
|
||||
@@ -655,6 +663,44 @@ function buildParams(
|
||||
return params;
|
||||
}
|
||||
|
||||
function buildChatTemplateKwargs(
|
||||
model: Model<"openai-completions">,
|
||||
options: OpenAICompletionsOptions | undefined,
|
||||
compat: ResolvedOpenAICompletionsCompat,
|
||||
): Record<string, ResolvedChatTemplateKwargValue> | undefined {
|
||||
const kwargs: Record<string, ResolvedChatTemplateKwargValue> = {};
|
||||
|
||||
for (const [key, value] of Object.entries(compat.chatTemplateKwargs)) {
|
||||
const resolved = resolveChatTemplateKwargValue(model, options, value);
|
||||
if (resolved !== undefined) {
|
||||
kwargs[key] = resolved;
|
||||
}
|
||||
}
|
||||
|
||||
return Object.keys(kwargs).length > 0 ? kwargs : undefined;
|
||||
}
|
||||
|
||||
function resolveChatTemplateKwargValue(
|
||||
model: Model<"openai-completions">,
|
||||
options: OpenAICompletionsOptions | undefined,
|
||||
value: ChatTemplateKwargValue,
|
||||
): ResolvedChatTemplateKwargValue | undefined {
|
||||
if (typeof value !== "object" || value === null) {
|
||||
return value;
|
||||
}
|
||||
|
||||
const reasoningEffort = options?.reasoningEffort;
|
||||
if (!reasoningEffort && value.omitWhenOff) {
|
||||
return undefined;
|
||||
}
|
||||
if (value.$var === "thinking.enabled") {
|
||||
return !!reasoningEffort;
|
||||
}
|
||||
|
||||
const mappedValue = reasoningEffort ? model.thinkingLevelMap?.[reasoningEffort] : model.thinkingLevelMap?.off;
|
||||
return mappedValue === undefined ? reasoningEffort : typeof mappedValue === "string" ? mappedValue : undefined;
|
||||
}
|
||||
|
||||
function getCompatCacheControl(
|
||||
compat: ResolvedOpenAICompletionsCompat,
|
||||
cacheRetention: CacheRetention,
|
||||
@@ -1167,6 +1213,7 @@ function detectCompat(model: Model<"openai-completions">): ResolvedOpenAIComplet
|
||||
: "openai",
|
||||
openRouterRouting: {},
|
||||
vercelGatewayRouting: {},
|
||||
chatTemplateKwargs: {},
|
||||
zaiToolStream: false,
|
||||
supportsStrictMode: !isMoonshot && !isTogether && !isCloudflareAiGateway && !isNvidia,
|
||||
cacheControlFormat,
|
||||
@@ -1205,6 +1252,7 @@ function getCompat(model: Model<"openai-completions">): ResolvedOpenAICompletion
|
||||
thinkingFormat: model.compat.thinkingFormat ?? detected.thinkingFormat,
|
||||
openRouterRouting: model.compat.openRouterRouting ?? {},
|
||||
vercelGatewayRouting: model.compat.vercelGatewayRouting ?? detected.vercelGatewayRouting,
|
||||
chatTemplateKwargs: model.compat.chatTemplateKwargs ?? detected.chatTemplateKwargs,
|
||||
zaiToolStream: model.compat.zaiToolStream ?? detected.zaiToolStream,
|
||||
supportsStrictMode: model.compat.supportsStrictMode ?? detected.supportsStrictMode,
|
||||
cacheControlFormat: model.compat.cacheControlFormat ?? detected.cacheControlFormat,
|
||||
|
||||
@@ -65,6 +65,15 @@ export type ImagesProvider = KnownImagesProvider | string;
|
||||
export type ThinkingLevel = "minimal" | "low" | "medium" | "high" | "xhigh";
|
||||
export type ModelThinkingLevel = "off" | ThinkingLevel;
|
||||
export type ThinkingLevelMap = Partial<Record<ModelThinkingLevel, string | null>>;
|
||||
export type ChatTemplateKwargValue =
|
||||
| string
|
||||
| number
|
||||
| boolean
|
||||
| null
|
||||
| {
|
||||
$var: "thinking.enabled" | "thinking.effort";
|
||||
omitWhenOff?: boolean;
|
||||
};
|
||||
|
||||
/** Token budgets for each thinking level (token-based providers only) */
|
||||
export interface ThinkingBudgets {
|
||||
@@ -403,7 +412,7 @@ export interface OpenAICompletionsCompat {
|
||||
requiresThinkingAsText?: boolean;
|
||||
/** Whether all replayed assistant messages must include an empty reasoning_content field when reasoning is enabled. Default: auto-detected from URL. */
|
||||
requiresReasoningContentOnAssistantMessages?: boolean;
|
||||
/** Format for reasoning/thinking parameter. "openai" uses reasoning_effort, "openrouter" uses reasoning: { effort }, "deepseek" uses thinking: { type } plus reasoning_effort when supported, "together" uses reasoning: { enabled } plus reasoning_effort when supported, "zai" uses thinking: { type }, "qwen" uses top-level enable_thinking: boolean, "qwen-chat-template" uses chat_template_kwargs.enable_thinking, "string-thinking" uses top-level thinking: string, and "ant-ling" uses reasoning: { effort } only when the mapped effort is non-null. Default: "openai". */
|
||||
/** Format for reasoning/thinking parameter. "openai" uses reasoning_effort, "openrouter" uses reasoning: { effort }, "deepseek" uses thinking: { type } plus reasoning_effort when supported, "together" uses reasoning: { enabled } plus reasoning_effort when supported, "zai" uses thinking: { type }, "qwen" uses top-level enable_thinking: boolean, "qwen-chat-template" uses chat_template_kwargs.enable_thinking and preserve_thinking, "chat-template" uses configurable chat_template_kwargs, "string-thinking" uses top-level thinking: string, and "ant-ling" uses reasoning: { effort } only when the mapped effort is non-null. Default: "openai". */
|
||||
thinkingFormat?:
|
||||
| "openai"
|
||||
| "openrouter"
|
||||
@@ -411,9 +420,12 @@ export interface OpenAICompletionsCompat {
|
||||
| "together"
|
||||
| "zai"
|
||||
| "qwen"
|
||||
| "chat-template"
|
||||
| "qwen-chat-template"
|
||||
| "string-thinking"
|
||||
| "ant-ling";
|
||||
/** Kwargs to send as `chat_template_kwargs` when `thinkingFormat` is `chat-template`. Use `{ "$var": "thinking.enabled" }` or `{ "$var": "thinking.effort" }` for pi-controlled thinking values. */
|
||||
chatTemplateKwargs?: Record<string, ChatTemplateKwargValue>;
|
||||
/** OpenRouter-compatible routing preferences sent as the `provider` request field. */
|
||||
openRouterRouting?: OpenRouterRouting;
|
||||
/** Vercel AI Gateway routing preferences. Only used when baseUrl points to Vercel AI Gateway. */
|
||||
|
||||
Reference in New Issue
Block a user