mirror of
https://github.com/tiennm99/ccs.git
synced 2026-07-16 12:15:57 +00:00
feat: add gpt-5.5 to codex model catalogs
This commit is contained in:
@@ -18,6 +18,7 @@ const KNOWN_CODEX_MODELS = new Set(
|
||||
);
|
||||
|
||||
const FREE_PLAN_FALLBACKS = new Map<string, string>([
|
||||
['gpt-5.5', FREE_SAFE_DEFAULT_MODEL],
|
||||
['gpt-5.3-codex', FREE_SAFE_DEFAULT_MODEL],
|
||||
['gpt-5.3-codex-spark', FREE_SAFE_FAST_MODEL],
|
||||
]);
|
||||
|
||||
@@ -188,6 +188,19 @@ export const MODEL_CATALOG: Partial<Record<CLIProxyProvider, ProviderCatalog>> =
|
||||
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',
|
||||
|
||||
@@ -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<string, string>;
|
||||
};
|
||||
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(() => {});
|
||||
|
||||
@@ -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');
|
||||
|
||||
@@ -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',
|
||||
|
||||
@@ -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}
|
||||
/>
|
||||
</div>
|
||||
@@ -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'}
|
||||
</Badge>
|
||||
</div>
|
||||
<p className="text-xs text-muted-foreground">
|
||||
@@ -500,16 +502,16 @@ function TopLevelControlsForm({
|
||||
{/* TODO i18n: missing key codex.docs */}
|
||||
<span className="text-[10px] uppercase tracking-[0.14em]">Docs</span>
|
||||
<a
|
||||
href="https://developers.openai.com/api/docs/models/gpt-5.4"
|
||||
href="https://platform.openai.com/docs/models"
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
className="underline underline-offset-2 hover:text-foreground"
|
||||
>
|
||||
{/* TODO i18n: missing key codex.gpt54ModelPage */}
|
||||
GPT-5.4 model page
|
||||
{/* TODO i18n: missing key codex.gptModelGuide */}
|
||||
GPT-5 model guide
|
||||
</a>
|
||||
<a
|
||||
href="https://openai.com/index/introducing-gpt-5-4/"
|
||||
href="https://openai.com/index/introducing-gpt-5-5/"
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
className="underline underline-offset-2 hover:text-foreground"
|
||||
|
||||
@@ -259,6 +259,19 @@ export const MODEL_CATALOGS: Record<string, ProviderCatalog> = {
|
||||
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',
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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');
|
||||
|
||||
Reference in New Issue
Block a user