feat: 修复 Codex 模型映射并添加登录后模型配置面板

- configs.ts: 将 codex 字段从 Anthropic 模型名改为实际 OpenAI 模型名
  (opus→gpt-5.4, sonnet→gpt-5.4-mini, haiku→gpt-5.4-mini, opus47→gpt-5.5)
- modelMapping.ts: 移除不存在的 gpt-5.4-nano,修复 haiku 映射,添加 opus47
- ConsoleOAuthFlow.tsx: OAuth 成功后显示模型配置面板,可编辑三种模型名称
- 已登录用户再次选择 Codex 时跳过 OAuth 直接进入模型配置
- Ctrl+R 快捷键清除登录状态并重新 OAuth
- modelOptions.ts: codex provider 支持 CODEX_DEFAULT_*_MODEL 环境变量

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
claude-code-best
2026-04-26 23:38:56 +08:00
parent d091dd8bae
commit 1058b7e643
7 changed files with 330 additions and 52 deletions

View File

@@ -45,7 +45,7 @@ describe('resolveCodexModel', () => {
}) })
test('maps known haiku model via DEFAULT_MODEL_MAP', () => { test('maps known haiku model via DEFAULT_MODEL_MAP', () => {
expect(resolveCodexModel('claude-haiku-4-5-20251001')).toBe('gpt-5.4-nano') expect(resolveCodexModel('claude-haiku-4-5-20251001')).toBe('gpt-5.4-mini')
}) })
test('maps known opus model via DEFAULT_MODEL_MAP', () => { test('maps known opus model via DEFAULT_MODEL_MAP', () => {
@@ -58,7 +58,7 @@ describe('resolveCodexModel', () => {
}) })
test('maps legacy haiku models', () => { test('maps legacy haiku models', () => {
expect(resolveCodexModel('claude-3-5-haiku-20241022')).toBe('gpt-5.4-nano') expect(resolveCodexModel('claude-3-5-haiku-20241022')).toBe('gpt-5.4-mini')
}) })
test('maps legacy opus models', () => { test('maps legacy opus models', () => {
@@ -67,7 +67,7 @@ describe('resolveCodexModel', () => {
}) })
test('uses family default for unrecognized haiku model', () => { test('uses family default for unrecognized haiku model', () => {
expect(resolveCodexModel('claude-haiku-99')).toBe('gpt-5.4-nano') expect(resolveCodexModel('claude-haiku-99')).toBe('gpt-5.4-mini')
}) })
test('uses family default for unrecognized sonnet model', () => { test('uses family default for unrecognized sonnet model', () => {

View File

@@ -12,15 +12,16 @@ const DEFAULT_MODEL_MAP: Record<string, string> = {
'claude-opus-4-1-20250805': 'gpt-5.4', 'claude-opus-4-1-20250805': 'gpt-5.4',
'claude-opus-4-5-20251101': 'gpt-5.4', 'claude-opus-4-5-20251101': 'gpt-5.4',
'claude-opus-4-6': 'gpt-5.4', 'claude-opus-4-6': 'gpt-5.4',
'claude-haiku-4-5-20251001': 'gpt-5.4-nano', 'claude-opus-4-7': 'gpt-5.5',
'claude-3-5-haiku-20241022': 'gpt-5.4-nano', 'claude-haiku-4-5-20251001': 'gpt-5.4-mini',
'claude-3-5-haiku-20241022': 'gpt-5.4-mini',
} }
/** /**
* Default model for each family when an exact match is not in DEFAULT_MODEL_MAP. * Default model for each family when an exact match is not in DEFAULT_MODEL_MAP.
*/ */
const DEFAULT_FAMILY_MAP: Record<string, string> = { const DEFAULT_FAMILY_MAP: Record<string, string> = {
haiku: 'gpt-5.4-nano', haiku: 'gpt-5.4-mini',
sonnet: 'gpt-5.4-mini', sonnet: 'gpt-5.4-mini',
opus: 'gpt-5.4', opus: 'gpt-5.4',
} }

View File

@@ -58,6 +58,18 @@ type OAuthStatus =
} // Gemini Generate Content API platform } // Gemini Generate Content API platform
| { state: 'codex_oauth_waiting'; url: string } // ChatGPT OAuth browser login in progress | { state: 'codex_oauth_waiting'; url: string } // ChatGPT OAuth browser login in progress
| { state: 'codex_oauth_start' } // Trigger ChatGPT OAuth flow | { state: 'codex_oauth_start' } // Trigger ChatGPT OAuth flow
| {
state: 'codex_models'
haikuModel: string
sonnetModel: string
opusModel: string
activeField: 'haiku_model' | 'sonnet_model' | 'opus_model'
codexResult: {
apiKey: string | null
accessToken: string
refreshToken: string
}
} // Codex model name configuration after OAuth success
| { state: 'ready_to_start' } // Flow started, waiting for browser to open | { state: 'ready_to_start' } // Flow started, waiting for browser to open
| { state: 'waiting_for_login'; url: string } // Browser opened, waiting for user to login | { state: 'waiting_for_login'; url: string } // Browser opened, waiting for user to login
| { state: 'creating_api_key' } // Got access token, creating API key | { state: 'creating_api_key' } // Got access token, creating API key
@@ -365,31 +377,19 @@ export function ConsoleOAuthFlow({
manualCode: manualCodePromise, manualCode: manualCodePromise,
}) })
const env: Record<string, string | undefined> = { // Transition to model configuration panel with defaults
CODEX_API_KEY: result.apiKey ?? undefined, setOAuthStatus({
CODEX_ACCESS_TOKEN: result.accessToken, state: 'codex_models',
CODEX_REFRESH_TOKEN: result.refreshToken, haikuModel: process.env.CODEX_DEFAULT_HAIKU_MODEL || 'gpt-5.4-mini',
CODEX_LOGIN_METHOD: 'chatgpt_subscription', sonnetModel: process.env.CODEX_DEFAULT_SONNET_MODEL || 'gpt-5.4-mini',
} opusModel: process.env.CODEX_DEFAULT_OPUS_MODEL || 'gpt-5.5',
updateSettingsForSource('userSettings', { activeField: 'haiku_model',
modelType: 'codex', codexResult: {
env, apiKey: result.apiKey,
} as any) accessToken: result.accessToken,
for (const [key, value] of Object.entries(env)) { refreshToken: result.refreshToken,
if (value !== undefined) {
process.env[key] = value
}
}
setOAuthStatus({ state: 'success' })
void sendNotification(
{
message: 'OpenAI Codex (ChatGPT) login successful',
notificationType: 'auth_success',
}, },
terminal, })
)
onDone()
} catch (err) { } catch (err) {
logError(err as Error) logError(err as Error)
setOAuthStatus({ setOAuthStatus({
@@ -714,7 +714,37 @@ function OAuthStatusMessage({
}) })
} else if (value === 'codex_chatgpt') { } else if (value === 'codex_chatgpt') {
logEvent('tengu_codex_chatgpt_selected', {}) logEvent('tengu_codex_chatgpt_selected', {})
setOAuthStatus({ state: 'codex_oauth_start' }) // Skip OAuth if already authenticated — go straight to model config
const settings = getSettings_DEPRECATED()
const hasToken = !!(
process.env.CODEX_ACCESS_TOKEN ||
settings?.env?.CODEX_ACCESS_TOKEN
)
if (hasToken) {
setOAuthStatus({
state: 'codex_models',
haikuModel:
process.env.CODEX_DEFAULT_HAIKU_MODEL ||
settings?.env?.CODEX_DEFAULT_HAIKU_MODEL ||
'gpt-5.4-mini',
sonnetModel:
process.env.CODEX_DEFAULT_SONNET_MODEL ||
settings?.env?.CODEX_DEFAULT_SONNET_MODEL ||
'gpt-5.4-mini',
opusModel:
process.env.CODEX_DEFAULT_OPUS_MODEL ||
settings?.env?.CODEX_DEFAULT_OPUS_MODEL ||
'gpt-5.5',
activeField: 'haiku_model',
codexResult: {
apiKey: process.env.CODEX_API_KEY || null,
accessToken: process.env.CODEX_ACCESS_TOKEN || '',
refreshToken: process.env.CODEX_REFRESH_TOKEN || '',
},
})
} else {
setOAuthStatus({ state: 'codex_oauth_start' })
}
} else if (value === 'gemini_api') { } else if (value === 'gemini_api') {
logEvent('tengu_gemini_api_selected', {}) logEvent('tengu_gemini_api_selected', {})
setOAuthStatus({ setOAuthStatus({
@@ -1489,6 +1519,231 @@ function OAuthStatusMessage({
) )
} }
case 'codex_models': {
type CodexField = 'haiku_model' | 'sonnet_model' | 'opus_model'
const CODEX_FIELDS: CodexField[] = ['haiku_model', 'sonnet_model', 'opus_model']
const cm = oauthStatus as {
state: 'codex_models'
activeField: CodexField
haikuModel: string
sonnetModel: string
opusModel: string
codexResult: { apiKey: string | null; accessToken: string; refreshToken: string }
}
const { activeField, haikuModel, sonnetModel, opusModel, codexResult } = cm
const codexDisplayValues: Record<CodexField, string> = {
haiku_model: haikuModel,
sonnet_model: sonnetModel,
opus_model: opusModel,
}
const [codexModelInput, setCodexModelInput] = useState(
() => codexDisplayValues[activeField],
)
const [codexModelCursor, setCodexModelCursor] = useState(
() => codexDisplayValues[activeField].length,
)
const buildCodexModelState = useCallback(
(field: CodexField, value: string, newActive?: CodexField) => {
const s = {
state: 'codex_models' as const,
activeField: newActive ?? activeField,
haikuModel,
sonnetModel,
opusModel,
codexResult,
}
switch (field) {
case 'haiku_model':
return { ...s, haikuModel: value }
case 'sonnet_model':
return { ...s, sonnetModel: value }
case 'opus_model':
return { ...s, opusModel: value }
}
},
[activeField, haikuModel, sonnetModel, opusModel, codexResult],
)
const doCodexModelSave = useCallback(() => {
const finalVals = { ...codexDisplayValues, [activeField]: codexModelInput }
const env: Record<string, string | undefined> = {
CODEX_API_KEY: codexResult.apiKey ?? undefined,
CODEX_ACCESS_TOKEN: codexResult.accessToken,
CODEX_REFRESH_TOKEN: codexResult.refreshToken,
CODEX_LOGIN_METHOD: 'chatgpt_subscription',
CODEX_DEFAULT_HAIKU_MODEL: finalVals.haiku_model,
CODEX_DEFAULT_SONNET_MODEL: finalVals.sonnet_model,
CODEX_DEFAULT_OPUS_MODEL: finalVals.opus_model,
}
const { error } = updateSettingsForSource('userSettings', {
modelType: 'codex' as any,
env,
} as any)
if (error) {
setOAuthStatus({
state: 'error',
message: 'Failed to save settings. Please try again.',
toRetry: {
state: 'codex_models',
haikuModel: finalVals.haiku_model,
sonnetModel: finalVals.sonnet_model,
opusModel: finalVals.opus_model,
activeField: 'haiku_model',
codexResult,
},
})
} else {
for (const [k, v] of Object.entries(env)) {
if (v !== undefined) {
process.env[k] = v
}
}
setOAuthStatus({ state: 'success' })
void onDone()
}
}, [activeField, codexModelInput, codexDisplayValues, codexResult, setOAuthStatus, onDone])
const handleCodexModelEnter = useCallback(() => {
const idx = CODEX_FIELDS.indexOf(activeField)
if (idx === CODEX_FIELDS.length - 1) {
setOAuthStatus(buildCodexModelState(activeField, codexModelInput))
doCodexModelSave()
} else {
const next = CODEX_FIELDS[idx + 1]!
setOAuthStatus(buildCodexModelState(activeField, codexModelInput, next))
setCodexModelInput(codexDisplayValues[next] ?? '')
setCodexModelCursor((codexDisplayValues[next] ?? '').length)
}
}, [
activeField,
codexModelInput,
buildCodexModelState,
doCodexModelSave,
codexDisplayValues,
setOAuthStatus,
])
useKeybinding(
'tabs:next',
() => {
const idx = CODEX_FIELDS.indexOf(activeField)
if (idx < CODEX_FIELDS.length - 1) {
setOAuthStatus(
buildCodexModelState(activeField, codexModelInput, CODEX_FIELDS[idx + 1]),
)
setCodexModelInput(codexDisplayValues[CODEX_FIELDS[idx + 1]!] ?? '')
setCodexModelCursor((codexDisplayValues[CODEX_FIELDS[idx + 1]!] ?? '').length)
}
},
{ context: 'FormField' },
)
useKeybinding(
'tabs:previous',
() => {
const idx = CODEX_FIELDS.indexOf(activeField)
if (idx > 0) {
setOAuthStatus(
buildCodexModelState(activeField, codexModelInput, CODEX_FIELDS[idx - 1]),
)
setCodexModelInput(codexDisplayValues[CODEX_FIELDS[idx - 1]!] ?? '')
setCodexModelCursor((codexDisplayValues[CODEX_FIELDS[idx - 1]!] ?? '').length)
}
},
{ context: 'FormField' },
)
useKeybinding(
'confirm:no',
() => {
setOAuthStatus({ state: 'idle' })
},
{ context: 'Confirmation' },
)
// Ctrl+D: clear codex login state and re-login
useKeybinding(
'oauth:codex-relogin',
() => {
// Clear codex credentials from process.env
delete process.env.CODEX_ACCESS_TOKEN
delete process.env.CODEX_REFRESH_TOKEN
delete process.env.CODEX_API_KEY
delete process.env.CODEX_LOGIN_METHOD
delete process.env.CODEX_DEFAULT_HAIKU_MODEL
delete process.env.CODEX_DEFAULT_SONNET_MODEL
delete process.env.CODEX_DEFAULT_OPUS_MODEL
// Clear from settings.json
updateSettingsForSource('userSettings', {
modelType: undefined,
env: {
CODEX_ACCESS_TOKEN: undefined,
CODEX_REFRESH_TOKEN: undefined,
CODEX_API_KEY: undefined,
CODEX_LOGIN_METHOD: undefined,
CODEX_DEFAULT_HAIKU_MODEL: undefined,
CODEX_DEFAULT_SONNET_MODEL: undefined,
CODEX_DEFAULT_OPUS_MODEL: undefined,
},
} as any)
// Restart OAuth flow
setOAuthStatus({ state: 'codex_oauth_start' })
},
{ context: 'FormField' },
)
const codexModelColumns = useTerminalSize().columns - 20
const renderCodexModelRow = (
field: CodexField,
label: string,
) => {
const active = activeField === field
const val = codexDisplayValues[field]
return (
<Box>
<Text
backgroundColor={active ? 'suggestion' : undefined}
color={active ? 'inverseText' : undefined}
>
{` ${label} `}
</Text>
<Text> </Text>
{active ? (
<TextInput
value={codexModelInput}
onChange={setCodexModelInput}
onSubmit={handleCodexModelEnter}
cursorOffset={codexModelCursor}
onChangeCursorOffset={setCodexModelCursor}
columns={codexModelColumns}
focus={true}
/>
) : val ? (
<Text color="success">{val}</Text>
) : null}
</Box>
)
}
return (
<Box flexDirection="column" gap={1}>
<Text bold>Codex Model Configuration</Text>
<Text dimColor>
ChatGPT login successful. Configure model names (press Enter on last field to save).
</Text>
<Box flexDirection="column" gap={1}>
{renderCodexModelRow('haiku_model', 'Haiku ')}
{renderCodexModelRow('sonnet_model', 'Sonnet ')}
{renderCodexModelRow('opus_model', 'Opus ')}
</Box>
<Text dimColor>
/Tab to switch · Enter on last field to save · Ctrl+R to re-login · Esc to go back
</Text>
</Box>
)
}
case 'platform_setup': case 'platform_setup':
return ( return (
<Box flexDirection="column" gap={1} marginTop={1}> <Box flexDirection="column" gap={1} marginTop={1}>

View File

@@ -156,6 +156,8 @@ export const DEFAULT_BINDINGS: KeybindingBlock[] = [
'shift+tab': 'tabs:previous', 'shift+tab': 'tabs:previous',
up: 'tabs:previous', up: 'tabs:previous',
down: 'tabs:next', down: 'tabs:next',
// Re-login: clear codex credentials and restart OAuth
'ctrl+r': 'oauth:codex-relogin',
}, },
}, },
{ {

View File

@@ -109,6 +109,8 @@ export const KEYBINDING_ACTIONS = [
// Tabs navigation actions // Tabs navigation actions
'tabs:next', 'tabs:next',
'tabs:previous', 'tabs:previous',
// OAuth re-login action (codex model config panel)
'oauth:codex-relogin',
// Transcript viewer actions // Transcript viewer actions
'transcript:toggleShowAll', 'transcript:toggleShowAll',
'transcript:exit', 'transcript:exit',

View File

@@ -13,7 +13,7 @@ export const CLAUDE_3_7_SONNET_CONFIG = {
foundry: 'claude-3-7-sonnet', foundry: 'claude-3-7-sonnet',
openai: 'claude-3-7-sonnet-20250219', openai: 'claude-3-7-sonnet-20250219',
gemini: 'claude-3-7-sonnet-20250219', gemini: 'claude-3-7-sonnet-20250219',
codex: 'claude-3-7-sonnet-20250219', codex: 'gpt-5.4-mini',
grok: 'claude-3-7-sonnet-20250219', grok: 'claude-3-7-sonnet-20250219',
} as const satisfies ModelConfig } as const satisfies ModelConfig
@@ -24,7 +24,7 @@ export const CLAUDE_3_5_V2_SONNET_CONFIG = {
foundry: 'claude-3-5-sonnet', foundry: 'claude-3-5-sonnet',
openai: 'claude-3-5-sonnet-20241022', openai: 'claude-3-5-sonnet-20241022',
gemini: 'claude-3-5-sonnet-20241022', gemini: 'claude-3-5-sonnet-20241022',
codex: 'claude-3-5-sonnet-20241022', codex: 'gpt-5.4-mini',
grok: 'claude-3-5-sonnet-20241022', grok: 'claude-3-5-sonnet-20241022',
} as const satisfies ModelConfig } as const satisfies ModelConfig
@@ -35,7 +35,7 @@ export const CLAUDE_3_5_HAIKU_CONFIG = {
foundry: 'claude-3-5-haiku', foundry: 'claude-3-5-haiku',
openai: 'claude-3-5-haiku-20241022', openai: 'claude-3-5-haiku-20241022',
gemini: 'claude-3-5-haiku-20241022', gemini: 'claude-3-5-haiku-20241022',
codex: 'claude-3-5-haiku-20241022', codex: 'gpt-5.4-mini',
grok: 'claude-3-5-haiku-20241022', grok: 'claude-3-5-haiku-20241022',
} as const satisfies ModelConfig } as const satisfies ModelConfig
@@ -46,7 +46,7 @@ export const CLAUDE_HAIKU_4_5_CONFIG = {
foundry: 'claude-haiku-4-5', foundry: 'claude-haiku-4-5',
openai: 'claude-haiku-4-5-20251001', openai: 'claude-haiku-4-5-20251001',
gemini: 'claude-haiku-4-5-20251001', gemini: 'claude-haiku-4-5-20251001',
codex: 'claude-haiku-4-5-20251001', codex: 'gpt-5.4-mini',
grok: 'claude-haiku-4-5-20251001', grok: 'claude-haiku-4-5-20251001',
} as const satisfies ModelConfig } as const satisfies ModelConfig
@@ -57,7 +57,7 @@ export const CLAUDE_SONNET_4_CONFIG = {
foundry: 'claude-sonnet-4', foundry: 'claude-sonnet-4',
openai: 'claude-sonnet-4-20250514', openai: 'claude-sonnet-4-20250514',
gemini: 'claude-sonnet-4-20250514', gemini: 'claude-sonnet-4-20250514',
codex: 'claude-sonnet-4-20250514', codex: 'gpt-5.4-mini',
grok: 'claude-sonnet-4-20250514', grok: 'claude-sonnet-4-20250514',
} as const satisfies ModelConfig } as const satisfies ModelConfig
@@ -68,7 +68,7 @@ export const CLAUDE_SONNET_4_5_CONFIG = {
foundry: 'claude-sonnet-4-5', foundry: 'claude-sonnet-4-5',
openai: 'claude-sonnet-4-5-20250929', openai: 'claude-sonnet-4-5-20250929',
gemini: 'claude-sonnet-4-5-20250929', gemini: 'claude-sonnet-4-5-20250929',
codex: 'claude-sonnet-4-5-20250929', codex: 'gpt-5.4-mini',
grok: 'claude-sonnet-4-5-20250929', grok: 'claude-sonnet-4-5-20250929',
} as const satisfies ModelConfig } as const satisfies ModelConfig
@@ -79,7 +79,7 @@ export const CLAUDE_OPUS_4_CONFIG = {
foundry: 'claude-opus-4', foundry: 'claude-opus-4',
openai: 'claude-opus-4-20250514', openai: 'claude-opus-4-20250514',
gemini: 'claude-opus-4-20250514', gemini: 'claude-opus-4-20250514',
codex: 'claude-opus-4-20250514', codex: 'gpt-5.4',
grok: 'claude-opus-4-20250514', grok: 'claude-opus-4-20250514',
} as const satisfies ModelConfig } as const satisfies ModelConfig
@@ -90,7 +90,7 @@ export const CLAUDE_OPUS_4_1_CONFIG = {
foundry: 'claude-opus-4-1', foundry: 'claude-opus-4-1',
openai: 'claude-opus-4-1-20250805', openai: 'claude-opus-4-1-20250805',
gemini: 'claude-opus-4-1-20250805', gemini: 'claude-opus-4-1-20250805',
codex: 'claude-opus-4-1-20250805', codex: 'gpt-5.4',
grok: 'claude-opus-4-1-20250805', grok: 'claude-opus-4-1-20250805',
} as const satisfies ModelConfig } as const satisfies ModelConfig
@@ -101,7 +101,7 @@ export const CLAUDE_OPUS_4_5_CONFIG = {
foundry: 'claude-opus-4-5', foundry: 'claude-opus-4-5',
openai: 'claude-opus-4-5-20251101', openai: 'claude-opus-4-5-20251101',
gemini: 'claude-opus-4-5-20251101', gemini: 'claude-opus-4-5-20251101',
codex: 'claude-opus-4-5-20251101', codex: 'gpt-5.4',
grok: 'claude-opus-4-5-20251101', grok: 'claude-opus-4-5-20251101',
} as const satisfies ModelConfig } as const satisfies ModelConfig
@@ -112,7 +112,7 @@ export const CLAUDE_OPUS_4_6_CONFIG = {
foundry: 'claude-opus-4-6', foundry: 'claude-opus-4-6',
openai: 'claude-opus-4-6', openai: 'claude-opus-4-6',
gemini: 'claude-opus-4-6', gemini: 'claude-opus-4-6',
codex: 'claude-opus-4-6', codex: 'gpt-5.4',
grok: 'claude-opus-4-6', grok: 'claude-opus-4-6',
} as const satisfies ModelConfig } as const satisfies ModelConfig
@@ -123,7 +123,7 @@ export const CLAUDE_OPUS_4_7_CONFIG = {
foundry: 'claude-opus-4-7', foundry: 'claude-opus-4-7',
openai: 'claude-opus-4-7', openai: 'claude-opus-4-7',
gemini: 'claude-opus-4-7', gemini: 'claude-opus-4-7',
codex: 'claude-opus-4-7', codex: 'gpt-5.5',
grok: 'claude-opus-4-7', grok: 'claude-opus-4-7',
} as const satisfies ModelConfig } as const satisfies ModelConfig
@@ -134,7 +134,7 @@ export const CLAUDE_SONNET_4_6_CONFIG = {
foundry: 'claude-sonnet-4-6', foundry: 'claude-sonnet-4-6',
openai: 'claude-sonnet-4-6', openai: 'claude-sonnet-4-6',
gemini: 'claude-sonnet-4-6', gemini: 'claude-sonnet-4-6',
codex: 'claude-sonnet-4-6', codex: 'gpt-5.4-mini',
grok: 'claude-sonnet-4-6', grok: 'claude-sonnet-4-6',
} as const satisfies ModelConfig } as const satisfies ModelConfig

View File

@@ -83,7 +83,9 @@ function getCustomSonnetOption(): ModelOption | undefined {
? process.env.OPENAI_DEFAULT_SONNET_MODEL ? process.env.OPENAI_DEFAULT_SONNET_MODEL
: provider === 'gemini' : provider === 'gemini'
? process.env.GEMINI_DEFAULT_SONNET_MODEL ? process.env.GEMINI_DEFAULT_SONNET_MODEL
: process.env.ANTHROPIC_DEFAULT_SONNET_MODEL : provider === 'codex'
? process.env.CODEX_DEFAULT_SONNET_MODEL
: process.env.ANTHROPIC_DEFAULT_SONNET_MODEL
// When a 3P user has a custom sonnet model string, show it directly // When a 3P user has a custom sonnet model string, show it directly
if (is3P && customSonnetModel) { if (is3P && customSonnetModel) {
const is1m = has1mContext(customSonnetModel) const is1m = has1mContext(customSonnetModel)
@@ -93,13 +95,17 @@ function getCustomSonnetOption(): ModelOption | undefined {
? process.env.OPENAI_DEFAULT_SONNET_MODEL_NAME ? process.env.OPENAI_DEFAULT_SONNET_MODEL_NAME
: provider === 'gemini' : provider === 'gemini'
? process.env.GEMINI_DEFAULT_SONNET_MODEL_NAME ? process.env.GEMINI_DEFAULT_SONNET_MODEL_NAME
: process.env.ANTHROPIC_DEFAULT_SONNET_MODEL_NAME : provider === 'codex'
? process.env.CODEX_DEFAULT_SONNET_MODEL_NAME
: process.env.ANTHROPIC_DEFAULT_SONNET_MODEL_NAME
const descEnv = const descEnv =
provider === 'openai' provider === 'openai'
? process.env.OPENAI_DEFAULT_SONNET_MODEL_DESCRIPTION ? process.env.OPENAI_DEFAULT_SONNET_MODEL_DESCRIPTION
: provider === 'gemini' : provider === 'gemini'
? process.env.GEMINI_DEFAULT_SONNET_MODEL_DESCRIPTION ? process.env.GEMINI_DEFAULT_SONNET_MODEL_DESCRIPTION
: process.env.ANTHROPIC_DEFAULT_SONNET_MODEL_DESCRIPTION : provider === 'codex'
? process.env.CODEX_DEFAULT_SONNET_MODEL_DESCRIPTION
: process.env.ANTHROPIC_DEFAULT_SONNET_MODEL_DESCRIPTION
return { return {
value: 'sonnet', value: 'sonnet',
label: nameEnv ?? customSonnetModel, label: nameEnv ?? customSonnetModel,
@@ -132,7 +138,9 @@ function getCustomOpusOption(): ModelOption | undefined {
? process.env.OPENAI_DEFAULT_OPUS_MODEL ? process.env.OPENAI_DEFAULT_OPUS_MODEL
: provider === 'gemini' : provider === 'gemini'
? process.env.GEMINI_DEFAULT_OPUS_MODEL ? process.env.GEMINI_DEFAULT_OPUS_MODEL
: process.env.ANTHROPIC_DEFAULT_OPUS_MODEL : provider === 'codex'
? process.env.CODEX_DEFAULT_OPUS_MODEL
: process.env.ANTHROPIC_DEFAULT_OPUS_MODEL
// When a 3P user has a custom opus model string, show it directly // When a 3P user has a custom opus model string, show it directly
if (is3P && customOpusModel) { if (is3P && customOpusModel) {
const is1m = has1mContext(customOpusModel) const is1m = has1mContext(customOpusModel)
@@ -142,13 +150,17 @@ function getCustomOpusOption(): ModelOption | undefined {
? process.env.OPENAI_DEFAULT_OPUS_MODEL_NAME ? process.env.OPENAI_DEFAULT_OPUS_MODEL_NAME
: provider === 'gemini' : provider === 'gemini'
? process.env.GEMINI_DEFAULT_OPUS_MODEL_NAME ? process.env.GEMINI_DEFAULT_OPUS_MODEL_NAME
: process.env.ANTHROPIC_DEFAULT_OPUS_MODEL_NAME : provider === 'codex'
? process.env.CODEX_DEFAULT_OPUS_MODEL_NAME
: process.env.ANTHROPIC_DEFAULT_OPUS_MODEL_NAME
const descEnv = const descEnv =
provider === 'openai' provider === 'openai'
? process.env.OPENAI_DEFAULT_OPUS_MODEL_DESCRIPTION ? process.env.OPENAI_DEFAULT_OPUS_MODEL_DESCRIPTION
: provider === 'gemini' : provider === 'gemini'
? process.env.GEMINI_DEFAULT_OPUS_MODEL_DESCRIPTION ? process.env.GEMINI_DEFAULT_OPUS_MODEL_DESCRIPTION
: process.env.ANTHROPIC_DEFAULT_OPUS_MODEL_DESCRIPTION : provider === 'codex'
? process.env.CODEX_DEFAULT_OPUS_MODEL_DESCRIPTION
: process.env.ANTHROPIC_DEFAULT_OPUS_MODEL_DESCRIPTION
return { return {
value: 'opus', value: 'opus',
label: nameEnv ?? customOpusModel, label: nameEnv ?? customOpusModel,
@@ -232,7 +244,9 @@ function getCustomHaikuOption(): ModelOption | undefined {
? process.env.OPENAI_DEFAULT_HAIKU_MODEL ? process.env.OPENAI_DEFAULT_HAIKU_MODEL
: provider === 'gemini' : provider === 'gemini'
? process.env.GEMINI_DEFAULT_HAIKU_MODEL ? process.env.GEMINI_DEFAULT_HAIKU_MODEL
: process.env.ANTHROPIC_DEFAULT_HAIKU_MODEL : provider === 'codex'
? process.env.CODEX_DEFAULT_HAIKU_MODEL
: process.env.ANTHROPIC_DEFAULT_HAIKU_MODEL
// When a 3P user has a custom haiku model string, show it directly // When a 3P user has a custom haiku model string, show it directly
if (is3P && customHaikuModel) { if (is3P && customHaikuModel) {
// Use appropriate NAME/DESCRIPTION env vars based on provider // Use appropriate NAME/DESCRIPTION env vars based on provider
@@ -241,13 +255,17 @@ function getCustomHaikuOption(): ModelOption | undefined {
? process.env.OPENAI_DEFAULT_HAIKU_MODEL_NAME ? process.env.OPENAI_DEFAULT_HAIKU_MODEL_NAME
: provider === 'gemini' : provider === 'gemini'
? process.env.GEMINI_DEFAULT_HAIKU_MODEL_NAME ? process.env.GEMINI_DEFAULT_HAIKU_MODEL_NAME
: process.env.ANTHROPIC_DEFAULT_HAIKU_MODEL_NAME : provider === 'codex'
? process.env.CODEX_DEFAULT_HAIKU_MODEL_NAME
: process.env.ANTHROPIC_DEFAULT_HAIKU_MODEL_NAME
const descEnv = const descEnv =
provider === 'openai' provider === 'openai'
? process.env.OPENAI_DEFAULT_HAIKU_MODEL_DESCRIPTION ? process.env.OPENAI_DEFAULT_HAIKU_MODEL_DESCRIPTION
: provider === 'gemini' : provider === 'gemini'
? process.env.GEMINI_DEFAULT_HAIKU_MODEL_DESCRIPTION ? process.env.GEMINI_DEFAULT_HAIKU_MODEL_DESCRIPTION
: process.env.ANTHROPIC_DEFAULT_HAIKU_MODEL_DESCRIPTION : provider === 'codex'
? process.env.CODEX_DEFAULT_HAIKU_MODEL_DESCRIPTION
: process.env.ANTHROPIC_DEFAULT_HAIKU_MODEL_DESCRIPTION
return { return {
value: 'haiku', value: 'haiku',
label: nameEnv ?? customHaikuModel, label: nameEnv ?? customHaikuModel,