Merge pull request #599 from kaitranntt/fix/598-gemini-3-1-pro-preview

fix(cliproxy): support gemini-3.1-pro-preview alias routing
This commit is contained in:
Kai (Tam Nhu) Tran authored and GitHub committed 2026-02-22 00:57:30 +07:00
commit 06a4f3f131
2 files changed
+357 -38

No files matched your search

@@ -621,6 +621,113 @@ auth-dir: "${cliproxyDir.replace(/\\/g, '/')}/auth"
}
});
it('generates Gemini 3.1 compatibility aliases without fork', () => {
regenerateConfig();
const cliproxyDir = path.join(testDir, '.ccs', 'cliproxy');
const config = fs.readFileSync(path.join(cliproxyDir, 'config.yaml'), 'utf-8');
const lines = config.split('\n');
const gemini31AliasLines = [
'alias: gemini-3.1-pro-preview',
'alias: gemini-3.1-pro-preview-customtools',
];
for (const aliasLine of gemini31AliasLines) {
const lineIndex = lines.findIndex((line) => line.includes(aliasLine));
assert(lineIndex >= 0, `Should include ${aliasLine}`);
const nextLine = lines[lineIndex + 1] || '';
assert(
!nextLine.trim().startsWith('fork:'),
`Gemini alias should not have fork: ${aliasLine}`
);
}
});
it('generates dot and hyphen alias forms for preview compatibility', () => {
regenerateConfig();
const cliproxyDir = path.join(testDir, '.ccs', 'cliproxy');
const config = fs.readFileSync(path.join(cliproxyDir, 'config.yaml'), 'utf-8');
assert(config.includes('alias: gemini-3.1-pro-preview'), 'Should include dotted version alias');
assert(config.includes('alias: gemini-3-1-pro-preview'), 'Should include hyphen version alias');
assert(
config.includes('alias: gemini-3-1-pro-preview-customtools'),
'Should include hyphen customtools alias'
);
});
it('preserves multiple aliases that share the same model name', () => {
const cliproxyDir = path.join(testDir, '.ccs', 'cliproxy');
fs.mkdirSync(cliproxyDir, { recursive: true });
const initialConfig = `# CLIProxyAPI config generated by CCS v8
port: 8317
api-keys:
- "ccs-internal-managed"
auth-dir: "${cliproxyDir.replace(/\\/g, '/')}/auth"
oauth-model-alias:
antigravity:
- name: custom-model
alias: custom-alias-a
- name: custom-model
alias: custom-alias-b
`;
fs.writeFileSync(path.join(cliproxyDir, 'config.yaml'), initialConfig);
regenerateConfig();
const newConfig = fs.readFileSync(path.join(cliproxyDir, 'config.yaml'), 'utf-8');
assert(newConfig.includes('alias: custom-alias-a'), 'Should preserve first alias');
assert(newConfig.includes('alias: custom-alias-b'), 'Should preserve second alias');
assert.strictEqual(
(newConfig.match(/alias: custom-alias-a/g) || []).length,
1,
'Should keep one entry for first alias'
);
assert.strictEqual(
(newConfig.match(/alias: custom-alias-b/g) || []).length,
1,
'Should keep one entry for second alias'
);
});
it('enriches aliases from cached catalog for unseen preview minor versions', () => {
const cliproxyDir = path.join(testDir, '.ccs', 'cliproxy');
const cachePath = path.join(testDir, '.ccs', 'model-catalog-cache.json');
fs.mkdirSync(path.dirname(cachePath), { recursive: true });
regenerateConfig();
const beforeCacheConfig = fs.readFileSync(path.join(cliproxyDir, 'config.yaml'), 'utf-8');
assert(
!beforeCacheConfig.includes('alias: gemini-3.11-pro-preview'),
'Should not include unseen minor alias before cache enrichment'
);
const cachePayload = {
providers: {
agy: [{ id: 'gemini-3.11-pro-preview', display_name: 'Gemini 3.11 Pro Preview' }],
},
fetchedAt: Date.now(),
};
fs.writeFileSync(cachePath, JSON.stringify(cachePayload));
regenerateConfig();
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'
);
assert(
afterCacheConfig.includes('alias: gemini-3.11-pro-preview-customtools'),
'Should include compatibility alias for cache-derived entry'
);
});
it('preserves user-added aliases with fork during regeneration', () => {
const cliproxyDir = path.join(testDir, '.ccs', 'cliproxy');
fs.mkdirSync(cliproxyDir, { recursive: true });