zidane 7.2.5 → 8.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (376) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +34 -6
  3. package/dist/{acp-D-tVyUjw.js → acp-DQDhi2dj.js} +230 -77
  4. package/dist/acp-DQDhi2dj.js.map +1 -0
  5. package/dist/acp-cli.d.ts +1 -1
  6. package/dist/acp-cli.js +9 -66
  7. package/dist/acp-cli.js.map +1 -1
  8. package/dist/acp.d.ts +10 -590
  9. package/dist/acp.d.ts.map +1 -1
  10. package/dist/acp.js +3 -3
  11. package/dist/{agent-D0zZnGbt.js → agent-DSLNmBp0.js} +14401 -13214
  12. package/dist/agent-DSLNmBp0.js.map +1 -0
  13. package/dist/agent.d.ts +1 -1
  14. package/dist/agent.js +3 -2
  15. package/dist/aliasing-lVFbm81n.js +217 -0
  16. package/dist/aliasing-lVFbm81n.js.map +1 -0
  17. package/dist/{anthropic-C2aole0G.js → anthropic-CD00LhUP.js} +1442 -1264
  18. package/dist/anthropic-CD00LhUP.js.map +1 -0
  19. package/dist/artifacts-CV2hUKnL.js.map +1 -1
  20. package/dist/{atomic-write-B7zr1ddF.js → atomic-write-Ijgf2Mhc.js} +13 -3
  21. package/dist/atomic-write-Ijgf2Mhc.js.map +1 -0
  22. package/dist/call-tool-dHlbGOIY.js +70 -0
  23. package/dist/call-tool-dHlbGOIY.js.map +1 -0
  24. package/dist/chat/pure.d.ts +372 -6
  25. package/dist/chat/pure.d.ts.map +1 -1
  26. package/dist/chat/pure.js +35 -244
  27. package/dist/chat/pure.js.map +1 -1
  28. package/dist/{approvals-DKaJZYlm.js → chat-JPJJ8uu5.js} +15879 -14631
  29. package/dist/chat-JPJJ8uu5.js.map +1 -0
  30. package/dist/chat.d.ts +4 -6
  31. package/dist/chat.js +23 -12
  32. package/dist/cli-shared-C-YCaglL.js +159 -0
  33. package/dist/cli-shared-C-YCaglL.js.map +1 -0
  34. package/dist/client-core-BQSyDALT.d.ts +2115 -0
  35. package/dist/client-core-BQSyDALT.d.ts.map +1 -0
  36. package/dist/codemode-worker.d.ts +1 -0
  37. package/dist/codemode-worker.js +155 -0
  38. package/dist/codemode-worker.js.map +1 -0
  39. package/dist/codemode.d.ts +352 -0
  40. package/dist/codemode.d.ts.map +1 -0
  41. package/dist/codemode.js +5 -0
  42. package/dist/connection-Dr-Js4yZ.d.ts +28 -0
  43. package/dist/connection-Dr-Js4yZ.d.ts.map +1 -0
  44. package/dist/connection-loop-gdh22LTI.js +112 -0
  45. package/dist/connection-loop-gdh22LTI.js.map +1 -0
  46. package/dist/context-segments-BHKlagL6.js +1016 -0
  47. package/dist/context-segments-BHKlagL6.js.map +1 -0
  48. package/dist/{context-transport-T_6AYIvy.js → context-transport-DSMTUsK1.js} +3 -3
  49. package/dist/{context-transport-T_6AYIvy.js.map → context-transport-DSMTUsK1.js.map} +1 -1
  50. package/dist/contexts/daytona.d.ts +19 -8
  51. package/dist/contexts/daytona.d.ts.map +1 -1
  52. package/dist/contexts/daytona.js +1 -440
  53. package/dist/contexts/docker.d.ts +36 -7
  54. package/dist/contexts/docker.d.ts.map +1 -1
  55. package/dist/contexts/docker.js +1 -456
  56. package/dist/contexts/e2b.d.ts +68 -13
  57. package/dist/contexts/e2b.d.ts.map +1 -1
  58. package/dist/contexts/e2b.js +1 -382
  59. package/dist/contexts/sandbox.d.ts +1 -1
  60. package/dist/contexts/sandbox.js +5 -0
  61. package/dist/contexts/sandbox.js.map +1 -1
  62. package/dist/{contexts-CRE9pw07.js → contexts-d7UolYot.js} +1059 -524
  63. package/dist/contexts-d7UolYot.js.map +1 -0
  64. package/dist/contexts.d.ts +3 -3
  65. package/dist/contexts.js +1 -1
  66. package/dist/cred-keys-GpBg71cP.js +105 -0
  67. package/dist/cred-keys-GpBg71cP.js.map +1 -0
  68. package/dist/{auth-BG2rVKSt.js → credentials-JttEuRON.js} +55 -206
  69. package/dist/credentials-JttEuRON.js.map +1 -0
  70. package/dist/{cursor-iojRXHF9.js → cursor-CdjaQTBW.js} +3 -3
  71. package/dist/{cursor-iojRXHF9.js.map → cursor-CdjaQTBW.js.map} +1 -1
  72. package/dist/daemon-cli.d.ts +1 -1
  73. package/dist/daemon-cli.js +3 -2
  74. package/dist/daemon-cli.js.map +1 -1
  75. package/dist/daytona-DG3omipZ.js +513 -0
  76. package/dist/daytona-DG3omipZ.js.map +1 -0
  77. package/dist/defaults-Cx3zvDOV.js +23 -0
  78. package/dist/defaults-Cx3zvDOV.js.map +1 -0
  79. package/dist/dispatcher-BMlu2BmZ.js +4941 -0
  80. package/dist/dispatcher-BMlu2BmZ.js.map +1 -0
  81. package/dist/docker-BZhMMJUp.js +727 -0
  82. package/dist/docker-BZhMMJUp.js.map +1 -0
  83. package/dist/e2b-CEVOdRib.js +480 -0
  84. package/dist/e2b-CEVOdRib.js.map +1 -0
  85. package/dist/edit-utils-EGosADZq.js +234 -0
  86. package/dist/edit-utils-EGosADZq.js.map +1 -0
  87. package/dist/environment-8wsKE2Ln.js +214 -0
  88. package/dist/environment-8wsKE2Ln.js.map +1 -0
  89. package/dist/eval-BNcvle_J.js +1595 -0
  90. package/dist/eval-BNcvle_J.js.map +1 -0
  91. package/dist/eval.d.ts +2 -2
  92. package/dist/eval.js +1 -1489
  93. package/dist/executor-Cx5-8yqi.js +621 -0
  94. package/dist/executor-Cx5-8yqi.js.map +1 -0
  95. package/dist/extension-authoring-DyGGmq9V.js +385 -0
  96. package/dist/extension-authoring-DyGGmq9V.js.map +1 -0
  97. package/dist/extensions.d.ts +2 -2
  98. package/dist/extensions.js +3 -3
  99. package/dist/{fetch-url-DX75gpL0.js → fetch-url-Ct2TjDWt.js} +4 -4
  100. package/dist/{fetch-url-DX75gpL0.js.map → fetch-url-Ct2TjDWt.js.map} +1 -1
  101. package/dist/{format-BF745pLL.js → format-C2NQEVUH.js} +39 -2
  102. package/dist/format-C2NQEVUH.js.map +1 -0
  103. package/dist/format-bytes-C7tfc3Zm.js +55 -0
  104. package/dist/format-bytes-C7tfc3Zm.js.map +1 -0
  105. package/dist/headless-C_rNUuYC.js +960 -0
  106. package/dist/headless-C_rNUuYC.js.map +1 -0
  107. package/dist/headless.d.ts +1 -1
  108. package/dist/headless.js +1 -413
  109. package/dist/{history-search-C4bk1Wz_.js → history-search-CcYzF8-0.js} +7 -3
  110. package/dist/history-search-CcYzF8-0.js.map +1 -0
  111. package/dist/history-search-worker.d.ts +1 -1
  112. package/dist/history-search-worker.js +1 -1
  113. package/dist/host-D7NrI03V.js +378 -0
  114. package/dist/host-D7NrI03V.js.map +1 -0
  115. package/dist/host-signals-BcP5QKUD.js +118 -0
  116. package/dist/host-signals-BcP5QKUD.js.map +1 -0
  117. package/dist/identity-CwfO8K-t.js +26 -0
  118. package/dist/identity-CwfO8K-t.js.map +1 -0
  119. package/dist/{index-BgN1T3lk.d.ts → index-BGe1fQT7.d.ts} +10987 -9320
  120. package/dist/index-BGe1fQT7.d.ts.map +1 -0
  121. package/dist/index-BVQsIKGn.d.ts +448 -0
  122. package/dist/index-BVQsIKGn.d.ts.map +1 -0
  123. package/dist/{index-C6NEd5y_.d.ts → index-CHABJd-L.d.ts} +3386 -502
  124. package/dist/index-CHABJd-L.d.ts.map +1 -0
  125. package/dist/{index-C37_ppWv.d.ts → index-D6a7qXpg.d.ts} +2 -3
  126. package/dist/index-D6a7qXpg.d.ts.map +1 -0
  127. package/dist/index.d.ts +6 -6
  128. package/dist/index.js +27 -23
  129. package/dist/{completion-core-BRo86R_L.js → inline-ghost-BVRQeGoL.js} +50 -2
  130. package/dist/inline-ghost-BVRQeGoL.js.map +1 -0
  131. package/dist/ipc/remote.d.ts +313 -0
  132. package/dist/ipc/remote.d.ts.map +1 -0
  133. package/dist/ipc/remote.js +4 -0
  134. package/dist/ipc.d.ts +6 -964
  135. package/dist/ipc.js +403 -4
  136. package/dist/ipc.js.map +1 -0
  137. package/dist/{isolation-Kfoof0MM.d.ts → isolation-D9L650W5.d.ts} +100 -15
  138. package/dist/isolation-D9L650W5.d.ts.map +1 -0
  139. package/dist/json-rpc--HXQti1E.js +350 -0
  140. package/dist/json-rpc--HXQti1E.js.map +1 -0
  141. package/dist/links-j8rED1sR.js +603 -0
  142. package/dist/links-j8rED1sR.js.map +1 -0
  143. package/dist/local-terminal-D8QThwo_.js +252 -0
  144. package/dist/local-terminal-D8QThwo_.js.map +1 -0
  145. package/dist/{logger--C1VQjwJ.js → logger-Gtqlayx8.js} +199 -173
  146. package/dist/logger-Gtqlayx8.js.map +1 -0
  147. package/dist/logs-view-CWG8aUAG.js.map +1 -1
  148. package/dist/{mcp-CgNd-f3F.js → mcp-_wecH9Qe.js} +608 -562
  149. package/dist/mcp-_wecH9Qe.js.map +1 -0
  150. package/dist/mcp.d.ts +2 -2
  151. package/dist/mcp.js +2 -2
  152. package/dist/media-sniff-UKijEaiQ.js.map +1 -1
  153. package/dist/{messages-2jcOA_5R.js → messages-BqiwcD2Q.js} +1017 -1014
  154. package/dist/messages-BqiwcD2Q.js.map +1 -0
  155. package/dist/{oauth-DxHO17JE.js → oauth-Px_pBB9W.js} +5 -5
  156. package/dist/{oauth-DxHO17JE.js.map → oauth-Px_pBB9W.js.map} +1 -1
  157. package/dist/{openai-compat-Dy56weK8.js → openai-compat-CFrpH7uq.js} +432 -589
  158. package/dist/openai-compat-CFrpH7uq.js.map +1 -0
  159. package/dist/orchestration-BCGmB8Ps.js +511 -0
  160. package/dist/orchestration-BCGmB8Ps.js.map +1 -0
  161. package/dist/output/stream-json.d.ts +1 -2
  162. package/dist/output/stream-json.d.ts.map +1 -1
  163. package/dist/output/stream-json.js +1 -1
  164. package/dist/output/terminal.d.ts +1 -2
  165. package/dist/output/terminal.d.ts.map +1 -1
  166. package/dist/output/terminal.js +13 -7
  167. package/dist/output/terminal.js.map +1 -1
  168. package/dist/{plugins-gbI7SBA6.js → plugins-DS7mahzZ.js} +20 -101
  169. package/dist/plugins-DS7mahzZ.js.map +1 -0
  170. package/dist/plugins.d.ts +1 -1
  171. package/dist/plugins.js +1 -2
  172. package/dist/prelude-Cxo4t74B.js +517 -0
  173. package/dist/prelude-Cxo4t74B.js.map +1 -0
  174. package/dist/presets.d.ts +1 -1
  175. package/dist/presets.js +1 -2
  176. package/dist/project-root-B8zADr4o.js +167 -0
  177. package/dist/project-root-B8zADr4o.js.map +1 -0
  178. package/dist/project-user-paths-BSgtrRxl.js +58 -0
  179. package/dist/project-user-paths-BSgtrRxl.js.map +1 -0
  180. package/dist/{prompts-Pqc3JdW_.d.ts → prompts-DYcvqShf.d.ts} +14 -11
  181. package/dist/prompts-DYcvqShf.d.ts.map +1 -0
  182. package/dist/protocol-DnhqqSmE.js +13 -0
  183. package/dist/protocol-DnhqqSmE.js.map +1 -0
  184. package/dist/providers/anthropic.d.ts +2 -2
  185. package/dist/providers/anthropic.js +1 -2
  186. package/dist/providers/arcee.d.ts +1 -1
  187. package/dist/providers/arcee.js +1 -1
  188. package/dist/providers/baseten.d.ts +1 -1
  189. package/dist/providers/baseten.js +1 -1
  190. package/dist/providers/cerebras.d.ts +1 -1
  191. package/dist/providers/cerebras.js +3 -2
  192. package/dist/providers/cerebras.js.map +1 -1
  193. package/dist/providers/local.d.ts +1 -1
  194. package/dist/providers/local.js +1 -1
  195. package/dist/providers/openai-compat.d.ts +1 -1
  196. package/dist/providers/openai-compat.js +1 -2
  197. package/dist/providers/openai.d.ts +1 -1
  198. package/dist/providers/openai.js +15 -12
  199. package/dist/providers/openai.js.map +1 -1
  200. package/dist/providers/openrouter.d.ts +1 -1
  201. package/dist/providers/openrouter.js +3 -2
  202. package/dist/providers/openrouter.js.map +1 -1
  203. package/dist/providers/xai.d.ts +1 -1
  204. package/dist/providers/xai.js +3 -3
  205. package/dist/{providers-BVhnFyiY.js → providers-XUR7F4Hi.js} +4 -4
  206. package/dist/{providers-BVhnFyiY.js.map → providers-XUR7F4Hi.js.map} +1 -1
  207. package/dist/providers.d.ts +1 -1
  208. package/dist/providers.js +4 -4
  209. package/dist/registry-D6ShBWJU.js +5234 -0
  210. package/dist/registry-D6ShBWJU.js.map +1 -0
  211. package/dist/remote-hosts-BtA_9ZGp.js +97 -0
  212. package/dist/remote-hosts-BtA_9ZGp.js.map +1 -0
  213. package/dist/restate.d.ts +2 -3
  214. package/dist/restate.d.ts.map +1 -1
  215. package/dist/restate.js +631 -572
  216. package/dist/restate.js.map +1 -1
  217. package/dist/run-summary-CklLiZ4y.js +288 -0
  218. package/dist/run-summary-CklLiZ4y.js.map +1 -0
  219. package/dist/{sandbox-BH0WQkXn.d.ts → sandbox-C5dR5DwQ.d.ts} +6 -3
  220. package/dist/sandbox-C5dR5DwQ.d.ts.map +1 -0
  221. package/dist/session/sqlite.d.ts +1 -2
  222. package/dist/session/sqlite.d.ts.map +1 -1
  223. package/dist/session/sqlite.js +1 -616
  224. package/dist/session-factory-BUGY5P40.js +1576 -0
  225. package/dist/session-factory-BUGY5P40.js.map +1 -0
  226. package/dist/{session-BqRP1hS7.js → session-xh9JXu6i.js} +94 -52
  227. package/dist/session-xh9JXu6i.js.map +1 -0
  228. package/dist/session.d.ts +1 -1
  229. package/dist/session.js +2 -2
  230. package/dist/settings-keys-Ckf29NeM.js +677 -0
  231. package/dist/settings-keys-Ckf29NeM.js.map +1 -0
  232. package/dist/shell-path-Dqaoow2J.js +412 -0
  233. package/dist/shell-path-Dqaoow2J.js.map +1 -0
  234. package/dist/{skills-BC3dodWp.js → skills-DKqZJm4X.js} +430 -470
  235. package/dist/skills-DKqZJm4X.js.map +1 -0
  236. package/dist/skills.d.ts +2 -2
  237. package/dist/skills.js +1 -2
  238. package/dist/source-mPExaUm8.js +381 -0
  239. package/dist/source-mPExaUm8.js.map +1 -0
  240. package/dist/sqlite-DV1DQzN2.js +698 -0
  241. package/dist/sqlite-DV1DQzN2.js.map +1 -0
  242. package/dist/{src-CkNQKFKr.js → src-BRMYRJib.js} +903 -1121
  243. package/dist/src-BRMYRJib.js.map +1 -0
  244. package/dist/{stdio-DPpBDPx5.js → stdio-C6YyoW3I.js} +4 -4
  245. package/dist/{stdio-DPpBDPx5.js.map → stdio-C6YyoW3I.js.map} +1 -1
  246. package/dist/{stdio-loader-Bbx19dMZ.js → stdio-loader-C830Vg-Z.js} +4 -4
  247. package/dist/{stdio-loader-Bbx19dMZ.js.map → stdio-loader-C830Vg-Z.js.map} +1 -1
  248. package/dist/system-prompt-MNVHatSD.d.ts.map +1 -1
  249. package/dist/timeout-DEaqslLO.d.ts.map +1 -1
  250. package/dist/todo-edits-Dn251YUP.js +1790 -0
  251. package/dist/todo-edits-Dn251YUP.js.map +1 -0
  252. package/dist/{turn-operations-DrbJlpq9.js → tool-formatters-IQFDrdrs.js} +1456 -2120
  253. package/dist/tool-formatters-IQFDrdrs.js.map +1 -0
  254. package/dist/tool-state-Dku6YqAB.js +989 -0
  255. package/dist/tool-state-Dku6YqAB.js.map +1 -0
  256. package/dist/tools/fetch-url.d.ts +1 -2
  257. package/dist/tools/fetch-url.d.ts.map +1 -1
  258. package/dist/tools/fetch-url.js +1 -2
  259. package/dist/tools/prompts.d.ts +1 -1
  260. package/dist/tools/prompts.js +7 -7
  261. package/dist/tools/prompts.js.map +1 -1
  262. package/dist/tools/web-search.d.ts +1 -2
  263. package/dist/tools/web-search.d.ts.map +1 -1
  264. package/dist/tools/web-search.js +2 -2
  265. package/dist/tools/web-search.js.map +1 -1
  266. package/dist/tools-_DnT3AGM.js +578 -0
  267. package/dist/tools-_DnT3AGM.js.map +1 -0
  268. package/dist/tools.d.ts +3 -3
  269. package/dist/tools.js +4 -2
  270. package/dist/tui.d.ts +534 -517
  271. package/dist/tui.d.ts.map +1 -1
  272. package/dist/tui.js +34933 -27243
  273. package/dist/tui.js.map +1 -1
  274. package/dist/turn-operations-B8sokwi5.js +333 -0
  275. package/dist/turn-operations-B8sokwi5.js.map +1 -0
  276. package/dist/turn-operations-DQX5ZZni.d.ts +3089 -0
  277. package/dist/turn-operations-DQX5ZZni.d.ts.map +1 -0
  278. package/dist/types-C7ZFOztE.d.ts +132 -0
  279. package/dist/types-C7ZFOztE.d.ts.map +1 -0
  280. package/dist/types-CH5XpIHw.js +114 -0
  281. package/dist/types-CH5XpIHw.js.map +1 -0
  282. package/dist/{types-CWgENVLY.js → types-Cu0ZGDu9.js} +10 -6
  283. package/dist/types-Cu0ZGDu9.js.map +1 -0
  284. package/dist/types-IqegbJEE.d.ts +624 -0
  285. package/dist/types-IqegbJEE.d.ts.map +1 -0
  286. package/dist/types.d.ts +4 -4
  287. package/dist/types.js +1 -1
  288. package/dist/url-D8HCl65b.js +1259 -0
  289. package/dist/url-D8HCl65b.js.map +1 -0
  290. package/dist/wasm-BVT-j5cl.js +33 -0
  291. package/dist/wasm-BVT-j5cl.js.map +1 -0
  292. package/dist/workspace-exec-stream-SV2R9d5S.js +355 -0
  293. package/dist/workspace-exec-stream-SV2R9d5S.js.map +1 -0
  294. package/dist/ws-CIHMvlSh.js +952 -0
  295. package/dist/ws-CIHMvlSh.js.map +1 -0
  296. package/dist/ws-client-N7NxzvQp.js +230 -0
  297. package/dist/ws-client-N7NxzvQp.js.map +1 -0
  298. package/dist/{xai-CazjStOK.js → xai-CvJTeLrI.js} +165 -5
  299. package/dist/xai-CvJTeLrI.js.map +1 -0
  300. package/dist/xdg-zweed0-t.js +117 -0
  301. package/dist/xdg-zweed0-t.js.map +1 -0
  302. package/docs/ACP.md +52 -0
  303. package/docs/ARCHITECTURE.md +103 -6
  304. package/docs/ARTIFACTS.md +8 -4
  305. package/docs/CHAT.md +165 -14
  306. package/docs/EXECUTION_CONTEXT.md +8 -0
  307. package/docs/EXTENSIONS.md +123 -2
  308. package/docs/HEADLESS.md +2 -0
  309. package/docs/IPC.md +775 -64
  310. package/docs/MACHINES.md +456 -0
  311. package/docs/PANELS.md +3 -0
  312. package/docs/README.md +4 -0
  313. package/docs/RESTATE.md +3 -2
  314. package/docs/RUN_IN_BACKGROUND.md +10 -2
  315. package/docs/SERVER.md +1085 -0
  316. package/docs/SKILL.md +6 -1
  317. package/docs/TERMINAL.md +75 -0
  318. package/docs/TUI.md +65 -14
  319. package/package.json +58 -26
  320. package/scripts/eval.ts +4 -0
  321. package/dist/acp-D-tVyUjw.js.map +0 -1
  322. package/dist/agent-D0zZnGbt.js.map +0 -1
  323. package/dist/anthropic-C2aole0G.js.map +0 -1
  324. package/dist/approvals-DKaJZYlm.js.map +0 -1
  325. package/dist/atomic-write-B7zr1ddF.js.map +0 -1
  326. package/dist/auth-BG2rVKSt.js.map +0 -1
  327. package/dist/completion-core-BRo86R_L.js.map +0 -1
  328. package/dist/contexts/daytona.js.map +0 -1
  329. package/dist/contexts/docker.js.map +0 -1
  330. package/dist/contexts/e2b.js.map +0 -1
  331. package/dist/contexts-CRE9pw07.js.map +0 -1
  332. package/dist/eval.js.map +0 -1
  333. package/dist/format-BF745pLL.js.map +0 -1
  334. package/dist/glob-DluQFSw1.js +0 -270
  335. package/dist/glob-DluQFSw1.js.map +0 -1
  336. package/dist/headless.js.map +0 -1
  337. package/dist/history-search-C4bk1Wz_.js.map +0 -1
  338. package/dist/index-BgN1T3lk.d.ts.map +0 -1
  339. package/dist/index-C37_ppWv.d.ts.map +0 -1
  340. package/dist/index-C6NEd5y_.d.ts.map +0 -1
  341. package/dist/ipc-BKVIIOqH.js +0 -331
  342. package/dist/ipc-BKVIIOqH.js.map +0 -1
  343. package/dist/ipc.d.ts.map +0 -1
  344. package/dist/isolation-Kfoof0MM.d.ts.map +0 -1
  345. package/dist/json-rpc-rSWMUh9b.js +0 -192
  346. package/dist/json-rpc-rSWMUh9b.js.map +0 -1
  347. package/dist/logger--C1VQjwJ.js.map +0 -1
  348. package/dist/mcp-CgNd-f3F.js.map +0 -1
  349. package/dist/messages-2jcOA_5R.js.map +0 -1
  350. package/dist/openai-compat-Dy56weK8.js.map +0 -1
  351. package/dist/output-cap-C9zukcCj.js +0 -100
  352. package/dist/output-cap-C9zukcCj.js.map +0 -1
  353. package/dist/panels-B6gRk4bf.js +0 -789
  354. package/dist/panels-B6gRk4bf.js.map +0 -1
  355. package/dist/plugins-gbI7SBA6.js.map +0 -1
  356. package/dist/prompts-Pqc3JdW_.d.ts.map +0 -1
  357. package/dist/run-summary-BU_NgwUT.js +0 -269
  358. package/dist/run-summary-BU_NgwUT.js.map +0 -1
  359. package/dist/sandbox-BH0WQkXn.d.ts.map +0 -1
  360. package/dist/session/sqlite.js.map +0 -1
  361. package/dist/session-BqRP1hS7.js.map +0 -1
  362. package/dist/shell-path-DfdXrGg9.js +0 -1549
  363. package/dist/shell-path-DfdXrGg9.js.map +0 -1
  364. package/dist/skills-BC3dodWp.js.map +0 -1
  365. package/dist/src-CkNQKFKr.js.map +0 -1
  366. package/dist/todo-edits-UOwgxGKu.js +0 -528
  367. package/dist/todo-edits-UOwgxGKu.js.map +0 -1
  368. package/dist/tool-formatters-DoRLnfuD.d.ts +0 -759
  369. package/dist/tool-formatters-DoRLnfuD.d.ts.map +0 -1
  370. package/dist/transcript-anchors-BeudMbXx.d.ts +0 -1762
  371. package/dist/transcript-anchors-BeudMbXx.d.ts.map +0 -1
  372. package/dist/turn-operations-C8bMBDl_.d.ts +0 -1258
  373. package/dist/turn-operations-C8bMBDl_.d.ts.map +0 -1
  374. package/dist/turn-operations-DrbJlpq9.js.map +0 -1
  375. package/dist/types-CWgENVLY.js.map +0 -1
  376. package/dist/xai-CazjStOK.js.map +0 -1
package/dist/restate.js CHANGED
@@ -1,7 +1,8 @@
1
- import { L as buildAliasMaps } from "./openai-compat-Dy56weK8.js";
2
- import { i as coerceToolResultContent, l as toolOutputByteLength, u as toolResultToText } from "./types-CWgENVLY.js";
3
- import { At as reserveChildLabel, a as stagedToolState, ar as hydrateReadStateFromSessionAsync, i as isToolStateOps } from "./agent-D0zZnGbt.js";
1
+ import { d as toolResultToText, i as coerceToolResultContent, u as toolOutputByteLength } from "./types-Cu0ZGDu9.js";
2
+ import { n as buildAliasMaps } from "./aliasing-lVFbm81n.js";
3
+ import { C as hydrateReadStateFromSessionAsync, i as stagedToolState, m as reserveChildLabel, r as isToolStateOps } from "./tool-state-Dku6YqAB.js";
4
4
  import { r as formatTokenUsage } from "./stats-DAKBEKjc.js";
5
+ import { n as DEFAULT_MEDIA_BUDGET, t as DEFAULT_MAX_IMAGE_EDGE } from "./defaults-Cx3zvDOV.js";
5
6
  import { createHash } from "node:crypto";
6
7
  //#region src/restate/awakeable.ts
7
8
  /**
@@ -72,7 +73,7 @@ function restateAwakeableTool(options) {
72
73
  awakeableId: awakeable.id
73
74
  };
74
75
  }, runOpts);
75
- if (marker.awakeableId !== awakeable.id) throw new Error(`restateAwakeableTool(${name}): journal drift — broadcast marker carries awakeable "${marker.awakeableId}" but this replay minted "${awakeable.id}". The journal and the code path no longer line up; refusing to park on an unreachable awakeable.`);
76
+ if (marker.awakeableId !== awakeable.id) throw new Error(`restateAwakeableTool(${name}): journal drift: broadcast marker carries awakeable "${marker.awakeableId}" but this replay minted "${awakeable.id}". The journal and the code path no longer line up; refusing to park on an unreachable awakeable.`);
76
77
  const value = await awakeable.promise;
77
78
  if (toResult) return toResult(value, input);
78
79
  return typeof value === "string" ? value : JSON.stringify(value);
@@ -152,11 +153,12 @@ function restateBehavior(overrides = {}) {
152
153
  cache: true,
153
154
  shouldRethrowToolError: shouldRethrowRestateControlError,
154
155
  compactStrategy: "tail",
155
- compactThreshold: 128 * 1024,
156
+ compactThreshold: 131072,
156
157
  compactKeepTurns: 8,
157
158
  elideStaleReads: "stub",
158
- mediaKeepTurns: 8,
159
- toolOutputBudget: 64 * 1024,
159
+ mediaBudget: DEFAULT_MEDIA_BUDGET,
160
+ maxImageEdge: DEFAULT_MAX_IMAGE_EDGE,
161
+ toolOutputBudget: 65536,
160
162
  autoCompact: { threshold: .85 },
161
163
  ...overrides
162
164
  };
@@ -280,8 +282,7 @@ function rethrowSoftToolError(value) {
280
282
  return value;
281
283
  }
282
284
  //#endregion
283
- //#region src/restate/tool.ts
284
- const SHELL_BACKGROUND_DISABLED_MESSAGE = "shell error: background mode is disabled for Restate-backed agents. Fall back to foreground (drop `run_in_background`).";
285
+ //#region src/restate/tool-hydrate.ts
285
286
  /**
286
287
  * Once-per-session (per process) guard for the restate tool wrapper's read-state
287
288
  * hydration. Rebuilds the map from `session.turns` the first time any wrapped
@@ -294,182 +295,30 @@ const SHELL_BACKGROUND_DISABLED_MESSAGE = "shell error: background mode is disab
294
295
  * `restateTool`-wrapped consumers; it is NOT what the gate depends on.
295
296
  */
296
297
  const HYDRATED_READ_STATE_SESSIONS = /* @__PURE__ */ new WeakSet();
297
- /**
298
- * Wrap a single `ToolDef` so its `execute` runs inside `ctx.run`. The
299
- * tool's `spec` and `isConcurrencySafe` pass through unchanged.
300
- */
301
- function restateTool(inner, ctx, options = {}) {
302
- const runOpts = options.runOptions ?? { maxRetryAttempts: 1 };
303
- const nameFor = options.entryName ?? ((seq, name) => `tool-${name}-${seq}`);
304
- const canonicalName = inner.spec.name;
305
- const shellBackgroundDisabled = (options.disableShellBackground ?? options.detachedTasks !== "durable") && canonicalName === "shell";
306
- const durableStart = options.durableStart;
307
- if (durableStart && !durableStart.attach && !durableStart.wait) throw new Error(`restateTool(${canonicalName}): durableStart needs an \`attach\` (in-journal wait) or a \`wait\` (awakeable park) phase`);
308
- let seq = 0;
309
- const hydrateOnce = async (toolCtx) => {
310
- if (!toolCtx.session || HYDRATED_READ_STATE_SESSIONS.has(toolCtx.session)) return;
311
- HYDRATED_READ_STATE_SESSIONS.add(toolCtx.session);
312
- let aliasMaps;
313
- if (toolCtx.toolAliases) try {
314
- aliasMaps = buildAliasMaps(toolCtx.toolAliases, Object.keys(toolCtx.tools));
315
- } catch {
316
- aliasMaps = void 0;
317
- }
318
- await hydrateReadStateFromSessionAsync(toolCtx.session, toolCtx.handle.cwd, {
319
- defaultLineNumbers: toolCtx.behavior?.readLineNumbers ?? true,
320
- ...aliasMaps ? { aliasMaps } : {},
321
- readFileForHash: async (path) => {
322
- try {
323
- return await toolCtx.execution.readFile(toolCtx.handle, path);
324
- } catch {
325
- return null;
326
- }
327
- }
328
- });
329
- };
330
- const softErrors = options.softErrors ?? true;
331
- const coerceBlocks = options.coerceResultBlocks ?? true;
332
- const runJournaled = (input, toolCtx) => {
333
- seq += 1;
334
- return ctx.run(nameFor(seq, canonicalName, input, toolCtx.callId), async () => {
335
- options.replayTracker?.markLive();
336
- await hydrateOnce(toolCtx);
337
- const staged = stagedToolState(toolCtx.state);
338
- staged?.clear();
339
- if (shellBackgroundDisabled && input.run_in_background === true) return SHELL_BACKGROUND_DISABLED_MESSAGE;
340
- if (!softErrors) {
341
- const out = await inner.execute(input, toolCtx);
342
- return attachToolState(coerceBlocks ? coerceToolResultContent(out) : out, staged);
343
- }
344
- try {
345
- const out = await inner.execute(input, toolCtx);
346
- return attachToolState(coerceBlocks ? coerceToolResultContent(out) : out, staged);
347
- } catch (err) {
348
- if (isRestateControlOrAbort(err, toolCtx.signal)) throw err;
349
- return attachToolState(makeSoftToolError(err), staged);
350
- }
351
- }, runOpts);
352
- };
353
- const finishJournaled = async (journaled, staged) => {
354
- let value;
355
- try {
356
- value = await journaled;
357
- } catch (err) {
358
- staged?.clear();
359
- throw err;
360
- }
361
- const output = applyToolState(value, staged);
362
- return softErrors ? rethrowSoftToolError(output) : output;
363
- };
364
- const executeDurably = (input, toolCtx) => {
365
- const staged = stagedToolState(toolCtx.state);
366
- if (!softErrors && !staged) return runJournaled(input, toolCtx);
367
- return finishJournaled(runJournaled(input, toolCtx), staged);
368
- };
369
- const durableExecuteImpl = (input, toolCtx) => {
370
- const staged = stagedToolState(toolCtx.state);
371
- if (!softErrors && !staged) return runJournaled(input, toolCtx);
372
- return unwrapDurableToolValue(runJournaled(input, toolCtx), staged, softErrors);
373
- };
374
- const executeTwoPhaseInner = async (input, toolCtx) => {
375
- const start = durableStart;
376
- const staged = stagedToolState(toolCtx.state);
377
- seq += 1;
378
- const entry = nameFor(seq, canonicalName, input, toolCtx.callId);
379
- const runFinal = async (body) => applyToolState(await ctx.run(entry, async () => {
380
- options.replayTracker?.markLive();
381
- return attachToolState(await body(), staged);
382
- }, runOpts), staged);
383
- const token = await ctx.run(`${entry}-start`, async () => {
384
- options.replayTracker?.markLive();
385
- await hydrateOnce(toolCtx);
386
- return start.start(input, toolCtx);
387
- }, runOpts);
388
- const onAbort = start.onAbort;
389
- const signal = toolCtx.signal;
390
- let fired = false;
391
- const fireAbortCleanup = () => {
392
- if (fired || !onAbort) return;
393
- fired = true;
394
- Promise.resolve(onAbort(token, input, toolCtx)).catch((err) => {
395
- if (process.env.ZIDANE_DEBUG) process.stderr.write(`[zidane/restate] durableStart onAbort threw: ${err instanceof Error ? err.message : String(err)}\n`);
396
- });
397
- };
398
- const wait = start.wait;
399
- if (wait) {
400
- if (wait.inline?.(token, input, toolCtx)) {
401
- if (!onAbort || !signal) return await runFinal(() => wait.result(token, null, input, toolCtx));
402
- if (signal.aborted) fireAbortCleanup();
403
- else signal.addEventListener("abort", fireAbortCleanup, { once: true });
404
- try {
405
- return await runFinal(() => wait.result(token, null, input, toolCtx));
406
- } finally {
407
- signal.removeEventListener("abort", fireAbortCleanup);
408
- }
409
- }
410
- if (signal?.aborted) {
411
- fireAbortCleanup();
412
- throw new Error(`${canonicalName}: aborted before durable wait registration`);
413
- }
414
- signal?.addEventListener("abort", fireAbortCleanup, { once: true });
298
+ /** Hydrate the session's read-state map once per session (per process) — see {@link HYDRATED_READ_STATE_SESSIONS}. */
299
+ async function hydrateOnce(toolCtx) {
300
+ if (!toolCtx.session || HYDRATED_READ_STATE_SESSIONS.has(toolCtx.session)) return;
301
+ HYDRATED_READ_STATE_SESSIONS.add(toolCtx.session);
302
+ let aliasMaps;
303
+ if (toolCtx.toolAliases) try {
304
+ aliasMaps = buildAliasMaps(toolCtx.toolAliases, Object.keys(toolCtx.tools));
305
+ } catch {
306
+ aliasMaps = void 0;
307
+ }
308
+ await hydrateReadStateFromSessionAsync(toolCtx.session, toolCtx.handle.cwd, {
309
+ defaultLineNumbers: toolCtx.behavior?.readLineNumbers ?? true,
310
+ ...aliasMaps ? { aliasMaps } : {},
311
+ readFileForHash: async (path) => {
415
312
  try {
416
- const timeoutMs = typeof wait.timeoutMs === "function" ? wait.timeoutMs(input, toolCtx) : wait.timeoutMs;
417
- const awakeable = awakeableWithTimeout(ctx, {
418
- ...timeoutMs !== void 0 ? { timeoutMs } : {},
419
- ...wait.promises ? { promises: wait.promises } : {}
420
- });
421
- const marker = await ctx.run(`${entry}-register`, async () => {
422
- options.replayTracker?.markLive();
423
- await wait.register(token, awakeable.id, input, toolCtx);
424
- return {
425
- registered: true,
426
- awakeableId: awakeable.id
427
- };
428
- }, runOpts);
429
- if (marker.awakeableId !== awakeable.id) throw new Error(`restateTool(${canonicalName}): journal drift — registration marker carries awakeable "${marker.awakeableId}" but this replay minted "${awakeable.id}". Refusing to park on an unreachable awakeable.`);
430
- const resumed = await parkWithSignal(awakeable.promise, signal, canonicalName);
431
- return await runFinal(() => wait.result(token, resumed, input, toolCtx));
432
- } finally {
433
- signal?.removeEventListener("abort", fireAbortCleanup);
313
+ return await toolCtx.execution.readFile(toolCtx.handle, path);
314
+ } catch {
315
+ return null;
434
316
  }
435
317
  }
436
- const attach = () => runFinal(() => start.attach(token, input, toolCtx));
437
- if (!onAbort || !signal) return attach();
438
- if (signal.aborted) {
439
- fireAbortCleanup();
440
- return attach();
441
- }
442
- signal.addEventListener("abort", fireAbortCleanup, { once: true });
443
- try {
444
- return await attach();
445
- } finally {
446
- signal.removeEventListener("abort", fireAbortCleanup);
447
- }
448
- };
449
- const executeTwoPhase = async (input, toolCtx) => {
450
- const staged = stagedToolState(toolCtx.state);
451
- try {
452
- return await executeTwoPhaseInner(input, toolCtx);
453
- } catch (err) {
454
- staged?.clear();
455
- throw err;
456
- }
457
- };
458
- if (durableStart) {
459
- const { durableExecute: _dropped, ...rest } = inner;
460
- return {
461
- ...rest,
462
- spec: shellBackgroundDisabled ? withoutShellBackgroundInput(inner.spec) : inner.spec,
463
- execute: executeTwoPhase
464
- };
465
- }
466
- return {
467
- ...inner,
468
- spec: shellBackgroundDisabled ? withoutShellBackgroundInput(inner.spec) : inner.spec,
469
- execute: executeDurably,
470
- durableExecute: durableExecuteImpl
471
- };
318
+ });
472
319
  }
320
+ //#endregion
321
+ //#region src/restate/tool-journal.ts
473
322
  function isToolStateEnvelope(value) {
474
323
  if (typeof value !== "object" || value === null || Array.isArray(value)) return false;
475
324
  const candidate = value;
@@ -525,6 +374,85 @@ function unwrapDurableToolValue(promise, staged, softErrors) {
525
374
  return softErrors ? rethrowSoftToolError(output) : output;
526
375
  });
527
376
  }
377
+ //#endregion
378
+ //#region src/restate/tool-two-phase.ts
379
+ /** The two-phase (start + attach / awakeable wait) execution — see `restateTool`. */
380
+ async function executeTwoPhaseInner(env, input, toolCtx) {
381
+ const { ctx, options, runOpts, nameFor, canonicalName, durableStart, counter } = env;
382
+ const start = durableStart;
383
+ const staged = stagedToolState(toolCtx.state);
384
+ counter.seq += 1;
385
+ const entry = nameFor(counter.seq, canonicalName, input, toolCtx.callId);
386
+ const runFinal = async (body) => applyToolState(await ctx.run(entry, async () => {
387
+ options.replayTracker?.markLive();
388
+ return attachToolState(await body(), staged);
389
+ }, runOpts), staged);
390
+ const token = await ctx.run(`${entry}-start`, async () => {
391
+ options.replayTracker?.markLive();
392
+ await hydrateOnce(toolCtx);
393
+ return start.start(input, toolCtx);
394
+ }, runOpts);
395
+ const onAbort = start.onAbort;
396
+ const signal = toolCtx.signal;
397
+ let fired = false;
398
+ const fireAbortCleanup = () => {
399
+ if (fired || !onAbort) return;
400
+ fired = true;
401
+ Promise.resolve(onAbort(token, input, toolCtx)).catch((err) => {
402
+ if (process.env.ZIDANE_DEBUG) process.stderr.write(`[zidane/restate] durableStart onAbort threw: ${err instanceof Error ? err.message : String(err)}\n`);
403
+ });
404
+ };
405
+ const wait = start.wait;
406
+ if (wait) {
407
+ if (wait.inline?.(token, input, toolCtx)) {
408
+ if (!onAbort || !signal) return await runFinal(() => wait.result(token, null, input, toolCtx));
409
+ if (signal.aborted) fireAbortCleanup();
410
+ else signal.addEventListener("abort", fireAbortCleanup, { once: true });
411
+ try {
412
+ return await runFinal(() => wait.result(token, null, input, toolCtx));
413
+ } finally {
414
+ signal.removeEventListener("abort", fireAbortCleanup);
415
+ }
416
+ }
417
+ if (signal?.aborted) {
418
+ fireAbortCleanup();
419
+ throw new Error(`${canonicalName}: aborted before durable wait registration`);
420
+ }
421
+ signal?.addEventListener("abort", fireAbortCleanup, { once: true });
422
+ try {
423
+ const timeoutMs = typeof wait.timeoutMs === "function" ? wait.timeoutMs(input, toolCtx) : wait.timeoutMs;
424
+ const awakeable = awakeableWithTimeout(ctx, {
425
+ ...timeoutMs !== void 0 ? { timeoutMs } : {},
426
+ ...wait.promises ? { promises: wait.promises } : {}
427
+ });
428
+ const marker = await ctx.run(`${entry}-register`, async () => {
429
+ options.replayTracker?.markLive();
430
+ await wait.register(token, awakeable.id, input, toolCtx);
431
+ return {
432
+ registered: true,
433
+ awakeableId: awakeable.id
434
+ };
435
+ }, runOpts);
436
+ if (marker.awakeableId !== awakeable.id) throw new Error(`restateTool(${canonicalName}): journal drift: registration marker carries awakeable "${marker.awakeableId}" but this replay minted "${awakeable.id}". Refusing to park on an unreachable awakeable.`);
437
+ const resumed = await parkWithSignal(awakeable.promise, signal, canonicalName);
438
+ return await runFinal(() => wait.result(token, resumed, input, toolCtx));
439
+ } finally {
440
+ signal?.removeEventListener("abort", fireAbortCleanup);
441
+ }
442
+ }
443
+ const attach = () => runFinal(() => start.attach(token, input, toolCtx));
444
+ if (!onAbort || !signal) return attach();
445
+ if (signal.aborted) {
446
+ fireAbortCleanup();
447
+ return attach();
448
+ }
449
+ signal.addEventListener("abort", fireAbortCleanup, { once: true });
450
+ try {
451
+ return await attach();
452
+ } finally {
453
+ signal.removeEventListener("abort", fireAbortCleanup);
454
+ }
455
+ }
528
456
  /**
529
457
  * Park on `promise`, but stop waiting when the per-call abort signal
530
458
  * fires (run abort, `cancelTool`, sibling-cascade cancel) — a deliberate
@@ -549,6 +477,98 @@ function parkWithSignal(promise, signal, name) {
549
477
  });
550
478
  });
551
479
  }
480
+ //#endregion
481
+ //#region src/restate/tool.ts
482
+ const SHELL_BACKGROUND_DISABLED_MESSAGE = "shell error: background mode is disabled for Restate-backed agents. Fall back to foreground (drop `run_in_background`).";
483
+ /**
484
+ * Wrap a single `ToolDef` so its `execute` runs inside `ctx.run`. The
485
+ * tool's `spec` and `isConcurrencySafe` pass through unchanged.
486
+ */
487
+ function restateTool(inner, ctx, options = {}) {
488
+ const runOpts = options.runOptions ?? { maxRetryAttempts: 1 };
489
+ const nameFor = options.entryName ?? ((seq, name) => `tool-${name}-${seq}`);
490
+ const canonicalName = inner.spec.name;
491
+ const shellBackgroundDisabled = (options.disableShellBackground ?? options.detachedTasks !== "durable") && canonicalName === "shell";
492
+ const durableStart = options.durableStart;
493
+ if (durableStart && !durableStart.attach && !durableStart.wait) throw new Error(`restateTool(${canonicalName}): durableStart needs an \`attach\` (in-journal wait) or a \`wait\` (awakeable park) phase`);
494
+ const counter = { seq: 0 };
495
+ const softErrors = options.softErrors ?? true;
496
+ const coerceBlocks = options.coerceResultBlocks ?? true;
497
+ const runJournaled = (input, toolCtx) => {
498
+ counter.seq += 1;
499
+ return ctx.run(nameFor(counter.seq, canonicalName, input, toolCtx.callId), async () => {
500
+ options.replayTracker?.markLive();
501
+ await hydrateOnce(toolCtx);
502
+ const staged = stagedToolState(toolCtx.state);
503
+ staged?.clear();
504
+ if (shellBackgroundDisabled && input.run_in_background === true) return SHELL_BACKGROUND_DISABLED_MESSAGE;
505
+ if (!softErrors) {
506
+ const out = await inner.execute(input, toolCtx);
507
+ return attachToolState(coerceBlocks ? coerceToolResultContent(out) : out, staged);
508
+ }
509
+ try {
510
+ const out = await inner.execute(input, toolCtx);
511
+ return attachToolState(coerceBlocks ? coerceToolResultContent(out) : out, staged);
512
+ } catch (err) {
513
+ if (isRestateControlOrAbort(err, toolCtx.signal)) throw err;
514
+ return attachToolState(makeSoftToolError(err), staged);
515
+ }
516
+ }, runOpts);
517
+ };
518
+ const finishJournaled = async (journaled, staged) => {
519
+ let value;
520
+ try {
521
+ value = await journaled;
522
+ } catch (err) {
523
+ staged?.clear();
524
+ throw err;
525
+ }
526
+ const output = applyToolState(value, staged);
527
+ return softErrors ? rethrowSoftToolError(output) : output;
528
+ };
529
+ const executeDurably = (input, toolCtx) => {
530
+ const staged = stagedToolState(toolCtx.state);
531
+ if (!softErrors && !staged) return runJournaled(input, toolCtx);
532
+ return finishJournaled(runJournaled(input, toolCtx), staged);
533
+ };
534
+ const durableExecuteImpl = (input, toolCtx) => {
535
+ const staged = stagedToolState(toolCtx.state);
536
+ if (!softErrors && !staged) return runJournaled(input, toolCtx);
537
+ return unwrapDurableToolValue(runJournaled(input, toolCtx), staged, softErrors);
538
+ };
539
+ const twoPhaseEnv = {
540
+ ctx,
541
+ options,
542
+ runOpts,
543
+ nameFor,
544
+ canonicalName,
545
+ durableStart,
546
+ counter
547
+ };
548
+ const executeTwoPhase = async (input, toolCtx) => {
549
+ const staged = stagedToolState(toolCtx.state);
550
+ try {
551
+ return await executeTwoPhaseInner(twoPhaseEnv, input, toolCtx);
552
+ } catch (err) {
553
+ staged?.clear();
554
+ throw err;
555
+ }
556
+ };
557
+ if (durableStart) {
558
+ const { durableExecute: _dropped, ...rest } = inner;
559
+ return {
560
+ ...rest,
561
+ spec: shellBackgroundDisabled ? withoutShellBackgroundInput(inner.spec) : inner.spec,
562
+ execute: executeTwoPhase
563
+ };
564
+ }
565
+ return {
566
+ ...inner,
567
+ spec: shellBackgroundDisabled ? withoutShellBackgroundInput(inner.spec) : inner.spec,
568
+ execute: executeDurably,
569
+ durableExecute: durableExecuteImpl
570
+ };
571
+ }
552
572
  function withoutShellBackgroundInput(spec) {
553
573
  const inputSchema = spec.inputSchema;
554
574
  const properties = isRecord(inputSchema.properties) ? inputSchema.properties : void 0;
@@ -583,7 +603,7 @@ function wrapAgentTools(tools, ctx, opts = {}) {
583
603
  const excludeSet = new Set(opts.exclude ?? []);
584
604
  const skipWaitTask = opts.detachedTasks === "durable";
585
605
  const wrapped = {};
586
- for (const [name, def] of Object.entries(tools)) wrapped[name] = excludeSet.has(name) || def.runsNestedAgent === true || skipWaitTask && def.spec.name === "wait_task" ? def : restateTool(def, ctx, opts);
606
+ for (const [name, def] of Object.entries(tools)) wrapped[name] = excludeSet.has(name) || def.runsNestedAgent === true || def.callsNestedTools === true || skipWaitTask && def.spec.name === "wait_task" ? def : restateTool(def, ctx, opts);
587
607
  return wrapped;
588
608
  }
589
609
  //#endregion
@@ -825,7 +845,7 @@ function restateSessionStore(ctx, options = {}) {
825
845
  function guardSessionId(sessionId) {
826
846
  if (warnedMismatch || sessionId === ctx.key) return;
827
847
  warnedMismatch = true;
828
- process.stderr.write(`[zidane/restate] restateSessionStore: sessionId "${sessionId}" != bound object key "${ctx.key}". This store ignores the sessionId and operates on the bound object — pass createSession({ id: ctx.key }) to silence this.\n`);
848
+ process.stderr.write(`[zidane/restate] restateSessionStore: sessionId "${sessionId}" != bound object key "${ctx.key}". This store ignores the sessionId and uses the bound object. Pass createSession({ id: ctx.key }) to silence this.\n`);
829
849
  }
830
850
  async function generateTurnId() {
831
851
  if (nextTurnSeq === void 0) nextTurnSeq = (await loadTurns()).length;
@@ -981,7 +1001,107 @@ function maxDefined(values) {
981
1001
  return max;
982
1002
  }
983
1003
  //#endregion
984
- //#region src/restate/spawn.ts
1004
+ //#region src/restate/spawn-events.ts
1005
+ /**
1006
+ * Replay a finished child's transcript onto the PARENT's hook bus as `child:*`
1007
+ * events, so hosts that already render subagent activity (`src/output/
1008
+ * terminal.ts`, the GUI engine, any `child:tool:*` listener) light up for
1009
+ * parallel children without a single change.
1010
+ *
1011
+ * Not live \u2014 hook bubbling cannot cross an invocation boundary, so these fire
1012
+ * when the child finishes, in submission order. Everything here is derived
1013
+ * from the journaled call result, so a parent replay produces the identical
1014
+ * sequence; like the in-process tool's `child:tool:*`, they DO re-fire on that
1015
+ * replay, so hosts dedupe by `callId` / `turnId` or gate on
1016
+ * `createReplayTracker`.
1017
+ *
1018
+ * Only events that describe things the child actually did are synthesized.
1019
+ * `tool:gate` / `tool:transform` / `tool:dispatched` / `tool:cancelled` /
1020
+ * `background:*` describe decisions taken inside another process; inventing
1021
+ * them would be fiction, so they stay absent.
1022
+ */
1023
+ async function replayChildEvents(child, turns, ctx) {
1024
+ if (turns.length === 0) return;
1025
+ const outputs = /* @__PURE__ */ new Map();
1026
+ for (const turn of turns) for (const block of turn.content) if (block.type === "tool_result") outputs.set(block.callId, {
1027
+ output: block.output,
1028
+ ...block.isError !== void 0 ? { isError: block.isError } : {}
1029
+ });
1030
+ const childIdentity = {
1031
+ childId: child.label,
1032
+ depth: child.depth
1033
+ };
1034
+ const identity = {
1035
+ ...childIdentity,
1036
+ runId: child.runId,
1037
+ ...child.parentRunId !== void 0 ? { parentRunId: child.parentRunId } : {},
1038
+ parentCallId: child.callId
1039
+ };
1040
+ const runToolCounts = {};
1041
+ let assistantTurns = 0;
1042
+ for (const turn of turns) {
1043
+ if (turn.role !== "assistant") continue;
1044
+ assistantTurns += 1;
1045
+ const text = turn.content.filter((block) => block.type === "text").map((block) => block.text).join("");
1046
+ if (text.length > 0) await ctx.hooks.callHook("child:stream:text", {
1047
+ ...childIdentity,
1048
+ turnId: turn.id,
1049
+ delta: text,
1050
+ text
1051
+ });
1052
+ const turnToolCounts = {};
1053
+ for (const block of turn.content) {
1054
+ if (block.type !== "tool_call") continue;
1055
+ runToolCounts[block.name] = (runToolCounts[block.name] ?? 0) + 1;
1056
+ turnToolCounts[block.name] = (turnToolCounts[block.name] ?? 0) + 1;
1057
+ const base = {
1058
+ ...identity,
1059
+ turnId: turn.id,
1060
+ callId: block.id,
1061
+ name: block.name,
1062
+ displayName: block.name,
1063
+ input: block.input,
1064
+ runToolCounts: { ...runToolCounts }
1065
+ };
1066
+ await ctx.hooks.callHook("child:tool:before", base);
1067
+ const settled = outputs.get(block.id);
1068
+ if (settled === void 0) continue;
1069
+ const isError = settled.isError === true;
1070
+ if (isError) await ctx.hooks.callHook("child:tool:error", {
1071
+ ...base,
1072
+ error: new Error(toolResultToText(settled.output))
1073
+ });
1074
+ await ctx.hooks.callHook("child:tool:after", {
1075
+ ...base,
1076
+ result: settled.output,
1077
+ isError,
1078
+ outputBytes: toolOutputByteLength(settled.output)
1079
+ });
1080
+ }
1081
+ const usage = turn.usage ?? {
1082
+ input: 0,
1083
+ output: 0
1084
+ };
1085
+ await ctx.hooks.callHook("child:turn:after", {
1086
+ ...childIdentity,
1087
+ turn: assistantTurns,
1088
+ turnId: turn.id,
1089
+ usage,
1090
+ message: turn,
1091
+ toolCounts: {
1092
+ turn: { ...turnToolCounts },
1093
+ run: { ...runToolCounts }
1094
+ }
1095
+ });
1096
+ await ctx.hooks.callHook("child:stream:end", {
1097
+ ...childIdentity,
1098
+ turnId: turn.id,
1099
+ text
1100
+ });
1101
+ }
1102
+ }
1103
+ //#endregion
1104
+ //#region src/restate/spawn-state.ts
985
1105
  const ZERO_STATS = {
986
1106
  totalIn: 0,
987
1107
  totalOut: 0,
@@ -990,405 +1110,344 @@ const ZERO_STATS = {
990
1110
  turns: 0,
991
1111
  elapsed: 0
992
1112
  };
993
- const DEFAULT_DESCRIPTION = "Delegate a self-contained task to a sub-agent that runs independently and returns only its final report. Several spawn calls in one turn run in parallel.";
994
- function restateSpawnTool(options) {
995
- const persist = options.persist ?? true;
996
- const emitEvents = options.emitChildEvents ?? true;
997
- let dispatchSeq = 0;
998
- let sessionlessLabels = 0;
999
- let cancelSignalled = false;
1000
- let nestedLabels = 0;
1001
- const pending = [];
1002
- const drainRegistered = /* @__PURE__ */ new WeakSet();
1003
- /**
1004
- * Build the request and the bookkeeping entry. Deliberately side-effect free
1005
- * apart from reserving the label: the fleet path has to be able to reject a
1006
- * misconfigured `dispatch` (below) without leaving a phantom child queued for
1007
- * the merge. `commit` is what actually enrols the child.
1008
- */
1009
- function prepare(input, ctx) {
1010
- const task = String(input.task ?? "");
1011
- const depth = (ctx.depth ?? 0) + 1;
1012
- const label = ctx.session ? reserveChildLabel(ctx.session) : `child-${++sessionlessLabels}`;
1013
- return {
1014
- entry: {
1015
- order: ++dispatchSeq,
1016
- label,
1017
- task,
1018
- depth,
1019
- callId: ctx.callId,
1020
- runId: `${ctx.runId ?? "run"}-${label}`,
1021
- ...ctx.runId !== void 0 ? { parentRunId: ctx.runId } : {},
1022
- ...ctx.session !== void 0 ? { session: ctx.session } : {}
1023
- },
1024
- req: {
1025
- task,
1026
- label,
1027
- depth,
1028
- ...ctx.runId !== void 0 ? { parentRunId: ctx.runId } : {},
1029
- parentCallId: ctx.callId,
1030
- ...ctx.session !== void 0 ? { sessionId: ctx.session.id } : {},
1031
- ...typeof input.model === "string" ? { model: input.model } : {},
1032
- ...typeof input.subagent_type === "string" ? { subagentType: input.subagent_type } : {}
1033
- }
1034
- };
1035
- }
1036
- /** Enrol a dispatched child for merging, and announce it. */
1037
- function commit(entry, input, ctx) {
1038
- pending.push(entry);
1039
- registerDrain(ctx);
1040
- watchAbort(entry, ctx);
1041
- Promise.resolve(ctx.hooks.callHook("spawn:before", {
1113
+ function errorText(entry) {
1114
+ if (entry.failure !== void 0) return entry.failure instanceof Error ? entry.failure.message : String(entry.failure);
1115
+ return entry.result?.error ?? "sub-agent failed";
1116
+ }
1117
+ //#endregion
1118
+ //#region src/restate/spawn-merge.ts
1119
+ /**
1120
+ * Persist finished children and announce them. Runs where awaiting is legal,
1121
+ * in submission order rather than settlement order, so two children that
1122
+ * complete out of order still land deterministically.
1123
+ */
1124
+ async function drain(rt, ctx) {
1125
+ if (rt.pending.length === 0) return;
1126
+ const batch = rt.pending.splice(0, rt.pending.length).sort((a, b) => a.order - b.order);
1127
+ let touchedSession;
1128
+ for (const entry of batch) {
1129
+ const result = entry.result;
1130
+ const stats = result?.stats ?? ZERO_STATS;
1131
+ const status = result?.status ?? (entry.cancelRequested ? "aborted" : "error");
1132
+ const session = entry.session;
1133
+ if (rt.persist && session) {
1134
+ touchedSession = session;
1135
+ session.startRun(entry.runId, entry.task, {
1136
+ ...entry.parentRunId !== void 0 ? { parentRunId: entry.parentRunId } : {},
1137
+ depth: entry.depth,
1138
+ label: entry.label,
1139
+ ...entry.callId ? { parentCallId: entry.callId } : {}
1140
+ });
1141
+ if (result && result.turns.length > 0) await session.appendTurns(result.turns.map((turn) => ({
1142
+ ...turn,
1143
+ runId: entry.runId
1144
+ })));
1145
+ const rollup = {
1146
+ turns: stats.turns,
1147
+ tokensIn: stats.totalIn,
1148
+ tokensOut: stats.totalOut,
1149
+ ...stats.cost !== void 0 ? { cost: stats.cost } : {}
1150
+ };
1151
+ if (status === "completed") session.completeRun(entry.runId, rollup);
1152
+ else if (status === "error") session.errorRun(entry.runId, errorText(entry), rollup);
1153
+ else session.abortRun(entry.runId, rollup);
1154
+ stampJournaledRunTimes(session, entry, result);
1155
+ }
1156
+ if (rt.emitEvents && result) await replayChildEvents(entry, result.turns, ctx);
1157
+ if (result?.children && result.children.length > 0) {
1158
+ const merged = await mergeDescendants(rt, {
1159
+ ...entry,
1160
+ parentChildId: entry.label
1161
+ }, result.children, ctx);
1162
+ if (merged) touchedSession = merged;
1163
+ }
1164
+ rt.options.onChildMerged?.({
1165
+ label: entry.label,
1166
+ task: entry.task,
1167
+ depth: entry.depth,
1168
+ status,
1169
+ stats,
1170
+ turns: result?.turns ?? [],
1171
+ ...result?.startedAt !== void 0 ? { startedAt: result.startedAt } : {},
1172
+ ...result?.endedAt !== void 0 ? { endedAt: result.endedAt } : {},
1173
+ ...result?.children !== void 0 ? { children: result.children } : {}
1174
+ }, ctx);
1175
+ if (status === "error") await ctx.hooks.callHook("spawn:error", {
1176
+ id: entry.label,
1177
+ task: entry.task,
1178
+ error: new Error(errorText(entry)),
1179
+ depth: entry.depth
1180
+ });
1181
+ await ctx.hooks.callHook("spawn:complete", {
1042
1182
  id: entry.label,
1043
1183
  task: entry.task,
1044
1184
  callId: entry.callId,
1045
1185
  depth: entry.depth,
1046
- ...typeof input.model === "string" ? { model: input.model } : {}
1047
- })).catch(() => {});
1048
- }
1049
- function registerDrain(ctx) {
1050
- if (drainRegistered.has(ctx.hooks)) return;
1051
- drainRegistered.add(ctx.hooks);
1052
- ctx.hooks.hook("tool-results:after", async () => {
1053
- await drain(ctx);
1054
- });
1055
- ctx.hooks.hook("turn:after", async () => {
1056
- await drain(ctx);
1186
+ status,
1187
+ stats,
1188
+ ...result?.text ? { text: result.text } : {}
1057
1189
  });
1058
1190
  }
1059
- /**
1060
- * Persist finished children and announce them. Runs where awaiting is legal,
1061
- * in submission order rather than settlement order, so two children that
1062
- * complete out of order still land deterministically.
1063
- */
1064
- async function drain(ctx) {
1065
- if (pending.length === 0) return;
1066
- const batch = pending.splice(0, pending.length).sort((a, b) => a.order - b.order);
1067
- let touchedSession;
1068
- for (const entry of batch) {
1069
- const result = entry.result;
1070
- const stats = result?.stats ?? ZERO_STATS;
1071
- const status = result?.status ?? (entry.cancelRequested ? "aborted" : "error");
1072
- const session = entry.session;
1073
- if (persist && session) {
1074
- touchedSession = session;
1075
- session.startRun(entry.runId, entry.task, {
1076
- ...entry.parentRunId !== void 0 ? { parentRunId: entry.parentRunId } : {},
1077
- depth: entry.depth,
1078
- label: entry.label
1079
- });
1080
- if (result && result.turns.length > 0) await session.appendTurns(result.turns.map((turn) => ({
1081
- ...turn,
1082
- runId: entry.runId
1083
- })));
1084
- const rollup = {
1085
- turns: stats.turns,
1086
- tokensIn: stats.totalIn,
1087
- tokensOut: stats.totalOut,
1088
- ...stats.cost !== void 0 ? { cost: stats.cost } : {}
1089
- };
1090
- if (status === "completed") session.completeRun(entry.runId, rollup);
1091
- else if (status === "error") session.errorRun(entry.runId, errorText(entry), rollup);
1092
- else session.abortRun(entry.runId, rollup);
1093
- stampJournaledRunTimes(session, entry, result);
1094
- }
1095
- if (emitEvents && result) await replayChildEvents(entry, result.turns, ctx);
1096
- if (result?.children && result.children.length > 0) {
1097
- const merged = await mergeDescendants(entry, result.children, ctx);
1098
- if (merged) touchedSession = merged;
1099
- }
1100
- options.onChildMerged?.({
1101
- label: entry.label,
1102
- task: entry.task,
1103
- depth: entry.depth,
1104
- status,
1105
- stats,
1106
- turns: result?.turns ?? [],
1107
- ...result?.startedAt !== void 0 ? { startedAt: result.startedAt } : {},
1108
- ...result?.endedAt !== void 0 ? { endedAt: result.endedAt } : {},
1109
- ...result?.children !== void 0 ? { children: result.children } : {}
1110
- }, ctx);
1111
- if (status === "error") await ctx.hooks.callHook("spawn:error", {
1112
- id: entry.label,
1113
- task: entry.task,
1114
- error: new Error(errorText(entry)),
1115
- depth: entry.depth
1116
- });
1117
- await ctx.hooks.callHook("spawn:complete", {
1118
- id: entry.label,
1119
- task: entry.task,
1120
- callId: entry.callId,
1121
- depth: entry.depth,
1122
- status,
1123
- stats,
1124
- ...result?.text ? { text: result.text } : {}
1191
+ await touchedSession?.save();
1192
+ }
1193
+ /**
1194
+ * Merge a child's own descendants under it, depth-first and in the order the
1195
+ * child reported them.
1196
+ *
1197
+ * Each nested child is RE-LABELED from the merging session's counter: the
1198
+ * label it arrived with was minted by its own parent's counter and would
1199
+ * collide (every level starts at `child-1`). Re-labeling keeps the session's
1200
+ * labels unique and makes the synthesized events agree with the persisted
1201
+ * tree.
1202
+ *
1203
+ * Each nested child is announced as `child:spawn:before` → its work →
1204
+ * (`child:spawn:error`) → `child:spawn:complete`, owned by the merged label
1205
+ * of the child that spawned it (`parentChildId`) — the same lifecycle an
1206
+ * in-process nested spawn bubbles, so hosts nest and close it identically.
1207
+ * Unconditional, like the top-level `spawn:complete`: lifecycle is not
1208
+ * `emitChildEvents` traffic. No `callId`: the spawn call inside the child is
1209
+ * not part of the merged result.
1210
+ */
1211
+ async function mergeDescendants(rt, parent, nested, ctx) {
1212
+ let touched;
1213
+ const session = parent.session;
1214
+ for (const child of nested) {
1215
+ const depth = parent.depth + 1;
1216
+ const label = session ? reserveChildLabel(session) : `${parent.runId}-nested-${++rt.nestedLabels}`;
1217
+ const runId = `${parent.runId}-${label}`;
1218
+ const record = {
1219
+ id: label,
1220
+ task: child.task,
1221
+ depth,
1222
+ parentChildId: parent.parentChildId
1223
+ };
1224
+ await ctx.hooks.callHook("child:spawn:before", record);
1225
+ if (rt.persist && session) {
1226
+ touched = session;
1227
+ session.startRun(runId, child.task, {
1228
+ parentRunId: parent.runId,
1229
+ depth,
1230
+ label
1125
1231
  });
1126
- }
1127
- await touchedSession?.save();
1128
- }
1129
- /**
1130
- * Merge a child's own descendants under it, depth-first and in the order the
1131
- * child reported them.
1132
- *
1133
- * Each nested child is RE-LABELED from the merging session's counter: the
1134
- * label it arrived with was minted by its own parent's counter and would
1135
- * collide (every level starts at `child-1`). Re-labeling keeps the session's
1136
- * labels unique and makes the synthesized events agree with the persisted
1137
- * tree.
1138
- */
1139
- async function mergeDescendants(parent, nested, ctx) {
1140
- let touched;
1141
- const session = parent.session;
1142
- for (const child of nested) {
1143
- const depth = parent.depth + 1;
1144
- const label = session ? reserveChildLabel(session) : `${parent.runId}-nested-${++nestedLabels}`;
1145
- const runId = `${parent.runId}-${label}`;
1146
- if (persist && session) {
1147
- touched = session;
1148
- session.startRun(runId, child.task, {
1149
- parentRunId: parent.runId,
1150
- depth,
1151
- label
1152
- });
1153
- if (child.turns.length > 0) await session.appendTurns(child.turns.map((turn) => ({
1154
- ...turn,
1155
- runId
1156
- })));
1157
- const rollup = {
1158
- turns: child.stats.turns,
1159
- tokensIn: child.stats.totalIn,
1160
- tokensOut: child.stats.totalOut,
1161
- ...child.stats.cost !== void 0 ? { cost: child.stats.cost } : {}
1162
- };
1163
- if (child.status === "completed") session.completeRun(runId, rollup);
1164
- else if (child.status === "error") session.errorRun(runId, "sub-agent failed", rollup);
1165
- else session.abortRun(runId, rollup);
1166
- const record = session.runs.find((run) => run.id === runId);
1167
- if (record) {
1168
- const startedAt = child.startedAt ?? child.turns[0]?.createdAt;
1169
- const endedAt = child.endedAt ?? child.turns[child.turns.length - 1]?.createdAt ?? startedAt;
1170
- if (startedAt !== void 0) record.startedAt = startedAt;
1171
- if (endedAt !== void 0) record.endedAt = endedAt;
1172
- }
1232
+ if (child.turns.length > 0) await session.appendTurns(child.turns.map((turn) => ({
1233
+ ...turn,
1234
+ runId
1235
+ })));
1236
+ const rollup = {
1237
+ turns: child.stats.turns,
1238
+ tokensIn: child.stats.totalIn,
1239
+ tokensOut: child.stats.totalOut,
1240
+ ...child.stats.cost !== void 0 ? { cost: child.stats.cost } : {}
1241
+ };
1242
+ if (child.status === "completed") session.completeRun(runId, rollup);
1243
+ else if (child.status === "error") session.errorRun(runId, "sub-agent failed", rollup);
1244
+ else session.abortRun(runId, rollup);
1245
+ const run = session.runs.find((r) => r.id === runId);
1246
+ if (run) {
1247
+ const startedAt = child.startedAt ?? child.turns[0]?.createdAt;
1248
+ const endedAt = child.endedAt ?? child.turns[child.turns.length - 1]?.createdAt ?? startedAt;
1249
+ if (startedAt !== void 0) run.startedAt = startedAt;
1250
+ if (endedAt !== void 0) run.endedAt = endedAt;
1173
1251
  }
1174
- if (emitEvents) await replayChildEvents({
1175
- label,
1176
- depth,
1252
+ }
1253
+ if (rt.emitEvents) await replayChildEvents({
1254
+ label,
1255
+ depth,
1256
+ runId,
1257
+ callId: parent.callId,
1258
+ ...parent.runId ? { parentRunId: parent.runId } : {}
1259
+ }, child.turns, ctx);
1260
+ if (child.children && child.children.length > 0) {
1261
+ const deeper = await mergeDescendants(rt, {
1177
1262
  runId,
1263
+ depth,
1178
1264
  callId: parent.callId,
1179
- ...parent.runId ? { parentRunId: parent.runId } : {}
1180
- }, child.turns, ctx);
1181
- if (child.children && child.children.length > 0) {
1182
- const deeper = await mergeDescendants({
1183
- runId,
1184
- depth,
1185
- callId: parent.callId,
1186
- ...session ? { session } : {}
1187
- }, child.children, ctx);
1188
- touched = touched ?? deeper;
1189
- }
1265
+ parentChildId: label,
1266
+ ...session ? { session } : {}
1267
+ }, child.children, ctx);
1268
+ touched = touched ?? deeper;
1190
1269
  }
1191
- return touched;
1192
- }
1193
- /**
1194
- * Repair the run record's timestamps with journaled values.
1195
- *
1196
- * `startRun` / `completeRun` / `errorRun` / `abortRun` stamp `Date.now()`
1197
- * internally, and these records reach `ctx.set` through `save()` below — so a
1198
- * live value here changes the state payload on a replay and kills the
1199
- * invocation with `RestateError 570`. The loop repairs its own runs exactly
1200
- * this way (`agent.ts`: `sessionRun.startedAt = runStartedAt`, `run.endedAt =
1201
- * await clock.now()`); the merge path has to do the same.
1202
- *
1203
- * Sampling the parent's clock here is not an option: the drain runs inside a
1204
- * hook the loop may abandon (`settledHook`), and an awaited journal op left in
1205
- * flight is its own failure mode. Everything below is already journaled by the
1206
- * time it reaches us — either measured by the child on ITS clock and carried
1207
- * inside the journaled call result, or read from state the parent's own run
1208
- * already wrote.
1209
- */
1210
- function stampJournaledRunTimes(session, entry, result) {
1211
- const merged = session.runs.find((run) => run.id === entry.runId);
1212
- if (!merged) return;
1213
- const turns = result?.turns ?? [];
1214
- const parentStartedAt = entry.parentRunId !== void 0 ? session.runs.find((run) => run.id === entry.parentRunId)?.startedAt : void 0;
1215
- const startedAt = result?.startedAt ?? turns[0]?.createdAt ?? parentStartedAt;
1216
- const endedAt = result?.endedAt ?? turns[turns.length - 1]?.createdAt ?? startedAt;
1217
- if (startedAt !== void 0) merged.startedAt = startedAt;
1218
- if (endedAt !== void 0) merged.endedAt = endedAt;
1219
- }
1220
- /**
1221
- * Replay a finished child's transcript onto the PARENT's hook bus as `child:*`
1222
- * events, so hosts that already render subagent activity (`src/output/
1223
- * terminal.ts`, the GUI engine, any `child:tool:*` listener) light up for
1224
- * parallel children without a single change.
1225
- *
1226
- * Not live \u2014 hook bubbling cannot cross an invocation boundary, so these fire
1227
- * when the child finishes, in submission order. Everything here is derived
1228
- * from the journaled call result, so a parent replay produces the identical
1229
- * sequence; like the in-process tool's `child:tool:*`, they DO re-fire on that
1230
- * replay, so hosts dedupe by `callId` / `turnId` or gate on
1231
- * `createReplayTracker`.
1232
- *
1233
- * Only events that describe things the child actually did are synthesized.
1234
- * `tool:gate` / `tool:transform` / `tool:dispatched` / `tool:cancelled` /
1235
- * `background:*` describe decisions taken inside another process; inventing
1236
- * them would be fiction, so they stay absent.
1237
- */
1238
- async function replayChildEvents(child, turns, ctx) {
1239
- if (turns.length === 0) return;
1240
- const outputs = /* @__PURE__ */ new Map();
1241
- for (const turn of turns) for (const block of turn.content) if (block.type === "tool_result") outputs.set(block.callId, {
1242
- output: block.output,
1243
- ...block.isError !== void 0 ? { isError: block.isError } : {}
1270
+ if (child.status === "error") await ctx.hooks.callHook("child:spawn:error", {
1271
+ ...record,
1272
+ error: /* @__PURE__ */ new Error("sub-agent failed")
1273
+ });
1274
+ await ctx.hooks.callHook("child:spawn:complete", {
1275
+ ...record,
1276
+ status: child.status,
1277
+ stats: child.stats
1244
1278
  });
1245
- const childIdentity = {
1246
- childId: child.label,
1247
- depth: child.depth
1248
- };
1249
- const identity = {
1250
- ...childIdentity,
1251
- runId: child.runId,
1252
- ...child.parentRunId !== void 0 ? { parentRunId: child.parentRunId } : {},
1253
- parentCallId: child.callId
1254
- };
1255
- const runToolCounts = {};
1256
- let assistantTurns = 0;
1257
- for (const turn of turns) {
1258
- if (turn.role !== "assistant") continue;
1259
- assistantTurns += 1;
1260
- const text = turn.content.filter((block) => block.type === "text").map((block) => block.text).join("");
1261
- if (text.length > 0) await ctx.hooks.callHook("child:stream:text", {
1262
- ...childIdentity,
1263
- turnId: turn.id,
1264
- delta: text,
1265
- text
1266
- });
1267
- const turnToolCounts = {};
1268
- for (const block of turn.content) {
1269
- if (block.type !== "tool_call") continue;
1270
- runToolCounts[block.name] = (runToolCounts[block.name] ?? 0) + 1;
1271
- turnToolCounts[block.name] = (turnToolCounts[block.name] ?? 0) + 1;
1272
- const base = {
1273
- ...identity,
1274
- turnId: turn.id,
1275
- callId: block.id,
1276
- name: block.name,
1277
- displayName: block.name,
1278
- input: block.input,
1279
- runToolCounts: { ...runToolCounts }
1280
- };
1281
- await ctx.hooks.callHook("child:tool:before", base);
1282
- const settled = outputs.get(block.id);
1283
- if (settled === void 0) continue;
1284
- if (settled.isError === true) {
1285
- await ctx.hooks.callHook("child:tool:error", {
1286
- ...base,
1287
- error: new Error(toolResultToText(settled.output))
1288
- });
1289
- continue;
1290
- }
1291
- await ctx.hooks.callHook("child:tool:after", {
1292
- ...base,
1293
- result: settled.output,
1294
- outputBytes: toolOutputByteLength(settled.output)
1295
- });
1296
- }
1297
- const usage = turn.usage ?? {
1298
- input: 0,
1299
- output: 0
1300
- };
1301
- await ctx.hooks.callHook("child:turn:after", {
1302
- ...childIdentity,
1303
- turn: assistantTurns,
1304
- turnId: turn.id,
1305
- usage,
1306
- message: turn,
1307
- toolCounts: {
1308
- turn: { ...turnToolCounts },
1309
- run: { ...runToolCounts }
1310
- }
1311
- });
1312
- await ctx.hooks.callHook("child:stream:end", {
1313
- ...childIdentity,
1314
- turnId: turn.id,
1315
- text
1316
- });
1317
- }
1318
- }
1319
- function errorText(entry) {
1320
- if (entry.failure !== void 0) return entry.failure instanceof Error ? entry.failure.message : String(entry.failure);
1321
- return entry.result?.error ?? "sub-agent failed";
1322
1279
  }
1323
- /**
1324
- * Shape the model-facing result. Mirrors the in-process tool's wording so a
1325
- * host or model tuned on one reads the other.
1326
- *
1327
- * `stats.elapsed` is safe to print here even though it is a live measurement:
1328
- * the child measured it inside ITS invocation and it arrives in the journaled
1329
- * call result, so the parent replays the same bytes. (Sampling it on the
1330
- * parent side is what corrupts a transcript — see `docs/RESTATE.md`.)
1331
- */
1332
- /**
1333
- * Arm the abort path for one child. Nothing is read off the dispatch promise:
1334
- * touching its `invocationId` mid-flight would register a second consumer on
1335
- * the runtime's progress channel (see `onAbort`'s note), so the hook gets
1336
- * labels and the host cancels the tree.
1337
- */
1338
- function watchAbort(entry, ctx) {
1339
- if (!options.onAbort) return;
1340
- if (ctx.signal.aborted) {
1341
- requestCancel(ctx);
1342
- return;
1280
+ return touched;
1281
+ }
1282
+ /**
1283
+ * Repair the run record's timestamps with journaled values.
1284
+ *
1285
+ * `startRun` / `completeRun` / `errorRun` / `abortRun` stamp `Date.now()`
1286
+ * internally, and these records reach `ctx.set` through `save()` below — so a
1287
+ * live value here changes the state payload on a replay and kills the
1288
+ * invocation with `RestateError 570`. The loop repairs its own runs exactly
1289
+ * this way (`agent.ts`: `sessionRun.startedAt = runStartedAt`, `run.endedAt =
1290
+ * await clock.now()`); the merge path has to do the same.
1291
+ *
1292
+ * Sampling the parent's clock here is not an option: the drain runs inside a
1293
+ * hook the loop may abandon (`settledHook`), and an awaited journal op left in
1294
+ * flight is its own failure mode. Everything below is already journaled by the
1295
+ * time it reaches us — either measured by the child on ITS clock and carried
1296
+ * inside the journaled call result, or read from state the parent's own run
1297
+ * already wrote.
1298
+ */
1299
+ function stampJournaledRunTimes(session, entry, result) {
1300
+ const merged = session.runs.find((run) => run.id === entry.runId);
1301
+ if (!merged) return;
1302
+ const turns = result?.turns ?? [];
1303
+ const parentStartedAt = entry.parentRunId !== void 0 ? session.runs.find((run) => run.id === entry.parentRunId)?.startedAt : void 0;
1304
+ const startedAt = result?.startedAt ?? turns[0]?.createdAt ?? parentStartedAt;
1305
+ const endedAt = result?.endedAt ?? turns[turns.length - 1]?.createdAt ?? startedAt;
1306
+ if (startedAt !== void 0) merged.startedAt = startedAt;
1307
+ if (endedAt !== void 0) merged.endedAt = endedAt;
1308
+ }
1309
+ //#endregion
1310
+ //#region src/restate/spawn-dispatch.ts
1311
+ /**
1312
+ * Build the request and the bookkeeping entry. Deliberately side-effect free
1313
+ * apart from reserving the label: the fleet path has to be able to reject a
1314
+ * misconfigured `dispatch` (below) without leaving a phantom child queued for
1315
+ * the merge. `commit` is what actually enrols the child.
1316
+ */
1317
+ function prepare(rt, input, ctx) {
1318
+ const task = String(input.task ?? "");
1319
+ const depth = (ctx.depth ?? 0) + 1;
1320
+ const label = ctx.session ? reserveChildLabel(ctx.session) : `child-${++rt.sessionlessLabels}`;
1321
+ return {
1322
+ entry: {
1323
+ order: ++rt.dispatchSeq,
1324
+ label,
1325
+ task,
1326
+ depth,
1327
+ callId: ctx.callId,
1328
+ runId: `${ctx.runId ?? "run"}-${label}`,
1329
+ ...ctx.runId !== void 0 ? { parentRunId: ctx.runId } : {},
1330
+ ...ctx.session !== void 0 ? { session: ctx.session } : {}
1331
+ },
1332
+ req: {
1333
+ task,
1334
+ label,
1335
+ depth,
1336
+ ...ctx.runId !== void 0 ? { parentRunId: ctx.runId } : {},
1337
+ parentCallId: ctx.callId,
1338
+ ...ctx.session !== void 0 ? { sessionId: ctx.session.id } : {},
1339
+ ...typeof input.model === "string" ? { model: input.model } : {},
1340
+ ...typeof input.subagent_type === "string" ? { subagentType: input.subagent_type } : {}
1343
1341
  }
1344
- const onAbort = () => requestCancel(ctx);
1345
- ctx.signal.addEventListener("abort", onAbort, { once: true });
1346
- entry.release = () => ctx.signal.removeEventListener("abort", onAbort);
1347
- }
1348
- /**
1349
- * Fire the host's abort hook once for the whole in-flight set. Called once per
1350
- * abort, not once per child: cancelling the tree is a single operation, and a
1351
- * second call would append a redundant journal command.
1352
- */
1353
- function requestCancel(ctx) {
1354
- const onAbort = options.onAbort;
1355
- if (!onAbort || cancelSignalled) return;
1356
- const inFlight = pending.filter((entry) => !entry.settled);
1357
- if (inFlight.length === 0) return;
1358
- cancelSignalled = true;
1359
- for (const entry of inFlight) entry.cancelRequested = true;
1360
- onAbort(inFlight.map((entry) => ({
1361
- label: entry.label,
1362
- task: entry.task,
1363
- depth: entry.depth
1364
- })), ctx);
1342
+ };
1343
+ }
1344
+ /** Enrol a dispatched child for merging, and announce it. */
1345
+ function commit(rt, entry, input, ctx) {
1346
+ rt.pending.push(entry);
1347
+ registerDrain(rt, ctx);
1348
+ watchAbort(rt, entry, ctx);
1349
+ Promise.resolve(ctx.hooks.callHook("spawn:before", {
1350
+ id: entry.label,
1351
+ task: entry.task,
1352
+ callId: entry.callId,
1353
+ depth: entry.depth,
1354
+ ...typeof input.model === "string" ? { model: input.model } : {}
1355
+ })).catch(() => {});
1356
+ }
1357
+ function registerDrain(rt, ctx) {
1358
+ if (rt.drainRegistered.has(ctx.hooks)) return;
1359
+ rt.drainRegistered.add(ctx.hooks);
1360
+ ctx.hooks.hook("tool-results:after", async () => {
1361
+ await drain(rt, ctx);
1362
+ });
1363
+ ctx.hooks.hook("turn:after", async () => {
1364
+ await drain(rt, ctx);
1365
+ });
1366
+ }
1367
+ /**
1368
+ * Shape the model-facing result. Mirrors the in-process tool's wording so a
1369
+ * host or model tuned on one reads the other.
1370
+ *
1371
+ * `stats.elapsed` is safe to print here even though it is a live measurement:
1372
+ * the child measured it inside ITS invocation and it arrives in the journaled
1373
+ * call result, so the parent replays the same bytes. (Sampling it on the
1374
+ * parent side is what corrupts a transcript — see `docs/RESTATE.md`.)
1375
+ */
1376
+ /**
1377
+ * Arm the abort path for one child. Nothing is read off the dispatch promise:
1378
+ * touching its `invocationId` mid-flight would register a second consumer on
1379
+ * the runtime's progress channel (see `onAbort`'s note), so the hook gets
1380
+ * labels and the host cancels the tree.
1381
+ */
1382
+ function watchAbort(rt, entry, ctx) {
1383
+ if (!rt.options.onAbort) return;
1384
+ if (ctx.signal.aborted) {
1385
+ requestCancel(rt, ctx);
1386
+ return;
1365
1387
  }
1366
- function settle(entry, value, failure) {
1367
- entry.settled = true;
1368
- entry.release?.();
1369
- if (failure !== void 0) {
1370
- entry.failure = failure;
1371
- if (entry.cancelRequested) return `[sub-agent ${entry.label}] Aborted (cancelled)`;
1372
- return `[sub-agent ${entry.label}] Error: ${errorText(entry)}`;
1373
- }
1374
- const result = value ?? {
1375
- status: "error",
1376
- text: "",
1377
- turns: [],
1378
- stats: ZERO_STATS
1379
- };
1380
- entry.result = result;
1381
- const head = `[sub-agent ${entry.label}]`;
1382
- const usage = `Tokens: ${formatTokenUsage(result.stats)}`;
1383
- if (result.status === "completed") return [
1384
- `${head} Completed in ${result.stats.turns} turns (${result.stats.elapsed}ms)`,
1385
- usage,
1386
- "",
1387
- result.text || "(no text response)"
1388
- ].join("\n");
1389
- if (result.status === "error") return `${head} Error: ${errorText(entry)}`;
1390
- return [`${head} ${result.status === "timeout" ? "Timed out" : "Aborted"} after ${result.stats.turns} turns (${result.stats.elapsed}ms)`, usage].join("\n");
1388
+ const onAbort = () => requestCancel(rt, ctx);
1389
+ ctx.signal.addEventListener("abort", onAbort, { once: true });
1390
+ entry.release = () => ctx.signal.removeEventListener("abort", onAbort);
1391
+ }
1392
+ /**
1393
+ * Fire the host's abort hook once for the whole in-flight set. Called once per
1394
+ * abort, not once per child: cancelling the tree is a single operation, and a
1395
+ * second call would append a redundant journal command.
1396
+ */
1397
+ function requestCancel(rt, ctx) {
1398
+ const onAbort = rt.options.onAbort;
1399
+ if (!onAbort || rt.cancelSignalled) return;
1400
+ const inFlight = rt.pending.filter((entry) => !entry.settled);
1401
+ if (inFlight.length === 0) return;
1402
+ rt.cancelSignalled = true;
1403
+ for (const entry of inFlight) entry.cancelRequested = true;
1404
+ onAbort(inFlight.map((entry) => ({
1405
+ label: entry.label,
1406
+ task: entry.task,
1407
+ depth: entry.depth
1408
+ })), ctx);
1409
+ }
1410
+ function settle(entry, value, failure) {
1411
+ entry.settled = true;
1412
+ entry.release?.();
1413
+ if (failure !== void 0) {
1414
+ entry.failure = failure;
1415
+ if (entry.cancelRequested) return `[sub-agent ${entry.label}] Aborted (cancelled)`;
1416
+ return `[sub-agent ${entry.label}] Error: ${errorText(entry)}`;
1391
1417
  }
1418
+ const result = value ?? {
1419
+ status: "error",
1420
+ text: "",
1421
+ turns: [],
1422
+ stats: ZERO_STATS
1423
+ };
1424
+ entry.result = result;
1425
+ const head = `[sub-agent ${entry.label}]`;
1426
+ const usage = `Tokens: ${formatTokenUsage(result.stats)}`;
1427
+ if (result.status === "completed") return [
1428
+ `${head} Completed in ${result.stats.turns} turns (${result.stats.elapsed}ms)`,
1429
+ usage,
1430
+ "",
1431
+ result.text || "(no text response)"
1432
+ ].join("\n");
1433
+ if (result.status === "error") return `${head} Error: ${errorText(entry)}`;
1434
+ return [`${head} ${result.status === "timeout" ? "Timed out" : "Aborted"} after ${result.stats.turns} turns (${result.stats.elapsed}ms)`, usage].join("\n");
1435
+ }
1436
+ //#endregion
1437
+ //#region src/restate/spawn.ts
1438
+ const DEFAULT_DESCRIPTION = "Delegate a self-contained task to a sub-agent that runs independently and returns only its final report. Several spawn calls in one turn run in parallel.";
1439
+ function restateSpawnTool(options) {
1440
+ const rt = {
1441
+ options,
1442
+ persist: options.persist ?? true,
1443
+ emitEvents: options.emitChildEvents ?? true,
1444
+ dispatchSeq: 0,
1445
+ sessionlessLabels: 0,
1446
+ cancelSignalled: false,
1447
+ nestedLabels: 0,
1448
+ pending: [],
1449
+ drainRegistered: /* @__PURE__ */ new WeakSet()
1450
+ };
1392
1451
  return {
1393
1452
  spec: {
1394
1453
  name: "spawn",
@@ -1415,16 +1474,16 @@ function restateSpawnTool(options) {
1415
1474
  isConcurrencySafe: true,
1416
1475
  runsNestedAgent: true,
1417
1476
  durableExecute: (input, ctx) => {
1418
- const { req, entry } = prepare(input, ctx);
1477
+ const { req, entry } = prepare(rt, input, ctx);
1419
1478
  const promise = options.dispatch(req, ctx);
1420
1479
  if (typeof promise.map !== "function") throw new TypeError("restateSpawnTool: `dispatch` must return the runtime's durable promise (e.g. `ctx.serviceClient(svc).runChild(req)`), which exposes `map`.");
1421
- commit(entry, input, ctx);
1480
+ commit(rt, entry, input, ctx);
1422
1481
  return promise.map((value, failure) => settle(entry, value, failure));
1423
1482
  },
1424
1483
  execute: async (input, ctx) => {
1425
- const { req, entry } = prepare(input, ctx);
1484
+ const { req, entry } = prepare(rt, input, ctx);
1426
1485
  const promise = options.dispatch(req, ctx);
1427
- commit(entry, input, ctx);
1486
+ commit(rt, entry, input, ctx);
1428
1487
  try {
1429
1488
  return settle(entry, await promise);
1430
1489
  } catch (err) {
@@ -1554,7 +1613,7 @@ function restateWaitBackground(options) {
1554
1613
  awakeableId: awakeable.id
1555
1614
  };
1556
1615
  }, runOpts);
1557
- if (marker.awakeableId !== awakeable.id) throw new Error(`restateWaitBackground(${taskId}): journal drift — registration marker carries awakeable "${marker.awakeableId}" but this replay minted "${awakeable.id}". Refusing to park on an unreachable awakeable.`);
1616
+ if (marker.awakeableId !== awakeable.id) throw new Error(`restateWaitBackground(${taskId}): journal drift: registration marker carries awakeable "${marker.awakeableId}" but this replay minted "${awakeable.id}". Refusing to park on an unreachable awakeable.`);
1558
1617
  const found = (await ctx.run(`${entry}-probe`, async () => {
1559
1618
  options.replayTracker?.markLive();
1560
1619
  return [...await probe(handle, taskId)];