@machina.ai/cell-cli-core 1.13.0-rc5 → 1.16.0-rc2

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 (424) hide show
  1. package/dist/index.d.ts +2 -1
  2. package/dist/index.js +2 -1
  3. package/dist/index.js.map +1 -1
  4. package/dist/package.json +1 -1
  5. package/dist/src/agents/codebase-investigator.test.d.ts +6 -0
  6. package/dist/src/agents/codebase-investigator.test.js +35 -0
  7. package/dist/src/agents/codebase-investigator.test.js.map +1 -0
  8. package/dist/src/agents/executor.d.ts +3 -0
  9. package/dist/src/agents/executor.js +21 -0
  10. package/dist/src/agents/executor.js.map +1 -1
  11. package/dist/src/agents/executor.test.js +358 -3
  12. package/dist/src/agents/executor.test.js.map +1 -1
  13. package/dist/src/code_assist/codeAssist.test.d.ts +6 -0
  14. package/dist/src/code_assist/codeAssist.test.js +99 -0
  15. package/dist/src/code_assist/codeAssist.test.js.map +1 -0
  16. package/dist/src/code_assist/experiments/client_metadata.js +2 -1
  17. package/dist/src/code_assist/experiments/client_metadata.js.map +1 -1
  18. package/dist/src/code_assist/experiments/client_metadata.test.d.ts +6 -0
  19. package/dist/src/code_assist/experiments/client_metadata.test.js +99 -0
  20. package/dist/src/code_assist/experiments/client_metadata.test.js.map +1 -0
  21. package/dist/src/code_assist/experiments/experiments.js +2 -2
  22. package/dist/src/code_assist/experiments/experiments.js.map +1 -1
  23. package/dist/src/code_assist/experiments/experiments.test.d.ts +6 -0
  24. package/dist/src/code_assist/experiments/experiments.test.js +92 -0
  25. package/dist/src/code_assist/experiments/experiments.test.js.map +1 -0
  26. package/dist/src/code_assist/experiments/flagNames.d.ts +13 -0
  27. package/dist/src/code_assist/experiments/flagNames.js +13 -0
  28. package/dist/src/code_assist/experiments/flagNames.js.map +1 -0
  29. package/dist/src/code_assist/experiments/types.d.ts +1 -1
  30. package/dist/src/code_assist/oauth-credential-storage.test.js +49 -0
  31. package/dist/src/code_assist/oauth-credential-storage.test.js.map +1 -1
  32. package/dist/src/code_assist/server.js +5 -8
  33. package/dist/src/code_assist/server.js.map +1 -1
  34. package/dist/src/code_assist/server.test.js +109 -28
  35. package/dist/src/code_assist/server.test.js.map +1 -1
  36. package/dist/src/config/config.d.ts +34 -2
  37. package/dist/src/config/config.js +147 -26
  38. package/dist/src/config/config.js.map +1 -1
  39. package/dist/src/config/config.test.js +436 -19
  40. package/dist/src/config/config.test.js.map +1 -1
  41. package/dist/src/config/defaultModelConfigs.d.ts +7 -0
  42. package/dist/src/config/defaultModelConfigs.js +158 -0
  43. package/dist/src/config/defaultModelConfigs.js.map +1 -0
  44. package/dist/src/config/models.d.ts +22 -1
  45. package/dist/src/config/models.js +49 -6
  46. package/dist/src/config/models.js.map +1 -1
  47. package/dist/src/config/models.test.js +71 -10
  48. package/dist/src/config/models.test.js.map +1 -1
  49. package/dist/src/confirmation-bus/message-bus.d.ts +1 -1
  50. package/dist/src/confirmation-bus/message-bus.js +2 -2
  51. package/dist/src/confirmation-bus/message-bus.js.map +1 -1
  52. package/dist/src/confirmation-bus/message-bus.test.js +30 -24
  53. package/dist/src/confirmation-bus/message-bus.test.js.map +1 -1
  54. package/dist/src/confirmation-bus/types.d.ts +1 -0
  55. package/dist/src/core/baseLlmClient.d.ts +4 -8
  56. package/dist/src/core/baseLlmClient.js +3 -8
  57. package/dist/src/core/baseLlmClient.js.map +1 -1
  58. package/dist/src/core/baseLlmClient.test.js +22 -27
  59. package/dist/src/core/baseLlmClient.test.js.map +1 -1
  60. package/dist/src/core/client.d.ts +6 -5
  61. package/dist/src/core/client.js +33 -33
  62. package/dist/src/core/client.js.map +1 -1
  63. package/dist/src/core/client.test.js +40 -22
  64. package/dist/src/core/client.test.js.map +1 -1
  65. package/dist/src/core/coreToolScheduler.js +7 -1
  66. package/dist/src/core/coreToolScheduler.js.map +1 -1
  67. package/dist/src/core/coreToolScheduler.test.js +151 -357
  68. package/dist/src/core/coreToolScheduler.test.js.map +1 -1
  69. package/dist/src/core/geminiChat.d.ts +6 -4
  70. package/dist/src/core/geminiChat.js +106 -29
  71. package/dist/src/core/geminiChat.js.map +1 -1
  72. package/dist/src/core/geminiChat.test.js +317 -16
  73. package/dist/src/core/geminiChat.test.js.map +1 -1
  74. package/dist/src/core/logger.d.ts +7 -2
  75. package/dist/src/core/logger.js +15 -9
  76. package/dist/src/core/logger.js.map +1 -1
  77. package/dist/src/core/logger.test.js +31 -16
  78. package/dist/src/core/logger.test.js.map +1 -1
  79. package/dist/src/core/loggingContentGenerator.test.d.ts +6 -0
  80. package/dist/src/core/loggingContentGenerator.test.js +180 -0
  81. package/dist/src/core/loggingContentGenerator.test.js.map +1 -0
  82. package/dist/src/core/nonInteractiveToolExecutor.test.js +1 -0
  83. package/dist/src/core/nonInteractiveToolExecutor.test.js.map +1 -1
  84. package/dist/src/core/prompts.js +8 -11
  85. package/dist/src/core/prompts.js.map +1 -1
  86. package/dist/src/core/tokenLimits.test.d.ts +6 -0
  87. package/dist/src/core/tokenLimits.test.js +26 -0
  88. package/dist/src/core/tokenLimits.test.js.map +1 -0
  89. package/dist/src/fallback/handler.js +52 -7
  90. package/dist/src/fallback/handler.js.map +1 -1
  91. package/dist/src/fallback/handler.test.js +69 -16
  92. package/dist/src/fallback/handler.test.js.map +1 -1
  93. package/dist/src/fallback/types.d.ts +1 -1
  94. package/dist/src/generated/git-commit.d.ts +2 -2
  95. package/dist/src/generated/git-commit.js +2 -2
  96. package/dist/src/hooks/hookAggregator.d.ts +68 -0
  97. package/dist/src/hooks/hookAggregator.js +262 -0
  98. package/dist/src/hooks/hookAggregator.js.map +1 -0
  99. package/dist/src/hooks/hookAggregator.test.d.ts +6 -0
  100. package/dist/src/hooks/hookAggregator.test.js +387 -0
  101. package/dist/src/hooks/hookAggregator.test.js.map +1 -0
  102. package/dist/src/hooks/hookRunner.d.ts +42 -0
  103. package/dist/src/hooks/hookRunner.js +272 -0
  104. package/dist/src/hooks/hookRunner.js.map +1 -0
  105. package/dist/src/hooks/hookRunner.test.d.ts +6 -0
  106. package/dist/src/hooks/hookRunner.test.js +468 -0
  107. package/dist/src/hooks/hookRunner.test.js.map +1 -0
  108. package/dist/src/hooks/hookTranslator.d.ts +3 -3
  109. package/dist/src/hooks/types.js +1 -1
  110. package/dist/src/hooks/types.js.map +1 -1
  111. package/dist/src/hooks/types.test.js +280 -2
  112. package/dist/src/hooks/types.test.js.map +1 -1
  113. package/dist/src/ide/detect-ide.d.ts +4 -0
  114. package/dist/src/ide/detect-ide.js +6 -1
  115. package/dist/src/ide/detect-ide.js.map +1 -1
  116. package/dist/src/ide/detect-ide.test.js +5 -0
  117. package/dist/src/ide/detect-ide.test.js.map +1 -1
  118. package/dist/src/ide/ide-client.d.ts +3 -1
  119. package/dist/src/ide/ide-client.js +66 -59
  120. package/dist/src/ide/ide-client.js.map +1 -1
  121. package/dist/src/ide/ide-client.test.js +159 -0
  122. package/dist/src/ide/ide-client.test.js.map +1 -1
  123. package/dist/src/ide/ide-installer.js +71 -21
  124. package/dist/src/ide/ide-installer.js.map +1 -1
  125. package/dist/src/ide/ide-installer.test.js +42 -1
  126. package/dist/src/ide/ide-installer.test.js.map +1 -1
  127. package/dist/src/ide/process-utils.js +16 -0
  128. package/dist/src/ide/process-utils.js.map +1 -1
  129. package/dist/src/ide/process-utils.test.js +3 -3
  130. package/dist/src/ide/process-utils.test.js.map +1 -1
  131. package/dist/src/ide/types.d.ts +1 -1
  132. package/dist/src/ide/types.js +1 -1
  133. package/dist/src/index.d.ts +2 -0
  134. package/dist/src/index.js +2 -0
  135. package/dist/src/index.js.map +1 -1
  136. package/dist/src/mcp/google-auth-provider.js +1 -1
  137. package/dist/src/mcp/google-auth-provider.js.map +1 -1
  138. package/dist/src/mcp/oauth-provider.js +2 -2
  139. package/dist/src/mcp/oauth-provider.js.map +1 -1
  140. package/dist/src/mcp/oauth-provider.test.js +177 -0
  141. package/dist/src/mcp/oauth-provider.test.js.map +1 -1
  142. package/dist/src/mcp/sa-impersonation-provider.js +1 -1
  143. package/dist/src/mcp/sa-impersonation-provider.js.map +1 -1
  144. package/dist/src/policy/config.js +3 -1
  145. package/dist/src/policy/config.js.map +1 -1
  146. package/dist/src/policy/config.test.js +135 -1
  147. package/dist/src/policy/config.test.js.map +1 -1
  148. package/dist/src/policy/policies/discovered.toml +8 -0
  149. package/dist/src/policy/policies/write.toml +10 -0
  150. package/dist/src/policy/policy-engine.d.ts +12 -3
  151. package/dist/src/policy/policy-engine.js +71 -9
  152. package/dist/src/policy/policy-engine.js.map +1 -1
  153. package/dist/src/policy/policy-engine.test.js +460 -76
  154. package/dist/src/policy/policy-engine.test.js.map +1 -1
  155. package/dist/src/policy/toml-loader.d.ts +2 -1
  156. package/dist/src/policy/toml-loader.js +103 -6
  157. package/dist/src/policy/toml-loader.js.map +1 -1
  158. package/dist/src/policy/toml-loader.test.js +222 -368
  159. package/dist/src/policy/toml-loader.test.js.map +1 -1
  160. package/dist/src/policy/types.d.ts +65 -0
  161. package/dist/src/policy/types.js +4 -0
  162. package/dist/src/policy/types.js.map +1 -1
  163. package/dist/src/prompts/mcp-prompts.test.d.ts +6 -0
  164. package/dist/src/prompts/mcp-prompts.test.js +40 -0
  165. package/dist/src/prompts/mcp-prompts.test.js.map +1 -0
  166. package/dist/src/prompts/prompt-registry.test.d.ts +6 -0
  167. package/dist/src/prompts/prompt-registry.test.js +111 -0
  168. package/dist/src/prompts/prompt-registry.test.js.map +1 -0
  169. package/dist/src/routing/modelRouterService.js +15 -0
  170. package/dist/src/routing/modelRouterService.js.map +1 -1
  171. package/dist/src/routing/modelRouterService.test.js +62 -0
  172. package/dist/src/routing/modelRouterService.test.js.map +1 -1
  173. package/dist/src/routing/strategies/classifierStrategy.d.ts +1 -1
  174. package/dist/src/routing/strategies/classifierStrategy.js +6 -14
  175. package/dist/src/routing/strategies/classifierStrategy.js.map +1 -1
  176. package/dist/src/routing/strategies/classifierStrategy.test.js +13 -10
  177. package/dist/src/routing/strategies/classifierStrategy.test.js.map +1 -1
  178. package/dist/src/routing/strategies/fallbackStrategy.js +1 -1
  179. package/dist/src/routing/strategies/fallbackStrategy.js.map +1 -1
  180. package/dist/src/routing/strategies/fallbackStrategy.test.js +4 -0
  181. package/dist/src/routing/strategies/fallbackStrategy.test.js.map +1 -1
  182. package/dist/src/routing/strategies/overrideStrategy.js +2 -2
  183. package/dist/src/routing/strategies/overrideStrategy.js.map +1 -1
  184. package/dist/src/routing/strategies/overrideStrategy.test.js +3 -0
  185. package/dist/src/routing/strategies/overrideStrategy.test.js.map +1 -1
  186. package/dist/src/safety/built-in.d.ts +21 -0
  187. package/dist/src/safety/built-in.js +106 -0
  188. package/dist/src/safety/built-in.js.map +1 -0
  189. package/dist/src/safety/built-in.test.d.ts +6 -0
  190. package/dist/src/safety/built-in.test.js +199 -0
  191. package/dist/src/safety/built-in.test.js.map +1 -0
  192. package/dist/src/safety/checker-runner.d.ts +48 -0
  193. package/dist/src/safety/checker-runner.js +208 -0
  194. package/dist/src/safety/checker-runner.js.map +1 -0
  195. package/dist/src/safety/checker-runner.test.d.ts +6 -0
  196. package/dist/src/safety/checker-runner.test.js +238 -0
  197. package/dist/src/safety/checker-runner.test.js.map +1 -0
  198. package/dist/src/safety/context-builder.d.ts +23 -0
  199. package/dist/src/safety/context-builder.js +47 -0
  200. package/dist/src/safety/context-builder.js.map +1 -0
  201. package/dist/src/safety/context-builder.test.d.ts +6 -0
  202. package/dist/src/safety/context-builder.test.js +49 -0
  203. package/dist/src/safety/context-builder.test.js.map +1 -0
  204. package/dist/src/safety/protocol.d.ts +88 -0
  205. package/dist/src/safety/protocol.js +15 -0
  206. package/dist/src/safety/protocol.js.map +1 -0
  207. package/dist/src/safety/registry.d.ts +26 -0
  208. package/dist/src/safety/registry.js +65 -0
  209. package/dist/src/safety/registry.js.map +1 -0
  210. package/dist/src/safety/registry.test.d.ts +6 -0
  211. package/dist/src/safety/registry.test.js +31 -0
  212. package/dist/src/safety/registry.test.js.map +1 -0
  213. package/dist/src/services/chatCompressionService.test.js +1 -0
  214. package/dist/src/services/chatCompressionService.test.js.map +1 -1
  215. package/dist/src/services/gitService.js +1 -1
  216. package/dist/src/services/gitService.js.map +1 -1
  217. package/dist/src/services/gitService.test.js +1 -1
  218. package/dist/src/services/gitService.test.js.map +1 -1
  219. package/dist/src/services/loopDetectionService.d.ts +3 -0
  220. package/dist/src/services/loopDetectionService.js +81 -42
  221. package/dist/src/services/loopDetectionService.js.map +1 -1
  222. package/dist/src/services/loopDetectionService.test.js +101 -1
  223. package/dist/src/services/loopDetectionService.test.js.map +1 -1
  224. package/dist/src/services/modelConfig.golden.test.d.ts +6 -0
  225. package/dist/src/services/modelConfig.golden.test.js +42 -0
  226. package/dist/src/services/modelConfig.golden.test.js.map +1 -0
  227. package/dist/src/services/modelConfig.integration.test.d.ts +6 -0
  228. package/dist/src/services/modelConfig.integration.test.js +213 -0
  229. package/dist/src/services/modelConfig.integration.test.js.map +1 -0
  230. package/dist/src/services/modelConfigService.d.ts +46 -0
  231. package/dist/src/services/modelConfigService.js +146 -0
  232. package/dist/src/services/modelConfigService.js.map +1 -0
  233. package/dist/src/services/modelConfigService.test.d.ts +6 -0
  234. package/dist/src/services/modelConfigService.test.js +509 -0
  235. package/dist/src/services/modelConfigService.test.js.map +1 -0
  236. package/dist/src/services/test-data/resolved-aliases.golden.json +169 -0
  237. package/dist/src/telemetry/clearcut-logger/clearcut-logger.d.ts +11 -9
  238. package/dist/src/telemetry/clearcut-logger/clearcut-logger.js +174 -150
  239. package/dist/src/telemetry/clearcut-logger/clearcut-logger.js.map +1 -1
  240. package/dist/src/telemetry/clearcut-logger/clearcut-logger.test.d.ts +1 -0
  241. package/dist/src/telemetry/clearcut-logger/clearcut-logger.test.js +76 -20
  242. package/dist/src/telemetry/clearcut-logger/clearcut-logger.test.js.map +1 -1
  243. package/dist/src/telemetry/clearcut-logger/event-metadata-key.d.ts +6 -1
  244. package/dist/src/telemetry/clearcut-logger/event-metadata-key.js +18 -5
  245. package/dist/src/telemetry/clearcut-logger/event-metadata-key.js.map +1 -1
  246. package/dist/src/telemetry/index.d.ts +2 -2
  247. package/dist/src/telemetry/index.js +2 -2
  248. package/dist/src/telemetry/index.js.map +1 -1
  249. package/dist/src/telemetry/loggers.d.ts +7 -7
  250. package/dist/src/telemetry/loggers.js +23 -23
  251. package/dist/src/telemetry/loggers.js.map +1 -1
  252. package/dist/src/telemetry/loggers.test.circular.js +0 -1
  253. package/dist/src/telemetry/loggers.test.circular.js.map +1 -1
  254. package/dist/src/telemetry/loggers.test.js +72 -18
  255. package/dist/src/telemetry/loggers.test.js.map +1 -1
  256. package/dist/src/telemetry/metrics.d.ts +8 -4
  257. package/dist/src/telemetry/metrics.js +10 -4
  258. package/dist/src/telemetry/metrics.js.map +1 -1
  259. package/dist/src/telemetry/metrics.test.js +42 -0
  260. package/dist/src/telemetry/metrics.test.js.map +1 -1
  261. package/dist/src/telemetry/telemetryAttributes.js +1 -0
  262. package/dist/src/telemetry/telemetryAttributes.js.map +1 -1
  263. package/dist/src/telemetry/types.d.ts +17 -11
  264. package/dist/src/telemetry/types.js +53 -28
  265. package/dist/src/telemetry/types.js.map +1 -1
  266. package/dist/src/tools/base-tool-invocation.test.d.ts +6 -0
  267. package/dist/src/tools/base-tool-invocation.test.js +85 -0
  268. package/dist/src/tools/base-tool-invocation.test.js.map +1 -0
  269. package/dist/src/tools/edit.d.ts +1 -1
  270. package/dist/src/tools/edit.js +31 -33
  271. package/dist/src/tools/edit.js.map +1 -1
  272. package/dist/src/tools/edit.test.js +31 -20
  273. package/dist/src/tools/edit.test.js.map +1 -1
  274. package/dist/src/tools/glob.d.ts +1 -1
  275. package/dist/src/tools/glob.js +7 -7
  276. package/dist/src/tools/glob.js.map +1 -1
  277. package/dist/src/tools/glob.test.js +20 -17
  278. package/dist/src/tools/glob.test.js.map +1 -1
  279. package/dist/src/tools/grep.d.ts +1 -1
  280. package/dist/src/tools/grep.js +9 -9
  281. package/dist/src/tools/grep.js.map +1 -1
  282. package/dist/src/tools/grep.test.js +15 -12
  283. package/dist/src/tools/grep.test.js.map +1 -1
  284. package/dist/src/tools/ls.d.ts +1 -1
  285. package/dist/src/tools/ls.js +14 -15
  286. package/dist/src/tools/ls.js.map +1 -1
  287. package/dist/src/tools/ls.test.js +32 -33
  288. package/dist/src/tools/ls.test.js.map +1 -1
  289. package/dist/src/tools/mcp-client.js +24 -52
  290. package/dist/src/tools/mcp-client.js.map +1 -1
  291. package/dist/src/tools/mcp-client.test.js +18 -0
  292. package/dist/src/tools/mcp-client.test.js.map +1 -1
  293. package/dist/src/tools/mcp-tool.d.ts +1 -0
  294. package/dist/src/tools/mcp-tool.js +5 -2
  295. package/dist/src/tools/mcp-tool.js.map +1 -1
  296. package/dist/src/tools/memoryTool.js +1 -1
  297. package/dist/src/tools/memoryTool.js.map +1 -1
  298. package/dist/src/tools/memoryTool.test.js +1 -1
  299. package/dist/src/tools/memoryTool.test.js.map +1 -1
  300. package/dist/src/tools/modifiable-tool.d.ts +5 -1
  301. package/dist/src/tools/modifiable-tool.js +34 -13
  302. package/dist/src/tools/modifiable-tool.js.map +1 -1
  303. package/dist/src/tools/modifiable-tool.test.js +56 -22
  304. package/dist/src/tools/modifiable-tool.test.js.map +1 -1
  305. package/dist/src/tools/read-file.d.ts +2 -2
  306. package/dist/src/tools/read-file.js +20 -24
  307. package/dist/src/tools/read-file.js.map +1 -1
  308. package/dist/src/tools/read-file.test.js +63 -51
  309. package/dist/src/tools/read-file.test.js.map +1 -1
  310. package/dist/src/tools/read-many-files.d.ts +2 -9
  311. package/dist/src/tools/read-many-files.js +10 -21
  312. package/dist/src/tools/read-many-files.js.map +1 -1
  313. package/dist/src/tools/read-many-files.test.js +37 -35
  314. package/dist/src/tools/read-many-files.test.js.map +1 -1
  315. package/dist/src/tools/ripGrep.d.ts +25 -8
  316. package/dist/src/tools/ripGrep.js +148 -176
  317. package/dist/src/tools/ripGrep.js.map +1 -1
  318. package/dist/src/tools/ripGrep.test.js +383 -58
  319. package/dist/src/tools/ripGrep.test.js.map +1 -1
  320. package/dist/src/tools/shell.d.ts +1 -1
  321. package/dist/src/tools/shell.js +17 -15
  322. package/dist/src/tools/shell.js.map +1 -1
  323. package/dist/src/tools/shell.test.js +66 -36
  324. package/dist/src/tools/shell.test.js.map +1 -1
  325. package/dist/src/tools/smart-edit.d.ts +6 -1
  326. package/dist/src/tools/smart-edit.js +18 -17
  327. package/dist/src/tools/smart-edit.js.map +1 -1
  328. package/dist/src/tools/smart-edit.test.js +49 -24
  329. package/dist/src/tools/smart-edit.test.js.map +1 -1
  330. package/dist/src/tools/tool-registry.d.ts +29 -4
  331. package/dist/src/tools/tool-registry.js +108 -29
  332. package/dist/src/tools/tool-registry.js.map +1 -1
  333. package/dist/src/tools/tool-registry.test.js +134 -4
  334. package/dist/src/tools/tool-registry.test.js.map +1 -1
  335. package/dist/src/tools/tools.d.ts +2 -1
  336. package/dist/src/tools/tools.js +5 -2
  337. package/dist/src/tools/tools.js.map +1 -1
  338. package/dist/src/tools/web-fetch.js +2 -4
  339. package/dist/src/tools/web-fetch.js.map +1 -1
  340. package/dist/src/tools/web-fetch.test.js +11 -4
  341. package/dist/src/tools/web-fetch.test.js.map +1 -1
  342. package/dist/src/tools/web-search.js +1 -2
  343. package/dist/src/tools/web-search.js.map +1 -1
  344. package/dist/src/tools/web-search.test.js +11 -5
  345. package/dist/src/tools/web-search.test.js.map +1 -1
  346. package/dist/src/tools/write-file.js +31 -31
  347. package/dist/src/tools/write-file.js.map +1 -1
  348. package/dist/src/tools/write-file.test.js +24 -5
  349. package/dist/src/tools/write-file.test.js.map +1 -1
  350. package/dist/src/tools/write-todos.d.ts +29 -0
  351. package/dist/src/tools/write-todos.js +34 -1
  352. package/dist/src/tools/write-todos.js.map +1 -1
  353. package/dist/src/utils/editCorrector.js +4 -15
  354. package/dist/src/utils/editCorrector.js.map +1 -1
  355. package/dist/src/utils/editCorrector.test.js +16 -0
  356. package/dist/src/utils/editCorrector.test.js.map +1 -1
  357. package/dist/src/utils/editor.d.ts +3 -1
  358. package/dist/src/utils/editor.js +18 -1
  359. package/dist/src/utils/editor.js.map +1 -1
  360. package/dist/src/utils/editor.test.js +11 -0
  361. package/dist/src/utils/editor.test.js.map +1 -1
  362. package/dist/src/utils/environmentContext.js +3 -1
  363. package/dist/src/utils/environmentContext.js.map +1 -1
  364. package/dist/src/utils/environmentContext.test.js +6 -0
  365. package/dist/src/utils/environmentContext.test.js.map +1 -1
  366. package/dist/src/utils/events.d.ts +14 -11
  367. package/dist/src/utils/events.js +1 -14
  368. package/dist/src/utils/events.js.map +1 -1
  369. package/dist/src/utils/extensionLoader.d.ts +8 -0
  370. package/dist/src/utils/extensionLoader.js +61 -15
  371. package/dist/src/utils/extensionLoader.js.map +1 -1
  372. package/dist/src/utils/extensionLoader.test.js +83 -19
  373. package/dist/src/utils/extensionLoader.test.js.map +1 -1
  374. package/dist/src/utils/fileUtils.test.js +75 -60
  375. package/dist/src/utils/fileUtils.test.js.map +1 -1
  376. package/dist/src/utils/flashFallback.test.js +2 -2
  377. package/dist/src/utils/flashFallback.test.js.map +1 -1
  378. package/dist/src/utils/googleQuotaErrors.d.ts +2 -1
  379. package/dist/src/utils/googleQuotaErrors.js +20 -12
  380. package/dist/src/utils/googleQuotaErrors.js.map +1 -1
  381. package/dist/src/utils/httpErrors.d.ts +18 -0
  382. package/dist/src/utils/httpErrors.js +36 -0
  383. package/dist/src/utils/httpErrors.js.map +1 -0
  384. package/dist/src/utils/llm-edit-fixer.js +1 -2
  385. package/dist/src/utils/llm-edit-fixer.js.map +1 -1
  386. package/dist/src/utils/llm-edit-fixer.test.js +16 -1
  387. package/dist/src/utils/llm-edit-fixer.test.js.map +1 -1
  388. package/dist/src/utils/memoryDiscovery.d.ts +8 -0
  389. package/dist/src/utils/memoryDiscovery.js +24 -0
  390. package/dist/src/utils/memoryDiscovery.js.map +1 -1
  391. package/dist/src/utils/memoryDiscovery.test.js +43 -1
  392. package/dist/src/utils/memoryDiscovery.test.js.map +1 -1
  393. package/dist/src/utils/nextSpeakerChecker.js +1 -2
  394. package/dist/src/utils/nextSpeakerChecker.js.map +1 -1
  395. package/dist/src/utils/nextSpeakerChecker.test.js +10 -4
  396. package/dist/src/utils/nextSpeakerChecker.test.js.map +1 -1
  397. package/dist/src/utils/pathReader.js +4 -4
  398. package/dist/src/utils/pathReader.js.map +1 -1
  399. package/dist/src/utils/pathReader.test.js +44 -1
  400. package/dist/src/utils/pathReader.test.js.map +1 -1
  401. package/dist/src/utils/paths.d.ts +1 -1
  402. package/dist/src/utils/paths.js +5 -3
  403. package/dist/src/utils/paths.js.map +1 -1
  404. package/dist/src/utils/retry.d.ts +0 -9
  405. package/dist/src/utils/retry.js +24 -28
  406. package/dist/src/utils/retry.js.map +1 -1
  407. package/dist/src/utils/retry.test.js +51 -0
  408. package/dist/src/utils/retry.test.js.map +1 -1
  409. package/dist/src/utils/shell-utils.js +5 -3
  410. package/dist/src/utils/shell-utils.js.map +1 -1
  411. package/dist/src/utils/shell-utils.test.js +9 -9
  412. package/dist/src/utils/shell-utils.test.js.map +1 -1
  413. package/dist/src/utils/summarizer.d.ts +4 -2
  414. package/dist/src/utils/summarizer.js +6 -8
  415. package/dist/src/utils/summarizer.js.map +1 -1
  416. package/dist/src/utils/summarizer.test.js +32 -11
  417. package/dist/src/utils/summarizer.test.js.map +1 -1
  418. package/dist/src/utils/workspaceContext.d.ts +4 -3
  419. package/dist/src/utils/workspaceContext.js +10 -11
  420. package/dist/src/utils/workspaceContext.js.map +1 -1
  421. package/dist/src/utils/workspaceContext.test.js +1 -1
  422. package/dist/src/utils/workspaceContext.test.js.map +1 -1
  423. package/dist/tsconfig.tsbuildinfo +1 -1
  424. package/package.json +1 -1
@@ -5,11 +5,12 @@
5
5
  */
6
6
  import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
7
7
  import { ApiError } from '@google/genai';
8
- import { GeminiChat, InvalidStreamError, StreamEventType, } from './geminiChat.js';
8
+ import { GeminiChat, InvalidStreamError, StreamEventType, SYNTHETIC_THOUGHT_SIGNATURE, } from './geminiChat.js';
9
9
  import { setSimulate429 } from '../utils/testUtils.js';
10
- import { DEFAULT_GEMINI_FLASH_MODEL } from '../config/models.js';
10
+ import { DEFAULT_GEMINI_FLASH_MODEL, DEFAULT_GEMINI_MODEL, PREVIEW_GEMINI_MODEL, } from '../config/models.js';
11
11
  import { AuthType } from './contentGenerator.js';
12
- import {} from '../utils/retry.js';
12
+ import { TerminalQuotaError } from '../utils/googleQuotaErrors.js';
13
+ import { retryWithBackoff } from '../utils/retry.js';
13
14
  import { uiTelemetryService } from '../telemetry/uiTelemetry.js';
14
15
  // Mock fs module to prevent actual file system operations during tests
15
16
  const mockFileSystem = new Map();
@@ -83,6 +84,7 @@ describe('GeminiChat', () => {
83
84
  getTelemetryLogPromptsEnabled: () => true,
84
85
  getUsageStatisticsEnabled: () => true,
85
86
  getDebugMode: () => false,
87
+ getPreviewFeatures: () => false,
86
88
  getContentGeneratorConfig: vi.fn().mockReturnValue({
87
89
  authType: 'oauth-personal', // Ensure this is set for fallback tests
88
90
  model: 'test-model',
@@ -102,6 +104,11 @@ describe('GeminiChat', () => {
102
104
  }),
103
105
  getContentGenerator: vi.fn().mockReturnValue(mockContentGenerator),
104
106
  getRetryFetchErrors: vi.fn().mockReturnValue(false),
107
+ isPreviewModelBypassMode: vi.fn().mockReturnValue(false),
108
+ setPreviewModelBypassMode: vi.fn(),
109
+ isPreviewModelFallbackMode: vi.fn().mockReturnValue(false),
110
+ setPreviewModelFallbackMode: vi.fn(),
111
+ isInteractive: vi.fn().mockReturnValue(false),
105
112
  };
106
113
  // Disable 429 simulation for tests
107
114
  setSimulate429(false);
@@ -196,7 +203,7 @@ describe('GeminiChat', () => {
196
203
  })();
197
204
  vi.mocked(mockContentGenerator.generateContentStream).mockResolvedValue(streamWithNoFinish);
198
205
  // 2. Action & Assert: The stream should fail because there's no finish reason.
199
- const stream = await chat.sendMessageStream('test-model', { message: 'test message' }, 'prompt-id-no-finish-empty-end');
206
+ const stream = await chat.sendMessageStream('gemini-2.0-flash', { message: 'test message' }, 'prompt-id-no-finish-empty-end');
200
207
  await expect((async () => {
201
208
  for await (const _ of stream) {
202
209
  /* consume stream */
@@ -366,6 +373,84 @@ describe('GeminiChat', () => {
366
373
  expect(modelTurn?.parts?.length).toBe(1);
367
374
  expect(modelTurn?.parts[0].text).toBe('This is the visible text that should not be lost.');
368
375
  });
376
+ it('should use maxAttempts=1 for retryWithBackoff when in Preview Model Fallback Mode', async () => {
377
+ vi.mocked(mockConfig.isPreviewModelFallbackMode).mockReturnValue(true);
378
+ vi.mocked(mockContentGenerator.generateContentStream).mockResolvedValue((async function* () {
379
+ yield {
380
+ candidates: [
381
+ {
382
+ content: { parts: [{ text: 'Success' }] },
383
+ finishReason: 'STOP',
384
+ },
385
+ ],
386
+ };
387
+ })());
388
+ const stream = await chat.sendMessageStream(PREVIEW_GEMINI_MODEL, { message: 'test' }, 'prompt-id-fast-retry');
389
+ for await (const _ of stream) {
390
+ // consume stream
391
+ }
392
+ expect(mockRetryWithBackoff).toHaveBeenCalledWith(expect.any(Function), expect.objectContaining({
393
+ maxAttempts: 1,
394
+ }));
395
+ });
396
+ it('should NOT use maxAttempts=1 for other models even in Preview Model Fallback Mode', async () => {
397
+ vi.mocked(mockConfig.isPreviewModelFallbackMode).mockReturnValue(true);
398
+ vi.mocked(mockContentGenerator.generateContentStream).mockResolvedValue((async function* () {
399
+ yield {
400
+ candidates: [
401
+ {
402
+ content: { parts: [{ text: 'Success' }] },
403
+ finishReason: 'STOP',
404
+ },
405
+ ],
406
+ };
407
+ })());
408
+ const stream = await chat.sendMessageStream(DEFAULT_GEMINI_FLASH_MODEL, { message: 'test' }, 'prompt-id-normal-retry');
409
+ for await (const _ of stream) {
410
+ // consume stream
411
+ }
412
+ expect(mockRetryWithBackoff).toHaveBeenCalledWith(expect.any(Function), expect.objectContaining({
413
+ maxAttempts: undefined, // Should use default
414
+ }));
415
+ });
416
+ it('should pass DEFAULT_GEMINI_MODEL to handleFallback when Preview Model is bypassed (downgraded)', async () => {
417
+ // ARRANGE
418
+ vi.mocked(mockConfig.isPreviewModelBypassMode).mockReturnValue(true);
419
+ // Mock retryWithBackoff to simulate catching the error and calling onPersistent429
420
+ vi.mocked(retryWithBackoff).mockImplementation(async (apiCall, options) => {
421
+ const onPersistent429 = options?.onPersistent429;
422
+ try {
423
+ await apiCall();
424
+ }
425
+ catch (error) {
426
+ if (onPersistent429) {
427
+ await onPersistent429(AuthType.LOGIN_WITH_GOOGLE, error);
428
+ }
429
+ throw error;
430
+ }
431
+ });
432
+ // We need the API call to fail so retryWithBackoff calls the callback.
433
+ vi.mocked(mockContentGenerator.generateContentStream).mockRejectedValue(new TerminalQuotaError('Simulated Quota Error', {
434
+ code: 429,
435
+ message: 'Simulated Quota Error',
436
+ details: [],
437
+ }));
438
+ // ACT
439
+ const consumeStream = async () => {
440
+ const stream = await chat.sendMessageStream(PREVIEW_GEMINI_MODEL, { message: 'test' }, 'prompt-id-bypass');
441
+ // Consume the stream to trigger execution
442
+ for await (const _ of stream) {
443
+ // do nothing
444
+ }
445
+ };
446
+ await expect(consumeStream()).rejects.toThrow('Simulated Quota Error');
447
+ expect(retryWithBackoff).toHaveBeenCalled();
448
+ // ASSERT
449
+ // handleFallback is called via onPersistent429Callback
450
+ // We verify it was called with DEFAULT_GEMINI_MODEL
451
+ expect(mockHandleFallback).toHaveBeenCalledWith(expect.anything(), DEFAULT_GEMINI_MODEL, // This is the key assertion
452
+ expect.anything(), expect.anything());
453
+ });
369
454
  it('should throw an error when a tool call is followed by an empty stream response', async () => {
370
455
  // 1. Setup: A history where the model has just made a function call.
371
456
  const initialHistory = [
@@ -399,7 +484,7 @@ describe('GeminiChat', () => {
399
484
  })();
400
485
  vi.mocked(mockContentGenerator.generateContentStream).mockResolvedValue(emptyStreamResponse);
401
486
  // 3. Action: Send the function response back to the model and consume the stream.
402
- const stream = await chat.sendMessageStream('test-model', {
487
+ const stream = await chat.sendMessageStream('gemini-2.0-flash', {
403
488
  message: {
404
489
  functionResponse: {
405
490
  name: 'find_restaurant',
@@ -461,7 +546,7 @@ describe('GeminiChat', () => {
461
546
  };
462
547
  })();
463
548
  vi.mocked(mockContentGenerator.generateContentStream).mockResolvedValue(streamWithoutFinishReason);
464
- const stream = await chat.sendMessageStream('test-model', { message: 'test' }, 'prompt-id-1');
549
+ const stream = await chat.sendMessageStream('gemini-2.0-flash', { message: 'test' }, 'prompt-id-1');
465
550
  await expect((async () => {
466
551
  for await (const _ of stream) {
467
552
  // consume stream
@@ -484,7 +569,7 @@ describe('GeminiChat', () => {
484
569
  };
485
570
  })();
486
571
  vi.mocked(mockContentGenerator.generateContentStream).mockResolvedValue(streamWithEmptyResponse);
487
- const stream = await chat.sendMessageStream('test-model', { message: 'test' }, 'prompt-id-1');
572
+ const stream = await chat.sendMessageStream('gemini-2.0-flash', { message: 'test' }, 'prompt-id-1');
488
573
  await expect((async () => {
489
574
  for await (const _ of stream) {
490
575
  // consume stream
@@ -515,6 +600,71 @@ describe('GeminiChat', () => {
515
600
  }
516
601
  })()).resolves.not.toThrow();
517
602
  });
603
+ it('should throw InvalidStreamError when finishReason is MALFORMED_FUNCTION_CALL', async () => {
604
+ // Setup: Stream with MALFORMED_FUNCTION_CALL finish reason and empty response
605
+ const streamWithMalformedFunctionCall = (async function* () {
606
+ yield {
607
+ candidates: [
608
+ {
609
+ content: {
610
+ role: 'model',
611
+ parts: [], // Empty parts
612
+ },
613
+ finishReason: 'MALFORMED_FUNCTION_CALL',
614
+ },
615
+ ],
616
+ };
617
+ })();
618
+ vi.mocked(mockContentGenerator.generateContentStream).mockResolvedValue(streamWithMalformedFunctionCall);
619
+ const stream = await chat.sendMessageStream('gemini-2.5-pro', { message: 'test' }, 'prompt-id-malformed');
620
+ // Should throw an error
621
+ await expect((async () => {
622
+ for await (const _ of stream) {
623
+ // consume stream
624
+ }
625
+ })()).rejects.toThrow(InvalidStreamError);
626
+ });
627
+ it('should retry when finishReason is MALFORMED_FUNCTION_CALL', async () => {
628
+ // 1. Mock the API to fail once with MALFORMED_FUNCTION_CALL, then succeed.
629
+ vi.mocked(mockContentGenerator.generateContentStream)
630
+ .mockImplementationOnce(async () => (async function* () {
631
+ yield {
632
+ candidates: [
633
+ {
634
+ content: { parts: [], role: 'model' },
635
+ finishReason: 'MALFORMED_FUNCTION_CALL',
636
+ },
637
+ ],
638
+ };
639
+ })())
640
+ .mockImplementationOnce(async () =>
641
+ // Second attempt succeeds
642
+ (async function* () {
643
+ yield {
644
+ candidates: [
645
+ {
646
+ content: { parts: [{ text: 'Success after retry' }] },
647
+ finishReason: 'STOP',
648
+ },
649
+ ],
650
+ };
651
+ })());
652
+ // 2. Send a message
653
+ const stream = await chat.sendMessageStream('gemini-2.5-pro', { message: 'test retry' }, 'prompt-id-retry-malformed');
654
+ const events = [];
655
+ for await (const event of stream) {
656
+ events.push(event);
657
+ }
658
+ // 3. Assertions
659
+ // Should be called twice (initial + retry)
660
+ expect(mockContentGenerator.generateContentStream).toHaveBeenCalledTimes(2);
661
+ // Check for a retry event
662
+ expect(events.some((e) => e.type === StreamEventType.RETRY)).toBe(true);
663
+ // Check for the successful content chunk
664
+ expect(events.some((e) => e.type === StreamEventType.CHUNK &&
665
+ e.value.candidates?.[0]?.content?.parts?.[0]?.text ===
666
+ 'Success after retry')).toBe(true);
667
+ });
518
668
  it('should call generateContentStream with the correct parameters', async () => {
519
669
  const response = (async function* () {
520
670
  yield {
@@ -583,6 +733,23 @@ describe('GeminiChat', () => {
583
733
  });
584
734
  });
585
735
  describe('sendMessageStream with retries', () => {
736
+ it('should not retry on invalid content if model does not start with gemini-2', async () => {
737
+ // Mock the stream to fail.
738
+ vi.mocked(mockContentGenerator.generateContentStream).mockImplementation(async () => (async function* () {
739
+ yield {
740
+ candidates: [{ content: { parts: [{ text: '' }] } }],
741
+ };
742
+ })());
743
+ const stream = await chat.sendMessageStream('gemini-1.5-pro', { message: 'test' }, 'prompt-id-no-retry');
744
+ await expect((async () => {
745
+ for await (const _ of stream) {
746
+ // Must loop to trigger the internal logic that throws.
747
+ }
748
+ })()).rejects.toThrow(InvalidStreamError);
749
+ // Should be called only 1 time (no retry)
750
+ expect(mockContentGenerator.generateContentStream).toHaveBeenCalledTimes(1);
751
+ expect(mockLogContentRetry).not.toHaveBeenCalled();
752
+ });
586
753
  it('should yield a RETRY event when an invalid stream is encountered', async () => {
587
754
  // ARRANGE: Mock the stream to fail once, then succeed.
588
755
  vi.mocked(mockContentGenerator.generateContentStream)
@@ -606,7 +773,7 @@ describe('GeminiChat', () => {
606
773
  };
607
774
  })());
608
775
  // ACT: Send a message and collect all events from the stream.
609
- const stream = await chat.sendMessageStream('test-model', { message: 'test' }, 'prompt-id-yield-retry');
776
+ const stream = await chat.sendMessageStream('gemini-2.0-flash', { message: 'test' }, 'prompt-id-yield-retry');
610
777
  const events = [];
611
778
  for await (const event of stream) {
612
779
  events.push(event);
@@ -638,7 +805,7 @@ describe('GeminiChat', () => {
638
805
  ],
639
806
  };
640
807
  })());
641
- const stream = await chat.sendMessageStream('test-model', { message: 'test' }, 'prompt-id-retry-success');
808
+ const stream = await chat.sendMessageStream('gemini-2.0-flash', { message: 'test' }, 'prompt-id-retry-success');
642
809
  const chunks = [];
643
810
  for await (const chunk of stream) {
644
811
  chunks.push(chunk);
@@ -689,7 +856,7 @@ describe('GeminiChat', () => {
689
856
  ],
690
857
  };
691
858
  })());
692
- const stream = await chat.sendMessageStream('test-model', { message: 'test', config: { temperature: 0.5 } }, 'prompt-id-retry-temperature');
859
+ const stream = await chat.sendMessageStream('gemini-2.0-flash', { message: 'test', config: { temperature: 0.5 } }, 'prompt-id-retry-temperature');
693
860
  for await (const _ of stream) {
694
861
  // consume stream
695
862
  }
@@ -720,7 +887,7 @@ describe('GeminiChat', () => {
720
887
  ],
721
888
  };
722
889
  })());
723
- const stream = await chat.sendMessageStream('test-model', { message: 'test' }, 'prompt-id-retry-fail');
890
+ const stream = await chat.sendMessageStream('gemini-2.0-flash', { message: 'test' }, 'prompt-id-retry-fail');
724
891
  await expect(async () => {
725
892
  for await (const _ of stream) {
726
893
  // Must loop to trigger the internal logic that throws.
@@ -769,7 +936,7 @@ describe('GeminiChat', () => {
769
936
  it('should not retry on 400 Bad Request errors', async () => {
770
937
  const error400 = new ApiError({ message: 'Bad Request', status: 400 });
771
938
  vi.mocked(mockContentGenerator.generateContentStream).mockRejectedValue(error400);
772
- const stream = await chat.sendMessageStream('test-model', { message: 'test' }, 'prompt-id-400');
939
+ const stream = await chat.sendMessageStream('gemini-2.0-flash', { message: 'test' }, 'prompt-id-400');
773
940
  await expect((async () => {
774
941
  for await (const _ of stream) {
775
942
  /* consume stream */
@@ -900,7 +1067,7 @@ describe('GeminiChat', () => {
900
1067
  };
901
1068
  })());
902
1069
  // 3. Send a new message
903
- const stream = await chat.sendMessageStream('test-model', { message: 'Second question' }, 'prompt-id-retry-existing');
1070
+ const stream = await chat.sendMessageStream('gemini-2.0-flash', { message: 'Second question' }, 'prompt-id-retry-existing');
904
1071
  for await (const _ of stream) {
905
1072
  // consume stream
906
1073
  }
@@ -952,7 +1119,7 @@ describe('GeminiChat', () => {
952
1119
  };
953
1120
  })());
954
1121
  // 2. Call the method and consume the stream.
955
- const stream = await chat.sendMessageStream('test-model', { message: 'test empty stream' }, 'prompt-id-empty-stream');
1122
+ const stream = await chat.sendMessageStream('gemini-2.0-flash', { message: 'test empty stream' }, 'prompt-id-empty-stream');
956
1123
  const chunks = [];
957
1124
  for await (const chunk of stream) {
958
1125
  chunks.push(chunk);
@@ -1136,7 +1303,7 @@ describe('GeminiChat', () => {
1136
1303
  vi.mocked(mockConfig.getModel).mockReturnValue('gemini-pro');
1137
1304
  vi.mocked(mockContentGenerator.generateContentStream).mockRejectedValue(error429);
1138
1305
  mockHandleFallback.mockResolvedValue(false);
1139
- const stream = await chat.sendMessageStream('test-model', { message: 'test stop' }, 'prompt-id-fb2');
1306
+ const stream = await chat.sendMessageStream('gemini-2.0-flash', { message: 'test stop' }, 'prompt-id-fb2');
1140
1307
  await expect((async () => {
1141
1308
  for await (const _ of stream) {
1142
1309
  /* consume stream */
@@ -1180,7 +1347,7 @@ describe('GeminiChat', () => {
1180
1347
  };
1181
1348
  })());
1182
1349
  // Send a message and consume the stream
1183
- const stream = await chat.sendMessageStream('test-model', { message: 'test' }, 'prompt-id-discard-test');
1350
+ const stream = await chat.sendMessageStream('gemini-2.0-flash', { message: 'test' }, 'prompt-id-discard-test');
1184
1351
  const events = [];
1185
1352
  for await (const event of stream) {
1186
1353
  events.push(event);
@@ -1231,5 +1398,139 @@ describe('GeminiChat', () => {
1231
1398
  ]);
1232
1399
  });
1233
1400
  });
1401
+ describe('Preview Model Fallback Logic', () => {
1402
+ it('should reset previewModelBypassMode to false at the start of sendMessageStream', async () => {
1403
+ const stream = (async function* () {
1404
+ yield {
1405
+ candidates: [
1406
+ {
1407
+ content: { role: 'model', parts: [{ text: 'Success' }] },
1408
+ finishReason: 'STOP',
1409
+ },
1410
+ ],
1411
+ };
1412
+ })();
1413
+ vi.mocked(mockContentGenerator.generateContentStream).mockResolvedValue(stream);
1414
+ await chat.sendMessageStream('test-model', { message: 'test' }, 'prompt-id-preview-model-reset');
1415
+ expect(mockConfig.setPreviewModelBypassMode).toHaveBeenCalledWith(false);
1416
+ });
1417
+ it('should reset previewModelFallbackMode to false upon successful Preview Model usage', async () => {
1418
+ const stream = (async function* () {
1419
+ yield {
1420
+ candidates: [
1421
+ {
1422
+ content: { role: 'model', parts: [{ text: 'Success' }] },
1423
+ finishReason: 'STOP',
1424
+ },
1425
+ ],
1426
+ };
1427
+ })();
1428
+ vi.mocked(mockContentGenerator.generateContentStream).mockResolvedValue(stream);
1429
+ const resultStream = await chat.sendMessageStream(PREVIEW_GEMINI_MODEL, { message: 'test' }, 'prompt-id-preview-model-healing');
1430
+ for await (const _ of resultStream) {
1431
+ // consume stream
1432
+ }
1433
+ expect(mockConfig.setPreviewModelFallbackMode).toHaveBeenCalledWith(false);
1434
+ });
1435
+ it('should NOT reset previewModelFallbackMode if Preview Model was bypassed (downgraded)', async () => {
1436
+ const stream = (async function* () {
1437
+ yield {
1438
+ candidates: [
1439
+ {
1440
+ content: { role: 'model', parts: [{ text: 'Success' }] },
1441
+ finishReason: 'STOP',
1442
+ },
1443
+ ],
1444
+ };
1445
+ })();
1446
+ vi.mocked(mockContentGenerator.generateContentStream).mockResolvedValue(stream);
1447
+ // Simulate bypass mode being active (downgrade happened)
1448
+ vi.mocked(mockConfig.isPreviewModelBypassMode).mockReturnValue(true);
1449
+ const resultStream = await chat.sendMessageStream(PREVIEW_GEMINI_MODEL, { message: 'test' }, 'prompt-id-bypass-no-healing');
1450
+ for await (const _ of resultStream) {
1451
+ // consume stream
1452
+ }
1453
+ expect(mockConfig.setPreviewModelFallbackMode).not.toHaveBeenCalled();
1454
+ });
1455
+ });
1456
+ describe('ensureActiveLoopHasThoughtSignatures', () => {
1457
+ it('should add thoughtSignature to the first functionCall in each model turn of the active loop', () => {
1458
+ const chat = new GeminiChat(mockConfig, {}, []);
1459
+ const history = [
1460
+ { role: 'user', parts: [{ text: 'Old message' }] },
1461
+ {
1462
+ role: 'model',
1463
+ parts: [{ functionCall: { name: 'old_tool', args: {} } }],
1464
+ },
1465
+ { role: 'user', parts: [{ text: 'Find a restaurant' }] }, // active loop starts here
1466
+ {
1467
+ role: 'model',
1468
+ parts: [
1469
+ { functionCall: { name: 'find_restaurant', args: {} } }, // This one gets a signature
1470
+ { functionCall: { name: 'find_restaurant_2', args: {} } }, // This one does NOT
1471
+ ],
1472
+ },
1473
+ {
1474
+ role: 'user',
1475
+ parts: [
1476
+ { functionResponse: { name: 'find_restaurant', response: {} } },
1477
+ ],
1478
+ },
1479
+ {
1480
+ role: 'model',
1481
+ parts: [
1482
+ {
1483
+ functionCall: { name: 'tool_with_sig', args: {} },
1484
+ thoughtSignature: 'existing-sig',
1485
+ },
1486
+ { functionCall: { name: 'another_tool', args: {} } }, // This one does NOT get a signature
1487
+ ],
1488
+ },
1489
+ ];
1490
+ const newContents = chat.ensureActiveLoopHasThoughtSignatures(history);
1491
+ // Outside active loop - unchanged
1492
+ expect(newContents[1]?.parts?.[0]).not.toHaveProperty('thoughtSignature');
1493
+ // Inside active loop, first model turn
1494
+ // First function call gets a signature
1495
+ expect(newContents[3]?.parts?.[0]?.thoughtSignature).toBe(SYNTHETIC_THOUGHT_SIGNATURE);
1496
+ // Second function call does NOT
1497
+ expect(newContents[3]?.parts?.[1]).not.toHaveProperty('thoughtSignature');
1498
+ // User functionResponse part - unchanged (this is not a model turn)
1499
+ expect(newContents[4]?.parts?.[0]).not.toHaveProperty('thoughtSignature');
1500
+ // Inside active loop, second model turn
1501
+ // First function call already has a signature, so nothing changes
1502
+ expect(newContents[5]?.parts?.[0]?.thoughtSignature).toBe('existing-sig');
1503
+ // Second function call does NOT get a signature
1504
+ expect(newContents[5]?.parts?.[1]).not.toHaveProperty('thoughtSignature');
1505
+ });
1506
+ it('should not modify contents if there is no user text message', () => {
1507
+ const chat = new GeminiChat(mockConfig, {}, []);
1508
+ const history = [
1509
+ {
1510
+ role: 'user',
1511
+ parts: [{ functionResponse: { name: 'tool1', response: {} } }],
1512
+ },
1513
+ {
1514
+ role: 'model',
1515
+ parts: [{ functionCall: { name: 'tool2', args: {} } }],
1516
+ },
1517
+ ];
1518
+ const newContents = chat.ensureActiveLoopHasThoughtSignatures(history);
1519
+ expect(newContents).toEqual(history);
1520
+ expect(newContents[1]?.parts?.[0]).not.toHaveProperty('thoughtSignature');
1521
+ });
1522
+ it('should handle an empty history', () => {
1523
+ const chat = new GeminiChat(mockConfig, {}, []);
1524
+ const history = [];
1525
+ const newContents = chat.ensureActiveLoopHasThoughtSignatures(history);
1526
+ expect(newContents).toEqual([]);
1527
+ });
1528
+ it('should handle history with only a user message', () => {
1529
+ const chat = new GeminiChat(mockConfig, {}, []);
1530
+ const history = [{ role: 'user', parts: [{ text: 'Hello' }] }];
1531
+ const newContents = chat.ensureActiveLoopHasThoughtSignatures(history);
1532
+ expect(newContents).toEqual(history);
1533
+ });
1534
+ });
1234
1535
  });
1235
1536
  //# sourceMappingURL=geminiChat.test.js.map