feat(core): set up onboarding telemetry (#23118)

Co-authored-by: Yuna Seol <yunaseol@google.com>
This commit is contained in:
Yuna Seol
2026-03-20 21:15:47 -04:00
committed by GitHub
parent fc03891a11
commit 244a608186
14 changed files with 390 additions and 36 deletions
+26 -5
View File
@@ -15,11 +15,17 @@ import {
} from './types.js';
import { CodeAssistServer, type HttpOptions } from './server.js';
import type { AuthClient } from 'google-auth-library';
import type { ValidationHandler } from '../fallback/types.js';
import { ChangeAuthRequestedError } from '../utils/errors.js';
import { ValidationRequiredError } from '../utils/googleQuotaErrors.js';
import { debugLogger } from '../utils/debugLogger.js';
import { createCache, type CacheService } from '../utils/cache.js';
import type { Config } from '../config/config.js';
import {
logOnboardingStart,
logOnboardingSuccess,
OnboardingStartEvent,
OnboardingSuccessEvent,
} from '../telemetry/index.js';
export class ProjectIdRequiredError extends Error {
constructor() {
@@ -54,6 +60,7 @@ export interface UserData {
userTier: UserTierId;
userTierName?: string;
paidTier?: GeminiUserTier;
hasOnboardedPreviously?: boolean;
}
// Cache to store the results of setupUser to avoid redundant network calls.
@@ -94,7 +101,8 @@ export function resetUserDataCacheForTesting() {
* retry, auth change, or cancellation.
*
* @param client - The authenticated client to use for API calls
* @param validationHandler - Optional handler for account validation flow
* @param config - The CLI configuration
* @param httpOptions - Optional HTTP options
* @returns The user's project ID, tier ID, and tier name
* @throws {ValidationRequiredError} If account validation is required
* @throws {ProjectIdRequiredError} If no project ID is available and required
@@ -103,7 +111,7 @@ export function resetUserDataCacheForTesting() {
*/
export async function setupUser(
client: AuthClient,
validationHandler?: ValidationHandler,
config: Config,
httpOptions: HttpOptions = {},
): Promise<UserData> {
const projectId =
@@ -119,7 +127,7 @@ export async function setupUser(
);
return projectCache.getOrCreate(projectId, () =>
_doSetupUser(client, projectId, validationHandler, httpOptions),
_doSetupUser(client, projectId, config, httpOptions),
);
}
@@ -129,7 +137,7 @@ export async function setupUser(
async function _doSetupUser(
client: AuthClient,
projectId: string | undefined,
validationHandler?: ValidationHandler,
config: Config,
httpOptions: HttpOptions = {},
): Promise<UserData> {
const caServer = new CodeAssistServer(
@@ -146,6 +154,8 @@ async function _doSetupUser(
pluginType: 'GEMINI',
};
const validationHandler = config.getValidationHandler();
let loadRes: LoadCodeAssistResponse;
while (true) {
loadRes = await caServer.loadCodeAssist({
@@ -194,6 +204,8 @@ async function _doSetupUser(
UserTierId.STANDARD,
userTierName: loadRes.paidTier?.name ?? loadRes.currentTier.name,
paidTier: loadRes.paidTier ?? undefined,
hasOnboardedPreviously:
loadRes.currentTier.hasOnboardedPreviously ?? true,
};
}
@@ -206,6 +218,8 @@ async function _doSetupUser(
loadRes.paidTier?.id ?? loadRes.currentTier.id ?? UserTierId.STANDARD,
userTierName: loadRes.paidTier?.name ?? loadRes.currentTier.name,
paidTier: loadRes.paidTier ?? undefined,
hasOnboardedPreviously:
loadRes.currentTier.hasOnboardedPreviously ?? true,
};
}
@@ -236,6 +250,8 @@ async function _doSetupUser(
};
}
logOnboardingStart(config, new OnboardingStartEvent());
let lroRes = await caServer.onboardUser(onboardReq);
if (!lroRes.done && lroRes.name) {
const operationName = lroRes.name;
@@ -245,12 +261,16 @@ async function _doSetupUser(
}
}
const userTier = tier.id ?? UserTierId.STANDARD;
logOnboardingSuccess(config, new OnboardingSuccessEvent(userTier));
if (!lroRes.response?.cloudaicompanionProject?.id) {
if (projectId) {
return {
projectId,
userTier: tier.id ?? UserTierId.STANDARD,
userTierName: tier.name,
hasOnboardedPreviously: tier.hasOnboardedPreviously ?? false,
};
}
@@ -261,6 +281,7 @@ async function _doSetupUser(
projectId: lroRes.response.cloudaicompanionProject.id,
userTier: tier.id ?? UserTierId.STANDARD,
userTierName: tier.name,
hasOnboardedPreviously: tier.hasOnboardedPreviously ?? false,
};
}