diff --git a/ui/src/lib/model-catalogs.ts b/ui/src/lib/model-catalogs.ts index ea566f9f..e6b03dcb 100644 --- a/ui/src/lib/model-catalogs.ts +++ b/ui/src/lib/model-catalogs.ts @@ -1150,6 +1150,9 @@ export function buildUiCatalog( : (model.extendedContext ?? staticModel?.extendedContext), presetMapping: staticModel?.presetMapping, reasoningLevels: model.reasoningLevels ?? staticModel?.reasoningLevels, + codexMaxEffort: model.codexMaxEffort ?? staticModel?.codexMaxEffort, + codexEfforts: model.codexEfforts ?? staticModel?.codexEfforts, + codexServiceTiers: model.codexServiceTiers ?? staticModel?.codexServiceTiers, }; }); diff --git a/ui/tests/unit/ui/lib/model-catalogs-codex-merge.test.ts b/ui/tests/unit/ui/lib/model-catalogs-codex-merge.test.ts new file mode 100644 index 00000000..79b13e09 --- /dev/null +++ b/ui/tests/unit/ui/lib/model-catalogs-codex-merge.test.ts @@ -0,0 +1,30 @@ +import { describe, expect, it } from 'vitest'; +import { buildUiCatalog } from '@/lib/model-catalogs'; + +describe('buildUiCatalog codex tuning metadata merge', () => { + it('preserves static codex effort and service-tier metadata when the live catalog omits them', () => { + const merged = buildUiCatalog('codex', { + provider: 'codex', + displayName: 'Codex', + defaultModel: 'gpt-5.6-sol', + models: [{ id: 'gpt-5.6-sol', name: 'GPT-5.6 Sol' }], + }); + + const model = merged?.models.find((entry) => entry.id === 'gpt-5.6-sol'); + expect(model?.codexMaxEffort).toBe('xhigh'); + expect(model?.codexEfforts).toEqual(['low', 'medium', 'high', 'xhigh']); + expect(model?.codexServiceTiers).toEqual(['fast']); + }); + + it('prefers live metadata over static when the live catalog provides it', () => { + const merged = buildUiCatalog('codex', { + provider: 'codex', + displayName: 'Codex', + defaultModel: 'gpt-5.6-sol', + models: [{ id: 'gpt-5.6-sol', name: 'GPT-5.6 Sol', codexServiceTiers: [] }], + }); + + const model = merged?.models.find((entry) => entry.id === 'gpt-5.6-sol'); + expect(model?.codexServiceTiers).toEqual([]); + }); +});