fix(cliproxy): reduce gemini alias model bloat

This commit is contained in:
Tam Nhu Tran
2026-03-04 02:46:52 +07:00
parent 9281ac24fb
commit 276649f05d
2 changed files with 8 additions and 74 deletions
+3 -69
View File
@@ -10,7 +10,6 @@ import { getProviderDisplayName } from '../provider-capabilities';
import { getModelMappingFromConfig } from '../base-config-loader';
import { loadOrCreateUnifiedConfig } from '../../config/unified-config-loader';
import { getEffectiveApiKey, getEffectiveManagementSecret } from '../auth-token-manager';
import { getCachedCatalog } from '../catalog-cache';
import { getDeniedModelIdReasonForProvider } from '../model-id-normalizer';
import { getAuthDir, getProviderAuthDir, getConfigPathForPort } from './path-resolver';
import { CLIPROXY_DEFAULT_PORT } from './port-manager';
@@ -35,8 +34,9 @@ export const CCS_CONTROL_PANEL_SECRET = 'ccs';
* v10: Migrated deprecated gemini-claude-* aliases to upstream claude-* aliases
* v11: Migrated deprecated claude-sonnet-4-6-thinking aliases to claude-sonnet-4-6
* v12: Removed denylisted Antigravity Claude 4.5 aliases
* v13: Removed aggressive Gemini alias expansion to reduce model list noise in Control Panel
*/
export const CLIPROXY_CONFIG_VERSION = 12;
export const CLIPROXY_CONFIG_VERSION = 13;
interface OAuthModelAliasEntry {
name: string;
@@ -44,7 +44,6 @@ interface OAuthModelAliasEntry {
fork?: boolean;
}
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-';
const DEPRECATED_ANTIGRAVITY_SONNET_46_THINKING_REGEX = /^claude-sonnet-4(?:[.-])6-thinking$/i;
@@ -227,16 +226,6 @@ function buildGeminiCompatibilityAliases(alias: string): string[] {
queue.push(candidate);
};
const basePreviewMatch = alias.match(/^gemini-(\d+)-(pro|flash)-preview(?:-customtools)?$/);
if (basePreviewMatch) {
const major = basePreviewMatch[1];
const family = basePreviewMatch[2];
for (const minor of GEMINI_MINOR_COMPAT_RANGE) {
enqueue(`gemini-${major}.${minor}-${family}-preview`);
enqueue(`gemini-${major}-${minor}-${family}-preview`);
}
}
const visited = new Set<string>();
while (queue.length > 0) {
const current = queue.pop();
@@ -261,56 +250,6 @@ function buildGeminiCompatibilityAliases(alias: string): string[] {
return [...variants];
}
function getGeminiPreviewFamily(alias: string): string | null {
const withoutCustomTools = alias.replace(/-customtools$/, '');
const normalized = toHyphenatedGeminiVersionAlias(withoutCustomTools) || withoutCustomTools;
const majorMinorMatch = normalized.match(/^gemini-(\d+)-(\d+)-(.+-preview(?:-[0-9-]+)?)$/);
if (majorMinorMatch) {
return `gemini-${majorMinorMatch[1]}-${majorMinorMatch[3]}`;
}
const majorOnlyMatch = normalized.match(/^gemini-(\d+)-(.+-preview(?:-[0-9-]+)?)$/);
if (majorOnlyMatch) {
return `gemini-${majorOnlyMatch[1]}-${majorOnlyMatch[2]}`;
}
return null;
}
function getCacheDerivedAntigravityAliases(
currentEntries: OAuthModelAliasEntry[]
): OAuthModelAliasEntry[] {
const cached = getCachedCatalog();
const remoteAgyModels = cached?.providers?.agy;
if (!remoteAgyModels || remoteAgyModels.length === 0) return [];
const familyToName = new Map<string, string>();
for (const entry of currentEntries) {
const family = getGeminiPreviewFamily(entry.alias);
if (family && !familyToName.has(family)) {
familyToName.set(family, entry.name);
}
}
const derivedAliases: OAuthModelAliasEntry[] = [];
for (const remoteModel of remoteAgyModels) {
if (!remoteModel || typeof remoteModel.id !== 'string') continue;
const family = getGeminiPreviewFamily(remoteModel.id);
if (!family) continue;
const mappedName = familyToName.get(family);
if (mappedName) {
derivedAliases.push({
name: mappedName,
alias: remoteModel.id,
});
}
}
return derivedAliases;
}
function getCompatibilityAliases(entries: OAuthModelAliasEntry[]): OAuthModelAliasEntry[] {
const compatibilityAliases: OAuthModelAliasEntry[] = [];
for (const entry of entries) {
@@ -347,12 +286,7 @@ function generateOAuthModelAliasSection(existingAliases?: string): string {
}
}
// Pull latest known aliases from cached remote catalog when available.
for (const alias of getCacheDerivedAntigravityAliases(aliasEntries)) {
addAliasEntry(aliasEntries, aliasIndexByKey, alias);
}
// Expand compatibility aliases to reduce breakage on upstream naming drift.
// Expand lightweight compatibility aliases (dot/hyphen + customtools toggle).
for (const alias of getCompatibilityAliases(aliasEntries)) {
addAliasEntry(aliasEntries, aliasIndexByKey, alias);
}
+5 -5
View File
@@ -709,7 +709,7 @@ oauth-model-alias:
);
});
it('enriches aliases from cached catalog for unseen preview minor versions', () => {
it('does not auto-enrich aliases from cached catalog to avoid model list bloat', () => {
const cliproxyDir = path.join(testDir, '.ccs', 'cliproxy');
const cachePath = path.join(testDir, '.ccs', 'model-catalog-cache.json');
fs.mkdirSync(path.dirname(cachePath), { recursive: true });
@@ -734,12 +734,12 @@ oauth-model-alias:
const afterCacheConfig = fs.readFileSync(path.join(cliproxyDir, 'config.yaml'), 'utf-8');
assert(
afterCacheConfig.includes('alias: gemini-3.11-pro-preview'),
'Should include cache-derived unseen minor alias'
!afterCacheConfig.includes('alias: gemini-3.11-pro-preview'),
'Should not include cache-derived unseen minor alias'
);
assert(
afterCacheConfig.includes('alias: gemini-3.11-pro-preview-customtools'),
'Should include compatibility alias for cache-derived entry'
!afterCacheConfig.includes('alias: gemini-3.11-pro-preview-customtools'),
'Should not include compatibility alias for cache-derived entry'
);
});