fix(startup): show --model flag override on startup screen (#898)
The startup screen was only reading model from env vars and settings, ignoring the --model CLI flag since it's parsed by Commander.js after the banner prints. Now eagerly parses --model from argv before rendering so the displayed model matches what the session will actually use.
This commit is contained in:
@@ -14,6 +14,7 @@ const ENV_KEYS = [
|
|||||||
'GEMINI_MODEL',
|
'GEMINI_MODEL',
|
||||||
'MISTRAL_MODEL',
|
'MISTRAL_MODEL',
|
||||||
'ANTHROPIC_MODEL',
|
'ANTHROPIC_MODEL',
|
||||||
|
'CLAUDE_MODEL',
|
||||||
'NVIDIA_NIM',
|
'NVIDIA_NIM',
|
||||||
'MINIMAX_API_KEY',
|
'MINIMAX_API_KEY',
|
||||||
]
|
]
|
||||||
@@ -186,3 +187,71 @@ describe('detectProvider — explicit dedicated-provider env flags', () => {
|
|||||||
expect(detectProvider().name).toBe('MiniMax')
|
expect(detectProvider().name).toBe('MiniMax')
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// --- modelOverride from --model flag ---
|
||||||
|
|
||||||
|
describe('detectProvider — modelOverride from --model flag', () => {
|
||||||
|
test('modelOverride overrides default Anthropic model', () => {
|
||||||
|
const result = detectProvider('claude-opus-4-6')
|
||||||
|
expect(result.name).toBe('Anthropic')
|
||||||
|
expect(result.model).toContain('opus')
|
||||||
|
})
|
||||||
|
|
||||||
|
test('modelOverride alias is resolved for Anthropic', () => {
|
||||||
|
const result = detectProvider('opus')
|
||||||
|
expect(result.name).toBe('Anthropic')
|
||||||
|
expect(result.model).toContain('opus')
|
||||||
|
})
|
||||||
|
|
||||||
|
test('modelOverride takes priority over ANTHROPIC_MODEL env var', () => {
|
||||||
|
process.env.ANTHROPIC_MODEL = 'claude-haiku-4-5-20251001'
|
||||||
|
const result = detectProvider('claude-opus-4-6')
|
||||||
|
expect(result.name).toBe('Anthropic')
|
||||||
|
expect(result.model).toContain('opus')
|
||||||
|
})
|
||||||
|
|
||||||
|
test('modelOverride takes priority over CLAUDE_MODEL env var', () => {
|
||||||
|
process.env.CLAUDE_MODEL = 'claude-haiku-4-5-20251001'
|
||||||
|
const result = detectProvider('claude-opus-4-6')
|
||||||
|
expect(result.name).toBe('Anthropic')
|
||||||
|
expect(result.model).toContain('opus')
|
||||||
|
})
|
||||||
|
|
||||||
|
test('modelOverride works for OpenAI provider', () => {
|
||||||
|
process.env.CLAUDE_CODE_USE_OPENAI = '1'
|
||||||
|
process.env.OPENAI_API_KEY = 'test-key'
|
||||||
|
process.env.OPENAI_MODEL = 'gpt-4o'
|
||||||
|
const result = detectProvider('gpt-4-turbo')
|
||||||
|
expect(result.model).toContain('gpt-4-turbo')
|
||||||
|
})
|
||||||
|
|
||||||
|
test('modelOverride works for Gemini provider', () => {
|
||||||
|
process.env.CLAUDE_CODE_USE_GEMINI = '1'
|
||||||
|
const result = detectProvider('gemini-2.5-pro')
|
||||||
|
expect(result.model).toBe('gemini-2.5-pro')
|
||||||
|
})
|
||||||
|
|
||||||
|
test('modelOverride works for Mistral provider', () => {
|
||||||
|
process.env.CLAUDE_CODE_USE_MISTRAL = '1'
|
||||||
|
const result = detectProvider('mistral-large-latest')
|
||||||
|
expect(result.model).toBe('mistral-large-latest')
|
||||||
|
})
|
||||||
|
|
||||||
|
test('modelOverride works for GitHub provider', () => {
|
||||||
|
process.env.CLAUDE_CODE_USE_GITHUB = '1'
|
||||||
|
const result = detectProvider('gpt-4o')
|
||||||
|
expect(result.model).toContain('gpt-4o')
|
||||||
|
})
|
||||||
|
|
||||||
|
test('undefined modelOverride preserves default behavior', () => {
|
||||||
|
const result = detectProvider(undefined)
|
||||||
|
expect(result.name).toBe('Anthropic')
|
||||||
|
expect(result.model).toContain('sonnet')
|
||||||
|
})
|
||||||
|
|
||||||
|
test('no argument preserves default behavior', () => {
|
||||||
|
const result = detectProvider()
|
||||||
|
expect(result.name).toBe('Anthropic')
|
||||||
|
expect(result.model).toContain('sonnet')
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|||||||
@@ -84,33 +84,33 @@ const LOGO_CLAUDE = [
|
|||||||
|
|
||||||
// ─── Provider detection ───────────────────────────────────────────────────────
|
// ─── Provider detection ───────────────────────────────────────────────────────
|
||||||
|
|
||||||
export function detectProvider(): { name: string; model: string; baseUrl: string; isLocal: boolean } {
|
export function detectProvider(modelOverride?: string): { name: string; model: string; baseUrl: string; isLocal: boolean } {
|
||||||
const useGemini = process.env.CLAUDE_CODE_USE_GEMINI === '1' || process.env.CLAUDE_CODE_USE_GEMINI === 'true'
|
const useGemini = process.env.CLAUDE_CODE_USE_GEMINI === '1' || process.env.CLAUDE_CODE_USE_GEMINI === 'true'
|
||||||
const useGithub = process.env.CLAUDE_CODE_USE_GITHUB === '1' || process.env.CLAUDE_CODE_USE_GITHUB === 'true'
|
const useGithub = process.env.CLAUDE_CODE_USE_GITHUB === '1' || process.env.CLAUDE_CODE_USE_GITHUB === 'true'
|
||||||
const useOpenAI = process.env.CLAUDE_CODE_USE_OPENAI === '1' || process.env.CLAUDE_CODE_USE_OPENAI === 'true'
|
const useOpenAI = process.env.CLAUDE_CODE_USE_OPENAI === '1' || process.env.CLAUDE_CODE_USE_OPENAI === 'true'
|
||||||
const useMistral = process.env.CLAUDE_CODE_USE_MISTRAL === '1' || process.env.CLAUDE_CODE_USE_MISTRAL === 'true'
|
const useMistral = process.env.CLAUDE_CODE_USE_MISTRAL === '1' || process.env.CLAUDE_CODE_USE_MISTRAL === 'true'
|
||||||
|
|
||||||
if (useGemini) {
|
if (useGemini) {
|
||||||
const model = process.env.GEMINI_MODEL || 'gemini-2.0-flash'
|
const model = modelOverride || process.env.GEMINI_MODEL || 'gemini-2.0-flash'
|
||||||
const baseUrl = process.env.GEMINI_BASE_URL || 'https://generativelanguage.googleapis.com/v1beta/openai'
|
const baseUrl = process.env.GEMINI_BASE_URL || 'https://generativelanguage.googleapis.com/v1beta/openai'
|
||||||
return { name: 'Google Gemini', model, baseUrl, isLocal: false }
|
return { name: 'Google Gemini', model, baseUrl, isLocal: false }
|
||||||
}
|
}
|
||||||
|
|
||||||
if (useMistral) {
|
if (useMistral) {
|
||||||
const model = process.env.MISTRAL_MODEL || 'devstral-latest'
|
const model = modelOverride || process.env.MISTRAL_MODEL || 'devstral-latest'
|
||||||
const baseUrl = process.env.MISTRAL_BASE_URL || 'https://api.mistral.ai/v1'
|
const baseUrl = process.env.MISTRAL_BASE_URL || 'https://api.mistral.ai/v1'
|
||||||
return { name: 'Mistral', model, baseUrl, isLocal: false }
|
return { name: 'Mistral', model, baseUrl, isLocal: false }
|
||||||
}
|
}
|
||||||
|
|
||||||
if (useGithub) {
|
if (useGithub) {
|
||||||
const model = process.env.OPENAI_MODEL || 'github:copilot'
|
const model = modelOverride || process.env.OPENAI_MODEL || 'github:copilot'
|
||||||
const baseUrl =
|
const baseUrl =
|
||||||
process.env.OPENAI_BASE_URL || 'https://api.githubcopilot.com'
|
process.env.OPENAI_BASE_URL || 'https://api.githubcopilot.com'
|
||||||
return { name: 'GitHub Copilot', model, baseUrl, isLocal: false }
|
return { name: 'GitHub Copilot', model, baseUrl, isLocal: false }
|
||||||
}
|
}
|
||||||
|
|
||||||
if (useOpenAI) {
|
if (useOpenAI) {
|
||||||
const rawModel = process.env.OPENAI_MODEL || 'gpt-4o'
|
const rawModel = modelOverride || process.env.OPENAI_MODEL || 'gpt-4o'
|
||||||
const resolvedRequest = resolveProviderRequest({
|
const resolvedRequest = resolveProviderRequest({
|
||||||
model: rawModel,
|
model: rawModel,
|
||||||
baseUrl: process.env.OPENAI_BASE_URL,
|
baseUrl: process.env.OPENAI_BASE_URL,
|
||||||
@@ -166,7 +166,7 @@ export function detectProvider(): { name: string; model: string; baseUrl: string
|
|||||||
|
|
||||||
// Default: Anthropic - check settings.model first, then env vars
|
// Default: Anthropic - check settings.model first, then env vars
|
||||||
const settings = getSettings_DEPRECATED() || {}
|
const settings = getSettings_DEPRECATED() || {}
|
||||||
const modelSetting = settings.model || process.env.ANTHROPIC_MODEL || process.env.CLAUDE_MODEL || 'claude-sonnet-4-6'
|
const modelSetting = modelOverride || settings.model || process.env.ANTHROPIC_MODEL || process.env.CLAUDE_MODEL || 'claude-sonnet-4-6'
|
||||||
const resolvedModel = parseUserSpecifiedModel(modelSetting)
|
const resolvedModel = parseUserSpecifiedModel(modelSetting)
|
||||||
const baseUrl = process.env.ANTHROPIC_BASE_URL ?? 'https://api.anthropic.com'
|
const baseUrl = process.env.ANTHROPIC_BASE_URL ?? 'https://api.anthropic.com'
|
||||||
const isLocal = isLocalProviderUrl(baseUrl)
|
const isLocal = isLocalProviderUrl(baseUrl)
|
||||||
@@ -182,11 +182,11 @@ function boxRow(content: string, width: number, rawLen: number): string {
|
|||||||
|
|
||||||
// ─── Main ─────────────────────────────────────────────────────────────────────
|
// ─── Main ─────────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
export function printStartupScreen(): void {
|
export function printStartupScreen(modelOverride?: string): void {
|
||||||
// Skip in non-interactive / CI / print mode
|
// Skip in non-interactive / CI / print mode
|
||||||
if (process.env.CI || !process.stdout.isTTY) return
|
if (process.env.CI || !process.stdout.isTTY) return
|
||||||
|
|
||||||
const p = detectProvider()
|
const p = detectProvider(modelOverride)
|
||||||
const W = 62
|
const W = 62
|
||||||
const out: string[] = []
|
const out: string[] = []
|
||||||
|
|
||||||
|
|||||||
@@ -134,9 +134,13 @@ async function main(): Promise<void> {
|
|||||||
|
|
||||||
await validateProviderEnvForStartupOrExit()
|
await validateProviderEnvForStartupOrExit()
|
||||||
|
|
||||||
|
// Parse --model early so the startup screen can display the override
|
||||||
|
const { eagerParseCliFlag } = await import('../utils/cliArgs.js')
|
||||||
|
const earlyModelFlag = eagerParseCliFlag('--model')
|
||||||
|
|
||||||
// Print the gradient startup screen before the Ink UI loads
|
// Print the gradient startup screen before the Ink UI loads
|
||||||
const { printStartupScreen } = await import('../components/StartupScreen.js')
|
const { printStartupScreen } = await import('../components/StartupScreen.js')
|
||||||
printStartupScreen()
|
printStartupScreen(earlyModelFlag)
|
||||||
|
|
||||||
// For all other paths, load the startup profiler
|
// For all other paths, load the startup profiler
|
||||||
const {
|
const {
|
||||||
|
|||||||
Reference in New Issue
Block a user