feat(quota): list Gemini Argon in the Antigravity Gemini quota group

This commit is contained in:
Supra4E8C
2026-10-16 10:48:54 +08:00
parent 27547a4447
commit c59ab414a8
3 changed files with 73 additions and 2 deletions
@@ -10,7 +10,11 @@ import { QuotaMeter } from '../../components/QuotaMeter';
import { collectQuotaRowInstants, pickUrgentRowId } from '../../resetSchedule';
import type { QuotaBodyProps } from '../../types';
import { getNextAntigravityCountdownUpdateDelay } from './countdown';
import { resolveAntigravityBucketLabelKey, resolveAntigravityGroupLabelKey } from './labels';
import {
resolveAntigravityBucketLabelKey,
resolveAntigravityGroupLabelKey,
resolveAntigravityGroupModels,
} from './labels';
const formatAntigravityDuration = (t: TFunction, deltaMs: number): string => {
const totalMinutes = Math.max(1, Math.ceil(deltaMs / 60000));
@@ -151,7 +155,12 @@ export function AntigravityQuotaBody({ quota, classes }: QuotaBodyProps<Antigrav
resolveAntigravityGroupLabelKey(group.label),
t
);
const groupDescription = translateAntigravityQuotaDescription(group.description, t);
const groupModels = resolveAntigravityGroupModels(group.label, group.description);
const groupDescription = groupModels
? t('antigravity_quota.group_models_description', {
models: groupModels.join(', '),
})
: translateAntigravityQuotaDescription(group.description, t);
return (
<div key={group.id} className={classes.antigravityQuotaGroup}>
@@ -32,6 +32,15 @@ const BUCKET_WINDOW_KEYS = new Map<string, string>([
['month', 'monthly_limit'],
]);
/**
* 上游分组描述未列出、但实际共享该分组额度的模型,追加到「此分组包含」列表末尾。
*/
const GROUP_EXTRA_MODELS = new Map<string, readonly string[]>([
['group_gemini_models', ['Gemini Argon']],
]);
const GROUP_MODELS_PATTERN = /^models within this group:\s*(.+)$/i;
const normalizeText = (value: string): string => value.trim().toLowerCase().replace(/\s+/g, ' ');
/** 去掉上游常见的 "Remaining" 后缀,如 "Weekly Limit Remaining" → "weekly limit"。 */
@@ -42,6 +51,32 @@ export function resolveAntigravityGroupLabelKey(label: string): string | null {
return GROUP_LABEL_KEYS.get(normalizeText(label)) ?? null;
}
/**
* 解析分组描述中的模型列表,并追加该分组的补充模型(大小写不敏感去重)。
* 描述不是「Models within this group: ...」格式时返回 null,由调用方显示原文。
*/
export function resolveAntigravityGroupModels(
label: string,
description: string | undefined
): string[] | null {
const match = description?.trim().match(GROUP_MODELS_PATTERN);
if (!match) return null;
const models = match[1]
.split(',')
.map((model) => model.trim())
.filter(Boolean);
const groupKey = resolveAntigravityGroupLabelKey(label);
const extras = groupKey ? (GROUP_EXTRA_MODELS.get(groupKey) ?? []) : [];
const seen = new Set(models.map(normalizeText));
extras.forEach((model) => {
if (seen.has(normalizeText(model))) return;
seen.add(normalizeText(model));
models.push(model);
});
return models;
}
export function resolveAntigravityBucketLabelKey(
label: string,
window: string | undefined
+27
View File
@@ -2,6 +2,7 @@ import { describe, expect, test } from 'bun:test';
import {
resolveAntigravityBucketLabelKey,
resolveAntigravityGroupLabelKey,
resolveAntigravityGroupModels,
} from '@/features/quota/providers/antigravity/labels';
import { buildAntigravityQuotaGroups } from '@/utils/quota/builders';
@@ -14,6 +15,32 @@ describe('Antigravity quota label keys', () => {
expect(resolveAntigravityGroupLabelKey('Image Models')).toBeNull();
});
test('appends Gemini Argon to the Gemini group model list', () => {
expect(
resolveAntigravityGroupModels(
'Gemini Models',
'Models within this group: Gemini Flash, Gemini Pro'
)
).toEqual(['Gemini Flash', 'Gemini Pro', 'Gemini Argon']);
expect(
resolveAntigravityGroupModels(
'Gemini Models',
'Models within this group: Gemini Flash, gemini argon'
)
).toEqual(['Gemini Flash', 'gemini argon']);
});
test('leaves other groups and non-list descriptions untouched', () => {
expect(
resolveAntigravityGroupModels(
'Claude and GPT models',
'Models within this group: Claude Opus, Claude Sonnet, GPT-OSS'
)
).toEqual(['Claude Opus', 'Claude Sonnet', 'GPT-OSS']);
expect(resolveAntigravityGroupModels('Gemini Models', 'Shared Gemini quota')).toBeNull();
expect(resolveAntigravityGroupModels('Gemini Models', undefined)).toBeNull();
});
test('ignores the upstream "Remaining" suffix on bucket names', () => {
expect(resolveAntigravityBucketLabelKey('Five Hour Limit Remaining', '5h')).toBe(
'five_hour_limit'