zidane 7.2.4 → 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.
- package/LICENSE +21 -0
- package/README.md +34 -6
- package/dist/{acp-D-tVyUjw.js → acp-DQDhi2dj.js} +230 -77
- package/dist/acp-DQDhi2dj.js.map +1 -0
- package/dist/acp-cli.d.ts +1 -1
- package/dist/acp-cli.js +9 -66
- package/dist/acp-cli.js.map +1 -1
- package/dist/acp.d.ts +10 -590
- package/dist/acp.d.ts.map +1 -1
- package/dist/acp.js +3 -3
- package/dist/{agent-D0zZnGbt.js → agent-DSLNmBp0.js} +14401 -13214
- package/dist/agent-DSLNmBp0.js.map +1 -0
- package/dist/agent.d.ts +1 -1
- package/dist/agent.js +3 -2
- package/dist/aliasing-lVFbm81n.js +217 -0
- package/dist/aliasing-lVFbm81n.js.map +1 -0
- package/dist/{anthropic-C2aole0G.js → anthropic-CD00LhUP.js} +1442 -1264
- package/dist/anthropic-CD00LhUP.js.map +1 -0
- package/dist/artifacts-CV2hUKnL.js.map +1 -1
- package/dist/{atomic-write-B7zr1ddF.js → atomic-write-Ijgf2Mhc.js} +13 -3
- package/dist/atomic-write-Ijgf2Mhc.js.map +1 -0
- package/dist/call-tool-dHlbGOIY.js +70 -0
- package/dist/call-tool-dHlbGOIY.js.map +1 -0
- package/dist/chat/pure.d.ts +372 -6
- package/dist/chat/pure.d.ts.map +1 -1
- package/dist/chat/pure.js +35 -244
- package/dist/chat/pure.js.map +1 -1
- package/dist/{approvals-DKaJZYlm.js → chat-JPJJ8uu5.js} +15879 -14631
- package/dist/chat-JPJJ8uu5.js.map +1 -0
- package/dist/chat.d.ts +4 -6
- package/dist/chat.js +23 -12
- package/dist/cli-shared-C-YCaglL.js +159 -0
- package/dist/cli-shared-C-YCaglL.js.map +1 -0
- package/dist/client-core-BQSyDALT.d.ts +2115 -0
- package/dist/client-core-BQSyDALT.d.ts.map +1 -0
- package/dist/codemode-worker.d.ts +1 -0
- package/dist/codemode-worker.js +155 -0
- package/dist/codemode-worker.js.map +1 -0
- package/dist/codemode.d.ts +352 -0
- package/dist/codemode.d.ts.map +1 -0
- package/dist/codemode.js +5 -0
- package/dist/connection-Dr-Js4yZ.d.ts +28 -0
- package/dist/connection-Dr-Js4yZ.d.ts.map +1 -0
- package/dist/connection-loop-gdh22LTI.js +112 -0
- package/dist/connection-loop-gdh22LTI.js.map +1 -0
- package/dist/context-segments-BHKlagL6.js +1016 -0
- package/dist/context-segments-BHKlagL6.js.map +1 -0
- package/dist/{context-transport-T_6AYIvy.js → context-transport-DSMTUsK1.js} +3 -3
- package/dist/{context-transport-T_6AYIvy.js.map → context-transport-DSMTUsK1.js.map} +1 -1
- package/dist/contexts/daytona.d.ts +19 -8
- package/dist/contexts/daytona.d.ts.map +1 -1
- package/dist/contexts/daytona.js +1 -440
- package/dist/contexts/docker.d.ts +36 -7
- package/dist/contexts/docker.d.ts.map +1 -1
- package/dist/contexts/docker.js +1 -456
- package/dist/contexts/e2b.d.ts +68 -13
- package/dist/contexts/e2b.d.ts.map +1 -1
- package/dist/contexts/e2b.js +1 -382
- package/dist/contexts/sandbox.d.ts +1 -1
- package/dist/contexts/sandbox.js +5 -0
- package/dist/contexts/sandbox.js.map +1 -1
- package/dist/{contexts-CRE9pw07.js → contexts-d7UolYot.js} +1059 -524
- package/dist/contexts-d7UolYot.js.map +1 -0
- package/dist/contexts.d.ts +3 -3
- package/dist/contexts.js +1 -1
- package/dist/cred-keys-GpBg71cP.js +105 -0
- package/dist/cred-keys-GpBg71cP.js.map +1 -0
- package/dist/{auth-BG2rVKSt.js → credentials-JttEuRON.js} +55 -206
- package/dist/credentials-JttEuRON.js.map +1 -0
- package/dist/{cursor-iojRXHF9.js → cursor-CdjaQTBW.js} +3 -3
- package/dist/{cursor-iojRXHF9.js.map → cursor-CdjaQTBW.js.map} +1 -1
- package/dist/daemon-cli.d.ts +1 -1
- package/dist/daemon-cli.js +3 -2
- package/dist/daemon-cli.js.map +1 -1
- package/dist/daytona-DG3omipZ.js +513 -0
- package/dist/daytona-DG3omipZ.js.map +1 -0
- package/dist/defaults-Cx3zvDOV.js +23 -0
- package/dist/defaults-Cx3zvDOV.js.map +1 -0
- package/dist/dispatcher-BMlu2BmZ.js +4941 -0
- package/dist/dispatcher-BMlu2BmZ.js.map +1 -0
- package/dist/docker-BZhMMJUp.js +727 -0
- package/dist/docker-BZhMMJUp.js.map +1 -0
- package/dist/e2b-CEVOdRib.js +480 -0
- package/dist/e2b-CEVOdRib.js.map +1 -0
- package/dist/edit-utils-EGosADZq.js +234 -0
- package/dist/edit-utils-EGosADZq.js.map +1 -0
- package/dist/environment-8wsKE2Ln.js +214 -0
- package/dist/environment-8wsKE2Ln.js.map +1 -0
- package/dist/eval-BNcvle_J.js +1595 -0
- package/dist/eval-BNcvle_J.js.map +1 -0
- package/dist/eval.d.ts +2 -2
- package/dist/eval.js +1 -1489
- package/dist/executor-Cx5-8yqi.js +621 -0
- package/dist/executor-Cx5-8yqi.js.map +1 -0
- package/dist/extension-authoring-DyGGmq9V.js +385 -0
- package/dist/extension-authoring-DyGGmq9V.js.map +1 -0
- package/dist/extensions.d.ts +2 -2
- package/dist/extensions.js +3 -3
- package/dist/{fetch-url-DX75gpL0.js → fetch-url-Ct2TjDWt.js} +4 -4
- package/dist/{fetch-url-DX75gpL0.js.map → fetch-url-Ct2TjDWt.js.map} +1 -1
- package/dist/{format-BF745pLL.js → format-C2NQEVUH.js} +39 -2
- package/dist/format-C2NQEVUH.js.map +1 -0
- package/dist/format-bytes-C7tfc3Zm.js +55 -0
- package/dist/format-bytes-C7tfc3Zm.js.map +1 -0
- package/dist/headless-C_rNUuYC.js +960 -0
- package/dist/headless-C_rNUuYC.js.map +1 -0
- package/dist/headless.d.ts +1 -1
- package/dist/headless.js +1 -413
- package/dist/{history-search-C4bk1Wz_.js → history-search-CcYzF8-0.js} +7 -3
- package/dist/history-search-CcYzF8-0.js.map +1 -0
- package/dist/history-search-worker.d.ts +1 -1
- package/dist/history-search-worker.js +1 -1
- package/dist/host-D7NrI03V.js +378 -0
- package/dist/host-D7NrI03V.js.map +1 -0
- package/dist/host-signals-BcP5QKUD.js +118 -0
- package/dist/host-signals-BcP5QKUD.js.map +1 -0
- package/dist/identity-CwfO8K-t.js +26 -0
- package/dist/identity-CwfO8K-t.js.map +1 -0
- package/dist/{index-BgN1T3lk.d.ts → index-BGe1fQT7.d.ts} +10987 -9320
- package/dist/index-BGe1fQT7.d.ts.map +1 -0
- package/dist/index-BVQsIKGn.d.ts +448 -0
- package/dist/index-BVQsIKGn.d.ts.map +1 -0
- package/dist/{index-C6NEd5y_.d.ts → index-CHABJd-L.d.ts} +3386 -502
- package/dist/index-CHABJd-L.d.ts.map +1 -0
- package/dist/{index-C37_ppWv.d.ts → index-D6a7qXpg.d.ts} +2 -3
- package/dist/index-D6a7qXpg.d.ts.map +1 -0
- package/dist/index.d.ts +6 -6
- package/dist/index.js +27 -23
- package/dist/{completion-core-BRo86R_L.js → inline-ghost-BVRQeGoL.js} +50 -2
- package/dist/inline-ghost-BVRQeGoL.js.map +1 -0
- package/dist/ipc/remote.d.ts +313 -0
- package/dist/ipc/remote.d.ts.map +1 -0
- package/dist/ipc/remote.js +4 -0
- package/dist/ipc.d.ts +6 -964
- package/dist/ipc.js +403 -4
- package/dist/ipc.js.map +1 -0
- package/dist/{isolation-Kfoof0MM.d.ts → isolation-D9L650W5.d.ts} +100 -15
- package/dist/isolation-D9L650W5.d.ts.map +1 -0
- package/dist/json-rpc--HXQti1E.js +350 -0
- package/dist/json-rpc--HXQti1E.js.map +1 -0
- package/dist/links-j8rED1sR.js +603 -0
- package/dist/links-j8rED1sR.js.map +1 -0
- package/dist/local-terminal-D8QThwo_.js +252 -0
- package/dist/local-terminal-D8QThwo_.js.map +1 -0
- package/dist/{logger--C1VQjwJ.js → logger-Gtqlayx8.js} +199 -173
- package/dist/logger-Gtqlayx8.js.map +1 -0
- package/dist/logs-view-CWG8aUAG.js.map +1 -1
- package/dist/{mcp-CgNd-f3F.js → mcp-_wecH9Qe.js} +608 -562
- package/dist/mcp-_wecH9Qe.js.map +1 -0
- package/dist/mcp.d.ts +2 -2
- package/dist/mcp.js +2 -2
- package/dist/media-sniff-UKijEaiQ.js.map +1 -1
- package/dist/{messages-2jcOA_5R.js → messages-BqiwcD2Q.js} +1017 -1014
- package/dist/messages-BqiwcD2Q.js.map +1 -0
- package/dist/{oauth-DxHO17JE.js → oauth-Px_pBB9W.js} +5 -5
- package/dist/{oauth-DxHO17JE.js.map → oauth-Px_pBB9W.js.map} +1 -1
- package/dist/{openai-compat-Dy56weK8.js → openai-compat-CFrpH7uq.js} +432 -589
- package/dist/openai-compat-CFrpH7uq.js.map +1 -0
- package/dist/orchestration-BCGmB8Ps.js +511 -0
- package/dist/orchestration-BCGmB8Ps.js.map +1 -0
- package/dist/output/stream-json.d.ts +1 -2
- package/dist/output/stream-json.d.ts.map +1 -1
- package/dist/output/stream-json.js +1 -1
- package/dist/output/terminal.d.ts +1 -2
- package/dist/output/terminal.d.ts.map +1 -1
- package/dist/output/terminal.js +13 -7
- package/dist/output/terminal.js.map +1 -1
- package/dist/{plugins-gbI7SBA6.js → plugins-DS7mahzZ.js} +20 -101
- package/dist/plugins-DS7mahzZ.js.map +1 -0
- package/dist/plugins.d.ts +1 -1
- package/dist/plugins.js +1 -2
- package/dist/prelude-Cxo4t74B.js +517 -0
- package/dist/prelude-Cxo4t74B.js.map +1 -0
- package/dist/presets.d.ts +1 -1
- package/dist/presets.js +1 -2
- package/dist/project-root-B8zADr4o.js +167 -0
- package/dist/project-root-B8zADr4o.js.map +1 -0
- package/dist/project-user-paths-BSgtrRxl.js +58 -0
- package/dist/project-user-paths-BSgtrRxl.js.map +1 -0
- package/dist/{prompts-Pqc3JdW_.d.ts → prompts-DYcvqShf.d.ts} +14 -11
- package/dist/prompts-DYcvqShf.d.ts.map +1 -0
- package/dist/protocol-DnhqqSmE.js +13 -0
- package/dist/protocol-DnhqqSmE.js.map +1 -0
- package/dist/providers/anthropic.d.ts +2 -2
- package/dist/providers/anthropic.js +1 -2
- package/dist/providers/arcee.d.ts +1 -1
- package/dist/providers/arcee.js +1 -1
- package/dist/providers/baseten.d.ts +1 -1
- package/dist/providers/baseten.js +1 -1
- package/dist/providers/cerebras.d.ts +1 -1
- package/dist/providers/cerebras.js +3 -2
- package/dist/providers/cerebras.js.map +1 -1
- package/dist/providers/local.d.ts +1 -1
- package/dist/providers/local.js +1 -1
- package/dist/providers/openai-compat.d.ts +1 -1
- package/dist/providers/openai-compat.js +1 -2
- package/dist/providers/openai.d.ts +1 -1
- package/dist/providers/openai.js +15 -12
- package/dist/providers/openai.js.map +1 -1
- package/dist/providers/openrouter.d.ts +1 -1
- package/dist/providers/openrouter.js +3 -2
- package/dist/providers/openrouter.js.map +1 -1
- package/dist/providers/xai.d.ts +1 -1
- package/dist/providers/xai.js +3 -3
- package/dist/{providers-BVhnFyiY.js → providers-XUR7F4Hi.js} +4 -4
- package/dist/{providers-BVhnFyiY.js.map → providers-XUR7F4Hi.js.map} +1 -1
- package/dist/providers.d.ts +1 -1
- package/dist/providers.js +4 -4
- package/dist/registry-D6ShBWJU.js +5234 -0
- package/dist/registry-D6ShBWJU.js.map +1 -0
- package/dist/remote-hosts-BtA_9ZGp.js +97 -0
- package/dist/remote-hosts-BtA_9ZGp.js.map +1 -0
- package/dist/restate.d.ts +2 -3
- package/dist/restate.d.ts.map +1 -1
- package/dist/restate.js +631 -572
- package/dist/restate.js.map +1 -1
- package/dist/run-summary-CklLiZ4y.js +288 -0
- package/dist/run-summary-CklLiZ4y.js.map +1 -0
- package/dist/{sandbox-BH0WQkXn.d.ts → sandbox-C5dR5DwQ.d.ts} +6 -3
- package/dist/sandbox-C5dR5DwQ.d.ts.map +1 -0
- package/dist/session/sqlite.d.ts +1 -2
- package/dist/session/sqlite.d.ts.map +1 -1
- package/dist/session/sqlite.js +1 -616
- package/dist/session-factory-BUGY5P40.js +1576 -0
- package/dist/session-factory-BUGY5P40.js.map +1 -0
- package/dist/{session-BqRP1hS7.js → session-xh9JXu6i.js} +94 -52
- package/dist/session-xh9JXu6i.js.map +1 -0
- package/dist/session.d.ts +1 -1
- package/dist/session.js +2 -2
- package/dist/settings-keys-Ckf29NeM.js +677 -0
- package/dist/settings-keys-Ckf29NeM.js.map +1 -0
- package/dist/shell-path-Dqaoow2J.js +412 -0
- package/dist/shell-path-Dqaoow2J.js.map +1 -0
- package/dist/{skills-BC3dodWp.js → skills-DKqZJm4X.js} +430 -470
- package/dist/skills-DKqZJm4X.js.map +1 -0
- package/dist/skills.d.ts +2 -2
- package/dist/skills.js +1 -2
- package/dist/source-mPExaUm8.js +381 -0
- package/dist/source-mPExaUm8.js.map +1 -0
- package/dist/sqlite-DV1DQzN2.js +698 -0
- package/dist/sqlite-DV1DQzN2.js.map +1 -0
- package/dist/{src-CkNQKFKr.js → src-BRMYRJib.js} +903 -1121
- package/dist/src-BRMYRJib.js.map +1 -0
- package/dist/{stdio-DPpBDPx5.js → stdio-C6YyoW3I.js} +4 -4
- package/dist/{stdio-DPpBDPx5.js.map → stdio-C6YyoW3I.js.map} +1 -1
- package/dist/{stdio-loader-Bbx19dMZ.js → stdio-loader-C830Vg-Z.js} +4 -4
- package/dist/{stdio-loader-Bbx19dMZ.js.map → stdio-loader-C830Vg-Z.js.map} +1 -1
- package/dist/system-prompt-MNVHatSD.d.ts.map +1 -1
- package/dist/timeout-DEaqslLO.d.ts.map +1 -1
- package/dist/todo-edits-Dn251YUP.js +1790 -0
- package/dist/todo-edits-Dn251YUP.js.map +1 -0
- package/dist/{turn-operations-DrbJlpq9.js → tool-formatters-IQFDrdrs.js} +1456 -2120
- package/dist/tool-formatters-IQFDrdrs.js.map +1 -0
- package/dist/tool-state-Dku6YqAB.js +989 -0
- package/dist/tool-state-Dku6YqAB.js.map +1 -0
- package/dist/tools/fetch-url.d.ts +1 -2
- package/dist/tools/fetch-url.d.ts.map +1 -1
- package/dist/tools/fetch-url.js +1 -2
- package/dist/tools/prompts.d.ts +1 -1
- package/dist/tools/prompts.js +7 -7
- package/dist/tools/prompts.js.map +1 -1
- package/dist/tools/web-search.d.ts +1 -2
- package/dist/tools/web-search.d.ts.map +1 -1
- package/dist/tools/web-search.js +2 -2
- package/dist/tools/web-search.js.map +1 -1
- package/dist/tools-_DnT3AGM.js +578 -0
- package/dist/tools-_DnT3AGM.js.map +1 -0
- package/dist/tools.d.ts +3 -3
- package/dist/tools.js +4 -2
- package/dist/tui.d.ts +534 -517
- package/dist/tui.d.ts.map +1 -1
- package/dist/tui.js +34933 -27242
- package/dist/tui.js.map +1 -1
- package/dist/turn-operations-B8sokwi5.js +333 -0
- package/dist/turn-operations-B8sokwi5.js.map +1 -0
- package/dist/turn-operations-DQX5ZZni.d.ts +3089 -0
- package/dist/turn-operations-DQX5ZZni.d.ts.map +1 -0
- package/dist/types-C7ZFOztE.d.ts +132 -0
- package/dist/types-C7ZFOztE.d.ts.map +1 -0
- package/dist/types-CH5XpIHw.js +114 -0
- package/dist/types-CH5XpIHw.js.map +1 -0
- package/dist/{types-CWgENVLY.js → types-Cu0ZGDu9.js} +10 -6
- package/dist/types-Cu0ZGDu9.js.map +1 -0
- package/dist/types-IqegbJEE.d.ts +624 -0
- package/dist/types-IqegbJEE.d.ts.map +1 -0
- package/dist/types.d.ts +4 -4
- package/dist/types.js +1 -1
- package/dist/url-D8HCl65b.js +1259 -0
- package/dist/url-D8HCl65b.js.map +1 -0
- package/dist/wasm-BVT-j5cl.js +33 -0
- package/dist/wasm-BVT-j5cl.js.map +1 -0
- package/dist/workspace-exec-stream-SV2R9d5S.js +355 -0
- package/dist/workspace-exec-stream-SV2R9d5S.js.map +1 -0
- package/dist/ws-CIHMvlSh.js +952 -0
- package/dist/ws-CIHMvlSh.js.map +1 -0
- package/dist/ws-client-N7NxzvQp.js +230 -0
- package/dist/ws-client-N7NxzvQp.js.map +1 -0
- package/dist/{xai-CazjStOK.js → xai-CvJTeLrI.js} +165 -5
- package/dist/xai-CvJTeLrI.js.map +1 -0
- package/dist/xdg-zweed0-t.js +117 -0
- package/dist/xdg-zweed0-t.js.map +1 -0
- package/docs/ACP.md +52 -0
- package/docs/ARCHITECTURE.md +103 -6
- package/docs/ARTIFACTS.md +8 -4
- package/docs/CHAT.md +165 -14
- package/docs/EXECUTION_CONTEXT.md +8 -0
- package/docs/EXTENSIONS.md +123 -2
- package/docs/HEADLESS.md +2 -0
- package/docs/IPC.md +775 -64
- package/docs/MACHINES.md +456 -0
- package/docs/PANELS.md +3 -0
- package/docs/README.md +4 -0
- package/docs/RESTATE.md +3 -2
- package/docs/RUN_IN_BACKGROUND.md +10 -2
- package/docs/SERVER.md +1085 -0
- package/docs/SKILL.md +6 -1
- package/docs/TERMINAL.md +75 -0
- package/docs/TUI.md +65 -14
- package/package.json +58 -26
- package/scripts/eval.ts +4 -0
- package/dist/acp-D-tVyUjw.js.map +0 -1
- package/dist/agent-D0zZnGbt.js.map +0 -1
- package/dist/anthropic-C2aole0G.js.map +0 -1
- package/dist/approvals-DKaJZYlm.js.map +0 -1
- package/dist/atomic-write-B7zr1ddF.js.map +0 -1
- package/dist/auth-BG2rVKSt.js.map +0 -1
- package/dist/completion-core-BRo86R_L.js.map +0 -1
- package/dist/contexts/daytona.js.map +0 -1
- package/dist/contexts/docker.js.map +0 -1
- package/dist/contexts/e2b.js.map +0 -1
- package/dist/contexts-CRE9pw07.js.map +0 -1
- package/dist/eval.js.map +0 -1
- package/dist/format-BF745pLL.js.map +0 -1
- package/dist/glob-DluQFSw1.js +0 -270
- package/dist/glob-DluQFSw1.js.map +0 -1
- package/dist/headless.js.map +0 -1
- package/dist/history-search-C4bk1Wz_.js.map +0 -1
- package/dist/index-BgN1T3lk.d.ts.map +0 -1
- package/dist/index-C37_ppWv.d.ts.map +0 -1
- package/dist/index-C6NEd5y_.d.ts.map +0 -1
- package/dist/ipc-zVSyo6K1.js +0 -331
- package/dist/ipc-zVSyo6K1.js.map +0 -1
- package/dist/ipc.d.ts.map +0 -1
- package/dist/isolation-Kfoof0MM.d.ts.map +0 -1
- package/dist/json-rpc-rSWMUh9b.js +0 -192
- package/dist/json-rpc-rSWMUh9b.js.map +0 -1
- package/dist/logger--C1VQjwJ.js.map +0 -1
- package/dist/mcp-CgNd-f3F.js.map +0 -1
- package/dist/messages-2jcOA_5R.js.map +0 -1
- package/dist/openai-compat-Dy56weK8.js.map +0 -1
- package/dist/output-cap-C9zukcCj.js +0 -100
- package/dist/output-cap-C9zukcCj.js.map +0 -1
- package/dist/panels-B6gRk4bf.js +0 -789
- package/dist/panels-B6gRk4bf.js.map +0 -1
- package/dist/plugins-gbI7SBA6.js.map +0 -1
- package/dist/prompts-Pqc3JdW_.d.ts.map +0 -1
- package/dist/run-summary-BU_NgwUT.js +0 -269
- package/dist/run-summary-BU_NgwUT.js.map +0 -1
- package/dist/sandbox-BH0WQkXn.d.ts.map +0 -1
- package/dist/session/sqlite.js.map +0 -1
- package/dist/session-BqRP1hS7.js.map +0 -1
- package/dist/shell-path-h5czzllR.js +0 -1549
- package/dist/shell-path-h5czzllR.js.map +0 -1
- package/dist/skills-BC3dodWp.js.map +0 -1
- package/dist/src-CkNQKFKr.js.map +0 -1
- package/dist/todo-edits-UOwgxGKu.js +0 -528
- package/dist/todo-edits-UOwgxGKu.js.map +0 -1
- package/dist/tool-formatters-DoRLnfuD.d.ts +0 -759
- package/dist/tool-formatters-DoRLnfuD.d.ts.map +0 -1
- package/dist/transcript-anchors-BeudMbXx.d.ts +0 -1762
- package/dist/transcript-anchors-BeudMbXx.d.ts.map +0 -1
- package/dist/turn-operations-C8bMBDl_.d.ts +0 -1258
- package/dist/turn-operations-C8bMBDl_.d.ts.map +0 -1
- package/dist/turn-operations-DrbJlpq9.js.map +0 -1
- package/dist/types-CWgENVLY.js.map +0 -1
- package/dist/xai-CazjStOK.js.map +0 -1
package/dist/restate.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
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
|
|
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:
|
|
156
|
+
compactThreshold: 131072,
|
|
156
157
|
compactKeepTurns: 8,
|
|
157
158
|
elideStaleReads: "stub",
|
|
158
|
-
|
|
159
|
-
|
|
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
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
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
|
-
|
|
417
|
-
|
|
418
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
const
|
|
1011
|
-
const
|
|
1012
|
-
const
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
callId:
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
...
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
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
|
-
|
|
1047
|
-
|
|
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
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
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
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
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
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
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
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
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
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
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
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
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
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
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
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
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
|
|
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)];
|