import type { ProviderConfig, ProviderId, ThinkingCapability, ThinkingEffort, ThinkingLevel, ThinkingRequestAdapter, } from '@/lib/types/provider'; export function getModelMetadataKey(providerId: string, modelId: string): string { return `${providerId}:${modelId}`; } function effortCapability( requestAdapter: ThinkingRequestAdapter, effortValues: ThinkingEffort[], defaultEffort: ThinkingEffort, ): ThinkingCapability { return { control: 'effort', requestAdapter, effortValues, defaultEffort, defaultMode: effortValues.includes('none') ? 'disabled' : 'enabled', toggleable: effortValues.includes('none'), budgetAdjustable: true, defaultEnabled: !effortValues.includes('none'), }; } function levelCapability( levelValues: ThinkingLevel[], defaultLevel: ThinkingLevel, ): ThinkingCapability { return { control: 'level', requestAdapter: 'google', levelValues, defaultLevel, defaultMode: 'enabled', toggleable: false, budgetAdjustable: true, defaultEnabled: true, }; } function toggleCapability( requestAdapter: ThinkingRequestAdapter, defaultEnabled = true, ): ThinkingCapability { return { control: 'toggle', requestAdapter, defaultMode: defaultEnabled ? 'enabled' : 'disabled', toggleable: true, budgetAdjustable: false, defaultEnabled, }; } function toggleBudgetCapability( requestAdapter: ThinkingRequestAdapter, range: { min: number; max: number; step?: number; allowDynamic?: boolean; disableValue?: number }, defaultEnabled = false, defaultBudgetTokens?: number, ): ThinkingCapability { return { control: 'toggle-budget', requestAdapter, budgetRange: range, defaultBudgetTokens, defaultMode: defaultEnabled ? 'enabled' : 'disabled', toggleable: true, budgetAdjustable: true, defaultEnabled, }; } function budgetOnlyCapability( requestAdapter: ThinkingRequestAdapter, range: { min: number; max: number; step?: number; allowDynamic?: boolean }, defaultBudgetTokens?: number, ): ThinkingCapability { return { control: 'budget-only', requestAdapter, budgetRange: range, defaultBudgetTokens, defaultMode: 'enabled', toggleable: false, budgetAdjustable: true, defaultEnabled: true, }; } const fixedThinkingCapability: ThinkingCapability = { control: 'none', requestAdapter: 'none', defaultMode: 'enabled', toggleable: false, budgetAdjustable: false, defaultEnabled: true, }; const anthropicManualBudgetByEffort: Partial> = { low: 4096, medium: 10240, high: 32768, max: 64000, }; const anthropicManualEffort: ThinkingCapability = { control: 'effort', requestAdapter: 'anthropic', effortValues: ['none', 'low', 'medium', 'high', 'max'], defaultEffort: 'medium', defaultMode: 'enabled', toggleable: true, budgetAdjustable: true, defaultEnabled: true, anthropicThinking: { type: 'enabled', budgetByEffort: anthropicManualBudgetByEffort, }, }; const anthropicAdaptiveEffort: ThinkingCapability = { ...anthropicManualEffort, anthropicThinking: { type: 'adaptive' }, }; const anthropicBudget: ThinkingCapability = toggleBudgetCapability( 'anthropic', { min: 1024, max: 64000, step: 1024 }, false, 1024, ); const anthropicOpus47Effort: ThinkingCapability = { ...anthropicAdaptiveEffort, effortValues: ['none', 'low', 'medium', 'high', 'xhigh', 'max'], }; const deepseekEffort: ThinkingCapability = { control: 'effort', requestAdapter: 'deepseek', effortValues: ['none', 'high', 'max'], defaultEffort: 'high', defaultMode: 'enabled', toggleable: true, budgetAdjustable: true, defaultEnabled: true, }; const hunyuanHy3Effort: ThinkingCapability = { control: 'effort', requestAdapter: 'hunyuan', effortValues: ['none', 'low', 'high'], defaultEffort: 'none', defaultMode: 'disabled', toggleable: true, budgetAdjustable: true, defaultEnabled: false, }; const qwenBudgetEnabled = toggleBudgetCapability( 'qwen', { min: 0, max: 81920, step: 1024, disableValue: 0 }, true, ); const qwenBudgetDisabled = toggleBudgetCapability( 'qwen', { min: 0, max: 81920, step: 1024, disableValue: 0 }, false, ); const siliconflowBudget = budgetOnlyCapability( 'siliconflow', { min: 128, max: 32768, step: 1024 }, 4096, ); const siliconflowToggleBudget = toggleBudgetCapability( 'siliconflow', { min: 128, max: 32768, step: 1024, disableValue: 0 }, true, 4096, ); const doubaoMode: ThinkingCapability = { control: 'mode', requestAdapter: 'doubao', defaultMode: 'auto', toggleable: true, budgetAdjustable: false, defaultEnabled: true, }; const doubaoSeed20Effort: ThinkingCapability = { control: 'effort', requestAdapter: 'doubao', effortValues: ['minimal', 'low', 'medium', 'high'], defaultEffort: 'medium', defaultMode: 'enabled', toggleable: true, budgetAdjustable: true, defaultEnabled: true, }; const THINKING_CAPABILITIES: Record = { [getModelMetadataKey('openai', 'gpt-5.5')]: effortCapability( 'openai', ['low', 'medium', 'high', 'xhigh'], 'medium', ), [getModelMetadataKey('openai', 'gpt-5.4-pro')]: effortCapability( 'openai', ['medium', 'high', 'xhigh'], 'medium', ), [getModelMetadataKey('openai', 'gpt-5.4')]: effortCapability( 'openai', ['none', 'low', 'medium', 'high', 'xhigh'], 'none', ), [getModelMetadataKey('openai', 'gpt-5.4-mini')]: effortCapability( 'openai', ['none', 'low', 'medium', 'high', 'xhigh'], 'none', ), [getModelMetadataKey('openai', 'gpt-5.4-nano')]: effortCapability( 'openai', ['none', 'low', 'medium', 'high', 'xhigh'], 'none', ), [getModelMetadataKey('anthropic', 'claude-opus-4-7')]: anthropicOpus47Effort, [getModelMetadataKey('anthropic', 'claude-opus-4-6')]: anthropicAdaptiveEffort, [getModelMetadataKey('anthropic', 'claude-sonnet-4-6')]: anthropicAdaptiveEffort, [getModelMetadataKey('anthropic', 'claude-sonnet-4-5')]: anthropicManualEffort, [getModelMetadataKey('anthropic', 'claude-haiku-4-5')]: anthropicBudget, [getModelMetadataKey('google', 'gemini-3.1-pro-preview')]: levelCapability( ['minimal', 'low', 'medium', 'high'], 'high', ), [getModelMetadataKey('google', 'gemini-3-flash-preview')]: levelCapability( ['minimal', 'low', 'medium', 'high'], 'high', ), [getModelMetadataKey('google', 'gemini-2.5-flash')]: toggleBudgetCapability( 'google', { min: 0, max: 24576, step: 1024, allowDynamic: true, disableValue: 0 }, true, -1, ), [getModelMetadataKey('google', 'gemini-2.5-flash-lite')]: toggleBudgetCapability( 'google', { min: 0, max: 24576, step: 1024, allowDynamic: true, disableValue: 0 }, false, 0, ), [getModelMetadataKey('google', 'gemini-2.5-pro')]: budgetOnlyCapability( 'google', { min: 128, max: 32768, step: 1024, allowDynamic: true }, -1, ), [getModelMetadataKey('glm', 'glm-5.1')]: toggleCapability('glm'), [getModelMetadataKey('glm', 'glm-5v-turbo')]: toggleCapability('glm'), [getModelMetadataKey('glm', 'glm-5')]: toggleCapability('glm'), [getModelMetadataKey('glm', 'glm-4.7')]: toggleCapability('glm'), [getModelMetadataKey('glm', 'glm-4.7-flashx')]: toggleCapability('glm'), [getModelMetadataKey('glm', 'glm-4.7-flash')]: toggleCapability('glm'), [getModelMetadataKey('glm', 'glm-4.6')]: toggleCapability('glm'), [getModelMetadataKey('glm', 'glm-4.6v')]: toggleCapability('glm'), [getModelMetadataKey('glm', 'glm-4.6v-flash')]: toggleCapability('glm'), [getModelMetadataKey('qwen', 'qwen3.6-max-preview')]: qwenBudgetDisabled, [getModelMetadataKey('qwen', 'qwen3.6-plus')]: qwenBudgetEnabled, [getModelMetadataKey('qwen', 'qwen3.6-plus-2026-04-02')]: qwenBudgetEnabled, [getModelMetadataKey('qwen', 'qwen3.6-flash')]: qwenBudgetEnabled, [getModelMetadataKey('qwen', 'qwen3.6-flash-2026-04-16')]: qwenBudgetEnabled, [getModelMetadataKey('qwen', 'qwen3.6-35b-a3b')]: qwenBudgetEnabled, [getModelMetadataKey('qwen', 'qwen3.5-flash')]: qwenBudgetEnabled, [getModelMetadataKey('qwen', 'qwen3.5-plus')]: qwenBudgetEnabled, [getModelMetadataKey('qwen', 'qwen3-max')]: qwenBudgetDisabled, [getModelMetadataKey('qwen', 'qwen3-vl-plus')]: qwenBudgetDisabled, [getModelMetadataKey('deepseek', 'deepseek-v4-pro')]: deepseekEffort, [getModelMetadataKey('deepseek', 'deepseek-v4-flash')]: deepseekEffort, [getModelMetadataKey('kimi', 'kimi-k2.6')]: toggleCapability('kimi'), [getModelMetadataKey('kimi', 'kimi-k2.5')]: toggleCapability('kimi'), [getModelMetadataKey('kimi', 'kimi-k2-thinking')]: toggleCapability('kimi'), [getModelMetadataKey('siliconflow', 'deepseek-ai/DeepSeek-R1')]: siliconflowBudget, [getModelMetadataKey('siliconflow', 'deepseek-ai/DeepSeek-R1-Distill-Qwen-7B')]: siliconflowBudget, [getModelMetadataKey('siliconflow', 'Qwen/Qwen3-VL-32B-Instruct')]: siliconflowToggleBudget, [getModelMetadataKey('siliconflow', 'THUDM/GLM-4.1V-9B-Thinking')]: siliconflowBudget, [getModelMetadataKey('siliconflow', 'THUDM/GLM-Z1-Rumination-32B-0414')]: siliconflowBudget, [getModelMetadataKey('doubao', 'doubao-seed-2-0-pro-260215')]: doubaoSeed20Effort, [getModelMetadataKey('doubao', 'doubao-seed-2-0-lite-260215')]: doubaoSeed20Effort, [getModelMetadataKey('doubao', 'doubao-seed-2-0-mini-260215')]: doubaoSeed20Effort, [getModelMetadataKey('doubao', 'doubao-seed-1-8-251228')]: doubaoMode, [getModelMetadataKey('openrouter', 'deepseek/deepseek-v4-pro')]: effortCapability( 'openrouter', ['low', 'medium', 'high'], 'medium', ), [getModelMetadataKey('openrouter', 'deepseek/deepseek-v4-flash')]: effortCapability( 'openrouter', ['low', 'medium', 'high'], 'medium', ), [getModelMetadataKey('grok', 'grok-4.20-reasoning')]: fixedThinkingCapability, [getModelMetadataKey('grok', 'grok-4.20-multi-agent')]: fixedThinkingCapability, [getModelMetadataKey('grok', 'grok-4-1-fast-reasoning')]: fixedThinkingCapability, [getModelMetadataKey('minimax', 'MiniMax-M2.7')]: fixedThinkingCapability, [getModelMetadataKey('tencent-hunyuan', 'hy3-preview')]: hunyuanHy3Effort, [getModelMetadataKey('xiaomi', 'mimo-v2.5-pro')]: toggleCapability('xiaomi'), [getModelMetadataKey('xiaomi', 'mimo-v2.5')]: toggleCapability('xiaomi'), }; export function getCatalogThinkingCapability( providerId: string, modelId: string, ): ThinkingCapability | undefined { return THINKING_CAPABILITIES[getModelMetadataKey(providerId, modelId)]; } export function applyModelMetadata(providers: Record): void { for (const provider of Object.values(providers)) { for (const model of provider.models) { const thinking = getCatalogThinkingCapability(provider.id, model.id); if (thinking) { model.capabilities = { ...model.capabilities, thinking, }; } } } }