@terminai/core 0.26.0 → 0.50.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (97) hide show
  1. package/LICENSE +247 -0
  2. package/README.md +422 -0
  3. package/dist/docs/CONTRIBUTING.md +8 -8
  4. package/dist/docs/changelogs/index.md +5 -5
  5. package/dist/docs/cli/commands.md +43 -17
  6. package/dist/docs/cli/quick-reference.md +61 -0
  7. package/dist/docs/cli/telemetry.md +3 -792
  8. package/dist/docs/extensions/index.md +1 -1
  9. package/dist/docs/get-started/configuration.md +6 -2
  10. package/dist/docs/index.md +17 -17
  11. package/dist/docs/{termai-comparison.md → terminai-comparison.md} +18 -18
  12. package/dist/docs/{termai-examples.md → terminai-examples.md} +2 -2
  13. package/dist/docs/{termai-operator-recipes.md → terminai-operator-recipes.md} +1 -1
  14. package/dist/docs/{termai-process-manager.md → terminai-process-manager.md} +7 -7
  15. package/dist/docs/{termai-quickstart.md → terminai-quickstart.md} +10 -10
  16. package/dist/docs/{termai-system.md → terminai-system.md} +2 -2
  17. package/dist/index.d.ts +0 -1
  18. package/dist/index.js +0 -1
  19. package/dist/index.js.map +1 -1
  20. package/dist/src/auth/wizardSettings.js +3 -0
  21. package/dist/src/auth/wizardSettings.js.map +1 -1
  22. package/dist/src/auth/wizardSettings.test.js +3 -0
  23. package/dist/src/auth/wizardSettings.test.js.map +1 -1
  24. package/dist/src/brain/__tests__/advisors.test.js +25 -6
  25. package/dist/src/brain/__tests__/advisors.test.js.map +1 -1
  26. package/dist/src/brain/__tests__/cognitiveArchitecture.test.js +24 -0
  27. package/dist/src/brain/__tests__/cognitiveArchitecture.test.js.map +1 -1
  28. package/dist/src/brain/__tests__/thinkingOrchestrator.test.js +29 -5
  29. package/dist/src/brain/__tests__/thinkingOrchestrator.test.js.map +1 -1
  30. package/dist/src/config/builder.js +4 -1
  31. package/dist/src/config/builder.js.map +1 -1
  32. package/dist/src/config/settings/loader.d.ts +1 -0
  33. package/dist/src/config/settings/loader.js +10 -0
  34. package/dist/src/config/settings/loader.js.map +1 -1
  35. package/dist/src/config/settings/schema.d.ts +2 -5
  36. package/dist/src/config/settings/schema.js +2 -3
  37. package/dist/src/config/settings/schema.js.map +1 -1
  38. package/dist/src/core/client.test.js +0 -2
  39. package/dist/src/core/client.test.js.map +1 -1
  40. package/dist/src/core/coreToolScheduler.test.js +1 -1
  41. package/dist/src/core/coreToolScheduler.test.js.map +1 -1
  42. package/dist/src/generated/git-commit.d.ts +2 -2
  43. package/dist/src/generated/git-commit.js +2 -2
  44. package/dist/src/generated/git-commit.js.map +1 -1
  45. package/dist/src/mcp/token-storage/hybrid-token-storage.d.ts +3 -0
  46. package/dist/src/mcp/token-storage/hybrid-token-storage.js +34 -13
  47. package/dist/src/mcp/token-storage/hybrid-token-storage.js.map +1 -1
  48. package/dist/src/mcp/token-storage/hybrid-token-storage.test.js +25 -0
  49. package/dist/src/mcp/token-storage/hybrid-token-storage.test.js.map +1 -1
  50. package/dist/src/openai_chatgpt/imports.test.js +17 -1
  51. package/dist/src/openai_chatgpt/imports.test.js.map +1 -1
  52. package/dist/src/telemetry/config.d.ts +1 -0
  53. package/dist/src/telemetry/config.js +3 -4
  54. package/dist/src/telemetry/config.js.map +1 -1
  55. package/dist/src/telemetry/config.test.js +6 -4
  56. package/dist/src/telemetry/config.test.js.map +1 -1
  57. package/dist/src/telemetry/index.d.ts +0 -2
  58. package/dist/src/telemetry/index.js +0 -2
  59. package/dist/src/telemetry/index.js.map +1 -1
  60. package/dist/src/telemetry/loggers.js +0 -36
  61. package/dist/src/telemetry/loggers.js.map +1 -1
  62. package/dist/src/telemetry/loggers.test.js +17 -1
  63. package/dist/src/telemetry/loggers.test.js.map +1 -1
  64. package/dist/src/telemetry/sdk.js +24 -19
  65. package/dist/src/telemetry/sdk.js.map +1 -1
  66. package/dist/src/telemetry/sdk.test.js +17 -135
  67. package/dist/src/telemetry/sdk.test.js.map +1 -1
  68. package/dist/src/tools/confirmation-policy.test.js +1 -1
  69. package/dist/src/tools/confirmation-policy.test.js.map +1 -1
  70. package/dist/src/utils/paths.js +7 -3
  71. package/dist/src/utils/paths.js.map +1 -1
  72. package/dist/src/utils/paths.test.js +31 -2
  73. package/dist/src/utils/paths.test.js.map +1 -1
  74. package/dist/src/utils/shell-permissions.test.js +4 -2
  75. package/dist/src/utils/shell-permissions.test.js.map +1 -1
  76. package/dist/src/utils/shell-utils.test.js +4 -2
  77. package/dist/src/utils/shell-utils.test.js.map +1 -1
  78. package/dist/tsconfig.tsbuildinfo +1 -1
  79. package/package.json +1 -5
  80. package/dist/src/telemetry/clearcut-logger/clearcut-logger.d.ts +0 -159
  81. package/dist/src/telemetry/clearcut-logger/clearcut-logger.js +0 -1210
  82. package/dist/src/telemetry/clearcut-logger/clearcut-logger.js.map +0 -1
  83. package/dist/src/telemetry/clearcut-logger/clearcut-logger.test.d.ts +0 -20
  84. package/dist/src/telemetry/clearcut-logger/clearcut-logger.test.js +0 -835
  85. package/dist/src/telemetry/clearcut-logger/clearcut-logger.test.js.map +0 -1
  86. package/dist/src/telemetry/clearcut-logger/event-metadata-key.d.ts +0 -140
  87. package/dist/src/telemetry/clearcut-logger/event-metadata-key.js +0 -350
  88. package/dist/src/telemetry/clearcut-logger/event-metadata-key.js.map +0 -1
  89. package/dist/src/telemetry/gcp-exporters.d.ts +0 -36
  90. package/dist/src/telemetry/gcp-exporters.js +0 -121
  91. package/dist/src/telemetry/gcp-exporters.js.map +0 -1
  92. package/dist/src/telemetry/gcp-exporters.test.d.ts +0 -7
  93. package/dist/src/telemetry/gcp-exporters.test.js +0 -319
  94. package/dist/src/telemetry/gcp-exporters.test.js.map +0 -1
  95. package/dist/src/telemetry/integration.test.circular.d.ts +0 -7
  96. package/dist/src/telemetry/integration.test.circular.js +0 -55
  97. package/dist/src/telemetry/integration.test.circular.js.map +0 -1
@@ -1,1210 +0,0 @@
1
- /**
2
- * @license
3
- * Copyright 2025 Google LLC
4
- * Portions Copyright 2025 TerminaI Authors
5
- * SPDX-License-Identifier: Apache-2.0
6
- */
7
- import { createHash } from 'node:crypto';
8
- import { HttpsProxyAgent } from 'https-proxy-agent';
9
- import { EventMetadataKey } from './event-metadata-key.js';
10
- import { InstallationManager } from '../../utils/installationManager.js';
11
- import { UserAccountManager } from '../../utils/userAccountManager.js';
12
- import { safeJsonStringify, safeJsonStringifyBooleanValuesOnly, } from '../../utils/safeJsonStringify.js';
13
- import { FixedDeque } from 'mnemonist';
14
- import { GIT_COMMIT_INFO, CLI_VERSION } from '../../generated/git-commit.js';
15
- import { IDE_DEFINITIONS, detectIdeFromEnv, isCloudShell, } from '../../ide/detect-ide.js';
16
- import { debugLogger } from '../../utils/debugLogger.js';
17
- export var EventNames;
18
- (function (EventNames) {
19
- EventNames["START_SESSION"] = "start_session";
20
- EventNames["NEW_PROMPT"] = "new_prompt";
21
- EventNames["TOOL_CALL"] = "tool_call";
22
- EventNames["FILE_OPERATION"] = "file_operation";
23
- EventNames["API_REQUEST"] = "api_request";
24
- EventNames["API_RESPONSE"] = "api_response";
25
- EventNames["API_ERROR"] = "api_error";
26
- EventNames["END_SESSION"] = "end_session";
27
- EventNames["FLASH_FALLBACK"] = "flash_fallback";
28
- EventNames["RIPGREP_FALLBACK"] = "ripgrep_fallback";
29
- EventNames["LOOP_DETECTED"] = "loop_detected";
30
- EventNames["LOOP_DETECTION_DISABLED"] = "loop_detection_disabled";
31
- EventNames["NEXT_SPEAKER_CHECK"] = "next_speaker_check";
32
- EventNames["SLASH_COMMAND"] = "slash_command";
33
- EventNames["MALFORMED_JSON_RESPONSE"] = "malformed_json_response";
34
- EventNames["IDE_CONNECTION"] = "ide_connection";
35
- EventNames["KITTY_SEQUENCE_OVERFLOW"] = "kitty_sequence_overflow";
36
- EventNames["CHAT_COMPRESSION"] = "chat_compression";
37
- EventNames["CONVERSATION_FINISHED"] = "conversation_finished";
38
- EventNames["INVALID_CHUNK"] = "invalid_chunk";
39
- EventNames["CONTENT_RETRY"] = "content_retry";
40
- EventNames["CONTENT_RETRY_FAILURE"] = "content_retry_failure";
41
- EventNames["EXTENSION_ENABLE"] = "extension_enable";
42
- EventNames["EXTENSION_DISABLE"] = "extension_disable";
43
- EventNames["EXTENSION_INSTALL"] = "extension_install";
44
- EventNames["EXTENSION_UNINSTALL"] = "extension_uninstall";
45
- EventNames["EXTENSION_UPDATE"] = "extension_update";
46
- EventNames["TOOL_OUTPUT_TRUNCATED"] = "tool_output_truncated";
47
- EventNames["MODEL_ROUTING"] = "model_routing";
48
- EventNames["MODEL_SLASH_COMMAND"] = "model_slash_command";
49
- EventNames["SMART_EDIT_STRATEGY"] = "smart_edit_strategy";
50
- EventNames["SMART_EDIT_CORRECTION"] = "smart_edit_correction";
51
- EventNames["AGENT_START"] = "agent_start";
52
- EventNames["AGENT_FINISH"] = "agent_finish";
53
- EventNames["RECOVERY_ATTEMPT"] = "recovery_attempt";
54
- EventNames["WEB_FETCH_FALLBACK_ATTEMPT"] = "web_fetch_fallback_attempt";
55
- EventNames["LLM_LOOP_CHECK"] = "llm_loop_check";
56
- })(EventNames || (EventNames = {}));
57
- /**
58
- * Determine the surface that the user is currently using. Surface is effectively the
59
- * distribution channel in which the user is using Gemini CLI. Gemini CLI comes bundled
60
- * w/ Firebase Studio and Cloud Shell. Users that manually download themselves will
61
- * likely be "SURFACE_NOT_SET".
62
- *
63
- * This is computed based upon a series of environment variables these distribution
64
- * methods might have in their runtimes.
65
- */
66
- function determineSurface() {
67
- if (process.env['SURFACE']) {
68
- return process.env['SURFACE'];
69
- }
70
- else if (isCloudShell()) {
71
- return IDE_DEFINITIONS.cloudshell.name;
72
- }
73
- else if (process.env['GITHUB_SHA']) {
74
- return 'GitHub';
75
- }
76
- else if (process.env['TERM_PROGRAM'] === 'vscode') {
77
- return detectIdeFromEnv().name || IDE_DEFINITIONS.vscode.name;
78
- }
79
- else {
80
- return 'SURFACE_NOT_SET';
81
- }
82
- }
83
- /**
84
- * Determines the GitHub Actions workflow name if the CLI is running in a GitHub Actions environment.
85
- */
86
- function determineGHWorkflowName() {
87
- return process.env['GH_WORKFLOW_NAME'];
88
- }
89
- /**
90
- * Determines the GitHub repository name if the CLI is running in a GitHub Actions environment.
91
- */
92
- function determineGHRepositoryName() {
93
- return process.env['GITHUB_REPOSITORY'];
94
- }
95
- /**
96
- * Clearcut URL to send logging events to.
97
- */
98
- const CLEARCUT_URL = 'https://play.googleapis.com/log?format=json&hasfast=true';
99
- /**
100
- * Interval in which buffered events are sent to clearcut.
101
- */
102
- const FLUSH_INTERVAL_MS = 1000 * 60;
103
- /**
104
- * Maximum amount of events to keep in memory. Events added after this amount
105
- * are dropped until the next flush to clearcut, which happens periodically as
106
- * defined by {@link FLUSH_INTERVAL_MS}.
107
- */
108
- const MAX_EVENTS = 1000;
109
- /**
110
- * Maximum events to retry after a failed clearcut flush
111
- */
112
- const MAX_RETRY_EVENTS = 100;
113
- // Singleton class for batch posting log events to Clearcut. When a new event comes in, the elapsed time
114
- // is checked and events are flushed to Clearcut if at least a minute has passed since the last flush.
115
- export class ClearcutLogger {
116
- // Singleton disabled for sovereign fork - keeping declaration for potential re-enablement
117
- // private static _instance: ClearcutLogger;
118
- config;
119
- sessionData = [];
120
- promptId = '';
121
- installationManager;
122
- userAccountManager;
123
- hashedGHRepositoryName;
124
- /**
125
- * Queue of pending events that need to be flushed to the server. New events
126
- * are added to this queue and then flushed on demand (via `flushToClearcut`)
127
- */
128
- events;
129
- /**
130
- * The last time that the events were successfully flushed to the server.
131
- */
132
- lastFlushTime = Date.now();
133
- /**
134
- * the value is true when there is a pending flush happening. This prevents
135
- * concurrent flush operations.
136
- */
137
- flushing = false;
138
- /**
139
- * This value is true when a flush was requested during an ongoing flush.
140
- */
141
- pendingFlush = false;
142
- constructor(config) {
143
- this.config = config;
144
- this.events = new FixedDeque(Array, MAX_EVENTS);
145
- this.promptId = config?.getSessionId() ?? '';
146
- this.installationManager = new InstallationManager();
147
- this.userAccountManager = new UserAccountManager();
148
- const ghRepositoryName = determineGHRepositoryName();
149
- if (ghRepositoryName) {
150
- this.hashedGHRepositoryName = createHash('sha256')
151
- .update(ghRepositoryName)
152
- .digest('hex');
153
- }
154
- }
155
- static getInstance(_config) {
156
- // Disabled for sovereign fork
157
- return undefined;
158
- }
159
- /** For testing purposes only. */
160
- static clearInstance() {
161
- // Disabled for sovereign fork - singleton not used
162
- // ClearcutLogger._instance = undefined;
163
- }
164
- enqueueHelper(event) {
165
- // Manually handle overflow for FixedDeque, which throws when full.
166
- const wasAtCapacity = this.events.size >= MAX_EVENTS;
167
- if (wasAtCapacity) {
168
- this.events.shift(); // Evict oldest element to make space.
169
- }
170
- this.events.push([
171
- {
172
- event_time_ms: Date.now(),
173
- source_extension_json: safeJsonStringify(event),
174
- },
175
- ]);
176
- if (wasAtCapacity && this.config?.getDebugMode()) {
177
- debugLogger.debug(`ClearcutLogger: Dropped old event to prevent memory leak (queue size: ${this.events.size})`);
178
- }
179
- }
180
- enqueueLogEvent(event) {
181
- try {
182
- this.enqueueHelper(event);
183
- }
184
- catch (error) {
185
- if (this.config?.getDebugMode()) {
186
- console.error('ClearcutLogger: Failed to enqueue log event.', error);
187
- }
188
- }
189
- }
190
- async enqueueLogEventAfterExperimentsLoadAsync(event) {
191
- try {
192
- // eslint-disable-next-line @typescript-eslint/no-floating-promises
193
- this.config?.getExperimentsAsync().then((experiments) => {
194
- if (experiments) {
195
- const exp_id_data = [
196
- {
197
- gemini_cli_key: EventMetadataKey.GEMINI_CLI_EXPERIMENT_IDS,
198
- value: experiments.experimentIds.toString() ?? 'NA',
199
- },
200
- ];
201
- event.event_metadata = [[...event.event_metadata[0], ...exp_id_data]];
202
- }
203
- this.enqueueHelper(event);
204
- });
205
- }
206
- catch (error) {
207
- if (this.config?.getDebugMode()) {
208
- console.error('ClearcutLogger: Failed to enqueue log event.', error);
209
- }
210
- }
211
- }
212
- createBasicLogEvent(eventName, data = []) {
213
- const email = this.userAccountManager.getCachedGoogleAccount();
214
- const surface = determineSurface();
215
- const ghWorkflowName = determineGHWorkflowName();
216
- const baseMetadata = [
217
- ...data,
218
- {
219
- gemini_cli_key: EventMetadataKey.GEMINI_CLI_SURFACE,
220
- value: surface,
221
- },
222
- {
223
- gemini_cli_key: EventMetadataKey.GEMINI_CLI_VERSION,
224
- value: CLI_VERSION,
225
- },
226
- {
227
- gemini_cli_key: EventMetadataKey.GEMINI_CLI_GIT_COMMIT_HASH,
228
- value: GIT_COMMIT_INFO,
229
- },
230
- {
231
- gemini_cli_key: EventMetadataKey.GEMINI_CLI_OS,
232
- value: process.platform,
233
- },
234
- ];
235
- if (ghWorkflowName) {
236
- baseMetadata.push({
237
- gemini_cli_key: EventMetadataKey.GEMINI_CLI_GH_WORKFLOW_NAME,
238
- value: ghWorkflowName,
239
- });
240
- }
241
- if (this.hashedGHRepositoryName) {
242
- baseMetadata.push({
243
- gemini_cli_key: EventMetadataKey.GEMINI_CLI_GH_REPOSITORY_NAME_HASH,
244
- value: this.hashedGHRepositoryName,
245
- });
246
- }
247
- const logEvent = {
248
- console_type: 'GEMINI_CLI',
249
- application: 102, // GEMINI_CLI
250
- event_name: eventName,
251
- event_metadata: [baseMetadata],
252
- };
253
- // Should log either email or install ID, not both. See go/cloudmill-1p-oss-instrumentation#define-sessionable-id
254
- if (email) {
255
- logEvent.client_email = email;
256
- }
257
- else {
258
- logEvent.client_install_id = this.installationManager.getInstallationId();
259
- }
260
- return logEvent;
261
- }
262
- createLogEvent(eventName, data = []) {
263
- if (eventName !== EventNames.START_SESSION) {
264
- data.push(...this.sessionData);
265
- }
266
- const totalAccounts = this.userAccountManager.getLifetimeGoogleAccounts();
267
- data = this.addDefaultFields(data, totalAccounts);
268
- return this.createBasicLogEvent(eventName, data);
269
- }
270
- flushIfNeeded() {
271
- if (Date.now() - this.lastFlushTime < FLUSH_INTERVAL_MS) {
272
- return;
273
- }
274
- this.flushToClearcut().catch((error) => {
275
- debugLogger.debug('Error flushing to Clearcut:', error);
276
- });
277
- }
278
- async flushToClearcut() {
279
- if (this.flushing) {
280
- if (this.config?.getDebugMode()) {
281
- debugLogger.debug('ClearcutLogger: Flush already in progress, marking pending flush.');
282
- }
283
- this.pendingFlush = true;
284
- return Promise.resolve({});
285
- }
286
- this.flushing = true;
287
- if (this.config?.getDebugMode()) {
288
- debugLogger.log('Flushing log events to Clearcut.');
289
- }
290
- const eventsToSend = this.events.toArray();
291
- this.events.clear();
292
- const request = [
293
- {
294
- log_source_name: 'CONCORD',
295
- request_time_ms: Date.now(),
296
- log_event: eventsToSend,
297
- },
298
- ];
299
- let result = {};
300
- try {
301
- const response = await fetch(CLEARCUT_URL, {
302
- method: 'POST',
303
- body: safeJsonStringify(request),
304
- headers: {
305
- 'Content-Type': 'application/json',
306
- },
307
- });
308
- const responseBody = await response.text();
309
- if (response.status >= 200 && response.status < 300) {
310
- this.lastFlushTime = Date.now();
311
- const nextRequestWaitMs = Number(JSON.parse(responseBody)[0]);
312
- result = {
313
- ...result,
314
- nextRequestWaitMs,
315
- };
316
- }
317
- else {
318
- if (this.config?.getDebugMode()) {
319
- console.error(`Error flushing log events: HTTP ${response.status}: ${response.statusText}`);
320
- }
321
- // Re-queue failed events for retry
322
- this.requeueFailedEvents(eventsToSend);
323
- }
324
- }
325
- catch (e) {
326
- if (this.config?.getDebugMode()) {
327
- console.error('Error flushing log events:', e);
328
- }
329
- // Re-queue failed events for retry
330
- this.requeueFailedEvents(eventsToSend);
331
- }
332
- this.flushing = false;
333
- // If a flush was requested while we were flushing, flush again
334
- if (this.pendingFlush) {
335
- this.pendingFlush = false;
336
- // Fire and forget the pending flush
337
- this.flushToClearcut().catch((error) => {
338
- if (this.config?.getDebugMode()) {
339
- debugLogger.debug('Error in pending flush to Clearcut:', error);
340
- }
341
- });
342
- }
343
- return result;
344
- }
345
- logStartSessionEvent(event) {
346
- const data = [
347
- {
348
- gemini_cli_key: EventMetadataKey.GEMINI_CLI_START_SESSION_MODEL,
349
- value: event.model,
350
- },
351
- {
352
- gemini_cli_key: EventMetadataKey.GEMINI_CLI_START_SESSION_EMBEDDING_MODEL,
353
- value: event.embedding_model,
354
- },
355
- {
356
- gemini_cli_key: EventMetadataKey.GEMINI_CLI_START_SESSION_SANDBOX,
357
- value: event.sandbox_enabled.toString(),
358
- },
359
- {
360
- gemini_cli_key: EventMetadataKey.GEMINI_CLI_START_SESSION_CORE_TOOLS,
361
- value: event.core_tools_enabled,
362
- },
363
- {
364
- gemini_cli_key: EventMetadataKey.GEMINI_CLI_START_SESSION_APPROVAL_MODE,
365
- value: event.approval_mode,
366
- },
367
- {
368
- gemini_cli_key: EventMetadataKey.GEMINI_CLI_START_SESSION_API_KEY_ENABLED,
369
- value: event.api_key_enabled.toString(),
370
- },
371
- {
372
- gemini_cli_key: EventMetadataKey.GEMINI_CLI_START_SESSION_VERTEX_API_ENABLED,
373
- value: event.vertex_ai_enabled.toString(),
374
- },
375
- {
376
- gemini_cli_key: EventMetadataKey.GEMINI_CLI_START_SESSION_DEBUG_MODE_ENABLED,
377
- value: event.debug_enabled.toString(),
378
- },
379
- {
380
- gemini_cli_key: EventMetadataKey.GEMINI_CLI_START_SESSION_VERTEX_API_ENABLED,
381
- value: event.vertex_ai_enabled.toString(),
382
- },
383
- {
384
- gemini_cli_key: EventMetadataKey.GEMINI_CLI_START_SESSION_MCP_SERVERS,
385
- value: event.mcp_servers,
386
- },
387
- {
388
- gemini_cli_key: EventMetadataKey.GEMINI_CLI_START_SESSION_VERTEX_API_ENABLED,
389
- value: event.vertex_ai_enabled.toString(),
390
- },
391
- {
392
- gemini_cli_key: EventMetadataKey.GEMINI_CLI_START_SESSION_TELEMETRY_ENABLED,
393
- value: event.telemetry_enabled.toString(),
394
- },
395
- {
396
- gemini_cli_key: EventMetadataKey.GEMINI_CLI_START_SESSION_TELEMETRY_LOG_USER_PROMPTS_ENABLED,
397
- value: event.telemetry_log_user_prompts_enabled.toString(),
398
- },
399
- {
400
- gemini_cli_key: EventMetadataKey.GEMINI_CLI_START_SESSION_MCP_SERVERS_COUNT,
401
- value: event.mcp_servers_count
402
- ? event.mcp_servers_count.toString()
403
- : '',
404
- },
405
- {
406
- gemini_cli_key: EventMetadataKey.GEMINI_CLI_START_SESSION_MCP_TOOLS_COUNT,
407
- value: event.mcp_tools_count?.toString() ?? '',
408
- },
409
- {
410
- gemini_cli_key: EventMetadataKey.GEMINI_CLI_START_SESSION_MCP_TOOLS,
411
- value: event.mcp_tools ? event.mcp_tools : '',
412
- },
413
- {
414
- gemini_cli_key: EventMetadataKey.GEMINI_CLI_START_SESSION_EXTENSIONS_COUNT,
415
- value: event.extensions_count.toString(),
416
- },
417
- // We deliberately do not log the names of extensions here, to be safe.
418
- {
419
- gemini_cli_key: EventMetadataKey.GEMINI_CLI_START_SESSION_EXTENSION_IDS,
420
- value: event.extension_ids.toString(),
421
- },
422
- ];
423
- this.sessionData = data;
424
- // Flush after experiments finish loading from CCPA server
425
- // eslint-disable-next-line @typescript-eslint/no-floating-promises
426
- this.enqueueLogEventAfterExperimentsLoadAsync(this.createLogEvent(EventNames.START_SESSION, data)).then(() => {
427
- this.flushToClearcut().catch((error) => {
428
- debugLogger.debug('Error flushing to Clearcut:', error);
429
- });
430
- });
431
- }
432
- logNewPromptEvent(event) {
433
- this.promptId = event.prompt_id;
434
- const data = [
435
- {
436
- gemini_cli_key: EventMetadataKey.GEMINI_CLI_USER_PROMPT_LENGTH,
437
- value: JSON.stringify(event.prompt_length),
438
- },
439
- ];
440
- this.enqueueLogEvent(this.createLogEvent(EventNames.NEW_PROMPT, data));
441
- this.flushIfNeeded();
442
- }
443
- logToolCallEvent(event) {
444
- const data = [
445
- {
446
- gemini_cli_key: EventMetadataKey.GEMINI_CLI_TOOL_CALL_NAME,
447
- value: JSON.stringify(event.function_name),
448
- },
449
- {
450
- gemini_cli_key: EventMetadataKey.GEMINI_CLI_TOOL_CALL_DECISION,
451
- value: JSON.stringify(event.decision),
452
- },
453
- {
454
- gemini_cli_key: EventMetadataKey.GEMINI_CLI_TOOL_CALL_SUCCESS,
455
- value: JSON.stringify(event.success),
456
- },
457
- {
458
- gemini_cli_key: EventMetadataKey.GEMINI_CLI_TOOL_CALL_DURATION_MS,
459
- value: JSON.stringify(event.duration_ms),
460
- },
461
- {
462
- gemini_cli_key: EventMetadataKey.GEMINI_CLI_TOOL_CALL_ERROR_TYPE,
463
- value: JSON.stringify(event.error_type),
464
- },
465
- {
466
- gemini_cli_key: EventMetadataKey.GEMINI_CLI_TOOL_TYPE,
467
- value: JSON.stringify(event.tool_type),
468
- },
469
- {
470
- gemini_cli_key: EventMetadataKey.GEMINI_CLI_TOOL_CALL_CONTENT_LENGTH,
471
- value: JSON.stringify(event.content_length),
472
- },
473
- {
474
- gemini_cli_key: EventMetadataKey.GEMINI_CLI_TOOL_CALL_MCP_SERVER_NAME,
475
- value: JSON.stringify(event.mcp_server_name),
476
- },
477
- ];
478
- if (event.metadata) {
479
- const metadataMapping = {
480
- model_added_lines: EventMetadataKey.GEMINI_CLI_AI_ADDED_LINES,
481
- model_removed_lines: EventMetadataKey.GEMINI_CLI_AI_REMOVED_LINES,
482
- model_added_chars: EventMetadataKey.GEMINI_CLI_AI_ADDED_CHARS,
483
- model_removed_chars: EventMetadataKey.GEMINI_CLI_AI_REMOVED_CHARS,
484
- user_added_lines: EventMetadataKey.GEMINI_CLI_USER_ADDED_LINES,
485
- user_removed_lines: EventMetadataKey.GEMINI_CLI_USER_REMOVED_LINES,
486
- user_added_chars: EventMetadataKey.GEMINI_CLI_USER_ADDED_CHARS,
487
- user_removed_chars: EventMetadataKey.GEMINI_CLI_USER_REMOVED_CHARS,
488
- };
489
- for (const [key, gemini_cli_key] of Object.entries(metadataMapping)) {
490
- if (event.metadata[key] !== undefined) {
491
- data.push({
492
- gemini_cli_key,
493
- value: JSON.stringify(event.metadata[key]),
494
- });
495
- }
496
- }
497
- }
498
- if (event.extension_id) {
499
- data.push({
500
- gemini_cli_key: EventMetadataKey.GEMINI_CLI_EXTENSION_ID,
501
- value: event.extension_id,
502
- });
503
- }
504
- const logEvent = this.createLogEvent(EventNames.TOOL_CALL, data);
505
- this.enqueueLogEvent(logEvent);
506
- this.flushIfNeeded();
507
- }
508
- logFileOperationEvent(event) {
509
- const data = [
510
- {
511
- gemini_cli_key: EventMetadataKey.GEMINI_CLI_TOOL_CALL_NAME,
512
- value: JSON.stringify(event.tool_name),
513
- },
514
- {
515
- gemini_cli_key: EventMetadataKey.GEMINI_CLI_FILE_OPERATION_TYPE,
516
- value: JSON.stringify(event.operation),
517
- },
518
- {
519
- gemini_cli_key: EventMetadataKey.GEMINI_CLI_FILE_OPERATION_LINES,
520
- value: JSON.stringify(event.lines),
521
- },
522
- {
523
- gemini_cli_key: EventMetadataKey.GEMINI_CLI_FILE_OPERATION_MIMETYPE,
524
- value: JSON.stringify(event.mimetype),
525
- },
526
- {
527
- gemini_cli_key: EventMetadataKey.GEMINI_CLI_FILE_OPERATION_EXTENSION,
528
- value: JSON.stringify(event.extension),
529
- },
530
- ];
531
- if (event.programming_language) {
532
- data.push({
533
- gemini_cli_key: EventMetadataKey.GEMINI_CLI_PROGRAMMING_LANGUAGE,
534
- value: event.programming_language,
535
- });
536
- }
537
- const logEvent = this.createLogEvent(EventNames.FILE_OPERATION, data);
538
- this.enqueueLogEvent(logEvent);
539
- this.flushIfNeeded();
540
- }
541
- logApiRequestEvent(event) {
542
- const data = [
543
- {
544
- gemini_cli_key: EventMetadataKey.GEMINI_CLI_API_REQUEST_MODEL,
545
- value: JSON.stringify(event.model),
546
- },
547
- ];
548
- this.enqueueLogEvent(this.createLogEvent(EventNames.API_REQUEST, data));
549
- this.flushIfNeeded();
550
- }
551
- logApiResponseEvent(event) {
552
- const data = [
553
- {
554
- gemini_cli_key: EventMetadataKey.GEMINI_CLI_API_RESPONSE_MODEL,
555
- value: JSON.stringify(event.model),
556
- },
557
- {
558
- gemini_cli_key: EventMetadataKey.GEMINI_CLI_API_RESPONSE_STATUS_CODE,
559
- value: JSON.stringify(event.status_code),
560
- },
561
- {
562
- gemini_cli_key: EventMetadataKey.GEMINI_CLI_API_RESPONSE_DURATION_MS,
563
- value: JSON.stringify(event.duration_ms),
564
- },
565
- {
566
- gemini_cli_key: EventMetadataKey.GEMINI_CLI_API_RESPONSE_INPUT_TOKEN_COUNT,
567
- value: JSON.stringify(event.usage.input_token_count),
568
- },
569
- {
570
- gemini_cli_key: EventMetadataKey.GEMINI_CLI_API_RESPONSE_OUTPUT_TOKEN_COUNT,
571
- value: JSON.stringify(event.usage.output_token_count),
572
- },
573
- {
574
- gemini_cli_key: EventMetadataKey.GEMINI_CLI_API_RESPONSE_CACHED_TOKEN_COUNT,
575
- value: JSON.stringify(event.usage.cached_content_token_count),
576
- },
577
- {
578
- gemini_cli_key: EventMetadataKey.GEMINI_CLI_API_RESPONSE_THINKING_TOKEN_COUNT,
579
- value: JSON.stringify(event.usage.thoughts_token_count),
580
- },
581
- {
582
- gemini_cli_key: EventMetadataKey.GEMINI_CLI_API_RESPONSE_TOOL_TOKEN_COUNT,
583
- value: JSON.stringify(event.usage.tool_token_count),
584
- },
585
- ];
586
- this.enqueueLogEvent(this.createLogEvent(EventNames.API_RESPONSE, data));
587
- this.flushIfNeeded();
588
- }
589
- logApiErrorEvent(event) {
590
- const data = [
591
- {
592
- gemini_cli_key: EventMetadataKey.GEMINI_CLI_API_ERROR_MODEL,
593
- value: JSON.stringify(event.model),
594
- },
595
- {
596
- gemini_cli_key: EventMetadataKey.GEMINI_CLI_API_ERROR_TYPE,
597
- value: JSON.stringify(event.error_type),
598
- },
599
- {
600
- gemini_cli_key: EventMetadataKey.GEMINI_CLI_API_ERROR_STATUS_CODE,
601
- value: JSON.stringify(event.status_code),
602
- },
603
- {
604
- gemini_cli_key: EventMetadataKey.GEMINI_CLI_API_ERROR_DURATION_MS,
605
- value: JSON.stringify(event.duration_ms),
606
- },
607
- ];
608
- this.enqueueLogEvent(this.createLogEvent(EventNames.API_ERROR, data));
609
- this.flushIfNeeded();
610
- }
611
- logChatCompressionEvent(event) {
612
- const data = [
613
- {
614
- gemini_cli_key: EventMetadataKey.GEMINI_CLI_COMPRESSION_TOKENS_BEFORE,
615
- value: `${event.tokens_before}`,
616
- },
617
- {
618
- gemini_cli_key: EventMetadataKey.GEMINI_CLI_COMPRESSION_TOKENS_AFTER,
619
- value: `${event.tokens_after}`,
620
- },
621
- ];
622
- this.enqueueLogEvent(this.createLogEvent(EventNames.CHAT_COMPRESSION, data));
623
- }
624
- logFlashFallbackEvent() {
625
- this.enqueueLogEvent(this.createLogEvent(EventNames.FLASH_FALLBACK, []));
626
- this.flushToClearcut().catch((error) => {
627
- debugLogger.debug('Error flushing to Clearcut:', error);
628
- });
629
- }
630
- logRipgrepFallbackEvent() {
631
- this.enqueueLogEvent(this.createLogEvent(EventNames.RIPGREP_FALLBACK, []));
632
- this.flushToClearcut().catch((error) => {
633
- debugLogger.debug('Error flushing to Clearcut:', error);
634
- });
635
- }
636
- logLoopDetectedEvent(event) {
637
- const data = [
638
- {
639
- gemini_cli_key: EventMetadataKey.GEMINI_CLI_LOOP_DETECTED_TYPE,
640
- value: JSON.stringify(event.loop_type),
641
- },
642
- ];
643
- if (event.confirmed_by_model) {
644
- data.push({
645
- gemini_cli_key: EventMetadataKey.GEMINI_CLI_LOOP_DETECTED_CONFIRMED_BY_MODEL,
646
- value: event.confirmed_by_model,
647
- });
648
- }
649
- this.enqueueLogEvent(this.createLogEvent(EventNames.LOOP_DETECTED, data));
650
- this.flushIfNeeded();
651
- }
652
- logLoopDetectionDisabledEvent() {
653
- const data = [];
654
- this.enqueueLogEvent(this.createLogEvent(EventNames.LOOP_DETECTION_DISABLED, data));
655
- this.flushIfNeeded();
656
- }
657
- logNextSpeakerCheck(event) {
658
- const data = [
659
- {
660
- gemini_cli_key: EventMetadataKey.GEMINI_CLI_RESPONSE_FINISH_REASON,
661
- value: JSON.stringify(event.finish_reason),
662
- },
663
- {
664
- gemini_cli_key: EventMetadataKey.GEMINI_CLI_NEXT_SPEAKER_CHECK_RESULT,
665
- value: JSON.stringify(event.result),
666
- },
667
- ];
668
- this.enqueueLogEvent(this.createLogEvent(EventNames.NEXT_SPEAKER_CHECK, data));
669
- this.flushIfNeeded();
670
- }
671
- logSlashCommandEvent(event) {
672
- const data = [
673
- {
674
- gemini_cli_key: EventMetadataKey.GEMINI_CLI_SLASH_COMMAND_NAME,
675
- value: JSON.stringify(event.command),
676
- },
677
- ];
678
- if (event.subcommand) {
679
- data.push({
680
- gemini_cli_key: EventMetadataKey.GEMINI_CLI_SLASH_COMMAND_SUBCOMMAND,
681
- value: JSON.stringify(event.subcommand),
682
- });
683
- }
684
- if (event.status) {
685
- data.push({
686
- gemini_cli_key: EventMetadataKey.GEMINI_CLI_SLASH_COMMAND_STATUS,
687
- value: JSON.stringify(event.status),
688
- });
689
- }
690
- if (event.extension_id) {
691
- data.push({
692
- gemini_cli_key: EventMetadataKey.GEMINI_CLI_EXTENSION_ID,
693
- value: event.extension_id,
694
- });
695
- }
696
- this.enqueueLogEvent(this.createLogEvent(EventNames.SLASH_COMMAND, data));
697
- this.flushIfNeeded();
698
- }
699
- logMalformedJsonResponseEvent(event) {
700
- const data = [
701
- {
702
- gemini_cli_key: EventMetadataKey.GEMINI_CLI_MALFORMED_JSON_RESPONSE_MODEL,
703
- value: JSON.stringify(event.model),
704
- },
705
- ];
706
- this.enqueueLogEvent(this.createLogEvent(EventNames.MALFORMED_JSON_RESPONSE, data));
707
- this.flushIfNeeded();
708
- }
709
- logIdeConnectionEvent(event) {
710
- const data = [
711
- {
712
- gemini_cli_key: EventMetadataKey.GEMINI_CLI_IDE_CONNECTION_TYPE,
713
- value: JSON.stringify(event.connection_type),
714
- },
715
- ];
716
- // Flush after experiments finish loading from CCPA server
717
- // eslint-disable-next-line @typescript-eslint/no-floating-promises
718
- this.enqueueLogEventAfterExperimentsLoadAsync(this.createLogEvent(EventNames.START_SESSION, data)).then(() => {
719
- this.flushToClearcut().catch((error) => {
720
- debugLogger.debug('Error flushing to Clearcut:', error);
721
- });
722
- });
723
- }
724
- logConversationFinishedEvent(event) {
725
- const data = [
726
- {
727
- gemini_cli_key: EventMetadataKey.GEMINI_CLI_SESSION_ID,
728
- value: this.config?.getSessionId() ?? '',
729
- },
730
- {
731
- gemini_cli_key: EventMetadataKey.GEMINI_CLI_CONVERSATION_TURN_COUNT,
732
- value: JSON.stringify(event.turnCount),
733
- },
734
- {
735
- gemini_cli_key: EventMetadataKey.GEMINI_CLI_APPROVAL_MODE,
736
- value: event.approvalMode,
737
- },
738
- ];
739
- this.enqueueLogEvent(this.createLogEvent(EventNames.CONVERSATION_FINISHED, data));
740
- this.flushIfNeeded();
741
- }
742
- logEndSessionEvent() {
743
- // Flush immediately on session end.
744
- this.enqueueLogEvent(this.createLogEvent(EventNames.END_SESSION, []));
745
- this.flushToClearcut().catch((error) => {
746
- debugLogger.debug('Error flushing to Clearcut:', error);
747
- });
748
- }
749
- logInvalidChunkEvent(event) {
750
- const data = [];
751
- if (event.error_message) {
752
- data.push({
753
- gemini_cli_key: EventMetadataKey.GEMINI_CLI_INVALID_CHUNK_ERROR_MESSAGE,
754
- value: event.error_message,
755
- });
756
- }
757
- this.enqueueLogEvent(this.createLogEvent(EventNames.INVALID_CHUNK, data));
758
- this.flushIfNeeded();
759
- }
760
- logContentRetryEvent(event) {
761
- const data = [
762
- {
763
- gemini_cli_key: EventMetadataKey.GEMINI_CLI_CONTENT_RETRY_ATTEMPT_NUMBER,
764
- value: String(event.attempt_number),
765
- },
766
- {
767
- gemini_cli_key: EventMetadataKey.GEMINI_CLI_CONTENT_RETRY_ERROR_TYPE,
768
- value: event.error_type,
769
- },
770
- {
771
- gemini_cli_key: EventMetadataKey.GEMINI_CLI_CONTENT_RETRY_DELAY_MS,
772
- value: String(event.retry_delay_ms),
773
- },
774
- {
775
- gemini_cli_key: EventMetadataKey.GEMINI_CLI_API_REQUEST_MODEL,
776
- value: event.model,
777
- },
778
- ];
779
- this.enqueueLogEvent(this.createLogEvent(EventNames.CONTENT_RETRY, data));
780
- this.flushIfNeeded();
781
- }
782
- logContentRetryFailureEvent(event) {
783
- const data = [
784
- {
785
- gemini_cli_key: EventMetadataKey.GEMINI_CLI_CONTENT_RETRY_FAILURE_TOTAL_ATTEMPTS,
786
- value: String(event.total_attempts),
787
- },
788
- {
789
- gemini_cli_key: EventMetadataKey.GEMINI_CLI_CONTENT_RETRY_FAILURE_FINAL_ERROR_TYPE,
790
- value: event.final_error_type,
791
- },
792
- {
793
- gemini_cli_key: EventMetadataKey.GEMINI_CLI_API_REQUEST_MODEL,
794
- value: event.model,
795
- },
796
- ];
797
- if (event.total_duration_ms) {
798
- data.push({
799
- gemini_cli_key: EventMetadataKey.GEMINI_CLI_CONTENT_RETRY_FAILURE_TOTAL_DURATION_MS,
800
- value: String(event.total_duration_ms),
801
- });
802
- }
803
- this.enqueueLogEvent(this.createLogEvent(EventNames.CONTENT_RETRY_FAILURE, data));
804
- this.flushIfNeeded();
805
- }
806
- async logExtensionInstallEvent(event) {
807
- const data = [
808
- {
809
- gemini_cli_key: EventMetadataKey.GEMINI_CLI_EXTENSION_NAME,
810
- value: event.hashed_extension_name,
811
- },
812
- {
813
- gemini_cli_key: EventMetadataKey.GEMINI_CLI_EXTENSION_ID,
814
- value: event.extension_id,
815
- },
816
- {
817
- gemini_cli_key: EventMetadataKey.GEMINI_CLI_EXTENSION_VERSION,
818
- value: event.extension_version,
819
- },
820
- {
821
- gemini_cli_key: EventMetadataKey.GEMINI_CLI_EXTENSION_SOURCE,
822
- value: event.extension_source,
823
- },
824
- {
825
- gemini_cli_key: EventMetadataKey.GEMINI_CLI_EXTENSION_INSTALL_STATUS,
826
- value: event.status,
827
- },
828
- ];
829
- this.enqueueLogEvent(this.createBasicLogEvent(EventNames.EXTENSION_INSTALL, data));
830
- await this.flushToClearcut().catch((error) => {
831
- debugLogger.debug('Error flushing to Clearcut:', error);
832
- });
833
- }
834
- async logExtensionUninstallEvent(event) {
835
- const data = [
836
- {
837
- gemini_cli_key: EventMetadataKey.GEMINI_CLI_EXTENSION_NAME,
838
- value: event.hashed_extension_name,
839
- },
840
- {
841
- gemini_cli_key: EventMetadataKey.GEMINI_CLI_EXTENSION_ID,
842
- value: event.extension_id,
843
- },
844
- {
845
- gemini_cli_key: EventMetadataKey.GEMINI_CLI_EXTENSION_UNINSTALL_STATUS,
846
- value: event.status,
847
- },
848
- ];
849
- this.enqueueLogEvent(this.createBasicLogEvent(EventNames.EXTENSION_UNINSTALL, data));
850
- await this.flushToClearcut().catch((error) => {
851
- debugLogger.debug('Error flushing to Clearcut:', error);
852
- });
853
- }
854
- async logExtensionUpdateEvent(event) {
855
- const data = [
856
- {
857
- gemini_cli_key: EventMetadataKey.GEMINI_CLI_EXTENSION_NAME,
858
- value: event.hashed_extension_name,
859
- },
860
- {
861
- gemini_cli_key: EventMetadataKey.GEMINI_CLI_EXTENSION_ID,
862
- value: event.extension_id,
863
- },
864
- {
865
- gemini_cli_key: EventMetadataKey.GEMINI_CLI_EXTENSION_VERSION,
866
- value: event.extension_version,
867
- },
868
- {
869
- gemini_cli_key: EventMetadataKey.GEMINI_CLI_EXTENSION_PREVIOUS_VERSION,
870
- value: event.extension_previous_version,
871
- },
872
- {
873
- gemini_cli_key: EventMetadataKey.GEMINI_CLI_EXTENSION_SOURCE,
874
- value: event.extension_source,
875
- },
876
- {
877
- gemini_cli_key: EventMetadataKey.GEMINI_CLI_EXTENSION_UPDATE_STATUS,
878
- value: event.status,
879
- },
880
- ];
881
- this.enqueueLogEvent(this.createBasicLogEvent(EventNames.EXTENSION_UPDATE, data));
882
- await this.flushToClearcut().catch((error) => {
883
- debugLogger.debug('Error flushing to Clearcut:', error);
884
- });
885
- }
886
- logToolOutputTruncatedEvent(event) {
887
- const data = [
888
- {
889
- gemini_cli_key: EventMetadataKey.GEMINI_CLI_TOOL_CALL_NAME,
890
- value: JSON.stringify(event.tool_name),
891
- },
892
- {
893
- gemini_cli_key: EventMetadataKey.GEMINI_CLI_TOOL_OUTPUT_TRUNCATED_ORIGINAL_LENGTH,
894
- value: JSON.stringify(event.original_content_length),
895
- },
896
- {
897
- gemini_cli_key: EventMetadataKey.GEMINI_CLI_TOOL_OUTPUT_TRUNCATED_TRUNCATED_LENGTH,
898
- value: JSON.stringify(event.truncated_content_length),
899
- },
900
- {
901
- gemini_cli_key: EventMetadataKey.GEMINI_CLI_TOOL_OUTPUT_TRUNCATED_THRESHOLD,
902
- value: JSON.stringify(event.threshold),
903
- },
904
- {
905
- gemini_cli_key: EventMetadataKey.GEMINI_CLI_TOOL_OUTPUT_TRUNCATED_LINES,
906
- value: JSON.stringify(event.lines),
907
- },
908
- ];
909
- this.enqueueLogEvent(this.createLogEvent(EventNames.TOOL_OUTPUT_TRUNCATED, data));
910
- this.flushIfNeeded();
911
- }
912
- logModelRoutingEvent(event) {
913
- const data = [
914
- {
915
- gemini_cli_key: EventMetadataKey.GEMINI_CLI_ROUTING_DECISION,
916
- value: event.decision_model,
917
- },
918
- {
919
- gemini_cli_key: EventMetadataKey.GEMINI_CLI_ROUTING_DECISION_SOURCE,
920
- value: event.decision_source,
921
- },
922
- {
923
- gemini_cli_key: EventMetadataKey.GEMINI_CLI_ROUTING_LATENCY_MS,
924
- value: event.routing_latency_ms.toString(),
925
- },
926
- {
927
- gemini_cli_key: EventMetadataKey.GEMINI_CLI_ROUTING_FAILURE,
928
- value: event.failed.toString(),
929
- },
930
- ];
931
- if (event.error_message) {
932
- data.push({
933
- gemini_cli_key: EventMetadataKey.GEMINI_CLI_ROUTING_FAILURE_REASON,
934
- value: event.error_message,
935
- });
936
- }
937
- this.enqueueLogEvent(this.createLogEvent(EventNames.MODEL_ROUTING, data));
938
- this.flushIfNeeded();
939
- }
940
- async logExtensionEnableEvent(event) {
941
- const data = [
942
- {
943
- gemini_cli_key: EventMetadataKey.GEMINI_CLI_EXTENSION_NAME,
944
- value: event.hashed_extension_name,
945
- },
946
- {
947
- gemini_cli_key: EventMetadataKey.GEMINI_CLI_EXTENSION_ID,
948
- value: event.extension_id,
949
- },
950
- {
951
- gemini_cli_key: EventMetadataKey.GEMINI_CLI_EXTENSION_ENABLE_SETTING_SCOPE,
952
- value: event.setting_scope,
953
- },
954
- ];
955
- this.enqueueLogEvent(this.createBasicLogEvent(EventNames.EXTENSION_ENABLE, data));
956
- await this.flushToClearcut().catch((error) => {
957
- debugLogger.debug('Error flushing to Clearcut:', error);
958
- });
959
- }
960
- logModelSlashCommandEvent(event) {
961
- const data = [
962
- {
963
- gemini_cli_key: EventMetadataKey.GEMINI_CLI_MODEL_SLASH_COMMAND,
964
- value: event.model_name,
965
- },
966
- ];
967
- this.enqueueLogEvent(this.createLogEvent(EventNames.MODEL_SLASH_COMMAND, data));
968
- this.flushIfNeeded();
969
- }
970
- async logExtensionDisableEvent(event) {
971
- const data = [
972
- {
973
- gemini_cli_key: EventMetadataKey.GEMINI_CLI_EXTENSION_NAME,
974
- value: event.hashed_extension_name,
975
- },
976
- {
977
- gemini_cli_key: EventMetadataKey.GEMINI_CLI_EXTENSION_ID,
978
- value: event.extension_id,
979
- },
980
- {
981
- gemini_cli_key: EventMetadataKey.GEMINI_CLI_EXTENSION_DISABLE_SETTING_SCOPE,
982
- value: event.setting_scope,
983
- },
984
- ];
985
- this.enqueueLogEvent(this.createBasicLogEvent(EventNames.EXTENSION_DISABLE, data));
986
- await this.flushToClearcut().catch((error) => {
987
- debugLogger.debug('Error flushing to Clearcut:', error);
988
- });
989
- }
990
- logSmartEditStrategyEvent(event) {
991
- const data = [
992
- {
993
- gemini_cli_key: EventMetadataKey.GEMINI_CLI_SMART_EDIT_STRATEGY,
994
- value: event.strategy,
995
- },
996
- ];
997
- this.enqueueLogEvent(this.createLogEvent(EventNames.SMART_EDIT_STRATEGY, data));
998
- this.flushIfNeeded();
999
- }
1000
- logSmartEditCorrectionEvent(event) {
1001
- const data = [
1002
- {
1003
- gemini_cli_key: EventMetadataKey.GEMINI_CLI_SMART_EDIT_CORRECTION,
1004
- value: event.correction,
1005
- },
1006
- ];
1007
- this.enqueueLogEvent(this.createLogEvent(EventNames.SMART_EDIT_CORRECTION, data));
1008
- this.flushIfNeeded();
1009
- }
1010
- logAgentStartEvent(event) {
1011
- const data = [
1012
- {
1013
- gemini_cli_key: EventMetadataKey.GEMINI_CLI_AGENT_ID,
1014
- value: event.agent_id,
1015
- },
1016
- {
1017
- gemini_cli_key: EventMetadataKey.GEMINI_CLI_AGENT_NAME,
1018
- value: event.agent_name,
1019
- },
1020
- ];
1021
- this.enqueueLogEvent(this.createLogEvent(EventNames.AGENT_START, data));
1022
- this.flushIfNeeded();
1023
- }
1024
- logAgentFinishEvent(event) {
1025
- const data = [
1026
- {
1027
- gemini_cli_key: EventMetadataKey.GEMINI_CLI_AGENT_ID,
1028
- value: event.agent_id,
1029
- },
1030
- {
1031
- gemini_cli_key: EventMetadataKey.GEMINI_CLI_AGENT_NAME,
1032
- value: event.agent_name,
1033
- },
1034
- {
1035
- gemini_cli_key: EventMetadataKey.GEMINI_CLI_AGENT_DURATION_MS,
1036
- value: event.duration_ms.toString(),
1037
- },
1038
- {
1039
- gemini_cli_key: EventMetadataKey.GEMINI_CLI_AGENT_TURN_COUNT,
1040
- value: event.turn_count.toString(),
1041
- },
1042
- {
1043
- gemini_cli_key: EventMetadataKey.GEMINI_CLI_AGENT_TERMINATE_REASON,
1044
- value: event.terminate_reason,
1045
- },
1046
- ];
1047
- this.enqueueLogEvent(this.createLogEvent(EventNames.AGENT_FINISH, data));
1048
- this.flushIfNeeded();
1049
- }
1050
- logRecoveryAttemptEvent(event) {
1051
- const data = [
1052
- {
1053
- gemini_cli_key: EventMetadataKey.GEMINI_CLI_AGENT_ID,
1054
- value: event.agent_id,
1055
- },
1056
- {
1057
- gemini_cli_key: EventMetadataKey.GEMINI_CLI_AGENT_NAME,
1058
- value: event.agent_name,
1059
- },
1060
- {
1061
- gemini_cli_key: EventMetadataKey.GEMINI_CLI_AGENT_RECOVERY_REASON,
1062
- value: event.reason,
1063
- },
1064
- {
1065
- gemini_cli_key: EventMetadataKey.GEMINI_CLI_AGENT_RECOVERY_DURATION_MS,
1066
- value: event.duration_ms.toString(),
1067
- },
1068
- {
1069
- gemini_cli_key: EventMetadataKey.GEMINI_CLI_AGENT_RECOVERY_SUCCESS,
1070
- value: event.success.toString(),
1071
- },
1072
- {
1073
- gemini_cli_key: EventMetadataKey.GEMINI_CLI_AGENT_TURN_COUNT,
1074
- value: event.turn_count.toString(),
1075
- },
1076
- ];
1077
- this.enqueueLogEvent(this.createLogEvent(EventNames.RECOVERY_ATTEMPT, data));
1078
- this.flushIfNeeded();
1079
- }
1080
- logWebFetchFallbackAttemptEvent(event) {
1081
- const data = [
1082
- {
1083
- gemini_cli_key: EventMetadataKey.GEMINI_CLI_WEB_FETCH_FALLBACK_REASON,
1084
- value: event.reason,
1085
- },
1086
- ];
1087
- this.enqueueLogEvent(this.createLogEvent(EventNames.WEB_FETCH_FALLBACK_ATTEMPT, data));
1088
- this.flushIfNeeded();
1089
- }
1090
- logLlmLoopCheckEvent(event) {
1091
- const data = [
1092
- {
1093
- gemini_cli_key: EventMetadataKey.GEMINI_CLI_PROMPT_ID,
1094
- value: event.prompt_id,
1095
- },
1096
- {
1097
- gemini_cli_key: EventMetadataKey.GEMINI_CLI_LLM_LOOP_CHECK_FLASH_CONFIDENCE,
1098
- value: event.flash_confidence.toString(),
1099
- },
1100
- {
1101
- gemini_cli_key: EventMetadataKey.GEMINI_CLI_LLM_LOOP_CHECK_MAIN_MODEL,
1102
- value: event.main_model,
1103
- },
1104
- {
1105
- gemini_cli_key: EventMetadataKey.GEMINI_CLI_LLM_LOOP_CHECK_MAIN_MODEL_CONFIDENCE,
1106
- value: event.main_model_confidence.toString(),
1107
- },
1108
- ];
1109
- this.enqueueLogEvent(this.createLogEvent(EventNames.LLM_LOOP_CHECK, data));
1110
- this.flushIfNeeded();
1111
- }
1112
- /**
1113
- * Adds default fields to data, and returns a new data array. This fields
1114
- * should exist on all log events.
1115
- */
1116
- addDefaultFields(data, totalAccounts) {
1117
- const defaultLogMetadata = [
1118
- {
1119
- gemini_cli_key: EventMetadataKey.GEMINI_CLI_SESSION_ID,
1120
- value: this.config?.getSessionId() ?? '',
1121
- },
1122
- {
1123
- gemini_cli_key: EventMetadataKey.GEMINI_CLI_AUTH_TYPE,
1124
- value: JSON.stringify(this.config?.getContentGeneratorConfig()?.authType),
1125
- },
1126
- {
1127
- gemini_cli_key: EventMetadataKey.GEMINI_CLI_GOOGLE_ACCOUNTS_COUNT,
1128
- value: `${totalAccounts}`,
1129
- },
1130
- {
1131
- gemini_cli_key: EventMetadataKey.GEMINI_CLI_PROMPT_ID,
1132
- value: this.promptId,
1133
- },
1134
- {
1135
- gemini_cli_key: EventMetadataKey.GEMINI_CLI_NODE_VERSION,
1136
- value: process.versions.node,
1137
- },
1138
- {
1139
- gemini_cli_key: EventMetadataKey.GEMINI_CLI_USER_SETTINGS,
1140
- value: this.getConfigJson(),
1141
- },
1142
- {
1143
- gemini_cli_key: EventMetadataKey.GEMINI_CLI_INTERACTIVE,
1144
- value: this.config?.isInteractive().toString() ?? 'false',
1145
- },
1146
- ];
1147
- if (this.config?.getExperiments()) {
1148
- defaultLogMetadata.push({
1149
- gemini_cli_key: EventMetadataKey.GEMINI_CLI_EXPERIMENT_IDS,
1150
- value: this.config?.getExperiments()?.experimentIds.toString() ?? 'NA',
1151
- });
1152
- }
1153
- return [...data, ...defaultLogMetadata];
1154
- }
1155
- getProxyAgent() {
1156
- const proxyUrl = this.config?.getProxy();
1157
- if (!proxyUrl)
1158
- return undefined;
1159
- // undici which is widely used in the repo can only support http & https proxy protocol,
1160
- // https://github.com/nodejs/undici/issues/2224
1161
- if (proxyUrl.startsWith('http')) {
1162
- return new HttpsProxyAgent(proxyUrl);
1163
- }
1164
- else {
1165
- throw new Error('Unsupported proxy type');
1166
- }
1167
- }
1168
- getConfigJson() {
1169
- return safeJsonStringifyBooleanValuesOnly(this.config);
1170
- }
1171
- shutdown() {
1172
- this.logEndSessionEvent();
1173
- }
1174
- requeueFailedEvents(eventsToSend) {
1175
- // Add the events back to the front of the queue to be retried, but limit retry queue size
1176
- const eventsToRetry = eventsToSend.slice(-MAX_RETRY_EVENTS); // Keep only the most recent events
1177
- // Log a warning if we're dropping events
1178
- if (eventsToSend.length > MAX_RETRY_EVENTS && this.config?.getDebugMode()) {
1179
- debugLogger.warn(`ClearcutLogger: Dropping ${eventsToSend.length - MAX_RETRY_EVENTS} events due to retry queue limit. Total events: ${eventsToSend.length}, keeping: ${MAX_RETRY_EVENTS}`);
1180
- }
1181
- // Determine how many events can be re-queued
1182
- const availableSpace = MAX_EVENTS - this.events.size;
1183
- const numEventsToRequeue = Math.min(eventsToRetry.length, availableSpace);
1184
- if (numEventsToRequeue === 0) {
1185
- if (this.config?.getDebugMode()) {
1186
- debugLogger.debug(`ClearcutLogger: No events re-queued (queue size: ${this.events.size})`);
1187
- }
1188
- return;
1189
- }
1190
- // Get the most recent events to re-queue
1191
- const eventsToRequeue = eventsToRetry.slice(eventsToRetry.length - numEventsToRequeue);
1192
- // Prepend events to the front of the deque to be retried first.
1193
- // We iterate backwards to maintain the original order of the failed events.
1194
- for (let i = eventsToRequeue.length - 1; i >= 0; i--) {
1195
- this.events.unshift(eventsToRequeue[i]);
1196
- }
1197
- // Clear any potential overflow
1198
- while (this.events.size > MAX_EVENTS) {
1199
- this.events.pop();
1200
- }
1201
- if (this.config?.getDebugMode()) {
1202
- debugLogger.debug(`ClearcutLogger: Re-queued ${numEventsToRequeue} events for retry (queue size: ${this.events.size})`);
1203
- }
1204
- }
1205
- }
1206
- export const TEST_ONLY = {
1207
- MAX_RETRY_EVENTS,
1208
- MAX_EVENTS,
1209
- };
1210
- //# sourceMappingURL=clearcut-logger.js.map