@machina.ai/cell-cli-core 1.10.0-rc1 → 1.13.0-rc1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (549) hide show
  1. package/dist/index.d.ts +5 -0
  2. package/dist/index.js +4 -0
  3. package/dist/index.js.map +1 -1
  4. package/dist/package.json +13 -5
  5. package/dist/src/agents/codebase-investigator.js +2 -5
  6. package/dist/src/agents/codebase-investigator.js.map +1 -1
  7. package/dist/src/agents/executor.d.ts +19 -0
  8. package/dist/src/agents/executor.js +234 -46
  9. package/dist/src/agents/executor.js.map +1 -1
  10. package/dist/src/agents/executor.test.js +371 -40
  11. package/dist/src/agents/executor.test.js.map +1 -1
  12. package/dist/src/agents/registry.js +4 -3
  13. package/dist/src/agents/registry.js.map +1 -1
  14. package/dist/src/agents/subagent-tool-wrapper.test.js +2 -4
  15. package/dist/src/agents/subagent-tool-wrapper.test.js.map +1 -1
  16. package/dist/src/agents/types.d.ts +2 -1
  17. package/dist/src/agents/types.js +1 -0
  18. package/dist/src/agents/types.js.map +1 -1
  19. package/dist/src/code_assist/converter.d.ts +1 -0
  20. package/dist/src/code_assist/converter.js +1 -0
  21. package/dist/src/code_assist/converter.js.map +1 -1
  22. package/dist/src/code_assist/converter.test.js +19 -0
  23. package/dist/src/code_assist/converter.test.js.map +1 -1
  24. package/dist/src/code_assist/experiments/client_metadata.d.ts +12 -0
  25. package/dist/src/code_assist/experiments/client_metadata.js +49 -0
  26. package/dist/src/code_assist/experiments/client_metadata.js.map +1 -0
  27. package/dist/src/code_assist/experiments/experiments.d.ts +17 -0
  28. package/dist/src/code_assist/experiments/experiments.js +36 -0
  29. package/dist/src/code_assist/experiments/experiments.js.map +1 -0
  30. package/dist/src/code_assist/experiments/types.d.ts +35 -0
  31. package/dist/src/code_assist/experiments/types.js +7 -0
  32. package/dist/src/code_assist/experiments/types.js.map +1 -0
  33. package/dist/src/code_assist/oauth-credential-storage.js +5 -4
  34. package/dist/src/code_assist/oauth-credential-storage.js.map +1 -1
  35. package/dist/src/code_assist/oauth-credential-storage.test.js +15 -3
  36. package/dist/src/code_assist/oauth-credential-storage.test.js.map +1 -1
  37. package/dist/src/code_assist/oauth2.d.ts +2 -2
  38. package/dist/src/code_assist/oauth2.js +64 -51
  39. package/dist/src/code_assist/oauth2.js.map +1 -1
  40. package/dist/src/code_assist/oauth2.test.js +65 -33
  41. package/dist/src/code_assist/oauth2.test.js.map +1 -1
  42. package/dist/src/code_assist/server.d.ts +6 -4
  43. package/dist/src/code_assist/server.js +11 -0
  44. package/dist/src/code_assist/server.js.map +1 -1
  45. package/dist/src/code_assist/server.test.js +17 -0
  46. package/dist/src/code_assist/server.test.js.map +1 -1
  47. package/dist/src/code_assist/setup.d.ts +2 -2
  48. package/dist/src/code_assist/setup.js.map +1 -1
  49. package/dist/src/code_assist/types.d.ts +1 -1
  50. package/dist/src/code_assist/types.js.map +1 -1
  51. package/dist/src/commands/extensions.d.ts +7 -0
  52. package/dist/src/commands/extensions.js +9 -0
  53. package/dist/src/commands/extensions.js.map +1 -0
  54. package/dist/src/commands/extensions.test.js +19 -0
  55. package/dist/src/commands/extensions.test.js.map +1 -0
  56. package/dist/src/config/config.d.ts +81 -32
  57. package/dist/src/config/config.js +193 -66
  58. package/dist/src/config/config.js.map +1 -1
  59. package/dist/src/config/config.test.js +115 -36
  60. package/dist/src/config/config.test.js.map +1 -1
  61. package/dist/src/config/models.d.ts +1 -1
  62. package/dist/src/config/models.js +2 -2
  63. package/dist/src/config/models.js.map +1 -1
  64. package/dist/src/config/storage.d.ts +3 -0
  65. package/dist/src/config/storage.js +20 -0
  66. package/dist/src/config/storage.js.map +1 -1
  67. package/dist/src/confirmation-bus/message-bus.d.ts +2 -1
  68. package/dist/src/confirmation-bus/message-bus.js +7 -1
  69. package/dist/src/confirmation-bus/message-bus.js.map +1 -1
  70. package/dist/src/confirmation-bus/types.d.ts +12 -2
  71. package/dist/src/confirmation-bus/types.js +1 -0
  72. package/dist/src/confirmation-bus/types.js.map +1 -1
  73. package/dist/src/core/apiKeyCredentialStorage.d.ts +17 -0
  74. package/dist/src/core/apiKeyCredentialStorage.js +64 -0
  75. package/dist/src/core/apiKeyCredentialStorage.js.map +1 -0
  76. package/dist/src/core/apiKeyCredentialStorage.test.d.ts +6 -0
  77. package/dist/src/core/apiKeyCredentialStorage.test.js +71 -0
  78. package/dist/src/core/apiKeyCredentialStorage.test.js.map +1 -0
  79. package/dist/src/core/client.d.ts +2 -11
  80. package/dist/src/core/client.js +31 -170
  81. package/dist/src/core/client.js.map +1 -1
  82. package/dist/src/core/client.test.js +107 -429
  83. package/dist/src/core/client.test.js.map +1 -1
  84. package/dist/src/core/contentGenerator.js +64 -59
  85. package/dist/src/core/contentGenerator.js.map +1 -1
  86. package/dist/src/core/contentGenerator.test.js +38 -4
  87. package/dist/src/core/contentGenerator.test.js.map +1 -1
  88. package/dist/src/core/coreToolScheduler.d.ts +8 -2
  89. package/dist/src/core/coreToolScheduler.js +337 -172
  90. package/dist/src/core/coreToolScheduler.js.map +1 -1
  91. package/dist/src/core/coreToolScheduler.test.js +363 -12
  92. package/dist/src/core/coreToolScheduler.test.js.map +1 -1
  93. package/dist/src/core/fakeContentGenerator.d.ts +33 -0
  94. package/dist/src/core/fakeContentGenerator.js +58 -0
  95. package/dist/src/core/fakeContentGenerator.js.map +1 -0
  96. package/dist/src/core/fakeContentGenerator.test.d.ts +6 -0
  97. package/dist/src/core/fakeContentGenerator.test.js +127 -0
  98. package/dist/src/core/fakeContentGenerator.test.js.map +1 -0
  99. package/dist/src/core/geminiChat.d.ts +2 -0
  100. package/dist/src/core/geminiChat.js +7 -2
  101. package/dist/src/core/geminiChat.js.map +1 -1
  102. package/dist/src/core/geminiChat.test.js +15 -3
  103. package/dist/src/core/geminiChat.test.js.map +1 -1
  104. package/dist/src/core/logger.js +21 -19
  105. package/dist/src/core/logger.js.map +1 -1
  106. package/dist/src/core/loggingContentGenerator.d.ts +1 -0
  107. package/dist/src/core/loggingContentGenerator.js +113 -33
  108. package/dist/src/core/loggingContentGenerator.js.map +1 -1
  109. package/dist/src/core/nonInteractiveToolExecutor.js +5 -4
  110. package/dist/src/core/nonInteractiveToolExecutor.js.map +1 -1
  111. package/dist/src/core/nonInteractiveToolExecutor.test.js +3 -0
  112. package/dist/src/core/nonInteractiveToolExecutor.test.js.map +1 -1
  113. package/dist/src/core/prompts.js +115 -72
  114. package/dist/src/core/prompts.js.map +1 -1
  115. package/dist/src/core/prompts.test.js +30 -108
  116. package/dist/src/core/prompts.test.js.map +1 -1
  117. package/dist/src/core/recordingContentGenerator.d.ts +18 -0
  118. package/dist/src/core/recordingContentGenerator.js +77 -0
  119. package/dist/src/core/recordingContentGenerator.js.map +1 -0
  120. package/dist/src/core/recordingContentGenerator.test.d.ts +6 -0
  121. package/dist/src/core/recordingContentGenerator.test.js +101 -0
  122. package/dist/src/core/recordingContentGenerator.test.js.map +1 -0
  123. package/dist/src/core/turn.d.ts +2 -0
  124. package/dist/src/core/turn.js +3 -1
  125. package/dist/src/core/turn.js.map +1 -1
  126. package/dist/src/core/turn.test.js +48 -0
  127. package/dist/src/core/turn.test.js.map +1 -1
  128. package/dist/src/fallback/handler.js +2 -0
  129. package/dist/src/fallback/handler.js.map +1 -1
  130. package/dist/src/generated/git-commit.d.ts +2 -2
  131. package/dist/src/generated/git-commit.js +2 -2
  132. package/dist/src/hooks/hookPlanner.d.ts +46 -0
  133. package/dist/src/hooks/hookPlanner.js +108 -0
  134. package/dist/src/hooks/hookPlanner.js.map +1 -0
  135. package/dist/src/hooks/hookPlanner.test.d.ts +6 -0
  136. package/dist/src/hooks/hookPlanner.test.js +255 -0
  137. package/dist/src/hooks/hookPlanner.test.js.map +1 -0
  138. package/dist/src/hooks/hookRegistry.d.ts +87 -0
  139. package/dist/src/hooks/hookRegistry.js +198 -0
  140. package/dist/src/hooks/hookRegistry.js.map +1 -0
  141. package/dist/src/hooks/hookRegistry.test.d.ts +6 -0
  142. package/dist/src/hooks/hookRegistry.test.js +341 -0
  143. package/dist/src/hooks/hookRegistry.test.js.map +1 -0
  144. package/dist/src/hooks/hookTranslator.d.ts +113 -0
  145. package/dist/src/hooks/hookTranslator.js +232 -0
  146. package/dist/src/hooks/hookTranslator.js.map +1 -0
  147. package/dist/src/hooks/hookTranslator.test.d.ts +6 -0
  148. package/dist/src/hooks/hookTranslator.test.js +192 -0
  149. package/dist/src/hooks/hookTranslator.test.js.map +1 -0
  150. package/dist/src/hooks/types.d.ts +384 -0
  151. package/dist/src/hooks/types.js +284 -0
  152. package/dist/src/hooks/types.js.map +1 -0
  153. package/dist/src/hooks/types.test.d.ts +6 -0
  154. package/dist/src/hooks/types.test.js +35 -0
  155. package/dist/src/hooks/types.test.js.map +1 -0
  156. package/dist/src/ide/ide-client.js +2 -1
  157. package/dist/src/ide/ide-client.js.map +1 -1
  158. package/dist/src/index.d.ts +15 -0
  159. package/dist/src/index.js +18 -0
  160. package/dist/src/index.js.map +1 -1
  161. package/dist/src/mcp/google-auth-provider.d.ts +2 -0
  162. package/dist/src/mcp/google-auth-provider.js +21 -3
  163. package/dist/src/mcp/google-auth-provider.js.map +1 -1
  164. package/dist/src/mcp/google-auth-provider.test.js +42 -9
  165. package/dist/src/mcp/google-auth-provider.test.js.map +1 -1
  166. package/dist/src/mcp/mcpLauncher.d.ts +26 -0
  167. package/dist/src/mcp/mcpLauncher.js +238 -0
  168. package/dist/src/mcp/mcpLauncher.js.map +1 -0
  169. package/dist/src/mcp/oauth-provider.d.ts +8 -5
  170. package/dist/src/mcp/oauth-provider.js +140 -55
  171. package/dist/src/mcp/oauth-provider.js.map +1 -1
  172. package/dist/src/mcp/oauth-provider.test.js +191 -2
  173. package/dist/src/mcp/oauth-provider.test.js.map +1 -1
  174. package/dist/src/mcp/oauth-token-storage.js +5 -4
  175. package/dist/src/mcp/oauth-token-storage.js.map +1 -1
  176. package/dist/src/mcp/oauth-token-storage.test.js +17 -11
  177. package/dist/src/mcp/oauth-token-storage.test.js.map +1 -1
  178. package/dist/src/mcp/oauth-utils.d.ts +7 -0
  179. package/dist/src/mcp/oauth-utils.js +28 -8
  180. package/dist/src/mcp/oauth-utils.js.map +1 -1
  181. package/dist/src/mcp/oauth-utils.test.js +45 -2
  182. package/dist/src/mcp/oauth-utils.test.js.map +1 -1
  183. package/dist/src/mcp/sa-impersonation-provider.d.ts +0 -6
  184. package/dist/src/mcp/sa-impersonation-provider.js +6 -23
  185. package/dist/src/mcp/sa-impersonation-provider.js.map +1 -1
  186. package/dist/src/mcp/token-storage/base-token-storage.test.js +75 -84
  187. package/dist/src/mcp/token-storage/base-token-storage.test.js.map +1 -1
  188. package/dist/src/mcp/token-storage/file-token-storage.js +1 -1
  189. package/dist/src/mcp/token-storage/file-token-storage.js.map +1 -1
  190. package/dist/src/mcp/token-storage/file-token-storage.test.js +7 -5
  191. package/dist/src/mcp/token-storage/file-token-storage.test.js.map +1 -1
  192. package/dist/src/mcp/token-storage/hybrid-token-storage.js +1 -1
  193. package/dist/src/mcp/token-storage/hybrid-token-storage.js.map +1 -1
  194. package/dist/src/mcp/token-storage/hybrid-token-storage.test.js +2 -2
  195. package/dist/src/mcp/token-storage/hybrid-token-storage.test.js.map +1 -1
  196. package/dist/src/mcp/token-storage/keychain-token-storage.d.ts +6 -2
  197. package/dist/src/mcp/token-storage/keychain-token-storage.js +63 -7
  198. package/dist/src/mcp/token-storage/keychain-token-storage.js.map +1 -1
  199. package/dist/src/mcp/token-storage/keychain-token-storage.test.js +54 -3
  200. package/dist/src/mcp/token-storage/keychain-token-storage.test.js.map +1 -1
  201. package/dist/src/mcp/token-storage/types.d.ts +6 -0
  202. package/dist/src/mcp/token-storage/types.js.map +1 -1
  203. package/dist/src/output/stream-json-formatter.d.ts +32 -0
  204. package/dist/src/output/stream-json-formatter.js +52 -0
  205. package/dist/src/output/stream-json-formatter.js.map +1 -0
  206. package/dist/src/output/stream-json-formatter.test.d.ts +6 -0
  207. package/dist/src/output/stream-json-formatter.test.js +479 -0
  208. package/dist/src/output/stream-json-formatter.test.js.map +1 -0
  209. package/dist/src/output/types.d.ts +63 -1
  210. package/dist/src/output/types.js +11 -0
  211. package/dist/src/output/types.js.map +1 -1
  212. package/dist/src/policy/config.d.ts +31 -0
  213. package/dist/src/policy/config.js +197 -0
  214. package/dist/src/policy/config.js.map +1 -0
  215. package/dist/src/policy/config.test.d.ts +6 -0
  216. package/dist/src/policy/config.test.js +404 -0
  217. package/dist/src/policy/config.test.js.map +1 -0
  218. package/dist/src/policy/index.d.ts +2 -0
  219. package/dist/src/policy/index.js +2 -0
  220. package/dist/src/policy/index.js.map +1 -1
  221. package/dist/src/policy/policies/read-only.toml +56 -0
  222. package/dist/src/policy/policies/write.toml +63 -0
  223. package/dist/src/policy/policies/yolo.toml +31 -0
  224. package/dist/src/policy/policy-engine.js +4 -0
  225. package/dist/src/policy/policy-engine.js.map +1 -1
  226. package/dist/src/policy/toml-loader.d.ts +46 -0
  227. package/dist/src/policy/toml-loader.js +314 -0
  228. package/dist/src/policy/toml-loader.js.map +1 -0
  229. package/dist/src/policy/toml-loader.test.d.ts +6 -0
  230. package/dist/src/policy/toml-loader.test.js +522 -0
  231. package/dist/src/policy/toml-loader.test.js.map +1 -0
  232. package/dist/src/policy/types.d.ts +18 -0
  233. package/dist/src/policy/types.js +6 -0
  234. package/dist/src/policy/types.js.map +1 -1
  235. package/dist/src/prompts/prompt-registry.js +2 -1
  236. package/dist/src/prompts/prompt-registry.js.map +1 -1
  237. package/dist/src/routing/strategies/classifierStrategy.js +3 -2
  238. package/dist/src/routing/strategies/classifierStrategy.js.map +1 -1
  239. package/dist/src/services/chatCompressionService.d.ts +32 -0
  240. package/dist/src/services/chatCompressionService.js +162 -0
  241. package/dist/src/services/chatCompressionService.js.map +1 -0
  242. package/dist/src/services/chatCompressionService.test.d.ts +6 -0
  243. package/dist/src/services/chatCompressionService.test.js +209 -0
  244. package/dist/src/services/chatCompressionService.test.js.map +1 -0
  245. package/dist/src/services/chatRecordingService.js +9 -8
  246. package/dist/src/services/chatRecordingService.js.map +1 -1
  247. package/dist/src/services/fileDiscoveryService.d.ts +2 -14
  248. package/dist/src/services/fileDiscoveryService.js +19 -55
  249. package/dist/src/services/fileDiscoveryService.js.map +1 -1
  250. package/dist/src/services/fileDiscoveryService.test.js +91 -11
  251. package/dist/src/services/fileDiscoveryService.test.js.map +1 -1
  252. package/dist/src/services/loopDetectionService.d.ts +1 -1
  253. package/dist/src/services/loopDetectionService.js +27 -13
  254. package/dist/src/services/loopDetectionService.js.map +1 -1
  255. package/dist/src/services/loopDetectionService.test.js +119 -11
  256. package/dist/src/services/loopDetectionService.test.js.map +1 -1
  257. package/dist/src/services/shellExecutionService.js +50 -23
  258. package/dist/src/services/shellExecutionService.js.map +1 -1
  259. package/dist/src/services/shellExecutionService.test.js +82 -15
  260. package/dist/src/services/shellExecutionService.test.js.map +1 -1
  261. package/dist/src/telemetry/activity-monitor.d.ts +116 -0
  262. package/dist/src/telemetry/activity-monitor.js +209 -0
  263. package/dist/src/telemetry/activity-monitor.js.map +1 -0
  264. package/dist/src/telemetry/activity-monitor.test.d.ts +6 -0
  265. package/dist/src/telemetry/activity-monitor.test.js +248 -0
  266. package/dist/src/telemetry/activity-monitor.test.js.map +1 -0
  267. package/dist/src/telemetry/clearcut-logger/clearcut-logger.d.ts +5 -1
  268. package/dist/src/telemetry/clearcut-logger/clearcut-logger.js +135 -57
  269. package/dist/src/telemetry/clearcut-logger/clearcut-logger.js.map +1 -1
  270. package/dist/src/telemetry/clearcut-logger/clearcut-logger.test.js +43 -75
  271. package/dist/src/telemetry/clearcut-logger/clearcut-logger.test.js.map +1 -1
  272. package/dist/src/telemetry/clearcut-logger/event-metadata-key.d.ts +7 -1
  273. package/dist/src/telemetry/clearcut-logger/event-metadata-key.js +13 -1
  274. package/dist/src/telemetry/clearcut-logger/event-metadata-key.js.map +1 -1
  275. package/dist/src/telemetry/gcp-exporters.js +0 -1
  276. package/dist/src/telemetry/gcp-exporters.js.map +1 -1
  277. package/dist/src/telemetry/gcp-exporters.test.js +1 -1
  278. package/dist/src/telemetry/gcp-exporters.test.js.map +1 -1
  279. package/dist/src/telemetry/index.d.ts +4 -2
  280. package/dist/src/telemetry/index.js +5 -3
  281. package/dist/src/telemetry/index.js.map +1 -1
  282. package/dist/src/telemetry/loggers.d.ts +2 -1
  283. package/dist/src/telemetry/loggers.js +37 -26
  284. package/dist/src/telemetry/loggers.js.map +1 -1
  285. package/dist/src/telemetry/loggers.test.js +215 -56
  286. package/dist/src/telemetry/loggers.test.js.map +1 -1
  287. package/dist/src/telemetry/metrics.d.ts +55 -6
  288. package/dist/src/telemetry/metrics.js +89 -1
  289. package/dist/src/telemetry/metrics.js.map +1 -1
  290. package/dist/src/telemetry/metrics.test.js +172 -213
  291. package/dist/src/telemetry/metrics.test.js.map +1 -1
  292. package/dist/src/telemetry/sdk.js +3 -2
  293. package/dist/src/telemetry/sdk.js.map +1 -1
  294. package/dist/src/telemetry/semantic.d.ts +82 -0
  295. package/dist/src/telemetry/semantic.js +269 -0
  296. package/dist/src/telemetry/semantic.js.map +1 -0
  297. package/dist/src/telemetry/semantic.test.d.ts +6 -0
  298. package/dist/src/telemetry/semantic.test.js +387 -0
  299. package/dist/src/telemetry/semantic.test.js.map +1 -0
  300. package/dist/src/telemetry/telemetry-utils.test.js +29 -28
  301. package/dist/src/telemetry/telemetry-utils.test.js.map +1 -1
  302. package/dist/src/telemetry/trace.d.ts +46 -0
  303. package/dist/src/telemetry/trace.js +121 -0
  304. package/dist/src/telemetry/trace.js.map +1 -0
  305. package/dist/src/telemetry/types.d.ts +79 -34
  306. package/dist/src/telemetry/types.js +191 -61
  307. package/dist/src/telemetry/types.js.map +1 -1
  308. package/dist/src/telemetry/uiTelemetry.js +6 -6
  309. package/dist/src/telemetry/uiTelemetry.js.map +1 -1
  310. package/dist/src/telemetry/uiTelemetry.test.js +88 -66
  311. package/dist/src/telemetry/uiTelemetry.test.js.map +1 -1
  312. package/dist/src/tools/edit.d.ts +3 -2
  313. package/dist/src/tools/edit.js +24 -19
  314. package/dist/src/tools/edit.js.map +1 -1
  315. package/dist/src/tools/edit.test.js +78 -2
  316. package/dist/src/tools/edit.test.js.map +1 -1
  317. package/dist/src/tools/glob.d.ts +3 -2
  318. package/dist/src/tools/glob.js +15 -19
  319. package/dist/src/tools/glob.js.map +1 -1
  320. package/dist/src/tools/glob.test.js +203 -199
  321. package/dist/src/tools/glob.test.js.map +1 -1
  322. package/dist/src/tools/grep.d.ts +3 -2
  323. package/dist/src/tools/grep.js +22 -16
  324. package/dist/src/tools/grep.js.map +1 -1
  325. package/dist/src/tools/ls.d.ts +3 -2
  326. package/dist/src/tools/ls.js +15 -20
  327. package/dist/src/tools/ls.js.map +1 -1
  328. package/dist/src/tools/ls.test.js +2 -9
  329. package/dist/src/tools/ls.test.js.map +1 -1
  330. package/dist/src/tools/mcp-client-manager.d.ts +49 -11
  331. package/dist/src/tools/mcp-client-manager.js +209 -31
  332. package/dist/src/tools/mcp-client-manager.js.map +1 -1
  333. package/dist/src/tools/mcp-client-manager.test.js +132 -25
  334. package/dist/src/tools/mcp-client-manager.test.js.map +1 -1
  335. package/dist/src/tools/mcp-client.d.ts +5 -1
  336. package/dist/src/tools/mcp-client.js +85 -104
  337. package/dist/src/tools/mcp-client.js.map +1 -1
  338. package/dist/src/tools/mcp-client.test.js +65 -6
  339. package/dist/src/tools/mcp-client.test.js.map +1 -1
  340. package/dist/src/tools/mcp-tool.d.ts +5 -2
  341. package/dist/src/tools/mcp-tool.js +16 -8
  342. package/dist/src/tools/mcp-tool.js.map +1 -1
  343. package/dist/src/tools/memoryTool.d.ts +6 -4
  344. package/dist/src/tools/memoryTool.js +13 -10
  345. package/dist/src/tools/memoryTool.js.map +1 -1
  346. package/dist/src/tools/message-bus-integration.test.js +14 -1
  347. package/dist/src/tools/message-bus-integration.test.js.map +1 -1
  348. package/dist/src/tools/modifiable-tool.js +3 -2
  349. package/dist/src/tools/modifiable-tool.js.map +1 -1
  350. package/dist/src/tools/read-file.d.ts +4 -3
  351. package/dist/src/tools/read-file.js +16 -11
  352. package/dist/src/tools/read-file.js.map +1 -1
  353. package/dist/src/tools/read-file.test.js +25 -2
  354. package/dist/src/tools/read-file.test.js.map +1 -1
  355. package/dist/src/tools/read-many-files.d.ts +4 -3
  356. package/dist/src/tools/read-many-files.js +19 -37
  357. package/dist/src/tools/read-many-files.js.map +1 -1
  358. package/dist/src/tools/read-many-files.test.js +0 -1
  359. package/dist/src/tools/read-many-files.test.js.map +1 -1
  360. package/dist/src/tools/ripGrep.d.ts +3 -2
  361. package/dist/src/tools/ripGrep.js +47 -17
  362. package/dist/src/tools/ripGrep.js.map +1 -1
  363. package/dist/src/tools/ripGrep.test.js +106 -60
  364. package/dist/src/tools/ripGrep.test.js.map +1 -1
  365. package/dist/src/tools/shell.d.ts +7 -5
  366. package/dist/src/tools/shell.js +39 -68
  367. package/dist/src/tools/shell.js.map +1 -1
  368. package/dist/src/tools/shell.test.js +69 -9
  369. package/dist/src/tools/shell.test.js.map +1 -1
  370. package/dist/src/tools/smart-edit.d.ts +3 -2
  371. package/dist/src/tools/smart-edit.js +30 -18
  372. package/dist/src/tools/smart-edit.js.map +1 -1
  373. package/dist/src/tools/smart-edit.test.js +62 -2
  374. package/dist/src/tools/smart-edit.test.js.map +1 -1
  375. package/dist/src/tools/tool-names.d.ts +8 -0
  376. package/dist/src/tools/tool-names.js +8 -5
  377. package/dist/src/tools/tool-names.js.map +1 -1
  378. package/dist/src/tools/tool-registry.d.ts +6 -19
  379. package/dist/src/tools/tool-registry.js +14 -49
  380. package/dist/src/tools/tool-registry.js.map +1 -1
  381. package/dist/src/tools/tool-registry.test.js +2 -24
  382. package/dist/src/tools/tool-registry.test.js.map +1 -1
  383. package/dist/src/tools/tools.d.ts +22 -8
  384. package/dist/src/tools/tools.js +65 -36
  385. package/dist/src/tools/tools.js.map +1 -1
  386. package/dist/src/tools/web-fetch.d.ts +4 -3
  387. package/dist/src/tools/web-fetch.js +37 -25
  388. package/dist/src/tools/web-fetch.js.map +1 -1
  389. package/dist/src/tools/web-fetch.test.js +262 -1
  390. package/dist/src/tools/web-fetch.test.js.map +1 -1
  391. package/dist/src/tools/web-search.d.ts +4 -3
  392. package/dist/src/tools/web-search.js +8 -6
  393. package/dist/src/tools/web-search.js.map +1 -1
  394. package/dist/src/tools/write-file.d.ts +3 -2
  395. package/dist/src/tools/write-file.js +8 -8
  396. package/dist/src/tools/write-file.js.map +1 -1
  397. package/dist/src/tools/write-file.test.js +1 -2
  398. package/dist/src/tools/write-file.test.js.map +1 -1
  399. package/dist/src/tools/write-todos.d.ts +4 -8
  400. package/dist/src/tools/write-todos.js +15 -6
  401. package/dist/src/tools/write-todos.js.map +1 -1
  402. package/dist/src/tools/write-todos.test.js +2 -2
  403. package/dist/src/tools/write-todos.test.js.map +1 -1
  404. package/dist/src/utils/bfsFileSearch.js +3 -2
  405. package/dist/src/utils/bfsFileSearch.js.map +1 -1
  406. package/dist/src/utils/channel.d.ts +19 -0
  407. package/dist/src/utils/channel.js +49 -0
  408. package/dist/src/utils/channel.js.map +1 -0
  409. package/dist/src/utils/channel.test.d.ts +6 -0
  410. package/dist/src/utils/channel.test.js +170 -0
  411. package/dist/src/utils/channel.test.js.map +1 -0
  412. package/dist/src/utils/debugLogger.d.ts +25 -0
  413. package/dist/src/utils/debugLogger.js +33 -0
  414. package/dist/src/utils/debugLogger.js.map +1 -0
  415. package/dist/src/utils/debugLogger.test.d.ts +6 -0
  416. package/dist/src/utils/debugLogger.test.js +67 -0
  417. package/dist/src/utils/debugLogger.test.js.map +1 -0
  418. package/dist/src/utils/delay.d.ts +16 -0
  419. package/dist/src/utils/delay.js +43 -0
  420. package/dist/src/utils/delay.js.map +1 -0
  421. package/dist/src/utils/delay.test.d.ts +6 -0
  422. package/dist/src/utils/delay.test.js +88 -0
  423. package/dist/src/utils/delay.test.js.map +1 -0
  424. package/dist/src/utils/editCorrector.js +5 -9
  425. package/dist/src/utils/editCorrector.js.map +1 -1
  426. package/dist/src/utils/editCorrector.test.js +3 -5
  427. package/dist/src/utils/editCorrector.test.js.map +1 -1
  428. package/dist/src/utils/editor.js +33 -38
  429. package/dist/src/utils/editor.js.map +1 -1
  430. package/dist/src/utils/environmentContext.d.ts +2 -1
  431. package/dist/src/utils/environmentContext.js +18 -33
  432. package/dist/src/utils/environmentContext.js.map +1 -1
  433. package/dist/src/utils/environmentContext.test.js +0 -34
  434. package/dist/src/utils/environmentContext.test.js.map +1 -1
  435. package/dist/src/utils/errorParsing.d.ts +1 -1
  436. package/dist/src/utils/errorParsing.js +5 -33
  437. package/dist/src/utils/errorParsing.js.map +1 -1
  438. package/dist/src/utils/errorParsing.test.js +0 -88
  439. package/dist/src/utils/errorParsing.test.js.map +1 -1
  440. package/dist/src/utils/errors.d.ts +3 -0
  441. package/dist/src/utils/errors.js +6 -0
  442. package/dist/src/utils/errors.js.map +1 -1
  443. package/dist/src/utils/events.d.ts +88 -0
  444. package/dist/src/utils/events.js +77 -0
  445. package/dist/src/utils/events.js.map +1 -0
  446. package/dist/src/utils/events.test.d.ts +6 -0
  447. package/dist/src/utils/events.test.js +131 -0
  448. package/dist/src/utils/events.test.js.map +1 -0
  449. package/dist/src/utils/extensionLoader.d.ts +78 -0
  450. package/dist/src/utils/extensionLoader.js +162 -0
  451. package/dist/src/utils/extensionLoader.js.map +1 -0
  452. package/dist/src/utils/extensionLoader.test.d.ts +6 -0
  453. package/dist/src/utils/extensionLoader.test.js +90 -0
  454. package/dist/src/utils/extensionLoader.test.js.map +1 -0
  455. package/dist/src/utils/fetch.d.ts +1 -0
  456. package/dist/src/utils/fetch.js +4 -0
  457. package/dist/src/utils/fetch.js.map +1 -1
  458. package/dist/src/utils/fileUtils.d.ts +4 -0
  459. package/dist/src/utils/fileUtils.js +34 -2
  460. package/dist/src/utils/fileUtils.js.map +1 -1
  461. package/dist/src/utils/fileUtils.test.js +12 -1
  462. package/dist/src/utils/fileUtils.test.js.map +1 -1
  463. package/dist/src/utils/flashFallback.test.js +26 -45
  464. package/dist/src/utils/flashFallback.test.js.map +1 -1
  465. package/dist/src/utils/getFolderStructure.js +9 -17
  466. package/dist/src/utils/getFolderStructure.js.map +1 -1
  467. package/dist/src/utils/gitIgnoreParser.d.ts +4 -1
  468. package/dist/src/utils/gitIgnoreParser.js +28 -10
  469. package/dist/src/utils/gitIgnoreParser.js.map +1 -1
  470. package/dist/src/utils/gitIgnoreParser.test.js +58 -0
  471. package/dist/src/utils/gitIgnoreParser.test.js.map +1 -1
  472. package/dist/src/utils/googleErrors.d.ts +104 -0
  473. package/dist/src/utils/googleErrors.js +152 -0
  474. package/dist/src/utils/googleErrors.js.map +1 -0
  475. package/dist/src/utils/googleErrors.test.d.ts +6 -0
  476. package/dist/src/utils/googleErrors.test.js +301 -0
  477. package/dist/src/utils/googleErrors.test.js.map +1 -0
  478. package/dist/src/utils/googleQuotaErrors.d.ts +36 -0
  479. package/dist/src/utils/googleQuotaErrors.js +149 -0
  480. package/dist/src/utils/googleQuotaErrors.js.map +1 -0
  481. package/dist/src/utils/googleQuotaErrors.test.d.ts +6 -0
  482. package/dist/src/utils/googleQuotaErrors.test.js +311 -0
  483. package/dist/src/utils/googleQuotaErrors.test.js.map +1 -0
  484. package/dist/src/utils/ignorePatterns.test.js +26 -30
  485. package/dist/src/utils/ignorePatterns.test.js.map +1 -1
  486. package/dist/src/utils/installationManager.js +2 -1
  487. package/dist/src/utils/installationManager.js.map +1 -1
  488. package/dist/src/utils/installationManager.test.js +3 -3
  489. package/dist/src/utils/installationManager.test.js.map +1 -1
  490. package/dist/src/utils/llm-edit-fixer.d.ts +1 -1
  491. package/dist/src/utils/llm-edit-fixer.js +29 -4
  492. package/dist/src/utils/llm-edit-fixer.js.map +1 -1
  493. package/dist/src/utils/llm-edit-fixer.test.js +21 -0
  494. package/dist/src/utils/llm-edit-fixer.test.js.map +1 -1
  495. package/dist/src/utils/memoryDiscovery.d.ts +11 -1
  496. package/dist/src/utils/memoryDiscovery.js +150 -11
  497. package/dist/src/utils/memoryDiscovery.js.map +1 -1
  498. package/dist/src/utils/memoryDiscovery.test.js +157 -19
  499. package/dist/src/utils/memoryDiscovery.test.js.map +1 -1
  500. package/dist/src/utils/memoryImportProcessor.js +3 -2
  501. package/dist/src/utils/memoryImportProcessor.js.map +1 -1
  502. package/dist/src/utils/nextSpeakerChecker.js +2 -1
  503. package/dist/src/utils/nextSpeakerChecker.js.map +1 -1
  504. package/dist/src/utils/package.d.ts +12 -0
  505. package/dist/src/utils/package.js +15 -0
  506. package/dist/src/utils/package.js.map +1 -0
  507. package/dist/src/utils/paths.js +126 -26
  508. package/dist/src/utils/paths.js.map +1 -1
  509. package/dist/src/utils/paths.test.js +200 -68
  510. package/dist/src/utils/paths.test.js.map +1 -1
  511. package/dist/src/utils/quotaErrorDetection.d.ts +0 -2
  512. package/dist/src/utils/quotaErrorDetection.js +0 -46
  513. package/dist/src/utils/quotaErrorDetection.js.map +1 -1
  514. package/dist/src/utils/retry.d.ts +1 -0
  515. package/dist/src/utils/retry.js +57 -158
  516. package/dist/src/utils/retry.js.map +1 -1
  517. package/dist/src/utils/retry.test.js +48 -109
  518. package/dist/src/utils/retry.test.js.map +1 -1
  519. package/dist/src/utils/safeJsonStringify.d.ts +4 -4
  520. package/dist/src/utils/safeJsonStringify.js +31 -7
  521. package/dist/src/utils/safeJsonStringify.js.map +1 -1
  522. package/dist/src/utils/shell-utils.d.ts +14 -2
  523. package/dist/src/utils/shell-utils.js +381 -136
  524. package/dist/src/utils/shell-utils.js.map +1 -1
  525. package/dist/src/utils/shell-utils.test.js +242 -60
  526. package/dist/src/utils/shell-utils.test.js.map +1 -1
  527. package/dist/src/utils/summarizer.js +2 -1
  528. package/dist/src/utils/summarizer.js.map +1 -1
  529. package/dist/src/utils/summarizer.test.js +0 -1
  530. package/dist/src/utils/summarizer.test.js.map +1 -1
  531. package/dist/src/utils/systemEncoding.js +5 -4
  532. package/dist/src/utils/systemEncoding.js.map +1 -1
  533. package/dist/src/utils/tool-utils.d.ts +2 -2
  534. package/dist/src/utils/tool-utils.js +14 -5
  535. package/dist/src/utils/tool-utils.js.map +1 -1
  536. package/dist/src/utils/userAccountManager.js +5 -4
  537. package/dist/src/utils/userAccountManager.js.map +1 -1
  538. package/dist/src/utils/workspaceContext.js +3 -2
  539. package/dist/src/utils/workspaceContext.js.map +1 -1
  540. package/dist/src/utils/workspaceContext.test.js +2 -2
  541. package/dist/src/utils/workspaceContext.test.js.map +1 -1
  542. package/dist/tsconfig.tsbuildinfo +1 -1
  543. package/package.json +13 -5
  544. package/dist/src/core/subagent.d.ts +0 -236
  545. package/dist/src/core/subagent.js +0 -482
  546. package/dist/src/core/subagent.js.map +0 -1
  547. package/dist/src/core/subagent.test.js +0 -556
  548. package/dist/src/core/subagent.test.js.map +0 -1
  549. /package/dist/src/{core/subagent.test.d.ts → commands/extensions.test.d.ts} +0 -0
@@ -8,15 +8,15 @@ import { AgentExecutor } from './executor.js';
8
8
  import { makeFakeConfig } from '../test-utils/config.js';
9
9
  import { ToolRegistry } from '../tools/tool-registry.js';
10
10
  import { LSTool } from '../tools/ls.js';
11
- import { ReadFileTool } from '../tools/read-file.js';
11
+ import { LS_TOOL_NAME, READ_FILE_TOOL_NAME } from '../tools/tool-names.js';
12
12
  import { GeminiChat, StreamEventType, } from '../core/geminiChat.js';
13
13
  import {} from '@google/genai';
14
14
  import { MockTool } from '../test-utils/mock-tool.js';
15
15
  import { getDirectoryContextString } from '../utils/environmentContext.js';
16
16
  import { z } from 'zod';
17
17
  import { promptIdContext } from '../utils/promptIdContext.js';
18
- import { logAgentStart, logAgentFinish } from '../telemetry/loggers.js';
19
- import { AgentStartEvent, AgentFinishEvent } from '../telemetry/types.js';
18
+ import { logAgentStart, logAgentFinish, logRecoveryAttempt, } from '../telemetry/loggers.js';
19
+ import { AgentStartEvent, AgentFinishEvent, RecoveryAttemptEvent, } from '../telemetry/types.js';
20
20
  import { AgentTerminateMode } from './types.js';
21
21
  const { mockSendMessageStream, mockExecuteToolCall } = vi.hoisted(() => ({
22
22
  mockSendMessageStream: vi.fn(),
@@ -38,6 +38,7 @@ vi.mock('../utils/environmentContext.js');
38
38
  vi.mock('../telemetry/loggers.js', () => ({
39
39
  logAgentStart: vi.fn(),
40
40
  logAgentFinish: vi.fn(),
41
+ logRecoveryAttempt: vi.fn(),
41
42
  }));
42
43
  vi.mock('../utils/promptIdContext.js', async (importOriginal) => {
43
44
  const actual = await importOriginal();
@@ -55,6 +56,7 @@ const mockedGetDirectoryContextString = vi.mocked(getDirectoryContextString);
55
56
  const mockedPromptIdContext = vi.mocked(promptIdContext);
56
57
  const mockedLogAgentStart = vi.mocked(logAgentStart);
57
58
  const mockedLogAgentFinish = vi.mocked(logAgentFinish);
59
+ const mockedLogRecoveryAttempt = vi.mocked(logRecoveryAttempt);
58
60
  // Constants for testing
59
61
  const TASK_COMPLETE_TOOL_NAME = 'complete_task';
60
62
  const MOCK_TOOL_NOT_ALLOWED = new MockTool({ name: 'write_file_interactive' });
@@ -102,7 +104,7 @@ let parentToolRegistry;
102
104
  /**
103
105
  * Type-safe helper to create agent definitions for tests.
104
106
  */
105
- const createTestDefinition = (tools = [LSTool.Name], runConfigOverrides = {}, outputConfigMode = 'default', schema = z.string()) => {
107
+ const createTestDefinition = (tools = [LS_TOOL_NAME], runConfigOverrides = {}, outputConfigMode = 'default', schema = z.string()) => {
106
108
  let outputConfig;
107
109
  if (outputConfigMode === 'default') {
108
110
  outputConfig = {
@@ -144,7 +146,7 @@ describe('AgentExecutor', () => {
144
146
  mockConfig = makeFakeConfig();
145
147
  parentToolRegistry = new ToolRegistry(mockConfig);
146
148
  parentToolRegistry.registerTool(new LSTool(mockConfig));
147
- parentToolRegistry.registerTool(new ReadFileTool(mockConfig));
149
+ parentToolRegistry.registerTool(new MockTool({ name: READ_FILE_TOOL_NAME }));
148
150
  parentToolRegistry.registerTool(MOCK_TOOL_NOT_ALLOWED);
149
151
  vi.spyOn(mockConfig, 'getToolRegistry').mockResolvedValue(parentToolRegistry);
150
152
  mockedGetDirectoryContextString.mockResolvedValue('Mocked Environment Context');
@@ -158,7 +160,7 @@ describe('AgentExecutor', () => {
158
160
  });
159
161
  describe('create (Initialization and Validation)', () => {
160
162
  it('should create successfully with allowed tools', async () => {
161
- const definition = createTestDefinition([LSTool.Name]);
163
+ const definition = createTestDefinition([LS_TOOL_NAME]);
162
164
  const executor = await AgentExecutor.create(definition, mockConfig, onActivity);
163
165
  expect(executor).toBeInstanceOf(AgentExecutor);
164
166
  });
@@ -167,11 +169,14 @@ describe('AgentExecutor', () => {
167
169
  await expect(AgentExecutor.create(definition, mockConfig, onActivity)).rejects.toThrow(/not on the allow-list for non-interactive execution/);
168
170
  });
169
171
  it('should create an isolated ToolRegistry for the agent', async () => {
170
- const definition = createTestDefinition([LSTool.Name, ReadFileTool.Name]);
172
+ const definition = createTestDefinition([
173
+ LS_TOOL_NAME,
174
+ READ_FILE_TOOL_NAME,
175
+ ]);
171
176
  const executor = await AgentExecutor.create(definition, mockConfig, onActivity);
172
177
  const agentRegistry = executor['toolRegistry'];
173
178
  expect(agentRegistry).not.toBe(parentToolRegistry);
174
- expect(agentRegistry.getAllToolNames()).toEqual(expect.arrayContaining([LSTool.Name, ReadFileTool.Name]));
179
+ expect(agentRegistry.getAllToolNames()).toEqual(expect.arrayContaining([LS_TOOL_NAME, READ_FILE_TOOL_NAME]));
175
180
  expect(agentRegistry.getAllToolNames()).toHaveLength(2);
176
181
  expect(agentRegistry.getTool(MOCK_TOOL_NOT_ALLOWED.name)).toBeUndefined();
177
182
  });
@@ -204,12 +209,12 @@ describe('AgentExecutor', () => {
204
209
  const executor = await AgentExecutor.create(definition, mockConfig, onActivity);
205
210
  const inputs = { goal: 'Find files' };
206
211
  // Turn 1: Model calls ls
207
- mockModelResponse([{ name: LSTool.Name, args: { path: '.' }, id: 'call1' }], 'T1: Listing');
212
+ mockModelResponse([{ name: LS_TOOL_NAME, args: { path: '.' }, id: 'call1' }], 'T1: Listing');
208
213
  mockExecuteToolCall.mockResolvedValueOnce({
209
214
  status: 'success',
210
215
  request: {
211
216
  callId: 'call1',
212
- name: LSTool.Name,
217
+ name: LS_TOOL_NAME,
213
218
  args: { path: '.' },
214
219
  isClientInitiated: false,
215
220
  prompt_id: 'test-prompt',
@@ -222,7 +227,7 @@ describe('AgentExecutor', () => {
222
227
  responseParts: [
223
228
  {
224
229
  functionResponse: {
225
- name: LSTool.Name,
230
+ name: LS_TOOL_NAME,
226
231
  response: { result: 'file1.txt' },
227
232
  id: 'call1',
228
233
  },
@@ -255,7 +260,7 @@ describe('AgentExecutor', () => {
255
260
  const sentTools = firstToolGroup.functionDeclarations;
256
261
  expect(sentTools).toBeDefined();
257
262
  expect(sentTools).toEqual(expect.arrayContaining([
258
- expect.objectContaining({ name: LSTool.Name }),
263
+ expect.objectContaining({ name: LS_TOOL_NAME }),
259
264
  expect.objectContaining({ name: TASK_COMPLETE_TOOL_NAME }),
260
265
  ]));
261
266
  const completeToolDef = sentTools.find((t) => t.name === TASK_COMPLETE_TOOL_NAME);
@@ -281,7 +286,7 @@ describe('AgentExecutor', () => {
281
286
  }),
282
287
  expect.objectContaining({
283
288
  type: 'TOOL_CALL_END',
284
- data: { name: LSTool.Name, output: 'file1.txt' },
289
+ data: { name: LS_TOOL_NAME, output: 'file1.txt' },
285
290
  }),
286
291
  expect.objectContaining({
287
292
  type: 'TOOL_CALL_START',
@@ -300,16 +305,16 @@ describe('AgentExecutor', () => {
300
305
  ]));
301
306
  });
302
307
  it('should execute successfully when model calls complete_task without output (Happy Path No Output)', async () => {
303
- const definition = createTestDefinition([LSTool.Name], {}, 'none');
308
+ const definition = createTestDefinition([LS_TOOL_NAME], {}, 'none');
304
309
  const executor = await AgentExecutor.create(definition, mockConfig, onActivity);
305
310
  mockModelResponse([
306
- { name: LSTool.Name, args: { path: '.' }, id: 'call1' },
311
+ { name: LS_TOOL_NAME, args: { path: '.' }, id: 'call1' },
307
312
  ]);
308
313
  mockExecuteToolCall.mockResolvedValueOnce({
309
314
  status: 'success',
310
315
  request: {
311
316
  callId: 'call1',
312
- name: LSTool.Name,
317
+ name: LS_TOOL_NAME,
313
318
  args: { path: '.' },
314
319
  isClientInitiated: false,
315
320
  prompt_id: 'test-prompt',
@@ -322,7 +327,7 @@ describe('AgentExecutor', () => {
322
327
  responseParts: [
323
328
  {
324
329
  functionResponse: {
325
- name: LSTool.Name,
330
+ name: LS_TOOL_NAME,
326
331
  response: {},
327
332
  id: 'call1',
328
333
  },
@@ -353,13 +358,13 @@ describe('AgentExecutor', () => {
353
358
  const definition = createTestDefinition();
354
359
  const executor = await AgentExecutor.create(definition, mockConfig, onActivity);
355
360
  mockModelResponse([
356
- { name: LSTool.Name, args: { path: '.' }, id: 'call1' },
361
+ { name: LS_TOOL_NAME, args: { path: '.' }, id: 'call1' },
357
362
  ]);
358
363
  mockExecuteToolCall.mockResolvedValueOnce({
359
364
  status: 'success',
360
365
  request: {
361
366
  callId: 'call1',
362
- name: LSTool.Name,
367
+ name: LS_TOOL_NAME,
363
368
  args: { path: '.' },
364
369
  isClientInitiated: false,
365
370
  prompt_id: 'test-prompt',
@@ -372,7 +377,7 @@ describe('AgentExecutor', () => {
372
377
  responseParts: [
373
378
  {
374
379
  functionResponse: {
375
- name: LSTool.Name,
380
+ name: LS_TOOL_NAME,
376
381
  response: {},
377
382
  id: 'call1',
378
383
  },
@@ -383,15 +388,18 @@ describe('AgentExecutor', () => {
383
388
  contentLength: undefined,
384
389
  },
385
390
  });
391
+ // Turn 2 (protocol violation)
386
392
  mockModelResponse([], 'I think I am done.');
393
+ // Turn 3 (recovery turn - also fails)
394
+ mockModelResponse([], 'I still give up.');
387
395
  const output = await executor.run({ goal: 'Strict test' }, signal);
388
- expect(mockSendMessageStream).toHaveBeenCalledTimes(2);
389
- const expectedError = `Agent stopped calling tools but did not call '${TASK_COMPLETE_TOOL_NAME}' to finalize the session.`;
390
- expect(output.terminate_reason).toBe(AgentTerminateMode.ERROR);
396
+ expect(mockSendMessageStream).toHaveBeenCalledTimes(3);
397
+ const expectedError = `Agent stopped calling tools but did not call '${TASK_COMPLETE_TOOL_NAME}'.`;
398
+ expect(output.terminate_reason).toBe(AgentTerminateMode.ERROR_NO_COMPLETE_TASK_CALL);
391
399
  expect(output.result).toBe(expectedError);
392
400
  // Telemetry check for error
393
401
  expect(mockedLogAgentFinish).toHaveBeenCalledWith(mockConfig, expect.objectContaining({
394
- terminate_reason: AgentTerminateMode.ERROR,
402
+ terminate_reason: AgentTerminateMode.ERROR_NO_COMPLETE_TASK_CALL,
395
403
  }));
396
404
  expect(activities).toContainEqual(expect.objectContaining({
397
405
  type: 'ERROR',
@@ -464,15 +472,15 @@ describe('AgentExecutor', () => {
464
472
  expect(errors[0].data['error']).toContain('Task already marked complete in this turn');
465
473
  });
466
474
  it('should execute parallel tool calls and then complete', async () => {
467
- const definition = createTestDefinition([LSTool.Name]);
475
+ const definition = createTestDefinition([LS_TOOL_NAME]);
468
476
  const executor = await AgentExecutor.create(definition, mockConfig, onActivity);
469
477
  const call1 = {
470
- name: LSTool.Name,
478
+ name: LS_TOOL_NAME,
471
479
  args: { path: '/a' },
472
480
  id: 'c1',
473
481
  };
474
482
  const call2 = {
475
- name: LSTool.Name,
483
+ name: LS_TOOL_NAME,
476
484
  args: { path: '/b' },
477
485
  id: 'c2',
478
486
  };
@@ -543,13 +551,13 @@ describe('AgentExecutor', () => {
543
551
  ]));
544
552
  });
545
553
  it('SECURITY: should block unauthorized tools and provide explicit failure to model', async () => {
546
- const definition = createTestDefinition([LSTool.Name]);
554
+ const definition = createTestDefinition([LS_TOOL_NAME]);
547
555
  const executor = await AgentExecutor.create(definition, mockConfig, onActivity);
548
556
  // Turn 1: Model tries to use a tool not in its config
549
557
  const badCallId = 'bad_call_1';
550
558
  mockModelResponse([
551
559
  {
552
- name: ReadFileTool.Name,
560
+ name: READ_FILE_TOOL_NAME,
553
561
  args: { path: 'secret.txt' },
554
562
  id: badCallId,
555
563
  },
@@ -578,7 +586,7 @@ describe('AgentExecutor', () => {
578
586
  expect(parts[0]).toEqual(expect.objectContaining({
579
587
  functionResponse: expect.objectContaining({
580
588
  id: badCallId,
581
- name: ReadFileTool.Name,
589
+ name: READ_FILE_TOOL_NAME,
582
590
  response: {
583
591
  error: expect.stringContaining('Unauthorized tool call'),
584
592
  },
@@ -589,19 +597,19 @@ describe('AgentExecutor', () => {
589
597
  type: 'ERROR',
590
598
  data: expect.objectContaining({
591
599
  context: 'tool_call_unauthorized',
592
- name: ReadFileTool.Name,
600
+ name: READ_FILE_TOOL_NAME,
593
601
  }),
594
602
  }));
595
603
  });
596
604
  });
597
605
  describe('run (Termination Conditions)', () => {
598
606
  const mockWorkResponse = (id) => {
599
- mockModelResponse([{ name: LSTool.Name, args: { path: '.' }, id }]);
607
+ mockModelResponse([{ name: LS_TOOL_NAME, args: { path: '.' }, id }]);
600
608
  mockExecuteToolCall.mockResolvedValueOnce({
601
609
  status: 'success',
602
610
  request: {
603
611
  callId: id,
604
- name: LSTool.Name,
612
+ name: LS_TOOL_NAME,
605
613
  args: { path: '.' },
606
614
  isClientInitiated: false,
607
615
  prompt_id: 'test-prompt',
@@ -612,7 +620,7 @@ describe('AgentExecutor', () => {
612
620
  callId: id,
613
621
  resultDisplay: 'ok',
614
622
  responseParts: [
615
- { functionResponse: { name: LSTool.Name, response: {}, id } },
623
+ { functionResponse: { name: LS_TOOL_NAME, response: {}, id } },
616
624
  ],
617
625
  error: undefined,
618
626
  errorType: undefined,
@@ -622,22 +630,66 @@ describe('AgentExecutor', () => {
622
630
  };
623
631
  it('should terminate when max_turns is reached', async () => {
624
632
  const MAX = 2;
625
- const definition = createTestDefinition([LSTool.Name], {
633
+ const definition = createTestDefinition([LS_TOOL_NAME], {
626
634
  max_turns: MAX,
627
635
  });
628
636
  const executor = await AgentExecutor.create(definition, mockConfig);
629
637
  mockWorkResponse('t1');
630
638
  mockWorkResponse('t2');
639
+ // Recovery turn
640
+ mockModelResponse([], 'I give up');
631
641
  const output = await executor.run({ goal: 'Turns test' }, signal);
632
642
  expect(output.terminate_reason).toBe(AgentTerminateMode.MAX_TURNS);
633
- expect(mockSendMessageStream).toHaveBeenCalledTimes(MAX);
643
+ expect(mockSendMessageStream).toHaveBeenCalledTimes(MAX + 1);
644
+ });
645
+ it('should terminate with TIMEOUT if a model call takes too long', async () => {
646
+ const definition = createTestDefinition([LS_TOOL_NAME], {
647
+ max_time_minutes: 0.5, // 30 seconds
648
+ });
649
+ const executor = await AgentExecutor.create(definition, mockConfig, onActivity);
650
+ // Mock a model call that is interruptible by an abort signal.
651
+ mockSendMessageStream.mockImplementationOnce(async (_model, params) => {
652
+ const signal = params?.config?.abortSignal;
653
+ // eslint-disable-next-line require-yield
654
+ return (async function* () {
655
+ await new Promise((resolve) => {
656
+ // This promise resolves when aborted, ending the generator.
657
+ signal?.addEventListener('abort', () => {
658
+ resolve();
659
+ });
660
+ });
661
+ })();
662
+ });
663
+ // Recovery turn
664
+ mockModelResponse([], 'I give up');
665
+ const runPromise = executor.run({ goal: 'Timeout test' }, signal);
666
+ // Advance time past the timeout to trigger the abort.
667
+ await vi.advanceTimersByTimeAsync(31 * 1000);
668
+ const output = await runPromise;
669
+ expect(output.terminate_reason).toBe(AgentTerminateMode.TIMEOUT);
670
+ expect(output.result).toContain('Agent timed out after 0.5 minutes.');
671
+ expect(mockSendMessageStream).toHaveBeenCalledTimes(2);
672
+ // Verify activity stream reported the timeout
673
+ expect(activities).toContainEqual(expect.objectContaining({
674
+ type: 'ERROR',
675
+ data: expect.objectContaining({
676
+ context: 'timeout',
677
+ error: 'Agent timed out after 0.5 minutes.',
678
+ }),
679
+ }));
680
+ // Verify telemetry
681
+ expect(mockedLogAgentFinish).toHaveBeenCalledWith(mockConfig, expect.objectContaining({
682
+ terminate_reason: AgentTerminateMode.TIMEOUT,
683
+ }));
634
684
  });
635
- it('should terminate if timeout is reached', async () => {
636
- const definition = createTestDefinition([LSTool.Name], {
685
+ it('should terminate with TIMEOUT if a tool call takes too long', async () => {
686
+ const definition = createTestDefinition([LS_TOOL_NAME], {
637
687
  max_time_minutes: 1,
638
688
  });
639
689
  const executor = await AgentExecutor.create(definition, mockConfig);
640
- mockModelResponse([{ name: LSTool.Name, args: { path: '.' }, id: 't1' }]);
690
+ mockModelResponse([
691
+ { name: LS_TOOL_NAME, args: { path: '.' }, id: 't1' },
692
+ ]);
641
693
  // Long running tool
642
694
  mockExecuteToolCall.mockImplementationOnce(async (_ctx, reqInfo) => {
643
695
  await vi.advanceTimersByTimeAsync(61 * 1000);
@@ -656,9 +708,11 @@ describe('AgentExecutor', () => {
656
708
  },
657
709
  };
658
710
  });
711
+ // Recovery turn
712
+ mockModelResponse([], 'I give up');
659
713
  const output = await executor.run({ goal: 'Timeout test' }, signal);
660
714
  expect(output.terminate_reason).toBe(AgentTerminateMode.TIMEOUT);
661
- expect(mockSendMessageStream).toHaveBeenCalledTimes(1);
715
+ expect(mockSendMessageStream).toHaveBeenCalledTimes(2);
662
716
  });
663
717
  it('should terminate when AbortSignal is triggered', async () => {
664
718
  const definition = createTestDefinition();
@@ -676,5 +730,282 @@ describe('AgentExecutor', () => {
676
730
  expect(output.terminate_reason).toBe(AgentTerminateMode.ABORTED);
677
731
  });
678
732
  });
733
+ describe('run (Recovery Turns)', () => {
734
+ const mockWorkResponse = (id) => {
735
+ mockModelResponse([{ name: LS_TOOL_NAME, args: { path: '.' }, id }]);
736
+ mockExecuteToolCall.mockResolvedValueOnce({
737
+ status: 'success',
738
+ request: {
739
+ callId: id,
740
+ name: LS_TOOL_NAME,
741
+ args: { path: '.' },
742
+ isClientInitiated: false,
743
+ prompt_id: 'test-prompt',
744
+ },
745
+ tool: {},
746
+ invocation: {},
747
+ response: {
748
+ callId: id,
749
+ resultDisplay: 'ok',
750
+ responseParts: [
751
+ { functionResponse: { name: LS_TOOL_NAME, response: {}, id } },
752
+ ],
753
+ error: undefined,
754
+ errorType: undefined,
755
+ contentLength: undefined,
756
+ },
757
+ });
758
+ };
759
+ it('should recover successfully if complete_task is called during the grace turn after MAX_TURNS', async () => {
760
+ const MAX = 1;
761
+ const definition = createTestDefinition([LS_TOOL_NAME], {
762
+ max_turns: MAX,
763
+ });
764
+ const executor = await AgentExecutor.create(definition, mockConfig, onActivity);
765
+ // Turn 1 (hits max_turns)
766
+ mockWorkResponse('t1');
767
+ // Recovery Turn (succeeds)
768
+ mockModelResponse([
769
+ {
770
+ name: TASK_COMPLETE_TOOL_NAME,
771
+ args: { finalResult: 'Recovered!' },
772
+ id: 't2',
773
+ },
774
+ ], 'Recovering from max turns');
775
+ const output = await executor.run({ goal: 'Turns recovery' }, signal);
776
+ expect(output.terminate_reason).toBe(AgentTerminateMode.GOAL);
777
+ expect(output.result).toBe('Recovered!');
778
+ expect(mockSendMessageStream).toHaveBeenCalledTimes(MAX + 1); // 1 regular + 1 recovery
779
+ expect(activities).toContainEqual(expect.objectContaining({
780
+ type: 'THOUGHT_CHUNK',
781
+ data: {
782
+ text: 'Execution limit reached (MAX_TURNS). Attempting one final recovery turn with a grace period.',
783
+ },
784
+ }));
785
+ expect(activities).toContainEqual(expect.objectContaining({
786
+ type: 'THOUGHT_CHUNK',
787
+ data: { text: 'Graceful recovery succeeded.' },
788
+ }));
789
+ });
790
+ it('should fail if complete_task is NOT called during the grace turn after MAX_TURNS', async () => {
791
+ const MAX = 1;
792
+ const definition = createTestDefinition([LS_TOOL_NAME], {
793
+ max_turns: MAX,
794
+ });
795
+ const executor = await AgentExecutor.create(definition, mockConfig, onActivity);
796
+ // Turn 1 (hits max_turns)
797
+ mockWorkResponse('t1');
798
+ // Recovery Turn (fails by calling no tools)
799
+ mockModelResponse([], 'I give up again.');
800
+ const output = await executor.run({ goal: 'Turns recovery fail' }, signal);
801
+ expect(output.terminate_reason).toBe(AgentTerminateMode.MAX_TURNS);
802
+ expect(output.result).toContain('Agent reached max turns limit');
803
+ expect(mockSendMessageStream).toHaveBeenCalledTimes(MAX + 1);
804
+ expect(activities).toContainEqual(expect.objectContaining({
805
+ type: 'ERROR',
806
+ data: expect.objectContaining({
807
+ context: 'recovery_turn',
808
+ error: 'Graceful recovery attempt failed. Reason: stop',
809
+ }),
810
+ }));
811
+ });
812
+ it('should recover successfully from a protocol violation (no complete_task)', async () => {
813
+ const definition = createTestDefinition();
814
+ const executor = await AgentExecutor.create(definition, mockConfig, onActivity);
815
+ // Turn 1: Normal work
816
+ mockWorkResponse('t1');
817
+ // Turn 2: Protocol violation (no tool calls)
818
+ mockModelResponse([], 'I think I am done, but I forgot the right tool.');
819
+ // Turn 3: Recovery turn (succeeds)
820
+ mockModelResponse([
821
+ {
822
+ name: TASK_COMPLETE_TOOL_NAME,
823
+ args: { finalResult: 'Recovered from violation!' },
824
+ id: 't3',
825
+ },
826
+ ], 'My mistake, here is the completion.');
827
+ const output = await executor.run({ goal: 'Violation recovery' }, signal);
828
+ expect(mockSendMessageStream).toHaveBeenCalledTimes(3);
829
+ expect(output.terminate_reason).toBe(AgentTerminateMode.GOAL);
830
+ expect(output.result).toBe('Recovered from violation!');
831
+ expect(activities).toContainEqual(expect.objectContaining({
832
+ type: 'THOUGHT_CHUNK',
833
+ data: {
834
+ text: 'Execution limit reached (ERROR_NO_COMPLETE_TASK_CALL). Attempting one final recovery turn with a grace period.',
835
+ },
836
+ }));
837
+ });
838
+ it('should fail recovery from a protocol violation if it violates again', async () => {
839
+ const definition = createTestDefinition();
840
+ const executor = await AgentExecutor.create(definition, mockConfig, onActivity);
841
+ // Turn 1: Normal work
842
+ mockWorkResponse('t1');
843
+ // Turn 2: Protocol violation (no tool calls)
844
+ mockModelResponse([], 'I think I am done, but I forgot the right tool.');
845
+ // Turn 3: Recovery turn (fails again)
846
+ mockModelResponse([], 'I still dont know what to do.');
847
+ const output = await executor.run({ goal: 'Violation recovery fail' }, signal);
848
+ expect(mockSendMessageStream).toHaveBeenCalledTimes(3);
849
+ expect(output.terminate_reason).toBe(AgentTerminateMode.ERROR_NO_COMPLETE_TASK_CALL);
850
+ expect(output.result).toContain(`Agent stopped calling tools but did not call '${TASK_COMPLETE_TOOL_NAME}'`);
851
+ expect(activities).toContainEqual(expect.objectContaining({
852
+ type: 'ERROR',
853
+ data: expect.objectContaining({
854
+ context: 'recovery_turn',
855
+ error: 'Graceful recovery attempt failed. Reason: stop',
856
+ }),
857
+ }));
858
+ });
859
+ it('should recover successfully from a TIMEOUT', async () => {
860
+ const definition = createTestDefinition([LS_TOOL_NAME], {
861
+ max_time_minutes: 0.5, // 30 seconds
862
+ });
863
+ const executor = await AgentExecutor.create(definition, mockConfig, onActivity);
864
+ // Mock a model call that gets interrupted by the timeout.
865
+ mockSendMessageStream.mockImplementationOnce(async (_model, params) => {
866
+ const signal = params?.config?.abortSignal;
867
+ // eslint-disable-next-line require-yield
868
+ return (async function* () {
869
+ // This promise never resolves, it waits for abort.
870
+ await new Promise((resolve) => {
871
+ signal?.addEventListener('abort', () => resolve());
872
+ });
873
+ })();
874
+ });
875
+ // Recovery turn (succeeds)
876
+ mockModelResponse([
877
+ {
878
+ name: TASK_COMPLETE_TOOL_NAME,
879
+ args: { finalResult: 'Recovered from timeout!' },
880
+ id: 't2',
881
+ },
882
+ ], 'Apologies for the delay, finishing up.');
883
+ const runPromise = executor.run({ goal: 'Timeout recovery' }, signal);
884
+ // Advance time past the timeout to trigger the abort and recovery.
885
+ await vi.advanceTimersByTimeAsync(31 * 1000);
886
+ const output = await runPromise;
887
+ expect(mockSendMessageStream).toHaveBeenCalledTimes(2); // 1 failed + 1 recovery
888
+ expect(output.terminate_reason).toBe(AgentTerminateMode.GOAL);
889
+ expect(output.result).toBe('Recovered from timeout!');
890
+ expect(activities).toContainEqual(expect.objectContaining({
891
+ type: 'THOUGHT_CHUNK',
892
+ data: {
893
+ text: 'Execution limit reached (TIMEOUT). Attempting one final recovery turn with a grace period.',
894
+ },
895
+ }));
896
+ });
897
+ it('should fail recovery from a TIMEOUT if the grace period also times out', async () => {
898
+ const definition = createTestDefinition([LS_TOOL_NAME], {
899
+ max_time_minutes: 0.5, // 30 seconds
900
+ });
901
+ const executor = await AgentExecutor.create(definition, mockConfig, onActivity);
902
+ mockSendMessageStream.mockImplementationOnce(async (_model, params) => {
903
+ const signal = params?.config?.abortSignal;
904
+ // eslint-disable-next-line require-yield
905
+ return (async function* () {
906
+ await new Promise((resolve) => signal?.addEventListener('abort', () => resolve()));
907
+ })();
908
+ });
909
+ // Mock the recovery call to also be long-running
910
+ mockSendMessageStream.mockImplementationOnce(async (_model, params) => {
911
+ const signal = params?.config?.abortSignal;
912
+ // eslint-disable-next-line require-yield
913
+ return (async function* () {
914
+ await new Promise((resolve) => signal?.addEventListener('abort', () => resolve()));
915
+ })();
916
+ });
917
+ const runPromise = executor.run({ goal: 'Timeout recovery fail' }, signal);
918
+ // 1. Trigger the main timeout
919
+ await vi.advanceTimersByTimeAsync(31 * 1000);
920
+ // 2. Let microtasks run (start recovery turn)
921
+ await vi.advanceTimersByTimeAsync(1);
922
+ // 3. Trigger the grace period timeout (60s)
923
+ await vi.advanceTimersByTimeAsync(61 * 1000);
924
+ const output = await runPromise;
925
+ expect(mockSendMessageStream).toHaveBeenCalledTimes(2);
926
+ expect(output.terminate_reason).toBe(AgentTerminateMode.TIMEOUT);
927
+ expect(output.result).toContain('Agent timed out after 0.5 minutes.');
928
+ expect(activities).toContainEqual(expect.objectContaining({
929
+ type: 'ERROR',
930
+ data: expect.objectContaining({
931
+ context: 'recovery_turn',
932
+ error: 'Graceful recovery attempt failed. Reason: stop',
933
+ }),
934
+ }));
935
+ });
936
+ });
937
+ describe('Telemetry and Logging', () => {
938
+ const mockWorkResponse = (id) => {
939
+ mockModelResponse([{ name: LS_TOOL_NAME, args: { path: '.' }, id }]);
940
+ mockExecuteToolCall.mockResolvedValueOnce({
941
+ status: 'success',
942
+ request: {
943
+ callId: id,
944
+ name: LS_TOOL_NAME,
945
+ args: { path: '.' },
946
+ isClientInitiated: false,
947
+ prompt_id: 'test-prompt',
948
+ },
949
+ tool: {},
950
+ invocation: {},
951
+ response: {
952
+ callId: id,
953
+ resultDisplay: 'ok',
954
+ responseParts: [
955
+ { functionResponse: { name: LS_TOOL_NAME, response: {}, id } },
956
+ ],
957
+ error: undefined,
958
+ errorType: undefined,
959
+ contentLength: undefined,
960
+ },
961
+ });
962
+ };
963
+ beforeEach(() => {
964
+ mockedLogRecoveryAttempt.mockClear();
965
+ });
966
+ it('should log a RecoveryAttemptEvent when a recoverable error occurs and recovery fails', async () => {
967
+ const MAX = 1;
968
+ const definition = createTestDefinition([LS_TOOL_NAME], {
969
+ max_turns: MAX,
970
+ });
971
+ const executor = await AgentExecutor.create(definition, mockConfig);
972
+ // Turn 1 (hits max_turns)
973
+ mockWorkResponse('t1');
974
+ // Recovery Turn (fails by calling no tools)
975
+ mockModelResponse([], 'I give up again.');
976
+ await executor.run({ goal: 'Turns recovery fail' }, signal);
977
+ expect(mockedLogRecoveryAttempt).toHaveBeenCalledTimes(1);
978
+ const recoveryEvent = mockedLogRecoveryAttempt.mock.calls[0][1];
979
+ expect(recoveryEvent).toBeInstanceOf(RecoveryAttemptEvent);
980
+ expect(recoveryEvent.agent_name).toBe(definition.name);
981
+ expect(recoveryEvent.reason).toBe(AgentTerminateMode.MAX_TURNS);
982
+ expect(recoveryEvent.success).toBe(false);
983
+ expect(recoveryEvent.turn_count).toBe(1);
984
+ expect(recoveryEvent.duration_ms).toBeGreaterThanOrEqual(0);
985
+ });
986
+ it('should log a successful RecoveryAttemptEvent when recovery succeeds', async () => {
987
+ const MAX = 1;
988
+ const definition = createTestDefinition([LS_TOOL_NAME], {
989
+ max_turns: MAX,
990
+ });
991
+ const executor = await AgentExecutor.create(definition, mockConfig);
992
+ // Turn 1 (hits max_turns)
993
+ mockWorkResponse('t1');
994
+ // Recovery Turn (succeeds)
995
+ mockModelResponse([
996
+ {
997
+ name: TASK_COMPLETE_TOOL_NAME,
998
+ args: { finalResult: 'Recovered!' },
999
+ id: 't2',
1000
+ },
1001
+ ], 'Recovering from max turns');
1002
+ await executor.run({ goal: 'Turns recovery success' }, signal);
1003
+ expect(mockedLogRecoveryAttempt).toHaveBeenCalledTimes(1);
1004
+ const recoveryEvent = mockedLogRecoveryAttempt.mock.calls[0][1];
1005
+ expect(recoveryEvent).toBeInstanceOf(RecoveryAttemptEvent);
1006
+ expect(recoveryEvent.success).toBe(true);
1007
+ expect(recoveryEvent.reason).toBe(AgentTerminateMode.MAX_TURNS);
1008
+ });
1009
+ });
679
1010
  });
680
1011
  //# sourceMappingURL=executor.test.js.map