fix(cliproxy): normalize deprecated antigravity Claude aliases

This commit is contained in:
Tam Nhu Tran
2026-02-26 14:33:47 +07:00
parent 6d752724ec
commit ff9dbb3061
2 changed files with 56 additions and 9 deletions
+21 -8
View File
@@ -31,8 +31,9 @@ export const CCS_CONTROL_PANEL_SECRET = 'ccs';
* v7: Added fork:true for Claude model aliases (keep both upstream and alias names)
* v8: Added Gemini 3.1 preview aliases for provider routing compatibility
* v9: Added resilient alias compatibility expansion and cache-assisted alias enrichment
* v10: Migrated deprecated gemini-claude-* aliases to upstream claude-* aliases
*/
export const CLIPROXY_CONFIG_VERSION = 9;
export const CLIPROXY_CONFIG_VERSION = 10;
interface OAuthModelAliasEntry {
name: string;
@@ -41,6 +42,8 @@ interface OAuthModelAliasEntry {
}
const GEMINI_MINOR_COMPAT_RANGE = [1, 2, 3, 4, 5, 6, 7, 8, 9] as const;
const DEPRECATED_ANTIGRAVITY_ALIAS_PREFIX = 'gemini-claude-';
const UPSTREAM_CLAUDE_ALIAS_PREFIX = 'claude-';
/**
* Default Antigravity oauth-model-alias entries.
@@ -54,12 +57,12 @@ const DEFAULT_ANTIGRAVITY_ALIASES: OAuthModelAliasEntry[] = [
{ name: 'gemini-3-pro-high', alias: 'gemini-3.1-pro-preview' },
{ name: 'gemini-3-pro-high', alias: 'gemini-3.1-pro-preview-customtools' },
{ name: 'gemini-3-flash', alias: 'gemini-3-flash-preview' },
{ name: 'claude-sonnet-4-6', alias: 'gemini-claude-sonnet-4-6', fork: true },
{ name: 'claude-sonnet-4-6-thinking', alias: 'gemini-claude-sonnet-4-6-thinking', fork: true },
{ name: 'claude-sonnet-4-5', alias: 'gemini-claude-sonnet-4-5', fork: true },
{ name: 'claude-sonnet-4-5-thinking', alias: 'gemini-claude-sonnet-4-5-thinking', fork: true },
{ name: 'claude-opus-4-5-thinking', alias: 'gemini-claude-opus-4-5-thinking', fork: true },
{ name: 'claude-opus-4-6-thinking', alias: 'gemini-claude-opus-4-6-thinking', fork: true },
{ name: 'claude-sonnet-4-6', alias: 'claude-sonnet-4-6', fork: true },
{ name: 'claude-sonnet-4-6-thinking', alias: 'claude-sonnet-4-6-thinking', fork: true },
{ name: 'claude-sonnet-4-5', alias: 'claude-sonnet-4-5', fork: true },
{ name: 'claude-sonnet-4-5-thinking', alias: 'claude-sonnet-4-5-thinking', fork: true },
{ name: 'claude-opus-4-5-thinking', alias: 'claude-opus-4-5-thinking', fork: true },
{ name: 'claude-opus-4-6-thinking', alias: 'claude-opus-4-6-thinking', fork: true },
];
/**
@@ -101,6 +104,16 @@ function sanitizeYamlScalar(rawValue: string): string {
return trimmed;
}
function normalizeAntigravityAlias(rawAlias: string): string {
const normalized = sanitizeYamlScalar(rawAlias);
if (normalized.toLowerCase().startsWith(DEPRECATED_ANTIGRAVITY_ALIAS_PREFIX)) {
return (
UPSTREAM_CLAUDE_ALIAS_PREFIX + normalized.slice(DEPRECATED_ANTIGRAVITY_ALIAS_PREFIX.length)
);
}
return normalized;
}
function addAliasEntry(
entries: OAuthModelAliasEntry[],
indexByKey: Map<string, number>,
@@ -108,7 +121,7 @@ function addAliasEntry(
): void {
const normalized: OAuthModelAliasEntry = {
name: sanitizeYamlScalar(entry.name),
alias: sanitizeYamlScalar(entry.alias),
alias: normalizeAntigravityAlias(entry.alias),
fork: entry.fork || undefined,
};
if (!normalized.name || !normalized.alias) return;
+35 -1
View File
@@ -587,11 +587,15 @@ auth-dir: "${cliproxyDir.replace(/\\/g, '/')}/auth"
assert(config.includes('claude-sonnet-4-5'), 'Should include Claude sonnet model');
assert(config.includes('claude-sonnet-4-6'), 'Should include Claude Sonnet 4.6 model');
assert(config.includes('fork: true'), 'Should include fork: true for Claude aliases');
assert(
!config.includes('alias: gemini-claude-'),
'Should not emit deprecated gemini-claude aliases'
);
// Verify fork: true appears after each Claude alias entry
const lines = config.split('\n');
for (let i = 0; i < lines.length; i++) {
if (lines[i].includes('alias: gemini-claude-')) {
if (lines[i].includes('alias: claude-')) {
assert(
lines[i + 1] && lines[i + 1].trim() === 'fork: true',
`fork: true should follow Claude alias at line ${i}: ${lines[i]}`
@@ -766,5 +770,35 @@ oauth-model-alias:
}
}
});
it('normalizes deprecated gemini-claude aliases during regeneration', () => {
const cliproxyDir = path.join(testDir, '.ccs', 'cliproxy');
fs.mkdirSync(cliproxyDir, { recursive: true });
const initialConfig = `# CLIProxyAPI config generated by CCS v9
port: 8317
api-keys:
- "ccs-internal-managed"
auth-dir: "${cliproxyDir.replace(/\\/g, '/')}/auth"
oauth-model-alias:
antigravity:
- name: claude-sonnet-4-6-thinking
alias: gemini-claude-sonnet-4-6-thinking
fork: true
`;
fs.writeFileSync(path.join(cliproxyDir, 'config.yaml'), initialConfig);
regenerateConfig();
const newConfig = fs.readFileSync(path.join(cliproxyDir, 'config.yaml'), 'utf-8');
assert(
newConfig.includes('alias: claude-sonnet-4-6-thinking'),
'Should include normalized upstream Claude alias'
);
assert(
!newConfig.includes('alias: gemini-claude-sonnet-4-6-thinking'),
'Should remove deprecated gemini-claude alias after regeneration'
);
});
});
});