@google/gemini-cli-core 0.0.77777772 → 0.0.77777774

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 (291) hide show
  1. package/README.md +108 -71
  2. package/dist/index.d.ts +3 -1
  3. package/dist/index.js +2 -1
  4. package/dist/index.js.map +1 -1
  5. package/dist/src/agents/codebase-investigator.d.ts +46 -0
  6. package/dist/src/agents/codebase-investigator.js +136 -0
  7. package/dist/src/agents/codebase-investigator.js.map +1 -0
  8. package/dist/src/agents/executor.d.ts +92 -0
  9. package/dist/src/agents/executor.js +579 -0
  10. package/dist/src/agents/executor.js.map +1 -0
  11. package/dist/src/agents/executor.test.d.ts +6 -0
  12. package/dist/src/agents/executor.test.js +595 -0
  13. package/dist/src/agents/executor.test.js.map +1 -0
  14. package/dist/src/agents/invocation.d.ts +46 -0
  15. package/dist/src/agents/invocation.js +102 -0
  16. package/dist/src/agents/invocation.js.map +1 -0
  17. package/dist/src/agents/invocation.test.d.ts +6 -0
  18. package/dist/src/agents/invocation.test.js +215 -0
  19. package/dist/src/agents/invocation.test.js.map +1 -0
  20. package/dist/src/agents/registry.d.ts +36 -0
  21. package/dist/src/agents/registry.js +60 -0
  22. package/dist/src/agents/registry.js.map +1 -0
  23. package/dist/src/agents/registry.test.d.ts +6 -0
  24. package/dist/src/agents/registry.test.js +146 -0
  25. package/dist/src/agents/registry.test.js.map +1 -0
  26. package/dist/src/agents/schema-utils.d.ts +39 -0
  27. package/dist/src/agents/schema-utils.js +57 -0
  28. package/dist/src/agents/schema-utils.js.map +1 -0
  29. package/dist/src/agents/schema-utils.test.d.ts +6 -0
  30. package/dist/src/agents/schema-utils.test.js +144 -0
  31. package/dist/src/agents/schema-utils.test.js.map +1 -0
  32. package/dist/src/agents/subagent-tool-wrapper.d.ts +38 -0
  33. package/dist/src/agents/subagent-tool-wrapper.js +48 -0
  34. package/dist/src/agents/subagent-tool-wrapper.js.map +1 -0
  35. package/dist/src/agents/subagent-tool-wrapper.test.d.ts +6 -0
  36. package/dist/src/agents/subagent-tool-wrapper.test.js +112 -0
  37. package/dist/src/agents/subagent-tool-wrapper.test.js.map +1 -0
  38. package/dist/src/agents/types.d.ts +145 -0
  39. package/dist/src/agents/types.js +18 -0
  40. package/dist/src/agents/types.js.map +1 -0
  41. package/dist/src/agents/utils.d.ts +15 -0
  42. package/dist/src/agents/utils.js +29 -0
  43. package/dist/src/agents/utils.js.map +1 -0
  44. package/dist/src/agents/utils.test.d.ts +6 -0
  45. package/dist/src/agents/utils.test.js +87 -0
  46. package/dist/src/agents/utils.test.js.map +1 -0
  47. package/dist/src/code_assist/oauth-credential-storage.js +1 -1
  48. package/dist/src/code_assist/oauth-credential-storage.js.map +1 -1
  49. package/dist/src/code_assist/oauth2.test.js +14 -13
  50. package/dist/src/code_assist/oauth2.test.js.map +1 -1
  51. package/dist/src/code_assist/setup.js +4 -2
  52. package/dist/src/code_assist/setup.js.map +1 -1
  53. package/dist/src/config/config.d.ts +37 -11
  54. package/dist/src/config/config.js +77 -18
  55. package/dist/src/config/config.js.map +1 -1
  56. package/dist/src/config/config.test.js +88 -3
  57. package/dist/src/config/config.test.js.map +1 -1
  58. package/dist/src/config/storage.d.ts +0 -1
  59. package/dist/src/config/storage.js +2 -2
  60. package/dist/src/config/storage.js.map +1 -1
  61. package/dist/src/config/storage.test.js +7 -6
  62. package/dist/src/config/storage.test.js.map +1 -1
  63. package/dist/src/core/baseLlmClient.js +19 -21
  64. package/dist/src/core/baseLlmClient.js.map +1 -1
  65. package/dist/src/core/baseLlmClient.test.js +57 -17
  66. package/dist/src/core/baseLlmClient.test.js.map +1 -1
  67. package/dist/src/core/client.d.ts +3 -1
  68. package/dist/src/core/client.js +68 -46
  69. package/dist/src/core/client.js.map +1 -1
  70. package/dist/src/core/client.test.js +385 -95
  71. package/dist/src/core/client.test.js.map +1 -1
  72. package/dist/src/core/contentGenerator.js +3 -1
  73. package/dist/src/core/contentGenerator.js.map +1 -1
  74. package/dist/src/core/coreToolScheduler.js +12 -12
  75. package/dist/src/core/coreToolScheduler.js.map +1 -1
  76. package/dist/src/core/coreToolScheduler.test.js +260 -23
  77. package/dist/src/core/coreToolScheduler.test.js.map +1 -1
  78. package/dist/src/core/geminiChat.d.ts +7 -11
  79. package/dist/src/core/geminiChat.js +31 -74
  80. package/dist/src/core/geminiChat.js.map +1 -1
  81. package/dist/src/core/geminiChat.test.js +60 -229
  82. package/dist/src/core/geminiChat.test.js.map +1 -1
  83. package/dist/src/core/logger.test.js +2 -2
  84. package/dist/src/core/logger.test.js.map +1 -1
  85. package/dist/src/core/nonInteractiveToolExecutor.test.js +11 -11
  86. package/dist/src/core/nonInteractiveToolExecutor.test.js.map +1 -1
  87. package/dist/src/core/prompts.d.ts +2 -1
  88. package/dist/src/core/prompts.js +91 -17
  89. package/dist/src/core/prompts.js.map +1 -1
  90. package/dist/src/core/prompts.test.js +78 -29
  91. package/dist/src/core/prompts.test.js.map +1 -1
  92. package/dist/src/core/turn.d.ts +14 -2
  93. package/dist/src/core/turn.js +12 -1
  94. package/dist/src/core/turn.js.map +1 -1
  95. package/dist/src/core/turn.test.js +14 -2
  96. package/dist/src/core/turn.test.js.map +1 -1
  97. package/dist/src/generated/git-commit.d.ts +2 -2
  98. package/dist/src/generated/git-commit.js +2 -2
  99. package/dist/src/ide/detect-ide.d.ts +1 -0
  100. package/dist/src/ide/detect-ide.js +4 -1
  101. package/dist/src/ide/detect-ide.js.map +1 -1
  102. package/dist/src/ide/detect-ide.test.js +11 -0
  103. package/dist/src/ide/detect-ide.test.js.map +1 -1
  104. package/dist/src/ide/ide-client.js +3 -3
  105. package/dist/src/ide/ide-client.test.js +4 -4
  106. package/dist/src/ide/ide-installer.js +1 -1
  107. package/dist/src/ide/ide-installer.js.map +1 -1
  108. package/dist/src/ide/ide-installer.test.js +13 -1
  109. package/dist/src/ide/ide-installer.test.js.map +1 -1
  110. package/dist/src/index.d.ts +1 -0
  111. package/dist/src/index.js +1 -0
  112. package/dist/src/index.js.map +1 -1
  113. package/dist/src/mcp/sa-impersonation-provider.d.ts +33 -0
  114. package/dist/src/mcp/sa-impersonation-provider.js +130 -0
  115. package/dist/src/mcp/sa-impersonation-provider.js.map +1 -0
  116. package/dist/src/mcp/sa-impersonation-provider.test.d.ts +6 -0
  117. package/dist/src/mcp/sa-impersonation-provider.test.js +117 -0
  118. package/dist/src/mcp/sa-impersonation-provider.test.js.map +1 -0
  119. package/dist/src/mcp/token-storage/file-token-storage.js +2 -1
  120. package/dist/src/mcp/token-storage/file-token-storage.js.map +1 -1
  121. package/dist/src/mcp/token-storage/file-token-storage.test.js +4 -3
  122. package/dist/src/mcp/token-storage/file-token-storage.test.js.map +1 -1
  123. package/dist/src/services/chatRecordingService.d.ts +2 -1
  124. package/dist/src/services/chatRecordingService.js +2 -1
  125. package/dist/src/services/chatRecordingService.js.map +1 -1
  126. package/dist/src/services/fileSystemService.d.ts +9 -0
  127. package/dist/src/services/fileSystemService.js +11 -0
  128. package/dist/src/services/fileSystemService.js.map +1 -1
  129. package/dist/src/services/shellExecutionService.d.ts +3 -0
  130. package/dist/src/services/shellExecutionService.js +165 -49
  131. package/dist/src/services/shellExecutionService.js.map +1 -1
  132. package/dist/src/services/shellExecutionService.test.js +74 -5
  133. package/dist/src/services/shellExecutionService.test.js.map +1 -1
  134. package/dist/src/telemetry/clearcut-logger/clearcut-logger.d.ts +14 -2
  135. package/dist/src/telemetry/clearcut-logger/clearcut-logger.js +119 -12
  136. package/dist/src/telemetry/clearcut-logger/clearcut-logger.js.map +1 -1
  137. package/dist/src/telemetry/clearcut-logger/clearcut-logger.test.js +99 -1
  138. package/dist/src/telemetry/clearcut-logger/clearcut-logger.test.js.map +1 -1
  139. package/dist/src/telemetry/clearcut-logger/event-metadata-key.d.ts +13 -3
  140. package/dist/src/telemetry/clearcut-logger/event-metadata-key.js +32 -5
  141. package/dist/src/telemetry/clearcut-logger/event-metadata-key.js.map +1 -1
  142. package/dist/src/telemetry/constants.d.ts +0 -52
  143. package/dist/src/telemetry/constants.js +0 -54
  144. package/dist/src/telemetry/constants.js.map +1 -1
  145. package/dist/src/telemetry/index.d.ts +5 -3
  146. package/dist/src/telemetry/index.js +11 -4
  147. package/dist/src/telemetry/index.js.map +1 -1
  148. package/dist/src/telemetry/loggers.d.ts +8 -2
  149. package/dist/src/telemetry/loggers.js +187 -288
  150. package/dist/src/telemetry/loggers.js.map +1 -1
  151. package/dist/src/telemetry/loggers.test.circular.js +3 -3
  152. package/dist/src/telemetry/loggers.test.circular.js.map +1 -1
  153. package/dist/src/telemetry/loggers.test.js +232 -13
  154. package/dist/src/telemetry/loggers.test.js.map +1 -1
  155. package/dist/src/telemetry/memory-monitor.d.ts +149 -0
  156. package/dist/src/telemetry/memory-monitor.js +335 -0
  157. package/dist/src/telemetry/memory-monitor.js.map +1 -0
  158. package/dist/src/telemetry/memory-monitor.test.d.ts +6 -0
  159. package/dist/src/telemetry/memory-monitor.test.js +472 -0
  160. package/dist/src/telemetry/memory-monitor.test.js.map +1 -0
  161. package/dist/src/telemetry/metrics.d.ts +406 -20
  162. package/dist/src/telemetry/metrics.js +479 -235
  163. package/dist/src/telemetry/metrics.js.map +1 -1
  164. package/dist/src/telemetry/metrics.test.js +551 -55
  165. package/dist/src/telemetry/metrics.test.js.map +1 -1
  166. package/dist/src/telemetry/telemetryAttributes.d.ts +8 -0
  167. package/dist/src/telemetry/telemetryAttributes.js +18 -0
  168. package/dist/src/telemetry/telemetryAttributes.js.map +1 -0
  169. package/dist/src/telemetry/types.d.ts +150 -3
  170. package/dist/src/telemetry/types.js +664 -33
  171. package/dist/src/telemetry/types.js.map +1 -1
  172. package/dist/src/telemetry/uiTelemetry.d.ts +1 -1
  173. package/dist/src/telemetry/uiTelemetry.js +1 -1
  174. package/dist/src/telemetry/uiTelemetry.js.map +1 -1
  175. package/dist/src/telemetry/uiTelemetry.test.js +3 -3
  176. package/dist/src/telemetry/uiTelemetry.test.js.map +1 -1
  177. package/dist/src/test-utils/mock-tool.d.ts +28 -3
  178. package/dist/src/test-utils/mock-tool.js +71 -1
  179. package/dist/src/test-utils/mock-tool.js.map +1 -1
  180. package/dist/src/tools/glob.js +2 -1
  181. package/dist/src/tools/glob.js.map +1 -1
  182. package/dist/src/tools/mcp-client.d.ts +3 -2
  183. package/dist/src/tools/mcp-client.js +45 -33
  184. package/dist/src/tools/mcp-client.js.map +1 -1
  185. package/dist/src/tools/mcp-client.test.js +168 -5
  186. package/dist/src/tools/mcp-client.test.js.map +1 -1
  187. package/dist/src/tools/memoryTool.d.ts +1 -1
  188. package/dist/src/tools/memoryTool.js +1 -2
  189. package/dist/src/tools/memoryTool.js.map +1 -1
  190. package/dist/src/tools/memoryTool.test.js +9 -8
  191. package/dist/src/tools/memoryTool.test.js.map +1 -1
  192. package/dist/src/tools/shell.js +2 -2
  193. package/dist/src/tools/shell.js.map +1 -1
  194. package/dist/src/tools/shell.test.js +1 -1
  195. package/dist/src/tools/shell.test.js.map +1 -1
  196. package/dist/src/tools/smart-edit.d.ts +1 -1
  197. package/dist/src/tools/smart-edit.js +114 -10
  198. package/dist/src/tools/smart-edit.js.map +1 -1
  199. package/dist/src/tools/smart-edit.test.js +91 -29
  200. package/dist/src/tools/smart-edit.test.js.map +1 -1
  201. package/dist/src/tools/tool-error.d.ts +21 -0
  202. package/dist/src/tools/tool-error.js +27 -0
  203. package/dist/src/tools/tool-error.js.map +1 -1
  204. package/dist/src/tools/tool-names.d.ts +9 -0
  205. package/dist/src/tools/tool-names.js +18 -0
  206. package/dist/src/tools/tool-names.js.map +1 -0
  207. package/dist/src/tools/tool-registry.test.js +10 -10
  208. package/dist/src/tools/tool-registry.test.js.map +1 -1
  209. package/dist/src/tools/web-fetch.js +3 -0
  210. package/dist/src/tools/web-fetch.js.map +1 -1
  211. package/dist/src/tools/web-fetch.test.js +44 -0
  212. package/dist/src/tools/web-fetch.test.js.map +1 -1
  213. package/dist/src/tools/web-search.js +2 -1
  214. package/dist/src/tools/web-search.js.map +1 -1
  215. package/dist/src/tools/write-file.js +2 -1
  216. package/dist/src/tools/write-file.js.map +1 -1
  217. package/dist/src/tools/write-todos.d.ts +1 -1
  218. package/dist/src/tools/write-todos.js +4 -3
  219. package/dist/src/tools/write-todos.js.map +1 -1
  220. package/dist/src/utils/editCorrector.js +2 -2
  221. package/dist/src/utils/editCorrector.js.map +1 -1
  222. package/dist/src/utils/editor.js +1 -0
  223. package/dist/src/utils/editor.js.map +1 -1
  224. package/dist/src/utils/editor.test.js +1 -0
  225. package/dist/src/utils/editor.test.js.map +1 -1
  226. package/dist/src/utils/errorParsing.d.ts +1 -1
  227. package/dist/src/utils/errorParsing.js +5 -33
  228. package/dist/src/utils/errorParsing.js.map +1 -1
  229. package/dist/src/utils/errorParsing.test.js +0 -88
  230. package/dist/src/utils/errorParsing.test.js.map +1 -1
  231. package/dist/src/utils/flashFallback.test.js +26 -45
  232. package/dist/src/utils/flashFallback.test.js.map +1 -1
  233. package/dist/src/utils/formatters.d.ts +1 -0
  234. package/dist/src/utils/formatters.js +2 -1
  235. package/dist/src/utils/formatters.js.map +1 -1
  236. package/dist/src/utils/formatters.test.d.ts +6 -0
  237. package/dist/src/utils/formatters.test.js +26 -0
  238. package/dist/src/utils/formatters.test.js.map +1 -0
  239. package/dist/src/utils/getFolderStructure.test.js +7 -6
  240. package/dist/src/utils/getFolderStructure.test.js.map +1 -1
  241. package/dist/src/utils/googleErrors.d.ts +104 -0
  242. package/dist/src/utils/googleErrors.js +108 -0
  243. package/dist/src/utils/googleErrors.js.map +1 -0
  244. package/dist/src/utils/googleErrors.test.d.ts +6 -0
  245. package/dist/src/utils/googleErrors.test.js +212 -0
  246. package/dist/src/utils/googleErrors.test.js.map +1 -0
  247. package/dist/src/utils/googleQuotaErrors.d.ts +35 -0
  248. package/dist/src/utils/googleQuotaErrors.js +108 -0
  249. package/dist/src/utils/googleQuotaErrors.js.map +1 -0
  250. package/dist/src/utils/googleQuotaErrors.test.d.ts +6 -0
  251. package/dist/src/utils/googleQuotaErrors.test.js +189 -0
  252. package/dist/src/utils/googleQuotaErrors.test.js.map +1 -0
  253. package/dist/src/utils/installationManager.test.js +2 -1
  254. package/dist/src/utils/installationManager.test.js.map +1 -1
  255. package/dist/src/utils/llm-edit-fixer.js +13 -4
  256. package/dist/src/utils/llm-edit-fixer.js.map +1 -1
  257. package/dist/src/utils/llm-edit-fixer.test.js +81 -0
  258. package/dist/src/utils/llm-edit-fixer.test.js.map +1 -1
  259. package/dist/src/utils/memoryDiscovery.d.ts +1 -0
  260. package/dist/src/utils/memoryDiscovery.js +2 -1
  261. package/dist/src/utils/memoryDiscovery.js.map +1 -1
  262. package/dist/src/utils/memoryDiscovery.test.js +99 -21
  263. package/dist/src/utils/memoryDiscovery.test.js.map +1 -1
  264. package/dist/src/utils/memoryImportProcessor.js +13 -20
  265. package/dist/src/utils/memoryImportProcessor.js.map +1 -1
  266. package/dist/src/utils/memoryImportProcessor.test.js +14 -0
  267. package/dist/src/utils/memoryImportProcessor.test.js.map +1 -1
  268. package/dist/src/utils/pathCorrector.d.ts +25 -0
  269. package/dist/src/utils/pathCorrector.js +33 -0
  270. package/dist/src/utils/pathCorrector.js.map +1 -0
  271. package/dist/src/utils/pathCorrector.test.d.ts +6 -0
  272. package/dist/src/utils/pathCorrector.test.js +83 -0
  273. package/dist/src/utils/pathCorrector.test.js.map +1 -0
  274. package/dist/src/utils/quotaErrorDetection.d.ts +0 -2
  275. package/dist/src/utils/quotaErrorDetection.js +0 -46
  276. package/dist/src/utils/quotaErrorDetection.js.map +1 -1
  277. package/dist/src/utils/retry.d.ts +3 -1
  278. package/dist/src/utils/retry.js +53 -161
  279. package/dist/src/utils/retry.js.map +1 -1
  280. package/dist/src/utils/retry.test.js +90 -149
  281. package/dist/src/utils/retry.test.js.map +1 -1
  282. package/dist/src/utils/terminalSerializer.d.ts +1 -4
  283. package/dist/src/utils/terminalSerializer.js +3 -3
  284. package/dist/src/utils/terminalSerializer.js.map +1 -1
  285. package/dist/src/utils/userAccountManager.test.js +2 -1
  286. package/dist/src/utils/userAccountManager.test.js.map +1 -1
  287. package/dist/tsconfig.tsbuildinfo +1 -1
  288. package/package.json +1 -1
  289. package/dist/src/test-utils/tools.d.ts +0 -45
  290. package/dist/src/test-utils/tools.js +0 -105
  291. package/dist/src/test-utils/tools.js.map +0 -1
@@ -6,7 +6,8 @@
6
6
  import { describe, it, expect, vi, beforeEach } from 'vitest';
7
7
  import { FileOperation, MemoryMetricType, ToolExecutionPhase, ApiRequestPhase, } from './metrics.js';
8
8
  import { makeFakeConfig } from '../test-utils/config.js';
9
- import { ModelRoutingEvent } from './types.js';
9
+ import { ModelRoutingEvent, AgentFinishEvent } from './types.js';
10
+ import { AgentTerminateMode } from '../agents/types.js';
10
11
  const mockCounterAddFn = vi.fn();
11
12
  const mockHistogramRecordFn = vi.fn();
12
13
  const mockCreateCounterFn = vi.fn();
@@ -34,9 +35,15 @@ function originalOtelMockFactory() {
34
35
  setLogger: vi.fn(),
35
36
  warn: vi.fn(),
36
37
  },
38
+ DiagConsoleLogger: vi.fn(),
39
+ DiagLogLevel: {
40
+ NONE: 0,
41
+ INFO: 1,
42
+ },
37
43
  };
38
44
  }
39
45
  vi.mock('@opentelemetry/api');
46
+ vi.mock('./telemetryAttributes.js');
40
47
  describe('Telemetry Metrics', () => {
41
48
  let initializeMetricsModule;
42
49
  let recordTokenUsageMetricsModule;
@@ -53,6 +60,10 @@ describe('Telemetry Metrics', () => {
53
60
  let recordPerformanceScoreModule;
54
61
  let recordPerformanceRegressionModule;
55
62
  let recordBaselineComparisonModule;
63
+ let recordGenAiClientTokenUsageModule;
64
+ let recordGenAiClientOperationDurationModule;
65
+ let recordFlickerFrameModule;
66
+ let recordAgentRunMetricsModule;
56
67
  beforeEach(async () => {
57
68
  vi.resetModules();
58
69
  vi.doMock('@opentelemetry/api', () => {
@@ -60,6 +71,12 @@ describe('Telemetry Metrics', () => {
60
71
  actualApi.metrics.getMeter.mockReturnValue(mockMeterInstance);
61
72
  return actualApi;
62
73
  });
74
+ const { getCommonAttributes } = await import('./telemetryAttributes.js');
75
+ getCommonAttributes.mockReturnValue({
76
+ 'session.id': 'test-session-id',
77
+ 'installation.id': 'test-installation-id',
78
+ 'user.email': 'test@example.com',
79
+ });
63
80
  const metricsJsModule = await import('./metrics.js');
64
81
  initializeMetricsModule = metricsJsModule.initializeMetrics;
65
82
  recordTokenUsageMetricsModule = metricsJsModule.recordTokenUsageMetrics;
@@ -79,6 +96,12 @@ describe('Telemetry Metrics', () => {
79
96
  recordPerformanceRegressionModule =
80
97
  metricsJsModule.recordPerformanceRegression;
81
98
  recordBaselineComparisonModule = metricsJsModule.recordBaselineComparison;
99
+ recordGenAiClientTokenUsageModule =
100
+ metricsJsModule.recordGenAiClientTokenUsage;
101
+ recordGenAiClientOperationDurationModule =
102
+ metricsJsModule.recordGenAiClientOperationDuration;
103
+ recordFlickerFrameModule = metricsJsModule.recordFlickerFrame;
104
+ recordAgentRunMetricsModule = metricsJsModule.recordAgentRunMetrics;
82
105
  const otelApiModule = await import('@opentelemetry/api');
83
106
  mockCounterAddFn.mockClear();
84
107
  mockCreateCounterFn.mockClear();
@@ -89,6 +112,39 @@ describe('Telemetry Metrics', () => {
89
112
  mockCreateCounterFn.mockReturnValue(mockCounterInstance);
90
113
  mockCreateHistogramFn.mockReturnValue(mockHistogramInstance);
91
114
  });
115
+ describe('recordFlickerFrame', () => {
116
+ it('does not record metrics if not initialized', () => {
117
+ const config = makeFakeConfig({});
118
+ recordFlickerFrameModule(config);
119
+ expect(mockCounterAddFn).not.toHaveBeenCalled();
120
+ });
121
+ it('records a flicker frame event when initialized', () => {
122
+ const config = makeFakeConfig({});
123
+ initializeMetricsModule(config);
124
+ recordFlickerFrameModule(config);
125
+ // Called for session, then for flicker
126
+ expect(mockCounterAddFn).toHaveBeenCalledTimes(2);
127
+ expect(mockCounterAddFn).toHaveBeenNthCalledWith(2, 1, {
128
+ 'session.id': 'test-session-id',
129
+ 'installation.id': 'test-installation-id',
130
+ 'user.email': 'test@example.com',
131
+ });
132
+ });
133
+ });
134
+ describe('initializeMetrics', () => {
135
+ const mockConfig = {
136
+ getSessionId: () => 'test-session-id',
137
+ getTelemetryEnabled: () => true,
138
+ };
139
+ it('should apply common attributes including email', () => {
140
+ initializeMetricsModule(mockConfig);
141
+ expect(mockCounterAddFn).toHaveBeenCalledWith(1, {
142
+ 'session.id': 'test-session-id',
143
+ 'installation.id': 'test-installation-id',
144
+ 'user.email': 'test@example.com',
145
+ });
146
+ });
147
+ });
92
148
  describe('recordChatCompressionMetrics', () => {
93
149
  it('does not record metrics if not initialized', () => {
94
150
  const lol = makeFakeConfig({});
@@ -107,6 +163,8 @@ describe('Telemetry Metrics', () => {
107
163
  });
108
164
  expect(mockCounterAddFn).toHaveBeenCalledWith(1, {
109
165
  'session.id': 'test-session-id',
166
+ 'installation.id': 'test-installation-id',
167
+ 'user.email': 'test@example.com',
110
168
  tokens_after: 100,
111
169
  tokens_before: 200,
112
170
  });
@@ -118,18 +176,28 @@ describe('Telemetry Metrics', () => {
118
176
  getTelemetryEnabled: () => true,
119
177
  };
120
178
  it('should not record metrics if not initialized', () => {
121
- recordTokenUsageMetricsModule(mockConfig, 'gemini-pro', 100, 'input');
179
+ recordTokenUsageMetricsModule(mockConfig, 100, {
180
+ model: 'gemini-pro',
181
+ type: 'input',
182
+ });
122
183
  expect(mockCounterAddFn).not.toHaveBeenCalled();
123
184
  });
124
185
  it('should record token usage with the correct attributes', () => {
125
186
  initializeMetricsModule(mockConfig);
126
- recordTokenUsageMetricsModule(mockConfig, 'gemini-pro', 100, 'input');
187
+ recordTokenUsageMetricsModule(mockConfig, 100, {
188
+ model: 'gemini-pro',
189
+ type: 'input',
190
+ });
127
191
  expect(mockCounterAddFn).toHaveBeenCalledTimes(2);
128
192
  expect(mockCounterAddFn).toHaveBeenNthCalledWith(1, 1, {
129
193
  'session.id': 'test-session-id',
194
+ 'installation.id': 'test-installation-id',
195
+ 'user.email': 'test@example.com',
130
196
  });
131
197
  expect(mockCounterAddFn).toHaveBeenNthCalledWith(2, 100, {
132
198
  'session.id': 'test-session-id',
199
+ 'installation.id': 'test-installation-id',
200
+ 'user.email': 'test@example.com',
133
201
  model: 'gemini-pro',
134
202
  type: 'input',
135
203
  });
@@ -137,27 +205,47 @@ describe('Telemetry Metrics', () => {
137
205
  it('should record token usage for different types', () => {
138
206
  initializeMetricsModule(mockConfig);
139
207
  mockCounterAddFn.mockClear();
140
- recordTokenUsageMetricsModule(mockConfig, 'gemini-pro', 50, 'output');
208
+ recordTokenUsageMetricsModule(mockConfig, 50, {
209
+ model: 'gemini-pro',
210
+ type: 'output',
211
+ });
141
212
  expect(mockCounterAddFn).toHaveBeenCalledWith(50, {
142
213
  'session.id': 'test-session-id',
214
+ 'installation.id': 'test-installation-id',
215
+ 'user.email': 'test@example.com',
143
216
  model: 'gemini-pro',
144
217
  type: 'output',
145
218
  });
146
- recordTokenUsageMetricsModule(mockConfig, 'gemini-pro', 25, 'thought');
219
+ recordTokenUsageMetricsModule(mockConfig, 25, {
220
+ model: 'gemini-pro',
221
+ type: 'thought',
222
+ });
147
223
  expect(mockCounterAddFn).toHaveBeenCalledWith(25, {
148
224
  'session.id': 'test-session-id',
225
+ 'installation.id': 'test-installation-id',
226
+ 'user.email': 'test@example.com',
149
227
  model: 'gemini-pro',
150
228
  type: 'thought',
151
229
  });
152
- recordTokenUsageMetricsModule(mockConfig, 'gemini-pro', 75, 'cache');
230
+ recordTokenUsageMetricsModule(mockConfig, 75, {
231
+ model: 'gemini-pro',
232
+ type: 'cache',
233
+ });
153
234
  expect(mockCounterAddFn).toHaveBeenCalledWith(75, {
154
235
  'session.id': 'test-session-id',
236
+ 'installation.id': 'test-installation-id',
237
+ 'user.email': 'test@example.com',
155
238
  model: 'gemini-pro',
156
239
  type: 'cache',
157
240
  });
158
- recordTokenUsageMetricsModule(mockConfig, 'gemini-pro', 125, 'tool');
241
+ recordTokenUsageMetricsModule(mockConfig, 125, {
242
+ model: 'gemini-pro',
243
+ type: 'tool',
244
+ });
159
245
  expect(mockCounterAddFn).toHaveBeenCalledWith(125, {
160
246
  'session.id': 'test-session-id',
247
+ 'installation.id': 'test-installation-id',
248
+ 'user.email': 'test@example.com',
161
249
  model: 'gemini-pro',
162
250
  type: 'tool',
163
251
  });
@@ -165,9 +253,14 @@ describe('Telemetry Metrics', () => {
165
253
  it('should handle different models', () => {
166
254
  initializeMetricsModule(mockConfig);
167
255
  mockCounterAddFn.mockClear();
168
- recordTokenUsageMetricsModule(mockConfig, 'gemini-ultra', 200, 'input');
256
+ recordTokenUsageMetricsModule(mockConfig, 200, {
257
+ model: 'gemini-ultra',
258
+ type: 'input',
259
+ });
169
260
  expect(mockCounterAddFn).toHaveBeenCalledWith(200, {
170
261
  'session.id': 'test-session-id',
262
+ 'installation.id': 'test-installation-id',
263
+ 'user.email': 'test@example.com',
171
264
  model: 'gemini-ultra',
172
265
  type: 'input',
173
266
  });
@@ -179,18 +272,32 @@ describe('Telemetry Metrics', () => {
179
272
  getTelemetryEnabled: () => true,
180
273
  };
181
274
  it('should not record metrics if not initialized', () => {
182
- recordFileOperationMetricModule(mockConfig, FileOperation.CREATE, 10, 'text/plain', 'txt');
275
+ recordFileOperationMetricModule(mockConfig, {
276
+ operation: FileOperation.CREATE,
277
+ lines: 10,
278
+ mimetype: 'text/plain',
279
+ extension: 'txt',
280
+ });
183
281
  expect(mockCounterAddFn).not.toHaveBeenCalled();
184
282
  });
185
283
  it('should record file creation with all attributes', () => {
186
284
  initializeMetricsModule(mockConfig);
187
- recordFileOperationMetricModule(mockConfig, FileOperation.CREATE, 10, 'text/plain', 'txt');
285
+ recordFileOperationMetricModule(mockConfig, {
286
+ operation: FileOperation.CREATE,
287
+ lines: 10,
288
+ mimetype: 'text/plain',
289
+ extension: 'txt',
290
+ });
188
291
  expect(mockCounterAddFn).toHaveBeenCalledTimes(2);
189
292
  expect(mockCounterAddFn).toHaveBeenNthCalledWith(1, 1, {
190
293
  'session.id': 'test-session-id',
294
+ 'installation.id': 'test-installation-id',
295
+ 'user.email': 'test@example.com',
191
296
  });
192
297
  expect(mockCounterAddFn).toHaveBeenNthCalledWith(2, 1, {
193
298
  'session.id': 'test-session-id',
299
+ 'installation.id': 'test-installation-id',
300
+ 'user.email': 'test@example.com',
194
301
  operation: FileOperation.CREATE,
195
302
  lines: 10,
196
303
  mimetype: 'text/plain',
@@ -200,18 +307,27 @@ describe('Telemetry Metrics', () => {
200
307
  it('should record file read with minimal attributes', () => {
201
308
  initializeMetricsModule(mockConfig);
202
309
  mockCounterAddFn.mockClear();
203
- recordFileOperationMetricModule(mockConfig, FileOperation.READ);
310
+ recordFileOperationMetricModule(mockConfig, {
311
+ operation: FileOperation.READ,
312
+ });
204
313
  expect(mockCounterAddFn).toHaveBeenCalledWith(1, {
205
314
  'session.id': 'test-session-id',
315
+ 'installation.id': 'test-installation-id',
316
+ 'user.email': 'test@example.com',
206
317
  operation: FileOperation.READ,
207
318
  });
208
319
  });
209
320
  it('should record file update with some attributes', () => {
210
321
  initializeMetricsModule(mockConfig);
211
322
  mockCounterAddFn.mockClear();
212
- recordFileOperationMetricModule(mockConfig, FileOperation.UPDATE, undefined, 'application/javascript');
323
+ recordFileOperationMetricModule(mockConfig, {
324
+ operation: FileOperation.UPDATE,
325
+ mimetype: 'application/javascript',
326
+ });
213
327
  expect(mockCounterAddFn).toHaveBeenCalledWith(1, {
214
328
  'session.id': 'test-session-id',
329
+ 'installation.id': 'test-installation-id',
330
+ 'user.email': 'test@example.com',
215
331
  operation: FileOperation.UPDATE,
216
332
  mimetype: 'application/javascript',
217
333
  });
@@ -219,18 +335,29 @@ describe('Telemetry Metrics', () => {
219
335
  it('should record file operation without diffStat', () => {
220
336
  initializeMetricsModule(mockConfig);
221
337
  mockCounterAddFn.mockClear();
222
- recordFileOperationMetricModule(mockConfig, FileOperation.UPDATE, undefined, undefined, undefined);
338
+ recordFileOperationMetricModule(mockConfig, {
339
+ operation: FileOperation.UPDATE,
340
+ });
223
341
  expect(mockCounterAddFn).toHaveBeenCalledWith(1, {
224
342
  'session.id': 'test-session-id',
343
+ 'installation.id': 'test-installation-id',
344
+ 'user.email': 'test@example.com',
225
345
  operation: FileOperation.UPDATE,
226
346
  });
227
347
  });
228
348
  it('should record minimal file operation when optional parameters are undefined', () => {
229
349
  initializeMetricsModule(mockConfig);
230
350
  mockCounterAddFn.mockClear();
231
- recordFileOperationMetricModule(mockConfig, FileOperation.UPDATE, 10, 'text/plain', 'txt', undefined);
351
+ recordFileOperationMetricModule(mockConfig, {
352
+ operation: FileOperation.UPDATE,
353
+ lines: 10,
354
+ mimetype: 'text/plain',
355
+ extension: 'txt',
356
+ });
232
357
  expect(mockCounterAddFn).toHaveBeenCalledWith(1, {
233
358
  'session.id': 'test-session-id',
359
+ 'installation.id': 'test-installation-id',
360
+ 'user.email': 'test@example.com',
234
361
  operation: FileOperation.UPDATE,
235
362
  lines: 10,
236
363
  mimetype: 'text/plain',
@@ -240,9 +367,13 @@ describe('Telemetry Metrics', () => {
240
367
  it('should not include diffStat attributes when diffStat is not provided', () => {
241
368
  initializeMetricsModule(mockConfig);
242
369
  mockCounterAddFn.mockClear();
243
- recordFileOperationMetricModule(mockConfig, FileOperation.UPDATE, undefined, undefined, undefined);
370
+ recordFileOperationMetricModule(mockConfig, {
371
+ operation: FileOperation.UPDATE,
372
+ });
244
373
  expect(mockCounterAddFn).toHaveBeenCalledWith(1, {
245
374
  'session.id': 'test-session-id',
375
+ 'installation.id': 'test-installation-id',
376
+ 'user.email': 'test@example.com',
246
377
  operation: FileOperation.UPDATE,
247
378
  });
248
379
  });
@@ -264,6 +395,8 @@ describe('Telemetry Metrics', () => {
264
395
  recordModelRoutingMetricsModule(mockConfig, event);
265
396
  expect(mockHistogramRecordFn).toHaveBeenCalledWith(150, {
266
397
  'session.id': 'test-session-id',
398
+ 'installation.id': 'test-installation-id',
399
+ 'user.email': 'test@example.com',
267
400
  'routing.decision_model': 'gemini-pro',
268
401
  'routing.decision_source': 'default',
269
402
  });
@@ -276,17 +409,226 @@ describe('Telemetry Metrics', () => {
276
409
  recordModelRoutingMetricsModule(mockConfig, event);
277
410
  expect(mockHistogramRecordFn).toHaveBeenCalledWith(200, {
278
411
  'session.id': 'test-session-id',
412
+ 'installation.id': 'test-installation-id',
413
+ 'user.email': 'test@example.com',
279
414
  'routing.decision_model': 'gemini-pro',
280
415
  'routing.decision_source': 'classifier',
281
416
  });
282
417
  expect(mockCounterAddFn).toHaveBeenCalledTimes(2);
283
418
  expect(mockCounterAddFn).toHaveBeenNthCalledWith(2, 1, {
284
419
  'session.id': 'test-session-id',
420
+ 'installation.id': 'test-installation-id',
421
+ 'user.email': 'test@example.com',
285
422
  'routing.decision_source': 'classifier',
286
423
  'routing.error_message': 'test-error',
287
424
  });
288
425
  });
289
426
  });
427
+ describe('recordAgentRunMetrics', () => {
428
+ const mockConfig = {
429
+ getSessionId: () => 'test-session-id',
430
+ getTelemetryEnabled: () => true,
431
+ };
432
+ it('should not record metrics if not initialized', () => {
433
+ const event = new AgentFinishEvent('agent-123', 'TestAgent', 1000, 5, AgentTerminateMode.GOAL);
434
+ recordAgentRunMetricsModule(mockConfig, event);
435
+ expect(mockCounterAddFn).not.toHaveBeenCalled();
436
+ expect(mockHistogramRecordFn).not.toHaveBeenCalled();
437
+ });
438
+ it('should record agent run metrics', () => {
439
+ initializeMetricsModule(mockConfig);
440
+ mockCounterAddFn.mockClear();
441
+ mockHistogramRecordFn.mockClear();
442
+ const event = new AgentFinishEvent('agent-123', 'TestAgent', 1000, 5, AgentTerminateMode.GOAL);
443
+ recordAgentRunMetricsModule(mockConfig, event);
444
+ // Verify agent run counter
445
+ expect(mockCounterAddFn).toHaveBeenCalledWith(1, {
446
+ 'session.id': 'test-session-id',
447
+ 'installation.id': 'test-installation-id',
448
+ 'user.email': 'test@example.com',
449
+ agent_name: 'TestAgent',
450
+ terminate_reason: 'GOAL',
451
+ });
452
+ // Verify agent duration histogram
453
+ expect(mockHistogramRecordFn).toHaveBeenCalledWith(1000, {
454
+ 'session.id': 'test-session-id',
455
+ 'installation.id': 'test-installation-id',
456
+ 'user.email': 'test@example.com',
457
+ agent_name: 'TestAgent',
458
+ });
459
+ // Verify agent turns histogram
460
+ expect(mockHistogramRecordFn).toHaveBeenCalledWith(5, {
461
+ 'session.id': 'test-session-id',
462
+ 'installation.id': 'test-installation-id',
463
+ 'user.email': 'test@example.com',
464
+ agent_name: 'TestAgent',
465
+ });
466
+ });
467
+ });
468
+ describe('OpenTelemetry GenAI Semantic Convention Metrics', () => {
469
+ const mockConfig = {
470
+ getSessionId: () => 'test-session-id',
471
+ getTelemetryEnabled: () => true,
472
+ };
473
+ describe('recordGenAiClientTokenUsage', () => {
474
+ it('should not record metrics when not initialized', () => {
475
+ recordGenAiClientTokenUsageModule(mockConfig, 100, {
476
+ 'gen_ai.operation.name': 'generate_content',
477
+ 'gen_ai.provider.name': 'gcp.gen_ai',
478
+ 'gen_ai.token.type': 'input',
479
+ });
480
+ expect(mockHistogramRecordFn).not.toHaveBeenCalled();
481
+ });
482
+ it('should record input token usage with correct attributes', () => {
483
+ initializeMetricsModule(mockConfig);
484
+ mockHistogramRecordFn.mockClear();
485
+ recordGenAiClientTokenUsageModule(mockConfig, 150, {
486
+ 'gen_ai.operation.name': 'generate_content',
487
+ 'gen_ai.provider.name': 'gcp.gen_ai',
488
+ 'gen_ai.token.type': 'input',
489
+ 'gen_ai.request.model': 'gemini-2.0-flash',
490
+ 'gen_ai.response.model': 'gemini-2.0-flash',
491
+ });
492
+ expect(mockHistogramRecordFn).toHaveBeenCalledWith(150, {
493
+ 'session.id': 'test-session-id',
494
+ 'installation.id': 'test-installation-id',
495
+ 'user.email': 'test@example.com',
496
+ 'gen_ai.operation.name': 'generate_content',
497
+ 'gen_ai.provider.name': 'gcp.gen_ai',
498
+ 'gen_ai.token.type': 'input',
499
+ 'gen_ai.request.model': 'gemini-2.0-flash',
500
+ 'gen_ai.response.model': 'gemini-2.0-flash',
501
+ });
502
+ });
503
+ it('should record output token usage with correct attributes', () => {
504
+ initializeMetricsModule(mockConfig);
505
+ mockHistogramRecordFn.mockClear();
506
+ recordGenAiClientTokenUsageModule(mockConfig, 75, {
507
+ 'gen_ai.operation.name': 'generate_content',
508
+ 'gen_ai.provider.name': 'gcp.vertex_ai',
509
+ 'gen_ai.token.type': 'output',
510
+ 'gen_ai.request.model': 'gemini-pro',
511
+ });
512
+ expect(mockHistogramRecordFn).toHaveBeenCalledWith(75, {
513
+ 'session.id': 'test-session-id',
514
+ 'installation.id': 'test-installation-id',
515
+ 'user.email': 'test@example.com',
516
+ 'gen_ai.operation.name': 'generate_content',
517
+ 'gen_ai.provider.name': 'gcp.vertex_ai',
518
+ 'gen_ai.token.type': 'output',
519
+ 'gen_ai.request.model': 'gemini-pro',
520
+ });
521
+ });
522
+ it('should record token usage with optional attributes', () => {
523
+ initializeMetricsModule(mockConfig);
524
+ mockHistogramRecordFn.mockClear();
525
+ recordGenAiClientTokenUsageModule(mockConfig, 200, {
526
+ 'gen_ai.operation.name': 'generate_content',
527
+ 'gen_ai.provider.name': 'gcp.vertex_ai',
528
+ 'gen_ai.token.type': 'input',
529
+ 'gen_ai.request.model': 'text-embedding-004',
530
+ 'server.address': 'aiplatform.googleapis.com',
531
+ 'server.port': 443,
532
+ });
533
+ expect(mockHistogramRecordFn).toHaveBeenCalledWith(200, {
534
+ 'session.id': 'test-session-id',
535
+ 'installation.id': 'test-installation-id',
536
+ 'user.email': 'test@example.com',
537
+ 'gen_ai.operation.name': 'generate_content',
538
+ 'gen_ai.provider.name': 'gcp.vertex_ai',
539
+ 'gen_ai.token.type': 'input',
540
+ 'gen_ai.request.model': 'text-embedding-004',
541
+ 'server.address': 'aiplatform.googleapis.com',
542
+ 'server.port': 443,
543
+ });
544
+ });
545
+ });
546
+ describe('recordGenAiClientOperationDuration', () => {
547
+ it('should not record metrics when not initialized', () => {
548
+ recordGenAiClientOperationDurationModule(mockConfig, 2.5, {
549
+ 'gen_ai.operation.name': 'generate_content',
550
+ 'gen_ai.provider.name': 'gcp.gen_ai',
551
+ });
552
+ expect(mockHistogramRecordFn).not.toHaveBeenCalled();
553
+ });
554
+ it('should record successful operation duration with correct attributes', () => {
555
+ initializeMetricsModule(mockConfig);
556
+ mockHistogramRecordFn.mockClear();
557
+ recordGenAiClientOperationDurationModule(mockConfig, 1.25, {
558
+ 'gen_ai.operation.name': 'generate_content',
559
+ 'gen_ai.provider.name': 'gcp.gen_ai',
560
+ 'gen_ai.request.model': 'gemini-2.0-flash',
561
+ 'gen_ai.response.model': 'gemini-2.0-flash',
562
+ });
563
+ expect(mockHistogramRecordFn).toHaveBeenCalledWith(1.25, {
564
+ 'session.id': 'test-session-id',
565
+ 'installation.id': 'test-installation-id',
566
+ 'user.email': 'test@example.com',
567
+ 'gen_ai.operation.name': 'generate_content',
568
+ 'gen_ai.provider.name': 'gcp.gen_ai',
569
+ 'gen_ai.request.model': 'gemini-2.0-flash',
570
+ 'gen_ai.response.model': 'gemini-2.0-flash',
571
+ });
572
+ });
573
+ it('should record failed operation duration with error type', () => {
574
+ initializeMetricsModule(mockConfig);
575
+ mockHistogramRecordFn.mockClear();
576
+ recordGenAiClientOperationDurationModule(mockConfig, 3.75, {
577
+ 'gen_ai.operation.name': 'generate_content',
578
+ 'gen_ai.provider.name': 'gcp.vertex_ai',
579
+ 'gen_ai.request.model': 'gemini-pro',
580
+ 'error.type': 'quota_exceeded',
581
+ });
582
+ expect(mockHistogramRecordFn).toHaveBeenCalledWith(3.75, {
583
+ 'session.id': 'test-session-id',
584
+ 'installation.id': 'test-installation-id',
585
+ 'user.email': 'test@example.com',
586
+ 'gen_ai.operation.name': 'generate_content',
587
+ 'gen_ai.provider.name': 'gcp.vertex_ai',
588
+ 'gen_ai.request.model': 'gemini-pro',
589
+ 'error.type': 'quota_exceeded',
590
+ });
591
+ });
592
+ it('should record operation duration with server details', () => {
593
+ initializeMetricsModule(mockConfig);
594
+ mockHistogramRecordFn.mockClear();
595
+ recordGenAiClientOperationDurationModule(mockConfig, 0.95, {
596
+ 'gen_ai.operation.name': 'generate_content',
597
+ 'gen_ai.provider.name': 'gcp.vertex_ai',
598
+ 'gen_ai.request.model': 'gemini-1.5-pro',
599
+ 'gen_ai.response.model': 'gemini-1.5-pro-001',
600
+ 'server.address': 'us-central1-aiplatform.googleapis.com',
601
+ 'server.port': 443,
602
+ });
603
+ expect(mockHistogramRecordFn).toHaveBeenCalledWith(0.95, {
604
+ 'session.id': 'test-session-id',
605
+ 'installation.id': 'test-installation-id',
606
+ 'user.email': 'test@example.com',
607
+ 'gen_ai.operation.name': 'generate_content',
608
+ 'gen_ai.provider.name': 'gcp.vertex_ai',
609
+ 'gen_ai.request.model': 'gemini-1.5-pro',
610
+ 'gen_ai.response.model': 'gemini-1.5-pro-001',
611
+ 'server.address': 'us-central1-aiplatform.googleapis.com',
612
+ 'server.port': 443,
613
+ });
614
+ });
615
+ it('should handle minimal required attributes', () => {
616
+ initializeMetricsModule(mockConfig);
617
+ mockHistogramRecordFn.mockClear();
618
+ recordGenAiClientOperationDurationModule(mockConfig, 2.1, {
619
+ 'gen_ai.operation.name': 'generate_content',
620
+ 'gen_ai.provider.name': 'gcp.gen_ai',
621
+ });
622
+ expect(mockHistogramRecordFn).toHaveBeenCalledWith(2.1, {
623
+ 'session.id': 'test-session-id',
624
+ 'installation.id': 'test-installation-id',
625
+ 'user.email': 'test@example.com',
626
+ 'gen_ai.operation.name': 'generate_content',
627
+ 'gen_ai.provider.name': 'gcp.gen_ai',
628
+ });
629
+ });
630
+ });
631
+ });
290
632
  describe('Performance Monitoring Metrics', () => {
291
633
  const mockConfig = {
292
634
  getSessionId: () => 'test-session-id',
@@ -301,21 +643,29 @@ describe('Telemetry Metrics', () => {
301
643
  };
302
644
  initializeMetricsModule(mockConfigDisabled);
303
645
  mockHistogramRecordFn.mockClear();
304
- recordStartupPerformanceModule(mockConfigDisabled, 'settings_loading', 100, {
305
- auth_type: 'gemini',
646
+ recordStartupPerformanceModule(mockConfigDisabled, 100, {
647
+ phase: 'settings_loading',
648
+ details: {
649
+ auth_type: 'gemini',
650
+ },
306
651
  });
307
652
  expect(mockHistogramRecordFn).not.toHaveBeenCalled();
308
653
  });
309
654
  it('should record startup performance with phase and details', () => {
310
655
  initializeMetricsModule(mockConfig);
311
656
  mockHistogramRecordFn.mockClear();
312
- recordStartupPerformanceModule(mockConfig, 'settings_loading', 150, {
313
- auth_type: 'gemini',
314
- telemetry_enabled: true,
315
- settings_sources: 2,
657
+ recordStartupPerformanceModule(mockConfig, 150, {
658
+ phase: 'settings_loading',
659
+ details: {
660
+ auth_type: 'gemini',
661
+ telemetry_enabled: true,
662
+ settings_sources: 2,
663
+ },
316
664
  });
317
665
  expect(mockHistogramRecordFn).toHaveBeenCalledWith(150, {
318
666
  'session.id': 'test-session-id',
667
+ 'installation.id': 'test-installation-id',
668
+ 'user.email': 'test@example.com',
319
669
  phase: 'settings_loading',
320
670
  auth_type: 'gemini',
321
671
  telemetry_enabled: true,
@@ -325,9 +675,11 @@ describe('Telemetry Metrics', () => {
325
675
  it('should record startup performance without details', () => {
326
676
  initializeMetricsModule(mockConfig);
327
677
  mockHistogramRecordFn.mockClear();
328
- recordStartupPerformanceModule(mockConfig, 'cleanup', 50);
678
+ recordStartupPerformanceModule(mockConfig, 50, { phase: 'cleanup' });
329
679
  expect(mockHistogramRecordFn).toHaveBeenCalledWith(50, {
330
680
  'session.id': 'test-session-id',
681
+ 'installation.id': 'test-installation-id',
682
+ 'user.email': 'test@example.com',
331
683
  phase: 'cleanup',
332
684
  });
333
685
  });
@@ -336,12 +688,17 @@ describe('Telemetry Metrics', () => {
336
688
  mockHistogramRecordFn.mockClear();
337
689
  // Test with realistic floating-point values that performance.now() would return
338
690
  const floatingPointDuration = 123.45678;
339
- recordStartupPerformanceModule(mockConfig, 'total_startup', floatingPointDuration, {
340
- is_tty: true,
341
- has_question: false,
691
+ recordStartupPerformanceModule(mockConfig, floatingPointDuration, {
692
+ phase: 'total_startup',
693
+ details: {
694
+ is_tty: true,
695
+ has_question: false,
696
+ },
342
697
  });
343
698
  expect(mockHistogramRecordFn).toHaveBeenCalledWith(floatingPointDuration, {
344
699
  'session.id': 'test-session-id',
700
+ 'installation.id': 'test-installation-id',
701
+ 'user.email': 'test@example.com',
345
702
  phase: 'total_startup',
346
703
  is_tty: true,
347
704
  has_question: false,
@@ -352,9 +709,14 @@ describe('Telemetry Metrics', () => {
352
709
  it('should record memory usage for different memory types', () => {
353
710
  initializeMetricsModule(mockConfig);
354
711
  mockHistogramRecordFn.mockClear();
355
- recordMemoryUsageModule(mockConfig, MemoryMetricType.HEAP_USED, 15728640, 'startup');
712
+ recordMemoryUsageModule(mockConfig, 15728640, {
713
+ memory_type: MemoryMetricType.HEAP_USED,
714
+ component: 'startup',
715
+ });
356
716
  expect(mockHistogramRecordFn).toHaveBeenCalledWith(15728640, {
357
717
  'session.id': 'test-session-id',
718
+ 'installation.id': 'test-installation-id',
719
+ 'user.email': 'test@example.com',
358
720
  memory_type: 'heap_used',
359
721
  component: 'startup',
360
722
  });
@@ -362,22 +724,37 @@ describe('Telemetry Metrics', () => {
362
724
  it('should record memory usage for all memory metric types', () => {
363
725
  initializeMetricsModule(mockConfig);
364
726
  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');
727
+ recordMemoryUsageModule(mockConfig, 31457280, {
728
+ memory_type: MemoryMetricType.HEAP_TOTAL,
729
+ component: 'api_call',
730
+ });
731
+ recordMemoryUsageModule(mockConfig, 2097152, {
732
+ memory_type: MemoryMetricType.EXTERNAL,
733
+ component: 'tool_execution',
734
+ });
735
+ recordMemoryUsageModule(mockConfig, 41943040, {
736
+ memory_type: MemoryMetricType.RSS,
737
+ component: 'memory_monitor',
738
+ });
368
739
  expect(mockHistogramRecordFn).toHaveBeenCalledTimes(3); // One for each call
369
740
  expect(mockHistogramRecordFn).toHaveBeenNthCalledWith(1, 31457280, {
370
741
  'session.id': 'test-session-id',
742
+ 'installation.id': 'test-installation-id',
743
+ 'user.email': 'test@example.com',
371
744
  memory_type: 'heap_total',
372
745
  component: 'api_call',
373
746
  });
374
747
  expect(mockHistogramRecordFn).toHaveBeenNthCalledWith(2, 2097152, {
375
748
  'session.id': 'test-session-id',
749
+ 'installation.id': 'test-installation-id',
750
+ 'user.email': 'test@example.com',
376
751
  memory_type: 'external',
377
752
  component: 'tool_execution',
378
753
  });
379
754
  expect(mockHistogramRecordFn).toHaveBeenNthCalledWith(3, 41943040, {
380
755
  'session.id': 'test-session-id',
756
+ 'installation.id': 'test-installation-id',
757
+ 'user.email': 'test@example.com',
381
758
  memory_type: 'rss',
382
759
  component: 'memory_monitor',
383
760
  });
@@ -385,11 +762,14 @@ describe('Telemetry Metrics', () => {
385
762
  it('should record memory usage without component', () => {
386
763
  initializeMetricsModule(mockConfig);
387
764
  mockHistogramRecordFn.mockClear();
388
- recordMemoryUsageModule(mockConfig, MemoryMetricType.HEAP_USED, 15728640);
765
+ recordMemoryUsageModule(mockConfig, 15728640, {
766
+ memory_type: MemoryMetricType.HEAP_USED,
767
+ });
389
768
  expect(mockHistogramRecordFn).toHaveBeenCalledWith(15728640, {
390
769
  'session.id': 'test-session-id',
770
+ 'installation.id': 'test-installation-id',
771
+ 'user.email': 'test@example.com',
391
772
  memory_type: 'heap_used',
392
- component: undefined,
393
773
  });
394
774
  });
395
775
  });
@@ -397,19 +777,24 @@ describe('Telemetry Metrics', () => {
397
777
  it('should record CPU usage percentage', () => {
398
778
  initializeMetricsModule(mockConfig);
399
779
  mockHistogramRecordFn.mockClear();
400
- recordCpuUsageModule(mockConfig, 85.5, 'tool_execution');
780
+ recordCpuUsageModule(mockConfig, 85.5, {
781
+ component: 'tool_execution',
782
+ });
401
783
  expect(mockHistogramRecordFn).toHaveBeenCalledWith(85.5, {
402
784
  'session.id': 'test-session-id',
785
+ 'installation.id': 'test-installation-id',
786
+ 'user.email': 'test@example.com',
403
787
  component: 'tool_execution',
404
788
  });
405
789
  });
406
790
  it('should record CPU usage without component', () => {
407
791
  initializeMetricsModule(mockConfig);
408
792
  mockHistogramRecordFn.mockClear();
409
- recordCpuUsageModule(mockConfig, 42.3);
793
+ recordCpuUsageModule(mockConfig, 42.3, {});
410
794
  expect(mockHistogramRecordFn).toHaveBeenCalledWith(42.3, {
411
795
  'session.id': 'test-session-id',
412
- component: undefined,
796
+ 'installation.id': 'test-installation-id',
797
+ 'user.email': 'test@example.com',
413
798
  });
414
799
  });
415
800
  });
@@ -420,6 +805,8 @@ describe('Telemetry Metrics', () => {
420
805
  recordToolQueueDepthModule(mockConfig, 3);
421
806
  expect(mockHistogramRecordFn).toHaveBeenCalledWith(3, {
422
807
  'session.id': 'test-session-id',
808
+ 'installation.id': 'test-installation-id',
809
+ 'user.email': 'test@example.com',
423
810
  });
424
811
  });
425
812
  it('should record zero queue depth', () => {
@@ -428,6 +815,8 @@ describe('Telemetry Metrics', () => {
428
815
  recordToolQueueDepthModule(mockConfig, 0);
429
816
  expect(mockHistogramRecordFn).toHaveBeenCalledWith(0, {
430
817
  'session.id': 'test-session-id',
818
+ 'installation.id': 'test-installation-id',
819
+ 'user.email': 'test@example.com',
431
820
  });
432
821
  });
433
822
  });
@@ -435,9 +824,14 @@ describe('Telemetry Metrics', () => {
435
824
  it('should record tool execution breakdown for all phases', () => {
436
825
  initializeMetricsModule(mockConfig);
437
826
  mockHistogramRecordFn.mockClear();
438
- recordToolExecutionBreakdownModule(mockConfig, 'Read', ToolExecutionPhase.VALIDATION, 25);
827
+ recordToolExecutionBreakdownModule(mockConfig, 25, {
828
+ function_name: 'Read',
829
+ phase: ToolExecutionPhase.VALIDATION,
830
+ });
439
831
  expect(mockHistogramRecordFn).toHaveBeenCalledWith(25, {
440
832
  'session.id': 'test-session-id',
833
+ 'installation.id': 'test-installation-id',
834
+ 'user.email': 'test@example.com',
441
835
  function_name: 'Read',
442
836
  phase: 'validation',
443
837
  });
@@ -445,22 +839,37 @@ describe('Telemetry Metrics', () => {
445
839
  it('should record execution breakdown for different phases', () => {
446
840
  initializeMetricsModule(mockConfig);
447
841
  mockHistogramRecordFn.mockClear();
448
- recordToolExecutionBreakdownModule(mockConfig, 'Bash', ToolExecutionPhase.PREPARATION, 50);
449
- recordToolExecutionBreakdownModule(mockConfig, 'Bash', ToolExecutionPhase.EXECUTION, 1500);
450
- recordToolExecutionBreakdownModule(mockConfig, 'Bash', ToolExecutionPhase.RESULT_PROCESSING, 75);
842
+ recordToolExecutionBreakdownModule(mockConfig, 50, {
843
+ function_name: 'Bash',
844
+ phase: ToolExecutionPhase.PREPARATION,
845
+ });
846
+ recordToolExecutionBreakdownModule(mockConfig, 1500, {
847
+ function_name: 'Bash',
848
+ phase: ToolExecutionPhase.EXECUTION,
849
+ });
850
+ recordToolExecutionBreakdownModule(mockConfig, 75, {
851
+ function_name: 'Bash',
852
+ phase: ToolExecutionPhase.RESULT_PROCESSING,
853
+ });
451
854
  expect(mockHistogramRecordFn).toHaveBeenCalledTimes(3); // One for each call
452
855
  expect(mockHistogramRecordFn).toHaveBeenNthCalledWith(1, 50, {
453
856
  'session.id': 'test-session-id',
857
+ 'installation.id': 'test-installation-id',
858
+ 'user.email': 'test@example.com',
454
859
  function_name: 'Bash',
455
860
  phase: 'preparation',
456
861
  });
457
862
  expect(mockHistogramRecordFn).toHaveBeenNthCalledWith(2, 1500, {
458
863
  'session.id': 'test-session-id',
864
+ 'installation.id': 'test-installation-id',
865
+ 'user.email': 'test@example.com',
459
866
  function_name: 'Bash',
460
867
  phase: 'execution',
461
868
  });
462
869
  expect(mockHistogramRecordFn).toHaveBeenNthCalledWith(3, 75, {
463
870
  'session.id': 'test-session-id',
871
+ 'installation.id': 'test-installation-id',
872
+ 'user.email': 'test@example.com',
464
873
  function_name: 'Bash',
465
874
  phase: 'result_processing',
466
875
  });
@@ -470,9 +879,15 @@ describe('Telemetry Metrics', () => {
470
879
  it('should record token efficiency metrics', () => {
471
880
  initializeMetricsModule(mockConfig);
472
881
  mockHistogramRecordFn.mockClear();
473
- recordTokenEfficiencyModule(mockConfig, 'gemini-pro', 'cache_hit_rate', 0.85, 'api_request');
882
+ recordTokenEfficiencyModule(mockConfig, 0.85, {
883
+ model: 'gemini-pro',
884
+ metric: 'cache_hit_rate',
885
+ context: 'api_request',
886
+ });
474
887
  expect(mockHistogramRecordFn).toHaveBeenCalledWith(0.85, {
475
888
  'session.id': 'test-session-id',
889
+ 'installation.id': 'test-installation-id',
890
+ 'user.email': 'test@example.com',
476
891
  model: 'gemini-pro',
477
892
  metric: 'cache_hit_rate',
478
893
  context: 'api_request',
@@ -481,12 +896,16 @@ describe('Telemetry Metrics', () => {
481
896
  it('should record token efficiency without context', () => {
482
897
  initializeMetricsModule(mockConfig);
483
898
  mockHistogramRecordFn.mockClear();
484
- recordTokenEfficiencyModule(mockConfig, 'gemini-pro', 'tokens_per_operation', 125.5);
899
+ recordTokenEfficiencyModule(mockConfig, 125.5, {
900
+ model: 'gemini-pro',
901
+ metric: 'tokens_per_operation',
902
+ });
485
903
  expect(mockHistogramRecordFn).toHaveBeenCalledWith(125.5, {
486
904
  'session.id': 'test-session-id',
905
+ 'installation.id': 'test-installation-id',
906
+ 'user.email': 'test@example.com',
487
907
  model: 'gemini-pro',
488
908
  metric: 'tokens_per_operation',
489
- context: undefined,
490
909
  });
491
910
  });
492
911
  });
@@ -494,9 +913,14 @@ describe('Telemetry Metrics', () => {
494
913
  it('should record API request breakdown for all phases', () => {
495
914
  initializeMetricsModule(mockConfig);
496
915
  mockHistogramRecordFn.mockClear();
497
- recordApiRequestBreakdownModule(mockConfig, 'gemini-pro', ApiRequestPhase.REQUEST_PREPARATION, 15);
916
+ recordApiRequestBreakdownModule(mockConfig, 15, {
917
+ model: 'gemini-pro',
918
+ phase: ApiRequestPhase.REQUEST_PREPARATION,
919
+ });
498
920
  expect(mockHistogramRecordFn).toHaveBeenCalledWith(15, {
499
921
  'session.id': 'test-session-id',
922
+ 'installation.id': 'test-installation-id',
923
+ 'user.email': 'test@example.com',
500
924
  model: 'gemini-pro',
501
925
  phase: 'request_preparation',
502
926
  });
@@ -504,22 +928,37 @@ describe('Telemetry Metrics', () => {
504
928
  it('should record API request breakdown for different phases', () => {
505
929
  initializeMetricsModule(mockConfig);
506
930
  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);
931
+ recordApiRequestBreakdownModule(mockConfig, 250, {
932
+ model: 'gemini-pro',
933
+ phase: ApiRequestPhase.NETWORK_LATENCY,
934
+ });
935
+ recordApiRequestBreakdownModule(mockConfig, 100, {
936
+ model: 'gemini-pro',
937
+ phase: ApiRequestPhase.RESPONSE_PROCESSING,
938
+ });
939
+ recordApiRequestBreakdownModule(mockConfig, 50, {
940
+ model: 'gemini-pro',
941
+ phase: ApiRequestPhase.TOKEN_PROCESSING,
942
+ });
510
943
  expect(mockHistogramRecordFn).toHaveBeenCalledTimes(3); // One for each call
511
944
  expect(mockHistogramRecordFn).toHaveBeenNthCalledWith(1, 250, {
512
945
  'session.id': 'test-session-id',
946
+ 'installation.id': 'test-installation-id',
947
+ 'user.email': 'test@example.com',
513
948
  model: 'gemini-pro',
514
949
  phase: 'network_latency',
515
950
  });
516
951
  expect(mockHistogramRecordFn).toHaveBeenNthCalledWith(2, 100, {
517
952
  'session.id': 'test-session-id',
953
+ 'installation.id': 'test-installation-id',
954
+ 'user.email': 'test@example.com',
518
955
  model: 'gemini-pro',
519
956
  phase: 'response_processing',
520
957
  });
521
958
  expect(mockHistogramRecordFn).toHaveBeenNthCalledWith(3, 50, {
522
959
  'session.id': 'test-session-id',
960
+ 'installation.id': 'test-installation-id',
961
+ 'user.email': 'test@example.com',
523
962
  model: 'gemini-pro',
524
963
  phase: 'token_processing',
525
964
  });
@@ -529,9 +968,14 @@ describe('Telemetry Metrics', () => {
529
968
  it('should record performance score with category and baseline', () => {
530
969
  initializeMetricsModule(mockConfig);
531
970
  mockHistogramRecordFn.mockClear();
532
- recordPerformanceScoreModule(mockConfig, 85.5, 'memory_efficiency', 80.0);
971
+ recordPerformanceScoreModule(mockConfig, 85.5, {
972
+ category: 'memory_efficiency',
973
+ baseline: 80.0,
974
+ });
533
975
  expect(mockHistogramRecordFn).toHaveBeenCalledWith(85.5, {
534
976
  'session.id': 'test-session-id',
977
+ 'installation.id': 'test-installation-id',
978
+ 'user.email': 'test@example.com',
535
979
  category: 'memory_efficiency',
536
980
  baseline: 80.0,
537
981
  });
@@ -539,11 +983,14 @@ describe('Telemetry Metrics', () => {
539
983
  it('should record performance score without baseline', () => {
540
984
  initializeMetricsModule(mockConfig);
541
985
  mockHistogramRecordFn.mockClear();
542
- recordPerformanceScoreModule(mockConfig, 92.3, 'overall_performance');
986
+ recordPerformanceScoreModule(mockConfig, 92.3, {
987
+ category: 'overall_performance',
988
+ });
543
989
  expect(mockHistogramRecordFn).toHaveBeenCalledWith(92.3, {
544
990
  'session.id': 'test-session-id',
991
+ 'installation.id': 'test-installation-id',
992
+ 'user.email': 'test@example.com',
545
993
  category: 'overall_performance',
546
- baseline: undefined,
547
994
  });
548
995
  });
549
996
  });
@@ -552,10 +999,17 @@ describe('Telemetry Metrics', () => {
552
999
  initializeMetricsModule(mockConfig);
553
1000
  mockCounterAddFn.mockClear();
554
1001
  mockHistogramRecordFn.mockClear();
555
- recordPerformanceRegressionModule(mockConfig, 'startup_time', 1200, 1000, 'medium');
1002
+ recordPerformanceRegressionModule(mockConfig, {
1003
+ metric: 'startup_time',
1004
+ current_value: 1200,
1005
+ baseline_value: 1000,
1006
+ severity: 'medium',
1007
+ });
556
1008
  // Verify regression counter
557
1009
  expect(mockCounterAddFn).toHaveBeenCalledWith(1, {
558
1010
  'session.id': 'test-session-id',
1011
+ 'installation.id': 'test-installation-id',
1012
+ 'user.email': 'test@example.com',
559
1013
  metric: 'startup_time',
560
1014
  severity: 'medium',
561
1015
  current_value: 1200,
@@ -564,6 +1018,8 @@ describe('Telemetry Metrics', () => {
564
1018
  // Verify baseline comparison histogram (20% increase)
565
1019
  expect(mockHistogramRecordFn).toHaveBeenCalledWith(20, {
566
1020
  'session.id': 'test-session-id',
1021
+ 'installation.id': 'test-installation-id',
1022
+ 'user.email': 'test@example.com',
567
1023
  metric: 'startup_time',
568
1024
  severity: 'medium',
569
1025
  current_value: 1200,
@@ -574,10 +1030,17 @@ describe('Telemetry Metrics', () => {
574
1030
  initializeMetricsModule(mockConfig);
575
1031
  mockCounterAddFn.mockClear();
576
1032
  mockHistogramRecordFn.mockClear();
577
- recordPerformanceRegressionModule(mockConfig, 'memory_usage', 100, 0, 'high');
1033
+ recordPerformanceRegressionModule(mockConfig, {
1034
+ metric: 'memory_usage',
1035
+ current_value: 100,
1036
+ baseline_value: 0,
1037
+ severity: 'high',
1038
+ });
578
1039
  // Verify regression counter still recorded
579
1040
  expect(mockCounterAddFn).toHaveBeenCalledWith(1, {
580
1041
  'session.id': 'test-session-id',
1042
+ 'installation.id': 'test-installation-id',
1043
+ 'user.email': 'test@example.com',
581
1044
  metric: 'memory_usage',
582
1045
  severity: 'high',
583
1046
  current_value: 100,
@@ -589,10 +1052,22 @@ describe('Telemetry Metrics', () => {
589
1052
  it('should record different severity levels', () => {
590
1053
  initializeMetricsModule(mockConfig);
591
1054
  mockCounterAddFn.mockClear();
592
- recordPerformanceRegressionModule(mockConfig, 'api_latency', 500, 400, 'low');
593
- recordPerformanceRegressionModule(mockConfig, 'cpu_usage', 90, 70, 'high');
1055
+ recordPerformanceRegressionModule(mockConfig, {
1056
+ metric: 'api_latency',
1057
+ current_value: 500,
1058
+ baseline_value: 400,
1059
+ severity: 'low',
1060
+ });
1061
+ recordPerformanceRegressionModule(mockConfig, {
1062
+ metric: 'cpu_usage',
1063
+ current_value: 90,
1064
+ baseline_value: 70,
1065
+ severity: 'high',
1066
+ });
594
1067
  expect(mockCounterAddFn).toHaveBeenNthCalledWith(1, 1, {
595
1068
  'session.id': 'test-session-id',
1069
+ 'installation.id': 'test-installation-id',
1070
+ 'user.email': 'test@example.com',
596
1071
  metric: 'api_latency',
597
1072
  severity: 'low',
598
1073
  current_value: 500,
@@ -600,6 +1075,8 @@ describe('Telemetry Metrics', () => {
600
1075
  });
601
1076
  expect(mockCounterAddFn).toHaveBeenNthCalledWith(2, 1, {
602
1077
  'session.id': 'test-session-id',
1078
+ 'installation.id': 'test-installation-id',
1079
+ 'user.email': 'test@example.com',
603
1080
  metric: 'cpu_usage',
604
1081
  severity: 'high',
605
1082
  current_value: 90,
@@ -611,10 +1088,17 @@ describe('Telemetry Metrics', () => {
611
1088
  it('should record baseline comparison with percentage change', () => {
612
1089
  initializeMetricsModule(mockConfig);
613
1090
  mockHistogramRecordFn.mockClear();
614
- recordBaselineComparisonModule(mockConfig, 'memory_usage', 120, 100, 'performance_tracking');
1091
+ recordBaselineComparisonModule(mockConfig, {
1092
+ metric: 'memory_usage',
1093
+ current_value: 120,
1094
+ baseline_value: 100,
1095
+ category: 'performance_tracking',
1096
+ });
615
1097
  // 20% increase: (120 - 100) / 100 * 100 = 20%
616
1098
  expect(mockHistogramRecordFn).toHaveBeenCalledWith(20, {
617
1099
  'session.id': 'test-session-id',
1100
+ 'installation.id': 'test-installation-id',
1101
+ 'user.email': 'test@example.com',
618
1102
  metric: 'memory_usage',
619
1103
  category: 'performance_tracking',
620
1104
  current_value: 120,
@@ -624,10 +1108,17 @@ describe('Telemetry Metrics', () => {
624
1108
  it('should handle negative percentage change (improvement)', () => {
625
1109
  initializeMetricsModule(mockConfig);
626
1110
  mockHistogramRecordFn.mockClear();
627
- recordBaselineComparisonModule(mockConfig, 'startup_time', 800, 1000, 'optimization');
1111
+ recordBaselineComparisonModule(mockConfig, {
1112
+ metric: 'startup_time',
1113
+ current_value: 800,
1114
+ baseline_value: 1000,
1115
+ category: 'optimization',
1116
+ });
628
1117
  // 20% decrease: (800 - 1000) / 1000 * 100 = -20%
629
1118
  expect(mockHistogramRecordFn).toHaveBeenCalledWith(-20, {
630
1119
  'session.id': 'test-session-id',
1120
+ 'installation.id': 'test-installation-id',
1121
+ 'user.email': 'test@example.com',
631
1122
  metric: 'startup_time',
632
1123
  category: 'optimization',
633
1124
  current_value: 800,
@@ -640,7 +1131,12 @@ describe('Telemetry Metrics', () => {
640
1131
  const diagSpy = vi.spyOn(mockedModule.diag, 'warn');
641
1132
  initializeMetricsModule(mockConfig);
642
1133
  mockHistogramRecordFn.mockClear();
643
- recordBaselineComparisonModule(mockConfig, 'new_metric', 50, 0, 'testing');
1134
+ recordBaselineComparisonModule(mockConfig, {
1135
+ metric: 'new_metric',
1136
+ current_value: 50,
1137
+ baseline_value: 0,
1138
+ category: 'testing',
1139
+ });
644
1140
  expect(diagSpy).toHaveBeenCalledWith('Baseline value is zero, skipping comparison.');
645
1141
  expect(mockHistogramRecordFn).not.toHaveBeenCalled();
646
1142
  });