From 716272a1e2c534bf3d4cbde20c39d2d90acd6de5 Mon Sep 17 00:00:00 2001 From: Ubuntu Date: Sat, 24 Jan 2026 23:04:48 +0800 Subject: [PATCH] =?UTF-8?q?fix(oauth):=20=E5=BD=BB=E5=BA=95=E4=BF=AE?= =?UTF-8?q?=E5=A4=8D=20project=5Fid=20=E4=B8=A2=E5=A4=B1=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 根本原因: - BuildAccountCredentials 只在 project_id 非空时才添加该字段 - LoadCodeAssist 失败时返回空字符串 → 新 credentials 不包含 project_id 键 - 普通合并逻辑只保留新 credentials 中不存在的键,无法覆盖空值 解决方案: 1. 在合并后特殊处理 project_id:如果新值为空但旧值非空,保留旧值 2. LoadCodeAssist 失败不再返回错误,只记录警告 3. Token 刷新成功(access_token 已更新)就不应标记账户为 error 改进效果: - 即使 LoadCodeAssist 连续失败,已有的 project_id 也不会丢失 - 避免因临时网络问题将账户误标记为不可用 - 允许在下次刷新时自动重试获取 project_id Co-Authored-By: Claude Sonnet 4.5 --- .../internal/handler/admin/account_handler.go | 23 +++++++++++-------- .../service/antigravity_token_refresher.go | 22 +++++++++++++----- 2 files changed, 30 insertions(+), 15 deletions(-) diff --git a/backend/internal/handler/admin/account_handler.go b/backend/internal/handler/admin/account_handler.go index 188aa0ec..bbf5d026 100644 --- a/backend/internal/handler/admin/account_handler.go +++ b/backend/internal/handler/admin/account_handler.go @@ -547,9 +547,18 @@ func (h *AccountHandler) Refresh(c *gin.Context) { } } - // 如果 project_id 获取失败,先更新凭证,再标记账户为 error + // 特殊处理 project_id:如果新值为空但旧值非空,保留旧值 + // 这确保了即使 LoadCodeAssist 失败,project_id 也不会丢失 + if newProjectID, _ := newCredentials["project_id"].(string); newProjectID == "" { + if oldProjectID := strings.TrimSpace(account.GetCredential("project_id")); oldProjectID != "" { + newCredentials["project_id"] = oldProjectID + } + } + + // 如果 project_id 获取失败,更新凭证但不标记为 error + // LoadCodeAssist 失败可能是临时网络问题,给它机会在下次自动刷新时重试 if tokenInfo.ProjectIDMissing { - // 先更新凭证 + // 先更新凭证(token 本身刷新成功了) _, updateErr := h.adminService.UpdateAccount(c.Request.Context(), accountID, &service.UpdateAccountInput{ Credentials: newCredentials, }) @@ -557,14 +566,10 @@ func (h *AccountHandler) Refresh(c *gin.Context) { response.InternalError(c, "Failed to update credentials: "+updateErr.Error()) return } - // 标记账户为 error - if setErr := h.adminService.SetAccountError(c.Request.Context(), accountID, "missing_project_id: 账户缺少project id,可能无法使用Antigravity"); setErr != nil { - response.InternalError(c, "Failed to set account error: "+setErr.Error()) - return - } + // 不标记为 error,只返回警告信息 response.Success(c, gin.H{ - "message": "Token refreshed but project_id is missing, account marked as error", - "warning": "missing_project_id", + "message": "Token refreshed successfully, but project_id could not be retrieved (will retry automatically)", + "warning": "missing_project_id_temporary", }) return } diff --git a/backend/internal/service/antigravity_token_refresher.go b/backend/internal/service/antigravity_token_refresher.go index 2beb9e84..e33f88d0 100644 --- a/backend/internal/service/antigravity_token_refresher.go +++ b/backend/internal/service/antigravity_token_refresher.go @@ -4,6 +4,7 @@ import ( "context" "fmt" "log" + "strings" "time" ) @@ -56,22 +57,31 @@ func (r *AntigravityTokenRefresher) Refresh(ctx context.Context, account *Accoun } newCredentials := r.antigravityOAuthService.BuildAccountCredentials(tokenInfo) + // 合并旧的 credentials,保留新 credentials 中不存在的字段 for k, v := range account.Credentials { if _, exists := newCredentials[k]; !exists { newCredentials[k] = v } } - // 如果 project_id 获取失败但之前有 project_id,不返回错误(只是临时网络故障) - // 只有真正缺失 project_id(从未获取过)时才返回错误 + // 特殊处理 project_id:如果新值为空但旧值非空,保留旧值 + // 这确保了即使 LoadCodeAssist 失败,project_id 也不会丢失 + if newProjectID, _ := newCredentials["project_id"].(string); newProjectID == "" { + if oldProjectID := strings.TrimSpace(account.GetCredential("project_id")); oldProjectID != "" { + newCredentials["project_id"] = oldProjectID + } + } + + // 如果 project_id 获取失败,只记录警告,不返回错误 + // LoadCodeAssist 失败可能是临时网络问题,应该允许重试而不是立即标记为不可重试错误 + // Token 刷新本身是成功的(access_token 和 refresh_token 已更新) if tokenInfo.ProjectIDMissing { - // 检查是否保留了旧的 project_id if tokenInfo.ProjectID != "" { - // 有旧的 project_id,只是本次获取失败,记录警告但不返回错误 + // 有旧的 project_id,本次获取失败,保留旧值 log.Printf("[AntigravityTokenRefresher] Account %d: LoadCodeAssist 临时失败,保留旧 project_id", account.ID) } else { - // 真正缺失 project_id,返回错误 - return newCredentials, fmt.Errorf("missing_project_id: 账户缺少project id,可能无法使用Antigravity") + // 从未获取过 project_id,本次也失败,但不返回错误以允许下次重试 + log.Printf("[AntigravityTokenRefresher] Account %d: LoadCodeAssist 失败,project_id 缺失,但 token 已更新,将在下次刷新时重试", account.ID) } }