export type OpenCodeTransport = | 'responses' | 'messages' | 'chat-completions' | 'google-models' export type OpenCodeModelCatalogEntry = { id: string label: string description: string transport: OpenCodeTransport free?: boolean keyless?: boolean supported?: boolean } const RESPONSES_DESCRIPTION = 'OpenCode Zen Responses endpoint' const MESSAGES_DESCRIPTION = 'OpenCode Zen Messages endpoint' const CHAT_COMPLETIONS_DESCRIPTION = 'OpenCode Zen Chat Completions endpoint' const GOOGLE_MODELS_DESCRIPTION = 'OpenCode Zen Google models endpoint' export const OPENCODE_MODEL_CATALOG: OpenCodeModelCatalogEntry[] = [ { id: 'claude-opus-4-6', label: 'Claude Opus 4.6', description: `OpenCode Zen Claude model via the ${MESSAGES_DESCRIPTION}`, transport: 'messages', supported: true, }, { id: 'claude-opus-4-5', label: 'Claude Opus 4.5', description: `OpenCode Zen Claude model via the ${MESSAGES_DESCRIPTION}`, transport: 'messages', supported: true, }, { id: 'claude-opus-4-1', label: 'Claude Opus 4.1', description: `OpenCode Zen Claude model via the ${MESSAGES_DESCRIPTION}`, transport: 'messages', supported: true, }, { id: 'claude-sonnet-4-6', label: 'Claude Sonnet 4.6', description: `OpenCode Zen Claude model via the ${MESSAGES_DESCRIPTION}`, transport: 'messages', supported: true, }, { id: 'claude-sonnet-4-5', label: 'Claude Sonnet 4.5', description: `OpenCode Zen Claude model via the ${MESSAGES_DESCRIPTION}`, transport: 'messages', supported: true, }, { id: 'claude-sonnet-4', label: 'Claude Sonnet 4', description: `OpenCode Zen Claude model via the ${MESSAGES_DESCRIPTION}`, transport: 'messages', supported: true, }, { id: 'claude-3-5-haiku', label: 'Claude 3.5 Haiku', description: `OpenCode Zen Claude model via the ${MESSAGES_DESCRIPTION}`, transport: 'messages', supported: true, }, { id: 'claude-haiku-4-5', label: 'Claude Haiku 4.5', description: `OpenCode Zen Claude model via the ${MESSAGES_DESCRIPTION}`, transport: 'messages', supported: true, }, { id: 'gemini-3.1-pro', label: 'Gemini 3.1 Pro', description: `Available on OpenCode Zen via the ${GOOGLE_MODELS_DESCRIPTION} (not wired in Mervelas yet)`, transport: 'google-models', supported: false, }, { id: 'gemini-3-pro', label: 'Gemini 3 Pro', description: `Available on OpenCode Zen via the ${GOOGLE_MODELS_DESCRIPTION} (not wired in Mervelas yet)`, transport: 'google-models', supported: false, }, { id: 'gemini-3-flash', label: 'Gemini 3 Flash', description: `Available on OpenCode Zen via the ${GOOGLE_MODELS_DESCRIPTION} (not wired in Mervelas yet)`, transport: 'google-models', supported: false, }, { id: 'gpt-5.4', label: 'GPT 5.4', description: `OpenCode Zen GPT model via the ${RESPONSES_DESCRIPTION}`, transport: 'responses', supported: true, }, { id: 'gpt-5.4-pro', label: 'GPT 5.4 Pro', description: `Premium OpenCode Zen GPT model via the ${RESPONSES_DESCRIPTION}`, transport: 'responses', supported: true, }, { id: 'gpt-5.4-mini', label: 'GPT 5.4 Mini', description: `Smaller OpenCode Zen GPT model via the ${RESPONSES_DESCRIPTION}`, transport: 'responses', supported: true, }, { id: 'gpt-5.4-nano', label: 'GPT 5.4 Nano', description: `Smallest OpenCode Zen GPT model via the ${RESPONSES_DESCRIPTION}`, transport: 'responses', supported: true, }, { id: 'gpt-5.3-codex-spark', label: 'GPT 5.3 Codex Spark', description: `Coding-focused OpenCode Zen model via the ${RESPONSES_DESCRIPTION}`, transport: 'responses', supported: true, }, { id: 'gpt-5.3-codex', label: 'GPT 5.3 Codex', description: `Coding-focused OpenCode Zen model via the ${RESPONSES_DESCRIPTION}`, transport: 'responses', supported: true, }, { id: 'gpt-5.2', label: 'GPT 5.2', description: `OpenCode Zen GPT model via the ${RESPONSES_DESCRIPTION}`, transport: 'responses', supported: true, }, { id: 'gpt-5.2-codex', label: 'GPT 5.2 Codex', description: `OpenCode Zen GPT coding model via the ${RESPONSES_DESCRIPTION}`, transport: 'responses', supported: true, }, { id: 'gpt-5.1', label: 'GPT 5.1', description: `OpenCode Zen GPT model via the ${RESPONSES_DESCRIPTION}`, transport: 'responses', supported: true, }, { id: 'gpt-5.1-codex-max', label: 'GPT 5.1 Codex Max', description: `OpenCode Zen GPT coding model via the ${RESPONSES_DESCRIPTION}`, transport: 'responses', supported: true, }, { id: 'gpt-5.1-codex', label: 'GPT 5.1 Codex', description: `OpenCode Zen GPT coding model via the ${RESPONSES_DESCRIPTION}`, transport: 'responses', supported: true, }, { id: 'gpt-5.1-codex-mini', label: 'GPT 5.1 Codex Mini', description: `OpenCode Zen GPT coding model via the ${RESPONSES_DESCRIPTION}`, transport: 'responses', supported: true, }, { id: 'gpt-5', label: 'GPT 5', description: `OpenCode Zen GPT model via the ${RESPONSES_DESCRIPTION}`, transport: 'responses', supported: true, }, { id: 'gpt-5-codex', label: 'GPT 5 Codex', description: `OpenCode Zen GPT coding model via the ${RESPONSES_DESCRIPTION}`, transport: 'responses', supported: true, }, { id: 'gpt-5-nano', label: 'GPT 5 Nano', description: `Free on OpenCode Zen and usable without a key via the ${CHAT_COMPLETIONS_DESCRIPTION}`, transport: 'chat-completions', free: true, keyless: true, supported: true, }, { id: 'glm-5', label: 'GLM 5', description: `Available on OpenCode Zen via the ${CHAT_COMPLETIONS_DESCRIPTION}`, transport: 'chat-completions', supported: true, }, { id: 'glm-4.7', label: 'GLM 4.7', description: `Available on OpenCode Zen via the ${CHAT_COMPLETIONS_DESCRIPTION}`, transport: 'chat-completions', supported: true, }, { id: 'glm-4.6', label: 'GLM 4.6', description: `Available on OpenCode Zen via the ${CHAT_COMPLETIONS_DESCRIPTION}`, transport: 'chat-completions', supported: true, }, { id: 'minimax-m2.5', label: 'MiniMax M2.5', description: `Available on OpenCode Zen via the ${CHAT_COMPLETIONS_DESCRIPTION}`, transport: 'chat-completions', supported: true, }, { id: 'minimax-m2.5-free', label: 'MiniMax M2.5 Free', description: `Free on OpenCode Zen via the ${CHAT_COMPLETIONS_DESCRIPTION}`, transport: 'chat-completions', free: true, keyless: true, supported: true, }, { id: 'minimax-m2.1', label: 'MiniMax M2.1', description: `Available on OpenCode Zen via the ${CHAT_COMPLETIONS_DESCRIPTION}`, transport: 'chat-completions', supported: true, }, { id: 'qwen3.6-plus-free', label: 'Qwen 3.6 Plus Free', description: `Free on OpenCode Zen via the ${CHAT_COMPLETIONS_DESCRIPTION}`, transport: 'chat-completions', free: true, keyless: true, supported: true, }, { id: 'mimo-v2-pro-free', label: 'MiMo V2 Pro Free', description: `Free on OpenCode Zen via the ${CHAT_COMPLETIONS_DESCRIPTION}`, transport: 'chat-completions', free: true, keyless: true, supported: true, }, { id: 'mimo-v2-omni-free', label: 'MiMo V2 Omni Free', description: `Free on OpenCode Zen via the ${CHAT_COMPLETIONS_DESCRIPTION}`, transport: 'chat-completions', free: true, keyless: true, supported: true, }, { id: 'mimo-v2-flash-free', label: 'MiMo V2 Flash Free', description: `Free on OpenCode Zen via the ${CHAT_COMPLETIONS_DESCRIPTION}`, transport: 'chat-completions', free: true, keyless: true, supported: true, }, { id: 'kimi-k2.5', label: 'Kimi K2.5', description: `Available on OpenCode Zen via the ${CHAT_COMPLETIONS_DESCRIPTION}`, transport: 'chat-completions', supported: true, }, { id: 'kimi-k2', label: 'Kimi K2', description: `Available on OpenCode Zen via the ${CHAT_COMPLETIONS_DESCRIPTION}`, transport: 'chat-completions', supported: true, }, { id: 'kimi-k2-thinking', label: 'Kimi K2 Thinking', description: `Available on OpenCode Zen via the ${CHAT_COMPLETIONS_DESCRIPTION}`, transport: 'chat-completions', supported: true, }, { id: 'trinity-large-preview-free', label: 'Trinity Large Preview Free', description: `Free on OpenCode Zen via the ${CHAT_COMPLETIONS_DESCRIPTION}`, transport: 'chat-completions', free: true, keyless: true, supported: true, }, { id: 'big-pickle', label: 'Big Pickle', description: `Free on OpenCode Zen via the ${CHAT_COMPLETIONS_DESCRIPTION}`, transport: 'chat-completions', free: true, keyless: true, supported: true, }, { id: 'nemotron-3-super-free', label: 'Nemotron 3 Super Free', description: `Free on OpenCode Zen via the ${CHAT_COMPLETIONS_DESCRIPTION}`, transport: 'chat-completions', free: true, keyless: true, supported: true, }, ] const OPENCODE_MODEL_LOOKUP = new Map( OPENCODE_MODEL_CATALOG.map(model => [model.id, model]), ) export function getOpenCodeModelCatalogEntry( model: string, ): OpenCodeModelCatalogEntry | undefined { return OPENCODE_MODEL_LOOKUP.get(model.trim()) } export function getOpenCodeTransportForModel( model: string, ): OpenCodeTransport | null { const normalized = model.trim().toLowerCase() const known = getOpenCodeModelCatalogEntry(normalized) if (known) { return known.transport } if (normalized.startsWith('claude-')) { return 'messages' } if ( normalized.startsWith('gpt-') || normalized.startsWith('codex') || normalized.includes('codex') ) { return 'responses' } if (normalized.startsWith('gemini-')) { return 'google-models' } return 'chat-completions' } export function isSupportedOpenCodeTransport( transport: OpenCodeTransport | null, ): boolean { return ( transport === 'responses' || transport === 'messages' || transport === 'chat-completions' ) }