mirror of
https://github.com/claude-code-best/claude-code.git
synced 2026-06-15 12:55:51 +00:00
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:
@@ -45,7 +45,7 @@ describe('resolveCodexModel', () => {
|
||||
})
|
||||
|
||||
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', () => {
|
||||
@@ -58,7 +58,7 @@ describe('resolveCodexModel', () => {
|
||||
})
|
||||
|
||||
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', () => {
|
||||
@@ -67,7 +67,7 @@ describe('resolveCodexModel', () => {
|
||||
})
|
||||
|
||||
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', () => {
|
||||
|
||||
@@ -12,15 +12,16 @@ const DEFAULT_MODEL_MAP: Record<string, string> = {
|
||||
'claude-opus-4-1-20250805': 'gpt-5.4',
|
||||
'claude-opus-4-5-20251101': 'gpt-5.4',
|
||||
'claude-opus-4-6': 'gpt-5.4',
|
||||
'claude-haiku-4-5-20251001': 'gpt-5.4-nano',
|
||||
'claude-3-5-haiku-20241022': 'gpt-5.4-nano',
|
||||
'claude-opus-4-7': 'gpt-5.5',
|
||||
'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.
|
||||
*/
|
||||
const DEFAULT_FAMILY_MAP: Record<string, string> = {
|
||||
haiku: 'gpt-5.4-nano',
|
||||
haiku: 'gpt-5.4-mini',
|
||||
sonnet: 'gpt-5.4-mini',
|
||||
opus: 'gpt-5.4',
|
||||
}
|
||||
|
||||
@@ -58,6 +58,18 @@ type OAuthStatus =
|
||||
} // Gemini Generate Content API platform
|
||||
| { state: 'codex_oauth_waiting'; url: string } // ChatGPT OAuth browser login in progress
|
||||
| { 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: 'waiting_for_login'; url: string } // Browser opened, waiting for user to login
|
||||
| { state: 'creating_api_key' } // Got access token, creating API key
|
||||
@@ -365,31 +377,19 @@ export function ConsoleOAuthFlow({
|
||||
manualCode: manualCodePromise,
|
||||
})
|
||||
|
||||
const env: Record<string, string | undefined> = {
|
||||
CODEX_API_KEY: result.apiKey ?? undefined,
|
||||
CODEX_ACCESS_TOKEN: result.accessToken,
|
||||
CODEX_REFRESH_TOKEN: result.refreshToken,
|
||||
CODEX_LOGIN_METHOD: 'chatgpt_subscription',
|
||||
}
|
||||
updateSettingsForSource('userSettings', {
|
||||
modelType: 'codex',
|
||||
env,
|
||||
} as any)
|
||||
for (const [key, value] of Object.entries(env)) {
|
||||
if (value !== undefined) {
|
||||
process.env[key] = value
|
||||
}
|
||||
}
|
||||
|
||||
setOAuthStatus({ state: 'success' })
|
||||
void sendNotification(
|
||||
{
|
||||
message: 'OpenAI Codex (ChatGPT) login successful',
|
||||
notificationType: 'auth_success',
|
||||
// Transition to model configuration panel with defaults
|
||||
setOAuthStatus({
|
||||
state: 'codex_models',
|
||||
haikuModel: process.env.CODEX_DEFAULT_HAIKU_MODEL || 'gpt-5.4-mini',
|
||||
sonnetModel: process.env.CODEX_DEFAULT_SONNET_MODEL || 'gpt-5.4-mini',
|
||||
opusModel: process.env.CODEX_DEFAULT_OPUS_MODEL || 'gpt-5.5',
|
||||
activeField: 'haiku_model',
|
||||
codexResult: {
|
||||
apiKey: result.apiKey,
|
||||
accessToken: result.accessToken,
|
||||
refreshToken: result.refreshToken,
|
||||
},
|
||||
terminal,
|
||||
)
|
||||
onDone()
|
||||
})
|
||||
} catch (err) {
|
||||
logError(err as Error)
|
||||
setOAuthStatus({
|
||||
@@ -714,7 +714,37 @@ function OAuthStatusMessage({
|
||||
})
|
||||
} else if (value === 'codex_chatgpt') {
|
||||
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') {
|
||||
logEvent('tengu_gemini_api_selected', {})
|
||||
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':
|
||||
return (
|
||||
<Box flexDirection="column" gap={1} marginTop={1}>
|
||||
|
||||
@@ -156,6 +156,8 @@ export const DEFAULT_BINDINGS: KeybindingBlock[] = [
|
||||
'shift+tab': 'tabs:previous',
|
||||
up: 'tabs:previous',
|
||||
down: 'tabs:next',
|
||||
// Re-login: clear codex credentials and restart OAuth
|
||||
'ctrl+r': 'oauth:codex-relogin',
|
||||
},
|
||||
},
|
||||
{
|
||||
|
||||
@@ -109,6 +109,8 @@ export const KEYBINDING_ACTIONS = [
|
||||
// Tabs navigation actions
|
||||
'tabs:next',
|
||||
'tabs:previous',
|
||||
// OAuth re-login action (codex model config panel)
|
||||
'oauth:codex-relogin',
|
||||
// Transcript viewer actions
|
||||
'transcript:toggleShowAll',
|
||||
'transcript:exit',
|
||||
|
||||
@@ -13,7 +13,7 @@ export const CLAUDE_3_7_SONNET_CONFIG = {
|
||||
foundry: 'claude-3-7-sonnet',
|
||||
openai: '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',
|
||||
} as const satisfies ModelConfig
|
||||
|
||||
@@ -24,7 +24,7 @@ export const CLAUDE_3_5_V2_SONNET_CONFIG = {
|
||||
foundry: 'claude-3-5-sonnet',
|
||||
openai: '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',
|
||||
} as const satisfies ModelConfig
|
||||
|
||||
@@ -35,7 +35,7 @@ export const CLAUDE_3_5_HAIKU_CONFIG = {
|
||||
foundry: 'claude-3-5-haiku',
|
||||
openai: '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',
|
||||
} as const satisfies ModelConfig
|
||||
|
||||
@@ -46,7 +46,7 @@ export const CLAUDE_HAIKU_4_5_CONFIG = {
|
||||
foundry: 'claude-haiku-4-5',
|
||||
openai: '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',
|
||||
} as const satisfies ModelConfig
|
||||
|
||||
@@ -57,7 +57,7 @@ export const CLAUDE_SONNET_4_CONFIG = {
|
||||
foundry: 'claude-sonnet-4',
|
||||
openai: 'claude-sonnet-4-20250514',
|
||||
gemini: 'claude-sonnet-4-20250514',
|
||||
codex: 'claude-sonnet-4-20250514',
|
||||
codex: 'gpt-5.4-mini',
|
||||
grok: 'claude-sonnet-4-20250514',
|
||||
} as const satisfies ModelConfig
|
||||
|
||||
@@ -68,7 +68,7 @@ export const CLAUDE_SONNET_4_5_CONFIG = {
|
||||
foundry: 'claude-sonnet-4-5',
|
||||
openai: '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',
|
||||
} as const satisfies ModelConfig
|
||||
|
||||
@@ -79,7 +79,7 @@ export const CLAUDE_OPUS_4_CONFIG = {
|
||||
foundry: 'claude-opus-4',
|
||||
openai: 'claude-opus-4-20250514',
|
||||
gemini: 'claude-opus-4-20250514',
|
||||
codex: 'claude-opus-4-20250514',
|
||||
codex: 'gpt-5.4',
|
||||
grok: 'claude-opus-4-20250514',
|
||||
} as const satisfies ModelConfig
|
||||
|
||||
@@ -90,7 +90,7 @@ export const CLAUDE_OPUS_4_1_CONFIG = {
|
||||
foundry: 'claude-opus-4-1',
|
||||
openai: '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',
|
||||
} as const satisfies ModelConfig
|
||||
|
||||
@@ -101,7 +101,7 @@ export const CLAUDE_OPUS_4_5_CONFIG = {
|
||||
foundry: 'claude-opus-4-5',
|
||||
openai: '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',
|
||||
} as const satisfies ModelConfig
|
||||
|
||||
@@ -112,7 +112,7 @@ export const CLAUDE_OPUS_4_6_CONFIG = {
|
||||
foundry: 'claude-opus-4-6',
|
||||
openai: 'claude-opus-4-6',
|
||||
gemini: 'claude-opus-4-6',
|
||||
codex: 'claude-opus-4-6',
|
||||
codex: 'gpt-5.4',
|
||||
grok: 'claude-opus-4-6',
|
||||
} as const satisfies ModelConfig
|
||||
|
||||
@@ -123,7 +123,7 @@ export const CLAUDE_OPUS_4_7_CONFIG = {
|
||||
foundry: 'claude-opus-4-7',
|
||||
openai: 'claude-opus-4-7',
|
||||
gemini: 'claude-opus-4-7',
|
||||
codex: 'claude-opus-4-7',
|
||||
codex: 'gpt-5.5',
|
||||
grok: 'claude-opus-4-7',
|
||||
} as const satisfies ModelConfig
|
||||
|
||||
@@ -134,7 +134,7 @@ export const CLAUDE_SONNET_4_6_CONFIG = {
|
||||
foundry: 'claude-sonnet-4-6',
|
||||
openai: 'claude-sonnet-4-6',
|
||||
gemini: 'claude-sonnet-4-6',
|
||||
codex: 'claude-sonnet-4-6',
|
||||
codex: 'gpt-5.4-mini',
|
||||
grok: 'claude-sonnet-4-6',
|
||||
} as const satisfies ModelConfig
|
||||
|
||||
|
||||
@@ -83,7 +83,9 @@ function getCustomSonnetOption(): ModelOption | undefined {
|
||||
? process.env.OPENAI_DEFAULT_SONNET_MODEL
|
||||
: provider === 'gemini'
|
||||
? 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
|
||||
if (is3P && customSonnetModel) {
|
||||
const is1m = has1mContext(customSonnetModel)
|
||||
@@ -93,13 +95,17 @@ function getCustomSonnetOption(): ModelOption | undefined {
|
||||
? process.env.OPENAI_DEFAULT_SONNET_MODEL_NAME
|
||||
: provider === 'gemini'
|
||||
? 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 =
|
||||
provider === 'openai'
|
||||
? process.env.OPENAI_DEFAULT_SONNET_MODEL_DESCRIPTION
|
||||
: provider === 'gemini'
|
||||
? 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 {
|
||||
value: 'sonnet',
|
||||
label: nameEnv ?? customSonnetModel,
|
||||
@@ -132,7 +138,9 @@ function getCustomOpusOption(): ModelOption | undefined {
|
||||
? process.env.OPENAI_DEFAULT_OPUS_MODEL
|
||||
: provider === 'gemini'
|
||||
? 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
|
||||
if (is3P && customOpusModel) {
|
||||
const is1m = has1mContext(customOpusModel)
|
||||
@@ -142,13 +150,17 @@ function getCustomOpusOption(): ModelOption | undefined {
|
||||
? process.env.OPENAI_DEFAULT_OPUS_MODEL_NAME
|
||||
: provider === 'gemini'
|
||||
? 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 =
|
||||
provider === 'openai'
|
||||
? process.env.OPENAI_DEFAULT_OPUS_MODEL_DESCRIPTION
|
||||
: provider === 'gemini'
|
||||
? 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 {
|
||||
value: 'opus',
|
||||
label: nameEnv ?? customOpusModel,
|
||||
@@ -232,7 +244,9 @@ function getCustomHaikuOption(): ModelOption | undefined {
|
||||
? process.env.OPENAI_DEFAULT_HAIKU_MODEL
|
||||
: provider === 'gemini'
|
||||
? 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
|
||||
if (is3P && customHaikuModel) {
|
||||
// Use appropriate NAME/DESCRIPTION env vars based on provider
|
||||
@@ -241,13 +255,17 @@ function getCustomHaikuOption(): ModelOption | undefined {
|
||||
? process.env.OPENAI_DEFAULT_HAIKU_MODEL_NAME
|
||||
: provider === 'gemini'
|
||||
? 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 =
|
||||
provider === 'openai'
|
||||
? process.env.OPENAI_DEFAULT_HAIKU_MODEL_DESCRIPTION
|
||||
: provider === 'gemini'
|
||||
? 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 {
|
||||
value: 'haiku',
|
||||
label: nameEnv ?? customHaikuModel,
|
||||
|
||||
Reference in New Issue
Block a user