mirror of
https://github.com/tiennm99/ccs.git
synced 2026-09-02 18:18:43 +00:00
fix: normalize ccsxp codex model flag aliases
This commit is contained in:
@@ -26,6 +26,8 @@ import {
|
|||||||
import { createLogger } from '../services/logging';
|
import { createLogger } from '../services/logging';
|
||||||
import { getEffectiveApiKey } from '../cliproxy/auth/auth-token-manager';
|
import { getEffectiveApiKey } from '../cliproxy/auth/auth-token-manager';
|
||||||
import { resolveLifecyclePort } from '../cliproxy/config/port-manager';
|
import { resolveLifecyclePort } from '../cliproxy/config/port-manager';
|
||||||
|
import { getModelMaxLevel } from '../cliproxy/model-catalog';
|
||||||
|
import { parseCodexModelTuningAlias } from '../cliproxy/ai-providers/model-id-normalizer';
|
||||||
import {
|
import {
|
||||||
CCSXP_CLIPROXY_SHORTCUT_ENV,
|
CCSXP_CLIPROXY_SHORTCUT_ENV,
|
||||||
CODEX_CLIPROXY_PROVIDER_ENV_KEY,
|
CODEX_CLIPROXY_PROVIDER_ENV_KEY,
|
||||||
@@ -39,6 +41,7 @@ const CODEX_RUNTIME_PROVIDER_ID = 'ccs_runtime';
|
|||||||
const CODEX_RUNTIME_ENV_KEY = 'CCS_CODEX_API_KEY';
|
const CODEX_RUNTIME_ENV_KEY = 'CCS_CODEX_API_KEY';
|
||||||
const CODEX_REASONING_LEVELS = new Set(['minimal', 'low', 'medium', 'high', 'xhigh']);
|
const CODEX_REASONING_LEVELS = new Set(['minimal', 'low', 'medium', 'high', 'xhigh']);
|
||||||
const CODEX_INFO_FLAGS = new Set(['--help', '-h', '--version', '-v']);
|
const CODEX_INFO_FLAGS = new Set(['--help', '-h', '--version', '-v']);
|
||||||
|
const CODEX_FAST_SERVICE_TIER = 'priority';
|
||||||
|
|
||||||
function formatTomlString(value: string): string {
|
function formatTomlString(value: string): string {
|
||||||
return JSON.stringify(value);
|
return JSON.stringify(value);
|
||||||
@@ -102,6 +105,72 @@ function normalizeCodexReasoningOverride(value: string | number | undefined): st
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function normalizeCodexModelFlagValue(value: string): {
|
||||||
|
model: string;
|
||||||
|
effort?: string;
|
||||||
|
serviceTier?: string;
|
||||||
|
} | null {
|
||||||
|
const parsed = parseCodexModelTuningAlias(value);
|
||||||
|
if (!parsed || !parsed.baseModel) return null;
|
||||||
|
if (getModelMaxLevel('codex', parsed.baseModel) === undefined) return null;
|
||||||
|
return {
|
||||||
|
model: parsed.baseModel,
|
||||||
|
effort: parsed.effort ?? undefined,
|
||||||
|
serviceTier: parsed.serviceTier ? CODEX_FAST_SERVICE_TIER : undefined,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function normalizeCcsxpCodexModelFlagAliases(args: string[]): {
|
||||||
|
args: string[];
|
||||||
|
overrides: string[];
|
||||||
|
} {
|
||||||
|
const normalizedArgs = [...args];
|
||||||
|
let reasoningEffort: string | undefined;
|
||||||
|
let serviceTier: string | undefined;
|
||||||
|
|
||||||
|
const applyModelValue = (value: string): string => {
|
||||||
|
const normalized = normalizeCodexModelFlagValue(value);
|
||||||
|
if (!normalized) {
|
||||||
|
reasoningEffort = undefined;
|
||||||
|
serviceTier = undefined;
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
reasoningEffort = normalized.effort;
|
||||||
|
serviceTier = normalized.serviceTier;
|
||||||
|
return normalized.model;
|
||||||
|
};
|
||||||
|
|
||||||
|
for (let index = 0; index < normalizedArgs.length; index += 1) {
|
||||||
|
const arg = normalizedArgs[index];
|
||||||
|
if (arg === '-m' || arg === '--model') {
|
||||||
|
const nextValue = normalizedArgs[index + 1];
|
||||||
|
if (typeof nextValue === 'string') {
|
||||||
|
normalizedArgs[index + 1] = applyModelValue(nextValue);
|
||||||
|
index += 1;
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const prefix of ['--model=', '-m=']) {
|
||||||
|
if (arg.startsWith(prefix)) {
|
||||||
|
normalizedArgs[index] = `${prefix}${applyModelValue(arg.slice(prefix.length))}`;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const overrides: string[] = [];
|
||||||
|
if (reasoningEffort) {
|
||||||
|
overrides.push(`model_reasoning_effort=${formatTomlString(reasoningEffort)}`);
|
||||||
|
}
|
||||||
|
if (serviceTier) {
|
||||||
|
overrides.push(`service_tier=${formatTomlString(serviceTier)}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
return { args: normalizedArgs, overrides };
|
||||||
|
}
|
||||||
|
|
||||||
function isInformationalCodexInvocation(args: string[]): boolean {
|
function isInformationalCodexInvocation(args: string[]): boolean {
|
||||||
if (args.length === 1) {
|
if (args.length === 1) {
|
||||||
return CODEX_INFO_FLAGS.has(args[0] || '');
|
return CODEX_INFO_FLAGS.has(args[0] || '');
|
||||||
@@ -220,20 +289,23 @@ export class CodexAdapter implements TargetAdapter {
|
|||||||
const runtimeConfigOverrides = creds?.runtimeConfigOverrides ?? [];
|
const runtimeConfigOverrides = creds?.runtimeConfigOverrides ?? [];
|
||||||
|
|
||||||
if (profileType === 'default') {
|
if (profileType === 'default') {
|
||||||
const overrides = [...runtimeConfigOverrides];
|
const modelFlagNormalization = isCcsxpCliproxyShortcut()
|
||||||
|
? normalizeCcsxpCodexModelFlagAliases(userArgs)
|
||||||
|
: { args: userArgs, overrides: [] };
|
||||||
|
const overrides = [...runtimeConfigOverrides, ...modelFlagNormalization.overrides];
|
||||||
if (reasoningOverride) {
|
if (reasoningOverride) {
|
||||||
overrides.push(`model_reasoning_effort=${formatTomlString(reasoningOverride)}`);
|
overrides.push(`model_reasoning_effort=${formatTomlString(reasoningOverride)}`);
|
||||||
}
|
}
|
||||||
if (overrides.length === 0) {
|
if (overrides.length === 0) {
|
||||||
return userArgs;
|
return modelFlagNormalization.args;
|
||||||
}
|
}
|
||||||
if (!codexBinarySupportsConfigOverrides(options?.binaryInfo)) {
|
if (!codexBinarySupportsConfigOverrides(options?.binaryInfo)) {
|
||||||
if (reasoningOverride) {
|
if (reasoningOverride || modelFlagNormalization.overrides.length > 0) {
|
||||||
throw buildConfigOverrideSupportError(hydrateCodexBinaryVersion(options?.binaryInfo));
|
throw buildConfigOverrideSupportError(hydrateCodexBinaryVersion(options?.binaryInfo));
|
||||||
}
|
}
|
||||||
return userArgs;
|
return modelFlagNormalization.args;
|
||||||
}
|
}
|
||||||
return [...buildConfigOverrideArgs(overrides), ...userArgs];
|
return [...buildConfigOverrideArgs(overrides), ...modelFlagNormalization.args];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!codexBinarySupportsConfigOverrides(options?.binaryInfo)) {
|
if (!codexBinarySupportsConfigOverrides(options?.binaryInfo)) {
|
||||||
|
|||||||
@@ -819,6 +819,33 @@ process.exit(0);
|
|||||||
expect(codexConfig).not.toContain('gpt-5.5-high-fast');
|
expect(codexConfig).not.toContain('gpt-5.5-high-fast');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('normalizes ccsxp native Codex model flag effort aliases before cliproxy requests', () => {
|
||||||
|
if (process.platform === 'win32') return;
|
||||||
|
|
||||||
|
const result = runCcsxpAlias(['-m', 'gpt-5.5-high', 'fix failing tests'], {
|
||||||
|
...process.env,
|
||||||
|
CI: '1',
|
||||||
|
NO_COLOR: '1',
|
||||||
|
HOME: tmpHome,
|
||||||
|
CCS_HOME: tmpHome,
|
||||||
|
CCS_CODEX_PATH: fakeCodexPath,
|
||||||
|
CCS_TEST_CODEX_ARGS_OUT: codexArgsLogPath,
|
||||||
|
CCS_TEST_CODEX_ENV_OUT: codexEnvLogPath,
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(result.status).toBe(0);
|
||||||
|
const codexCalls = readLoggedCodexCalls(codexArgsLogPath);
|
||||||
|
expect(codexCalls.at(-1)).toEqual([
|
||||||
|
'-c',
|
||||||
|
'model_reasoning_effort="high"',
|
||||||
|
'--config',
|
||||||
|
'model_provider="cliproxy"',
|
||||||
|
'-m',
|
||||||
|
'gpt-5.5',
|
||||||
|
'fix failing tests',
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
it('normalizes ccsxp native low Codex tuning aliases in config.toml', () => {
|
it('normalizes ccsxp native low Codex tuning aliases in config.toml', () => {
|
||||||
if (process.platform === 'win32') return;
|
if (process.platform === 'win32') return;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user