feat(cliproxy): clarify codex effort mapping and preset UX

This commit is contained in:
Tam Nhu Tran committed 2026-02-14 11:31:18 +07:00
1 parent a0d7c14ea0
commit 945db1d690
13 files changed
+245 -73

No files matched your search

+2 -2
View File
@@ -165,7 +165,7 @@ export const MODEL_CATALOG: Partial<Record<CLIProxyProvider, ProviderCatalog>> =
{
id: 'gpt-5.3-codex',
name: 'GPT-5.3 Codex',
description: 'Full reasoning support (xhigh)',
description: 'Supports up to xhigh effort',
thinking: {
type: 'levels',
levels: ['medium', 'high', 'xhigh'],
@@ -187,7 +187,7 @@ export const MODEL_CATALOG: Partial<Record<CLIProxyProvider, ProviderCatalog>> =
{
id: 'gpt-5-mini',
name: 'GPT-5 Mini',
description: 'Capped at high reasoning (no xhigh)',
description: 'Capped at high effort (no xhigh)',
thinking: {
type: 'levels',
levels: ['medium', 'high'],
+36 -11
View File
@@ -14,6 +14,22 @@ import { CLIProxyProvider } from './types';
import { initUI, color, bold, dim, ok, info, header } from '../utils/ui';
import { getCcsDir } from '../utils/config-manager';
const CODEX_EFFORT_SUFFIX_REGEX = /-(xhigh|high|medium)$/i;
function stripCodexEffortSuffix(model: string, provider: CLIProxyProvider): string {
if (provider !== 'codex') return model;
return model.replace(CODEX_EFFORT_SUFFIX_REGEX, '');
}
function normalizeCodexTierModel(
provider: CLIProxyProvider,
model: string,
fallbackEffort: 'medium' | 'high' | 'xhigh'
): string {
if (provider !== 'codex') return model;
return CODEX_EFFORT_SUFFIX_REGEX.test(model) ? model : `${model}-${fallbackEffort}`;
}
/**
* Check if provider has user settings configured
*/
@@ -120,7 +136,9 @@ export async function configureProviderModel(
// Find default index - use current model if configured, otherwise catalog default
const currentModel = getCurrentModel(provider, customSettingsPath);
const targetModel = currentModel || catalog.defaultModel;
const targetModel = currentModel
? stripCodexEffortSuffix(currentModel, provider)
: catalog.defaultModel;
const defaultIdx = catalog.models.findIndex((m) => m.id === targetModel);
const safeDefaultIdx = defaultIdx >= 0 ? defaultIdx : 0;
@@ -142,10 +160,14 @@ export async function configureProviderModel(
// Get base env vars for defaults
const baseEnv = getClaudeEnvVars(provider);
const codexSonnetModel =
provider === 'codex' && !selectedModel.match(/-(xhigh|high|medium)$/)
? `${selectedModel}-high`
: selectedModel;
const selectedDefaultModel = normalizeCodexTierModel(provider, selectedModel, 'xhigh');
const selectedOpusModel = normalizeCodexTierModel(provider, selectedModel, 'xhigh');
const selectedSonnetModel = normalizeCodexTierModel(provider, selectedModel, 'high');
const selectedHaikuModel = normalizeCodexTierModel(
provider,
baseEnv.ANTHROPIC_DEFAULT_HAIKU_MODEL || selectedModel,
'medium'
);
// Read existing settings to preserve user customizations
let existingSettings: Record<string, unknown> = {};
@@ -167,10 +189,10 @@ export async function configureProviderModel(
const ccsControlledEnv: Record<string, string> = {
ANTHROPIC_BASE_URL: baseEnv.ANTHROPIC_BASE_URL || '',
ANTHROPIC_AUTH_TOKEN: baseEnv.ANTHROPIC_AUTH_TOKEN || '',
ANTHROPIC_MODEL: selectedModel,
ANTHROPIC_DEFAULT_OPUS_MODEL: selectedModel,
ANTHROPIC_DEFAULT_SONNET_MODEL: codexSonnetModel,
ANTHROPIC_DEFAULT_HAIKU_MODEL: baseEnv.ANTHROPIC_DEFAULT_HAIKU_MODEL || '',
ANTHROPIC_MODEL: selectedDefaultModel,
ANTHROPIC_DEFAULT_OPUS_MODEL: selectedOpusModel,
ANTHROPIC_DEFAULT_SONNET_MODEL: selectedSonnetModel,
ANTHROPIC_DEFAULT_HAIKU_MODEL: selectedHaikuModel,
};
// Merge: user env vars (preserved) + CCS controlled (override)
@@ -232,13 +254,16 @@ export async function showCurrentConfig(provider: CLIProxyProvider): Promise<voi
const currentModel = getCurrentModel(provider);
const settingsPath = getProviderSettingsPath(provider);
const normalizedCurrentModel = currentModel
? stripCodexEffortSuffix(currentModel, provider)
: undefined;
console.error('');
console.error(header(`${catalog.displayName} Model Configuration`));
console.error('');
if (currentModel) {
const entry = catalog.models.find((m) => m.id === currentModel);
const entry = catalog.models.find((m) => m.id === normalizedCurrentModel);
const displayName = entry?.name || 'Unknown';
console.error(
` ${bold('Current:')} ${color(displayName, 'success')} ${dim(`(${currentModel})`)}`
@@ -255,7 +280,7 @@ export async function showCurrentConfig(provider: CLIProxyProvider): Promise<voi
console.error(dim(' [DEPRECATED] = Not recommended for use'));
console.error('');
catalog.models.forEach((m) => {
const isCurrent = m.id === currentModel;
const isCurrent = m.id === normalizedCurrentModel;
console.error(formatModelDetailed(m, isCurrent));
});
+41 -17
View File
@@ -35,6 +35,21 @@ interface SettingsFile {
[key: string]: unknown;
}
const CODEX_EFFORT_SUFFIX_REGEX = /-(xhigh|high|medium)$/i;
function hasCodexEffortSuffix(model: string): boolean {
return CODEX_EFFORT_SUFFIX_REGEX.test(model);
}
function normalizeCodexTierModel(
provider: CLIProxyProfileName | undefined,
model: string,
fallbackEffort: 'medium' | 'high' | 'xhigh'
): string {
if (provider !== 'codex') return model;
return hasCodexEffortSuffix(model) ? model : `${model}-${fallbackEffort}`;
}
/**
* Build settings env object for a variant
*/
@@ -44,26 +59,25 @@ function buildSettingsEnv(
port: number = CLIPROXY_DEFAULT_PORT
): SettingsEnv {
const baseEnv = getClaudeEnvVars(provider as CLIProxyProvider, port);
const codexSonnetModel = normalizeCodexSonnetModel(provider, model);
const defaultModel = normalizeCodexTierModel(provider, model, 'xhigh');
const opusModel = normalizeCodexTierModel(provider, model, 'xhigh');
const sonnetModel = normalizeCodexTierModel(provider, model, 'high');
const haikuModel = normalizeCodexTierModel(
provider,
baseEnv.ANTHROPIC_DEFAULT_HAIKU_MODEL || model,
'medium'
);
return {
ANTHROPIC_BASE_URL: baseEnv.ANTHROPIC_BASE_URL || '',
ANTHROPIC_AUTH_TOKEN: baseEnv.ANTHROPIC_AUTH_TOKEN || '',
ANTHROPIC_MODEL: model,
ANTHROPIC_DEFAULT_OPUS_MODEL: model,
ANTHROPIC_DEFAULT_SONNET_MODEL: codexSonnetModel,
ANTHROPIC_DEFAULT_HAIKU_MODEL: baseEnv.ANTHROPIC_DEFAULT_HAIKU_MODEL || model,
ANTHROPIC_MODEL: defaultModel,
ANTHROPIC_DEFAULT_OPUS_MODEL: opusModel,
ANTHROPIC_DEFAULT_SONNET_MODEL: sonnetModel,
ANTHROPIC_DEFAULT_HAIKU_MODEL: haikuModel,
};
}
function normalizeCodexSonnetModel(
provider: CLIProxyProfileName | undefined,
model: string
): string {
if (provider !== 'codex') return model;
return /-(xhigh|high|medium)$/.test(model) ? model : `${model}-high`;
}
/**
* Ensure directory exists
*/
@@ -299,10 +313,20 @@ export function updateSettingsModel(
if (model) {
settings.env = settings.env || ({} as SettingsEnv);
const codexSonnetModel = normalizeCodexSonnetModel(provider, model);
settings.env.ANTHROPIC_MODEL = model;
settings.env.ANTHROPIC_DEFAULT_OPUS_MODEL = model;
settings.env.ANTHROPIC_DEFAULT_SONNET_MODEL = codexSonnetModel;
settings.env.ANTHROPIC_MODEL = normalizeCodexTierModel(provider, model, 'xhigh');
settings.env.ANTHROPIC_DEFAULT_OPUS_MODEL = normalizeCodexTierModel(provider, model, 'xhigh');
settings.env.ANTHROPIC_DEFAULT_SONNET_MODEL = normalizeCodexTierModel(
provider,
model,
'high'
);
if (provider === 'codex' && settings.env.ANTHROPIC_DEFAULT_HAIKU_MODEL) {
settings.env.ANTHROPIC_DEFAULT_HAIKU_MODEL = normalizeCodexTierModel(
provider,
settings.env.ANTHROPIC_DEFAULT_HAIKU_MODEL,
'medium'
);
}
} else {
// Clear model settings to use defaults
delete (settings.env as unknown as Record<string, string>).ANTHROPIC_MODEL;
+3 -2
View File
@@ -168,7 +168,7 @@ Run ${color('ccs config', 'command')} for web dashboard`.trim();
],
[
['ccs gemini', 'Google Gemini (gemini-2.5-pro or 3-pro)'],
['ccs codex', 'OpenAI Codex (gpt-5.3-codex)'],
['ccs codex', 'OpenAI Codex (supports -medium/-high/-xhigh model suffixes)'],
['ccs agy', 'Antigravity (Claude/Gemini models)'],
['ccs qwen', 'Qwen Code (qwen3-coder)'],
['ccs kiro', 'Kiro (AWS CodeWhisperer Claude models)'],
@@ -346,11 +346,12 @@ Run ${color('ccs config', 'command')} for web dashboard`.trim();
['--thinking <number>', 'Custom token budget (512-100000)'],
['', ''],
['--effort <level>', 'Codex alias for reasoning effort (medium/high/xhigh)'],
['--effort xhigh', 'Codex 5.3 full-depth reasoning'],
['--effort xhigh', 'Pin Codex effort to xhigh for this run'],
['', ''],
['Note:', 'Extended thinking allocates compute for step-by-step reasoning'],
['', 'before responding.'],
['', 'Providers: agy/gemini use --thinking, codex uses --effort (or --thinking alias).'],
['', 'Codex model suffixes also pin effort: -medium / -high / -xhigh.'],
]);
// Extended Context (1M)