From 226844b8b2e71bb4c7a7f05ab5582af5a33c03c9 Mon Sep 17 00:00:00 2001 From: erio Date: Tue, 10 Mar 2026 18:08:58 +0800 Subject: [PATCH] fix(antigravity): change VALIDATION_REQUIRED 403 to SetError and enrich degraded usage with account error status - VALIDATION_REQUIRED now marks account as error (permanent) instead of temp unschedulable (10min) - When usage fetch fails with 401 but account has 403 error, show correct forbidden/banned status instead of needs_reauth --- .../internal/service/account_usage_service.go | 25 +++++++++++++++++++ backend/internal/service/ratelimit_service.go | 25 +++++-------------- 2 files changed, 31 insertions(+), 19 deletions(-) diff --git a/backend/internal/service/account_usage_service.go b/backend/internal/service/account_usage_service.go index 041df38bb8..799c192b48 100644 --- a/backend/internal/service/account_usage_service.go +++ b/backend/internal/service/account_usage_service.go @@ -700,6 +700,7 @@ func (s *AccountUsageService) getAntigravityUsage(ctx context.Context, account * fetchResult, err := s.antigravityQuotaFetcher.FetchQuota(fetchCtx, account, proxyURL) if err != nil { degraded := buildAntigravityDegradedUsage(err) + enrichDegradedWithAccountError(degraded, account) s.cache.antigravityCache.Store(account.ID, &antigravityUsageCache{ usageInfo: degraded, timestamp: time.Now(), @@ -785,6 +786,30 @@ func buildAntigravityDegradedUsage(err error) *UsageInfo { return info } +// enrichDegradedWithAccountError 结合账号错误状态修正降级 UsageInfo +// 场景:被封号的账号 OAuth token 失效,FetchAvailableModels 返回 401, +// 降级逻辑设置了 needs_reauth,但账号实际是 403 封号/需验证。 +// 此函数用账号的 error_message 覆盖降级信息,显示正确的 forbidden 状态。 +func enrichDegradedWithAccountError(info *UsageInfo, account *Account) { + if info == nil || account == nil || account.Status != StatusError { + return + } + msg := strings.ToLower(account.ErrorMessage) + if !strings.Contains(msg, "403") && !strings.Contains(msg, "forbidden") && + !strings.Contains(msg, "violation") && !strings.Contains(msg, "validation") { + return + } + fbType := classifyForbiddenType(account.ErrorMessage) + info.IsForbidden = true + info.ForbiddenType = fbType + info.ForbiddenReason = account.ErrorMessage + info.NeedsVerify = fbType == forbiddenTypeValidation + info.IsBanned = fbType == forbiddenTypeViolation + info.ValidationURL = extractValidationURL(account.ErrorMessage) + info.ErrorCode = errorCodeForbidden + info.NeedsReauth = false +} + // addWindowStats 为 usage 数据添加窗口期统计 // 使用独立缓存(1 分钟),与 API 缓存分离 func (s *AccountUsageService) addWindowStats(ctx context.Context, account *Account, usage *UsageInfo) { diff --git a/backend/internal/service/ratelimit_service.go b/backend/internal/service/ratelimit_service.go index 6eaab63f0f..28c87f0b28 100644 --- a/backend/internal/service/ratelimit_service.go +++ b/backend/internal/service/ratelimit_service.go @@ -616,12 +616,8 @@ func (s *RateLimitService) handleAuthError(ctx context.Context, account *Account slog.Warn("account_disabled_auth_error", "account_id", account.ID, "error", errorMsg) } -// antigravityValidationBlockDuration Antigravity validation 类型 403 的临时封禁时长 -// 与 Antigravity-Manager 一致(10 分钟) -const antigravityValidationBlockDuration = 10 * time.Minute - // handle403 处理 403 Forbidden 错误 -// Antigravity 平台区分 validation(临时不可调度)和 violation(永久 SetError); +// Antigravity 平台区分 validation/violation/generic 三种类型,均 SetError 永久禁用; // 其他平台保持原有 SetError 行为。 func (s *RateLimitService) handle403(ctx context.Context, account *Account, upstreamMsg string, responseBody []byte) (shouldDisable bool) { if account.Platform == PlatformAntigravity { @@ -637,7 +633,7 @@ func (s *RateLimitService) handle403(ctx context.Context, account *Account, upst } // handleAntigravity403 处理 Antigravity 平台的 403 错误 -// validation(需要验证)→ 临时不可调度(到期自动恢复) +// validation(需要验证)→ 永久 SetError(需人工去 Google 验证后恢复) // violation(违规封号)→ 永久 SetError(需人工处理) // generic(通用禁止)→ 永久 SetError func (s *RateLimitService) handleAntigravity403(ctx context.Context, account *Account, upstreamMsg string, responseBody []byte) (shouldDisable bool) { @@ -645,21 +641,12 @@ func (s *RateLimitService) handleAntigravity403(ctx context.Context, account *Ac switch fbType { case forbiddenTypeValidation: - // VALIDATION_REQUIRED: 临时不可调度,到期自动恢复 - until := time.Now().Add(antigravityValidationBlockDuration) - reason := "Validation required (403)" + // VALIDATION_REQUIRED: 永久禁用,需人工去 Google 验证后手动恢复 + msg := "Validation required (403): account needs Google verification" if upstreamMsg != "" { - reason = "Validation required (403): " + upstreamMsg - } - if err := s.accountRepo.SetTempUnschedulable(ctx, account.ID, until, reason); err != nil { - slog.Warn("antigravity_validation_block_failed", "account_id", account.ID, "error", err) - } else { - slog.Info("antigravity_validation_block_set", - "account_id", account.ID, - "until", until, - "forbidden_type", fbType, - ) + msg = "Validation required (403): " + upstreamMsg } + s.handleAuthError(ctx, account, msg) return true case forbiddenTypeViolation: