/** * Agent CLI Model Definitions. * * Static model definitions for each CLI type. * Based on the pattern from Claudable (other/cweb). */ import type { CodexReasoningEffort } from 'chrome-mcp-shared'; // ============================================================ // Types // ============================================================ export interface ModelDefinition { id: string; name: string; description?: string; supportsImages?: boolean; /** Supported reasoning effort levels for Codex models */ supportedReasoningEfforts?: readonly CodexReasoningEffort[]; } export type AgentCliType = 'claude' | 'codex' | 'cursor' | 'qwen' | 'glm'; // ============================================================ // Claude Models // ============================================================ export const CLAUDE_MODELS: ModelDefinition[] = [ { id: 'claude-sonnet-4-5-20250929', name: 'Claude Sonnet 4.5', description: 'Balanced model with large context window', supportsImages: true, }, { id: 'claude-opus-4-5-20251101', name: 'Claude Opus 4.5', description: 'Strongest reasoning model', supportsImages: true, }, { id: 'claude-haiku-4-5-20251001', name: 'Claude Haiku 4.5', description: 'Fast and cost-efficient', supportsImages: true, }, ]; export const CLAUDE_DEFAULT_MODEL = 'claude-sonnet-4-5-20250929'; // ============================================================ // Codex Models // ============================================================ /** Standard reasoning efforts supported by all models */ const CODEX_STANDARD_EFFORTS: readonly CodexReasoningEffort[] = ['low', 'medium', 'high']; /** Extended reasoning efforts (includes xhigh) - only for gpt-5.2 and gpt-5.1-codex-max */ const CODEX_EXTENDED_EFFORTS: readonly CodexReasoningEffort[] = ['low', 'medium', 'high', 'xhigh']; export const CODEX_MODELS: ModelDefinition[] = [ { id: 'gpt-5.1', name: 'GPT-5.1', description: 'OpenAI high-quality reasoning model', supportedReasoningEfforts: CODEX_STANDARD_EFFORTS, }, { id: 'gpt-5.2', name: 'GPT-5.2', description: 'OpenAI flagship reasoning model with extended effort support', supportedReasoningEfforts: CODEX_EXTENDED_EFFORTS, }, { id: 'gpt-5.1-codex', name: 'GPT-5.1 Codex', description: 'Coding-optimized model for agent workflows', supportedReasoningEfforts: CODEX_STANDARD_EFFORTS, }, { id: 'gpt-5.1-codex-max', name: 'GPT-5.1 Codex Max', description: 'Highest quality coding model with extended effort support', supportedReasoningEfforts: CODEX_EXTENDED_EFFORTS, }, { id: 'gpt-5.1-codex-mini', name: 'GPT-5.1 Codex Mini', description: 'Fast, cost-efficient coding model', supportedReasoningEfforts: CODEX_STANDARD_EFFORTS, }, ]; export const CODEX_DEFAULT_MODEL = 'gpt-5.1'; // Codex model alias normalization const CODEX_ALIAS_MAP: Record = { gpt5: 'gpt-5.1', gpt_5: 'gpt-5.1', 'gpt-5': 'gpt-5.1', 'gpt-5.0': 'gpt-5.1', }; const CODEX_KNOWN_IDS = new Set(CODEX_MODELS.map((model) => model.id)); /** * Normalize a Codex model ID, handling aliases and falling back to default. */ export function normalizeCodexModelId(model?: string | null): string { if (!model || typeof model !== 'string') { return CODEX_DEFAULT_MODEL; } const trimmed = model.trim(); if (!trimmed) { return CODEX_DEFAULT_MODEL; } const lower = trimmed.toLowerCase(); if (CODEX_ALIAS_MAP[lower]) { return CODEX_ALIAS_MAP[lower]; } if (CODEX_KNOWN_IDS.has(lower)) { return lower; } // If the exact casing exists, allow it if (CODEX_KNOWN_IDS.has(trimmed)) { return trimmed; } return CODEX_DEFAULT_MODEL; } /** * Get supported reasoning efforts for a Codex model. * Returns standard efforts (low/medium/high) for unknown models. */ export function getCodexReasoningEfforts(modelId?: string | null): readonly CodexReasoningEffort[] { const normalized = normalizeCodexModelId(modelId); const model = CODEX_MODELS.find((m) => m.id === normalized); return model?.supportedReasoningEfforts ?? CODEX_STANDARD_EFFORTS; } /** * Check if a model supports xhigh reasoning effort. */ export function supportsXhighEffort(modelId?: string | null): boolean { const efforts = getCodexReasoningEfforts(modelId); return efforts.includes('xhigh'); } // ============================================================ // Cursor Models // ============================================================ export const CURSOR_MODELS: ModelDefinition[] = [ { id: 'auto', name: 'Auto', description: 'Cursor auto-selects the best model', }, { id: 'claude-sonnet-4-5-20250929', name: 'Claude Sonnet 4.5', description: 'Anthropic Claude via Cursor', supportsImages: true, }, { id: 'gpt-4.1', name: 'GPT-4.1', description: 'OpenAI model via Cursor', }, ]; export const CURSOR_DEFAULT_MODEL = 'auto'; // ============================================================ // Qwen Models // ============================================================ export const QWEN_MODELS: ModelDefinition[] = [ { id: 'qwen3-coder-plus', name: 'Qwen3 Coder Plus', description: 'Balanced 32k context model for coding', }, { id: 'qwen3-coder-pro', name: 'Qwen3 Coder Pro', description: 'Larger 128k context with stronger reasoning', }, { id: 'qwen3-coder', name: 'Qwen3 Coder', description: 'Fast iteration model', }, ]; export const QWEN_DEFAULT_MODEL = 'qwen3-coder-plus'; // ============================================================ // GLM Models // ============================================================ export const GLM_MODELS: ModelDefinition[] = [ { id: 'glm-4.6', name: 'GLM 4.6', description: 'Zhipu GLM 4.6 agent runtime', }, ]; export const GLM_DEFAULT_MODEL = 'glm-4.6'; // ============================================================ // Aggregated Definitions // ============================================================ export const CLI_MODEL_DEFINITIONS: Record = { claude: CLAUDE_MODELS, codex: CODEX_MODELS, cursor: CURSOR_MODELS, qwen: QWEN_MODELS, glm: GLM_MODELS, }; export const CLI_DEFAULT_MODELS: Record = { claude: CLAUDE_DEFAULT_MODEL, codex: CODEX_DEFAULT_MODEL, cursor: CURSOR_DEFAULT_MODEL, qwen: QWEN_DEFAULT_MODEL, glm: GLM_DEFAULT_MODEL, }; // ============================================================ // Helper Functions // ============================================================ /** * Get model definitions for a specific CLI type. */ export function getModelsForCli(cli: string | null | undefined): ModelDefinition[] { if (!cli) return []; const key = cli.toLowerCase() as AgentCliType; return CLI_MODEL_DEFINITIONS[key] || []; } /** * Get the default model for a CLI type. */ export function getDefaultModelForCli(cli: string | null | undefined): string { if (!cli) return ''; const key = cli.toLowerCase() as AgentCliType; return CLI_DEFAULT_MODELS[key] || ''; } /** * Get display name for a model ID. */ export function getModelDisplayName( cli: string | null | undefined, modelId: string | null | undefined, ): string { if (!cli || !modelId) return modelId || ''; const models = getModelsForCli(cli); const model = models.find((m) => m.id === modelId); return model?.name || modelId; }