fix(cliproxy): align gemini flash pricing and dashboard imports

This commit is contained in:
Tam Nhu Tran
2026-03-28 09:54:26 -04:00
parent 2251312411
commit 2423864817
8 changed files with 55 additions and 2 deletions
+6
View File
@@ -718,10 +718,16 @@ const MODEL_PRICING_ALIASES: Record<string, string> = {
'qwen3-235b': 'qwen3-max',
'qwen3-vl-plus': 'qwen3.5-plus',
'qwen3-32b': 'qwen3.5-plus',
'gemini-3-flash-preview': 'gemini-2.5-flash',
'gemini-3-flash-preview-customtools': 'gemini-2.5-flash',
'gemini-3.1-pro-preview': 'gemini-3-pro-preview',
'gemini-3.1-flash-preview': 'gemini-2.5-flash',
'gemini-3.1-pro-preview-customtools': 'gemini-3-pro-preview',
'gemini-3.1-flash-preview-customtools': 'gemini-2.5-flash',
'gemini-3-1-pro-preview': 'gemini-3-pro-preview',
'gemini-3-1-flash-preview': 'gemini-2.5-flash',
'gemini-3-1-pro-preview-customtools': 'gemini-3-pro-preview',
'gemini-3-1-flash-preview-customtools': 'gemini-2.5-flash',
};
// Default pricing for unknown models
+15
View File
@@ -261,6 +261,21 @@ describe('Model Catalog', () => {
);
});
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');
+16
View File
@@ -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');
+1 -1
View File
@@ -5,7 +5,7 @@
import type { ModelEntry, ProviderCatalog } from '@/components/cliproxy/provider-model-selector';
import { stripModelConfigurationSuffixes } from '@/lib/extended-context-utils';
import { GEMINI_MINOR_VERSION_COMPATIBILITY_IDS } from '../../../src/shared/gemini-minor-version-compatibility';
import { GEMINI_MINOR_VERSION_COMPATIBILITY_IDS } from '@shared/gemini-minor-version-compatibility';
const GEMINI_PREVIEW_MODEL_ID_PATTERN =
/^gemini-(\d+(?:[.-]\d+)*)-(pro|flash)-preview(-customtools)?$/i;
+13
View File
@@ -92,4 +92,17 @@ describe('claude preset utils', () => {
'gemini-3-flash-preview'
);
});
it('passes through non-Gemini model ids unchanged', () => {
expect(resolveCatalogModelId('claude-sonnet-4-6')).toBe('claude-sonnet-4-6');
});
it('falls back to the catalog id when no live model matches', () => {
expect(resolveCatalogModelId('gemini-3.1-pro-preview', [])).toBe('gemini-3.1-pro-preview');
expect(
resolveCatalogModelId('gemini-3.1-pro-preview', [
{ id: 'gemini-2.5-pro', owned_by: 'google' },
])
).toBe('gemini-3.1-pro-preview');
});
});
+2 -1
View File
@@ -26,7 +26,8 @@
/* Path alias */
"baseUrl": ".",
"paths": {
"@/*": ["./src/*"]
"@/*": ["./src/*"],
"@shared/*": ["../src/shared/*"]
}
},
"include": ["src"]
+1
View File
@@ -11,6 +11,7 @@ export default defineConfig({
plugins: [react(), tailwindcss()],
resolve: {
alias: {
'@shared': path.resolve(REPO_ROOT, './src/shared'),
'@': path.resolve(__dirname, './src'),
},
},
+1
View File
@@ -45,6 +45,7 @@ export default defineConfig({
},
resolve: {
alias: {
'@shared': path.resolve(__dirname, '../src/shared'),
'@': path.resolve(__dirname, './src'),
'@tests': path.resolve(__dirname, './tests'),
},