feat: add model thinking level metadata

closes #3208
This commit is contained in:
Mario Zechner
2026-05-02 01:20:01 +02:00
parent 73b7b2c564
commit 80f06d3636
28 changed files with 527 additions and 243 deletions

View File

@@ -78,6 +78,82 @@ const EAGER_TOOL_INPUT_STREAMING_UNSUPPORTED_ANTHROPIC_MODELS = new Set([
"github-copilot:claude-sonnet-4.5",
]);
const DEEPSEEK_V4_THINKING_LEVEL_MAP = {
minimal: null,
low: null,
medium: null,
high: "high",
xhigh: "max",
} as const;
function mergeThinkingLevelMap(model: Model<any>, map: NonNullable<Model<any>["thinkingLevelMap"]>): void {
model.thinkingLevelMap = { ...model.thinkingLevelMap, ...map };
}
function supportsOpenAiXhigh(modelId: string): boolean {
return (
modelId.includes("gpt-5.2") ||
modelId.includes("gpt-5.3") ||
modelId.includes("gpt-5.4") ||
modelId.includes("gpt-5.5")
);
}
function isGoogleThinkingApi(model: Model<any>): boolean {
return model.api === "google-generative-ai" || model.api === "google-vertex";
}
function isGemini3ProModel(modelId: string): boolean {
return /gemini-3(?:\.\d+)?-pro/.test(modelId.toLowerCase());
}
function isGemini3FlashModel(modelId: string): boolean {
return /gemini-3(?:\.\d+)?-flash/.test(modelId.toLowerCase());
}
function isGemma4Model(modelId: string): boolean {
return /gemma-?4/.test(modelId.toLowerCase());
}
function applyThinkingLevelMetadata(model: Model<any>): void {
if (
(model.api === "openai-responses" || model.api === "azure-openai-responses") &&
model.id.startsWith("gpt-5")
) {
mergeThinkingLevelMap(model, { off: null });
}
if (supportsOpenAiXhigh(model.id)) {
mergeThinkingLevelMap(model, { xhigh: "xhigh" });
}
if (model.id.includes("opus-4-6") || model.id.includes("opus-4.6")) {
mergeThinkingLevelMap(model, { xhigh: "max" });
}
if (model.id.includes("opus-4-7") || model.id.includes("opus-4.7")) {
mergeThinkingLevelMap(model, { xhigh: "xhigh" });
}
if (model.api === "openai-completions" && model.id.includes("deepseek-v4")) {
mergeThinkingLevelMap(model, DEEPSEEK_V4_THINKING_LEVEL_MAP);
}
if (isGoogleThinkingApi(model) && isGemini3ProModel(model.id)) {
mergeThinkingLevelMap(model, { off: null, minimal: null, low: "LOW", medium: null, high: "HIGH" });
}
if (isGoogleThinkingApi(model) && isGemini3FlashModel(model.id)) {
mergeThinkingLevelMap(model, { off: null });
}
if (isGoogleThinkingApi(model) && isGemma4Model(model.id)) {
mergeThinkingLevelMap(model, { off: null, minimal: "MINIMAL", low: null, medium: null, high: "HIGH" });
}
if (model.provider === "groq" && model.id === "qwen/qwen3-32b") {
mergeThinkingLevelMap(model, { minimal: null, low: null, medium: null, high: "default" });
}
if (model.provider === "openai-codex" && supportsOpenAiXhigh(model.id)) {
mergeThinkingLevelMap(model, { minimal: "low" });
}
if (model.provider === "openai-codex" && model.id === "gpt-5.1-codex-mini") {
mergeThinkingLevelMap(model, { minimal: "medium", low: "medium", medium: "medium", high: "high" });
}
}
function getAnthropicMessagesCompat(provider: string, modelId: string): AnthropicMessagesCompat | undefined {
return EAGER_TOOL_INPUT_STREAMING_UNSUPPORTED_ANTHROPIC_MODELS.has(`${provider}:${modelId}`)
? { supportsEagerToolInputStreaming: false }
@@ -1164,13 +1240,6 @@ async function generateModels() {
const deepseekCompat: OpenAICompletionsCompat = {
requiresReasoningContentOnAssistantMessages: true,
thinkingFormat: "deepseek",
reasoningEffortMap: {
minimal: "high",
low: "high",
medium: "high",
high: "high",
xhigh: "max",
},
};
const deepseekV4Models: Model<"openai-completions">[] = [
{
@@ -1224,6 +1293,7 @@ async function generateModels() {
}
: deepseekCompat),
};
mergeThinkingLevelMap(candidate, DEEPSEEK_V4_THINKING_LEVEL_MAP);
}
}
@@ -1615,6 +1685,10 @@ async function generateModels() {
}));
allModels.push(...azureOpenAiModels);
for (const model of allModels) {
applyThinkingLevelMetadata(model);
}
// Group by provider and deduplicate by model ID
const providers: Record<string, Record<string, Model<any>>> = {};
for (const model of allModels) {
@@ -1662,6 +1736,9 @@ export const MODELS = {
`;
}
output += `\t\t\treasoning: ${model.reasoning},\n`;
if (model.thinkingLevelMap) {
output += `\t\t\tthinkingLevelMap: ${JSON.stringify(model.thinkingLevelMap)},\n`;
}
output += `\t\t\tinput: [${model.input.map(i => `"${i}"`).join(", ")}],\n`;
output += `\t\t\tcost: {\n`;
output += `\t\t\t\tinput: ${model.cost.input},\n`;