| import type { |
| ThinkingCapability, |
| ThinkingConfig, |
| ThinkingEffort, |
| ThinkingLevel, |
| ThinkingMode, |
| } from '@/lib/types/provider'; |
|
|
| export function getThinkingConfigKey(providerId: string, modelId: string): string { |
| return `${providerId}:${modelId}`; |
| } |
|
|
| export function supportsConfigurableThinking( |
| thinking?: ThinkingCapability, |
| ): thinking is ThinkingCapability { |
| return !!thinking?.control && thinking.control !== 'none' && !!thinking.requestAdapter; |
| } |
|
|
| export function clampBudgetForCapability( |
| thinking: ThinkingCapability, |
| budgetTokens?: number, |
| ): number | undefined { |
| const range = thinking.budgetRange; |
| if (!range || typeof budgetTokens !== 'number' || Number.isNaN(budgetTokens)) { |
| return undefined; |
| } |
| if (budgetTokens === -1 && range.allowDynamic) return -1; |
| return Math.max(range.min, Math.min(range.max, Math.round(budgetTokens))); |
| } |
|
|
| export function getThinkingMode( |
| config?: ThinkingConfig, |
| ): 'disabled' | 'enabled' | 'auto' | undefined { |
| if (!config) return undefined; |
| if (config.mode && config.mode !== 'default') return config.mode; |
| if (config.enabled === false) return 'disabled'; |
| if (config.enabled === true) return 'enabled'; |
| return undefined; |
| } |
|
|
| export function pickThinkingEffort( |
| thinking: ThinkingCapability, |
| config: ThinkingConfig, |
| ): ThinkingEffort | undefined { |
| const allowed = thinking.effortValues; |
| if (!allowed?.length) return undefined; |
| if (config.effort && allowed.includes(config.effort)) return config.effort; |
|
|
| const mode = getThinkingMode(config); |
| if (mode === 'disabled') { |
| return ( |
| (allowed.includes('none') && 'none') || |
| (allowed.includes('minimal') && 'minimal') || |
| (allowed.includes('low') && 'low') || |
| thinking.defaultEffort |
| ); |
| } |
| if (mode === 'enabled') return thinking.defaultEffort; |
| return undefined; |
| } |
|
|
| export function pickThinkingLevel( |
| thinking: ThinkingCapability, |
| config: ThinkingConfig, |
| ): ThinkingLevel | undefined { |
| const allowed = thinking.levelValues; |
| if (!allowed?.length) return undefined; |
| if (config.level && allowed.includes(config.level)) return config.level; |
|
|
| const mode = getThinkingMode(config); |
| if (mode === 'disabled') { |
| return ( |
| (allowed.includes('minimal') && 'minimal') || |
| (allowed.includes('low') && 'low') || |
| thinking.defaultLevel |
| ); |
| } |
| if (mode === 'enabled') return thinking.defaultLevel; |
| return undefined; |
| } |
|
|
| export function pickThinkingBudget( |
| thinking: ThinkingCapability, |
| config: ThinkingConfig, |
| ): number | undefined { |
| const range = thinking.budgetRange; |
| if (!range) return undefined; |
|
|
| const mode = getThinkingMode(config); |
| if (mode === 'disabled' && range.disableValue !== undefined) { |
| return range.disableValue; |
| } |
|
|
| const rawBudget = |
| typeof config.budgetTokens === 'number' ? config.budgetTokens : thinking.defaultBudgetTokens; |
| return clampBudgetForCapability(thinking, rawBudget); |
| } |
|
|
| function defaultModeForCapability(thinking: ThinkingCapability): ThinkingMode { |
| return thinking.defaultMode ?? (thinking.defaultEnabled === false ? 'disabled' : 'enabled'); |
| } |
|
|
| function defaultEffortForCapability(thinking: ThinkingCapability): ThinkingEffort | undefined { |
| return thinking.defaultEffort ?? thinking.effortValues?.[0]; |
| } |
|
|
| function defaultLevelForCapability(thinking: ThinkingCapability): ThinkingLevel | undefined { |
| return thinking.defaultLevel ?? thinking.levelValues?.[0]; |
| } |
|
|
| export function getDefaultThinkingConfig( |
| thinking?: ThinkingCapability, |
| ): ThinkingConfig | undefined { |
| if (!supportsConfigurableThinking(thinking)) return undefined; |
|
|
| switch (thinking.control) { |
| case 'effort': { |
| const effort = defaultEffortForCapability(thinking); |
| return effort |
| ? { mode: effort === 'none' ? 'disabled' : 'enabled', effort } |
| : { mode: defaultModeForCapability(thinking) }; |
| } |
| case 'level': { |
| const level = defaultLevelForCapability(thinking); |
| return level ? { mode: 'enabled', level } : { mode: defaultModeForCapability(thinking) }; |
| } |
| case 'toggle': |
| return { mode: defaultModeForCapability(thinking) }; |
| case 'toggle-budget': |
| return { |
| mode: defaultModeForCapability(thinking), |
| budgetTokens: thinking.defaultBudgetTokens, |
| }; |
| case 'budget-only': |
| return { mode: 'enabled', budgetTokens: thinking.defaultBudgetTokens }; |
| case 'mode': |
| return { mode: defaultModeForCapability(thinking) }; |
| default: |
| return undefined; |
| } |
| } |
|
|
| export function normalizeThinkingConfig( |
| thinking: ThinkingCapability | undefined, |
| config: ThinkingConfig | undefined, |
| ): ThinkingConfig | undefined { |
| if (!supportsConfigurableThinking(thinking)) return undefined; |
|
|
| const mode = getThinkingMode(config); |
|
|
| switch (thinking.control) { |
| case 'effort': { |
| const effort = |
| (config ? pickThinkingEffort(thinking, config) : undefined) ?? |
| defaultEffortForCapability(thinking); |
| if (!effort) return undefined; |
| return { mode: effort === 'none' ? 'disabled' : 'enabled', effort }; |
| } |
| case 'level': { |
| const level = |
| (config ? pickThinkingLevel(thinking, config) : undefined) ?? |
| defaultLevelForCapability(thinking); |
| if (!level) return undefined; |
| return { mode: 'enabled', level }; |
| } |
| case 'toggle': |
| return { mode: mode ?? defaultModeForCapability(thinking) }; |
| case 'toggle-budget': { |
| const normalizedMode = mode ?? defaultModeForCapability(thinking); |
| const budget = config ? pickThinkingBudget(thinking, config) : undefined; |
| return { |
| mode: normalizedMode, |
| budgetTokens: budget ?? thinking.defaultBudgetTokens, |
| }; |
| } |
| case 'budget-only': { |
| const budget = config ? pickThinkingBudget(thinking, config) : undefined; |
| return { |
| mode: 'enabled', |
| budgetTokens: budget ?? thinking.defaultBudgetTokens, |
| }; |
| } |
| case 'mode': |
| return { mode: mode ?? defaultModeForCapability(thinking) }; |
| default: |
| return undefined; |
| } |
| } |
|
|
| export function getThinkingDisplayValue( |
| thinking: ThinkingCapability | undefined, |
| config: ThinkingConfig | undefined, |
| ): string | undefined { |
| const normalized = |
| normalizeThinkingConfig(thinking, config) ?? getDefaultThinkingConfig(thinking); |
| if (!supportsConfigurableThinking(thinking) || !normalized) return undefined; |
|
|
| if (thinking.control === 'effort') return normalized.effort; |
| if (thinking.control === 'level') return normalized.level; |
| if (thinking.control === 'budget-only') { |
| return normalized.budgetTokens === -1 ? 'dynamic' : `${normalized.budgetTokens ?? ''}`; |
| } |
| if (thinking.control === 'toggle-budget') { |
| if (normalized.mode === 'disabled') return 'off'; |
| if (normalized.budgetTokens === -1 && thinking.budgetRange?.allowDynamic) return 'auto'; |
| return normalized.budgetTokens && normalized.budgetTokens !== -1 |
| ? `${normalized.budgetTokens}` |
| : 'on'; |
| } |
| if (thinking.control === 'mode') return normalized.mode; |
| return normalized.mode === 'disabled' ? 'off' : 'on'; |
| } |
|
|