From 70fd1baaa8ad632e0c546bda64db0b8750637c98 Mon Sep 17 00:00:00 2001 From: Badri Narayanan S Date: Tue, 13 Jan 2026 18:11:45 +0530 Subject: [PATCH] fix: improve loadCodeAssist for Google One AI Pro accounts - Add separate LOAD_CODE_ASSIST_ENDPOINTS (prod first) and LOAD_CODE_ASSIST_HEADERS (google-api-nodejs-client User-Agent) - Add duetProject to metadata for project discovery - Silent fallback when API returns success but no project (matches opencode-antigravity-auth behavior) - Only warn when all endpoints fail with actual errors Fixes #114, addresses discussion #113 Co-Authored-By: Claude --- src/account-manager/credentials.js | 34 ++++++++++++++++++++++-------- src/cloudcode/model-api.js | 15 +++++++++---- src/constants.js | 21 ++++++++++++++++++ 3 files changed, 57 insertions(+), 13 deletions(-) diff --git a/src/account-manager/credentials.js b/src/account-manager/credentials.js index f5e3489..c223071 100644 --- a/src/account-manager/credentials.js +++ b/src/account-manager/credentials.js @@ -7,8 +7,8 @@ import { ANTIGRAVITY_DB_PATH, TOKEN_REFRESH_INTERVAL_MS, - ANTIGRAVITY_ENDPOINT_FALLBACKS, - ANTIGRAVITY_HEADERS, + LOAD_CODE_ASSIST_ENDPOINTS, + LOAD_CODE_ASSIST_HEADERS, DEFAULT_PROJECT_ID } from '../constants.js'; import { refreshAccessToken } from '../auth/oauth.js'; @@ -113,31 +113,39 @@ export async function getProjectForAccount(account, token, projectCache) { * @returns {Promise} Project ID */ export async function discoverProject(token) { - for (const endpoint of ANTIGRAVITY_ENDPOINT_FALLBACKS) { + let lastError = null; + let gotSuccessfulResponse = false; + + for (const endpoint of LOAD_CODE_ASSIST_ENDPOINTS) { try { const response = await fetch(`${endpoint}/v1internal:loadCodeAssist`, { method: 'POST', headers: { 'Authorization': `Bearer ${token}`, 'Content-Type': 'application/json', - ...ANTIGRAVITY_HEADERS + ...LOAD_CODE_ASSIST_HEADERS }, body: JSON.stringify({ metadata: { ideType: 'IDE_UNSPECIFIED', platform: 'PLATFORM_UNSPECIFIED', - pluginType: 'GEMINI' + pluginType: 'GEMINI', + duetProject: DEFAULT_PROJECT_ID } }) }); if (!response.ok) { const errorText = await response.text(); - logger.warn(`[AccountManager] Project discovery failed at ${endpoint}: ${response.status} - ${errorText}`); + lastError = `${response.status} - ${errorText}`; + logger.debug(`[AccountManager] loadCodeAssist failed at ${endpoint}: ${lastError}`); continue; } const data = await response.json(); + gotSuccessfulResponse = true; + + logger.debug(`[AccountManager] loadCodeAssist response from ${endpoint}:`, JSON.stringify(data)); if (typeof data.cloudaicompanionProject === 'string') { logger.success(`[AccountManager] Discovered project: ${data.cloudaicompanionProject}`); @@ -147,13 +155,21 @@ export async function discoverProject(token) { logger.success(`[AccountManager] Discovered project: ${data.cloudaicompanionProject.id}`); return data.cloudaicompanionProject.id; } + + // API returned success but no project - this is normal for Google One AI Pro accounts + // Silently fall back to default project (matches opencode-antigravity-auth behavior) + logger.debug(`[AccountManager] No project in response, using default: ${DEFAULT_PROJECT_ID}`); + return DEFAULT_PROJECT_ID; } catch (error) { - logger.warn(`[AccountManager] Project discovery failed at ${endpoint}:`, error.message); + lastError = error.message; + logger.debug(`[AccountManager] loadCodeAssist error at ${endpoint}:`, error.message); } } - logger.warn(`[AccountManager] Project discovery failed for all endpoints. Using default project: ${DEFAULT_PROJECT_ID}`); - logger.warn(`[AccountManager] If you see 404 errors, your account may not have Gemini Code Assist enabled.`); + // Only warn if all endpoints failed with errors (not just missing project) + if (!gotSuccessfulResponse) { + logger.warn(`[AccountManager] loadCodeAssist failed for all endpoints: ${lastError}`); + } return DEFAULT_PROJECT_ID; } diff --git a/src/cloudcode/model-api.js b/src/cloudcode/model-api.js index e87c240..7a1eeb8 100644 --- a/src/cloudcode/model-api.js +++ b/src/cloudcode/model-api.js @@ -4,7 +4,13 @@ * Handles model listing and quota retrieval from the Cloud Code API. */ -import { ANTIGRAVITY_ENDPOINT_FALLBACKS, ANTIGRAVITY_HEADERS, getModelFamily } from '../constants.js'; +import { + ANTIGRAVITY_ENDPOINT_FALLBACKS, + ANTIGRAVITY_HEADERS, + LOAD_CODE_ASSIST_ENDPOINTS, + LOAD_CODE_ASSIST_HEADERS, + getModelFamily +} from '../constants.js'; import { logger } from '../utils/logger.js'; /** @@ -122,10 +128,10 @@ export async function getSubscriptionTier(token) { const headers = { 'Authorization': `Bearer ${token}`, 'Content-Type': 'application/json', - ...ANTIGRAVITY_HEADERS + ...LOAD_CODE_ASSIST_HEADERS }; - for (const endpoint of ANTIGRAVITY_ENDPOINT_FALLBACKS) { + for (const endpoint of LOAD_CODE_ASSIST_ENDPOINTS) { try { const url = `${endpoint}/v1internal:loadCodeAssist`; const response = await fetch(url, { @@ -135,7 +141,8 @@ export async function getSubscriptionTier(token) { metadata: { ideType: 'IDE_UNSPECIFIED', platform: 'PLATFORM_UNSPECIFIED', - pluginType: 'GEMINI' + pluginType: 'GEMINI', + duetProject: 'rising-fact-p41fc' } }) }); diff --git a/src/constants.js b/src/constants.js index a45af14..c70783d 100644 --- a/src/constants.js +++ b/src/constants.js @@ -57,6 +57,25 @@ export const ANTIGRAVITY_HEADERS = { }) }; +// Endpoint order for loadCodeAssist (prod first) +// loadCodeAssist works better on prod for fresh/unprovisioned accounts +export const LOAD_CODE_ASSIST_ENDPOINTS = [ + ANTIGRAVITY_ENDPOINT_PROD, + ANTIGRAVITY_ENDPOINT_DAILY +]; + +// Hybrid headers specifically for loadCodeAssist +// Uses google-api-nodejs-client User-Agent (required for project discovery on some accounts) +export const LOAD_CODE_ASSIST_HEADERS = { + 'User-Agent': 'google-api-nodejs-client/9.15.1', + 'X-Goog-Api-Client': 'google-cloud-sdk vscode_cloudshelleditor/0.1', + 'Client-Metadata': JSON.stringify({ + ideType: 'IDE_UNSPECIFIED', + platform: 'PLATFORM_UNSPECIFIED', + pluginType: 'GEMINI' + }) +}; + // Default project ID if none can be discovered export const DEFAULT_PROJECT_ID = 'rising-fact-p41fc'; @@ -171,6 +190,8 @@ export const MODEL_FALLBACK_MAP = { export default { ANTIGRAVITY_ENDPOINT_FALLBACKS, ANTIGRAVITY_HEADERS, + LOAD_CODE_ASSIST_ENDPOINTS, + LOAD_CODE_ASSIST_HEADERS, DEFAULT_PROJECT_ID, TOKEN_REFRESH_INTERVAL_MS, REQUEST_BODY_LIMIT,