SPB Git

spb/zyquo-cloud-web Public MIT

Zyquo Cloud Web — every cloud model, one beautiful chat, entirely in your browser.

TypeScript 81.9% CSS 8.9% JavaScript 7.5% Shell 1.1% HTML 0.6%
31.9 KB · 410 lines typescript
Raw Blame History
1/*2 *  catalog.ts3 *  Zyquo Cloud Web4 *5 *  Author: Simon-Pierre Boucher6 *  Mail: contact@spboucher.ai7 *8 *  The complete model catalog — ALL 170 models ported 1:1 from native9 *  Zyquo Cloud's ModelCatalogData.swift (counts: openai 27, anthropic 11,10 *  xai 5, mistral 10, gemini 14, qwen 32, deepseek 2, kimi 12, perplexity 4,11 *  together 16, deepinfra 34, cerebras 3). Never hardcode models in views or12 *  clients — instances come exclusively from here (+ user custom models).13 */1415import type {16  AIModel,17  ModelCapabilities,18  ModelPricing,19  ParameterSupport,20  Provider,21} from '../types'2223// --- Compact constructors (defaults mirror the native structs) ---2425function C(o: Partial<ModelCapabilities> = {}): ModelCapabilities {26  return {27    vision: false,28    tools: false,29    reasoning: false,30    streaming: true,31    jsonMode: false,32    citations: false,33    ...o,34  }35}3637function P(o: Partial<ParameterSupport> = {}): ParameterSupport {38  return {39    temperature: true,40    topP: true,41    frequencyPenalty: false,42    presencePenalty: false,43    usesMaxCompletionTokens: false,44    reasoningEffort: false,45    thinkingToggle: false,46    requiresStreaming: false,47    ...o,48  }49}5051function $(inputPerMTok: number, outputPerMTok: number): ModelPricing {52  return { inputPerMTok, outputPerMTok }53}5455type Flag = 'rec' | 'legacy'5657function m(58  provider: Provider,59  id: string,60  displayName: string,61  contextWindow: number,62  maxOutputTokens: number | null,63  capabilities: ModelCapabilities,64  pricing: ModelPricing | null,65  parameterSupport: ParameterSupport,66  flag?: Flag67): AIModel {68  return {69    id,70    provider,71    displayName,72    contextWindow,73    maxOutputTokens,74    capabilities,75    pricing,76    parameterSupport,77    isLegacy: flag === 'legacy',78    isRecommended: flag === 'rec',79  }80}8182// --- Shared presets (native: ParameterSupport(), .openAIDefault, openAIReasoning) ---8384const psDefault = P()85const psOpenAI = P({ frequencyPenalty: true, presencePenalty: true })86const psOAIReasoning = P({87  temperature: false,88  topP: false,89  usesMaxCompletionTokens: true,90  reasoningEffort: true,91})9293// --- OpenAI (27) ---9495const openai: AIModel[] = [96  m('openai', 'gpt-5.6-sol', 'GPT-5.6 Sol', 1050000, 128000, C({ vision: true, tools: true, reasoning: true, jsonMode: true }), $(5, 30), psOAIReasoning, 'rec'),97  m('openai', 'gpt-5.6-terra', 'GPT-5.6 Terra', 1050000, 128000, C({ vision: true, tools: true, reasoning: true, jsonMode: true }), $(2.5, 15), psOAIReasoning, 'rec'),98  m('openai', 'gpt-5.6-luna', 'GPT-5.6 Luna', 1050000, 128000, C({ vision: true, tools: true, reasoning: true, jsonMode: true }), $(1, 6), psOAIReasoning),99  m('openai', 'chat-latest', 'ChatGPT Latest', 128000, null, C({ vision: true, tools: true, jsonMode: true }), $(5, 30), P({ frequencyPenalty: true, presencePenalty: true, usesMaxCompletionTokens: true })),100  m('openai', 'gpt-5.5', 'GPT-5.5', 400000, null, C({ vision: true, tools: true, reasoning: true, jsonMode: true }), $(5, 30), psOAIReasoning),101  m('openai', 'gpt-5.4', 'GPT-5.4', 400000, 128000, C({ vision: true, tools: true, reasoning: true, jsonMode: true }), $(2.5, 15), psOAIReasoning),102  m('openai', 'gpt-5.4-mini', 'GPT-5.4 mini', 400000, null, C({ vision: true, tools: true, reasoning: true, jsonMode: true }), $(0.75, 4.5), psOAIReasoning),103  m('openai', 'gpt-5.4-nano', 'GPT-5.4 nano', 400000, null, C({ vision: true, tools: true, reasoning: true, jsonMode: true }), $(0.2, 1.25), psOAIReasoning),104  m('openai', 'gpt-5.3-chat-latest', 'GPT-5.3 Chat Latest', 128000, null, C({ vision: true, tools: true, jsonMode: true }), null, P({ frequencyPenalty: true, presencePenalty: true, usesMaxCompletionTokens: true })),105  m('openai', 'gpt-5.2', 'GPT-5.2', 400000, 128000, C({ vision: true, tools: true, reasoning: true, jsonMode: true }), $(1.75, 14), psOAIReasoning),106  m('openai', 'gpt-5.2-chat-latest', 'GPT-5.2 Chat Latest', 128000, 16000, C({ vision: true, tools: true, jsonMode: true }), $(1.75, 14), P({ frequencyPenalty: true, presencePenalty: true, usesMaxCompletionTokens: true })),107  m('openai', 'gpt-5.1', 'GPT-5.1', 400000, 128000, C({ vision: true, tools: true, reasoning: true, jsonMode: true }), $(1.25, 10), psOAIReasoning),108  m('openai', 'gpt-5', 'GPT-5', 400000, 128000, C({ vision: true, tools: true, reasoning: true, jsonMode: true }), $(1.25, 10), psOAIReasoning),109  m('openai', 'gpt-5-mini', 'GPT-5 mini', 400000, 128000, C({ vision: true, tools: true, reasoning: true, jsonMode: true }), $(0.25, 2), psOAIReasoning),110  m('openai', 'gpt-5-nano', 'GPT-5 nano', 400000, 128000, C({ vision: true, tools: true, reasoning: true, jsonMode: true }), $(0.05, 0.4), psOAIReasoning),111  m('openai', 'o3', 'OpenAI o3', 200000, 100000, C({ vision: true, tools: true, reasoning: true, jsonMode: true }), $(2, 8), psOAIReasoning),112  m('openai', 'o4-mini', 'OpenAI o4-mini', 200000, 100000, C({ vision: true, tools: true, reasoning: true, jsonMode: true }), $(1.1, 4.4), psOAIReasoning),113  m('openai', 'o3-mini', 'OpenAI o3-mini', 200000, 100000, C({ tools: true, reasoning: true, jsonMode: true }), $(1.1, 4.4), psOAIReasoning, 'legacy'),114  m('openai', 'o1', 'OpenAI o1', 200000, 100000, C({ vision: true, tools: true, reasoning: true, jsonMode: true }), $(15, 60), psOAIReasoning, 'legacy'),115  m('openai', 'gpt-4.1', 'GPT-4.1', 1047576, 32768, C({ vision: true, tools: true, jsonMode: true }), $(2, 8), psOpenAI, 'legacy'),116  m('openai', 'gpt-4.1-mini', 'GPT-4.1 mini', 1047576, 32768, C({ vision: true, tools: true, jsonMode: true }), $(0.4, 1.6), psOpenAI, 'legacy'),117  m('openai', 'gpt-4.1-nano', 'GPT-4.1 nano', 1047576, 32768, C({ vision: true, tools: true, jsonMode: true }), $(0.1, 0.4), psOpenAI, 'legacy'),118  m('openai', 'gpt-4o', 'GPT-4o', 128000, 16384, C({ vision: true, tools: true, jsonMode: true }), $(2.5, 10), psOpenAI, 'legacy'),119  m('openai', 'gpt-4o-mini', 'GPT-4o mini', 128000, 16384, C({ vision: true, tools: true, jsonMode: true }), $(0.15, 0.6), psOpenAI, 'legacy'),120  m('openai', 'gpt-4-turbo', 'GPT-4 Turbo', 128000, 4096, C({ vision: true, tools: true, jsonMode: true }), $(10, 30), psOpenAI, 'legacy'),121  m('openai', 'gpt-4', 'GPT-4', 8192, 8192, C({ tools: true }), $(30, 60), psOpenAI, 'legacy'),122  m('openai', 'gpt-3.5-turbo', 'GPT-3.5 Turbo', 16385, 4096, C({ tools: true, jsonMode: true }), $(0.5, 1.5), psOpenAI, 'legacy'),123]124125// --- Anthropic (11) ---126127const psClaudeThinking = P({ temperature: false, topP: false, thinkingToggle: true })128const psClaudeClassic = P({ thinkingToggle: true })129130const anthropic: AIModel[] = [131  m('anthropic', 'claude-opus-5', 'Claude Opus 5', 1000000, 128000, C({ vision: true, tools: true, reasoning: true, jsonMode: true }), $(5, 25), psClaudeThinking, 'rec'),132  m('anthropic', 'claude-sonnet-5', 'Claude Sonnet 5', 1000000, 128000, C({ vision: true, tools: true, reasoning: true, jsonMode: true }), $(3, 15), psClaudeThinking, 'rec'),133  // Thinking always on — no toggle sent.134  m('anthropic', 'claude-fable-5', 'Claude Fable 5', 1000000, 128000, C({ vision: true, tools: true, reasoning: true, jsonMode: true }), $(10, 50), P({ temperature: false, topP: false })),135  m('anthropic', 'claude-opus-4-8', 'Claude Opus 4.8', 1000000, 128000, C({ vision: true, tools: true, reasoning: true, jsonMode: true }), $(5, 25), psClaudeThinking),136  m('anthropic', 'claude-opus-4-7', 'Claude Opus 4.7', 1000000, 128000, C({ vision: true, tools: true, reasoning: true, jsonMode: true }), $(5, 25), psClaudeThinking),137  m('anthropic', 'claude-opus-4-6', 'Claude Opus 4.6', 1000000, 128000, C({ vision: true, tools: true, reasoning: true, jsonMode: true }), $(5, 25), psClaudeClassic),138  m('anthropic', 'claude-sonnet-4-6', 'Claude Sonnet 4.6', 1000000, 128000, C({ vision: true, tools: true, reasoning: true, jsonMode: true }), $(3, 15), psClaudeClassic),139  m('anthropic', 'claude-haiku-4-5-20251001', 'Claude Haiku 4.5', 200000, 64000, C({ vision: true, tools: true, reasoning: true, jsonMode: true }), $(1, 5), psClaudeClassic),140  m('anthropic', 'claude-opus-4-5-20251101', 'Claude Opus 4.5', 200000, 64000, C({ vision: true, tools: true, reasoning: true, jsonMode: true }), $(5, 25), psClaudeClassic, 'legacy'),141  m('anthropic', 'claude-sonnet-4-5-20250929', 'Claude Sonnet 4.5', 1000000, 64000, C({ vision: true, tools: true, reasoning: true, jsonMode: true }), $(3, 15), psClaudeClassic, 'legacy'),142  m('anthropic', 'claude-opus-4-1-20250805', 'Claude Opus 4.1', 200000, 32000, C({ vision: true, tools: true, reasoning: true, jsonMode: true }), $(15, 75), psClaudeClassic, 'legacy'),143]144145// --- xAI (5) ---146147const xai: AIModel[] = [148  m('xai', 'grok-4.5', 'Grok 4.5', 500000, null, C({ vision: true, tools: true, reasoning: true, jsonMode: true }), $(2, 6), P({ reasoningEffort: true }), 'rec'),149  m('xai', 'grok-4.3', 'Grok 4.3', 1000000, null, C({ vision: true, tools: true, reasoning: true, jsonMode: true }), $(1.25, 2.5), P({ reasoningEffort: true })),150  m('xai', 'grok-4.20', 'Grok 4.20 Reasoning', 1000000, null, C({ vision: true, tools: true, reasoning: true, jsonMode: true }), $(1.25, 2.5), psDefault),151  m('xai', 'grok-4.20-non-reasoning', 'Grok 4.20 Non-Reasoning', 1000000, null, C({ vision: true, tools: true, jsonMode: true }), $(1.25, 2.5), psDefault),152  m('xai', 'grok-code-fast-1', 'Grok Code Fast 1', 256000, null, C({ vision: true, tools: true, reasoning: true, jsonMode: true }), $(1, 2), psDefault, 'rec'),153]154155// --- Mistral (10) ---156157const mistral: AIModel[] = [158  m('mistral', 'mistral-medium-latest', 'Mistral Medium 3.5', 262144, null, C({ vision: true, tools: true, reasoning: true, jsonMode: true }), $(1.5, 7.5), P({ frequencyPenalty: true, presencePenalty: true, reasoningEffort: true }), 'rec'),159  m('mistral', 'mistral-large-latest', 'Mistral Large 3', 262144, null, C({ vision: true, tools: true, jsonMode: true }), $(0.5, 1.5), psOpenAI, 'rec'),160  m('mistral', 'mistral-small-latest', 'Mistral Small 4', 262144, null, C({ vision: true, tools: true, reasoning: true, jsonMode: true }), $(0.15, 0.6), P({ frequencyPenalty: true, presencePenalty: true, reasoningEffort: true }), 'rec'),161  m('mistral', 'codestral-latest', 'Codestral', 256000, null, C({ tools: true, jsonMode: true }), $(0.3, 0.9), psOpenAI),162  m('mistral', 'ministral-14b-latest', 'Ministral 3 14B', 262144, null, C({ vision: true, tools: true, jsonMode: true }), $(0.2, 0.2), psOpenAI),163  m('mistral', 'ministral-8b-latest', 'Ministral 3 8B', 262144, null, C({ vision: true, tools: true, jsonMode: true }), $(0.15, 0.15), psOpenAI),164  m('mistral', 'ministral-3b-latest', 'Ministral 3 3B', 131072, null, C({ vision: true, tools: true, jsonMode: true }), $(0.1, 0.1), psOpenAI),165  m('mistral', 'magistral-medium-latest', 'Magistral Medium', 131072, null, C({ tools: true, reasoning: true, jsonMode: true }), $(2, 5), psOpenAI, 'legacy'),166  m('mistral', 'devstral-latest', 'Devstral 2', 262144, null, C({ tools: true, jsonMode: true }), $(0.4, 2), psOpenAI, 'legacy'),167  m('mistral', 'open-mistral-nemo', 'Mistral Nemo', 131072, null, C({ tools: true, jsonMode: true }), $(0.15, 0.15), psOpenAI, 'legacy'),168]169170// --- Google Gemini (14) ---171172const psGemini = P({ reasoningEffort: true })173174const gemini: AIModel[] = [175  m('gemini', 'gemini-3.6-flash', 'Gemini 3.6 Flash', 1048576, 65536, C({ vision: true, tools: true, reasoning: true, jsonMode: true }), $(1.5, 7.5), psGemini, 'rec'),176  m('gemini', 'gemini-3.5-flash', 'Gemini 3.5 Flash', 1048576, 65536, C({ vision: true, tools: true, reasoning: true, jsonMode: true }), $(1.5, 9), psGemini),177  m('gemini', 'gemini-3.5-flash-lite', 'Gemini 3.5 Flash-Lite', 1048576, 65536, C({ vision: true, tools: true, reasoning: true, jsonMode: true }), $(0.3, 2.5), psGemini, 'rec'),178  m('gemini', 'gemini-3.1-pro-preview', 'Gemini 3.1 Pro (Preview)', 1048576, 65536, C({ vision: true, tools: true, reasoning: true, jsonMode: true }), $(2, 12), psGemini, 'rec'),179  m('gemini', 'gemini-3.1-flash-lite', 'Gemini 3.1 Flash-Lite', 1048576, 65536, C({ vision: true, tools: true, reasoning: true, jsonMode: true }), $(0.25, 1.5), psGemini),180  m('gemini', 'gemini-2.5-pro', 'Gemini 2.5 Pro', 1048576, 65536, C({ vision: true, tools: true, reasoning: true, jsonMode: true }), $(1.25, 10), psGemini),181  m('gemini', 'gemini-2.5-flash', 'Gemini 2.5 Flash', 1048576, 65536, C({ vision: true, tools: true, reasoning: true, jsonMode: true }), $(0.3, 2.5), psGemini),182  m('gemini', 'gemini-2.5-flash-lite', 'Gemini 2.5 Flash-Lite', 1048576, 65536, C({ vision: true, tools: true, reasoning: true, jsonMode: true }), $(0.1, 0.4), psGemini),183  m('gemini', 'gemini-pro-latest', 'Gemini Pro (Latest)', 1048576, 65536, C({ vision: true, tools: true, reasoning: true, jsonMode: true }), null, psGemini),184  m('gemini', 'gemini-flash-latest', 'Gemini Flash (Latest)', 1048576, 65536, C({ vision: true, tools: true, reasoning: true, jsonMode: true }), null, psGemini),185  m('gemini', 'gemini-flash-lite-latest', 'Gemini Flash-Lite (Latest)', 1048576, 65536, C({ vision: true, tools: true, reasoning: true, jsonMode: true }), null, psGemini),186  m('gemini', 'gemini-3-flash-preview', 'Gemini 3 Flash (Preview)', 1048576, 65536, C({ vision: true, tools: true, reasoning: true, jsonMode: true }), $(0.5, 3), psGemini),187  m('gemini', 'gemma-4-26b-a4b-it', 'Gemma 4 26B', 262144, 32768, C({ jsonMode: true }), null, psDefault),188  m('gemini', 'gemma-4-31b-it', 'Gemma 4 31B', 262144, 32768, C({ jsonMode: true }), null, psDefault),189]190191// --- Alibaba Qwen / DashScope intl (32) ---192193const psQwenThinking = P({ thinkingToggle: true })194const psQwenStream = P({ requiresStreaming: true })195196const qwen: AIModel[] = [197  m('qwen', 'qwen3.7-max', 'Qwen3.7 Max', 1000000, null, C({ tools: true, reasoning: true, jsonMode: true }), $(2.5, 7.5), psQwenThinking, 'rec'),198  m('qwen', 'qwen3.7-plus', 'Qwen3.7 Plus', 1000000, 65536, C({ vision: true, tools: true, reasoning: true, jsonMode: true }), $(0.32, 1.28), psQwenThinking, 'rec'),199  m('qwen', 'qwen3.7-flash', 'Qwen3.7 Flash', 1000000, 65536, C({ vision: true, tools: true, reasoning: true, jsonMode: true }), $(0.03, 0.13), psQwenThinking, 'rec'),200  m('qwen', 'qwen3.6-plus', 'Qwen3.6 Plus', 1000000, null, C({ vision: true, tools: true, reasoning: true, jsonMode: true }), null, psQwenThinking),201  m('qwen', 'qwen3.6-flash', 'Qwen3.6 Flash', 1000000, null, C({ vision: true, tools: true, reasoning: true, jsonMode: true }), null, psQwenThinking),202  m('qwen', 'qwen3.5-plus', 'Qwen3.5 Plus', 1000000, null, C({ vision: true, tools: true, reasoning: true, jsonMode: true }), null, psQwenThinking),203  m('qwen', 'qwen3.5-flash', 'Qwen3.5 Flash', 1000000, null, C({ vision: true, tools: true, reasoning: true, jsonMode: true }), null, psQwenThinking),204  m('qwen', 'qwen-max', 'Qwen Max', 128000, null, C({ tools: true, reasoning: true, jsonMode: true }), null, psQwenThinking),205  m('qwen', 'qwen-plus', 'Qwen Plus', 1000000, null, C({ tools: true, reasoning: true, jsonMode: true }), null, psQwenThinking),206  m('qwen', 'qwen-turbo', 'Qwen Turbo', 1000000, null, C({ tools: true, reasoning: true, jsonMode: true }), null, psQwenThinking, 'legacy'),207  m('qwen', 'qwen-flash', 'Qwen Flash', 1000000, null, C({ tools: true, reasoning: true, jsonMode: true }), null, psQwenThinking),208  m('qwen', 'qwen3-coder-plus', 'Qwen3 Coder Plus', 1000000, null, C({ tools: true, jsonMode: true }), null, psDefault),209  m('qwen', 'qwen3-coder-flash', 'Qwen3 Coder Flash', 1000000, null, C({ tools: true, jsonMode: true }), null, psDefault),210  m('qwen', 'qwen3-coder-next', 'Qwen3 Coder Next', 262144, null, C({ tools: true, jsonMode: true }), null, psDefault),211  m('qwen', 'qwen3-coder-480b-a35b-instruct', 'Qwen3 Coder 480B A35B', 262144, null, C({ tools: true, jsonMode: true }), null, psDefault),212  m('qwen', 'qwen3-vl-plus', 'Qwen3 VL Plus', 1000000, 65536, C({ vision: true, tools: true, reasoning: true, jsonMode: true }), null, psQwenThinking),213  m('qwen', 'qwen3-vl-flash', 'Qwen3 VL Flash', 1000000, 65536, C({ vision: true, tools: true, reasoning: true, jsonMode: true }), null, psQwenThinking),214  m('qwen', 'qwen3-vl-235b-a22b-instruct', 'Qwen3 VL 235B Instruct', 131072, null, C({ vision: true, tools: true, jsonMode: true }), null, psDefault),215  m('qwen', 'qwen3-vl-235b-a22b-thinking', 'Qwen3 VL 235B Thinking', 131072, null, C({ vision: true, tools: true, reasoning: true, jsonMode: true }), null, psDefault),216  m('qwen', 'qvq-max', 'QVQ Max', 131072, null, C({ vision: true, reasoning: true, jsonMode: true }), null, psQwenStream),217  m('qwen', 'qwq-plus', 'QwQ Plus', 131072, null, C({ tools: true, reasoning: true, jsonMode: true }), null, psQwenStream),218  m('qwen', 'qwen3.5-397b-a17b', 'Qwen3.5 397B A17B', 262144, null, C({ tools: true, reasoning: true, jsonMode: true }), null, psQwenThinking),219  m('qwen', 'qwen3.5-122b-a10b', 'Qwen3.5 122B A10B', 262144, null, C({ tools: true, reasoning: true, jsonMode: true }), null, psQwenThinking),220  m('qwen', 'qwen3.5-35b-a3b', 'Qwen3.5 35B A3B', 262144, null, C({ tools: true, reasoning: true, jsonMode: true }), null, psQwenThinking),221  m('qwen', 'qwen3-235b-a22b-instruct-2507', 'Qwen3 235B Instruct 2507', 262144, null, C({ tools: true, jsonMode: true }), null, psDefault),222  m('qwen', 'qwen3-235b-a22b-thinking-2507', 'Qwen3 235B Thinking 2507', 262144, null, C({ tools: true, reasoning: true, jsonMode: true }), null, psDefault),223  m('qwen', 'qwen3-next-80b-a3b-instruct', 'Qwen3 Next 80B Instruct', 262144, null, C({ tools: true, jsonMode: true }), null, psDefault),224  m('qwen', 'qwen3-next-80b-a3b-thinking', 'Qwen3 Next 80B Thinking', 262144, null, C({ tools: true, reasoning: true, jsonMode: true }), null, psDefault),225  m('qwen', 'deepseek-v4-pro', 'DeepSeek V4 Pro (DashScope)', 1000000, null, C({ tools: true, reasoning: true, jsonMode: true }), null, psQwenThinking),226  m('qwen', 'deepseek-v4-flash', 'DeepSeek V4 Flash (DashScope)', 1000000, null, C({ tools: true, reasoning: true, jsonMode: true }), null, psQwenThinking),227  m('qwen', 'glm-5.2', 'GLM 5.2 (DashScope)', 198000, null, C({ tools: true, reasoning: true, jsonMode: true }), null, psQwenThinking),228  m('qwen', 'kimi-k2.7-code', 'Kimi K2.7 Code (DashScope)', 262144, null, C({ tools: true, reasoning: true, jsonMode: true }), null, psQwenThinking),229]230231// --- DeepSeek (2) ---232233const psDeepSeek = P({ reasoningEffort: true, thinkingToggle: true })234235const deepseek: AIModel[] = [236  m('deepseek', 'deepseek-v4-flash', 'DeepSeek V4 Flash', 1000000, 384000, C({ tools: true, reasoning: true, jsonMode: true }), $(0.14, 0.28), psDeepSeek, 'rec'),237  m('deepseek', 'deepseek-v4-pro', 'DeepSeek V4 Pro', 1000000, 384000, C({ tools: true, reasoning: true, jsonMode: true }), $(0.435, 0.87), psDeepSeek, 'rec'),238]239240// --- Kimi / Moonshot (12) ---241242const psKimiMax = P({ temperature: false, topP: false, usesMaxCompletionTokens: true })243244const kimi: AIModel[] = [245  m('kimi', 'kimi-k3', 'Kimi K3', 1048576, 131072, C({ vision: true, tools: true, reasoning: true, jsonMode: true }), $(3, 15), psOAIReasoning, 'rec'),246  m('kimi', 'kimi-k2.7-code', 'Kimi K2.7 Code', 262144, null, C({ vision: true, tools: true, reasoning: true, jsonMode: true }), $(0.95, 4), psKimiMax, 'rec'),247  m('kimi', 'kimi-k2.7-code-highspeed', 'Kimi K2.7 Code Highspeed', 262144, null, C({ vision: true, tools: true, reasoning: true, jsonMode: true }), $(1.9, 8), psKimiMax),248  m('kimi', 'kimi-k2.6', 'Kimi K2.6', 262144, null, C({ vision: true, tools: true, reasoning: true, jsonMode: true }), $(0.95, 4), P({ temperature: false, topP: false, usesMaxCompletionTokens: true, thinkingToggle: true })),249  m('kimi', 'kimi-k2.5', 'Kimi K2.5', 262144, null, C({ vision: true, tools: true, reasoning: true, jsonMode: true }), $(0.6, 3), P({ temperature: false, topP: false, usesMaxCompletionTokens: true, thinkingToggle: true })),250  m('kimi', 'moonshot-v1-8k', 'Moonshot v1 8K', 8192, null, C({ tools: true, jsonMode: true }), $(0.2, 2), psOpenAI, 'legacy'),251  m('kimi', 'moonshot-v1-32k', 'Moonshot v1 32K', 32768, null, C({ tools: true, jsonMode: true }), $(1, 3), psOpenAI, 'legacy'),252  m('kimi', 'moonshot-v1-128k', 'Moonshot v1 128K', 131072, null, C({ tools: true, jsonMode: true }), $(2, 5), psOpenAI, 'legacy'),253  m('kimi', 'moonshot-v1-auto', 'Moonshot v1 Auto', 131072, null, C({ tools: true, jsonMode: true }), null, psOpenAI, 'legacy'),254  m('kimi', 'moonshot-v1-8k-vision-preview', 'Moonshot v1 8K Vision', 8192, null, C({ vision: true, tools: true, jsonMode: true }), $(0.2, 2), psOpenAI, 'legacy'),255  m('kimi', 'moonshot-v1-32k-vision-preview', 'Moonshot v1 32K Vision', 32768, null, C({ vision: true, tools: true, jsonMode: true }), $(1, 3), psOpenAI, 'legacy'),256  m('kimi', 'moonshot-v1-128k-vision-preview', 'Moonshot v1 128K Vision', 131072, null, C({ vision: true, tools: true, jsonMode: true }), $(2, 5), psOpenAI, 'legacy'),257]258259// --- Perplexity (4) — all citations, no /models endpoint ---260261const perplexity: AIModel[] = [262  m('perplexity', 'sonar', 'Sonar', 128000, 128000, C({ jsonMode: true, citations: true }), $(1, 1), psDefault, 'rec'),263  m('perplexity', 'sonar-pro', 'Sonar Pro', 200000, 8000, C({ jsonMode: true, citations: true }), $(3, 15), psDefault, 'rec'),264  m('perplexity', 'sonar-reasoning-pro', 'Sonar Reasoning Pro', 128000, null, C({ reasoning: true, jsonMode: true, citations: true }), $(2, 8), P({ reasoningEffort: true })),265  m('perplexity', 'sonar-deep-research', 'Sonar Deep Research', 128000, null, C({ reasoning: true, jsonMode: true, citations: true }), $(2, 8), P({ reasoningEffort: true })),266]267268// --- Together AI (16) ---269270const psTogetherStream = P({ frequencyPenalty: true, presencePenalty: true, requiresStreaming: true })271272const together: AIModel[] = [273  m('together', 'moonshotai/Kimi-K3', 'Kimi K3', 1000000, null, C({ tools: true, reasoning: true, jsonMode: true }), $(3, 15), psOpenAI, 'rec'),274  m('together', 'moonshotai/Kimi-K2.7-Code', 'Kimi K2.7 Code', 262144, null, C({ tools: true, reasoning: true, jsonMode: true }), $(0.95, 4), psOpenAI),275  m('together', 'moonshotai/Kimi-K2.6', 'Kimi K2.6', 262144, null, C({ tools: true, reasoning: true, jsonMode: true }), $(1.2, 4.5), psOpenAI),276  m('together', 'deepseek-ai/DeepSeek-V4-Pro', 'DeepSeek V4 Pro', 512000, null, C({ tools: true, reasoning: true, jsonMode: true }), $(1.74, 3.48), psOpenAI, 'rec'),277  m('together', 'zai-org/GLM-5.2', 'GLM 5.2', 512000, null, C({ tools: true, reasoning: true, jsonMode: true }), $(1.4, 4.4), psOpenAI),278  m('together', 'Qwen/Qwen3.7-Max', 'Qwen3.7 Max', 1000000, null, C({ tools: true, reasoning: true, jsonMode: true }), $(1.25, 3.75), psTogetherStream),279  m('together', 'Qwen/Qwen3.7-Plus', 'Qwen3.7 Plus', 1000000, null, C({ tools: true, jsonMode: true }), $(0.32, 1.28), psTogetherStream),280  m('together', 'Qwen/Qwen3.6-Plus', 'Qwen3.6 Plus', 1000000, null, C({ tools: true, jsonMode: true }), $(0.5, 3), psTogetherStream),281  m('together', 'Qwen/Qwen3.5-9B', 'Qwen3.5 9B', 262144, null, C({ tools: true, jsonMode: true }), $(0.17, 0.25), psTogetherStream),282  m('together', 'meta-llama/Llama-3.3-70B-Instruct-Turbo', 'Llama 3.3 70B Turbo', 131072, null, C({ tools: true, jsonMode: true }), $(1.04, 1.04), psOpenAI),283  m('together', 'openai/gpt-oss-120b', 'GPT-OSS 120B', 131072, null, C({ tools: true, reasoning: true, jsonMode: true }), $(0.15, 0.6), P({ frequencyPenalty: true, presencePenalty: true, reasoningEffort: true }), 'rec'),284  m('together', 'openai/gpt-oss-20b', 'GPT-OSS 20B', 131072, null, C({ tools: true, reasoning: true, jsonMode: true }), $(0.05, 0.2), P({ frequencyPenalty: true, presencePenalty: true, reasoningEffort: true })),285  m('together', 'nvidia/nemotron-3-ultra-550b-a55b', 'Nemotron 3 Ultra 550B', 512288, null, C({ tools: true, reasoning: true, jsonMode: true }), $(0.6, 3.6), psOpenAI),286  m('together', 'MiniMaxAI/MiniMax-M3', 'MiniMax M3', 524288, null, C({ tools: true, reasoning: true, jsonMode: true }), $(0.3, 1.2), psOpenAI),287  // Vision explicitly false — endpoint streams empty on images (verified 2026-07-30 natively).288  m('together', 'google/gemma-4-31B-it', 'Gemma 4 31B', 262144, null, C({ tools: true, jsonMode: true }), $(0.39, 0.97), psTogetherStream),289  m('together', 'thinkingmachines/Inkling', 'Inkling', 524288, null, C({ tools: true, reasoning: true, jsonMode: true }), $(1, 4.05), psOpenAI),290]291292// --- DeepInfra (34) ---293294const deepinfra: AIModel[] = [295  // Proxied Anthropic/Google models use bare defaults (no penalties).296  m('deepinfra', 'anthropic/claude-fable-5', 'Claude Fable 5', 1000000, null, C({ vision: true, tools: true, reasoning: true, jsonMode: true }), $(10, 50), psDefault),297  m('deepinfra', 'anthropic/claude-opus-5', 'Claude Opus 5', 1000000, null, C({ vision: true, tools: true, reasoning: true, jsonMode: true }), $(5, 25), psDefault),298  m('deepinfra', 'anthropic/claude-sonnet-5', 'Claude Sonnet 5', 1000000, null, C({ vision: true, tools: true, reasoning: true, jsonMode: true }), $(2, 10), psDefault),299  m('deepinfra', 'anthropic/claude-opus-4-8', 'Claude Opus 4.8', 1000000, null, C({ vision: true, tools: true, reasoning: true, jsonMode: true }), $(5, 25), psDefault),300  m('deepinfra', 'anthropic/claude-haiku-4-5', 'Claude Haiku 4.5', 200000, null, C({ vision: true, tools: true, reasoning: true, jsonMode: true }), $(1, 5), psDefault),301  m('deepinfra', 'google/gemini-3.1-pro', 'Gemini 3.1 Pro', 1000000, null, C({ vision: true, tools: true, reasoning: true, jsonMode: true }), $(2, 12), psDefault),302  m('deepinfra', 'google/gemini-3.5-flash', 'Gemini 3.5 Flash', 1000000, null, C({ vision: true, tools: true, reasoning: true, jsonMode: true }), $(1.5, 9), psDefault),303  m('deepinfra', 'google/gemini-3.1-flash-lite', 'Gemini 3.1 Flash-Lite', 1000000, null, C({ vision: true, tools: true, jsonMode: true }), $(0.25, 1.5), psDefault),304  m('deepinfra', 'google/gemini-2.5-pro', 'Gemini 2.5 Pro', 1000000, null, C({ vision: true, tools: true, reasoning: true, jsonMode: true }), $(1.25, 10), psDefault),305  m('deepinfra', 'google/gemini-2.5-flash', 'Gemini 2.5 Flash', 1000000, null, C({ vision: true, tools: true, reasoning: true, jsonMode: true }), $(0.3, 2.5), psDefault),306  m('deepinfra', 'deepseek-ai/DeepSeek-V4-Pro', 'DeepSeek V4 Pro', 1048576, null, C({ tools: true, reasoning: true, jsonMode: true }), $(1.3, 2.6), psOpenAI, 'rec'),307  m('deepinfra', 'deepseek-ai/DeepSeek-V4-Flash', 'DeepSeek V4 Flash', 1048576, null, C({ tools: true, jsonMode: true }), $(0.09, 0.18), psOpenAI, 'rec'),308  m('deepinfra', 'deepseek-ai/DeepSeek-V3.1', 'DeepSeek V3.1', 163840, null, C({ tools: true, reasoning: true, jsonMode: true }), $(0.25, 0.95), psOpenAI),309  m('deepinfra', 'deepseek-ai/DeepSeek-R1-0528', 'DeepSeek R1 0528', 163840, null, C({ reasoning: true }), $(0.5, 2.15), psOpenAI),310  m('deepinfra', 'moonshotai/Kimi-K2.7-Code', 'Kimi K2.7 Code', 262144, null, C({ tools: true, reasoning: true, jsonMode: true }), $(0.74, 3.5), psOpenAI),311  m('deepinfra', 'moonshotai/Kimi-K2.6', 'Kimi K2.6', 262144, null, C({ tools: true, reasoning: true, jsonMode: true }), $(0.75, 3.5), psOpenAI),312  m('deepinfra', 'moonshotai/Kimi-K2.5', 'Kimi K2.5', 262144, null, C({ tools: true, jsonMode: true }), $(0.45, 2.25), psTogetherStream),313  m('deepinfra', 'zai-org/GLM-5.2', 'GLM 5.2', 1048576, null, C({ tools: true, reasoning: true, jsonMode: true }), $(0.75, 2.4), psOpenAI, 'rec'),314  m('deepinfra', 'zai-org/GLM-4.7', 'GLM 4.7', 202752, null, C({ tools: true, reasoning: true, jsonMode: true }), $(0.4, 1.75), psOpenAI),315  m('deepinfra', 'Qwen/Qwen3.7-Max', 'Qwen3.7 Max', 256000, null, C({ tools: true, reasoning: true, jsonMode: true }), $(2.5, 7.5), psOpenAI),316  m('deepinfra', 'Qwen/Qwen3.5-397B-A17B', 'Qwen3.5 397B A17B', 262144, null, C({ tools: true, reasoning: true, jsonMode: true }), $(0.45, 3), psOpenAI),317  m('deepinfra', 'Qwen/Qwen3-235B-A22B-Instruct-2507', 'Qwen3 235B Instruct 2507', 262144, null, C({ tools: true, jsonMode: true }), $(0.09, 0.55), psOpenAI),318  m('deepinfra', 'Qwen/Qwen3-235B-A22B-Thinking-2507', 'Qwen3 235B Thinking 2507', 262144, null, C({ tools: true, reasoning: true, jsonMode: true }), $(0.23, 2.3), psOpenAI),319  m('deepinfra', 'Qwen/Qwen3-Coder-480B-A35B-Instruct-Turbo', 'Qwen3 Coder 480B Turbo', 262144, null, C({ tools: true, jsonMode: true }), $(0.3, 1), psOpenAI),320  m('deepinfra', 'Qwen/Qwen3-VL-235B-A22B-Instruct', 'Qwen3 VL 235B', 262144, null, C({ vision: true, tools: true, jsonMode: true }), $(0.2, 0.88), psOpenAI),321  m('deepinfra', 'meta-llama/Llama-4-Maverick-17B-128E-Instruct-FP8', 'Llama 4 Maverick', 1048576, null, C({ vision: true, tools: true, jsonMode: true }), $(0.2, 0.8), psOpenAI),322  m('deepinfra', 'meta-llama/Llama-4-Scout-17B-16E-Instruct', 'Llama 4 Scout', 327680, null, C({ vision: true, tools: true, jsonMode: true }), $(0.1, 0.3), psOpenAI),323  m('deepinfra', 'meta-llama/Llama-3.3-70B-Instruct-Turbo', 'Llama 3.3 70B Turbo', 131072, null, C({ tools: true, jsonMode: true }), $(0.1, 0.32), psOpenAI),324  m('deepinfra', 'meta-llama/Meta-Llama-3.1-8B-Instruct-Turbo', 'Llama 3.1 8B Turbo', 131072, null, C({ tools: true, jsonMode: true }), $(0.02, 0.04), psOpenAI),325  m('deepinfra', 'openai/gpt-oss-120b', 'GPT-OSS 120B', 131072, null, C({ tools: true, reasoning: true, jsonMode: true }), $(0.037, 0.17), P({ frequencyPenalty: true, presencePenalty: true, reasoningEffort: true }), 'rec'),326  m('deepinfra', 'openai/gpt-oss-20b', 'GPT-OSS 20B', 131072, null, C({ tools: true, reasoning: true, jsonMode: true }), $(0.03, 0.14), P({ frequencyPenalty: true, presencePenalty: true, reasoningEffort: true })),327  m('deepinfra', 'MiniMaxAI/MiniMax-M3', 'MiniMax M3', 524288, null, C({ tools: true, reasoning: true, jsonMode: true }), $(0.3, 1.2), psOpenAI),328  m('deepinfra', 'nvidia/NVIDIA-Nemotron-3-Ultra-550B-A55B', 'Nemotron 3 Ultra 550B', 262144, null, C({ tools: true, reasoning: true, jsonMode: true }), $(0.5, 2.2), psOpenAI),329  m('deepinfra', 'mistralai/Mistral-Small-3.2-24B-Instruct-2506', 'Mistral Small 3.2 24B', 128000, null, C({ vision: true, tools: true, jsonMode: true }), $(0.075, 0.2), psOpenAI),330]331332// --- Cerebras (3) ---333334const psCerebras = P({335  frequencyPenalty: true,336  presencePenalty: true,337  usesMaxCompletionTokens: true,338  reasoningEffort: true,339})340341const cerebras: AIModel[] = [342  m('cerebras', 'gpt-oss-120b', 'GPT-OSS 120B', 131072, 40000, C({ tools: true, reasoning: true, jsonMode: true }), $(0.35, 0.75), psCerebras, 'rec'),343  m('cerebras', 'gemma-4-31b', 'Gemma 4 31B', 131072, 40000, C({ vision: true, tools: true, reasoning: true, jsonMode: true }), $(0.99, 1.49), psCerebras),344  // Provider-announced discontinuation 2026-08-17.345  m('cerebras', 'zai-glm-4.7', 'GLM 4.7', 131072, 40000, C({ tools: true, reasoning: true, jsonMode: true }), $(2.25, 2.75), psCerebras, 'legacy'),346]347348// --- Aggregate (concatenation order is load-bearing: defaultModel = first recommended) ---349350export const CATALOG: readonly AIModel[] = [351  ...openai,352  ...anthropic,353  ...xai,354  ...mistral,355  ...gemini,356  ...qwen,357  ...deepseek,358  ...kimi,359  ...perplexity,360  ...together,361  ...deepinfra,362  ...cerebras,363]364365// --- Catalog queries (ported from ModelCatalog.swift) ---366367/** All catalog models for one provider (unranked — rank in the UI layer with favorites). */368export function modelsFor(provider: Provider): AIModel[] {369  return CATALOG.filter((model) => model.provider === provider)370}371372/** Lookup keyed on (provider, id) — ids duplicate across providers. */373export function findModel(provider: Provider, id: string): AIModel | undefined {374  return CATALOG.find((model) => model.provider === provider && model.id === id)375}376377/**378 * Cheapest non-legacy model for a provider, preferring non-reasoning models379 * (falls back to all candidates). Used for key tests and title generation.380 */381export function cheapestModel(provider: Provider): AIModel | undefined {382  const candidates = modelsFor(provider).filter((model) => !model.isLegacy)383  const preferred = candidates.filter((model) => !model.capabilities.reasoning)384  const pool = preferred.length > 0 ? preferred : candidates385  let best: AIModel | undefined386  let bestPrice = Infinity387  for (const model of pool) {388    const price = model.pricing?.outputPerMTok ?? Infinity389    if (price < bestPrice || best === undefined) {390      best = model391      bestPrice = price392    }393  }394  return best395}396397/** First recommended model in catalog order (gpt-5.6-sol). */398export function defaultModel(): AIModel {399  const recommended = CATALOG.find((model) => model.isRecommended)400  return recommended ?? (CATALOG[0] as AIModel)401}402403/** Picker rank: favorites (0) → recommended (1) → normal (2) → legacy (3). */404export function rankModel(model: AIModel, favoriteIDs: ReadonlySet<string>): number {405  if (favoriteIDs.has(model.id)) return 0406  if (model.isRecommended) return 1407  if (model.isLegacy) return 3408  return 2409}410