From ebb80df24a8cc80eb54db9a688ae7eafcd0f1640 Mon Sep 17 00:00:00 2001 From: Supra4E8C Date: Wed, 14 Jan 2026 16:44:36 +0800 Subject: [PATCH] fix(quota): include project_id in antigravity quota requests --- src/components/quota/quotaConfigs.ts | 41 ++++++++++++++++++++++++++-- src/services/api/authFiles.ts | 8 ++++++ 2 files changed, 47 insertions(+), 2 deletions(-) diff --git a/src/components/quota/quotaConfigs.ts b/src/components/quota/quotaConfigs.ts index 6a023d0..f1870e3 100644 --- a/src/components/quota/quotaConfigs.ts +++ b/src/components/quota/quotaConfigs.ts @@ -18,7 +18,7 @@ import type { GeminiCliQuotaBucketState, GeminiCliQuotaState } from '@/types'; -import { apiCallApi, getApiCallErrorMessage } from '@/services/api'; +import { apiCallApi, authFilesApi, getApiCallErrorMessage } from '@/services/api'; import { ANTIGRAVITY_QUOTA_URLS, ANTIGRAVITY_REQUEST_HEADERS, @@ -55,6 +55,8 @@ type QuotaUpdater = T | ((prev: T) => T); type QuotaType = 'antigravity' | 'codex' | 'gemini-cli'; +const DEFAULT_ANTIGRAVITY_PROJECT_ID = 'bamboo-precept-lgxtn'; + export interface QuotaStore { antigravityQuota: Record; codexQuota: Record; @@ -82,6 +84,38 @@ export interface QuotaConfig { renderQuotaItems: (quota: TState, t: TFunction, helpers: QuotaRenderHelpers) => ReactNode; } +const resolveAntigravityProjectId = async (file: AuthFileItem): Promise => { + try { + const text = await authFilesApi.downloadText(file.name); + const trimmed = text.trim(); + if (!trimmed) return DEFAULT_ANTIGRAVITY_PROJECT_ID; + + const parsed = JSON.parse(trimmed) as Record; + const topLevel = normalizeStringValue(parsed.project_id ?? parsed.projectId); + if (topLevel) return topLevel; + + const installed = + parsed.installed && typeof parsed.installed === 'object' && parsed.installed !== null + ? (parsed.installed as Record) + : null; + const installedProjectId = installed + ? normalizeStringValue(installed.project_id ?? installed.projectId) + : null; + if (installedProjectId) return installedProjectId; + + const web = + parsed.web && typeof parsed.web === 'object' && parsed.web !== null + ? (parsed.web as Record) + : null; + const webProjectId = web ? normalizeStringValue(web.project_id ?? web.projectId) : null; + if (webProjectId) return webProjectId; + } catch { + return DEFAULT_ANTIGRAVITY_PROJECT_ID; + } + + return DEFAULT_ANTIGRAVITY_PROJECT_ID; +}; + const fetchAntigravityQuota = async ( file: AuthFileItem, t: TFunction @@ -92,6 +126,9 @@ const fetchAntigravityQuota = async ( throw new Error(t('antigravity_quota.missing_auth_index')); } + const projectId = await resolveAntigravityProjectId(file); + const requestBody = JSON.stringify({ project_id: projectId }); + let lastError = ''; let lastStatus: number | undefined; let priorityStatus: number | undefined; @@ -104,7 +141,7 @@ const fetchAntigravityQuota = async ( method: 'POST', url, header: { ...ANTIGRAVITY_REQUEST_HEADERS }, - data: '{}' + data: requestBody }); if (result.statusCode < 200 || result.statusCode >= 300) { diff --git a/src/services/api/authFiles.ts b/src/services/api/authFiles.ts index 054b1cf..47a93f0 100644 --- a/src/services/api/authFiles.ts +++ b/src/services/api/authFiles.ts @@ -56,6 +56,14 @@ export const authFilesApi = { deleteAll: () => apiClient.delete('/auth-files', { params: { all: true } }), + downloadText: async (name: string): Promise => { + const response = await apiClient.getRaw(`/auth-files/download?name=${encodeURIComponent(name)}`, { + responseType: 'blob' + }); + const blob = response.data as Blob; + return blob.text(); + }, + // OAuth 排除模型 async getOauthExcludedModels(): Promise> { const data = await apiClient.get('/oauth-excluded-models');