From 654ce0d2f707bd8d6dc288e71d78184ca13a7d5c Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Fri, 24 Apr 2026 04:07:19 +0000 Subject: [PATCH 01/97] chore(release): 7.73.1-dev.12 [skip ci] --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 62a636fb..c6ab9f49 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@kaitranntt/ccs", - "version": "7.73.1-dev.11", + "version": "7.73.1-dev.12", "description": "Claude Code Switch - Instant profile switching between Claude, GLM, Kimi, and more", "keywords": [ "cli", From a6170a967d33fa01da5b15ccef2429490e7d2d99 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Fri, 24 Apr 2026 04:37:56 +0000 Subject: [PATCH 02/97] chore(release): 7.74.0-dev.1 [skip ci] --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index e2fbffd8..fab1de19 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@kaitranntt/ccs", - "version": "7.74.0", + "version": "7.74.0-dev.1", "description": "Claude Code Switch - Instant profile switching between Claude, GLM, Kimi, and more", "keywords": [ "cli", From 4efd61ee3477e2b80e0074c2ef1683d53c8b411c Mon Sep 17 00:00:00 2001 From: Tam Nhu Tran Date: Fri, 24 Apr 2026 10:30:59 -0400 Subject: [PATCH 03/97] feat: add gpt-5.5 to codex model catalogs --- src/cliproxy/codex-plan-compatibility.ts | 1 + src/cliproxy/model-catalog.ts | 13 ++++++ ...codex-plan-compatibility-reconcile.test.ts | 42 +++++++++++++++++++ .../cliproxy/codex-plan-compatibility.test.ts | 3 ++ tests/unit/cliproxy/model-catalog.test.js | 1 + .../codex-top-level-controls-card.tsx | 14 ++++--- ui/src/lib/model-catalogs.ts | 13 ++++++ .../codex-top-level-controls-card.test.tsx | 2 +- .../unit/ui/lib/model-catalogs-codex.test.ts | 3 ++ 9 files changed, 85 insertions(+), 7 deletions(-) diff --git a/src/cliproxy/codex-plan-compatibility.ts b/src/cliproxy/codex-plan-compatibility.ts index 5276f970..73cd82c8 100644 --- a/src/cliproxy/codex-plan-compatibility.ts +++ b/src/cliproxy/codex-plan-compatibility.ts @@ -18,6 +18,7 @@ const KNOWN_CODEX_MODELS = new Set( ); const FREE_PLAN_FALLBACKS = new Map([ + ['gpt-5.5', FREE_SAFE_DEFAULT_MODEL], ['gpt-5.3-codex', FREE_SAFE_DEFAULT_MODEL], ['gpt-5.3-codex-spark', FREE_SAFE_FAST_MODEL], ]); diff --git a/src/cliproxy/model-catalog.ts b/src/cliproxy/model-catalog.ts index ee1032f5..1f37537b 100644 --- a/src/cliproxy/model-catalog.ts +++ b/src/cliproxy/model-catalog.ts @@ -188,6 +188,19 @@ export const MODEL_CATALOG: Partial> = displayName: 'Copilot Codex', defaultModel: 'gpt-5.4', models: [ + { + id: 'gpt-5.5', + name: 'GPT-5.5', + tier: 'pro', + description: + 'Newest Codex-released GPT-5 family model; falls back to GPT-5.4 on free plans', + thinking: { + type: 'levels', + levels: ['low', 'medium', 'high', 'xhigh'], + maxLevel: 'xhigh', + dynamicAllowed: false, + }, + }, { id: 'gpt-5.4', name: 'GPT-5.4', diff --git a/tests/unit/cliproxy/codex-plan-compatibility-reconcile.test.ts b/tests/unit/cliproxy/codex-plan-compatibility-reconcile.test.ts index 1f004389..97ae8940 100644 --- a/tests/unit/cliproxy/codex-plan-compatibility-reconcile.test.ts +++ b/tests/unit/cliproxy/codex-plan-compatibility-reconcile.test.ts @@ -45,6 +45,48 @@ async function importCompatibilityModule(cacheTag: string) { const identity = (message: string) => message; describe('codex plan compatibility reconcile', () => { + it('warns about the GPT-5.5 free-plan fallback without rewriting saved settings', async () => { + const { tmpDir, settingsPath } = createCodexSettingsFixture(); + const errorSpy = spyOn(console, 'error').mockImplementation(() => {}); + + try { + const { reconcileCodexModelForActivePlan } = await importCompatibilityModule('gpt-5-5-free'); + + await reconcileCodexModelForActivePlan( + { + currentModel: 'gpt-5.5', + verbose: false, + }, + { + getDefaultAccount: () => ({ id: 'free@example.com' }) as never, + fetchCodexQuota: async () => ({ + success: true, + windows: [], + coreUsage: { fiveHour: null, weekly: null }, + planType: 'free', + lastUpdated: Date.now(), + accountId: 'free@example.com', + }), + formatInfo: identity, + formatWarn: identity, + } + ); + + const repaired = JSON.parse(fs.readFileSync(settingsPath, 'utf-8')) as { + env: Record; + }; + expect(repaired.env.ANTHROPIC_MODEL).toBe('gpt-5.3-codex'); + expect(repaired.env.ANTHROPIC_DEFAULT_OPUS_MODEL).toBe('gpt-5.3-codex'); + expect(repaired.env.ANTHROPIC_DEFAULT_SONNET_MODEL).toBe('gpt-5.3-codex'); + expect(repaired.env.ANTHROPIC_DEFAULT_HAIKU_MODEL).toBe('gpt-5.4-mini'); + expect(errorSpy).toHaveBeenCalledWith( + 'Codex free plan detected. Keeping saved model "gpt-5.5" in settings; runtime requests will fall back to "gpt-5.4" when needed.' + ); + } finally { + fs.rmSync(tmpDir, { recursive: true, force: true }); + } + }); + it('keeps saved Codex settings intact and warns about runtime fallback for free-plan accounts', async () => { const { tmpDir, settingsPath } = createCodexSettingsFixture('gpt-5.3-codex-spark'); const errorSpy = spyOn(console, 'error').mockImplementation(() => {}); diff --git a/tests/unit/cliproxy/codex-plan-compatibility.test.ts b/tests/unit/cliproxy/codex-plan-compatibility.test.ts index 2fc1266a..41f52c68 100644 --- a/tests/unit/cliproxy/codex-plan-compatibility.test.ts +++ b/tests/unit/cliproxy/codex-plan-compatibility.test.ts @@ -14,6 +14,8 @@ describe('codex plan compatibility', () => { }); it('maps paid-only free-plan models to safe fallbacks', () => { + expect(getFreePlanFallbackCodexModel('gpt-5.5')).toBe('gpt-5.4'); + expect(getFreePlanFallbackCodexModel('gpt-5.5-xhigh')).toBe('gpt-5.4'); expect(getFreePlanFallbackCodexModel('gpt-5.3-codex')).toBe('gpt-5.4'); expect(getFreePlanFallbackCodexModel('gpt-5.3-codex-xhigh')).toBe('gpt-5.4'); expect(getFreePlanFallbackCodexModel('gpt-5.3-codex(high)')).toBe('gpt-5.4'); @@ -71,6 +73,7 @@ describe('codex plan compatibility', () => { }); it('tracks Codex thinking caps for current safe defaults, paid models, and legacy aliases', () => { + expect(getModelMaxLevel('codex', 'gpt-5.5')).toBe('xhigh'); expect(getModelMaxLevel('codex', 'gpt-5.4')).toBe('xhigh'); expect(getModelMaxLevel('codex', 'gpt-5.4-mini')).toBe('high'); expect(getModelMaxLevel('codex', 'gpt-5-codex')).toBe('xhigh'); diff --git a/tests/unit/cliproxy/model-catalog.test.js b/tests/unit/cliproxy/model-catalog.test.js index 704c5764..bc11ce90 100644 --- a/tests/unit/cliproxy/model-catalog.test.js +++ b/tests/unit/cliproxy/model-catalog.test.js @@ -209,6 +209,7 @@ describe('Model Catalog', () => { const { MODEL_CATALOG } = modelCatalog; const ids = MODEL_CATALOG.codex.models.map((m) => m.id); assert.deepStrictEqual(ids, [ + 'gpt-5.5', 'gpt-5.4', 'gpt-5.4-mini', 'gpt-5.3-codex', diff --git a/ui/src/components/compatible-cli/codex-top-level-controls-card.tsx b/ui/src/components/compatible-cli/codex-top-level-controls-card.tsx index 54a88bdb..87b6c3a0 100644 --- a/ui/src/components/compatible-cli/codex-top-level-controls-card.tsx +++ b/ui/src/components/compatible-cli/codex-top-level-controls-card.tsx @@ -130,7 +130,7 @@ function TopLevelControlsForm({ onChange={(event) => setDraft((current) => ({ ...current, model: event.target.value || null })) } - placeholder="gpt-5.4" + placeholder="gpt-5.5" disabled={disabled} /> @@ -312,7 +312,9 @@ function TopLevelControlsForm({ className="text-[10px] uppercase tracking-[0.16em] text-muted-foreground" > {/* TODO i18n: missing keys codex.gpt54Selected / codex.gpt54Reference */} - {isGpt54Selected ? 'GPT-5.4 selected' : 'GPT-5.4 reference'} + {isGpt54Selected + ? 'GPT-5.4 long-context selected' + : 'GPT-5.4 long-context reference'}

@@ -500,16 +502,16 @@ function TopLevelControlsForm({ {/* TODO i18n: missing key codex.docs */} Docs - {/* TODO i18n: missing key codex.gpt54ModelPage */} - GPT-5.4 model page + {/* TODO i18n: missing key codex.gptModelGuide */} + GPT-5 model guide = { displayName: 'Codex', defaultModel: 'gpt-5-codex', models: [ + { + id: 'gpt-5.5', + name: 'GPT-5.5', + tier: 'paid', + description: 'Newest Codex-only GPT-5 family model', + codexMaxEffort: 'xhigh', + presetMapping: { + default: 'gpt-5.5', + opus: 'gpt-5.5', + sonnet: 'gpt-5.5', + haiku: 'gpt-5-codex-mini', + }, + }, { id: 'gpt-5-codex', name: 'GPT-5 Codex', diff --git a/ui/tests/unit/components/compatible-cli/codex-top-level-controls-card.test.tsx b/ui/tests/unit/components/compatible-cli/codex-top-level-controls-card.test.tsx index 803d48e3..fab41a28 100644 --- a/ui/tests/unit/components/compatible-cli/codex-top-level-controls-card.test.tsx +++ b/ui/tests/unit/components/compatible-cli/codex-top-level-controls-card.test.tsx @@ -28,7 +28,7 @@ describe('CodexTopLevelControlsCard', () => { const saveButton = screen.getByRole('button', { name: 'Save top-level settings' }); expect(saveButton).toBeDisabled(); - await userEvent.type(screen.getByPlaceholderText('gpt-5.4'), 'gpt-5.4-mini'); + await userEvent.type(screen.getByPlaceholderText('gpt-5.5'), 'gpt-5.4-mini'); expect(saveButton).toBeEnabled(); await userEvent.click(saveButton); diff --git a/ui/tests/unit/ui/lib/model-catalogs-codex.test.ts b/ui/tests/unit/ui/lib/model-catalogs-codex.test.ts index b8ceaf9a..4e3f5f94 100644 --- a/ui/tests/unit/ui/lib/model-catalogs-codex.test.ts +++ b/ui/tests/unit/ui/lib/model-catalogs-codex.test.ts @@ -4,10 +4,13 @@ import { MODEL_CATALOGS } from '@/lib/model-catalogs'; describe('codex model catalog defaults', () => { it('uses gpt-5-codex-mini as the haiku mapping for cross-plan codex presets', () => { const codexCatalog = MODEL_CATALOGS.codex; + const codex55 = codexCatalog.models.find((model) => model.id === 'gpt-5.5'); const codex53 = codexCatalog.models.find((model) => model.id === 'gpt-5.3-codex'); const codex52 = codexCatalog.models.find((model) => model.id === 'gpt-5.2-codex'); const codexMini = codexCatalog.models.find((model) => model.id === 'gpt-5-codex-mini'); + expect(codex55?.presetMapping?.haiku).toBe('gpt-5-codex-mini'); + expect(codex55?.codexMaxEffort).toBe('xhigh'); expect(codex53?.presetMapping?.haiku).toBe('gpt-5-codex-mini'); expect(codex52?.presetMapping?.haiku).toBe('gpt-5-codex-mini'); expect(codex53?.codexMaxEffort).toBe('xhigh'); From 02dae9c5cf00f4176d52620956b31c4099863cd1 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Fri, 24 Apr 2026 14:54:13 +0000 Subject: [PATCH 04/97] chore(release): 7.74.0-dev.2 [skip ci] --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index fab1de19..52ecf1a9 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@kaitranntt/ccs", - "version": "7.74.0-dev.1", + "version": "7.74.0-dev.2", "description": "Claude Code Switch - Instant profile switching between Claude, GLM, Kimi, and more", "keywords": [ "cli", From 2915ab0c40e8c22027884ff95f14a7df78ee275b Mon Sep 17 00:00:00 2001 From: B1GGersnow <2642448440@qq.com> Date: Sat, 25 Apr 2026 03:20:29 +0800 Subject: [PATCH 05/97] feat: add extra models support for API profiles Add ANTHROPIC_EXTRA_MODELS env var to allow each API profile to configure additional models alongside the primary ANTHROPIC_MODEL. These are synced to CLIProxy config.yaml during ccs cliproxy sync. - profile-mapper.ts: parse ANTHROPIC_EXTRA_MODELS on sync - profile-writer.ts: write extra models to settings.json - shared.ts + create-command.ts: --extra-models CLI flag - profile-routes.ts + route-helpers.ts: REST API support - profile-dialog.tsx + api-client.ts: frontend input --- src/api/services/profile-writer.ts | 19 ++++++++++++++----- src/cliproxy/sync/profile-mapper.ts | 15 +++++++++++++++ src/commands/api-command/create-command.ts | 6 +++++- src/commands/api-command/shared.ts | 17 +++++++++++++++++ src/web-server/routes/profile-routes.ts | 19 ++++++++++++++++--- src/web-server/routes/route-helpers.ts | 12 ++++++++++++ ui/src/components/profiles/profile-dialog.tsx | 16 ++++++++++++++++ ui/src/lib/api-client.ts | 2 ++ 8 files changed, 97 insertions(+), 9 deletions(-) diff --git a/src/api/services/profile-writer.ts b/src/api/services/profile-writer.ts index a39fdce9..b7c00ac7 100644 --- a/src/api/services/profile-writer.ts +++ b/src/api/services/profile-writer.ts @@ -91,7 +91,8 @@ function createSettingsFile( baseUrl: string, apiKey: string, models: ModelMapping, - provider?: string + provider?: string, + extraModels?: string[] ): string { const ccsDir = getCcsDir(); const settingsPath = path.join(ccsDir, `${name}.settings.json`); @@ -117,6 +118,9 @@ function createSettingsFile( ANTHROPIC_DEFAULT_OPUS_MODEL: models.opus, ANTHROPIC_DEFAULT_SONNET_MODEL: models.sonnet, ANTHROPIC_DEFAULT_HAIKU_MODEL: models.haiku, + ...(extraModels && extraModels.length > 0 + ? { ANTHROPIC_EXTRA_MODELS: extraModels.join(',') } + : {}), CCS_DROID_PROVIDER: droidProvider, }, }; @@ -179,7 +183,8 @@ function createApiProfileUnified( apiKey: string, models: ModelMapping, target: TargetType = 'claude', - provider?: string + provider?: string, + extraModels?: string[] ): void { const ccsDir = getCcsDir(); const settingsFile = `${name}.settings.json`; @@ -204,6 +209,9 @@ function createApiProfileUnified( ANTHROPIC_DEFAULT_OPUS_MODEL: models.opus, ANTHROPIC_DEFAULT_SONNET_MODEL: models.sonnet, ANTHROPIC_DEFAULT_HAIKU_MODEL: models.haiku, + ...(extraModels && extraModels.length > 0 + ? { ANTHROPIC_EXTRA_MODELS: extraModels.join(',') } + : {}), CCS_DROID_PROVIDER: droidProvider, }, }; @@ -240,7 +248,8 @@ export function createApiProfile( apiKey: string, models: ModelMapping, target: TargetType = 'claude', - provider?: string + provider?: string, + extraModels?: string[] ): CreateApiProfileResult { try { const deniedReason = getDeniedModelReason(baseUrl, models); @@ -251,9 +260,9 @@ export function createApiProfile( const settingsFile = `~/.ccs/${name}.settings.json`; if (isUnifiedMode()) { - createApiProfileUnified(name, baseUrl, apiKey, models, target, provider); + createApiProfileUnified(name, baseUrl, apiKey, models, target, provider, extraModels); } else { - createSettingsFile(name, baseUrl, apiKey, models, provider); + createSettingsFile(name, baseUrl, apiKey, models, provider, extraModels); updateLegacyConfig(name, target); } diff --git a/src/cliproxy/sync/profile-mapper.ts b/src/cliproxy/sync/profile-mapper.ts index 40583fa4..cb4b7a10 100644 --- a/src/cliproxy/sync/profile-mapper.ts +++ b/src/cliproxy/sync/profile-mapper.ts @@ -149,6 +149,21 @@ export function mapProfileToClaudeKey(profile: SyncableProfile): ClaudeKey | nul alias: '', }, ]; + + // Append extra models from ANTHROPIC_EXTRA_MODELS env var (comma-separated) + const extraModelsRaw = env.ANTHROPIC_EXTRA_MODELS; + if (extraModelsRaw && extraModelsRaw.trim()) { + const extraModels = extraModelsRaw + .split(',') + .map((m) => m.trim()) + .filter((m) => m.length > 0); + for (const extra of extraModels) { + claudeKey.models.push({ + name: extra, + alias: '', + }); + } + } } return claudeKey; diff --git a/src/commands/api-command/create-command.ts b/src/commands/api-command/create-command.ts index 1909c2dc..c7e6f782 100644 --- a/src/commands/api-command/create-command.ts +++ b/src/commands/api-command/create-command.ts @@ -493,7 +493,7 @@ export async function handleApiCreateCommand(args: string[]): Promise { console.log(''); console.log(info('Creating API profile...')); - const result = createApiProfile(name, baseUrl || '', apiKey, finalModels, target); + const result = createApiProfile(name, baseUrl || '', apiKey, finalModels, target, undefined, parsedArgs.extraModels); if (!result.success) { console.log(fail(`Failed to create API profile: ${result.error}`)); process.exit(1); @@ -534,6 +534,10 @@ export async function handleApiCreateCommand(args: string[]): Promise { ` Haiku: ${finalModels.haiku}`; } + if (parsedArgs.extraModels && parsedArgs.extraModels.length > 0) { + details += `\nExtraModels: ${parsedArgs.extraModels.join(', ')}`; + } + console.log(''); console.log(infoBox(details, 'API Profile Created')); if (hasClaudeMappings) { diff --git a/src/commands/api-command/shared.ts b/src/commands/api-command/shared.ts index 37dfe35f..657cbb3d 100644 --- a/src/commands/api-command/shared.ts +++ b/src/commands/api-command/shared.ts @@ -17,6 +17,7 @@ export interface ApiCommandArgs { baseUrl?: string; apiKey?: string; model?: string; + extraModels?: string[]; preset?: string; cliproxyProvider?: string; target?: TargetType; @@ -33,6 +34,7 @@ export const API_VALUE_FLAGS = [ '--base-url', '--api-key', '--model', + '--extra-models', '--preset', '--cliproxy-provider', '--target', @@ -222,6 +224,21 @@ export function parseApiCommandArgs( true ); + remaining = applyRepeatedOption( + remaining, + ['--extra-models'], + (value) => { + result.extraModels = value + .split(',') + .map((m) => m.trim()) + .filter((m) => m.length > 0); + }, + () => { + result.errors.push('Missing value for --extra-models'); + }, + false + ); + remaining = applyRepeatedOption( remaining, ['--preset'], diff --git a/src/web-server/routes/profile-routes.ts b/src/web-server/routes/profile-routes.ts index 84752b1d..de22ba4b 100644 --- a/src/web-server/routes/profile-routes.ts +++ b/src/web-server/routes/profile-routes.ts @@ -144,6 +144,7 @@ router.post('/', (req: Request, res: Response): void => { 'baseUrl', 'apiKey', 'model', + 'extraModels', 'opusModel', 'sonnetModel', 'haikuModel', @@ -156,7 +157,7 @@ router.post('/', (req: Request, res: Response): void => { return; } - const { name, baseUrl, apiKey, model, opusModel, sonnetModel, haikuModel, target } = req.body; + const { name, baseUrl, apiKey, model, extraModels, opusModel, sonnetModel, haikuModel, target } = req.body; const providerHint = req.body?.droidProvider ?? req.body?.provider; const parsedProvider = normalizeDroidProvider(providerHint); const normalizedBaseUrl = typeof baseUrl === 'string' ? baseUrl.trim() : ''; @@ -198,6 +199,14 @@ router.post('/', (req: Request, res: Response): void => { } // Create profile using unified-config-aware service + const parsedExtraModels: string[] | undefined = + typeof extraModels === 'string' && extraModels.trim() + ? extraModels + .split(',') + .map((m: string) => m.trim()) + .filter((m: string) => m.length > 0) + : undefined; + const result = createApiProfile( name, normalizedBaseUrl, @@ -209,7 +218,8 @@ router.post('/', (req: Request, res: Response): void => { haiku: haikuModel || model || '', }, parsedTarget || 'claude', - parsedProvider || undefined + parsedProvider || undefined, + parsedExtraModels ); if (!result.success) { @@ -409,6 +419,7 @@ router.put('/:name', (req: Request, res: Response): void => { 'baseUrl', 'apiKey', 'model', + 'extraModels', 'opusModel', 'sonnetModel', 'haikuModel', @@ -422,7 +433,7 @@ router.put('/:name', (req: Request, res: Response): void => { } const { name } = req.params; - const { baseUrl, apiKey, model, opusModel, sonnetModel, haikuModel, target } = req.body; + const { baseUrl, apiKey, model, extraModels, opusModel, sonnetModel, haikuModel, target } = req.body; const providerHint = req.body?.droidProvider ?? req.body?.provider; const parsedProvider = normalizeDroidProvider(providerHint); const normalizedBaseUrl = typeof baseUrl === 'string' ? baseUrl.trim() : baseUrl; @@ -457,6 +468,7 @@ router.put('/:name', (req: Request, res: Response): void => { baseUrl !== undefined || apiKey !== undefined || model !== undefined || + extraModels !== undefined || opusModel !== undefined || sonnetModel !== undefined || haikuModel !== undefined || @@ -473,6 +485,7 @@ router.put('/:name', (req: Request, res: Response): void => { baseUrl: normalizedBaseUrl, apiKey: normalizedApiKey, model, + extraModels, opusModel, sonnetModel, haikuModel, diff --git a/src/web-server/routes/route-helpers.ts b/src/web-server/routes/route-helpers.ts index b45f762a..3836711f 100644 --- a/src/web-server/routes/route-helpers.ts +++ b/src/web-server/routes/route-helpers.ts @@ -218,6 +218,7 @@ export function updateSettingsFile( baseUrl?: string; apiKey?: string; model?: string; + extraModels?: string; opusModel?: string; sonnetModel?: string; haikuModel?: string; @@ -336,6 +337,17 @@ export function updateSettingsFile( } } + // Handle extra models (comma-separated string) + if (updates.extraModels !== undefined) { + settings.env = settings.env || {}; + const normalized = typeof updates.extraModels === 'string' ? updates.extraModels.trim() : ''; + if (normalized.length > 0) { + settings.env.ANTHROPIC_EXTRA_MODELS = normalized; + } else { + delete settings.env.ANTHROPIC_EXTRA_MODELS; + } + } + if ( updates.provider !== undefined || updates.baseUrl !== undefined || diff --git a/ui/src/components/profiles/profile-dialog.tsx b/ui/src/components/profiles/profile-dialog.tsx index cdd03d69..d16caf27 100644 --- a/ui/src/components/profiles/profile-dialog.tsx +++ b/ui/src/components/profiles/profile-dialog.tsx @@ -34,6 +34,7 @@ const schema = z.object({ baseUrl: optionalUrlSchema, apiKey: z.string().min(10, 'API key must be at least 10 characters'), model: z.string().optional(), + extraModels: z.string().optional(), opusModel: z.string().optional(), sonnetModel: z.string().optional(), haikuModel: z.string().optional(), @@ -67,6 +68,7 @@ export function ProfileDialog({ open, onClose, profile }: ProfileDialogProps) { baseUrl: '', apiKey: '', model: '', + extraModels: '', opusModel: '', sonnetModel: '', haikuModel: '', @@ -102,6 +104,7 @@ export function ProfileDialog({ open, onClose, profile }: ProfileDialogProps) { baseUrl: data.baseUrl, apiKey: data.apiKey, model: data.model, + extraModels: data.extraModels, opusModel: data.opusModel, sonnetModel: data.sonnetModel, haikuModel: data.haikuModel, @@ -165,6 +168,19 @@ export function ProfileDialog({ open, onClose, profile }: ProfileDialogProps) {

+
+ + +

+ Comma-separated list of additional models available via this provider. These are + synced to CLIProxy alongside the default model. +

+
+ {/* Model Mapping Section */}