import type { ProviderAccount, ProviderVendorInfo } from '@/lib/providers'; import type { ConversationThinkingLevel, ProductModelRef } from '@/types/coding-conversation'; import { getImportedModelProfile } from '../../shared/imported-model-profile'; export interface CodingModelOption { key: string; accountId: string; modelId: string; label: string; availableThinkingLevels: ConversationThinkingLevel[] | null; } const STANDARD_THINKING_LEVELS: readonly ConversationThinkingLevel[] = [ 'off', 'minimal', 'low', 'medium', 'high', ]; const SERVER_REASONING_LEVELS = ['low', 'high', 'max'] as const; function availableThinkingLevels( account: ProviderAccount, modelId: string, ): ConversationThinkingLevel[] | null { const serverCapability = account.metadata?.worksSquareModelCapabilities?.[modelId]; if (serverCapability) { return [ ...(serverCapability.reasoningCanDisable ? ['off' as const] : []), ...SERVER_REASONING_LEVELS.filter((level) => serverCapability.reasoningEfforts.includes(level)), ]; } const profile = getImportedModelProfile(modelId)?.pi; if (!profile) return null; if (!profile.reasoning) return ['off']; if (!profile.thinkingLevelMap) return [...STANDARD_THINKING_LEVELS]; return [ ...STANDARD_THINKING_LEVELS.filter((level) => profile.thinkingLevelMap?.[level] !== null), ...(typeof profile.thinkingLevelMap.max === 'string' ? ['max' as const] : []), ]; } export function codingModelKey(model: Pick): string { return JSON.stringify([model.accountId, model.modelId]); } export function parseCodingModelKey(key: string): Pick | null { try { const value = JSON.parse(key) as unknown; if (!Array.isArray(value) || value.length !== 2) return null; const [accountId, modelId] = value; if (typeof accountId !== 'string' || !accountId.trim() || typeof modelId !== 'string' || !modelId.trim()) return null; return { accountId: accountId.trim(), modelId: modelId.trim() }; } catch { return null; } } export function buildCodingModelOptions( accounts: ProviderAccount[], vendors: ProviderVendorInfo[], ): CodingModelOption[] { const vendorNames = new Map(vendors.map((vendor) => [vendor.id, vendor.name])); const seen = new Set(); const options: CodingModelOption[] = []; for (const account of accounts) { if (!account.enabled) continue; const modelIds = [ account.model, ...(account.fallbackModels ?? []), ...(account.metadata?.customModels ?? []), ]; for (const value of modelIds) { const modelId = value?.trim(); if (!modelId) continue; const key = codingModelKey({ accountId: account.id, modelId }); if (seen.has(key)) continue; seen.add(key); const vendor = vendorNames.get(account.vendorId); options.push({ key, accountId: account.id, modelId, label: `${account.label}${vendor && vendor !== account.label ? ` ยท ${vendor}` : ''} / ${modelId}`, availableThinkingLevels: availableThinkingLevels(account, modelId), }); } } return options; }