完善 Antigravity 配额展示与 CI 断言

This commit is contained in:
MMEXA
2026-07-08 22:34:29 +08:00
parent 4866509938
commit c7186e1720
6 changed files with 111 additions and 19 deletions
@@ -120,6 +120,7 @@ import { useToast } from '@/composables/useToast'
import { parseApiError } from '@/utils/errorParser'
import {
compareAntigravityQuotaItems,
dedupeAntigravityQuotaItemsByLabel,
resolveAntigravityQuotaLabel,
} from '@/features/providers/utils/antigravityQuota'
@@ -232,7 +233,7 @@ function buildItemsFromQuotaSnapshot(quota: QuotaStatusSnapshot | null | undefin
.filter((item): item is QuotaItem => item !== null)
items.sort(compareAntigravityQuotaItems)
return items
return dedupeAntigravityQuotaItemsByLabel(items)
}
const items = computed<QuotaItem[]>(() => {
@@ -284,7 +285,7 @@ const items = computed<QuotaItem[]>(() => {
}
result.sort(compareAntigravityQuotaItems)
return result
return dedupeAntigravityQuotaItemsByLabel(result)
})
async function handleTestModel(modelName: string) {
@@ -959,6 +959,7 @@ import ProviderQuotaSectionHeader from '@/features/providers/components/Provider
import { useProxyNodesStore } from '@/stores/proxy-nodes'
import {
compareAntigravityQuotaItems,
dedupeAntigravityQuotaItemsByLabel,
resolveAntigravityQuotaLabel,
} from '@/features/providers/utils/antigravityQuota'
import {
@@ -3418,7 +3419,7 @@ function getAntigravityQuotaItems(metadata: UpstreamMetadata | null | undefined)
}
items.sort(compareAntigravityQuotaItems)
return items
return dedupeAntigravityQuotaItemsByLabel(items)
}
function getAntigravityQuotaItemsFromSnapshot(key: EndpointAPIKey): AntigravityQuotaItem[] {
@@ -3462,7 +3463,7 @@ function getAntigravityQuotaItemsFromSnapshot(key: EndpointAPIKey): AntigravityQ
.filter((item): item is AntigravityQuotaItem => item !== null)
items.sort(compareAntigravityQuotaItems)
return items
return dedupeAntigravityQuotaItemsByLabel(items)
}
const ANTIGRAVITY_QUOTA_PREVIEW_LIMIT = 6
@@ -164,12 +164,44 @@ describe('AntigravityQuotaDialog', () => {
expect(text).not.toContain('gemini-pro-agent')
expect(text).not.toContain('claude-opus-4-6-thinking')
expect(text.indexOf('Claude Opus 4.6 (Thinking)')).toBeLessThan(text.indexOf('Gemini 3.1 Pro (High)'))
expect(text.indexOf('Gemini 3.1 Pro (High)')).toBeLessThan(text.indexOf('Gemini 3.5 Flash (High)'))
expect(text.indexOf('Gemini 3.5 Flash (High)')).toBeLessThan(text.indexOf('Gemini 3.5 Flash (Medium)'))
expect(text.indexOf('Gemini 3.5 Flash (Medium)')).toBeLessThan(text.indexOf('Claude Opus 4.6 (Thinking)'))
expect(text.indexOf('Claude Opus 4.6 (Thinking)')).toBeLessThan(text.indexOf('Tab Flash Lite Preview'))
expect(text.indexOf('Gemini 3.5 Flash (Medium)')).toBeLessThan(text.indexOf('Tab Flash Lite Preview'))
expect(text.indexOf('Tab Flash Lite Preview')).toBeLessThan(text.indexOf('chat_20706'))
unmount()
})
it('renders one row for duplicate quota labels and keeps the preferred active bucket', () => {
const { root, unmount } = mount({
antigravity: {
quota_by_model: {
'gemini-3.1-pro-high': {
display_name: 'Gemini 3.1 Pro (High)',
remaining_fraction: 0.95,
used_percent: 5,
},
'gemini-pro-agent': {
display_name: 'Gemini 3.1 Pro (High)',
remaining_fraction: 0.4,
used_percent: 60,
},
'gemini-3-flash-agent': {
display_name: 'Gemini 3.5 Flash (High)',
remaining_fraction: 0.9,
used_percent: 10,
},
},
},
})
const text = root.textContent || ''
expect(text.match(/Gemini 3\.1 Pro \(High\)/g)).toHaveLength(1)
expect(text).toContain('40.0%')
expect(text).not.toContain('95.0%')
expect(text.indexOf('Gemini 3.1 Pro (High)')).toBeLessThan(text.indexOf('Gemini 3.5 Flash (High)'))
unmount()
})
})
@@ -2,6 +2,7 @@ import { describe, expect, it } from 'vitest'
import {
compareAntigravityQuotaItems,
dedupeAntigravityQuotaItemsByLabel,
resolveAntigravityQuotaLabel,
} from '@/features/providers/utils/antigravityQuota'
@@ -120,14 +121,55 @@ describe('antigravityQuota', () => {
].sort(compareAntigravityQuotaItems)
expect(items.map(item => item.model)).toEqual([
'claude-opus-4-6-thinking',
'gemini-pro-agent',
'gemini-3-flash-agent',
'gemini-3.5-flash-low',
'gemini-3.5-flash-extra-low',
'claude-opus-4-6-thinking',
'gemini-2.5-flash-lite',
'tab_flash_lite_preview',
'chat_20706',
])
})
it('deduplicates display labels while keeping the current preferred quota bucket', () => {
const items = dedupeAntigravityQuotaItemsByLabel([
{
model: 'gemini-3.1-pro-high',
label: 'Gemini 3.1 Pro (High)',
remainingPercent: 95,
resetSeconds: null,
},
{
model: 'gemini-pro-agent',
label: 'Gemini 3.1 Pro (High)',
remainingPercent: 40,
resetSeconds: null,
},
{
model: 'claude-sonnet-4-6-thinking',
label: 'Claude Sonnet 4.6 (Thinking)',
remainingPercent: 95,
resetSeconds: null,
},
{
model: 'claude-sonnet-4-6',
label: 'Claude Sonnet 4.6 (Thinking)',
remainingPercent: 40,
resetSeconds: null,
},
{
model: 'gemini-3-flash-agent',
label: 'Gemini 3.5 Flash (High)',
remainingPercent: 80,
resetSeconds: null,
},
])
expect(items.map(item => item.model)).toEqual([
'claude-sonnet-4-6',
'gemini-pro-agent',
'gemini-3-flash-agent',
])
})
})
@@ -29,15 +29,15 @@ const ANTIGRAVITY_MODEL_LABELS: Record<string, string> = {
}
const ANTIGRAVITY_MODEL_PRIORITY: Record<string, number> = {
'gemini-pro-agent': 10,
'gemini-3.1-pro-high': 10,
'gemini-3.1-pro-low': 20,
'gemini-3-flash-agent': 30,
'gemini-3.5-flash-low': 40,
'gemini-3.5-flash-extra-low': 50,
'claude-opus-4-6-thinking': 60,
'claude-sonnet-4-6': 70,
'claude-sonnet-4-6-thinking': 70,
'claude-opus-4-6-thinking': 10,
'claude-sonnet-4-6': 20,
'claude-sonnet-4-6-thinking': 25,
'gemini-pro-agent': 30,
'gemini-3.1-pro-high': 35,
'gemini-3.1-pro-low': 40,
'gemini-3-flash-agent': 50,
'gemini-3.5-flash-low': 60,
'gemini-3.5-flash-extra-low': 70,
'gemini-3.1-flash-image': 80,
'gemini-3.1-flash-lite': 90,
'gemini-3-flash': 180,
@@ -78,7 +78,7 @@ function getAntigravityModelPriority(model: string): number {
const normalizedModel = model.trim()
const explicit = ANTIGRAVITY_MODEL_PRIORITY[normalizedModel]
if (explicit !== undefined) return explicit
if (normalizedModel.startsWith('claude-')) return 90
if (normalizedModel.startsWith('claude-')) return 30
if (normalizedModel.startsWith('gemini-3.')) return 200
if (normalizedModel.startsWith('gemini-2.')) return 390
if (normalizedModel.startsWith('gemini-')) return 490
@@ -100,3 +100,18 @@ export function compareAntigravityQuotaItems<T extends AntigravityQuotaSortableI
|| a.label.localeCompare(b.label)
|| a.model.localeCompare(b.model)
}
export function dedupeAntigravityQuotaItemsByLabel<T extends AntigravityQuotaSortableItem>(
items: T[],
): T[] {
const selectedByLabel = new Map<string, T>()
for (const item of items) {
const label = item.label.trim()
if (!label) continue
const selected = selectedByLabel.get(label)
if (!selected || compareAntigravityQuotaItems(item, selected) < 0) {
selectedByLabel.set(label, item)
}
}
return Array.from(selectedByLabel.values()).sort(compareAntigravityQuotaItems)
}