@google/gemini-cli-core 0.9.0-nightly.20250926.1487841d → 0.9.0-nightly.20251001.33269bdb

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 (164) hide show
  1. package/dist/src/agents/codebase-investigator.d.ts +11 -0
  2. package/dist/src/agents/codebase-investigator.js +164 -0
  3. package/dist/src/agents/codebase-investigator.js.map +1 -0
  4. package/dist/src/agents/executor.d.ts +96 -0
  5. package/dist/src/agents/executor.js +438 -0
  6. package/dist/src/agents/executor.js.map +1 -0
  7. package/dist/src/agents/executor.test.d.ts +6 -0
  8. package/dist/src/agents/executor.test.js +492 -0
  9. package/dist/src/agents/executor.test.js.map +1 -0
  10. package/dist/src/agents/invocation.d.ts +45 -0
  11. package/dist/src/agents/invocation.js +101 -0
  12. package/dist/src/agents/invocation.js.map +1 -0
  13. package/dist/src/agents/invocation.test.d.ts +6 -0
  14. package/dist/src/agents/invocation.test.js +214 -0
  15. package/dist/src/agents/invocation.test.js.map +1 -0
  16. package/dist/src/agents/registry.d.ts +35 -0
  17. package/dist/src/agents/registry.js +58 -0
  18. package/dist/src/agents/registry.js.map +1 -0
  19. package/dist/src/agents/registry.test.d.ts +6 -0
  20. package/dist/src/agents/registry.test.js +146 -0
  21. package/dist/src/agents/registry.test.js.map +1 -0
  22. package/dist/src/agents/schema-utils.d.ts +39 -0
  23. package/dist/src/agents/schema-utils.js +57 -0
  24. package/dist/src/agents/schema-utils.js.map +1 -0
  25. package/dist/src/agents/schema-utils.test.d.ts +6 -0
  26. package/dist/src/agents/schema-utils.test.js +144 -0
  27. package/dist/src/agents/schema-utils.test.js.map +1 -0
  28. package/dist/src/agents/subagent-tool-wrapper.d.ts +38 -0
  29. package/dist/src/agents/subagent-tool-wrapper.js +48 -0
  30. package/dist/src/agents/subagent-tool-wrapper.js.map +1 -0
  31. package/dist/src/agents/subagent-tool-wrapper.test.d.ts +6 -0
  32. package/dist/src/agents/subagent-tool-wrapper.test.js +112 -0
  33. package/dist/src/agents/subagent-tool-wrapper.test.js.map +1 -0
  34. package/dist/src/agents/types.d.ts +123 -0
  35. package/dist/src/agents/types.js +17 -0
  36. package/dist/src/agents/types.js.map +1 -0
  37. package/dist/src/agents/utils.d.ts +15 -0
  38. package/dist/src/agents/utils.js +29 -0
  39. package/dist/src/agents/utils.js.map +1 -0
  40. package/dist/src/agents/utils.test.d.ts +6 -0
  41. package/dist/src/agents/utils.test.js +87 -0
  42. package/dist/src/agents/utils.test.js.map +1 -0
  43. package/dist/src/config/config.d.ts +11 -2
  44. package/dist/src/config/config.js +49 -3
  45. package/dist/src/config/config.js.map +1 -1
  46. package/dist/src/config/config.test.js +63 -0
  47. package/dist/src/config/config.test.js.map +1 -1
  48. package/dist/src/core/baseLlmClient.js +19 -21
  49. package/dist/src/core/baseLlmClient.js.map +1 -1
  50. package/dist/src/core/baseLlmClient.test.js +57 -17
  51. package/dist/src/core/baseLlmClient.test.js.map +1 -1
  52. package/dist/src/core/client.js +8 -29
  53. package/dist/src/core/client.js.map +1 -1
  54. package/dist/src/core/client.test.js +223 -94
  55. package/dist/src/core/client.test.js.map +1 -1
  56. package/dist/src/core/coreToolScheduler.test.js +33 -23
  57. package/dist/src/core/coreToolScheduler.test.js.map +1 -1
  58. package/dist/src/core/geminiChat.js +1 -1
  59. package/dist/src/core/geminiChat.js.map +1 -1
  60. package/dist/src/core/geminiChat.test.js +2 -1
  61. package/dist/src/core/geminiChat.test.js.map +1 -1
  62. package/dist/src/core/nonInteractiveToolExecutor.test.js +11 -11
  63. package/dist/src/core/nonInteractiveToolExecutor.test.js.map +1 -1
  64. package/dist/src/generated/git-commit.d.ts +2 -2
  65. package/dist/src/generated/git-commit.js +2 -2
  66. package/dist/src/ide/detect-ide.d.ts +1 -0
  67. package/dist/src/ide/detect-ide.js +4 -1
  68. package/dist/src/ide/detect-ide.js.map +1 -1
  69. package/dist/src/mcp/sa-impersonation-provider.d.ts +33 -0
  70. package/dist/src/mcp/sa-impersonation-provider.js +130 -0
  71. package/dist/src/mcp/sa-impersonation-provider.js.map +1 -0
  72. package/dist/src/mcp/sa-impersonation-provider.test.d.ts +6 -0
  73. package/dist/src/mcp/sa-impersonation-provider.test.js +117 -0
  74. package/dist/src/mcp/sa-impersonation-provider.test.js.map +1 -0
  75. package/dist/src/services/fileSystemService.d.ts +9 -0
  76. package/dist/src/services/fileSystemService.js +11 -0
  77. package/dist/src/services/fileSystemService.js.map +1 -1
  78. package/dist/src/services/shellExecutionService.d.ts +2 -0
  79. package/dist/src/services/shellExecutionService.js +48 -7
  80. package/dist/src/services/shellExecutionService.js.map +1 -1
  81. package/dist/src/services/shellExecutionService.test.js +13 -4
  82. package/dist/src/services/shellExecutionService.test.js.map +1 -1
  83. package/dist/src/telemetry/clearcut-logger/clearcut-logger.d.ts +4 -2
  84. package/dist/src/telemetry/clearcut-logger/clearcut-logger.js +15 -1
  85. package/dist/src/telemetry/clearcut-logger/clearcut-logger.js.map +1 -1
  86. package/dist/src/telemetry/clearcut-logger/clearcut-logger.test.js +18 -0
  87. package/dist/src/telemetry/clearcut-logger/clearcut-logger.test.js.map +1 -1
  88. package/dist/src/telemetry/clearcut-logger/event-metadata-key.d.ts +2 -1
  89. package/dist/src/telemetry/clearcut-logger/event-metadata-key.js +2 -0
  90. package/dist/src/telemetry/clearcut-logger/event-metadata-key.js.map +1 -1
  91. package/dist/src/telemetry/constants.d.ts +1 -24
  92. package/dist/src/telemetry/constants.js +1 -25
  93. package/dist/src/telemetry/constants.js.map +1 -1
  94. package/dist/src/telemetry/index.d.ts +1 -1
  95. package/dist/src/telemetry/index.js +7 -1
  96. package/dist/src/telemetry/index.js.map +1 -1
  97. package/dist/src/telemetry/loggers.d.ts +2 -1
  98. package/dist/src/telemetry/loggers.js +66 -11
  99. package/dist/src/telemetry/loggers.js.map +1 -1
  100. package/dist/src/telemetry/loggers.test.circular.js +3 -3
  101. package/dist/src/telemetry/loggers.test.circular.js.map +1 -1
  102. package/dist/src/telemetry/loggers.test.js +76 -9
  103. package/dist/src/telemetry/loggers.test.js.map +1 -1
  104. package/dist/src/telemetry/metrics.d.ts +363 -19
  105. package/dist/src/telemetry/metrics.js +415 -235
  106. package/dist/src/telemetry/metrics.js.map +1 -1
  107. package/dist/src/telemetry/metrics.test.js +352 -54
  108. package/dist/src/telemetry/metrics.test.js.map +1 -1
  109. package/dist/src/telemetry/types.d.ts +6 -0
  110. package/dist/src/telemetry/types.js +10 -0
  111. package/dist/src/telemetry/types.js.map +1 -1
  112. package/dist/src/telemetry/uiTelemetry.test.js +2 -2
  113. package/dist/src/telemetry/uiTelemetry.test.js.map +1 -1
  114. package/dist/src/test-utils/mock-tool.d.ts +28 -3
  115. package/dist/src/test-utils/mock-tool.js +71 -1
  116. package/dist/src/test-utils/mock-tool.js.map +1 -1
  117. package/dist/src/tools/glob.js +2 -1
  118. package/dist/src/tools/glob.js.map +1 -1
  119. package/dist/src/tools/mcp-client.js +16 -0
  120. package/dist/src/tools/mcp-client.js.map +1 -1
  121. package/dist/src/tools/shell.js +1 -54
  122. package/dist/src/tools/shell.js.map +1 -1
  123. package/dist/src/tools/shell.test.js +0 -1
  124. package/dist/src/tools/shell.test.js.map +1 -1
  125. package/dist/src/tools/smart-edit.d.ts +20 -1
  126. package/dist/src/tools/smart-edit.js +114 -4
  127. package/dist/src/tools/smart-edit.js.map +1 -1
  128. package/dist/src/tools/smart-edit.test.js +90 -6
  129. package/dist/src/tools/smart-edit.test.js.map +1 -1
  130. package/dist/src/tools/tool-names.d.ts +6 -0
  131. package/dist/src/tools/tool-names.js +15 -0
  132. package/dist/src/tools/tool-names.js.map +1 -0
  133. package/dist/src/tools/tool-registry.test.js +10 -10
  134. package/dist/src/tools/tool-registry.test.js.map +1 -1
  135. package/dist/src/utils/flashFallback.test.js +2 -2
  136. package/dist/src/utils/flashFallback.test.js.map +1 -1
  137. package/dist/src/utils/llm-edit-fixer.js +10 -1
  138. package/dist/src/utils/llm-edit-fixer.js.map +1 -1
  139. package/dist/src/utils/llm-edit-fixer.test.js +81 -0
  140. package/dist/src/utils/llm-edit-fixer.test.js.map +1 -1
  141. package/dist/src/utils/memoryImportProcessor.js +13 -20
  142. package/dist/src/utils/memoryImportProcessor.js.map +1 -1
  143. package/dist/src/utils/memoryImportProcessor.test.js +14 -0
  144. package/dist/src/utils/memoryImportProcessor.test.js.map +1 -1
  145. package/dist/src/utils/retry.d.ts +3 -1
  146. package/dist/src/utils/retry.js +13 -4
  147. package/dist/src/utils/retry.js.map +1 -1
  148. package/dist/src/utils/retry.test.js +2 -2
  149. package/dist/src/utils/retry.test.js.map +1 -1
  150. package/dist/src/utils/shell-utils.d.ts +0 -1
  151. package/dist/src/utils/shell-utils.js +1 -1
  152. package/dist/src/utils/shell-utils.js.map +1 -1
  153. package/dist/src/utils/terminalSerializer.d.ts +1 -4
  154. package/dist/src/utils/terminalSerializer.js +3 -3
  155. package/dist/src/utils/terminalSerializer.js.map +1 -1
  156. package/dist/src/utils/tool-utils.js +2 -2
  157. package/dist/src/utils/tool-utils.js.map +1 -1
  158. package/dist/src/utils/tool-utils.test.js +0 -8
  159. package/dist/src/utils/tool-utils.test.js.map +1 -1
  160. package/dist/tsconfig.tsbuildinfo +1 -1
  161. package/package.json +1 -1
  162. package/dist/src/test-utils/tools.d.ts +0 -45
  163. package/dist/src/test-utils/tools.js +0 -105
  164. package/dist/src/test-utils/tools.js.map +0 -1
@@ -34,6 +34,11 @@ function originalOtelMockFactory() {
34
34
  setLogger: vi.fn(),
35
35
  warn: vi.fn(),
36
36
  },
37
+ DiagConsoleLogger: vi.fn(),
38
+ DiagLogLevel: {
39
+ NONE: 0,
40
+ INFO: 1,
41
+ },
37
42
  };
38
43
  }
39
44
  vi.mock('@opentelemetry/api');
@@ -53,6 +58,8 @@ describe('Telemetry Metrics', () => {
53
58
  let recordPerformanceScoreModule;
54
59
  let recordPerformanceRegressionModule;
55
60
  let recordBaselineComparisonModule;
61
+ let recordGenAiClientTokenUsageModule;
62
+ let recordGenAiClientOperationDurationModule;
56
63
  beforeEach(async () => {
57
64
  vi.resetModules();
58
65
  vi.doMock('@opentelemetry/api', () => {
@@ -79,6 +86,10 @@ describe('Telemetry Metrics', () => {
79
86
  recordPerformanceRegressionModule =
80
87
  metricsJsModule.recordPerformanceRegression;
81
88
  recordBaselineComparisonModule = metricsJsModule.recordBaselineComparison;
89
+ recordGenAiClientTokenUsageModule =
90
+ metricsJsModule.recordGenAiClientTokenUsage;
91
+ recordGenAiClientOperationDurationModule =
92
+ metricsJsModule.recordGenAiClientOperationDuration;
82
93
  const otelApiModule = await import('@opentelemetry/api');
83
94
  mockCounterAddFn.mockClear();
84
95
  mockCreateCounterFn.mockClear();
@@ -118,12 +129,18 @@ describe('Telemetry Metrics', () => {
118
129
  getTelemetryEnabled: () => true,
119
130
  };
120
131
  it('should not record metrics if not initialized', () => {
121
- recordTokenUsageMetricsModule(mockConfig, 'gemini-pro', 100, 'input');
132
+ recordTokenUsageMetricsModule(mockConfig, 100, {
133
+ model: 'gemini-pro',
134
+ type: 'input',
135
+ });
122
136
  expect(mockCounterAddFn).not.toHaveBeenCalled();
123
137
  });
124
138
  it('should record token usage with the correct attributes', () => {
125
139
  initializeMetricsModule(mockConfig);
126
- recordTokenUsageMetricsModule(mockConfig, 'gemini-pro', 100, 'input');
140
+ recordTokenUsageMetricsModule(mockConfig, 100, {
141
+ model: 'gemini-pro',
142
+ type: 'input',
143
+ });
127
144
  expect(mockCounterAddFn).toHaveBeenCalledTimes(2);
128
145
  expect(mockCounterAddFn).toHaveBeenNthCalledWith(1, 1, {
129
146
  'session.id': 'test-session-id',
@@ -137,25 +154,37 @@ describe('Telemetry Metrics', () => {
137
154
  it('should record token usage for different types', () => {
138
155
  initializeMetricsModule(mockConfig);
139
156
  mockCounterAddFn.mockClear();
140
- recordTokenUsageMetricsModule(mockConfig, 'gemini-pro', 50, 'output');
157
+ recordTokenUsageMetricsModule(mockConfig, 50, {
158
+ model: 'gemini-pro',
159
+ type: 'output',
160
+ });
141
161
  expect(mockCounterAddFn).toHaveBeenCalledWith(50, {
142
162
  'session.id': 'test-session-id',
143
163
  model: 'gemini-pro',
144
164
  type: 'output',
145
165
  });
146
- recordTokenUsageMetricsModule(mockConfig, 'gemini-pro', 25, 'thought');
166
+ recordTokenUsageMetricsModule(mockConfig, 25, {
167
+ model: 'gemini-pro',
168
+ type: 'thought',
169
+ });
147
170
  expect(mockCounterAddFn).toHaveBeenCalledWith(25, {
148
171
  'session.id': 'test-session-id',
149
172
  model: 'gemini-pro',
150
173
  type: 'thought',
151
174
  });
152
- recordTokenUsageMetricsModule(mockConfig, 'gemini-pro', 75, 'cache');
175
+ recordTokenUsageMetricsModule(mockConfig, 75, {
176
+ model: 'gemini-pro',
177
+ type: 'cache',
178
+ });
153
179
  expect(mockCounterAddFn).toHaveBeenCalledWith(75, {
154
180
  'session.id': 'test-session-id',
155
181
  model: 'gemini-pro',
156
182
  type: 'cache',
157
183
  });
158
- recordTokenUsageMetricsModule(mockConfig, 'gemini-pro', 125, 'tool');
184
+ recordTokenUsageMetricsModule(mockConfig, 125, {
185
+ model: 'gemini-pro',
186
+ type: 'tool',
187
+ });
159
188
  expect(mockCounterAddFn).toHaveBeenCalledWith(125, {
160
189
  'session.id': 'test-session-id',
161
190
  model: 'gemini-pro',
@@ -165,7 +194,10 @@ describe('Telemetry Metrics', () => {
165
194
  it('should handle different models', () => {
166
195
  initializeMetricsModule(mockConfig);
167
196
  mockCounterAddFn.mockClear();
168
- recordTokenUsageMetricsModule(mockConfig, 'gemini-ultra', 200, 'input');
197
+ recordTokenUsageMetricsModule(mockConfig, 200, {
198
+ model: 'gemini-ultra',
199
+ type: 'input',
200
+ });
169
201
  expect(mockCounterAddFn).toHaveBeenCalledWith(200, {
170
202
  'session.id': 'test-session-id',
171
203
  model: 'gemini-ultra',
@@ -179,12 +211,22 @@ describe('Telemetry Metrics', () => {
179
211
  getTelemetryEnabled: () => true,
180
212
  };
181
213
  it('should not record metrics if not initialized', () => {
182
- recordFileOperationMetricModule(mockConfig, FileOperation.CREATE, 10, 'text/plain', 'txt');
214
+ recordFileOperationMetricModule(mockConfig, {
215
+ operation: FileOperation.CREATE,
216
+ lines: 10,
217
+ mimetype: 'text/plain',
218
+ extension: 'txt',
219
+ });
183
220
  expect(mockCounterAddFn).not.toHaveBeenCalled();
184
221
  });
185
222
  it('should record file creation with all attributes', () => {
186
223
  initializeMetricsModule(mockConfig);
187
- recordFileOperationMetricModule(mockConfig, FileOperation.CREATE, 10, 'text/plain', 'txt');
224
+ recordFileOperationMetricModule(mockConfig, {
225
+ operation: FileOperation.CREATE,
226
+ lines: 10,
227
+ mimetype: 'text/plain',
228
+ extension: 'txt',
229
+ });
188
230
  expect(mockCounterAddFn).toHaveBeenCalledTimes(2);
189
231
  expect(mockCounterAddFn).toHaveBeenNthCalledWith(1, 1, {
190
232
  'session.id': 'test-session-id',
@@ -200,7 +242,9 @@ describe('Telemetry Metrics', () => {
200
242
  it('should record file read with minimal attributes', () => {
201
243
  initializeMetricsModule(mockConfig);
202
244
  mockCounterAddFn.mockClear();
203
- recordFileOperationMetricModule(mockConfig, FileOperation.READ);
245
+ recordFileOperationMetricModule(mockConfig, {
246
+ operation: FileOperation.READ,
247
+ });
204
248
  expect(mockCounterAddFn).toHaveBeenCalledWith(1, {
205
249
  'session.id': 'test-session-id',
206
250
  operation: FileOperation.READ,
@@ -209,7 +253,10 @@ describe('Telemetry Metrics', () => {
209
253
  it('should record file update with some attributes', () => {
210
254
  initializeMetricsModule(mockConfig);
211
255
  mockCounterAddFn.mockClear();
212
- recordFileOperationMetricModule(mockConfig, FileOperation.UPDATE, undefined, 'application/javascript');
256
+ recordFileOperationMetricModule(mockConfig, {
257
+ operation: FileOperation.UPDATE,
258
+ mimetype: 'application/javascript',
259
+ });
213
260
  expect(mockCounterAddFn).toHaveBeenCalledWith(1, {
214
261
  'session.id': 'test-session-id',
215
262
  operation: FileOperation.UPDATE,
@@ -219,7 +266,9 @@ describe('Telemetry Metrics', () => {
219
266
  it('should record file operation without diffStat', () => {
220
267
  initializeMetricsModule(mockConfig);
221
268
  mockCounterAddFn.mockClear();
222
- recordFileOperationMetricModule(mockConfig, FileOperation.UPDATE, undefined, undefined, undefined);
269
+ recordFileOperationMetricModule(mockConfig, {
270
+ operation: FileOperation.UPDATE,
271
+ });
223
272
  expect(mockCounterAddFn).toHaveBeenCalledWith(1, {
224
273
  'session.id': 'test-session-id',
225
274
  operation: FileOperation.UPDATE,
@@ -228,7 +277,12 @@ describe('Telemetry Metrics', () => {
228
277
  it('should record minimal file operation when optional parameters are undefined', () => {
229
278
  initializeMetricsModule(mockConfig);
230
279
  mockCounterAddFn.mockClear();
231
- recordFileOperationMetricModule(mockConfig, FileOperation.UPDATE, 10, 'text/plain', 'txt', undefined);
280
+ recordFileOperationMetricModule(mockConfig, {
281
+ operation: FileOperation.UPDATE,
282
+ lines: 10,
283
+ mimetype: 'text/plain',
284
+ extension: 'txt',
285
+ });
232
286
  expect(mockCounterAddFn).toHaveBeenCalledWith(1, {
233
287
  'session.id': 'test-session-id',
234
288
  operation: FileOperation.UPDATE,
@@ -240,7 +294,9 @@ describe('Telemetry Metrics', () => {
240
294
  it('should not include diffStat attributes when diffStat is not provided', () => {
241
295
  initializeMetricsModule(mockConfig);
242
296
  mockCounterAddFn.mockClear();
243
- recordFileOperationMetricModule(mockConfig, FileOperation.UPDATE, undefined, undefined, undefined);
297
+ recordFileOperationMetricModule(mockConfig, {
298
+ operation: FileOperation.UPDATE,
299
+ });
244
300
  expect(mockCounterAddFn).toHaveBeenCalledWith(1, {
245
301
  'session.id': 'test-session-id',
246
302
  operation: FileOperation.UPDATE,
@@ -287,6 +343,156 @@ describe('Telemetry Metrics', () => {
287
343
  });
288
344
  });
289
345
  });
346
+ describe('OpenTelemetry GenAI Semantic Convention Metrics', () => {
347
+ const mockConfig = {
348
+ getSessionId: () => 'test-session-id',
349
+ getTelemetryEnabled: () => true,
350
+ };
351
+ describe('recordGenAiClientTokenUsage', () => {
352
+ it('should not record metrics when not initialized', () => {
353
+ recordGenAiClientTokenUsageModule(mockConfig, 100, {
354
+ 'gen_ai.operation.name': 'generate_content',
355
+ 'gen_ai.provider.name': 'gcp.gen_ai',
356
+ 'gen_ai.token.type': 'input',
357
+ });
358
+ expect(mockHistogramRecordFn).not.toHaveBeenCalled();
359
+ });
360
+ it('should record input token usage with correct attributes', () => {
361
+ initializeMetricsModule(mockConfig);
362
+ mockHistogramRecordFn.mockClear();
363
+ recordGenAiClientTokenUsageModule(mockConfig, 150, {
364
+ 'gen_ai.operation.name': 'generate_content',
365
+ 'gen_ai.provider.name': 'gcp.gen_ai',
366
+ 'gen_ai.token.type': 'input',
367
+ 'gen_ai.request.model': 'gemini-2.0-flash',
368
+ 'gen_ai.response.model': 'gemini-2.0-flash',
369
+ });
370
+ expect(mockHistogramRecordFn).toHaveBeenCalledWith(150, {
371
+ 'session.id': 'test-session-id',
372
+ 'gen_ai.operation.name': 'generate_content',
373
+ 'gen_ai.provider.name': 'gcp.gen_ai',
374
+ 'gen_ai.token.type': 'input',
375
+ 'gen_ai.request.model': 'gemini-2.0-flash',
376
+ 'gen_ai.response.model': 'gemini-2.0-flash',
377
+ });
378
+ });
379
+ it('should record output token usage with correct attributes', () => {
380
+ initializeMetricsModule(mockConfig);
381
+ mockHistogramRecordFn.mockClear();
382
+ recordGenAiClientTokenUsageModule(mockConfig, 75, {
383
+ 'gen_ai.operation.name': 'generate_content',
384
+ 'gen_ai.provider.name': 'gcp.vertex_ai',
385
+ 'gen_ai.token.type': 'output',
386
+ 'gen_ai.request.model': 'gemini-pro',
387
+ });
388
+ expect(mockHistogramRecordFn).toHaveBeenCalledWith(75, {
389
+ 'session.id': 'test-session-id',
390
+ 'gen_ai.operation.name': 'generate_content',
391
+ 'gen_ai.provider.name': 'gcp.vertex_ai',
392
+ 'gen_ai.token.type': 'output',
393
+ 'gen_ai.request.model': 'gemini-pro',
394
+ });
395
+ });
396
+ it('should record token usage with optional attributes', () => {
397
+ initializeMetricsModule(mockConfig);
398
+ mockHistogramRecordFn.mockClear();
399
+ recordGenAiClientTokenUsageModule(mockConfig, 200, {
400
+ 'gen_ai.operation.name': 'generate_content',
401
+ 'gen_ai.provider.name': 'gcp.vertex_ai',
402
+ 'gen_ai.token.type': 'input',
403
+ 'gen_ai.request.model': 'text-embedding-004',
404
+ 'server.address': 'aiplatform.googleapis.com',
405
+ 'server.port': 443,
406
+ });
407
+ expect(mockHistogramRecordFn).toHaveBeenCalledWith(200, {
408
+ 'session.id': 'test-session-id',
409
+ 'gen_ai.operation.name': 'generate_content',
410
+ 'gen_ai.provider.name': 'gcp.vertex_ai',
411
+ 'gen_ai.token.type': 'input',
412
+ 'gen_ai.request.model': 'text-embedding-004',
413
+ 'server.address': 'aiplatform.googleapis.com',
414
+ 'server.port': 443,
415
+ });
416
+ });
417
+ });
418
+ describe('recordGenAiClientOperationDuration', () => {
419
+ it('should not record metrics when not initialized', () => {
420
+ recordGenAiClientOperationDurationModule(mockConfig, 2.5, {
421
+ 'gen_ai.operation.name': 'generate_content',
422
+ 'gen_ai.provider.name': 'gcp.gen_ai',
423
+ });
424
+ expect(mockHistogramRecordFn).not.toHaveBeenCalled();
425
+ });
426
+ it('should record successful operation duration with correct attributes', () => {
427
+ initializeMetricsModule(mockConfig);
428
+ mockHistogramRecordFn.mockClear();
429
+ recordGenAiClientOperationDurationModule(mockConfig, 1.25, {
430
+ 'gen_ai.operation.name': 'generate_content',
431
+ 'gen_ai.provider.name': 'gcp.gen_ai',
432
+ 'gen_ai.request.model': 'gemini-2.0-flash',
433
+ 'gen_ai.response.model': 'gemini-2.0-flash',
434
+ });
435
+ expect(mockHistogramRecordFn).toHaveBeenCalledWith(1.25, {
436
+ 'session.id': 'test-session-id',
437
+ 'gen_ai.operation.name': 'generate_content',
438
+ 'gen_ai.provider.name': 'gcp.gen_ai',
439
+ 'gen_ai.request.model': 'gemini-2.0-flash',
440
+ 'gen_ai.response.model': 'gemini-2.0-flash',
441
+ });
442
+ });
443
+ it('should record failed operation duration with error type', () => {
444
+ initializeMetricsModule(mockConfig);
445
+ mockHistogramRecordFn.mockClear();
446
+ recordGenAiClientOperationDurationModule(mockConfig, 3.75, {
447
+ 'gen_ai.operation.name': 'generate_content',
448
+ 'gen_ai.provider.name': 'gcp.vertex_ai',
449
+ 'gen_ai.request.model': 'gemini-pro',
450
+ 'error.type': 'quota_exceeded',
451
+ });
452
+ expect(mockHistogramRecordFn).toHaveBeenCalledWith(3.75, {
453
+ 'session.id': 'test-session-id',
454
+ 'gen_ai.operation.name': 'generate_content',
455
+ 'gen_ai.provider.name': 'gcp.vertex_ai',
456
+ 'gen_ai.request.model': 'gemini-pro',
457
+ 'error.type': 'quota_exceeded',
458
+ });
459
+ });
460
+ it('should record operation duration with server details', () => {
461
+ initializeMetricsModule(mockConfig);
462
+ mockHistogramRecordFn.mockClear();
463
+ recordGenAiClientOperationDurationModule(mockConfig, 0.95, {
464
+ 'gen_ai.operation.name': 'generate_content',
465
+ 'gen_ai.provider.name': 'gcp.vertex_ai',
466
+ 'gen_ai.request.model': 'gemini-1.5-pro',
467
+ 'gen_ai.response.model': 'gemini-1.5-pro-001',
468
+ 'server.address': 'us-central1-aiplatform.googleapis.com',
469
+ 'server.port': 443,
470
+ });
471
+ expect(mockHistogramRecordFn).toHaveBeenCalledWith(0.95, {
472
+ 'session.id': 'test-session-id',
473
+ 'gen_ai.operation.name': 'generate_content',
474
+ 'gen_ai.provider.name': 'gcp.vertex_ai',
475
+ 'gen_ai.request.model': 'gemini-1.5-pro',
476
+ 'gen_ai.response.model': 'gemini-1.5-pro-001',
477
+ 'server.address': 'us-central1-aiplatform.googleapis.com',
478
+ 'server.port': 443,
479
+ });
480
+ });
481
+ it('should handle minimal required attributes', () => {
482
+ initializeMetricsModule(mockConfig);
483
+ mockHistogramRecordFn.mockClear();
484
+ recordGenAiClientOperationDurationModule(mockConfig, 2.1, {
485
+ 'gen_ai.operation.name': 'generate_content',
486
+ 'gen_ai.provider.name': 'gcp.gen_ai',
487
+ });
488
+ expect(mockHistogramRecordFn).toHaveBeenCalledWith(2.1, {
489
+ 'session.id': 'test-session-id',
490
+ 'gen_ai.operation.name': 'generate_content',
491
+ 'gen_ai.provider.name': 'gcp.gen_ai',
492
+ });
493
+ });
494
+ });
495
+ });
290
496
  describe('Performance Monitoring Metrics', () => {
291
497
  const mockConfig = {
292
498
  getSessionId: () => 'test-session-id',
@@ -301,18 +507,24 @@ describe('Telemetry Metrics', () => {
301
507
  };
302
508
  initializeMetricsModule(mockConfigDisabled);
303
509
  mockHistogramRecordFn.mockClear();
304
- recordStartupPerformanceModule(mockConfigDisabled, 'settings_loading', 100, {
305
- auth_type: 'gemini',
510
+ recordStartupPerformanceModule(mockConfigDisabled, 100, {
511
+ phase: 'settings_loading',
512
+ details: {
513
+ auth_type: 'gemini',
514
+ },
306
515
  });
307
516
  expect(mockHistogramRecordFn).not.toHaveBeenCalled();
308
517
  });
309
518
  it('should record startup performance with phase and details', () => {
310
519
  initializeMetricsModule(mockConfig);
311
520
  mockHistogramRecordFn.mockClear();
312
- recordStartupPerformanceModule(mockConfig, 'settings_loading', 150, {
313
- auth_type: 'gemini',
314
- telemetry_enabled: true,
315
- settings_sources: 2,
521
+ recordStartupPerformanceModule(mockConfig, 150, {
522
+ phase: 'settings_loading',
523
+ details: {
524
+ auth_type: 'gemini',
525
+ telemetry_enabled: true,
526
+ settings_sources: 2,
527
+ },
316
528
  });
317
529
  expect(mockHistogramRecordFn).toHaveBeenCalledWith(150, {
318
530
  'session.id': 'test-session-id',
@@ -325,7 +537,7 @@ describe('Telemetry Metrics', () => {
325
537
  it('should record startup performance without details', () => {
326
538
  initializeMetricsModule(mockConfig);
327
539
  mockHistogramRecordFn.mockClear();
328
- recordStartupPerformanceModule(mockConfig, 'cleanup', 50);
540
+ recordStartupPerformanceModule(mockConfig, 50, { phase: 'cleanup' });
329
541
  expect(mockHistogramRecordFn).toHaveBeenCalledWith(50, {
330
542
  'session.id': 'test-session-id',
331
543
  phase: 'cleanup',
@@ -336,9 +548,12 @@ describe('Telemetry Metrics', () => {
336
548
  mockHistogramRecordFn.mockClear();
337
549
  // Test with realistic floating-point values that performance.now() would return
338
550
  const floatingPointDuration = 123.45678;
339
- recordStartupPerformanceModule(mockConfig, 'total_startup', floatingPointDuration, {
340
- is_tty: true,
341
- has_question: false,
551
+ recordStartupPerformanceModule(mockConfig, floatingPointDuration, {
552
+ phase: 'total_startup',
553
+ details: {
554
+ is_tty: true,
555
+ has_question: false,
556
+ },
342
557
  });
343
558
  expect(mockHistogramRecordFn).toHaveBeenCalledWith(floatingPointDuration, {
344
559
  'session.id': 'test-session-id',
@@ -352,7 +567,10 @@ describe('Telemetry Metrics', () => {
352
567
  it('should record memory usage for different memory types', () => {
353
568
  initializeMetricsModule(mockConfig);
354
569
  mockHistogramRecordFn.mockClear();
355
- recordMemoryUsageModule(mockConfig, MemoryMetricType.HEAP_USED, 15728640, 'startup');
570
+ recordMemoryUsageModule(mockConfig, 15728640, {
571
+ memory_type: MemoryMetricType.HEAP_USED,
572
+ component: 'startup',
573
+ });
356
574
  expect(mockHistogramRecordFn).toHaveBeenCalledWith(15728640, {
357
575
  'session.id': 'test-session-id',
358
576
  memory_type: 'heap_used',
@@ -362,9 +580,18 @@ describe('Telemetry Metrics', () => {
362
580
  it('should record memory usage for all memory metric types', () => {
363
581
  initializeMetricsModule(mockConfig);
364
582
  mockHistogramRecordFn.mockClear();
365
- recordMemoryUsageModule(mockConfig, MemoryMetricType.HEAP_TOTAL, 31457280, 'api_call');
366
- recordMemoryUsageModule(mockConfig, MemoryMetricType.EXTERNAL, 2097152, 'tool_execution');
367
- recordMemoryUsageModule(mockConfig, MemoryMetricType.RSS, 41943040, 'memory_monitor');
583
+ recordMemoryUsageModule(mockConfig, 31457280, {
584
+ memory_type: MemoryMetricType.HEAP_TOTAL,
585
+ component: 'api_call',
586
+ });
587
+ recordMemoryUsageModule(mockConfig, 2097152, {
588
+ memory_type: MemoryMetricType.EXTERNAL,
589
+ component: 'tool_execution',
590
+ });
591
+ recordMemoryUsageModule(mockConfig, 41943040, {
592
+ memory_type: MemoryMetricType.RSS,
593
+ component: 'memory_monitor',
594
+ });
368
595
  expect(mockHistogramRecordFn).toHaveBeenCalledTimes(3); // One for each call
369
596
  expect(mockHistogramRecordFn).toHaveBeenNthCalledWith(1, 31457280, {
370
597
  'session.id': 'test-session-id',
@@ -385,11 +612,12 @@ describe('Telemetry Metrics', () => {
385
612
  it('should record memory usage without component', () => {
386
613
  initializeMetricsModule(mockConfig);
387
614
  mockHistogramRecordFn.mockClear();
388
- recordMemoryUsageModule(mockConfig, MemoryMetricType.HEAP_USED, 15728640);
615
+ recordMemoryUsageModule(mockConfig, 15728640, {
616
+ memory_type: MemoryMetricType.HEAP_USED,
617
+ });
389
618
  expect(mockHistogramRecordFn).toHaveBeenCalledWith(15728640, {
390
619
  'session.id': 'test-session-id',
391
620
  memory_type: 'heap_used',
392
- component: undefined,
393
621
  });
394
622
  });
395
623
  });
@@ -397,7 +625,9 @@ describe('Telemetry Metrics', () => {
397
625
  it('should record CPU usage percentage', () => {
398
626
  initializeMetricsModule(mockConfig);
399
627
  mockHistogramRecordFn.mockClear();
400
- recordCpuUsageModule(mockConfig, 85.5, 'tool_execution');
628
+ recordCpuUsageModule(mockConfig, 85.5, {
629
+ component: 'tool_execution',
630
+ });
401
631
  expect(mockHistogramRecordFn).toHaveBeenCalledWith(85.5, {
402
632
  'session.id': 'test-session-id',
403
633
  component: 'tool_execution',
@@ -406,10 +636,9 @@ describe('Telemetry Metrics', () => {
406
636
  it('should record CPU usage without component', () => {
407
637
  initializeMetricsModule(mockConfig);
408
638
  mockHistogramRecordFn.mockClear();
409
- recordCpuUsageModule(mockConfig, 42.3);
639
+ recordCpuUsageModule(mockConfig, 42.3, {});
410
640
  expect(mockHistogramRecordFn).toHaveBeenCalledWith(42.3, {
411
641
  'session.id': 'test-session-id',
412
- component: undefined,
413
642
  });
414
643
  });
415
644
  });
@@ -435,7 +664,10 @@ describe('Telemetry Metrics', () => {
435
664
  it('should record tool execution breakdown for all phases', () => {
436
665
  initializeMetricsModule(mockConfig);
437
666
  mockHistogramRecordFn.mockClear();
438
- recordToolExecutionBreakdownModule(mockConfig, 'Read', ToolExecutionPhase.VALIDATION, 25);
667
+ recordToolExecutionBreakdownModule(mockConfig, 25, {
668
+ function_name: 'Read',
669
+ phase: ToolExecutionPhase.VALIDATION,
670
+ });
439
671
  expect(mockHistogramRecordFn).toHaveBeenCalledWith(25, {
440
672
  'session.id': 'test-session-id',
441
673
  function_name: 'Read',
@@ -445,9 +677,18 @@ describe('Telemetry Metrics', () => {
445
677
  it('should record execution breakdown for different phases', () => {
446
678
  initializeMetricsModule(mockConfig);
447
679
  mockHistogramRecordFn.mockClear();
448
- recordToolExecutionBreakdownModule(mockConfig, 'Bash', ToolExecutionPhase.PREPARATION, 50);
449
- recordToolExecutionBreakdownModule(mockConfig, 'Bash', ToolExecutionPhase.EXECUTION, 1500);
450
- recordToolExecutionBreakdownModule(mockConfig, 'Bash', ToolExecutionPhase.RESULT_PROCESSING, 75);
680
+ recordToolExecutionBreakdownModule(mockConfig, 50, {
681
+ function_name: 'Bash',
682
+ phase: ToolExecutionPhase.PREPARATION,
683
+ });
684
+ recordToolExecutionBreakdownModule(mockConfig, 1500, {
685
+ function_name: 'Bash',
686
+ phase: ToolExecutionPhase.EXECUTION,
687
+ });
688
+ recordToolExecutionBreakdownModule(mockConfig, 75, {
689
+ function_name: 'Bash',
690
+ phase: ToolExecutionPhase.RESULT_PROCESSING,
691
+ });
451
692
  expect(mockHistogramRecordFn).toHaveBeenCalledTimes(3); // One for each call
452
693
  expect(mockHistogramRecordFn).toHaveBeenNthCalledWith(1, 50, {
453
694
  'session.id': 'test-session-id',
@@ -470,7 +711,11 @@ describe('Telemetry Metrics', () => {
470
711
  it('should record token efficiency metrics', () => {
471
712
  initializeMetricsModule(mockConfig);
472
713
  mockHistogramRecordFn.mockClear();
473
- recordTokenEfficiencyModule(mockConfig, 'gemini-pro', 'cache_hit_rate', 0.85, 'api_request');
714
+ recordTokenEfficiencyModule(mockConfig, 0.85, {
715
+ model: 'gemini-pro',
716
+ metric: 'cache_hit_rate',
717
+ context: 'api_request',
718
+ });
474
719
  expect(mockHistogramRecordFn).toHaveBeenCalledWith(0.85, {
475
720
  'session.id': 'test-session-id',
476
721
  model: 'gemini-pro',
@@ -481,12 +726,14 @@ describe('Telemetry Metrics', () => {
481
726
  it('should record token efficiency without context', () => {
482
727
  initializeMetricsModule(mockConfig);
483
728
  mockHistogramRecordFn.mockClear();
484
- recordTokenEfficiencyModule(mockConfig, 'gemini-pro', 'tokens_per_operation', 125.5);
729
+ recordTokenEfficiencyModule(mockConfig, 125.5, {
730
+ model: 'gemini-pro',
731
+ metric: 'tokens_per_operation',
732
+ });
485
733
  expect(mockHistogramRecordFn).toHaveBeenCalledWith(125.5, {
486
734
  'session.id': 'test-session-id',
487
735
  model: 'gemini-pro',
488
736
  metric: 'tokens_per_operation',
489
- context: undefined,
490
737
  });
491
738
  });
492
739
  });
@@ -494,7 +741,10 @@ describe('Telemetry Metrics', () => {
494
741
  it('should record API request breakdown for all phases', () => {
495
742
  initializeMetricsModule(mockConfig);
496
743
  mockHistogramRecordFn.mockClear();
497
- recordApiRequestBreakdownModule(mockConfig, 'gemini-pro', ApiRequestPhase.REQUEST_PREPARATION, 15);
744
+ recordApiRequestBreakdownModule(mockConfig, 15, {
745
+ model: 'gemini-pro',
746
+ phase: ApiRequestPhase.REQUEST_PREPARATION,
747
+ });
498
748
  expect(mockHistogramRecordFn).toHaveBeenCalledWith(15, {
499
749
  'session.id': 'test-session-id',
500
750
  model: 'gemini-pro',
@@ -504,9 +754,18 @@ describe('Telemetry Metrics', () => {
504
754
  it('should record API request breakdown for different phases', () => {
505
755
  initializeMetricsModule(mockConfig);
506
756
  mockHistogramRecordFn.mockClear();
507
- recordApiRequestBreakdownModule(mockConfig, 'gemini-pro', ApiRequestPhase.NETWORK_LATENCY, 250);
508
- recordApiRequestBreakdownModule(mockConfig, 'gemini-pro', ApiRequestPhase.RESPONSE_PROCESSING, 100);
509
- recordApiRequestBreakdownModule(mockConfig, 'gemini-pro', ApiRequestPhase.TOKEN_PROCESSING, 50);
757
+ recordApiRequestBreakdownModule(mockConfig, 250, {
758
+ model: 'gemini-pro',
759
+ phase: ApiRequestPhase.NETWORK_LATENCY,
760
+ });
761
+ recordApiRequestBreakdownModule(mockConfig, 100, {
762
+ model: 'gemini-pro',
763
+ phase: ApiRequestPhase.RESPONSE_PROCESSING,
764
+ });
765
+ recordApiRequestBreakdownModule(mockConfig, 50, {
766
+ model: 'gemini-pro',
767
+ phase: ApiRequestPhase.TOKEN_PROCESSING,
768
+ });
510
769
  expect(mockHistogramRecordFn).toHaveBeenCalledTimes(3); // One for each call
511
770
  expect(mockHistogramRecordFn).toHaveBeenNthCalledWith(1, 250, {
512
771
  'session.id': 'test-session-id',
@@ -529,7 +788,10 @@ describe('Telemetry Metrics', () => {
529
788
  it('should record performance score with category and baseline', () => {
530
789
  initializeMetricsModule(mockConfig);
531
790
  mockHistogramRecordFn.mockClear();
532
- recordPerformanceScoreModule(mockConfig, 85.5, 'memory_efficiency', 80.0);
791
+ recordPerformanceScoreModule(mockConfig, 85.5, {
792
+ category: 'memory_efficiency',
793
+ baseline: 80.0,
794
+ });
533
795
  expect(mockHistogramRecordFn).toHaveBeenCalledWith(85.5, {
534
796
  'session.id': 'test-session-id',
535
797
  category: 'memory_efficiency',
@@ -539,11 +801,12 @@ describe('Telemetry Metrics', () => {
539
801
  it('should record performance score without baseline', () => {
540
802
  initializeMetricsModule(mockConfig);
541
803
  mockHistogramRecordFn.mockClear();
542
- recordPerformanceScoreModule(mockConfig, 92.3, 'overall_performance');
804
+ recordPerformanceScoreModule(mockConfig, 92.3, {
805
+ category: 'overall_performance',
806
+ });
543
807
  expect(mockHistogramRecordFn).toHaveBeenCalledWith(92.3, {
544
808
  'session.id': 'test-session-id',
545
809
  category: 'overall_performance',
546
- baseline: undefined,
547
810
  });
548
811
  });
549
812
  });
@@ -552,7 +815,12 @@ describe('Telemetry Metrics', () => {
552
815
  initializeMetricsModule(mockConfig);
553
816
  mockCounterAddFn.mockClear();
554
817
  mockHistogramRecordFn.mockClear();
555
- recordPerformanceRegressionModule(mockConfig, 'startup_time', 1200, 1000, 'medium');
818
+ recordPerformanceRegressionModule(mockConfig, {
819
+ metric: 'startup_time',
820
+ current_value: 1200,
821
+ baseline_value: 1000,
822
+ severity: 'medium',
823
+ });
556
824
  // Verify regression counter
557
825
  expect(mockCounterAddFn).toHaveBeenCalledWith(1, {
558
826
  'session.id': 'test-session-id',
@@ -574,7 +842,12 @@ describe('Telemetry Metrics', () => {
574
842
  initializeMetricsModule(mockConfig);
575
843
  mockCounterAddFn.mockClear();
576
844
  mockHistogramRecordFn.mockClear();
577
- recordPerformanceRegressionModule(mockConfig, 'memory_usage', 100, 0, 'high');
845
+ recordPerformanceRegressionModule(mockConfig, {
846
+ metric: 'memory_usage',
847
+ current_value: 100,
848
+ baseline_value: 0,
849
+ severity: 'high',
850
+ });
578
851
  // Verify regression counter still recorded
579
852
  expect(mockCounterAddFn).toHaveBeenCalledWith(1, {
580
853
  'session.id': 'test-session-id',
@@ -589,8 +862,18 @@ describe('Telemetry Metrics', () => {
589
862
  it('should record different severity levels', () => {
590
863
  initializeMetricsModule(mockConfig);
591
864
  mockCounterAddFn.mockClear();
592
- recordPerformanceRegressionModule(mockConfig, 'api_latency', 500, 400, 'low');
593
- recordPerformanceRegressionModule(mockConfig, 'cpu_usage', 90, 70, 'high');
865
+ recordPerformanceRegressionModule(mockConfig, {
866
+ metric: 'api_latency',
867
+ current_value: 500,
868
+ baseline_value: 400,
869
+ severity: 'low',
870
+ });
871
+ recordPerformanceRegressionModule(mockConfig, {
872
+ metric: 'cpu_usage',
873
+ current_value: 90,
874
+ baseline_value: 70,
875
+ severity: 'high',
876
+ });
594
877
  expect(mockCounterAddFn).toHaveBeenNthCalledWith(1, 1, {
595
878
  'session.id': 'test-session-id',
596
879
  metric: 'api_latency',
@@ -611,7 +894,12 @@ describe('Telemetry Metrics', () => {
611
894
  it('should record baseline comparison with percentage change', () => {
612
895
  initializeMetricsModule(mockConfig);
613
896
  mockHistogramRecordFn.mockClear();
614
- recordBaselineComparisonModule(mockConfig, 'memory_usage', 120, 100, 'performance_tracking');
897
+ recordBaselineComparisonModule(mockConfig, {
898
+ metric: 'memory_usage',
899
+ current_value: 120,
900
+ baseline_value: 100,
901
+ category: 'performance_tracking',
902
+ });
615
903
  // 20% increase: (120 - 100) / 100 * 100 = 20%
616
904
  expect(mockHistogramRecordFn).toHaveBeenCalledWith(20, {
617
905
  'session.id': 'test-session-id',
@@ -624,7 +912,12 @@ describe('Telemetry Metrics', () => {
624
912
  it('should handle negative percentage change (improvement)', () => {
625
913
  initializeMetricsModule(mockConfig);
626
914
  mockHistogramRecordFn.mockClear();
627
- recordBaselineComparisonModule(mockConfig, 'startup_time', 800, 1000, 'optimization');
915
+ recordBaselineComparisonModule(mockConfig, {
916
+ metric: 'startup_time',
917
+ current_value: 800,
918
+ baseline_value: 1000,
919
+ category: 'optimization',
920
+ });
628
921
  // 20% decrease: (800 - 1000) / 1000 * 100 = -20%
629
922
  expect(mockHistogramRecordFn).toHaveBeenCalledWith(-20, {
630
923
  'session.id': 'test-session-id',
@@ -640,7 +933,12 @@ describe('Telemetry Metrics', () => {
640
933
  const diagSpy = vi.spyOn(mockedModule.diag, 'warn');
641
934
  initializeMetricsModule(mockConfig);
642
935
  mockHistogramRecordFn.mockClear();
643
- recordBaselineComparisonModule(mockConfig, 'new_metric', 50, 0, 'testing');
936
+ recordBaselineComparisonModule(mockConfig, {
937
+ metric: 'new_metric',
938
+ current_value: 50,
939
+ baseline_value: 0,
940
+ category: 'testing',
941
+ });
644
942
  expect(diagSpy).toHaveBeenCalledWith('Baseline value is zero, skipping comparison.');
645
943
  expect(mockHistogramRecordFn).not.toHaveBeenCalled();
646
944
  });