@google/gemini-cli-core 0.0.3-preview.4 → 0.0.4

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 (490) hide show
  1. package/LICENSE +2 -2
  2. package/README.md +12 -2
  3. package/dist/index.d.ts +6 -2
  4. package/dist/index.js +6 -2
  5. package/dist/index.js.map +1 -1
  6. package/dist/src/code_assist/codeAssist.d.ts +2 -0
  7. package/dist/src/code_assist/codeAssist.js +12 -0
  8. package/dist/src/code_assist/codeAssist.js.map +1 -1
  9. package/dist/src/code_assist/converter.d.ts +3 -1
  10. package/dist/src/code_assist/converter.js +2 -1
  11. package/dist/src/code_assist/converter.js.map +1 -1
  12. package/dist/src/code_assist/converter.test.js +10 -0
  13. package/dist/src/code_assist/converter.test.js.map +1 -1
  14. package/dist/src/code_assist/oauth-credential-storage.d.ts +25 -0
  15. package/dist/src/code_assist/oauth-credential-storage.js +109 -0
  16. package/dist/src/code_assist/oauth-credential-storage.js.map +1 -0
  17. package/dist/src/code_assist/oauth-credential-storage.test.js +136 -0
  18. package/dist/src/code_assist/oauth-credential-storage.test.js.map +1 -0
  19. package/dist/src/code_assist/oauth2.js +92 -29
  20. package/dist/src/code_assist/oauth2.js.map +1 -1
  21. package/dist/src/code_assist/oauth2.test.js +729 -339
  22. package/dist/src/code_assist/oauth2.test.js.map +1 -1
  23. package/dist/src/code_assist/server.d.ts +1 -1
  24. package/dist/src/code_assist/server.js +24 -1
  25. package/dist/src/code_assist/server.js.map +1 -1
  26. package/dist/src/code_assist/server.test.js +25 -0
  27. package/dist/src/code_assist/server.test.js.map +1 -1
  28. package/dist/src/code_assist/types.d.ts +17 -2
  29. package/dist/src/config/config.d.ts +72 -12
  30. package/dist/src/config/config.js +196 -64
  31. package/dist/src/config/config.js.map +1 -1
  32. package/dist/src/config/config.test.js +305 -178
  33. package/dist/src/config/config.test.js.map +1 -1
  34. package/dist/src/config/models.d.ts +16 -0
  35. package/dist/src/config/models.js +29 -0
  36. package/dist/src/config/models.js.map +1 -1
  37. package/dist/src/config/models.test.d.ts +6 -0
  38. package/dist/src/config/models.test.js +55 -0
  39. package/dist/src/config/models.test.js.map +1 -0
  40. package/dist/src/config/storage.d.ts +2 -0
  41. package/dist/src/config/storage.js +6 -1
  42. package/dist/src/config/storage.js.map +1 -1
  43. package/dist/src/config/storage.test.js +4 -0
  44. package/dist/src/config/storage.test.js.map +1 -1
  45. package/dist/src/confirmation-bus/index.d.ts +7 -0
  46. package/dist/src/confirmation-bus/index.js +8 -0
  47. package/dist/src/confirmation-bus/index.js.map +1 -0
  48. package/dist/src/confirmation-bus/message-bus.d.ts +17 -0
  49. package/dist/src/confirmation-bus/message-bus.js +81 -0
  50. package/dist/src/confirmation-bus/message-bus.js.map +1 -0
  51. package/dist/src/confirmation-bus/message-bus.test.d.ts +6 -0
  52. package/dist/src/confirmation-bus/message-bus.test.js +164 -0
  53. package/dist/src/confirmation-bus/message-bus.test.js.map +1 -0
  54. package/dist/src/confirmation-bus/types.d.ts +38 -0
  55. package/dist/src/confirmation-bus/types.js +15 -0
  56. package/dist/src/confirmation-bus/types.js.map +1 -0
  57. package/dist/src/core/baseLlmClient.d.ts +46 -0
  58. package/dist/src/core/baseLlmClient.js +112 -0
  59. package/dist/src/core/baseLlmClient.js.map +1 -0
  60. package/dist/src/core/baseLlmClient.test.d.ts +6 -0
  61. package/dist/src/core/baseLlmClient.test.js +253 -0
  62. package/dist/src/core/baseLlmClient.test.js.map +1 -0
  63. package/dist/src/core/client.d.ts +16 -21
  64. package/dist/src/core/client.js +145 -232
  65. package/dist/src/core/client.js.map +1 -1
  66. package/dist/src/core/client.test.js +393 -492
  67. package/dist/src/core/client.test.js.map +1 -1
  68. package/dist/src/core/contentGenerator.d.ts +2 -3
  69. package/dist/src/core/contentGenerator.js +0 -4
  70. package/dist/src/core/contentGenerator.js.map +1 -1
  71. package/dist/src/core/contentGenerator.test.js +1 -3
  72. package/dist/src/core/contentGenerator.test.js.map +1 -1
  73. package/dist/src/core/coreToolScheduler.d.ts +8 -3
  74. package/dist/src/core/coreToolScheduler.js +106 -5
  75. package/dist/src/core/coreToolScheduler.js.map +1 -1
  76. package/dist/src/core/coreToolScheduler.test.js +233 -5
  77. package/dist/src/core/coreToolScheduler.test.js.map +1 -1
  78. package/dist/src/core/geminiChat.d.ts +38 -32
  79. package/dist/src/core/geminiChat.js +209 -219
  80. package/dist/src/core/geminiChat.js.map +1 -1
  81. package/dist/src/core/geminiChat.test.js +674 -386
  82. package/dist/src/core/geminiChat.test.js.map +1 -1
  83. package/dist/src/core/loggingContentGenerator.js +13 -16
  84. package/dist/src/core/loggingContentGenerator.js.map +1 -1
  85. package/dist/src/core/nonInteractiveToolExecutor.test.js +59 -1
  86. package/dist/src/core/nonInteractiveToolExecutor.test.js.map +1 -1
  87. package/dist/src/core/prompts.d.ts +5 -0
  88. package/dist/src/core/prompts.js +63 -42
  89. package/dist/src/core/prompts.js.map +1 -1
  90. package/dist/src/core/prompts.test.js +130 -1
  91. package/dist/src/core/prompts.test.js.map +1 -1
  92. package/dist/src/core/subagent.js +7 -10
  93. package/dist/src/core/subagent.js.map +1 -1
  94. package/dist/src/core/subagent.test.js +32 -22
  95. package/dist/src/core/subagent.test.js.map +1 -1
  96. package/dist/src/core/turn.d.ts +21 -5
  97. package/dist/src/core/turn.js +45 -11
  98. package/dist/src/core/turn.js.map +1 -1
  99. package/dist/src/core/turn.test.js +340 -100
  100. package/dist/src/core/turn.test.js.map +1 -1
  101. package/dist/src/fallback/handler.d.ts +7 -0
  102. package/dist/src/fallback/handler.js +51 -0
  103. package/dist/src/fallback/handler.js.map +1 -0
  104. package/dist/src/fallback/handler.test.d.ts +6 -0
  105. package/dist/src/fallback/handler.test.js +130 -0
  106. package/dist/src/fallback/handler.test.js.map +1 -0
  107. package/dist/src/fallback/types.d.ts +14 -0
  108. package/dist/src/fallback/types.js +7 -0
  109. package/dist/src/fallback/types.js.map +1 -0
  110. package/dist/src/generated/git-commit.d.ts +2 -2
  111. package/dist/src/generated/git-commit.js +2 -2
  112. package/dist/src/generated/git-commit.js.map +1 -1
  113. package/dist/src/ide/constants.d.ts +3 -0
  114. package/dist/src/ide/constants.js +3 -0
  115. package/dist/src/ide/constants.js.map +1 -1
  116. package/dist/src/ide/detect-ide.d.ts +42 -14
  117. package/dist/src/ide/detect-ide.js +22 -68
  118. package/dist/src/ide/detect-ide.js.map +1 -1
  119. package/dist/src/ide/detect-ide.test.js +11 -51
  120. package/dist/src/ide/detect-ide.test.js.map +1 -1
  121. package/dist/src/ide/ide-client.d.ts +60 -18
  122. package/dist/src/ide/ide-client.js +275 -53
  123. package/dist/src/ide/ide-client.js.map +1 -1
  124. package/dist/src/ide/ide-client.test.js +239 -6
  125. package/dist/src/ide/ide-client.test.js.map +1 -1
  126. package/dist/src/ide/ide-installer.d.ts +2 -2
  127. package/dist/src/ide/ide-installer.js +15 -11
  128. package/dist/src/ide/ide-installer.js.map +1 -1
  129. package/dist/src/ide/ide-installer.test.js +30 -12
  130. package/dist/src/ide/ide-installer.test.js.map +1 -1
  131. package/dist/src/ide/ideContext.d.ts +35 -365
  132. package/dist/src/ide/ideContext.js +60 -106
  133. package/dist/src/ide/ideContext.js.map +1 -1
  134. package/dist/src/ide/ideContext.test.js +152 -24
  135. package/dist/src/ide/ideContext.test.js.map +1 -1
  136. package/dist/src/ide/process-utils.d.ts +0 -1
  137. package/dist/src/ide/process-utils.js +43 -25
  138. package/dist/src/ide/process-utils.js.map +1 -1
  139. package/dist/src/ide/process-utils.test.js +90 -4
  140. package/dist/src/ide/process-utils.test.js.map +1 -1
  141. package/dist/src/ide/types.d.ts +486 -0
  142. package/dist/src/ide/types.js +138 -0
  143. package/dist/src/ide/types.js.map +1 -0
  144. package/dist/src/index.d.ts +10 -2
  145. package/dist/src/index.js +11 -2
  146. package/dist/src/index.js.map +1 -1
  147. package/dist/src/mcp/oauth-provider.d.ts +15 -12
  148. package/dist/src/mcp/oauth-provider.js +63 -56
  149. package/dist/src/mcp/oauth-provider.js.map +1 -1
  150. package/dist/src/mcp/oauth-provider.test.js +74 -35
  151. package/dist/src/mcp/oauth-provider.test.js.map +1 -1
  152. package/dist/src/mcp/oauth-token-storage.d.ts +14 -10
  153. package/dist/src/mcp/oauth-token-storage.js +52 -20
  154. package/dist/src/mcp/oauth-token-storage.js.map +1 -1
  155. package/dist/src/mcp/oauth-token-storage.test.js +255 -162
  156. package/dist/src/mcp/oauth-token-storage.test.js.map +1 -1
  157. package/dist/src/mcp/token-storage/base-token-storage.d.ts +1 -1
  158. package/dist/src/mcp/token-storage/base-token-storage.js +1 -1
  159. package/dist/src/mcp/token-storage/base-token-storage.js.map +1 -1
  160. package/dist/src/mcp/token-storage/base-token-storage.test.js +1 -1
  161. package/dist/src/mcp/token-storage/base-token-storage.test.js.map +1 -1
  162. package/dist/src/mcp/token-storage/file-token-storage.d.ts +24 -0
  163. package/dist/src/mcp/token-storage/file-token-storage.js +144 -0
  164. package/dist/src/mcp/token-storage/file-token-storage.js.map +1 -0
  165. package/dist/src/mcp/token-storage/file-token-storage.test.d.ts +6 -0
  166. package/dist/src/mcp/token-storage/file-token-storage.test.js +235 -0
  167. package/dist/src/mcp/token-storage/file-token-storage.test.js.map +1 -0
  168. package/dist/src/mcp/token-storage/hybrid-token-storage.d.ts +23 -0
  169. package/dist/src/mcp/token-storage/hybrid-token-storage.js +78 -0
  170. package/dist/src/mcp/token-storage/hybrid-token-storage.js.map +1 -0
  171. package/dist/src/mcp/token-storage/hybrid-token-storage.test.d.ts +6 -0
  172. package/dist/src/mcp/token-storage/hybrid-token-storage.test.js +193 -0
  173. package/dist/src/mcp/token-storage/hybrid-token-storage.test.js.map +1 -0
  174. package/dist/src/mcp/token-storage/index.d.ts +11 -0
  175. package/dist/src/mcp/token-storage/index.js +12 -0
  176. package/dist/src/mcp/token-storage/index.js.map +1 -0
  177. package/dist/src/mcp/token-storage/keychain-token-storage.d.ts +31 -0
  178. package/dist/src/mcp/token-storage/keychain-token-storage.js +190 -0
  179. package/dist/src/mcp/token-storage/keychain-token-storage.js.map +1 -0
  180. package/dist/src/mcp/token-storage/keychain-token-storage.test.d.ts +6 -0
  181. package/dist/src/mcp/token-storage/keychain-token-storage.test.js +254 -0
  182. package/dist/src/mcp/token-storage/keychain-token-storage.test.js.map +1 -0
  183. package/dist/src/mcp/token-storage/types.d.ts +4 -0
  184. package/dist/src/mcp/token-storage/types.js +5 -1
  185. package/dist/src/mcp/token-storage/types.js.map +1 -1
  186. package/dist/src/output/json-formatter.d.ts +11 -0
  187. package/dist/src/output/json-formatter.js +30 -0
  188. package/dist/src/output/json-formatter.js.map +1 -0
  189. package/dist/src/output/json-formatter.test.d.ts +6 -0
  190. package/dist/src/output/json-formatter.test.js +266 -0
  191. package/dist/src/output/json-formatter.test.js.map +1 -0
  192. package/dist/src/output/types.d.ts +20 -0
  193. package/dist/src/output/types.js +11 -0
  194. package/dist/src/output/types.js.map +1 -0
  195. package/dist/src/policy/index.d.ts +7 -0
  196. package/dist/src/policy/index.js +8 -0
  197. package/dist/src/policy/index.js.map +1 -0
  198. package/dist/src/policy/policy-engine.d.ts +30 -0
  199. package/dist/src/policy/policy-engine.js +92 -0
  200. package/dist/src/policy/policy-engine.js.map +1 -0
  201. package/dist/src/policy/policy-engine.test.d.ts +6 -0
  202. package/dist/src/policy/policy-engine.test.js +515 -0
  203. package/dist/src/policy/policy-engine.test.js.map +1 -0
  204. package/dist/src/policy/stable-stringify.d.ts +58 -0
  205. package/dist/src/policy/stable-stringify.js +122 -0
  206. package/dist/src/policy/stable-stringify.js.map +1 -0
  207. package/dist/src/policy/types.d.ts +47 -0
  208. package/dist/src/policy/types.js +12 -0
  209. package/dist/src/policy/types.js.map +1 -0
  210. package/dist/src/routing/modelRouterService.d.ts +23 -0
  211. package/dist/src/routing/modelRouterService.js +70 -0
  212. package/dist/src/routing/modelRouterService.js.map +1 -0
  213. package/dist/src/routing/modelRouterService.test.d.ts +6 -0
  214. package/dist/src/routing/modelRouterService.test.js +98 -0
  215. package/dist/src/routing/modelRouterService.test.js.map +1 -0
  216. package/dist/src/routing/routingStrategy.d.ts +62 -0
  217. package/dist/src/routing/routingStrategy.js +7 -0
  218. package/dist/src/routing/routingStrategy.js.map +1 -0
  219. package/dist/src/routing/strategies/classifierStrategy.d.ts +12 -0
  220. package/dist/src/routing/strategies/classifierStrategy.js +173 -0
  221. package/dist/src/routing/strategies/classifierStrategy.js.map +1 -0
  222. package/dist/src/routing/strategies/classifierStrategy.test.d.ts +6 -0
  223. package/dist/src/routing/strategies/classifierStrategy.test.js +192 -0
  224. package/dist/src/routing/strategies/classifierStrategy.test.js.map +1 -0
  225. package/dist/src/routing/strategies/compositeStrategy.d.ts +26 -0
  226. package/dist/src/routing/strategies/compositeStrategy.js +67 -0
  227. package/dist/src/routing/strategies/compositeStrategy.js.map +1 -0
  228. package/dist/src/routing/strategies/compositeStrategy.test.d.ts +6 -0
  229. package/dist/src/routing/strategies/compositeStrategy.test.js +123 -0
  230. package/dist/src/routing/strategies/compositeStrategy.test.js.map +1 -0
  231. package/dist/src/routing/strategies/defaultStrategy.d.ts +12 -0
  232. package/dist/src/routing/strategies/defaultStrategy.js +20 -0
  233. package/dist/src/routing/strategies/defaultStrategy.js.map +1 -0
  234. package/dist/src/routing/strategies/defaultStrategy.test.d.ts +6 -0
  235. package/dist/src/routing/strategies/defaultStrategy.test.js +26 -0
  236. package/dist/src/routing/strategies/defaultStrategy.test.js.map +1 -0
  237. package/dist/src/routing/strategies/fallbackStrategy.d.ts +12 -0
  238. package/dist/src/routing/strategies/fallbackStrategy.js +25 -0
  239. package/dist/src/routing/strategies/fallbackStrategy.js.map +1 -0
  240. package/dist/src/routing/strategies/fallbackStrategy.test.d.ts +6 -0
  241. package/dist/src/routing/strategies/fallbackStrategy.test.js +55 -0
  242. package/dist/src/routing/strategies/fallbackStrategy.test.js.map +1 -0
  243. package/dist/src/routing/strategies/overrideStrategy.d.ts +15 -0
  244. package/dist/src/routing/strategies/overrideStrategy.js +28 -0
  245. package/dist/src/routing/strategies/overrideStrategy.js.map +1 -0
  246. package/dist/src/routing/strategies/overrideStrategy.test.d.ts +6 -0
  247. package/dist/src/routing/strategies/overrideStrategy.test.js +42 -0
  248. package/dist/src/routing/strategies/overrideStrategy.test.js.map +1 -0
  249. package/dist/src/services/chatRecordingService.d.ts +7 -13
  250. package/dist/src/services/chatRecordingService.js +28 -19
  251. package/dist/src/services/chatRecordingService.js.map +1 -1
  252. package/dist/src/services/chatRecordingService.test.js +62 -20
  253. package/dist/src/services/chatRecordingService.test.js.map +1 -1
  254. package/dist/src/services/fileDiscoveryService.d.ts +10 -0
  255. package/dist/src/services/fileDiscoveryService.js +31 -17
  256. package/dist/src/services/fileDiscoveryService.js.map +1 -1
  257. package/dist/src/services/gitService.js +9 -12
  258. package/dist/src/services/gitService.js.map +1 -1
  259. package/dist/src/services/gitService.test.js +10 -20
  260. package/dist/src/services/gitService.test.js.map +1 -1
  261. package/dist/src/services/loopDetectionService.d.ts +5 -0
  262. package/dist/src/services/loopDetectionService.js +36 -20
  263. package/dist/src/services/loopDetectionService.js.map +1 -1
  264. package/dist/src/services/loopDetectionService.test.js +41 -12
  265. package/dist/src/services/loopDetectionService.test.js.map +1 -1
  266. package/dist/src/services/shellExecutionService.d.ts +34 -2
  267. package/dist/src/services/shellExecutionService.js +192 -43
  268. package/dist/src/services/shellExecutionService.js.map +1 -1
  269. package/dist/src/services/shellExecutionService.test.js +184 -55
  270. package/dist/src/services/shellExecutionService.test.js.map +1 -1
  271. package/dist/src/telemetry/activity-detector.d.ts +41 -0
  272. package/dist/src/telemetry/activity-detector.js +61 -0
  273. package/dist/src/telemetry/activity-detector.js.map +1 -0
  274. package/dist/src/telemetry/activity-detector.test.d.ts +6 -0
  275. package/dist/src/telemetry/activity-detector.test.js +136 -0
  276. package/dist/src/telemetry/activity-detector.test.js.map +1 -0
  277. package/dist/src/telemetry/activity-types.d.ts +19 -0
  278. package/dist/src/telemetry/activity-types.js +21 -0
  279. package/dist/src/telemetry/activity-types.js.map +1 -0
  280. package/dist/src/telemetry/clearcut-logger/clearcut-logger.d.ts +16 -2
  281. package/dist/src/telemetry/clearcut-logger/clearcut-logger.js +143 -24
  282. package/dist/src/telemetry/clearcut-logger/clearcut-logger.js.map +1 -1
  283. package/dist/src/telemetry/clearcut-logger/clearcut-logger.test.js +101 -1
  284. package/dist/src/telemetry/clearcut-logger/clearcut-logger.test.js.map +1 -1
  285. package/dist/src/telemetry/clearcut-logger/event-metadata-key.d.ts +19 -2
  286. package/dist/src/telemetry/clearcut-logger/event-metadata-key.js +48 -2
  287. package/dist/src/telemetry/clearcut-logger/event-metadata-key.js.map +1 -1
  288. package/dist/src/telemetry/constants.d.ts +8 -0
  289. package/dist/src/telemetry/constants.js +8 -0
  290. package/dist/src/telemetry/constants.js.map +1 -1
  291. package/dist/src/telemetry/gcp-exporters.d.ts +34 -0
  292. package/dist/src/telemetry/gcp-exporters.js +117 -0
  293. package/dist/src/telemetry/gcp-exporters.js.map +1 -0
  294. package/dist/src/telemetry/gcp-exporters.test.d.ts +6 -0
  295. package/dist/src/telemetry/gcp-exporters.test.js +318 -0
  296. package/dist/src/telemetry/gcp-exporters.test.js.map +1 -0
  297. package/dist/src/telemetry/high-water-mark-tracker.d.ts +43 -0
  298. package/dist/src/telemetry/high-water-mark-tracker.js +88 -0
  299. package/dist/src/telemetry/high-water-mark-tracker.js.map +1 -0
  300. package/dist/src/telemetry/high-water-mark-tracker.test.d.ts +6 -0
  301. package/dist/src/telemetry/high-water-mark-tracker.test.js +152 -0
  302. package/dist/src/telemetry/high-water-mark-tracker.test.js.map +1 -0
  303. package/dist/src/telemetry/index.d.ts +7 -2
  304. package/dist/src/telemetry/index.js +7 -2
  305. package/dist/src/telemetry/index.js.map +1 -1
  306. package/dist/src/telemetry/loggers.d.ts +8 -1
  307. package/dist/src/telemetry/loggers.js +140 -8
  308. package/dist/src/telemetry/loggers.js.map +1 -1
  309. package/dist/src/telemetry/loggers.test.js +268 -39
  310. package/dist/src/telemetry/loggers.test.js.map +1 -1
  311. package/dist/src/telemetry/metrics.d.ts +4 -3
  312. package/dist/src/telemetry/metrics.js +33 -10
  313. package/dist/src/telemetry/metrics.js.map +1 -1
  314. package/dist/src/telemetry/metrics.test.js +47 -25
  315. package/dist/src/telemetry/metrics.test.js.map +1 -1
  316. package/dist/src/telemetry/rate-limiter.d.ts +48 -0
  317. package/dist/src/telemetry/rate-limiter.js +100 -0
  318. package/dist/src/telemetry/rate-limiter.js.map +1 -0
  319. package/dist/src/telemetry/rate-limiter.test.d.ts +6 -0
  320. package/dist/src/telemetry/rate-limiter.test.js +207 -0
  321. package/dist/src/telemetry/rate-limiter.test.js.map +1 -0
  322. package/dist/src/telemetry/sdk.js +16 -1
  323. package/dist/src/telemetry/sdk.js.map +1 -1
  324. package/dist/src/telemetry/sdk.test.js +95 -0
  325. package/dist/src/telemetry/sdk.test.js.map +1 -1
  326. package/dist/src/telemetry/types.d.ts +70 -6
  327. package/dist/src/telemetry/types.js +112 -8
  328. package/dist/src/telemetry/types.js.map +1 -1
  329. package/dist/src/telemetry/uiTelemetry.d.ts +1 -1
  330. package/dist/src/telemetry/uiTelemetry.js +6 -7
  331. package/dist/src/telemetry/uiTelemetry.js.map +1 -1
  332. package/dist/src/telemetry/uiTelemetry.test.js +15 -15
  333. package/dist/src/telemetry/uiTelemetry.test.js.map +1 -1
  334. package/dist/src/test-utils/index.d.ts +6 -0
  335. package/dist/src/test-utils/index.js +7 -0
  336. package/dist/src/test-utils/index.js.map +1 -0
  337. package/dist/src/test-utils/mock-tool.d.ts +41 -0
  338. package/dist/src/test-utils/mock-tool.js +51 -0
  339. package/dist/src/test-utils/mock-tool.js.map +1 -0
  340. package/dist/src/tools/diffOptions.js +21 -13
  341. package/dist/src/tools/diffOptions.js.map +1 -1
  342. package/dist/src/tools/diffOptions.test.js +58 -22
  343. package/dist/src/tools/diffOptions.test.js.map +1 -1
  344. package/dist/src/tools/edit.d.ts +2 -2
  345. package/dist/src/tools/edit.js +35 -44
  346. package/dist/src/tools/edit.js.map +1 -1
  347. package/dist/src/tools/edit.test.js +124 -13
  348. package/dist/src/tools/edit.test.js.map +1 -1
  349. package/dist/src/tools/glob.d.ts +5 -1
  350. package/dist/src/tools/glob.js +24 -17
  351. package/dist/src/tools/glob.js.map +1 -1
  352. package/dist/src/tools/glob.test.js +51 -0
  353. package/dist/src/tools/glob.test.js.map +1 -1
  354. package/dist/src/tools/ls.js +19 -32
  355. package/dist/src/tools/ls.js.map +1 -1
  356. package/dist/src/tools/ls.test.js +140 -280
  357. package/dist/src/tools/ls.test.js.map +1 -1
  358. package/dist/src/tools/mcp-client-manager.d.ts +5 -3
  359. package/dist/src/tools/mcp-client-manager.js +13 -4
  360. package/dist/src/tools/mcp-client-manager.js.map +1 -1
  361. package/dist/src/tools/mcp-client-manager.test.js +20 -1
  362. package/dist/src/tools/mcp-client-manager.test.js.map +1 -1
  363. package/dist/src/tools/mcp-client.d.ts +5 -5
  364. package/dist/src/tools/mcp-client.js +40 -35
  365. package/dist/src/tools/mcp-client.js.map +1 -1
  366. package/dist/src/tools/mcp-client.test.js +3 -3
  367. package/dist/src/tools/mcp-client.test.js.map +1 -1
  368. package/dist/src/tools/mcp-tool.d.ts +3 -2
  369. package/dist/src/tools/mcp-tool.js +9 -9
  370. package/dist/src/tools/mcp-tool.js.map +1 -1
  371. package/dist/src/tools/mcp-tool.test.js +28 -7
  372. package/dist/src/tools/mcp-tool.test.js.map +1 -1
  373. package/dist/src/tools/memoryTool.js +5 -33
  374. package/dist/src/tools/memoryTool.js.map +1 -1
  375. package/dist/src/tools/read-file.js +8 -3
  376. package/dist/src/tools/read-file.js.map +1 -1
  377. package/dist/src/tools/read-file.test.js +29 -0
  378. package/dist/src/tools/read-file.test.js.map +1 -1
  379. package/dist/src/tools/read-many-files.d.ts +1 -1
  380. package/dist/src/tools/read-many-files.js +18 -50
  381. package/dist/src/tools/read-many-files.js.map +1 -1
  382. package/dist/src/tools/read-many-files.test.js +4 -4
  383. package/dist/src/tools/read-many-files.test.js.map +1 -1
  384. package/dist/src/tools/ripGrep.d.ts +8 -0
  385. package/dist/src/tools/ripGrep.js +26 -1
  386. package/dist/src/tools/ripGrep.js.map +1 -1
  387. package/dist/src/tools/ripGrep.test.js +107 -5
  388. package/dist/src/tools/ripGrep.test.js.map +1 -1
  389. package/dist/src/tools/shell.d.ts +12 -2
  390. package/dist/src/tools/shell.js +20 -24
  391. package/dist/src/tools/shell.js.map +1 -1
  392. package/dist/src/tools/shell.test.js +35 -70
  393. package/dist/src/tools/shell.test.js.map +1 -1
  394. package/dist/src/tools/smart-edit.d.ts +72 -0
  395. package/dist/src/tools/smart-edit.js +594 -0
  396. package/dist/src/tools/smart-edit.js.map +1 -0
  397. package/dist/src/tools/smart-edit.test.d.ts +6 -0
  398. package/dist/src/tools/smart-edit.test.js +419 -0
  399. package/dist/src/tools/smart-edit.test.js.map +1 -0
  400. package/dist/src/tools/tool-registry.d.ts +2 -1
  401. package/dist/src/tools/tool-registry.js +6 -5
  402. package/dist/src/tools/tool-registry.js.map +1 -1
  403. package/dist/src/tools/tools.d.ts +14 -7
  404. package/dist/src/tools/tools.js +9 -2
  405. package/dist/src/tools/tools.js.map +1 -1
  406. package/dist/src/tools/web-fetch.js +4 -3
  407. package/dist/src/tools/web-fetch.js.map +1 -1
  408. package/dist/src/tools/web-search.d.ts +1 -1
  409. package/dist/src/tools/web-search.js +3 -1
  410. package/dist/src/tools/web-search.js.map +1 -1
  411. package/dist/src/tools/write-file.js +14 -19
  412. package/dist/src/tools/write-file.js.map +1 -1
  413. package/dist/src/tools/write-file.test.js +99 -19
  414. package/dist/src/tools/write-file.test.js.map +1 -1
  415. package/dist/src/utils/bfsFileSearch.js +11 -5
  416. package/dist/src/utils/bfsFileSearch.js.map +1 -1
  417. package/dist/src/utils/editCorrector.d.ts +7 -6
  418. package/dist/src/utils/editCorrector.js +61 -18
  419. package/dist/src/utils/editCorrector.js.map +1 -1
  420. package/dist/src/utils/editCorrector.test.js +30 -79
  421. package/dist/src/utils/editCorrector.test.js.map +1 -1
  422. package/dist/src/utils/editor.js +31 -44
  423. package/dist/src/utils/editor.js.map +1 -1
  424. package/dist/src/utils/editor.test.js +61 -75
  425. package/dist/src/utils/editor.test.js.map +1 -1
  426. package/dist/src/utils/errorParsing.js +2 -2
  427. package/dist/src/utils/errorParsing.js.map +1 -1
  428. package/dist/src/utils/errorParsing.test.js +7 -7
  429. package/dist/src/utils/errorParsing.test.js.map +1 -1
  430. package/dist/src/utils/errors.d.ts +6 -0
  431. package/dist/src/utils/errors.js +10 -0
  432. package/dist/src/utils/errors.js.map +1 -1
  433. package/dist/src/utils/fileUtils.d.ts +20 -3
  434. package/dist/src/utils/fileUtils.js +154 -32
  435. package/dist/src/utils/fileUtils.js.map +1 -1
  436. package/dist/src/utils/fileUtils.test.js +347 -29
  437. package/dist/src/utils/fileUtils.test.js.map +1 -1
  438. package/dist/src/utils/flashFallback.test.d.ts +6 -0
  439. package/dist/src/utils/{flashFallback.integration.test.js → flashFallback.test.js} +31 -27
  440. package/dist/src/utils/flashFallback.test.js.map +1 -0
  441. package/dist/src/utils/geminiIgnoreParser.d.ts +18 -0
  442. package/dist/src/utils/geminiIgnoreParser.js +61 -0
  443. package/dist/src/utils/geminiIgnoreParser.js.map +1 -0
  444. package/dist/src/utils/geminiIgnoreParser.test.d.ts +6 -0
  445. package/dist/src/utils/geminiIgnoreParser.test.js +50 -0
  446. package/dist/src/utils/geminiIgnoreParser.test.js.map +1 -0
  447. package/dist/src/utils/gitIgnoreParser.d.ts +3 -7
  448. package/dist/src/utils/gitIgnoreParser.js +125 -34
  449. package/dist/src/utils/gitIgnoreParser.js.map +1 -1
  450. package/dist/src/utils/gitIgnoreParser.test.js +66 -35
  451. package/dist/src/utils/gitIgnoreParser.test.js.map +1 -1
  452. package/dist/src/utils/llm-edit-fixer.d.ts +26 -0
  453. package/dist/src/utils/llm-edit-fixer.js +121 -0
  454. package/dist/src/utils/llm-edit-fixer.js.map +1 -0
  455. package/dist/src/utils/llm-edit-fixer.test.d.ts +6 -0
  456. package/dist/src/utils/llm-edit-fixer.test.js +105 -0
  457. package/dist/src/utils/llm-edit-fixer.test.js.map +1 -0
  458. package/dist/src/utils/memoryDiscovery.d.ts +5 -4
  459. package/dist/src/utils/memoryDiscovery.js +10 -9
  460. package/dist/src/utils/memoryDiscovery.js.map +1 -1
  461. package/dist/src/utils/memoryDiscovery.test.js +50 -25
  462. package/dist/src/utils/memoryDiscovery.test.js.map +1 -1
  463. package/dist/src/utils/nextSpeakerChecker.d.ts +2 -2
  464. package/dist/src/utils/nextSpeakerChecker.js +8 -2
  465. package/dist/src/utils/nextSpeakerChecker.js.map +1 -1
  466. package/dist/src/utils/nextSpeakerChecker.test.js +75 -64
  467. package/dist/src/utils/nextSpeakerChecker.test.js.map +1 -1
  468. package/dist/src/utils/promptIdContext.d.ts +7 -0
  469. package/dist/src/utils/promptIdContext.js +8 -0
  470. package/dist/src/utils/promptIdContext.js.map +1 -0
  471. package/dist/src/utils/shell-utils.d.ts +5 -0
  472. package/dist/src/utils/shell-utils.js +23 -0
  473. package/dist/src/utils/shell-utils.js.map +1 -1
  474. package/dist/src/utils/terminalSerializer.d.ts +28 -0
  475. package/dist/src/utils/terminalSerializer.js +432 -0
  476. package/dist/src/utils/terminalSerializer.js.map +1 -0
  477. package/dist/src/utils/terminalSerializer.test.d.ts +6 -0
  478. package/dist/src/utils/terminalSerializer.test.js +176 -0
  479. package/dist/src/utils/terminalSerializer.test.js.map +1 -0
  480. package/dist/src/utils/textUtils.d.ts +5 -0
  481. package/dist/src/utils/textUtils.js +14 -0
  482. package/dist/src/utils/textUtils.js.map +1 -1
  483. package/dist/src/utils/textUtils.test.d.ts +6 -0
  484. package/dist/src/utils/textUtils.test.js +59 -0
  485. package/dist/src/utils/textUtils.test.js.map +1 -0
  486. package/dist/tsconfig.tsbuildinfo +1 -1
  487. package/package.json +9 -3
  488. package/dist/google-gemini-cli-core-0.3.0-preview.3.tgz +0 -0
  489. package/dist/src/utils/flashFallback.integration.test.js.map +0 -1
  490. /package/dist/src/{utils/flashFallback.integration.test.d.ts → code_assist/oauth-credential-storage.test.d.ts} +0 -0
@@ -6,6 +6,7 @@
6
6
  import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
7
7
  import { Turn, GeminiEventType } from './turn.js';
8
8
  import { reportError } from '../utils/errorReporting.js';
9
+ import { StreamEventType } from './geminiChat.js';
9
10
  const mockSendMessageStream = vi.fn();
10
11
  const mockGetHistory = vi.fn();
11
12
  const mockMaybeIncludeSchemaDepthContext = vi.fn();
@@ -24,6 +25,7 @@ vi.mock('@google/genai', async (importOriginal) => {
24
25
  vi.mock('../utils/errorReporting', () => ({
25
26
  reportError: vi.fn(),
26
27
  }));
28
+ // Use the actual implementation from partUtils now that it's provided.
27
29
  vi.mock('../utils/generateContentResponseUtilities', () => ({
28
30
  getResponseText: (resp) => resp.candidates?.[0]?.content?.parts?.map((part) => part.text).join('') ||
29
31
  undefined,
@@ -55,19 +57,25 @@ describe('Turn', () => {
55
57
  it('should yield content events for text parts', async () => {
56
58
  const mockResponseStream = (async function* () {
57
59
  yield {
58
- candidates: [{ content: { parts: [{ text: 'Hello' }] } }],
60
+ type: StreamEventType.CHUNK,
61
+ value: {
62
+ candidates: [{ content: { parts: [{ text: 'Hello' }] } }],
63
+ },
59
64
  };
60
65
  yield {
61
- candidates: [{ content: { parts: [{ text: ' world' }] } }],
66
+ type: StreamEventType.CHUNK,
67
+ value: {
68
+ candidates: [{ content: { parts: [{ text: ' world' }] } }],
69
+ },
62
70
  };
63
71
  })();
64
72
  mockSendMessageStream.mockResolvedValue(mockResponseStream);
65
73
  const events = [];
66
74
  const reqParts = [{ text: 'Hi' }];
67
- for await (const event of turn.run(reqParts, new AbortController().signal)) {
75
+ for await (const event of turn.run('test-model', reqParts, new AbortController().signal)) {
68
76
  events.push(event);
69
77
  }
70
- expect(mockSendMessageStream).toHaveBeenCalledWith({
78
+ expect(mockSendMessageStream).toHaveBeenCalledWith('test-model', {
71
79
  message: reqParts,
72
80
  config: { abortSignal: expect.any(AbortSignal) },
73
81
  }, 'prompt-id-1');
@@ -80,21 +88,28 @@ describe('Turn', () => {
80
88
  it('should yield tool_call_request events for function calls', async () => {
81
89
  const mockResponseStream = (async function* () {
82
90
  yield {
83
- functionCalls: [
84
- {
85
- id: 'fc1',
86
- name: 'tool1',
87
- args: { arg1: 'val1' },
88
- isClientInitiated: false,
89
- },
90
- { name: 'tool2', args: { arg2: 'val2' }, isClientInitiated: false }, // No ID
91
- ],
91
+ type: StreamEventType.CHUNK,
92
+ value: {
93
+ functionCalls: [
94
+ {
95
+ id: 'fc1',
96
+ name: 'tool1',
97
+ args: { arg1: 'val1' },
98
+ isClientInitiated: false,
99
+ },
100
+ {
101
+ name: 'tool2',
102
+ args: { arg2: 'val2' },
103
+ isClientInitiated: false,
104
+ }, // No ID
105
+ ],
106
+ },
92
107
  };
93
108
  })();
94
109
  mockSendMessageStream.mockResolvedValue(mockResponseStream);
95
110
  const events = [];
96
111
  const reqParts = [{ text: 'Use tools' }];
97
- for await (const event of turn.run(reqParts, new AbortController().signal)) {
112
+ for await (const event of turn.run('test-model', reqParts, new AbortController().signal)) {
98
113
  events.push(event);
99
114
  }
100
115
  expect(events.length).toBe(2);
@@ -122,23 +137,29 @@ describe('Turn', () => {
122
137
  const abortController = new AbortController();
123
138
  const mockResponseStream = (async function* () {
124
139
  yield {
125
- candidates: [{ content: { parts: [{ text: 'First part' }] } }],
140
+ type: StreamEventType.CHUNK,
141
+ value: {
142
+ candidates: [{ content: { parts: [{ text: 'First part' }] } }],
143
+ },
126
144
  };
127
145
  abortController.abort();
128
146
  yield {
129
- candidates: [
130
- {
131
- content: {
132
- parts: [{ text: 'Second part - should not be processed' }],
147
+ type: StreamEventType.CHUNK,
148
+ value: {
149
+ candidates: [
150
+ {
151
+ content: {
152
+ parts: [{ text: 'Second part - should not be processed' }],
153
+ },
133
154
  },
134
- },
135
- ],
155
+ ],
156
+ },
136
157
  };
137
158
  })();
138
159
  mockSendMessageStream.mockResolvedValue(mockResponseStream);
139
160
  const events = [];
140
161
  const reqParts = [{ text: 'Test abort' }];
141
- for await (const event of turn.run(reqParts, abortController.signal)) {
162
+ for await (const event of turn.run('test-model', reqParts, abortController.signal)) {
142
163
  events.push(event);
143
164
  }
144
165
  expect(events).toEqual([
@@ -157,7 +178,7 @@ describe('Turn', () => {
157
178
  mockGetHistory.mockReturnValue(historyContent);
158
179
  mockMaybeIncludeSchemaDepthContext.mockResolvedValue(undefined);
159
180
  const events = [];
160
- for await (const event of turn.run(reqParts, new AbortController().signal)) {
181
+ for await (const event of turn.run('test-model', reqParts, new AbortController().signal)) {
161
182
  events.push(event);
162
183
  }
163
184
  expect(events.length).toBe(1);
@@ -172,90 +193,109 @@ describe('Turn', () => {
172
193
  it('should handle function calls with undefined name or args', async () => {
173
194
  const mockResponseStream = (async function* () {
174
195
  yield {
175
- functionCalls: [
176
- { id: 'fc1', name: undefined, args: { arg1: 'val1' } },
177
- { id: 'fc2', name: 'tool2', args: undefined },
178
- { id: 'fc3', name: undefined, args: undefined },
179
- ],
196
+ type: StreamEventType.CHUNK,
197
+ value: {
198
+ candidates: [],
199
+ functionCalls: [
200
+ // Add `id` back to the mock to match what the code expects
201
+ { id: 'fc1', name: undefined, args: { arg1: 'val1' } },
202
+ { id: 'fc2', name: 'tool2', args: undefined },
203
+ { id: 'fc3', name: undefined, args: undefined },
204
+ ],
205
+ },
180
206
  };
181
207
  })();
182
208
  mockSendMessageStream.mockResolvedValue(mockResponseStream);
183
209
  const events = [];
184
- const reqParts = [{ text: 'Test undefined tool parts' }];
185
- for await (const event of turn.run(reqParts, new AbortController().signal)) {
210
+ for await (const event of turn.run('test-model', [{ text: 'Test undefined tool parts' }], new AbortController().signal)) {
186
211
  events.push(event);
187
212
  }
188
213
  expect(events.length).toBe(3);
214
+ // Assertions for each specific tool call event
189
215
  const event1 = events[0];
190
- expect(event1.type).toBe(GeminiEventType.ToolCallRequest);
191
- expect(event1.value).toEqual(expect.objectContaining({
216
+ expect(event1.value).toMatchObject({
192
217
  callId: 'fc1',
193
218
  name: 'undefined_tool_name',
194
219
  args: { arg1: 'val1' },
195
- isClientInitiated: false,
196
- }));
197
- expect(turn.pendingToolCalls[0]).toEqual(event1.value);
220
+ });
198
221
  const event2 = events[1];
199
- expect(event2.type).toBe(GeminiEventType.ToolCallRequest);
200
- expect(event2.value).toEqual(expect.objectContaining({
222
+ expect(event2.value).toMatchObject({
201
223
  callId: 'fc2',
202
224
  name: 'tool2',
203
225
  args: {},
204
- isClientInitiated: false,
205
- }));
206
- expect(turn.pendingToolCalls[1]).toEqual(event2.value);
226
+ });
207
227
  const event3 = events[2];
208
- expect(event3.type).toBe(GeminiEventType.ToolCallRequest);
209
- expect(event3.value).toEqual(expect.objectContaining({
228
+ expect(event3.value).toMatchObject({
210
229
  callId: 'fc3',
211
230
  name: 'undefined_tool_name',
212
231
  args: {},
213
- isClientInitiated: false,
214
- }));
215
- expect(turn.pendingToolCalls[2]).toEqual(event3.value);
216
- expect(turn.getDebugResponses().length).toBe(1);
232
+ });
217
233
  });
218
234
  it('should yield finished event when response has finish reason', async () => {
219
235
  const mockResponseStream = (async function* () {
220
236
  yield {
221
- candidates: [
222
- {
223
- content: { parts: [{ text: 'Partial response' }] },
224
- finishReason: 'STOP',
237
+ type: StreamEventType.CHUNK,
238
+ value: {
239
+ candidates: [
240
+ {
241
+ content: { parts: [{ text: 'Partial response' }] },
242
+ finishReason: 'STOP',
243
+ },
244
+ ],
245
+ usageMetadata: {
246
+ promptTokenCount: 17,
247
+ candidatesTokenCount: 50,
248
+ cachedContentTokenCount: 10,
249
+ thoughtsTokenCount: 5,
250
+ toolUsePromptTokenCount: 2,
225
251
  },
226
- ],
252
+ },
227
253
  };
228
254
  })();
229
255
  mockSendMessageStream.mockResolvedValue(mockResponseStream);
230
256
  const events = [];
231
- const reqParts = [{ text: 'Test finish reason' }];
232
- for await (const event of turn.run(reqParts, new AbortController().signal)) {
257
+ for await (const event of turn.run('test-model', [{ text: 'Test finish reason' }], new AbortController().signal)) {
233
258
  events.push(event);
234
259
  }
235
260
  expect(events).toEqual([
236
261
  { type: GeminiEventType.Content, value: 'Partial response' },
237
- { type: GeminiEventType.Finished, value: 'STOP' },
262
+ {
263
+ type: GeminiEventType.Finished,
264
+ value: {
265
+ reason: 'STOP',
266
+ usageMetadata: {
267
+ promptTokenCount: 17,
268
+ candidatesTokenCount: 50,
269
+ cachedContentTokenCount: 10,
270
+ thoughtsTokenCount: 5,
271
+ toolUsePromptTokenCount: 2,
272
+ },
273
+ },
274
+ },
238
275
  ]);
239
276
  });
240
277
  it('should yield finished event for MAX_TOKENS finish reason', async () => {
241
278
  const mockResponseStream = (async function* () {
242
279
  yield {
243
- candidates: [
244
- {
245
- content: {
246
- parts: [
247
- { text: 'This is a long response that was cut off...' },
248
- ],
280
+ type: StreamEventType.CHUNK,
281
+ value: {
282
+ candidates: [
283
+ {
284
+ content: {
285
+ parts: [
286
+ { text: 'This is a long response that was cut off...' },
287
+ ],
288
+ },
289
+ finishReason: 'MAX_TOKENS',
249
290
  },
250
- finishReason: 'MAX_TOKENS',
251
- },
252
- ],
291
+ ],
292
+ },
253
293
  };
254
294
  })();
255
295
  mockSendMessageStream.mockResolvedValue(mockResponseStream);
256
296
  const events = [];
257
297
  const reqParts = [{ text: 'Generate long text' }];
258
- for await (const event of turn.run(reqParts, new AbortController().signal)) {
298
+ for await (const event of turn.run('test-model', reqParts, new AbortController().signal)) {
259
299
  events.push(event);
260
300
  }
261
301
  expect(events).toEqual([
@@ -263,46 +303,60 @@ describe('Turn', () => {
263
303
  type: GeminiEventType.Content,
264
304
  value: 'This is a long response that was cut off...',
265
305
  },
266
- { type: GeminiEventType.Finished, value: 'MAX_TOKENS' },
306
+ {
307
+ type: GeminiEventType.Finished,
308
+ value: { reason: 'MAX_TOKENS', usageMetadata: undefined },
309
+ },
267
310
  ]);
268
311
  });
269
312
  it('should yield finished event for SAFETY finish reason', async () => {
270
313
  const mockResponseStream = (async function* () {
271
314
  yield {
272
- candidates: [
273
- {
274
- content: { parts: [{ text: 'Content blocked' }] },
275
- finishReason: 'SAFETY',
276
- },
277
- ],
315
+ type: StreamEventType.CHUNK,
316
+ value: {
317
+ candidates: [
318
+ {
319
+ content: { parts: [{ text: 'Content blocked' }] },
320
+ finishReason: 'SAFETY',
321
+ },
322
+ ],
323
+ },
278
324
  };
279
325
  })();
280
326
  mockSendMessageStream.mockResolvedValue(mockResponseStream);
281
327
  const events = [];
282
328
  const reqParts = [{ text: 'Test safety' }];
283
- for await (const event of turn.run(reqParts, new AbortController().signal)) {
329
+ for await (const event of turn.run('test-model', reqParts, new AbortController().signal)) {
284
330
  events.push(event);
285
331
  }
286
332
  expect(events).toEqual([
287
333
  { type: GeminiEventType.Content, value: 'Content blocked' },
288
- { type: GeminiEventType.Finished, value: 'SAFETY' },
334
+ {
335
+ type: GeminiEventType.Finished,
336
+ value: { reason: 'SAFETY', usageMetadata: undefined },
337
+ },
289
338
  ]);
290
339
  });
291
- it('should not yield finished event when there is no finish reason', async () => {
340
+ it('should yield finished event with undefined reason when there is no finish reason', async () => {
292
341
  const mockResponseStream = (async function* () {
293
342
  yield {
294
- candidates: [
295
- {
296
- content: { parts: [{ text: 'Response without finish reason' }] },
297
- // No finishReason property
298
- },
299
- ],
343
+ type: StreamEventType.CHUNK,
344
+ value: {
345
+ candidates: [
346
+ {
347
+ content: {
348
+ parts: [{ text: 'Response without finish reason' }],
349
+ },
350
+ // No finishReason property
351
+ },
352
+ ],
353
+ },
300
354
  };
301
355
  })();
302
356
  mockSendMessageStream.mockResolvedValue(mockResponseStream);
303
357
  const events = [];
304
358
  const reqParts = [{ text: 'Test no finish reason' }];
305
- for await (const event of turn.run(reqParts, new AbortController().signal)) {
359
+ for await (const event of turn.run('test-model', reqParts, new AbortController().signal)) {
306
360
  events.push(event);
307
361
  }
308
362
  expect(events).toEqual([
@@ -311,37 +365,203 @@ describe('Turn', () => {
311
365
  value: 'Response without finish reason',
312
366
  },
313
367
  ]);
314
- // No Finished event should be emitted
315
368
  });
316
369
  it('should handle multiple responses with different finish reasons', async () => {
317
370
  const mockResponseStream = (async function* () {
318
371
  yield {
319
- candidates: [
320
- {
321
- content: { parts: [{ text: 'First part' }] },
322
- // No finish reason on first response
323
- },
324
- ],
372
+ type: StreamEventType.CHUNK,
373
+ value: {
374
+ candidates: [
375
+ {
376
+ content: { parts: [{ text: 'First part' }] },
377
+ // No finish reason on first response
378
+ },
379
+ ],
380
+ },
325
381
  };
326
382
  yield {
327
- candidates: [
328
- {
329
- content: { parts: [{ text: 'Second part' }] },
330
- finishReason: 'OTHER',
331
- },
332
- ],
383
+ value: {
384
+ type: StreamEventType.CHUNK,
385
+ candidates: [
386
+ {
387
+ content: { parts: [{ text: 'Second part' }] },
388
+ finishReason: 'OTHER',
389
+ },
390
+ ],
391
+ },
333
392
  };
334
393
  })();
335
394
  mockSendMessageStream.mockResolvedValue(mockResponseStream);
336
395
  const events = [];
337
396
  const reqParts = [{ text: 'Test multiple responses' }];
338
- for await (const event of turn.run(reqParts, new AbortController().signal)) {
397
+ for await (const event of turn.run('test-model', reqParts, new AbortController().signal)) {
339
398
  events.push(event);
340
399
  }
341
400
  expect(events).toEqual([
342
401
  { type: GeminiEventType.Content, value: 'First part' },
343
402
  { type: GeminiEventType.Content, value: 'Second part' },
344
- { type: GeminiEventType.Finished, value: 'OTHER' },
403
+ {
404
+ type: GeminiEventType.Finished,
405
+ value: { reason: 'OTHER', usageMetadata: undefined },
406
+ },
407
+ ]);
408
+ });
409
+ it('should yield citation and finished events when response has citationMetadata', async () => {
410
+ const mockResponseStream = (async function* () {
411
+ yield {
412
+ type: StreamEventType.CHUNK,
413
+ value: {
414
+ candidates: [
415
+ {
416
+ content: { parts: [{ text: 'Some text.' }] },
417
+ citationMetadata: {
418
+ citations: [
419
+ {
420
+ uri: 'https://example.com/source1',
421
+ title: 'Source 1 Title',
422
+ },
423
+ ],
424
+ },
425
+ finishReason: 'STOP',
426
+ },
427
+ ],
428
+ },
429
+ };
430
+ })();
431
+ mockSendMessageStream.mockResolvedValue(mockResponseStream);
432
+ const events = [];
433
+ for await (const event of turn.run('test-model', [{ text: 'Test citations' }], new AbortController().signal)) {
434
+ events.push(event);
435
+ }
436
+ expect(events).toEqual([
437
+ { type: GeminiEventType.Content, value: 'Some text.' },
438
+ {
439
+ type: GeminiEventType.Citation,
440
+ value: 'Citations:\n(Source 1 Title) https://example.com/source1',
441
+ },
442
+ {
443
+ type: GeminiEventType.Finished,
444
+ value: { reason: 'STOP', usageMetadata: undefined },
445
+ },
446
+ ]);
447
+ });
448
+ it('should yield a single citation event for multiple citations in one response', async () => {
449
+ const mockResponseStream = (async function* () {
450
+ yield {
451
+ type: StreamEventType.CHUNK,
452
+ value: {
453
+ candidates: [
454
+ {
455
+ content: { parts: [{ text: 'Some text.' }] },
456
+ citationMetadata: {
457
+ citations: [
458
+ {
459
+ uri: 'https://example.com/source2',
460
+ title: 'Title2',
461
+ },
462
+ {
463
+ uri: 'https://example.com/source1',
464
+ title: 'Title1',
465
+ },
466
+ ],
467
+ },
468
+ finishReason: 'STOP',
469
+ },
470
+ ],
471
+ },
472
+ };
473
+ })();
474
+ mockSendMessageStream.mockResolvedValue(mockResponseStream);
475
+ const events = [];
476
+ for await (const event of turn.run('test-model', [{ text: 'test' }], new AbortController().signal)) {
477
+ events.push(event);
478
+ }
479
+ expect(events).toEqual([
480
+ { type: GeminiEventType.Content, value: 'Some text.' },
481
+ {
482
+ type: GeminiEventType.Citation,
483
+ value: 'Citations:\n(Title1) https://example.com/source1\n(Title2) https://example.com/source2',
484
+ },
485
+ {
486
+ type: GeminiEventType.Finished,
487
+ value: { reason: 'STOP', usageMetadata: undefined },
488
+ },
489
+ ]);
490
+ });
491
+ it('should not yield citation event if there is no finish reason', async () => {
492
+ const mockResponseStream = (async function* () {
493
+ yield {
494
+ type: StreamEventType.CHUNK,
495
+ value: {
496
+ candidates: [
497
+ {
498
+ content: { parts: [{ text: 'Some text.' }] },
499
+ citationMetadata: {
500
+ citations: [
501
+ {
502
+ uri: 'https://example.com/source1',
503
+ title: 'Source 1 Title',
504
+ },
505
+ ],
506
+ },
507
+ // No finishReason
508
+ },
509
+ ],
510
+ },
511
+ };
512
+ })();
513
+ mockSendMessageStream.mockResolvedValue(mockResponseStream);
514
+ const events = [];
515
+ for await (const event of turn.run('test-model', [{ text: 'test' }], new AbortController().signal)) {
516
+ events.push(event);
517
+ }
518
+ expect(events).toEqual([
519
+ { type: GeminiEventType.Content, value: 'Some text.' },
520
+ ]);
521
+ // No Citation event (but we do get a Finished event with undefined reason)
522
+ expect(events.some((e) => e.type === GeminiEventType.Citation)).toBe(false);
523
+ });
524
+ it('should ignore citations without a URI', async () => {
525
+ const mockResponseStream = (async function* () {
526
+ yield {
527
+ type: StreamEventType.CHUNK,
528
+ value: {
529
+ candidates: [
530
+ {
531
+ content: { parts: [{ text: 'Some text.' }] },
532
+ citationMetadata: {
533
+ citations: [
534
+ {
535
+ uri: 'https://example.com/source1',
536
+ title: 'Good Source',
537
+ },
538
+ {
539
+ // uri is undefined
540
+ title: 'Bad Source',
541
+ },
542
+ ],
543
+ },
544
+ finishReason: 'STOP',
545
+ },
546
+ ],
547
+ },
548
+ };
549
+ })();
550
+ mockSendMessageStream.mockResolvedValue(mockResponseStream);
551
+ const events = [];
552
+ for await (const event of turn.run('test-model', [{ text: 'test' }], new AbortController().signal)) {
553
+ events.push(event);
554
+ }
555
+ expect(events).toEqual([
556
+ { type: GeminiEventType.Content, value: 'Some text.' },
557
+ {
558
+ type: GeminiEventType.Citation,
559
+ value: 'Citations:\n(Good Source) https://example.com/source1',
560
+ },
561
+ {
562
+ type: GeminiEventType.Finished,
563
+ value: { reason: 'STOP', usageMetadata: undefined },
564
+ },
345
565
  ]);
346
566
  });
347
567
  it('should not crash when cancelled request has malformed error', async () => {
@@ -357,12 +577,32 @@ describe('Turn', () => {
357
577
  });
358
578
  const events = [];
359
579
  const reqParts = [{ text: 'Test malformed error handling' }];
360
- for await (const event of turn.run(reqParts, abortController.signal)) {
580
+ for await (const event of turn.run('test-model', reqParts, abortController.signal)) {
361
581
  events.push(event);
362
582
  }
363
583
  expect(events).toEqual([{ type: GeminiEventType.UserCancelled }]);
364
584
  expect(reportError).not.toHaveBeenCalled();
365
585
  });
586
+ it('should yield a Retry event when it receives one from the chat stream', async () => {
587
+ const mockResponseStream = (async function* () {
588
+ yield { type: StreamEventType.RETRY };
589
+ yield {
590
+ type: StreamEventType.CHUNK,
591
+ value: {
592
+ candidates: [{ content: { parts: [{ text: 'Success' }] } }],
593
+ },
594
+ };
595
+ })();
596
+ mockSendMessageStream.mockResolvedValue(mockResponseStream);
597
+ const events = [];
598
+ for await (const event of turn.run('test-model', [], new AbortController().signal)) {
599
+ events.push(event);
600
+ }
601
+ expect(events).toEqual([
602
+ { type: GeminiEventType.Retry },
603
+ { type: GeminiEventType.Content, value: 'Success' },
604
+ ]);
605
+ });
366
606
  });
367
607
  describe('getDebugResponses', () => {
368
608
  it('should return collected debug responses', async () => {
@@ -373,12 +613,12 @@ describe('Turn', () => {
373
613
  functionCalls: [{ name: 'debugTool' }],
374
614
  };
375
615
  const mockResponseStream = (async function* () {
376
- yield resp1;
377
- yield resp2;
616
+ yield { type: StreamEventType.CHUNK, value: resp1 };
617
+ yield { type: StreamEventType.CHUNK, value: resp2 };
378
618
  })();
379
619
  mockSendMessageStream.mockResolvedValue(mockResponseStream);
380
620
  const reqParts = [{ text: 'Hi' }];
381
- for await (const _ of turn.run(reqParts, new AbortController().signal)) {
621
+ for await (const _ of turn.run('test-model', reqParts, new AbortController().signal)) {
382
622
  // consume stream
383
623
  }
384
624
  expect(turn.getDebugResponses()).toEqual([resp1, resp2]);