diff --git a/src/commands/provider.ts b/src/commands/provider.ts index 19b19c021..eae2e2dd2 100644 --- a/src/commands/provider.ts +++ b/src/commands/provider.ts @@ -63,6 +63,7 @@ const call: LocalCommandCall = async (args, context) => { const validProviders = [ 'anthropic', 'openai', + 'codex', 'gemini', 'grok', 'bedrock', @@ -120,10 +121,23 @@ const call: LocalCommandCall = async (args, context) => { } } + // Check env vars when switching to codex (including settings.env) + if (arg === 'codex') { + const mergedEnv = getMergedEnv() + const hasKey = !!mergedEnv.CODEX_API_KEY + if (!hasKey) { + updateSettingsForSource('userSettings', { modelType: 'codex' }) + return { + type: 'text', + value: `Switched to Codex provider.\nWarning: Missing env var: CODEX_API_KEY\nConfigure it via /login (ChatGPT Subscription) or set manually.`, + } + } + } + // Handle different provider types // - 'anthropic', 'openai', 'gemini' are stored in settings.json (persistent) // - 'bedrock', 'vertex', 'foundry' are env-only (do NOT touch settings.json) - if (arg === 'anthropic' || arg === 'openai' || arg === 'gemini' || arg === 'grok') { + if (arg === 'anthropic' || arg === 'openai' || arg === 'codex' || arg === 'gemini' || arg === 'grok') { // Clear any cloud provider env vars to avoid conflicts delete process.env.CLAUDE_CODE_USE_BEDROCK delete process.env.CLAUDE_CODE_USE_VERTEX @@ -131,7 +145,7 @@ const call: LocalCommandCall = async (args, context) => { delete process.env.CLAUDE_CODE_USE_OPENAI delete process.env.CLAUDE_CODE_USE_GEMINI delete process.env.CLAUDE_CODE_USE_GROK - // Update settings.json + delete process.env.CLAUDE_CODE_USE_CODEX updateSettingsForSource('userSettings', { modelType: arg }) // Ensure settings.env gets applied to process.env applyConfigEnvironmentVariables() @@ -157,9 +171,9 @@ const provider = { type: 'local', name: 'provider', description: - 'Switch API provider (anthropic/openai/gemini/grok/bedrock/vertex/foundry)', + 'Switch API provider (anthropic/openai/codex/gemini/grok/bedrock/vertex/foundry)', aliases: ['api'], - argumentHint: '[anthropic|openai|gemini|grok|bedrock|vertex|foundry|unset]', + argumentHint: '[anthropic|openai|codex|gemini|grok|bedrock|vertex|foundry|unset]', supportsNonInteractive: true, load: () => Promise.resolve({ call }), } satisfies Command diff --git a/src/utils/managedEnvConstants.ts b/src/utils/managedEnvConstants.ts index d1976c114..688e794c5 100644 --- a/src/utils/managedEnvConstants.ts +++ b/src/utils/managedEnvConstants.ts @@ -23,6 +23,7 @@ const PROVIDER_MANAGED_ENV_VARS = new Set([ 'CLAUDE_CODE_USE_VERTEX', 'CLAUDE_CODE_USE_FOUNDRY', 'CLAUDE_CODE_USE_GEMINI', + 'CLAUDE_CODE_USE_CODEX', // Endpoint config (base URLs, project/resource identifiers) 'ANTHROPIC_BASE_URL', 'ANTHROPIC_BEDROCK_BASE_URL', @@ -31,6 +32,7 @@ const PROVIDER_MANAGED_ENV_VARS = new Set([ 'ANTHROPIC_FOUNDRY_RESOURCE', 'ANTHROPIC_VERTEX_PROJECT_ID', 'GEMINI_BASE_URL', + 'CODEX_BASE_URL', // Region routing (per-model VERTEX_REGION_CLAUDE_* handled by prefix below) 'CLOUD_ML_REGION', // Auth @@ -43,6 +45,7 @@ const PROVIDER_MANAGED_ENV_VARS = new Set([ 'CLAUDE_CODE_SKIP_VERTEX_AUTH', 'CLAUDE_CODE_SKIP_FOUNDRY_AUTH', 'GEMINI_API_KEY', + 'CODEX_API_KEY', // Model defaults — often set to provider-specific ID formats 'ANTHROPIC_MODEL', 'ANTHROPIC_DEFAULT_HAIKU_MODEL', @@ -92,6 +95,17 @@ const PROVIDER_MANAGED_ENV_VARS = new Set([ 'GEMINI_DEFAULT_SONNET_MODEL_DESCRIPTION', 'GEMINI_DEFAULT_SONNET_MODEL_NAME', 'GEMINI_DEFAULT_SONNET_MODEL_SUPPORTED_CAPABILITIES', + // Codex provider specific + 'CODEX_BASE_URL', + 'CODEX_API_KEY', + 'CODEX_MODEL', + 'CODEX_DEFAULT_HAIKU_MODEL', + 'CODEX_DEFAULT_SONNET_MODEL', + 'CODEX_DEFAULT_OPUS_MODEL', + 'CODEX_IMGBB_API_KEY', + 'CODEX_LOGIN_METHOD', + 'CODEX_ACCESS_TOKEN', + 'CODEX_REFRESH_TOKEN', ]) const PROVIDER_MANAGED_ENV_PREFIXES = [ @@ -201,6 +215,7 @@ export const SAFE_ENV_VARS = new Set([ 'CLAUDE_CODE_USE_FOUNDRY', 'CLAUDE_CODE_USE_GEMINI', 'CLAUDE_CODE_USE_VERTEX', + 'CLAUDE_CODE_USE_CODEX', 'GEMINI_MODEL', 'GEMINI_SMALL_FAST_MODEL', 'GEMINI_DEFAULT_HAIKU_MODEL', @@ -215,6 +230,11 @@ export const SAFE_ENV_VARS = new Set([ 'GEMINI_DEFAULT_SONNET_MODEL_DESCRIPTION', 'GEMINI_DEFAULT_SONNET_MODEL_NAME', 'GEMINI_DEFAULT_SONNET_MODEL_SUPPORTED_CAPABILITIES', + // Codex provider specific + 'CODEX_DEFAULT_HAIKU_MODEL', + 'CODEX_DEFAULT_SONNET_MODEL', + 'CODEX_DEFAULT_OPUS_MODEL', + 'CODEX_IMGBB_API_KEY', 'DISABLE_AUTOUPDATER', 'DISABLE_BUG_COMMAND', 'DISABLE_COST_WARNINGS', diff --git a/src/utils/model/configs.ts b/src/utils/model/configs.ts index 58d157d9c..3a1bbf617 100644 --- a/src/utils/model/configs.ts +++ b/src/utils/model/configs.ts @@ -13,6 +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', grok: 'claude-3-7-sonnet-20250219', } as const satisfies ModelConfig @@ -23,6 +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', grok: 'claude-3-5-sonnet-20241022', } as const satisfies ModelConfig @@ -33,6 +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', grok: 'claude-3-5-haiku-20241022', } as const satisfies ModelConfig @@ -43,6 +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', grok: 'claude-haiku-4-5-20251001', } as const satisfies ModelConfig @@ -53,6 +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', grok: 'claude-sonnet-4-20250514', } as const satisfies ModelConfig @@ -63,6 +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', grok: 'claude-sonnet-4-5-20250929', } as const satisfies ModelConfig @@ -73,6 +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', grok: 'claude-opus-4-20250514', } as const satisfies ModelConfig @@ -83,6 +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', grok: 'claude-opus-4-1-20250805', } as const satisfies ModelConfig @@ -93,6 +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', grok: 'claude-opus-4-5-20251101', } as const satisfies ModelConfig @@ -103,6 +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', grok: 'claude-opus-4-6', } as const satisfies ModelConfig @@ -113,6 +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', grok: 'claude-opus-4-7', } as const satisfies ModelConfig @@ -123,6 +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', grok: 'claude-sonnet-4-6', } as const satisfies ModelConfig diff --git a/src/utils/model/providers.ts b/src/utils/model/providers.ts index 79572d42e..d04f88f70 100644 --- a/src/utils/model/providers.ts +++ b/src/utils/model/providers.ts @@ -8,12 +8,14 @@ export type APIProvider = | 'vertex' | 'foundry' | 'openai' + | 'codex' | 'gemini' | 'grok' export function getAPIProvider(): APIProvider { const modelType = getInitialSettings().modelType if (modelType === 'openai') return 'openai' + if (modelType === 'codex') return 'codex' if (modelType === 'gemini') return 'gemini' if (modelType === 'grok') return 'grok' @@ -22,6 +24,7 @@ export function getAPIProvider(): APIProvider { if (isEnvTruthy(process.env.CLAUDE_CODE_USE_FOUNDRY)) return 'foundry' if (isEnvTruthy(process.env.CLAUDE_CODE_USE_OPENAI)) return 'openai' + if (isEnvTruthy(process.env.CLAUDE_CODE_USE_CODEX)) return 'codex' if (isEnvTruthy(process.env.CLAUDE_CODE_USE_GEMINI)) return 'gemini' if (isEnvTruthy(process.env.CLAUDE_CODE_USE_GROK)) return 'grok' diff --git a/src/utils/status.tsx b/src/utils/status.tsx index b4cb087c2..f45a1436e 100644 --- a/src/utils/status.tsx +++ b/src/utils/status.tsx @@ -342,6 +342,7 @@ export function buildAPIProviderProperties(): Property[] { gemini: 'Gemini API', grok: 'Grok API', openai: 'OpenAI API', + codex: 'Codex API', }[apiProvider] properties.push({ label: 'API provider',