@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
@@ -0,0 +1,157 @@
1
+ import { z } from 'zod'
2
+
3
+ import type { AgentRuntimeContext } from '../../types/agent/base.js'
4
+ import type { TaskGateway } from '../../types/agent/gateway.js'
5
+ import type { ToolDefinition } from '../../types/tool/index.js'
6
+ import { defineTool } from '../defineTool.js'
7
+
8
+ import type { TaskLaunchedCallback } from './index.js'
9
+
10
+ /**
11
+ * Build the canonical Claude Code `Agent` tool — synchronous subagent
12
+ * delegation that mirrors what Claude is trained against in
13
+ * `code.claude.com/docs/en/sub-agents`.
14
+ *
15
+ * Semantics: parent calls `Agent({ description, prompt, subagent_type })`,
16
+ * the runtime spawns the chosen subagent with its own context window,
17
+ * the parent's tool call BLOCKS until the subagent finishes, and the
18
+ * subagent's final text comes back as the tool result. Intermediate
19
+ * subagent tool calls are isolated — only the summary surfaces to
20
+ * the parent.
21
+ *
22
+ * This is **NOT** the same shape as the legacy `create_task` /
23
+ * `continue_task` / `cancel_task` trio that this package ships
24
+ * alongside it: those are non-blocking and use a `<task-notification>`
25
+ * callback model. The async pattern is useful for hosts that want a
26
+ * work-queue surface, but it is not what Claude Code trained against.
27
+ * For free agentic alignment, prefer the canonical `Agent` tool; keep
28
+ * the legacy coordinator tools only when you genuinely need
29
+ * fire-and-forget multi-task fan-out.
30
+ */
31
+ export interface AgentToolOptions {
32
+ gateway: TaskGateway
33
+ workingDirectory: string
34
+ runtimeContext?: AgentRuntimeContext
35
+ allowedAgentIds: string[]
36
+
37
+ onTaskLaunched?: TaskLaunchedCallback
38
+ }
39
+
40
+ export function buildAgentTool(opts: AgentToolOptions): ToolDefinition {
41
+ const { gateway, allowedAgentIds: agentIds, onTaskLaunched } = opts
42
+ const cwd = opts.workingDirectory
43
+
44
+ const subagentTypeEnum =
45
+ agentIds.length > 0 ? z.enum(agentIds as [string, ...string[]]) : z.string()
46
+
47
+ return defineTool({
48
+ name: 'Agent',
49
+ description: `Delegate a task to a specialized subagent. BLOCKING: returns when the subagent has finished, with the subagent's final text as the tool result. The subagent runs in its own context window and cannot see your conversation — include all necessary context in the prompt. Available subagents: ${agentIds.join(', ')}. To run multiple subagents in parallel, call this tool multiple times in a single response.`,
50
+ inputSchema: z.object({
51
+ description: z.string().describe('Short label for tracking (shown to the user)'),
52
+ prompt: z
53
+ .string()
54
+ .describe('Self-contained task description with all context the subagent needs'),
55
+ subagent_type:
56
+ agentIds.length === 1
57
+ ? subagentTypeEnum
58
+ .optional()
59
+ .describe(`Which subagent to run (defaults to the only one: ${agentIds[0]})`)
60
+ : subagentTypeEnum.describe('Which subagent to run'),
61
+ }),
62
+ category: 'custom',
63
+ permissions: [],
64
+ readOnly: false,
65
+ destructive: false,
66
+ concurrencySafe: true,
67
+ async execute({ description, prompt, subagent_type }, context) {
68
+ // With a single registered subagent the type is optional — default to
69
+ // it so the model can't trip the "subagent_type required" validation.
70
+ const agentId = subagent_type ?? (agentIds.length === 1 ? agentIds[0] : undefined)
71
+ if (!agentId) {
72
+ return {
73
+ success: false,
74
+ output: '',
75
+ error: `subagent_type is required — choose one of: ${agentIds.join(', ')}`,
76
+ }
77
+ }
78
+ const handle = await gateway.createTask({
79
+ agentId,
80
+ prompt,
81
+ workingDirectory: cwd,
82
+ runtimeContext: opts.runtimeContext,
83
+ })
84
+
85
+ onTaskLaunched?.(handle.taskId, {
86
+ agentId,
87
+ description,
88
+ // Same canonical-envelope plumbing as coordinator/index.ts
89
+ // (ses_009-task-notification-envelope). For Agent-tool path
90
+ // the subagent run is awaited synchronously below, so this
91
+ // id is only used if a probe / hook unexpectedly forks the
92
+ // completion to the background notification channel.
93
+ originalToolUseId: context.toolUseId,
94
+ })
95
+
96
+ const completed = await gateway.waitForTask(handle.taskId)
97
+
98
+ // Two layers can disagree on whether the subagent succeeded:
99
+ //
100
+ // 1. `TaskHandle.state` — the gateway's terminal task state.
101
+ // Some gateways (e.g. vandal's) explicitly map
102
+ // `result.status !== 'completed'` to `state = 'failed'`,
103
+ // others (e.g. SDK's `LocalTaskGateway`) just forward
104
+ // whatever the AgentManager set, which does not always
105
+ // reflect run-level failure.
106
+ // 2. `BaseAgentResult.status` — the run's own status. The
107
+ // canonical source of truth for whether the agent actually
108
+ // finished its work; `lastError` carries the failure
109
+ // message when set.
110
+ //
111
+ // Treat the subagent as successful only when BOTH agree.
112
+ // Reporting a failed subagent as successful would silently
113
+ // hand the parent garbage output and make debugging
114
+ // impossible, which is what Codex flagged on the first cut.
115
+ const runStatus = completed.result?.status
116
+ const succeeded =
117
+ completed.state === 'completed' && (runStatus === undefined || runStatus === 'completed')
118
+
119
+ const resultText =
120
+ typeof completed.result?.result === 'string'
121
+ ? completed.result.result
122
+ : completed.result?.result !== undefined
123
+ ? JSON.stringify(completed.result.result)
124
+ : ''
125
+
126
+ if (!succeeded) {
127
+ const failureLabel =
128
+ completed.state !== 'completed' ? completed.state : (runStatus ?? 'failed')
129
+ const detail =
130
+ completed.result?.lastError ?? resultText ?? '(subagent provided no failure detail)'
131
+ return {
132
+ success: false,
133
+ output: '',
134
+ error: `Subagent ${agentId} ${failureLabel}: ${detail}`,
135
+ data: {
136
+ task_id: handle.taskId,
137
+ subagent_type: agentId,
138
+ state: completed.state,
139
+ status: runStatus,
140
+ lastError: completed.result?.lastError,
141
+ },
142
+ }
143
+ }
144
+
145
+ return {
146
+ success: true,
147
+ output: resultText || '(subagent returned no text)',
148
+ data: {
149
+ task_id: handle.taskId,
150
+ subagent_type: agentId,
151
+ state: completed.state,
152
+ status: runStatus,
153
+ },
154
+ }
155
+ },
156
+ })
157
+ }
@@ -2,6 +2,7 @@ import { z } from 'zod'
2
2
  import type { PlanManager } from '../../manager/plan/lifecycle.js'
3
3
  import type { AgentRuntimeContext } from '../../types/agent/base.js'
4
4
  import type { TaskGateway } from '../../types/agent/gateway.js'
5
+ import type { ResumeHandler, UserQuestionOption } from '../../types/hitl/index.js'
5
6
  import type { RunId, TaskId } from '../../types/ids/index.js'
6
7
  import type { TaskStore } from '../../types/task/index.js'
7
8
  import type { ToolDefinition } from '../../types/tool/index.js'
@@ -13,6 +14,13 @@ export type TaskLaunchedCallback = (
13
14
  agentId: string
14
15
  description: string
15
16
  planTaskId?: string
17
+ /**
18
+ * The assistant `tool_use_id` that dispatched this task.
19
+ * Threaded from `ToolContext.toolUseId` so the runtime can
20
+ * later emit a canonical `tool_result` content block bound
21
+ * to the same id when the background task completes.
22
+ */
23
+ originalToolUseId?: string
16
24
  },
17
25
  ) => void
18
26
 
@@ -29,6 +37,52 @@ export interface CoordinatorToolsOptions {
29
37
  getPlanManager?: () => PlanManager | undefined
30
38
 
31
39
  onTaskLaunched?: TaskLaunchedCallback
40
+
41
+ /**
42
+ * HITL park channel for `ask_user_question`. The tool is registered
43
+ * only when BOTH `resumeHandler` and `runId` are present — without a
44
+ * handler there is no one to route the question to, and without a
45
+ * runId the park request cannot be addressed.
46
+ */
47
+ resumeHandler?: ResumeHandler
48
+ }
49
+
50
+ const approvePlanStepSchema = z.object({
51
+ description: z.string().describe('What this step does'),
52
+ agent_id: z
53
+ .string()
54
+ .optional()
55
+ .describe('Which agent handles this (omit for orchestrator-owned steps)'),
56
+ depends_on: z.array(z.string()).optional().describe('Step descriptions this depends on'),
57
+ })
58
+
59
+ function normalizeApprovePlanSteps(value: unknown): unknown {
60
+ if (typeof value !== 'string') return value
61
+
62
+ const trimmed = value.trim()
63
+ if (!trimmed) return []
64
+
65
+ if (trimmed.startsWith('[')) {
66
+ try {
67
+ return JSON.parse(trimmed)
68
+ } catch {
69
+ // Fall through to plain-text line parsing.
70
+ }
71
+ }
72
+
73
+ const lines = trimmed
74
+ .split(/\r?\n+/)
75
+ .map((line) =>
76
+ line
77
+ .trim()
78
+ .replace(/^(?:[-*•]|\d+[.)])\s*/, '')
79
+ .trim(),
80
+ )
81
+ .filter(Boolean)
82
+
83
+ return (lines.length ? lines : [trimmed]).map((description) => ({
84
+ description,
85
+ }))
32
86
  }
33
87
 
34
88
  export function buildCoordinatorTools(opts: CoordinatorToolsOptions): ToolDefinition[] {
@@ -38,21 +92,30 @@ export function buildCoordinatorTools(opts: CoordinatorToolsOptions): ToolDefini
38
92
  taskStore,
39
93
  runId,
40
94
  getPlanManager,
41
- onTaskLaunched,
95
+ resumeHandler,
96
+ // `onTaskLaunched` was the entry point for the old
97
+ // non-blocking + envelope-injection flow. create_task is now
98
+ // blocking, so the callback is no longer wired here.
99
+ // Intentionally not destructured to keep the unused-binding
100
+ // lint clean; callers can still pass it for backwards
101
+ // compatibility (Agent tool consumes it from its own path).
42
102
  } = opts
43
103
  const cwd = opts.workingDirectory
104
+ void opts.onTaskLaunched
44
105
 
45
106
  const agentIdEnum = agentIds.length > 0 ? z.enum(agentIds as [string, ...string[]]) : z.string()
46
107
 
47
108
  const createTask = defineTool({
48
109
  name: 'create_task',
49
- description: `Launch a task on a specialized agent. NON-BLOCKING: returns immediately. You will receive a <task-notification> message when the agent finishes. Available agents: ${agentIds.join(', ')}. The agent cannot see your conversation include ALL necessary context in the prompt. To launch multiple tasks in parallel, call this tool multiple times in a single response. After launching, briefly tell the user what you launched and end your turn do NOT predict or fabricate results.`,
110
+ description: `Launch a task on a specialized agent and await its result. BLOCKING: returns the agent's final output as this call's tool_result. Available agents: ${agentIds.join(', ')}. Prefer compact assignments; for large context, write/read shared workspace files and pass filenames or references. To launch multiple tasks in parallel, call this tool multiple times in a single assistant turn the runtime executes every tool_use block from one response concurrently and delivers all tool_results together, so 'fan out 8 specialists' is one assistant message with 8 create_task blocks.`,
50
111
  inputSchema: z.object({
51
112
  agent_id: agentIdEnum.describe('Which agent to run'),
52
113
  prompt: z
53
114
  .string()
54
- .describe('Self-contained task description with all context the agent needs'),
55
- description: z.string().describe('Short summary for tracking (shown to user)'),
115
+ .describe(
116
+ 'Self-contained assignment for the agent. For large generated content, prefer workspace file references so provider output-token limits do not cut off the tool call.',
117
+ ),
118
+ description: z.string().describe('Short summary for tracking, shown to the user.'),
56
119
  plan_task_id: z
57
120
  .string()
58
121
  .optional()
@@ -65,7 +128,7 @@ export function buildCoordinatorTools(opts: CoordinatorToolsOptions): ToolDefini
65
128
  readOnly: false,
66
129
  destructive: false,
67
130
  concurrencySafe: true,
68
- async execute({ agent_id, prompt, description, plan_task_id }) {
131
+ async execute({ agent_id, prompt, description, plan_task_id }, _context) {
69
132
  let resolvedPlanTaskId = plan_task_id
70
133
 
71
134
  if (taskStore) {
@@ -93,22 +156,36 @@ export function buildCoordinatorTools(opts: CoordinatorToolsOptions): ToolDefini
93
156
  runtimeContext: opts.runtimeContext,
94
157
  })
95
158
 
96
- if (onTaskLaunched) {
97
- onTaskLaunched(handle.taskId, {
98
- agentId: agent_id,
99
- description,
100
- planTaskId: resolvedPlanTaskId,
159
+ // Industrial-standard Anthropic tool pattern: tool returns
160
+ // its real result as the tool_result for the dispatching
161
+ // tool_use. Parallel fan-out happens at the executor layer
162
+ // — when the supervisor emits N create_task blocks in one
163
+ // assistant turn, the runtime runs them with Promise.all
164
+ // and delivers all N tool_results together. No async
165
+ // envelope injection, no second tool_result for the same
166
+ // tool_use_id (which Anthropic rejects with 400).
167
+ const completed = await gateway.waitForTask(handle.taskId)
168
+ const success = completed.state === 'completed'
169
+ const resultText =
170
+ completed.result?.result ??
171
+ completed.result?.lastError ??
172
+ `Task finished with state: ${completed.state}`
173
+
174
+ if (resolvedPlanTaskId && taskStore) {
175
+ await taskStore.update(resolvedPlanTaskId as `task_${string}`, {
176
+ status: 'completed',
177
+ description: success ? undefined : `Failed: ${resultText.substring(0, 200)}`,
101
178
  })
102
179
  }
103
180
 
104
181
  return {
105
- success: true,
106
- output: `Task launched: ${handle.taskId} → ${agent_id} ("${description}"). You will receive a task-notification when it completes.`,
182
+ success,
183
+ output: resultText,
107
184
  data: {
108
185
  task_id: handle.taskId,
109
186
  agent_id,
110
187
  description,
111
- state: 'running',
188
+ state: completed.state,
112
189
  plan_task_id: resolvedPlanTaskId,
113
190
  },
114
191
  }
@@ -118,11 +195,9 @@ export function buildCoordinatorTools(opts: CoordinatorToolsOptions): ToolDefini
118
195
  const continueTask = defineTool({
119
196
  name: 'continue_task',
120
197
  description:
121
- 'Send a follow-up message to a previously completed task. NON-BLOCKING: the agent resumes in the background with full prior context. You will receive a task-notification when it finishes. Only use this with a task_id from a previous create_task or task-notification.',
198
+ "Send a follow-up message to a previously completed task and await the agent's next reply. BLOCKING: returns the agent's new output as this call's tool_result, the same shape as create_task. Only use this with a task_id from a previous create_task. To run multiple follow-ups in parallel, call this tool multiple times in a single assistant turn.",
122
199
  inputSchema: z.object({
123
- task_id: z
124
- .string()
125
- .describe('Agent task ID from a previous create_task or task-notification'),
200
+ task_id: z.string().describe('Agent task ID from a previous create_task'),
126
201
  message: z.string().describe('Follow-up instruction for the agent'),
127
202
  }),
128
203
  category: 'custom',
@@ -132,11 +207,22 @@ export function buildCoordinatorTools(opts: CoordinatorToolsOptions): ToolDefini
132
207
  concurrencySafe: true,
133
208
  async execute({ task_id, message }) {
134
209
  await gateway.continueTask(task_id as TaskId, message)
135
-
210
+ // Mirror create_task's blocking pattern: await the new
211
+ // completion and return the agent's output inline. The
212
+ // previous non-blocking shape ('You will receive a
213
+ // task-notification…') relied on a global
214
+ // onTaskCompleted listener that the iteration loop
215
+ // no longer registers (envelope path is dead).
216
+ const completed = await gateway.waitForTask(task_id as TaskId)
217
+ const success = completed.state === 'completed'
218
+ const resultText =
219
+ completed.result?.result ??
220
+ completed.result?.lastError ??
221
+ `Task finished with state: ${completed.state}`
136
222
  return {
137
- success: true,
138
- output: `Follow-up sent to ${task_id}. You will receive a task-notification when it finishes.`,
139
- data: { task_id, state: 'running' },
223
+ success,
224
+ output: resultText,
225
+ data: { task_id, state: completed.state },
140
226
  }
141
227
  },
142
228
  })
@@ -163,7 +249,75 @@ export function buildCoordinatorTools(opts: CoordinatorToolsOptions): ToolDefini
163
249
  },
164
250
  })
165
251
 
166
- const tools: ToolDefinition[] = [createTask, continueTask, cancelTask]
252
+ const agentTaskList = defineTool({
253
+ name: 'agent_task_list',
254
+ description:
255
+ "Inspect the live state of every agent task launched on this gateway via create_task: returns each task's id, agent, state (pending/running/completed/failed/canceled), and timing. Distinct from the plan-task store's `task_list` (which lists planning tasks): this tool lists running/completed worker invocations. Use it BEFORE declaring multi-worker work done — confirm every launched task reached `completed`, none still `running` or `failed`. Read-only and safe to call repeatedly.",
256
+ inputSchema: z.object({
257
+ state: z
258
+ .enum(['pending', 'running', 'completed', 'failed', 'canceled'])
259
+ .optional()
260
+ .describe('Filter by terminal/non-terminal state. Omit to list every task.'),
261
+ }),
262
+ category: 'custom',
263
+ permissions: [],
264
+ readOnly: true,
265
+ destructive: false,
266
+ concurrencySafe: true,
267
+ async execute({ state }) {
268
+ const handles = gateway.listTasks()
269
+ const filtered = state ? handles.filter((h) => h.state === state) : handles
270
+ const items = filtered.map((h) => {
271
+ const runStatus = h.result?.status
272
+ const lastError = h.result?.lastError ?? undefined
273
+ return {
274
+ task_id: h.taskId,
275
+ agent_id: h.agentId,
276
+ state: h.state,
277
+ run_status: runStatus,
278
+ created_at: new Date(h.createdAt).toISOString(),
279
+ completed_at: h.completedAt ? new Date(h.completedAt).toISOString() : null,
280
+ duration_ms: h.completedAt ? h.completedAt - h.createdAt : null,
281
+ last_error: lastError,
282
+ }
283
+ })
284
+ const summary = {
285
+ total: handles.length,
286
+ running: handles.filter((h) => h.state === 'running').length,
287
+ completed: handles.filter((h) => h.state === 'completed').length,
288
+ failed: handles.filter((h) => h.state === 'failed').length,
289
+ canceled: handles.filter((h) => h.state === 'canceled').length,
290
+ }
291
+ const lines = items.length
292
+ ? items.map(
293
+ (i) =>
294
+ `- ${i.task_id} → ${i.agent_id} [${i.state}${i.run_status && i.run_status !== i.state ? ` / ${i.run_status}` : ''}]${
295
+ i.duration_ms !== null ? ` (${Math.round(i.duration_ms / 1000)}s)` : ''
296
+ }${i.last_error ? ` — error: ${i.last_error.slice(0, 200)}` : ''}`,
297
+ )
298
+ : ['(no tasks launched yet)']
299
+ const header = `Tasks: ${summary.total} total — ${summary.running} running, ${summary.completed} completed, ${summary.failed} failed, ${summary.canceled} canceled`
300
+ return {
301
+ success: true,
302
+ output: [header, '', ...lines].join('\n'),
303
+ data: { items, summary },
304
+ }
305
+ },
306
+ })
307
+
308
+ // `continue_task` was a follow-up channel for a still-alive worker
309
+ // task. With `create_task` now blocking + tool_result returning
310
+ // the worker's final output, every worker reaches a terminal
311
+ // state by the time the supervisor wants to follow up — and the
312
+ // agent manager rejects `continue` on terminal tasks. The
313
+ // industrial pattern is to issue a fresh `create_task` that
314
+ // references the prior worker's output path, so we drop
315
+ // `continue_task` from the registered surface entirely. The
316
+ // definition stays in this file for now in case a future
317
+ // non-default gateway (one that keeps the worker process alive
318
+ // for follow-ups) wants to re-register it.
319
+ void continueTask
320
+ const tools: ToolDefinition[] = [createTask, cancelTask, agentTaskList]
167
321
 
168
322
  if (getPlanManager) {
169
323
  const approvePlan = defineTool({
@@ -176,26 +330,18 @@ export function buildCoordinatorTools(opts: CoordinatorToolsOptions): ToolDefini
176
330
  .describe('Short title for the plan (e.g. "TypeScript Security & Performance Review")'),
177
331
  summary: z.string().describe('1-3 sentence summary of what you plan to do'),
178
332
  steps: z
179
- .array(
180
- z.object({
181
- description: z.string().describe('What this step does'),
182
- agent_id: z
183
- .string()
184
- .optional()
185
- .describe('Which agent handles this (omit for orchestrator-owned steps)'),
186
- depends_on: z
187
- .array(z.string())
188
- .optional()
189
- .describe('Step descriptions this depends on'),
190
- }),
191
- )
333
+ .preprocess(normalizeApprovePlanSteps, z.array(approvePlanStepSchema))
192
334
  .describe('Ordered list of planned steps'),
193
335
  }),
194
336
  category: 'custom',
195
337
  permissions: [],
196
338
  readOnly: true,
197
339
  destructive: false,
198
- concurrencySafe: true,
340
+ // Parks through the SAME runId-keyed host resume registry as
341
+ // ask_user_question — concurrent parks in one batch clobber the
342
+ // registry entry and deadlock the loser, so the executor must
343
+ // serialize this tool exactly like the question tool.
344
+ concurrencySafe: false,
199
345
  async execute({ title, summary, steps }) {
200
346
  const pm = getPlanManager()
201
347
  if (!pm) {
@@ -224,17 +370,27 @@ export function buildCoordinatorTools(opts: CoordinatorToolsOptions): ToolDefini
224
370
 
225
371
  if (response.approved) {
226
372
  pm.startExecution()
373
+ // Approve-with-edits: when the user attached feedback to an
374
+ // approval, embed it in the model-visible output so the
375
+ // supervisor applies the edits during execution. A bare
376
+ // approve keeps the historical output byte-identical.
377
+ const output = response.feedback
378
+ ? `Plan approved by user with required edits — apply them during execution:\n${response.feedback}\nProceed with execution — launch workers via create_task.`
379
+ : 'Plan approved by user. Proceed with execution — launch workers via create_task.'
227
380
  return {
228
381
  success: true,
229
- output:
230
- 'Plan approved by user. Proceed with execution — launch workers via create_task.',
382
+ output,
231
383
  data: { approved: true, feedback: response.feedback },
232
384
  }
233
385
  }
234
386
 
387
+ // Rejection guidance follows the FEEDBACK, not a baked-in
388
+ // revise loop: the old unconditional "revise … and call
389
+ // approve_plan again" contradicted stop-style feedback, so a
390
+ // user rejecting a plan got another plan instead of a halt.
235
391
  return {
236
392
  success: false,
237
- output: `Plan rejected. User feedback: ${response.feedback ?? 'No feedback provided'}. Revise your plan based on this feedback and call approve_plan again, or ask the user for clarification.`,
393
+ output: `Plan rejected. User feedback: ${response.feedback ?? 'No feedback provided'}. Follow this feedback: if it requests changes, revise your plan and call approve_plan again; if it asks you to stop, acknowledge briefly and end your turn. If no feedback was provided, ask the user how to proceed before planning again.`,
238
394
  data: { approved: false, feedback: response.feedback },
239
395
  }
240
396
  },
@@ -242,5 +398,165 @@ export function buildCoordinatorTools(opts: CoordinatorToolsOptions): ToolDefini
242
398
  tools.push(approvePlan)
243
399
  }
244
400
 
401
+ if (resumeHandler && runId) {
402
+ const parkRunId = runId
403
+ const parkHandler = resumeHandler
404
+ const askUserQuestion = defineTool({
405
+ name: 'ask_user_question',
406
+ description:
407
+ 'Ask the user ONE question ONLY when you are blocked on a decision that is genuinely theirs to make — one you cannot resolve from their request, your tools, the files you can read, or sensible defaults. The question must be the genuinely undecidable thing in THIS task. Never ask for information a tool can discover (do not ask what you can read, list, or search), never re-ask what the conversation already answers, and never ask meta-questions like "Shall I proceed?" — plan ratification goes through approve_plan. Provide 2-4 genuinely distinct options derived from the actual context — concrete paths, never generic placeholders (for example, asked to prepare a presentation, ask "Who is the audience?" with options like Board / Engineering team / Customer); keep labels short (1-5 words) and give each option a one-line description of what practically changes if it is chosen. Put your recommended option FIRST and append " (Recommended)" to its label. Set multiSelect: true only when several options can apply at once. A free-text "Something else" escape hatch is always shown automatically — do not add your own "Other" option. Ask ONE question per call and prefer at most one question per assistant turn; if several decisions block you, ask only the ones that materially change your next actions, in sequence — most work needs at most 2-3 questions, so prefer proceeding on stated defaults over interrogating the user. Never invent answers or synthetic content on the user\'s behalf unless they explicitly asked for a random/test scenario. The answer arrives as this tool\'s result; if the result says the user did not answer, do not ask this or any other question again — proceed on your best judgment without assuming consent.',
408
+ inputSchema: z.object({
409
+ question: z
410
+ .string()
411
+ .min(1)
412
+ .describe('Full question text — clear, specific, ends with a question mark.'),
413
+ header: z
414
+ .string()
415
+ .max(24)
416
+ .optional()
417
+ .describe('Very short topic label for the question (e.g. "Audience", "Auth method").'),
418
+ options: z
419
+ .array(
420
+ z.object({
421
+ label: z
422
+ .string()
423
+ .min(1)
424
+ .max(80)
425
+ .describe(
426
+ 'Concise option label (1-5 words). Recommended option goes first with " (Recommended)" appended.',
427
+ ),
428
+ description: z
429
+ .string()
430
+ .max(300)
431
+ .optional()
432
+ .describe('One line on what practically changes if this option is chosen.'),
433
+ }),
434
+ )
435
+ .min(2)
436
+ .max(4)
437
+ .describe('2-4 genuinely distinct, context-derived options.'),
438
+ multiSelect: z
439
+ .boolean()
440
+ .optional()
441
+ .default(false)
442
+ .describe('True only when several options can apply at once.'),
443
+ allowFreeText: z
444
+ .boolean()
445
+ .optional()
446
+ .default(true)
447
+ .describe('Whether the user may answer in their own words.'),
448
+ }),
449
+ category: 'custom',
450
+ permissions: [],
451
+ readOnly: true,
452
+ destructive: false,
453
+ // MUST stay false: the executor serializes non-concurrency-safe
454
+ // tools in a single chain, so N question blocks in one assistant
455
+ // turn park strictly one-at-a-time. Hosts key their park/resolve
456
+ // registries by runId — concurrent parks on one run clobber each
457
+ // other and the first promise never resolves (run hangs to TTL).
458
+ concurrencySafe: false,
459
+ async execute({ question, header, options, multiSelect, allowFreeText }, context) {
460
+ const toolUseId = context.toolUseId
461
+ if (!toolUseId) {
462
+ // Without the executing tool_use_id the question has no
463
+ // stable identity: the host could never merge the awaiting
464
+ // card with its resolution, and answers could not be matched
465
+ // back. Hard-fail instead of parking an unmergeable id.
466
+ return {
467
+ success: false,
468
+ output: '',
469
+ error:
470
+ 'ask_user_question requires an executor that threads ToolContext.toolUseId; the question cannot be tracked without it.',
471
+ }
472
+ }
473
+
474
+ const questionOptions: UserQuestionOption[] = options.map((opt, i) => ({
475
+ id: `opt_${i + 1}`,
476
+ label: opt.label,
477
+ ...(opt.description !== undefined ? { description: opt.description } : {}),
478
+ }))
479
+
480
+ const decision = await parkHandler({
481
+ type: 'user_question',
482
+ runId: parkRunId,
483
+ checkpointId: `cp_question_${toolUseId}`,
484
+ question: {
485
+ questionId: toolUseId,
486
+ question,
487
+ ...(header !== undefined ? { header } : {}),
488
+ options: questionOptions,
489
+ multiSelect,
490
+ allowFreeText,
491
+ },
492
+ })
493
+
494
+ // The no-answer sentinel (explicitly NOT consent — fixes the
495
+ // "empty answer reads as approval" ambiguity): used for empty
496
+ // answers, misdirected legacy decisions (e.g. a stale replica
497
+ // resolving with approve/continue verbs), and answers that
498
+ // carry a different question's id.
499
+ const noAnswer = {
500
+ success: true,
501
+ output:
502
+ 'The user did not answer this question. Do not assume a choice or consent; proceed on your best judgment or continue without this information.',
503
+ data: { question, answered: false },
504
+ }
505
+
506
+ if (decision.action === 'abort') {
507
+ return {
508
+ success: false,
509
+ output:
510
+ 'The user declined to answer and asked to stop. Acknowledge briefly and end your turn.',
511
+ data: { question, answered: false, declined: true },
512
+ }
513
+ }
514
+
515
+ if (decision.action !== 'answer_question') return noAnswer
516
+ if (decision.questionId !== undefined && decision.questionId !== toolUseId) {
517
+ // Misdirection guard: this answer was meant for a different
518
+ // question parked under the same run (stale client). Never
519
+ // fabricate a selection against the wrong question.
520
+ return noAnswer
521
+ }
522
+
523
+ const stripRecommended = (label: string) =>
524
+ label.replace(/\s*\(recommended\)\s*$/i, '').trim()
525
+
526
+ const selected = decision.selectedOptionIds
527
+ .map((id) => questionOptions.find((opt) => opt.id === id))
528
+ .filter((opt): opt is UserQuestionOption => opt !== undefined)
529
+ .map((opt) => ({ id: opt.id, label: stripRecommended(opt.label) }))
530
+
531
+ const freeText = decision.freeText?.trim() ?? ''
532
+
533
+ if (selected.length === 0 && !freeText) return noAnswer
534
+
535
+ let output: string
536
+ if (selected.length > 0) {
537
+ const joined = selected.map((s) => `"${s.label}"`).join(', ')
538
+ output = `User answered "${question}": ${joined}`
539
+ if (freeText) {
540
+ output += `\nAdditional note from the user: "${freeText}"`
541
+ }
542
+ } else {
543
+ output = `User answered "${question}" in their own words: "${freeText}"`
544
+ }
545
+
546
+ return {
547
+ success: true,
548
+ output,
549
+ data: {
550
+ question,
551
+ selected,
552
+ ...(freeText ? { freeText } : {}),
553
+ answered: true,
554
+ },
555
+ }
556
+ },
557
+ })
558
+ tools.push(askUserQuestion)
559
+ }
560
+
245
561
  return tools
246
562
  }
@@ -65,6 +65,14 @@ export type RuntimeToolOverrides = Record<string, ToolAvailability | 'disabled'>
65
65
  export interface AgentRuntimeContext {
66
66
  label?: string
67
67
  outputDirectory?: string
68
+ /**
69
+ * Optional working/scratch directory the runtime exposes to the
70
+ * agent — sibling to `outputDirectory`, invisible to the
71
+ * output collector. Mirrors the Anthropic Cowork pattern
72
+ * where `/home/claude` is scratch and `/mnt/user-data/outputs` is
73
+ * user-visible.
74
+ */
75
+ scratchDirectory?: string
68
76
  outputFileMarker?: string
69
77
  notes?: readonly string[]
70
78
  }