@vybestack/llxprt-code-core 0.1.18-nightly.250808.f9b79d74 → 0.1.18-nightly.250812.12fa8ad2

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 (563) hide show
  1. package/README.md +49 -2
  2. package/dist/index.d.ts +6 -0
  3. package/dist/index.js +5 -0
  4. package/dist/index.js.map +1 -1
  5. package/dist/src/auth/anthropic-device-flow.d.ts +53 -0
  6. package/dist/src/auth/anthropic-device-flow.js +208 -0
  7. package/dist/src/auth/anthropic-device-flow.js.map +1 -0
  8. package/dist/src/auth/precedence.d.ts +55 -0
  9. package/dist/src/auth/precedence.js +211 -0
  10. package/dist/src/auth/precedence.js.map +1 -0
  11. package/dist/src/auth/qwen-device-flow.d.ts +45 -0
  12. package/dist/src/auth/qwen-device-flow.js +179 -0
  13. package/dist/src/auth/qwen-device-flow.js.map +1 -0
  14. package/dist/src/auth/token-store.d.ts +66 -0
  15. package/dist/src/auth/token-store.js +151 -0
  16. package/dist/src/auth/token-store.js.map +1 -0
  17. package/dist/src/auth/types.d.ts +130 -0
  18. package/dist/src/auth/types.js +60 -0
  19. package/dist/src/auth/types.js.map +1 -0
  20. package/dist/src/code_assist/converter.d.ts +2 -1
  21. package/dist/src/code_assist/converter.js +1 -1
  22. package/dist/src/code_assist/converter.js.map +1 -1
  23. package/dist/src/code_assist/oauth2.js +2 -1
  24. package/dist/src/code_assist/oauth2.js.map +1 -1
  25. package/dist/src/config/config.d.ts +78 -3
  26. package/dist/src/config/config.js +159 -6
  27. package/dist/src/config/config.js.map +1 -1
  28. package/dist/src/config/endpoints.d.ts +60 -0
  29. package/dist/src/config/endpoints.js +126 -0
  30. package/dist/src/config/endpoints.js.map +1 -0
  31. package/dist/src/config/profileManager.d.ts +14 -4
  32. package/dist/src/config/profileManager.js +90 -11
  33. package/dist/src/config/profileManager.js.map +1 -1
  34. package/dist/src/core/client.js +16 -16
  35. package/dist/src/core/client.js.map +1 -1
  36. package/dist/src/core/contentGenerator.d.ts +4 -1
  37. package/dist/src/core/contentGenerator.js +3 -0
  38. package/dist/src/core/contentGenerator.js.map +1 -1
  39. package/dist/src/core/logger.d.ts +1 -0
  40. package/dist/src/core/logger.js +18 -0
  41. package/dist/src/core/logger.js.map +1 -1
  42. package/dist/src/core/loggingContentGenerator.d.ts +24 -0
  43. package/dist/src/core/loggingContentGenerator.js +89 -0
  44. package/dist/src/core/loggingContentGenerator.js.map +1 -0
  45. package/dist/src/core/nonInteractiveToolExecutor.js +17 -0
  46. package/dist/src/core/nonInteractiveToolExecutor.js.map +1 -1
  47. package/dist/src/core/subagent.js +12 -10
  48. package/dist/src/core/subagent.js.map +1 -1
  49. package/dist/src/ide/ide-client.d.ts +2 -2
  50. package/dist/src/ide/ide-client.js +56 -18
  51. package/dist/src/ide/ide-client.js.map +1 -1
  52. package/dist/src/index.d.ts +11 -0
  53. package/dist/src/index.js +12 -0
  54. package/dist/src/index.js.map +1 -1
  55. package/dist/src/providers/BaseProvider.d.ts +149 -0
  56. package/dist/src/providers/BaseProvider.js +315 -0
  57. package/dist/src/providers/BaseProvider.js.map +1 -0
  58. package/dist/src/providers/IProvider.d.ts +1 -0
  59. package/dist/src/providers/IProviderManager.d.ts +5 -0
  60. package/dist/src/providers/LoggingProviderWrapper.d.ts +54 -0
  61. package/dist/src/providers/LoggingProviderWrapper.js +350 -0
  62. package/dist/src/providers/LoggingProviderWrapper.js.map +1 -0
  63. package/dist/src/providers/ProviderManager.d.ts +20 -1
  64. package/dist/src/providers/ProviderManager.js +236 -14
  65. package/dist/src/providers/ProviderManager.js.map +1 -1
  66. package/dist/src/providers/anthropic/AnthropicProvider.d.ts +20 -6
  67. package/dist/src/providers/anthropic/AnthropicProvider.js +172 -26
  68. package/dist/src/providers/anthropic/AnthropicProvider.js.map +1 -1
  69. package/dist/src/providers/gemini/GeminiProvider.d.ts +16 -7
  70. package/dist/src/providers/gemini/GeminiProvider.js +163 -148
  71. package/dist/src/providers/gemini/GeminiProvider.js.map +1 -1
  72. package/dist/src/providers/logging/ProviderContentExtractor.d.ts +27 -0
  73. package/dist/src/providers/logging/ProviderContentExtractor.js +198 -0
  74. package/dist/src/providers/logging/ProviderContentExtractor.js.map +1 -0
  75. package/dist/src/providers/logging/ProviderPerformanceTracker.d.ts +43 -0
  76. package/dist/src/providers/logging/ProviderPerformanceTracker.js +98 -0
  77. package/dist/src/providers/logging/ProviderPerformanceTracker.js.map +1 -0
  78. package/dist/src/providers/openai/OpenAIProvider.d.ts +53 -6
  79. package/dist/src/providers/openai/OpenAIProvider.js +373 -40
  80. package/dist/src/providers/openai/OpenAIProvider.js.map +1 -1
  81. package/dist/src/providers/openai/RESPONSES_API_MODELS.d.ts +1 -1
  82. package/dist/src/providers/openai/RESPONSES_API_MODELS.js +1 -0
  83. package/dist/src/providers/openai/RESPONSES_API_MODELS.js.map +1 -1
  84. package/dist/src/providers/openai/syntheticToolResponses.d.ts +52 -0
  85. package/dist/src/providers/openai/syntheticToolResponses.js +129 -0
  86. package/dist/src/providers/openai/syntheticToolResponses.js.map +1 -0
  87. package/dist/src/providers/types.d.ts +47 -0
  88. package/dist/src/services/git-stats-service.d.ts +32 -0
  89. package/dist/src/services/git-stats-service.js +22 -0
  90. package/dist/src/services/git-stats-service.js.map +1 -0
  91. package/dist/src/services/loopDetectionService.js +10 -6
  92. package/dist/src/services/loopDetectionService.js.map +1 -1
  93. package/dist/src/services/shellExecutionService.js +44 -8
  94. package/dist/src/services/shellExecutionService.js.map +1 -1
  95. package/dist/src/settings/SettingsService.d.ts +32 -0
  96. package/dist/src/settings/SettingsService.js +204 -0
  97. package/dist/src/settings/SettingsService.js.map +1 -0
  98. package/dist/src/settings/settingsServiceInstance.d.ts +12 -0
  99. package/dist/src/settings/settingsServiceInstance.js +24 -0
  100. package/dist/src/settings/settingsServiceInstance.js.map +1 -0
  101. package/dist/src/settings/types.d.ts +141 -0
  102. package/dist/src/settings/types.js +5 -0
  103. package/dist/src/settings/types.js.map +1 -0
  104. package/dist/src/storage/ConversationFileWriter.d.ts +16 -0
  105. package/dist/src/storage/ConversationFileWriter.js +69 -0
  106. package/dist/src/storage/ConversationFileWriter.js.map +1 -0
  107. package/dist/src/telemetry/clearcut-logger/clearcut-logger.d.ts +8 -0
  108. package/dist/src/telemetry/clearcut-logger/clearcut-logger.js +56 -3
  109. package/dist/src/telemetry/clearcut-logger/clearcut-logger.js.map +1 -1
  110. package/dist/src/telemetry/clearcut-logger/event-metadata-key.d.ts +5 -1
  111. package/dist/src/telemetry/clearcut-logger/event-metadata-key.js +11 -0
  112. package/dist/src/telemetry/clearcut-logger/event-metadata-key.js.map +1 -1
  113. package/dist/src/telemetry/constants.d.ts +5 -0
  114. package/dist/src/telemetry/constants.js +5 -0
  115. package/dist/src/telemetry/constants.js.map +1 -1
  116. package/dist/src/telemetry/loggers.d.ts +5 -1
  117. package/dist/src/telemetry/loggers.js +87 -1
  118. package/dist/src/telemetry/loggers.js.map +1 -1
  119. package/dist/src/telemetry/metrics.d.ts +2 -1
  120. package/dist/src/telemetry/metrics.js +7 -1
  121. package/dist/src/telemetry/metrics.js.map +1 -1
  122. package/dist/src/telemetry/tool-call-decision.d.ts +13 -0
  123. package/dist/src/telemetry/tool-call-decision.js +29 -0
  124. package/dist/src/telemetry/tool-call-decision.js.map +1 -0
  125. package/dist/src/telemetry/types.d.ts +56 -1
  126. package/dist/src/telemetry/types.js +123 -0
  127. package/dist/src/telemetry/types.js.map +1 -1
  128. package/dist/src/telemetry/uiTelemetry.d.ts +2 -1
  129. package/dist/src/telemetry/uiTelemetry.js +1 -1
  130. package/dist/src/telemetry/uiTelemetry.js.map +1 -1
  131. package/dist/src/tools/diffOptions.d.ts +2 -0
  132. package/dist/src/tools/diffOptions.js +28 -0
  133. package/dist/src/tools/diffOptions.js.map +1 -1
  134. package/dist/src/tools/edit.d.ts +8 -32
  135. package/dist/src/tools/edit.js +153 -136
  136. package/dist/src/tools/edit.js.map +1 -1
  137. package/dist/src/tools/glob.d.ts +3 -10
  138. package/dist/src/tools/glob.js +97 -99
  139. package/dist/src/tools/glob.js.map +1 -1
  140. package/dist/src/tools/grep.d.ts +3 -35
  141. package/dist/src/tools/grep.js +117 -88
  142. package/dist/src/tools/grep.js.map +1 -1
  143. package/dist/src/tools/mcp-client.d.ts +4 -3
  144. package/dist/src/tools/mcp-client.js +23 -6
  145. package/dist/src/tools/mcp-client.js.map +1 -1
  146. package/dist/src/tools/read-file.js +37 -9
  147. package/dist/src/tools/read-file.js.map +1 -1
  148. package/dist/src/tools/todo-pause.d.ts +22 -0
  149. package/dist/src/tools/todo-pause.js +93 -0
  150. package/dist/src/tools/todo-pause.js.map +1 -0
  151. package/dist/src/tools/tool-error.d.ts +4 -0
  152. package/dist/src/tools/tool-error.js +4 -0
  153. package/dist/src/tools/tool-error.js.map +1 -1
  154. package/dist/src/tools/tool-registry.js +3 -3
  155. package/dist/src/tools/tool-registry.js.map +1 -1
  156. package/dist/src/tools/tools.d.ts +18 -0
  157. package/dist/src/tools/tools.js +15 -0
  158. package/dist/src/tools/tools.js.map +1 -1
  159. package/dist/src/tools/write-file.d.ts +4 -0
  160. package/dist/src/tools/write-file.js +90 -16
  161. package/dist/src/tools/write-file.js.map +1 -1
  162. package/dist/src/types/modelParams.d.ts +2 -0
  163. package/dist/src/utils/environmentContext.js +1 -1
  164. package/dist/src/utils/errors.d.ts +3 -0
  165. package/dist/src/utils/errors.js +6 -0
  166. package/dist/src/utils/errors.js.map +1 -1
  167. package/dist/src/utils/fileUtils.d.ts +7 -0
  168. package/dist/src/utils/fileUtils.js +9 -0
  169. package/dist/src/utils/fileUtils.js.map +1 -1
  170. package/dist/src/utils/filesearch/fileSearch.d.ts +1 -0
  171. package/dist/src/utils/filesearch/fileSearch.js +27 -19
  172. package/dist/src/utils/filesearch/fileSearch.js.map +1 -1
  173. package/package.json +4 -2
  174. package/dist/src/code_assist/converter.test.d.ts +0 -6
  175. package/dist/src/code_assist/converter.test.js +0 -232
  176. package/dist/src/code_assist/converter.test.js.map +0 -1
  177. package/dist/src/code_assist/oauth2.test.d.ts +0 -6
  178. package/dist/src/code_assist/oauth2.test.js +0 -370
  179. package/dist/src/code_assist/oauth2.test.js.map +0 -1
  180. package/dist/src/code_assist/server.test.d.ts +0 -6
  181. package/dist/src/code_assist/server.test.js +0 -131
  182. package/dist/src/code_assist/server.test.js.map +0 -1
  183. package/dist/src/code_assist/setup.test.d.ts +0 -6
  184. package/dist/src/code_assist/setup.test.js +0 -65
  185. package/dist/src/code_assist/setup.test.js.map +0 -1
  186. package/dist/src/config/config.alwaysAllow.test.d.ts +0 -6
  187. package/dist/src/config/config.alwaysAllow.test.js +0 -84
  188. package/dist/src/config/config.alwaysAllow.test.js.map +0 -1
  189. package/dist/src/config/config.test.d.ts +0 -6
  190. package/dist/src/config/config.test.js +0 -361
  191. package/dist/src/config/config.test.js.map +0 -1
  192. package/dist/src/config/flashFallback.test.d.ts +0 -6
  193. package/dist/src/config/flashFallback.test.js +0 -91
  194. package/dist/src/config/flashFallback.test.js.map +0 -1
  195. package/dist/src/core/client.test.d.ts +0 -6
  196. package/dist/src/core/client.test.js +0 -1317
  197. package/dist/src/core/client.test.js.map +0 -1
  198. package/dist/src/core/contentGenerator.test.d.ts +0 -6
  199. package/dist/src/core/contentGenerator.test.js +0 -103
  200. package/dist/src/core/contentGenerator.test.js.map +0 -1
  201. package/dist/src/core/coreToolScheduler.test.d.ts +0 -6
  202. package/dist/src/core/coreToolScheduler.test.js +0 -637
  203. package/dist/src/core/coreToolScheduler.test.js.map +0 -1
  204. package/dist/src/core/geminiChat.test.d.ts +0 -6
  205. package/dist/src/core/geminiChat.test.js +0 -425
  206. package/dist/src/core/geminiChat.test.js.map +0 -1
  207. package/dist/src/core/googleGenAIWrapper.test.d.ts +0 -6
  208. package/dist/src/core/googleGenAIWrapper.test.js +0 -104
  209. package/dist/src/core/googleGenAIWrapper.test.js.map +0 -1
  210. package/dist/src/core/logger.test.d.ts +0 -6
  211. package/dist/src/core/logger.test.js +0 -438
  212. package/dist/src/core/logger.test.js.map +0 -1
  213. package/dist/src/core/nonInteractiveToolExecutor.test.d.ts +0 -6
  214. package/dist/src/core/nonInteractiveToolExecutor.test.js +0 -165
  215. package/dist/src/core/nonInteractiveToolExecutor.test.js.map +0 -1
  216. package/dist/src/core/prompts-async.test.d.ts +0 -6
  217. package/dist/src/core/prompts-async.test.js +0 -115
  218. package/dist/src/core/prompts-async.test.js.map +0 -1
  219. package/dist/src/core/prompts.test.d.ts +0 -6
  220. package/dist/src/core/prompts.test.js +0 -68
  221. package/dist/src/core/prompts.test.js.map +0 -1
  222. package/dist/src/core/subagent.test.d.ts +0 -6
  223. package/dist/src/core/subagent.test.js +0 -519
  224. package/dist/src/core/subagent.test.js.map +0 -1
  225. package/dist/src/core/tokenLimits.test.d.ts +0 -6
  226. package/dist/src/core/tokenLimits.test.js +0 -66
  227. package/dist/src/core/tokenLimits.test.js.map +0 -1
  228. package/dist/src/core/turn.test.d.ts +0 -6
  229. package/dist/src/core/turn.test.js +0 -366
  230. package/dist/src/core/turn.test.js.map +0 -1
  231. package/dist/src/hooks/tool-render-suppression-hook.test.d.ts +0 -6
  232. package/dist/src/hooks/tool-render-suppression-hook.test.js +0 -59
  233. package/dist/src/hooks/tool-render-suppression-hook.test.js.map +0 -1
  234. package/dist/src/ide/ide-installer.test.d.ts +0 -6
  235. package/dist/src/ide/ide-installer.test.js +0 -55
  236. package/dist/src/ide/ide-installer.test.js.map +0 -1
  237. package/dist/src/ide/ideContext.test.d.ts +0 -6
  238. package/dist/src/ide/ideContext.test.js +0 -265
  239. package/dist/src/ide/ideContext.test.js.map +0 -1
  240. package/dist/src/index.test.d.ts +0 -6
  241. package/dist/src/index.test.js +0 -12
  242. package/dist/src/index.test.js.map +0 -1
  243. package/dist/src/integration-tests/todo-system.test.d.ts +0 -6
  244. package/dist/src/integration-tests/todo-system.test.js +0 -46
  245. package/dist/src/integration-tests/todo-system.test.js.map +0 -1
  246. package/dist/src/mcp/google-auth-provider.test.d.ts +0 -6
  247. package/dist/src/mcp/google-auth-provider.test.js +0 -54
  248. package/dist/src/mcp/google-auth-provider.test.js.map +0 -1
  249. package/dist/src/mcp/oauth-provider.test.d.ts +0 -6
  250. package/dist/src/mcp/oauth-provider.test.js +0 -602
  251. package/dist/src/mcp/oauth-provider.test.js.map +0 -1
  252. package/dist/src/mcp/oauth-token-storage.test.d.ts +0 -6
  253. package/dist/src/mcp/oauth-token-storage.test.js +0 -205
  254. package/dist/src/mcp/oauth-token-storage.test.js.map +0 -1
  255. package/dist/src/mcp/oauth-utils.test.d.ts +0 -6
  256. package/dist/src/mcp/oauth-utils.test.js +0 -144
  257. package/dist/src/mcp/oauth-utils.test.js.map +0 -1
  258. package/dist/src/parsers/TextToolCallParser.multibyte.test.d.ts +0 -1
  259. package/dist/src/parsers/TextToolCallParser.multibyte.test.js +0 -42
  260. package/dist/src/parsers/TextToolCallParser.multibyte.test.js.map +0 -1
  261. package/dist/src/parsers/TextToolCallParser.test.d.ts +0 -1
  262. package/dist/src/parsers/TextToolCallParser.test.js +0 -225
  263. package/dist/src/parsers/TextToolCallParser.test.js.map +0 -1
  264. package/dist/src/prompt-config/TemplateEngine.test.d.ts +0 -1
  265. package/dist/src/prompt-config/TemplateEngine.test.js +0 -494
  266. package/dist/src/prompt-config/TemplateEngine.test.js.map +0 -1
  267. package/dist/src/prompt-config/prompt-cache.test.d.ts +0 -6
  268. package/dist/src/prompt-config/prompt-cache.test.js +0 -437
  269. package/dist/src/prompt-config/prompt-cache.test.js.map +0 -1
  270. package/dist/src/prompt-config/prompt-installer.test.d.ts +0 -7
  271. package/dist/src/prompt-config/prompt-installer.test.js +0 -503
  272. package/dist/src/prompt-config/prompt-installer.test.js.map +0 -1
  273. package/dist/src/prompt-config/prompt-loader.test.d.ts +0 -5
  274. package/dist/src/prompt-config/prompt-loader.test.js +0 -413
  275. package/dist/src/prompt-config/prompt-loader.test.js.map +0 -1
  276. package/dist/src/prompt-config/prompt-resolver.test.d.ts +0 -1
  277. package/dist/src/prompt-config/prompt-resolver.test.js +0 -529
  278. package/dist/src/prompt-config/prompt-resolver.test.js.map +0 -1
  279. package/dist/src/prompt-config/prompt-service.test.d.ts +0 -1
  280. package/dist/src/prompt-config/prompt-service.test.js +0 -811
  281. package/dist/src/prompt-config/prompt-service.test.js.map +0 -1
  282. package/dist/src/providers/ProviderManager.gemini-switch.test.d.ts +0 -6
  283. package/dist/src/providers/ProviderManager.gemini-switch.test.js +0 -57
  284. package/dist/src/providers/ProviderManager.gemini-switch.test.js.map +0 -1
  285. package/dist/src/providers/ProviderManager.test.d.ts +0 -6
  286. package/dist/src/providers/ProviderManager.test.js +0 -284
  287. package/dist/src/providers/ProviderManager.test.js.map +0 -1
  288. package/dist/src/providers/adapters/GeminiCompatibleWrapper.test.d.ts +0 -6
  289. package/dist/src/providers/adapters/GeminiCompatibleWrapper.test.js +0 -273
  290. package/dist/src/providers/adapters/GeminiCompatibleWrapper.test.js.map +0 -1
  291. package/dist/src/providers/anthropic/AnthropicProvider.modelParams.test.d.ts +0 -1
  292. package/dist/src/providers/anthropic/AnthropicProvider.modelParams.test.js +0 -48
  293. package/dist/src/providers/anthropic/AnthropicProvider.modelParams.test.js.map +0 -1
  294. package/dist/src/providers/anthropic/AnthropicProvider.test.d.ts +0 -1
  295. package/dist/src/providers/anthropic/AnthropicProvider.test.js +0 -487
  296. package/dist/src/providers/anthropic/AnthropicProvider.test.js.map +0 -1
  297. package/dist/src/providers/gemini/GeminiProvider.integration.test.d.ts +0 -6
  298. package/dist/src/providers/gemini/GeminiProvider.integration.test.js +0 -126
  299. package/dist/src/providers/gemini/GeminiProvider.integration.test.js.map +0 -1
  300. package/dist/src/providers/gemini/GeminiProvider.test.d.ts +0 -6
  301. package/dist/src/providers/gemini/GeminiProvider.test.js +0 -136
  302. package/dist/src/providers/gemini/GeminiProvider.test.js.map +0 -1
  303. package/dist/src/providers/integration/multi-provider.integration.test.d.ts +0 -6
  304. package/dist/src/providers/integration/multi-provider.integration.test.js +0 -292
  305. package/dist/src/providers/integration/multi-provider.integration.test.js.map +0 -1
  306. package/dist/src/providers/openai/ConversationCache.accumTokens.test.d.ts +0 -1
  307. package/dist/src/providers/openai/ConversationCache.accumTokens.test.js +0 -97
  308. package/dist/src/providers/openai/ConversationCache.accumTokens.test.js.map +0 -1
  309. package/dist/src/providers/openai/ConversationCache.test.d.ts +0 -1
  310. package/dist/src/providers/openai/ConversationCache.test.js +0 -113
  311. package/dist/src/providers/openai/ConversationCache.test.js.map +0 -1
  312. package/dist/src/providers/openai/OpenAIProvider.callResponses.stateless.test.d.ts +0 -1
  313. package/dist/src/providers/openai/OpenAIProvider.callResponses.stateless.test.js +0 -189
  314. package/dist/src/providers/openai/OpenAIProvider.callResponses.stateless.test.js.map +0 -1
  315. package/dist/src/providers/openai/OpenAIProvider.integration.test.d.ts +0 -6
  316. package/dist/src/providers/openai/OpenAIProvider.integration.test.js +0 -125
  317. package/dist/src/providers/openai/OpenAIProvider.integration.test.js.map +0 -1
  318. package/dist/src/providers/openai/OpenAIProvider.responses.test.d.ts +0 -1
  319. package/dist/src/providers/openai/OpenAIProvider.responses.test.js +0 -350
  320. package/dist/src/providers/openai/OpenAIProvider.responses.test.js.map +0 -1
  321. package/dist/src/providers/openai/OpenAIProvider.responsesIntegration.test.d.ts +0 -1
  322. package/dist/src/providers/openai/OpenAIProvider.responsesIntegration.test.js +0 -213
  323. package/dist/src/providers/openai/OpenAIProvider.responsesIntegration.test.js.map +0 -1
  324. package/dist/src/providers/openai/OpenAIProvider.shouldUseResponses.test.d.ts +0 -1
  325. package/dist/src/providers/openai/OpenAIProvider.shouldUseResponses.test.js +0 -59
  326. package/dist/src/providers/openai/OpenAIProvider.shouldUseResponses.test.js.map +0 -1
  327. package/dist/src/providers/openai/OpenAIProvider.stateful.integration.test.d.ts +0 -6
  328. package/dist/src/providers/openai/OpenAIProvider.stateful.integration.test.js +0 -105
  329. package/dist/src/providers/openai/OpenAIProvider.stateful.integration.test.js.map +0 -1
  330. package/dist/src/providers/openai/OpenAIProvider.switch.test.d.ts +0 -1
  331. package/dist/src/providers/openai/OpenAIProvider.switch.test.js +0 -256
  332. package/dist/src/providers/openai/OpenAIProvider.switch.test.js.map +0 -1
  333. package/dist/src/providers/openai/OpenAIProvider.test.d.ts +0 -16
  334. package/dist/src/providers/openai/OpenAIProvider.test.js +0 -620
  335. package/dist/src/providers/openai/OpenAIProvider.test.js.map +0 -1
  336. package/dist/src/providers/openai/ResponsesContextTrim.integration.test.d.ts +0 -1
  337. package/dist/src/providers/openai/ResponsesContextTrim.integration.test.js +0 -210
  338. package/dist/src/providers/openai/ResponsesContextTrim.integration.test.js.map +0 -1
  339. package/dist/src/providers/openai/__tests__/formatArrayResponse.test.d.ts +0 -1
  340. package/dist/src/providers/openai/__tests__/formatArrayResponse.test.js +0 -65
  341. package/dist/src/providers/openai/__tests__/formatArrayResponse.test.js.map +0 -1
  342. package/dist/src/providers/openai/buildResponsesRequest.stripToolCalls.test.d.ts +0 -1
  343. package/dist/src/providers/openai/buildResponsesRequest.stripToolCalls.test.js +0 -129
  344. package/dist/src/providers/openai/buildResponsesRequest.stripToolCalls.test.js.map +0 -1
  345. package/dist/src/providers/openai/buildResponsesRequest.test.d.ts +0 -1
  346. package/dist/src/providers/openai/buildResponsesRequest.test.js +0 -406
  347. package/dist/src/providers/openai/buildResponsesRequest.test.js.map +0 -1
  348. package/dist/src/providers/openai/buildResponsesRequest.undefined.test.d.ts +0 -1
  349. package/dist/src/providers/openai/buildResponsesRequest.undefined.test.js +0 -50
  350. package/dist/src/providers/openai/buildResponsesRequest.undefined.test.js.map +0 -1
  351. package/dist/src/providers/openai/estimateRemoteTokens.test.d.ts +0 -1
  352. package/dist/src/providers/openai/estimateRemoteTokens.test.js +0 -125
  353. package/dist/src/providers/openai/estimateRemoteTokens.test.js.map +0 -1
  354. package/dist/src/providers/openai/parseResponsesStream.responsesToolCalls.test.d.ts +0 -1
  355. package/dist/src/providers/openai/parseResponsesStream.responsesToolCalls.test.js +0 -192
  356. package/dist/src/providers/openai/parseResponsesStream.responsesToolCalls.test.js.map +0 -1
  357. package/dist/src/providers/openai/parseResponsesStream.test.d.ts +0 -1
  358. package/dist/src/providers/openai/parseResponsesStream.test.js +0 -151
  359. package/dist/src/providers/openai/parseResponsesStream.test.js.map +0 -1
  360. package/dist/src/services/fileDiscoveryService.test.d.ts +0 -6
  361. package/dist/src/services/fileDiscoveryService.test.js +0 -143
  362. package/dist/src/services/fileDiscoveryService.test.js.map +0 -1
  363. package/dist/src/services/gitService.test.d.ts +0 -6
  364. package/dist/src/services/gitService.test.js +0 -209
  365. package/dist/src/services/gitService.test.js.map +0 -1
  366. package/dist/src/services/loopDetectionService.test.d.ts +0 -6
  367. package/dist/src/services/loopDetectionService.test.js +0 -345
  368. package/dist/src/services/loopDetectionService.test.js.map +0 -1
  369. package/dist/src/services/shellExecutionService.multibyte.test.d.ts +0 -6
  370. package/dist/src/services/shellExecutionService.multibyte.test.js +0 -72
  371. package/dist/src/services/shellExecutionService.multibyte.test.js.map +0 -1
  372. package/dist/src/services/shellExecutionService.test.d.ts +0 -6
  373. package/dist/src/services/shellExecutionService.test.js +0 -272
  374. package/dist/src/services/shellExecutionService.test.js.map +0 -1
  375. package/dist/src/services/shellExecutionService.windows.multibyte.test.d.ts +0 -6
  376. package/dist/src/services/shellExecutionService.windows.multibyte.test.js +0 -98
  377. package/dist/src/services/shellExecutionService.windows.multibyte.test.js.map +0 -1
  378. package/dist/src/services/shellExecutionService.windows.test.d.ts +0 -6
  379. package/dist/src/services/shellExecutionService.windows.test.js +0 -79
  380. package/dist/src/services/shellExecutionService.windows.test.js.map +0 -1
  381. package/dist/src/services/tool-call-tracker-service.test.d.ts +0 -6
  382. package/dist/src/services/tool-call-tracker-service.test.js +0 -99
  383. package/dist/src/services/tool-call-tracker-service.test.js.map +0 -1
  384. package/dist/src/telemetry/loggers.test.d.ts +0 -6
  385. package/dist/src/telemetry/loggers.test.js +0 -572
  386. package/dist/src/telemetry/loggers.test.js.map +0 -1
  387. package/dist/src/telemetry/metrics.test.d.ts +0 -6
  388. package/dist/src/telemetry/metrics.test.js +0 -162
  389. package/dist/src/telemetry/metrics.test.js.map +0 -1
  390. package/dist/src/telemetry/telemetry.test.d.ts +0 -6
  391. package/dist/src/telemetry/telemetry.test.js +0 -54
  392. package/dist/src/telemetry/telemetry.test.js.map +0 -1
  393. package/dist/src/telemetry/uiTelemetry.test.d.ts +0 -6
  394. package/dist/src/telemetry/uiTelemetry.test.js +0 -517
  395. package/dist/src/telemetry/uiTelemetry.test.js.map +0 -1
  396. package/dist/src/tools/ToolFormatter.test.d.ts +0 -16
  397. package/dist/src/tools/ToolFormatter.test.js +0 -349
  398. package/dist/src/tools/ToolFormatter.test.js.map +0 -1
  399. package/dist/src/tools/ToolFormatter.toResponsesTool.test.d.ts +0 -1
  400. package/dist/src/tools/ToolFormatter.toResponsesTool.test.js +0 -241
  401. package/dist/src/tools/ToolFormatter.toResponsesTool.test.js.map +0 -1
  402. package/dist/src/tools/edit.test.d.ts +0 -6
  403. package/dist/src/tools/edit.test.js +0 -663
  404. package/dist/src/tools/edit.test.js.map +0 -1
  405. package/dist/src/tools/glob.test.d.ts +0 -6
  406. package/dist/src/tools/glob.test.js +0 -321
  407. package/dist/src/tools/glob.test.js.map +0 -1
  408. package/dist/src/tools/grep.test.d.ts +0 -6
  409. package/dist/src/tools/grep.test.js +0 -258
  410. package/dist/src/tools/grep.test.js.map +0 -1
  411. package/dist/src/tools/ls.test.d.ts +0 -6
  412. package/dist/src/tools/ls.test.js +0 -357
  413. package/dist/src/tools/ls.test.js.map +0 -1
  414. package/dist/src/tools/mcp-client.test.d.ts +0 -6
  415. package/dist/src/tools/mcp-client.test.js +0 -575
  416. package/dist/src/tools/mcp-client.test.js.map +0 -1
  417. package/dist/src/tools/mcp-tool.test.d.ts +0 -6
  418. package/dist/src/tools/mcp-tool.test.js +0 -501
  419. package/dist/src/tools/mcp-tool.test.js.map +0 -1
  420. package/dist/src/tools/memoryTool.test.d.ts +0 -6
  421. package/dist/src/tools/memoryTool.test.js +0 -266
  422. package/dist/src/tools/memoryTool.test.js.map +0 -1
  423. package/dist/src/tools/modifiable-tool.test.d.ts +0 -6
  424. package/dist/src/tools/modifiable-tool.test.js +0 -193
  425. package/dist/src/tools/modifiable-tool.test.js.map +0 -1
  426. package/dist/src/tools/read-file.test.d.ts +0 -6
  427. package/dist/src/tools/read-file.test.js +0 -313
  428. package/dist/src/tools/read-file.test.js.map +0 -1
  429. package/dist/src/tools/read-many-files.test.d.ts +0 -6
  430. package/dist/src/tools/read-many-files.test.js +0 -644
  431. package/dist/src/tools/read-many-files.test.js.map +0 -1
  432. package/dist/src/tools/shell.multibyte.test.d.ts +0 -6
  433. package/dist/src/tools/shell.multibyte.test.js +0 -75
  434. package/dist/src/tools/shell.multibyte.test.js.map +0 -1
  435. package/dist/src/tools/shell.test.d.ts +0 -6
  436. package/dist/src/tools/shell.test.js +0 -350
  437. package/dist/src/tools/shell.test.js.map +0 -1
  438. package/dist/src/tools/todo-read.test.d.ts +0 -6
  439. package/dist/src/tools/todo-read.test.js +0 -162
  440. package/dist/src/tools/todo-read.test.js.map +0 -1
  441. package/dist/src/tools/todo-schemas.test.d.ts +0 -6
  442. package/dist/src/tools/todo-schemas.test.js +0 -341
  443. package/dist/src/tools/todo-schemas.test.js.map +0 -1
  444. package/dist/src/tools/todo-store.test.d.ts +0 -6
  445. package/dist/src/tools/todo-store.test.js +0 -169
  446. package/dist/src/tools/todo-store.test.js.map +0 -1
  447. package/dist/src/tools/todo-write.test.d.ts +0 -6
  448. package/dist/src/tools/todo-write.test.js +0 -226
  449. package/dist/src/tools/todo-write.test.js.map +0 -1
  450. package/dist/src/tools/tool-registry.test.d.ts +0 -6
  451. package/dist/src/tools/tool-registry.test.js +0 -468
  452. package/dist/src/tools/tool-registry.test.js.map +0 -1
  453. package/dist/src/tools/tools.test.d.ts +0 -6
  454. package/dist/src/tools/tools.test.js +0 -117
  455. package/dist/src/tools/tools.test.js.map +0 -1
  456. package/dist/src/tools/web-fetch.integration.test.d.ts +0 -6
  457. package/dist/src/tools/web-fetch.integration.test.js +0 -532
  458. package/dist/src/tools/web-fetch.integration.test.js.map +0 -1
  459. package/dist/src/tools/web-search.test.d.ts +0 -6
  460. package/dist/src/tools/web-search.test.js +0 -229
  461. package/dist/src/tools/web-search.test.js.map +0 -1
  462. package/dist/src/tools/write-file.test.d.ts +0 -6
  463. package/dist/src/tools/write-file.test.js +0 -464
  464. package/dist/src/tools/write-file.test.js.map +0 -1
  465. package/dist/src/utils/bfsFileSearch.test.d.ts +0 -6
  466. package/dist/src/utils/bfsFileSearch.test.js +0 -191
  467. package/dist/src/utils/bfsFileSearch.test.js.map +0 -1
  468. package/dist/src/utils/editCorrector.test.d.ts +0 -6
  469. package/dist/src/utils/editCorrector.test.js +0 -564
  470. package/dist/src/utils/editCorrector.test.js.map +0 -1
  471. package/dist/src/utils/editor.test.d.ts +0 -6
  472. package/dist/src/utils/editor.test.js +0 -445
  473. package/dist/src/utils/editor.test.js.map +0 -1
  474. package/dist/src/utils/environmentContext.test.d.ts +0 -6
  475. package/dist/src/utils/environmentContext.test.js +0 -139
  476. package/dist/src/utils/environmentContext.test.js.map +0 -1
  477. package/dist/src/utils/errorReporting.test.d.ts +0 -6
  478. package/dist/src/utils/errorReporting.test.js +0 -130
  479. package/dist/src/utils/errorReporting.test.js.map +0 -1
  480. package/dist/src/utils/fileUtils.test.d.ts +0 -6
  481. package/dist/src/utils/fileUtils.test.js +0 -363
  482. package/dist/src/utils/fileUtils.test.js.map +0 -1
  483. package/dist/src/utils/filesearch/crawlCache.test.d.ts +0 -6
  484. package/dist/src/utils/filesearch/crawlCache.test.js +0 -103
  485. package/dist/src/utils/filesearch/crawlCache.test.js.map +0 -1
  486. package/dist/src/utils/filesearch/fileSearch.test.d.ts +0 -6
  487. package/dist/src/utils/filesearch/fileSearch.test.js +0 -654
  488. package/dist/src/utils/filesearch/fileSearch.test.js.map +0 -1
  489. package/dist/src/utils/filesearch/ignore.test.d.ts +0 -6
  490. package/dist/src/utils/filesearch/ignore.test.js +0 -57
  491. package/dist/src/utils/filesearch/ignore.test.js.map +0 -1
  492. package/dist/src/utils/filesearch/result-cache.test.d.ts +0 -6
  493. package/dist/src/utils/filesearch/result-cache.test.js +0 -47
  494. package/dist/src/utils/filesearch/result-cache.test.js.map +0 -1
  495. package/dist/src/utils/flashFallback.integration.test.d.ts +0 -6
  496. package/dist/src/utils/flashFallback.integration.test.js +0 -120
  497. package/dist/src/utils/flashFallback.integration.test.js.map +0 -1
  498. package/dist/src/utils/generateContentResponseUtilities.test.d.ts +0 -6
  499. package/dist/src/utils/generateContentResponseUtilities.test.js +0 -273
  500. package/dist/src/utils/generateContentResponseUtilities.test.js.map +0 -1
  501. package/dist/src/utils/getFolderStructure.test.d.ts +0 -6
  502. package/dist/src/utils/getFolderStructure.test.js +0 -282
  503. package/dist/src/utils/getFolderStructure.test.js.map +0 -1
  504. package/dist/src/utils/gitIgnoreParser.test.d.ts +0 -6
  505. package/dist/src/utils/gitIgnoreParser.test.js +0 -154
  506. package/dist/src/utils/gitIgnoreParser.test.js.map +0 -1
  507. package/dist/src/utils/memoryDiscovery.test.d.ts +0 -6
  508. package/dist/src/utils/memoryDiscovery.test.js +0 -181
  509. package/dist/src/utils/memoryDiscovery.test.js.map +0 -1
  510. package/dist/src/utils/memoryImportProcessor.test.d.ts +0 -6
  511. package/dist/src/utils/memoryImportProcessor.test.js +0 -715
  512. package/dist/src/utils/memoryImportProcessor.test.js.map +0 -1
  513. package/dist/src/utils/nextSpeakerChecker.test.d.ts +0 -6
  514. package/dist/src/utils/nextSpeakerChecker.test.js +0 -172
  515. package/dist/src/utils/nextSpeakerChecker.test.js.map +0 -1
  516. package/dist/src/utils/partUtils.test.d.ts +0 -6
  517. package/dist/src/utils/partUtils.test.js +0 -130
  518. package/dist/src/utils/partUtils.test.js.map +0 -1
  519. package/dist/src/utils/paths.test.d.ts +0 -6
  520. package/dist/src/utils/paths.test.js +0 -153
  521. package/dist/src/utils/paths.test.js.map +0 -1
  522. package/dist/src/utils/retry.test.d.ts +0 -6
  523. package/dist/src/utils/retry.test.js +0 -322
  524. package/dist/src/utils/retry.test.js.map +0 -1
  525. package/dist/src/utils/safeJsonStringify.test.d.ts +0 -6
  526. package/dist/src/utils/safeJsonStringify.test.js +0 -61
  527. package/dist/src/utils/safeJsonStringify.test.js.map +0 -1
  528. package/dist/src/utils/sanitization.test.d.ts +0 -6
  529. package/dist/src/utils/sanitization.test.js +0 -81
  530. package/dist/src/utils/sanitization.test.js.map +0 -1
  531. package/dist/src/utils/schemaValidator.test.d.ts +0 -6
  532. package/dist/src/utils/schemaValidator.test.js +0 -146
  533. package/dist/src/utils/schemaValidator.test.js.map +0 -1
  534. package/dist/src/utils/secure-browser-launcher.test.d.ts +0 -6
  535. package/dist/src/utils/secure-browser-launcher.test.js +0 -149
  536. package/dist/src/utils/secure-browser-launcher.test.js.map +0 -1
  537. package/dist/src/utils/shell-utils.shellReplacement.test.d.ts +0 -6
  538. package/dist/src/utils/shell-utils.shellReplacement.test.js +0 -149
  539. package/dist/src/utils/shell-utils.shellReplacement.test.js.map +0 -1
  540. package/dist/src/utils/shell-utils.test.d.ts +0 -6
  541. package/dist/src/utils/shell-utils.test.js +0 -200
  542. package/dist/src/utils/shell-utils.test.js.map +0 -1
  543. package/dist/src/utils/summarizer.test.d.ts +0 -6
  544. package/dist/src/utils/summarizer.test.js +0 -131
  545. package/dist/src/utils/summarizer.test.js.map +0 -1
  546. package/dist/src/utils/systemEncoding.test.d.ts +0 -6
  547. package/dist/src/utils/systemEncoding.test.js +0 -368
  548. package/dist/src/utils/systemEncoding.test.js.map +0 -1
  549. package/dist/src/utils/toolOutputLimiter.test.d.ts +0 -6
  550. package/dist/src/utils/toolOutputLimiter.test.js +0 -164
  551. package/dist/src/utils/toolOutputLimiter.test.js.map +0 -1
  552. package/dist/src/utils/unicodeUtils.test.d.ts +0 -6
  553. package/dist/src/utils/unicodeUtils.test.js +0 -120
  554. package/dist/src/utils/unicodeUtils.test.js.map +0 -1
  555. package/dist/src/utils/user_account.test.d.ts +0 -6
  556. package/dist/src/utils/user_account.test.js +0 -153
  557. package/dist/src/utils/user_account.test.js.map +0 -1
  558. package/dist/src/utils/user_id.test.d.ts +0 -6
  559. package/dist/src/utils/user_id.test.js +0 -21
  560. package/dist/src/utils/user_id.test.js.map +0 -1
  561. package/dist/src/utils/workspaceContext.test.d.ts +0 -6
  562. package/dist/src/utils/workspaceContext.test.js +0 -209
  563. package/dist/src/utils/workspaceContext.test.js.map +0 -1
@@ -1,1317 +0,0 @@
1
- /**
2
- * @license
3
- * Copyright 2025 Google LLC
4
- * SPDX-License-Identifier: Apache-2.0
5
- */
6
- import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
7
- // Mock prompts module before imports
8
- vi.mock('./prompts.js', () => ({
9
- getCoreSystemPromptAsync: vi
10
- .fn()
11
- .mockResolvedValue('Test system instruction'),
12
- getCompressionPrompt: vi.fn().mockReturnValue('Test compression prompt'),
13
- initializePromptSystem: vi.fn().mockResolvedValue(undefined),
14
- }));
15
- import { GoogleGenAI, } from '@google/genai';
16
- import { findIndexAfterFraction, GeminiClient } from './client.js';
17
- import { getCoreSystemPromptAsync } from './prompts.js';
18
- import { AuthType, } from './contentGenerator.js';
19
- import { Config } from '../config/config.js';
20
- import { GeminiEventType, Turn } from './turn.js';
21
- import { DEFAULT_GEMINI_FLASH_MODEL } from '../config/models.js';
22
- import { FileDiscoveryService } from '../services/fileDiscoveryService.js';
23
- import { setSimulate429 } from '../utils/testUtils.js';
24
- import { tokenLimit } from './tokenLimits.js';
25
- import { ideContext } from '../ide/ideContext.js';
26
- import { ComplexityAnalyzer } from '../services/complexity-analyzer.js';
27
- import { TodoReminderService } from '../services/todo-reminder-service.js';
28
- // --- Mocks ---
29
- const mockChatCreateFn = vi.fn();
30
- const mockGenerateContentFn = vi.fn();
31
- const mockEmbedContentFn = vi.fn();
32
- const mockTurnRunFn = vi.fn();
33
- vi.mock('@google/genai');
34
- vi.mock('../services/complexity-analyzer.js', () => ({
35
- ComplexityAnalyzer: vi.fn().mockImplementation(() => ({
36
- analyzeComplexity: vi.fn().mockReturnValue({
37
- complexityScore: 0.2,
38
- isComplex: false,
39
- detectedTasks: [],
40
- sequentialIndicators: [],
41
- questionCount: 0,
42
- shouldSuggestTodos: false,
43
- }),
44
- })),
45
- }));
46
- vi.mock('../services/todo-reminder-service.js', () => ({
47
- TodoReminderService: vi.fn().mockImplementation(() => ({
48
- getComplexTaskSuggestion: vi.fn(),
49
- })),
50
- }));
51
- vi.mock('./turn', () => {
52
- // Define a mock class that has the same shape as the real Turn
53
- class MockTurn {
54
- pendingToolCalls = [];
55
- // The run method is a property that holds our mock function
56
- run = mockTurnRunFn;
57
- constructor() {
58
- // The constructor can be empty or do some mock setup
59
- }
60
- }
61
- // Export the mock class as 'Turn'
62
- return {
63
- Turn: MockTurn,
64
- GeminiEventType: {
65
- MaxSessionTurns: 'MaxSessionTurns',
66
- ChatCompressed: 'ChatCompressed',
67
- },
68
- };
69
- });
70
- vi.mock('../config/config.js');
71
- vi.mock('../utils/getFolderStructure', () => ({
72
- getFolderStructure: vi.fn().mockResolvedValue('Mock Folder Structure'),
73
- }));
74
- vi.mock('../utils/errorReporting', () => ({ reportError: vi.fn() }));
75
- vi.mock('../utils/generateContentResponseUtilities', () => ({
76
- getResponseText: (result) => result.candidates?.[0]?.content?.parts?.map((part) => part.text).join('') ||
77
- undefined,
78
- }));
79
- vi.mock('../telemetry/index.js', () => ({
80
- logApiRequest: vi.fn(),
81
- logApiResponse: vi.fn(),
82
- logApiError: vi.fn(),
83
- }));
84
- vi.mock('../utils/retry.js', () => ({
85
- retryWithBackoff: vi.fn((apiCall) => apiCall()),
86
- }));
87
- vi.mock('../ide/ideContext.js');
88
- describe('findIndexAfterFraction', () => {
89
- const history = [
90
- { role: 'user', parts: [{ text: 'This is the first message.' }] }, // JSON length: 66
91
- { role: 'model', parts: [{ text: 'This is the second message.' }] }, // JSON length: 68
92
- { role: 'user', parts: [{ text: 'This is the third message.' }] }, // JSON length: 66
93
- { role: 'model', parts: [{ text: 'This is the fourth message.' }] }, // JSON length: 68
94
- { role: 'user', parts: [{ text: 'This is the fifth message.' }] }, // JSON length: 65
95
- ];
96
- // Total length: 333
97
- it('should throw an error for non-positive numbers', () => {
98
- expect(() => findIndexAfterFraction(history, 0)).toThrow('Fraction must be between 0 and 1');
99
- });
100
- it('should throw an error for a fraction greater than or equal to 1', () => {
101
- expect(() => findIndexAfterFraction(history, 1)).toThrow('Fraction must be between 0 and 1');
102
- });
103
- it('should handle a fraction in the middle', () => {
104
- // 333 * 0.5 = 166.5
105
- // 0: 66
106
- // 1: 66 + 68 = 134
107
- // 2: 134 + 66 = 200
108
- // 200 >= 166.5, so index is 2
109
- expect(findIndexAfterFraction(history, 0.5)).toBe(2);
110
- });
111
- it('should handle a fraction that results in the last index', () => {
112
- // 333 * 0.9 = 299.7
113
- // ...
114
- // 3: 200 + 68 = 268
115
- // 4: 268 + 65 = 333
116
- // 333 >= 299.7, so index is 4
117
- expect(findIndexAfterFraction(history, 0.9)).toBe(4);
118
- });
119
- it('should handle an empty history', () => {
120
- expect(findIndexAfterFraction([], 0.5)).toBe(0);
121
- });
122
- it('should handle a history with only one item', () => {
123
- expect(findIndexAfterFraction(history.slice(0, 1), 0.5)).toBe(0);
124
- });
125
- it('should handle history with weird parts', () => {
126
- const historyWithEmptyParts = [
127
- { role: 'user', parts: [{ text: 'Message 1' }] },
128
- { role: 'model', parts: [{ fileData: { fileUri: 'derp' } }] },
129
- { role: 'user', parts: [{ text: 'Message 2' }] },
130
- ];
131
- expect(findIndexAfterFraction(historyWithEmptyParts, 0.5)).toBe(1);
132
- });
133
- });
134
- describe('Gemini Client (client.ts)', () => {
135
- let client;
136
- beforeEach(async () => {
137
- vi.resetAllMocks();
138
- // Re-setup prompts mocks after reset
139
- vi.mocked(getCoreSystemPromptAsync).mockResolvedValue('Test system instruction');
140
- // Re-setup mocks after reset
141
- vi.mocked(ComplexityAnalyzer).mockImplementation(() => ({
142
- analyzeComplexity: vi.fn().mockReturnValue({
143
- complexityScore: 0.2,
144
- isComplex: false,
145
- detectedTasks: [],
146
- sequentialIndicators: [],
147
- questionCount: 0,
148
- shouldSuggestTodos: false,
149
- }),
150
- }));
151
- vi.mocked(TodoReminderService).mockImplementation(() => ({
152
- getComplexTaskSuggestion: vi.fn(),
153
- }));
154
- // Disable 429 simulation for tests
155
- setSimulate429(false);
156
- // Set up the mock for GoogleGenAI constructor and its methods
157
- const MockedGoogleGenAI = vi.mocked(GoogleGenAI);
158
- MockedGoogleGenAI.mockImplementation((..._args) => {
159
- const mockInstance = {
160
- chats: { create: mockChatCreateFn },
161
- models: {
162
- generateContent: mockGenerateContentFn,
163
- embedContent: mockEmbedContentFn,
164
- },
165
- };
166
- return mockInstance;
167
- });
168
- mockChatCreateFn.mockResolvedValue({});
169
- mockGenerateContentFn.mockResolvedValue({
170
- candidates: [
171
- {
172
- content: {
173
- parts: [{ text: '{"key": "value"}' }],
174
- },
175
- },
176
- ],
177
- });
178
- // Because the GeminiClient constructor kicks off an async process (startChat)
179
- // that depends on a fully-formed Config object, we need to mock the
180
- // entire implementation of Config for these tests.
181
- const mockToolRegistry = {
182
- getFunctionDeclarations: vi.fn().mockReturnValue([]),
183
- getTool: vi.fn().mockReturnValue(null),
184
- };
185
- const fileService = new FileDiscoveryService('/test/dir');
186
- const MockedConfig = vi.mocked(Config, true);
187
- const contentGeneratorConfig = {
188
- model: 'test-model',
189
- apiKey: 'test-key',
190
- vertexai: false,
191
- authType: AuthType.USE_GEMINI,
192
- };
193
- const mockConfigObject = {
194
- getContentGeneratorConfig: vi
195
- .fn()
196
- .mockReturnValue(contentGeneratorConfig),
197
- getToolRegistry: vi.fn().mockResolvedValue(mockToolRegistry),
198
- getModel: vi.fn().mockReturnValue('test-model'),
199
- getEmbeddingModel: vi.fn().mockReturnValue('test-embedding-model'),
200
- getApiKey: vi.fn().mockReturnValue('test-key'),
201
- getVertexAI: vi.fn().mockReturnValue(false),
202
- getUserAgent: vi.fn().mockReturnValue('test-agent'),
203
- getUserMemory: vi.fn().mockReturnValue(''),
204
- getFullContext: vi.fn().mockReturnValue(false),
205
- getSessionId: vi.fn().mockReturnValue('test-session-id'),
206
- getProxy: vi.fn().mockReturnValue(undefined),
207
- getWorkingDir: vi.fn().mockReturnValue('/test/dir'),
208
- getFileService: vi.fn().mockReturnValue(fileService),
209
- getMaxSessionTurns: vi.fn().mockReturnValue(0),
210
- getQuotaErrorOccurred: vi.fn().mockReturnValue(false),
211
- setQuotaErrorOccurred: vi.fn(),
212
- getNoBrowser: vi.fn().mockReturnValue(false),
213
- getUsageStatisticsEnabled: vi.fn().mockReturnValue(true),
214
- getIdeModeFeature: vi.fn().mockReturnValue(false),
215
- getIdeMode: vi.fn().mockReturnValue(true),
216
- getWorkspaceContext: vi.fn().mockReturnValue({
217
- getDirectories: vi.fn().mockReturnValue(['/test/dir']),
218
- }),
219
- getGeminiClient: vi.fn(),
220
- getDebugMode: vi.fn().mockReturnValue(false),
221
- setFallbackMode: vi.fn(),
222
- getComplexityAnalyzerSettings: vi.fn().mockReturnValue({
223
- complexityThreshold: 0.6,
224
- minTasksForSuggestion: 3,
225
- suggestionCooldownMs: 300000,
226
- }),
227
- };
228
- MockedConfig.mockImplementation(() => mockConfigObject);
229
- // We can instantiate the client here since Config is mocked
230
- // and the constructor will use the mocked GoogleGenAI
231
- const mockConfig = new Config({
232
- sessionId: 'test-session-id',
233
- });
234
- client = new GeminiClient(mockConfig);
235
- await client.initialize(contentGeneratorConfig);
236
- // Update the mock to return the client
237
- mockConfigObject.getGeminiClient.mockReturnValue(client);
238
- // Add missing methods to the client instance for tests
239
- client.getHistory = vi.fn().mockReturnValue([]);
240
- });
241
- afterEach(() => {
242
- vi.restoreAllMocks();
243
- });
244
- // NOTE: The following tests for startChat were removed due to persistent issues with
245
- // the @google/genai mock. Specifically, the mockChatCreateFn (representing instance.chats.create)
246
- // was not being detected as called by the GeminiClient instance.
247
- // This likely points to a subtle issue in how the GoogleGenerativeAI class constructor
248
- // and its instance methods are mocked and then used by the class under test.
249
- // For future debugging, ensure that the `this.client` in `GeminiClient` (which is an
250
- // instance of the mocked GoogleGenerativeAI) correctly has its `chats.create` method
251
- // pointing to `mockChatCreateFn`.
252
- // it('startChat should call getCoreSystemPrompt with userMemory and pass to chats.create', async () => { ... });
253
- // it('startChat should call getCoreSystemPrompt with empty string if userMemory is empty', async () => { ... });
254
- // NOTE: The following tests for generateJson were removed due to persistent issues with
255
- // the @google/genai mock, similar to the startChat tests. The mockGenerateContentFn
256
- // (representing instance.models.generateContent) was not being detected as called, or the mock
257
- // was not preventing an actual API call (leading to API key errors).
258
- // For future debugging, ensure `this.client.models.generateContent` in `GeminiClient` correctly
259
- // uses the `mockGenerateContentFn`.
260
- // it('generateJson should call getCoreSystemPrompt with userMemory and pass to generateContent', async () => { ... });
261
- // it('generateJson should call getCoreSystemPrompt with empty string if userMemory is empty', async () => { ... });
262
- describe('generateEmbedding', () => {
263
- const texts = ['hello world', 'goodbye world'];
264
- const testEmbeddingModel = 'test-embedding-model';
265
- it('should call embedContent with correct parameters and return embeddings', async () => {
266
- const mockEmbeddings = [
267
- [0.1, 0.2, 0.3],
268
- [0.4, 0.5, 0.6],
269
- ];
270
- const mockResponse = {
271
- embeddings: [
272
- { values: mockEmbeddings[0] },
273
- { values: mockEmbeddings[1] },
274
- ],
275
- };
276
- mockEmbedContentFn.mockResolvedValue(mockResponse);
277
- const result = await client.generateEmbedding(texts);
278
- expect(mockEmbedContentFn).toHaveBeenCalledTimes(1);
279
- expect(mockEmbedContentFn).toHaveBeenCalledWith({
280
- model: testEmbeddingModel,
281
- contents: texts,
282
- });
283
- expect(result).toEqual(mockEmbeddings);
284
- });
285
- it('should return an empty array if an empty array is passed', async () => {
286
- const result = await client.generateEmbedding([]);
287
- expect(result).toEqual([]);
288
- expect(mockEmbedContentFn).not.toHaveBeenCalled();
289
- });
290
- it('should throw an error if API response has no embeddings array', async () => {
291
- mockEmbedContentFn.mockResolvedValue({}); // No `embeddings` key
292
- await expect(client.generateEmbedding(texts)).rejects.toThrow('No embeddings found in API response.');
293
- });
294
- it('should throw an error if API response has an empty embeddings array', async () => {
295
- const mockResponse = {
296
- embeddings: [],
297
- };
298
- mockEmbedContentFn.mockResolvedValue(mockResponse);
299
- await expect(client.generateEmbedding(texts)).rejects.toThrow('No embeddings found in API response.');
300
- });
301
- it('should throw an error if API returns a mismatched number of embeddings', async () => {
302
- const mockResponse = {
303
- embeddings: [{ values: [1, 2, 3] }], // Only one for two texts
304
- };
305
- mockEmbedContentFn.mockResolvedValue(mockResponse);
306
- await expect(client.generateEmbedding(texts)).rejects.toThrow('API returned a mismatched number of embeddings. Expected 2, got 1.');
307
- });
308
- it('should throw an error if any embedding has nullish values', async () => {
309
- const mockResponse = {
310
- embeddings: [{ values: [1, 2, 3] }, { values: undefined }], // Second one is bad
311
- };
312
- mockEmbedContentFn.mockResolvedValue(mockResponse);
313
- await expect(client.generateEmbedding(texts)).rejects.toThrow('API returned an empty embedding for input text at index 1: "goodbye world"');
314
- });
315
- it('should throw an error if any embedding has an empty values array', async () => {
316
- const mockResponse = {
317
- embeddings: [{ values: [] }, { values: [1, 2, 3] }], // First one is bad
318
- };
319
- mockEmbedContentFn.mockResolvedValue(mockResponse);
320
- await expect(client.generateEmbedding(texts)).rejects.toThrow('API returned an empty embedding for input text at index 0: "hello world"');
321
- });
322
- it('should propagate errors from the API call', async () => {
323
- const apiError = new Error('API Failure');
324
- mockEmbedContentFn.mockRejectedValue(apiError);
325
- await expect(client.generateEmbedding(texts)).rejects.toThrow('API Failure');
326
- });
327
- });
328
- describe('generateContent', () => {
329
- it('should call generateContent with the correct parameters', async () => {
330
- const contents = [{ role: 'user', parts: [{ text: 'hello' }] }];
331
- const generationConfig = { temperature: 0.5 };
332
- const abortSignal = new AbortController().signal;
333
- // Mock the retryWithBackoff to directly call the apiCall function
334
- vi.mock('../utils/retry.js', () => ({
335
- retryWithBackoff: vi.fn((apiCall) => apiCall()),
336
- }));
337
- // Mock countTokens with a fresh mock function
338
- const mockContentGeneratorGenerateContent = vi.fn().mockResolvedValue({
339
- candidates: [
340
- {
341
- content: {
342
- parts: [{ text: 'response' }],
343
- },
344
- },
345
- ],
346
- });
347
- const mockGenerator = {
348
- countTokens: vi.fn().mockResolvedValue({ totalTokens: 1 }),
349
- generateContent: mockContentGeneratorGenerateContent,
350
- generateContentStream: vi.fn(),
351
- embedContent: vi.fn(),
352
- };
353
- client['contentGenerator'] = mockGenerator;
354
- client['isInitialized'] = vi.fn().mockReturnValue(true);
355
- const { retryWithBackoff } = await import('../utils/retry.js');
356
- vi.mocked(retryWithBackoff).mockImplementation(async (apiCall) => await apiCall());
357
- await client.generateContent(contents, generationConfig, abortSignal);
358
- expect(mockContentGeneratorGenerateContent).toHaveBeenCalledWith({
359
- model: 'test-model',
360
- config: {
361
- abortSignal,
362
- systemInstruction: 'Test system instruction',
363
- temperature: 0.5,
364
- topP: 1,
365
- },
366
- contents,
367
- }, 'test-session-id');
368
- });
369
- });
370
- describe('generateJson', () => {
371
- it('should call generateContent with the correct parameters', async () => {
372
- const contents = [{ role: 'user', parts: [{ text: 'hello' }] }];
373
- const schema = { type: 'string' };
374
- const abortSignal = new AbortController().signal;
375
- // Mock lazyInitialize to prevent it from overriding our mock
376
- client['lazyInitialize'] = vi.fn().mockResolvedValue(undefined);
377
- // Track the arguments manually
378
- let capturedRequest;
379
- let capturedPromptId;
380
- const mockGenerator = {
381
- countTokens: vi.fn().mockResolvedValue({ totalTokens: 1 }),
382
- generateContent: vi.fn(async (request, promptId) => {
383
- capturedRequest = request;
384
- capturedPromptId = promptId;
385
- return {
386
- candidates: [
387
- {
388
- content: {
389
- parts: [{ text: '{"key": "value"}' }],
390
- },
391
- },
392
- ],
393
- };
394
- }),
395
- generateContentStream: vi.fn(),
396
- embedContent: vi.fn(),
397
- };
398
- client['contentGenerator'] = mockGenerator;
399
- try {
400
- await client.generateJson(contents, schema, abortSignal);
401
- }
402
- catch (error) {
403
- console.error('Error in generateJson:', error);
404
- throw error;
405
- }
406
- // Check the captured arguments
407
- expect(capturedRequest).toBeDefined();
408
- expect(capturedPromptId).toBe('test-session-id');
409
- expect(capturedRequest).toMatchObject({
410
- model: 'test-model', // Should use current model from config
411
- config: {
412
- abortSignal,
413
- systemInstruction: 'Test system instruction',
414
- temperature: 0,
415
- topP: 1,
416
- responseSchema: schema,
417
- responseMimeType: 'application/json',
418
- },
419
- contents,
420
- });
421
- });
422
- it('should allow overriding model and config', async () => {
423
- const contents = [{ role: 'user', parts: [{ text: 'hello' }] }];
424
- const schema = { type: 'string' };
425
- const abortSignal = new AbortController().signal;
426
- const customModel = 'custom-json-model';
427
- const customConfig = { temperature: 0.9, topK: 20 };
428
- // Mock lazyInitialize to prevent it from overriding our mock
429
- client['lazyInitialize'] = vi.fn().mockResolvedValue(undefined);
430
- // Track the arguments manually
431
- let capturedRequest;
432
- let capturedPromptId;
433
- const mockGenerator = {
434
- countTokens: vi.fn().mockResolvedValue({ totalTokens: 1 }),
435
- generateContent: vi.fn(async (request, promptId) => {
436
- capturedRequest = request;
437
- capturedPromptId = promptId;
438
- return {
439
- candidates: [
440
- {
441
- content: {
442
- parts: [{ text: '{"key": "value"}' }],
443
- },
444
- },
445
- ],
446
- };
447
- }),
448
- };
449
- client['contentGenerator'] = mockGenerator;
450
- await client.generateJson(contents, schema, abortSignal, customModel, customConfig);
451
- // Check the captured arguments
452
- expect(capturedRequest).toBeDefined();
453
- expect(capturedPromptId).toBe('test-session-id');
454
- expect(capturedRequest).toMatchObject({
455
- model: customModel,
456
- config: {
457
- abortSignal,
458
- systemInstruction: 'Test system instruction',
459
- temperature: 0.9,
460
- topP: 1, // from default
461
- topK: 20,
462
- responseSchema: schema,
463
- responseMimeType: 'application/json',
464
- },
465
- contents,
466
- });
467
- });
468
- });
469
- describe('addHistory', () => {
470
- it('should call chat.addHistory with the provided content', async () => {
471
- const mockChat = {
472
- addHistory: vi.fn(),
473
- };
474
- client['chat'] = mockChat;
475
- const newContent = {
476
- role: 'user',
477
- parts: [{ text: 'New history item' }],
478
- };
479
- await client.addHistory(newContent);
480
- expect(mockChat.addHistory).toHaveBeenCalledWith(newContent);
481
- });
482
- });
483
- describe('resetChat', () => {
484
- it('should create a new chat session, clearing the old history', async () => {
485
- // Create mock chats with distinct histories
486
- const initialChatHistory = [
487
- { role: 'user', parts: [{ text: 'initial context' }] },
488
- { role: 'model', parts: [{ text: 'acknowledged' }] },
489
- ];
490
- const mockInitialChat = {
491
- getHistory: vi.fn().mockReturnValue(initialChatHistory),
492
- addHistory: vi.fn().mockImplementation((content) => {
493
- // Update the history when addHistory is called
494
- initialChatHistory.push(content);
495
- }),
496
- setHistory: vi.fn(),
497
- };
498
- const mockNewChat = {
499
- getHistory: vi.fn().mockReturnValue([
500
- { role: 'user', parts: [{ text: 'fresh start' }] },
501
- { role: 'model', parts: [{ text: 'ready' }] },
502
- ]),
503
- addHistory: vi.fn(),
504
- setHistory: vi.fn(),
505
- };
506
- // Mock startChat to return the new chat when called
507
- const mockStartChat = vi.fn().mockResolvedValue(mockNewChat);
508
- client['startChat'] = mockStartChat;
509
- client['chat'] = mockInitialChat;
510
- // Mock that client is initialized
511
- client['contentGenerator'] = {};
512
- client['isInitialized'] = vi.fn().mockReturnValue(true);
513
- // Override the global getHistory mock for this test
514
- const getHistoryMock = vi.mocked(client.getHistory);
515
- getHistoryMock.mockImplementation(async () => client.getChat().getHistory());
516
- // 1. Get the initial chat instance and verify initial state
517
- const initialChat = client.getChat();
518
- expect(initialChat).toBe(mockInitialChat);
519
- const initialHistory = await client.getHistory();
520
- expect(initialHistory).toHaveLength(2); // initial context + acknowledged
521
- // Add a message to the initial chat
522
- await client.addHistory({
523
- role: 'user',
524
- parts: [{ text: 'some old message' }],
525
- });
526
- const historyWithOldMessage = await client.getHistory();
527
- expect(historyWithOldMessage).toHaveLength(3);
528
- expect(JSON.stringify(historyWithOldMessage)).toContain('some old message');
529
- // 2. Call resetChat
530
- await client.resetChat();
531
- // 3. Verify the chat was replaced
532
- const newChat = client.getChat();
533
- expect(mockStartChat).toHaveBeenCalledTimes(1);
534
- expect(client['chat']).toBe(mockNewChat);
535
- expect(newChat).toBe(mockNewChat);
536
- expect(newChat).not.toBe(initialChat);
537
- // 4. Verify the history is from the new chat
538
- const newHistory = await client.getHistory();
539
- expect(newHistory).toHaveLength(2); // fresh start + ready
540
- expect(JSON.stringify(newHistory)).not.toContain('some old message');
541
- expect(JSON.stringify(newHistory)).toContain('fresh start');
542
- });
543
- });
544
- describe('tryCompressChat', () => {
545
- const mockCountTokens = vi.fn();
546
- const mockSendMessage = vi.fn();
547
- const mockGetHistory = vi.fn();
548
- beforeEach(() => {
549
- vi.mock('./tokenLimits', () => ({
550
- tokenLimit: vi.fn(),
551
- }));
552
- client['contentGenerator'] = {
553
- countTokens: mockCountTokens,
554
- };
555
- client['chat'] = {
556
- getHistory: mockGetHistory,
557
- addHistory: vi.fn(),
558
- setHistory: vi.fn(),
559
- sendMessage: mockSendMessage,
560
- };
561
- });
562
- it('should not trigger summarization if token count is below threshold', async () => {
563
- const MOCKED_TOKEN_LIMIT = 1000;
564
- vi.mocked(tokenLimit).mockReturnValue(MOCKED_TOKEN_LIMIT);
565
- mockGetHistory.mockReturnValue([
566
- { role: 'user', parts: [{ text: '...history...' }] },
567
- ]);
568
- mockCountTokens.mockResolvedValue({
569
- totalTokens: MOCKED_TOKEN_LIMIT * 0.699, // TOKEN_THRESHOLD_FOR_SUMMARIZATION = 0.7
570
- });
571
- const initialChat = client.getChat();
572
- const result = await client.tryCompressChat('prompt-id-2');
573
- const newChat = client.getChat();
574
- expect(tokenLimit).toHaveBeenCalled();
575
- expect(result).toBeNull();
576
- expect(newChat).toBe(initialChat);
577
- });
578
- it('should trigger summarization if token count is at threshold', async () => {
579
- const MOCKED_TOKEN_LIMIT = 1000;
580
- vi.mocked(tokenLimit).mockReturnValue(MOCKED_TOKEN_LIMIT);
581
- mockGetHistory.mockReturnValue([
582
- { role: 'user', parts: [{ text: '...history...' }] },
583
- ]);
584
- const originalTokenCount = 1000 * 0.7;
585
- const newTokenCount = 100;
586
- mockCountTokens
587
- .mockResolvedValueOnce({ totalTokens: originalTokenCount }) // First call for the check
588
- .mockResolvedValueOnce({ totalTokens: newTokenCount }); // Second call for the new history
589
- // Mock the summary response from the chat
590
- mockSendMessage.mockResolvedValue({
591
- role: 'model',
592
- parts: [{ text: 'This is a summary.' }],
593
- });
594
- const initialChat = client.getChat();
595
- const result = await client.tryCompressChat('prompt-id-3');
596
- const newChat = client.getChat();
597
- expect(tokenLimit).toHaveBeenCalled();
598
- expect(mockSendMessage).toHaveBeenCalled();
599
- // Assert that summarization happened and returned the correct stats
600
- expect(result).toEqual({
601
- originalTokenCount,
602
- newTokenCount,
603
- });
604
- // Assert that the chat was reset
605
- expect(newChat).not.toBe(initialChat);
606
- });
607
- it('should not compress across a function call response', async () => {
608
- const MOCKED_TOKEN_LIMIT = 1000;
609
- vi.mocked(tokenLimit).mockReturnValue(MOCKED_TOKEN_LIMIT);
610
- mockGetHistory.mockReturnValue([
611
- { role: 'user', parts: [{ text: '...history 1...' }] },
612
- { role: 'model', parts: [{ text: '...history 2...' }] },
613
- { role: 'user', parts: [{ text: '...history 3...' }] },
614
- { role: 'model', parts: [{ text: '...history 4...' }] },
615
- { role: 'user', parts: [{ text: '...history 5...' }] },
616
- { role: 'model', parts: [{ text: '...history 6...' }] },
617
- { role: 'user', parts: [{ text: '...history 7...' }] },
618
- { role: 'model', parts: [{ text: '...history 8...' }] },
619
- // Normally we would break here, but we have a function response.
620
- {
621
- role: 'user',
622
- parts: [{ functionResponse: { name: '...history 8...' } }],
623
- },
624
- { role: 'model', parts: [{ text: '...history 10...' }] },
625
- // Instead we will break here.
626
- { role: 'user', parts: [{ text: '...history 10...' }] },
627
- ]);
628
- const originalTokenCount = 1000 * 0.7;
629
- const newTokenCount = 100;
630
- mockCountTokens
631
- .mockResolvedValueOnce({ totalTokens: originalTokenCount }) // First call for the check
632
- .mockResolvedValueOnce({ totalTokens: newTokenCount }); // Second call for the new history
633
- // Mock the summary response from the chat
634
- mockSendMessage.mockResolvedValue({
635
- role: 'model',
636
- parts: [{ text: 'This is a summary.' }],
637
- });
638
- const initialChat = client.getChat();
639
- const result = await client.tryCompressChat('prompt-id-3');
640
- const newChat = client.getChat();
641
- expect(tokenLimit).toHaveBeenCalled();
642
- expect(mockSendMessage).toHaveBeenCalled();
643
- // Assert that summarization happened and returned the correct stats
644
- expect(result).toEqual({
645
- originalTokenCount,
646
- newTokenCount,
647
- });
648
- // Assert that the chat was reset
649
- expect(newChat).not.toBe(initialChat);
650
- // 1. standard start context message
651
- // 2. standard canned user start message
652
- // 3. compressed summary message
653
- // 4. standard canned user summary message
654
- // 5. The last user message (not the last 3 because that would start with a function response)
655
- expect(newChat.getHistory().length).toEqual(5);
656
- });
657
- it('should always trigger summarization when force is true, regardless of token count', async () => {
658
- mockGetHistory.mockReturnValue([
659
- { role: 'user', parts: [{ text: '...history...' }] },
660
- ]);
661
- const originalTokenCount = 10; // Well below threshold
662
- const newTokenCount = 5;
663
- mockCountTokens
664
- .mockResolvedValueOnce({ totalTokens: originalTokenCount })
665
- .mockResolvedValueOnce({ totalTokens: newTokenCount });
666
- // Mock the summary response from the chat
667
- mockSendMessage.mockResolvedValue({
668
- role: 'model',
669
- parts: [{ text: 'This is a summary.' }],
670
- });
671
- const initialChat = client.getChat();
672
- const result = await client.tryCompressChat('prompt-id-1', true); // force = true
673
- const newChat = client.getChat();
674
- expect(mockSendMessage).toHaveBeenCalled();
675
- expect(result).toEqual({
676
- originalTokenCount,
677
- newTokenCount,
678
- });
679
- // Assert that the chat was reset
680
- expect(newChat).not.toBe(initialChat);
681
- });
682
- });
683
- describe('sendMessageStream', () => {
684
- it('should include IDE context when ideModeFeature is enabled', async () => {
685
- // Arrange
686
- vi.mocked(ideContext.getIdeContext).mockReturnValue({
687
- workspaceState: {
688
- openFiles: [
689
- {
690
- path: '/path/to/active/file.ts',
691
- timestamp: Date.now(),
692
- isActive: true,
693
- selectedText: 'hello',
694
- cursor: { line: 5, character: 10 },
695
- },
696
- {
697
- path: '/path/to/recent/file1.ts',
698
- timestamp: Date.now(),
699
- },
700
- {
701
- path: '/path/to/recent/file2.ts',
702
- timestamp: Date.now(),
703
- },
704
- ],
705
- },
706
- });
707
- vi.spyOn(client['config'], 'getIdeModeFeature').mockReturnValue(true);
708
- const mockStream = (async function* () {
709
- yield { type: 'content', value: 'Hello' };
710
- })();
711
- mockTurnRunFn.mockReturnValue(mockStream);
712
- const mockChat = {
713
- addHistory: vi.fn(),
714
- getHistory: vi.fn().mockReturnValue([]),
715
- };
716
- client['chat'] = mockChat;
717
- const mockGenerator = {
718
- countTokens: vi.fn().mockResolvedValue({ totalTokens: 0 }),
719
- generateContent: mockGenerateContentFn,
720
- };
721
- client['contentGenerator'] = mockGenerator;
722
- const initialRequest = [{ text: 'Hi' }];
723
- // Act
724
- const stream = client.sendMessageStream(initialRequest, new AbortController().signal, 'prompt-id-ide');
725
- for await (const _ of stream) {
726
- // consume stream
727
- }
728
- // Assert
729
- expect(ideContext.getIdeContext).toHaveBeenCalled();
730
- const expectedContext = `
731
- This is the file that the user is looking at:
732
- - Path: /path/to/active/file.ts
733
- This is the cursor position in the file:
734
- - Cursor Position: Line 5, Character 10
735
- This is the selected text in the file:
736
- - hello
737
- Here are some other files the user has open, with the most recent at the top:
738
- - /path/to/recent/file1.ts
739
- - /path/to/recent/file2.ts
740
- `.trim();
741
- const expectedRequest = [{ text: expectedContext }, ...initialRequest];
742
- expect(mockTurnRunFn).toHaveBeenCalledWith(expectedRequest, expect.any(Object));
743
- });
744
- it('should not add context if ideModeFeature is enabled but no open files', async () => {
745
- // Arrange
746
- vi.mocked(ideContext.getIdeContext).mockReturnValue({
747
- workspaceState: {
748
- openFiles: [],
749
- },
750
- });
751
- vi.spyOn(client['config'], 'getIdeModeFeature').mockReturnValue(true);
752
- const mockStream = (async function* () {
753
- yield { type: 'content', value: 'Hello' };
754
- })();
755
- mockTurnRunFn.mockReturnValue(mockStream);
756
- const mockChat = {
757
- addHistory: vi.fn(),
758
- getHistory: vi.fn().mockReturnValue([]),
759
- };
760
- client['chat'] = mockChat;
761
- const mockGenerator = {
762
- countTokens: vi.fn().mockResolvedValue({ totalTokens: 0 }),
763
- generateContent: mockGenerateContentFn,
764
- };
765
- client['contentGenerator'] = mockGenerator;
766
- const initialRequest = [{ text: 'Hi' }];
767
- // Act
768
- const stream = client.sendMessageStream(initialRequest, new AbortController().signal, 'prompt-id-ide');
769
- for await (const _ of stream) {
770
- // consume stream
771
- }
772
- // Assert
773
- expect(ideContext.getIdeContext).toHaveBeenCalled();
774
- expect(mockTurnRunFn).toHaveBeenCalledWith(initialRequest, expect.any(Object));
775
- });
776
- it('should add context if ideModeFeature is enabled and there is one active file', async () => {
777
- // Arrange
778
- vi.mocked(ideContext.getIdeContext).mockReturnValue({
779
- workspaceState: {
780
- openFiles: [
781
- {
782
- path: '/path/to/active/file.ts',
783
- timestamp: Date.now(),
784
- isActive: true,
785
- selectedText: 'hello',
786
- cursor: { line: 5, character: 10 },
787
- },
788
- ],
789
- },
790
- });
791
- vi.spyOn(client['config'], 'getIdeModeFeature').mockReturnValue(true);
792
- const mockStream = (async function* () {
793
- yield { type: 'content', value: 'Hello' };
794
- })();
795
- mockTurnRunFn.mockReturnValue(mockStream);
796
- const mockChat = {
797
- addHistory: vi.fn(),
798
- getHistory: vi.fn().mockReturnValue([]),
799
- };
800
- client['chat'] = mockChat;
801
- const mockGenerator = {
802
- countTokens: vi.fn().mockResolvedValue({ totalTokens: 0 }),
803
- generateContent: mockGenerateContentFn,
804
- };
805
- client['contentGenerator'] = mockGenerator;
806
- const initialRequest = [{ text: 'Hi' }];
807
- // Act
808
- const stream = client.sendMessageStream(initialRequest, new AbortController().signal, 'prompt-id-ide');
809
- for await (const _ of stream) {
810
- // consume stream
811
- }
812
- // Assert
813
- expect(ideContext.getIdeContext).toHaveBeenCalled();
814
- const expectedContext = `
815
- This is the file that the user is looking at:
816
- - Path: /path/to/active/file.ts
817
- This is the cursor position in the file:
818
- - Cursor Position: Line 5, Character 10
819
- This is the selected text in the file:
820
- - hello
821
- `.trim();
822
- const expectedRequest = [{ text: expectedContext }, ...initialRequest];
823
- expect(mockTurnRunFn).toHaveBeenCalledWith(expectedRequest, expect.any(Object));
824
- });
825
- it('should add context if ideModeFeature is enabled and there are open files but no active file', async () => {
826
- // Arrange
827
- vi.mocked(ideContext.getIdeContext).mockReturnValue({
828
- workspaceState: {
829
- openFiles: [
830
- {
831
- path: '/path/to/recent/file1.ts',
832
- timestamp: Date.now(),
833
- },
834
- {
835
- path: '/path/to/recent/file2.ts',
836
- timestamp: Date.now(),
837
- },
838
- ],
839
- },
840
- });
841
- vi.spyOn(client['config'], 'getIdeModeFeature').mockReturnValue(true);
842
- const mockStream = (async function* () {
843
- yield { type: 'content', value: 'Hello' };
844
- })();
845
- mockTurnRunFn.mockReturnValue(mockStream);
846
- const mockChat = {
847
- addHistory: vi.fn(),
848
- getHistory: vi.fn().mockReturnValue([]),
849
- };
850
- client['chat'] = mockChat;
851
- const mockGenerator = {
852
- countTokens: vi.fn().mockResolvedValue({ totalTokens: 0 }),
853
- generateContent: mockGenerateContentFn,
854
- };
855
- client['contentGenerator'] = mockGenerator;
856
- const initialRequest = [{ text: 'Hi' }];
857
- // Act
858
- const stream = client.sendMessageStream(initialRequest, new AbortController().signal, 'prompt-id-ide');
859
- for await (const _ of stream) {
860
- // consume stream
861
- }
862
- // Assert
863
- expect(ideContext.getIdeContext).toHaveBeenCalled();
864
- const expectedContext = `
865
- Here are some files the user has open, with the most recent at the top:
866
- - /path/to/recent/file1.ts
867
- - /path/to/recent/file2.ts
868
- `.trim();
869
- const expectedRequest = [{ text: expectedContext }, ...initialRequest];
870
- expect(mockTurnRunFn).toHaveBeenCalledWith(expectedRequest, expect.any(Object));
871
- });
872
- it('should return the turn instance after the stream is complete', async () => {
873
- // Arrange
874
- const mockStream = (async function* () {
875
- yield { type: 'content', value: 'Hello' };
876
- })();
877
- mockTurnRunFn.mockReturnValue(mockStream);
878
- const mockChat = {
879
- addHistory: vi.fn(),
880
- getHistory: vi.fn().mockReturnValue([]),
881
- };
882
- client['chat'] = mockChat;
883
- const mockGenerator = {
884
- countTokens: vi.fn().mockResolvedValue({ totalTokens: 0 }),
885
- generateContent: vi.fn(),
886
- generateContentStream: vi.fn(),
887
- embedContent: vi.fn(),
888
- };
889
- client['contentGenerator'] = mockGenerator;
890
- // Act
891
- const stream = client.sendMessageStream([{ text: 'Hi' }], new AbortController().signal, 'prompt-id-1');
892
- // Consume the stream manually to get the final return value.
893
- let finalResult;
894
- while (true) {
895
- const result = await stream.next();
896
- if (result.done) {
897
- finalResult = result.value;
898
- break;
899
- }
900
- }
901
- // Assert
902
- expect(finalResult).toBeInstanceOf(Turn);
903
- });
904
- it.skip('should stop infinite loop after MAX_TURNS when nextSpeaker always returns model', async () => {
905
- // Get the mocked checkNextSpeaker function and configure it to trigger infinite loop
906
- const { checkNextSpeaker } = await import('../utils/nextSpeakerChecker.js');
907
- const mockCheckNextSpeaker = vi.mocked(checkNextSpeaker);
908
- mockCheckNextSpeaker.mockResolvedValue({
909
- next_speaker: 'model',
910
- reasoning: 'Test case - always continue',
911
- });
912
- // Mock provider manager to return 'gemini' provider
913
- const mockProviderManager = {
914
- getActiveProviderName: vi.fn().mockReturnValue('gemini'),
915
- getActiveProvider: vi.fn().mockReturnValue(null),
916
- };
917
- const mockContentGenConfig = {
918
- model: 'test-model',
919
- providerManager: mockProviderManager,
920
- };
921
- vi.spyOn(client['config'], 'getContentGeneratorConfig').mockReturnValue(mockContentGenConfig);
922
- // Mock Turn to have no pending tool calls (which would allow nextSpeaker check)
923
- const mockStream = (async function* () {
924
- yield { type: 'content', value: 'Continue...' };
925
- })();
926
- mockTurnRunFn.mockReturnValue(mockStream);
927
- const mockChat = {
928
- addHistory: vi.fn(),
929
- getHistory: vi.fn().mockReturnValue([]),
930
- };
931
- client['chat'] = mockChat;
932
- const mockGenerator = {
933
- countTokens: vi.fn().mockResolvedValue({ totalTokens: 0 }),
934
- };
935
- client['contentGenerator'] = mockGenerator;
936
- // Use a signal that never gets aborted
937
- const abortController = new AbortController();
938
- const signal = abortController.signal;
939
- // Act - Start the stream that should loop
940
- const stream = client.sendMessageStream([{ text: 'Start conversation' }], signal, 'prompt-id-2');
941
- // Count how many stream events we get
942
- let eventCount = 0;
943
- let finalResult;
944
- // Consume the stream and count iterations
945
- while (true) {
946
- const result = await stream.next();
947
- if (result.done) {
948
- finalResult = result.value;
949
- break;
950
- }
951
- eventCount++;
952
- // Safety check to prevent actual infinite loop in test
953
- if (eventCount > 200) {
954
- abortController.abort();
955
- throw new Error('Test exceeded expected event limit - possible actual infinite loop');
956
- }
957
- }
958
- // Assert
959
- expect(finalResult).toBeInstanceOf(Turn);
960
- // Debug: Check how many times checkNextSpeaker was called
961
- const callCount = mockCheckNextSpeaker.mock.calls.length;
962
- // If infinite loop protection is working, checkNextSpeaker should be called many times
963
- // but stop at MAX_TURNS (100). Since each recursive call should trigger checkNextSpeaker,
964
- // we expect it to be called multiple times before hitting the limit
965
- expect(mockCheckNextSpeaker).toHaveBeenCalled();
966
- // The test should demonstrate that the infinite loop protection works:
967
- // - If checkNextSpeaker is called many times (close to MAX_TURNS), it shows the loop was happening
968
- // - If it's only called once, the recursive behavior might not be triggered
969
- if (callCount === 0) {
970
- throw new Error('checkNextSpeaker was never called - the recursive condition was not met');
971
- }
972
- else if (callCount === 1) {
973
- // This might be expected behavior if the turn has pending tool calls or other conditions prevent recursion
974
- console.log('checkNextSpeaker called only once - no infinite loop occurred');
975
- }
976
- else {
977
- console.log(`checkNextSpeaker called ${callCount} times - infinite loop protection worked`);
978
- // If called multiple times, we expect it to be stopped before MAX_TURNS
979
- expect(callCount).toBeLessThanOrEqual(100); // Should not exceed MAX_TURNS
980
- }
981
- // The stream should produce events and eventually terminate
982
- expect(eventCount).toBeGreaterThanOrEqual(1);
983
- expect(eventCount).toBeLessThan(200); // Should not exceed our safety limit
984
- });
985
- it('should yield MaxSessionTurns and stop when session turn limit is reached', async () => {
986
- // Arrange
987
- const MAX_SESSION_TURNS = 5;
988
- vi.spyOn(client['config'], 'getMaxSessionTurns').mockReturnValue(MAX_SESSION_TURNS);
989
- const mockStream = (async function* () {
990
- yield { type: 'content', value: 'Hello' };
991
- })();
992
- mockTurnRunFn.mockReturnValue(mockStream);
993
- const mockChat = {
994
- addHistory: vi.fn(),
995
- getHistory: vi.fn().mockReturnValue([]),
996
- };
997
- client['chat'] = mockChat;
998
- const mockGenerator = {
999
- countTokens: vi.fn().mockResolvedValue({ totalTokens: 0 }),
1000
- };
1001
- client['contentGenerator'] = mockGenerator;
1002
- // Act & Assert
1003
- // Run up to the limit
1004
- for (let i = 0; i < MAX_SESSION_TURNS; i++) {
1005
- const stream = client.sendMessageStream([{ text: 'Hi' }], new AbortController().signal, 'prompt-id-4');
1006
- // consume stream
1007
- for await (const _event of stream) {
1008
- // do nothing
1009
- }
1010
- }
1011
- // This call should exceed the limit
1012
- const stream = client.sendMessageStream([{ text: 'Hi' }], new AbortController().signal, 'prompt-id-5');
1013
- const events = [];
1014
- for await (const event of stream) {
1015
- events.push(event);
1016
- }
1017
- expect(events).toEqual([{ type: GeminiEventType.MaxSessionTurns }]);
1018
- expect(mockTurnRunFn).toHaveBeenCalledTimes(MAX_SESSION_TURNS);
1019
- });
1020
- it.skip('should respect MAX_TURNS limit even when turns parameter is set to a large value', async () => {
1021
- // This test verifies that the infinite loop protection works even when
1022
- // someone tries to bypass it by calling with a very large turns value
1023
- // Get the mocked checkNextSpeaker function and configure it to trigger infinite loop
1024
- const { checkNextSpeaker } = await import('../utils/nextSpeakerChecker.js');
1025
- const mockCheckNextSpeaker = vi.mocked(checkNextSpeaker);
1026
- mockCheckNextSpeaker.mockResolvedValue({
1027
- next_speaker: 'model',
1028
- reasoning: 'Test case - always continue',
1029
- });
1030
- // Mock Turn to have no pending tool calls (which would allow nextSpeaker check)
1031
- const mockStream = (async function* () {
1032
- yield { type: 'content', value: 'Continue...' };
1033
- })();
1034
- mockTurnRunFn.mockReturnValue(mockStream);
1035
- const mockChat = {
1036
- addHistory: vi.fn(),
1037
- getHistory: vi.fn().mockReturnValue([]),
1038
- };
1039
- client['chat'] = mockChat;
1040
- const mockGenerator = {
1041
- countTokens: vi.fn().mockResolvedValue({ totalTokens: 0 }),
1042
- };
1043
- client['contentGenerator'] = mockGenerator;
1044
- // Use a signal that never gets aborted
1045
- const abortController = new AbortController();
1046
- const signal = abortController.signal;
1047
- // Act - Start the stream with an extremely high turns value
1048
- // This simulates a case where the turns protection is bypassed
1049
- const stream = client.sendMessageStream([{ text: 'Start conversation' }], signal, 'prompt-id-3', Number.MAX_SAFE_INTEGER);
1050
- // Count how many stream events we get
1051
- let eventCount = 0;
1052
- const maxTestIterations = 1000; // Higher limit to show the loop continues
1053
- // Consume the stream and count iterations
1054
- try {
1055
- while (true) {
1056
- const result = await stream.next();
1057
- if (result.done) {
1058
- break;
1059
- }
1060
- eventCount++;
1061
- // This test should hit this limit, demonstrating the infinite loop
1062
- if (eventCount > maxTestIterations) {
1063
- abortController.abort();
1064
- // This is the expected behavior - we hit the infinite loop
1065
- break;
1066
- }
1067
- }
1068
- }
1069
- catch (error) {
1070
- // If the test framework times out, that also demonstrates the infinite loop
1071
- console.error('Test timed out or errored:', error);
1072
- }
1073
- // Assert that the fix works - the loop should stop at MAX_TURNS
1074
- const callCount = mockCheckNextSpeaker.mock.calls.length;
1075
- // With the fix: even when turns is set to a very high value,
1076
- // the loop should stop at MAX_TURNS (100)
1077
- expect(callCount).toBeLessThanOrEqual(100); // Should not exceed MAX_TURNS
1078
- expect(eventCount).toBeLessThanOrEqual(200); // Should have reasonable number of events
1079
- console.log(`Infinite loop protection working: checkNextSpeaker called ${callCount} times, ` +
1080
- `${eventCount} events generated (properly bounded by MAX_TURNS)`);
1081
- });
1082
- });
1083
- describe('generateContent model usage', () => {
1084
- it('should use current model from config for content generation', async () => {
1085
- const initialModel = client['config'].getModel();
1086
- const contents = [{ role: 'user', parts: [{ text: 'test' }] }];
1087
- const currentModel = initialModel + '-changed';
1088
- // Mock getModel to return the changed model when called during generateContent
1089
- vi.spyOn(client['config'], 'getModel').mockReturnValue(currentModel);
1090
- // Mock the retryWithBackoff to directly call the apiCall function
1091
- vi.mock('../utils/retry.js', () => ({
1092
- retryWithBackoff: vi.fn((apiCall) => apiCall()),
1093
- }));
1094
- const mockContentGeneratorGenerateContent = vi.fn().mockResolvedValue({
1095
- candidates: [
1096
- {
1097
- content: {
1098
- parts: [{ text: 'response' }],
1099
- },
1100
- },
1101
- ],
1102
- });
1103
- const mockGenerator = {
1104
- countTokens: vi.fn().mockResolvedValue({ totalTokens: 1 }),
1105
- generateContent: mockContentGeneratorGenerateContent,
1106
- };
1107
- client['contentGenerator'] = mockGenerator;
1108
- client['isInitialized'] = vi.fn().mockReturnValue(true);
1109
- const { retryWithBackoff } = await import('../utils/retry.js');
1110
- vi.mocked(retryWithBackoff).mockImplementation(async (apiCall) => await apiCall());
1111
- await client.generateContent(contents, {}, new AbortController().signal);
1112
- // Verify the mock was called
1113
- expect(mockContentGeneratorGenerateContent).toHaveBeenCalledTimes(1);
1114
- // Get the actual call arguments
1115
- const actualCall = mockContentGeneratorGenerateContent.mock.calls[0];
1116
- // Assert on the model specifically
1117
- expect(actualCall[0].model).toBe(currentModel);
1118
- expect(actualCall[0].model).not.toBe(initialModel);
1119
- // Verify other expected properties exist
1120
- expect(actualCall[0]).toHaveProperty('contents', contents);
1121
- expect(actualCall[0]).toHaveProperty('config');
1122
- expect(actualCall[0].config).toHaveProperty('abortSignal');
1123
- expect(actualCall[0].config).toHaveProperty('systemInstruction');
1124
- // Verify prompt_id was passed
1125
- expect(actualCall[1]).toBe('test-session-id');
1126
- });
1127
- });
1128
- describe('tryCompressChat model usage', () => {
1129
- it('should use current model from config for token counting after sendMessage', async () => {
1130
- const initialModel = client['config'].getModel();
1131
- const mockCountTokens = vi
1132
- .fn()
1133
- .mockResolvedValueOnce({ totalTokens: 100000 })
1134
- .mockResolvedValueOnce({ totalTokens: 5000 });
1135
- const mockSendMessage = vi.fn().mockResolvedValue({ text: 'Summary' });
1136
- const mockChatHistory = [
1137
- { role: 'user', parts: [{ text: 'Long conversation' }] },
1138
- { role: 'model', parts: [{ text: 'Long response' }] },
1139
- ];
1140
- const mockChat = {
1141
- getHistory: vi.fn().mockReturnValue(mockChatHistory),
1142
- setHistory: vi.fn(),
1143
- sendMessage: mockSendMessage,
1144
- };
1145
- const mockGenerator = {
1146
- countTokens: mockCountTokens,
1147
- };
1148
- // mock the model has been changed between calls of `countTokens`
1149
- const firstCurrentModel = initialModel + '-changed-1';
1150
- const secondCurrentModel = initialModel + '-changed-2';
1151
- vi.spyOn(client['config'], 'getModel')
1152
- .mockReturnValueOnce(firstCurrentModel)
1153
- .mockReturnValueOnce(secondCurrentModel);
1154
- client['chat'] = mockChat;
1155
- client['contentGenerator'] = mockGenerator;
1156
- client['startChat'] = vi.fn().mockResolvedValue(mockChat);
1157
- const result = await client.tryCompressChat('prompt-id-4', true);
1158
- expect(mockCountTokens).toHaveBeenCalledTimes(2);
1159
- expect(mockCountTokens).toHaveBeenNthCalledWith(1, {
1160
- model: firstCurrentModel,
1161
- contents: mockChatHistory,
1162
- });
1163
- expect(mockCountTokens).toHaveBeenNthCalledWith(2, {
1164
- model: secondCurrentModel,
1165
- contents: expect.any(Array),
1166
- });
1167
- expect(result).toEqual({
1168
- originalTokenCount: 100000,
1169
- newTokenCount: 5000,
1170
- });
1171
- });
1172
- });
1173
- describe('handleFlashFallback', () => {
1174
- it('should use current model from config when checking for fallback', async () => {
1175
- const initialModel = client['config'].getModel();
1176
- const fallbackModel = DEFAULT_GEMINI_FLASH_MODEL;
1177
- // mock config been changed
1178
- const currentModel = initialModel + '-changed';
1179
- const getModelSpy = vi.spyOn(client['config'], 'getModel');
1180
- getModelSpy.mockReturnValue(currentModel);
1181
- const mockFallbackHandler = vi.fn().mockResolvedValue(true);
1182
- client['config'].flashFallbackHandler = mockFallbackHandler;
1183
- client['config'].setModel = vi.fn();
1184
- const result = await client['handleFlashFallback'](AuthType.LOGIN_WITH_GOOGLE);
1185
- expect(result).toBe(fallbackModel);
1186
- expect(mockFallbackHandler).toHaveBeenCalledWith(currentModel, fallbackModel, undefined);
1187
- });
1188
- });
1189
- // TODO: Re-enable when updateModel method is implemented
1190
- describe.skip('updateModel', () => {
1191
- it('should update model in config and reinitialize chat', async () => {
1192
- // Arrange
1193
- const mockSetModel = vi.fn();
1194
- const mockConfig = {
1195
- getModel: vi.fn().mockReturnValue('gemini-2.5-pro'),
1196
- setModel: mockSetModel,
1197
- getProjectRoot: vi.fn().mockReturnValue('/test'),
1198
- getWorkingDir: vi.fn().mockReturnValue('/test'),
1199
- getFullContext: vi.fn().mockReturnValue(false),
1200
- getUserMemory: vi.fn().mockReturnValue(''),
1201
- getLlxprtMdFileCount: vi.fn().mockReturnValue(0),
1202
- getFileService: vi.fn().mockReturnValue(null),
1203
- getCheckpointingEnabled: vi.fn().mockReturnValue(false),
1204
- getToolRegistry: vi.fn().mockResolvedValue({
1205
- generateSchema: vi.fn().mockReturnValue([]),
1206
- getToolTelemetry: vi.fn().mockReturnValue([]),
1207
- getFunctionDeclarations: vi.fn().mockReturnValue([]),
1208
- }),
1209
- };
1210
- client['config'] = mockConfig;
1211
- // Mock the content generator and chat
1212
- const mockContentGenerator = {
1213
- generateContent: vi.fn(),
1214
- generateContentStream: vi.fn(),
1215
- countTokens: vi.fn(),
1216
- embedContent: vi.fn(),
1217
- };
1218
- client['contentGenerator'] = mockContentGenerator;
1219
- // const initialChat = client['chat'];
1220
- // Act
1221
- // await client.updateModel('gemini-2.5-flash');
1222
- // Assert
1223
- // expect(mockSetModel).toHaveBeenCalledWith('gemini-2.5-flash');
1224
- // expect(client['model']).toBe('gemini-2.5-flash');
1225
- // expect(client['chat']).not.toBe(initialChat); // Chat should be reinitialized
1226
- // Skip test - updateModel method not implemented yet
1227
- expect(true).toBe(true);
1228
- });
1229
- });
1230
- // TODO: Re-enable when listAvailableModels method is implemented
1231
- describe.skip('listAvailableModels', () => {
1232
- beforeEach(() => {
1233
- global.fetch = vi.fn();
1234
- });
1235
- afterEach(() => {
1236
- vi.restoreAllMocks();
1237
- });
1238
- it('should fetch models from API for GEMINI auth type', async () => {
1239
- // Arrange
1240
- const mockModels = [
1241
- { name: 'models/gemini-2.5-pro', displayName: 'Gemini 2.5 Pro' },
1242
- { name: 'models/gemini-2.5-flash', displayName: 'Gemini 2.5 Flash' },
1243
- ];
1244
- const mockConfig = {
1245
- getContentGeneratorConfig: vi.fn().mockReturnValue({
1246
- authType: AuthType.USE_GEMINI,
1247
- apiKey: 'test-api-key',
1248
- }),
1249
- };
1250
- client['config'] = mockConfig;
1251
- global.fetch.mockResolvedValue({
1252
- ok: true,
1253
- json: vi.fn().mockResolvedValue({ models: mockModels }),
1254
- });
1255
- // Act
1256
- // const models = await client.listAvailableModels();
1257
- const models = []; // Placeholder - listAvailableModels not implemented
1258
- // Assert
1259
- expect(global.fetch).toHaveBeenCalledWith('https://generativelanguage.googleapis.com/v1beta/models?key=test-api-key', expect.objectContaining({
1260
- method: 'GET',
1261
- headers: { 'Content-Type': 'application/json' },
1262
- }));
1263
- expect(models).toEqual(mockModels);
1264
- });
1265
- it('should return OAuth marker for OAuth auth types', async () => {
1266
- // Arrange
1267
- const mockConfig = {
1268
- getContentGeneratorConfig: vi.fn().mockReturnValue({
1269
- authType: AuthType.LOGIN_WITH_GOOGLE,
1270
- }),
1271
- };
1272
- client['config'] = mockConfig;
1273
- // Act
1274
- // const models = await client.listAvailableModels();
1275
- const models = []; // Placeholder - listAvailableModels not implemented
1276
- // Assert
1277
- expect(models).toEqual([
1278
- {
1279
- name: 'oauth-not-supported',
1280
- displayName: 'OAuth Authentication',
1281
- description: 'Model listing is not available with OAuth authentication',
1282
- },
1283
- ]);
1284
- });
1285
- it('should return empty array when API call fails', async () => {
1286
- // Arrange
1287
- const mockConfig = {
1288
- getContentGeneratorConfig: vi.fn().mockReturnValue({
1289
- authType: AuthType.USE_GEMINI,
1290
- apiKey: 'test-api-key',
1291
- }),
1292
- };
1293
- client['config'] = mockConfig;
1294
- global.fetch.mockRejectedValue(new Error('Network error'));
1295
- // Act
1296
- // const models = await client.listAvailableModels();
1297
- const models = []; // Placeholder - listAvailableModels not implemented
1298
- // Assert
1299
- expect(models).toEqual([]);
1300
- });
1301
- it('should return empty array for unsupported auth type', async () => {
1302
- // Arrange
1303
- const mockConfig = {
1304
- getContentGeneratorConfig: vi.fn().mockReturnValue({
1305
- authType: undefined,
1306
- }),
1307
- };
1308
- client['config'] = mockConfig;
1309
- // Act
1310
- // const models = await client.listAvailableModels();
1311
- const models = []; // Placeholder - listAvailableModels not implemented
1312
- // Assert
1313
- expect(models).toEqual([]);
1314
- });
1315
- });
1316
- });
1317
- //# sourceMappingURL=client.test.js.map