bardd's picture
Fix gemini-3.1-pro-high by routing to pro-low with thinkingLevel high.
4badc3b
Raw
History Blame Contribute Delete
3.92 kB
/**
* User Onboarding
*
* Handles provisioning of managed projects for accounts that don't have one.
*/
import {
ONBOARD_USER_ENDPOINTS,
ANTIGRAVITY_HEADERS,
CLIENT_METADATA
} from '../constants.js';
import { logger } from '../utils/logger.js';
import { sleep, throttledFetch } from '../utils/helpers.js';
/**
* Get the default tier ID from allowed tiers list
*
* @param {Array} allowedTiers - List of allowed tiers from loadCodeAssist
* @returns {string|undefined} Default tier ID
*/
export function getDefaultTierId(allowedTiers) {
if (!allowedTiers || allowedTiers.length === 0) {
return undefined;
}
// Find the tier marked as default
for (const tier of allowedTiers) {
if (tier?.isDefault) {
return tier.id;
}
}
// Fall back to first tier
return allowedTiers[0]?.id;
}
/**
* Onboard a user to get a managed project
*
* @param {string} token - OAuth access token
* @param {string} tierId - Tier ID (raw API value, e.g., 'free-tier', 'standard-tier', 'g1-pro-tier')
* @param {string} [projectId] - Optional GCP project ID (required for non-free tiers)
* @param {number} [maxAttempts=10] - Maximum polling attempts
* @param {number} [delayMs=5000] - Delay between polling attempts
* @returns {Promise<string|null>} Managed project ID or null if failed
*/
export async function onboardUser(token, tierId, projectId = undefined, maxAttempts = 10, delayMs = 5000) {
const metadata = { ...CLIENT_METADATA };
if (projectId) {
metadata.duetProject = projectId;
}
const requestBody = {
tierId,
metadata
};
// Note: Do NOT add cloudaicompanionProject to requestBody
// Reference implementation only sets metadata.duetProject, not the body field
// Adding cloudaicompanionProject causes 400 errors for auto-provisioned tiers (g1-pro, g1-ultra)
logger.debug(`[Onboarding] Starting onboard with tierId: ${tierId}, projectId: ${projectId}`);
for (const endpoint of ONBOARD_USER_ENDPOINTS) {
for (let attempt = 0; attempt < maxAttempts; attempt++) {
try {
const response = await throttledFetch(`${endpoint}/v1internal:onboardUser`, {
method: 'POST',
headers: {
'Authorization': `Bearer ${token}`,
'Content-Type': 'application/json',
...ANTIGRAVITY_HEADERS
},
body: JSON.stringify(requestBody)
});
if (!response.ok) {
const errorText = await response.text();
logger.warn(`[Onboarding] onboardUser failed at ${endpoint}: ${response.status} - ${errorText}`);
break; // Try next endpoint
}
const data = await response.json();
logger.debug(`[Onboarding] onboardUser response (attempt ${attempt + 1}):`, JSON.stringify(data));
// Check if onboarding is complete
const managedProjectId = data.response?.cloudaicompanionProject?.id;
if (data.done && managedProjectId) {
return managedProjectId;
}
if (data.done && projectId) {
return projectId;
}
// Not done yet, wait and retry
if (attempt < maxAttempts - 1) {
logger.debug(`[Onboarding] onboardUser not complete, waiting ${delayMs}ms...`);
await sleep(delayMs);
}
} catch (error) {
logger.warn(`[Onboarding] onboardUser error at ${endpoint}:`, error.message);
break; // Try next endpoint
}
}
}
logger.warn(`[Onboarding] All onboarding attempts failed for tierId: ${tierId}`);
return null;
}