@markusylisiurunen/tau 0.3.32 → 0.3.34

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 (343) hide show
  1. package/README.md +15 -20
  2. package/dist/core/agent/agent_runtime.js +1551 -0
  3. package/dist/core/agent/agent_runtime.js.map +1 -0
  4. package/dist/core/agent/events.js +2 -0
  5. package/dist/core/agent/events.js.map +1 -0
  6. package/dist/core/commands/registry.js +0 -42
  7. package/dist/core/commands/registry.js.map +1 -1
  8. package/dist/core/config/content_loader.js +7 -3
  9. package/dist/core/config/content_loader.js.map +1 -1
  10. package/dist/core/index.js +3 -2
  11. package/dist/core/index.js.map +1 -1
  12. package/dist/core/models/catalog.js +7 -1
  13. package/dist/core/models/catalog.js.map +1 -1
  14. package/dist/core/models/tau_model_overrides.js +10 -0
  15. package/dist/core/models/tau_model_overrides.js.map +1 -0
  16. package/dist/core/modes/index.js.map +1 -1
  17. package/dist/core/personas.js +4 -2
  18. package/dist/core/personas.js.map +1 -1
  19. package/dist/core/runtime/agent_model.js +50 -0
  20. package/dist/core/runtime/agent_model.js.map +1 -0
  21. package/dist/core/runtime/chat_runtime.js +175 -63
  22. package/dist/core/runtime/chat_runtime.js.map +1 -1
  23. package/dist/core/runtime/model_executor.js +2 -0
  24. package/dist/core/runtime/model_executor.js.map +1 -0
  25. package/dist/core/runtime/model_sampler.js +21 -0
  26. package/dist/core/runtime/model_sampler.js.map +1 -0
  27. package/dist/core/session/auto_compaction_archive.js +239 -0
  28. package/dist/core/session/auto_compaction_archive.js.map +1 -0
  29. package/dist/core/session/compaction.js +97 -29
  30. package/dist/core/session/compaction.js.map +1 -1
  31. package/dist/core/session/direct_bash.js.map +1 -1
  32. package/dist/core/session/message_accumulator.js +3 -5
  33. package/dist/core/session/message_accumulator.js.map +1 -1
  34. package/dist/core/session/runner.js +274 -102
  35. package/dist/core/session/runner.js.map +1 -1
  36. package/dist/core/subagents/agent_supervisor.js +378 -0
  37. package/dist/core/subagents/agent_supervisor.js.map +1 -0
  38. package/dist/core/subagents/format.js +101 -0
  39. package/dist/core/subagents/format.js.map +1 -0
  40. package/dist/core/subagents/registry.js +3 -1
  41. package/dist/core/subagents/registry.js.map +1 -1
  42. package/dist/core/subagents/types.js +1 -0
  43. package/dist/core/subagents/types.js.map +1 -1
  44. package/dist/core/tools/activity.js +2 -0
  45. package/dist/core/tools/activity.js.map +1 -0
  46. package/dist/core/tools/bash.js +64 -67
  47. package/dist/core/tools/bash.js.map +1 -1
  48. package/dist/core/tools/catalog.js +49 -25
  49. package/dist/core/tools/catalog.js.map +1 -1
  50. package/dist/core/tools/code_mode.js +65 -58
  51. package/dist/core/tools/code_mode.js.map +1 -1
  52. package/dist/core/tools/edit.js +11 -12
  53. package/dist/core/tools/edit.js.map +1 -1
  54. package/dist/core/tools/interrupt_agent.js +119 -0
  55. package/dist/core/tools/interrupt_agent.js.map +1 -0
  56. package/dist/core/tools/list_agents.js +64 -0
  57. package/dist/core/tools/list_agents.js.map +1 -0
  58. package/dist/core/tools/nook.js +3 -2
  59. package/dist/core/tools/nook.js.map +1 -1
  60. package/dist/core/tools/registry.js +27 -13
  61. package/dist/core/tools/registry.js.map +1 -1
  62. package/dist/core/tools/send_input_to_agent.js +77 -93
  63. package/dist/core/tools/send_input_to_agent.js.map +1 -1
  64. package/dist/core/tools/spawn_agent.js +94 -114
  65. package/dist/core/tools/spawn_agent.js.map +1 -1
  66. package/dist/core/tools/tool_names.js +4 -2
  67. package/dist/core/tools/tool_names.js.map +1 -1
  68. package/dist/core/tools/view_image.js +11 -16
  69. package/dist/core/tools/view_image.js.map +1 -1
  70. package/dist/core/tools/wait_for_agents.js +76 -137
  71. package/dist/core/tools/wait_for_agents.js.map +1 -1
  72. package/dist/core/tools/web.js +3 -3
  73. package/dist/core/tools/web.js.map +1 -1
  74. package/dist/core/tools/write.js +10 -11
  75. package/dist/core/tools/write.js.map +1 -1
  76. package/dist/core/usage/logs.js.map +1 -1
  77. package/dist/core/utils/compact.js +19 -10
  78. package/dist/core/utils/compact.js.map +1 -1
  79. package/dist/core/utils/subagent_utils.js.map +1 -1
  80. package/dist/core/version.js +1 -1
  81. package/dist/diff_tool/app/dist/assets/actionscript-3-Cs6JJXT5.js +1 -0
  82. package/dist/diff_tool/app/dist/assets/ahk-CA9gdOdF.js +1 -0
  83. package/dist/diff_tool/app/dist/assets/ahk2-_6rzW9BS.js +1 -0
  84. package/dist/diff_tool/app/dist/assets/{angular-html-DbgxQryr.js → angular-html-vSIwre92.js} +1 -1
  85. package/dist/diff_tool/app/dist/assets/{angular-ts-Dzjq8SvI.js → angular-ts-B9yWa-IT.js} +1 -1
  86. package/dist/diff_tool/app/dist/assets/apex-KFGFyKwG.js +1 -0
  87. package/dist/diff_tool/app/dist/assets/{apl-6AmEMJr-.js → apl-CBg9ewu1.js} +1 -1
  88. package/dist/diff_tool/app/dist/assets/asciidoc-SCjQUq34.js +1 -0
  89. package/dist/diff_tool/app/dist/assets/{astro-BM8EbfIg.js → astro-BVjxSYjj.js} +1 -1
  90. package/dist/diff_tool/app/dist/assets/{bat-Bo4NYOV-.js → bat-qdxAdBWQ.js} +1 -1
  91. package/dist/diff_tool/app/dist/assets/bird2-CYIUgYqB.js +1 -0
  92. package/dist/diff_tool/app/dist/assets/{blade-DiKMnN3e.js → blade-jvqV5kiv.js} +1 -1
  93. package/dist/diff_tool/app/dist/assets/bsl-_VjlB9mv.js +1 -0
  94. package/dist/diff_tool/app/dist/assets/{c-DMT5X-u9.js → c-DDAfW08c.js} +1 -1
  95. package/dist/diff_tool/app/dist/assets/c3-D0apG41V.js +1 -0
  96. package/dist/diff_tool/app/dist/assets/catppuccin-frappe-C9Q5zVZY.js +1 -0
  97. package/dist/diff_tool/app/dist/assets/catppuccin-latte-CtsyrtPq.js +1 -0
  98. package/dist/diff_tool/app/dist/assets/catppuccin-macchiato-R8nAf1vR.js +1 -0
  99. package/dist/diff_tool/app/dist/assets/catppuccin-mocha-DjuaAJKi.js +1 -0
  100. package/dist/diff_tool/app/dist/assets/chapel-Qflwfgbt.js +1 -0
  101. package/dist/diff_tool/app/dist/assets/clarity-CtfBBspg.js +1 -0
  102. package/dist/diff_tool/app/dist/assets/{cobol-CACNMc1O.js → cobol-4iJI1LUg.js} +1 -1
  103. package/dist/diff_tool/app/dist/assets/{coffee-D_WUFE0g.js → coffee-C9LbGGO3.js} +1 -1
  104. package/dist/diff_tool/app/dist/assets/coq-DuBRPxYg.js +1 -0
  105. package/dist/diff_tool/app/dist/assets/cpp-B-x6veTx.js +1 -0
  106. package/dist/diff_tool/app/dist/assets/{crystal-wh93mtUe.js → crystal-S06EUmKn.js} +1 -1
  107. package/dist/diff_tool/app/dist/assets/{css-CCfuUqEr.js → css-DA4RYriG.js} +1 -1
  108. package/dist/diff_tool/app/dist/assets/{edge-DP-spcJf.js → edge-7dx6BjGp.js} +1 -1
  109. package/dist/diff_tool/app/dist/assets/{elixir-BXBkaEtJ.js → elixir-DPywG97a.js} +1 -1
  110. package/dist/diff_tool/app/dist/assets/{elm-BXr8OwKP.js → elm-Dgo_WnqC.js} +1 -1
  111. package/dist/diff_tool/app/dist/assets/emacs-lisp-c_oH4hRZ.js +1 -0
  112. package/dist/diff_tool/app/dist/assets/{erb-Cu5Zacs_.js → erb-CVW4PjFl.js} +1 -1
  113. package/dist/diff_tool/app/dist/assets/{gdresource-C0sCabJj.js → gdresource-xMC7jr7x.js} +1 -1
  114. package/dist/diff_tool/app/dist/assets/gdscript-DYvRD3hg.js +1 -0
  115. package/dist/diff_tool/app/dist/assets/{git-rebase-DO8LWld4.js → git-rebase-CtU0gmBJ.js} +1 -1
  116. package/dist/diff_tool/app/dist/assets/{glimmer-js-Bh-OAIDW.js → glimmer-js-twAYiPP2.js} +1 -1
  117. package/dist/diff_tool/app/dist/assets/{glimmer-ts-DI9lHU4q.js → glimmer-ts-BfNoXayN.js} +1 -1
  118. package/dist/diff_tool/app/dist/assets/{glsl--zoY4RCO.js → glsl-D_XrtFF7.js} +1 -1
  119. package/dist/diff_tool/app/dist/assets/{graphql-C8h2T_SC.js → graphql-B_GeapzM.js} +1 -1
  120. package/dist/diff_tool/app/dist/assets/hack-BCaCVoSX.js +1 -0
  121. package/dist/diff_tool/app/dist/assets/{haml-C2BBBsDW.js → haml-z9Mz7I1O.js} +1 -1
  122. package/dist/diff_tool/app/dist/assets/{handlebars-cZMztphK.js → handlebars-D0FVYagc.js} +1 -1
  123. package/dist/diff_tool/app/dist/assets/haxe-C8oCnwJJ.js +1 -0
  124. package/dist/diff_tool/app/dist/assets/{html-BtccomkJ.js → html-BOM4tb7u.js} +1 -1
  125. package/dist/diff_tool/app/dist/assets/{html-derivative-qjeUe52-.js → html-derivative-CsSlhJgr.js} +1 -1
  126. package/dist/diff_tool/app/dist/assets/{http-Dv8OQO33.js → http-Cjy9oaQn.js} +1 -1
  127. package/dist/diff_tool/app/dist/assets/{hurl-B6Fnr2ae.js → hurl-CjLQ7ql5.js} +1 -1
  128. package/dist/diff_tool/app/dist/assets/hxml-Dcm88srW.js +1 -0
  129. package/dist/diff_tool/app/dist/assets/index-QO81yN6b.js +1550 -0
  130. package/dist/diff_tool/app/dist/assets/{java-BuadWMcp.js → java-cn8DiFD8.js} +1 -1
  131. package/dist/diff_tool/app/dist/assets/{javascript-BIKxmHeL.js → javascript-CEnHZaZM.js} +1 -1
  132. package/dist/diff_tool/app/dist/assets/{jinja-Cm_guvgu.js → jinja-DIp6kVk7.js} +1 -1
  133. package/dist/diff_tool/app/dist/assets/{jison-Sst29gJb.js → jison-Dx116ito.js} +1 -1
  134. package/dist/diff_tool/app/dist/assets/{json-Bg6l2vym.js → json-C6B9h0n5.js} +1 -1
  135. package/dist/diff_tool/app/dist/assets/{jsx-BiREAxkr.js → jsx-CDEGT2B2.js} +1 -1
  136. package/dist/diff_tool/app/dist/assets/{julia-DAhrWFzr.js → julia-CsIJA3Km.js} +1 -1
  137. package/dist/diff_tool/app/dist/assets/{just-xBwbf5aT.js → just-DZRYvkQw.js} +1 -1
  138. package/dist/diff_tool/app/dist/assets/kanagawa-dragon-Bozd7klA.js +1 -0
  139. package/dist/diff_tool/app/dist/assets/kanagawa-lotus-BmuOG9ZW.js +1 -0
  140. package/dist/diff_tool/app/dist/assets/kanagawa-wave-BML5mF2J.js +1 -0
  141. package/dist/diff_tool/app/dist/assets/latex-CeR-RQOI.js +1 -0
  142. package/dist/diff_tool/app/dist/assets/{liquid-BTsCzVvF.js → liquid-Dhf8N4mn.js} +1 -1
  143. package/dist/diff_tool/app/dist/assets/{llvm-Cm23YOpf.js → llvm-DqHOMS-s.js} +1 -1
  144. package/dist/diff_tool/app/dist/assets/{lua-BJt9x0JP.js → lua-zVTVaJzn.js} +1 -1
  145. package/dist/diff_tool/app/dist/assets/luau-C2pBCSgt.js +1 -0
  146. package/dist/diff_tool/app/dist/assets/{marko-CWdJkbvC.js → marko-BGPq5r3o.js} +1 -1
  147. package/dist/diff_tool/app/dist/assets/mdc-D8K78bym.js +1 -0
  148. package/dist/diff_tool/app/dist/assets/mermaid-BxpfTIzt.js +1 -0
  149. package/dist/diff_tool/app/dist/assets/mojo-CFuIV2fl.js +1 -0
  150. package/dist/diff_tool/app/dist/assets/monokai-B_bV9PQ9.js +1 -0
  151. package/dist/diff_tool/app/dist/assets/moonbit-DgjMoLWr.js +1 -0
  152. package/dist/diff_tool/app/dist/assets/move-BYnGhZoM.js +1 -0
  153. package/dist/diff_tool/app/dist/assets/{nginx-BwS0G4IK.js → nginx-Bo-bEa75.js} +1 -1
  154. package/dist/diff_tool/app/dist/assets/{nim-B2VFbcs9.js → nim-Bfy5M54r.js} +1 -1
  155. package/dist/diff_tool/app/dist/assets/nsis-CjNLYCLg.js +1 -0
  156. package/dist/diff_tool/app/dist/assets/nushell-DHYfO66s.js +1 -0
  157. package/dist/diff_tool/app/dist/assets/org-BKetN7sT.js +1 -0
  158. package/dist/diff_tool/app/dist/assets/{perl-BTeqR-l8.js → perl-WiwTOQTV.js} +1 -1
  159. package/dist/diff_tool/app/dist/assets/{php-Crua7nbA.js → php-CM2FzhGV.js} +1 -1
  160. package/dist/diff_tool/app/dist/assets/{powershell-DshXNtvi.js → powershell-CCSX75yM.js} +1 -1
  161. package/dist/diff_tool/app/dist/assets/prisma-DMgNhnYS.js +1 -0
  162. package/dist/diff_tool/app/dist/assets/{pug-CUlgPjMU.js → pug-D2WvUHZ-.js} +1 -1
  163. package/dist/diff_tool/app/dist/assets/{qml-DI0IjNUw.js → qml-DGPbc6TL.js} +1 -1
  164. package/dist/diff_tool/app/dist/assets/r-CCFYJ_KM.js +1 -0
  165. package/dist/diff_tool/app/dist/assets/{razor-DrkKtFm5.js → razor-D1JuQWQz.js} +1 -1
  166. package/dist/diff_tool/app/dist/assets/rbs-C0MpOrj4.js +1 -0
  167. package/dist/diff_tool/app/dist/assets/red-DX1BQOs8.js +1 -0
  168. package/dist/diff_tool/app/dist/assets/{regexp-DRmxJil7.js → regexp-zTiHwMow.js} +1 -1
  169. package/dist/diff_tool/app/dist/assets/rose-pine-aMsaMD1D.js +1 -0
  170. package/dist/diff_tool/app/dist/assets/rose-pine-dawn-8PwUyIlP.js +1 -0
  171. package/dist/diff_tool/app/dist/assets/rose-pine-moon-DO-qXg-I.js +1 -0
  172. package/dist/diff_tool/app/dist/assets/{rst-DiRke36z.js → rst-CuUAArfH.js} +1 -1
  173. package/dist/diff_tool/app/dist/assets/{ruby-t7r9jzAg.js → ruby-DznrLCoG.js} +1 -1
  174. package/dist/diff_tool/app/dist/assets/{sas-CR7Z4kg-.js → sas-D2hJmLva.js} +1 -1
  175. package/dist/diff_tool/app/dist/assets/{scala-DKOlJaKm.js → scala-BiFt_7mu.js} +1 -1
  176. package/dist/diff_tool/app/dist/assets/{scss--CnPWaDv.js → scss-Cjb3p_6n.js} +1 -1
  177. package/dist/diff_tool/app/dist/assets/{shellscript-Bz7H5174.js → shellscript-BtwI-tfX.js} +1 -1
  178. package/dist/diff_tool/app/dist/assets/{shellsession-mlKnHJfN.js → shellsession-BYirS1xP.js} +1 -1
  179. package/dist/diff_tool/app/dist/assets/smalltalk-BHpQb5nM.js +1 -0
  180. package/dist/diff_tool/app/dist/assets/smithy-Dgaz7aur.js +1 -0
  181. package/dist/diff_tool/app/dist/assets/solarized-dark-UdsmMDCL.js +1 -0
  182. package/dist/diff_tool/app/dist/assets/solarized-light-C1IUL_tW.js +1 -0
  183. package/dist/diff_tool/app/dist/assets/solidity-Bj7E1mRn.js +1 -0
  184. package/dist/diff_tool/app/dist/assets/{soy-CKu9y9G1.js → soy-D4Ndk7-j.js} +1 -1
  185. package/dist/diff_tool/app/dist/assets/{sql-DcvKi3Jj.js → sql-DbLQ5SJl.js} +1 -1
  186. package/dist/diff_tool/app/dist/assets/{stata-Yo25QZyV.js → stata-BXoNBosJ.js} +1 -1
  187. package/dist/diff_tool/app/dist/assets/surrealql-toyTYnAL.js +1 -0
  188. package/dist/diff_tool/app/dist/assets/{svelte-BIhEVbnP.js → svelte-BEpa7pAW.js} +1 -1
  189. package/dist/diff_tool/app/dist/assets/swift-CyEgAFGc.js +1 -0
  190. package/dist/diff_tool/app/dist/assets/system-verilog-Dh5ihWbf.js +1 -0
  191. package/dist/diff_tool/app/dist/assets/{templ-D6FrV4mZ.js → templ-CZfW_RJI.js} +1 -1
  192. package/dist/diff_tool/app/dist/assets/tex-COemmIIu.js +1 -0
  193. package/dist/diff_tool/app/dist/assets/theming-B5HubD5i.js +1 -0
  194. package/dist/diff_tool/app/dist/assets/theming-BTK0wyKj.js +1 -0
  195. package/dist/diff_tool/app/dist/assets/theming-BTUlzJFw.js +1 -0
  196. package/dist/diff_tool/app/dist/assets/theming-BURFlYfV.js +1 -0
  197. package/dist/diff_tool/app/dist/assets/theming-BVZjihoZ.js +1 -0
  198. package/dist/diff_tool/app/dist/assets/theming-BWSkzMBn.js +1 -0
  199. package/dist/diff_tool/app/dist/assets/theming-BchIqPOb.js +1 -0
  200. package/dist/diff_tool/app/dist/assets/theming-CeLfRn2P.js +1 -0
  201. package/dist/diff_tool/app/dist/assets/theming-DMjwMSwU.js +1 -0
  202. package/dist/diff_tool/app/dist/assets/theming-QWGGdlwd.js +1 -0
  203. package/dist/diff_tool/app/dist/assets/{ts-tags-Kqn1PP6m.js → ts-tags-CMVUY_BA.js} +1 -1
  204. package/dist/diff_tool/app/dist/assets/{tsx-L3TEJWGL.js → tsx-BTvP6uzd.js} +1 -1
  205. package/dist/diff_tool/app/dist/assets/twig-DzP5RjJc.js +1 -0
  206. package/dist/diff_tool/app/dist/assets/{typescript-Dvc5RX4H.js → typescript-CQaGlMoX.js} +1 -1
  207. package/dist/diff_tool/app/dist/assets/{v-DETTlOr0.js → v-DBj4K9d_.js} +1 -1
  208. package/dist/diff_tool/app/dist/assets/{vb-Djn5o6TS.js → vb-DOwzaHZ0.js} +1 -1
  209. package/dist/diff_tool/app/dist/assets/verilog-B2gwz-sJ.js +1 -0
  210. package/dist/diff_tool/app/dist/assets/{vue-X1uI3I2A.js → vue-DaVWTtvb.js} +1 -1
  211. package/dist/diff_tool/app/dist/assets/{vue-html-BMpHEoeQ.js → vue-html-BA_OH0Xt.js} +1 -1
  212. package/dist/diff_tool/app/dist/assets/{vue-vine-DnTGaA4r.js → vue-vine-C_H4XbNR.js} +1 -1
  213. package/dist/diff_tool/app/dist/assets/{xml-QlPQXP0d.js → xml-1JLzpunp.js} +1 -1
  214. package/dist/diff_tool/app/dist/assets/{xsl-JpRU16Li.js → xsl-GtZi0Erj.js} +1 -1
  215. package/dist/diff_tool/app/dist/assets/{yaml-Djukn3_s.js → yaml-LueTtDDo.js} +1 -1
  216. package/dist/diff_tool/app/dist/index.html +1 -1
  217. package/dist/execution/execution_environment.js.map +1 -1
  218. package/dist/execution/tool_backend_execution_environment.js +1 -7
  219. package/dist/execution/tool_backend_execution_environment.js.map +1 -1
  220. package/dist/host/client_tool_broker.js +28 -21
  221. package/dist/host/client_tool_broker.js.map +1 -1
  222. package/dist/host/hosted_ephemeral_agent_session.js +109 -167
  223. package/dist/host/hosted_ephemeral_agent_session.js.map +1 -1
  224. package/dist/host/local_session_host.js +340 -248
  225. package/dist/host/local_session_host.js.map +1 -1
  226. package/dist/host/session_host.js.map +1 -1
  227. package/dist/host/session_protocol_handler.js +125 -105
  228. package/dist/host/session_protocol_handler.js.map +1 -1
  229. package/dist/main.js +10 -2
  230. package/dist/main.js.map +1 -1
  231. package/dist/protocol/index.d.ts +1 -1
  232. package/dist/protocol/session_protocol.d.ts +70 -36
  233. package/dist/protocol/session_protocol.js +235 -80
  234. package/dist/protocol/session_protocol.js.map +1 -1
  235. package/dist/sdk/index.d.ts +1 -1
  236. package/dist/sdk/index.js.map +1 -1
  237. package/dist/sdk/session.js +8 -25
  238. package/dist/sdk/session.js.map +1 -1
  239. package/dist/sdk/types.d.ts +4 -9
  240. package/dist/starter/prompts/approval-review-branch.md +7 -0
  241. package/dist/starter/prompts/approval-review-current-changes.md +7 -0
  242. package/dist/starter/prompts/approval-review-last-commit.md +7 -0
  243. package/dist/starter/skills/approval-review/SKILL.md +219 -0
  244. package/dist/store/file_session_store.js +13 -9
  245. package/dist/store/file_session_store.js.map +1 -1
  246. package/dist/store/session_snapshot_migrations.js +152 -0
  247. package/dist/store/session_snapshot_migrations.js.map +1 -0
  248. package/dist/tui/chat_controller/command_hints.js +0 -6
  249. package/dist/tui/chat_controller/command_hints.js.map +1 -1
  250. package/dist/tui/chat_view.js +19 -12
  251. package/dist/tui/chat_view.js.map +1 -1
  252. package/dist/tui/session_chat_app.js +0 -8
  253. package/dist/tui/session_chat_app.js.map +1 -1
  254. package/dist/tui/session_chat_controller.js +122 -178
  255. package/dist/tui/session_chat_controller.js.map +1 -1
  256. package/dist/tui/tool_ui_router.js +12 -226
  257. package/dist/tui/tool_ui_router.js.map +1 -1
  258. package/dist/tui/ui/bash_execution.js +3 -3
  259. package/dist/tui/ui/bash_execution.js.map +1 -1
  260. package/dist/tui/ui/chat_message_model.js +2 -2
  261. package/dist/tui/ui/chat_message_model.js.map +1 -1
  262. package/dist/tui/ui/subagent_panel.js +59 -26
  263. package/dist/tui/ui/subagent_panel.js.map +1 -1
  264. package/dist/tui/ui/tool_ui_model.js +2 -0
  265. package/dist/tui/ui/tool_ui_model.js.map +1 -0
  266. package/dist/tui/ui/tool_ui_registry.js +310 -36
  267. package/dist/tui/ui/tool_ui_registry.js.map +1 -1
  268. package/package.json +4 -4
  269. package/dist/core/events/types.js +0 -2
  270. package/dist/core/events/types.js.map +0 -1
  271. package/dist/core/modes/mode_adapter.js +0 -2
  272. package/dist/core/modes/mode_adapter.js.map +0 -1
  273. package/dist/core/runtime/conversation_turn_runtime.js +0 -88
  274. package/dist/core/runtime/conversation_turn_runtime.js.map +0 -1
  275. package/dist/core/session/core_session.js +0 -86
  276. package/dist/core/session/core_session.js.map +0 -1
  277. package/dist/core/session/pruning.js +0 -587
  278. package/dist/core/session/pruning.js.map +0 -1
  279. package/dist/core/session/session_engine.js +0 -1246
  280. package/dist/core/session/session_engine.js.map +0 -1
  281. package/dist/core/subagents/control_plane.js +0 -339
  282. package/dist/core/subagents/control_plane.js.map +0 -1
  283. package/dist/core/subagents/subagent_engine.js +0 -258
  284. package/dist/core/subagents/subagent_engine.js.map +0 -1
  285. package/dist/core/tools/terminate_agent.js +0 -162
  286. package/dist/core/tools/terminate_agent.js.map +0 -1
  287. package/dist/diff_tool/app/dist/assets/actionscript-3--17pq3dv.js +0 -1
  288. package/dist/diff_tool/app/dist/assets/apex-VAyPSnFM.js +0 -1
  289. package/dist/diff_tool/app/dist/assets/asciidoc-DE70LPWp.js +0 -1
  290. package/dist/diff_tool/app/dist/assets/bird2-C6vDhewU.js +0 -1
  291. package/dist/diff_tool/app/dist/assets/bsl-BkkzgIyY.js +0 -1
  292. package/dist/diff_tool/app/dist/assets/c3-BFHwR3_K.js +0 -1
  293. package/dist/diff_tool/app/dist/assets/catppuccin-frappe-3VR1Za6u.js +0 -1
  294. package/dist/diff_tool/app/dist/assets/catppuccin-latte-DwIHMF0Q.js +0 -1
  295. package/dist/diff_tool/app/dist/assets/catppuccin-macchiato-DYnBP6_5.js +0 -1
  296. package/dist/diff_tool/app/dist/assets/catppuccin-mocha-DYhrFGRu.js +0 -1
  297. package/dist/diff_tool/app/dist/assets/clarity-SemFz856.js +0 -1
  298. package/dist/diff_tool/app/dist/assets/coq-BrsZFFmf.js +0 -1
  299. package/dist/diff_tool/app/dist/assets/cpp-BcU9r9kv.js +0 -1
  300. package/dist/diff_tool/app/dist/assets/emacs-lisp-B4R74twV.js +0 -1
  301. package/dist/diff_tool/app/dist/assets/gdscript-Cp2uCuqX.js +0 -1
  302. package/dist/diff_tool/app/dist/assets/hack-DAsjGmmw.js +0 -1
  303. package/dist/diff_tool/app/dist/assets/haxe-OTjmBuCE.js +0 -1
  304. package/dist/diff_tool/app/dist/assets/hxml-B0Qn7Nwc.js +0 -1
  305. package/dist/diff_tool/app/dist/assets/index-U7G4V3LV.js +0 -1579
  306. package/dist/diff_tool/app/dist/assets/kanagawa-dragon-CXtmUGW6.js +0 -1
  307. package/dist/diff_tool/app/dist/assets/kanagawa-lotus-BN08jTvb.js +0 -1
  308. package/dist/diff_tool/app/dist/assets/kanagawa-wave-CTweb8Dz.js +0 -1
  309. package/dist/diff_tool/app/dist/assets/latex-Bydg2zYo.js +0 -1
  310. package/dist/diff_tool/app/dist/assets/luau-FMPmPwt6.js +0 -1
  311. package/dist/diff_tool/app/dist/assets/mdc-B6ddHTKx.js +0 -1
  312. package/dist/diff_tool/app/dist/assets/mermaid-Bk4SNUv9.js +0 -1
  313. package/dist/diff_tool/app/dist/assets/mojo-BgCJLMeH.js +0 -1
  314. package/dist/diff_tool/app/dist/assets/monokai-CdkpiU2Y.js +0 -1
  315. package/dist/diff_tool/app/dist/assets/moonbit-CaWjb8XO.js +0 -1
  316. package/dist/diff_tool/app/dist/assets/move-B1IS1UjX.js +0 -1
  317. package/dist/diff_tool/app/dist/assets/nushell-DcLAeLz5.js +0 -1
  318. package/dist/diff_tool/app/dist/assets/pierre-dark-CpLgRqie.js +0 -1
  319. package/dist/diff_tool/app/dist/assets/pierre-dark-protanopia-deuteranopia-B35FxJx-.js +0 -1
  320. package/dist/diff_tool/app/dist/assets/pierre-dark-soft-kZQmAZld.js +0 -1
  321. package/dist/diff_tool/app/dist/assets/pierre-dark-tritanopia-CpjhbsIL.js +0 -1
  322. package/dist/diff_tool/app/dist/assets/pierre-dark-vibrant-CpQYzh95.js +0 -1
  323. package/dist/diff_tool/app/dist/assets/pierre-light-CoaEpmwp.js +0 -1
  324. package/dist/diff_tool/app/dist/assets/pierre-light-protanopia-deuteranopia-0fSaH845.js +0 -1
  325. package/dist/diff_tool/app/dist/assets/pierre-light-soft-lWLdNTOI.js +0 -1
  326. package/dist/diff_tool/app/dist/assets/pierre-light-tritanopia-CEbqgOJL.js +0 -1
  327. package/dist/diff_tool/app/dist/assets/pierre-light-vibrant-D80Fkn33.js +0 -1
  328. package/dist/diff_tool/app/dist/assets/prisma-BsRQq5mF.js +0 -1
  329. package/dist/diff_tool/app/dist/assets/r-DRexFFDh.js +0 -1
  330. package/dist/diff_tool/app/dist/assets/red-CJ3rzSJv.js +0 -1
  331. package/dist/diff_tool/app/dist/assets/rose-pine-BthvhNj6.js +0 -1
  332. package/dist/diff_tool/app/dist/assets/rose-pine-dawn-Dg85fqjY.js +0 -1
  333. package/dist/diff_tool/app/dist/assets/rose-pine-moon-hon4tzzS.js +0 -1
  334. package/dist/diff_tool/app/dist/assets/smalltalk-B16xEiuN.js +0 -1
  335. package/dist/diff_tool/app/dist/assets/solarized-dark-DV17i1UV.js +0 -1
  336. package/dist/diff_tool/app/dist/assets/solarized-light-DSh2HLQt.js +0 -1
  337. package/dist/diff_tool/app/dist/assets/solidity-CKzVLygQ.js +0 -1
  338. package/dist/diff_tool/app/dist/assets/surrealql-CUddZ4Qk.js +0 -1
  339. package/dist/diff_tool/app/dist/assets/swift-DonLKvLd.js +0 -1
  340. package/dist/diff_tool/app/dist/assets/system-verilog-DJ5XKQeo.js +0 -1
  341. package/dist/diff_tool/app/dist/assets/tex-BOTYELrL.js +0 -1
  342. package/dist/diff_tool/app/dist/assets/twig-BpzmhnWz.js +0 -1
  343. package/dist/diff_tool/app/dist/assets/verilog-CiiDBU1e.js +0 -1
@@ -2,9 +2,12 @@ import { randomUUID } from "node:crypto";
2
2
  import { isDeepStrictEqual } from "node:util";
3
3
  import { resolvePromptTemplateWithBackend } from "../core/config/index.js";
4
4
  import { ChatRuntime } from "../core/runtime/chat_runtime.js";
5
+ import { SUBAGENT_ACTIVITY_FACET_KIND } from "../core/subagents/types.js";
6
+ import { appendUsageLogEntry, getUsageCostTotal, getUsageTotals, } from "../core/usage/logs.js";
5
7
  import { filterProjectPathAutocompleteEntries, loadProjectPathAutocompleteEntriesWithBackend, } from "../core/utils/project_files.js";
6
8
  import { hasAutoCompactionContinuationMetadata, isTauUserMessageHidden, } from "../core/utils/user_metadata.js";
7
9
  import { applySessionProtocolDelta, createSessionProtocolDeltaMessage, createSessionProtocolEphemeralMessage, } from "../protocol/session_protocol.js";
10
+ import { LEGACY_SESSION_CONTEXT_EPOCH } from "../store/session_snapshot_migrations.js";
8
11
  import { ClientToolBroker } from "./client_tool_broker.js";
9
12
  import { createExecutionEnvironmentSubagentRuntimeResolver } from "./execution_runtime.js";
10
13
  import { HostedEphemeralAgentSession } from "./hosted_ephemeral_agent_session.js";
@@ -61,12 +64,20 @@ export class LocalSessionHost {
61
64
  try {
62
65
  const recovered = normalizeRecoveredSnapshot(snapshot);
63
66
  hostedSession = await this.createLocalSessionHandle(executionEnvironment, recovered.snapshot, undefined, recovered.changed);
64
- hostedSession.session.restoreState({
65
- sessionId: recovered.snapshot.sessionId,
67
+ const agentRecovery = hostedSession.runtime.restoreState({
68
+ agentId: recovered.snapshot.sessionId,
69
+ revision: recovered.snapshot.agentState.revision,
70
+ contextEpoch: recovered.snapshot.agentState.contextEpoch,
66
71
  historyEntries: recovered.snapshot.messages.flatMap((entry) => entry.modelVisible && isCoreMessage(entry.message)
67
72
  ? [{ id: entry.id, message: entry.message }]
68
73
  : []),
74
+ ...(recovered.snapshot.agentState.usageCheckpoint
75
+ ? { usageCheckpoint: { ...recovered.snapshot.agentState.usageCheckpoint } }
76
+ : {}),
69
77
  });
78
+ if (recovered.changed || agentRecovery.recoveredToolResults.length > 0) {
79
+ await hostedSession.persistRecoveredAgentState(agentRecovery);
80
+ }
70
81
  return hostedSession;
71
82
  }
72
83
  catch (error) {
@@ -98,10 +109,11 @@ export class LocalSessionHost {
98
109
  return this.createLocalSessionHandleFromRuntimeContext(executionEnvironment, runtimeContext, bootstrap, catalog, committedSnapshot, forceNextSnapshotRevision);
99
110
  }
100
111
  createLocalSessionHandleFromRuntimeContext(executionEnvironment, runtimeContext, bootstrap, catalog, committedSnapshot, forceNextSnapshotRevision = false) {
112
+ let hostedSession;
101
113
  const runtime = ChatRuntime.create({
102
114
  persona: bootstrap.persona,
103
- toolRegistry: runtimeContext.toolRegistry,
104
- clientToolDefinitions: (sessionId) => this.clientToolBroker.getToolDefinitions(sessionId),
115
+ backend: executionEnvironment.getToolExecutionBackend(),
116
+ clientTools: (sessionId) => this.clientToolBroker.getToolDefinitions(sessionId),
105
117
  modelResolver: bootstrap.modelResolver,
106
118
  resolveSubagentRuntime: createExecutionEnvironmentSubagentRuntimeResolver({
107
119
  executionEnvironment,
@@ -110,13 +122,16 @@ export class LocalSessionHost {
110
122
  }),
111
123
  promptContext: runtimeContext.promptBootstrap.promptContext,
112
124
  environment: this.sessionOptions.environment,
125
+ eventSink: async (event) => await hostedSession.enqueueRuntimeEvent(event),
126
+ subagentEventSink: async (event) => await hostedSession.recordSubagentEvent(event),
113
127
  initialPromptComposition: committedSnapshot
114
128
  ? promptCompositionFromSnapshot(committedSnapshot)
115
129
  : undefined,
116
- config: bootstrap.config,
130
+ config: bootstrap.config ?? {},
131
+ recordUsage: this.sessionOptions.recordUsage,
117
132
  deps: this.sessionOptions.deps,
118
133
  });
119
- const hostedSession = new LocalHostedSessionHandle(runtime, runtimeContext.promptBootstrap, catalog, bootstrap, this.sessionOptions.includeAgentContext, executionEnvironment, this.store, committedSnapshot, forceNextSnapshotRevision, (session) => this.sessions.delete(session));
134
+ hostedSession = new LocalHostedSessionHandle(runtime, runtimeContext.promptBootstrap, catalog, bootstrap, this.sessionOptions.includeAgentContext, executionEnvironment, this.store, committedSnapshot, forceNextSnapshotRevision, this.sessionOptions.recordUsage ?? appendUsageLogEntry, (session) => this.sessions.delete(session));
120
135
  this.sessions.add(hostedSession);
121
136
  return hostedSession;
122
137
  }
@@ -304,6 +319,7 @@ class LocalHostedSessionHandle {
304
319
  includeAgentContext;
305
320
  executionEnvironment;
306
321
  store;
322
+ recordUsage;
307
323
  removeFromHost;
308
324
  session;
309
325
  committedSessionId;
@@ -324,7 +340,6 @@ class LocalHostedSessionHandle {
324
340
  ephemeralAgentSessions = new Map();
325
341
  pathAutocompleteCache;
326
342
  pathAutocompleteLoad;
327
- unsubscribeSubagentEvent;
328
343
  runtimeEventQueue = Promise.resolve();
329
344
  snapshotQueue = Promise.resolve();
330
345
  snapshotGeneration = 0;
@@ -337,7 +352,7 @@ class LocalHostedSessionHandle {
337
352
  costTotal = 0;
338
353
  forceNextSnapshotRevision;
339
354
  disposed = false;
340
- constructor(runtime, promptBootstrap, catalog, bootstrap, includeAgentContext, executionEnvironment, store, committedSnapshot, forceNextSnapshotRevision = false, removeFromHost = () => { }) {
355
+ constructor(runtime, promptBootstrap, catalog, bootstrap, includeAgentContext, executionEnvironment, store, committedSnapshot, forceNextSnapshotRevision, recordUsage, removeFromHost = () => { }) {
341
356
  this.runtime = runtime;
342
357
  this.promptBootstrap = promptBootstrap;
343
358
  this.catalog = catalog;
@@ -345,8 +360,9 @@ class LocalHostedSessionHandle {
345
360
  this.includeAgentContext = includeAgentContext;
346
361
  this.executionEnvironment = executionEnvironment;
347
362
  this.store = store;
363
+ this.recordUsage = recordUsage;
348
364
  this.removeFromHost = removeFromHost;
349
- this.session = runtime.session;
365
+ this.session = runtime;
350
366
  this.committedSessionId = committedSnapshot?.sessionId ?? this.session.sessionId;
351
367
  this.committedSnapshot = committedSnapshot
352
368
  ? cloneSessionProtocolSnapshot(committedSnapshot)
@@ -356,9 +372,6 @@ class LocalHostedSessionHandle {
356
372
  : undefined;
357
373
  this.forceNextSnapshotRevision = forceNextSnapshotRevision;
358
374
  this.restoreProtocolState(committedSnapshot);
359
- this.unsubscribeSubagentEvent = this.session.onSubagentEvent((event) => {
360
- void this.enqueueRuntimeEvent(event).catch(() => undefined);
361
- });
362
375
  }
363
376
  get isTurnRunning() {
364
377
  return this.runtime.isTurnRunning;
@@ -386,11 +399,9 @@ class LocalHostedSessionHandle {
386
399
  }
387
400
  async record(options) {
388
401
  this.assertActive();
389
- const userHistoryEntryId = this.session.addUserText(options.text, options.historyEntryId ? { historyEntryId: options.historyEntryId } : undefined);
390
- const snapshot = await this.commitSnapshot();
391
- this.emitSnapshotReset("user-message", snapshot);
402
+ const userHistoryEntryId = await this.session.commitUserText(options.text, options.historyEntryId ? { historyEntryId: options.historyEntryId } : undefined);
392
403
  return {
393
- snapshot,
404
+ snapshot: await this.snapshot(),
394
405
  userHistoryEntryId,
395
406
  };
396
407
  }
@@ -414,14 +425,8 @@ class LocalHostedSessionHandle {
414
425
  }
415
426
  let lastAssistantMessage;
416
427
  try {
417
- const result = await this.runtime.runTurn({
418
- onEvent: async (event) => {
419
- if (event.type === "assistant_final") {
420
- lastAssistantMessage = event.message;
421
- }
422
- await this.enqueueRuntimeEvent(event);
423
- },
424
- });
428
+ const result = await this.runtime.runTurn();
429
+ lastAssistantMessage = result.finalMessage;
425
430
  if (result.aborted && this.draftAssistantMessage) {
426
431
  await this.interruptDraftAssistantMessage();
427
432
  }
@@ -469,6 +474,33 @@ class LocalHostedSessionHandle {
469
474
  this.assertActive();
470
475
  return this.runtime.cancelTurnBoundaryStop();
471
476
  }
477
+ steer(text) {
478
+ this.assertActive();
479
+ if (!this.activeTurnPromise) {
480
+ throw new Error("cannot steer without an active turn");
481
+ }
482
+ const submission = this.runtime.steer(text);
483
+ return {
484
+ id: submission.id,
485
+ applied: submission.applied.then(async (association) => {
486
+ await this.commitSnapshot();
487
+ return { userHistoryEntryId: association.historyEntryId };
488
+ }),
489
+ result: submission.result.then(async (association) => {
490
+ const turn = turnOutcomeFromResult(association.result, association.result.finalMessage);
491
+ this.turnOutcomes.set(association.historyEntryId, turn);
492
+ await this.emitSnapshotResetIfChanged("assistant-message");
493
+ return {
494
+ userHistoryEntryId: association.historyEntryId,
495
+ turn,
496
+ };
497
+ }),
498
+ };
499
+ }
500
+ cancelSteering() {
501
+ this.assertActive();
502
+ return this.runtime.cancelSteering();
503
+ }
472
504
  async exec(options) {
473
505
  return await this.runExec(options.execId, options.signal, async (signal) => {
474
506
  const backend = this.executionEnvironment.getToolExecutionBackend();
@@ -505,26 +537,32 @@ class LocalHostedSessionHandle {
505
537
  }
506
538
  async setReasoning(reasoning) {
507
539
  this.assertActive();
508
- const fromRevision = this.committedSnapshot?.revision;
509
- this.runtime.setReasoning(reasoning);
510
- this.bootstrap.persona.settings.reasoning = reasoning;
511
- const snapshot = await this.commitSnapshot();
512
- if (fromRevision === undefined) {
513
- this.emitSnapshotReset("configuration", snapshot);
514
- }
515
- else if (snapshot.revision !== fromRevision) {
516
- this.emitDelta(createSessionProtocolDeltaMessage({
517
- sessionId: snapshot.sessionId,
518
- fromRevision: snapshot.revision - 1,
519
- toRevision: snapshot.revision,
520
- reason: "configuration",
521
- delta: {
522
- type: "snapshot.patch",
523
- changes: [{ type: "settings.set", settings: snapshot.settings }],
524
- },
525
- }));
526
- }
527
- return { revision: snapshot.revision, settings: snapshot.settings };
540
+ const write = this.runtimeEventQueue
541
+ .catch(() => undefined)
542
+ .then(async () => {
543
+ const fromRevision = this.committedSnapshot?.revision;
544
+ this.runtime.setReasoning(reasoning);
545
+ this.bootstrap.persona.settings.reasoning = reasoning;
546
+ const snapshot = await this.commitSnapshot();
547
+ if (fromRevision === undefined) {
548
+ this.emitSnapshotReset("configuration", snapshot);
549
+ }
550
+ else if (snapshot.revision !== fromRevision) {
551
+ this.emitDelta(createSessionProtocolDeltaMessage({
552
+ sessionId: snapshot.sessionId,
553
+ fromRevision,
554
+ toRevision: snapshot.revision,
555
+ reason: "configuration",
556
+ delta: {
557
+ type: "snapshot.patch",
558
+ changes: [{ type: "settings.set", settings: snapshot.settings }],
559
+ },
560
+ }));
561
+ }
562
+ return { revision: snapshot.revision, settings: snapshot.settings };
563
+ });
564
+ this.runtimeEventQueue = write.then(() => undefined, () => undefined);
565
+ return await write;
528
566
  }
529
567
  async setPersona(personaId) {
530
568
  this.assertActive();
@@ -665,29 +703,6 @@ class LocalHostedSessionHandle {
665
703
  };
666
704
  });
667
705
  }
668
- async pruneToolResults(options) {
669
- return await this.runMaintenance(async (signal) => {
670
- const result = await this.session.pruneToolResults({
671
- strategy: options.strategy,
672
- fraction: options.fraction,
673
- ...(options.guidance !== undefined ? { guidance: options.guidance } : {}),
674
- signal,
675
- });
676
- signal.throwIfAborted();
677
- this.reconcileProjections({ prunedToolResults: result.prunedToolResults });
678
- const snapshot = await this.commitSnapshot();
679
- this.emitSnapshotReset("maintenance", snapshot);
680
- return {
681
- snapshot,
682
- message: result.message,
683
- noop: result.noop,
684
- bashResultsPruned: result.bashResultsPruned,
685
- editCallsPruned: result.editCallsPruned,
686
- editResultsPruned: result.editResultsPruned,
687
- bytesPruned: result.bytesPruned,
688
- };
689
- });
690
- }
691
706
  async runMaintenance(operation) {
692
707
  this.assertActive();
693
708
  return await this.runActiveWork(operation);
@@ -729,22 +744,18 @@ class LocalHostedSessionHandle {
729
744
  }
730
745
  async rewindToHistoryEntryId(historyEntryId) {
731
746
  this.assertActive();
732
- const result = this.session.rewindToHistoryEntryId(historyEntryId);
747
+ const result = await this.session.rewindToHistoryEntryId(historyEntryId);
733
748
  if (!result) {
734
749
  throw new Error("rewind failed");
735
750
  }
736
- await this.runtimeEventQueue;
737
- this.reconcileProjections({ removeMissingAgents: true });
738
- const snapshot = await this.commitSnapshot();
739
- this.emitSnapshotReset("maintenance", snapshot);
740
751
  return {
741
- snapshot,
752
+ snapshot: await this.snapshot(),
742
753
  ...result,
743
754
  };
744
755
  }
745
- async terminateSubagent(subagentId) {
756
+ async interruptSubagent(subagentId) {
746
757
  this.assertActive();
747
- return { found: await this.session.terminateSubagent(subagentId) };
758
+ return { found: await this.session.interruptSubagent(subagentId) };
748
759
  }
749
760
  async createEphemeralContext(options) {
750
761
  this.assertActive();
@@ -753,12 +764,12 @@ class LocalHostedSessionHandle {
753
764
  contextId,
754
765
  persona: this.runtime.persona,
755
766
  config: this.bootstrap.config ?? {},
756
- modelResolver: this.bootstrap.modelResolver,
757
767
  discoveredSkills: this.bootstrap.discoveredSkills,
758
768
  includeAgentContext: this.includeAgentContext,
759
769
  executionEnvironment: this.executionEnvironment,
760
770
  instructions: options.instructions,
761
771
  tools: options.tools,
772
+ recordUsage: this.recordUsage,
762
773
  emitUpdate: (threadId, update) => {
763
774
  this.emitEphemeral(createSessionProtocolEphemeralMessage({
764
775
  sessionId: this.session.sessionId,
@@ -793,7 +804,28 @@ class LocalHostedSessionHandle {
793
804
  }
794
805
  async snapshot() {
795
806
  this.assertActive();
796
- return await this.commitSnapshot();
807
+ return this.runtime.isTurnRunning && this.committedSnapshot
808
+ ? await this.commitProjectedSnapshot()
809
+ : await this.commitSnapshot();
810
+ }
811
+ async persistRecoveredAgentState(recovery) {
812
+ this.assertActive();
813
+ for (const recovered of recovery.recoveredToolResults) {
814
+ const tool = this.tools.get(recovered.message.toolCallId);
815
+ if (!tool || tool.status === "streaming") {
816
+ continue;
817
+ }
818
+ this.tools.set(tool.id, tool.status === "queued" || tool.status === "running"
819
+ ? {
820
+ ...tool,
821
+ status: "cancelled",
822
+ finishedAt: recovered.message.timestamp,
823
+ resultMessageId: recovered.historyEntryId,
824
+ error: "Tool completion status is unknown after session recovery.",
825
+ }
826
+ : { ...tool, resultMessageId: recovered.historyEntryId });
827
+ }
828
+ await this.commitSnapshot();
797
829
  }
798
830
  async dispose() {
799
831
  if (!this.disposePromise) {
@@ -815,12 +847,6 @@ class LocalHostedSessionHandle {
815
847
  errors.push(error);
816
848
  }
817
849
  this.disposed = true;
818
- try {
819
- this.unsubscribeSubagentEvent();
820
- }
821
- catch (error) {
822
- errors.push(error);
823
- }
824
850
  for (const session of this.ephemeralAgentSessions.values()) {
825
851
  try {
826
852
  session.dispose();
@@ -854,10 +880,17 @@ class LocalHostedSessionHandle {
854
880
  this.snapshotQueue = write.catch(() => undefined);
855
881
  return await write;
856
882
  }
857
- async commitSnapshotWithRevision(revision) {
883
+ async commitProjectedSnapshot() {
858
884
  const write = this.snapshotQueue
859
885
  .catch(() => undefined)
860
- .then(() => this.writeSnapshotWithRevision(revision));
886
+ .then(() => this.writeProjectedSnapshot());
887
+ this.snapshotQueue = write.catch(() => undefined);
888
+ return await write;
889
+ }
890
+ async commitSnapshotPatch(reason, changes) {
891
+ const write = this.snapshotQueue
892
+ .catch(() => undefined)
893
+ .then(() => this.writeSnapshotPatch(reason, changes));
861
894
  this.snapshotQueue = write.catch(() => undefined);
862
895
  return await write;
863
896
  }
@@ -882,23 +915,47 @@ class LocalHostedSessionHandle {
882
915
  }
883
916
  return cloneSessionProtocolSnapshot(this.updateCommittedSnapshotAfterWrite(snapshot));
884
917
  }
885
- async writeSnapshotWithRevision(revision) {
918
+ async writeProjectedSnapshot() {
886
919
  this.assertNotDisposed();
887
920
  const generation = this.snapshotGeneration;
888
- const draft = this.buildSnapshotDraft();
889
- await this.switchSnapshotSession(draft.sessionId);
890
- const snapshot = {
891
- ...draft,
892
- revision,
893
- };
921
+ const current = this.committedSnapshot;
922
+ if (!current) {
923
+ return await this.writeSnapshot();
924
+ }
925
+ const snapshot = cloneSessionProtocolSnapshot(current);
926
+ if (this.persistedSnapshot && isDeepStrictEqual(this.persistedSnapshot, snapshot)) {
927
+ return snapshot;
928
+ }
894
929
  await this.store.commitSessionSnapshot(snapshot, {
895
930
  expectedRevision: this.persistedSnapshot?.revision ?? 0,
896
931
  });
897
932
  this.persistedSnapshot = cloneSessionProtocolSnapshot(snapshot);
898
933
  if (generation !== this.snapshotGeneration) {
899
- return await this.writeSnapshot();
934
+ return await this.writeProjectedSnapshot();
900
935
  }
901
- return cloneSessionProtocolSnapshot(this.updateCommittedSnapshotAfterWrite(snapshot));
936
+ return cloneSessionProtocolSnapshot(this.committedSnapshot ?? snapshot);
937
+ }
938
+ async writeSnapshotPatch(reason, changes) {
939
+ this.assertNotDisposed();
940
+ const current = this.committedSnapshot;
941
+ if (!current) {
942
+ throw new Error("cannot persist a session patch without a committed snapshot");
943
+ }
944
+ const delta = createSessionProtocolDeltaMessage({
945
+ sessionId: current.sessionId,
946
+ fromRevision: current.revision,
947
+ toRevision: current.revision + 1,
948
+ reason,
949
+ delta: { type: "snapshot.patch", changes },
950
+ });
951
+ const snapshot = applySessionProtocolDelta(current, delta);
952
+ await this.store.commitSessionSnapshot(snapshot, {
953
+ expectedRevision: this.persistedSnapshot?.revision ?? 0,
954
+ });
955
+ this.persistedSnapshot = cloneSessionProtocolSnapshot(snapshot);
956
+ this.committedSnapshot = cloneSessionProtocolSnapshot(snapshot);
957
+ this.snapshotGeneration += 1;
958
+ return delta;
902
959
  }
903
960
  async switchSnapshotSession(sessionId) {
904
961
  if (this.committedSessionId === sessionId) {
@@ -944,7 +1001,6 @@ class LocalHostedSessionHandle {
944
1001
  }
945
1002
  }
946
1003
  const operationIds = new Set(this.timelineExtras.filter((item) => item.type === "operation").map((item) => item.id));
947
- const prunedByToolId = new Map((options.prunedToolResults ?? []).map((result) => [result.toolCallId, result.content]));
948
1004
  for (const [id, facet] of this.facets) {
949
1005
  const subjectExists = facet.subject.type === "session" ||
950
1006
  (facet.subject.type === "message" && messageIds.has(facet.subject.id)) ||
@@ -953,26 +1009,21 @@ class LocalHostedSessionHandle {
953
1009
  (facet.subject.type === "operation" && operationIds.has(facet.subject.id));
954
1010
  if (!subjectExists) {
955
1011
  this.facets.delete(id);
956
- continue;
957
- }
958
- if (facet.subject.type === "tool") {
959
- const toolCallId = facet.subject.id;
960
- const content = prunedByToolId.get(toolCallId);
961
- if (content !== undefined && facet.kind === "tau.tool-ui-events") {
962
- this.facets.set(id, {
963
- ...facet,
964
- data: {
965
- events: [{ type: "tool_pruned", toolCallId, content }],
966
- },
967
- });
968
- }
969
1012
  }
970
1013
  }
971
1014
  }
972
1015
  buildSnapshotDraft() {
973
1016
  const messages = this.buildProtocolMessages();
1017
+ const agentState = this.session.snapshot();
974
1018
  return {
975
1019
  sessionId: this.session.sessionId,
1020
+ agentState: {
1021
+ revision: agentState.revision,
1022
+ contextEpoch: agentState.contextEpoch,
1023
+ ...(agentState.usageCheckpoint
1024
+ ? { usageCheckpoint: { ...agentState.usageCheckpoint } }
1025
+ : {}),
1026
+ },
976
1027
  lifecycle: this.runtime.isTurnRunning ? "running" : "idle",
977
1028
  costTotal: this.costTotal,
978
1029
  settings: {
@@ -1113,7 +1164,14 @@ class LocalHostedSessionHandle {
1113
1164
  const { revision, ...current } = this.committedSnapshot;
1114
1165
  return JSON.stringify(current) === JSON.stringify(next) ? revision : revision + 1;
1115
1166
  }
1116
- enqueueRuntimeEvent(event) {
1167
+ async recordSubagentEvent(event) {
1168
+ const write = this.runtimeEventQueue
1169
+ .catch(() => undefined)
1170
+ .then(() => this.recordSubagentUiEvent(event));
1171
+ this.runtimeEventQueue = write.catch(() => undefined);
1172
+ return await write;
1173
+ }
1174
+ async enqueueRuntimeEvent(event) {
1117
1175
  const write = this.runtimeEventQueue
1118
1176
  .catch(() => undefined)
1119
1177
  .then(() => this.recordRuntimeEvent(event));
@@ -1128,6 +1186,17 @@ class LocalHostedSessionHandle {
1128
1186
  }
1129
1187
  changes.push({ type: "tool.remove", id: tool.id });
1130
1188
  }
1189
+ agentStateChange() {
1190
+ const state = this.session.snapshot();
1191
+ return {
1192
+ type: "agent-state.set",
1193
+ agentState: {
1194
+ revision: state.revision,
1195
+ contextEpoch: state.contextEpoch,
1196
+ ...(state.usageCheckpoint ? { usageCheckpoint: { ...state.usageCheckpoint } } : {}),
1197
+ },
1198
+ };
1199
+ }
1131
1200
  async recordRuntimeEvent(event) {
1132
1201
  switch (event.type) {
1133
1202
  case "assistant_start": {
@@ -1241,44 +1310,116 @@ class LocalHostedSessionHandle {
1241
1310
  });
1242
1311
  return;
1243
1312
  }
1313
+ case "user_message":
1314
+ await this.emitPatch("user-message", [
1315
+ this.agentStateChange(),
1316
+ {
1317
+ type: "message.append",
1318
+ message: {
1319
+ id: event.historyEntryId,
1320
+ state: "committed",
1321
+ modelVisible: true,
1322
+ message: event.message,
1323
+ },
1324
+ timelineItem: timelineItemForMessage(event.historyEntryId),
1325
+ },
1326
+ ], { persist: true });
1327
+ return;
1328
+ case "history_rewound":
1329
+ this.reconcileProjections({ removeMissingAgents: true });
1330
+ await this.emitSnapshotResetIfChanged("maintenance");
1331
+ return;
1244
1332
  case "assistant_final": {
1245
1333
  this.draftAssistantMessage = undefined;
1246
- this.messageStates.delete(event.historyEntryId);
1334
+ const messageState = event.message.stopReason === "aborted" ? "interrupted" : "committed";
1335
+ if (messageState === "committed") {
1336
+ this.messageStates.delete(event.historyEntryId);
1337
+ }
1338
+ else {
1339
+ this.messageStates.set(event.historyEntryId, messageState);
1340
+ }
1341
+ const lifecycle = this.runtime.isTurnRunning
1342
+ ? "running"
1343
+ : "idle";
1247
1344
  const toolChanges = this.syncToolRunsFromAssistantMessage(event.historyEntryId, event.message);
1248
- this.costTotal += event.message.usage?.cost?.total ?? 0;
1345
+ const usage = getUsageTotals(event.message.usage);
1346
+ const cost = getUsageCostTotal(event.message.usage);
1347
+ this.costTotal += cost;
1348
+ this.recordUsage({
1349
+ timestamp: event.message.timestamp,
1350
+ sessionId: this.sessionId,
1351
+ personaId: event.personaId,
1352
+ provider: event.message.provider,
1353
+ model: event.message.model,
1354
+ api: event.message.api,
1355
+ reasoningEffort: event.reasoningEffort,
1356
+ usage,
1357
+ cost: { total: cost },
1358
+ agent: { type: "main" },
1359
+ });
1249
1360
  await this.emitPatch("assistant-message", [
1361
+ this.agentStateChange(),
1250
1362
  { type: "cost.set", costTotal: this.costTotal },
1251
1363
  {
1252
1364
  type: "message.replace",
1253
1365
  message: {
1254
1366
  id: event.historyEntryId,
1255
- state: "committed",
1367
+ state: messageState,
1256
1368
  modelVisible: true,
1257
1369
  message: event.message,
1258
1370
  },
1259
1371
  },
1372
+ ...(this.committedSnapshot?.lifecycle !== lifecycle
1373
+ ? [{ type: "lifecycle.set", lifecycle }]
1374
+ : []),
1260
1375
  ...toolChanges,
1261
1376
  ]);
1262
1377
  return;
1263
1378
  }
1379
+ case "tool_run_queued":
1380
+ case "tool_run_blocked":
1381
+ case "tool_run_started":
1382
+ case "tool_run_finished": {
1383
+ const existing = this.tools.get(event.toolCallId);
1384
+ if (!existing || existing.status === "streaming") {
1385
+ throw new Error(`missing completed protocol tool run for '${event.toolCallId}'`);
1386
+ }
1387
+ const nextTool = {
1388
+ ...existing,
1389
+ status: event.type === "tool_run_queued"
1390
+ ? "queued"
1391
+ : event.type === "tool_run_blocked"
1392
+ ? "blocked"
1393
+ : event.type === "tool_run_started"
1394
+ ? "running"
1395
+ : event.outcome,
1396
+ ...(event.type === "tool_run_started" || event.type === "tool_run_finished"
1397
+ ? { startedAt: existing.startedAt ?? event.timestamp }
1398
+ : {}),
1399
+ ...(event.type === "tool_run_blocked" || event.type === "tool_run_finished"
1400
+ ? { finishedAt: event.timestamp }
1401
+ : {}),
1402
+ };
1403
+ this.tools.set(nextTool.id, nextTool);
1404
+ await this.emitPatch("tool-run", [{ type: "tool.set", tool: structuredClone(nextTool) }]);
1405
+ return;
1406
+ }
1264
1407
  case "tool_result": {
1265
1408
  const existing = this.tools.get(event.message.toolCallId);
1266
1409
  if (existing?.status === "streaming") {
1267
1410
  throw new Error(`tool result arrived before '${event.message.toolCallId}' completed`);
1268
1411
  }
1269
1412
  if (existing) {
1413
+ if (existing.status === "queued" || existing.status === "running") {
1414
+ throw new Error(`tool result arrived before '${event.message.toolCallId}' finished`);
1415
+ }
1270
1416
  const nextTool = {
1271
1417
  ...existing,
1272
- status: existing.status === "blocked"
1273
- ? "blocked"
1274
- : event.message.isError
1275
- ? "failed"
1276
- : "succeeded",
1277
- finishedAt: event.message.timestamp,
1278
1418
  resultMessageId: event.historyEntryId,
1279
1419
  };
1280
1420
  this.tools.set(nextTool.id, nextTool);
1281
1421
  await this.emitPatch("tool-result", [
1422
+ this.agentStateChange(),
1282
1423
  {
1283
1424
  type: "message.append",
1284
1425
  message: {
@@ -1294,6 +1435,7 @@ class LocalHostedSessionHandle {
1294
1435
  return;
1295
1436
  }
1296
1437
  await this.emitPatch("tool-result", [
1438
+ this.agentStateChange(),
1297
1439
  {
1298
1440
  type: "message.append",
1299
1441
  message: {
@@ -1309,6 +1451,7 @@ class LocalHostedSessionHandle {
1309
1451
  }
1310
1452
  case "tool_recovery": {
1311
1453
  const changes = [
1454
+ this.agentStateChange(),
1312
1455
  {
1313
1456
  type: "message.append",
1314
1457
  message: {
@@ -1324,14 +1467,11 @@ class LocalHostedSessionHandle {
1324
1467
  if (!existing || existing.status === "streaming") {
1325
1468
  throw new Error(`missing completed protocol tool run for '${toolResult.toolCallId}'`);
1326
1469
  }
1470
+ if (existing.status === "queued" || existing.status === "running") {
1471
+ throw new Error(`tool recovery arrived before '${toolResult.toolCallId}' finished`);
1472
+ }
1327
1473
  const nextTool = {
1328
1474
  ...existing,
1329
- status: existing.status === "blocked"
1330
- ? "blocked"
1331
- : toolResult.isError
1332
- ? "failed"
1333
- : "succeeded",
1334
- finishedAt: toolResult.timestamp,
1335
1475
  };
1336
1476
  this.tools.set(nextTool.id, nextTool);
1337
1477
  changes.push({ type: "tool.set", tool: structuredClone(nextTool) });
@@ -1374,11 +1514,15 @@ class LocalHostedSessionHandle {
1374
1514
  this.reconcileProjections();
1375
1515
  await this.emitSnapshotReset("maintenance", await this.commitSnapshot());
1376
1516
  return;
1377
- case "tool_ui":
1378
- await this.recordToolUiEvent(event.uiEvent);
1517
+ case "tool_activity":
1518
+ await this.recordToolUiEvent(event.activity);
1379
1519
  return;
1380
- case "subagent_ui":
1381
- await this.recordSubagentUiEvent(event.event);
1520
+ case "turn_started":
1521
+ case "turn_finished":
1522
+ case "tool_call_admitted":
1523
+ case "model_retry_scheduled":
1524
+ case "model_retry_started":
1525
+ case "usage_checkpoint":
1382
1526
  return;
1383
1527
  }
1384
1528
  }
@@ -1399,47 +1543,20 @@ class LocalHostedSessionHandle {
1399
1543
  data: { events: [...events, structuredClone(event)] },
1400
1544
  };
1401
1545
  this.facets.set(facet.id, facet);
1402
- const tool = this.updateToolRunFromUiEvent(existingTool, event);
1546
+ const tool = {
1547
+ ...existingTool,
1548
+ facetIds: existingTool.facetIds.includes(facetId)
1549
+ ? existingTool.facetIds
1550
+ : [...existingTool.facetIds, facetId],
1551
+ };
1403
1552
  this.tools.set(tool.id, tool);
1404
1553
  await this.emitPatch("tool-run", [
1405
1554
  { type: "tool.set", tool },
1406
1555
  { type: "facet.set", facet: structuredClone(facet) },
1407
- ]);
1408
- }
1409
- updateToolRunFromUiEvent(tool, event) {
1410
- if (tool.status === "streaming") {
1411
- throw new Error(`tool UI event '${event.type}' arrived before tool call completion`);
1412
- }
1413
- const next = {
1414
- ...tool,
1415
- facetIds: tool.facetIds.includes(`tool-ui-${tool.toolCallId}`)
1416
- ? tool.facetIds
1417
- : [...tool.facetIds, `tool-ui-${tool.toolCallId}`],
1418
- };
1419
- if (event.type.endsWith("_started") || event.type === "tool_call_queued") {
1420
- next.status = event.type === "tool_call_queued" ? "queued" : "running";
1421
- next.startedAt ??= Date.now();
1422
- }
1423
- else if (event.type.endsWith("_blocked")) {
1424
- next.status = "blocked";
1425
- next.finishedAt = Date.now();
1426
- }
1427
- else if (event.type.endsWith("_finished")) {
1428
- next.status = "status" in event && event.status === "error" ? "failed" : "succeeded";
1429
- next.finishedAt = Date.now();
1430
- }
1431
- else if (event.type === "bash_aborted") {
1432
- next.status = "cancelled";
1433
- next.finishedAt = Date.now();
1434
- }
1435
- return next;
1556
+ ], { persist: false });
1436
1557
  }
1437
1558
  async recordSubagentUiEvent(event) {
1438
- const existing = "id" in event ? this.agents.get(event.id) : this.agents.get(event.state.id);
1439
- const agent = agentRunFromSubagentEvent(event, existing);
1440
- if (!agent) {
1441
- return;
1442
- }
1559
+ const agent = agentRunFromSubagentEvent(event);
1443
1560
  const previousCost = this.agentCostTotals.get(agent.id) ?? 0;
1444
1561
  this.costTotal += Math.max(0, agent.costTotal - previousCost);
1445
1562
  this.agentCostTotals.set(agent.id, agent.costTotal);
@@ -1447,10 +1564,27 @@ class LocalHostedSessionHandle {
1447
1564
  return;
1448
1565
  }
1449
1566
  this.agents.set(agent.id, agent);
1450
- await this.emitPatch("agent-run", [
1567
+ const changes = [
1451
1568
  { type: "cost.set", costTotal: this.costTotal },
1452
1569
  { type: "agent.set", agent: structuredClone(agent) },
1453
- ]);
1570
+ ];
1571
+ const facetId = `subagent-activity-${agent.id}`;
1572
+ if (event.type === "subagent_activity") {
1573
+ const facet = {
1574
+ id: facetId,
1575
+ subject: { type: "agent", id: agent.id },
1576
+ kind: SUBAGENT_ACTIVITY_FACET_KIND,
1577
+ version: 1,
1578
+ data: { text: event.text },
1579
+ };
1580
+ this.facets.set(facet.id, facet);
1581
+ changes.push({ type: "facet.set", facet: structuredClone(facet) });
1582
+ }
1583
+ else if ((event.type === "subagent_run_started" || event.type === "subagent_finished") &&
1584
+ this.facets.delete(facetId)) {
1585
+ changes.push({ type: "facet.remove", id: facetId });
1586
+ }
1587
+ await this.emitPatch("agent-run", changes, event.type === "subagent_activity" ? { persist: false } : {});
1454
1588
  }
1455
1589
  buildAssistantPartialChanges(previousDraft, nextDraft) {
1456
1590
  if (!previousDraft) {
@@ -1476,33 +1610,31 @@ class LocalHostedSessionHandle {
1476
1610
  return;
1477
1611
  }
1478
1612
  if (!this.committedSnapshot) {
1613
+ if (options.persist === false) {
1614
+ const snapshot = { ...this.buildSnapshotDraft(), revision: 1 };
1615
+ this.committedSnapshot = snapshot;
1616
+ this.snapshotGeneration += 1;
1617
+ this.emitSnapshotReset(reason, snapshot);
1618
+ return;
1619
+ }
1479
1620
  const snapshot = await this.commitSnapshot();
1480
1621
  this.emitSnapshotReset(reason, snapshot);
1481
1622
  return;
1482
1623
  }
1483
- const fromRevision = this.committedSnapshot.revision;
1484
- const toRevision = fromRevision + 1;
1624
+ if (options.persist !== false) {
1625
+ this.emitDelta(await this.commitSnapshotPatch(reason, changes));
1626
+ return;
1627
+ }
1485
1628
  const delta = createSessionProtocolDeltaMessage({
1486
1629
  sessionId: this.committedSnapshot.sessionId,
1487
- fromRevision,
1488
- toRevision,
1630
+ fromRevision: this.committedSnapshot.revision,
1631
+ toRevision: this.committedSnapshot.revision + 1,
1489
1632
  reason,
1490
1633
  delta: { type: "snapshot.patch", changes },
1491
1634
  });
1492
- if (options.persist === false) {
1493
- this.committedSnapshot = applySessionProtocolDelta(this.committedSnapshot, delta);
1494
- this.snapshotGeneration += 1;
1495
- this.emitDelta(delta);
1496
- return;
1497
- }
1498
- const snapshot = await this.commitSnapshotWithRevision(toRevision);
1499
- this.emitDelta(createSessionProtocolDeltaMessage({
1500
- sessionId: delta.sessionId,
1501
- fromRevision,
1502
- toRevision: snapshot.revision,
1503
- reason,
1504
- delta: { type: "snapshot.patch", changes },
1505
- }));
1635
+ this.committedSnapshot = applySessionProtocolDelta(this.committedSnapshot, delta);
1636
+ this.snapshotGeneration += 1;
1637
+ this.emitDelta(delta);
1506
1638
  }
1507
1639
  emitSnapshotReset(reason, snapshot) {
1508
1640
  this.emitDelta(createSessionProtocolDeltaMessage({
@@ -1576,27 +1708,7 @@ class LocalHostedSessionHandle {
1576
1708
  return;
1577
1709
  }
1578
1710
  const interruptedMessage = createInterruptedAssistantMessage(draft, this.runtime.persona.model);
1579
- this.session.addMessage(interruptedMessage, { historyEntryId: draft.id });
1580
- this.messageStates.set(draft.id, "interrupted");
1581
- this.draftAssistantMessage = undefined;
1582
- const changes = [
1583
- {
1584
- type: "message.replace",
1585
- message: {
1586
- id: draft.id,
1587
- state: "interrupted",
1588
- modelVisible: true,
1589
- message: interruptedMessage,
1590
- },
1591
- },
1592
- { type: "lifecycle.set", lifecycle: "idle" },
1593
- ];
1594
- for (const tool of this.tools.values()) {
1595
- if (tool.status === "streaming" && tool.origin.messageId === draft.id) {
1596
- this.removeToolRun(tool, changes);
1597
- }
1598
- }
1599
- await this.emitPatch("assistant-stream", changes);
1711
+ await this.session.commitInterruptedAssistant(interruptedMessage, draft.id);
1600
1712
  }
1601
1713
  async cleanupFailedTurn() {
1602
1714
  if (this.draftAssistantMessage) {
@@ -1610,6 +1722,9 @@ function turnOutcomeFromResult(result, assistantMessage) {
1610
1722
  if (result.blocked) {
1611
1723
  return { status: "blocked", ...result.blocked };
1612
1724
  }
1725
+ if (result.limitReached) {
1726
+ return { status: "failed", stopReason: "error", errorMessage: result.limitReached.message };
1727
+ }
1613
1728
  if (result.aborted || assistantMessage?.stopReason === "aborted") {
1614
1729
  return { status: "aborted", stopReason: "aborted" };
1615
1730
  }
@@ -1688,8 +1803,14 @@ function getAssistantDraftBlockText(message, type) {
1688
1803
  }
1689
1804
  function normalizeRecoveredSnapshot(snapshot) {
1690
1805
  const recovered = cloneSessionProtocolSnapshot(snapshot);
1691
- let changed = recovered.lifecycle !== "idle";
1806
+ const legacyAgentState = recovered.agentState.contextEpoch === LEGACY_SESSION_CONTEXT_EPOCH;
1807
+ let changed = recovered.lifecycle !== "idle" || legacyAgentState;
1692
1808
  recovered.lifecycle = "idle";
1809
+ if (Object.keys(recovered.agents).length > 0) {
1810
+ changed = true;
1811
+ recovered.agents = {};
1812
+ recovered.facets = Object.fromEntries(Object.entries(recovered.facets).filter(([, facet]) => facet.subject.type !== "agent"));
1813
+ }
1693
1814
  const streamingToolIds = new Set(Object.values(recovered.tools)
1694
1815
  .filter((tool) => tool.status === "streaming")
1695
1816
  .map((tool) => tool.id));
@@ -1698,11 +1819,13 @@ function normalizeRecoveredSnapshot(snapshot) {
1698
1819
  recovered.tools = Object.fromEntries(Object.entries(recovered.tools).filter(([id]) => !streamingToolIds.has(id)));
1699
1820
  recovered.facets = Object.fromEntries(Object.entries(recovered.facets).filter(([, facet]) => facet.subject.type !== "tool" || !streamingToolIds.has(facet.subject.id)));
1700
1821
  }
1822
+ let recoveredAgentHistory = false;
1701
1823
  recovered.messages = recovered.messages.map((message) => {
1702
1824
  if (message.state !== "draft" || message.message.role !== "assistant") {
1703
1825
  return message;
1704
1826
  }
1705
1827
  changed = true;
1828
+ recoveredAgentHistory = true;
1706
1829
  return {
1707
1830
  id: message.id,
1708
1831
  state: "interrupted",
@@ -1710,7 +1833,16 @@ function normalizeRecoveredSnapshot(snapshot) {
1710
1833
  message: createInterruptedAssistantMessageFromModelSnapshot(message, recovered.bootstrap.model),
1711
1834
  };
1712
1835
  });
1713
- return { snapshot: recovered, changed };
1836
+ if (recoveredAgentHistory) {
1837
+ recovered.agentState = {
1838
+ revision: recovered.agentState.revision + 1,
1839
+ contextEpoch: recovered.agentState.contextEpoch,
1840
+ ...(recovered.agentState.usageCheckpoint
1841
+ ? { usageCheckpoint: { ...recovered.agentState.usageCheckpoint } }
1842
+ : {}),
1843
+ };
1844
+ }
1845
+ return { snapshot: recovered, changed, legacyAgentState };
1714
1846
  }
1715
1847
  function promptCompositionFromSnapshot(snapshot) {
1716
1848
  const systemMessage = snapshot.messages[0];
@@ -1798,48 +1930,8 @@ function createInterruptedAssistantMessageFromModelSnapshot(draft, model) {
1798
1930
  timestamp: draft.message.timestamp,
1799
1931
  };
1800
1932
  }
1801
- function agentRunFromSubagentEvent(event, existing) {
1802
- const state = event.type === "subagent_spawned" || event.type === "subagent_finished"
1803
- ? event.state
1804
- : undefined;
1805
- if (event.type === "subagent_progress" && existing) {
1806
- return {
1807
- ...existing,
1808
- costTotal: event.costTotal,
1809
- turns: event.turns,
1810
- toolCalls: event.toolCalls,
1811
- usage: { ...event.usage },
1812
- progress: event.text,
1813
- };
1814
- }
1815
- if (event.type === "subagent_abort_requested" && existing) {
1816
- return { ...existing, abortRequested: true };
1817
- }
1818
- if (!state) {
1819
- return undefined;
1820
- }
1821
- return {
1822
- id: state.id,
1823
- name: state.name,
1824
- title: state.title,
1825
- status: state.status === "success"
1826
- ? "succeeded"
1827
- : state.status === "error"
1828
- ? "failed"
1829
- : state.status === "aborted"
1830
- ? "cancelled"
1831
- : "running",
1832
- ...(state.modelLabel !== undefined ? { modelLabel: state.modelLabel } : {}),
1833
- costTotal: state.costTotal,
1834
- turns: state.turns,
1835
- toolCalls: state.toolCalls,
1836
- usage: { ...state.usage },
1837
- startedAt: state.startedAt,
1838
- ...(state.finishedAt !== undefined ? { finishedAt: state.finishedAt } : {}),
1839
- abortRequested: state.abortRequested,
1840
- ...(state.finalText !== undefined ? { finalText: state.finalText } : {}),
1841
- ...(state.error !== undefined ? { error: state.error } : {}),
1842
- };
1933
+ function agentRunFromSubagentEvent(event) {
1934
+ return structuredClone(event.state);
1843
1935
  }
1844
1936
  function cloneResolvedBootstrap(bootstrap) {
1845
1937
  return {