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', () => {
|
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', () => {
|
||||||
|
|||||||
@@ -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',
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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}>
|
||||||
|
|||||||
@@ -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',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -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',
|
||||||
|
|||||||
@@ -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
|
||||||
|
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
Reference in New Issue
Block a user