mirror of
https://github.com/tiennm99/ccs.git
synced 2026-10-14 16:17:02 +00:00
Merge pull request #826 from kaitranntt/kai/fix/gemini-3-1-presets
fix(cliproxy): resolve gemini presets from live models
This commit is contained in:
19 files changed
+488
-54
No files matched your search
@@ -640,6 +640,8 @@ auth-dir: "${cliproxyDir.replace(/\\/g, '/')}/auth"
|
||||
const gemini31AliasLines = [
|
||||
'alias: gemini-3.1-pro-preview',
|
||||
'alias: gemini-3.1-pro-preview-customtools',
|
||||
'alias: gemini-3.1-flash-preview',
|
||||
'alias: gemini-3.1-flash-preview-customtools',
|
||||
];
|
||||
|
||||
for (const aliasLine of gemini31AliasLines) {
|
||||
|
||||
@@ -91,11 +91,11 @@ describe('Model Catalog', () => {
|
||||
assert.strictEqual(ids.includes('claude-sonnet-4-5'), false);
|
||||
});
|
||||
|
||||
it('includes Gemini 3 Pro (free via Antigravity)', () => {
|
||||
it('includes Gemini 3.1 Pro (free via Antigravity)', () => {
|
||||
const { MODEL_CATALOG } = modelCatalog;
|
||||
const gem3 = MODEL_CATALOG.agy.models.find((m) => m.id === 'gemini-3-pro-preview');
|
||||
assert(gem3, 'Should include Gemini 3 Pro');
|
||||
assert.strictEqual(gem3.name, 'Gemini 3 Pro');
|
||||
const gem3 = MODEL_CATALOG.agy.models.find((m) => m.id === 'gemini-3.1-pro-preview');
|
||||
assert(gem3, 'Should include Gemini 3.1 Pro');
|
||||
assert.strictEqual(gem3.name, 'Gemini 3.1 Pro');
|
||||
// AGY models are all free - no paid tier
|
||||
assert.strictEqual(gem3.tier, undefined, 'AGY models should not have paid tier');
|
||||
});
|
||||
@@ -139,11 +139,11 @@ describe('Model Catalog', () => {
|
||||
assert.strictEqual(MODEL_CATALOG.gemini.defaultModel, 'gemini-2.5-pro');
|
||||
});
|
||||
|
||||
it('includes Gemini 3 Pro with pro tier', () => {
|
||||
it('includes Gemini 3.1 Pro with pro tier', () => {
|
||||
const { MODEL_CATALOG } = modelCatalog;
|
||||
const gem3 = MODEL_CATALOG.gemini.models.find((m) => m.id === 'gemini-3-pro-preview');
|
||||
assert(gem3, 'Should include Gemini 3 Pro');
|
||||
assert.strictEqual(gem3.name, 'Gemini 3 Pro');
|
||||
const gem3 = MODEL_CATALOG.gemini.models.find((m) => m.id === 'gemini-3.1-pro-preview');
|
||||
assert(gem3, 'Should include Gemini 3.1 Pro');
|
||||
assert.strictEqual(gem3.name, 'Gemini 3.1 Pro');
|
||||
assert.strictEqual(gem3.tier, 'pro');
|
||||
});
|
||||
|
||||
@@ -246,6 +246,36 @@ describe('Model Catalog', () => {
|
||||
assert.strictEqual(legacySonnet?.id, 'claude-sonnet-4-6');
|
||||
});
|
||||
|
||||
it('treats Gemini 3 and 3.1 preview IDs as the same catalog family', () => {
|
||||
const { findModel, getSuggestedReplacementModel } = modelCatalog;
|
||||
const legacyAgyGemini = findModel('agy', 'gemini-3-pro-preview');
|
||||
const legacyGemini = findModel('gemini', 'gemini-3-pro-preview');
|
||||
const currentGemini = findModel('gemini', 'gemini-3.1-pro-preview');
|
||||
|
||||
assert.strictEqual(legacyAgyGemini?.id, 'gemini-3.1-pro-preview');
|
||||
assert.strictEqual(legacyGemini?.id, 'gemini-3.1-pro-preview');
|
||||
assert.strictEqual(currentGemini?.id, 'gemini-3.1-pro-preview');
|
||||
assert.strictEqual(
|
||||
getSuggestedReplacementModel('gemini', 'gemini-3.1-pro-preview'),
|
||||
'gemini-2.5-pro'
|
||||
);
|
||||
});
|
||||
|
||||
it('falls back to the next supported model when the default is excluded', () => {
|
||||
const { getSuggestedReplacementModel } = modelCatalog;
|
||||
|
||||
expect(getSuggestedReplacementModel('agy', 'claude-opus-4-6-thinking')).toBe(
|
||||
'claude-sonnet-4-6'
|
||||
);
|
||||
expect(getSuggestedReplacementModel('agy')).toBe('claude-opus-4-6-thinking');
|
||||
});
|
||||
|
||||
it('returns undefined when no provider catalog exists', () => {
|
||||
const { getSuggestedReplacementModel } = modelCatalog;
|
||||
|
||||
expect(getSuggestedReplacementModel('qwen')).toBeUndefined();
|
||||
});
|
||||
|
||||
it('returns undefined for unknown model', () => {
|
||||
const { findModel } = modelCatalog;
|
||||
const model = findModel('agy', 'unknown-model');
|
||||
@@ -325,7 +355,7 @@ describe('Model Catalog', () => {
|
||||
const sonnetThinkingIdx = models.findIndex((m) => m.id === 'claude-sonnet-4-6');
|
||||
|
||||
// Find indices of the remaining non-Claude model
|
||||
const geminiIdx = models.findIndex((m) => m.id === 'gemini-3-pro-preview');
|
||||
const geminiIdx = models.findIndex((m) => m.id === 'gemini-3.1-pro-preview');
|
||||
|
||||
// Primary Claude choices should appear ahead of Gemini fallback.
|
||||
assert(opusIdx < geminiIdx, 'Opus should be above Gemini');
|
||||
|
||||
@@ -168,6 +168,23 @@ describe('Gemini CLI Quota Fetcher', () => {
|
||||
expect(proBucket!.remainingFraction).toBe(0.9);
|
||||
});
|
||||
|
||||
it('should recognize Gemini 3.1 preview IDs during the rollout', () => {
|
||||
const rawBuckets = [
|
||||
{ model_id: 'gemini-3.1-flash-preview', remaining_fraction: 0.7 },
|
||||
{ model_id: 'gemini-3.1-pro-preview', remaining_fraction: 0.4 },
|
||||
];
|
||||
|
||||
const buckets = buildGeminiCliBuckets(rawBuckets);
|
||||
|
||||
const flashBucket = buckets.find((b) => b.label === 'Gemini Flash Series');
|
||||
const proBucket = buckets.find((b) => b.label === 'Gemini Pro Series');
|
||||
|
||||
expect(flashBucket).toBeDefined();
|
||||
expect(flashBucket!.modelIds).toContain('gemini-3.1-flash-preview');
|
||||
expect(proBucket).toBeDefined();
|
||||
expect(proBucket!.modelIds).toContain('gemini-3.1-pro-preview');
|
||||
});
|
||||
|
||||
it('should handle camelCase API response', () => {
|
||||
const rawBuckets = [{ modelId: 'gemini-3-flash-preview', remainingFraction: 0.75 }];
|
||||
|
||||
|
||||
@@ -76,6 +76,22 @@ describe('model-pricing', () => {
|
||||
expect(pricing).not.toEqual(getModelPricing('unknown-model-xyz'));
|
||||
});
|
||||
|
||||
it('should map Gemini 3 and 3.1 Flash preview variants to flash pricing', () => {
|
||||
const canonical = getModelPricing('gemini-2.5-flash');
|
||||
const aliases = [
|
||||
'gemini-3-flash-preview',
|
||||
'gemini-3-flash-preview-customtools',
|
||||
'gemini-3.1-flash-preview',
|
||||
'gemini-3.1-flash-preview-customtools',
|
||||
'gemini-3-1-flash-preview',
|
||||
'gemini-3-1-flash-preview-customtools',
|
||||
];
|
||||
|
||||
for (const model of aliases) {
|
||||
expect(getModelPricing(model)).toEqual(canonical);
|
||||
}
|
||||
});
|
||||
|
||||
it('should return different pricing for different model tiers', () => {
|
||||
const sonnet = getModelPricing('claude-sonnet-4-5');
|
||||
const opus = getModelPricing('claude-opus-4-5-20251101');
|
||||
|
||||
Reference in new issue
Block a user