| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
|
|
| import { |
| CLAUDE_MODEL_MAP, |
| CLAUDE_CANONICAL_MAP, |
| CURSOR_MODEL_MAP, |
| CODEX_MODEL_MAP, |
| DEFAULT_MODELS, |
| PROVIDER_PREFIXES, |
| isCursorModel, |
| isOpencodeModel, |
| isCopilotModel, |
| isGeminiModel, |
| stripProviderPrefix, |
| migrateModelId, |
| type PhaseModelEntry, |
| type ThinkingLevel, |
| type ReasoningEffort, |
| } from '@automaker/types'; |
|
|
| |
| const CODEX_MODEL_PREFIXES = ['codex-', 'gpt-']; |
| const OPENAI_O_SERIES_PATTERN = /^o\d/; |
| const OPENAI_O_SERIES_ALLOWED_MODELS = new Set<string>(); |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| export function resolveModelString( |
| modelKey?: string, |
| defaultModel: string = DEFAULT_MODELS.claude |
| ): string { |
| console.log( |
| `[ModelResolver] resolveModelString called with modelKey: "${modelKey}", defaultModel: "${defaultModel}"` |
| ); |
|
|
| |
| if (!modelKey) { |
| console.log(`[ModelResolver] No model specified, using default: ${defaultModel}`); |
| return defaultModel; |
| } |
|
|
| |
| const canonicalKey = migrateModelId(modelKey); |
| if (canonicalKey !== modelKey) { |
| console.log(`[ModelResolver] Migrated legacy ID: "${modelKey}" -> "${canonicalKey}"`); |
| } |
|
|
| |
| |
| if (canonicalKey.startsWith(PROVIDER_PREFIXES.cursor)) { |
| console.log(`[ModelResolver] Using Cursor model: ${canonicalKey}`); |
| return canonicalKey; |
| } |
|
|
| |
| if (canonicalKey.startsWith(PROVIDER_PREFIXES.codex)) { |
| console.log(`[ModelResolver] Using Codex model: ${canonicalKey}`); |
| return canonicalKey; |
| } |
|
|
| |
| if (isOpencodeModel(canonicalKey)) { |
| console.log(`[ModelResolver] Using OpenCode model: ${canonicalKey}`); |
| return canonicalKey; |
| } |
|
|
| |
| if (isCopilotModel(canonicalKey)) { |
| console.log(`[ModelResolver] Using Copilot model: ${canonicalKey}`); |
| return canonicalKey; |
| } |
|
|
| |
| if (isGeminiModel(canonicalKey)) { |
| console.log(`[ModelResolver] Using Gemini model: ${canonicalKey}`); |
| return canonicalKey; |
| } |
|
|
| |
| |
| if (canonicalKey in CLAUDE_CANONICAL_MAP) { |
| const resolved = CLAUDE_CANONICAL_MAP[canonicalKey as keyof typeof CLAUDE_CANONICAL_MAP]; |
| console.log(`[ModelResolver] Resolved Claude canonical ID: "${canonicalKey}" -> "${resolved}"`); |
| return resolved; |
| } |
|
|
| |
| if (canonicalKey.includes('claude-')) { |
| console.log(`[ModelResolver] Using full Claude model string: ${canonicalKey}`); |
| return canonicalKey; |
| } |
|
|
| |
| const resolved = CLAUDE_MODEL_MAP[canonicalKey]; |
| if (resolved) { |
| console.log(`[ModelResolver] Resolved Claude legacy alias: "${canonicalKey}" -> "${resolved}"`); |
| return resolved; |
| } |
|
|
| |
| if ( |
| CODEX_MODEL_PREFIXES.some((prefix) => canonicalKey.startsWith(prefix)) || |
| (OPENAI_O_SERIES_PATTERN.test(canonicalKey) && OPENAI_O_SERIES_ALLOWED_MODELS.has(canonicalKey)) |
| ) { |
| console.log(`[ModelResolver] Using OpenAI/Codex model: ${canonicalKey}`); |
| return canonicalKey; |
| } |
|
|
| |
| |
| console.log( |
| `[ModelResolver] Unknown model key "${canonicalKey}", passing through unchanged (may be a provider model)` |
| ); |
| return canonicalKey; |
| } |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| export function getEffectiveModel( |
| explicitModel?: string, |
| sessionModel?: string, |
| defaultModel?: string |
| ): string { |
| return resolveModelString(explicitModel || sessionModel, defaultModel); |
| } |
|
|
| |
| |
| |
| export interface ResolvedPhaseModel { |
| |
| model: string; |
| |
| thinkingLevel?: ThinkingLevel; |
| |
| reasoningEffort?: ReasoningEffort; |
| |
| providerId?: string; |
| } |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| export function resolvePhaseModel( |
| phaseModel: string | PhaseModelEntry | null | undefined, |
| defaultModel: string = DEFAULT_MODELS.claude |
| ): ResolvedPhaseModel { |
| console.log( |
| `[ModelResolver] resolvePhaseModel called with:`, |
| JSON.stringify(phaseModel), |
| `type: ${typeof phaseModel}` |
| ); |
|
|
| |
| if (!phaseModel) { |
| console.log(`[ModelResolver] phaseModel is null/undefined, using default`); |
| return { |
| model: resolveModelString(undefined, defaultModel), |
| thinkingLevel: undefined, |
| reasoningEffort: undefined, |
| }; |
| } |
|
|
| |
| if (typeof phaseModel === 'string') { |
| console.log(`[ModelResolver] phaseModel is string format (legacy): "${phaseModel}"`); |
| return { |
| model: resolveModelString(phaseModel, defaultModel), |
| thinkingLevel: undefined, |
| reasoningEffort: undefined, |
| }; |
| } |
|
|
| |
| console.log( |
| `[ModelResolver] phaseModel is object format: model="${phaseModel.model}", thinkingLevel="${phaseModel.thinkingLevel}", reasoningEffort="${phaseModel.reasoningEffort}", providerId="${phaseModel.providerId}"` |
| ); |
|
|
| |
| |
| if (phaseModel.providerId) { |
| console.log( |
| `[ModelResolver] Using provider model: providerId="${phaseModel.providerId}", model="${phaseModel.model}"` |
| ); |
| return { |
| model: phaseModel.model, |
| thinkingLevel: phaseModel.thinkingLevel, |
| reasoningEffort: phaseModel.reasoningEffort, |
| providerId: phaseModel.providerId, |
| }; |
| } |
|
|
| |
| return { |
| model: resolveModelString(phaseModel.model, defaultModel), |
| thinkingLevel: phaseModel.thinkingLevel, |
| reasoningEffort: phaseModel.reasoningEffort, |
| }; |
| } |
|
|