mirror of
https://github.com/router-for-me/Cli-Proxy-API-Management-Center.git
synced 2026-10-16 14:57:05 +08:00
feat(quota): list Gemini Argon in the Antigravity Gemini quota group
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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'
|
||||
|
||||
Reference in New Issue
Block a user