@machina.ai/cell-cli-core 1.0.21-rc4 → 1.4.0-rc1

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 (505) hide show
  1. package/dist/index.d.ts +6 -2
  2. package/dist/index.js +6 -2
  3. package/dist/index.js.map +1 -1
  4. package/dist/package.json +25 -11
  5. package/dist/src/code_assist/codeAssist.d.ts +6 -3
  6. package/dist/src/code_assist/codeAssist.js +12 -0
  7. package/dist/src/code_assist/codeAssist.js.map +1 -1
  8. package/dist/src/code_assist/converter.d.ts +3 -1
  9. package/dist/src/code_assist/converter.js +37 -5
  10. package/dist/src/code_assist/converter.js.map +1 -1
  11. package/dist/src/code_assist/converter.test.js +83 -0
  12. package/dist/src/code_assist/converter.test.js.map +1 -1
  13. package/dist/src/code_assist/oauth2.d.ts +2 -1
  14. package/dist/src/code_assist/oauth2.js +85 -49
  15. package/dist/src/code_assist/oauth2.js.map +1 -1
  16. package/dist/src/code_assist/oauth2.test.js +317 -15
  17. package/dist/src/code_assist/oauth2.test.js.map +1 -1
  18. package/dist/src/code_assist/server.d.ts +5 -5
  19. package/dist/src/code_assist/server.js +1 -1
  20. package/dist/src/code_assist/server.js.map +1 -1
  21. package/dist/src/code_assist/setup.d.ts +1 -1
  22. package/dist/src/code_assist/setup.js +1 -1
  23. package/dist/src/code_assist/setup.js.map +1 -1
  24. package/dist/src/code_assist/setup.test.js.map +1 -1
  25. package/dist/src/config/config.d.ts +53 -15
  26. package/dist/src/config/config.js +127 -47
  27. package/dist/src/config/config.js.map +1 -1
  28. package/dist/src/config/config.test.js +151 -6
  29. package/dist/src/config/config.test.js.map +1 -1
  30. package/dist/src/config/models.d.ts +1 -0
  31. package/dist/src/config/models.js +2 -0
  32. package/dist/src/config/models.js.map +1 -1
  33. package/dist/src/config/storage.d.ts +32 -0
  34. package/dist/src/config/storage.js +90 -0
  35. package/dist/src/config/storage.js.map +1 -0
  36. package/dist/src/config/storage.test.js +43 -0
  37. package/dist/src/config/storage.test.js.map +1 -0
  38. package/dist/src/core/client.d.ts +21 -11
  39. package/dist/src/core/client.js +83 -26
  40. package/dist/src/core/client.js.map +1 -1
  41. package/dist/src/core/client.test.js +398 -88
  42. package/dist/src/core/client.test.js.map +1 -1
  43. package/dist/src/core/contentGenerator.d.ts +6 -6
  44. package/dist/src/core/contentGenerator.js +4 -3
  45. package/dist/src/core/contentGenerator.js.map +1 -1
  46. package/dist/src/core/contentGenerator.test.js.map +1 -1
  47. package/dist/src/core/coreToolScheduler.d.ts +14 -5
  48. package/dist/src/core/coreToolScheduler.js +120 -49
  49. package/dist/src/core/coreToolScheduler.js.map +1 -1
  50. package/dist/src/core/coreToolScheduler.test.js +383 -72
  51. package/dist/src/core/coreToolScheduler.test.js.map +1 -1
  52. package/dist/src/core/geminiChat.d.ts +48 -15
  53. package/dist/src/core/geminiChat.js +327 -154
  54. package/dist/src/core/geminiChat.js.map +1 -1
  55. package/dist/src/core/geminiChat.test.js +1041 -257
  56. package/dist/src/core/geminiChat.test.js.map +1 -1
  57. package/dist/src/core/geminiRequest.js +1 -0
  58. package/dist/src/core/geminiRequest.js.map +1 -1
  59. package/dist/src/core/logger.d.ts +4 -2
  60. package/dist/src/core/logger.js +4 -3
  61. package/dist/src/core/logger.js.map +1 -1
  62. package/dist/src/core/logger.test.js +19 -18
  63. package/dist/src/core/logger.test.js.map +1 -1
  64. package/dist/src/core/loggingContentGenerator.d.ts +3 -3
  65. package/dist/src/core/loggingContentGenerator.js +11 -9
  66. package/dist/src/core/loggingContentGenerator.js.map +1 -1
  67. package/dist/src/core/nonInteractiveToolExecutor.d.ts +3 -5
  68. package/dist/src/core/nonInteractiveToolExecutor.js +15 -123
  69. package/dist/src/core/nonInteractiveToolExecutor.js.map +1 -1
  70. package/dist/src/core/nonInteractiveToolExecutor.test.js +116 -90
  71. package/dist/src/core/nonInteractiveToolExecutor.test.js.map +1 -1
  72. package/dist/src/core/prompts.js +8 -7
  73. package/dist/src/core/prompts.js.map +1 -1
  74. package/dist/src/core/prompts.test.js +21 -21
  75. package/dist/src/core/prompts.test.js.map +1 -1
  76. package/dist/src/core/subagent.d.ts +24 -18
  77. package/dist/src/core/subagent.js +126 -89
  78. package/dist/src/core/subagent.js.map +1 -1
  79. package/dist/src/core/subagent.test.js +51 -35
  80. package/dist/src/core/subagent.test.js.map +1 -1
  81. package/dist/src/core/turn.d.ts +33 -8
  82. package/dist/src/core/turn.js +59 -14
  83. package/dist/src/core/turn.js.map +1 -1
  84. package/dist/src/core/turn.test.js +349 -90
  85. package/dist/src/core/turn.test.js.map +1 -1
  86. package/dist/src/generated/git-commit.d.ts +2 -2
  87. package/dist/src/generated/git-commit.js +2 -2
  88. package/dist/src/generated/git-commit.js.map +1 -1
  89. package/dist/src/ide/constants.d.ts +1 -1
  90. package/dist/src/ide/constants.js +1 -1
  91. package/dist/src/ide/constants.js.map +1 -1
  92. package/dist/src/ide/detect-ide.d.ts +8 -3
  93. package/dist/src/ide/detect-ide.js +29 -11
  94. package/dist/src/ide/detect-ide.js.map +1 -1
  95. package/dist/src/ide/detect-ide.test.js +96 -52
  96. package/dist/src/ide/detect-ide.test.js.map +1 -1
  97. package/dist/src/ide/ide-client.d.ts +18 -9
  98. package/dist/src/ide/ide-client.js +151 -33
  99. package/dist/src/ide/ide-client.js.map +1 -1
  100. package/dist/src/ide/ide-client.test.js +147 -25
  101. package/dist/src/ide/ide-client.test.js.map +1 -1
  102. package/dist/src/ide/ide-installer.d.ts +1 -1
  103. package/dist/src/ide/ide-installer.js +31 -22
  104. package/dist/src/ide/ide-installer.js.map +1 -1
  105. package/dist/src/ide/ide-installer.test.js +82 -22
  106. package/dist/src/ide/ide-installer.test.js.map +1 -1
  107. package/dist/src/ide/ideContext.d.ts +12 -0
  108. package/dist/src/ide/ideContext.js +1 -0
  109. package/dist/src/ide/ideContext.js.map +1 -1
  110. package/dist/src/ide/process-utils.d.ts +13 -6
  111. package/dist/src/ide/process-utils.js +142 -35
  112. package/dist/src/ide/process-utils.js.map +1 -1
  113. package/dist/src/ide/process-utils.test.js +158 -0
  114. package/dist/src/ide/process-utils.test.js.map +1 -0
  115. package/dist/src/index.d.ts +12 -2
  116. package/dist/src/index.js +11 -1
  117. package/dist/src/index.js.map +1 -1
  118. package/dist/src/mcp/google-auth-provider.d.ts +3 -3
  119. package/dist/src/mcp/google-auth-provider.test.js.map +1 -1
  120. package/dist/src/mcp/oauth-provider.d.ts +13 -13
  121. package/dist/src/mcp/oauth-provider.js +32 -31
  122. package/dist/src/mcp/oauth-provider.js.map +1 -1
  123. package/dist/src/mcp/oauth-provider.test.js +75 -36
  124. package/dist/src/mcp/oauth-provider.test.js.map +1 -1
  125. package/dist/src/mcp/oauth-token-storage.d.ts +9 -31
  126. package/dist/src/mcp/oauth-token-storage.js +10 -13
  127. package/dist/src/mcp/oauth-token-storage.js.map +1 -1
  128. package/dist/src/mcp/oauth-token-storage.test.js +30 -27
  129. package/dist/src/mcp/oauth-token-storage.test.js.map +1 -1
  130. package/dist/src/mcp/oauth-utils.d.ts +9 -1
  131. package/dist/src/mcp/oauth-utils.js +41 -27
  132. package/dist/src/mcp/oauth-utils.js.map +1 -1
  133. package/dist/src/mcp/oauth-utils.test.js +41 -1
  134. package/dist/src/mcp/oauth-utils.test.js.map +1 -1
  135. package/dist/src/mcp/token-storage/base-token-storage.d.ts +19 -0
  136. package/dist/src/mcp/token-storage/base-token-storage.js +36 -0
  137. package/dist/src/mcp/token-storage/base-token-storage.js.map +1 -0
  138. package/dist/src/mcp/token-storage/base-token-storage.test.d.ts +6 -0
  139. package/dist/src/mcp/token-storage/base-token-storage.test.js +160 -0
  140. package/dist/src/mcp/token-storage/base-token-storage.test.js.map +1 -0
  141. package/dist/src/mcp/token-storage/file-token-storage.d.ts +24 -0
  142. package/dist/src/mcp/token-storage/file-token-storage.js +144 -0
  143. package/dist/src/mcp/token-storage/file-token-storage.js.map +1 -0
  144. package/dist/src/mcp/token-storage/file-token-storage.test.d.ts +6 -0
  145. package/dist/src/mcp/token-storage/file-token-storage.test.js +235 -0
  146. package/dist/src/mcp/token-storage/file-token-storage.test.js.map +1 -0
  147. package/dist/src/mcp/token-storage/hybrid-token-storage.d.ts +23 -0
  148. package/dist/src/mcp/token-storage/hybrid-token-storage.js +78 -0
  149. package/dist/src/mcp/token-storage/hybrid-token-storage.js.map +1 -0
  150. package/dist/src/mcp/token-storage/hybrid-token-storage.test.d.ts +6 -0
  151. package/dist/src/mcp/token-storage/hybrid-token-storage.test.js +193 -0
  152. package/dist/src/mcp/token-storage/hybrid-token-storage.test.js.map +1 -0
  153. package/dist/src/mcp/token-storage/keychain-token-storage.d.ts +31 -0
  154. package/dist/src/mcp/token-storage/keychain-token-storage.js +190 -0
  155. package/dist/src/mcp/token-storage/keychain-token-storage.js.map +1 -0
  156. package/dist/src/mcp/token-storage/keychain-token-storage.test.d.ts +6 -0
  157. package/dist/src/mcp/token-storage/keychain-token-storage.test.js +254 -0
  158. package/dist/src/mcp/token-storage/keychain-token-storage.test.js.map +1 -0
  159. package/dist/src/mcp/token-storage/types.d.ts +38 -0
  160. package/dist/src/mcp/token-storage/types.js +11 -0
  161. package/dist/src/mcp/token-storage/types.js.map +1 -0
  162. package/dist/src/prompts/mcp-prompts.d.ts +2 -2
  163. package/dist/src/prompts/prompt-registry.d.ts +1 -1
  164. package/dist/src/services/chatRecordingService.d.ts +6 -13
  165. package/dist/src/services/chatRecordingService.js +31 -19
  166. package/dist/src/services/chatRecordingService.js.map +1 -1
  167. package/dist/src/services/chatRecordingService.test.js +64 -25
  168. package/dist/src/services/chatRecordingService.test.js.map +1 -1
  169. package/dist/src/services/fileDiscoveryService.js +1 -1
  170. package/dist/src/services/fileDiscoveryService.js.map +1 -1
  171. package/dist/src/services/fileDiscoveryService.test.js +3 -3
  172. package/dist/src/services/fileDiscoveryService.test.js.map +1 -1
  173. package/dist/src/services/fileSystemService.js +1 -1
  174. package/dist/src/services/fileSystemService.js.map +1 -1
  175. package/dist/src/services/fileSystemService.test.js +1 -1
  176. package/dist/src/services/fileSystemService.test.js.map +1 -1
  177. package/dist/src/services/gitService.d.ts +3 -1
  178. package/dist/src/services/gitService.js +21 -12
  179. package/dist/src/services/gitService.js.map +1 -1
  180. package/dist/src/services/gitService.test.js +22 -19
  181. package/dist/src/services/gitService.test.js.map +1 -1
  182. package/dist/src/services/loopDetectionService.d.ts +3 -2
  183. package/dist/src/services/loopDetectionService.js +28 -4
  184. package/dist/src/services/loopDetectionService.js.map +1 -1
  185. package/dist/src/services/loopDetectionService.test.js +23 -1
  186. package/dist/src/services/loopDetectionService.test.js.map +1 -1
  187. package/dist/src/services/shellExecutionService.d.ts +8 -10
  188. package/dist/src/services/shellExecutionService.js +292 -135
  189. package/dist/src/services/shellExecutionService.js.map +1 -1
  190. package/dist/src/services/shellExecutionService.test.js +277 -42
  191. package/dist/src/services/shellExecutionService.test.js.map +1 -1
  192. package/dist/src/telemetry/clearcut-logger/clearcut-logger.d.ts +18 -4
  193. package/dist/src/telemetry/clearcut-logger/clearcut-logger.js +171 -11
  194. package/dist/src/telemetry/clearcut-logger/clearcut-logger.js.map +1 -1
  195. package/dist/src/telemetry/clearcut-logger/clearcut-logger.test.js +103 -11
  196. package/dist/src/telemetry/clearcut-logger/clearcut-logger.test.js.map +1 -1
  197. package/dist/src/telemetry/clearcut-logger/event-metadata-key.d.ts +31 -1
  198. package/dist/src/telemetry/clearcut-logger/event-metadata-key.js +75 -0
  199. package/dist/src/telemetry/clearcut-logger/event-metadata-key.js.map +1 -1
  200. package/dist/src/telemetry/constants.d.ts +9 -0
  201. package/dist/src/telemetry/constants.js +9 -0
  202. package/dist/src/telemetry/constants.js.map +1 -1
  203. package/dist/src/telemetry/file-exporters.d.ts +5 -4
  204. package/dist/src/telemetry/file-exporters.js +1 -1
  205. package/dist/src/telemetry/file-exporters.js.map +1 -1
  206. package/dist/src/telemetry/index.d.ts +5 -2
  207. package/dist/src/telemetry/index.js +3 -2
  208. package/dist/src/telemetry/index.js.map +1 -1
  209. package/dist/src/telemetry/loggers.d.ts +8 -2
  210. package/dist/src/telemetry/loggers.js +130 -2
  211. package/dist/src/telemetry/loggers.js.map +1 -1
  212. package/dist/src/telemetry/loggers.test.circular.js.map +1 -1
  213. package/dist/src/telemetry/loggers.test.js +105 -9
  214. package/dist/src/telemetry/loggers.test.js.map +1 -1
  215. package/dist/src/telemetry/metrics.d.ts +15 -4
  216. package/dist/src/telemetry/metrics.js +46 -8
  217. package/dist/src/telemetry/metrics.js.map +1 -1
  218. package/dist/src/telemetry/metrics.test.js +5 -25
  219. package/dist/src/telemetry/metrics.test.js.map +1 -1
  220. package/dist/src/telemetry/sdk.d.ts +1 -1
  221. package/dist/src/telemetry/sdk.js +3 -3
  222. package/dist/src/telemetry/sdk.js.map +1 -1
  223. package/dist/src/telemetry/telemetry-utils.d.ts +6 -0
  224. package/dist/src/telemetry/telemetry-utils.js +14 -0
  225. package/dist/src/telemetry/telemetry-utils.js.map +1 -0
  226. package/dist/src/telemetry/telemetry-utils.test.d.ts +6 -0
  227. package/dist/src/telemetry/telemetry-utils.test.js +40 -0
  228. package/dist/src/telemetry/telemetry-utils.test.js.map +1 -0
  229. package/dist/src/telemetry/types.d.ts +61 -6
  230. package/dist/src/telemetry/types.js +105 -4
  231. package/dist/src/telemetry/types.js.map +1 -1
  232. package/dist/src/telemetry/uiTelemetry.d.ts +2 -2
  233. package/dist/src/telemetry/uiTelemetry.js +5 -5
  234. package/dist/src/telemetry/uiTelemetry.js.map +1 -1
  235. package/dist/src/telemetry/uiTelemetry.test.js +20 -16
  236. package/dist/src/telemetry/uiTelemetry.test.js.map +1 -1
  237. package/dist/src/test-utils/config.d.ts +2 -1
  238. package/dist/src/test-utils/config.js.map +1 -1
  239. package/dist/src/test-utils/index.d.ts +6 -0
  240. package/dist/src/test-utils/index.js +7 -0
  241. package/dist/src/test-utils/index.js.map +1 -0
  242. package/dist/src/test-utils/mock-tool.d.ts +41 -0
  243. package/dist/src/test-utils/mock-tool.js +51 -0
  244. package/dist/src/test-utils/mock-tool.js.map +1 -0
  245. package/dist/src/test-utils/mockWorkspaceContext.d.ts +1 -1
  246. package/dist/src/test-utils/tools.d.ts +3 -2
  247. package/dist/src/test-utils/tools.js.map +1 -1
  248. package/dist/src/tools/diffOptions.d.ts +1 -1
  249. package/dist/src/tools/diffOptions.js +21 -13
  250. package/dist/src/tools/diffOptions.js.map +1 -1
  251. package/dist/src/tools/diffOptions.test.js +58 -22
  252. package/dist/src/tools/diffOptions.test.js.map +1 -1
  253. package/dist/src/tools/edit.d.ts +6 -5
  254. package/dist/src/tools/edit.js +47 -36
  255. package/dist/src/tools/edit.js.map +1 -1
  256. package/dist/src/tools/edit.test.js +77 -12
  257. package/dist/src/tools/edit.test.js.map +1 -1
  258. package/dist/src/tools/glob.d.ts +3 -2
  259. package/dist/src/tools/glob.js +17 -6
  260. package/dist/src/tools/glob.js.map +1 -1
  261. package/dist/src/tools/glob.test.js +29 -4
  262. package/dist/src/tools/glob.test.js.map +1 -1
  263. package/dist/src/tools/grep.d.ts +3 -2
  264. package/dist/src/tools/grep.js +35 -15
  265. package/dist/src/tools/grep.js.map +1 -1
  266. package/dist/src/tools/grep.test.js +26 -3
  267. package/dist/src/tools/grep.test.js.map +1 -1
  268. package/dist/src/tools/ls.d.ts +3 -2
  269. package/dist/src/tools/ls.js +12 -7
  270. package/dist/src/tools/ls.js.map +1 -1
  271. package/dist/src/tools/ls.test.js +7 -2
  272. package/dist/src/tools/ls.test.js.map +1 -1
  273. package/dist/src/tools/mcp-client-manager.d.ts +8 -6
  274. package/dist/src/tools/mcp-client-manager.js +30 -5
  275. package/dist/src/tools/mcp-client-manager.js.map +1 -1
  276. package/dist/src/tools/mcp-client-manager.test.js +20 -1
  277. package/dist/src/tools/mcp-client-manager.test.js.map +1 -1
  278. package/dist/src/tools/mcp-client.d.ts +18 -11
  279. package/dist/src/tools/mcp-client.js +67 -57
  280. package/dist/src/tools/mcp-client.js.map +1 -1
  281. package/dist/src/tools/mcp-client.test.js +29 -4
  282. package/dist/src/tools/mcp-client.test.js.map +1 -1
  283. package/dist/src/tools/mcp-tool.d.ts +6 -4
  284. package/dist/src/tools/mcp-tool.js +21 -11
  285. package/dist/src/tools/mcp-tool.js.map +1 -1
  286. package/dist/src/tools/mcp-tool.test.js +49 -12
  287. package/dist/src/tools/mcp-tool.test.js.map +1 -1
  288. package/dist/src/tools/memoryTool.d.ts +4 -3
  289. package/dist/src/tools/memoryTool.js +15 -38
  290. package/dist/src/tools/memoryTool.js.map +1 -1
  291. package/dist/src/tools/memoryTool.test.js +24 -12
  292. package/dist/src/tools/memoryTool.test.js.map +1 -1
  293. package/dist/src/tools/modifiable-tool.d.ts +2 -2
  294. package/dist/src/tools/modifiable-tool.js +3 -3
  295. package/dist/src/tools/modifiable-tool.js.map +1 -1
  296. package/dist/src/tools/modifiable-tool.test.js +4 -4
  297. package/dist/src/tools/modifiable-tool.test.js.map +1 -1
  298. package/dist/src/tools/read-file.d.ts +3 -2
  299. package/dist/src/tools/read-file.js +12 -34
  300. package/dist/src/tools/read-file.js.map +1 -1
  301. package/dist/src/tools/read-file.test.js +9 -6
  302. package/dist/src/tools/read-file.test.js.map +1 -1
  303. package/dist/src/tools/read-many-files.d.ts +3 -2
  304. package/dist/src/tools/read-many-files.js +35 -58
  305. package/dist/src/tools/read-many-files.js.map +1 -1
  306. package/dist/src/tools/read-many-files.test.js +64 -11
  307. package/dist/src/tools/read-many-files.test.js.map +1 -1
  308. package/dist/src/tools/ripGrep.d.ts +47 -0
  309. package/dist/src/tools/ripGrep.js +368 -0
  310. package/dist/src/tools/ripGrep.js.map +1 -0
  311. package/dist/src/tools/ripGrep.test.d.ts +6 -0
  312. package/dist/src/tools/ripGrep.test.js +874 -0
  313. package/dist/src/tools/ripGrep.test.js.map +1 -0
  314. package/dist/src/tools/shell.d.ts +3 -2
  315. package/dist/src/tools/shell.js +30 -25
  316. package/dist/src/tools/shell.js.map +1 -1
  317. package/dist/src/tools/shell.test.js +34 -25
  318. package/dist/src/tools/shell.test.js.map +1 -1
  319. package/dist/src/tools/smart-edit.d.ts +73 -0
  320. package/dist/src/tools/smart-edit.js +607 -0
  321. package/dist/src/tools/smart-edit.js.map +1 -0
  322. package/dist/src/tools/smart-edit.test.d.ts +6 -0
  323. package/dist/src/tools/smart-edit.test.js +405 -0
  324. package/dist/src/tools/smart-edit.test.js.map +1 -0
  325. package/dist/src/tools/tool-error.d.ts +17 -1
  326. package/dist/src/tools/tool-error.js +26 -0
  327. package/dist/src/tools/tool-error.js.map +1 -1
  328. package/dist/src/tools/tool-registry.d.ts +10 -4
  329. package/dist/src/tools/tool-registry.js +19 -7
  330. package/dist/src/tools/tool-registry.js.map +1 -1
  331. package/dist/src/tools/tool-registry.test.js +86 -3
  332. package/dist/src/tools/tool-registry.test.js.map +1 -1
  333. package/dist/src/tools/tools.d.ts +15 -9
  334. package/dist/src/tools/tools.js +12 -0
  335. package/dist/src/tools/tools.js.map +1 -1
  336. package/dist/src/tools/tools.test.js +1 -2
  337. package/dist/src/tools/tools.test.js.map +1 -1
  338. package/dist/src/tools/web-fetch.d.ts +3 -2
  339. package/dist/src/tools/web-fetch.js +14 -10
  340. package/dist/src/tools/web-fetch.js.map +1 -1
  341. package/dist/src/tools/web-fetch.test.js +55 -16
  342. package/dist/src/tools/web-fetch.test.js.map +1 -1
  343. package/dist/src/tools/web-search.d.ts +4 -3
  344. package/dist/src/tools/web-search.js +31 -8
  345. package/dist/src/tools/web-search.js.map +1 -1
  346. package/dist/src/tools/web-search.test.js +69 -1
  347. package/dist/src/tools/web-search.test.js.map +1 -1
  348. package/dist/src/tools/write-file.d.ts +4 -3
  349. package/dist/src/tools/write-file.js +14 -14
  350. package/dist/src/tools/write-file.js.map +1 -1
  351. package/dist/src/tools/write-file.test.js +14 -14
  352. package/dist/src/tools/write-file.test.js.map +1 -1
  353. package/dist/src/utils/bfsFileSearch.d.ts +2 -2
  354. package/dist/src/utils/bfsFileSearch.js +2 -2
  355. package/dist/src/utils/bfsFileSearch.js.map +1 -1
  356. package/dist/src/utils/bfsFileSearch.test.js +3 -3
  357. package/dist/src/utils/bfsFileSearch.test.js.map +1 -1
  358. package/dist/src/utils/editCorrector.d.ts +2 -2
  359. package/dist/src/utils/editCorrector.js +1 -1
  360. package/dist/src/utils/editCorrector.js.map +1 -1
  361. package/dist/src/utils/editCorrector.test.js +3 -3
  362. package/dist/src/utils/editCorrector.test.js.map +1 -1
  363. package/dist/src/utils/editor.js +2 -2
  364. package/dist/src/utils/editor.js.map +1 -1
  365. package/dist/src/utils/editor.test.js +2 -2
  366. package/dist/src/utils/editor.test.js.map +1 -1
  367. package/dist/src/utils/environmentContext.d.ts +2 -2
  368. package/dist/src/utils/environmentContext.js +1 -1
  369. package/dist/src/utils/environmentContext.js.map +1 -1
  370. package/dist/src/utils/environmentContext.test.js +1 -1
  371. package/dist/src/utils/environmentContext.test.js.map +1 -1
  372. package/dist/src/utils/errorReporting.d.ts +1 -1
  373. package/dist/src/utils/errors.d.ts +19 -0
  374. package/dist/src/utils/errors.js +32 -0
  375. package/dist/src/utils/errors.js.map +1 -1
  376. package/dist/src/utils/fetch.js +1 -1
  377. package/dist/src/utils/fetch.js.map +1 -1
  378. package/dist/src/utils/fileUtils.d.ts +23 -12
  379. package/dist/src/utils/fileUtils.js +160 -79
  380. package/dist/src/utils/fileUtils.js.map +1 -1
  381. package/dist/src/utils/fileUtils.test.js +314 -21
  382. package/dist/src/utils/fileUtils.test.js.map +1 -1
  383. package/dist/src/utils/filesearch/crawler.d.ts +1 -1
  384. package/dist/src/utils/filesearch/crawler.test.js +2 -2
  385. package/dist/src/utils/filesearch/crawler.test.js.map +1 -1
  386. package/dist/src/utils/filesearch/fileSearch.d.ts +1 -0
  387. package/dist/src/utils/filesearch/fileSearch.js +14 -9
  388. package/dist/src/utils/filesearch/fileSearch.js.map +1 -1
  389. package/dist/src/utils/filesearch/fileSearch.test.js +90 -0
  390. package/dist/src/utils/filesearch/fileSearch.test.js.map +1 -1
  391. package/dist/src/utils/generateContentResponseUtilities.d.ts +1 -2
  392. package/dist/src/utils/generateContentResponseUtilities.js +1 -13
  393. package/dist/src/utils/generateContentResponseUtilities.js.map +1 -1
  394. package/dist/src/utils/generateContentResponseUtilities.test.js +2 -40
  395. package/dist/src/utils/generateContentResponseUtilities.test.js.map +1 -1
  396. package/dist/src/utils/getFolderStructure.d.ts +2 -2
  397. package/dist/src/utils/getFolderStructure.js +2 -2
  398. package/dist/src/utils/getFolderStructure.js.map +1 -1
  399. package/dist/src/utils/getFolderStructure.test.js +13 -13
  400. package/dist/src/utils/getFolderStructure.test.js.map +1 -1
  401. package/dist/src/utils/getPty.d.ts +19 -0
  402. package/dist/src/utils/getPty.js +23 -0
  403. package/dist/src/utils/getPty.js.map +1 -0
  404. package/dist/src/utils/gitIgnoreParser.d.ts +1 -0
  405. package/dist/src/utils/gitIgnoreParser.js +104 -13
  406. package/dist/src/utils/gitIgnoreParser.js.map +1 -1
  407. package/dist/src/utils/gitIgnoreParser.test.js +69 -3
  408. package/dist/src/utils/gitIgnoreParser.test.js.map +1 -1
  409. package/dist/src/utils/gitUtils.js +2 -2
  410. package/dist/src/utils/gitUtils.js.map +1 -1
  411. package/dist/src/utils/ide-trust.d.ts +10 -0
  412. package/dist/src/utils/ide-trust.js +14 -0
  413. package/dist/src/utils/ide-trust.js.map +1 -0
  414. package/dist/src/utils/ignorePatterns.d.ts +103 -0
  415. package/dist/src/utils/ignorePatterns.js +220 -0
  416. package/dist/src/utils/ignorePatterns.js.map +1 -0
  417. package/dist/src/utils/ignorePatterns.test.d.ts +6 -0
  418. package/dist/src/utils/ignorePatterns.test.js +250 -0
  419. package/dist/src/utils/ignorePatterns.test.js.map +1 -0
  420. package/dist/src/utils/installationManager.d.ts +16 -0
  421. package/dist/src/utils/installationManager.js +50 -0
  422. package/dist/src/utils/installationManager.js.map +1 -0
  423. package/dist/src/utils/installationManager.test.d.ts +6 -0
  424. package/dist/src/utils/installationManager.test.js +83 -0
  425. package/dist/src/utils/installationManager.test.js.map +1 -0
  426. package/dist/src/utils/language-detection.d.ts +6 -0
  427. package/dist/src/utils/language-detection.js +101 -0
  428. package/dist/src/utils/language-detection.js.map +1 -0
  429. package/dist/src/utils/llm-edit-fixer.d.ts +25 -0
  430. package/dist/src/utils/llm-edit-fixer.js +112 -0
  431. package/dist/src/utils/llm-edit-fixer.js.map +1 -0
  432. package/dist/src/utils/memoryDiscovery.d.ts +7 -6
  433. package/dist/src/utils/memoryDiscovery.js +68 -33
  434. package/dist/src/utils/memoryDiscovery.js.map +1 -1
  435. package/dist/src/utils/memoryDiscovery.test.js +76 -20
  436. package/dist/src/utils/memoryDiscovery.test.js.map +1 -1
  437. package/dist/src/utils/memoryImportProcessor.js +2 -2
  438. package/dist/src/utils/memoryImportProcessor.js.map +1 -1
  439. package/dist/src/utils/memoryImportProcessor.test.js +2 -141
  440. package/dist/src/utils/memoryImportProcessor.test.js.map +1 -1
  441. package/dist/src/utils/messageInspectors.d.ts +1 -1
  442. package/dist/src/utils/nextSpeakerChecker.d.ts +2 -2
  443. package/dist/src/utils/nextSpeakerChecker.test.js +33 -0
  444. package/dist/src/utils/nextSpeakerChecker.test.js.map +1 -1
  445. package/dist/src/utils/partUtils.d.ts +22 -1
  446. package/dist/src/utils/partUtils.js +68 -0
  447. package/dist/src/utils/partUtils.js.map +1 -1
  448. package/dist/src/utils/partUtils.test.js +112 -1
  449. package/dist/src/utils/partUtils.test.js.map +1 -1
  450. package/dist/src/utils/pathReader.d.ts +17 -0
  451. package/dist/src/utils/pathReader.js +92 -0
  452. package/dist/src/utils/pathReader.js.map +1 -0
  453. package/dist/src/utils/pathReader.test.d.ts +6 -0
  454. package/dist/src/utils/pathReader.test.js +363 -0
  455. package/dist/src/utils/pathReader.test.js.map +1 -0
  456. package/dist/src/utils/paths.d.ts +1 -18
  457. package/dist/src/utils/paths.js +3 -29
  458. package/dist/src/utils/paths.js.map +1 -1
  459. package/dist/src/utils/quotaErrorDetection.d.ts +1 -1
  460. package/dist/src/utils/retry.test.js +4 -1
  461. package/dist/src/utils/retry.test.js.map +1 -1
  462. package/dist/src/utils/schemaValidator.js +4 -0
  463. package/dist/src/utils/schemaValidator.js.map +1 -1
  464. package/dist/src/utils/session.js +1 -1
  465. package/dist/src/utils/session.js.map +1 -1
  466. package/dist/src/utils/shell-utils.d.ts +1 -1
  467. package/dist/src/utils/shell-utils.js +23 -29
  468. package/dist/src/utils/shell-utils.js.map +1 -1
  469. package/dist/src/utils/shell-utils.test.js +7 -0
  470. package/dist/src/utils/shell-utils.test.js.map +1 -1
  471. package/dist/src/utils/summarizer.d.ts +2 -2
  472. package/dist/src/utils/summarizer.test.js.map +1 -1
  473. package/dist/src/utils/systemEncoding.js +2 -2
  474. package/dist/src/utils/systemEncoding.js.map +1 -1
  475. package/dist/src/utils/systemEncoding.test.js +2 -2
  476. package/dist/src/utils/systemEncoding.test.js.map +1 -1
  477. package/dist/src/utils/tool-utils.d.ts +19 -0
  478. package/dist/src/utils/tool-utils.js +58 -0
  479. package/dist/src/utils/tool-utils.js.map +1 -0
  480. package/dist/src/utils/tool-utils.test.d.ts +6 -0
  481. package/dist/src/utils/tool-utils.test.js +61 -0
  482. package/dist/src/utils/tool-utils.test.js.map +1 -0
  483. package/dist/src/utils/userAccountManager.d.ts +20 -0
  484. package/dist/src/utils/userAccountManager.js +114 -0
  485. package/dist/src/utils/userAccountManager.js.map +1 -0
  486. package/dist/src/utils/userAccountManager.test.d.ts +6 -0
  487. package/dist/src/utils/{user_account.test.js → userAccountManager.test.js} +33 -30
  488. package/dist/src/utils/userAccountManager.test.js.map +1 -0
  489. package/dist/src/utils/workspaceContext.js +13 -7
  490. package/dist/src/utils/workspaceContext.js.map +1 -1
  491. package/dist/src/utils/workspaceContext.test.js +41 -16
  492. package/dist/src/utils/workspaceContext.test.js.map +1 -1
  493. package/dist/tsconfig.tsbuildinfo +1 -1
  494. package/package.json +27 -13
  495. package/dist/src/utils/user_account.d.ts +0 -9
  496. package/dist/src/utils/user_account.js +0 -109
  497. package/dist/src/utils/user_account.js.map +0 -1
  498. package/dist/src/utils/user_account.test.js.map +0 -1
  499. package/dist/src/utils/user_id.d.ts +0 -11
  500. package/dist/src/utils/user_id.js +0 -49
  501. package/dist/src/utils/user_id.js.map +0 -1
  502. package/dist/src/utils/user_id.test.js +0 -21
  503. package/dist/src/utils/user_id.test.js.map +0 -1
  504. /package/dist/src/{utils/user_account.test.d.ts → config/storage.test.d.ts} +0 -0
  505. /package/dist/src/{utils/user_id.test.d.ts → ide/process-utils.test.d.ts} +0 -0
@@ -3,12 +3,13 @@
3
3
  * Copyright 2025 Google LLC
4
4
  * SPDX-License-Identifier: Apache-2.0
5
5
  */
6
- import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
7
- import { GoogleGenAI, } from '@google/genai';
8
- import { findIndexAfterFraction, GeminiClient } from './client.js';
9
- import { AuthType } from './contentGenerator.js';
6
+ import { describe, it, expect, vi, beforeEach, afterEach, } from 'vitest';
7
+ import { GoogleGenAI } from '@google/genai';
8
+ import { findIndexAfterFraction, isThinkingDefault, isThinkingSupported, GeminiClient, } from './client.js';
9
+ import { AuthType, } from './contentGenerator.js';
10
+ import {} from './geminiChat.js';
10
11
  import { Config } from '../config/config.js';
11
- import { GeminiEventType, Turn } from './turn.js';
12
+ import { CompressionStatus, GeminiEventType, Turn, } from './turn.js';
12
13
  import { getCoreSystemPrompt } from './prompts.js';
13
14
  import { DEFAULT_GEMINI_FLASH_MODEL } from '../config/models.js';
14
15
  import { FileDiscoveryService } from '../services/fileDiscoveryService.js';
@@ -16,13 +17,37 @@ import { setSimulate429 } from '../utils/testUtils.js';
16
17
  import { tokenLimit } from './tokenLimits.js';
17
18
  import { ideContext } from '../ide/ideContext.js';
18
19
  import { ClearcutLogger } from '../telemetry/clearcut-logger/clearcut-logger.js';
20
+ // Mock fs module to prevent actual file system operations during tests
21
+ const mockFileSystem = new Map();
22
+ vi.mock('node:fs', () => {
23
+ const fsModule = {
24
+ mkdirSync: vi.fn(),
25
+ writeFileSync: vi.fn((path, data) => {
26
+ mockFileSystem.set(path, data);
27
+ }),
28
+ readFileSync: vi.fn((path) => {
29
+ if (mockFileSystem.has(path)) {
30
+ return mockFileSystem.get(path);
31
+ }
32
+ throw Object.assign(new Error('ENOENT: no such file or directory'), {
33
+ code: 'ENOENT',
34
+ });
35
+ }),
36
+ existsSync: vi.fn((path) => mockFileSystem.has(path)),
37
+ };
38
+ return {
39
+ default: fsModule,
40
+ ...fsModule,
41
+ };
42
+ });
19
43
  // --- Mocks ---
20
44
  const mockChatCreateFn = vi.fn();
21
45
  const mockGenerateContentFn = vi.fn();
22
46
  const mockEmbedContentFn = vi.fn();
23
47
  const mockTurnRunFn = vi.fn();
24
48
  vi.mock('@google/genai');
25
- vi.mock('./turn', () => {
49
+ vi.mock('./turn', async (importOriginal) => {
50
+ const actual = await importOriginal();
26
51
  // Define a mock class that has the same shape as the real Turn
27
52
  class MockTurn {
28
53
  pendingToolCalls = [];
@@ -34,11 +59,8 @@ vi.mock('./turn', () => {
34
59
  }
35
60
  // Export the mock class as 'Turn'
36
61
  return {
62
+ ...actual,
37
63
  Turn: MockTurn,
38
- GeminiEventType: {
39
- MaxSessionTurns: 'MaxSessionTurns',
40
- ChatCompressed: 'ChatCompressed',
41
- },
42
64
  };
43
65
  });
44
66
  vi.mock('../config/config.js');
@@ -60,6 +82,18 @@ vi.mock('../telemetry/index.js', () => ({
60
82
  logApiError: vi.fn(),
61
83
  }));
62
84
  vi.mock('../ide/ideContext.js');
85
+ /**
86
+ * Array.fromAsync ponyfill, which will be available in es 2024.
87
+ *
88
+ * Buffers an async generator into an array and returns the result.
89
+ */
90
+ async function fromAsync(promise) {
91
+ const results = [];
92
+ for await (const result of promise) {
93
+ results.push(result);
94
+ }
95
+ return results;
96
+ }
63
97
  describe('findIndexAfterFraction', () => {
64
98
  const history = [
65
99
  { role: 'user', parts: [{ text: 'This is the first message.' }] }, // JSON length: 66
@@ -106,6 +140,33 @@ describe('findIndexAfterFraction', () => {
106
140
  expect(findIndexAfterFraction(historyWithEmptyParts, 0.5)).toBe(1);
107
141
  });
108
142
  });
143
+ describe('isThinkingSupported', () => {
144
+ it('should return true for gemini-2.5', () => {
145
+ expect(isThinkingSupported('gemini-2.5')).toBe(true);
146
+ });
147
+ it('should return true for gemini-2.5-pro', () => {
148
+ expect(isThinkingSupported('gemini-2.5-pro')).toBe(true);
149
+ });
150
+ it('should return false for other models', () => {
151
+ expect(isThinkingSupported('gemini-1.5-flash')).toBe(false);
152
+ expect(isThinkingSupported('some-other-model')).toBe(false);
153
+ });
154
+ });
155
+ describe('isThinkingDefault', () => {
156
+ it('should return false for gemini-2.5-flash-lite', () => {
157
+ expect(isThinkingDefault('gemini-2.5-flash-lite')).toBe(false);
158
+ });
159
+ it('should return true for gemini-2.5', () => {
160
+ expect(isThinkingDefault('gemini-2.5')).toBe(true);
161
+ });
162
+ it('should return true for gemini-2.5-pro', () => {
163
+ expect(isThinkingDefault('gemini-2.5-pro')).toBe(true);
164
+ });
165
+ it('should return false for other models', () => {
166
+ expect(isThinkingDefault('gemini-1.5-flash')).toBe(false);
167
+ expect(isThinkingDefault('some-other-model')).toBe(false);
168
+ });
169
+ });
109
170
  describe('Gemini Client (client.ts)', () => {
110
171
  let client;
111
172
  beforeEach(async () => {
@@ -152,7 +213,7 @@ describe('Gemini Client (client.ts)', () => {
152
213
  getContentGeneratorConfig: vi
153
214
  .fn()
154
215
  .mockReturnValue(contentGeneratorConfig),
155
- getToolRegistry: vi.fn().mockResolvedValue(mockToolRegistry),
216
+ getToolRegistry: vi.fn().mockReturnValue(mockToolRegistry),
156
217
  getModel: vi.fn().mockReturnValue('test-model'),
157
218
  getEmbeddingModel: vi.fn().mockReturnValue('test-embedding-model'),
158
219
  getApiKey: vi.fn().mockReturnValue('test-key'),
@@ -178,6 +239,12 @@ describe('Gemini Client (client.ts)', () => {
178
239
  getGeminiClient: vi.fn(),
179
240
  setFallbackMode: vi.fn(),
180
241
  getChatCompression: vi.fn().mockReturnValue(undefined),
242
+ getSkipNextSpeakerCheck: vi.fn().mockReturnValue(false),
243
+ getUseSmartEdit: vi.fn().mockReturnValue(false),
244
+ getProjectRoot: vi.fn().mockReturnValue('/test/project/root'),
245
+ storage: {
246
+ getProjectTempDir: vi.fn().mockReturnValue('/test/temp'),
247
+ },
181
248
  };
182
249
  const MockedConfig = vi.mocked(Config, true);
183
250
  MockedConfig.mockImplementation(() => mockConfigObject);
@@ -274,30 +341,6 @@ describe('Gemini Client (client.ts)', () => {
274
341
  await expect(client.generateEmbedding(texts)).rejects.toThrow('API Failure');
275
342
  });
276
343
  });
277
- describe('generateContent', () => {
278
- it('should call generateContent with the correct parameters', async () => {
279
- const contents = [{ role: 'user', parts: [{ text: 'hello' }] }];
280
- const generationConfig = { temperature: 0.5 };
281
- const abortSignal = new AbortController().signal;
282
- // Mock countTokens
283
- const mockGenerator = {
284
- countTokens: vi.fn().mockResolvedValue({ totalTokens: 1 }),
285
- generateContent: mockGenerateContentFn,
286
- };
287
- client['contentGenerator'] = mockGenerator;
288
- await client.generateContent(contents, generationConfig, abortSignal);
289
- expect(mockGenerateContentFn).toHaveBeenCalledWith({
290
- model: 'test-model',
291
- config: {
292
- abortSignal,
293
- systemInstruction: getCoreSystemPrompt(''),
294
- temperature: 0.5,
295
- topP: 1,
296
- },
297
- contents,
298
- }, 'test-session-id');
299
- });
300
- });
301
344
  describe('generateJson', () => {
302
345
  it('should call generateContent with the correct parameters', async () => {
303
346
  const contents = [{ role: 'user', parts: [{ text: 'hello' }] }];
@@ -309,9 +352,9 @@ describe('Gemini Client (client.ts)', () => {
309
352
  generateContent: mockGenerateContentFn,
310
353
  };
311
354
  client['contentGenerator'] = mockGenerator;
312
- await client.generateJson(contents, schema, abortSignal);
355
+ await client.generateJson(contents, schema, abortSignal, DEFAULT_GEMINI_FLASH_MODEL);
313
356
  expect(mockGenerateContentFn).toHaveBeenCalledWith({
314
- model: 'test-model', // Should use current model from config
357
+ model: DEFAULT_GEMINI_FLASH_MODEL,
315
358
  config: {
316
359
  abortSignal,
317
360
  systemInstruction: getCoreSystemPrompt(''),
@@ -324,7 +367,9 @@ describe('Gemini Client (client.ts)', () => {
324
367
  }, 'test-session-id');
325
368
  });
326
369
  it('should allow overriding model and config', async () => {
327
- const contents = [{ role: 'user', parts: [{ text: 'hello' }] }];
370
+ const contents = [
371
+ { role: 'user', parts: [{ text: 'hello' }] },
372
+ ];
328
373
  const schema = { type: 'string' };
329
374
  const abortSignal = new AbortController().signal;
330
375
  const customModel = 'custom-json-model';
@@ -404,6 +449,106 @@ describe('Gemini Client (client.ts)', () => {
404
449
  sendMessage: mockSendMessage,
405
450
  };
406
451
  });
452
+ function setup({ chatHistory = [
453
+ { role: 'user', parts: [{ text: 'Long conversation' }] },
454
+ { role: 'model', parts: [{ text: 'Long response' }] },
455
+ ], } = {}) {
456
+ const mockChat = {
457
+ getHistory: vi.fn().mockReturnValue(chatHistory),
458
+ setHistory: vi.fn(),
459
+ sendMessage: vi.fn().mockResolvedValue({ text: 'Summary' }),
460
+ };
461
+ const mockCountTokens = vi
462
+ .fn()
463
+ .mockResolvedValueOnce({ totalTokens: 1000 })
464
+ .mockResolvedValueOnce({ totalTokens: 5000 });
465
+ const mockGenerator = {
466
+ countTokens: mockCountTokens,
467
+ };
468
+ client['chat'] = mockChat;
469
+ client['contentGenerator'] = mockGenerator;
470
+ client['startChat'] = vi.fn().mockResolvedValue({ ...mockChat });
471
+ return { client, mockChat, mockGenerator };
472
+ }
473
+ describe('when compression inflates the token count', () => {
474
+ it('uses the truncated history for compression');
475
+ it('allows compression to be forced/manual after a failure', async () => {
476
+ const { client, mockGenerator } = setup();
477
+ mockGenerator.countTokens?.mockResolvedValue({
478
+ totalTokens: 1000,
479
+ });
480
+ await client.tryCompressChat('prompt-id-4'); // Fails
481
+ const result = await client.tryCompressChat('prompt-id-4', true);
482
+ expect(result).toEqual({
483
+ compressionStatus: CompressionStatus.COMPRESSED,
484
+ newTokenCount: 1000,
485
+ originalTokenCount: 1000,
486
+ });
487
+ });
488
+ it('yields the result even if the compression inflated the tokens', async () => {
489
+ const { client } = setup();
490
+ const result = await client.tryCompressChat('prompt-id-4', true);
491
+ expect(result).toEqual({
492
+ compressionStatus: CompressionStatus.COMPRESSION_FAILED_INFLATED_TOKEN_COUNT,
493
+ newTokenCount: 5000,
494
+ originalTokenCount: 1000,
495
+ });
496
+ });
497
+ it('does not manipulate the source chat', async () => {
498
+ const { client, mockChat } = setup();
499
+ await client.tryCompressChat('prompt-id-4', true);
500
+ expect(client['chat']).toBe(mockChat); // a new chat session was not created
501
+ });
502
+ it('restores the history back to the original', async () => {
503
+ vi.mocked(tokenLimit).mockReturnValue(1000);
504
+ mockCountTokens.mockResolvedValue({
505
+ totalTokens: 999,
506
+ });
507
+ const originalHistory = [
508
+ { role: 'user', parts: [{ text: 'what is your wisdom?' }] },
509
+ { role: 'model', parts: [{ text: 'some wisdom' }] },
510
+ { role: 'user', parts: [{ text: 'ahh that is a good a wisdom' }] },
511
+ ];
512
+ const { client } = setup({
513
+ chatHistory: originalHistory,
514
+ });
515
+ const { compressionStatus } = await client.tryCompressChat('prompt-id-4');
516
+ expect(compressionStatus).toBe(CompressionStatus.COMPRESSION_FAILED_INFLATED_TOKEN_COUNT);
517
+ expect(client['chat']?.setHistory).toHaveBeenCalledWith(originalHistory);
518
+ });
519
+ it('will not attempt to compress context after a failure', async () => {
520
+ const { client, mockGenerator } = setup();
521
+ await client.tryCompressChat('prompt-id-4');
522
+ const result = await client.tryCompressChat('prompt-id-5');
523
+ // it counts tokens for {original, compressed} and then never again
524
+ expect(mockGenerator.countTokens).toHaveBeenCalledTimes(2);
525
+ expect(result).toEqual({
526
+ compressionStatus: CompressionStatus.NOOP,
527
+ newTokenCount: 0,
528
+ originalTokenCount: 0,
529
+ });
530
+ });
531
+ });
532
+ it('attempts to compress with a maxOutputTokens set to the original token count', async () => {
533
+ vi.mocked(tokenLimit).mockReturnValue(1000);
534
+ mockCountTokens.mockResolvedValue({
535
+ totalTokens: 999,
536
+ });
537
+ mockGetHistory.mockReturnValue([
538
+ { role: 'user', parts: [{ text: '...history...' }] },
539
+ ]);
540
+ // Mock the summary response from the chat
541
+ mockSendMessage.mockResolvedValue({
542
+ role: 'model',
543
+ parts: [{ text: 'This is a summary.' }],
544
+ });
545
+ await client.tryCompressChat('prompt-id-2', true);
546
+ expect(mockSendMessage).toHaveBeenCalledWith(expect.objectContaining({
547
+ config: expect.objectContaining({
548
+ maxOutputTokens: 999,
549
+ }),
550
+ }), 'prompt-id-2');
551
+ });
407
552
  it('should not trigger summarization if token count is below threshold', async () => {
408
553
  const MOCKED_TOKEN_LIMIT = 1000;
409
554
  vi.mocked(tokenLimit).mockReturnValue(MOCKED_TOKEN_LIMIT);
@@ -417,7 +562,11 @@ describe('Gemini Client (client.ts)', () => {
417
562
  const result = await client.tryCompressChat('prompt-id-2');
418
563
  const newChat = client.getChat();
419
564
  expect(tokenLimit).toHaveBeenCalled();
420
- expect(result).toBeNull();
565
+ expect(result).toEqual({
566
+ compressionStatus: CompressionStatus.NOOP,
567
+ newTokenCount: 699,
568
+ originalTokenCount: 699,
569
+ });
421
570
  expect(newChat).toBe(initialChat);
422
571
  });
423
572
  it('logs a telemetry event when compressing', async () => {
@@ -474,6 +623,7 @@ describe('Gemini Client (client.ts)', () => {
474
623
  expect(mockSendMessage).toHaveBeenCalled();
475
624
  // Assert that summarization happened and returned the correct stats
476
625
  expect(result).toEqual({
626
+ compressionStatus: CompressionStatus.COMPRESSED,
477
627
  originalTokenCount,
478
628
  newTokenCount,
479
629
  });
@@ -518,6 +668,7 @@ describe('Gemini Client (client.ts)', () => {
518
668
  expect(mockSendMessage).toHaveBeenCalled();
519
669
  // Assert that summarization happened and returned the correct stats
520
670
  expect(result).toEqual({
671
+ compressionStatus: CompressionStatus.COMPRESSED,
521
672
  originalTokenCount,
522
673
  newTokenCount,
523
674
  });
@@ -549,14 +700,129 @@ describe('Gemini Client (client.ts)', () => {
549
700
  const newChat = client.getChat();
550
701
  expect(mockSendMessage).toHaveBeenCalled();
551
702
  expect(result).toEqual({
703
+ compressionStatus: CompressionStatus.COMPRESSED,
552
704
  originalTokenCount,
553
705
  newTokenCount,
554
706
  });
555
707
  // Assert that the chat was reset
556
708
  expect(newChat).not.toBe(initialChat);
557
709
  });
710
+ it('should use current model from config for token counting after sendMessage', async () => {
711
+ const initialModel = client['config'].getModel();
712
+ const mockCountTokens = vi
713
+ .fn()
714
+ .mockResolvedValueOnce({ totalTokens: 100000 })
715
+ .mockResolvedValueOnce({ totalTokens: 5000 });
716
+ const mockSendMessage = vi.fn().mockResolvedValue({ text: 'Summary' });
717
+ const mockChatHistory = [
718
+ { role: 'user', parts: [{ text: 'Long conversation' }] },
719
+ { role: 'model', parts: [{ text: 'Long response' }] },
720
+ ];
721
+ const mockChat = {
722
+ getHistory: vi.fn().mockReturnValue(mockChatHistory),
723
+ setHistory: vi.fn(),
724
+ sendMessage: mockSendMessage,
725
+ };
726
+ const mockGenerator = {
727
+ countTokens: mockCountTokens,
728
+ };
729
+ // mock the model has been changed between calls of `countTokens`
730
+ const firstCurrentModel = initialModel + '-changed-1';
731
+ const secondCurrentModel = initialModel + '-changed-2';
732
+ vi.spyOn(client['config'], 'getModel')
733
+ .mockReturnValueOnce(firstCurrentModel)
734
+ .mockReturnValueOnce(secondCurrentModel);
735
+ client['chat'] = mockChat;
736
+ client['contentGenerator'] = mockGenerator;
737
+ client['startChat'] = vi.fn().mockResolvedValue(mockChat);
738
+ const result = await client.tryCompressChat('prompt-id-4', true);
739
+ expect(mockCountTokens).toHaveBeenCalledTimes(2);
740
+ expect(mockCountTokens).toHaveBeenNthCalledWith(1, {
741
+ model: firstCurrentModel,
742
+ contents: mockChatHistory,
743
+ });
744
+ expect(mockCountTokens).toHaveBeenNthCalledWith(2, {
745
+ model: secondCurrentModel,
746
+ contents: expect.any(Array),
747
+ });
748
+ expect(result).toEqual({
749
+ compressionStatus: CompressionStatus.COMPRESSED,
750
+ originalTokenCount: 100000,
751
+ newTokenCount: 5000,
752
+ });
753
+ });
558
754
  });
559
755
  describe('sendMessageStream', () => {
756
+ it('emits a compression event when the context was automatically compressed', async () => {
757
+ // Arrange
758
+ const mockStream = (async function* () {
759
+ yield { type: 'content', value: 'Hello' };
760
+ })();
761
+ mockTurnRunFn.mockReturnValue(mockStream);
762
+ const mockChat = {
763
+ addHistory: vi.fn(),
764
+ getHistory: vi.fn().mockReturnValue([]),
765
+ };
766
+ client['chat'] = mockChat;
767
+ const mockGenerator = {
768
+ countTokens: vi.fn().mockResolvedValue({ totalTokens: 0 }),
769
+ generateContent: mockGenerateContentFn,
770
+ };
771
+ client['contentGenerator'] = mockGenerator;
772
+ const compressionInfo = {
773
+ compressionStatus: CompressionStatus.COMPRESSED,
774
+ originalTokenCount: 1000,
775
+ newTokenCount: 500,
776
+ };
777
+ vi.spyOn(client, 'tryCompressChat').mockResolvedValueOnce(compressionInfo);
778
+ // Act
779
+ const stream = client.sendMessageStream([{ text: 'Hi' }], new AbortController().signal, 'prompt-id-1');
780
+ const events = await fromAsync(stream);
781
+ // Assert
782
+ expect(events).toContainEqual({
783
+ type: GeminiEventType.ChatCompressed,
784
+ value: compressionInfo,
785
+ });
786
+ });
787
+ it.each([
788
+ {
789
+ compressionStatus: CompressionStatus.COMPRESSION_FAILED_INFLATED_TOKEN_COUNT,
790
+ },
791
+ { compressionStatus: CompressionStatus.NOOP },
792
+ {
793
+ compressionStatus: CompressionStatus.COMPRESSION_FAILED_TOKEN_COUNT_ERROR,
794
+ },
795
+ ])('does not emit a compression event when the status is $compressionStatus', async ({ compressionStatus }) => {
796
+ // Arrange
797
+ const mockStream = (async function* () {
798
+ yield { type: 'content', value: 'Hello' };
799
+ })();
800
+ mockTurnRunFn.mockReturnValue(mockStream);
801
+ const mockChat = {
802
+ addHistory: vi.fn(),
803
+ getHistory: vi.fn().mockReturnValue([]),
804
+ };
805
+ client['chat'] = mockChat;
806
+ const mockGenerator = {
807
+ countTokens: vi.fn().mockResolvedValue({ totalTokens: 0 }),
808
+ generateContent: mockGenerateContentFn,
809
+ };
810
+ client['contentGenerator'] = mockGenerator;
811
+ const compressionInfo = {
812
+ compressionStatus,
813
+ originalTokenCount: 1000,
814
+ newTokenCount: 500,
815
+ };
816
+ vi.spyOn(client, 'tryCompressChat').mockResolvedValueOnce(compressionInfo);
817
+ // Act
818
+ const stream = client.sendMessageStream([{ text: 'Hi' }], new AbortController().signal, 'prompt-id-1');
819
+ const events = await fromAsync(stream);
820
+ // Assert
821
+ expect(events).not.toContainEqual({
822
+ type: GeminiEventType.ChatCompressed,
823
+ value: expect.anything(),
824
+ });
825
+ });
560
826
  it('should include editor context when ideMode is enabled', async () => {
561
827
  // Arrange
562
828
  vi.mocked(ideContext.getIdeContext).mockReturnValue({
@@ -976,7 +1242,11 @@ ${JSON.stringify({
976
1242
  })();
977
1243
  beforeEach(() => {
978
1244
  client['forceFullIdeContext'] = false; // Reset before each delta test
979
- vi.spyOn(client, 'tryCompressChat').mockResolvedValue(null);
1245
+ vi.spyOn(client, 'tryCompressChat').mockResolvedValue({
1246
+ originalTokenCount: 0,
1247
+ newTokenCount: 0,
1248
+ compressionStatus: CompressionStatus.COMPRESSED,
1249
+ });
980
1250
  vi.spyOn(client['config'], 'getIdeMode').mockReturnValue(true);
981
1251
  mockTurnRunFn.mockReturnValue(mockStream);
982
1252
  const mockChat = {
@@ -1189,7 +1459,11 @@ ${JSON.stringify({
1189
1459
  describe('IDE context with pending tool calls', () => {
1190
1460
  let mockChat;
1191
1461
  beforeEach(() => {
1192
- vi.spyOn(client, 'tryCompressChat').mockResolvedValue(null);
1462
+ vi.spyOn(client, 'tryCompressChat').mockResolvedValue({
1463
+ originalTokenCount: 0,
1464
+ newTokenCount: 0,
1465
+ compressionStatus: CompressionStatus.COMPRESSED,
1466
+ });
1193
1467
  const mockStream = (async function* () {
1194
1468
  yield { type: 'content', value: 'response' };
1195
1469
  })();
@@ -1452,8 +1726,89 @@ ${JSON.stringify({
1452
1726
  expect(JSON.stringify(finalCall)).toContain('fileC.ts');
1453
1727
  });
1454
1728
  });
1729
+ it('should not call checkNextSpeaker when turn.run() yields an error', async () => {
1730
+ // Arrange
1731
+ const { checkNextSpeaker } = await import('../utils/nextSpeakerChecker.js');
1732
+ const mockCheckNextSpeaker = vi.mocked(checkNextSpeaker);
1733
+ const mockStream = (async function* () {
1734
+ yield {
1735
+ type: GeminiEventType.Error,
1736
+ value: { error: { message: 'test error' } },
1737
+ };
1738
+ })();
1739
+ mockTurnRunFn.mockReturnValue(mockStream);
1740
+ const mockChat = {
1741
+ addHistory: vi.fn(),
1742
+ getHistory: vi.fn().mockReturnValue([]),
1743
+ };
1744
+ client['chat'] = mockChat;
1745
+ const mockGenerator = {
1746
+ countTokens: vi.fn().mockResolvedValue({ totalTokens: 0 }),
1747
+ generateContent: mockGenerateContentFn,
1748
+ };
1749
+ client['contentGenerator'] = mockGenerator;
1750
+ // Act
1751
+ const stream = client.sendMessageStream([{ text: 'Hi' }], new AbortController().signal, 'prompt-id-error');
1752
+ for await (const _ of stream) {
1753
+ // consume stream
1754
+ }
1755
+ // Assert
1756
+ expect(mockCheckNextSpeaker).not.toHaveBeenCalled();
1757
+ });
1758
+ it('should not call checkNextSpeaker when turn.run() yields a value then an error', async () => {
1759
+ // Arrange
1760
+ const { checkNextSpeaker } = await import('../utils/nextSpeakerChecker.js');
1761
+ const mockCheckNextSpeaker = vi.mocked(checkNextSpeaker);
1762
+ const mockStream = (async function* () {
1763
+ yield { type: GeminiEventType.Content, value: 'some content' };
1764
+ yield {
1765
+ type: GeminiEventType.Error,
1766
+ value: { error: { message: 'test error' } },
1767
+ };
1768
+ })();
1769
+ mockTurnRunFn.mockReturnValue(mockStream);
1770
+ const mockChat = {
1771
+ addHistory: vi.fn(),
1772
+ getHistory: vi.fn().mockReturnValue([]),
1773
+ };
1774
+ client['chat'] = mockChat;
1775
+ const mockGenerator = {
1776
+ countTokens: vi.fn().mockResolvedValue({ totalTokens: 0 }),
1777
+ generateContent: mockGenerateContentFn,
1778
+ };
1779
+ client['contentGenerator'] = mockGenerator;
1780
+ // Act
1781
+ const stream = client.sendMessageStream([{ text: 'Hi' }], new AbortController().signal, 'prompt-id-error');
1782
+ for await (const _ of stream) {
1783
+ // consume stream
1784
+ }
1785
+ // Assert
1786
+ expect(mockCheckNextSpeaker).not.toHaveBeenCalled();
1787
+ });
1455
1788
  });
1456
1789
  describe('generateContent', () => {
1790
+ it('should call generateContent with the correct parameters', async () => {
1791
+ const contents = [{ role: 'user', parts: [{ text: 'hello' }] }];
1792
+ const generationConfig = { temperature: 0.5 };
1793
+ const abortSignal = new AbortController().signal;
1794
+ // Mock countTokens
1795
+ const mockGenerator = {
1796
+ countTokens: vi.fn().mockResolvedValue({ totalTokens: 1 }),
1797
+ generateContent: mockGenerateContentFn,
1798
+ };
1799
+ client['contentGenerator'] = mockGenerator;
1800
+ await client.generateContent(contents, generationConfig, abortSignal, DEFAULT_GEMINI_FLASH_MODEL);
1801
+ expect(mockGenerateContentFn).toHaveBeenCalledWith({
1802
+ model: DEFAULT_GEMINI_FLASH_MODEL,
1803
+ config: {
1804
+ abortSignal,
1805
+ systemInstruction: getCoreSystemPrompt(''),
1806
+ temperature: 0.5,
1807
+ topP: 1,
1808
+ },
1809
+ contents,
1810
+ }, 'test-session-id');
1811
+ });
1457
1812
  it('should use current model from config for content generation', async () => {
1458
1813
  const initialModel = client['config'].getModel();
1459
1814
  const contents = [{ role: 'user', parts: [{ text: 'test' }] }];
@@ -1464,64 +1819,19 @@ ${JSON.stringify({
1464
1819
  generateContent: mockGenerateContentFn,
1465
1820
  };
1466
1821
  client['contentGenerator'] = mockGenerator;
1467
- await client.generateContent(contents, {}, new AbortController().signal);
1822
+ await client.generateContent(contents, {}, new AbortController().signal, DEFAULT_GEMINI_FLASH_MODEL);
1468
1823
  expect(mockGenerateContentFn).not.toHaveBeenCalledWith({
1469
1824
  model: initialModel,
1470
1825
  config: expect.any(Object),
1471
1826
  contents,
1472
1827
  });
1473
1828
  expect(mockGenerateContentFn).toHaveBeenCalledWith({
1474
- model: currentModel,
1829
+ model: DEFAULT_GEMINI_FLASH_MODEL,
1475
1830
  config: expect.any(Object),
1476
1831
  contents,
1477
1832
  }, 'test-session-id');
1478
1833
  });
1479
1834
  });
1480
- describe('tryCompressChat', () => {
1481
- it('should use current model from config for token counting after sendMessage', async () => {
1482
- const initialModel = client['config'].getModel();
1483
- const mockCountTokens = vi
1484
- .fn()
1485
- .mockResolvedValueOnce({ totalTokens: 100000 })
1486
- .mockResolvedValueOnce({ totalTokens: 5000 });
1487
- const mockSendMessage = vi.fn().mockResolvedValue({ text: 'Summary' });
1488
- const mockChatHistory = [
1489
- { role: 'user', parts: [{ text: 'Long conversation' }] },
1490
- { role: 'model', parts: [{ text: 'Long response' }] },
1491
- ];
1492
- const mockChat = {
1493
- getHistory: vi.fn().mockReturnValue(mockChatHistory),
1494
- setHistory: vi.fn(),
1495
- sendMessage: mockSendMessage,
1496
- };
1497
- const mockGenerator = {
1498
- countTokens: mockCountTokens,
1499
- };
1500
- // mock the model has been changed between calls of `countTokens`
1501
- const firstCurrentModel = initialModel + '-changed-1';
1502
- const secondCurrentModel = initialModel + '-changed-2';
1503
- vi.spyOn(client['config'], 'getModel')
1504
- .mockReturnValueOnce(firstCurrentModel)
1505
- .mockReturnValueOnce(secondCurrentModel);
1506
- client['chat'] = mockChat;
1507
- client['contentGenerator'] = mockGenerator;
1508
- client['startChat'] = vi.fn().mockResolvedValue(mockChat);
1509
- const result = await client.tryCompressChat('prompt-id-4', true);
1510
- expect(mockCountTokens).toHaveBeenCalledTimes(2);
1511
- expect(mockCountTokens).toHaveBeenNthCalledWith(1, {
1512
- model: firstCurrentModel,
1513
- contents: mockChatHistory,
1514
- });
1515
- expect(mockCountTokens).toHaveBeenNthCalledWith(2, {
1516
- model: secondCurrentModel,
1517
- contents: expect.any(Array),
1518
- });
1519
- expect(result).toEqual({
1520
- originalTokenCount: 100000,
1521
- newTokenCount: 5000,
1522
- });
1523
- });
1524
- });
1525
1835
  describe('handleFlashFallback', () => {
1526
1836
  it('should use current model from config when checking for fallback', async () => {
1527
1837
  const initialModel = client['config'].getModel();