feat(quota): add normalization for Gemini CLI model IDs and update quota groups

This commit is contained in:
LTbinglingfeng
2026-02-06 19:11:57 +08:00
parent 3661530f5f
commit cade2647d6
4 changed files with 63 additions and 21 deletions

View File

@@ -28,6 +28,7 @@ import {
GEMINI_CLI_QUOTA_URL,
GEMINI_CLI_REQUEST_HEADERS,
normalizeAuthIndexValue,
normalizeGeminiCliModelId,
normalizeNumberValue,
normalizePlanType,
normalizeQuotaFraction,
@@ -368,7 +369,7 @@ const fetchGeminiCliQuota = async (
const parsedBuckets = buckets
.map((bucket) => {
const modelId = normalizeStringValue(bucket.modelId ?? bucket.model_id);
const modelId = normalizeGeminiCliModelId(bucket.modelId ?? bucket.model_id);
if (!modelId) return null;
const tokenType = normalizeStringValue(bucket.tokenType ?? bucket.token_type);
const remainingFractionRaw = normalizeQuotaFraction(

View File

@@ -10,7 +10,11 @@ import type {
GeminiCliParsedBucket,
GeminiCliQuotaBucketState,
} from '@/types';
import { ANTIGRAVITY_QUOTA_GROUPS, GEMINI_CLI_GROUP_LOOKUP } from './constants';
import {
ANTIGRAVITY_QUOTA_GROUPS,
GEMINI_CLI_GROUP_LOOKUP,
GEMINI_CLI_GROUP_ORDER,
} from './constants';
import { normalizeQuotaFraction } from './parsers';
import { isIgnoredGeminiCliModel } from './validators';
@@ -92,24 +96,40 @@ export function buildGeminiCliQuotaBuckets(
}
});
return Array.from(grouped.values()).map((bucket) => {
const uniqueModelIds = Array.from(new Set(bucket.modelIds));
const preferred = bucket.preferredBucket;
const remainingFraction = preferred
? preferred.remainingFraction
: bucket.fallbackRemainingFraction;
const remainingAmount = preferred ? preferred.remainingAmount : bucket.fallbackRemainingAmount;
const resetTime = preferred ? preferred.resetTime : bucket.fallbackResetTime;
return {
id: bucket.id,
label: bucket.label,
remainingFraction,
remainingAmount,
resetTime,
tokenType: bucket.tokenType,
modelIds: uniqueModelIds,
};
});
const toGroupOrder = (bucket: GeminiCliQuotaBucketGroup): number => {
const tokenSuffix = bucket.tokenType ? `-${bucket.tokenType}` : '';
const groupId = bucket.id.endsWith(tokenSuffix)
? bucket.id.slice(0, bucket.id.length - tokenSuffix.length)
: bucket.id;
return GEMINI_CLI_GROUP_ORDER.get(groupId) ?? Number.MAX_SAFE_INTEGER;
};
return Array.from(grouped.values())
.sort((a, b) => {
const orderDiff = toGroupOrder(a) - toGroupOrder(b);
if (orderDiff !== 0) return orderDiff;
const tokenTypeA = a.tokenType ?? '';
const tokenTypeB = b.tokenType ?? '';
return tokenTypeA.localeCompare(tokenTypeB);
})
.map((bucket) => {
const uniqueModelIds = Array.from(new Set(bucket.modelIds));
const preferred = bucket.preferredBucket;
const remainingFraction = preferred
? preferred.remainingFraction
: bucket.fallbackRemainingFraction;
const remainingAmount = preferred ? preferred.remainingAmount : bucket.fallbackRemainingAmount;
const resetTime = preferred ? preferred.resetTime : bucket.fallbackResetTime;
return {
id: bucket.id,
label: bucket.label,
remainingFraction,
remainingAmount,
resetTime,
tokenType: bucket.tokenType,
modelIds: uniqueModelIds,
};
});
}
export function getAntigravityQuotaInfo(entry?: AntigravityQuotaInfo): {

View File

@@ -119,11 +119,17 @@ export const GEMINI_CLI_REQUEST_HEADERS = {
};
export const GEMINI_CLI_QUOTA_GROUPS: GeminiCliQuotaGroupDefinition[] = [
{
id: 'gemini-flash-lite-series',
label: 'Gemini Flash Lite Series',
preferredModelId: 'gemini-2.5-flash-lite',
modelIds: ['gemini-2.5-flash-lite'],
},
{
id: 'gemini-flash-series',
label: 'Gemini Flash Series',
preferredModelId: 'gemini-3-flash-preview',
modelIds: ['gemini-3-flash-preview', 'gemini-2.5-flash', 'gemini-2.5-flash-lite'],
modelIds: ['gemini-3-flash-preview', 'gemini-2.5-flash'],
},
{
id: 'gemini-pro-series',
@@ -133,6 +139,10 @@ export const GEMINI_CLI_QUOTA_GROUPS: GeminiCliQuotaGroupDefinition[] = [
},
];
export const GEMINI_CLI_GROUP_ORDER = new Map(
GEMINI_CLI_QUOTA_GROUPS.map((group, index) => [group.id, index] as const)
);
export const GEMINI_CLI_GROUP_LOOKUP = new Map(
GEMINI_CLI_QUOTA_GROUPS.flatMap((group) =>
group.modelIds.map((modelId) => [modelId, group] as const)

View File

@@ -4,6 +4,8 @@
import type { CodexUsagePayload, GeminiCliQuotaPayload } from '@/types';
const GEMINI_CLI_MODEL_SUFFIX = '_vertex';
export function normalizeAuthIndexValue(value: unknown): string | null {
if (typeof value === 'number' && Number.isFinite(value)) {
return value.toString();
@@ -26,6 +28,15 @@ export function normalizeStringValue(value: unknown): string | null {
return null;
}
export function normalizeGeminiCliModelId(value: unknown): string | null {
const modelId = normalizeStringValue(value);
if (!modelId) return null;
if (modelId.endsWith(GEMINI_CLI_MODEL_SUFFIX)) {
return modelId.slice(0, -GEMINI_CLI_MODEL_SUFFIX.length);
}
return modelId;
}
export function normalizeNumberValue(value: unknown): number | null {
if (typeof value === 'number' && Number.isFinite(value)) return value;
if (typeof value === 'string') {