@google/gemini-cli-core 0.0.8999999 → 0.0.77777773

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 (362) hide show
  1. package/README.md +105 -62
  2. package/dist/index.d.ts +5 -2
  3. package/dist/index.js +4 -2
  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 +46 -15
  54. package/dist/src/config/config.js +106 -27
  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/constants.d.ts +11 -0
  59. package/dist/src/config/constants.js +16 -0
  60. package/dist/src/config/constants.js.map +1 -0
  61. package/dist/src/config/storage.d.ts +0 -1
  62. package/dist/src/config/storage.js +2 -2
  63. package/dist/src/config/storage.js.map +1 -1
  64. package/dist/src/config/storage.test.js +7 -6
  65. package/dist/src/config/storage.test.js.map +1 -1
  66. package/dist/src/core/baseLlmClient.d.ts +4 -0
  67. package/dist/src/core/baseLlmClient.js +24 -23
  68. package/dist/src/core/baseLlmClient.js.map +1 -1
  69. package/dist/src/core/baseLlmClient.test.js +76 -13
  70. package/dist/src/core/baseLlmClient.test.js.map +1 -1
  71. package/dist/src/core/client.d.ts +3 -1
  72. package/dist/src/core/client.js +68 -47
  73. package/dist/src/core/client.js.map +1 -1
  74. package/dist/src/core/client.test.js +385 -134
  75. package/dist/src/core/client.test.js.map +1 -1
  76. package/dist/src/core/contentGenerator.js +3 -1
  77. package/dist/src/core/contentGenerator.js.map +1 -1
  78. package/dist/src/core/coreToolScheduler.js +24 -15
  79. package/dist/src/core/coreToolScheduler.js.map +1 -1
  80. package/dist/src/core/coreToolScheduler.test.js +359 -23
  81. package/dist/src/core/coreToolScheduler.test.js.map +1 -1
  82. package/dist/src/core/geminiChat.d.ts +11 -14
  83. package/dist/src/core/geminiChat.js +75 -124
  84. package/dist/src/core/geminiChat.js.map +1 -1
  85. package/dist/src/core/geminiChat.test.js +260 -239
  86. package/dist/src/core/geminiChat.test.js.map +1 -1
  87. package/dist/src/core/logger.test.js +2 -2
  88. package/dist/src/core/logger.test.js.map +1 -1
  89. package/dist/src/core/nonInteractiveToolExecutor.test.js +11 -11
  90. package/dist/src/core/nonInteractiveToolExecutor.test.js.map +1 -1
  91. package/dist/src/core/prompts.d.ts +2 -1
  92. package/dist/src/core/prompts.js +93 -18
  93. package/dist/src/core/prompts.js.map +1 -1
  94. package/dist/src/core/prompts.test.js +78 -29
  95. package/dist/src/core/prompts.test.js.map +1 -1
  96. package/dist/src/core/turn.d.ts +15 -6
  97. package/dist/src/core/turn.js +14 -13
  98. package/dist/src/core/turn.js.map +1 -1
  99. package/dist/src/core/turn.test.js +14 -2
  100. package/dist/src/core/turn.test.js.map +1 -1
  101. package/dist/src/generated/git-commit.d.ts +2 -2
  102. package/dist/src/generated/git-commit.js +2 -2
  103. package/dist/src/generated/git-commit.js.map +1 -1
  104. package/dist/src/ide/detect-ide.d.ts +5 -2
  105. package/dist/src/ide/detect-ide.js +11 -2
  106. package/dist/src/ide/detect-ide.js.map +1 -1
  107. package/dist/src/ide/detect-ide.test.js +34 -0
  108. package/dist/src/ide/detect-ide.test.js.map +1 -1
  109. package/dist/src/ide/ide-client.d.ts +2 -1
  110. package/dist/src/ide/ide-client.js +25 -20
  111. package/dist/src/ide/ide-client.js.map +1 -1
  112. package/dist/src/ide/ide-client.test.js +6 -6
  113. package/dist/src/ide/ide-client.test.js.map +1 -1
  114. package/dist/src/ide/ide-installer.js +1 -1
  115. package/dist/src/ide/ide-installer.js.map +1 -1
  116. package/dist/src/ide/ide-installer.test.js +13 -1
  117. package/dist/src/ide/ide-installer.test.js.map +1 -1
  118. package/dist/src/index.d.ts +3 -0
  119. package/dist/src/index.js +3 -0
  120. package/dist/src/index.js.map +1 -1
  121. package/dist/src/mcp/oauth-provider.d.ts +1 -0
  122. package/dist/src/mcp/oauth-provider.js +19 -14
  123. package/dist/src/mcp/oauth-provider.js.map +1 -1
  124. package/dist/src/mcp/oauth-provider.test.js +137 -1
  125. package/dist/src/mcp/oauth-provider.test.js.map +1 -1
  126. package/dist/src/mcp/oauth-utils.js +1 -0
  127. package/dist/src/mcp/oauth-utils.js.map +1 -1
  128. package/dist/src/mcp/sa-impersonation-provider.d.ts +33 -0
  129. package/dist/src/mcp/sa-impersonation-provider.js +130 -0
  130. package/dist/src/mcp/sa-impersonation-provider.js.map +1 -0
  131. package/dist/src/mcp/sa-impersonation-provider.test.d.ts +6 -0
  132. package/dist/src/mcp/sa-impersonation-provider.test.js +117 -0
  133. package/dist/src/mcp/sa-impersonation-provider.test.js.map +1 -0
  134. package/dist/src/mcp/token-storage/file-token-storage.js +2 -1
  135. package/dist/src/mcp/token-storage/file-token-storage.js.map +1 -1
  136. package/dist/src/mcp/token-storage/file-token-storage.test.js +4 -3
  137. package/dist/src/mcp/token-storage/file-token-storage.test.js.map +1 -1
  138. package/dist/src/routing/strategies/compositeStrategy.js +4 -3
  139. package/dist/src/routing/strategies/compositeStrategy.js.map +1 -1
  140. package/dist/src/services/chatRecordingService.d.ts +3 -2
  141. package/dist/src/services/chatRecordingService.js +3 -2
  142. package/dist/src/services/chatRecordingService.js.map +1 -1
  143. package/dist/src/services/fileSystemService.d.ts +9 -0
  144. package/dist/src/services/fileSystemService.js +11 -0
  145. package/dist/src/services/fileSystemService.js.map +1 -1
  146. package/dist/src/services/shellExecutionService.d.ts +3 -0
  147. package/dist/src/services/shellExecutionService.js +165 -49
  148. package/dist/src/services/shellExecutionService.js.map +1 -1
  149. package/dist/src/services/shellExecutionService.test.js +74 -5
  150. package/dist/src/services/shellExecutionService.test.js.map +1 -1
  151. package/dist/src/telemetry/clearcut-logger/clearcut-logger.d.ts +18 -2
  152. package/dist/src/telemetry/clearcut-logger/clearcut-logger.js +156 -11
  153. package/dist/src/telemetry/clearcut-logger/clearcut-logger.js.map +1 -1
  154. package/dist/src/telemetry/clearcut-logger/clearcut-logger.test.d.ts +1 -0
  155. package/dist/src/telemetry/clearcut-logger/clearcut-logger.test.js +226 -1
  156. package/dist/src/telemetry/clearcut-logger/clearcut-logger.test.js.map +1 -1
  157. package/dist/src/telemetry/clearcut-logger/event-metadata-key.d.ts +19 -3
  158. package/dist/src/telemetry/clearcut-logger/event-metadata-key.js +44 -5
  159. package/dist/src/telemetry/clearcut-logger/event-metadata-key.js.map +1 -1
  160. package/dist/src/telemetry/config.d.ts +31 -0
  161. package/dist/src/telemetry/config.js +76 -0
  162. package/dist/src/telemetry/config.js.map +1 -0
  163. package/dist/src/telemetry/config.test.d.ts +6 -0
  164. package/dist/src/telemetry/config.test.js +124 -0
  165. package/dist/src/telemetry/config.test.js.map +1 -0
  166. package/dist/src/telemetry/constants.d.ts +0 -34
  167. package/dist/src/telemetry/constants.js +0 -34
  168. package/dist/src/telemetry/constants.js.map +1 -1
  169. package/dist/src/telemetry/index.d.ts +6 -2
  170. package/dist/src/telemetry/index.js +17 -2
  171. package/dist/src/telemetry/index.js.map +1 -1
  172. package/dist/src/telemetry/loggers.d.ts +10 -2
  173. package/dist/src/telemetry/loggers.js +206 -273
  174. package/dist/src/telemetry/loggers.js.map +1 -1
  175. package/dist/src/telemetry/loggers.test.circular.js +3 -3
  176. package/dist/src/telemetry/loggers.test.circular.js.map +1 -1
  177. package/dist/src/telemetry/loggers.test.js +260 -13
  178. package/dist/src/telemetry/loggers.test.js.map +1 -1
  179. package/dist/src/telemetry/memory-monitor.d.ts +149 -0
  180. package/dist/src/telemetry/memory-monitor.js +335 -0
  181. package/dist/src/telemetry/memory-monitor.js.map +1 -0
  182. package/dist/src/telemetry/memory-monitor.test.d.ts +6 -0
  183. package/dist/src/telemetry/memory-monitor.test.js +472 -0
  184. package/dist/src/telemetry/memory-monitor.test.js.map +1 -0
  185. package/dist/src/telemetry/metrics.d.ts +436 -11
  186. package/dist/src/telemetry/metrics.js +600 -110
  187. package/dist/src/telemetry/metrics.js.map +1 -1
  188. package/dist/src/telemetry/metrics.test.js +898 -16
  189. package/dist/src/telemetry/metrics.test.js.map +1 -1
  190. package/dist/src/telemetry/sdk.js +4 -1
  191. package/dist/src/telemetry/sdk.js.map +1 -1
  192. package/dist/src/telemetry/sdk.test.js +13 -0
  193. package/dist/src/telemetry/sdk.test.js.map +1 -1
  194. package/dist/src/telemetry/telemetryAttributes.d.ts +8 -0
  195. package/dist/src/telemetry/telemetryAttributes.js +18 -0
  196. package/dist/src/telemetry/telemetryAttributes.js.map +1 -0
  197. package/dist/src/telemetry/types.d.ts +167 -5
  198. package/dist/src/telemetry/types.js +692 -35
  199. package/dist/src/telemetry/types.js.map +1 -1
  200. package/dist/src/telemetry/uiTelemetry.d.ts +1 -1
  201. package/dist/src/telemetry/uiTelemetry.js +1 -1
  202. package/dist/src/telemetry/uiTelemetry.js.map +1 -1
  203. package/dist/src/telemetry/uiTelemetry.test.js +3 -3
  204. package/dist/src/telemetry/uiTelemetry.test.js.map +1 -1
  205. package/dist/src/test-utils/mock-tool.d.ts +28 -3
  206. package/dist/src/test-utils/mock-tool.js +71 -1
  207. package/dist/src/test-utils/mock-tool.js.map +1 -1
  208. package/dist/src/tools/edit.js +6 -0
  209. package/dist/src/tools/edit.js.map +1 -1
  210. package/dist/src/tools/edit.test.js +41 -0
  211. package/dist/src/tools/edit.test.js.map +1 -1
  212. package/dist/src/tools/glob.js +4 -2
  213. package/dist/src/tools/glob.js.map +1 -1
  214. package/dist/src/tools/ls.js +1 -1
  215. package/dist/src/tools/ls.js.map +1 -1
  216. package/dist/src/tools/mcp-client.d.ts +5 -14
  217. package/dist/src/tools/mcp-client.js +50 -97
  218. package/dist/src/tools/mcp-client.js.map +1 -1
  219. package/dist/src/tools/mcp-client.test.js +175 -157
  220. package/dist/src/tools/mcp-client.test.js.map +1 -1
  221. package/dist/src/tools/mcp-tool.js +30 -2
  222. package/dist/src/tools/mcp-tool.js.map +1 -1
  223. package/dist/src/tools/mcp-tool.test.js +117 -0
  224. package/dist/src/tools/mcp-tool.test.js.map +1 -1
  225. package/dist/src/tools/memoryTool.d.ts +1 -1
  226. package/dist/src/tools/memoryTool.js +1 -2
  227. package/dist/src/tools/memoryTool.js.map +1 -1
  228. package/dist/src/tools/memoryTool.test.js +9 -8
  229. package/dist/src/tools/memoryTool.test.js.map +1 -1
  230. package/dist/src/tools/message-bus-integration.test.d.ts +6 -0
  231. package/dist/src/tools/message-bus-integration.test.js +183 -0
  232. package/dist/src/tools/message-bus-integration.test.js.map +1 -0
  233. package/dist/src/tools/shell.js +60 -4
  234. package/dist/src/tools/shell.js.map +1 -1
  235. package/dist/src/tools/shell.test.js +2 -1
  236. package/dist/src/tools/shell.test.js.map +1 -1
  237. package/dist/src/tools/smart-edit.d.ts +1 -1
  238. package/dist/src/tools/smart-edit.js +122 -12
  239. package/dist/src/tools/smart-edit.js.map +1 -1
  240. package/dist/src/tools/smart-edit.test.js +136 -29
  241. package/dist/src/tools/smart-edit.test.js.map +1 -1
  242. package/dist/src/tools/tool-error.d.ts +22 -0
  243. package/dist/src/tools/tool-error.js +28 -0
  244. package/dist/src/tools/tool-error.js.map +1 -1
  245. package/dist/src/tools/tool-names.d.ts +9 -0
  246. package/dist/src/tools/tool-names.js +18 -0
  247. package/dist/src/tools/tool-names.js.map +1 -0
  248. package/dist/src/tools/tool-registry.test.js +10 -10
  249. package/dist/src/tools/tool-registry.test.js.map +1 -1
  250. package/dist/src/tools/tools.d.ts +11 -3
  251. package/dist/src/tools/tools.js +94 -3
  252. package/dist/src/tools/tools.js.map +1 -1
  253. package/dist/src/tools/web-fetch.js +3 -0
  254. package/dist/src/tools/web-fetch.js.map +1 -1
  255. package/dist/src/tools/web-fetch.test.js +44 -0
  256. package/dist/src/tools/web-fetch.test.js.map +1 -1
  257. package/dist/src/tools/web-search.js +2 -1
  258. package/dist/src/tools/web-search.js.map +1 -1
  259. package/dist/src/tools/write-file.js +2 -1
  260. package/dist/src/tools/write-file.js.map +1 -1
  261. package/dist/src/tools/write-todos.d.ts +25 -0
  262. package/dist/src/tools/write-todos.js +151 -0
  263. package/dist/src/tools/write-todos.js.map +1 -0
  264. package/dist/src/tools/write-todos.test.d.ts +6 -0
  265. package/dist/src/tools/write-todos.test.js +89 -0
  266. package/dist/src/tools/write-todos.test.js.map +1 -0
  267. package/dist/src/utils/bfsFileSearch.d.ts +1 -1
  268. package/dist/src/utils/editCorrector.js +2 -2
  269. package/dist/src/utils/editCorrector.js.map +1 -1
  270. package/dist/src/utils/editor.js +1 -0
  271. package/dist/src/utils/editor.js.map +1 -1
  272. package/dist/src/utils/editor.test.js +1 -0
  273. package/dist/src/utils/editor.test.js.map +1 -1
  274. package/dist/src/utils/errorParsing.d.ts +1 -1
  275. package/dist/src/utils/errorParsing.js +5 -33
  276. package/dist/src/utils/errorParsing.js.map +1 -1
  277. package/dist/src/utils/errorParsing.test.js +0 -88
  278. package/dist/src/utils/errorParsing.test.js.map +1 -1
  279. package/dist/src/utils/flashFallback.test.js +26 -45
  280. package/dist/src/utils/flashFallback.test.js.map +1 -1
  281. package/dist/src/utils/formatters.d.ts +1 -0
  282. package/dist/src/utils/formatters.js +2 -1
  283. package/dist/src/utils/formatters.js.map +1 -1
  284. package/dist/src/utils/formatters.test.d.ts +6 -0
  285. package/dist/src/utils/formatters.test.js +26 -0
  286. package/dist/src/utils/formatters.test.js.map +1 -0
  287. package/dist/src/utils/getFolderStructure.d.ts +1 -1
  288. package/dist/src/utils/getFolderStructure.js +1 -1
  289. package/dist/src/utils/getFolderStructure.js.map +1 -1
  290. package/dist/src/utils/getFolderStructure.test.js +7 -6
  291. package/dist/src/utils/getFolderStructure.test.js.map +1 -1
  292. package/dist/src/utils/googleErrors.d.ts +104 -0
  293. package/dist/src/utils/googleErrors.js +108 -0
  294. package/dist/src/utils/googleErrors.js.map +1 -0
  295. package/dist/src/utils/googleErrors.test.d.ts +6 -0
  296. package/dist/src/utils/googleErrors.test.js +212 -0
  297. package/dist/src/utils/googleErrors.test.js.map +1 -0
  298. package/dist/src/utils/googleQuotaErrors.d.ts +35 -0
  299. package/dist/src/utils/googleQuotaErrors.js +108 -0
  300. package/dist/src/utils/googleQuotaErrors.js.map +1 -0
  301. package/dist/src/utils/googleQuotaErrors.test.d.ts +6 -0
  302. package/dist/src/utils/googleQuotaErrors.test.js +189 -0
  303. package/dist/src/utils/googleQuotaErrors.test.js.map +1 -0
  304. package/dist/src/utils/installationManager.test.js +2 -1
  305. package/dist/src/utils/installationManager.test.js.map +1 -1
  306. package/dist/src/utils/llm-edit-fixer.js +14 -4
  307. package/dist/src/utils/llm-edit-fixer.js.map +1 -1
  308. package/dist/src/utils/llm-edit-fixer.test.js +81 -0
  309. package/dist/src/utils/llm-edit-fixer.test.js.map +1 -1
  310. package/dist/src/utils/memoryDiscovery.d.ts +2 -1
  311. package/dist/src/utils/memoryDiscovery.js +3 -2
  312. package/dist/src/utils/memoryDiscovery.js.map +1 -1
  313. package/dist/src/utils/memoryDiscovery.test.js +99 -21
  314. package/dist/src/utils/memoryDiscovery.test.js.map +1 -1
  315. package/dist/src/utils/memoryImportProcessor.js +13 -20
  316. package/dist/src/utils/memoryImportProcessor.js.map +1 -1
  317. package/dist/src/utils/memoryImportProcessor.test.js +14 -0
  318. package/dist/src/utils/memoryImportProcessor.test.js.map +1 -1
  319. package/dist/src/utils/pathCorrector.d.ts +25 -0
  320. package/dist/src/utils/pathCorrector.js +33 -0
  321. package/dist/src/utils/pathCorrector.js.map +1 -0
  322. package/dist/src/utils/pathCorrector.test.d.ts +6 -0
  323. package/dist/src/utils/pathCorrector.test.js +83 -0
  324. package/dist/src/utils/pathCorrector.test.js.map +1 -0
  325. package/dist/src/utils/quotaErrorDetection.d.ts +0 -2
  326. package/dist/src/utils/quotaErrorDetection.js +0 -46
  327. package/dist/src/utils/quotaErrorDetection.js.map +1 -1
  328. package/dist/src/utils/retry.d.ts +3 -1
  329. package/dist/src/utils/retry.js +60 -162
  330. package/dist/src/utils/retry.js.map +1 -1
  331. package/dist/src/utils/retry.test.js +105 -135
  332. package/dist/src/utils/retry.test.js.map +1 -1
  333. package/dist/src/utils/schemaValidator.js +11 -1
  334. package/dist/src/utils/schemaValidator.js.map +1 -1
  335. package/dist/src/utils/schemaValidator.test.d.ts +6 -0
  336. package/dist/src/utils/schemaValidator.test.js +113 -0
  337. package/dist/src/utils/schemaValidator.test.js.map +1 -0
  338. package/dist/src/utils/shell-utils.d.ts +1 -0
  339. package/dist/src/utils/shell-utils.js +6 -2
  340. package/dist/src/utils/shell-utils.js.map +1 -1
  341. package/dist/src/utils/shell-utils.test.js +5 -0
  342. package/dist/src/utils/shell-utils.test.js.map +1 -1
  343. package/dist/src/utils/terminalSerializer.d.ts +1 -4
  344. package/dist/src/utils/terminalSerializer.js +3 -3
  345. package/dist/src/utils/terminalSerializer.js.map +1 -1
  346. package/dist/src/utils/thoughtUtils.d.ts +21 -0
  347. package/dist/src/utils/thoughtUtils.js +39 -0
  348. package/dist/src/utils/thoughtUtils.js.map +1 -0
  349. package/dist/src/utils/thoughtUtils.test.d.ts +6 -0
  350. package/dist/src/utils/thoughtUtils.test.js +78 -0
  351. package/dist/src/utils/thoughtUtils.test.js.map +1 -0
  352. package/dist/src/utils/tool-utils.js +2 -2
  353. package/dist/src/utils/tool-utils.js.map +1 -1
  354. package/dist/src/utils/tool-utils.test.js +8 -0
  355. package/dist/src/utils/tool-utils.test.js.map +1 -1
  356. package/dist/src/utils/userAccountManager.test.js +2 -1
  357. package/dist/src/utils/userAccountManager.test.js.map +1 -1
  358. package/dist/tsconfig.tsbuildinfo +1 -1
  359. package/package.json +2 -2
  360. package/dist/src/test-utils/tools.d.ts +0 -45
  361. package/dist/src/test-utils/tools.js +0 -105
  362. package/dist/src/test-utils/tools.js.map +0 -1
@@ -4,9 +4,10 @@
4
4
  * SPDX-License-Identifier: Apache-2.0
5
5
  */
6
6
  import { describe, it, expect, vi, beforeEach } from 'vitest';
7
- import { FileOperation } from './metrics.js';
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();
@@ -28,19 +29,41 @@ function originalOtelMockFactory() {
28
29
  },
29
30
  ValueType: {
30
31
  INT: 1,
32
+ DOUBLE: 2,
31
33
  },
32
34
  diag: {
33
35
  setLogger: vi.fn(),
36
+ warn: vi.fn(),
37
+ },
38
+ DiagConsoleLogger: vi.fn(),
39
+ DiagLogLevel: {
40
+ NONE: 0,
41
+ INFO: 1,
34
42
  },
35
43
  };
36
44
  }
37
45
  vi.mock('@opentelemetry/api');
46
+ vi.mock('./telemetryAttributes.js');
38
47
  describe('Telemetry Metrics', () => {
39
48
  let initializeMetricsModule;
40
49
  let recordTokenUsageMetricsModule;
41
50
  let recordFileOperationMetricModule;
42
51
  let recordChatCompressionMetricsModule;
43
52
  let recordModelRoutingMetricsModule;
53
+ let recordStartupPerformanceModule;
54
+ let recordMemoryUsageModule;
55
+ let recordCpuUsageModule;
56
+ let recordToolQueueDepthModule;
57
+ let recordToolExecutionBreakdownModule;
58
+ let recordTokenEfficiencyModule;
59
+ let recordApiRequestBreakdownModule;
60
+ let recordPerformanceScoreModule;
61
+ let recordPerformanceRegressionModule;
62
+ let recordBaselineComparisonModule;
63
+ let recordGenAiClientTokenUsageModule;
64
+ let recordGenAiClientOperationDurationModule;
65
+ let recordFlickerFrameModule;
66
+ let recordAgentRunMetricsModule;
44
67
  beforeEach(async () => {
45
68
  vi.resetModules();
46
69
  vi.doMock('@opentelemetry/api', () => {
@@ -48,6 +71,12 @@ describe('Telemetry Metrics', () => {
48
71
  actualApi.metrics.getMeter.mockReturnValue(mockMeterInstance);
49
72
  return actualApi;
50
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
+ });
51
80
  const metricsJsModule = await import('./metrics.js');
52
81
  initializeMetricsModule = metricsJsModule.initializeMetrics;
53
82
  recordTokenUsageMetricsModule = metricsJsModule.recordTokenUsageMetrics;
@@ -55,6 +84,24 @@ describe('Telemetry Metrics', () => {
55
84
  recordChatCompressionMetricsModule =
56
85
  metricsJsModule.recordChatCompressionMetrics;
57
86
  recordModelRoutingMetricsModule = metricsJsModule.recordModelRoutingMetrics;
87
+ recordStartupPerformanceModule = metricsJsModule.recordStartupPerformance;
88
+ recordMemoryUsageModule = metricsJsModule.recordMemoryUsage;
89
+ recordCpuUsageModule = metricsJsModule.recordCpuUsage;
90
+ recordToolQueueDepthModule = metricsJsModule.recordToolQueueDepth;
91
+ recordToolExecutionBreakdownModule =
92
+ metricsJsModule.recordToolExecutionBreakdown;
93
+ recordTokenEfficiencyModule = metricsJsModule.recordTokenEfficiency;
94
+ recordApiRequestBreakdownModule = metricsJsModule.recordApiRequestBreakdown;
95
+ recordPerformanceScoreModule = metricsJsModule.recordPerformanceScore;
96
+ recordPerformanceRegressionModule =
97
+ metricsJsModule.recordPerformanceRegression;
98
+ recordBaselineComparisonModule = metricsJsModule.recordBaselineComparison;
99
+ recordGenAiClientTokenUsageModule =
100
+ metricsJsModule.recordGenAiClientTokenUsage;
101
+ recordGenAiClientOperationDurationModule =
102
+ metricsJsModule.recordGenAiClientOperationDuration;
103
+ recordFlickerFrameModule = metricsJsModule.recordFlickerFrame;
104
+ recordAgentRunMetricsModule = metricsJsModule.recordAgentRunMetrics;
58
105
  const otelApiModule = await import('@opentelemetry/api');
59
106
  mockCounterAddFn.mockClear();
60
107
  mockCreateCounterFn.mockClear();
@@ -65,6 +112,39 @@ describe('Telemetry Metrics', () => {
65
112
  mockCreateCounterFn.mockReturnValue(mockCounterInstance);
66
113
  mockCreateHistogramFn.mockReturnValue(mockHistogramInstance);
67
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
+ });
68
148
  describe('recordChatCompressionMetrics', () => {
69
149
  it('does not record metrics if not initialized', () => {
70
150
  const lol = makeFakeConfig({});
@@ -83,6 +163,8 @@ describe('Telemetry Metrics', () => {
83
163
  });
84
164
  expect(mockCounterAddFn).toHaveBeenCalledWith(1, {
85
165
  'session.id': 'test-session-id',
166
+ 'installation.id': 'test-installation-id',
167
+ 'user.email': 'test@example.com',
86
168
  tokens_after: 100,
87
169
  tokens_before: 200,
88
170
  });
@@ -91,20 +173,31 @@ describe('Telemetry Metrics', () => {
91
173
  describe('recordTokenUsageMetrics', () => {
92
174
  const mockConfig = {
93
175
  getSessionId: () => 'test-session-id',
176
+ getTelemetryEnabled: () => true,
94
177
  };
95
178
  it('should not record metrics if not initialized', () => {
96
- recordTokenUsageMetricsModule(mockConfig, 'gemini-pro', 100, 'input');
179
+ recordTokenUsageMetricsModule(mockConfig, 100, {
180
+ model: 'gemini-pro',
181
+ type: 'input',
182
+ });
97
183
  expect(mockCounterAddFn).not.toHaveBeenCalled();
98
184
  });
99
185
  it('should record token usage with the correct attributes', () => {
100
186
  initializeMetricsModule(mockConfig);
101
- recordTokenUsageMetricsModule(mockConfig, 'gemini-pro', 100, 'input');
187
+ recordTokenUsageMetricsModule(mockConfig, 100, {
188
+ model: 'gemini-pro',
189
+ type: 'input',
190
+ });
102
191
  expect(mockCounterAddFn).toHaveBeenCalledTimes(2);
103
192
  expect(mockCounterAddFn).toHaveBeenNthCalledWith(1, 1, {
104
193
  'session.id': 'test-session-id',
194
+ 'installation.id': 'test-installation-id',
195
+ 'user.email': 'test@example.com',
105
196
  });
106
197
  expect(mockCounterAddFn).toHaveBeenNthCalledWith(2, 100, {
107
198
  'session.id': 'test-session-id',
199
+ 'installation.id': 'test-installation-id',
200
+ 'user.email': 'test@example.com',
108
201
  model: 'gemini-pro',
109
202
  type: 'input',
110
203
  });
@@ -112,27 +205,47 @@ describe('Telemetry Metrics', () => {
112
205
  it('should record token usage for different types', () => {
113
206
  initializeMetricsModule(mockConfig);
114
207
  mockCounterAddFn.mockClear();
115
- recordTokenUsageMetricsModule(mockConfig, 'gemini-pro', 50, 'output');
208
+ recordTokenUsageMetricsModule(mockConfig, 50, {
209
+ model: 'gemini-pro',
210
+ type: 'output',
211
+ });
116
212
  expect(mockCounterAddFn).toHaveBeenCalledWith(50, {
117
213
  'session.id': 'test-session-id',
214
+ 'installation.id': 'test-installation-id',
215
+ 'user.email': 'test@example.com',
118
216
  model: 'gemini-pro',
119
217
  type: 'output',
120
218
  });
121
- recordTokenUsageMetricsModule(mockConfig, 'gemini-pro', 25, 'thought');
219
+ recordTokenUsageMetricsModule(mockConfig, 25, {
220
+ model: 'gemini-pro',
221
+ type: 'thought',
222
+ });
122
223
  expect(mockCounterAddFn).toHaveBeenCalledWith(25, {
123
224
  'session.id': 'test-session-id',
225
+ 'installation.id': 'test-installation-id',
226
+ 'user.email': 'test@example.com',
124
227
  model: 'gemini-pro',
125
228
  type: 'thought',
126
229
  });
127
- recordTokenUsageMetricsModule(mockConfig, 'gemini-pro', 75, 'cache');
230
+ recordTokenUsageMetricsModule(mockConfig, 75, {
231
+ model: 'gemini-pro',
232
+ type: 'cache',
233
+ });
128
234
  expect(mockCounterAddFn).toHaveBeenCalledWith(75, {
129
235
  'session.id': 'test-session-id',
236
+ 'installation.id': 'test-installation-id',
237
+ 'user.email': 'test@example.com',
130
238
  model: 'gemini-pro',
131
239
  type: 'cache',
132
240
  });
133
- recordTokenUsageMetricsModule(mockConfig, 'gemini-pro', 125, 'tool');
241
+ recordTokenUsageMetricsModule(mockConfig, 125, {
242
+ model: 'gemini-pro',
243
+ type: 'tool',
244
+ });
134
245
  expect(mockCounterAddFn).toHaveBeenCalledWith(125, {
135
246
  'session.id': 'test-session-id',
247
+ 'installation.id': 'test-installation-id',
248
+ 'user.email': 'test@example.com',
136
249
  model: 'gemini-pro',
137
250
  type: 'tool',
138
251
  });
@@ -140,9 +253,14 @@ describe('Telemetry Metrics', () => {
140
253
  it('should handle different models', () => {
141
254
  initializeMetricsModule(mockConfig);
142
255
  mockCounterAddFn.mockClear();
143
- recordTokenUsageMetricsModule(mockConfig, 'gemini-ultra', 200, 'input');
256
+ recordTokenUsageMetricsModule(mockConfig, 200, {
257
+ model: 'gemini-ultra',
258
+ type: 'input',
259
+ });
144
260
  expect(mockCounterAddFn).toHaveBeenCalledWith(200, {
145
261
  'session.id': 'test-session-id',
262
+ 'installation.id': 'test-installation-id',
263
+ 'user.email': 'test@example.com',
146
264
  model: 'gemini-ultra',
147
265
  type: 'input',
148
266
  });
@@ -151,20 +269,35 @@ describe('Telemetry Metrics', () => {
151
269
  describe('recordFileOperationMetric', () => {
152
270
  const mockConfig = {
153
271
  getSessionId: () => 'test-session-id',
272
+ getTelemetryEnabled: () => true,
154
273
  };
155
274
  it('should not record metrics if not initialized', () => {
156
- 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
+ });
157
281
  expect(mockCounterAddFn).not.toHaveBeenCalled();
158
282
  });
159
283
  it('should record file creation with all attributes', () => {
160
284
  initializeMetricsModule(mockConfig);
161
- 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
+ });
162
291
  expect(mockCounterAddFn).toHaveBeenCalledTimes(2);
163
292
  expect(mockCounterAddFn).toHaveBeenNthCalledWith(1, 1, {
164
293
  'session.id': 'test-session-id',
294
+ 'installation.id': 'test-installation-id',
295
+ 'user.email': 'test@example.com',
165
296
  });
166
297
  expect(mockCounterAddFn).toHaveBeenNthCalledWith(2, 1, {
167
298
  'session.id': 'test-session-id',
299
+ 'installation.id': 'test-installation-id',
300
+ 'user.email': 'test@example.com',
168
301
  operation: FileOperation.CREATE,
169
302
  lines: 10,
170
303
  mimetype: 'text/plain',
@@ -174,18 +307,27 @@ describe('Telemetry Metrics', () => {
174
307
  it('should record file read with minimal attributes', () => {
175
308
  initializeMetricsModule(mockConfig);
176
309
  mockCounterAddFn.mockClear();
177
- recordFileOperationMetricModule(mockConfig, FileOperation.READ);
310
+ recordFileOperationMetricModule(mockConfig, {
311
+ operation: FileOperation.READ,
312
+ });
178
313
  expect(mockCounterAddFn).toHaveBeenCalledWith(1, {
179
314
  'session.id': 'test-session-id',
315
+ 'installation.id': 'test-installation-id',
316
+ 'user.email': 'test@example.com',
180
317
  operation: FileOperation.READ,
181
318
  });
182
319
  });
183
320
  it('should record file update with some attributes', () => {
184
321
  initializeMetricsModule(mockConfig);
185
322
  mockCounterAddFn.mockClear();
186
- recordFileOperationMetricModule(mockConfig, FileOperation.UPDATE, undefined, 'application/javascript');
323
+ recordFileOperationMetricModule(mockConfig, {
324
+ operation: FileOperation.UPDATE,
325
+ mimetype: 'application/javascript',
326
+ });
187
327
  expect(mockCounterAddFn).toHaveBeenCalledWith(1, {
188
328
  'session.id': 'test-session-id',
329
+ 'installation.id': 'test-installation-id',
330
+ 'user.email': 'test@example.com',
189
331
  operation: FileOperation.UPDATE,
190
332
  mimetype: 'application/javascript',
191
333
  });
@@ -193,18 +335,29 @@ describe('Telemetry Metrics', () => {
193
335
  it('should record file operation without diffStat', () => {
194
336
  initializeMetricsModule(mockConfig);
195
337
  mockCounterAddFn.mockClear();
196
- recordFileOperationMetricModule(mockConfig, FileOperation.UPDATE, undefined, undefined, undefined);
338
+ recordFileOperationMetricModule(mockConfig, {
339
+ operation: FileOperation.UPDATE,
340
+ });
197
341
  expect(mockCounterAddFn).toHaveBeenCalledWith(1, {
198
342
  'session.id': 'test-session-id',
343
+ 'installation.id': 'test-installation-id',
344
+ 'user.email': 'test@example.com',
199
345
  operation: FileOperation.UPDATE,
200
346
  });
201
347
  });
202
348
  it('should record minimal file operation when optional parameters are undefined', () => {
203
349
  initializeMetricsModule(mockConfig);
204
350
  mockCounterAddFn.mockClear();
205
- 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
+ });
206
357
  expect(mockCounterAddFn).toHaveBeenCalledWith(1, {
207
358
  'session.id': 'test-session-id',
359
+ 'installation.id': 'test-installation-id',
360
+ 'user.email': 'test@example.com',
208
361
  operation: FileOperation.UPDATE,
209
362
  lines: 10,
210
363
  mimetype: 'text/plain',
@@ -214,9 +367,13 @@ describe('Telemetry Metrics', () => {
214
367
  it('should not include diffStat attributes when diffStat is not provided', () => {
215
368
  initializeMetricsModule(mockConfig);
216
369
  mockCounterAddFn.mockClear();
217
- recordFileOperationMetricModule(mockConfig, FileOperation.UPDATE, undefined, undefined, undefined);
370
+ recordFileOperationMetricModule(mockConfig, {
371
+ operation: FileOperation.UPDATE,
372
+ });
218
373
  expect(mockCounterAddFn).toHaveBeenCalledWith(1, {
219
374
  'session.id': 'test-session-id',
375
+ 'installation.id': 'test-installation-id',
376
+ 'user.email': 'test@example.com',
220
377
  operation: FileOperation.UPDATE,
221
378
  });
222
379
  });
@@ -224,6 +381,7 @@ describe('Telemetry Metrics', () => {
224
381
  describe('recordModelRoutingMetrics', () => {
225
382
  const mockConfig = {
226
383
  getSessionId: () => 'test-session-id',
384
+ getTelemetryEnabled: () => true,
227
385
  };
228
386
  it('should not record metrics if not initialized', () => {
229
387
  const event = new ModelRoutingEvent('gemini-pro', 'default', 100, 'test-reason', false, undefined);
@@ -237,6 +395,8 @@ describe('Telemetry Metrics', () => {
237
395
  recordModelRoutingMetricsModule(mockConfig, event);
238
396
  expect(mockHistogramRecordFn).toHaveBeenCalledWith(150, {
239
397
  'session.id': 'test-session-id',
398
+ 'installation.id': 'test-installation-id',
399
+ 'user.email': 'test@example.com',
240
400
  'routing.decision_model': 'gemini-pro',
241
401
  'routing.decision_source': 'default',
242
402
  });
@@ -249,16 +409,738 @@ describe('Telemetry Metrics', () => {
249
409
  recordModelRoutingMetricsModule(mockConfig, event);
250
410
  expect(mockHistogramRecordFn).toHaveBeenCalledWith(200, {
251
411
  'session.id': 'test-session-id',
412
+ 'installation.id': 'test-installation-id',
413
+ 'user.email': 'test@example.com',
252
414
  'routing.decision_model': 'gemini-pro',
253
415
  'routing.decision_source': 'classifier',
254
416
  });
255
417
  expect(mockCounterAddFn).toHaveBeenCalledTimes(2);
256
418
  expect(mockCounterAddFn).toHaveBeenNthCalledWith(2, 1, {
257
419
  'session.id': 'test-session-id',
420
+ 'installation.id': 'test-installation-id',
421
+ 'user.email': 'test@example.com',
258
422
  'routing.decision_source': 'classifier',
259
423
  'routing.error_message': 'test-error',
260
424
  });
261
425
  });
262
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
+ });
632
+ describe('Performance Monitoring Metrics', () => {
633
+ const mockConfig = {
634
+ getSessionId: () => 'test-session-id',
635
+ getTelemetryEnabled: () => true,
636
+ };
637
+ describe('recordStartupPerformance', () => {
638
+ it('should not record metrics when performance monitoring is disabled', async () => {
639
+ // Re-import with performance monitoring disabled by mocking the config
640
+ const mockConfigDisabled = {
641
+ getSessionId: () => 'test-session-id',
642
+ getTelemetryEnabled: () => false, // Disable telemetry to disable performance monitoring
643
+ };
644
+ initializeMetricsModule(mockConfigDisabled);
645
+ mockHistogramRecordFn.mockClear();
646
+ recordStartupPerformanceModule(mockConfigDisabled, 100, {
647
+ phase: 'settings_loading',
648
+ details: {
649
+ auth_type: 'gemini',
650
+ },
651
+ });
652
+ expect(mockHistogramRecordFn).not.toHaveBeenCalled();
653
+ });
654
+ it('should record startup performance with phase and details', () => {
655
+ initializeMetricsModule(mockConfig);
656
+ mockHistogramRecordFn.mockClear();
657
+ recordStartupPerformanceModule(mockConfig, 150, {
658
+ phase: 'settings_loading',
659
+ details: {
660
+ auth_type: 'gemini',
661
+ telemetry_enabled: true,
662
+ settings_sources: 2,
663
+ },
664
+ });
665
+ expect(mockHistogramRecordFn).toHaveBeenCalledWith(150, {
666
+ 'session.id': 'test-session-id',
667
+ 'installation.id': 'test-installation-id',
668
+ 'user.email': 'test@example.com',
669
+ phase: 'settings_loading',
670
+ auth_type: 'gemini',
671
+ telemetry_enabled: true,
672
+ settings_sources: 2,
673
+ });
674
+ });
675
+ it('should record startup performance without details', () => {
676
+ initializeMetricsModule(mockConfig);
677
+ mockHistogramRecordFn.mockClear();
678
+ recordStartupPerformanceModule(mockConfig, 50, { phase: 'cleanup' });
679
+ expect(mockHistogramRecordFn).toHaveBeenCalledWith(50, {
680
+ 'session.id': 'test-session-id',
681
+ 'installation.id': 'test-installation-id',
682
+ 'user.email': 'test@example.com',
683
+ phase: 'cleanup',
684
+ });
685
+ });
686
+ it('should handle floating-point duration values from performance.now()', () => {
687
+ initializeMetricsModule(mockConfig);
688
+ mockHistogramRecordFn.mockClear();
689
+ // Test with realistic floating-point values that performance.now() would return
690
+ const floatingPointDuration = 123.45678;
691
+ recordStartupPerformanceModule(mockConfig, floatingPointDuration, {
692
+ phase: 'total_startup',
693
+ details: {
694
+ is_tty: true,
695
+ has_question: false,
696
+ },
697
+ });
698
+ expect(mockHistogramRecordFn).toHaveBeenCalledWith(floatingPointDuration, {
699
+ 'session.id': 'test-session-id',
700
+ 'installation.id': 'test-installation-id',
701
+ 'user.email': 'test@example.com',
702
+ phase: 'total_startup',
703
+ is_tty: true,
704
+ has_question: false,
705
+ });
706
+ });
707
+ });
708
+ describe('recordMemoryUsage', () => {
709
+ it('should record memory usage for different memory types', () => {
710
+ initializeMetricsModule(mockConfig);
711
+ mockHistogramRecordFn.mockClear();
712
+ recordMemoryUsageModule(mockConfig, 15728640, {
713
+ memory_type: MemoryMetricType.HEAP_USED,
714
+ component: 'startup',
715
+ });
716
+ expect(mockHistogramRecordFn).toHaveBeenCalledWith(15728640, {
717
+ 'session.id': 'test-session-id',
718
+ 'installation.id': 'test-installation-id',
719
+ 'user.email': 'test@example.com',
720
+ memory_type: 'heap_used',
721
+ component: 'startup',
722
+ });
723
+ });
724
+ it('should record memory usage for all memory metric types', () => {
725
+ initializeMetricsModule(mockConfig);
726
+ mockHistogramRecordFn.mockClear();
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
+ });
739
+ expect(mockHistogramRecordFn).toHaveBeenCalledTimes(3); // One for each call
740
+ expect(mockHistogramRecordFn).toHaveBeenNthCalledWith(1, 31457280, {
741
+ 'session.id': 'test-session-id',
742
+ 'installation.id': 'test-installation-id',
743
+ 'user.email': 'test@example.com',
744
+ memory_type: 'heap_total',
745
+ component: 'api_call',
746
+ });
747
+ expect(mockHistogramRecordFn).toHaveBeenNthCalledWith(2, 2097152, {
748
+ 'session.id': 'test-session-id',
749
+ 'installation.id': 'test-installation-id',
750
+ 'user.email': 'test@example.com',
751
+ memory_type: 'external',
752
+ component: 'tool_execution',
753
+ });
754
+ expect(mockHistogramRecordFn).toHaveBeenNthCalledWith(3, 41943040, {
755
+ 'session.id': 'test-session-id',
756
+ 'installation.id': 'test-installation-id',
757
+ 'user.email': 'test@example.com',
758
+ memory_type: 'rss',
759
+ component: 'memory_monitor',
760
+ });
761
+ });
762
+ it('should record memory usage without component', () => {
763
+ initializeMetricsModule(mockConfig);
764
+ mockHistogramRecordFn.mockClear();
765
+ recordMemoryUsageModule(mockConfig, 15728640, {
766
+ memory_type: MemoryMetricType.HEAP_USED,
767
+ });
768
+ expect(mockHistogramRecordFn).toHaveBeenCalledWith(15728640, {
769
+ 'session.id': 'test-session-id',
770
+ 'installation.id': 'test-installation-id',
771
+ 'user.email': 'test@example.com',
772
+ memory_type: 'heap_used',
773
+ });
774
+ });
775
+ });
776
+ describe('recordCpuUsage', () => {
777
+ it('should record CPU usage percentage', () => {
778
+ initializeMetricsModule(mockConfig);
779
+ mockHistogramRecordFn.mockClear();
780
+ recordCpuUsageModule(mockConfig, 85.5, {
781
+ component: 'tool_execution',
782
+ });
783
+ expect(mockHistogramRecordFn).toHaveBeenCalledWith(85.5, {
784
+ 'session.id': 'test-session-id',
785
+ 'installation.id': 'test-installation-id',
786
+ 'user.email': 'test@example.com',
787
+ component: 'tool_execution',
788
+ });
789
+ });
790
+ it('should record CPU usage without component', () => {
791
+ initializeMetricsModule(mockConfig);
792
+ mockHistogramRecordFn.mockClear();
793
+ recordCpuUsageModule(mockConfig, 42.3, {});
794
+ expect(mockHistogramRecordFn).toHaveBeenCalledWith(42.3, {
795
+ 'session.id': 'test-session-id',
796
+ 'installation.id': 'test-installation-id',
797
+ 'user.email': 'test@example.com',
798
+ });
799
+ });
800
+ });
801
+ describe('recordToolQueueDepth', () => {
802
+ it('should record tool queue depth', () => {
803
+ initializeMetricsModule(mockConfig);
804
+ mockHistogramRecordFn.mockClear();
805
+ recordToolQueueDepthModule(mockConfig, 3);
806
+ expect(mockHistogramRecordFn).toHaveBeenCalledWith(3, {
807
+ 'session.id': 'test-session-id',
808
+ 'installation.id': 'test-installation-id',
809
+ 'user.email': 'test@example.com',
810
+ });
811
+ });
812
+ it('should record zero queue depth', () => {
813
+ initializeMetricsModule(mockConfig);
814
+ mockHistogramRecordFn.mockClear();
815
+ recordToolQueueDepthModule(mockConfig, 0);
816
+ expect(mockHistogramRecordFn).toHaveBeenCalledWith(0, {
817
+ 'session.id': 'test-session-id',
818
+ 'installation.id': 'test-installation-id',
819
+ 'user.email': 'test@example.com',
820
+ });
821
+ });
822
+ });
823
+ describe('recordToolExecutionBreakdown', () => {
824
+ it('should record tool execution breakdown for all phases', () => {
825
+ initializeMetricsModule(mockConfig);
826
+ mockHistogramRecordFn.mockClear();
827
+ recordToolExecutionBreakdownModule(mockConfig, 25, {
828
+ function_name: 'Read',
829
+ phase: ToolExecutionPhase.VALIDATION,
830
+ });
831
+ expect(mockHistogramRecordFn).toHaveBeenCalledWith(25, {
832
+ 'session.id': 'test-session-id',
833
+ 'installation.id': 'test-installation-id',
834
+ 'user.email': 'test@example.com',
835
+ function_name: 'Read',
836
+ phase: 'validation',
837
+ });
838
+ });
839
+ it('should record execution breakdown for different phases', () => {
840
+ initializeMetricsModule(mockConfig);
841
+ mockHistogramRecordFn.mockClear();
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
+ });
854
+ expect(mockHistogramRecordFn).toHaveBeenCalledTimes(3); // One for each call
855
+ expect(mockHistogramRecordFn).toHaveBeenNthCalledWith(1, 50, {
856
+ 'session.id': 'test-session-id',
857
+ 'installation.id': 'test-installation-id',
858
+ 'user.email': 'test@example.com',
859
+ function_name: 'Bash',
860
+ phase: 'preparation',
861
+ });
862
+ expect(mockHistogramRecordFn).toHaveBeenNthCalledWith(2, 1500, {
863
+ 'session.id': 'test-session-id',
864
+ 'installation.id': 'test-installation-id',
865
+ 'user.email': 'test@example.com',
866
+ function_name: 'Bash',
867
+ phase: 'execution',
868
+ });
869
+ expect(mockHistogramRecordFn).toHaveBeenNthCalledWith(3, 75, {
870
+ 'session.id': 'test-session-id',
871
+ 'installation.id': 'test-installation-id',
872
+ 'user.email': 'test@example.com',
873
+ function_name: 'Bash',
874
+ phase: 'result_processing',
875
+ });
876
+ });
877
+ });
878
+ describe('recordTokenEfficiency', () => {
879
+ it('should record token efficiency metrics', () => {
880
+ initializeMetricsModule(mockConfig);
881
+ mockHistogramRecordFn.mockClear();
882
+ recordTokenEfficiencyModule(mockConfig, 0.85, {
883
+ model: 'gemini-pro',
884
+ metric: 'cache_hit_rate',
885
+ context: 'api_request',
886
+ });
887
+ expect(mockHistogramRecordFn).toHaveBeenCalledWith(0.85, {
888
+ 'session.id': 'test-session-id',
889
+ 'installation.id': 'test-installation-id',
890
+ 'user.email': 'test@example.com',
891
+ model: 'gemini-pro',
892
+ metric: 'cache_hit_rate',
893
+ context: 'api_request',
894
+ });
895
+ });
896
+ it('should record token efficiency without context', () => {
897
+ initializeMetricsModule(mockConfig);
898
+ mockHistogramRecordFn.mockClear();
899
+ recordTokenEfficiencyModule(mockConfig, 125.5, {
900
+ model: 'gemini-pro',
901
+ metric: 'tokens_per_operation',
902
+ });
903
+ expect(mockHistogramRecordFn).toHaveBeenCalledWith(125.5, {
904
+ 'session.id': 'test-session-id',
905
+ 'installation.id': 'test-installation-id',
906
+ 'user.email': 'test@example.com',
907
+ model: 'gemini-pro',
908
+ metric: 'tokens_per_operation',
909
+ });
910
+ });
911
+ });
912
+ describe('recordApiRequestBreakdown', () => {
913
+ it('should record API request breakdown for all phases', () => {
914
+ initializeMetricsModule(mockConfig);
915
+ mockHistogramRecordFn.mockClear();
916
+ recordApiRequestBreakdownModule(mockConfig, 15, {
917
+ model: 'gemini-pro',
918
+ phase: ApiRequestPhase.REQUEST_PREPARATION,
919
+ });
920
+ expect(mockHistogramRecordFn).toHaveBeenCalledWith(15, {
921
+ 'session.id': 'test-session-id',
922
+ 'installation.id': 'test-installation-id',
923
+ 'user.email': 'test@example.com',
924
+ model: 'gemini-pro',
925
+ phase: 'request_preparation',
926
+ });
927
+ });
928
+ it('should record API request breakdown for different phases', () => {
929
+ initializeMetricsModule(mockConfig);
930
+ mockHistogramRecordFn.mockClear();
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
+ });
943
+ expect(mockHistogramRecordFn).toHaveBeenCalledTimes(3); // One for each call
944
+ expect(mockHistogramRecordFn).toHaveBeenNthCalledWith(1, 250, {
945
+ 'session.id': 'test-session-id',
946
+ 'installation.id': 'test-installation-id',
947
+ 'user.email': 'test@example.com',
948
+ model: 'gemini-pro',
949
+ phase: 'network_latency',
950
+ });
951
+ expect(mockHistogramRecordFn).toHaveBeenNthCalledWith(2, 100, {
952
+ 'session.id': 'test-session-id',
953
+ 'installation.id': 'test-installation-id',
954
+ 'user.email': 'test@example.com',
955
+ model: 'gemini-pro',
956
+ phase: 'response_processing',
957
+ });
958
+ expect(mockHistogramRecordFn).toHaveBeenNthCalledWith(3, 50, {
959
+ 'session.id': 'test-session-id',
960
+ 'installation.id': 'test-installation-id',
961
+ 'user.email': 'test@example.com',
962
+ model: 'gemini-pro',
963
+ phase: 'token_processing',
964
+ });
965
+ });
966
+ });
967
+ describe('recordPerformanceScore', () => {
968
+ it('should record performance score with category and baseline', () => {
969
+ initializeMetricsModule(mockConfig);
970
+ mockHistogramRecordFn.mockClear();
971
+ recordPerformanceScoreModule(mockConfig, 85.5, {
972
+ category: 'memory_efficiency',
973
+ baseline: 80.0,
974
+ });
975
+ expect(mockHistogramRecordFn).toHaveBeenCalledWith(85.5, {
976
+ 'session.id': 'test-session-id',
977
+ 'installation.id': 'test-installation-id',
978
+ 'user.email': 'test@example.com',
979
+ category: 'memory_efficiency',
980
+ baseline: 80.0,
981
+ });
982
+ });
983
+ it('should record performance score without baseline', () => {
984
+ initializeMetricsModule(mockConfig);
985
+ mockHistogramRecordFn.mockClear();
986
+ recordPerformanceScoreModule(mockConfig, 92.3, {
987
+ category: 'overall_performance',
988
+ });
989
+ expect(mockHistogramRecordFn).toHaveBeenCalledWith(92.3, {
990
+ 'session.id': 'test-session-id',
991
+ 'installation.id': 'test-installation-id',
992
+ 'user.email': 'test@example.com',
993
+ category: 'overall_performance',
994
+ });
995
+ });
996
+ });
997
+ describe('recordPerformanceRegression', () => {
998
+ it('should record performance regression with baseline comparison', () => {
999
+ initializeMetricsModule(mockConfig);
1000
+ mockCounterAddFn.mockClear();
1001
+ mockHistogramRecordFn.mockClear();
1002
+ recordPerformanceRegressionModule(mockConfig, {
1003
+ metric: 'startup_time',
1004
+ current_value: 1200,
1005
+ baseline_value: 1000,
1006
+ severity: 'medium',
1007
+ });
1008
+ // Verify regression counter
1009
+ expect(mockCounterAddFn).toHaveBeenCalledWith(1, {
1010
+ 'session.id': 'test-session-id',
1011
+ 'installation.id': 'test-installation-id',
1012
+ 'user.email': 'test@example.com',
1013
+ metric: 'startup_time',
1014
+ severity: 'medium',
1015
+ current_value: 1200,
1016
+ baseline_value: 1000,
1017
+ });
1018
+ // Verify baseline comparison histogram (20% increase)
1019
+ expect(mockHistogramRecordFn).toHaveBeenCalledWith(20, {
1020
+ 'session.id': 'test-session-id',
1021
+ 'installation.id': 'test-installation-id',
1022
+ 'user.email': 'test@example.com',
1023
+ metric: 'startup_time',
1024
+ severity: 'medium',
1025
+ current_value: 1200,
1026
+ baseline_value: 1000,
1027
+ });
1028
+ });
1029
+ it('should handle zero baseline value gracefully', () => {
1030
+ initializeMetricsModule(mockConfig);
1031
+ mockCounterAddFn.mockClear();
1032
+ mockHistogramRecordFn.mockClear();
1033
+ recordPerformanceRegressionModule(mockConfig, {
1034
+ metric: 'memory_usage',
1035
+ current_value: 100,
1036
+ baseline_value: 0,
1037
+ severity: 'high',
1038
+ });
1039
+ // Verify regression counter still recorded
1040
+ expect(mockCounterAddFn).toHaveBeenCalledWith(1, {
1041
+ 'session.id': 'test-session-id',
1042
+ 'installation.id': 'test-installation-id',
1043
+ 'user.email': 'test@example.com',
1044
+ metric: 'memory_usage',
1045
+ severity: 'high',
1046
+ current_value: 100,
1047
+ baseline_value: 0,
1048
+ });
1049
+ // Verify no baseline comparison due to zero baseline
1050
+ expect(mockHistogramRecordFn).not.toHaveBeenCalled();
1051
+ });
1052
+ it('should record different severity levels', () => {
1053
+ initializeMetricsModule(mockConfig);
1054
+ mockCounterAddFn.mockClear();
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
+ });
1067
+ expect(mockCounterAddFn).toHaveBeenNthCalledWith(1, 1, {
1068
+ 'session.id': 'test-session-id',
1069
+ 'installation.id': 'test-installation-id',
1070
+ 'user.email': 'test@example.com',
1071
+ metric: 'api_latency',
1072
+ severity: 'low',
1073
+ current_value: 500,
1074
+ baseline_value: 400,
1075
+ });
1076
+ expect(mockCounterAddFn).toHaveBeenNthCalledWith(2, 1, {
1077
+ 'session.id': 'test-session-id',
1078
+ 'installation.id': 'test-installation-id',
1079
+ 'user.email': 'test@example.com',
1080
+ metric: 'cpu_usage',
1081
+ severity: 'high',
1082
+ current_value: 90,
1083
+ baseline_value: 70,
1084
+ });
1085
+ });
1086
+ });
1087
+ describe('recordBaselineComparison', () => {
1088
+ it('should record baseline comparison with percentage change', () => {
1089
+ initializeMetricsModule(mockConfig);
1090
+ mockHistogramRecordFn.mockClear();
1091
+ recordBaselineComparisonModule(mockConfig, {
1092
+ metric: 'memory_usage',
1093
+ current_value: 120,
1094
+ baseline_value: 100,
1095
+ category: 'performance_tracking',
1096
+ });
1097
+ // 20% increase: (120 - 100) / 100 * 100 = 20%
1098
+ expect(mockHistogramRecordFn).toHaveBeenCalledWith(20, {
1099
+ 'session.id': 'test-session-id',
1100
+ 'installation.id': 'test-installation-id',
1101
+ 'user.email': 'test@example.com',
1102
+ metric: 'memory_usage',
1103
+ category: 'performance_tracking',
1104
+ current_value: 120,
1105
+ baseline_value: 100,
1106
+ });
1107
+ });
1108
+ it('should handle negative percentage change (improvement)', () => {
1109
+ initializeMetricsModule(mockConfig);
1110
+ mockHistogramRecordFn.mockClear();
1111
+ recordBaselineComparisonModule(mockConfig, {
1112
+ metric: 'startup_time',
1113
+ current_value: 800,
1114
+ baseline_value: 1000,
1115
+ category: 'optimization',
1116
+ });
1117
+ // 20% decrease: (800 - 1000) / 1000 * 100 = -20%
1118
+ expect(mockHistogramRecordFn).toHaveBeenCalledWith(-20, {
1119
+ 'session.id': 'test-session-id',
1120
+ 'installation.id': 'test-installation-id',
1121
+ 'user.email': 'test@example.com',
1122
+ metric: 'startup_time',
1123
+ category: 'optimization',
1124
+ current_value: 800,
1125
+ baseline_value: 1000,
1126
+ });
1127
+ });
1128
+ it('should skip recording when baseline is zero', async () => {
1129
+ // Access the actual mocked module
1130
+ const mockedModule = (await vi.importMock('@opentelemetry/api'));
1131
+ const diagSpy = vi.spyOn(mockedModule.diag, 'warn');
1132
+ initializeMetricsModule(mockConfig);
1133
+ mockHistogramRecordFn.mockClear();
1134
+ recordBaselineComparisonModule(mockConfig, {
1135
+ metric: 'new_metric',
1136
+ current_value: 50,
1137
+ baseline_value: 0,
1138
+ category: 'testing',
1139
+ });
1140
+ expect(diagSpy).toHaveBeenCalledWith('Baseline value is zero, skipping comparison.');
1141
+ expect(mockHistogramRecordFn).not.toHaveBeenCalled();
1142
+ });
1143
+ });
1144
+ });
263
1145
  });
264
1146
  //# sourceMappingURL=metrics.test.js.map