mirror of
https://github.com/google-gemini/gemini-cli.git
synced 2026-04-10 13:22:51 -07:00
feat(billing): implement G1 AI credits overage flow with billing telemetry (#18590)
This commit is contained in:
255
packages/core/src/telemetry/billingEvents.ts
Normal file
255
packages/core/src/telemetry/billingEvents.ts
Normal file
@@ -0,0 +1,255 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright 2026 Google LLC
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
import type { Config } from '../config/config.js';
|
||||
import type { LogAttributes } from '@opentelemetry/api-logs';
|
||||
import type { BaseTelemetryEvent } from './types.js';
|
||||
import { getCommonAttributes } from './telemetryAttributes.js';
|
||||
import type { OverageStrategy } from '../billing/billing.js';
|
||||
|
||||
/** Overage menu option that can be selected by the user */
|
||||
export type OverageOption =
|
||||
| 'use_credits'
|
||||
| 'use_fallback'
|
||||
| 'manage'
|
||||
| 'stop'
|
||||
| 'get_credits';
|
||||
|
||||
// ============================================================================
|
||||
// Event: Overage Menu Shown
|
||||
// ============================================================================
|
||||
|
||||
export const EVENT_OVERAGE_MENU_SHOWN = 'gemini_cli.overage_menu_shown';
|
||||
|
||||
export class OverageMenuShownEvent implements BaseTelemetryEvent {
|
||||
'event.name': 'overage_menu_shown';
|
||||
'event.timestamp': string;
|
||||
model: string;
|
||||
credit_balance: number;
|
||||
overage_strategy: OverageStrategy;
|
||||
|
||||
constructor(
|
||||
model: string,
|
||||
creditBalance: number,
|
||||
overageStrategy: OverageStrategy,
|
||||
) {
|
||||
this['event.name'] = 'overage_menu_shown';
|
||||
this['event.timestamp'] = new Date().toISOString();
|
||||
this.model = model;
|
||||
this.credit_balance = creditBalance;
|
||||
this.overage_strategy = overageStrategy;
|
||||
}
|
||||
|
||||
toOpenTelemetryAttributes(config: Config): LogAttributes {
|
||||
return {
|
||||
...getCommonAttributes(config),
|
||||
'event.name': EVENT_OVERAGE_MENU_SHOWN,
|
||||
'event.timestamp': this['event.timestamp'],
|
||||
model: this.model,
|
||||
credit_balance: this.credit_balance,
|
||||
overage_strategy: this.overage_strategy,
|
||||
};
|
||||
}
|
||||
|
||||
toLogBody(): string {
|
||||
return `Overage menu shown for model ${this.model} with ${this.credit_balance} credits available.`;
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Event: Overage Option Selected
|
||||
// ============================================================================
|
||||
|
||||
export const EVENT_OVERAGE_OPTION_SELECTED =
|
||||
'gemini_cli.overage_option_selected';
|
||||
|
||||
export class OverageOptionSelectedEvent implements BaseTelemetryEvent {
|
||||
'event.name': 'overage_option_selected';
|
||||
'event.timestamp': string;
|
||||
model: string;
|
||||
selected_option: OverageOption;
|
||||
credit_balance: number;
|
||||
|
||||
constructor(
|
||||
model: string,
|
||||
selectedOption: OverageOption,
|
||||
creditBalance: number,
|
||||
) {
|
||||
this['event.name'] = 'overage_option_selected';
|
||||
this['event.timestamp'] = new Date().toISOString();
|
||||
this.model = model;
|
||||
this.selected_option = selectedOption;
|
||||
this.credit_balance = creditBalance;
|
||||
}
|
||||
|
||||
toOpenTelemetryAttributes(config: Config): LogAttributes {
|
||||
return {
|
||||
...getCommonAttributes(config),
|
||||
'event.name': EVENT_OVERAGE_OPTION_SELECTED,
|
||||
'event.timestamp': this['event.timestamp'],
|
||||
model: this.model,
|
||||
selected_option: this.selected_option,
|
||||
credit_balance: this.credit_balance,
|
||||
};
|
||||
}
|
||||
|
||||
toLogBody(): string {
|
||||
return `Overage option '${this.selected_option}' selected for model ${this.model}.`;
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Event: Empty Wallet Menu Shown
|
||||
// ============================================================================
|
||||
|
||||
export const EVENT_EMPTY_WALLET_MENU_SHOWN =
|
||||
'gemini_cli.empty_wallet_menu_shown';
|
||||
|
||||
export class EmptyWalletMenuShownEvent implements BaseTelemetryEvent {
|
||||
'event.name': 'empty_wallet_menu_shown';
|
||||
'event.timestamp': string;
|
||||
model: string;
|
||||
|
||||
constructor(model: string) {
|
||||
this['event.name'] = 'empty_wallet_menu_shown';
|
||||
this['event.timestamp'] = new Date().toISOString();
|
||||
this.model = model;
|
||||
}
|
||||
|
||||
toOpenTelemetryAttributes(config: Config): LogAttributes {
|
||||
return {
|
||||
...getCommonAttributes(config),
|
||||
'event.name': EVENT_EMPTY_WALLET_MENU_SHOWN,
|
||||
'event.timestamp': this['event.timestamp'],
|
||||
model: this.model,
|
||||
};
|
||||
}
|
||||
|
||||
toLogBody(): string {
|
||||
return `Empty wallet menu shown for model ${this.model}.`;
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Event: Credit Purchase Click
|
||||
// ============================================================================
|
||||
|
||||
export const EVENT_CREDIT_PURCHASE_CLICK = 'gemini_cli.credit_purchase_click';
|
||||
|
||||
export class CreditPurchaseClickEvent implements BaseTelemetryEvent {
|
||||
'event.name': 'credit_purchase_click';
|
||||
'event.timestamp': string;
|
||||
source: 'overage_menu' | 'empty_wallet_menu' | 'manage';
|
||||
model: string;
|
||||
|
||||
constructor(
|
||||
source: 'overage_menu' | 'empty_wallet_menu' | 'manage',
|
||||
model: string,
|
||||
) {
|
||||
this['event.name'] = 'credit_purchase_click';
|
||||
this['event.timestamp'] = new Date().toISOString();
|
||||
this.source = source;
|
||||
this.model = model;
|
||||
}
|
||||
|
||||
toOpenTelemetryAttributes(config: Config): LogAttributes {
|
||||
return {
|
||||
...getCommonAttributes(config),
|
||||
'event.name': EVENT_CREDIT_PURCHASE_CLICK,
|
||||
'event.timestamp': this['event.timestamp'],
|
||||
source: this.source,
|
||||
model: this.model,
|
||||
};
|
||||
}
|
||||
|
||||
toLogBody(): string {
|
||||
return `Credit purchase clicked from ${this.source} for model ${this.model}.`;
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Event: Credits Used
|
||||
// ============================================================================
|
||||
|
||||
export const EVENT_CREDITS_USED = 'gemini_cli.credits_used';
|
||||
|
||||
export class CreditsUsedEvent implements BaseTelemetryEvent {
|
||||
'event.name': 'credits_used';
|
||||
'event.timestamp': string;
|
||||
model: string;
|
||||
credits_consumed: number;
|
||||
credits_remaining: number;
|
||||
|
||||
constructor(
|
||||
model: string,
|
||||
creditsConsumed: number,
|
||||
creditsRemaining: number,
|
||||
) {
|
||||
this['event.name'] = 'credits_used';
|
||||
this['event.timestamp'] = new Date().toISOString();
|
||||
this.model = model;
|
||||
this.credits_consumed = creditsConsumed;
|
||||
this.credits_remaining = creditsRemaining;
|
||||
}
|
||||
|
||||
toOpenTelemetryAttributes(config: Config): LogAttributes {
|
||||
return {
|
||||
...getCommonAttributes(config),
|
||||
'event.name': EVENT_CREDITS_USED,
|
||||
'event.timestamp': this['event.timestamp'],
|
||||
model: this.model,
|
||||
credits_consumed: this.credits_consumed,
|
||||
credits_remaining: this.credits_remaining,
|
||||
};
|
||||
}
|
||||
|
||||
toLogBody(): string {
|
||||
return `${this.credits_consumed} credits consumed for model ${this.model}. ${this.credits_remaining} remaining.`;
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Event: API Key Updated (Auth Type Changed)
|
||||
// ============================================================================
|
||||
|
||||
export const EVENT_API_KEY_UPDATED = 'gemini_cli.api_key_updated';
|
||||
|
||||
export class ApiKeyUpdatedEvent implements BaseTelemetryEvent {
|
||||
'event.name': 'api_key_updated';
|
||||
'event.timestamp': string;
|
||||
previous_auth_type: string;
|
||||
new_auth_type: string;
|
||||
|
||||
constructor(previousAuthType: string, newAuthType: string) {
|
||||
this['event.name'] = 'api_key_updated';
|
||||
this['event.timestamp'] = new Date().toISOString();
|
||||
this.previous_auth_type = previousAuthType;
|
||||
this.new_auth_type = newAuthType;
|
||||
}
|
||||
|
||||
toOpenTelemetryAttributes(config: Config): LogAttributes {
|
||||
return {
|
||||
...getCommonAttributes(config),
|
||||
'event.name': EVENT_API_KEY_UPDATED,
|
||||
'event.timestamp': this['event.timestamp'],
|
||||
previous_auth_type: this.previous_auth_type,
|
||||
new_auth_type: this.new_auth_type,
|
||||
};
|
||||
}
|
||||
|
||||
toLogBody(): string {
|
||||
return `Auth type changed from ${this.previous_auth_type} to ${this.new_auth_type}.`;
|
||||
}
|
||||
}
|
||||
|
||||
/** Union type of all billing-related telemetry events */
|
||||
export type BillingTelemetryEvent =
|
||||
| OverageMenuShownEvent
|
||||
| OverageOptionSelectedEvent
|
||||
| EmptyWalletMenuShownEvent
|
||||
| CreditPurchaseClickEvent
|
||||
| CreditsUsedEvent
|
||||
| ApiKeyUpdatedEvent;
|
||||
Reference in New Issue
Block a user