@namzu/sdk 0.6.0 → 1.1.0

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 (429) hide show
  1. package/CHANGELOG.md +529 -0
  2. package/dist/advisory/executor.d.ts.map +1 -1
  3. package/dist/advisory/executor.js +9 -2
  4. package/dist/advisory/executor.js.map +1 -1
  5. package/dist/advisory/executor.test.d.ts +2 -1
  6. package/dist/advisory/executor.test.d.ts.map +1 -1
  7. package/dist/advisory/executor.test.js +7 -4
  8. package/dist/advisory/executor.test.js.map +1 -1
  9. package/dist/agents/ReactiveAgent.d.ts.map +1 -1
  10. package/dist/agents/ReactiveAgent.js +7 -0
  11. package/dist/agents/ReactiveAgent.js.map +1 -1
  12. package/dist/agents/SupervisorAgent.d.ts +22 -1
  13. package/dist/agents/SupervisorAgent.d.ts.map +1 -1
  14. package/dist/agents/SupervisorAgent.js +54 -14
  15. package/dist/agents/SupervisorAgent.js.map +1 -1
  16. package/dist/agents/__tests__/supervisor-ledger.test.d.ts +2 -0
  17. package/dist/agents/__tests__/supervisor-ledger.test.d.ts.map +1 -0
  18. package/dist/agents/__tests__/supervisor-ledger.test.js +131 -0
  19. package/dist/agents/__tests__/supervisor-ledger.test.js.map +1 -0
  20. package/dist/bridge/sse/mapper.test.js +2 -2
  21. package/dist/config/runtime.d.ts +24 -0
  22. package/dist/config/runtime.d.ts.map +1 -1
  23. package/dist/config/runtime.js +9 -0
  24. package/dist/config/runtime.js.map +1 -1
  25. package/dist/connector/builtins/webhook.test.js +17 -0
  26. package/dist/connector/builtins/webhook.test.js.map +1 -1
  27. package/dist/connector/index.d.ts +1 -0
  28. package/dist/connector/index.d.ts.map +1 -1
  29. package/dist/connector/index.js +1 -0
  30. package/dist/connector/index.js.map +1 -1
  31. package/dist/connector/mcp/client.d.ts.map +1 -1
  32. package/dist/connector/mcp/client.js +4 -0
  33. package/dist/connector/mcp/client.js.map +1 -1
  34. package/dist/connector/mcp/index.d.ts +1 -0
  35. package/dist/connector/mcp/index.d.ts.map +1 -1
  36. package/dist/connector/mcp/index.js +1 -0
  37. package/dist/connector/mcp/index.js.map +1 -1
  38. package/dist/connector/mcp/streamable-http.d.ts +22 -0
  39. package/dist/connector/mcp/streamable-http.d.ts.map +1 -0
  40. package/dist/connector/mcp/streamable-http.js +128 -0
  41. package/dist/connector/mcp/streamable-http.js.map +1 -0
  42. package/dist/connector/mcp/streamable-http.test.d.ts +2 -0
  43. package/dist/connector/mcp/streamable-http.test.d.ts.map +1 -0
  44. package/dist/connector/mcp/streamable-http.test.js +132 -0
  45. package/dist/connector/mcp/streamable-http.test.js.map +1 -0
  46. package/dist/constants/compaction/index.d.ts.map +1 -1
  47. package/dist/constants/compaction/index.js +8 -3
  48. package/dist/constants/compaction/index.js.map +1 -1
  49. package/dist/constants/sandbox/index.d.ts +21 -0
  50. package/dist/constants/sandbox/index.d.ts.map +1 -1
  51. package/dist/constants/sandbox/index.js +30 -0
  52. package/dist/constants/sandbox/index.js.map +1 -1
  53. package/dist/constants/tools/index.d.ts.map +1 -1
  54. package/dist/constants/tools/index.js +33 -2
  55. package/dist/constants/tools/index.js.map +1 -1
  56. package/dist/manager/run/persistence.d.ts.map +1 -1
  57. package/dist/manager/run/persistence.js +35 -5
  58. package/dist/manager/run/persistence.js.map +1 -1
  59. package/dist/persona/assembler.d.ts +1 -0
  60. package/dist/persona/assembler.d.ts.map +1 -1
  61. package/dist/persona/assembler.js +37 -6
  62. package/dist/persona/assembler.js.map +1 -1
  63. package/dist/provider/collect.d.ts.map +1 -1
  64. package/dist/provider/collect.js +4 -1
  65. package/dist/provider/collect.js.map +1 -1
  66. package/dist/provider/collect.test.js +2 -2
  67. package/dist/public-runtime.d.ts +6 -5
  68. package/dist/public-runtime.d.ts.map +1 -1
  69. package/dist/public-runtime.js +6 -5
  70. package/dist/public-runtime.js.map +1 -1
  71. package/dist/public-tools.d.ts +2 -0
  72. package/dist/public-tools.d.ts.map +1 -1
  73. package/dist/public-tools.js +2 -0
  74. package/dist/public-tools.js.map +1 -1
  75. package/dist/public-types.d.ts +3 -0
  76. package/dist/public-types.d.ts.map +1 -1
  77. package/dist/registry/index.d.ts +2 -0
  78. package/dist/registry/index.d.ts.map +1 -1
  79. package/dist/registry/index.js +1 -0
  80. package/dist/registry/index.js.map +1 -1
  81. package/dist/registry/tool/execute.d.ts +27 -0
  82. package/dist/registry/tool/execute.d.ts.map +1 -1
  83. package/dist/registry/tool/execute.js +192 -7
  84. package/dist/registry/tool/execute.js.map +1 -1
  85. package/dist/registry/tool/execute.test.d.ts +9 -4
  86. package/dist/registry/tool/execute.test.d.ts.map +1 -1
  87. package/dist/registry/tool/execute.test.js +178 -7
  88. package/dist/registry/tool/execute.test.js.map +1 -1
  89. package/dist/registry/toolset/catalog.d.ts +42 -0
  90. package/dist/registry/toolset/catalog.d.ts.map +1 -0
  91. package/dist/registry/toolset/catalog.js +217 -0
  92. package/dist/registry/toolset/catalog.js.map +1 -0
  93. package/dist/registry/toolset/catalog.test.d.ts +2 -0
  94. package/dist/registry/toolset/catalog.test.d.ts.map +1 -0
  95. package/dist/registry/toolset/catalog.test.js +147 -0
  96. package/dist/registry/toolset/catalog.test.js.map +1 -0
  97. package/dist/runtime/query/__tests__/deferred-tools.test.d.ts +2 -0
  98. package/dist/runtime/query/__tests__/deferred-tools.test.d.ts.map +1 -0
  99. package/dist/runtime/query/__tests__/deferred-tools.test.js +185 -0
  100. package/dist/runtime/query/__tests__/deferred-tools.test.js.map +1 -0
  101. package/dist/runtime/query/__tests__/executor-concurrency.test.d.ts +2 -0
  102. package/dist/runtime/query/__tests__/executor-concurrency.test.d.ts.map +1 -0
  103. package/dist/runtime/query/__tests__/executor-concurrency.test.js +98 -0
  104. package/dist/runtime/query/__tests__/executor-concurrency.test.js.map +1 -0
  105. package/dist/runtime/query/__tests__/executor-plugin-hooks.test.js +38 -3
  106. package/dist/runtime/query/__tests__/executor-plugin-hooks.test.js.map +1 -1
  107. package/dist/runtime/query/__tests__/long-document-flow.test.d.ts +2 -0
  108. package/dist/runtime/query/__tests__/long-document-flow.test.d.ts.map +1 -0
  109. package/dist/runtime/query/__tests__/long-document-flow.test.js +154 -0
  110. package/dist/runtime/query/__tests__/long-document-flow.test.js.map +1 -0
  111. package/dist/runtime/query/__tests__/prompt.test.js +51 -2
  112. package/dist/runtime/query/__tests__/prompt.test.js.map +1 -1
  113. package/dist/runtime/query/__tests__/stream-recovery.test.d.ts +2 -0
  114. package/dist/runtime/query/__tests__/stream-recovery.test.d.ts.map +1 -0
  115. package/dist/runtime/query/__tests__/stream-recovery.test.js +126 -0
  116. package/dist/runtime/query/__tests__/stream-recovery.test.js.map +1 -0
  117. package/dist/runtime/query/continuation.d.ts +16 -0
  118. package/dist/runtime/query/continuation.d.ts.map +1 -0
  119. package/dist/runtime/query/continuation.js +16 -0
  120. package/dist/runtime/query/continuation.js.map +1 -0
  121. package/dist/runtime/query/executor.d.ts +3 -0
  122. package/dist/runtime/query/executor.d.ts.map +1 -1
  123. package/dist/runtime/query/executor.js +71 -3
  124. package/dist/runtime/query/executor.js.map +1 -1
  125. package/dist/runtime/query/index.d.ts +9 -0
  126. package/dist/runtime/query/index.d.ts.map +1 -1
  127. package/dist/runtime/query/index.js +42 -5
  128. package/dist/runtime/query/index.js.map +1 -1
  129. package/dist/runtime/query/iteration/index.d.ts +24 -0
  130. package/dist/runtime/query/iteration/index.d.ts.map +1 -1
  131. package/dist/runtime/query/iteration/index.js +326 -66
  132. package/dist/runtime/query/iteration/index.js.map +1 -1
  133. package/dist/runtime/query/iteration/phases/checkpoint.d.ts.map +1 -1
  134. package/dist/runtime/query/iteration/phases/checkpoint.js +2 -2
  135. package/dist/runtime/query/iteration/phases/checkpoint.js.map +1 -1
  136. package/dist/runtime/query/iteration/phases/compaction.d.ts +8 -0
  137. package/dist/runtime/query/iteration/phases/compaction.d.ts.map +1 -1
  138. package/dist/runtime/query/iteration/phases/compaction.js +84 -3
  139. package/dist/runtime/query/iteration/phases/compaction.js.map +1 -1
  140. package/dist/runtime/query/iteration/phases/context.d.ts +22 -0
  141. package/dist/runtime/query/iteration/phases/context.d.ts.map +1 -1
  142. package/dist/runtime/query/iteration/phases/context.js +53 -0
  143. package/dist/runtime/query/iteration/phases/context.js.map +1 -1
  144. package/dist/runtime/query/iteration/phases/hitl-abort-race.test.d.ts +2 -0
  145. package/dist/runtime/query/iteration/phases/hitl-abort-race.test.d.ts.map +1 -0
  146. package/dist/runtime/query/iteration/phases/hitl-abort-race.test.js +73 -0
  147. package/dist/runtime/query/iteration/phases/hitl-abort-race.test.js.map +1 -0
  148. package/dist/runtime/query/iteration/phases/hitl-answer-question.test.d.ts +2 -0
  149. package/dist/runtime/query/iteration/phases/hitl-answer-question.test.d.ts.map +1 -0
  150. package/dist/runtime/query/iteration/phases/hitl-answer-question.test.js +120 -0
  151. package/dist/runtime/query/iteration/phases/hitl-answer-question.test.js.map +1 -0
  152. package/dist/runtime/query/iteration/phases/tool-review.d.ts +1 -1
  153. package/dist/runtime/query/iteration/phases/tool-review.d.ts.map +1 -1
  154. package/dist/runtime/query/iteration/phases/tool-review.js +7 -2
  155. package/dist/runtime/query/iteration/phases/tool-review.js.map +1 -1
  156. package/dist/runtime/query/iteration/phases/working-memory-compaction.test.d.ts +19 -0
  157. package/dist/runtime/query/iteration/phases/working-memory-compaction.test.d.ts.map +1 -0
  158. package/dist/runtime/query/iteration/phases/working-memory-compaction.test.js +177 -0
  159. package/dist/runtime/query/iteration/phases/working-memory-compaction.test.js.map +1 -0
  160. package/dist/runtime/query/iteration/phases/working-memory.d.ts +31 -0
  161. package/dist/runtime/query/iteration/phases/working-memory.d.ts.map +1 -0
  162. package/dist/runtime/query/iteration/phases/working-memory.js +81 -0
  163. package/dist/runtime/query/iteration/phases/working-memory.js.map +1 -0
  164. package/dist/runtime/query/prompt.d.ts.map +1 -1
  165. package/dist/runtime/query/prompt.js +21 -1
  166. package/dist/runtime/query/prompt.js.map +1 -1
  167. package/dist/runtime/query/tooling.d.ts +1 -0
  168. package/dist/runtime/query/tooling.d.ts.map +1 -1
  169. package/dist/runtime/query/tooling.js +1 -0
  170. package/dist/runtime/query/tooling.js.map +1 -1
  171. package/dist/sandbox/provider/local.d.ts.map +1 -1
  172. package/dist/sandbox/provider/local.js +32 -1
  173. package/dist/sandbox/provider/local.js.map +1 -1
  174. package/dist/session/workspace/__tests__/shared-run.test.d.ts +2 -0
  175. package/dist/session/workspace/__tests__/shared-run.test.d.ts.map +1 -0
  176. package/dist/session/workspace/__tests__/shared-run.test.js +147 -0
  177. package/dist/session/workspace/__tests__/shared-run.test.js.map +1 -0
  178. package/dist/session/workspace/index.d.ts +2 -0
  179. package/dist/session/workspace/index.d.ts.map +1 -1
  180. package/dist/session/workspace/index.js +1 -0
  181. package/dist/session/workspace/index.js.map +1 -1
  182. package/dist/session/workspace/shared-run.d.ts +81 -0
  183. package/dist/session/workspace/shared-run.d.ts.map +1 -0
  184. package/dist/session/workspace/shared-run.js +252 -0
  185. package/dist/session/workspace/shared-run.js.map +1 -0
  186. package/dist/skills/loader.d.ts.map +1 -1
  187. package/dist/skills/loader.js +36 -6
  188. package/dist/skills/loader.js.map +1 -1
  189. package/dist/skills/loader.test.d.ts +2 -0
  190. package/dist/skills/loader.test.d.ts.map +1 -0
  191. package/dist/skills/loader.test.js +65 -0
  192. package/dist/skills/loader.test.js.map +1 -0
  193. package/dist/streaming/coalesce.test.js +1 -1
  194. package/dist/streaming/coalesce.test.js.map +1 -1
  195. package/dist/tools/builtins/__tests__/edit.test.d.ts +2 -0
  196. package/dist/tools/builtins/__tests__/edit.test.d.ts.map +1 -0
  197. package/dist/tools/builtins/__tests__/edit.test.js +38 -0
  198. package/dist/tools/builtins/__tests__/edit.test.js.map +1 -0
  199. package/dist/tools/builtins/__tests__/payload-budget.test.d.ts +2 -0
  200. package/dist/tools/builtins/__tests__/payload-budget.test.d.ts.map +1 -0
  201. package/dist/tools/builtins/__tests__/payload-budget.test.js +70 -0
  202. package/dist/tools/builtins/__tests__/payload-budget.test.js.map +1 -0
  203. package/dist/tools/builtins/__tests__/read-file.test.d.ts +2 -0
  204. package/dist/tools/builtins/__tests__/read-file.test.d.ts.map +1 -0
  205. package/dist/tools/builtins/__tests__/read-file.test.js +33 -0
  206. package/dist/tools/builtins/__tests__/read-file.test.js.map +1 -0
  207. package/dist/tools/builtins/__tests__/verify-outputs.test.d.ts +2 -0
  208. package/dist/tools/builtins/__tests__/verify-outputs.test.d.ts.map +1 -0
  209. package/dist/tools/builtins/__tests__/verify-outputs.test.js +52 -0
  210. package/dist/tools/builtins/__tests__/verify-outputs.test.js.map +1 -0
  211. package/dist/tools/builtins/__tests__/write-file.test.d.ts +2 -0
  212. package/dist/tools/builtins/__tests__/write-file.test.d.ts.map +1 -0
  213. package/dist/tools/builtins/__tests__/write-file.test.js +74 -0
  214. package/dist/tools/builtins/__tests__/write-file.test.js.map +1 -0
  215. package/dist/tools/builtins/bash.d.ts.map +1 -1
  216. package/dist/tools/builtins/bash.js +40 -7
  217. package/dist/tools/builtins/bash.js.map +1 -1
  218. package/dist/tools/builtins/edit.d.ts +5 -2
  219. package/dist/tools/builtins/edit.d.ts.map +1 -1
  220. package/dist/tools/builtins/edit.js +114 -18
  221. package/dist/tools/builtins/edit.js.map +1 -1
  222. package/dist/tools/builtins/index.d.ts +1 -0
  223. package/dist/tools/builtins/index.d.ts.map +1 -1
  224. package/dist/tools/builtins/index.js +13 -13
  225. package/dist/tools/builtins/index.js.map +1 -1
  226. package/dist/tools/builtins/read-file.d.ts +1 -0
  227. package/dist/tools/builtins/read-file.d.ts.map +1 -1
  228. package/dist/tools/builtins/read-file.js +73 -10
  229. package/dist/tools/builtins/read-file.js.map +1 -1
  230. package/dist/tools/builtins/search-tools.d.ts.map +1 -1
  231. package/dist/tools/builtins/search-tools.js +35 -7
  232. package/dist/tools/builtins/search-tools.js.map +1 -1
  233. package/dist/tools/builtins/verify-outputs.d.ts +5 -0
  234. package/dist/tools/builtins/verify-outputs.d.ts.map +1 -0
  235. package/dist/tools/builtins/verify-outputs.js +103 -0
  236. package/dist/tools/builtins/verify-outputs.js.map +1 -0
  237. package/dist/tools/builtins/write-file.d.ts +3 -2
  238. package/dist/tools/builtins/write-file.d.ts.map +1 -1
  239. package/dist/tools/builtins/write-file.js +72 -12
  240. package/dist/tools/builtins/write-file.js.map +1 -1
  241. package/dist/tools/coordinator/__tests__/agent.test.d.ts +15 -0
  242. package/dist/tools/coordinator/__tests__/agent.test.d.ts.map +1 -0
  243. package/dist/tools/coordinator/__tests__/agent.test.js +142 -0
  244. package/dist/tools/coordinator/__tests__/agent.test.js.map +1 -0
  245. package/dist/tools/coordinator/__tests__/approve-plan.test.d.ts +2 -0
  246. package/dist/tools/coordinator/__tests__/approve-plan.test.d.ts.map +1 -0
  247. package/dist/tools/coordinator/__tests__/approve-plan.test.js +114 -0
  248. package/dist/tools/coordinator/__tests__/approve-plan.test.js.map +1 -0
  249. package/dist/tools/coordinator/__tests__/ask-user-question.test.d.ts +2 -0
  250. package/dist/tools/coordinator/__tests__/ask-user-question.test.d.ts.map +1 -0
  251. package/dist/tools/coordinator/__tests__/ask-user-question.test.js +309 -0
  252. package/dist/tools/coordinator/__tests__/ask-user-question.test.js.map +1 -0
  253. package/dist/tools/coordinator/__tests__/task-list.test.d.ts +13 -0
  254. package/dist/tools/coordinator/__tests__/task-list.test.d.ts.map +1 -0
  255. package/dist/tools/coordinator/__tests__/task-list.test.js +162 -0
  256. package/dist/tools/coordinator/__tests__/task-list.test.js.map +1 -0
  257. package/dist/tools/coordinator/agent.d.ts +34 -0
  258. package/dist/tools/coordinator/agent.d.ts.map +1 -0
  259. package/dist/tools/coordinator/agent.js +107 -0
  260. package/dist/tools/coordinator/agent.js.map +1 -0
  261. package/dist/tools/coordinator/index.d.ts +15 -0
  262. package/dist/tools/coordinator/index.d.ts.map +1 -1
  263. package/dist/tools/coordinator/index.js +305 -35
  264. package/dist/tools/coordinator/index.js.map +1 -1
  265. package/dist/types/agent/base.d.ts +8 -0
  266. package/dist/types/agent/base.d.ts.map +1 -1
  267. package/dist/types/agent/index.d.ts +1 -0
  268. package/dist/types/agent/index.d.ts.map +1 -1
  269. package/dist/types/agent/index.js +1 -0
  270. package/dist/types/agent/index.js.map +1 -1
  271. package/dist/types/agent/reactive.d.ts +38 -0
  272. package/dist/types/agent/reactive.d.ts.map +1 -1
  273. package/dist/types/agent/supervisor.d.ts +32 -0
  274. package/dist/types/agent/supervisor.d.ts.map +1 -1
  275. package/dist/types/agent/working-memory.d.ts +29 -0
  276. package/dist/types/agent/working-memory.d.ts.map +1 -0
  277. package/dist/types/agent/working-memory.js +2 -0
  278. package/dist/types/agent/working-memory.js.map +1 -0
  279. package/dist/types/common/index.d.ts +10 -0
  280. package/dist/types/common/index.d.ts.map +1 -1
  281. package/dist/types/common/index.js +18 -0
  282. package/dist/types/common/index.js.map +1 -1
  283. package/dist/types/common/usage-merge.test.d.ts +2 -0
  284. package/dist/types/common/usage-merge.test.d.ts.map +1 -0
  285. package/dist/types/common/usage-merge.test.js +48 -0
  286. package/dist/types/common/usage-merge.test.js.map +1 -0
  287. package/dist/types/connector/mcp.d.ts +9 -2
  288. package/dist/types/connector/mcp.d.ts.map +1 -1
  289. package/dist/types/hitl/index.d.ts +42 -0
  290. package/dist/types/hitl/index.d.ts.map +1 -1
  291. package/dist/types/hitl/index.js +11 -0
  292. package/dist/types/hitl/index.js.map +1 -1
  293. package/dist/types/message/index.d.ts +22 -1
  294. package/dist/types/message/index.d.ts.map +1 -1
  295. package/dist/types/message/index.js +7 -2
  296. package/dist/types/message/index.js.map +1 -1
  297. package/dist/types/provider/chat.d.ts +11 -9
  298. package/dist/types/provider/chat.d.ts.map +1 -1
  299. package/dist/types/run/events.d.ts +6 -0
  300. package/dist/types/run/events.d.ts.map +1 -1
  301. package/dist/types/run/events.js.map +1 -1
  302. package/dist/types/sandbox/index.d.ts +193 -0
  303. package/dist/types/sandbox/index.d.ts.map +1 -1
  304. package/dist/types/sandbox/index.js.map +1 -1
  305. package/dist/types/skills/index.d.ts +2 -0
  306. package/dist/types/skills/index.d.ts.map +1 -1
  307. package/dist/types/tool/index.d.ts +22 -0
  308. package/dist/types/tool/index.d.ts.map +1 -1
  309. package/dist/types/toolset/index.d.ts +71 -0
  310. package/dist/types/toolset/index.d.ts.map +1 -0
  311. package/dist/types/toolset/index.js +2 -0
  312. package/dist/types/toolset/index.js.map +1 -0
  313. package/dist/types/workspace/index.d.ts +1 -0
  314. package/dist/types/workspace/index.d.ts.map +1 -1
  315. package/dist/types/workspace/shared-run.d.ts +61 -0
  316. package/dist/types/workspace/shared-run.d.ts.map +1 -0
  317. package/dist/types/workspace/shared-run.js +2 -0
  318. package/dist/types/workspace/shared-run.js.map +1 -0
  319. package/dist/verification/index.d.ts +1 -0
  320. package/dist/verification/index.d.ts.map +1 -1
  321. package/dist/verification/index.js +1 -0
  322. package/dist/verification/index.js.map +1 -1
  323. package/dist/verification/presets.d.ts +53 -0
  324. package/dist/verification/presets.d.ts.map +1 -0
  325. package/dist/verification/presets.js +70 -0
  326. package/dist/verification/presets.js.map +1 -0
  327. package/dist/verification/presets.test.d.ts +16 -0
  328. package/dist/verification/presets.test.d.ts.map +1 -0
  329. package/dist/verification/presets.test.js +79 -0
  330. package/dist/verification/presets.test.js.map +1 -0
  331. package/dist/version.d.ts.map +1 -1
  332. package/dist/version.js +25 -4
  333. package/dist/version.js.map +1 -1
  334. package/package.json +3 -2
  335. package/src/advisory/executor.test.ts +7 -4
  336. package/src/advisory/executor.ts +11 -2
  337. package/src/agents/ReactiveAgent.ts +7 -0
  338. package/src/agents/SupervisorAgent.ts +63 -16
  339. package/src/agents/__tests__/supervisor-ledger.test.ts +185 -0
  340. package/src/bridge/sse/mapper.test.ts +2 -2
  341. package/src/config/runtime.ts +9 -0
  342. package/src/connector/builtins/webhook.test.ts +21 -0
  343. package/src/connector/index.ts +1 -0
  344. package/src/connector/mcp/client.ts +4 -0
  345. package/src/connector/mcp/index.ts +1 -0
  346. package/src/connector/mcp/streamable-http.test.ts +169 -0
  347. package/src/connector/mcp/streamable-http.ts +152 -0
  348. package/src/constants/compaction/index.ts +8 -3
  349. package/src/constants/sandbox/index.ts +37 -0
  350. package/src/constants/tools/index.ts +33 -2
  351. package/src/manager/run/persistence.ts +34 -6
  352. package/src/persona/assembler.ts +43 -8
  353. package/src/provider/collect.test.ts +2 -2
  354. package/src/provider/collect.ts +4 -1
  355. package/src/public-runtime.ts +15 -1
  356. package/src/public-tools.ts +2 -0
  357. package/src/public-types.ts +7 -0
  358. package/src/registry/index.ts +7 -0
  359. package/src/registry/tool/execute.test.ts +211 -7
  360. package/src/registry/tool/execute.ts +199 -11
  361. package/src/registry/toolset/catalog.test.ts +165 -0
  362. package/src/registry/toolset/catalog.ts +283 -0
  363. package/src/runtime/query/__tests__/deferred-tools.test.ts +230 -0
  364. package/src/runtime/query/__tests__/executor-concurrency.test.ts +122 -0
  365. package/src/runtime/query/__tests__/executor-plugin-hooks.test.ts +48 -3
  366. package/src/runtime/query/__tests__/long-document-flow.test.ts +180 -0
  367. package/src/runtime/query/__tests__/prompt.test.ts +55 -2
  368. package/src/runtime/query/__tests__/stream-recovery.test.ts +156 -0
  369. package/src/runtime/query/continuation.ts +16 -0
  370. package/src/runtime/query/executor.ts +82 -13
  371. package/src/runtime/query/index.ts +58 -5
  372. package/src/runtime/query/iteration/index.ts +361 -74
  373. package/src/runtime/query/iteration/phases/checkpoint.ts +7 -2
  374. package/src/runtime/query/iteration/phases/compaction.ts +89 -3
  375. package/src/runtime/query/iteration/phases/context.ts +68 -0
  376. package/src/runtime/query/iteration/phases/hitl-abort-race.test.ts +86 -0
  377. package/src/runtime/query/iteration/phases/hitl-answer-question.test.ts +139 -0
  378. package/src/runtime/query/iteration/phases/tool-review.ts +7 -3
  379. package/src/runtime/query/iteration/phases/working-memory-compaction.test.ts +215 -0
  380. package/src/runtime/query/iteration/phases/working-memory.ts +86 -0
  381. package/src/runtime/query/prompt.ts +17 -1
  382. package/src/runtime/query/tooling.ts +2 -0
  383. package/src/sandbox/provider/local.ts +33 -0
  384. package/src/session/workspace/__tests__/shared-run.test.ts +181 -0
  385. package/src/session/workspace/index.ts +6 -0
  386. package/src/session/workspace/shared-run.ts +317 -0
  387. package/src/skills/loader.test.ts +89 -0
  388. package/src/skills/loader.ts +37 -6
  389. package/src/streaming/coalesce.test.ts +4 -4
  390. package/src/tools/builtins/__tests__/edit.test.ts +57 -0
  391. package/src/tools/builtins/__tests__/payload-budget.test.ts +92 -0
  392. package/src/tools/builtins/__tests__/read-file.test.ts +43 -0
  393. package/src/tools/builtins/__tests__/verify-outputs.test.ts +71 -0
  394. package/src/tools/builtins/__tests__/write-file.test.ts +97 -0
  395. package/src/tools/builtins/bash.ts +48 -7
  396. package/src/tools/builtins/edit.ts +162 -27
  397. package/src/tools/builtins/index.ts +13 -13
  398. package/src/tools/builtins/read-file.ts +81 -10
  399. package/src/tools/builtins/search-tools.ts +42 -7
  400. package/src/tools/builtins/verify-outputs.ts +126 -0
  401. package/src/tools/builtins/write-file.ts +83 -14
  402. package/src/tools/coordinator/__tests__/agent.test.ts +172 -0
  403. package/src/tools/coordinator/__tests__/approve-plan.test.ts +139 -0
  404. package/src/tools/coordinator/__tests__/ask-user-question.test.ts +370 -0
  405. package/src/tools/coordinator/__tests__/task-list.test.ts +182 -0
  406. package/src/tools/coordinator/agent.ts +157 -0
  407. package/src/tools/coordinator/index.ts +355 -39
  408. package/src/types/agent/base.ts +8 -0
  409. package/src/types/agent/index.ts +1 -0
  410. package/src/types/agent/reactive.ts +42 -0
  411. package/src/types/agent/supervisor.ts +36 -0
  412. package/src/types/agent/working-memory.ts +29 -0
  413. package/src/types/common/index.ts +19 -0
  414. package/src/types/common/usage-merge.test.ts +53 -0
  415. package/src/types/connector/mcp.ts +14 -2
  416. package/src/types/hitl/index.ts +52 -1
  417. package/src/types/message/index.ts +32 -2
  418. package/src/types/provider/chat.ts +12 -9
  419. package/src/types/run/events.ts +6 -0
  420. package/src/types/sandbox/index.ts +219 -0
  421. package/src/types/skills/index.ts +4 -0
  422. package/src/types/tool/index.ts +24 -0
  423. package/src/types/toolset/index.ts +86 -0
  424. package/src/types/workspace/index.ts +9 -0
  425. package/src/types/workspace/shared-run.ts +65 -0
  426. package/src/verification/index.ts +1 -0
  427. package/src/verification/presets.test.ts +112 -0
  428. package/src/verification/presets.ts +72 -0
  429. package/src/version.ts +26 -4
@@ -1,12 +1,37 @@
1
+ import { findSafeTrimIndex } from '../../../../compaction/dangling.js'
1
2
  import { serializeState } from '../../../../compaction/serializer.js'
2
3
  import { buildVerifiedSummary } from '../../../../compaction/verifier.js'
3
4
  import { CHARS_PER_TOKEN } from '../../../../constants/limits.js'
4
5
  import { createSystemMessage } from '../../../../types/message/index.js'
5
6
  import type { IterationContext } from './context.js'
7
+ import { isWorkingMemoryMessage } from './working-memory.js'
6
8
 
7
9
  const COMPACTION_HEADER =
8
10
  '[COMPACTED CONTEXT] The following is a structured summary of the conversation so far.'
9
11
 
12
+ /**
13
+ * Identity check for a prior compaction summary in the leading floor. Used to
14
+ * REPLACE one in place on the per-iteration (contextWindowTokens) path so at
15
+ * most one `[COMPACTED CONTEXT]` block ever lives in the never-trimmed floor,
16
+ * and by the checkpoint-restore path to PRESERVE the summary across a resume
17
+ * (it is the only surviving record of the older history the run compacted away).
18
+ */
19
+ export function isCompactionMessage(content: string | null | undefined): boolean {
20
+ return typeof content === 'string' && content.startsWith(COMPACTION_HEADER)
21
+ }
22
+
23
+ /**
24
+ * Minimum number of compactable (older) messages required before a compaction
25
+ * pass is worth running. When there is NOTHING between the never-trimmed
26
+ * leading floor and the recent window, a pass would only replace nothing with a
27
+ * `[COMPACTED CONTEXT]` summary that joins the floor — pure overhead that fires
28
+ * again next iteration (the permanent-floor thrash, ses_055 D7). Set to the
29
+ * literal EMPTY guard so any existing compaction consumer with ≥1 older message
30
+ * stays byte-identical; the per-iteration Vandal path additionally defangs the
31
+ * cost with `llmVerification:false`.
32
+ */
33
+ const MIN_OLDER_MESSAGES_TO_COMPACT = 1
34
+
10
35
  function estimateTokens(ctx: IterationContext): number {
11
36
  let chars = 0
12
37
  for (const msg of ctx.runMgr.messages) {
@@ -31,7 +56,13 @@ export async function runCompactionCheck(ctx: IterationContext): Promise<void> {
31
56
  if (!manager) return
32
57
 
33
58
  const estimatedTokens = estimateTokens(ctx)
34
- const budget = ctx.runConfig.tokenBudget
59
+ // F1: measure the CURRENT window against the model context window when the
60
+ // host supplies one, falling back to the run-level cumulative `tokenBudget`
61
+ // otherwise. Repointing the SINGLE `budget` assignment moves BOTH the
62
+ // `<= 0` guard AND the divisor at once — so "compaction on + tokenBudget=0"
63
+ // is no longer a silent no-op. Existing consumers (no contextWindowTokens)
64
+ // stay byte-identical.
65
+ const budget = config.contextWindowTokens ?? ctx.runConfig.tokenBudget
35
66
  if (budget <= 0) return
36
67
 
37
68
  const usage = estimatedTokens / budget
@@ -63,10 +94,34 @@ export async function runCompactionCheck(ctx: IterationContext): Promise<void> {
63
94
  }
64
95
  if (systemMessages.length === 0) return
65
96
 
66
- const keepStart = messages.length - config.keepRecentMessages
97
+ // Tool-pair atomicity guard. A naive cut at `length - keepRecentMessages`
98
+ // can land BETWEEN an assistant-with-toolCalls (which would be dropped into
99
+ // `olderMessages`) and its `tool` results (kept in `recentMessages`),
100
+ // leaving orphaned `tool_result` blocks at the head of the recent window.
101
+ // The Anthropic provider then emits a `tool_result` with no matching
102
+ // `tool_use` and the API rejects the next turn with a 400 — so compaction,
103
+ // whose whole job is to keep a long run alive, instead kills it. Snap the
104
+ // boundary FORWARD to a safe point (existing `findSafeTrimIndex`, previously
105
+ // only wired to the unused ConversationManager strategy classes) so no pair
106
+ // is split. Any message this moves out of the recent window is already
107
+ // represented in the extracted WorkingState the summary is built from.
108
+ const keepStart = findSafeTrimIndex(messages, messages.length - config.keepRecentMessages)
67
109
  const recentMessages = messages.slice(keepStart)
68
110
  const olderMessages = messages.slice(systemMessages.length, keepStart)
69
111
 
112
+ // D7: nothing meaningful to compact — skip instead of thrashing the
113
+ // permanent leading floor every iteration (and avoid an LLM verification
114
+ // call when there is no older history to summarize). Scoped to the new
115
+ // contextWindowTokens path so any existing consumer (tokenBudget-only) keeps
116
+ // its exact prior behavior — byte-identical (ses_055 verify).
117
+ if (config.contextWindowTokens != null && olderMessages.length < MIN_OLDER_MESSAGES_TO_COMPACT) {
118
+ ctx.log.debug('Skipping compaction — too few older messages', {
119
+ runId: ctx.runMgr.id,
120
+ olderMessages: olderMessages.length,
121
+ })
122
+ return
123
+ }
124
+
70
125
  let compactedContent: string
71
126
 
72
127
  if (config.llmVerification && manager.slotCount() < config.richStateThreshold) {
@@ -77,7 +132,38 @@ export async function runCompactionCheck(ctx: IterationContext): Promise<void> {
77
132
 
78
133
  const compactionMessage = createSystemMessage(`${COMPACTION_HEADER}\n\n${compactedContent}`)
79
134
 
80
- const newMessages = [...systemMessages, compactionMessage, ...recentMessages]
135
+ // On the new per-iteration (contextWindowTokens) path, drop any PRIOR
136
+ // `[COMPACTED CONTEXT]` summary from the leading floor — `serializeState` is
137
+ // cumulative, so the new summary supersedes it. Without this the never-trimmed
138
+ // floor accumulates one redundant summary per pass and the frequent
139
+ // per-iteration trigger makes that bloat unbounded (ses_055 verify, MEDIUM).
140
+ // Legacy consumers (no contextWindowTokens) keep their exact prior
141
+ // accumulation behavior — byte-identical.
142
+ const preservedSystem =
143
+ config.contextWindowTokens != null
144
+ ? systemMessages.filter((m) => !isCompactionMessage(m.content))
145
+ : systemMessages
146
+ const newMessages = [...preservedSystem, compactionMessage, ...recentMessages]
147
+
148
+ // OPAQUE survival guard (ses_055 D1): the pinned working-memory slot is a
149
+ // leading system message, so it is kept in `preservedSystem` (the compaction
150
+ // filter only drops prior `[COMPACTED CONTEXT]` summaries, never the WM slot)
151
+ // and survives for free — this branch is DEFENSIVE-ONLY, exercised only if a
152
+ // future change drops the slot from the rebuilt set. It re-pins the block
153
+ // already present in `messages` (the one `refreshWorkingMemory` placed).
154
+ // Identity is the sentinel HEADER only — no path parsing, no second provider
155
+ // call, no host format knowledge in the SDK.
156
+ const survives = newMessages.some((m) => m.role === 'system' && isWorkingMemoryMessage(m.content))
157
+ if (!survives) {
158
+ const priorSlot = messages.find((m) => m.role === 'system' && isWorkingMemoryMessage(m.content))
159
+ if (priorSlot) {
160
+ // Re-pin as the last leading system message, before the summary.
161
+ newMessages.splice(preservedSystem.length, 0, priorSlot)
162
+ ctx.log.warn('Re-pinned working-memory slot dropped by compaction', {
163
+ runId: ctx.runMgr.id,
164
+ })
165
+ }
166
+ }
81
167
 
82
168
  const oldCount = messages.length
83
169
  messages.length = 0
@@ -6,6 +6,7 @@ import type { PlanManager } from '../../../../manager/plan/lifecycle.js'
6
6
  import type { RunPersistence } from '../../../../manager/run/persistence.js'
7
7
  import type { ActivityStore } from '../../../../store/activity/memory.js'
8
8
  import type { TaskGateway, TaskHandle } from '../../../../types/agent/gateway.js'
9
+ import type { WorkingMemoryProvider } from '../../../../types/agent/working-memory.js'
9
10
  import type { HITLResumeDecision, ResumeHandler } from '../../../../types/hitl/index.js'
10
11
  import type { TaskId } from '../../../../types/ids/index.js'
11
12
  import type { LLMProvider } from '../../../../types/provider/index.js'
@@ -22,6 +23,16 @@ export interface LaunchedTaskMeta {
22
23
  readonly agentId: string
23
24
  readonly description: string
24
25
  readonly planTaskId?: string
26
+ /**
27
+ * The `tool_use_id` of the assistant `create_task` block that
28
+ * spawned this background task. Required to emit the canonical
29
+ * `tool_result` content block when the task completes — without
30
+ * it we'd fall back to the legacy synthetic-user-message inject
31
+ * (see ses_009-task-notification-envelope). Optional because
32
+ * older call paths that don't thread `ToolContext.toolUseId`
33
+ * still publish the meta without it.
34
+ */
35
+ readonly originalToolUseId?: string
25
36
  }
26
37
 
27
38
  export interface IterationContext {
@@ -53,6 +64,8 @@ export interface IterationContext {
53
64
 
54
65
  readonly workingStateManager?: WorkingStateManager
55
66
 
67
+ readonly workingMemoryProvider?: WorkingMemoryProvider
68
+
56
69
  readonly advisoryCtx?: AdvisoryContext
57
70
 
58
71
  readonly agentBus?: AgentBus
@@ -64,6 +77,57 @@ export interface IterationContext {
64
77
 
65
78
  export type PhaseSignal = 'continue' | 'stop'
66
79
 
80
+ /**
81
+ * Await a HITL `resumeHandler` decision, but RACE it against the run's abort
82
+ * signal. A Stop that arrives while the run is parked on a tool-review or
83
+ * iteration checkpoint used to do nothing until the host eventually answered
84
+ * (the park await was not cancellable). Racing the signal lets a Stop resolve
85
+ * the park immediately as an `abort` decision, which `handleHITLDecision`
86
+ * turns into `setStopReason('cancelled') + markCancelled + stop`. Fails closed:
87
+ * a resume-handler rejection also resolves to `abort` rather than hanging.
88
+ */
89
+ export async function awaitDecisionOrAbort(
90
+ ctx: IterationContext,
91
+ request: Parameters<ResumeHandler>[0],
92
+ ): Promise<HITLResumeDecision> {
93
+ const signal = ctx.abortController?.signal
94
+ // No abort signal wired (e.g. a minimal test harness) → behave exactly as a
95
+ // direct resumeHandler await, no race. In production RunContextFactory always
96
+ // provides the controller, so the race below is live.
97
+ if (!signal) return ctx.resumeHandler(request)
98
+ const abortDecision: HITLResumeDecision = {
99
+ action: 'abort',
100
+ reason: 'run aborted while parked for HITL',
101
+ }
102
+ if (signal.aborted) return abortDecision
103
+ return new Promise<HITLResumeDecision>((resolve) => {
104
+ let settled = false
105
+ const onAbort = (): void => {
106
+ if (settled) return
107
+ settled = true
108
+ resolve(abortDecision)
109
+ }
110
+ signal.addEventListener('abort', onAbort, { once: true })
111
+ Promise.resolve(ctx.resumeHandler(request)).then(
112
+ (decision) => {
113
+ if (settled) return
114
+ settled = true
115
+ signal.removeEventListener('abort', onAbort)
116
+ resolve(decision)
117
+ },
118
+ (err) => {
119
+ if (settled) return
120
+ settled = true
121
+ signal.removeEventListener('abort', onAbort)
122
+ resolve({
123
+ action: 'abort',
124
+ reason: err instanceof Error ? err.message : 'resume handler failed',
125
+ })
126
+ },
127
+ )
128
+ })
129
+ }
130
+
67
131
  export async function* handleHITLDecision(
68
132
  ctx: IterationContext,
69
133
  decision: HITLResumeDecision,
@@ -115,6 +179,10 @@ export async function* handleHITLDecision(
115
179
  case 'approve_tools':
116
180
  case 'modify_tools':
117
181
  case 'reject_tools':
182
+ // 'answer_question' can only arrive misdirected at an iteration
183
+ // checkpoint (answers are consumed inside the ask_user_question
184
+ // tool's own park); treat it as a plain continue.
185
+ case 'answer_question':
118
186
  return 'continue'
119
187
  default: {
120
188
  const _exhaustive: never = decision
@@ -0,0 +1,86 @@
1
+ import { describe, expect, it } from 'vitest'
2
+
3
+ import type { HITLResumeDecision } from '../../../../types/hitl/index.js'
4
+ import type { RunId } from '../../../../types/ids/index.js'
5
+ import { type IterationContext, awaitDecisionOrAbort } from './context.js'
6
+
7
+ /**
8
+ * C12: a Stop that arrives while the run is parked on a HITL decision must
9
+ * interrupt the park (resolve as `abort`) instead of hanging until the host
10
+ * eventually answers. `awaitDecisionOrAbort` races `resumeHandler` against
11
+ * `ctx.abortController.signal`.
12
+ */
13
+
14
+ function ctxWith(opts: {
15
+ controller?: AbortController
16
+ resumeHandler: IterationContext['resumeHandler']
17
+ }): IterationContext {
18
+ return {
19
+ abortController: opts.controller,
20
+ resumeHandler: opts.resumeHandler,
21
+ runMgr: { id: 'run_abort_test' as RunId },
22
+ } as unknown as IterationContext
23
+ }
24
+
25
+ const REVIEW_REQUEST = {
26
+ type: 'tool_review' as const,
27
+ runId: 'run_abort_test' as RunId,
28
+ checkpointId: 'cp_1' as `cp_${string}`,
29
+ toolCalls: [],
30
+ }
31
+
32
+ describe('awaitDecisionOrAbort (C12 — cancellable HITL park)', () => {
33
+ it('returns abort immediately when the signal is already aborted', async () => {
34
+ const controller = new AbortController()
35
+ controller.abort()
36
+ const ctx = ctxWith({
37
+ controller,
38
+ // A handler that never resolves — proving we did not wait on it.
39
+ resumeHandler: () => new Promise<HITLResumeDecision>(() => {}),
40
+ })
41
+ const decision = await awaitDecisionOrAbort(ctx, REVIEW_REQUEST)
42
+ expect(decision.action).toBe('abort')
43
+ })
44
+
45
+ it('resolves as abort when the signal fires DURING the park', async () => {
46
+ const controller = new AbortController()
47
+ const ctx = ctxWith({
48
+ controller,
49
+ resumeHandler: () => new Promise<HITLResumeDecision>(() => {}), // never answers
50
+ })
51
+ const pending = awaitDecisionOrAbort(ctx, REVIEW_REQUEST)
52
+ controller.abort()
53
+ const decision = await pending
54
+ expect(decision.action).toBe('abort')
55
+ })
56
+
57
+ it('returns the real decision when the handler answers before any abort', async () => {
58
+ const controller = new AbortController()
59
+ const ctx = ctxWith({
60
+ controller,
61
+ resumeHandler: async () => ({ action: 'approve_tools' }) as HITLResumeDecision,
62
+ })
63
+ const decision = await awaitDecisionOrAbort(ctx, REVIEW_REQUEST)
64
+ expect(decision.action).toBe('approve_tools')
65
+ })
66
+
67
+ it('degrades to a direct resumeHandler await when no controller is wired', async () => {
68
+ const ctx = ctxWith({
69
+ resumeHandler: async () => ({ action: 'reject_tools' }) as HITLResumeDecision,
70
+ })
71
+ const decision = await awaitDecisionOrAbort(ctx, REVIEW_REQUEST)
72
+ expect(decision.action).toBe('reject_tools')
73
+ })
74
+
75
+ it('fails closed to abort when the resume handler rejects', async () => {
76
+ const controller = new AbortController()
77
+ const ctx = ctxWith({
78
+ controller,
79
+ resumeHandler: async () => {
80
+ throw new Error('handler boom')
81
+ },
82
+ })
83
+ const decision = await awaitDecisionOrAbort(ctx, REVIEW_REQUEST)
84
+ expect(decision.action).toBe('abort')
85
+ })
86
+ })
@@ -0,0 +1,139 @@
1
+ import { describe, expect, it } from 'vitest'
2
+
3
+ import { type HITLResumeDecision, autoApproveHandler } from '../../../../types/hitl/index.js'
4
+ import type { CheckpointId, RunId } from '../../../../types/ids/index.js'
5
+ import type { ChatCompletionResponse } from '../../../../types/provider/index.js'
6
+ import type { RunEvent } from '../../../../types/run/index.js'
7
+ import { type IterationContext, handleHITLDecision } from './context.js'
8
+ import { runToolReview } from './tool-review.js'
9
+
10
+ async function drainGenerator<TReturn>(
11
+ gen: AsyncGenerator<RunEvent, TReturn>,
12
+ ): Promise<{ events: RunEvent[]; value: TReturn }> {
13
+ const events: RunEvent[] = []
14
+ let next = await gen.next()
15
+ while (!next.done) {
16
+ events.push(next.value)
17
+ next = await gen.next()
18
+ }
19
+ return { events, value: next.value }
20
+ }
21
+
22
+ describe('autoApproveHandler user_question case', () => {
23
+ it('returns the non-fabricating no-answer sentinel with the questionId echoed', async () => {
24
+ const decision = await autoApproveHandler({
25
+ type: 'user_question',
26
+ runId: 'run_headless_test' as RunId,
27
+ checkpointId: 'cp_question_toolu_1' as CheckpointId,
28
+ question: {
29
+ questionId: 'toolu_1',
30
+ question: 'Pick one?',
31
+ options: [
32
+ { id: 'opt_1', label: 'A' },
33
+ { id: 'opt_2', label: 'B' },
34
+ ],
35
+ multiSelect: false,
36
+ allowFreeText: true,
37
+ },
38
+ })
39
+
40
+ expect(decision).toEqual({
41
+ action: 'answer_question',
42
+ selectedOptionIds: [],
43
+ freeText: 'No user is available to answer. Proceed using your best judgment.',
44
+ questionId: 'toolu_1',
45
+ })
46
+ })
47
+ })
48
+
49
+ describe('handleHITLDecision answer_question case', () => {
50
+ it("treats a misdirected 'answer_question' at an iteration checkpoint as continue", async () => {
51
+ // The branch returns without touching the context — answers are
52
+ // consumed inside the ask_user_question tool's own park, so an
53
+ // answer arriving here can only be misdirected.
54
+ const ctx = {} as IterationContext
55
+ const { events, value } = await drainGenerator(
56
+ handleHITLDecision(
57
+ ctx,
58
+ { action: 'answer_question', selectedOptionIds: ['opt_1'] },
59
+ 'cp_checkpoint_1',
60
+ 'iteration checkpoint',
61
+ ),
62
+ )
63
+ expect(value).toBe('continue')
64
+ expect(events).toEqual([])
65
+ })
66
+ })
67
+
68
+ describe('runToolReview answer_question case', () => {
69
+ function reviewContext(decision: HITLResumeDecision) {
70
+ const warns: string[] = []
71
+ const pushed: unknown[] = []
72
+ let batches = 0
73
+ const ctx = {
74
+ tools: { get: () => undefined },
75
+ checkpointMgr: {
76
+ create: async () => ({ id: 'cp_review_1' as CheckpointId }),
77
+ },
78
+ emitEvent: async () => {},
79
+ drainPending: (): Generator<RunEvent> => [][Symbol.iterator]() as Generator<RunEvent>,
80
+ resumeHandler: async () => decision,
81
+ log: {
82
+ debug: () => {},
83
+ info: () => {},
84
+ warn: (message: string) => {
85
+ warns.push(message)
86
+ },
87
+ error: () => {},
88
+ },
89
+ runMgr: {
90
+ id: 'run_tool_review_test' as RunId,
91
+ pushMessage: (message: unknown) => {
92
+ pushed.push(message)
93
+ },
94
+ },
95
+ toolExecutor: {
96
+ executeBatch: async () => {
97
+ batches += 1
98
+ return { messages: [], results: [] }
99
+ },
100
+ },
101
+ } as unknown as IterationContext
102
+ return { ctx, warns, pushed, batchCount: () => batches }
103
+ }
104
+
105
+ const response: ChatCompletionResponse = {
106
+ id: 'resp_1',
107
+ model: 'test-model',
108
+ message: {
109
+ role: 'assistant',
110
+ content: null,
111
+ toolCalls: [
112
+ {
113
+ id: 'toolu_review_1',
114
+ type: 'function',
115
+ function: { name: 'ask_user_question', arguments: '{}' },
116
+ },
117
+ ],
118
+ },
119
+ finishReason: 'tool_calls',
120
+ usage: {
121
+ promptTokens: 0,
122
+ completionTokens: 0,
123
+ totalTokens: 0,
124
+ cachedTokens: 0,
125
+ cacheWriteTokens: 0,
126
+ },
127
+ }
128
+
129
+ it("warns and executes the batch on a misdirected 'answer_question' instead of stalling", async () => {
130
+ const { ctx, warns, batchCount } = reviewContext({
131
+ action: 'answer_question',
132
+ selectedOptionIds: [],
133
+ })
134
+ const { value } = await drainGenerator(runToolReview(ctx, response, 1))
135
+ expect(value).toBe('executed')
136
+ expect(batchCount()).toBe(1)
137
+ expect(warns).toHaveLength(1)
138
+ })
139
+ })
@@ -2,7 +2,7 @@ import { createUserMessage } from '../../../../types/message/index.js'
2
2
  import type { ChatCompletionResponse } from '../../../../types/provider/index.js'
3
3
  import type { RunEvent } from '../../../../types/run/index.js'
4
4
  import type { VerificationGate } from '../../../../verification/index.js'
5
- import type { IterationContext } from './context.js'
5
+ import { type IterationContext, awaitDecisionOrAbort } from './context.js'
6
6
 
7
7
  interface VerificationAwareContext extends IterationContext {
8
8
  readonly verificationGate?: VerificationGate
@@ -94,7 +94,7 @@ export async function* runToolReview(
94
94
  })
95
95
  yield* ctx.drainPending()
96
96
 
97
- const reviewDecision = await ctx.resumeHandler({
97
+ const reviewDecision = await awaitDecisionOrAbort(ctx, {
98
98
  type: 'tool_review',
99
99
  runId: ctx.runMgr.id,
100
100
  checkpointId: reviewCheckpoint.id,
@@ -198,7 +198,11 @@ export async function* runToolReview(
198
198
  }
199
199
 
200
200
  case 'approve_plan':
201
- case 'reject_plan': {
201
+ case 'reject_plan':
202
+ // 'answer_question' belongs to an ask_user_question park, not a
203
+ // tool review — like the misdirected plan decisions above, warn
204
+ // and proceed with execution rather than stalling the run.
205
+ case 'answer_question': {
202
206
  ctx.log.warn('Unexpected plan decision during tool review', {
203
207
  action: reviewDecision.action,
204
208
  })