mirror of
https://github.com/tiennm99/ccs.git
synced 2026-09-02 18:18:43 +00:00
fix(codex): canonicalize dashboard presets and migrate suffixed settings
This commit is contained in:
@@ -28,12 +28,19 @@ import {
|
|||||||
/** Settings file structure for user overrides */
|
/** Settings file structure for user overrides */
|
||||||
interface ProviderSettings {
|
interface ProviderSettings {
|
||||||
env: NodeJS.ProcessEnv;
|
env: NodeJS.ProcessEnv;
|
||||||
|
presets?: Array<Record<string, unknown>>;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Model name prefix that was deprecated in CLIProxyAPI registry */
|
/** Model name prefix that was deprecated in CLIProxyAPI registry */
|
||||||
const DEPRECATED_MODEL_PREFIX = 'gemini-claude-';
|
const DEPRECATED_MODEL_PREFIX = 'gemini-claude-';
|
||||||
/** Replacement prefix matching actual upstream model names */
|
/** Replacement prefix matching actual upstream model names */
|
||||||
const UPSTREAM_MODEL_PREFIX = 'claude-';
|
const UPSTREAM_MODEL_PREFIX = 'claude-';
|
||||||
|
const CODEX_EFFORT_SUFFIX_REGEX = /-(xhigh|high|medium)$/i;
|
||||||
|
const PRESET_MODEL_KEYS = ['default', 'opus', 'sonnet', 'haiku'] as const;
|
||||||
|
|
||||||
|
function stripCodexEffortSuffix(modelId: string): string {
|
||||||
|
return modelId.replace(CODEX_EFFORT_SUFFIX_REGEX, '');
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Migrate deprecated gemini-claude-* model names to upstream claude-* names in a settings file.
|
* Migrate deprecated gemini-claude-* model names to upstream claude-* names in a settings file.
|
||||||
@@ -68,6 +75,58 @@ function migrateDeprecatedModelNames(settingsPath: string, settings: ProviderSet
|
|||||||
return migrated;
|
return migrated;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Migrate codex effort-suffixed model IDs in settings to canonical IDs.
|
||||||
|
* Example: gpt-5.3-codex-xhigh -> gpt-5.3-codex
|
||||||
|
*/
|
||||||
|
function migrateCodexEffortSuffixes(
|
||||||
|
settingsPath: string,
|
||||||
|
provider: CLIProxyProvider,
|
||||||
|
settings: ProviderSettings
|
||||||
|
): boolean {
|
||||||
|
if (provider !== 'codex') return false;
|
||||||
|
if (!settings.env || typeof settings.env !== 'object') return false;
|
||||||
|
|
||||||
|
let migrated = false;
|
||||||
|
|
||||||
|
for (const key of MODEL_ENV_VAR_KEYS) {
|
||||||
|
const value = settings.env[key];
|
||||||
|
if (typeof value !== 'string') continue;
|
||||||
|
const canonical = stripCodexEffortSuffix(value);
|
||||||
|
if (canonical !== value) {
|
||||||
|
settings.env[key] = canonical;
|
||||||
|
migrated = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Array.isArray(settings.presets)) {
|
||||||
|
for (const preset of settings.presets) {
|
||||||
|
if (!preset || typeof preset !== 'object') continue;
|
||||||
|
const presetRecord = preset as Record<string, unknown>;
|
||||||
|
|
||||||
|
for (const key of PRESET_MODEL_KEYS) {
|
||||||
|
const value = presetRecord[key];
|
||||||
|
if (typeof value !== 'string') continue;
|
||||||
|
const canonical = stripCodexEffortSuffix(value);
|
||||||
|
if (canonical !== value) {
|
||||||
|
presetRecord[key] = canonical;
|
||||||
|
migrated = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (migrated) {
|
||||||
|
try {
|
||||||
|
fs.writeFileSync(settingsPath, JSON.stringify(settings, null, 2) + '\n', { mode: 0o600 });
|
||||||
|
} catch {
|
||||||
|
// Best-effort migration — don't block startup if write fails
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return migrated;
|
||||||
|
}
|
||||||
|
|
||||||
/** Remote proxy configuration for URL rewriting */
|
/** Remote proxy configuration for URL rewriting */
|
||||||
export interface RemoteProxyRewriteConfig {
|
export interface RemoteProxyRewriteConfig {
|
||||||
host: string;
|
host: string;
|
||||||
@@ -285,6 +344,8 @@ export function getEffectiveEnvVars(
|
|||||||
if (settings.env && typeof settings.env === 'object') {
|
if (settings.env && typeof settings.env === 'object') {
|
||||||
// Migrate deprecated gemini-claude-* model names if present
|
// Migrate deprecated gemini-claude-* model names if present
|
||||||
migrateDeprecatedModelNames(expandedPath, settings);
|
migrateDeprecatedModelNames(expandedPath, settings);
|
||||||
|
// Migrate codex effort suffixes to canonical IDs if present
|
||||||
|
migrateCodexEffortSuffixes(expandedPath, provider, settings);
|
||||||
// Custom variant settings found - merge with global env
|
// Custom variant settings found - merge with global env
|
||||||
envVars = { ...globalEnv, ...settings.env };
|
envVars = { ...globalEnv, ...settings.env };
|
||||||
// Ensure required vars are present (fall back to defaults if missing)
|
// Ensure required vars are present (fall back to defaults if missing)
|
||||||
@@ -316,6 +377,8 @@ export function getEffectiveEnvVars(
|
|||||||
if (settings.env && typeof settings.env === 'object') {
|
if (settings.env && typeof settings.env === 'object') {
|
||||||
// Migrate deprecated gemini-claude-* model names if present
|
// Migrate deprecated gemini-claude-* model names if present
|
||||||
migrateDeprecatedModelNames(settingsPath, settings);
|
migrateDeprecatedModelNames(settingsPath, settings);
|
||||||
|
// Migrate codex effort suffixes to canonical IDs if present
|
||||||
|
migrateCodexEffortSuffixes(settingsPath, provider, settings);
|
||||||
// User override found - merge with global env
|
// User override found - merge with global env
|
||||||
envVars = { ...globalEnv, ...settings.env };
|
envVars = { ...globalEnv, ...settings.env };
|
||||||
// Ensure required vars are present (fall back to defaults if missing)
|
// Ensure required vars are present (fall back to defaults if missing)
|
||||||
@@ -403,6 +466,7 @@ export function getRemoteEnvVars(
|
|||||||
const settings: ProviderSettings = JSON.parse(content);
|
const settings: ProviderSettings = JSON.parse(content);
|
||||||
if (settings.env && typeof settings.env === 'object') {
|
if (settings.env && typeof settings.env === 'object') {
|
||||||
migrateDeprecatedModelNames(expandedPath, settings);
|
migrateDeprecatedModelNames(expandedPath, settings);
|
||||||
|
migrateCodexEffortSuffixes(expandedPath, provider, settings);
|
||||||
userEnvVars = settings.env as Record<string, string>;
|
userEnvVars = settings.env as Record<string, string>;
|
||||||
}
|
}
|
||||||
} catch {
|
} catch {
|
||||||
@@ -421,6 +485,7 @@ export function getRemoteEnvVars(
|
|||||||
const settings: ProviderSettings = JSON.parse(content);
|
const settings: ProviderSettings = JSON.parse(content);
|
||||||
if (settings.env && typeof settings.env === 'object') {
|
if (settings.env && typeof settings.env === 'object') {
|
||||||
migrateDeprecatedModelNames(settingsPath, settings);
|
migrateDeprecatedModelNames(settingsPath, settings);
|
||||||
|
migrateCodexEffortSuffixes(settingsPath, provider, settings);
|
||||||
userEnvVars = settings.env as Record<string, string>;
|
userEnvVars = settings.env as Record<string, string>;
|
||||||
}
|
}
|
||||||
} catch {
|
} catch {
|
||||||
|
|||||||
@@ -22,6 +22,14 @@ import { deduplicateCcsHooks } from '../../utils/websearch/hook-utils';
|
|||||||
import type { Settings } from '../../types/config';
|
import type { Settings } from '../../types/config';
|
||||||
|
|
||||||
const router = Router();
|
const router = Router();
|
||||||
|
const CODEX_EFFORT_SUFFIX_REGEX = /-(xhigh|high|medium)$/i;
|
||||||
|
const MODEL_ENV_KEYS = [
|
||||||
|
'ANTHROPIC_MODEL',
|
||||||
|
'ANTHROPIC_DEFAULT_OPUS_MODEL',
|
||||||
|
'ANTHROPIC_DEFAULT_SONNET_MODEL',
|
||||||
|
'ANTHROPIC_DEFAULT_HAIKU_MODEL',
|
||||||
|
] as const;
|
||||||
|
const PRESET_MODEL_KEYS = ['default', 'opus', 'sonnet', 'haiku'] as const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Helper: Resolve settings path for profile or variant
|
* Helper: Resolve settings path for profile or variant
|
||||||
@@ -42,6 +50,59 @@ function resolveSettingsPath(profileOrVariant: string): string {
|
|||||||
return path.join(ccsDir, `${profileOrVariant}.settings.json`);
|
return path.join(ccsDir, `${profileOrVariant}.settings.json`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function isCodexProfile(profileOrVariant: string): boolean {
|
||||||
|
if (profileOrVariant.toLowerCase() === 'codex') return true;
|
||||||
|
const variants = listVariants();
|
||||||
|
return variants[profileOrVariant]?.provider === 'codex';
|
||||||
|
}
|
||||||
|
|
||||||
|
function stripCodexEffortSuffix(modelId: string): string {
|
||||||
|
return modelId.replace(CODEX_EFFORT_SUFFIX_REGEX, '');
|
||||||
|
}
|
||||||
|
|
||||||
|
function canonicalizeCodexSettings(profileOrVariant: string, settings: Settings): Settings {
|
||||||
|
if (!isCodexProfile(profileOrVariant)) return settings;
|
||||||
|
|
||||||
|
let changed = false;
|
||||||
|
const next: Settings = { ...settings };
|
||||||
|
|
||||||
|
if (settings.env && typeof settings.env === 'object') {
|
||||||
|
const env = { ...settings.env };
|
||||||
|
for (const key of MODEL_ENV_KEYS) {
|
||||||
|
const value = env[key];
|
||||||
|
if (typeof value !== 'string') continue;
|
||||||
|
const canonical = stripCodexEffortSuffix(value);
|
||||||
|
if (canonical !== value) {
|
||||||
|
env[key] = canonical;
|
||||||
|
changed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
next.env = env;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Array.isArray(settings.presets)) {
|
||||||
|
const normalizedPresets = settings.presets.map((preset) => {
|
||||||
|
const normalizedPreset = { ...preset };
|
||||||
|
let presetChanged = false;
|
||||||
|
|
||||||
|
for (const key of PRESET_MODEL_KEYS) {
|
||||||
|
const value = normalizedPreset[key];
|
||||||
|
const canonical = stripCodexEffortSuffix(value);
|
||||||
|
if (canonical !== value) {
|
||||||
|
normalizedPreset[key] = canonical;
|
||||||
|
presetChanged = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (presetChanged) changed = true;
|
||||||
|
return normalizedPreset;
|
||||||
|
});
|
||||||
|
next.presets = normalizedPresets;
|
||||||
|
}
|
||||||
|
|
||||||
|
return changed ? next : settings;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Helper: Mask API keys in settings
|
* Helper: Mask API keys in settings
|
||||||
*/
|
*/
|
||||||
@@ -73,7 +134,7 @@ router.get('/:profile', (req: Request, res: Response): void => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const stat = fs.statSync(settingsPath);
|
const stat = fs.statSync(settingsPath);
|
||||||
const settings = loadSettings(settingsPath);
|
const settings = canonicalizeCodexSettings(profile, loadSettings(settingsPath));
|
||||||
const masked = maskApiKeys(settings);
|
const masked = maskApiKeys(settings);
|
||||||
|
|
||||||
res.json({
|
res.json({
|
||||||
@@ -101,7 +162,7 @@ router.get('/:profile/raw', (req: Request, res: Response): void => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const stat = fs.statSync(settingsPath);
|
const stat = fs.statSync(settingsPath);
|
||||||
const settings = loadSettings(settingsPath);
|
const settings = canonicalizeCodexSettings(profile, loadSettings(settingsPath));
|
||||||
|
|
||||||
res.json({
|
res.json({
|
||||||
profile,
|
profile,
|
||||||
@@ -137,14 +198,16 @@ router.put('/:profile', (req: Request, res: Response): void => {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const normalizedSettings = canonicalizeCodexSettings(profile, settings as Settings);
|
||||||
|
|
||||||
// Deduplicate CCS hooks to prevent accumulation (fixes #450)
|
// Deduplicate CCS hooks to prevent accumulation (fixes #450)
|
||||||
// This handles cases where duplicate hooks were added by previous versions
|
// This handles cases where duplicate hooks were added by previous versions
|
||||||
deduplicateCcsHooks(settings as Record<string, unknown>);
|
deduplicateCcsHooks(normalizedSettings as Record<string, unknown>);
|
||||||
|
|
||||||
const ccsDir = getCcsDir();
|
const ccsDir = getCcsDir();
|
||||||
|
|
||||||
// Check for missing required fields (warning, not blocking - runtime fills defaults)
|
// Check for missing required fields (warning, not blocking - runtime fills defaults)
|
||||||
const missingFields = checkRequiredEnvVars(settings);
|
const missingFields = checkRequiredEnvVars(normalizedSettings);
|
||||||
const settingsPath = resolveSettingsPath(profile);
|
const settingsPath = resolveSettingsPath(profile);
|
||||||
|
|
||||||
const fileExists = fs.existsSync(settingsPath);
|
const fileExists = fs.existsSync(settingsPath);
|
||||||
@@ -163,7 +226,7 @@ router.put('/:profile', (req: Request, res: Response): void => {
|
|||||||
|
|
||||||
// Create backup only if file exists AND content actually changed
|
// Create backup only if file exists AND content actually changed
|
||||||
let backupPath: string | undefined;
|
let backupPath: string | undefined;
|
||||||
const newContent = JSON.stringify(settings, null, 2) + '\n';
|
const newContent = JSON.stringify(normalizedSettings, null, 2) + '\n';
|
||||||
if (fileExists) {
|
if (fileExists) {
|
||||||
const existingContent = fs.readFileSync(settingsPath, 'utf8');
|
const existingContent = fs.readFileSync(settingsPath, 'utf8');
|
||||||
// Only create backup if content differs
|
// Only create backup if content differs
|
||||||
@@ -220,7 +283,7 @@ router.get('/:profile/presets', (req: Request, res: Response): void => {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const settings = loadSettings(settingsPath);
|
const settings = canonicalizeCodexSettings(profile, loadSettings(settingsPath));
|
||||||
res.json({ presets: settings.presets || [] });
|
res.json({ presets: settings.presets || [] });
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
res.status(500).json({ error: (error as Error).message });
|
res.status(500).json({ error: (error as Error).message });
|
||||||
@@ -257,12 +320,20 @@ router.post('/:profile/presets', (req: Request, res: Response): void => {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const normalizePresetModel = (modelId: string): string =>
|
||||||
|
isCodexProfile(profile) ? stripCodexEffortSuffix(modelId) : modelId;
|
||||||
|
|
||||||
|
const normalizedDefaultModel = normalizePresetModel(defaultModel);
|
||||||
|
const normalizedOpusModel = normalizePresetModel(opus || defaultModel);
|
||||||
|
const normalizedSonnetModel = normalizePresetModel(sonnet || defaultModel);
|
||||||
|
const normalizedHaikuModel = normalizePresetModel(haiku || defaultModel);
|
||||||
|
|
||||||
const preset = {
|
const preset = {
|
||||||
name,
|
name,
|
||||||
default: defaultModel,
|
default: normalizedDefaultModel,
|
||||||
opus: opus || defaultModel,
|
opus: normalizedOpusModel,
|
||||||
sonnet: sonnet || defaultModel,
|
sonnet: normalizedSonnetModel,
|
||||||
haiku: haiku || defaultModel,
|
haiku: normalizedHaikuModel,
|
||||||
};
|
};
|
||||||
|
|
||||||
settings.presets.push(preset);
|
settings.presets.push(preset);
|
||||||
|
|||||||
@@ -13,8 +13,12 @@ interface EnvSettings {
|
|||||||
ANTHROPIC_DEFAULT_HAIKU_MODEL: string;
|
ANTHROPIC_DEFAULT_HAIKU_MODEL: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
function writeSettings(settingsPath: string, env: EnvSettings): void {
|
function writeSettings(
|
||||||
fs.writeFileSync(settingsPath, JSON.stringify({ env }, null, 2));
|
settingsPath: string,
|
||||||
|
env: EnvSettings,
|
||||||
|
extras?: Record<string, unknown>
|
||||||
|
): void {
|
||||||
|
fs.writeFileSync(settingsPath, JSON.stringify({ env, ...(extras || {}) }, null, 2));
|
||||||
}
|
}
|
||||||
|
|
||||||
describe('getEffectiveEnvVars local provider URL normalization', () => {
|
describe('getEffectiveEnvVars local provider URL normalization', () => {
|
||||||
@@ -42,6 +46,18 @@ describe('getEffectiveEnvVars local provider URL normalization', () => {
|
|||||||
|
|
||||||
const env = getEffectiveEnvVars('codex', 8317, settingsPath);
|
const env = getEffectiveEnvVars('codex', 8317, settingsPath);
|
||||||
expect(env.ANTHROPIC_BASE_URL).toBe('http://127.0.0.1:8317/api/provider/codex');
|
expect(env.ANTHROPIC_BASE_URL).toBe('http://127.0.0.1:8317/api/provider/codex');
|
||||||
|
expect(env.ANTHROPIC_MODEL).toBe('gpt-5.3-codex');
|
||||||
|
expect(env.ANTHROPIC_DEFAULT_OPUS_MODEL).toBe('gpt-5.3-codex');
|
||||||
|
expect(env.ANTHROPIC_DEFAULT_SONNET_MODEL).toBe('gpt-5.3-codex');
|
||||||
|
expect(env.ANTHROPIC_DEFAULT_HAIKU_MODEL).toBe('gpt-5-mini');
|
||||||
|
|
||||||
|
const persisted = JSON.parse(fs.readFileSync(settingsPath, 'utf-8')) as {
|
||||||
|
env: Record<string, string>;
|
||||||
|
};
|
||||||
|
expect(persisted.env.ANTHROPIC_MODEL).toBe('gpt-5.3-codex');
|
||||||
|
expect(persisted.env.ANTHROPIC_DEFAULT_OPUS_MODEL).toBe('gpt-5.3-codex');
|
||||||
|
expect(persisted.env.ANTHROPIC_DEFAULT_SONNET_MODEL).toBe('gpt-5.3-codex');
|
||||||
|
expect(persisted.env.ANTHROPIC_DEFAULT_HAIKU_MODEL).toBe('gpt-5-mini');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('rewrites wrong local provider path to the requested provider', () => {
|
it('rewrites wrong local provider path to the requested provider', () => {
|
||||||
@@ -88,4 +104,39 @@ describe('getEffectiveEnvVars local provider URL normalization', () => {
|
|||||||
expect(env.ANTHROPIC_DEFAULT_SONNET_MODEL).toBe('claude-sonnet-4-6-thinking');
|
expect(env.ANTHROPIC_DEFAULT_SONNET_MODEL).toBe('claude-sonnet-4-6-thinking');
|
||||||
expect(env.ANTHROPIC_DEFAULT_HAIKU_MODEL).toBe('claude-haiku-4-5');
|
expect(env.ANTHROPIC_DEFAULT_HAIKU_MODEL).toBe('claude-haiku-4-5');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('migrates codex preset model mappings to canonical IDs', () => {
|
||||||
|
writeSettings(
|
||||||
|
settingsPath,
|
||||||
|
{
|
||||||
|
ANTHROPIC_BASE_URL: 'http://127.0.0.1:8317/api/provider/codex',
|
||||||
|
ANTHROPIC_AUTH_TOKEN: 'ccs-internal-managed',
|
||||||
|
ANTHROPIC_MODEL: 'gpt-5.3-codex-xhigh',
|
||||||
|
ANTHROPIC_DEFAULT_OPUS_MODEL: 'gpt-5.3-codex-xhigh',
|
||||||
|
ANTHROPIC_DEFAULT_SONNET_MODEL: 'gpt-5.3-codex-high',
|
||||||
|
ANTHROPIC_DEFAULT_HAIKU_MODEL: 'gpt-5-mini-medium',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
presets: [
|
||||||
|
{
|
||||||
|
name: 'legacy-codex',
|
||||||
|
default: 'gpt-5.3-codex-xhigh',
|
||||||
|
opus: 'gpt-5.3-codex-xhigh',
|
||||||
|
sonnet: 'gpt-5.3-codex-high',
|
||||||
|
haiku: 'gpt-5-mini-medium',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
getEffectiveEnvVars('codex', 8317, settingsPath);
|
||||||
|
|
||||||
|
const persisted = JSON.parse(fs.readFileSync(settingsPath, 'utf-8')) as {
|
||||||
|
presets: Array<Record<string, string>>;
|
||||||
|
};
|
||||||
|
expect(persisted.presets[0]?.default).toBe('gpt-5.3-codex');
|
||||||
|
expect(persisted.presets[0]?.opus).toBe('gpt-5.3-codex');
|
||||||
|
expect(persisted.presets[0]?.sonnet).toBe('gpt-5.3-codex');
|
||||||
|
expect(persisted.presets[0]?.haiku).toBe('gpt-5-mini');
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -140,10 +140,10 @@ export const MODEL_CATALOGS: Record<string, ProviderCatalog> = {
|
|||||||
name: 'GPT-5.3 Codex',
|
name: 'GPT-5.3 Codex',
|
||||||
description: 'Supports up to xhigh effort',
|
description: 'Supports up to xhigh effort',
|
||||||
presetMapping: {
|
presetMapping: {
|
||||||
default: 'gpt-5.3-codex-xhigh',
|
default: 'gpt-5.3-codex',
|
||||||
opus: 'gpt-5.3-codex-xhigh',
|
opus: 'gpt-5.3-codex',
|
||||||
sonnet: 'gpt-5.3-codex-high',
|
sonnet: 'gpt-5.3-codex',
|
||||||
haiku: 'gpt-5-mini-medium',
|
haiku: 'gpt-5-mini',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -151,10 +151,10 @@ export const MODEL_CATALOGS: Record<string, ProviderCatalog> = {
|
|||||||
name: 'GPT-5.2 Codex',
|
name: 'GPT-5.2 Codex',
|
||||||
description: 'Previous stable Codex model',
|
description: 'Previous stable Codex model',
|
||||||
presetMapping: {
|
presetMapping: {
|
||||||
default: 'gpt-5.2-codex-xhigh',
|
default: 'gpt-5.2-codex',
|
||||||
opus: 'gpt-5.2-codex-xhigh',
|
opus: 'gpt-5.2-codex',
|
||||||
sonnet: 'gpt-5.2-codex-high',
|
sonnet: 'gpt-5.2-codex',
|
||||||
haiku: 'gpt-5-mini-medium',
|
haiku: 'gpt-5-mini',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -162,10 +162,10 @@ export const MODEL_CATALOGS: Record<string, ProviderCatalog> = {
|
|||||||
name: 'GPT-5 Mini',
|
name: 'GPT-5 Mini',
|
||||||
description: 'Fast, capped at high effort (no xhigh)',
|
description: 'Fast, capped at high effort (no xhigh)',
|
||||||
presetMapping: {
|
presetMapping: {
|
||||||
default: 'gpt-5-mini-medium',
|
default: 'gpt-5-mini',
|
||||||
opus: 'gpt-5.3-codex-xhigh',
|
opus: 'gpt-5.3-codex',
|
||||||
sonnet: 'gpt-5-mini-high',
|
sonnet: 'gpt-5-mini',
|
||||||
haiku: 'gpt-5-mini-medium',
|
haiku: 'gpt-5-mini',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -174,9 +174,9 @@ export const MODEL_CATALOGS: Record<string, ProviderCatalog> = {
|
|||||||
description: 'Legacy most capable Codex model',
|
description: 'Legacy most capable Codex model',
|
||||||
presetMapping: {
|
presetMapping: {
|
||||||
default: 'gpt-5.1-codex-max',
|
default: 'gpt-5.1-codex-max',
|
||||||
opus: 'gpt-5.1-codex-max-high',
|
opus: 'gpt-5.1-codex-max',
|
||||||
sonnet: 'gpt-5.1-codex-max',
|
sonnet: 'gpt-5.1-codex-max',
|
||||||
haiku: 'gpt-5.1-codex-mini-high',
|
haiku: 'gpt-5.1-codex-mini',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user