zidane 9.1.1 → 9.1.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (279) hide show
  1. package/dist/{acp-Di9WvMDF.js → acp-Cl4gCZN6.js} +7 -7
  2. package/dist/{acp-Di9WvMDF.js.map → acp-Cl4gCZN6.js.map} +1 -1
  3. package/dist/acp-cli.js +5 -5
  4. package/dist/acp.d.ts +2 -2
  5. package/dist/acp.js +1 -1
  6. package/dist/{agent-DJhpTS-B.js → agent-Dh_XZ7fj.js} +74 -19
  7. package/dist/agent-Dh_XZ7fj.js.map +1 -0
  8. package/dist/agent.d.ts +1 -1
  9. package/dist/agent.js +1 -1
  10. package/dist/{auth-store-port-DFgf22oo.js → auth-store-port-DBl2JUC6.js} +2 -2
  11. package/dist/{auth-store-port-DFgf22oo.js.map → auth-store-port-DBl2JUC6.js.map} +1 -1
  12. package/dist/{auto-update-restart-BFB7Ek87.js → auto-update-restart-CF_kjcJd.js} +277 -41
  13. package/dist/auto-update-restart-CF_kjcJd.js.map +1 -0
  14. package/dist/{browser-BcoCCB_n.js → browser-BkdeKnxO.js} +56 -2
  15. package/dist/browser-BkdeKnxO.js.map +1 -0
  16. package/dist/{browser-entry-ypi8CyE-.d.ts → browser-entry-BCwruqNa.d.ts} +10 -10
  17. package/dist/{browser-entry-ypi8CyE-.d.ts.map → browser-entry-BCwruqNa.d.ts.map} +1 -1
  18. package/dist/channels.d.ts +5 -5
  19. package/dist/chat/browser.d.ts +4 -4
  20. package/dist/chat/browser.js +6 -6
  21. package/dist/chat/pure.d.ts +5 -5
  22. package/dist/chat/pure.js +8 -8
  23. package/dist/chat.d.ts +5 -5
  24. package/dist/chat.js +55 -55
  25. package/dist/chat.js.map +1 -1
  26. package/dist/{cli-shared-CabruH8Z.js → cli-shared-DIV9c5Nr.js} +4 -4
  27. package/dist/{cli-shared-CabruH8Z.js.map → cli-shared-DIV9c5Nr.js.map} +1 -1
  28. package/dist/cli-style-DBEm6CyT.js +105 -0
  29. package/dist/cli-style-DBEm6CyT.js.map +1 -0
  30. package/dist/{client-core-CIixwznM.d.ts → client-core-C_4m_oL6.d.ts} +4 -4
  31. package/dist/{client-core-CIixwznM.d.ts.map → client-core-C_4m_oL6.d.ts.map} +1 -1
  32. package/dist/{client-CCaIXWue.d.ts → client-ygTASGis.d.ts} +2 -2
  33. package/dist/{client-CCaIXWue.d.ts.map → client-ygTASGis.d.ts.map} +1 -1
  34. package/dist/codemode-worker.js +8 -5
  35. package/dist/codemode-worker.js.map +1 -1
  36. package/dist/codemode.d.ts +16 -0
  37. package/dist/codemode.d.ts.map +1 -1
  38. package/dist/codemode.js +2 -2
  39. package/dist/{connection-loop-QmWL-fJf.d.ts → connection-loop-D_pRONCr.d.ts} +4 -4
  40. package/dist/{connection-loop-QmWL-fJf.d.ts.map → connection-loop-D_pRONCr.d.ts.map} +1 -1
  41. package/dist/contexts/daytona.d.ts +3 -3
  42. package/dist/contexts/docker.d.ts +1 -1
  43. package/dist/contexts/e2b.d.ts +2 -2
  44. package/dist/contexts/sandbox.d.ts +1 -1
  45. package/dist/{contexts-C72b0mMa.js → contexts-DLZTSRHU.js} +17 -106
  46. package/dist/contexts-DLZTSRHU.js.map +1 -0
  47. package/dist/contexts.d.ts +4 -4
  48. package/dist/contexts.js +2 -2
  49. package/dist/{credentials-wwETW8rI.js → credentials-D71duF64.js} +2 -2
  50. package/dist/{credentials-wwETW8rI.js.map → credentials-D71duF64.js.map} +1 -1
  51. package/dist/{cwd-picker-CcekODCt.js → cwd-picker-BsHA6HKv.js} +4 -4
  52. package/dist/{cwd-picker-CcekODCt.js.map → cwd-picker-BsHA6HKv.js.map} +1 -1
  53. package/dist/daemon-cli.js +4 -3
  54. package/dist/daemon-cli.js.map +1 -1
  55. package/dist/{decisions-CXmK0nz9.js → decisions-hsw5XS2g.js} +3 -1
  56. package/dist/decisions-hsw5XS2g.js.map +1 -0
  57. package/dist/{discovery-DycXFxdA.js → discovery-DD4wPWKS.js} +4 -4
  58. package/dist/{discovery-DycXFxdA.js.map → discovery-DD4wPWKS.js.map} +1 -1
  59. package/dist/durable/sqlite.d.ts +2 -2
  60. package/dist/durable.d.ts +1 -1
  61. package/dist/{engine-VQ86XGdG.js → engine-BDmtgr2O.js} +6 -6
  62. package/dist/{engine-VQ86XGdG.js.map → engine-BDmtgr2O.js.map} +1 -1
  63. package/dist/{eval-Bod0I1W_.js → eval-CfGUDAkN.js} +3 -3
  64. package/dist/{eval-Bod0I1W_.js.map → eval-CfGUDAkN.js.map} +1 -1
  65. package/dist/eval.d.ts +1 -1
  66. package/dist/eval.js +1 -1
  67. package/dist/{executor-C7RQrkEq.js → executor-EWOhLyd9.js} +4 -4
  68. package/dist/{executor-C7RQrkEq.js.map → executor-EWOhLyd9.js.map} +1 -1
  69. package/dist/{extension-mark-BqKdEZwF.js → extension-mark-_rhkDWL5.js} +9 -6
  70. package/dist/extension-mark-_rhkDWL5.js.map +1 -0
  71. package/dist/extensions/testing.d.ts +1 -1
  72. package/dist/extensions/testing.js +2 -2
  73. package/dist/{extensions-BCx4QuGB.js → extensions-DklXPjiq.js} +8 -8
  74. package/dist/{extensions-BCx4QuGB.js.map → extensions-DklXPjiq.js.map} +1 -1
  75. package/dist/{extensions-client-D8tEAcMw.d.ts → extensions-client-D4Q2XRKV.d.ts} +31 -5
  76. package/dist/extensions-client-D4Q2XRKV.d.ts.map +1 -0
  77. package/dist/extensions.d.ts +1 -1
  78. package/dist/extensions.js +6 -6
  79. package/dist/{fold-rules-DvLK8pbf.d.ts → fold-rules-1DpDwG9h.d.ts} +2 -2
  80. package/dist/{fold-rules-DvLK8pbf.d.ts.map → fold-rules-1DpDwG9h.d.ts.map} +1 -1
  81. package/dist/{google-Crva32sk.js → google-BtMW9KzL.js} +2 -2
  82. package/dist/{google-Crva32sk.js.map → google-BtMW9KzL.js.map} +1 -1
  83. package/dist/{headless-CCm-jLLT.js → headless-CQm19BL0.js} +4 -4
  84. package/dist/{headless-CCm-jLLT.js.map → headless-CQm19BL0.js.map} +1 -1
  85. package/dist/headless.d.ts +1 -1
  86. package/dist/headless.js +1 -1
  87. package/dist/history-worker.js +1 -1
  88. package/dist/{host-BHMs9jsN.js → host-DEoEzQal.js} +13 -4
  89. package/dist/host-DEoEzQal.js.map +1 -0
  90. package/dist/{host-scoped-settings-CrbcqOkP.js → host-scoped-settings-WBYaCork.js} +2 -2
  91. package/dist/{host-scoped-settings-CrbcqOkP.js.map → host-scoped-settings-WBYaCork.js.map} +1 -1
  92. package/dist/{host-signals-Jsjd_-4g.js → host-signals-91zyko_i.js} +5 -5
  93. package/dist/{host-signals-Jsjd_-4g.js.map → host-signals-91zyko_i.js.map} +1 -1
  94. package/dist/{host-wO_6GW0y.js → host-uP3t08w8.js} +276 -103
  95. package/dist/host-uP3t08w8.js.map +1 -0
  96. package/dist/{host-version-CNAr9pov.js → host-version-_RHlAB29.js} +2 -2
  97. package/dist/{host-version-CNAr9pov.js.map → host-version-_RHlAB29.js.map} +1 -1
  98. package/dist/{index-C6nnKu32.d.ts → index-B0PLo9jn.d.ts} +4 -4
  99. package/dist/{index-C6nnKu32.d.ts.map → index-B0PLo9jn.d.ts.map} +1 -1
  100. package/dist/{index-Djnc8Peh.d.ts → index-De4x-s76.d.ts} +14 -14
  101. package/dist/{index-Djnc8Peh.d.ts.map → index-De4x-s76.d.ts.map} +1 -1
  102. package/dist/{index-CGbOWa7y.d.ts → index-WlE93Q6d.d.ts} +411 -3
  103. package/dist/index-WlE93Q6d.d.ts.map +1 -0
  104. package/dist/{index-CCf_WeTQ.d.ts → index-f-XWIoYo.d.ts} +2 -2
  105. package/dist/{index-CCf_WeTQ.d.ts.map → index-f-XWIoYo.d.ts.map} +1 -1
  106. package/dist/index.d.ts +5 -5
  107. package/dist/index.js +17 -17
  108. package/dist/ipc/browser-types.d.ts +304 -7
  109. package/dist/ipc/browser-types.d.ts.map +1 -1
  110. package/dist/ipc/browser.d.ts +4 -4
  111. package/dist/ipc/browser.js +2 -2
  112. package/dist/ipc/remote.d.ts +6 -6
  113. package/dist/ipc/remote.js +3 -3
  114. package/dist/{ipc-BzWhIybr.js → ipc-CatnsVEd.js} +4 -4
  115. package/dist/{ipc-BzWhIybr.js.map → ipc-CatnsVEd.js.map} +1 -1
  116. package/dist/ipc.d.ts +10 -10
  117. package/dist/ipc.js +8 -8
  118. package/dist/{json-Dj-YATkZ.js → json-BjClr43H.js} +2 -20
  119. package/dist/json-BjClr43H.js.map +1 -0
  120. package/dist/{links-CJG_rFvf.js → links-a8C9eby4.js} +9 -9
  121. package/dist/{links-CJG_rFvf.js.map → links-a8C9eby4.js.map} +1 -1
  122. package/dist/{loaded-entry-DTURJo_R.js → loaded-entry-D6jzt5HQ.js} +2 -2
  123. package/dist/{loaded-entry-DTURJo_R.js.map → loaded-entry-D6jzt5HQ.js.map} +1 -1
  124. package/dist/mcp.d.ts +1 -1
  125. package/dist/{media-type-BtA0cbfI.d.ts → media-type-ZSmAGHvg.d.ts} +188 -7
  126. package/dist/media-type-ZSmAGHvg.d.ts.map +1 -0
  127. package/dist/{memory-DuVGrzbl.js → memory-CJy52DNi.js} +132 -31
  128. package/dist/memory-CJy52DNi.js.map +1 -0
  129. package/dist/model-test-CAtJ76kM.js.map +1 -1
  130. package/dist/{move-session-kylExJ5H.js → move-session-D7ILECs-.js} +4 -4
  131. package/dist/{move-session-kylExJ5H.js.map → move-session-D7ILECs-.js.map} +1 -1
  132. package/dist/{nested-call-record-DlzPeTB7.js → nested-call-record-OayszZBQ.js} +4 -3
  133. package/dist/nested-call-record-OayszZBQ.js.map +1 -0
  134. package/dist/output/stream-json.d.ts +1 -1
  135. package/dist/output/terminal.d.ts +1 -1
  136. package/dist/{path-display-COVV71Yu.js → path-display-CAWz-sMq.js} +3 -3
  137. package/dist/{path-display-COVV71Yu.js.map → path-display-CAWz-sMq.js.map} +1 -1
  138. package/dist/plugins.d.ts +1 -1
  139. package/dist/{prelude-CVKoUzV8.js → prelude-BwiSR1uA.js} +16 -5
  140. package/dist/prelude-BwiSR1uA.js.map +1 -0
  141. package/dist/{presets-CBt6rFfS.js → presets-CMY43nUP.js} +3 -3
  142. package/dist/{presets-CBt6rFfS.js.map → presets-CMY43nUP.js.map} +1 -1
  143. package/dist/presets.d.ts +1 -1
  144. package/dist/presets.js +1 -1
  145. package/dist/{protocol-CEVqBO-q.d.ts → protocol-C2lqKuMd.d.ts} +50 -7
  146. package/dist/protocol-C2lqKuMd.d.ts.map +1 -0
  147. package/dist/protocol-DOGyHgLQ.js.map +1 -1
  148. package/dist/protocol-NSllElLw.js.map +1 -1
  149. package/dist/providers/anthropic.d.ts +1 -1
  150. package/dist/providers/arcee.d.ts +1 -1
  151. package/dist/providers/baseten.d.ts +1 -1
  152. package/dist/providers/cerebras.d.ts +1 -1
  153. package/dist/providers/google.d.ts +1 -1
  154. package/dist/providers/google.js +1 -1
  155. package/dist/providers/local.d.ts +1 -1
  156. package/dist/providers/neuralwatt.d.ts +1 -1
  157. package/dist/providers/openai-compat.d.ts +1 -1
  158. package/dist/providers/openai.d.ts +1 -1
  159. package/dist/providers/openrouter.d.ts +1 -1
  160. package/dist/providers/xai.d.ts +1 -1
  161. package/dist/{providers-Z0TaBp1O.js → providers-zVRxiJDv.js} +5 -5
  162. package/dist/providers-zVRxiJDv.js.map +1 -0
  163. package/dist/providers.d.ts +1 -1
  164. package/dist/providers.js +1 -1
  165. package/dist/{readonly-db-D7Z-k0pQ.js → readonly-db-DrbT8tX6.js} +2 -2
  166. package/dist/{readonly-db-D7Z-k0pQ.js.map → readonly-db-DrbT8tX6.js.map} +1 -1
  167. package/dist/{registry-BKjeBnoy.js → registry-CBoYDIND.js} +2 -2
  168. package/dist/{registry-BKjeBnoy.js.map → registry-CBoYDIND.js.map} +1 -1
  169. package/dist/{registry-B6Ww76iW.js → registry-CQOU5jvF.js} +2 -2
  170. package/dist/{registry-B6Ww76iW.js.map → registry-CQOU5jvF.js.map} +1 -1
  171. package/dist/{registry-B9INJwJR.js → registry-YUUqbYGr.js} +324 -39
  172. package/dist/registry-YUUqbYGr.js.map +1 -0
  173. package/dist/{remote-hosts-BMWoHCWO.js → remote-hosts-CT8Q95dR.js} +4 -4
  174. package/dist/{remote-hosts-BMWoHCWO.js.map → remote-hosts-CT8Q95dR.js.map} +1 -1
  175. package/dist/{repo-url-D4Dr8NfZ.js → repo-url-DLjjuVk_.js} +169 -2
  176. package/dist/repo-url-DLjjuVk_.js.map +1 -0
  177. package/dist/restate.d.ts +2 -2
  178. package/dist/{sandbox-BwiPGKF7.d.ts → sandbox-B4OW6oNx.d.ts} +2 -2
  179. package/dist/{sandbox-BwiPGKF7.d.ts.map → sandbox-B4OW6oNx.d.ts.map} +1 -1
  180. package/dist/script-progress-CrZ507Qq.js +900 -0
  181. package/dist/script-progress-CrZ507Qq.js.map +1 -0
  182. package/dist/session/sqlite.d.ts +1 -1
  183. package/dist/session.d.ts +1 -1
  184. package/dist/{setting-BQBSyUq0.js → setting-_jh2OtiL.js} +6 -6
  185. package/dist/{setting-BQBSyUq0.js.map → setting-_jh2OtiL.js.map} +1 -1
  186. package/dist/{settings-catalog-4IU2i_jG.js → settings-catalog-DEZlXP51.js} +14 -2
  187. package/dist/settings-catalog-DEZlXP51.js.map +1 -0
  188. package/dist/{settings-keys-iI_Y-7MC.js → settings-keys-BT0_oKjO.js} +3 -3
  189. package/dist/{settings-keys-iI_Y-7MC.js.map → settings-keys-BT0_oKjO.js.map} +1 -1
  190. package/dist/{skills-CFXRItJ6.js → skills-CEbosUlM.js} +2 -2
  191. package/dist/{skills-CFXRItJ6.js.map → skills-CEbosUlM.js.map} +1 -1
  192. package/dist/skills.d.ts +1 -1
  193. package/dist/skills.js +1 -1
  194. package/dist/{source-Bl1Z501r.js → source-3ZnEPOSa.js} +3 -2
  195. package/dist/source-3ZnEPOSa.js.map +1 -0
  196. package/dist/{sqlite-runtime-BZ2L4RaG.d.ts → sqlite-runtime-CS_LBaAN.d.ts} +2 -2
  197. package/dist/sqlite-runtime-CS_LBaAN.d.ts.map +1 -0
  198. package/dist/{src-BY_ND2xn.js → src-BmTXDta8.js} +2 -2
  199. package/dist/{src-BY_ND2xn.js.map → src-BmTXDta8.js.map} +1 -1
  200. package/dist/{store-C6gI7FfZ.js → store-ByCDaKgJ.js} +14 -3
  201. package/dist/store-ByCDaKgJ.js.map +1 -0
  202. package/dist/{system-freeze-m5o1sGIM.js → system-freeze-DxJ-lRhu.js} +3 -3
  203. package/dist/{system-freeze-m5o1sGIM.js.map → system-freeze-DxJ-lRhu.js.map} +1 -1
  204. package/dist/{todo-edits-CbukbjyV.js → todo-edits-Dyj32ds6.js} +4 -3
  205. package/dist/todo-edits-Dyj32ds6.js.map +1 -0
  206. package/dist/tools/fetch-url.d.ts +1 -1
  207. package/dist/tools/web-search.d.ts +1 -1
  208. package/dist/{tools-CVTGhggj.js → tools-BsrGQ8K4.js} +2 -2
  209. package/dist/{tools-CVTGhggj.js.map → tools-BsrGQ8K4.js.map} +1 -1
  210. package/dist/tools.d.ts +1 -1
  211. package/dist/tools.js +3 -3
  212. package/dist/{transcript-anchors-CiSi_UBn.js → transcript-anchors-DMjvyUjk.js} +3 -3
  213. package/dist/{transcript-anchors-CiSi_UBn.js.map → transcript-anchors-DMjvyUjk.js.map} +1 -1
  214. package/dist/{transcript-reconcile-jbSBjLq2.js → transcript-reconcile-DpQO85wl.js} +3 -3
  215. package/dist/{transcript-reconcile-jbSBjLq2.js.map → transcript-reconcile-DpQO85wl.js.map} +1 -1
  216. package/dist/tui.d.ts +9 -9
  217. package/dist/tui.d.ts.map +1 -1
  218. package/dist/tui.js +289 -38
  219. package/dist/tui.js.map +1 -1
  220. package/dist/{types-bDQagoiL.d.ts → types-2HrgolQz.d.ts} +20 -8
  221. package/dist/types-2HrgolQz.d.ts.map +1 -0
  222. package/dist/types-4q1bFG53.js +122 -0
  223. package/dist/types-4q1bFG53.js.map +1 -0
  224. package/dist/{types-DnRd9_cA.d.ts → types-SXqk6hLD.d.ts} +3 -3
  225. package/dist/{types-DnRd9_cA.d.ts.map → types-SXqk6hLD.d.ts.map} +1 -1
  226. package/dist/types-myxheQkw.js.map +1 -1
  227. package/dist/types.d.ts +3 -3
  228. package/dist/{usage-summary-BfcXjiSM.js → usage-summary-BM7B3JdI.js} +2 -2
  229. package/dist/{usage-summary-BfcXjiSM.js.map → usage-summary-BM7B3JdI.js.map} +1 -1
  230. package/dist/{version-DqqqvHDP.js → version-DwQI12WA.js} +2 -2
  231. package/dist/{version-DqqqvHDP.js.map → version-DwQI12WA.js.map} +1 -1
  232. package/dist/{wait-task-BX4NcOOm.js → wait-task-BiI5UaZQ.js} +13 -3
  233. package/dist/wait-task-BiI5UaZQ.js.map +1 -0
  234. package/dist/{wire-CLm2rMK0.js → wire-Dxwxb7QQ.js} +2 -2
  235. package/dist/{wire-CLm2rMK0.js.map → wire-Dxwxb7QQ.js.map} +1 -1
  236. package/dist/{write-file-0E6TUJ9A.js → write-file-Dquu7MzB.js} +5 -3
  237. package/dist/write-file-Dquu7MzB.js.map +1 -0
  238. package/dist/{ws-DfGGYQ4W.js → ws-CA3o2nie.js} +4 -4
  239. package/dist/{ws-DfGGYQ4W.js.map → ws-CA3o2nie.js.map} +1 -1
  240. package/dist/{ws-client-CFMbhsNq.js → ws-client-C0iPAAzc.js} +2 -2
  241. package/dist/{ws-client-CFMbhsNq.js.map → ws-client-C0iPAAzc.js.map} +1 -1
  242. package/docs/CHAT.md +55 -0
  243. package/docs/CODEMODE.md +37 -0
  244. package/docs/EXTENSIONS.md +8 -6
  245. package/docs/RELEASE-NOTES-NEXT.md +48 -1
  246. package/docs/RELEASE.md +9 -1
  247. package/package.json +2 -3
  248. package/dist/agent-DJhpTS-B.js.map +0 -1
  249. package/dist/auto-update-restart-BFB7Ek87.js.map +0 -1
  250. package/dist/browser-BcoCCB_n.js.map +0 -1
  251. package/dist/contexts-C72b0mMa.js.map +0 -1
  252. package/dist/decisions-CXmK0nz9.js.map +0 -1
  253. package/dist/extension-mark-BqKdEZwF.js.map +0 -1
  254. package/dist/extensions-client-D8tEAcMw.d.ts.map +0 -1
  255. package/dist/host-BHMs9jsN.js.map +0 -1
  256. package/dist/host-wO_6GW0y.js.map +0 -1
  257. package/dist/index-CGbOWa7y.d.ts.map +0 -1
  258. package/dist/json-Dj-YATkZ.js.map +0 -1
  259. package/dist/media-type-BtA0cbfI.d.ts.map +0 -1
  260. package/dist/memory-DuVGrzbl.js.map +0 -1
  261. package/dist/nested-call-events-BYk8XvGX.js +0 -182
  262. package/dist/nested-call-events-BYk8XvGX.js.map +0 -1
  263. package/dist/nested-call-record-DlzPeTB7.js.map +0 -1
  264. package/dist/prelude-CVKoUzV8.js.map +0 -1
  265. package/dist/protocol-CEVqBO-q.d.ts.map +0 -1
  266. package/dist/providers-Z0TaBp1O.js.map +0 -1
  267. package/dist/registry-B9INJwJR.js.map +0 -1
  268. package/dist/repo-url-D4Dr8NfZ.js.map +0 -1
  269. package/dist/settings-catalog-4IU2i_jG.js.map +0 -1
  270. package/dist/source-Bl1Z501r.js.map +0 -1
  271. package/dist/sqlite-runtime-BZ2L4RaG.d.ts.map +0 -1
  272. package/dist/store-C6gI7FfZ.js.map +0 -1
  273. package/dist/todo-edits-CbukbjyV.js.map +0 -1
  274. package/dist/types-DTMEhKJO.js +0 -14
  275. package/dist/types-DTMEhKJO.js.map +0 -1
  276. package/dist/types-bDQagoiL.d.ts.map +0 -1
  277. package/dist/wait-task-BX4NcOOm.js.map +0 -1
  278. package/dist/write-file-0E6TUJ9A.js.map +0 -1
  279. package/scripts/eval.ts +0 -179
@@ -0,0 +1 @@
1
+ {"version":3,"file":"agent-Dh_XZ7fj.js","names":["buildCatalog","turnsToMessages","resolvePath","pathResolve","DEFAULT_MAX_NUDGES","builtinShell","builtinShellKill","builtinWaitTask","pathResolve","destroy","destroyAgent"],"sources":["../src/agent-behavior.ts","../src/agent-bootstrap.ts","../src/run-durability.ts","../src/agent-durable.ts","../src/agent-mcp-naming.ts","../src/agent-extensions.ts","../src/agent-history.ts","../src/extensions/hooks/bridge.ts","../src/agent-interceptors.ts","../src/model-targets.ts","../src/tool-cancel.ts","../src/agent-runtime.ts","../src/loop-recovery.ts","../src/compact/errors.ts","../src/compact/messages.ts","../src/compact/prompt.ts","../src/compact/compact.ts","../src/compact/restore.ts","../src/cache-telemetry.ts","../src/loop-persistence.ts","../src/loop-compaction.ts","../src/loop-context.ts","../src/loop-stale-reads.ts","../src/behaviors/thinking-decay.ts","../src/loop-stream.ts","../src/loop-tool-step.ts","../src/loop-nested-calls.ts","../src/loop-wire.ts","../src/media/shrink.ts","../src/loop-tool-dispatch.ts","../src/loop-tool-batch.ts","../src/loop-turn-stream.ts","../src/loop-turn.ts","../src/loop-auto-compact.ts","../src/agent-compact.ts","../src/agent-context.ts","../src/agent-lifecycle.ts","../src/agent-resume.ts","../src/agent-lease.ts","../src/agent-run-finalize.ts","../src/agent-tool-disclosure.ts","../src/behaviors/dedup-tools.ts","../src/behaviors/shared.ts","../src/behaviors/max-turns-warning.ts","../src/behaviors/progress-nudges.ts","../src/behaviors/transcript-notes.ts","../src/behaviors/shell-tool-nudges.ts","../src/behaviors/text-tool-call-rescue.ts","../src/behaviors/thinking-overrun-policy.ts","../src/behaviors/tool-budgets.ts","../src/behaviors/unknown-tool-recovery.ts","../src/behaviors/write-file-existing-policy.ts","../src/tools/codemode/config.ts","../src/tools/codemode/description.ts","../src/tools/codemode/discovery.ts","../src/tools/codemode/output.ts","../src/tools/codemode/script-api.ts","../src/tools/codemode/store.ts","../src/tools/codemode/direct-calls.ts","../src/tools/codemode/index.ts","../src/agent-run-gates.ts","../src/agent-tool-registry.ts","../src/agent-run-prompt.ts","../src/agent-task-notifications.ts","../src/loop.ts","../src/agent-run.ts","../src/agent.ts"],"sourcesContent":["/**\n * Behavior resolution: field-merging agent + run `AgentBehavior` into the\n * one frozen view the run and loop read, plus the lifecycle timeout defaults.\n */\n\nimport type { AgentBehavior } from './types'\n\n// ---------------------------------------------------------------------------\n// Behavior resolution\n// ---------------------------------------------------------------------------\n\n/** Default watchdog, in ms, for the whole MCP connect step (custom `mcpConnector` and built-in connect). See `AgentBehavior.mcpConnectTimeoutMs`. */\nexport const DEFAULT_CUSTOM_MCP_CONNECT_TIMEOUT_MS = 2 * 60 * 1000\n/** Default watchdog for the first `executionContext.spawn()`. See `AgentBehavior.spawnTimeoutMs`. */\nexport const DEFAULT_SPAWN_TIMEOUT_MS = 5 * 60 * 1000\n/** Default watchdog for `agent.destroy()` teardown awaits. See `AgentBehavior.destroyTimeoutMs`. */\nexport const DEFAULT_DESTROY_TIMEOUT_MS = 30 * 1000\n\ntype DefaultedBehaviorKeys = 'cache' | 'compactStrategy' | 'toolDisclosure' | 'mcpToolNameSeparator' | 'surfaceMcpInstructions' | 'strictToolPairing'\ntype ResolvedBehaviorKeys\n = | 'maxConcurrentTools' | 'maxTurns' | 'maxCostUsd' | 'retry' | 'maxTotalTokens' | 'maxWallMs'\n | 'providerStreamStartTimeoutMs' | 'providerStreamTimeoutMs' | 'providerStreamIdleTimeoutMs' | 'mcpConnectTimeoutMs'\n | 'hookTimeoutMs' | 'spawnTimeoutMs' | 'destroyTimeoutMs'\n | 'maxTokens' | 'modelCatalog' | 'thinkingBudget' | 'taskBudget' | 'effortHint' | 'modelOptions' | 'schema' | 'toolOutputBudget'\n | 'toolOutputBudgetExcludeTools' | 'compactThreshold' | 'compactThresholdWindowFraction' | 'compactLowWaterFraction' | 'compactSkip' | 'compactKeepTurns' | 'contextWindow' | 'cacheTtl'\n | 'thinkingDecay' | 'dedupReads' | 'dedupTools' | 'requireReadBeforeEdit' | 'trackShellReads' | 'shellToolNudges'\n | 'toolBudgets' | 'repeatGuard' | 'readLineNumbers' | 'elideStaleReads' | 'mediaKeepTurns' | 'mediaBudget' | 'maxImageEdge' | 'autoCompact' | 'toolSearch'\n | 'persistThreshold' | 'persistExcludeTools' | 'persistDir' | 'persistMaxBytes'\n | 'tasksDir' | 'shellLongTimeoutMs' | 'disableBackgroundTasks' | 'maxConsecutivePauseTurns' | 'maxConsecutiveRefusalResumes' | 'resumeOnMaxTokens' | 'maxConsecutiveLengthResumes' | 'persistTurns'\n | 'maxPairingRepairsPerTurn' | 'maxTurnsWarning' | 'maxTurnsWarningMessage'\n | 'backgroundOutputCap' | 'backgroundStallWatchdogMs' | 'extensions'\n | 'toolBatchExecutor' | 'toolBatchTimeoutMs'\n | 'thinkingOverrunPolicy' | 'readFileDefaults'\n | 'writeFileExistingPolicy' | 'textToolCallRescue' | 'unknownToolRecovery' | 'progressNudges'\n | 'codemode'\n | DefaultedBehaviorKeys\n\n/**\n * Result of merging agent-level and per-run {@link AgentBehavior}. Mirrors the\n * subset of `AgentBehavior` fields the loop reads; the six fields with\n * built-in defaults (`cache`, `compactStrategy`, `toolDisclosure`,\n * `mcpToolNameSeparator`, `surfaceMcpInstructions`, `strictToolPairing`) are\n * always present.\n */\nexport type ResolvedBehavior\n = & Pick<AgentBehavior, Exclude<ResolvedBehaviorKeys, DefaultedBehaviorKeys>>\n & Required<Pick<AgentBehavior, DefaultedBehaviorKeys>>\n\n/** The layer whose media policy (`mediaKeepTurns` + `mediaBudget`) applies. */\nfunction mediaPolicyLayer(agentBehavior?: AgentBehavior, runBehavior?: AgentBehavior): AgentBehavior | undefined {\n return runBehavior?.mediaKeepTurns !== undefined || runBehavior?.mediaBudget !== undefined\n ? runBehavior\n : agentBehavior\n}\n\n/**\n * Merge agent-level and per-run behavior field by field. A run value wins over\n * the agent value, then built-in defaults apply. `mediaKeepTurns` and\n * `mediaBudget` resolve together from one layer, and `extensions` merges\n * shallowly.\n */\nexport function resolveBehavior(\n agentBehavior?: AgentBehavior,\n runBehavior?: AgentBehavior,\n): ResolvedBehavior {\n return {\n maxConcurrentTools: runBehavior?.maxConcurrentTools ?? agentBehavior?.maxConcurrentTools,\n toolBatchExecutor: runBehavior?.toolBatchExecutor ?? agentBehavior?.toolBatchExecutor,\n toolBatchTimeoutMs: runBehavior?.toolBatchTimeoutMs ?? agentBehavior?.toolBatchTimeoutMs,\n maxTurns: runBehavior?.maxTurns ?? agentBehavior?.maxTurns,\n maxTurnsWarning: runBehavior?.maxTurnsWarning ?? agentBehavior?.maxTurnsWarning,\n maxTurnsWarningMessage: runBehavior?.maxTurnsWarningMessage ?? agentBehavior?.maxTurnsWarningMessage,\n maxCostUsd: runBehavior?.maxCostUsd ?? agentBehavior?.maxCostUsd,\n retry: runBehavior?.retry ?? agentBehavior?.retry,\n maxTotalTokens: runBehavior?.maxTotalTokens ?? agentBehavior?.maxTotalTokens,\n maxWallMs: runBehavior?.maxWallMs ?? agentBehavior?.maxWallMs,\n providerStreamStartTimeoutMs: runBehavior?.providerStreamStartTimeoutMs ?? agentBehavior?.providerStreamStartTimeoutMs,\n providerStreamTimeoutMs: runBehavior?.providerStreamTimeoutMs ?? agentBehavior?.providerStreamTimeoutMs,\n providerStreamIdleTimeoutMs: runBehavior?.providerStreamIdleTimeoutMs ?? agentBehavior?.providerStreamIdleTimeoutMs,\n mcpConnectTimeoutMs: runBehavior?.mcpConnectTimeoutMs ?? agentBehavior?.mcpConnectTimeoutMs,\n hookTimeoutMs: runBehavior?.hookTimeoutMs ?? agentBehavior?.hookTimeoutMs,\n spawnTimeoutMs: runBehavior?.spawnTimeoutMs ?? agentBehavior?.spawnTimeoutMs,\n destroyTimeoutMs: runBehavior?.destroyTimeoutMs ?? agentBehavior?.destroyTimeoutMs,\n maxTokens: runBehavior?.maxTokens ?? agentBehavior?.maxTokens,\n modelCatalog: runBehavior?.modelCatalog ?? agentBehavior?.modelCatalog,\n thinkingBudget: runBehavior?.thinkingBudget ?? agentBehavior?.thinkingBudget,\n taskBudget: runBehavior?.taskBudget ?? agentBehavior?.taskBudget,\n effortHint: runBehavior?.effortHint ?? agentBehavior?.effortHint,\n thinkingOverrunPolicy: runBehavior?.thinkingOverrunPolicy ?? agentBehavior?.thinkingOverrunPolicy,\n modelOptions: runBehavior?.modelOptions ?? agentBehavior?.modelOptions,\n schema: runBehavior?.schema ?? agentBehavior?.schema,\n cache: runBehavior?.cache ?? agentBehavior?.cache ?? true,\n cacheTtl: runBehavior?.cacheTtl ?? agentBehavior?.cacheTtl,\n toolOutputBudget: runBehavior?.toolOutputBudget ?? agentBehavior?.toolOutputBudget,\n toolOutputBudgetExcludeTools: runBehavior?.toolOutputBudgetExcludeTools ?? agentBehavior?.toolOutputBudgetExcludeTools,\n readFileDefaults: runBehavior?.readFileDefaults ?? agentBehavior?.readFileDefaults,\n compactStrategy: runBehavior?.compactStrategy ?? agentBehavior?.compactStrategy ?? 'off' as const,\n compactThreshold: runBehavior?.compactThreshold ?? agentBehavior?.compactThreshold,\n compactThresholdWindowFraction: runBehavior?.compactThresholdWindowFraction ?? agentBehavior?.compactThresholdWindowFraction,\n compactLowWaterFraction: runBehavior?.compactLowWaterFraction ?? agentBehavior?.compactLowWaterFraction,\n compactSkip: runBehavior?.compactSkip ?? agentBehavior?.compactSkip,\n contextWindow: runBehavior?.contextWindow ?? agentBehavior?.contextWindow,\n compactKeepTurns: runBehavior?.compactKeepTurns ?? agentBehavior?.compactKeepTurns,\n thinkingDecay: runBehavior?.thinkingDecay ?? agentBehavior?.thinkingDecay,\n writeFileExistingPolicy: runBehavior?.writeFileExistingPolicy ?? agentBehavior?.writeFileExistingPolicy,\n textToolCallRescue: runBehavior?.textToolCallRescue ?? agentBehavior?.textToolCallRescue,\n unknownToolRecovery: runBehavior?.unknownToolRecovery ?? agentBehavior?.unknownToolRecovery,\n progressNudges: runBehavior?.progressNudges ?? agentBehavior?.progressNudges,\n dedupReads: runBehavior?.dedupReads ?? agentBehavior?.dedupReads,\n dedupTools: runBehavior?.dedupTools ?? agentBehavior?.dedupTools,\n requireReadBeforeEdit: runBehavior?.requireReadBeforeEdit ?? agentBehavior?.requireReadBeforeEdit,\n trackShellReads: runBehavior?.trackShellReads ?? agentBehavior?.trackShellReads,\n shellToolNudges: runBehavior?.shellToolNudges ?? agentBehavior?.shellToolNudges,\n toolBudgets: runBehavior?.toolBudgets ?? agentBehavior?.toolBudgets,\n repeatGuard: runBehavior?.repeatGuard ?? agentBehavior?.repeatGuard,\n readLineNumbers: runBehavior?.readLineNumbers ?? agentBehavior?.readLineNumbers,\n elideStaleReads: runBehavior?.elideStaleReads ?? agentBehavior?.elideStaleReads,\n // Resolved as a pair from one layer: a run that sets either knob replaces\n // the agent's media policy whole, so a run-level `mediaKeepTurns` isn't\n // shadowed by a profile's `mediaBudget` (or vice versa).\n mediaKeepTurns: mediaPolicyLayer(agentBehavior, runBehavior)?.mediaKeepTurns,\n mediaBudget: mediaPolicyLayer(agentBehavior, runBehavior)?.mediaBudget,\n maxImageEdge: runBehavior?.maxImageEdge ?? agentBehavior?.maxImageEdge,\n autoCompact: runBehavior?.autoCompact ?? agentBehavior?.autoCompact,\n toolDisclosure: runBehavior?.toolDisclosure ?? agentBehavior?.toolDisclosure ?? 'eager' as const,\n mcpToolNameSeparator: runBehavior?.mcpToolNameSeparator ?? agentBehavior?.mcpToolNameSeparator ?? '_' as const,\n toolSearch: runBehavior?.toolSearch ?? agentBehavior?.toolSearch,\n codemode: runBehavior?.codemode ?? agentBehavior?.codemode,\n surfaceMcpInstructions: runBehavior?.surfaceMcpInstructions ?? agentBehavior?.surfaceMcpInstructions ?? true,\n persistThreshold: runBehavior?.persistThreshold ?? agentBehavior?.persistThreshold,\n persistExcludeTools: runBehavior?.persistExcludeTools ?? agentBehavior?.persistExcludeTools,\n persistDir: runBehavior?.persistDir ?? agentBehavior?.persistDir,\n persistMaxBytes: runBehavior?.persistMaxBytes ?? agentBehavior?.persistMaxBytes,\n tasksDir: runBehavior?.tasksDir ?? agentBehavior?.tasksDir,\n shellLongTimeoutMs: runBehavior?.shellLongTimeoutMs ?? agentBehavior?.shellLongTimeoutMs,\n disableBackgroundTasks: runBehavior?.disableBackgroundTasks ?? agentBehavior?.disableBackgroundTasks,\n backgroundOutputCap: runBehavior?.backgroundOutputCap ?? agentBehavior?.backgroundOutputCap,\n backgroundStallWatchdogMs: runBehavior?.backgroundStallWatchdogMs ?? agentBehavior?.backgroundStallWatchdogMs,\n // Shallow merge (not last-writer-wins on the whole bag) so a run can\n // override ONE host extension without re-declaring the rest.\n extensions: (runBehavior?.extensions || agentBehavior?.extensions)\n ? { ...agentBehavior?.extensions, ...runBehavior?.extensions }\n : undefined,\n strictToolPairing: runBehavior?.strictToolPairing ?? agentBehavior?.strictToolPairing ?? false,\n maxPairingRepairsPerTurn: runBehavior?.maxPairingRepairsPerTurn ?? agentBehavior?.maxPairingRepairsPerTurn,\n maxConsecutivePauseTurns: runBehavior?.maxConsecutivePauseTurns ?? agentBehavior?.maxConsecutivePauseTurns,\n maxConsecutiveRefusalResumes: runBehavior?.maxConsecutiveRefusalResumes ?? agentBehavior?.maxConsecutiveRefusalResumes,\n resumeOnMaxTokens: runBehavior?.resumeOnMaxTokens ?? agentBehavior?.resumeOnMaxTokens,\n maxConsecutiveLengthResumes: runBehavior?.maxConsecutiveLengthResumes ?? agentBehavior?.maxConsecutiveLengthResumes,\n persistTurns: runBehavior?.persistTurns ?? agentBehavior?.persistTurns,\n }\n}\n","/**\n * Lazy, idempotent agent bootstrap: the execution handle, skills\n * resolution, and MCP connection — each a shared in-flight promise so\n * concurrent callers converge on one outcome.\n */\n\nimport type { AgentRuntime } from './agent-runtime'\nimport type { ExecutionHandle } from './contexts'\nimport type { McpExecutionBinding } from './mcp'\nimport { DEFAULT_CUSTOM_MCP_CONNECT_TIMEOUT_MS, DEFAULT_SPAWN_TIMEOUT_MS } from './agent-behavior'\nimport { connectMcpServers, wrapDiscoveredMcpTools } from './mcp'\nimport { buildCatalog } from './skills/catalog'\nimport { resolveSkills } from './skills/resolve'\nimport { resolveTimeoutMs, withTimeout } from './timeout'\n\n/** `destroy()` raced an in-flight spawn — the run's own teardown, not a spawn failure. */\nexport class SpawnDestroyedError extends Error {\n constructor() {\n super('agent destroyed while the execution context was spawning')\n this.name = 'SpawnDestroyedError'\n }\n}\n\nexport async function ensureExecutionHandle(rt: AgentRuntime, spawnTimeoutMs: number): Promise<ExecutionHandle> {\n const { hooks, executionContext, resolveInjectedHandle } = rt\n // Fast path only when BOTH the handle exists and the ready hook fired —\n // an injected handle still owes the hook its one `spawned: false` call.\n if (rt.executionHandle && rt.executionReadyFired)\n return rt.executionHandle\n rt.executionSpawnPromise ??= (async () => {\n try {\n const generationAtStart = rt.destroyGeneration\n // A lazily-resolved injected handle is host-owned: bound, never spawned.\n const spawnedThisCall = !rt.executionHandle && !resolveInjectedHandle\n if (!rt.executionHandle) {\n rt.executionHandle = await withTimeout(resolveInjectedHandle ? resolveInjectedHandle() : executionContext.spawn(), {\n operation: 'execution context spawn',\n timeoutMs: spawnTimeoutMs,\n message: `Execution context spawn timed out after ${spawnTimeoutMs}ms (configurable via \\`spawnTimeoutMs\\`).`,\n })\n }\n // Destroy raced THIS spawn (epoch advanced mid-flight): the fresh\n // handle would leak a live container on a dead agent — tear it\n // down and reject. An epoch, not the `destroyed` boolean: spawns\n // STARTED after a destroy are the supported resurrection path.\n if (rt.destroyGeneration !== generationAtStart) {\n const leaked = rt.executionHandle\n rt.executionHandle = null\n // Only reap a handle WE spawned — an injected handle is\n // host-owned and must survive the agent (see `injectedHandle`).\n if (leaked && spawnedThisCall)\n await executionContext.destroy(leaked).catch(() => {})\n throw new SpawnDestroyedError()\n }\n // Surface the bound handle ONCE — the journalable seam for durable\n // hosts that want to record the minted id. `spawned` distinguishes\n // an agent-minted handle from a host-injected one.\n if (!rt.executionReadyFired) {\n rt.executionReadyFired = true\n await hooks.callHook('execution:ready', { handle: rt.executionHandle, spawned: spawnedThisCall })\n }\n return rt.executionHandle\n }\n finally {\n rt.executionSpawnPromise = null\n }\n })()\n return rt.executionSpawnPromise\n}\n\n/**\n * Resolve skills once for the lifetime of the agent. Idempotent and\n * concurrency-safe; no-op when `skills` is disabled or omitted.\n *\n * Used by `run()` (lazy bootstrap), `warmup()` (eager bootstrap), and\n * `activateSkill()` (so the public API doesn't leak the timing of `run()`).\n * Fires `skills:resolve` (mutable `skills` array) and `skills:catalog`\n * (mutable `catalog`) in that order — exactly once per agent.\n */\nexport async function ensureSkillsResolved(rt: AgentRuntime): Promise<void> {\n const { hooks, skillsConfig, skillsDisabled } = rt\n if (skillsDisabled || !skillsConfig)\n return\n if (rt.resolvedSkills)\n return\n if (rt.skillsResolvePromise)\n return rt.skillsResolvePromise\n\n rt.skillsResolvePromise = (async () => {\n // Shell interpolation does not run here. It runs per `skills_use`\n // invocation so command output is fresh on each activation rather than\n // cached at resolution time.\n const bundle = await resolveSkills(skillsConfig)\n rt.resolvedSkills = bundle.skills\n rt.skillsCleanup = bundle.cleanup\n await hooks.callHook('skills:resolve', { skills: rt.resolvedSkills })\n\n // The catalog prose branches on whether the `skills_use` tool will be\n // auto-injected into this agent's tool set. We predict the same gate\n // `run()` applies at tool-merge time: skills tool is registered iff\n // the config doesn't opt out AND the catalog is non-empty. A run-level\n // `tools` override can still suppress injection, but we don't yet know\n // `options.tools` — that's an acceptable mismatch (the model reads the\n // system prompt once; consumers doing aggressive per-run tool overrides\n // already accept that context reflects the agent default).\n const skillsToolRegistered = skillsConfig.tool !== false && rt.resolvedSkills.length > 0\n const catalogCtx = {\n catalog: buildCatalog(rt.resolvedSkills, { skillsToolRegistered }),\n skills: rt.resolvedSkills,\n }\n await hooks.callHook('skills:catalog', catalogCtx)\n rt.skillsCatalog = catalogCtx.catalog\n })()\n\n try {\n await rt.skillsResolvePromise\n }\n catch (err) {\n // Drop the cached promise so a subsequent call gets a fresh attempt.\n // Resolution is local-FS I/O — failures (e.g. tmpdir creation) are\n // usually transient or signal a misconfigured `skills.write`.\n rt.skillsResolvePromise = null\n throw err\n }\n}\n\n/**\n * Pre-connect MCP servers. Returns the shared in-flight promise when a\n * bootstrap is already running, so concurrent callers converge on one\n * connection. Clears the cached promise on failure so the next caller can\n * retry — leaving a rejected promise cached would permanently poison future\n * runs on the same agent.\n */\nexport async function ensureMcpConnected(rt: AgentRuntime, options: { mcpConnectTimeoutMs?: number, maxWallMs?: number } = {}): Promise<void> {\n const { hooks, executionContext, allMcpServers, agentBehavior, mcpConnector, mcpToolWrap } = rt\n if (rt.mcpConnection || allMcpServers.length === 0)\n return\n if (rt.mcpWarmupPromise)\n return rt.mcpWarmupPromise\n\n rt.mcpWarmupPromise = (async () => {\n // Outer connect watchdog. The custom connector has no internal bound;\n // the built-in `connectMcpServers` bounds each server's bootstrap but\n // has no aggregate guard — a hang in discovery aggregation / a\n // bootstrap that ignores its own timeout would leave the first run\n // pending forever. Both paths share this generous bound + late-close.\n const timeoutMs = resolveTimeoutMs(\n options.mcpConnectTimeoutMs ?? agentBehavior?.mcpConnectTimeoutMs,\n DEFAULT_CUSTOM_MCP_CONNECT_TIMEOUT_MS,\n options.maxWallMs,\n )\n let timedOut = false\n // Bind the execution context for `scope: 'context'` servers. The\n // binding is LAZY (`getHandle`), so this costs nothing when no such\n // server exists — and nothing for a sub-agent that inherits the config\n // but reuses the parent's live connection. The handle materialises at\n // the moment a context-scoped transport is actually built.\n const execution: McpExecutionBinding = {\n context: executionContext,\n getHandle: () => ensureExecutionHandle(\n rt,\n resolveTimeoutMs(agentBehavior?.spawnTimeoutMs, DEFAULT_SPAWN_TIMEOUT_MS, options.maxWallMs),\n ),\n }\n const pending = mcpConnector\n ? mcpConnector(allMcpServers, hooks, { execution })\n : connectMcpServers(allMcpServers, undefined, hooks, { execution })\n // A connection that resolves after we stopped awaiting it (timeout) or\n // after destroy() must be closed, not leaked.\n pending.then((lateConnection) => {\n if (timedOut || rt.destroyed)\n void lateConnection.close().catch(() => {})\n }, () => {})\n const connection = await withTimeout(pending, {\n operation: mcpConnector ? 'custom MCP connector' : 'MCP connect',\n timeoutMs,\n onTimeout: () => { timedOut = true },\n message: mcpConnector\n ? `Custom MCP connector timed out after ${timeoutMs}ms.`\n : `MCP server connection timed out after ${timeoutMs}ms (configurable via \\`mcpConnectTimeoutMs\\`).`,\n })\n // If destroy() fired while we were bootstrapping, close the fresh\n // connection immediately rather than leak it into a destroyed agent.\n // destroy() awaits this promise before returning, so its subsequent\n // `if (mcpConnection) close()` branch would handle this too — but only\n // when assignment wins the race. Closing here unconditionally is safer.\n if (rt.destroyed) {\n await connection.close().catch(() => {})\n return\n }\n // Post-discovery wrap (e.g. durable journaling). Applied here so it\n // covers BOTH the default and a custom `mcpConnector`, and every\n // discovered tool — eager or lazily-connected. Only `tools` is\n // re-shaped; `instructions` / `close` are shared with `connection`. A\n // throwing wrap (consumer code) must close the open connection, not leak it.\n try {\n rt.mcpConnection = mcpToolWrap\n ? { ...connection, tools: wrapDiscoveredMcpTools(connection.tools, mcpToolWrap, allMcpServers) }\n : connection\n }\n catch (err) {\n await connection.close().catch(() => {})\n throw err\n }\n })()\n\n try {\n await rt.mcpWarmupPromise\n }\n catch (err) {\n // Drop the cached promise so the next `run()` / `warmup()` call gets a\n // fresh attempt. MCP failures at bootstrap are typically transient\n // (network blip, slow stdio spawn) and the partial-failure path in\n // `connectMcpServers` already tolerates any server that does come up.\n rt.mcpWarmupPromise = null\n throw err\n }\n}\n\nexport async function warmup(rt: AgentRuntime, options: { mcpConnectTimeoutMs?: number, maxWallMs?: number } = {}): Promise<void> {\n // Post-destroy no-op. Without this guard, a `warmup()` (or a `run()` that\n // calls warmup) after `destroy()` would open a fresh MCP connection that\n // nobody ever closes — the `mcpConnection.close()` branch of `destroy` has\n // already run and won't run again.\n if (rt.destroyed)\n return\n // MCP + skills are independent — bootstrap them in parallel. Either side\n // is a no-op when already settled, so repeat `warmup()` calls stay cheap.\n // A rejection on one side still propagates via Promise.all; the other\n // side's promise stays cached and gets reused on the next call.\n await Promise.all([ensureMcpConnected(rt, options), ensureSkillsResolved(rt)])\n}\n","/**\n * A run's durable runtime and scope, as the loop consults them.\n *\n * Every durability decision of the loop goes through here: whether the run\n * replays a journal (`runtime.mode`), whether it keeps step checkpoints\n * (`checkpoint`), which errors are the runtime's control flow\n * (`runtime.isControlError`), the model and tool steps both modes record,\n * the replay-only steps (loop decisions, a compaction summarizer,\n * post-compact file reads, the background sweep) and durable sleeps.\n */\n\nimport type { StepKey } from './durable/keys'\nimport type { DurableRuntime, RunScope, StepHandler, StepHandlerContext, StepHandlers, StepKind } from './durable/types'\nimport type { AgentClock } from './types'\nimport { AsyncLocalStorage } from 'node:async_hooks'\nimport { MODEL_CALL, stepKey } from './durable/keys'\n\nexport interface RunDurability {\n readonly runtime: DurableRuntime\n readonly scope: RunScope\n /**\n * The run records its model and tool calls as steps of a checkpoint-mode\n * runtime, so `Agent.resume` can continue it after a process death. Set\n * when the agent was given that runtime and a session; the memory runtime\n * an agent falls back to records no steps.\n */\n readonly checkpoint: boolean\n /** The loop's current turn index: the `turn` of the keys {@link key} mints. Kept current by `runLoop`. */\n turn: number\n /** Key of the next step named `name` in the current turn; a name repeated in a turn gets a `#n` suffix. */\n key: (name: string) => StepKey\n /** Key of the next model request of the current turn: `attempt` counts the requests the turn made before (retries, fallbacks). */\n modelKey: () => StepKey\n /** Key of the tool call `callId` (a nested call's id is `<caller>/<n>`). */\n toolKey: (callId: string) => StepKey\n /**\n * Outputs of tool steps written to their call's persisted-output blob\n * (`spillStepOutput`), by path, until the dispatch persisted the call's\n * result: the same bytes are not written twice.\n */\n readonly spilled: Map<string, string>\n}\n\n/** The live work of a step the loop issues: `StepLive.callbacks` holds it, the runtime records its result. */\nexport type LiveStepWork<T> = (context: StepHandlerContext) => Promise<T>\n\n/** Set while the live work of a step runs (see {@link insideStepWork}). */\nconst stepWork = new AsyncLocalStorage<true>()\n\n/**\n * Runs the live work it is handed (`StepLive.callbacks`). The steps of the\n * loop close over live state (the provider, the tool, abort, queues), so\n * the work is the closure itself; the runtime records its result.\n */\nconst runLive: StepHandler = async (_payload, context) => stepWork.run(true, () => (context.callbacks as LiveStepWork<never>)(context))\n\n/**\n * Whether the caller runs inside the live work of a step (a tool body, a\n * model stream and the hooks it fires). There the step's record is what a\n * replay sees, so nothing may be journaled on its own: the run's journaled\n * clock and decisions fall back to their live forms.\n */\nexport function insideStepWork(): boolean {\n return stepWork.getStore() === true\n}\n\n/** Kinds of the steps the loop issues. */\nexport const LOOP_STEP_KINDS = {\n model: 'model',\n tool: 'tool',\n /** What `tool:gate` kept for a call whose body has no step of its own (see `keepDirectBodyGate`). */\n gate: 'gate',\n decision: 'decision',\n compact: 'compact',\n /** The run-start background sweep (`ExecutionContext.listBackground`). */\n reconcile: 'reconcile',\n} as const satisfies Record<string, StepKind>\n\nconst LOOP_STEP_HANDLERS: StepHandlers = Object.fromEntries(Object.values(LOOP_STEP_KINDS).map(kind => [kind, runLive]))\n\n/** Open the run's scope on `runtime`. Close it with `scope.close()` when the run ends. */\nexport async function openRunDurability(runtime: DurableRuntime, options: { sessionId: string, runId: string, checkpoint?: boolean }): Promise<RunDurability> {\n const { checkpoint = false, ...run } = options\n const scope = await runtime.openRun({ ...run, handlers: LOOP_STEP_HANDLERS })\n const seen = new Map<string, number>()\n const next = (slot: string): number => {\n const n = seen.get(slot) ?? 0\n seen.set(slot, n + 1)\n return n\n }\n const durability: RunDurability = {\n runtime,\n scope,\n checkpoint: checkpoint && runtime.mode === 'checkpoint',\n turn: 0,\n key: (name) => {\n const n = next(`${durability.turn}:${name}`)\n return stepKey({ run: options.runId, turn: durability.turn, call: n === 0 ? name : `${name}#${n}`, attempt: 0 })\n },\n modelKey: () => stepKey({ run: options.runId, turn: durability.turn, call: MODEL_CALL, attempt: next(`${durability.turn}:\\u0000model`) }),\n toolKey: callId => stepKey({ run: options.runId, turn: durability.turn, call: callId, attempt: 0 }),\n spilled: new Map(),\n }\n return durability\n}\n\n/** Whether the run replays a journal: replay-only logic runs only then. */\nexport function replays(durability: RunDurability): boolean {\n return durability.runtime.mode === 'replay'\n}\n\n/** Whether model and tool calls run as steps: always in replay mode, in checkpoint mode when the run keeps checkpoints. */\nexport function recordsSteps(durability: RunDurability): boolean {\n return replays(durability) || durability.checkpoint\n}\n\n/**\n * The step records a turn commit makes obsolete: every record of the run up\n * to the current loop turn. Only checkpoint runs prune; a journal keeps its\n * entries.\n */\nexport function committedSteps(durability: RunDurability): { runId: string, throughTurn: number } | undefined {\n return durability.checkpoint ? { runId: durability.scope.runId, throughTurn: durability.turn } : undefined\n}\n\n/**\n * The run's clock: in replay mode the runtime's journaled `now()` and\n * `uuid()`, so a replay regenerates the same session metadata; otherwise\n * `clock` (the run's or the agent's). Inside a step's work (a tool body\n * reading `ToolContext.clock`) it is `clock`: the step's record already\n * covers what the work returns, and a journaled read there would nest.\n */\nexport function runClock(durability: RunDurability, clock: AgentClock): AgentClock {\n if (!replays(durability))\n return clock\n const { scope } = durability\n return {\n now: () => insideStepWork() ? clock.now() : scope.now(),\n randomUUID: () => insideStepWork() ? clock.randomUUID() : scope.uuid(),\n }\n}\n\n/**\n * Run `work` as a replay-only journaled step: in replay mode its result is\n * recorded and a replay returns it instead of running `work` again. Other\n * modes just run it. The result must be JSON-serializable.\n */\nexport async function journaledStep<T>(durability: RunDurability, kind: StepKind, name: string, work: () => Promise<T>): Promise<T> {\n if (!replays(durability))\n return work()\n const outcome = await durability.scope.step<T>(\n { kind, key: durability.key(name), payload: { name }, replay: 'safe' },\n { callbacks: work },\n )\n if (outcome.status !== 'completed')\n throw new Error(`journaled step \"${name}\" no longer matches its record`)\n return outcome.value\n}\n","/**\n * Which durable runtime an agent run consults (see `LoopContext.durable`).\n */\n\nimport type { AgentRuntime } from './agent-runtime'\nimport type { DurableRuntime } from './durable/types'\nimport type { RunDurability } from './run-durability'\nimport { openRunDurability } from './run-durability'\n\n/** Open the durable scope of run `runId` on its runtime ({@link runtimeForRun}). */\nexport function openAgentRunDurability(rt: AgentRuntime, runId: string): Promise<RunDurability> {\n return openRunDurability(runtimeForRun(rt), { sessionId: rt.session?.id ?? runId, runId, checkpoint: checkpointsRuns(rt) })\n}\n\n/**\n * Whether the agent's runs keep step checkpoints: it was given a\n * checkpoint-mode runtime and a session to resume from. The memory runtime\n * an agent falls back to records no steps.\n */\nexport function checkpointsRuns(rt: AgentRuntime): boolean {\n return rt.durable?.mode === 'checkpoint' && rt.session !== undefined\n}\n\n/** The runtime of one run: `AgentOptions.durable` when given, else the agent's memory runtime. */\nexport function runtimeForRun(rt: AgentRuntime): DurableRuntime {\n return rt.durable ?? rt.memoryDurable\n}\n","/**\n * MCP tool naming: attributing canonical `mcp_<server>_<tool>` names to\n * their configured server, separator aliases, and the MCP server\n * instructions section of the system prompt.\n */\n\nimport type { AgentBehavior, McpServerConfig } from './types'\nimport { connectMcpServers } from './mcp'\n\n/**\n * Resolve which configured MCP server a namespaced tool name belongs to.\n *\n * Tools coming through {@link connectMcpServers} are keyed `mcp_<server>_<tool>`.\n * Server names may themselves contain underscores, so a naive `split('_')[1]`\n * would mis-attribute tools — instead, we test each configured server name as\n * a prefix candidate and pick the longest match. Each lookup scans every\n * configured server, which is cheap for the handful of servers a host configures.\n */\nexport function resolveServerForTool(\n toolName: string,\n servers: readonly McpServerConfig[] | undefined,\n): McpServerConfig | undefined {\n if (!servers || servers.length === 0)\n return undefined\n let best: McpServerConfig | undefined\n let bestLen = -1\n for (const server of servers) {\n const prefix = `mcp_${server.name}_`\n if (toolName.startsWith(prefix) && server.name.length > bestLen) {\n best = server\n bestLen = server.name.length\n }\n }\n return best\n}\n\nexport function resolveMcpToolParts(\n canonicalName: string,\n servers: readonly McpServerConfig[] | undefined,\n): { server: string, tool: string } | undefined {\n const server = resolveServerForTool(canonicalName, servers)\n if (server) {\n const prefix = `mcp_${server.name}_`\n return { server: server.name, tool: canonicalName.slice(prefix.length) }\n }\n\n if (!canonicalName.startsWith('mcp_'))\n return undefined\n const tail = canonicalName.slice(4)\n const sep = tail.indexOf('_')\n if (sep <= 0 || sep >= tail.length - 1)\n return undefined\n return { server: tail.slice(0, sep), tool: tail.slice(sep + 1) }\n}\n\nexport function buildMcpToolNameSeparatorAliases(\n mcpToolNames: Iterable<string>,\n servers: readonly McpServerConfig[] | undefined,\n separator: NonNullable<AgentBehavior['mcpToolNameSeparator']>,\n): Record<string, string> | undefined {\n if (separator === '_')\n return undefined\n\n const aliases: Record<string, string> = {}\n for (const canonicalName of mcpToolNames) {\n const parts = resolveMcpToolParts(canonicalName, servers)\n if (!parts)\n continue\n const wireName = `mcp${separator}${parts.server}${separator}${parts.tool}`\n if (wireName !== canonicalName)\n aliases[canonicalName] = wireName\n }\n return Object.keys(aliases).length > 0 ? aliases : undefined\n}\n\n/**\n * Render the per-server MCP `instructions` payloads into a single\n * `# MCP Server Instructions` section. Matches the shape the Claude Code\n * SDK emits so eval traces stay comparable.\n *\n * Empty / whitespace-only entries are filtered out upstream (see\n * `bootstrapServer`); this function only renders what survived. Callers\n * that pass an empty map get an empty string back — no stub heading.\n *\n * Output shape:\n *\n * # MCP Server Instructions\n *\n * ## acme\n * The project is provisioned. Use `apply_migration` directly.\n *\n * ## linear\n * …\n *\n * Server names are emitted in Map iteration order (config order), which\n * is byte-stable across runs.\n */\nexport function renderMcpInstructionsSection(instructions: ReadonlyMap<string, string>): string {\n if (instructions.size === 0)\n return ''\n const parts: string[] = ['# MCP Server Instructions', '']\n let first = true\n for (const [name, body] of instructions) {\n if (!first)\n parts.push('')\n first = false\n parts.push(`## ${name}`)\n parts.push(body.trim())\n }\n return parts.join('\\n')\n}\n","/**\n * Extension registry integration: folding the registry into agent options\n * and applying its run / behavior / MCP-config / tool-catalog transforms,\n * skill policies, and tool-result metadata sections.\n */\n\nimport type { ResolvedBehavior } from './agent-behavior'\nimport type { AgentOptions } from './agent-types'\nimport type { ContextExtensionRow, ContextExtensionSection } from './chat/context-breakdown'\nimport type { ExtensionBehaviorTransform, ExtensionMcpConfigTransform, ExtensionOrderedContribution, ExtensionRegistry, ExtensionRuntimeEnv, ExtensionRunTransform, ExtensionSkillPolicy, ExtensionToolCatalogTransform, ExtensionToolResultMetadataRegistration } from './extensions'\nimport type { Preset } from './presets'\nimport type { SkillConfig } from './skills/types'\nimport type { ToolDef, ToolDescriptions } from './tools/types'\nimport type { AgentBehavior, AgentRunOptions, McpServerConfig, SessionContentBlock, SessionTurn, ToolResultMetadata } from './types'\nimport { resolveBehavior } from './agent-behavior'\nimport { resolveMcpToolParts } from './agent-mcp-naming'\nimport { errorMessage } from './errors'\nimport { composeExtensionPreset } from './extensions/compose-preset'\n\nfunction extensionEnv<T>(entry: ExtensionOrderedContribution<T>): ExtensionRuntimeEnv {\n return { extensionName: entry.extensionName, source: entry.source }\n}\n\nexport function applyRunTransforms(\n options: AgentRunOptions,\n transforms: readonly ExtensionOrderedContribution<ExtensionRunTransform>[] | undefined,\n): AgentRunOptions {\n if (!transforms?.length)\n return options\n let next: AgentRunOptions = { ...options }\n for (const entry of transforms) {\n try {\n const out = entry.value(next, extensionEnv(entry))\n if (out)\n next = { ...out }\n }\n catch (err) {\n debugExtensionRuntimeError(entry.extensionName, 'run transform', err)\n }\n }\n return next\n}\n\nexport function applyBehaviorTransforms(\n behavior: ResolvedBehavior,\n transforms: readonly ExtensionOrderedContribution<ExtensionBehaviorTransform>[] | undefined,\n explicitRunBehavior: AgentBehavior | undefined,\n): ResolvedBehavior {\n if (!transforms?.length)\n return behavior\n let next: AgentBehavior = { ...behavior }\n for (const entry of transforms) {\n try {\n const out = entry.value(next, extensionEnv(entry))\n if (out)\n next = { ...out }\n }\n catch (err) {\n debugExtensionRuntimeError(entry.extensionName, 'behavior transform', err)\n }\n }\n if (explicitRunBehavior) {\n const writable = next as Record<string, unknown>\n for (const [key, value] of Object.entries(explicitRunBehavior)) {\n if (value !== undefined)\n writable[key] = value\n }\n }\n return resolveBehavior(next)\n}\n\nexport function applyMcpConfigTransforms(\n servers: readonly McpServerConfig[],\n transforms: readonly ExtensionOrderedContribution<ExtensionMcpConfigTransform>[] | undefined,\n): McpServerConfig[] {\n let next = [...servers]\n if (!transforms?.length)\n return next\n for (const entry of transforms) {\n try {\n const out = entry.value(next, extensionEnv(entry))\n if (out)\n next = [...out]\n }\n catch (err) {\n debugExtensionRuntimeError(entry.extensionName, 'MCP config transform', err)\n }\n }\n return next\n}\n\nexport function applyToolCatalogTransforms(\n tools: Readonly<Record<string, ToolDef>>,\n transforms: readonly ExtensionOrderedContribution<ExtensionToolCatalogTransform>[] | undefined,\n phase: 'run' | 'pre-run',\n mcpToolNames: ReadonlySet<string>,\n): Record<string, ToolDef> {\n let next: Readonly<Record<string, ToolDef>> = tools\n if (transforms?.length) {\n for (const entry of transforms) {\n try {\n const out = entry.value(next, { ...extensionEnv(entry), phase, mcpToolNames })\n if (out)\n next = out\n }\n catch (err) {\n debugExtensionRuntimeError(entry.extensionName, 'tool catalog transform', err)\n }\n }\n }\n const out: Record<string, ToolDef> = {}\n for (const tool of Object.values(next)) {\n if (tool?.spec?.name)\n out[tool.spec.name] = tool\n }\n return out\n}\n\n/**\n * Apply `AgentOptions.toolDescriptions` to a spec-name-indexed registry.\n * Returns a new record; matched tools are shallow-copied with a rewritten\n * `spec.description` so the host's original `ToolDef` (and the framework's\n * `builtinShell` identity) is never mutated. Unmatched keys are ignored.\n *\n * Callers run this LAST in their pipeline — after catalog transforms and the\n * built-in `shell` rewrite — so a function-form override sees the text the\n * model would otherwise have received.\n */\nexport function applyToolDescriptionOverrides(\n tools: Record<string, ToolDef>,\n overrides: ToolDescriptions | undefined,\n mcpToolNames: ReadonlySet<string>,\n mcpServers: readonly McpServerConfig[] | undefined,\n): Record<string, ToolDef> {\n if (!overrides || Object.keys(overrides).length === 0)\n return tools\n const out: Record<string, ToolDef> = { ...tools }\n for (const [name, override] of Object.entries(overrides)) {\n const tool = out[name]\n if (!tool)\n continue\n const current = tool.spec.description || ''\n let description: string\n if (typeof override === 'string') {\n description = override\n }\n else if (typeof override === 'function') {\n const mcpServer = mcpToolNames.has(name) ? resolveMcpToolParts(name, mcpServers)?.server : undefined\n description = override(current, { name, spec: tool.spec, ...(mcpServer ? { mcpServer } : {}) })\n }\n else {\n continue\n }\n if (typeof description !== 'string' || description === current)\n continue\n out[name] = { ...tool, spec: { ...tool.spec, description } }\n }\n return out\n}\n\nexport async function applySkillPolicies(input: {\n policies: readonly ExtensionOrderedContribution<ExtensionSkillPolicy>[] | undefined\n skills: readonly SkillConfig[]\n options: AgentRunOptions\n activate: (skill: SkillConfig) => Promise<void>\n}): Promise<void> {\n if (!input.policies?.length || input.skills.length === 0)\n return\n const byName = new Map(input.skills.map(skill => [skill.name, skill]))\n for (const entry of input.policies) {\n const policy = entry.value\n if (!policy.autoActivate)\n continue\n const skill = byName.get(policy.name)\n if (!skill)\n continue\n try {\n const ok = policy.when\n ? await policy.when({\n ...extensionEnv(entry),\n skills: input.skills,\n run: {\n ...(input.options.model !== undefined ? { model: input.options.model } : {}),\n ...(input.options.prompt !== undefined ? { prompt: input.options.prompt } : {}),\n ...(input.options.parentRunId !== undefined ? { parentRunId: input.options.parentRunId } : {}),\n ...(input.options.depth !== undefined ? { depth: input.options.depth } : {}),\n },\n })\n : true\n if (ok)\n await input.activate(skill)\n }\n catch (err) {\n debugExtensionRuntimeError(entry.extensionName, 'skill policy', err)\n }\n }\n}\n\nexport function toolResultMetadataSections(\n registrations: readonly ExtensionOrderedContribution<ExtensionToolResultMetadataRegistration>[] | undefined,\n turns: readonly SessionTurn[],\n): ContextExtensionSection[] {\n if (!registrations?.length)\n return []\n const out: ContextExtensionSection[] = []\n for (const entry of registrations) {\n const registration = entry.value\n const entries: Array<{ value: ToolResultMetadata[string], turn: SessionTurn, block: Extract<SessionContentBlock, { type: 'tool_result' }> }> = []\n for (const turn of turns) {\n for (const block of turn.content) {\n if (block.type !== 'tool_result' || !block.metadata)\n continue\n const value = block.metadata[registration.namespace]\n if (value !== undefined)\n entries.push({ value, turn, block })\n }\n }\n if (entries.length === 0)\n continue\n try {\n const projected = registration.contextRows?.({\n namespace: registration.namespace,\n entries,\n turns,\n })\n if (projected) {\n if (Array.isArray(projected)) {\n // An explicitly-empty projection means \"nothing to show\" — skip the\n // namespace entirely rather than emit a header with no rows.\n if (projected.length === 0)\n continue\n if (projected.every(row => row && typeof row === 'object' && 'value' in row))\n out.push({ id: `metadata:${registration.namespace}`, label: registration.namespace, rows: projected as ContextExtensionRow[] })\n else\n out.push(...projected as ContextExtensionSection[])\n }\n else {\n out.push(projected as ContextExtensionSection)\n }\n continue\n }\n }\n catch (err) {\n debugExtensionRuntimeError(entry.extensionName, 'tool-result metadata projection', err)\n }\n out.push({\n id: `metadata:${registration.namespace}`,\n label: registration.namespace,\n rows: [{ label: 'Entries', value: String(entries.length) }],\n })\n }\n return out\n}\n\nfunction debugExtensionRuntimeError(extensionName: string, surface: string, err: unknown): void {\n if (!process.env.ZIDANE_DEBUG)\n return\n process.stderr.write(`[zidane/extensions] ${extensionName} ${surface} failed: ${errorMessage(err)}\\n`)\n}\n\n/**\n * Fold a pre-built {@link ExtensionRegistry} into plain {@link AgentOptions},\n * returning a fresh options object with `extensions` stripped — so the rest of\n * {@link createAgent} runs against a registry-free shape and stays untouched.\n *\n * Precedence mirrors the chat host (`composePresets(extensionPreset,\n * profile.preset)`): the extension is the BASE, explicit `AgentOptions` WIN on\n * collision.\n * - `tools` (merged by name) / `mcpServers` (deduped by name) / `toolAliases`\n * / `behavior` (tool-name-keyed sub-records deep-merge) — composed via\n * {@link composeExtensionPreset}(registry, explicit), which layers the\n * explicit preset over the extension's; explicit wins on collision.\n * - `skills` — last-wins, so an explicit `skills` REPLACES the extension's\n * wholesale (`composePresets` doesn't per-skill merge).\n * - `hooks` — bucketed per event so handlers from BOTH sides fire (extension\n * first, then explicit); \"winning\" doesn't apply, both run.\n * - subagents — whichever `spawn` tool survives the compose (explicit or\n * extension) is rebuilt with the extensions' subagents and the runtime's\n * subagent edits so the model can dispatch extension subagents.\n *\n * `extensions.runtime` (the runtime's registries) becomes `extensionRuntime`\n * unless the options already carry one: interceptors and catalogs reach the\n * agent through it. Global instructions (`ctx.instructions.add` without a\n * session) are appended to `system` when the agent is created.\n *\n * `themes` / `agents` / `providers` are host/picker concerns and\n * intentionally left out.\n */\nexport function foldExtensionRegistry(options: AgentOptions): AgentOptions {\n const reg = options.extensions\n if (!reg)\n return options\n\n // Explicit options as a preset slice, layered LAST so they win. Carries the\n // fields `buildExtensionPreset` can contribute, plus toolAliases,\n // toolDescriptions and behavior, which extensions never set but we route\n // through for a uniform merge.\n const explicitPreset: Preset = {\n ...(options.tools !== undefined ? { tools: options.tools } : {}),\n ...(options.toolAliases !== undefined ? { toolAliases: options.toolAliases } : {}),\n ...(options.toolDescriptions !== undefined ? { toolDescriptions: options.toolDescriptions } : {}),\n ...(options.behavior !== undefined ? { behavior: options.behavior } : {}),\n ...(options.mcpServers !== undefined ? { mcpServers: options.mcpServers } : {}),\n ...(options.skills !== undefined ? { skills: options.skills } : {}),\n ...(options.hooks !== undefined ? { hooks: options.hooks } : {}),\n ...(options.runTransforms !== undefined ? { runTransforms: options.runTransforms } : {}),\n ...(options.behaviorTransforms !== undefined ? { behaviorTransforms: options.behaviorTransforms } : {}),\n ...(options.toolCatalogTransforms !== undefined ? { toolCatalogTransforms: options.toolCatalogTransforms } : {}),\n ...(options.mcpConfigTransforms !== undefined ? { mcpConfigTransforms: options.mcpConfigTransforms } : {}),\n ...(options.skillPolicies !== undefined ? { skillPolicies: options.skillPolicies } : {}),\n ...(options.toolResultMetadata !== undefined ? { toolResultMetadata: options.toolResultMetadata } : {}),\n }\n const composed = composeExtensionPreset(reg, explicitPreset)\n // Global extension instructions (`ctx.instructions.add` without a session) trail the agent's own `system`.\n const instructions = reg.runtime?.instructions.list() ?? []\n const system = instructions.length === 0 ? options.system : [...(options.system ? [options.system] : []), ...instructions].join('\\n\\n')\n const contextBreakdownSections = [\n ...reg.contextBreakdownSections,\n ...reg.contextPanelSections,\n ...(options.contextBreakdownSections ?? []),\n ]\n\n return {\n ...options,\n ...(composed.tools !== undefined ? { tools: composed.tools } : {}),\n ...(composed.toolAliases !== undefined ? { toolAliases: composed.toolAliases } : {}),\n ...(composed.toolDescriptions !== undefined ? { toolDescriptions: composed.toolDescriptions } : {}),\n ...(composed.behavior !== undefined ? { behavior: composed.behavior } : {}),\n ...(composed.mcpServers !== undefined ? { mcpServers: composed.mcpServers } : {}),\n ...(composed.skills !== undefined ? { skills: composed.skills } : {}),\n ...(composed.hooks !== undefined ? { hooks: composed.hooks } : {}),\n ...(composed.runTransforms !== undefined ? { runTransforms: composed.runTransforms } : {}),\n ...(composed.behaviorTransforms !== undefined ? { behaviorTransforms: composed.behaviorTransforms } : {}),\n ...(composed.toolCatalogTransforms !== undefined ? { toolCatalogTransforms: composed.toolCatalogTransforms } : {}),\n ...(composed.mcpConfigTransforms !== undefined ? { mcpConfigTransforms: composed.mcpConfigTransforms } : {}),\n ...(composed.skillPolicies !== undefined ? { skillPolicies: composed.skillPolicies } : {}),\n ...(composed.toolResultMetadata !== undefined ? { toolResultMetadata: composed.toolResultMetadata } : {}),\n ...(system !== undefined ? { system } : {}),\n ...(contextBreakdownSections.length > 0 ? { contextBreakdownSections } : {}),\n // The extension runtime's registries ride through; explicit `extensionRuntime` wins.\n ...(reg.runtime && options.extensionRuntime === undefined ? { extensionRuntime: reg.runtime } : {}),\n extensions: undefined,\n }\n}\n","/**\n * Session history for a run: resume validation, seed-turn selection,\n * orphan tool_use repair, and the gates that rehydrate skill activation and\n * read-before-edit state from the transcript.\n */\n\nimport type { Hookable } from 'hookable'\n\nimport type { AgentHooks } from './agent-hooks'\nimport type { AliasMaps } from './aliasing'\nimport type { ExecutionContext, ExecutionHandle } from './contexts'\nimport type { Provider, ToolResult } from './providers'\nimport type { Session } from './session'\nimport type { SkillActivationState } from './skills/activation'\nimport type { SkillConfig } from './skills/types'\nimport type { AgentClock, AgentRunOptions, SessionTurn } from './types'\nimport { resumeChainRunIds } from './session'\nimport { detectTurnInterruption, filterUnresolvedToolUses, SYNTHETIC_TOOL_RESULT_PLACEHOLDER } from './session/messages'\nimport { getReadState, hydrateReadStateFromSessionAsync, readStateKey } from './tools/read-state'\n\n/**\n * If the trailing assistant turn in `turns` carries `tool_call` blocks with\n * no matching `tool_result` in a following user turn, mutate `turns` in\n * place to append a synthetic tool-results turn that closes every dangling\n * tool_use id. Used by the error path of `agent.run` to prevent a thrown\n * loop from leaving the persisted session with an orphan tool_use — which\n * Anthropic rejects on resume.\n *\n * Each synthetic result carries the shared\n * {@link SYNTHETIC_TOOL_RESULT_PLACEHOLDER} text (so consumers can pattern-\n * match the same way they would on a live pre-send repair) and\n * `isError: true` so the model treats it as a failed call.\n *\n * Fires `pairing:repair` (mode `orphan-tool-use-append`) for each synthetic\n * result, mirroring the wire-level repair pass's observability so postmortem\n * dashboards see the same telemetry shape regardless of where the orphan\n * was detected.\n *\n * No-op when:\n * - The trailing turn isn't an assistant turn (already closed, or session\n * ends with the seeded user prompt).\n * - The assistant turn has no `tool_call` blocks.\n * - All tool_use ids are already answered by a tool_result in an earlier\n * turn (defensive — shouldn't happen but cheap to check).\n */\nexport async function synthesizeMissingToolResults(\n turns: SessionTurn[],\n syntheticTurnId: string,\n runId: string,\n provider: Provider,\n hooks: Hookable<AgentHooks>,\n clock: AgentClock,\n): Promise<void> {\n if (turns.length === 0)\n return\n const last = turns[turns.length - 1]\n if (last.role !== 'assistant')\n return\n const pendingIds: string[] = []\n for (const block of last.content) {\n if (block.type === 'tool_call')\n pendingIds.push(block.id)\n }\n if (pendingIds.length === 0)\n return\n // Defensive: drop the IDs that an earlier turn already answered with a\n // tool_result. Belt-and-suspenders; the caller only invokes us when the\n // assistant turn is the last one.\n const answered = new Set<string>()\n for (const turn of turns.slice(0, -1)) {\n for (const block of turn.content) {\n if (block.type === 'tool_result')\n answered.add(block.callId)\n }\n }\n const dangling = pendingIds.filter(id => !answered.has(id))\n if (dangling.length === 0)\n return\n const results: ToolResult[] = dangling.map(id => ({\n id,\n content: SYNTHETIC_TOOL_RESULT_PLACEHOLDER,\n isError: true,\n }))\n const msg = provider.toolResultsMessage(results)\n turns.push({\n id: syntheticTurnId,\n runId,\n role: msg.role,\n content: msg.content,\n createdAt: await clock.now(),\n })\n for (const callId of dangling) {\n await hooks.callHook('pairing:repair', {\n mode: 'orphan-tool-use-append',\n callId,\n messageIndex: turns.length - 2,\n })\n }\n}\n\ninterface SeedTurnsInput {\n session: Session | null | undefined\n options: AgentRunOptions\n /**\n * Cached `filterUnresolvedToolUses(session.turns)` from the resume guard, when\n * that guard already ran over the unmodified turn list. Reused to avoid a\n * second full scan; ignored when the subagent filter changed the view.\n */\n resumeFilteredTurns: SessionTurn[] | undefined\n /**\n * `Agent.resume` continues this run: a spawned child's (`parentRunId`)\n * history is its own run lineage, like a `resumeRunId` seed.\n */\n resumedRunId?: string\n}\n\n/**\n * Choose the prior turns a run starts from, or `undefined` for a fresh start.\n *\n * Two resume flavors:\n * - `resumeRunId` (child-run resume), or `resumedRunId` on a spawned child\n * that `Agent.resume` continues: seed ONLY the referenced prior run's\n * lineage. Used by the spawn tool to continue a stopped/failed subagent —\n * the parent's conversation (and every other child's) stays invisible,\n * mirroring how a fresh child starts from just its task prompt. Allowed\n * WITH `parentRunId` set (unlike a full-session resume).\n * - full-session resume: the historical top-level path, on re-runs\n * (`runs > 0`) or promptless runs (session turns already contain the user\n * message). **Excluded for child agents**: when the spawn tool runs with\n * `persist: true`, the child shares the parent's session for *storage* but\n * its conversation must start fresh from the task prompt. Otherwise the\n * child would pull in the parent's in-flight assistant turn — including the\n * parent's pending `spawn` tool_use — and every provider (Anthropic loudly,\n * OpenAI implicitly) rejects a history where a `tool_use` lacks its\n * matching `tool_result`.\n */\nexport function selectSeedTurns(input: SeedTurnsInput): SessionTurn[] | undefined {\n const { session, options, resumeFilteredTurns } = input\n\n const lineageOf = options.resumeRunId ?? (options.parentRunId ? input.resumedRunId : undefined)\n if (lineageOf && session) {\n // Seed the FULL resume lineage: a resumed run only persists the turns it\n // produced itself, so a second-generation resume (child-3 resumes child-2\n // resumes child-1) must union the turns of every run in the\n // `resumedFromRunId` chain — filtering on the latest run alone would\n // silently drop the original conversation. `session.turns` is\n // chronological, so the union stays in order.\n //\n // `filterUnresolvedToolUses` repairs a child killed mid-tool: an orphan\n // `tool_use` with no matching `tool_result` would be rejected by the\n // provider on the very first continuation call.\n const chain = resumeChainRunIds(session.runs, lineageOf)\n return filterUnresolvedToolUses(\n session.turns.filter(t => t.runId !== undefined && chain.has(t.runId)),\n )\n }\n\n const isResume = session\n && session.turns.length > 0\n && (session.runs.length > 0 || !options.prompt)\n && !options.parentRunId\n && !options.resumeRunId\n if (!isResume)\n return undefined\n\n // Filter out turns from subagent runs (depth > 0). With `persist: true` every\n // child agent appends its own user/assistant turns to the shared\n // `session.turns` array, sandwiched between the parent's `tool_call` (for\n // `spawn`) and the parent's `tool_result`. Replaying those child turns into\n // the resumed parent's conversation puts an unrelated user/assistant pair\n // right after the `tool_call`, breaking the Anthropic `tool_use →\n // tool_result` adjacency rule and crashing the very first API call after\n // reload.\n //\n // We keep turns with no `runId` (legacy data) and turns whose `runId` belongs\n // to a top-level run; everything that came from a subagent run stays in the\n // persisted session for transcript reconstruction (see `eventsFromTurns`) but\n // is invisible to the resumed conversation.\n const childRunIds = childRunIdSet(session)\n const resumed = childRunIds.size === 0\n ? session.turns\n : session.turns.filter(t => !t.runId || !childRunIds.has(t.runId))\n\n // L1 — defense at resume time: drop assistant turns whose every `tool_call`\n // is unresolved (no matching `tool_result` later in the transcript). Without\n // this, a session killed mid-tool would resume with an orphan tool_use that\n // Anthropic rejects on the very first API call. The runtime conversation uses\n // the filtered view; the persisted session keeps the original turns so\n // transcript replay still shows what the model tried to do.\n //\n // When the resume guard above already filtered the unmodified `session.turns`,\n // reuse that cached result; otherwise (subagent filter removed something)\n // filter the post-subagent view.\n return (resumeFilteredTurns && resumed === session.turns)\n ? resumeFilteredTurns\n : filterUnresolvedToolUses(resumed)\n}\n\n/**\n * Rebuild skill activation state from a session's `skills_use` tool_calls,\n * honoring the most recent `mode` per skill (`activate` wins unless a later\n * `deactivate` overrides it). Idempotent: `activate()` is a no-op for\n * already-active skills, so re-running is safe and only fires `skills:activate`\n * (`via: 'resume'`) for skills it newly activates. Shared by the run-start\n * resume rehydration and the mid-loop durable-replay gate below.\n */\nexport async function rehydrateActiveSkillsFromTurns(\n turns: readonly SessionTurn[],\n resolvedSkills: readonly SkillConfig[],\n state: SkillActivationState,\n hooks: Hookable<AgentHooks>,\n): Promise<void> {\n const skillsByName = new Map(resolvedSkills.map(s => [s.name, s]))\n const lastModeBySkill = new Map<string, 'activate' | 'deactivate'>()\n for (const turn of turns) {\n if (turn.role !== 'assistant')\n continue\n for (const block of turn.content) {\n if (block.type !== 'tool_call' || block.name !== 'skills_use')\n continue\n const input = block.input as { name?: string, mode?: string } | undefined\n const skillName = input?.name\n if (!skillName)\n continue\n lastModeBySkill.set(skillName, input?.mode === 'deactivate' ? 'deactivate' : 'activate')\n }\n }\n for (const [skillName, mode] of lastModeBySkill) {\n if (mode !== 'activate')\n continue\n const skill = skillsByName.get(skillName)\n if (!skill)\n continue\n if (state.activate(skill, 'resume') === 'ok')\n await hooks.callHook('skills:activate', { skill, via: 'resume' })\n }\n}\n\n/**\n * Skill-activation pre-hydration, as a `tool:gate` hook. Same hazard shape as\n * `installReadBeforeEditHydrationGate`: `skills_read` / `skills_run_script`\n * refuse inside their (possibly journaled) `execute` body when the named skill\n * isn't active, but activation lives in an in-memory state machine populated by\n * `skills_use`'s LIVE body. Under durable replay, a `skills_use` from earlier in\n * the SAME run is replayed from the journal (its `state.activate` never re-runs),\n * and the run-start resume rehydration only saw the pre-run turns — so the later\n * `skills_read` runs live with the skill inactive and journals a permanent\n * \"skill is not active\" refusal.\n *\n * This gate fires in the loop before the body, re-runs on every replay, and\n * rebuilds activation from the in-memory `session.turns` (which replay\n * repopulates with the within-run `skills_use`) when the target skill is\n * inactive. It never blocks — the body keeps the authoritative check.\n */\nexport function installSkillsActivationHydrationGate(\n hooks: Hookable<AgentHooks>,\n deps: {\n session: Session | undefined\n getResolvedSkills: () => readonly SkillConfig[] | null\n state: SkillActivationState\n },\n): () => void {\n const session = deps.session\n if (!session)\n return () => {}\n return hooks.hook('tool:gate', async (ctx) => {\n if (ctx.name !== 'skills_read' && ctx.name !== 'skills_run_script')\n return\n const resolvedSkills = deps.getResolvedSkills()\n if (!resolvedSkills || resolvedSkills.length === 0)\n return\n const skillName = typeof (ctx.input as { name?: unknown })?.name === 'string'\n ? (ctx.input as { name: string }).name\n : undefined\n if (!skillName || deps.state.isActive(skillName))\n return\n try {\n await rehydrateActiveSkillsFromTurns(session.turns, resolvedSkills, deps.state, hooks)\n }\n catch {\n // Best-effort — the body still performs the authoritative `isActive` check.\n }\n })\n}\n\n/**\n * Read-before-edit read-state pre-hydration, as a `tool:gate` hook.\n *\n * The `requireReadBeforeEdit` verdict lives inside `edit` / `multi_edit`'s\n * `execute` body, which compares the model-provided path against the\n * per-session read-state map. That map is in-memory and populated by side\n * effects (`read_file`'s `rememberRead`, a prior edit's `readState.set`) that\n * run only on LIVE execution. Under a replay-mode durable runtime those side\n * effects DON'T re-run on replay. Worse, recording the tool body freezes\n * whatever verdict the body produced. So if the map is empty the first time an\n * edit runs live (e.g. the preceding `read_file` was replayed from the journal\n * on a fresh process), the edit records a permanent \"has not been read\"\n * rejection that no later replay can undo.\n *\n * This gate closes that hole independently of how the consumer wraps tools: it\n * fires in zidane's loop BEFORE the tool's (possibly journaled) `execute`, and\n * re-fires on every replay. When the target path is missing from the read-state\n * map, it rebuilds the map from the DURABLE transcript (`session.turns`, which\n * replay repopulates) — purely, outside any journal — so the downstream\n * `execute` check sees a populated map and never journals a false negative.\n *\n * Cheap by construction: it only scans when the path is genuinely absent from\n * the map (a single `Map.has` on the hot path), and never blocks — the actual\n * verdict (including disk-drift detection) stays in `execute`.\n */\nexport function installReadBeforeEditHydrationGate(\n hooks: Hookable<AgentHooks>,\n enabled: boolean,\n deps: {\n session: Session | undefined\n getHandle: () => ExecutionHandle | null | undefined\n execution: ExecutionContext\n aliasMaps: AliasMaps\n defaultLineNumbers: boolean\n },\n): () => void {\n const session = deps.session\n if (!enabled || !session)\n return () => {}\n return hooks.hook('tool:gate', async (ctx) => {\n // Names are canonical at gate time (the loop rewrites wire → canonical\n // before dispatch), so match the canonical edit tools directly.\n if (ctx.name !== 'edit' && ctx.name !== 'multi_edit')\n return\n const handle = deps.getHandle()\n if (!handle)\n return\n const target = typeof (ctx.input as { path?: unknown })?.path === 'string'\n ? (ctx.input as { path: string }).path\n : undefined\n if (!target)\n return\n const map = getReadState(session)\n if (!map)\n return\n const key = readStateKey(handle.cwd, target)\n if (map.has(key))\n return\n try {\n await hydrateReadStateFromSessionAsync(session, handle.cwd, {\n defaultLineNumbers: deps.defaultLineNumbers,\n aliasMaps: deps.aliasMaps,\n readFileForHash: async (path) => {\n try {\n return await deps.execution.readFile(handle, path)\n }\n catch {\n return null\n }\n },\n })\n }\n catch {\n // Best-effort — `execute` still performs the authoritative check, and a\n // recoverable \"re-read first\" tool_result is the worst case.\n }\n })\n}\n\n/**\n * Set of runIds belonging to subagent (depth > 0) runs in a session. Used to\n * filter child-run turns out of the resumed conversation and out of\n * last-turn-usage accounting — both need \"everything a subagent produced\",\n * keyed by `runId`. Returns an empty set for a sessionless agent.\n */\nexport function childRunIdSet(session: Session | null | undefined): Set<string> {\n const ids = new Set<string>()\n for (const r of session?.runs ?? []) {\n if ((r.depth ?? 0) > 0)\n ids.add(r.id)\n }\n return ids\n}\n\n/**\n * Validate `agent.run()`'s prompt/resume preconditions and compute the\n * unresolved-tool-filtered resume view (returned for reuse in the seed block).\n *\n * `prompt` is required unless resuming a session that already has turns. The\n * resume guard inspects the trailing turn AFTER filtering unresolved tool_uses\n * (L1) — a session that ended on an orphan assistant turn (process death\n * mid-tool, `kill -9`) gets its trailing assistant dropped before the\n * \"trailing must be user\" check, so a recoverable session doesn't get a\n * spurious `cannot resume without prompt` error.\n *\n * Throws on an unrecoverable resume request; otherwise returns the filtered\n * turns (or `undefined` when the session has no turns).\n */\nexport function validateAndPrepareResume(\n session: Session | null | undefined,\n prompt: AgentRunOptions['prompt'],\n hasPendingTaskNotifications = false,\n): SessionTurn[] | undefined {\n const hasSessionTurns = !!session && session.turns.length > 0\n if (!prompt && !hasSessionTurns && !hasPendingTaskNotifications)\n throw new Error('prompt is required when no session with existing turns is provided')\n\n let resumeFilteredTurns: SessionTurn[] | undefined\n if (hasSessionTurns)\n resumeFilteredTurns = filterUnresolvedToolUses(session!.turns)\n\n // A prompt-less run is also legal when background-task exits are queued:\n // the run-start drain seeds a user turn carrying the `<task-notification>`\n // blocks, so the conversation stays well-formed even though the trailing\n // persisted turn is a completed assistant message. This is the \"auto-wake\"\n // path — hosts call `run({ prompt: '' })` when `hasPendingTaskNotifications`\n // flips true while the agent is idle.\n if (!prompt && resumeFilteredTurns && !hasPendingTaskNotifications) {\n const lastTurn = resumeFilteredTurns.at(-1)\n if (lastTurn && lastTurn.role !== 'user') {\n const tail = detectTurnInterruption(resumeFilteredTurns)\n const detail = tail === 'completed'\n ? 'last turn is a completed assistant message'\n : 'last turn is mid-stream assistant content'\n throw new Error(`cannot resume without prompt: ${detail}. Pass a prompt to agent.run({ prompt: … }).`)\n }\n }\n return resumeFilteredTurns\n}\n","/**\n * Adapters that run interceptors from inside the existing mutating hook call\n * sites. The agent build registers each on the agent bus\n * (`agent.hooks.hook('tool:gate', bridgeLegacyMutatingHook(registry, 'tool:gate'))`)\n * so the loop keeps firing the hooks it fires today while extensions write\n * interceptors.\n *\n * `mcp:tool:gate` and `mcp:tool:transform` have no bridge on purpose:\n * `tool:gate` and `tool:transform` already fire for MCP tools under their\n * `mcp_<server>_<tool>` name, so bridging both would run each chain twice.\n * `oauth:refresh` has none either: its payload is a clone, sent after the\n * credentials were stored, so nothing written to it is read back.\n */\n\nimport type { AgentHooks } from '../../agent'\nimport type { JsonValue } from '../../types'\nimport type { HookEvents, ToolCall, ToolCallDecision } from '../api/hooks'\nimport type { InterceptorName, InterceptorRegistry } from './registry'\nimport { isSafeRecordKey } from '../shared'\nimport { isJson } from '../storage/json'\nimport { readonlyView } from './readonly'\n\n/** Each mutating agent hook and the interceptor that replaces it. */\nexport const LEGACY_INTERCEPTORS = {\n 'tool:gate': 'tool.call',\n 'tool:transform': 'tool.result',\n 'validation:coerce': 'validation',\n 'context:transform': 'context',\n 'system:transform': 'system',\n 'mcp:tools:filter': 'mcp.tools',\n 'tracing:redact': 'tracing.redact',\n 'content-ref:resolve': 'content-ref.resolve',\n} as const satisfies Partial<Record<keyof AgentHooks, InterceptorName>>\n\n/** A mutating agent hook that has a bridge. */\nexport type LegacyMutatingHook = keyof typeof LEGACY_INTERCEPTORS\n\n/** The agent-bus handler a bridge returns: synchronous for `tracing:redact`, async otherwise. */\nexport type LegacyBridgeHandler<K extends LegacyMutatingHook> = K extends 'tracing:redact'\n ? (ctx: HookEvents[K]) => void\n : (ctx: HookEvents[K]) => Promise<void>\n\n/** Options of {@link bridgeLegacyMutatingHook}. */\nexport interface LegacyBridgeOptions {\n /** The session of the bus the handler is registered on. Fills `sessionId` on interceptor inputs. */\n sessionId?: () => string | undefined\n /**\n * Resolves a `tool.call` that ended on `'ask'` through the host's approval\n * flow. Without it, an `'ask'` blocks the call. Never called for a resumed call.\n */\n onAsk?: (call: ToolCall) => Promise<Exclude<ToolCallDecision, 'ask'>> | Exclude<ToolCallDecision, 'ask'>\n /** The MCP server of a namespaced tool name, for `ToolCall.mcpServer`. */\n mcpServerOf?: (tool: string) => string | undefined\n}\n\nconst NO_APPROVAL_FLOW = 'This call needs approval, and no approval flow is available.'\n\n/** Replaces every own key of `target` with those of `next`, keeping the object (the hooks' in-place mutation contract). */\nfunction replaceInPlace(target: Record<string, unknown>, next: Readonly<Record<string, unknown>>): void {\n if (target === next)\n return\n for (const key of Object.keys(target))\n delete target[key]\n Object.assign(target, next)\n}\n\nfunction optional<T extends Record<string, unknown>>(fields: T): Partial<T> {\n const out: Partial<T> = {}\n for (const [k, v] of Object.entries(fields)) {\n if (v !== undefined)\n out[k as keyof T] = v as T[keyof T]\n }\n return out\n}\n\n/**\n * Returns an agent-bus handler for mutating hook `name` that runs the\n * matching interceptor chain and writes its result back onto the hook\n * context the way the call site reads it.\n *\n * - `tool:gate`: skips calls an earlier handler already blocked or answered.\n * `{ block }` sets `block`/`reason`, `{ result }` sets `result`, `{ patch }`\n * replaces `input` in place (the loop validates it after the gate), `'ask'`\n * goes to `onAsk`.\n * - `tool:transform`: writes `result` and `isError`, and sets each returned\n * `metadata` namespace on the result's metadata (a non-JSON value or an\n * unsafe key is dropped). Interceptors see the metadata read-only.\n * - `validation:coerce`: replaces `input` in place. The hook fires after\n * validation, only when it coerced something; the loop validates a\n * changed input again (`fireValidationCoerce`).\n * - `context:transform`, `system:transform`, `mcp:tools:filter`,\n * `content-ref:resolve`, `tracing:redact`: write `messages`, `system`,\n * `tools`, `data`, `redacted`.\n *\n * With no interceptor registered the handler returns at once.\n *\n * @param registry - The shared interceptor registry.\n * @param name - The legacy hook to bridge.\n * @param opts - Session id, approval flow, MCP server lookup.\n * @returns A handler to pass to `agent.hooks.hook(name, …)`.\n */\nexport function bridgeLegacyMutatingHook<K extends LegacyMutatingHook>(registry: InterceptorRegistry, name: K, opts: LegacyBridgeOptions = {}): LegacyBridgeHandler<K> {\n const sessionId = (): { sessionId?: string } => optional({ sessionId: opts.sessionId?.() })\n const handlers: { [N in LegacyMutatingHook]: LegacyBridgeHandler<N> } = {\n 'tool:gate': async (ctx) => {\n if (ctx.block || ctx.result !== undefined || !registry.has('tool.call', ctx.name))\n return\n const call: ToolCall = {\n tool: ctx.name,\n displayName: ctx.displayName,\n input: ctx.input,\n callId: ctx.callId,\n turnId: ctx.turnId,\n runToolCounts: ctx.runToolCounts,\n ...sessionId(),\n ...optional({ runId: ctx.runId, parentRunId: ctx.parentRunId, depth: ctx.depth, mcpServer: opts.mcpServerOf?.(ctx.name) }),\n ...(ctx.resumed ? { resumed: true as const } : {}),\n }\n let decision = await registry.runInterceptors('tool.call', call, 'allow')\n if (decision === 'ask') {\n if (ctx.resumed)\n return\n decision = opts.onAsk ? await opts.onAsk(call) : { block: NO_APPROVAL_FLOW }\n }\n if (decision === 'allow')\n return\n if ('block' in decision) {\n ctx.block = true\n ctx.reason = decision.block\n }\n else if ('result' in decision) {\n if (!ctx.resumed)\n ctx.result = decision.result\n }\n else {\n replaceInPlace(ctx.input, decision.patch)\n }\n },\n 'tool:transform': async (ctx) => {\n if (!registry.has('tool.result', ctx.name))\n return\n const next = await registry.runInterceptors('tool.result', {\n tool: ctx.name,\n displayName: ctx.displayName,\n input: ctx.input,\n callId: ctx.callId,\n turnId: ctx.turnId,\n result: ctx.result,\n isError: ctx.isError,\n metadata: readonlyView(ctx.metadata),\n ...sessionId(),\n }, { result: ctx.result, isError: ctx.isError })\n ctx.result = next.result\n ctx.isError = next.isError\n for (const [namespace, value] of Object.entries(next.metadata ?? {})) {\n if (isSafeRecordKey(namespace) && isJson(value))\n ctx.metadata[namespace] = value as JsonValue\n }\n },\n 'validation:coerce': async (ctx) => {\n if (!registry.has('validation'))\n return\n const next = await registry.runInterceptors('validation', { ...ctx, ...sessionId() }, ctx.input)\n replaceInPlace(ctx.input, next)\n },\n 'context:transform': async (ctx) => {\n if (!registry.has('context'))\n return\n const next = await registry.runInterceptors('context', { messages: ctx.messages, ...sessionId() }, ctx.messages)\n if (next !== ctx.messages)\n ctx.messages = [...next]\n },\n 'system:transform': async (ctx) => {\n if (!registry.has('system'))\n return\n ctx.system = await registry.runInterceptors('system', {\n system: ctx.system,\n messages: ctx.messages,\n turn: ctx.turn,\n turnId: ctx.turnId,\n ...optional({ sessionId: opts.sessionId?.() ?? ctx.session?.id }),\n }, ctx.system)\n },\n 'mcp:tools:filter': async (ctx) => {\n if (!registry.has('mcp.tools', ctx.server))\n return\n const next = await registry.runInterceptors('mcp.tools', ctx, ctx.tools)\n if (next !== ctx.tools)\n ctx.tools = [...next]\n },\n 'content-ref:resolve': async (ctx) => {\n if (!registry.has('content-ref.resolve'))\n return\n const { data, ...input } = ctx\n const next = await registry.runInterceptors('content-ref.resolve', input, data)\n if (typeof next === 'string')\n ctx.data = next\n },\n 'tracing:redact': (ctx) => {\n if (!registry.has('tracing.redact'))\n return\n const { redacted, ...input } = ctx\n ctx.redacted = registry.runInterceptorsSync('tracing.redact', input, redacted)\n },\n }\n return handlers[name]\n}\n","/**\n * Extension API at the agent's call sites: the interceptor chains\n * (`ctx.hooks.intercept`) and the tools catalog, read from\n * `AgentOptions.extensionRuntime` (folded from `ExtensionRegistry.runtime` by\n * `foldExtensionRegistry`).\n *\n * Call sites check `registry?.has(name)` before calling a helper here, so an\n * agent built without an extension runtime, or with no interceptor of that name,\n * takes the exact path it took before (no await, no allocation).\n */\n\nimport type { Hookable } from 'hookable'\nimport type { ResolvedBehavior } from './agent-behavior'\nimport type { AgentHooks } from './agent-hooks'\nimport type { ProviderDescriptor } from './chat/providers'\nimport type { ExecutionContext, ExecutionHandle } from './contexts/types'\nimport type { NamedTool } from './extensions/api/catalogs'\nimport type { ToolCall as InterceptedToolCall, PromptInput, ToolCallDecision } from './extensions/api/hooks'\nimport type { Sourced, ToolsCatalog } from './extensions/catalog'\nimport type { InterceptorRegistry, LegacyBridgeOptions, LegacyMutatingHook } from './extensions/hooks'\nimport type { Provider } from './providers'\nimport type { SkillConfig } from './skills/types'\nimport type { ToolDef } from './tools/types'\nimport type { AgentBehavior, AgentRunOptions, McpServerConfig } from './types'\nimport { resolveBehavior } from './agent-behavior'\nimport { resolveMcpToolParts } from './agent-mcp-naming'\nimport { errorMessage } from './errors'\nimport { bridgeLegacyMutatingHook } from './extensions/hooks'\n\n/**\n * What the agent reads of the extension runtime. `ExtensionRuntimeOutputs`\n * (`ExtensionRegistry.runtime`) satisfies it; tests can pass only the parts they use.\n */\nexport interface AgentExtensionRuntime {\n /** The shared interceptor chains. */\n readonly interceptors: InterceptorRegistry\n /** The shared catalogs. Only the tools catalog is read by the agent. */\n readonly catalogs?: { readonly tools?: Pick<ToolsCatalog, 'read'> }\n}\n\n/** Where a call that needs approval comes from, when a subagent made it. */\nexport interface ToolCallOrigin {\n /** The spawn id of the subagent that made the call (`child-1`). */\n childId: string\n}\n\n/**\n * Resolves a `tool.call` interceptor's `'ask'` verdict through the host's\n * approval flow. Without one, an `'ask'` blocks the call. `origin` is set\n * for a subagent's call (the spawn tool passes it).\n */\nexport type ToolCallApprover = (call: InterceptedToolCall, origin?: ToolCallOrigin) => Promise<Exclude<ToolCallDecision, 'ask'>> | Exclude<ToolCallDecision, 'ask'>\n\n/**\n * What a subagent's interceptor inputs name, from the agent that spawned it\n * (`AgentOptions.extensionScope`): its session, and the run that spawned it.\n */\nexport interface ExtensionCallScope {\n /** The parent's session. Wins over the child's own (a child without a shared session has none). */\n sessionId?: () => string | undefined\n /** The parent's run, for `ToolCall.parentRunId` when the child run carries none (it has no shared session). */\n parentRunId?: string\n}\n\n/** The mutating hooks the agent bridges on its bus. `tracing:redact` is not fired on the bus: the tracer runs that chain itself. */\ntype AgentBridgedHook = Exclude<LegacyMutatingHook, 'tracing:redact'>\n\n/** Every bridged hook, in the order the bridges are registered. */\nexport const AGENT_BRIDGED_HOOKS: readonly AgentBridgedHook[] = [\n 'tool:gate',\n 'tool:transform',\n 'validation:coerce',\n 'context:transform',\n 'system:transform',\n 'mcp:tools:filter',\n 'content-ref:resolve',\n]\n\n/**\n * Registers the interceptor bridges on an agent's hook bus, so the loop's\n * existing mutating hooks (`tool:gate`, `tool:transform`,\n * `validation:coerce`, `context:transform`, `system:transform`,\n * `mcp:tools:filter`, `content-ref:resolve`) run the matching chains.\n *\n * @param hooks - The agent's hook bus.\n * @param registry - The shared interceptor registry.\n * @param opts - Session id, approval flow and MCP server lookup for the bridges.\n * @param fallback - Fields the `tool:gate` bridge reads when the call carries none.\n * @param fallback.parentRunId - The spawning run, for a subagent's `ToolCall.parentRunId`.\n * @returns A function that removes every bridge.\n */\nexport function installInterceptorBridges(hooks: Hookable<AgentHooks>, registry: InterceptorRegistry, opts: LegacyBridgeOptions, fallback: { parentRunId?: string } = {}): () => void {\n const register = <K extends AgentBridgedHook>(name: K): () => void => {\n const handler = bridgeLegacyMutatingHook(registry, name, opts)\n const parentRunId = fallback.parentRunId\n if (name !== 'tool:gate' || parentRunId === undefined)\n // The bridge's handler is the hook's own signature; hookable's overloads can't see that through `K`.\n return hooks.hook(name, handler as never)\n // The bridge reads `parentRunId` off the gate context; the context itself\n // stays as the loop built it (writes go through to it).\n const withParent = (ctx: Parameters<AgentHooks['tool:gate']>[0]): Promise<void> => (handler as (c: typeof ctx) => Promise<void>)(\n ctx.parentRunId !== undefined\n ? ctx\n : new Proxy(ctx, { get: (target, prop, receiver) => prop === 'parentRunId' ? parentRunId : Reflect.get(target, prop, receiver) }),\n )\n return hooks.hook('tool:gate', withParent)\n }\n const unregisters = AGENT_BRIDGED_HOOKS.map(register)\n return () => {\n for (const unregister of unregisters)\n unregister()\n }\n}\n\n/**\n * Runs the `run` chain over a run's options, after the registry's run\n * transforms (`runTransforms`).\n *\n * @param registry - The interceptor registry.\n * @param options - The run options so far.\n * @returns The options the chain settled on (a copy when changed).\n */\nexport async function interceptRunOptions(registry: InterceptorRegistry, options: AgentRunOptions): Promise<AgentRunOptions> {\n const next = await registry.runInterceptors('run', options, options)\n return next === options ? options : { ...next }\n}\n\n/**\n * Runs the `behavior` chain over a resolved behavior, after the registry's\n * behavior transforms (`behaviorTransforms`). Explicit run-level behavior keys\n * still win, as they do over those transforms.\n *\n * @param registry - The interceptor registry.\n * @param behavior - The behavior so far.\n * @param explicitRunBehavior - `AgentRunOptions.behavior`, re-applied over the chain's result.\n * @returns The resolved behavior (`behavior` itself when no handler changed it).\n */\nexport async function interceptBehavior(registry: InterceptorRegistry, behavior: ResolvedBehavior, explicitRunBehavior: AgentBehavior | undefined): Promise<ResolvedBehavior> {\n const next = await registry.runInterceptors('behavior', behavior, behavior)\n if (next === behavior)\n return behavior\n const merged: Record<string, unknown> = { ...next }\n if (explicitRunBehavior) {\n for (const [key, value] of Object.entries(explicitRunBehavior)) {\n if (value !== undefined)\n merged[key] = value\n }\n }\n return resolveBehavior(merged as AgentBehavior)\n}\n\n/**\n * Runs the `skills.activate` chain at run start, after the registry's skill\n * policies (`skillPolicies`), and activates each named skill that resolved.\n *\n * @param registry - The interceptor registry.\n * @param input - The resolved skills, the run options, and the activation callback.\n * @param input.skills - Skills resolved for this run.\n * @param input.options - The run options (model, prompt, parent run, depth are shown).\n * @param input.activate - Activates one skill explicitly.\n */\nexport async function interceptSkillActivation(registry: InterceptorRegistry, input: {\n skills: readonly SkillConfig[]\n options: AgentRunOptions\n activate: (skill: SkillConfig) => Promise<void>\n}): Promise<void> {\n if (input.skills.length === 0)\n return\n const { options } = input\n const names = await registry.runInterceptors('skills.activate', {\n skills: input.skills,\n run: {\n ...(options.model !== undefined ? { model: options.model } : {}),\n ...(options.prompt !== undefined ? { prompt: options.prompt } : {}),\n ...(options.parentRunId !== undefined ? { parentRunId: options.parentRunId } : {}),\n ...(options.depth !== undefined ? { depth: options.depth } : {}),\n },\n }, [])\n const byName = new Map(input.skills.map(skill => [skill.name, skill]))\n for (const name of new Set(names)) {\n const skill = byName.get(name)\n if (!skill)\n continue\n try {\n await input.activate(skill)\n }\n catch (err) {\n if (process.env.ZIDANE_DEBUG)\n process.stderr.write(`[zidane/extensions] skills.activate: activating \"${name}\" failed: ${errorMessage(err)}\\n`)\n }\n }\n}\n\n/**\n * Replays the extension tools catalog over a tool record (extension tools added,\n * transforms applied). The record's MCP tools carry their server as origin.\n *\n * @param catalog - The shared tools catalog.\n * @param tools - Spec-name-indexed tools, after the registry's catalog transforms (`toolCatalogTransforms`).\n * @param context - Phase, session and MCP attribution.\n * @param context.phase - `'pre-run'` for listings, `'run'` when building a run.\n * @param context.sessionId - The agent's session.\n * @param context.mcpToolNames - Names of the MCP tools in `tools`.\n * @param context.mcpServers - Configured MCP servers, to name a tool's server.\n * @returns A new spec-name-indexed record.\n */\nexport function applyCatalogTools(\n catalog: Pick<ToolsCatalog, 'read'>,\n tools: Readonly<Record<string, ToolDef>>,\n context: { phase: 'pre-run' | 'run', sessionId?: string, mcpToolNames: ReadonlySet<string>, mcpServers: readonly McpServerConfig[] | undefined },\n): Record<string, ToolDef> {\n const base: Sourced<NamedTool>[] = []\n for (const def of Object.values(tools)) {\n const name = def.spec.name\n base.push({\n item: { name, def },\n origin: context.mcpToolNames.has(name)\n ? { kind: 'mcp', server: resolveMcpToolParts(name, context.mcpServers)?.server ?? '' }\n : { kind: 'builtin' },\n })\n }\n const value = catalog.read({ phase: context.phase, ...(context.sessionId !== undefined ? { sessionId: context.sessionId } : {}), base })\n const out: Record<string, ToolDef> = {}\n for (const tool of value.items) {\n if (tool.def?.spec?.name)\n out[tool.def.spec.name] = tool.def\n }\n return out\n}\n\n/**\n * Runs the `prompt` chain over a submitted prompt. Hosts call it in their\n * submit pipeline after `/` command interception and the registry's prompt\n * transforms, before skill resolution.\n *\n * @param registry - The interceptor registry, or `undefined` without an extension runtime.\n * @param input - The prompt as submitted.\n * @returns The prompt to submit, or `{ handled: true }` when an extension consumed it.\n */\nexport async function interceptPrompt(registry: InterceptorRegistry | undefined, input: PromptInput): Promise<PromptInput | { handled: true }> {\n if (!registry?.has('prompt'))\n return input\n return registry.runInterceptors('prompt', input, input)\n}\n\n/** A prompt as a host submits it, with the host's own attachment type. */\nexport interface SubmittedPrompt<A> {\n text: string\n attachments: readonly A[]\n metadata: Readonly<Record<string, unknown>>\n delivery: PromptInput['delivery']\n}\n\nconst DELIVERIES: ReadonlySet<string> = new Set<PromptInput['delivery']>(['auto', 'steer', 'followUp'])\n\n/**\n * Runs the `prompt` chain over a host's submitted prompt and maps the result\n * back onto the host's attachments. An interceptor sees each attachment as\n * `{ name, mimeType }`; the attachments it returns are matched to the\n * submitted ones by name, in order, so it can drop, reorder or retype them.\n * One whose name matches none is dropped: it has no content to send.\n *\n * @param registry - The interceptor registry, or `undefined` without an extension runtime.\n * @param sessionId - The session the prompt goes to.\n * @param prompt - The prompt after `/` command interception and the registry's prompt transforms.\n * @returns The prompt to submit (`prompt` itself when nothing changed), or `{ handled: true }`.\n */\nexport async function interceptSubmittedPrompt<A extends { name: string, mediaType: string }>(\n registry: InterceptorRegistry | undefined,\n sessionId: string | undefined,\n prompt: SubmittedPrompt<A>,\n): Promise<SubmittedPrompt<A> | { handled: true }> {\n if (!registry?.has('prompt'))\n return prompt\n const input: PromptInput = {\n ...(sessionId !== undefined ? { sessionId } : {}),\n text: prompt.text,\n attachments: prompt.attachments.map(a => ({ name: a.name, mimeType: a.mediaType })),\n metadata: prompt.metadata,\n delivery: prompt.delivery,\n }\n const out = await interceptPrompt(registry, input)\n if (out === input)\n return prompt\n if ('handled' in out)\n return out.handled === true ? { handled: true } : prompt\n const attachments: A[] = []\n if (out.attachments === input.attachments || !Array.isArray(out.attachments)) {\n attachments.push(...prompt.attachments)\n }\n else {\n const unused = [...prompt.attachments]\n for (const next of out.attachments) {\n const at = unused.findIndex(a => a.name === next?.name)\n if (at < 0)\n continue\n const [original] = unused.splice(at, 1) as [A]\n attachments.push(typeof next.mimeType === 'string' && next.mimeType !== original.mediaType ? { ...original, mediaType: next.mimeType } : original)\n }\n }\n return {\n text: typeof out.text === 'string' ? out.text : prompt.text,\n attachments,\n metadata: out.metadata && typeof out.metadata === 'object' ? out.metadata : prompt.metadata,\n delivery: DELIVERIES.has(out.delivery) ? out.delivery : prompt.delivery,\n }\n}\n\nfunction isProvider(value: unknown): value is Provider {\n return !!value && typeof value === 'object' && typeof (value as Partial<Provider>).stream === 'function'\n}\n\n/**\n * Wraps a provider a descriptor's factory built with the `provider` chain,\n * after the provider middlewares. Factories are synchronous and the chain\n * is not, so the chain runs once, on the first `stream` or `countTokens`\n * call; until it has, the other members read the provider as built.\n *\n * @param registry - The interceptor registry, or `undefined` without an extension runtime.\n * @param provider - The provider the factory (and provider middlewares) produced.\n * @param descriptor - The descriptor it came from (`match` filters on its key).\n * @returns `provider` itself when no `provider` interceptor matches, else a wrapper.\n */\nexport function interceptProvider(registry: InterceptorRegistry | undefined, provider: Provider, descriptor: ProviderDescriptor): Provider {\n if (!registry?.has('provider', descriptor.key))\n return provider\n let resolved: Provider | undefined\n let pending: Promise<Provider> | undefined\n const resolve = (): Promise<Provider> => pending ??= registry.runInterceptors('provider', { provider, descriptor }, provider)\n .then(next => (resolved = isProvider(next) ? next : provider))\n const current = (): Provider => resolved ?? provider\n return new Proxy(provider, {\n get(_target, prop) {\n if (prop === 'stream')\n return async (...args: Parameters<Provider['stream']>) => (await resolve()).stream(...args)\n if (prop === 'countTokens' && current().countTokens) {\n return async (...args: Parameters<NonNullable<Provider['countTokens']>>) => {\n const next = await resolve()\n return next.countTokens ? next.countTokens(...args) : null\n }\n }\n const target = current()\n const value: unknown = Reflect.get(target, prop)\n return typeof value === 'function' ? (value as (...a: unknown[]) => unknown).bind(target) : value\n },\n })\n}\n\n/**\n * Runs the `retry` chain over a stream failure the loop would retry.\n *\n * @param registry - The interceptor registry.\n * @param input - Attempt, error text, provider and model.\n * @param input.attempt - The attempt that failed (1-based).\n * @param input.error - The error message.\n * @param input.provider - Provider name.\n * @param input.model - Model id.\n * @param delayMs - The backoff the loop computed.\n * @returns The backoff to wait, or `undefined` when an interceptor vetoed the retry.\n */\nexport async function interceptRetry(registry: InterceptorRegistry, input: { attempt: number, error: string, provider: string, model: string }, delayMs: number): Promise<number | undefined> {\n const out = await registry.runInterceptors('retry', input, { retry: true, delayMs })\n if (!out.retry)\n return undefined\n const next = out.delayMs\n return typeof next === 'number' && Number.isFinite(next) && next >= 0 ? next : delayMs\n}\n\nconst shellEnvContexts = new WeakMap<object, { execution: ExecutionContext, wrapped: ExecutionContext }>()\n\n/**\n * The execution context a tool body gets: `execution` itself, or, when a\n * `shell.env` interceptor is registered, a view whose `exec` and\n * `execBackground` run the chain over the command's environment first. The\n * chain starts from the caller's `env` (empty for the shell tool) and its\n * result is added on top of the context's own environment.\n *\n * @param owner - The object the view is cached on (the loop context).\n * @param execution - The run's execution context.\n * @param registry - The interceptor registry, or `undefined` without an extension runtime.\n * @param sessionId - The session, for the interceptor input.\n * @returns The context to hand the tool.\n */\nexport function executionForTools(owner: object, execution: ExecutionContext, registry: InterceptorRegistry | undefined, sessionId: string | undefined): ExecutionContext {\n if (!registry?.has('shell.env'))\n return execution\n const cached = shellEnvContexts.get(owner)\n if (cached?.execution === execution)\n return cached.wrapped\n const envFor = async (handle: ExecutionHandle, command: string, options: { cwd?: string, env?: Record<string, string> } | undefined): Promise<Record<string, string> | undefined> => {\n const initial = options?.env ?? {}\n const next = await registry.runInterceptors('shell.env', {\n command,\n cwd: options?.cwd ?? handle.cwd,\n ...(sessionId !== undefined ? { sessionId } : {}),\n }, initial)\n return next === initial ? options?.env : { ...next }\n }\n // Prototype-linked so every other member (and `this` inside them) is the context's own.\n const wrapped = Object.create(execution) as ExecutionContext\n wrapped.exec = async (handle, command, options) => {\n const env = await envFor(handle, command, options)\n return execution.exec(handle, command, env === options?.env ? options : { ...options, env })\n }\n const background = execution.execBackground\n if (background) {\n wrapped.execBackground = async (handle, command, options) => {\n const env = await envFor(handle, command, options)\n return background.call(execution, handle, command, env === options.env ? options : { ...options, ...(env ? { env } : {}) })\n }\n }\n shellEnvContexts.set(owner, { execution, wrapped })\n return wrapped\n}\n","import type { Provider } from './providers'\nimport type { ModelTarget, ModelTargetSpec } from './types'\n\n/**\n * Normalize `AgentOptions.provider` into a non-empty provider list.\n *\n * In multi-provider setups every provider needs a non-blank, unique name —\n * model entries reference providers by `Provider.name`, so a blank or\n * duplicate name would make the reference ambiguous (and surface as a\n * baffling `duplicate provider name \"\"` otherwise). A single provider\n * has no such constraint: its name plays no role in target resolution. Throws at agent construction rather than at\n * run time.\n *\n * @param provider - A single provider or an ordered list of providers.\n */\nexport function normalizeProviders(provider: Provider | Provider[]): Provider[] {\n // Copy — the agent holds this list for its lifetime, so a caller mutating\n // the array they passed must not silently rewire the fallback chain.\n const providers = Array.isArray(provider) ? [...provider] : [provider]\n if (providers.length === 0)\n throw new Error('AgentOptions.provider: provider array must not be empty')\n if (providers.length === 1)\n return providers\n const seen = new Set<string>()\n for (const p of providers) {\n if (!p.name.trim()) {\n throw new Error(\n 'AgentOptions.provider: multi-provider setups need a name on every provider, since model entries refer to providers by name',\n )\n }\n if (seen.has(p.name)) {\n throw new Error(\n `AgentOptions.provider: duplicate provider name \"${p.name}\". Names must be unique so model entries can refer to them.`,\n )\n }\n seen.add(p.name)\n }\n return providers\n}\n\n/**\n * Resolve a run's model selection into an ordered, de-duplicated fallback\n * chain of provider+model targets. `targets[0]` is the primary.\n *\n * Expansion rules:\n * - `undefined` → each provider's `meta.defaultModel`, in provider order.\n * - `string` → that model id on every provider, in provider order.\n * - array → entries in order; a `{ provider, model }` entry resolves to that\n * one provider (throws on unknown names), while bare strings and\n * provider-less objects fan out across all providers.\n *\n * @param providers - Configured providers, in priority order. Must not be empty.\n * @param model - Model id, or an ordered list of model ids and `{ provider, model }` entries. Omit to use each provider's default model.\n */\nexport function resolveModelTargets(\n providers: readonly Provider[],\n model?: string | ReadonlyArray<string | ModelTargetSpec>,\n): ModelTarget[] {\n // Guard the exported boundary: `createAgent` always passes the\n // `normalizeProviders` output, but direct callers could hand an empty\n // list — which would silently resolve to zero targets and crash later.\n if (providers.length === 0)\n throw new Error('resolveModelTargets: providers list must not be empty')\n const targets: ModelTarget[] = []\n const push = (provider: Provider, model: string, contextWindow?: number): void => {\n if (!targets.some(t => t.provider === provider && t.model === model))\n targets.push({ provider, model, ...(contextWindow !== undefined ? { contextWindow } : {}) })\n }\n const fanOut = (model: string, contextWindow?: number): void => {\n for (const p of providers) push(p, model, contextWindow)\n }\n\n if (model === undefined) {\n for (const p of providers) push(p, p.meta.defaultModel)\n }\n else if (typeof model === 'string') {\n fanOut(model)\n }\n else {\n if (model.length === 0)\n throw new Error('model: fallback array must not be empty')\n for (const entry of model) {\n if (typeof entry === 'string') {\n fanOut(entry)\n }\n else if (entry.provider === undefined) {\n fanOut(entry.model, entry.contextWindow)\n }\n else {\n const p = providers.find(x => x.name === entry.provider)\n if (!p) {\n throw new Error(\n `model: unknown provider \"${entry.provider}\". Configured providers: ${providers.map(x => x.name).join(', ')}`,\n )\n }\n push(p, entry.model, entry.contextWindow)\n }\n }\n }\n return targets\n}\n","/**\n * Per-call tool-cancellation registry shared between the agent and the loop.\n *\n * The loop registers an `AbortController` for each tool call right before it\n * dispatches (gate → execute), and unregisters it in a `finally`, so the live\n * map only ever holds *currently dispatching* calls. `agent.cancelTool(callId)`\n * flips the matching call's controller without unwinding the rest of the run.\n *\n * Two subtleties this registry owns so callers don't have to:\n *\n * - **Pre-registration race.** A host can learn a call's id from the streamed\n * assistant turn and ask to cancel it BEFORE the loop has dispatched it\n * (very reachable when a batch runs calls one after another, because\n * unsafe tools run alone and `maxConcurrentTools` caps the rest — a later\n * call in a batch registers only when its turn comes). A cancel for\n * an un-registered id is parked in a bounded FIFO and applied the instant\n * the call registers, instead of being silently dropped.\n *\n * - **Bounded parking.** Parked kills for ids that never dispatch (a\n * hallucinated id, a call the model retracted) can't accumulate: the FIFO\n * evicts oldest past its cap, and the agent clears it at run boundaries so a\n * stale kill never leaks across runs onto a later call that happens to reuse\n * the same id.\n */\n\n/** Fallback reason stamped on the abort signal when `cancel` gets no explicit reason. */\nconst DEFAULT_KILL_MESSAGE = 'user-cancelled-tool'\n/** Upper bound on parked pre-registration kills — FIFO-evicted past this. */\nconst DEFAULT_MAX_PENDING_KILLS = 64\n\nexport interface ToolCancelRegistry {\n /**\n * Bind `controller` to `callId` (loop, at dispatch). If a kill for `callId`\n * was parked before it registered, it is applied immediately.\n */\n register: (callId: string, controller: AbortController) => void\n /** Drop the live binding for `callId` (loop, in `finally`). */\n unregister: (callId: string) => void\n /**\n * Cancel the in-flight call `callId`. Returns `true` when a live, not-yet-\n * aborted controller was flipped; `false` otherwise — including when the\n * cancel is parked for the pre-registration race (the call hasn't dispatched\n * yet). Idempotent: a second cancel of an already-aborted call returns\n * `false`.\n */\n cancel: (callId: string, reason?: string) => boolean\n /** Abort every live controller (agent teardown) and drop all state. */\n abortAll: (reason: string) => void\n /** Drop parked pre-registration kills (agent, at run boundaries). */\n clearPending: () => void\n}\n\nexport interface ToolCancelRegistryOptions {\n /** Reason stamped on the abort signal when `cancel` is called without one. */\n defaultMessage?: string\n /** Cap on parked pre-registration kills. Defaults to 64. */\n maxPendingKills?: number\n}\n\nexport function createToolCancelRegistry(options: ToolCancelRegistryOptions = {}): ToolCancelRegistry {\n const defaultMessage = options.defaultMessage ?? DEFAULT_KILL_MESSAGE\n const maxPending = typeof options.maxPendingKills === 'number' && options.maxPendingKills > 0\n ? Math.floor(options.maxPendingKills)\n : DEFAULT_MAX_PENDING_KILLS\n\n // Currently-dispatching calls, keyed by callId.\n const live = new Map<string, AbortController>()\n // Kills that arrived before their call registered: callId → reason. A plain\n // Map preserves insertion order, so the first key is the FIFO eviction\n // target.\n const pending = new Map<string, string>()\n\n function park(callId: string, reason: string): void {\n // Re-set to refresh insertion order (most-recent kill wins the slot).\n pending.delete(callId)\n pending.set(callId, reason)\n while (pending.size > maxPending) {\n const oldest = pending.keys().next().value\n if (oldest === undefined)\n break\n pending.delete(oldest)\n }\n }\n\n function applyParked(callId: string, controller: AbortController): void {\n const reason = pending.get(callId)\n if (reason === undefined)\n return\n pending.delete(callId)\n if (!controller.signal.aborted)\n controller.abort(reason)\n }\n\n return {\n register(callId, controller) {\n live.set(callId, controller)\n applyParked(callId, controller)\n },\n unregister(callId) {\n live.delete(callId)\n },\n cancel(callId, reason) {\n const message = reason ?? defaultMessage\n const controller = live.get(callId)\n if (controller) {\n if (controller.signal.aborted)\n return false\n // `reason` rides the abort signal so a signal-aware tool body that\n // surfaces `signal.reason` sees the same string the `tool:cancelled`\n // hook receives.\n controller.abort(message)\n return true\n }\n park(callId, message)\n return false\n },\n abortAll(reason) {\n for (const controller of live.values()) {\n if (!controller.signal.aborted)\n controller.abort(reason)\n }\n live.clear()\n pending.clear()\n },\n clearPending() {\n pending.clear()\n },\n }\n}\n","/**\n * Agent-scoped runtime state for `createAgent()`, its construction, and the\n * run-scope / run-id bookkeeping every run shares.\n */\n\nimport type { Hookable } from 'hookable'\nimport type { ContextAssembly } from './agent-context'\nimport type { AgentHooks } from './agent-hooks'\nimport type { AgentExtensionRuntime } from './agent-interceptors'\nimport type { AgentOptions } from './agent-types'\nimport type { ExecutionContext, ExecutionHandle, TaskExitInfo, TaskStallInfo } from './contexts'\nimport type { Decider } from './decisions'\nimport type { AgentDecide } from './decisions/types'\nimport type { DurableOptions, DurableRuntime } from './durable/types'\nimport type { InterceptorRegistry } from './extensions/hooks'\nimport type { LoopContext, OverflowRescueState } from './loop-context'\nimport type { McpConnection } from './mcp'\nimport type { Provider } from './providers'\nimport type { RunDurability } from './run-durability'\nimport type { Session } from './session'\nimport type { SkillActivationState } from './skills/activation'\nimport type { SkillConfig } from './skills/types'\nimport type { ToolCancelRegistry } from './tool-cancel'\nimport type { ToolStateController } from './tool-state'\nimport type { ToolDef } from './tools/types'\nimport type { McpServerConfig, SessionTurn } from './types'\nimport { createHooks } from 'hookable'\nimport { recordAgentExtensionWiring } from './agent-extension-wiring'\nimport { applyMcpConfigTransforms, foldExtensionRegistry } from './agent-extensions'\nimport { isDecisionHookEvent, isKnownHookEvent } from './agent-hooks'\nimport { installInterceptorBridges } from './agent-interceptors'\nimport { resolveMcpToolParts } from './agent-mcp-naming'\nimport { createProcessContext } from './contexts'\nimport { createDecider } from './decisions'\nimport { createMemoryRuntime } from './durable/memory'\nimport { normalizeProviders } from './model-targets'\nimport { insideStepWork, journaledStep, LOOP_STEP_KINDS, replays } from './run-durability'\nimport { createSkillActivationState } from './skills/activation'\nimport { createToolCancelRegistry } from './tool-cancel'\nimport { createToolStateController } from './tool-state'\n\n/** See {@link AgentRuntime.pendingRun}. */\nexport interface PendingRun {\n suspended: boolean\n aborted: boolean\n settled: Promise<void>\n}\n\n/**\n * Agent-scoped state behind one `createAgent()` instance. Everything the\n * agent's operations share lives here: the folded construction options,\n * the hook bus, run-scope liveness, execution / MCP / skills bootstrap\n * state, steering queues, and background-task notification queues.\n *\n * Fields the operations reassign are plain properties; everything else is\n * `readonly`.\n */\nexport interface AgentRuntime {\n readonly providers: Provider[]\n /** PRIMARY provider — see `normalizeProviders` in `createAgentRuntime`. */\n readonly provider: Provider\n readonly hooks: Hookable<AgentHooks>\n readonly executionContext: ExecutionContext\n readonly sourceTools: Record<string, ToolDef>\n readonly toolStateController: ToolStateController\n readonly toolCancels: ToolCancelRegistry\n readonly resolveInjectedHandle: (() => Promise<ExecutionHandle>) | undefined\n readonly executionHandleInjected: boolean\n readonly allMcpServers: McpServerConfig[]\n readonly steeringQueue: string[]\n readonly nonInterruptingNudgeQueue: string[]\n readonly followUpQueue: string[]\n readonly pendingTaskNotifications: Map<string, TaskExitInfo>\n readonly pendingStallNotifications: Map<string, TaskStallInfo>\n readonly notifiedTaskIds: Set<string>\n readonly skillsConfig: AgentOptions['skills']\n readonly skillsDisabled: boolean\n readonly skillActivationState: SkillActivationState\n /** Backs `agent.decide` and the `ctx.decide` attached to hook contexts. */\n readonly decider: Decider\n /**\n * Context-overflow rescue cutoff shared by every run of this agent; each\n * run's `LoopContext.overflowRescue` points at this holder, so a later run\n * re-applies the stubs instead of being rejected again.\n */\n readonly overflowRescue: OverflowRescueState\n\n // Folded construction options (`foldExtensionRegistry`).\n readonly agentName: AgentOptions['name']\n readonly agentSystem: AgentOptions['system']\n readonly toolAliases: AgentOptions['toolAliases']\n readonly toolDescriptions: AgentOptions['toolDescriptions']\n readonly agentBehavior: AgentOptions['behavior']\n readonly mcpServers: AgentOptions['mcpServers']\n /** `AgentOptions.session`, or the session `AgentOptions.sessionId` loaded (`ensureAgentSession`). */\n session: Session | undefined\n /** `AgentOptions.sessionId`: the session to load on first use. */\n readonly sessionId: string | undefined\n /** The load of `sessionId` in flight or done; cleared when it failed, so the next call retries. */\n sessionLoad: Promise<void> | null\n /** Drops the `session:save` / `session:meta` listeners `bindSessionHooks` put on `session`. */\n unbindSession: (() => void) | null\n readonly agentReadState: AgentOptions['readState']\n readonly agentSkills: AgentOptions['skills']\n readonly mcpConnector: AgentOptions['mcpConnector']\n readonly mcpToolWrap: AgentOptions['mcpToolWrap']\n readonly eager: AgentOptions['eager']\n readonly agentClock: AgentOptions['clock']\n /** The runtime of `AgentOptions.durable`: when set, every run consults it. */\n readonly durable: DurableRuntime | undefined\n /** `AgentOptions.durable.onInterrupted`; `'heal'` when unset or given a bare runtime. */\n readonly onInterrupted: 'resume' | 'heal'\n /** The runtime of runs without `durable`. */\n readonly memoryDurable: DurableRuntime\n readonly contextBreakdownSections: AgentOptions['contextBreakdownSections']\n readonly runTransforms: AgentOptions['runTransforms']\n readonly behaviorTransforms: AgentOptions['behaviorTransforms']\n readonly toolCatalogTransforms: AgentOptions['toolCatalogTransforms']\n readonly skillPolicies: AgentOptions['skillPolicies']\n readonly toolResultMetadata: AgentOptions['toolResultMetadata']\n readonly artifactsOption: AgentOptions['artifacts']\n /** The extension interceptor chains (`AgentOptions.extensionRuntime`); `undefined` without an extension runtime. */\n readonly interceptors: InterceptorRegistry | undefined\n /** The extension tools catalog each run's tool set is replayed through; `undefined` without one. */\n readonly toolsCatalog: NonNullable<AgentExtensionRuntime['catalogs']>['tools']\n\n // Run-scope liveness (see `resetRunScope`).\n abortController: AbortController | undefined\n /** Aborted by `Agent.suspend` (see `LoopContext.suspendSignal`). Unset outside a run, and on a replay-mode run. */\n suspendController: AbortController | undefined\n /**\n * Set for the whole of an `Agent.run` / `Agent.resume` call that awaits\n * before its run starts (loading the `sessionId` session, checking a run\n * to resume). The agent counts as running throughout. A suspend or abort\n * while no run is in flight sets `suspended` / `aborted`, and no run\n * starts after it; an abort during the resumed run of `run()` keeps the\n * prompt from running. `settled` resolves once the call returned.\n */\n pendingRun: PendingRun | undefined\n running: boolean\n idleResolve: (() => void) | undefined\n idlePromise: Promise<void> | undefined\n /** The durable scope of the run in flight, for what runs beside the loop (decisions). */\n activeDurability?: RunDurability\n\n // Execution handle bootstrap (see `ensureExecutionHandle`).\n executionHandle: ExecutionHandle | null\n executionReadyFired: boolean\n destroyed: boolean\n /**\n * Bumped by every `destroy()`. The spawn seam compares epochs instead of\n * the `destroyed` boolean because destroy-then-run RESURRECTION is a\n * supported contract (see \"allows re-spawn after destroy\"): a spawn\n * started AFTER a destroy is legitimate, only a destroy landing DURING\n * a spawn must reap the fresh handle.\n */\n destroyGeneration: number\n executionSpawnPromise: Promise<ExecutionHandle> | null\n\n // MCP + context breakdown.\n mcpConnection: McpConnection | null\n lastContextAssembly: ContextAssembly | null\n mcpWarmupPromise: Promise<void> | null\n\n conversationTurns: SessionTurn[]\n /**\n * Loop context of the latest run that sent a provider request, and the loop\n * turn that sent the last one (`ctx.lastRequest`). `agent.compact()`\n * resends that request, or builds the next turn's request from this\n * context, so a manual summary reads the conversation from the prompt cache.\n */\n lastRunContext: { ctx: LoopContext, turn: number } | null\n /** Loop context of the run in progress, `null` between runs. Read for the last request's time while a run is still going. */\n activeRunContext: LoopContext | null\n // Run id minting (see `syncRunCounter`).\n runCounter: number\n scannedRuns: number\n scannedTurns: number\n\n // Skills bootstrap (see `ensureSkillsResolved`).\n resolvedSkills: SkillConfig[] | null\n skillsCatalog: string | null\n skillsResolvePromise: Promise<void> | null\n skillsCleanup: () => void\n}\n\n/**\n * Fold the options and build the agent-scoped runtime. Registers the\n * agent-lifetime `hooks` option (throwing on unknown event names) and\n * seeds the run counter from the bound session.\n */\nexport function createAgentRuntime(rawOptions: AgentOptions): AgentRuntime {\n const { provider: providerOption, name: agentName, system: agentSystem, tools: agentTools, toolAliases, toolDescriptions, behavior: agentBehavior, execution, handle: injectedHandle, mcpServers, session, sessionId, readState: agentReadState, toolState: toolStateStore, skills: agentSkills, mcpConnector, mcpToolWrap, eager, hooks: initialHooks, clock: agentClock, durable: durableOption, toolKill, contextBreakdownSections, runTransforms, behaviorTransforms, toolCatalogTransforms, mcpConfigTransforms, skillPolicies, toolResultMetadata, artifacts: artifactsOption, decisions, extensionRuntime, approveToolCall, extensionScope } = foldExtensionRegistry(rawOptions)\n const { runtime: durable, onInterrupted = 'heal' } = durableOptionsOf(durableOption)\n if (durable && session?.store && session.store !== durable.stores.session)\n throw new Error('createAgent: `session` is stored in another store than `durable.stores.session`. Pass `sessionId` instead to load or create the session there, or leave one of the two options out.')\n if (sessionId !== undefined && session)\n throw new Error('createAgent: pass `session` or `sessionId`, not both.')\n if (sessionId !== undefined && !durable)\n throw new Error('createAgent: `sessionId` needs `durable`: the session loads from `durable.stores.session`. Without one, pass `session`.')\n // Normalized provider list (validated: non-empty, unique names). `provider`\n // stays the PRIMARY provider — every agent-level surface (frozen `meta`,\n // context breakdown, default model) reads it, preserving single-provider\n // behavior byte-for-byte. Additional providers only come into play through\n // run-level model-target resolution (fallback chains).\n const providers = normalizeProviders(providerOption)\n const provider = providers[0]\n const hooks = createHooks<AgentHooks>()\n const executionContext = execution ?? createProcessContext()\n const sourceTools = agentTools ?? {}\n // One controller per agent: the snapshot is shared across runs (state\n // written in run 1 is visible in run 2 without a reload) while each tool\n // call gets its own staging view. Always constructed — without a store it\n // is an in-memory map, so `ctx.state` behaves identically everywhere and\n // only durability differs.\n // A durable runtime keeps the session's tool state next to its steps.\n const toolStateSessionId = session?.id ?? sessionId\n const toolStateController = createToolStateController(toolStateStore ?? (durable && toolStateSessionId !== undefined ? durable.stores.toolState(toolStateSessionId) : undefined))\n\n // Decisions: one decider per agent. The run signal is read lazily through\n // `rtRef` because `rt` is assembled below.\n let rtRef: AgentRuntime | undefined\n const decider = createDecider({ providers, config: decisions, hooks })\n installDecideInjection(hooks, decider, () => rtRef?.abortController?.signal, () => rtRef?.activeDurability)\n\n // Agent-lifetime hooks declared on `AgentOptions.hooks` (typically supplied\n // by a preset). Registered here so they fire across every `run()` — same\n // semantics as a manual `agent.hooks.hook(...)` call right after createAgent.\n // Unknown event names throw immediately so typos in preset definitions\n // never silently no-op. Mirrors the per-run registration block in `run()`.\n if (initialHooks) {\n for (const [event, handler] of Object.entries(initialHooks)) {\n if (!isKnownHookEvent(event)) {\n throw new Error(\n `Unknown hook event \"${event}\" passed to createAgent(). See AgentHooks for valid events.`,\n )\n }\n const handlerList = Array.isArray(handler) ? handler : [handler]\n for (const fn of handlerList) {\n if (typeof fn !== 'function')\n continue\n hooks.hook(event, fn as AgentHooks[typeof event])\n }\n }\n }\n\n // Per-agent queue of background-task exits the model hasn't been told\n // about yet. Drained at the start of every `agent.run()` — each entry\n // becomes a `<task-notification>` text block prepended to the seeded\n // user turn. Suppression (via `tool:after` hook for `shell_kill` and\n // `read_file`) deletes entries before they're drained, so a model\n // that's already aware of an exit doesn't get a duplicate signal.\n //\n // Map keyed by `taskId` so re-enqueueing the same task overwrites\n // rather than duplicates. Cleared on `agent.destroy()` AND on `reset()`\n // so the next agent instance starts clean.\n const pendingTaskNotifications = new Map<string, TaskExitInfo>()\n // One-shot stall signals from the background watchdog, keyed by taskId.\n // Same drain/suppression lifecycle as `pendingTaskNotifications`; an\n // exit for the same task supersedes its pending stall (the\n // `background:exit` listener deletes the matching entry).\n const pendingStallNotifications = new Map<string, TaskStallInfo>()\n // Task ids the model has already been told about (drained notification,\n // shell_kill result, read of the output file, wait_task return). The\n // pull-based reconcile at run start consults this so re-listing a\n // terminated task on every subsequent run doesn't re-notify. Grows by\n // one small string per background task over the agent's lifetime —\n // bounded; cleared on reset()/destroy().\n const notifiedTaskIds = new Set<string>()\n // Per-callId abort registry mutated by the loop's `executeSingleTool` —\n // shared with `cancelTool()` (`./agent-lifecycle`) so an external caller (TUI keybind,\n // SDK consumer) can flip a single in-flight call's signal without\n // unwinding the whole run. The loop registers the controller before\n // gate/execute and unregisters it in a finally, so the live map only\n // ever holds currently dispatching calls. The registry also parks kills\n // that arrive before a call dispatches (the pre-registration race) and\n // applies them at registration. Lives on the agent (not the run scope)\n // so the same instance survives across the loop's per-batch reuses;\n // parked kills are cleared at each run start and on destroy.\n const toolCancels = createToolCancelRegistry(\n toolKill?.defaultMessage !== undefined ? { defaultMessage: toolKill.defaultMessage } : {},\n )\n const resolveInjectedHandle = typeof injectedHandle === 'function' ? injectedHandle : undefined\n const executionHandleInjected = injectedHandle !== undefined\n const allMcpServers = applyMcpConfigTransforms(mcpServers ?? [], mcpConfigTransforms)\n const steeringQueue: string[] = []\n // Advisory nudges. Deliberately NOT `steeringQueue`: the batch schedulers\n // skip remaining sibling tool calls when the steering queue is non-empty\n // mid-batch. These drain at the turn boundary instead.\n const nonInterruptingNudgeQueue: string[] = []\n const followUpQueue: string[] = []\n\n // Skills — resolved lazily and idempotently via `ensureSkillsResolved()`.\n // First call from `run()` / `warmup()` / `activateSkill()` wins; concurrent\n // callers converge on `skillsResolvePromise` so we never scan twice.\n const skillsConfig = agentSkills\n const skillsEnabledValue = skillsConfig?.enabled\n const skillsDisabled = skillsEnabledValue === false || (Array.isArray(skillsEnabledValue) && skillsEnabledValue.length === 0)\n\n // Per-agent activation state (lives across runs; `run-end` deactivates every\n // skill at each run boundary, `reset` clears everything, `resume` rehydrates).\n const skillActivationState = createSkillActivationState({\n maxActive: skillsConfig?.maxActive,\n })\n\n const rt: AgentRuntime = {\n providers,\n provider,\n hooks,\n executionContext,\n sourceTools,\n toolStateController,\n toolCancels,\n resolveInjectedHandle,\n executionHandleInjected,\n allMcpServers,\n steeringQueue,\n nonInterruptingNudgeQueue,\n followUpQueue,\n pendingTaskNotifications,\n pendingStallNotifications,\n notifiedTaskIds,\n skillsConfig,\n skillsDisabled,\n skillActivationState,\n decider,\n agentName,\n agentSystem,\n toolAliases,\n toolDescriptions,\n agentBehavior,\n mcpServers,\n session,\n sessionId,\n sessionLoad: null,\n unbindSession: null,\n agentReadState,\n agentSkills,\n mcpConnector,\n mcpToolWrap,\n eager,\n agentClock,\n durable,\n onInterrupted,\n memoryDurable: createMemoryRuntime(),\n contextBreakdownSections,\n runTransforms,\n behaviorTransforms,\n toolCatalogTransforms,\n skillPolicies,\n toolResultMetadata,\n artifactsOption,\n interceptors: extensionRuntime?.interceptors,\n toolsCatalog: extensionRuntime?.catalogs?.tools,\n // Run-scope liveness (see `resetRunScope`).\n abortController: undefined,\n suspendController: undefined,\n pendingRun: undefined,\n running: false,\n idleResolve: undefined,\n idlePromise: undefined,\n // A host-injected handle is used verbatim and never spawned/destroyed by the\n // agent (the host owns its lifecycle). `executionReadyFired` gates the\n // one-shot `execution:ready` hook.\n executionHandle: typeof injectedHandle === 'object' ? injectedHandle : null,\n executionReadyFired: false,\n destroyed: false,\n destroyGeneration: 0,\n // Shared in-flight spawn promise — same idiom as `mcpWarmupPromise`:\n // `run()`'s lazy bootstrap and the public `ensureExecution()` (extension\n // `ctx.workspace`, host bridges) must observe ONE spawn + ONE\n // `execution:ready` journal event, never race two containers into\n // existence. A rejected spawn clears the slot so the next caller retries.\n executionSpawnPromise: null,\n mcpConnection: null,\n // Snapshot of the last run's assembled prompt pieces (system, wire tools,\n // deferred tools, MCP groups, skills/subagent catalogs) + the model used.\n // Captured in `run()` right after the prompt is finalized; read on demand by\n // `getContextBreakdown()`. `null` until the first run assembles a prompt.\n lastContextAssembly: null,\n // Shared in-flight warmup promise. Guarantees that concurrent `warmup()` calls\n // and the lazy bootstrap inside `run()` observe the same outcome — we never\n // kick off the connector twice, and a failure in one caller propagates to\n // every awaiter instead of getting masked by a retry.\n mcpWarmupPromise: null,\n conversationTurns: session?.turns.slice() ?? [],\n lastRunContext: null,\n activeRunContext: null,\n overflowRescue: {},\n // `runCounter` mints sequential `run_${N}` ids via `++runCounter`. The\n // naive `session.runs.length` initializer is unsound when the loaded\n // session's `runs[]` is thinner than the runIds referenced by its\n // turns — which happens to forks (the fork starts with the parent's\n // turns but a fresh empty `runs[]`) and to any persistence path that\n // ever lost runs while keeping turns. In those cases starting from\n // `length` would re-mint `run_1`, colliding with a runId already\n // referenced by a turn in the same session. We instead pick the max\n // numeric `run_N` id ever observed in EITHER `runs` or `turns[].runId`\n // so the next mint is guaranteed unique within this session.\n //\n // `syncRunCounter()` scans incrementally: it remembers how far it has\n // walked `runs` and `turns` and only visits the appended tail on each\n // re-sync. Append-only semantics make the tail scan sound; a\n // shrunk/replaced array (reset, fork re-seed) falls back to a full\n // rescan from offset 0. The regex matches the canonical `run_<int>`\n // shape minted by this module; caller-supplied custom id schemes are\n // ignored (they don't conflict with `run_N`).\n runCounter: 0,\n scannedRuns: 0,\n scannedTurns: 0,\n resolvedSkills: null,\n skillsCatalog: null,\n // Shared in-flight skills-resolution promise. Mirrors `mcpWarmupPromise`:\n // guarantees a single resolution pass even under concurrent callers, and\n // surfaces failures to every awaiter instead of masking them with a retry.\n skillsResolvePromise: null,\n // Cleanup fn for the inline-skills temp directory (created by\n // `resolveSkills` when `skills.write` is set). Replaced with the real\n // teardown on first resolution; called from `destroy()` so the OS temp\n // doesn't fill up across many short-lived agents.\n skillsCleanup: () => {},\n }\n rtRef = rt\n syncRunCounter(rt)\n // Extension interceptors on the mutating hooks, after the agent-lifetime hooks\n // (extension hooks on the agent's hook bus among them) and before any the host adds later.\n if (extensionRuntime) {\n // A subagent names its parent's session (`extensionScope`); its own is absent without a shared one.\n const ownSessionId = (): string | undefined => rt.session?.id ?? rt.sessionId\n const sessionIdOf = extensionScope?.sessionId\n const sessionId = sessionIdOf ? (): string | undefined => sessionIdOf() ?? ownSessionId() : ownSessionId\n installInterceptorBridges(hooks, extensionRuntime.interceptors, {\n sessionId,\n ...(approveToolCall ? { onAsk: approveToolCall } : {}),\n mcpServerOf: tool => rt.mcpConnection?.tools[tool] ? resolveMcpToolParts(tool, rt.allMcpServers)?.server : undefined,\n }, extensionScope?.parentRunId !== undefined ? { parentRunId: extensionScope.parentRunId } : {})\n // Read by the spawn tool (a child inherits the runtime) and the tracer (`tracing.redact`).\n recordAgentExtensionWiring(hooks, { extensionRuntime, ...(approveToolCall ? { approveToolCall } : {}), sessionId })\n }\n return rt\n}\n\n/** `AgentOptions.durable` as {@link DurableOptions}: a bare runtime is shorthand for `{ runtime }`. */\nfunction durableOptionsOf(option: AgentOptions['durable']): Partial<DurableOptions> {\n if (!option)\n return {}\n return 'runtime' in option ? option : { runtime: option }\n}\n\n/**\n * Attach `decide` to every object hook context right before its handlers run\n * (hookable passes the same `args` array to `beforeEach` and to handlers).\n * Non-enumerable, so contexts that get logged, serialized or spread are\n * unaffected; bubbled copies get a fresh binding when re-fired. Skipped for\n * `decision:*` events (no recursive decisions) and for frozen contexts.\n *\n * The binding captures the signal of the run active when the hook fires, so a\n * stashed `ctx.decide` stays tied to its own run. Only the latest binding is\n * cached: a new run (fresh controller) replaces it.\n */\nfunction installDecideInjection(hooks: Hookable<AgentHooks>, decider: Decider, currentRunSignal: () => AbortSignal | undefined, currentDurability: () => RunDurability | undefined): void {\n let cached: { runId: string | undefined, signal: AbortSignal | undefined, decide: AgentDecide } | undefined\n const bound = (runId: string | undefined): AgentDecide => {\n const signal = currentRunSignal()\n // A hook fired inside a step's work (a `stream:*` hook during the model\n // step) decides live: the step's record is what a replay sees, and a\n // decision journaled there would nest in it.\n if (insideStepWork())\n return decider.forRun(runId, signal)\n if (!cached || cached.runId !== runId || cached.signal !== signal) {\n // In replay mode a decision of the active run is a recorded step, so a\n // replay takes the branch the live attempt took, under the same id.\n const durability = currentDurability()\n const journaled = durability && replays(durability) && durability.scope.runId === runId\n ? {\n journal: <T>(work: () => Promise<T>) => journaledStep(durability, LOOP_STEP_KINDS.decision, 'decide', work),\n newId: () => durability.scope.uuid(),\n }\n : undefined\n cached = { runId, signal, decide: decider.forRun(runId, signal, journaled?.journal, journaled?.newId) }\n }\n return cached.decide\n }\n hooks.beforeEach((event) => {\n if (isDecisionHookEvent(event.name))\n return\n const ctx: unknown = event.args[0]\n if (!ctx || typeof ctx !== 'object' || Object.hasOwn(ctx, 'decide') || !Object.isExtensible(ctx))\n return\n const runId = (ctx as { runId?: unknown }).runId\n Object.defineProperty(ctx, 'decide', {\n value: bound(typeof runId === 'string' ? runId : undefined),\n enumerable: false,\n configurable: true,\n })\n })\n}\n\n// Reset the run-scoped liveness state (running flag, abort controller, idle\n// gate). Funnels the defensive `finally` resets in `run()` through one place\n// so the inner (happy/abort/throw) and outer (setup-threw) cleanup paths\n// can't drift. Idempotent: re-clearing already-cleared state is a no-op,\n// so both `finally` blocks can call it. Resolving `idleResolve`\n// wakes any `waitForIdle()` awaiters before dropping the promise.\nexport function resetRunScope(rt: AgentRuntime): void {\n rt.running = false\n rt.abortController = undefined\n rt.suspendController = undefined\n rt.idleResolve?.()\n rt.idlePromise = undefined\n rt.idleResolve = undefined\n}\n\nfunction considerRunId(rt: AgentRuntime, id: string | undefined): void {\n if (!id)\n return\n const m = /^run_(\\d+)$/.exec(id)\n if (!m)\n return\n const n = Number.parseInt(m[1], 10)\n if (Number.isFinite(n) && n > rt.runCounter)\n rt.runCounter = n\n}\n/** Re-scan the session for `run_N` ids (incrementally — see the `runCounter` doc in `createAgentRuntime`). */\nexport function syncRunCounter(rt: AgentRuntime): void {\n const { session } = rt\n if (!session)\n return\n if (session.runs.length < rt.scannedRuns)\n rt.scannedRuns = 0\n if (session.turns.length < rt.scannedTurns)\n rt.scannedTurns = 0\n for (let i = rt.scannedRuns; i < session.runs.length; i++)\n considerRunId(rt, session.runs[i].id)\n for (let i = rt.scannedTurns; i < session.turns.length; i++)\n considerRunId(rt, session.turns[i].runId)\n rt.scannedRuns = session.runs.length\n rt.scannedTurns = session.turns.length\n}\n","/**\n * Stream-failure classification — decide what a failed `provider.stream()` call\n * entitles the loop to do next.\n *\n * The decision is pure (error in, verdict out), so the question \"why did this\n * failure retry instead of failing over?\" is answered here and can be tested\n * without a live provider mock.\n *\n * The module decides NOTHING about how a recovery is carried out: applying a\n * backoff, recompacting the transcript, and advancing the fallback chain all\n * mutate loop state and live in `loop-turn-stream.ts`. This file only answers\n * \"which of them is allowed?\".\n */\n\nimport type { ClassifiedError } from './errors'\nimport type { AgentClock, RetryConfig } from './types'\nimport { isTransientTransportError } from './errors'\nimport { abortableSleep, OperationTimeoutError } from './timeout'\n\n/**\n * Operation labels used by the provider-stream watchdogs.\n *\n * Single source of truth for the strings so `withTimeout` callers and the\n * failure classifier can never drift: the classifier matches on exactly the\n * label the watchdog emits.\n */\nexport const PROVIDER_WATCHDOG_OPERATIONS = {\n 'first response': 'provider first response',\n 'total stream': 'provider total stream',\n 'stream inactivity': 'provider stream inactivity',\n} as const\n\nexport type ProviderWatchdogKind = keyof typeof PROVIDER_WATCHDOG_OPERATIONS\n\n/** Watchdog operation names that count as provider-stream failures. */\nconst PROVIDER_WATCHDOG_OPERATION_SET: ReadonlySet<string> = new Set(Object.values(PROVIDER_WATCHDOG_OPERATIONS))\n\nconst RETRY_DEFAULTS = {\n maxAttempts: 3,\n initialDelayMs: 1000,\n maxDelayMs: 30_000,\n} as const\n\nexport interface ResolvedRetryConfig {\n maxAttempts: number\n initialDelayMs: number\n maxDelayMs: number\n}\n\n/**\n * Normalize a user-supplied `RetryConfig` (any field may be missing or invalid)\n * into a fully-populated config the retry loop can use without per-field guards.\n *\n * Invalid values (non-finite, < 1 for `maxAttempts`, < 0 for delays) fall back\n * to defaults rather than throwing — this is a behavior knob, not a validation\n * boundary, and a bad value here shouldn't crash a run.\n */\nexport function resolveRetryConfig(cfg: RetryConfig | undefined): ResolvedRetryConfig {\n const maxAttempts = Number.isFinite(cfg?.maxAttempts) && (cfg!.maxAttempts as number) >= 1\n ? Math.floor(cfg!.maxAttempts as number)\n : RETRY_DEFAULTS.maxAttempts\n const initialDelayMs = Number.isFinite(cfg?.initialDelayMs) && (cfg!.initialDelayMs as number) >= 0\n ? (cfg!.initialDelayMs as number)\n : RETRY_DEFAULTS.initialDelayMs\n const maxDelayMs = Number.isFinite(cfg?.maxDelayMs) && (cfg!.maxDelayMs as number) >= 0\n ? (cfg!.maxDelayMs as number)\n : RETRY_DEFAULTS.maxDelayMs\n return { maxAttempts, initialDelayMs, maxDelayMs }\n}\n\n/**\n * Server-declared `retry-after` above this is treated as \"not a transient\n * blip\" by the fallback machinery: burst rate limits announce seconds,\n * quota/usage exhaustion announces minutes-to-hours. A run holding more\n * fallback targets fails over immediately instead of burning its retry\n * budget against a wall that won't move within the wait window; a\n * single-target run still waits (capped at `maxDelayMs`) because waiting\n * is its only option.\n */\nexport const LONG_RETRY_AFTER_FALLBACK_MS = 15_000\n\n/** Observable state of the half-built stream at the moment it failed. */\nexport interface StreamProgress {\n /** Assistant text received so far this turn. */\n text: string\n /** Thinking text received so far this turn. */\n thinking: string\n /** A provider-side tool executed during the stream (a side effect we can't undo). */\n serverToolActivity: boolean\n /** Tool-call content (name or argument deltas) started streaming, so a call may already be on screen. */\n toolCallActivity: boolean\n}\n\nexport interface StreamFailureInput {\n /** The thrown value. */\n err: unknown\n /** `true` when the run's own signal is already aborted. */\n runAborted: boolean\n /** Provider classifier, if the provider supplies one. */\n classifyError: ((err: unknown) => ClassifiedError | null) | undefined\n progress: StreamProgress\n /** 1-based attempt number that just failed. */\n attempt: number\n retry: ResolvedRetryConfig\n /** `true` when the fallback chain still holds an untried target. */\n hasNextTarget: boolean\n}\n\n/**\n * What the loop is permitted to do about a failed stream. One of\n * `canRetry` / `canRecoverOverflow` / `canFallback` being false does not imply\n * another is true. A failure with no permitted recovery is terminal.\n */\nexport interface StreamFailureAssessment {\n /** The run was cancelled; no recovery applies and the error is terminal. */\n wasAborted: boolean\n /** Provider verdict, or `null` when unclassified / aborted. */\n classified: ClassifiedError | null\n /**\n * Nothing observable was produced before the failure, reasoning included.\n * Gates overflow recovery, whose `context_exceeded` rejection comes before\n * any output.\n */\n cleanSlate: boolean\n /**\n * Re-sending the turn is safe: no text, tool-call content, or provider-side\n * tool execution streamed. Reasoning alone does not count: it is not part\n * of the reply that gets persisted, and the next attempt generates its own.\n * Gates retry and fallback. Implied by `cleanSlate`.\n */\n reissuable: boolean\n /**\n * Reasoning streamed before the failure. When the turn is re-sent, the\n * caller drops it and tells hosts to discard what they showed.\n */\n streamedThinking: boolean\n /** Server-declared wait before retrying, in ms, when it supplied one. */\n retryAfterMs: number | undefined\n /** Take the backoff-and-re-issue path. */\n canRetry: boolean\n /**\n * The server declared a wait long enough that failing over beats waiting.\n * Only ever true when a next target exists — otherwise waiting is the only\n * option and the retry stands.\n */\n preferFallbackOverRetry: boolean\n /** Take the emergency-compaction path (subject to the caller's budget). */\n canRecoverOverflow: boolean\n /** Advance to the next provider+model target. */\n canFallback: boolean\n}\n\n/**\n * Classify a failed stream attempt.\n *\n * Retry eligibility covers three sources: an error the provider's own classifier\n * marked retryable, a provider-stream watchdog timeout, and a transport-level\n * failure. The latter two are retryable BY CONSTRUCTION for the first-response\n * watchdog and for any dropped connection — zero observable events arrived, so\n * re-issuing is at least as safe as the mid-stream `overloaded_error` retries\n * the classifier opts into. The total-stream and inactivity watchdogs ride the\n * same carve-out but lean on `reissuable` for their safety.\n *\n * Retry and fallback both require `reissuable`: text, tool-call content and\n * server-side tool execution block them (text was shown as an answer, a tool\n * call may be on screen, a server tool already ran and was billed). A failure\n * after reasoning-only output stays eligible, so a stream that thinks and then\n * stalls is re-sent instead of ending the run.\n *\n * Transport failures need their own source because they happen BELOW the API:\n * they carry no status and no error body, so `classifyError` returns `null` and\n * the classifier-driven branch can never fire for them.\n *\n * Fallback excludes two classifications:\n * - `context_exceeded` — owned by overflow recovery; the transcript is the\n * problem, not the provider.\n * - `tool_pairing_corruption` — transcript-level corruption fails identically\n * on every provider.\n *\n * Everything else (rate limit, overload, 5xx, auth/billing, even unclassified\n * network failures) is provider-side: a sibling target may well succeed, and a\n * genuinely broken request just exhausts the chain and surfaces the last error.\n */\nexport function assessStreamFailure(input: StreamFailureInput): StreamFailureAssessment {\n const { err, runAborted, classifyError, progress, attempt, retry, hasNextTarget } = input\n\n const wasAborted = runAborted || (err instanceof Error && err.name === 'AbortError')\n const classified = !wasAborted ? (classifyError?.(err) ?? null) : null\n const reissuable = progress.text === '' && !progress.toolCallActivity && !progress.serverToolActivity\n const streamedThinking = progress.thinking !== ''\n const cleanSlate = reissuable && !streamedThinking\n\n const isRetryable = classified?.kind === 'provider_error' && classified.retryable === true\n const isStreamWatchdogTimeout = !wasAborted\n && err instanceof OperationTimeoutError\n && PROVIDER_WATCHDOG_OPERATION_SET.has(err.operation)\n // A dead socket never reached the API, so no provider classifier can label it\n // and `isRetryable` is structurally unreachable for it. It earns a retry by\n // the same argument as the watchdog above: nothing observable arrived.\n // `reissuable` below still does the safety work for both.\n const isTransportFailure = !wasAborted && isTransientTransportError(err)\n\n const canRetry = !wasAborted\n && (isRetryable || isStreamWatchdogTimeout || isTransportFailure)\n && reissuable\n && attempt < retry.maxAttempts\n\n // A header wins; else the reset the classifier read from the body (Gemini's RetryInfo).\n const retryAfterMs = canRetry ? (extractRetryAfterMs(err) ?? classified?.limit?.retryAfterMs) : undefined\n const preferFallbackOverRetry = retryAfterMs !== undefined\n && retryAfterMs > LONG_RETRY_AFTER_FALLBACK_MS\n && hasNextTarget\n\n const canRecoverOverflow = !wasAborted\n && classified?.kind === 'context_exceeded'\n && cleanSlate\n\n const canFallback = !wasAborted\n && reissuable\n && hasNextTarget\n && classified?.kind !== 'context_exceeded'\n && classified?.kind !== 'tool_pairing_corruption'\n\n return {\n wasAborted,\n classified,\n cleanSlate,\n reissuable,\n streamedThinking,\n retryAfterMs,\n canRetry,\n preferFallbackOverRetry,\n canRecoverOverflow,\n canFallback,\n }\n}\n\n/**\n * Backoff delay for the next attempt.\n *\n * A server-declared `retry-after` wins (capped at `maxDelayMs`); otherwise\n * full-jitter exponential backoff — a uniform draw from `[0, capped)` rather\n * than a fixed `capped`, so a fleet of clients retrying the same overloaded\n * endpoint spreads out instead of stampeding in lockstep.\n *\n * `random` draws from `[0, 1)`; pass {@link retryJitter} so a durable run\n * replays the same delay.\n */\nexport function computeRetryDelayMs(\n attempt: number,\n cfg: ResolvedRetryConfig,\n retryAfterMs: number | undefined,\n random: () => number = Math.random,\n): number {\n if (retryAfterMs !== undefined && retryAfterMs >= 0)\n return Math.min(retryAfterMs, cfg.maxDelayMs)\n const exponential = cfg.initialDelayMs * 2 ** (attempt - 1)\n const capped = Math.min(exponential, cfg.maxDelayMs)\n return Math.floor(random() * capped)\n}\n\n/**\n * The clock the retry helpers take: the run's ids, whether the run replays a\n * journal, and its (durable where the runtime has one) sleep.\n */\nexport interface RetryClock extends Pick<AgentClock, 'randomUUID'> {\n /** The run replays a journal (`DurableRuntime.mode === 'replay'`). */\n replays?: boolean\n /** Wait `ms`; a durable timer where the runtime has one. Absent: a timer. */\n sleep?: (ms: number) => Promise<void>\n}\n\n/**\n * Jitter source for {@link computeRetryDelayMs}. A replaying run replays its\n * journaled `randomUUID()` sequence, so the draw is hashed from it:\n * `Math.random` would pick a different delay on replay (and announce it on\n * `stream:retry`). Other runs keep `Math.random`.\n */\nexport function retryJitter(clock: Pick<RetryClock, 'replays' | 'randomUUID'> | undefined): () => number {\n if (clock?.replays !== true)\n return Math.random\n return () => {\n // FNV-1a: works for any id format, not only hex UUIDs.\n let hash = 0x811C9DC5\n for (const ch of clock.randomUUID()) {\n hash ^= ch.charCodeAt(0)\n hash = Math.imul(hash, 0x01000193)\n }\n return (hash >>> 0) / 2 ** 32\n }\n}\n\n/**\n * Wait out a retry backoff. Uses `clock.sleep` when the clock has one (a\n * durable timer on a replay runtime, so a replay doesn't sleep again), else\n * a timer. Rejects when `signal` aborts either way; an abandoned durable\n * sleep is left to the runtime. The durable timer starts even when `signal`\n * already aborted: a replay, which never sees the abort, starts it too.\n */\nexport function backoffSleep(ms: number, signal: AbortSignal, clock: Pick<RetryClock, 'sleep'> | undefined): Promise<void> {\n const sleep = clock?.sleep\n if (!sleep)\n return abortableSleep(ms, signal)\n const timer = sleep(ms)\n if (signal.aborted) {\n timer.catch(() => {})\n return Promise.reject(signal.reason ?? new DOMException('Aborted', 'AbortError'))\n }\n return new Promise((resolve, reject) => {\n const onAbort = () => reject(signal.reason ?? new DOMException('Aborted', 'AbortError'))\n signal.addEventListener('abort', onAbort, { once: true })\n timer.then(\n () => {\n signal.removeEventListener('abort', onAbort)\n resolve()\n },\n (err) => {\n signal.removeEventListener('abort', onAbort)\n reject(err)\n },\n )\n })\n}\n\n/**\n * Extract a `retry-after` value (in milliseconds) from an error's `.headers`, if any.\n *\n * Supports both `retry-after-ms` (non-standard but Stainless-emitted; already in ms,\n * always integer) and the standard `retry-after` header (integer seconds, RFC 7231).\n * Returns `undefined` when neither is present, non-numeric, or negative.\n *\n * `parseInt` over `parseFloat` here matches the actual contract — Stainless emits\n * `retry-after-ms` as an integer and RFC 7231 specifies a non-negative integer for\n * the seconds form. The HTTP-date form of `retry-after` is deliberately unsupported\n * (Anthropic + OpenAI both emit numeric seconds; supporting dates invites clock-skew\n * concerns for negligible benefit).\n */\nexport function extractRetryAfterMs(err: unknown): number | undefined {\n if (!err || typeof err !== 'object')\n return undefined\n const headers = (err as { headers?: unknown }).headers\n if (!headers || typeof headers !== 'object')\n return undefined\n // Support both `Map`/`Headers`-like with `.get()` and plain objects.\n const get = (key: string): string | undefined => {\n const h = headers as { get?: (k: string) => string | null | undefined } & Record<string, unknown>\n if (typeof h.get === 'function') {\n const v = h.get(key)\n return typeof v === 'string' ? v : undefined\n }\n const v = h[key]\n return typeof v === 'string' ? v : undefined\n }\n const ms = get('retry-after-ms')\n if (ms !== undefined) {\n const parsed = Number.parseInt(ms, 10)\n if (Number.isFinite(parsed) && parsed >= 0)\n return parsed\n }\n const seconds = get('retry-after')\n if (seconds !== undefined) {\n const parsed = Number.parseInt(seconds, 10)\n if (Number.isFinite(parsed) && parsed >= 0)\n return parsed * 1000\n }\n return undefined\n}\n","/**\n * Typed errors thrown by the compaction helper.\n *\n * Lives in its own file so both the runner and the pure messages module\n * can import without circular dependencies.\n */\n\n/**\n * Raised when the caller's inputs make compaction meaningless before any\n * API call is attempted. Common cases:\n * - empty `turns`\n * - `keepTurns >= turns.length` (no older content to summarize)\n * - `'from'` / `'up_to'` anchor id not found in `turns`\n * - the resolved `toSummarize` slice has no text-bearing content\n *\n * Synchronous — thrown from `compactConversation()` before the provider\n * call so the caller can recover without a network round-trip.\n * @param message - Description of the invalid input.\n */\nexport class CompactInvalidInputError extends Error {\n /**\n * Creates the error.\n *\n * @param message - Description of the invalid input.\n */\n constructor(message: string) {\n super(message)\n this.name = 'CompactInvalidInputError'\n }\n}\n\n/**\n * Raised when the provider rejects the compaction request with\n * `prompt_too_long` (or an equivalent) and the head-truncation retry\n * budget has been exhausted. Callers can inspect `ptlRetries` to log\n * how far the retry loop got before giving up.\n * @param message - Error message.\n * @param ptlRetries - Number of head-truncation retries made before giving up.\n */\nexport class CompactPromptTooLongError extends Error {\n /**\n * Creates the error.\n *\n * @param message - Error message.\n * @param ptlRetries - Number of head-truncation retries made before giving up.\n */\n constructor(message: string, public readonly ptlRetries: number) {\n super(message)\n this.name = 'CompactPromptTooLongError'\n }\n}\n","/**\n * Pure helpers for compaction — slicing, image stripping, head-truncation\n * on `prompt_too_long`, and the synthetic-turn builder.\n *\n * Everything in this file is total and side-effect-free. Inputs are never\n * mutated; helpers return fresh arrays whenever they modify content.\n */\n\nimport type {\n SessionContentBlock,\n SessionTurn,\n ToolResultContent,\n TurnUsage,\n} from '../types'\nimport { toolOutputByteLength } from '../types'\nimport { CompactInvalidInputError } from './errors'\nimport { utf8ByteLength } from './utils'\n\n/**\n * What to summarize and what to preserve verbatim.\n *\n * - `'full'` — summarize everything, no preserved tail.\n * - `'tail'` — summarize everything before the last `keepTurns` turns.\n * - `{ kind: 'from', turnId }` — summarize from the anchor turn onward.\n * - `{ kind: 'up_to', turnId }` — summarize up to (and including) the anchor.\n */\nexport type CompactScope\n = | 'full'\n | 'tail'\n | { kind: 'from', turnId: string }\n | { kind: 'up_to', turnId: string }\n\n/** Result of {@link sliceForCompaction}: the turns to summarize and the turns to keep. */\nexport interface CompactionSlice {\n /** The portion of the conversation that will be summarized. */\n toSummarize: readonly SessionTurn[]\n /** The portion that stays verbatim in the post-compact history. */\n preserved: readonly SessionTurn[]\n}\n\n/**\n * Partition `turns` into `(toSummarize, preserved)` according to `scope`.\n *\n * Throws {@link CompactInvalidInputError} on degenerate inputs so the\n * caller doesn't pay for a doomed provider call:\n * - empty `turns`\n * - `scope: 'tail'` with `keepTurns >= turns.length` (nothing to summarize)\n * - `scope: { from | up_to }` with an anchor id that isn't in `turns`\n * - the resulting `toSummarize` slice contains no text-bearing content\n * (only system turns or empty content)\n *\n * Pure. Returns references to the original `SessionTurn` objects — the\n * caller can compare by identity (=== Object.is) to confirm.\n * @param turns - Conversation in chronological order.\n * @param scope - Which part of the conversation to summarize.\n * @param keepTurns - Trailing turns to keep when `scope` is `'tail'`. Negative values count as 0.\n */\nexport function sliceForCompaction(\n turns: readonly SessionTurn[],\n scope: CompactScope,\n keepTurns: number,\n): CompactionSlice {\n if (turns.length === 0)\n throw new CompactInvalidInputError('No turns to compact.')\n\n let toSummarize: readonly SessionTurn[]\n let preserved: readonly SessionTurn[]\n\n if (scope === 'full') {\n toSummarize = turns\n preserved = []\n }\n else if (scope === 'tail') {\n const keep = Math.max(0, keepTurns)\n if (keep >= turns.length) {\n throw new CompactInvalidInputError(\n `Nothing to compact: keepTurns (${keep}) covers the entire conversation (${turns.length} turns).`,\n )\n }\n const safeCut = findSafeRoundBoundary(turns, turns.length - keep)\n toSummarize = turns.slice(0, safeCut)\n preserved = turns.slice(safeCut)\n }\n else if (scope.kind === 'from') {\n const idx = turns.findIndex(t => t.id === scope.turnId)\n if (idx < 0)\n throw new CompactInvalidInputError(`Anchor turn not found: \"${scope.turnId}\".`)\n // 'from' summarizes the recent portion (anchor onward); everything\n // before stays verbatim. Walk the anchor BACKWARD to the start of\n // the round containing it so neither half ends mid-round (avoids\n // orphan `tool_use` in `preserved` AND orphan `tool_result` at\n // the head of `toSummarize`).\n const safeIdx = findSafeRoundBoundary(turns, idx)\n preserved = turns.slice(0, safeIdx)\n toSummarize = turns.slice(safeIdx)\n }\n else {\n // 'up_to' summarizes the older portion (up to and including the anchor);\n // everything after stays verbatim. Same `tool_use ↔ tool_result`\n // adjacency rule as 'tail': cut backward if the proposed boundary\n // would orphan a `tool_use` at the end of `toSummarize`.\n const idx = turns.findIndex(t => t.id === scope.turnId)\n if (idx < 0)\n throw new CompactInvalidInputError(`Anchor turn not found: \"${scope.turnId}\".`)\n const safeCut = findSafeRoundBoundary(turns, idx + 1)\n toSummarize = turns.slice(0, safeCut)\n preserved = turns.slice(safeCut)\n }\n\n if (toSummarize.length === 0)\n throw new CompactInvalidInputError('Compaction scope resolved to zero turns.')\n if (!hasTextBearingContent(toSummarize))\n throw new CompactInvalidInputError('Compaction scope contains no text-bearing turns to summarize.')\n\n return { toSummarize, preserved }\n}\n\n/**\n * Replace every attachment block in `turns` with a short text marker\n * (`[image]`, `[audio]`, `[video]` or `[document]`).\n *\n * Covers two shapes:\n * - Top-level image, audio, video and document content blocks.\n * - The same block types inside `tool_result.output` array form\n * (multimodal tool results — e.g. an MCP browser screenshot).\n *\n * Unconditional by design: even on vision-capable models, the summary\n * call doesn't benefit from raw image bytes (the model can't refer to\n * them after the summary lands), and stripping uniformly avoids\n * `prompt_too_long` on image-heavy sessions.\n *\n * Returns a fresh array; input turns / blocks are never mutated.\n * @param turns - Turns to flatten.\n */\nexport function stripImagesFromTurns(turns: readonly SessionTurn[]): SessionTurn[] {\n return turns.map(turn => stripImagesFromTurn(turn))\n}\n\nfunction stripImagesFromTurn(turn: SessionTurn): SessionTurn {\n let touched = false\n const nextContent: SessionContentBlock[] = []\n for (const block of turn.content) {\n if (block.type === 'image') {\n touched = true\n nextContent.push({ type: 'text', text: '[image]' })\n continue\n }\n if (block.type === 'audio') {\n touched = true\n nextContent.push({ type: 'text', text: '[audio]' })\n continue\n }\n if (block.type === 'video') {\n touched = true\n nextContent.push({ type: 'text', text: '[video]' })\n continue\n }\n if (block.type === 'document') {\n touched = true\n nextContent.push({ type: 'text', text: '[document]' })\n continue\n }\n if (block.type === 'tool_result' && Array.isArray(block.output)) {\n const flat = stripAttachmentsFromToolResult(block.output)\n if (flat) {\n touched = true\n nextContent.push({ ...block, output: flat })\n continue\n }\n }\n nextContent.push(block)\n }\n return touched ? { ...turn, content: nextContent } : turn\n}\n\n/**\n * Return a fresh `ToolResultContent[]` with image, audio, video and document\n * blocks flattened to text placeholders (`[image]` and so on), or `null` when\n * none were present (caller keeps the original input). Returning a new mutable array — never the\n * input — keeps the `tool_result.output` slot's mutable type contract\n * satisfied without leaky `as`-casts at the call site.\n */\nfunction stripAttachmentsFromToolResult(parts: readonly ToolResultContent[]): ToolResultContent[] | null {\n let touched = false\n const out: ToolResultContent[] = []\n for (const part of parts) {\n if (part.type === 'image') {\n touched = true\n out.push({ type: 'text', text: '[image]' })\n }\n else if (part.type === 'audio') {\n touched = true\n out.push({ type: 'text', text: '[audio]' })\n }\n else if (part.type === 'video') {\n touched = true\n out.push({ type: 'text', text: '[video]' })\n }\n else if (part.type === 'document') {\n touched = true\n out.push({ type: 'text', text: '[document]' })\n }\n else {\n out.push(part)\n }\n }\n return touched ? out : null\n}\n\n/**\n * Shrink `turns` for a `prompt_too_long` retry and return a fresh array.\n *\n * Drops whole rounds from the head until the remaining slice is at most\n * HALF the byte size of the input (always dropping at least one round).\n * Halving is the load-bearing property: the retry budget is small (3 by\n * default), so shrinkage must be geometric, not linear. Dropping a single\n * round per retry would never converge on a very long session where each\n * round is a rounding error against the overflow, and compaction would fail\n * with `prompt_too_long after 3 retries` even though a smaller prompt would\n * have succeeded.\n *\n * A round is a contiguous `[user, assistant?, tool_results?]` group.\n *\n * Adjacency-safe: only whole rounds are dropped, so the result still\n * respects every provider's `tool_use ↔ tool_result` adjacency rule.\n *\n * Returns `turns` unchanged when only one round (or less) remains — the\n * caller is expected to interpret that as \"cannot shrink further\" and\n * give up the retry loop.\n * @param turns - Turns of the failed attempt, oldest first.\n */\nexport function truncateHeadForPtlRetry(turns: readonly SessionTurn[]): SessionTurn[] {\n if (turns.length <= 1)\n return turns.slice()\n\n const targetBytes = Math.floor(turnsByteLength(turns) / 2)\n let remaining = dropOldestRound(turns)\n if (remaining.length === turns.length)\n return remaining // nothing droppable — caller stops retrying\n\n while (remaining.length > 1 && turnsByteLength(remaining) > targetBytes) {\n const next = dropOldestRound(remaining)\n if (next.length === remaining.length)\n break\n remaining = next\n }\n return remaining\n}\n\n/**\n * Drop the oldest round from `turns`. Returns a copy of `turns` unchanged\n * when no clean round boundary exists to cut at.\n */\nfunction dropOldestRound(turns: readonly SessionTurn[]): SessionTurn[] {\n if (turns.length <= 1)\n return turns.slice()\n\n // Find the first turn that opens a clean conversational round we can\n // drop ending on — start with the first `user` turn (it's the natural\n // start-of-round marker).\n const firstUserIdx = turns.findIndex(t => t.role === 'user')\n if (firstUserIdx < 0)\n return turns.slice()\n\n // Skip past every turn that belongs to this round: the user turn\n // itself, the assistant reply (if any), and the next user turn whose\n // content is *only* tool_result blocks (an immediate follow-up that\n // closes out tool calls). Stop when we reach the next round-opening\n // user turn (i.e. one that carries non-tool_result content).\n let cursor = firstUserIdx + 1\n while (cursor < turns.length) {\n const turn = turns[cursor]\n if (turn.role === 'assistant') {\n cursor++\n continue\n }\n if (turn.role === 'user' && isToolResultsOnlyTurn(turn)) {\n cursor++\n continue\n }\n break\n }\n\n // If the cursor walked all the way to the end, refuse to truncate —\n // the remaining slice would be empty, which is never useful.\n if (cursor >= turns.length)\n return turns.slice()\n\n return turns.slice(cursor)\n}\n\n/**\n * Rough byte size of a turn slice — text, thinking, tool outputs, and\n * tool-call inputs. Image blocks are deliberately excluded: the runner\n * strips them (`stripImagesFromTurns`) before any byte math runs.\n * Single source of truth for both the PTL halving target and the\n * runner's `onAttempt` reporting.\n */\nexport function turnsByteLength(turns: readonly SessionTurn[]): number {\n let total = 0\n for (const turn of turns) {\n for (const block of turn.content) {\n if (block.type === 'text' || block.type === 'thinking')\n total += utf8ByteLength(block.text)\n else if (block.type === 'tool_result')\n total += toolOutputByteLength(block.output)\n else if (block.type === 'tool_call')\n total += utf8ByteLength(JSON.stringify(block.input))\n // Prior markers reach the summarizer's wire as inlined text\n // (`turnsToMessages` renders \"[Previous compaction summary]\\n…\"),\n // so they must count toward the PTL halving target too.\n else if (block.type === 'compact-summary')\n total += utf8ByteLength(block.summary)\n }\n }\n return total\n}\n\nfunction isToolResultsOnlyTurn(turn: SessionTurn): boolean {\n if (turn.content.length === 0)\n return false\n return turn.content.every(block => block.type === 'tool_result')\n}\n\n/**\n * Walk `proposedCut` backward to the nearest position where splitting at\n * that index produces a round-boundary-clean partition — i.e. neither\n * half breaks the `tool_use ↔ tool_result` adjacency rule that every\n * provider (most strictly Anthropic) enforces.\n *\n * The hazardous case: the proposed cut lands BETWEEN an assistant turn\n * carrying `tool_call` blocks and the user turn carrying the matching\n * `tool_result` blocks. Then `toSummarize` ends with an orphan\n * `tool_use` (provider 400 on the summarization request) AND `preserved`\n * starts with an orphan `tool_result` (provider 400 on the next live\n * agent run against the wire-level cutoff output).\n *\n * Algorithm: keep walking `cut` backward as long as `turns[cut - 1]`\n * is an assistant turn with at least one `tool_call` block. The walk\n * stops when:\n * - we reach `cut = 0` (slice would be empty; caller's existing\n * \"scope resolved to zero turns\" guard handles it), or\n * - the trailing turn is user-role (clean — model emits no pending\n * tool_use from user turns), or\n * - the trailing turn is assistant text without tool_use (clean —\n * text-only response is a complete round).\n *\n * Returning the adjusted cut over-preserves the tail relative to the\n * caller's request — `keepTurns` is interpreted as the MINIMUM number\n * of turns kept verbatim, not the exact count.\n */\nfunction findSafeRoundBoundary(turns: readonly SessionTurn[], proposedCut: number): number {\n let cut = Math.max(0, Math.min(turns.length, proposedCut))\n while (cut > 0 && hasPendingToolUse(turns[cut - 1]))\n cut--\n return cut\n}\n\n/** Does this turn end with any unanswered `tool_use` blocks? */\nfunction hasPendingToolUse(turn: SessionTurn): boolean {\n if (turn.role !== 'assistant')\n return false\n for (const block of turn.content) {\n if (block.type === 'tool_call')\n return true\n }\n return false\n}\n\nfunction hasTextBearingContent(turns: readonly SessionTurn[]): boolean {\n for (const turn of turns) {\n if (turn.role === 'system')\n continue\n for (const block of turn.content) {\n if (block.type === 'text' && block.text.trim().length > 0)\n return true\n if (block.type === 'tool_call' || block.type === 'tool_result')\n return true\n }\n }\n return false\n}\n\n// ---------------------------------------------------------------------------\n// Summary turn builder\n// ---------------------------------------------------------------------------\n\n/**\n * Maximum length of an anchor turn's textual preview, in characters. Long\n * enough to give the model recognizable context (the first paragraph of\n * a typical user message), short enough that it doesn't blow the\n * cache-stability invariant for the prompt prefix.\n */\nexport const ANCHOR_PREVIEW_MAX_CHARS = 200\n\n/**\n * Extract the first ~200 chars of text-bearing content from a turn — the\n * preview surfaced in `from` / `up_to` direction prompts so the model\n * knows where the slice begins.\n * @param turn - Anchor turn to preview.\n */\nexport function anchorPreviewFor(turn: SessionTurn): string {\n for (const block of turn.content) {\n if (block.type === 'text' && block.text.trim().length > 0) {\n const flat = block.text.replace(/\\s+/g, ' ').trim()\n return flat.length > ANCHOR_PREVIEW_MAX_CHARS\n ? `${flat.slice(0, ANCHOR_PREVIEW_MAX_CHARS - 1)}…`\n : flat\n }\n }\n return '(no preview available)'\n}\n\n/**\n * Input shape for {@link summaryToTurn}. Designed to align with the\n * fields of `CompactResult` so a caller can spread the runner's output\n * with a single `replacesTurnIds` rename — no field-by-field unpacking\n * required.\n *\n * Primitive shape (no `CompactResult` import) keeps this module free of\n * dependencies on the runner — `compact.ts` imports from here, not the\n * other way around.\n */\nexport interface SummaryToTurnInput {\n /** Summary text — typically `CompactResult.summary`. */\n summary: string\n /** Turn ids being replaced — typically `CompactResult.summarizedTurnIds`. */\n replacesTurnIds: readonly string[]\n /** Model id that produced the summary. */\n model: string\n /** Token usage from the summary call. */\n usage: TurnUsage\n /** Defaults to `Date.now()` when omitted. */\n compactedAt?: number\n /**\n * Turn id. Defaults to `crypto.randomUUID()`. A replaying run passes an\n * id from its runtime's clock so the marker turn is byte-identical on\n * replay; pair it with a {@link compactedAt} from the same clock.\n */\n id?: string\n}\n\n/**\n * Build a synthetic `SessionTurn` carrying a single `compact-summary`\n * block, ready to append to a session.\n *\n * The turn's role is `'user'` so it sits at a conversational boundary\n * the way the model expects. The caller is responsible for\n * `session.appendTurns([turn])`. The id defaults to `crypto.randomUUID()`\n * (override via `input.id` for durable-execution replay stability).\n *\n * Typical use after running `compactConversation`:\n *\n * ```ts\n * const result = await compactConversation({ provider, turns })\n * const turn = summaryToTurn({\n * summary: result.summary,\n * replacesTurnIds: result.summarizedTurnIds,\n * model: result.model,\n * usage: result.usage,\n * })\n * await session.appendTurns([turn])\n * ```\n * @param input - Summary text, replaced turn ids, model, usage and optional id and timestamp.\n */\nexport function summaryToTurn(input: SummaryToTurnInput): SessionTurn {\n const compactedAt = input.compactedAt ?? Date.now()\n return {\n id: input.id ?? crypto.randomUUID(),\n role: 'user',\n content: [{\n type: 'compact-summary',\n replacesTurnIds: input.replacesTurnIds,\n summary: input.summary,\n model: input.model,\n usage: input.usage,\n compactedAt,\n }],\n createdAt: compactedAt,\n }\n}\n","/**\n * Pure prompt builders for conversation compaction.\n *\n * The builders produce the **system prompt** for a no-tools summary call.\n * They are total functions of `(direction, anchorPreview?)` and produce\n * byte-stable output for the same inputs — that's load-bearing for the\n * provider's prompt cache: repeated compactions in the same host process\n * share the same prefix and read cache instead of writing it.\n *\n * Inspired by Claude Code's `services/compact/prompt.ts` — same 9-section\n * scaffold, same `<analysis> + <summary>` envelope, same no-tools\n * preamble. Adapted to zidane-specific wording (no \"Claude\" references)\n * and trimmed of the bits that don't apply (no `marble_origami`-style\n * query sources, no compaction-fingerprint header).\n */\n\n/** Identifier for the section of the conversation being summarized. */\nexport type CompactDirection = 'full' | 'tail' | 'from' | 'up_to'\n\n/** Options passed to a {@link CompactPromptBuilder}. */\nexport interface CompactPromptOptions {\n /** Which part of the conversation the summary covers. */\n direction: CompactDirection\n /**\n * Short preview of the anchor turn's text — only used by `'from'` and\n * `'up_to'`. Pass the first ~200 chars of the anchor turn so the model\n * has a recognizable handle on where the slice begins / ends. Empty /\n * undefined for `'full'` and `'tail'`.\n */\n anchorPreview?: string\n}\n\n/**\n * Function shape for callers that want to swap in a domain-specific\n * summary prompt (security review handoff, support-ticket continuation,\n * etc.) without touching the runner. Default: {@link buildCompactPrompt}.\n */\nexport type CompactPromptBuilder = (opts: CompactPromptOptions) => string\n\n// ---------------------------------------------------------------------------\n// Composable blocks — each one is a frozen string for cache-stability and\n// quoted verbatim from inside the named builders below. Exported so\n// callers building custom prompts can stitch them together.\n// ---------------------------------------------------------------------------\n\n/**\n * No-tools guard. The runner sends `tools: []` to the provider already,\n * but some models still hallucinate tool-call intent on a long\n * conversation. The prose guard is cheap insurance.\n */\nexport const NO_TOOLS_PREAMBLE = `CRITICAL: Respond with TEXT ONLY. Do NOT call any tools.\n\n- Do NOT use Read, Bash, Grep, Glob, Edit, Write, or ANY other tool.\n- You already have all the context you need in the conversation above.\n- Tool calls will be REJECTED and will waste your only turn — you will fail the task.\n- Your entire response must be plain text: an <analysis> block followed by a <summary> block.`\n\n/**\n * Body shared by every direction. Lays out the 9-section scaffold,\n * mirrors Claude Code's `BASE_COMPACT_PROMPT` so a model already trained\n * on the layout produces the same shape.\n */\nexport const BASE_INSTRUCTIONS = `Your task is to create a detailed summary of the conversation so far, paying close attention to the user's explicit requests and your previous actions.\n\nThis summary should be thorough in capturing technical details, code patterns, and architectural decisions that would be essential for continuing development work without losing context.\n\nBefore providing your final summary, wrap your analysis in <analysis> tags to organize your thoughts and ensure you've covered all necessary points. In your analysis process:\n\n1. Chronologically analyze each message and section of the conversation. For each section thoroughly identify:\n - The user's explicit requests and intents\n - Your approach to addressing the user's requests\n - Key decisions, technical concepts and code patterns\n - Specific details like file names, full code snippets, function signatures, file edits\n - Errors that you ran into and how you fixed them\n - Pay special attention to specific user feedback that you received, especially if the user told you to do something differently.\n - Record what changed and why, not how tools were driven (e.g. which shell commands or scripts made an edit); the next context chooses its own tools.\n2. Double-check for technical accuracy and completeness.\n\nYour summary, wrapped in <summary> tags, must include the following sections:\n\n1. Primary Request and Intent\n2. Key Technical Concepts\n3. Files and Code Sections (with paths; include code snippets only when load-bearing)\n4. Errors and fixes\n5. Problem Solving\n6. All user messages (list ALL non-tool user messages, verbatim)\n7. Pending Tasks\n8. Current Work\n9. Optional Next Step (include direct quotes from the most recent conversation when relevant)`\n\n/** Trailer prompting the model to begin. Same on every direction. */\nexport const TRAILER = 'Provide your <analysis> and <summary> now.'\n\n// ---------------------------------------------------------------------------\n// Direction blurbs — the only knob that varies between builders. Each is\n// frozen and concise so cache-key drift is impossible between calls with\n// the same direction.\n// ---------------------------------------------------------------------------\n\nconst FULL_BLURB = `## Scope\nThe conversation above is being summarized in full. Capture every section the user might need to resume from a fresh context.`\n\nconst TAIL_BLURB = `## Scope\nSummarize the conversation above. The most recent turns will be preserved verbatim alongside your summary, so prioritize older context that would otherwise be lost.`\n\nconst FROM_BLURB = `## Scope\nSummarize the conversation FROM the marked anchor onward (the recent portion). Everything before the anchor will be preserved verbatim.\n\nAnchor turn (preview):\n%ANCHOR_PREVIEW%`\n\nconst UP_TO_BLURB = `## Scope\nSummarize the conversation UP TO the marked anchor (the older portion). Everything from the anchor onward will be preserved verbatim — your summary's job is to compress the prior context the user can no longer scroll back to.\n\nAnchor turn (preview):\n%ANCHOR_PREVIEW%`\n\n// ---------------------------------------------------------------------------\n// Named builders — discoverable, single-purpose, cache-stable.\n// ---------------------------------------------------------------------------\n\n/** Compose the full prompt with a custom direction-blurb. Internal helper. */\nfunction compose(blurb: string): string {\n return [NO_TOOLS_PREAMBLE, BASE_INSTRUCTIONS, blurb, TRAILER].join('\\n\\n')\n}\n\n/** Builds the summary prompt for summarizing the whole conversation. */\nexport function buildFullCompactPrompt(): string {\n return compose(FULL_BLURB)\n}\n\n/** Builds the summary prompt for summarizing everything before the preserved tail. */\nexport function buildTailCompactPrompt(): string {\n return compose(TAIL_BLURB)\n}\n\n/**\n * Builds the summary prompt for summarizing from an anchor turn onward.\n *\n * @param anchorPreview - Short text preview of the anchor turn.\n */\nexport function buildFromCompactPrompt(anchorPreview: string): string {\n return compose(FROM_BLURB.replace('%ANCHOR_PREVIEW%', anchorPreview))\n}\n\n/**\n * Builds the summary prompt for summarizing up to an anchor turn.\n *\n * @param anchorPreview - Short text preview of the anchor turn.\n */\nexport function buildUpToCompactPrompt(anchorPreview: string): string {\n return compose(UP_TO_BLURB.replace('%ANCHOR_PREVIEW%', anchorPreview))\n}\n\n/**\n * Opening of {@link buildCompactInstruction}: the {@link NO_TOOLS_PREAMBLE}\n * adapted to a request that still lists the conversation's tools (they stay\n * so the request matches the conversation's and reads from cache). Says it\n * comes from the harness because, unlike the system prompt, this text sits\n * in a user-role message the summary would otherwise quote as the user's.\n */\nconst PREFIX_PREAMBLE = `Do not call any tools. Reply with the summary only.\n\nThis is an automated compaction request from the harness, NOT a message from the user — do not quote or attribute it as one. Do not answer or carry out the latest user message now: it stays in the conversation after your summary and gets its answer then. Summarize the whole conversation from its very first message, keeping every fact, name, code and number the user gave. The tools above are listed only so this request matches the conversation; any tool call is discarded and wastes your only turn. You already have all the context you need in the conversation above. Your entire response must be plain text: an <analysis> block followed by a <summary> block.`\n\n/** Placement note for {@link buildCompactInstruction}: the summarizer sees the kept tail too. */\nconst PREFIX_VERBATIM_NOTE = 'The conversation above still includes the most recent turns. They stay verbatim after your summary, so the summary must carry everything older that the next context needs.'\n\nfunction blurbFor(opts: CompactPromptOptions): string {\n switch (opts.direction) {\n case 'full':\n return FULL_BLURB\n case 'tail':\n return TAIL_BLURB\n case 'from':\n case 'up_to': {\n const preview = opts.anchorPreview ?? ''\n if (preview.length === 0)\n throw new Error(`buildCompactInstruction: \\`anchorPreview\\` is required for direction \"${opts.direction}\".`)\n return (opts.direction === 'from' ? FROM_BLURB : UP_TO_BLURB).replace('%ANCHOR_PREVIEW%', preview)\n }\n }\n}\n\n/**\n * Builds the summary instruction appended to the END of the conversation's\n * own request (the prefix-cache path of `compactConversation`). Same\n * instructions as {@link buildCompactPrompt}, worded for a request that\n * keeps the conversation's system prompt and tools.\n *\n * @param opts - Direction and anchor preview, as for {@link buildCompactPrompt}.\n */\nexport function buildCompactInstruction(opts: CompactPromptOptions): string {\n return [PREFIX_PREAMBLE, BASE_INSTRUCTIONS, blurbFor(opts), PREFIX_VERBATIM_NOTE, TRAILER].join('\\n\\n')\n}\n\n/**\n * Default public builder. Dispatches by direction to the four named\n * builders. Throws when `from` / `up_to` are passed without an\n * `anchorPreview` — those scopes only make sense with an anchor and a\n * silent fallback would produce a prompt that doesn't tell the model\n * where the slice begins.\n */\nexport const buildCompactPrompt: CompactPromptBuilder = (opts) => {\n switch (opts.direction) {\n case 'full':\n return buildFullCompactPrompt()\n case 'tail':\n return buildTailCompactPrompt()\n case 'from': {\n const preview = opts.anchorPreview ?? ''\n if (preview.length === 0)\n throw new Error('buildCompactPrompt: `anchorPreview` is required for direction \"from\".')\n return buildFromCompactPrompt(preview)\n }\n case 'up_to': {\n const preview = opts.anchorPreview ?? ''\n if (preview.length === 0)\n throw new Error('buildCompactPrompt: `anchorPreview` is required for direction \"up_to\".')\n return buildUpToCompactPrompt(preview)\n }\n }\n}\n","/**\n * `compactConversation` — drive a one-shot summary call against a\n * provider and return a structured envelope describing what was\n * summarized and what stays verbatim.\n *\n * This is the harness primitive. It does not mutate the session, does\n * not own re-entrancy guards, does not enforce a circuit breaker — those\n * belong to whoever wires compaction into a control loop (the agent\n * loop's autocompact trigger, the TUI's session-details modal action,\n * an SDK consumer's batch job).\n *\n * Architecture: mirrors {@link generateSessionTitle} verbatim. The\n * provider's `stream()` is the one-shot completion primitive zidane\n * already exposes; this module reuses it directly instead of layering\n * a second abstraction on top.\n *\n * Caching: the system prompt is byte-stable per `(direction,\n * anchorPreview)` pair (see `./prompt.ts`). Repeated compactions in the\n * same host process share that prefix and read provider cache instead\n * of writing it.\n */\n\nimport type { ResolvedRetryConfig, RetryClock } from '../loop-recovery'\nimport type { Provider, StreamOptions } from '../providers'\nimport type {\n SessionContentBlock,\n SessionMessage,\n SessionTurn,\n ThinkingLevel,\n TurnUsage,\n} from '../types'\nimport type { CompactionSlice, CompactScope } from './messages'\nimport type { CompactPromptBuilder } from './prompt'\nimport { isTransientTransportError } from '../errors'\nimport { backoffSleep, computeRetryDelayMs, extractRetryAfterMs, retryJitter } from '../loop-recovery'\nimport { ensureToolResultPairing } from '../session/messages'\nimport { linkAbortSignal, resolveTimeoutMs, withInactivityTimeout } from '../timeout'\nimport { isWireTurn } from '../types'\nimport { CompactPromptTooLongError } from './errors'\nimport {\n anchorPreviewFor,\n sliceForCompaction,\n stripImagesFromTurns,\n truncateHeadForPtlRetry,\n turnsByteLength,\n} from './messages'\nimport { buildCompactInstruction, buildCompactPrompt } from './prompt'\nimport { utf8ByteLength } from './utils'\n\n// ---------------------------------------------------------------------------\n// Public API\n// ---------------------------------------------------------------------------\n\n/** Options for {@link compactConversation}. */\nexport interface CompactOptions {\n /** Provider used for the summary call. Called with empty tools list. */\n provider: Provider\n /** Conversation to compact, in chronological order. */\n turns: readonly SessionTurn[]\n /**\n * What to summarize. Default: `'tail'` — summarize everything before\n * the last `keepTurns` turns. See {@link CompactScope}.\n */\n scope?: CompactScope\n /**\n * Trailing turns left untouched when `scope: 'tail'`. Default: 4.\n * Matches `AgentBehavior.compactKeepTurns` so a host that uses both\n * mechanisms shares one knob.\n */\n keepTurns?: number\n /** Model id used for the summary call. Default: `provider.meta.defaultModel`. */\n model?: string\n /**\n * Maximum tokens the summary itself can occupy. Default: 20_000 — the\n * p99.99 of summary output size in Claude Code's `COMPACT_MAX_OUTPUT`.\n * Reasonable for any model with a 200k+ window.\n */\n maxOutputTokens?: number\n /** Optional reasoning level. Default: `'off'` — summarization rarely benefits from thinking. */\n thinking?: ThinkingLevel\n /** Optional cancellation signal forwarded to `provider.stream()`. */\n signal?: AbortSignal\n /**\n * Clock for transient-error backoff: its `sleep` and, when it `replays`,\n * its jitter source (see `retryJitter`), so a durable replay neither\n * re-sleeps in real time nor picks a different delay. Default: a timer\n * and `Math.random`.\n */\n clock?: RetryClock\n /**\n * Errors matching this predicate are rethrown instead of being swallowed\n * or retried. The agent loop passes its durable runtime's\n * `isControlError`, so control errors (suspension, cancellation) escape.\n */\n shouldRethrowError?: (error: unknown) => boolean\n /**\n * INACTIVITY watchdog for the provider summary call in milliseconds —\n * the clock resets on every streamed delta (text or thinking), so it\n * bounds silence, not total duration. A hung stream fails after this\n * much dead air; a healthy-but-slow stream (huge prompt → minutes of\n * generation) is never killed mid-summary. Note the window also covers\n * time-to-first-token: prompt ingestion on very large contexts emits\n * nothing, which is why the default is generous. Set `0` to disable.\n * Default: 300000 (5 minutes of silence).\n */\n providerStreamTimeoutMs?: number\n /**\n * Retries with head-truncation when the provider reports\n * `prompt_too_long`. Each retry halves the working set (dropping whole\n * rounds from the head) before re-issuing the call, so shrinkage is\n * geometric and converges even on very long sessions.\n * Default: 3. Set 0 to fail-fast.\n */\n maxPtlRetries?: number\n /**\n * Optional builder override. The default builder dispatches by\n * direction to the named builders in `./prompt.ts`; pass a custom\n * function to swap in a domain-specific summary prompt.\n */\n prompt?: CompactPromptBuilder\n /**\n * The conversation's next request exactly as the agent loop would send it:\n * system, tools, wire messages, thinking and cache settings. When set, the\n * summary call sends it unchanged plus the summary instruction at the end,\n * so the provider reads the conversation from its prompt cache and the\n * summarizer sees the same reasoning the model does. Only the output cap\n * changes (`maxOutputTokens`); `model` and `thinking` come from the request.\n *\n * Falls back to the standalone summary call when the response calls a\n * tool or has no text, or the call fails for any reason but an abort.\n * Ignored when a custom {@link prompt} builder is set.\n */\n prefixRequest?: Omit<StreamOptions, 'signal'>\n /**\n * Lifecycle hook for observability. Fires once per provider call,\n * including retries. The `kind` field tells you whether the call is\n * the initial attempt, the standalone call after a {@link prefixRequest}\n * attempt fell back, a head-truncated retry, or a transient-error\n * retry — useful for surfacing progress in a UI spinner.\n */\n onAttempt?: (event: { attempt: number, kind: 'initial' | 'prefix-fallback' | 'ptl-retry' | 'transient-retry' }) => void\n /**\n * Streaming-progress hook — fires on every streamed delta (text AND\n * thinking) with a cumulative rough output-token estimate for the\n * CURRENT provider attempt (the counter resets on retries). Lets hosts\n * paint live \"Compacting… ~N tokens\" feedback instead of a silent\n * multi-minute spinner. Deltas arrive at provider cadence — throttle\n * on the consumer side. Synchronous and exception-safe by design.\n */\n onProgress?: (progress: CompactStreamProgress) => void\n /**\n * Lifecycle hook fired after preflight succeeds and before the first\n * provider call starts. Useful for UI state (\"Compacting...\") and telemetry.\n * Synchronous by design so observability cannot hang compaction.\n */\n onStart?: (event: CompactStartEvent) => void\n /**\n * Lifecycle hook fired exactly once after {@link onStart}, on both success\n * and failure. Synchronous by design so observability cannot hang compaction.\n */\n onEnd?: (event: CompactEndEvent) => void\n /**\n * Supplies the summary instead of the provider. Called once, after\n * {@link onStart} and before any provider call, with the turns the summary\n * would cover. A `{ summary }` answer is the result (no provider call, zero\n * usage); `undefined` or `null` runs the summary call as usual. The agent\n * loop passes the extension `compaction` interceptors here.\n */\n summarize?: (input: { messages: SessionMessage[], turns: readonly SessionTurn[] }) => Promise<{ summary: string } | undefined | null>\n}\n\n/** Payload for {@link CompactOptions.onProgress}. */\nexport interface CompactStreamProgress {\n /** Cumulative characters streamed so far (text + thinking) this attempt. */\n streamedChars: number\n /** Rough token estimate — `streamedChars / 4`, the classic English/code heuristic. */\n estOutputTokens: number\n}\n\n/** Payload for {@link CompactOptions.onStart}. */\nexport interface CompactStartEvent {\n /** Model id used for the summary call. */\n model: string\n /** Resolved scope of this compaction. */\n scope: CompactScope\n /** Ids of the turns that will be sent to the summarizer. */\n summarizedTurnIds: readonly string[]\n /** Ids of the turns left untouched. */\n preservedTurnIds: readonly string[]\n}\n\n/**\n * Payload for {@link CompactOptions.onEnd}: the result on success, or the thrown error with the elapsed time on failure.\n */\nexport type CompactEndEvent\n = | {\n status: 'success'\n durationMs: number\n result: CompactResult\n }\n | {\n status: 'error'\n durationMs: number\n error: unknown\n }\n\nfunction fireCompactLifecycle(fn: (() => void) | undefined): void {\n if (!fn)\n return\n try {\n fn()\n }\n catch (err) {\n if (process.env.ZIDANE_DEBUG)\n console.error('[zidane] compact lifecycle hook failed:', err)\n }\n}\n\n/**\n * Directive appended as the trailing user message of every summary call\n * (see {@link withTrailingSummaryDirective} for the placement contract).\n * Deliberately self-identifying and TAG-FREE: unlike the system prompt's\n * TRAILER it must not contain the literal `<analysis>`/`<summary>`\n * markers, because summarizers sometimes quote the trailing user message\n * verbatim (e.g. under \"All User Messages\") and the tags would leak into\n * the summary body — caught by the compaction inference test.\n *\n * Compaction-specific: paired with the compaction system prompt, which\n * carries the actual format instructions this directive points at.\n */\nconst SUMMARY_USER_DIRECTIVE\n = '[Conversation ends here. This is an automated compaction request from the harness, NOT a message from the user — do not quote or attribute it as one. Summarize the conversation above now, following the format in your system instructions.]'\n\n/**\n * Guarantee the summary directive is the LAST content the model sees.\n *\n * Appending the directive only when the conversation ends with an assistant\n * turn is not enough. In tool-heavy sessions the tail is almost always\n * user-role already — a `tool_result`-only turn — so the only summarization\n * cue would be the system prompt, hundreds of thousands of tokens away from\n * the tail. On very large prompts models drift toward answering the most\n * recent message instead, producing a short conversational reply that path 4\n * of `stripAnalysisBlock` then accepts verbatim as \"the summary\" (observed in\n * the wild: 1800 turns \"summarized\" into ~200 output tokens).\n *\n * The directive is ALWAYS its own synthetic user message — never merged\n * into the trailing user message as an extra text block. When merged, the\n * summarizer attributes the directive to the USER\n * (\"All User Messages: … 'Provide your <analysis> and <summary> now.'\"),\n * contaminating the summary with harness scaffolding. Consecutive\n * user-role messages are wire-safe: Anthropic folds adjacent same-role\n * messages server-side and the other providers normalize them (same\n * contract `applyCompactSummaryCutoff` relies on). The directive text is\n * additionally self-identifying and avoids the literal envelope tags, so\n * even a model that quotes it verbatim can't leak `<analysis>`/`<summary>`\n * markup into the summary body.\n */\nfunction withTrailingSummaryDirective(messages: SessionMessage[], provider: Provider): SessionMessage[] {\n if (messages.length === 0)\n return messages\n const last = messages[messages.length - 1]\n const lastBlock = last.content[last.content.length - 1]\n if (last.role === 'user' && lastBlock?.type === 'text' && lastBlock.text === SUMMARY_USER_DIRECTIVE)\n return messages // already terminated by the directive — idempotent\n return [...messages, provider.userMessage(SUMMARY_USER_DIRECTIVE)]\n}\n\n/** Outcome of a successful {@link compactConversation} call. */\nexport interface CompactResult {\n /** The summary text, with any `<analysis>` block stripped. */\n summary: string\n /** Token usage from the (last successful) summary call. */\n usage: TurnUsage\n /** Model id used to produce the summary. */\n model: string\n /** Number of `prompt_too_long` retries that fired before success. 0 on first-try success. */\n ptlRetries: number\n /**\n * Turn ids actually covered by the summary — i.e., the ids of turns\n * that made it to the provider. **PTL-retry safe**: when head-truncation\n * shrank the scope, only the surviving (post-truncation) turn ids\n * appear here. Drives `summaryToTurn`'s `replacesTurnIds`; the wire-\n * level cutoff in `applyCompactSummaryCutoff` reads the same field\n * from the persisted marker.\n */\n summarizedTurnIds: readonly string[]\n /**\n * Turn ids dropped by PTL head-truncation before reaching the\n * provider. **Empty on first-try success.** These turns are NOT\n * covered by the summary — callers should either leave them in the\n * conversation history (they stay visible to the model verbatim,\n * since the id-based cutoff only elides ids the marker explicitly\n * claims) or surface a \"compaction lost N turns of context\" warning.\n *\n * The harness keeps these in the wire-level conversation by default;\n * the safety contract is \"the summary describes exactly what's in\n * `summarizedTurnIds` — nothing more, nothing less\".\n */\n droppedDueToPtl: readonly string[]\n /** Turns left untouched (the preserved tail / verbatim slice). */\n preservedTurns: readonly SessionTurn[]\n /** Byte length of turns actually summarized (post-PTL-truncation). */\n beforeBytes: number\n /** UTF-8 byte length of the summary text (rough \"after\" measure). */\n afterBytes: number\n}\n\nexport { CompactInvalidInputError, CompactPromptTooLongError } from './errors'\nexport type { CompactionSlice, CompactScope, SummaryToTurnInput } from './messages'\nexport type { CompactDirection, CompactPromptBuilder, CompactPromptOptions } from './prompt'\n\n// ---------------------------------------------------------------------------\n// Defaults — locked constants so behavior is predictable across host setups.\n// ---------------------------------------------------------------------------\n\n/** Default `keepTurns` for `scope: 'tail'`. Matches `AgentBehavior.compactKeepTurns`. */\nconst DEFAULT_KEEP_TURNS = 4\n/**\n * Default inactivity window for the summary stream. Generous on purpose:\n * it must absorb time-to-first-token on near-window prompts (~1M tokens\n * of ingestion produces no deltas for minutes). Mid-stream, any healthy\n * provider emits deltas far more often than this. A flat cap on the\n * WHOLE call would fail on the very sessions compaction exists for\n * (observed with a 2-minute cap: a 1.5M-token session, provider still\n * ingesting when the watchdog fired).\n */\nconst DEFAULT_COMPACT_STALL_TIMEOUT_MS = 5 * 60 * 1000\n\n/** Rough chars-per-token divisor for the {@link CompactOptions.onProgress} estimate. */\nconst CHARS_PER_TOKEN_ESTIMATE = 4\n\n/** Default max output tokens for the summary call. */\nexport const DEFAULT_MAX_OUTPUT_TOKENS = 20_000\n\n/** Default PTL retry budget. */\nconst DEFAULT_MAX_PTL_RETRIES = 3\n\n/** Maximum transient-error retries before giving up. Independent of PTL. */\nconst TRANSIENT_RETRY_BUDGET = 2\n\n/**\n * Backoff for transient retries. Shares the turn loop's policy\n * ({@link computeRetryDelayMs}: a server-declared `retry-after` wins, otherwise\n * exponential with full jitter) but keeps its own constants — the budget here is\n * 2 rather than 3, and a summarize call is cheap to re-issue, so waiting out the\n * loop's multi-second defaults would cost more than it buys.\n *\n * The jittered curve is FULL jitter — a uniform draw from `[0, capped)` — so it\n * raises the expected gap between re-dials (125ms, then 250ms on average) rather\n * than guaranteeing a floor; a near-zero wait is still a normal draw. Spreading\n * the retries out is the point, and an immediate re-dial of a socket that just\n * dropped is only the least promising single timing, not a disaster.\n */\nconst TRANSIENT_RETRY_BACKOFF: ResolvedRetryConfig = {\n // Never read by `computeRetryDelayMs`; the budget is enforced separately by\n // the `transientRetries < TRANSIENT_RETRY_BUDGET` check below. Present only\n // because `ResolvedRetryConfig` requires the field, and kept equal to the real\n // budget so the two can't drift into contradicting each other.\n maxAttempts: TRANSIENT_RETRY_BUDGET,\n initialDelayMs: 250,\n // Binds only on a server-declared `retry-after`, which `computeRetryDelayMs`\n // clamps to this value — a 529 asking for 30s becomes a 2s wait here, which is\n // the right trade for a summarize call that is cheap to re-issue and should not\n // stall the turn behind it. It is pure headroom for the jittered path: at a\n // budget of 2 that exponential tops out at 250 * 2^1 = 500, and would first\n // exceed 2s only at attempt 5.\n maxDelayMs: 2000,\n}\n\n// ---------------------------------------------------------------------------\n// Runner\n// ---------------------------------------------------------------------------\n\n/**\n * Summarizes older turns of a conversation with one provider call.\n *\n * Retries with a shortened head on `prompt_too_long` and retries transient provider errors a limited number of times. Does not modify `opts.turns`.\n *\n * Throws {@link CompactInvalidInputError} when the inputs cannot be compacted, {@link CompactPromptTooLongError} when the retry budget runs out, and rethrows aborts from `opts.signal` unchanged.\n *\n * @param opts - Compaction options. See {@link CompactOptions}.\n * @returns The summary, usage and the turn ids it covers.\n */\nexport async function compactConversation(opts: CompactOptions): Promise<CompactResult> {\n // ---- Phase 1: pure preflight (no API call) -----------------------------\n // Throws CompactInvalidInputError on degenerate inputs so the caller can\n // bail without spending a network round-trip on a doomed request.\n const slice = sliceForCompaction(\n opts.turns,\n opts.scope ?? 'tail',\n opts.keepTurns ?? DEFAULT_KEEP_TURNS,\n )\n\n const scope = opts.scope ?? 'tail'\n const direction = scopeToDirection(scope)\n const anchorPreview = direction === 'from' || direction === 'up_to'\n ? anchorPreviewFor(anchorTurnFor(slice, opts.scope!))\n : undefined\n\n const builder = opts.prompt ?? buildCompactPrompt\n const systemPrompt = builder({\n direction,\n ...(anchorPreview !== undefined ? { anchorPreview } : {}),\n })\n\n const prefixRequest = opts.prompt ? undefined : opts.prefixRequest\n const model = opts.model ?? opts.provider.meta.defaultModel\n const maxOutputTokens = opts.maxOutputTokens ?? DEFAULT_MAX_OUTPUT_TOKENS\n const maxPtlRetries = Math.max(0, opts.maxPtlRetries ?? DEFAULT_MAX_PTL_RETRIES)\n\n // ---- Phase 2: retry-aware provider call --------------------------------\n // Strips images once up-front (cheap, deterministic) so each retry\n // doesn't re-flatten the same blocks.\n let workingTurns: readonly SessionTurn[] = stripImagesFromTurns(slice.toSummarize)\n let ptlRetries = 0\n let transientRetries = 0\n let attempt = 0\n // Usage of a prefix-cache call that produced output but fell back: real\n // spend, so it is billed into the standalone result.\n let wastedUsage: TurnUsage | undefined\n\n // Fire onStart only once prep that can throw is done, so the onStart/onEnd\n // pair stays balanced: every onStart is followed by exactly one onEnd.\n const startedAt = Date.now()\n fireCompactLifecycle(() => opts.onStart?.({\n model: prefixRequest?.model ?? model,\n scope,\n summarizedTurnIds: slice.toSummarize.map(t => t.id),\n preservedTurnIds: slice.preserved.map(t => t.id),\n }))\n\n const succeed = (summary: string, usage: TurnUsage, resultModel: string): CompactResult => {\n // PTL retries shrink the scope — the marker should ONLY claim\n // ownership of turns that actually fed the summary. Compute the\n // dropped set up-front (cheap; turn counts are O(100s) at worst)\n // so callers can decide whether to warn the user.\n const workingIds = new Set(workingTurns.map(t => t.id))\n const droppedDueToPtl: string[] = []\n if (ptlRetries > 0) {\n for (const t of slice.toSummarize) {\n if (!workingIds.has(t.id))\n droppedDueToPtl.push(t.id)\n }\n }\n\n const result: CompactResult = {\n summary,\n usage: { ...(wastedUsage ? addUsage(wastedUsage, usage) : usage), modelId: usage.modelId ?? resultModel },\n model: resultModel,\n ptlRetries,\n summarizedTurnIds: workingTurns.map(t => t.id),\n droppedDueToPtl,\n preservedTurns: slice.preserved,\n beforeBytes: turnsByteLength(workingTurns),\n afterBytes: utf8ByteLength(summary),\n }\n fireCompactLifecycle(() => opts.onEnd?.({\n status: 'success',\n durationMs: Date.now() - startedAt,\n result,\n }))\n return result\n }\n\n try {\n if (opts.summarize) {\n const supplied = await opts.summarize({ messages: turnsToMessages(slice.toSummarize), turns: slice.toSummarize })\n if (supplied && typeof supplied.summary === 'string')\n return succeed(supplied.summary, { input: 0, output: 0 }, model)\n }\n\n if (prefixRequest) {\n attempt++\n opts.onAttempt?.({ attempt, kind: 'initial' })\n const instruction = buildCompactInstruction({\n direction,\n ...(anchorPreview !== undefined ? { anchorPreview } : {}),\n })\n const prefixed = await runPrefixSummary(opts, prefixRequest, instruction, maxOutputTokens)\n if (prefixed.ok)\n return succeed(prefixed.out.summary, prefixed.out.usage, prefixRequest.model)\n wastedUsage = prefixed.usage\n }\n\n while (true) {\n attempt++\n const kind: 'initial' | 'prefix-fallback' | 'ptl-retry' | 'transient-retry'\n = ptlRetries > 0\n ? 'ptl-retry'\n : transientRetries > 0 ? 'transient-retry' : prefixRequest ? 'prefix-fallback' : 'initial'\n opts.onAttempt?.({ attempt, kind })\n\n try {\n // Build wire messages, then run the same defensive pairing pass\n // the agent loop uses on every live turn (see `applyPairingRepair`\n // in `src/loop-wire.ts`). A session can contain orphan `tool_use` blocks\n // even after `sliceForCompaction`'s round-boundary walk: PTL\n // head-truncation shrinks the working set after the first attempt\n // (which can lop the head off an in-flight round), prior-loop\n // crashes can leave dangling tool_use ids in the persisted history,\n // and `turnsToMessages` itself can drop the only `text` block on\n // an assistant turn carrying signed thinking that has no signature.\n // Without this pass the summarizer fires a request the provider 400s\n // on with `'tool_use' ids were found without 'tool_result' blocks\n // immediately after`, which surfaces to the user as\n // \"compaction failed\" with a raw provider message.\n const paired = ensureToolResultPairing(turnsToMessages(workingTurns))\n const messages = withTrailingSummaryDirective(paired, opts.provider)\n const { summary, usage } = await runOnce({\n ...streamRunOptions(opts),\n request: {\n model,\n system: systemPrompt,\n tools: [],\n messages,\n maxTokens: maxOutputTokens,\n ...(opts.thinking !== undefined ? { thinking: opts.thinking } : {}),\n },\n })\n return succeed(summary, usage, model)\n }\n catch (err) {\n // Abort flows propagate unchanged so callers can pattern-match.\n if (isAbortError(err, opts.signal) || opts.shouldRethrowError?.(err))\n throw err\n\n if (isContextOverflowError(err, opts.provider)) {\n if (ptlRetries >= maxPtlRetries) {\n throw new CompactPromptTooLongError(\n `Compaction failed: prompt_too_long after ${ptlRetries} retries.`,\n ptlRetries,\n )\n }\n const truncated = truncateHeadForPtlRetry(workingTurns)\n if (truncated.length === workingTurns.length) {\n // Nothing more to truncate — refuse to spin.\n throw new CompactPromptTooLongError(\n `Compaction failed: prompt_too_long and conversation cannot be shrunk further.`,\n ptlRetries,\n )\n }\n workingTurns = truncated\n ptlRetries++\n continue\n }\n\n if (isTransientError(err) && transientRetries < TRANSIENT_RETRY_BUDGET) {\n transientRetries++\n // Honour a server-declared `retry-after` the same way the turn loop\n // does: compaction retries 5xx, and Anthropic sends the header on 529\n // and 503 routinely, so discarding it would put three requests inside a\n // second against an endpoint that just asked for longer.\n //\n // Rejects if the caller aborts mid-wait; that lands on the outer catch\n // and propagates unchanged, matching the abort contract at the top of\n // this block. A never-aborting signal stands in when none was given.\n const delayMs = computeRetryDelayMs(transientRetries, TRANSIENT_RETRY_BACKOFF, extractRetryAfterMs(err), retryJitter(opts.clock))\n await backoffSleep(delayMs, opts.signal ?? new AbortController().signal, opts.clock)\n continue\n }\n\n throw err\n }\n }\n }\n catch (err) {\n fireCompactLifecycle(() => opts.onEnd?.({\n status: 'error',\n durationMs: Date.now() - startedAt,\n error: err,\n }))\n throw err\n }\n}\n\n// ---------------------------------------------------------------------------\n// Internals\n// ---------------------------------------------------------------------------\n\ninterface RunOnceOptions {\n provider: Provider\n /** The full request; `runOnce` adds only its own abort signal. */\n request: Omit<StreamOptions, 'signal'>\n signal?: AbortSignal\n providerStreamTimeoutMs?: number\n onProgress?: (progress: CompactStreamProgress) => void\n}\n\n/** The envelope the summary instructions ask the model to wrap its summary in. */\nconst SUMMARY_ENVELOPE = /<summary>[\\s\\S]*?<\\/summary>/\n\n/** A response with no usable text anywhere; carries its usage, which was still billed. */\nclass NoSummaryTextError extends Error {\n constructor(readonly usage: TurnUsage) {\n super('Compaction failed: provider returned no summary text.')\n }\n}\n\ninterface RunOnceResult {\n summary: string\n usage: TurnUsage\n /** Tool calls the response requested. */\n toolCallCount: number\n /** The summary came from the thinking channel because the text was empty. */\n fromThinking: boolean\n /** The response wrapped its summary in the `<summary>` envelope the instructions ask for. */\n hasSummaryEnvelope: boolean\n}\n\n/** The {@link RunOnceOptions} that come straight from the caller's options. */\nfunction streamRunOptions(opts: CompactOptions): Omit<RunOnceOptions, 'request'> {\n return {\n provider: opts.provider,\n ...(opts.signal !== undefined ? { signal: opts.signal } : {}),\n ...(opts.providerStreamTimeoutMs !== undefined ? { providerStreamTimeoutMs: opts.providerStreamTimeoutMs } : {}),\n ...(opts.onProgress !== undefined ? { onProgress: opts.onProgress } : {}),\n }\n}\n\n/**\n * Summary call that reuses the conversation's own request (see\n * {@link CompactOptions.prefixRequest}). Returns `ok: false` when the caller\n * should fall back to the standalone call, with the usage of a response that\n * came back but was unusable; rethrows aborts.\n *\n * Everything but `messages` and `maxTokens` is sent as given: a changed\n * system prompt, tool list or cache setting misses the provider cache, and\n * on Anthropic a changed thinking setting also invalidates the cached\n * messages. `toolChoice` stays unset for the same reason.\n */\nasync function runPrefixSummary(\n opts: CompactOptions,\n request: Omit<StreamOptions, 'signal'>,\n instruction: string,\n maxTokens: number,\n): Promise<{ ok: true, out: RunOnceResult } | { ok: false, usage?: TurnUsage }> {\n const fallBack = (reason: string, usage?: TurnUsage): { ok: false, usage?: TurnUsage } => {\n if (process.env.ZIDANE_DEBUG)\n console.error(`[zidane] compact prefix-cache summary fell back to the standalone call: ${reason}`)\n return usage ? { ok: false, usage } : { ok: false }\n }\n try {\n const out = await runOnce({\n ...streamRunOptions(opts),\n // A set thinking budget must stay under max_tokens: a provider that\n // shrinks it to fit changes the thinking config, which on Anthropic\n // invalidates the cached messages.\n request: {\n ...request,\n messages: withTrailingInstruction(request.messages, instruction, opts.provider),\n maxTokens: request.thinkingBudget !== undefined ? request.thinkingBudget + maxTokens : maxTokens,\n },\n })\n if (out.toolCallCount > 0)\n return fallBack(`response called ${out.toolCallCount} tool(s)`, out.usage)\n // With the conversation's thinking on, the thinking channel is the\n // model's reasoning about the summary, not the summary itself.\n if (out.fromThinking)\n return fallBack('response had no text', out.usage)\n // Without the envelope the model answered the conversation instead of\n // summarizing it (seen with a pending user request): never keep that.\n if (!out.hasSummaryEnvelope)\n return fallBack('response had no <summary> block', out.usage)\n return { ok: true, out }\n }\n catch (err) {\n if (isAbortError(err, opts.signal) || opts.shouldRethrowError?.(err))\n throw err\n const reason = isContextOverflowError(err, opts.provider) ? 'context overflow' : 'provider error'\n return fallBack(`${reason}: ${err instanceof Error ? err.message : String(err)}`, err instanceof NoSummaryTextError ? err.usage : undefined)\n }\n}\n\n/** Token and cost sum of two calls; `b` supplies the non-additive fields. */\nfunction addUsage(a: TurnUsage, b: TurnUsage): TurnUsage {\n const sum = (x: number | undefined, y: number | undefined): number | undefined =>\n x === undefined && y === undefined ? undefined : (x ?? 0) + (y ?? 0)\n const out: TurnUsage = { ...b, input: a.input + b.input, output: a.output + b.output }\n for (const key of ['cacheCreation', 'cacheRead', 'thinking', 'cost'] as const) {\n const v = sum(a[key], b[key])\n if (v !== undefined)\n out[key] = v\n }\n return out\n}\n\n/**\n * Append the summary instruction as the last content of the request: a\n * system-note block on a trailing user message (a tool-result turn, usually),\n * else a new user message. Never mutates `messages`, which the caller still owns.\n */\nfunction withTrailingInstruction(messages: readonly SessionMessage[], instruction: string, provider: Provider): SessionMessage[] {\n // A system note, not plain user text: Anthropic sends it as its own system\n // message after the user's, other providers as <system-reminder> text, so the\n // instruction never reads as part of the user's pending request.\n const block = { type: 'text' as const, text: instruction, systemNote: { kind: 'compaction', label: 'Compaction' } }\n const last = messages[messages.length - 1]\n if (last?.role === 'user')\n return [...messages.slice(0, -1), { ...last, content: [...last.content, block] }]\n return [...messages, { ...provider.userMessage(instruction), content: [block] }]\n}\n\n/**\n * Single provider call. Strips the `<analysis>` block and returns the\n * post-trim summary text along with the usage report.\n *\n * Why not just use `result.text`: some providers stream deltas without\n * emitting a concatenated `text` field at the end (or set it to an\n * empty string when the stream finished via tool-call). Accumulating\n * deltas in `text` and falling back to `result.text` mirrors\n * `generateSessionTitle` and handles every adapter shape.\n */\nasync function runOnce(opts: RunOnceOptions): Promise<RunOnceResult> {\n let streamed = ''\n const abort = new AbortController()\n const unlink = opts.signal ? linkAbortSignal(opts.signal, abort) : () => {}\n const timeoutMs = resolveTimeoutMs(opts.providerStreamTimeoutMs, DEFAULT_COMPACT_STALL_TIMEOUT_MS)\n let abandoned = false\n // Live progress — counts BOTH channels (text + thinking) since\n // reasoning summarizers stream thinking long before any text.\n let progressChars = 0\n const emitProgress = () => {\n if (!opts.onProgress)\n return\n fireCompactLifecycle(() => opts.onProgress?.({\n streamedChars: progressChars,\n estOutputTokens: Math.round(progressChars / CHARS_PER_TOKEN_ESTIMATE),\n }))\n }\n // Liveness reporter wired up after the watchdog exists — deltas landing\n // before assignment just don't extend the deadline, which is harmless.\n let touchRef: () => void = () => {}\n let streamPromise\n try {\n streamPromise = opts.provider.stream(\n { ...opts.request, signal: abort.signal },\n {\n onText: (delta) => {\n touchRef()\n progressChars += delta.length\n emitProgress()\n if (!abandoned)\n streamed += delta\n },\n // Reasoning models stream through the thinking channel long before\n // (or instead of) emitting text — that's liveness AND progress too.\n onThinking: (delta) => {\n touchRef()\n progressChars += delta.length\n emitProgress()\n },\n },\n )\n }\n catch (err) {\n unlink()\n throw err\n }\n streamPromise.catch(() => {})\n\n let result\n try {\n const guarded = withInactivityTimeout(streamPromise, {\n operation: 'compact provider stream',\n timeoutMs,\n onTimeout: () => {\n abandoned = true\n abort.abort('compact-provider-timeout')\n },\n message: `Compaction provider stream stalled: no stream activity for ${timeoutMs}ms.`,\n })\n touchRef = guarded.touch\n result = await guarded.promise\n }\n finally {\n unlink()\n }\n\n const raw = streamed.length > 0 ? streamed : result.text\n let summary = stripAnalysisBlock(raw).trim()\n\n // Reasoning-model fallback. Some models (Qwen-thinking, GLM, DeepSeek\n // reasoning variants, …) write the entire response into their\n // reasoning channel rather than `delta.content`. From this layer the\n // `text` stream is empty, but the assistant message carries\n // `{ type: 'thinking', text }` blocks containing the actual summary\n // (often still wrapped in `<analysis>` / `<summary>` tags from the\n // prompt). Walk those blocks and apply the same extraction waterfall\n // before giving up. Saves the user from \"model misbehaved, retry\" on\n // every compaction when their selected model happens to reason\n // instead of speak.\n let fromThinking = false\n if (summary.length === 0) {\n const thinking = collectThinkingText(result.assistantMessage)\n if (thinking.length > 0) {\n summary = stripAnalysisBlock(thinking).trim()\n fromThinking = true\n }\n }\n\n if (summary.length === 0) {\n // Truly empty — aborted stream, tool-call-only turn, or a model\n // that refused to summarize. `stripAnalysisBlock` already fell back\n // to raw `<analysis>` content when the model wrapped everything in\n // the wrong tag; the thinking fallback above caught the reasoning-\n // channel case. Reaching this branch means there's nothing usable\n // anywhere in the response.\n throw new NoSummaryTextError(result.usage)\n }\n const hasSummaryEnvelope = SUMMARY_ENVELOPE.test(fromThinking ? collectThinkingText(result.assistantMessage) : raw)\n return { summary, usage: result.usage, toolCallCount: result.toolCalls?.length ?? 0, fromThinking, hasSummaryEnvelope }\n}\n\n/**\n * Concatenate every `thinking`-block's text from an assistant message.\n *\n * Reasoning models route their output through provider-specific\n * \"thinking\" channels (Anthropic native thinking, OpenAI o-series\n * reasoning, OpenAI-compat `reasoning_content`, OpenRouter\n * `reasoning_details`). All of them surface as `{ type: 'thinking', text }`\n * blocks on the normalized `SessionMessage.content` by the time the\n * provider's `stream()` returns. Walking the blocks is provider-agnostic\n * — works for every adapter without bespoke per-provider handling.\n *\n * Returns the empty string when no thinking blocks are present, so the\n * caller's \"did we get anything?\" check stays a single `.length === 0`.\n */\nfunction collectThinkingText(message: SessionMessage): string {\n const parts: string[] = []\n for (const block of message.content) {\n if (block.type === 'thinking' && typeof block.text === 'string' && block.text.length > 0)\n parts.push(block.text)\n }\n return parts.join('\\n')\n}\n\n/**\n * Extract the summary text from the provider's response, peeling off\n * any envelope the model wrapped it in.\n *\n * The compact prompt asks for `<analysis>...</analysis><summary>...</summary>`\n * but real models drift from the format. This function tries four\n * extraction paths in order of strictness:\n *\n * 1. **Strict path** — strip `<analysis>...</analysis>` blocks and\n * extract the `<summary>...</summary>` envelope. Matches the\n * prompt-following ideal.\n * 2. **Loose path** — same strip, but accept whatever's outside the\n * `<analysis>` tags as the summary (no `<summary>` envelope\n * required). Handles models that drop the wrapper but keep the\n * analysis.\n * 3. **Analysis-as-summary fallback** — when the entire response is a\n * single `<analysis>` block (model conflated the two concepts),\n * return the analysis content. Better than failing the compaction\n * and forcing the user to retry.\n * 4. **Raw passthrough** — no recognized envelope. Return the text\n * as-is and let `runOnce`'s empty-check decide whether to throw.\n *\n * Matches Claude Code's `formatCompactSummary` for path (1) + (2) and\n * adds (3) as a graceful-degradation layer we ran into in the wild\n * (smaller / non-Anthropic models sometimes produce analysis-only).\n */\nfunction stripAnalysisBlock(text: string): string {\n // Strict + loose: strip `<analysis>...</analysis>` non-greedy + dot-all\n // (`[\\s\\S]` matches newlines without needing the `s` flag).\n const analysisStripped = text.replace(/<analysis>[\\s\\S]*?<\\/analysis>/g, '')\n\n // Path 1: explicit `<summary>...</summary>` envelope.\n const summaryMatch = analysisStripped.match(/<summary>([\\s\\S]*?)<\\/summary>/)\n if (summaryMatch)\n return summaryMatch[1]\n\n // Path 2: anything outside the `<analysis>` block.\n if (analysisStripped.trim().length > 0)\n return analysisStripped\n\n // Path 3: response was nothing but an `<analysis>` block — extract\n // its content and use that as the summary. The model meant to give\n // us a summary; it just wrapped it in the wrong tag.\n const analysisMatch = text.match(/<analysis>([\\s\\S]*?)<\\/analysis>/)\n if (analysisMatch)\n return analysisMatch[1]\n\n // Path 4: no envelope of any shape — return verbatim.\n return text\n}\n\n/**\n * Convert turns into the wire-level `SessionMessage[]` shape. Drops\n * system turns (rare; they'd confuse a summary call), and inlines any\n * pre-existing `compact-summary` markers as plain text so the\n * provider's wire converter doesn't have to know about zidane's\n * internal block type.\n *\n * Inlining (instead of dropping) is intentional: a session already\n * compacted once still contains the prior summary as load-bearing\n * context. Surfacing it as `[Previous compaction summary]\\n…` lets the\n * new summarization integrate it instead of forgetting it.\n */\nfunction turnsToMessages(turns: readonly SessionTurn[]): SessionMessage[] {\n const out: SessionMessage[] = []\n for (const turn of turns) {\n // Only wire turns are summarized — `system` is out-of-band and `command`\n // is display-only, neither reaches the model. Shared, fail-safe guard.\n if (!isWireTurn(turn))\n continue\n const content: SessionContentBlock[] = []\n for (const block of turn.content) {\n if (block.type === 'compact-summary') {\n content.push({\n type: 'text',\n text: `[Previous compaction summary]\\n${block.summary}`,\n })\n continue\n }\n // Strip `thinking` blocks. They're the model's internal reasoning,\n // signed by the producing provider (`signatureProducer: 'anthropic'`),\n // and only valid in a follow-up request when that same request has\n // extended thinking enabled. The compaction call deliberately runs\n // with `thinking: undefined` (summarization rarely benefits from\n // reasoning, and we don't want to pay the budget), so re-sending\n // thinking blocks puts Anthropic in an inconsistent state: it\n // accepts the request without 400-ing but silently returns an\n // empty `text` response. The user-visible symptom is \"Compaction\n // failed: provider returned no summary text\" on sessions where\n // any turn used extended thinking. Thinking is opaque-by-design;\n // dropping it for the summary call doesn't lose conversational\n // content (the model's visible text is in adjacent `text` blocks).\n if (block.type === 'thinking')\n continue\n content.push(block)\n }\n if (content.length === 0)\n continue\n out.push({ role: turn.role, content })\n }\n return out\n}\n\nfunction scopeToDirection(scope: CompactScope): 'full' | 'tail' | 'from' | 'up_to' {\n if (scope === 'full' || scope === 'tail')\n return scope\n return scope.kind\n}\n\nfunction anchorTurnFor(slice: CompactionSlice, scope: CompactScope): SessionTurn {\n // Caller-side invariant: `sliceForCompaction` already verified the anchor\n // exists when scope.kind is set. We re-locate it here so the preview is\n // built from the exact same turn the prompt builder will reference.\n if (typeof scope === 'string')\n throw new Error('anchorTurnFor: scope must be object form')\n if (scope.kind === 'from')\n return slice.toSummarize[0]!\n return slice.toSummarize[slice.toSummarize.length - 1]!\n}\n\n// ---------------------------------------------------------------------------\n// Error classification\n// ---------------------------------------------------------------------------\n\n/**\n * Whether `err` is a context-window-overflow rejection — the condition the\n * PTL head-truncation retry exists to recover from.\n *\n * Trusts the PROVIDER's own `classifyError` first: it's authored per provider\n * and knows exactly where that provider puts the overflow signal (top-level\n * `code`, nested `error.code`, HTTP `status`, message phrasing), so compaction\n * recognizes EXACTLY what the agent loop treats as `context_exceeded` — the two\n * paths can't drift. Falls back to the generic {@link isPromptTooLongError}\n * heuristic for providers that ship no classifier (or classify it as something\n * else).\n *\n * This covers a provider that surfaces overflow as\n * `code: 'context_length_exceeded'` (which the loop recovers from) when the bare\n * heuristic would miss it: the summary call head-truncates and retries instead\n * of failing with the raw provider error.\n */\nfunction isContextOverflowError(err: unknown, provider: Provider): boolean {\n try {\n if (provider.classifyError?.(err)?.kind === 'context_exceeded')\n return true\n }\n catch {\n // A throwing classifier must not mask the overflow — fall through to the heuristic.\n }\n return isPromptTooLongError(err)\n}\n\n/**\n * Provider-agnostic predicate for the \"prompt is too long\" rejection.\n * Inspects error code, type, status, and message substring — every\n * provider names this case differently but the message is recognizable.\n */\nfunction isPromptTooLongError(err: unknown): boolean {\n if (!err || typeof err !== 'object')\n return false\n const e = err as Record<string, unknown>\n // Recognize both the `prompt_too_long` code and the structured\n // `context_length_exceeded` code some providers (OpenAI/Codex, xAI) set —\n // the latter often ships with a generic message that the message-regex below\n // wouldn't catch, so the code check is the only signal.\n if (typeof e.code === 'string' && /prompt[_ ]too[_ ]long|context[_ ]length[_ ]exceeded/i.test(e.code))\n return true\n if (typeof e.status === 'number' && (e.status === 413 || e.status === 400)) {\n const message = typeof e.message === 'string' ? e.message : ''\n if (/prompt[_ ]too[_ ]long|context[_ ]length|maximum[_ ]context|too many tokens/i.test(message))\n return true\n }\n if (typeof e.message === 'string'\n && /prompt[_ ]too[_ ]long|context[_ ]length[_ ]exceeded|context window/i.test(e.message)) {\n return true\n }\n // Anthropic SDK shape: `error.error.type === 'invalid_request_error'`\n // with a `prompt is too long` message.\n const nested = (e.error ?? {}) as Record<string, unknown>\n if (typeof nested.type === 'string' && nested.type === 'invalid_request_error') {\n const message = typeof nested.message === 'string' ? nested.message : ''\n if (/prompt[_ ]too[_ ]long|too long|context window/i.test(message))\n return true\n }\n return false\n}\n\n/**\n * Transient network / 5xx errors worth retrying once or twice.\n *\n * The 5xx test stays local and deliberately plain (`>= 500 && < 600`, where\n * `isRetryableHttpStatus` exempts 501 and adds 429) — see the note in\n * `errors.ts`. Re-summarizing has no side effects, so this leans further toward\n * retrying than the turn loop does.\n *\n * The transport half is NOT local: socket teardowns spell themselves a dozen\n * ways across runtimes, so `isTransientTransportError` keeps the one shared\n * list. A private copy here would drift and miss a runtime's wording. The\n * shared check also looks at `status`, so a 401 whose body happens to say\n * \"terminated\" is not retried as if the socket had dropped.\n */\nfunction isTransientError(err: unknown): boolean {\n if (!err || typeof err !== 'object')\n return false\n const e = err as Record<string, unknown>\n if (typeof e.status === 'number' && e.status >= 500 && e.status < 600)\n return true\n return isTransientTransportError(err)\n}\n\nfunction isAbortError(err: unknown, signal: AbortSignal | undefined): boolean {\n if (signal?.aborted)\n return true\n if (!err || typeof err !== 'object')\n return false\n const e = err as Record<string, unknown>\n if (e.name === 'AbortError')\n return true\n if (typeof e.message === 'string' && /aborted/i.test(e.message))\n return true\n return false\n}\n","/**\n * Post-compact restoration — re-inject load-bearing working state as\n * synthetic tool-call/tool-result pairs after a {@link compactConversation}\n * marker lands in a session.\n *\n * Without this step, the model has a narrative summary but loses direct\n * access to the files it was actively editing and the skills it was\n * following. Restoration re-attaches the top-N recently-read files and\n * active skills so the next turn starts with full working context — no\n * forced re-reads, no degraded continuation.\n *\n * Design — synthetic tool_call/tool_result pairs:\n *\n * Two turns are appended after the compaction marker:\n *\n * [marker] ← from `summaryToTurn(result)`\n * [assistant, tool_calls × N] ← synthetic, one tool_call per item\n * [user, tool_results × N] ← synthetic, matching results\n * [new prompt] ← user's next message\n *\n * The synthetic turns look identical to what the agent would produce if it\n * had actually run `read_file` / `skills_use` — by design, because at the\n * moment of compaction those operations had just happened with that data.\n *\n * Persisted blocks use **canonical** tool names (e.g. `read_file`). The\n * agent loop's `rewriteMessagesToWire` translates them to whatever alias\n * the host configured before they reach the provider, exactly as it does\n * for real calls. Restoration therefore \"just works\" through aliasing —\n * the helper does not need to consult the alias map.\n *\n * Budgets — mirror Claude Code's `services/compact/compact.ts:122-130`:\n *\n * - 50_000 tokens total file budget, 5_000 per file, max 5 files\n * - 25_000 tokens total skill budget, 5_000 per skill (no count cap)\n *\n * Tokens are estimated at 4 chars/token — same heuristic Claude Code uses\n * for budget arithmetic. Hosts can override every limit.\n *\n * Failure modes:\n *\n * - File read fails (deleted, permissions) → skip silently. Other items\n * still proceed.\n * - No `execution` / `handle` passed → file restoration is a no-op;\n * skill restoration still works (skills carry their content inline).\n * - Empty `recentFiles` AND empty `activeSkills` → returns `{ turns: [] }`\n * so the caller's `appendTurns([summary, ...attachments])` is a no-op\n * on the attachments.\n */\n\nimport type { ExecutionContext, ExecutionHandle } from '../contexts'\nimport type { Session } from '../session'\nimport type { ActiveSkill } from '../skills/activation'\nimport type { AgentClock, SessionContentBlock, SessionTurn } from '../types'\nimport { isAbsolute, relative } from 'node:path'\nimport { getReadState } from '../tools/read-state'\nimport { DEFAULT_AGENT_CLOCK } from '../types'\nimport { BYTES_PER_TOKEN, estimateTokens, utf8ByteLength } from './utils'\n\n// ---------------------------------------------------------------------------\n// Defaults — match Claude Code's published constants for parity.\n// ---------------------------------------------------------------------------\n\nconst DEFAULT_FILE_TOKEN_BUDGET = 50_000\nconst DEFAULT_FILE_TOKEN_PER_FILE_CAP = 5_000\nconst DEFAULT_MAX_FILES_TO_RESTORE = 5\n\nconst DEFAULT_SKILL_TOKEN_BUDGET = 25_000\nconst DEFAULT_SKILL_TOKEN_PER_SKILL_CAP = 5_000\n\n/** Default canonical tool names — `rewriteMessagesToWire` handles aliasing. */\nconst DEFAULT_READ_FILE_TOOL_NAME = 'read_file'\nconst DEFAULT_SKILLS_USE_TOOL_NAME = 'skills_use'\n\n// ---------------------------------------------------------------------------\n// Public types\n// ---------------------------------------------------------------------------\n\n/** One file selected for restoration, with its last-read timestamp for ranking. */\nexport interface RecentFile {\n /** Path relative to the execution context's `handle.cwd`. */\n path: string\n /** Wall-clock when the file was last read, in ms. Drives recency ranking. */\n mtimeMs: number\n}\n\n/** Options for {@link buildPostCompactAttachments}. */\nexport interface PostCompactRestoreOptions {\n // ---- What to restore ---------------------------------------------------\n\n /**\n * Files to consider for restoration, ranked by recency. Typically derived\n * via {@link selectFilesFromReadState} from `getReadState(session)`.\n * The helper takes the top {@link PostCompactRestoreOptions.maxFilesToRestore}\n * by `mtimeMs` descending, fetches their current content, and synthesizes\n * `read_file` tool_call/tool_result pairs.\n */\n recentFiles?: readonly RecentFile[]\n\n /**\n * Active skills to re-inject. Typically `agent.activeSkills`. Each entry\n * yields a synthetic `skills_use` tool_call/tool_result pair carrying the\n * skill's instructions (possibly truncated to the per-skill budget).\n */\n activeSkills?: readonly ActiveSkill[]\n\n // ---- I/O ---------------------------------------------------------------\n\n /**\n * Execution context used to fetch file content. **Required for file\n * restoration.** Skills come pre-loaded (instructions live on the\n * `SkillConfig`), so they don't need the context.\n */\n execution?: ExecutionContext\n /** Handle of the execution context. File restoration needs both `execution` and `handle`. */\n handle?: ExecutionHandle\n\n /**\n * Optional abort signal. Checked before each file read so a caller that\n * bounds restoration (e.g. a host capping its compaction barrier) can stop\n * the FS round-trips promptly instead of reading every candidate. File\n * restoration already isolates per-file failures, so an abort mid-loop just\n * returns whatever was gathered so far.\n */\n signal?: AbortSignal\n /**\n * Errors matching this predicate are rethrown instead of being skipped as\n * unreadable files. The agent loop passes its durable runtime's\n * `isControlError`, so control errors (suspension, cancellation) escape.\n */\n shouldRethrowError?: (error: unknown) => boolean\n\n // ---- Tool naming -------------------------------------------------------\n\n /**\n * Canonical name of the file-read tool. Defaults to `read_file`. Aliases\n * (e.g. `Read`) are NOT specified here — the agent loop's\n * `rewriteMessagesToWire` handles wire conversion automatically.\n *\n * Override only when a host registered file-read under a different\n * canonical name (not just an alias).\n */\n readFileToolName?: string\n /**\n * Canonical name of the skill-activation tool. Defaults to `skills_use`.\n * Same aliasing semantics as `readFileToolName`.\n */\n skillsUseToolName?: string\n\n // ---- Budgets -----------------------------------------------------------\n\n /** Total token budget for file restoration. Default: 50_000. */\n fileTokenBudget?: number\n /** Per-file token cap. Default: 5_000. */\n fileTokenPerFileCap?: number\n /** Maximum file count. Default: 5. */\n maxFilesToRestore?: number\n\n /** Total token budget for skill restoration. Default: 25_000. */\n skillTokenBudget?: number\n /** Per-skill token cap. Default: 5_000. */\n skillTokenPerSkillCap?: number\n\n // ---- Filtering ---------------------------------------------------------\n\n /**\n * Paths to skip — typically the file paths already covered by the\n * compaction result's `preservedTurns`. Avoids double-injection when the\n * recent reads sit in the preserved tail.\n */\n excludePaths?: readonly string[]\n\n // ---- Synthesis ---------------------------------------------------------\n\n /**\n * Optional `runId` to tag the synthetic turns with — useful for hosts\n * that want the restoration turns to roll up under the same run as the\n * compaction marker. Defaults to undefined (orphan turns).\n */\n runId?: string\n\n /**\n * Time + UUID source for the synthesized turns' `id` / `createdAt`.\n * Defaults to {@link DEFAULT_AGENT_CLOCK} (`Date.now()` /\n * `crypto.randomUUID()`). A replaying run passes the runtime's clock so\n * the restoration turns are byte-identical on replay. The synthetic\n * `tool_call`/`tool_result` `callId`s are already deterministic\n * (`compact-restore-file-${i}`), so only the turn envelope needs the clock.\n */\n clock?: AgentClock\n /**\n * Record the file reads as one step, so a replay restores the contents the\n * live attempt read (and sent to the model), not the files as they are now.\n * Absent: the reads just run.\n */\n journal?: <T>(name: string, fn: () => Promise<T>) => Promise<T>\n}\n\n/**\n * Envelope returned by {@link buildPostCompactAttachments}. The caller\n * spreads `turns` into `session.appendTurns([summaryTurn, ...turns])`.\n * Count fields drive UI banners (\"restored 5 files + 2 skills\").\n */\nexport interface PostCompactAttachments {\n /**\n * Two synthetic turns when at least one item was restored, otherwise\n * an empty array. The pair is `[assistant_with_tool_calls,\n * user_with_tool_results]` — adjacent and well-formed for every\n * provider's `tool_use ↔ tool_result` invariant.\n */\n turns: readonly SessionTurn[]\n /** Count of files actually restored (post-budget). */\n restoredFiles: number\n /** Count of skills actually restored (post-budget). */\n restoredSkills: number\n /** Rough total token cost of the restoration payload (sum of all content). */\n estimatedTokens: number\n}\n\n// ---------------------------------------------------------------------------\n// Pure helpers — exported for tests + caller convenience\n// ---------------------------------------------------------------------------\n\n/**\n * Convert a raw read-state map into a deduped, path-ranked list ready for\n * restoration. Multiple entries for the same path (different\n * `(offset, limit, maxBytes)` slices) collapse to one — keeping the most\n * recent `mtimeMs`.\n *\n * Keys are the absolute paths `readStateKey` writes, and paths come back\n * absolute, so every execution context reads them the same way. Entries\n * outside `cwd` are dropped: they belong to another workspace.\n *\n * Pure. Most callers want {@link selectFilesFromSession}, which wraps\n * `getReadState(session)` + this function in one call so the host\n * doesn't have to reach into the tools layer.\n * @param readState - Read-state map keyed by absolute path, with a `mtimeMs` per entry.\n * @param cwd - Working directory whose files to keep.\n */\nexport function selectFilesFromReadState(\n readState: ReadonlyMap<string, { mtimeMs: number }>,\n cwd: string,\n): RecentFile[] {\n const byPath = new Map<string, number>()\n for (const [path, entry] of readState) {\n const inside = relative(cwd, path)\n if (inside.length === 0 || inside.startsWith('..') || isAbsolute(inside))\n continue\n const prior = byPath.get(path) ?? -Infinity\n if (entry.mtimeMs > prior)\n byPath.set(path, entry.mtimeMs)\n }\n return Array.from(byPath, ([path, mtimeMs]) => ({ path, mtimeMs }))\n .sort((a, b) => b.mtimeMs - a.mtimeMs)\n}\n\n/**\n * Session-aware convenience: extract recently-read files directly from\n * a {@link Session} via its per-session read-state map.\n *\n * Hosts (TUI / SDK consumers) typically have a `Session` and a `cwd`\n * (the active agent's `handle.cwd`) on hand — this wrapper saves them\n * from reaching into `src/tools/read-state.ts` directly. Returns an\n * empty list when no read state has been recorded yet (fresh session,\n * or `behavior.dedupReads === false`).\n *\n * Equivalent to:\n *\n * ```ts\n * const state = getReadState(session)\n * return state ? selectFilesFromReadState(state, cwd) : []\n * ```\n * @param session - Session whose read state to use.\n * @param cwd - Working directory whose entries to keep.\n */\nexport function selectFilesFromSession(\n session: Session,\n cwd: string,\n): RecentFile[] {\n const state = getReadState(session)\n return state ? selectFilesFromReadState(state, cwd) : []\n}\n\n/**\n * Pick the top `maxFiles` from `files` (descending by `mtimeMs`),\n * dropping any whose path appears in `excludePaths`.\n *\n * Stable for equal mtimes — files with the same timestamp retain their\n * input order. Pure.\n * @param files - Candidate files.\n * @param opts - Selection options. `maxFiles` caps the result; `excludePaths` lists paths to drop.\n */\nexport function selectRecentFiles(\n files: readonly RecentFile[],\n opts: { maxFiles: number, excludePaths?: readonly string[] },\n): RecentFile[] {\n const excluded = new Set(opts.excludePaths ?? [])\n const filtered = files.filter(f => !excluded.has(f.path))\n // Defensive sort — caller may pass an already-sorted list, but doing it\n // here keeps the function total regardless of input order.\n const sorted = filtered.slice().sort((a, b) => b.mtimeMs - a.mtimeMs)\n return sorted.slice(0, Math.max(0, opts.maxFiles))\n}\n\n// ---------------------------------------------------------------------------\n// Internal — content formatting + truncation\n// ---------------------------------------------------------------------------\n\ninterface FormattedFile {\n /** Tool-result content (line-numbered, with optional truncation footer). */\n body: string\n /** Whether the content was truncated to fit the per-file budget. */\n truncated: boolean\n /** Estimated token cost of `body` (post-truncation). */\n estimatedTokens: number\n}\n\ninterface FormattedSkill {\n body: string\n truncated: boolean\n estimatedTokens: number\n}\n\n/**\n * Format a file's contents to match `read_file`'s output shape — 1-indexed\n * line numbers separated by tabs, identical to what the model has seen\n * from real `read_file` calls. Applies the per-file token cap by truncating\n * at the nearest line boundary; appends a footer pointing at the next\n * offset so the model can re-read the rest if needed.\n */\nfunction formatFileForRestoration(\n content: string,\n perFileTokenCap: number,\n): FormattedFile {\n const totalBytes = utf8ByteLength(content)\n const allLines = content.split('\\n')\n const totalLines = allLines.length\n\n // Build the line-numbered body first; tokens are counted on the\n // numbered form because that's what reaches the provider.\n const numbered: string[] = []\n let runningChars = 0\n const charCap = Math.max(1, perFileTokenCap) * BYTES_PER_TOKEN\n let truncatedAt = -1\n let midLineCut = false\n\n for (let i = 0; i < allLines.length; i++) {\n const numberedLine = `${i + 1}\\t${allLines[i]}`\n const lineCharCost = numberedLine.length + (i < allLines.length - 1 ? 1 : 0) // +1 for the joining '\\n' on every line but the last\n if (runningChars + lineCharCost > charCap) {\n if (numbered.length === 0) {\n // The first line on its own already overflows (typical for\n // minified JS, CSV-on-one-line, etc.). Cut it at the char\n // boundary so we return SOMETHING useful — the head of the\n // file — instead of either failing or admitting a huge first\n // line that blows the budget. Mid-line cuts mean we can't\n // suggest a precise re-read offset; the footer says so.\n const cutTo = Math.max(1, charCap - `${i + 1}\\t`.length)\n numbered.push(`${i + 1}\\t${allLines[i].slice(0, cutTo)}`)\n midLineCut = true\n }\n truncatedAt = i\n break\n }\n numbered.push(numberedLine)\n runningChars += lineCharCost\n }\n\n const body = numbered.join('\\n')\n if (truncatedAt < 0)\n return { body, truncated: false, estimatedTokens: estimateTokens(body) }\n\n const lineLabel = midLineCut\n ? `line ${truncatedAt + 1} (mid-line)`\n : `line ${truncatedAt}`\n const offsetHint = midLineCut\n ? `mid-line cut prevents a precise offset — re-read with offset=${truncatedAt + 1} and a larger maxBytes`\n : `re-read with offset=${truncatedAt + 1} to continue`\n const footer = `\\n\\n…truncated at ${lineLabel} (post-compact restoration cap: ${perFileTokenCap} tokens). File has ${totalLines} lines, ${totalBytes} bytes total — ${offsetHint}.`\n const truncated = body + footer\n return { body: truncated, truncated: true, estimatedTokens: estimateTokens(truncated) }\n}\n\n/**\n * Format a skill's instructions for restoration. Skills are plain markdown\n * — no line numbering, no wrapping XML envelope (the model already\n * understands the format from real `skills_use` calls). Truncation cuts\n * at a line boundary when possible; appends a marker so the model knows\n * the body is incomplete.\n */\nfunction formatSkillForRestoration(\n instructions: string,\n perSkillTokenCap: number,\n): FormattedSkill {\n const charCap = Math.max(1, perSkillTokenCap) * BYTES_PER_TOKEN\n if (instructions.length <= charCap) {\n return { body: instructions, truncated: false, estimatedTokens: estimateTokens(instructions) }\n }\n // Truncate at the nearest line boundary at or before charCap so the\n // body stays markdown-parseable.\n const head = instructions.slice(0, charCap)\n const lastNewline = head.lastIndexOf('\\n')\n const cutoff = lastNewline > 0 ? lastNewline : charCap\n const truncatedBody\n = `${instructions.slice(0, cutoff).trimEnd()}\\n\\n…[truncated post-compact at ${perSkillTokenCap} tokens; full skill body lives at the skill's location]`\n return {\n body: truncatedBody,\n truncated: true,\n estimatedTokens: estimateTokens(truncatedBody),\n }\n}\n\n// ---------------------------------------------------------------------------\n// Public runner\n// ---------------------------------------------------------------------------\n\n/**\n * Build the synthetic turns to append after a `compact-summary` marker.\n *\n * Returns a `PostCompactAttachments` envelope; the caller is responsible\n * for `session.appendTurns([summaryTurn, ...result.turns])`. The two\n * synthetic turns are always emitted together (or both omitted when\n * nothing was restored) so the `tool_use ↔ tool_result` adjacency\n * invariant holds regardless of caller code path.\n *\n * Failure isolation: a single file's read failure never blocks the rest\n * of restoration — that file is skipped silently and processing\n * continues. The returned `restoredFiles` count reflects what actually\n * landed in the synthesized turns.\n * @param opts - Files, skills, execution context and budgets. See {@link PostCompactRestoreOptions}.\n */\nexport async function buildPostCompactAttachments(\n opts: PostCompactRestoreOptions,\n): Promise<PostCompactAttachments> {\n const fileTokenBudget = opts.fileTokenBudget ?? DEFAULT_FILE_TOKEN_BUDGET\n const fileTokenPerFileCap = opts.fileTokenPerFileCap ?? DEFAULT_FILE_TOKEN_PER_FILE_CAP\n const maxFilesToRestore = opts.maxFilesToRestore ?? DEFAULT_MAX_FILES_TO_RESTORE\n const skillTokenBudget = opts.skillTokenBudget ?? DEFAULT_SKILL_TOKEN_BUDGET\n const skillTokenPerSkillCap = opts.skillTokenPerSkillCap ?? DEFAULT_SKILL_TOKEN_PER_SKILL_CAP\n const readFileToolName = opts.readFileToolName ?? DEFAULT_READ_FILE_TOOL_NAME\n const skillsUseToolName = opts.skillsUseToolName ?? DEFAULT_SKILLS_USE_TOOL_NAME\n\n // ---- Phase 1: pick candidates --------------------------------------\n //\n // Tool-availability is governed at the input layer: callers control\n // which categories are restored by what they pass. To skip files,\n // pass empty `recentFiles` (or none). To skip skills, pass empty\n // `activeSkills` (or none). The runner trusts the caller to know\n // what tools the next agent run will have access to — auto-injected\n // tools (`skills_use`, MCP, interaction tools) aren't introspectable\n // from a profile config and constructing a tool-allowlist here would\n // be incomplete by design.\n const candidateFiles = opts.recentFiles && opts.recentFiles.length > 0\n ? selectRecentFiles(opts.recentFiles, {\n maxFiles: maxFilesToRestore,\n ...(opts.excludePaths ? { excludePaths: opts.excludePaths } : {}),\n })\n : []\n const candidateSkills = opts.activeSkills ?? []\n\n // ---- Phase 2: fetch + format files (with per-file + group budget) --\n let fileCalls: Array<{ callId: string, path: string, body: string, estimatedTokens: number }> = []\n let fileBudgetUsed = 0\n const { execution, handle } = opts\n if (candidateFiles.length > 0 && execution && handle) {\n const readFiles = async (): Promise<{ fileCalls: typeof fileCalls, fileBudgetUsed: number }> => {\n const calls: typeof fileCalls = []\n let used = 0\n for (let i = 0; i < candidateFiles.length; i++) {\n // Stop early if the caller aborted (e.g. a bounded compaction barrier) —\n // `readFile` itself takes no signal, so this is the cancellation seam.\n if (opts.signal?.aborted)\n break\n const file = candidateFiles[i]\n let content: string\n try {\n content = await execution.readFile(handle, file.path)\n }\n catch (err) {\n if (opts.shouldRethrowError?.(err))\n throw err\n // File deleted / unreadable since the last read — skip silently.\n continue\n }\n const formatted = formatFileForRestoration(content, fileTokenPerFileCap)\n if (used + formatted.estimatedTokens > fileTokenBudget) {\n // Adding this file would blow the group budget. Stop here — the\n // remaining files are older anyway (candidates are pre-sorted by\n // recency descending).\n break\n }\n used += formatted.estimatedTokens\n calls.push({\n callId: `compact-restore-file-${i}`,\n path: file.path,\n body: formatted.body,\n estimatedTokens: formatted.estimatedTokens,\n })\n }\n return { fileCalls: calls, fileBudgetUsed: used }\n }\n const read = opts.journal ? await opts.journal('compact-restore-files', readFiles) : await readFiles()\n fileCalls = read.fileCalls\n fileBudgetUsed = read.fileBudgetUsed\n }\n\n // ---- Phase 3: format skills (no I/O — instructions are inline) -----\n const skillCalls: Array<{ callId: string, name: string, body: string, estimatedTokens: number }> = []\n let skillBudgetUsed = 0\n for (let i = 0; i < candidateSkills.length; i++) {\n const active = candidateSkills[i]\n const instructions = active.skill.instructions ?? ''\n if (instructions.trim().length === 0)\n continue\n const formatted = formatSkillForRestoration(instructions, skillTokenPerSkillCap)\n if (skillBudgetUsed + formatted.estimatedTokens > skillTokenBudget)\n break\n skillBudgetUsed += formatted.estimatedTokens\n skillCalls.push({\n callId: `compact-restore-skill-${i}`,\n name: active.skill.name,\n body: formatted.body,\n estimatedTokens: formatted.estimatedTokens,\n })\n }\n\n // ---- Phase 4: synthesize turns -------------------------------------\n if (fileCalls.length === 0 && skillCalls.length === 0) {\n return { turns: [], restoredFiles: 0, restoredSkills: 0, estimatedTokens: 0 }\n }\n\n const assistantBlocks: SessionContentBlock[] = []\n const userBlocks: SessionContentBlock[] = []\n\n for (const fc of fileCalls) {\n assistantBlocks.push({\n type: 'tool_call',\n id: fc.callId,\n name: readFileToolName,\n input: { path: fc.path },\n })\n userBlocks.push({\n type: 'tool_result',\n callId: fc.callId,\n output: fc.body,\n })\n }\n for (const sc of skillCalls) {\n assistantBlocks.push({\n type: 'tool_call',\n id: sc.callId,\n name: skillsUseToolName,\n input: { name: sc.name },\n })\n userBlocks.push({\n type: 'tool_result',\n callId: sc.callId,\n output: sc.body,\n })\n }\n\n const clock = opts.clock ?? DEFAULT_AGENT_CLOCK\n const now = await clock.now()\n const tag = opts.runId ? { runId: opts.runId } : {}\n const turns: SessionTurn[] = [\n {\n id: clock.randomUUID(),\n role: 'assistant',\n content: assistantBlocks,\n createdAt: now,\n ...tag,\n },\n {\n id: clock.randomUUID(),\n role: 'user',\n content: userBlocks,\n // +1 ms so the user turn sorts after the assistant turn under\n // tie-breaking sorts that walk by `createdAt`.\n createdAt: now + 1,\n ...tag,\n },\n ]\n\n return {\n turns,\n restoredFiles: fileCalls.length,\n restoredSkills: skillCalls.length,\n estimatedTokens: fileBudgetUsed + skillBudgetUsed,\n }\n}\n","/**\n * Per-dimension cache-break detection.\n *\n * The agent surfaces `cacheRead` / `cacheCreation` in {@link TurnUsage}, but\n * doesn't answer the load-bearing diagnostic question: *which* dimension\n * busted the cache? When `cacheCreation > 0` on turn N+1 with no obvious\n * reason, you want to know whether the system prompt, the tool list, the\n * thinking config, or the model id changed — without re-reading the loop\n * source.\n *\n * This module hashes each cache-affecting dimension at `turn:before`, then\n * on `turn:after` checks whether the latest turn read its share of the\n * cached prefix. If not, it diffs the previous turn's dimension hashes\n * against the current ones and logs the responsible dimension(s).\n *\n * Wire contract:\n *\n * - Install via {@link installCacheBreakLogger} on the agent's hook bus.\n * Returns an uninstall fn. Not idempotent: calling install twice on the\n * same bus leaves two listeners, so callers manage lifecycle.\n * - Output sink defaults to `console.error`; pass `log` to redirect into a\n * {@link Logger}, span attribute writer, or test buffer.\n * - Heuristic only: a missing cache read on turn 1 is expected (nothing\n * cached yet); the logger only reports once it has a baseline — an\n * earlier turn on this bus, or the session's last request (see\n * {@link CacheBreakLoggerOptions.sessionBaseline}).\n * - Pure helper {@link diffCacheDimensions} is exported for tests so the\n * diff logic can be exercised without standing up the loop.\n *\n * The dimensions tracked are the inputs the provider treats as part of the\n * cache key — `system`, `tools`, `model`, thinking config, and the message\n * PREFIX. Tools are hashed after `provider.formatTools`, so MCP catalogues\n * showing up mid-run also register as a break. Messages are hashed\n * per-message and compared positionally (`messageHashes` / the\n * `messagePrefix` dimension): appending — what every healthy turn does — is\n * deliberately silent, while an in-place rewrite of an earlier message\n * (compaction, stale-read elision, media age-out, host-side history trims)\n * reports the exact index that diverged.\n *\n * When `system` changed, the diff also names WHICH part: the sections the SDK\n * appends (skills catalog, searchable tools catalog, MCP instructions), the\n * host's rules block, and the static / dynamic halves of a host prompt split\n * with `SYSTEM_PROMPT_BOUNDARY` (see {@link CacheSystemSection}).\n *\n * The last request of an agent bound to a session is kept per session id at\n * process level, so a freshly built agent on the same session compares its\n * first request against the previous agent's last one: a break caused by\n * rebuilding the agent is reported and attributed like any other.\n */\n\nimport type { Hookable } from 'hookable'\nimport type { AgentHooks } from './agent'\nimport type { AgentCacheChange, AgentCacheImpact } from './agent-types'\nimport type { StreamOptions } from './providers'\nimport type { ThinkingLevel } from './thinking-levels'\nimport type { CacheTtl } from './types'\nimport { splitSystemPrompt, SYSTEM_PROMPT_BOUNDARY } from './system-prompt'\n\n// ---------------------------------------------------------------------------\n// Public types\n// ---------------------------------------------------------------------------\n\n/**\n * Snapshot of per-request dimensions that contribute to the provider-side\n * prompt cache key. Hashed at `turn:before` and stashed for diffing on the\n * next request.\n *\n * Hashes are FNV-1a 32-bit (cheap, no allocations on the hot path,\n * collision rate good enough for diff detection — we're not signing\n * anything). For verbose output the helper also captures byte lengths so\n * `system: 1024 → 1031` reads like a real diff line.\n */\nexport interface CacheDimensionSnapshot {\n /** Hash of `options.system` (with boundary marker preserved). */\n systemHash: number\n /** Byte length of `options.system`. */\n systemBytes: number\n /** Hash of the JSON-serialized `options.tools` array. */\n toolsHash: number\n /** Number of tools in the array. */\n toolsCount: number\n /** Model id. */\n model: string\n /** Thinking level — `'off'` when absent. */\n thinking: string\n /** Exact thinking budget — `0` when absent. */\n thinkingBudget: number\n /** Whole-task thinking budget (Anthropic adaptive-only) — `0` when absent. */\n taskBudget: number\n /** Whether the level-derived effort hint is emitted — `true` when absent. */\n effortHint: boolean\n /**\n * Per-message content hashes, in order. Compared POSITIONALLY against the\n * previous turn so that appending messages — what every healthy turn does —\n * is not mistaken for a rewrite. A single cumulative hash cannot make that\n * distinction: it changes on plain growth too, and would name this dimension\n * on literally every break, drowning the real culprit.\n *\n * Tracked because the expensive real-world breaks live here, not in the\n * request scaffold: compaction, stale-read elision, media age-out and history\n * trimming all rewrite the transcript mid-conversation, and none of them touch\n * `system`, `tools`, or the model id. A run can lose its entire transcript to\n * a cache miss with every other dimension reading perfectly stable.\n */\n messageHashes: readonly number[]\n /** Number of messages in the request. */\n messageCount: number\n /**\n * Hash of each part of `system` the snapshot could find, keyed by\n * {@link CacheSystemSection}. A section missing from the request has no key.\n * The host's parts (`hostStatic`, `hostDynamic`) are hashed with the other\n * sections removed, so a change in a catalog is not also blamed on the host.\n * Absent on snapshots built before this field existed.\n */\n systemSections?: Readonly<Partial<Record<CacheSystemSection, number>>>\n}\n\n/**\n * A part of the system prompt that a `system` change can be traced to.\n *\n * - `skillsCatalog`: the skills catalog the SDK appends.\n * - `toolsCatalog`: the searchable tools catalog the SDK appends.\n * - `mcpInstructions`: the MCP server instructions the SDK appends.\n * - `rules`: the rules block the run passed as `contextSections.rulesBlock`.\n * - `hostStatic`: the rest of the prompt above `SYSTEM_PROMPT_BOUNDARY`, or\n * the whole rest of the prompt when it has no boundary.\n * - `hostDynamic`: the rest of the prompt below `SYSTEM_PROMPT_BOUNDARY`.\n */\nexport type CacheSystemSection\n = | 'skillsCatalog'\n | 'toolsCatalog'\n | 'mcpInstructions'\n | 'rules'\n | 'hostStatic'\n | 'hostDynamic'\n\n/**\n * Texts of the system prompt sections a snapshot can name: the sections the\n * SDK appended and the host's rules block. Each must be a substring of the\n * request's `system` to count; anything else is ignored.\n */\nexport interface CachePromptSections {\n /** The skills catalog the SDK appended. */\n skillsCatalog?: string\n /** The searchable tools catalog the SDK appended. */\n toolsCatalog?: string\n /** The MCP server instructions the SDK appended. */\n mcpInstructions?: string\n /** The rules block the run passed as `contextSections.rulesBlock`. */\n rules?: string\n}\n\n/** Result of {@link diffCacheDimensions}. */\nexport interface CacheDimensionDiff {\n /** Dimension names whose hashes differ between the two snapshots. */\n changed: readonly CacheDimensionName[]\n /** Per-dimension details — only filled for changed dimensions. */\n details: Readonly<Partial<Record<CacheDimensionName, string>>>\n /**\n * Message index where the prefixes diverged, when `changed` includes\n * `'messagePrefix'`. Chunk-aligned values (multiples of the compaction\n * chunk) point at tail compaction / media age-out; non-aligned values point\n * at stale-read stubbing or host-side history surgery.\n */\n messagePrefixDivergedAt?: number\n /**\n * The parts of `system` that changed, when `changed` includes `'system'`\n * and both snapshots carry {@link CacheDimensionSnapshot.systemSections}.\n * Empty when the change could not be traced to one part.\n */\n systemSections?: readonly CacheSystemSection[]\n}\n\n/** Cache-affecting dimension names. */\nexport type CacheDimensionName\n = | 'system'\n | 'tools'\n | 'model'\n | 'thinking'\n | 'thinkingBudget'\n | 'taskBudget'\n | 'effortHint'\n /**\n * Per-message hashes compared positionally over the shared range — see\n * {@link CacheDimensionSnapshot.messageHashes}. Appends are silent (every\n * healthy turn grows the list); any in-place rewrite of a shared position,\n * including the previous turn's last message, is reported with its index.\n */\n | 'messagePrefix'\n\n/**\n * Structured payload of the `'cache:break'` agent hook, emitted by\n * {@link installCacheBreakLogger} whenever a turn reads back materially less\n * prefix than the previous turn established (see `expectedReadAtLeast` /\n * `expectedReadRatio` on {@link CacheBreakLoggerOptions}).\n *\n * `changed` names the request dimensions that differ from the previous turn —\n * the culprit when the host rewrote something. An EMPTY `changed` is itself a\n * signal: the request was byte-stable AT THIS WIRE and the provider still\n * failed to serve the prefix. Three suspects, in the order to check them:\n *\n * 1. TTL expiry — a long pause since the previous turn (compare wall-clock\n * gaps; the default window is ~5 minutes).\n * 2. Provider-side eviction — no pause, no pattern; typically isolated.\n * 3. Downstream transformation churn — on architectures where a gateway CASTS\n * this request into another provider's format (Anthropic → OpenAI\n * Responses, Converse, …), these dimensions only cover the PRE-cast bytes.\n * A transform that isn't prefix-monotonic (unstable id mapping, per-request\n * injections, config-derived fields like reasoning effort) breaks the\n * vendor's cache while reading as byte-stable here. Recurring\n * empty-`changed` breaks on a cast route point at the transform, not at\n * this agent — instrument the gateway's OUTPUT with the same positional\n * hashing (`hashMessages`) to name the churn.\n */\nexport interface CacheBreakInfo {\n /**\n * 1-based turn index as counted by the detector — monotonic across the\n * INSTALLER'S lifetime, i.e. every `agent.run()` on this hook bus. It does\n * NOT reset per run the way `turn:after`'s `ctx.turn` does, so don't\n * correlate the two on any prompt after the first; use `turnId` for that.\n */\n turn: number\n /** Id of the turn that broke the cache. */\n turnId: string\n /** Model id of the request that broke — pair with a provider key to price the break. */\n model: string\n /** Tokens read from the cache on the turn that broke. */\n cacheRead: number\n /** Tokens written to the cache on the turn that broke. */\n cacheCreation: number\n /** The floor that tripped: `max(expectedReadAtLeast, ratio-derived floor)`. */\n expectedAtLeast: number\n /**\n * Approximate tokens re-billed by this break: the prefix the previous turn\n * had cached minus what this turn actually read back. That portion was\n * re-written at the cache-write rate (~1.25x input) instead of read at the\n * cache-read rate (~0.1x), so the extra spend is roughly\n * `1.15 x rebilledTokens` input-token equivalents. Approximate because the\n * healthy-turn counterfactual (the genuine new-transcript delta) is folded\n * into `cacheCreation` and cannot be separated out.\n */\n rebilledTokens: number\n /** Request dimensions that changed since the previous turn; empty ⇒ suspect TTL/eviction. */\n changed: CacheDimensionName[]\n /** Human-readable per-dimension diffs, keyed by the entries of `changed`. */\n details: Partial<Record<CacheDimensionName, string>>\n /** The parts of the system prompt that changed, when `changed` includes `'system'` — see {@link CacheDimensionDiff.systemSections}. */\n systemSections?: CacheSystemSection[]\n}\n\n/**\n * Structured payload of the `'cache:drift'` agent hook, emitted by\n * {@link installCacheBreakLogger} at `turn:before` whenever the outgoing\n * request DIVERGES from the previous completed turn's — any tracked dimension,\n * including an in-place rewrite of the message prefix.\n *\n * Drift is the PREDICTIVE counterpart of `'cache:break'`: it fires from the\n * request bytes alone, before (and regardless of whether) the provider\n * confirms a miss. That makes it the signal that works everywhere the\n * confirmed-cost path cannot see — providers that report no cache usage, and\n * format-casting gateways where this wire is the last observable point before\n * the cast. A turn that drifts here and then reports a healthy `cacheRead`\n * means the provider absorbed the change (e.g. only the tail moved); a turn\n * that drifts AND breaks gives the break its attribution for free.\n *\n * Intentional rewrites drift too, by design — that is the attribution story\n * for planned invalidations: tail compaction and media age-out cut on\n * chunk-aligned indices (`divergedAt` a multiple of the compaction chunk),\n * stale-read stubbing rewrites a read's own position, host history surgery\n * lands anywhere. `details.messagePrefix` carries the same hint in prose.\n */\nexport interface CacheDriftInfo {\n /** 1-based turn index, installer-lifetime monotonic — see {@link CacheBreakInfo.turn}. */\n turn: number\n /** Id of the turn the outgoing request belongs to. */\n turnId: string\n /** Model id of the OUTGOING request (post-fallback, pre-provider). */\n model: string\n /** Dimensions that differ from the previous completed turn's request. */\n changed: CacheDimensionName[]\n /** Human-readable per-dimension diffs, keyed by the entries of `changed`. */\n details: Partial<Record<CacheDimensionName, string>>\n /** Message index of an in-place prefix rewrite — see {@link CacheDimensionDiff.messagePrefixDivergedAt}. */\n divergedAt?: number\n /** Number of messages in the previous completed turn's request. */\n previousMessageCount: number\n /** Number of messages in the outgoing request. */\n messageCount: number\n /** The parts of the system prompt that changed, when `changed` includes `'system'` — see {@link CacheDimensionDiff.systemSections}. */\n systemSections?: CacheSystemSection[]\n}\n\n// ---------------------------------------------------------------------------\n// Configuration\n// ---------------------------------------------------------------------------\n\n/** Options for {@link installCacheBreakLogger}. */\nexport interface CacheBreakLoggerOptions {\n /**\n * Sink for log lines. Defaults to `console.error`. Use a {@link Logger} or\n * a test buffer here when you want the output to land somewhere other than\n * stderr.\n *\n * NOT every line is a dimension diff: unless {@link onEmitError} is\n * provided, `'cache:break'` handler errors are also routed here (prefixed\n * `cache-break: 'cache:break' handler threw:`). A host that counts `log`\n * invocations as \"dimension changes\" — the journal-mode wiring — should\n * either pass `onEmitError` or count via the `'cache:break'` hook instead.\n */\n log?: (line: string) => void\n /**\n * Sink for errors thrown by `'cache:break'` hook consumers. The emission is\n * try/caught so a UI bug in a handler can't unwind into the loop and abort\n * the run; this is where that error surfaces. Defaults to the {@link log}\n * channel (never a louder one — hosts route `log` away from stderr for good\n * reasons). Pass a dedicated sink when `log` invocations are being counted\n * as metrics.\n */\n onEmitError?: (error: unknown) => void\n /**\n * When `true`, emit a log line on EVERY turn (not just cache breaks) with\n * the per-dimension hashes. Useful for offline correlation; off by default\n * to keep the logger zero-noise on happy paths.\n */\n verbose?: boolean\n /**\n * Absolute floor for \"this turn missed cache\". The logger reports when\n * `cacheRead` falls below the threshold AND the dimensions differ from the\n * previous turn.\n *\n * Defaults to `1`, which on its own only catches TOTAL cache loss. That is not\n * the common failure: when the system prompt or the message prefix is\n * rewritten, `tools` + the static system block still match, so `cacheRead`\n * stays comfortably non-zero — pinned to a CONSTANT equal to that scaffold —\n * while the entire conversation re-bills at the cache-write rate. An\n * absolute-only threshold reports such a run as perfectly healthy.\n *\n * {@link CacheBreakLoggerOptions.expectedReadRatio} is the fix and is on by\n * default; this field remains as the absolute floor beneath it.\n */\n expectedReadAtLeast?: number\n /**\n * Detect PARTIAL-prefix breaks by comparing this turn's `cacheRead` against\n * the prefix the previous turn established (`cacheRead + cacheCreation`).\n * The conversation only grows, so a healthy turn reads back at least what the\n * one before it wrote; reading materially less means something at or before\n * the last message changed.\n *\n * Defaults to `0.8` — the slack absorbs tokenizer jitter and any uncached\n * dynamic system block, which is re-billed by design. Set `0` to disable and\n * detect only total loss through `expectedReadAtLeast`.\n */\n expectedReadRatio?: number\n /**\n * Share the comparison baseline with other agents bound to the same session.\n * When on, the last request of a top-level run on a session is kept per\n * session id at process level, and a newly built agent compares its first\n * request against it, so a cache break caused by rebuilding the agent is\n * reported instead of starting from a blank slate. Subagent runs never\n * share. Set `false` to keep the baseline per logger.\n *\n * @default true\n */\n sessionBaseline?: boolean\n}\n\n// ---------------------------------------------------------------------------\n// Hashing\n// ---------------------------------------------------------------------------\n\nconst FNV_OFFSET = 0x811C9DC5\nconst FNV_PRIME = 0x01000193\n\n/**\n * Smallest previous-prefix size the ratio test will judge. Below this the run\n * has barely started (or the provider reports no cache at all) and the ratio is\n * noise — the absolute floor still applies.\n */\nconst MIN_JUDGED_PREFIX_TOKENS = 1024\n\n/**\n * FNV-1a-style 32-bit hash over UTF-16 code units. Pure and allocation-free.\n * Cryptographic strength is irrelevant here — we only need change detection,\n * and a 32-bit collision is unlikely for the few dimensions tracked.\n *\n * Feeds the FULL char code into the mix (same as read-state's\n * `hashContent`) — masking to the low byte would collapse code points that\n * share a low byte, so a non-ASCII system-prompt change could hash\n * identically and silently hide a cache-dimension drift.\n *\n * Exported for tests; callers shouldn't typically import directly.\n *\n * @param s - String to hash.\n */\nexport function fnv1a32(s: string): number {\n let h = FNV_OFFSET\n for (let i = 0; i < s.length; i++) {\n h ^= s.charCodeAt(i)\n // Multiply by FNV_PRIME mod 2^32, using `Math.imul` to keep within\n // 32-bit signed range (avoid >>> 0 ping-pong on every iteration).\n h = Math.imul(h, FNV_PRIME)\n }\n // Map signed → unsigned 32-bit so the printed hex is stable.\n return h >>> 0\n}\n\n/**\n * Build a {@link CacheDimensionSnapshot} from a `turn:before` payload.\n *\n * Pure — exported so hosts can compute snapshots outside the logger (e.g.\n * stamping them onto custom telemetry spans). The hash is deterministic on\n * byte-identical inputs.\n *\n * @param options - Stream options of the outgoing request.\n * @param sections - Texts of the sections inside `options.system` to hash separately. The halves around `SYSTEM_PROMPT_BOUNDARY` are always hashed.\n */\nexport function snapshotCacheDimensions(options: StreamOptions, sections?: CachePromptSections): CacheDimensionSnapshot {\n const messages = options.messages ?? []\n return buildSnapshot(options, fnv1a32(JSON.stringify(options.tools ?? [])), hashMessages(messages), sections)\n}\n\n// Per-object memo for the logger's snapshots. Messages, blocks and the wire\n// tools array are immutable by convention (an edit swaps in a new object, and\n// the run's formatted tools are one cached array), so each is hashed once\n// instead of re-serializing the whole transcript every turn. The hashes are\n// only ever compared with each other within this process.\nconst blockHashes = new WeakMap<object, number>()\nconst toolsHashes = new WeakMap<object, number>()\n\nfunction memoBlockHash(block: unknown): number {\n if (typeof block !== 'object' || block === null)\n return fnv1a32(JSON.stringify(block) ?? '')\n let h = blockHashes.get(block)\n if (h === undefined) {\n h = fnv1a32(JSON.stringify(block) ?? '')\n blockHashes.set(block, h)\n }\n return h\n}\n\n/** {@link hashMessages} with each content block hashed once per object; same per-position contract, different values. */\nfunction hashMessagesMemo(messages: readonly { role: string, content: unknown }[]): number[] {\n const out: number[] = []\n for (const message of messages) {\n if (!message) {\n out.push(0)\n continue\n }\n let h = mixString(FNV_OFFSET, message.role ?? '')\n if (Array.isArray(message.content)) {\n for (const block of message.content)\n h = Math.imul(h ^ memoBlockHash(block), FNV_PRIME)\n }\n else {\n h = mixString(h, JSON.stringify(message.content) ?? '')\n }\n out.push(h >>> 0)\n }\n return out\n}\n\n/** The logger's snapshot: {@link snapshotCacheDimensions} with the memoized hashes (same `toolsHash` value). */\nfunction snapshotCacheDimensionsMemo(options: StreamOptions, sections: CachePromptSections | undefined): CacheDimensionSnapshot {\n const tools = options.tools\n let toolsHash = tools && typeof tools === 'object' ? toolsHashes.get(tools) : undefined\n if (toolsHash === undefined) {\n toolsHash = fnv1a32(JSON.stringify(tools ?? []))\n if (tools && typeof tools === 'object')\n toolsHashes.set(tools, toolsHash)\n }\n return buildSnapshot(options, toolsHash, hashMessagesMemo(options.messages ?? []), sections)\n}\n\nfunction buildSnapshot(options: StreamOptions, toolsHash: number, messageHashes: number[], sections: CachePromptSections | undefined): CacheDimensionSnapshot {\n return {\n systemHash: fnv1a32(options.system),\n systemBytes: options.system.length,\n toolsHash,\n toolsCount: Array.isArray(options.tools) ? options.tools.length : 0,\n model: options.model,\n thinking: options.thinking ?? 'off',\n thinkingBudget: options.thinkingBudget ?? 0,\n taskBudget: options.taskBudget ?? 0,\n effortHint: options.effortHint !== false,\n messageHashes,\n messageCount: messageHashes.length,\n systemSections: hashSystemSections(options.system, sections),\n }\n}\n\n/** Sections hashed from their own text, in the order a diff names them. */\nconst TEXT_SECTIONS = ['skillsCatalog', 'toolsCatalog', 'mcpInstructions', 'rules'] as const\n\n/** Every section, in the order a diff names them. */\nconst SYSTEM_SECTION_ORDER: readonly CacheSystemSection[] = [...TEXT_SECTIONS, 'hostStatic', 'hostDynamic']\n\nconst SYSTEM_SECTION_LABELS: Record<CacheSystemSection, string> = {\n skillsCatalog: 'skills catalog',\n toolsCatalog: 'searchable tools catalog',\n mcpInstructions: 'MCP instructions',\n rules: 'rules',\n hostStatic: 'static prompt',\n hostDynamic: 'dynamic prompt',\n}\n\nfunction hashSystemSections(system: string, sections: CachePromptSections | undefined): Partial<Record<CacheSystemSection, number>> {\n const out: Partial<Record<CacheSystemSection, number>> = {}\n const hasBoundary = system.includes(SYSTEM_PROMPT_BOUNDARY)\n let { static: staticPart, dynamic } = splitSystemPrompt(system)\n for (const name of TEXT_SECTIONS) {\n const text = sections?.[name]\n if (!text || !system.includes(text))\n continue\n out[name] = fnv1a32(text)\n // Cut it out of the host halves so its change is blamed on it alone.\n if (staticPart.includes(text))\n staticPart = cutSection(staticPart, text)\n else\n dynamic = cutSection(dynamic, text)\n }\n out.hostStatic = fnv1a32(staticPart)\n if (hasBoundary)\n out.hostDynamic = fnv1a32(dynamic)\n return out\n}\n\n/** Remove `text` and the blank line `appendStaticSection` joined it with, so adding or dropping a section leaves the rest unchanged. */\nfunction cutSection(haystack: string, text: string): string {\n for (const piece of [`\\n\\n${text}`, `${text}\\n\\n`, text]) {\n const at = haystack.indexOf(piece)\n if (at >= 0)\n return haystack.slice(0, at) + haystack.slice(at + piece.length)\n }\n return haystack\n}\n\n// Where the logger reads the section texts of the run on a given hook bus.\n// `createAgent` registers its own bus; a bare bus has none and only gets the\n// host halves.\nconst promptSectionSources = new WeakMap<object, () => CachePromptSections | undefined>()\n\n/**\n * Tell the cache-break logger installed on `hooks` where to read the texts of\n * the current run's system prompt sections. `createAgent` calls this for its\n * own hook bus; hosts don't need to.\n *\n * @internal\n * @param hooks - Hook bus of the agent.\n * @param read - Returns the current run's section texts, or `undefined` before the first run.\n */\nexport function registerCachePromptSections(hooks: Hookable<AgentHooks>, read: () => CachePromptSections | undefined): void {\n promptSectionSources.set(hooks, read)\n}\n\n/** Last completed request of a top-level run on a session, shared by every logger in the process. */\ninterface SessionBaseline {\n snapshot: CacheDimensionSnapshot\n prefixTokens: number\n}\n\n/** Enough for every session a long-lived host keeps open; the oldest entry goes first. */\nconst MAX_SESSION_BASELINES = 256\nconst sessionBaselines = new Map<string, SessionBaseline>()\n\nfunction rememberSessionBaseline(sessionId: string, baseline: SessionBaseline): void {\n sessionBaselines.delete(sessionId)\n sessionBaselines.set(sessionId, baseline)\n if (sessionBaselines.size > MAX_SESSION_BASELINES) {\n const oldest = sessionBaselines.keys().next().value\n if (oldest !== undefined)\n sessionBaselines.delete(oldest)\n }\n}\n\n/**\n * Drops the session's shared baseline (the session was deleted).\n *\n * @param sessionId - The session.\n */\nexport function forgetSessionCacheBaseline(sessionId: string): void {\n sessionBaselines.delete(sessionId)\n}\n\n/** Sessions with a shared baseline kept. */\nexport function sessionCacheBaselineCount(): number {\n return sessionBaselines.size\n}\n\n/**\n * Hash each message independently, preserving order.\n *\n * Per-message rather than cumulative so the diff can tell an APPEND (healthy)\n * from a REWRITE (a cache break) by comparing positionally — see\n * {@link CacheDimensionSnapshot.messageHashes}.\n *\n * Folds field-by-field into a rolling FNV rather than `JSON.stringify`-ing the\n * whole list at once: on a long run the transcript is hundreds of KB, and\n * building one giant string every turn just to throw it away is the kind of\n * overhead that gets telemetry ripped back out.\n *\n * Exported so hosts can stamp the same hashes onto their own spans.\n *\n * @param messages - Messages in transcript order.\n */\nexport function hashMessages(messages: readonly { role: string, content: unknown }[]): number[] {\n const out: number[] = []\n for (const message of messages) {\n if (!message) {\n out.push(0)\n continue\n }\n let h = mixString(FNV_OFFSET, message.role ?? '')\n // `JSON.stringify` yields `undefined` (the value, not a string) for\n // undefined input — public export, so don't let a malformed message throw\n // inside a diagnostics helper.\n h = mixString(h, JSON.stringify(message.content) ?? '')\n out.push(h >>> 0)\n }\n return out\n}\n\n/**\n * Index of the first message whose content differs, or -1 when one list is a\n * pure prefix of the other (i.e. messages were only appended).\n */\nfunction firstDivergentIndex(prev: readonly number[], curr: readonly number[]): number {\n const shared = Math.min(prev.length, curr.length)\n for (let i = 0; i < shared; i++) {\n if (prev[i] !== curr[i])\n return i\n }\n return -1\n}\n\n/** Mix a string into a running FNV-1a state. */\nfunction mixString(seed: number, s: string): number {\n let h = seed\n for (let i = 0; i < s.length; i++) {\n h ^= s.charCodeAt(i)\n h = Math.imul(h, FNV_PRIME)\n }\n return h\n}\n\n// ---------------------------------------------------------------------------\n// Diffing\n// ---------------------------------------------------------------------------\n\n/**\n * Compare two snapshots and return the list of dimensions whose bytes\n * differ. The `details` map carries a short human-readable description per\n * changed dimension (e.g. `system: 1024 → 1031 bytes`).\n *\n * Pure / no I/O. Use this in tests to assert the diff logic; the logger\n * itself just formats and emits the result.\n *\n * @param prev - Snapshot of the previous turn.\n * @param curr - Snapshot of the current turn.\n */\nexport function diffCacheDimensions(\n prev: CacheDimensionSnapshot,\n curr: CacheDimensionSnapshot,\n): CacheDimensionDiff {\n const changed: CacheDimensionName[] = []\n const details: Partial<Record<CacheDimensionName, string>> = {}\n let systemSections: CacheSystemSection[] | undefined\n\n if (prev.systemHash !== curr.systemHash) {\n changed.push('system')\n details.system = `${prev.systemBytes} → ${curr.systemBytes} bytes (hash ${hex(prev.systemHash)} → ${hex(curr.systemHash)})`\n const before = prev.systemSections\n const after = curr.systemSections\n if (before && after) {\n systemSections = SYSTEM_SECTION_ORDER.filter(name => before[name] !== after[name])\n // A prompt with no boundary and no known sections is all `hostStatic`:\n // naming it would only repeat that the prompt changed.\n const informative = Object.keys(before).length > 1 || Object.keys(after).length > 1\n if (informative && systemSections.length > 0)\n details.system += `\\nin ${systemSections.map(name => SYSTEM_SECTION_LABELS[name]).join(', ')}`\n }\n }\n if (prev.toolsHash !== curr.toolsHash) {\n changed.push('tools')\n details.tools = `${prev.toolsCount} → ${curr.toolsCount} tools (hash ${hex(prev.toolsHash)} → ${hex(curr.toolsHash)})`\n }\n if (prev.model !== curr.model) {\n changed.push('model')\n details.model = `${prev.model} → ${curr.model}`\n }\n if (prev.thinking !== curr.thinking) {\n changed.push('thinking')\n details.thinking = `${prev.thinking} → ${curr.thinking}`\n }\n if (prev.thinkingBudget !== curr.thinkingBudget) {\n changed.push('thinkingBudget')\n details.thinkingBudget = `${prev.thinkingBudget} → ${curr.thinkingBudget}`\n }\n if (prev.taskBudget !== curr.taskBudget) {\n changed.push('taskBudget')\n details.taskBudget = `${prev.taskBudget} → ${curr.taskBudget}`\n }\n if (prev.effortHint !== curr.effortHint) {\n changed.push('effortHint')\n details.effortHint = `${prev.effortHint} → ${curr.effortHint}`\n }\n // Reported last, mirroring the provider's tools → system → messages ordering:\n // a change here invalidates the least, a change in `tools` the most.\n //\n // Only a POSITIONAL divergence counts. Appending messages is what every\n // healthy turn does and must never be reported, or this dimension would name\n // itself on every single break and bury the real culprit.\n const divergentAt = firstDivergentIndex(prev.messageHashes, curr.messageHashes)\n if (divergentAt >= 0) {\n changed.push('messagePrefix')\n // Two lines: the fact, then the usual suspects. Notice rows render each\n // line on its own so this never reads as one run-on sentence.\n details.messagePrefix = `message ${divergentAt} of ${prev.messageCount}→${curr.messageCount} rewritten`\n + `\\nlikely compaction or history trimming`\n }\n\n // Single tail return so a dimension added below the messagePrefix check can\n // never be silently skipped on the turns where the prefix diverged — the\n // turns where full attribution matters most.\n return {\n changed,\n details,\n ...(divergentAt >= 0 ? { messagePrefixDivergedAt: divergentAt } : {}),\n ...(systemSections ? { systemSections } : {}),\n }\n}\n\nfunction hex(n: number): string {\n return `0x${n.toString(16).padStart(8, '0')}`\n}\n\n// ---------------------------------------------------------------------------\n// Hook installer\n// ---------------------------------------------------------------------------\n\n/**\n * Install the cache-break logger on an agent's hook bus.\n *\n * Subscribes to `turn:before` (snapshot) + `turn:after` (compare with prior\n * snapshot, log breaks), plus `session:start` + `agent:start` to pick up the\n * session's baseline (unless `sessionBaseline: false`). Returns an\n * `uninstall` fn that detaches every listener. Idempotent w.r.t. agent\n * lifecycle — installs/uninstalls cleanly across runs.\n *\n * Recommended setup:\n *\n * ```ts\n * const uninstall = installCacheBreakLogger(agent.hooks, {\n * log: line => logger.debug(line),\n * verbose: !!process.env.ZIDANE_DEBUG?.includes('cache'),\n * })\n * // ...\n * uninstall()\n * ```\n *\n * Performance: hashing runs on each `turn:before`. The tools array and each\n * message block are serialized once per object (memoized), so a turn costs\n * the system prompt plus the blocks that are new since the last one.\n * Disabled callers pay nothing (don't install).\n *\n * @param hooks - Agent hook bus to install the logger on.\n * @param options - Logger options. All fields are optional.\n */\nexport function installCacheBreakLogger(\n hooks: Hookable<AgentHooks>,\n options: CacheBreakLoggerOptions = {},\n): () => void {\n const log = options.log ?? ((line: string) => console.error(line))\n // Defaults into `log` (not console.error): hosts route `log` away from\n // stderr for good reasons — the TUI's alternate screen, e.g. — and a\n // consumer bug should not get a louder channel than the feature itself.\n const onEmitError = options.onEmitError\n ?? ((error: unknown) => log(`cache-break: 'cache:break' handler threw: ${String(error)}`))\n const verbose = options.verbose === true\n const expectedReadAtLeast = options.expectedReadAtLeast ?? 1\n const expectedReadRatio = options.expectedReadRatio ?? 0.8\n const shareBySession = options.sessionBaseline !== false\n\n // Latest completed snapshot. Across runs on the same bus it persists, which\n // is what we want: the first turn of run N+1 should hit cache if it shares\n // a prefix with the last turn of run N. With `sessionBaseline` on, a run\n // bound to a session starts from that session's process-wide baseline\n // instead, so the same holds across agent rebuilds.\n let prev: CacheDimensionSnapshot | undefined\n /**\n * Size of the prefix the previous turn left cached (`cacheRead +\n * cacheCreation`). Turn N+1 should read back at least this much.\n */\n let previousPrefixTokens = 0\n let turnIndex = 0\n let pending: { snapshot: CacheDimensionSnapshot, turnIndex: number, turnId: string } | undefined\n // `session:start` names the session; the `agent:start` that follows says\n // whether the run is top-level. Subagents with a persisted child run share\n // their parent's session and must not overwrite its baseline.\n let startingSessionId: string | undefined\n let baselineSessionId: string | undefined\n\n function onSessionStart(ctx: { sessionId: string }): void {\n startingSessionId = ctx.sessionId\n }\n\n function onAgentStart(ctx: { depth: number }): void {\n baselineSessionId = ctx.depth === 0 ? startingSessionId : undefined\n startingSessionId = undefined\n const shared = baselineSessionId !== undefined ? sessionBaselines.get(baselineSessionId) : undefined\n if (shared) {\n prev = shared.snapshot\n previousPrefixTokens = shared.prefixTokens\n }\n }\n\n function onTurnBefore(ctx: { turn: number, turnId: string, options: StreamOptions }): void {\n const curr = snapshotCacheDimensionsMemo(ctx.options, promptSectionSources.get(hooks)?.())\n turnIndex += 1\n\n if (verbose) {\n log(formatVerboseLine({\n turn: turnIndex,\n turnId: ctx.turnId,\n snapshot: curr,\n }))\n }\n\n // Stash for the matching `turn:after`. The confirmed-cost path can't run\n // here — the cache-read result lands on `turn:after.usage`.\n pending = { snapshot: curr, turnIndex, turnId: ctx.turnId }\n\n // Predictive path: the request bytes alone tell us the prefix moved,\n // before any provider accounting. `prev` is the last COMPLETED turn's\n // snapshot (assigned at its `turn:after`), so a turn that errors before\n // completion doesn't become the comparison baseline. Fires for\n // intentional rewrites too — that is the attribution channel for\n // compaction cuts and stale-read stubs, not noise (see CacheDriftInfo).\n //\n // FIRE-AND-FORGET, deliberately not awaited: `turn:before` is dispatched\n // through the loop's PROPAGATING hook timeout (`boundedHook`), so awaiting\n // arbitrary drift consumers here would let a slow subscriber time out the\n // whole dispatch and abort the run — the exact coupling `onEmitError`\n // exists to rule out. (`'cache:break'` on `turn:after` rides the\n // timeout-swallowing dispatch, so awaiting is safe THERE.) Synchronous\n // subscribers still complete before the request goes out — hookable\n // invokes handlers inline — while async subscribers detach; the payload is\n // a fresh object per emission, so detached consumers can't observe later\n // mutation. Errors from either path route to `onEmitError`.\n if (prev) {\n const diff = diffCacheDimensions(prev, curr)\n if (diff.changed.length > 0) {\n try {\n void Promise.resolve(hooks.callHook('cache:drift', {\n turn: turnIndex,\n turnId: ctx.turnId,\n model: curr.model,\n changed: [...diff.changed],\n details: { ...diff.details },\n ...(diff.messagePrefixDivergedAt !== undefined ? { divergedAt: diff.messagePrefixDivergedAt } : {}),\n previousMessageCount: prev.messageCount,\n messageCount: curr.messageCount,\n ...(diff.systemSections ? { systemSections: [...diff.systemSections] } : {}),\n })).catch(onEmitError)\n }\n catch (error) {\n // a synchronously-throwing dispatch path must not unwind into the loop\n onEmitError(error)\n }\n }\n }\n }\n\n async function onTurnAfter(ctx: { turn: number, turnId: string, usage: { cacheRead?: number, cacheCreation?: number } }): Promise<void> {\n if (!pending || pending.turnId !== ctx.turnId)\n return\n const { snapshot: curr, turnIndex: tIdx } = pending\n pending = undefined\n\n // Skip break detection on providers that don't report `cacheRead` —\n // treating undefined as 0 would log a false break every turn on Codex,\n // Cerebras, or any host without a cache_read field. We can only diagnose\n // breaks when the provider tells us how much cache was actually used.\n if (prev && typeof ctx.usage.cacheRead === 'number') {\n const cacheRead = ctx.usage.cacheRead\n // Below the absolute floor, OR materially short of the prefix the previous\n // turn already had cached. The second test is the one that catches a\n // partial break, where `cacheRead` is large but covers only the scaffold.\n const ratioFloor = expectedReadRatio > 0 && previousPrefixTokens >= MIN_JUDGED_PREFIX_TOKENS\n ? previousPrefixTokens * expectedReadRatio\n : 0\n if (cacheRead < expectedReadAtLeast || cacheRead < ratioFloor) {\n const diff = diffCacheDimensions(prev, curr)\n // The text line stays gated on an attributable dimension change; the\n // typed hook fires on EVERY break — an\n // empty `changed` is the TTL-expiry / provider-eviction signature and\n // hosts (TUI chip, dashboards) want to see it.\n if (diff.changed.length > 0) {\n log(formatBreakLine({\n turn: tIdx,\n turnId: ctx.turnId,\n cacheRead,\n cacheCreation: ctx.usage.cacheCreation ?? 0,\n diff,\n }))\n }\n // Emission is side-effect-safe: this runs inside the loop's\n // `turn:after` dispatch, so a throwing consumer handler (a UI bug,\n // say) would otherwise unwind into the loop and abort the run — a\n // bad trade for an observational diagnostics module. Errors are\n // surfaced through the `log` channel instead of propagated.\n try {\n await hooks.callHook('cache:break', {\n turn: tIdx,\n turnId: ctx.turnId,\n model: curr.model,\n cacheRead,\n cacheCreation: ctx.usage.cacheCreation ?? 0,\n // Journal mode pins `expectedReadAtLeast` to Infinity (\"report\n // every dimension change\"), and Infinity JSON-serializes as\n // `null` — a metrics pipeline consuming this payload would see a\n // null floor on every break. When the absolute floor is\n // non-finite, report the tightest FINITE floor that actually\n // tripped: the ratio floor when this turn read less than it,\n // otherwise the previous turn's cached prefix (the \"should have\n // read everything\" claim the pin amounts to).\n expectedAtLeast: Number.isFinite(expectedReadAtLeast)\n ? Math.max(expectedReadAtLeast, Math.round(ratioFloor))\n : cacheRead < ratioFloor\n ? Math.round(ratioFloor)\n : Math.round(previousPrefixTokens),\n rebilledTokens: Math.max(0, Math.round(previousPrefixTokens - cacheRead)),\n changed: [...diff.changed],\n details: { ...diff.details },\n ...(diff.systemSections ? { systemSections: [...diff.systemSections] } : {}),\n })\n }\n catch (error) {\n onEmitError(error)\n }\n }\n }\n\n previousPrefixTokens = (ctx.usage.cacheRead ?? 0) + (ctx.usage.cacheCreation ?? 0)\n prev = curr\n if (baselineSessionId !== undefined)\n rememberSessionBaseline(baselineSessionId, { snapshot: curr, prefixTokens: previousPrefixTokens })\n }\n\n // Hookable's `.hook()` returns its own unregister fn — keep both so\n // `uninstall()` is symmetric with the install path and survives a\n // future hookable rename of `removeHook`.\n const unregisters = [\n hooks.hook('turn:before', onTurnBefore),\n hooks.hook('turn:after', onTurnAfter),\n ...(shareBySession ? [hooks.hook('session:start', onSessionStart), hooks.hook('agent:start', onAgentStart)] : []),\n ]\n\n return () => {\n for (const unregister of unregisters)\n unregister()\n }\n}\n\n// ---------------------------------------------------------------------------\n// Estimates\n// ---------------------------------------------------------------------------\n\nconst CACHE_TTL_MS: Record<CacheTtl, number> = { '5m': 5 * 60_000, '1h': 60 * 60_000 }\n\n/**\n * Epoch ms when the prompt cache written by `request` is estimated to expire:\n * when it was sent plus its cache lifetime (5 minutes unless it set\n * `cacheTtl`). `null` without a request. Backs `agent.cacheExpiresAt()`.\n *\n * @param request - The last request sent, or `undefined` when none was.\n */\nexport function estimateCacheExpiresAt(request: { sentAt: number, cacheTtl?: CacheTtl } | undefined): number | null {\n if (!request)\n return null\n return request.sentAt + CACHE_TTL_MS[request.cacheTtl ?? '5m']\n}\n\n/** What {@link estimateCacheImpact} knows about the last request. */\ninterface LastRequestFacts {\n /** Model id and thinking level of the last request; absent when none was sent. */\n request?: { model: string, thinking: ThinkingLevel }\n /** `input + cacheRead + cacheCreation` of the last assistant turn. */\n promptTokens: number\n /** From {@link estimateCacheExpiresAt}. */\n expiresAt: number | null\n}\n\n/**\n * Estimate what `change` would make the next request read again, against\n * the last request. Backs `agent.cacheImpact()`; see there for the rules.\n *\n * @param last - What is known about the last request.\n * @param change - The change the host is about to make.\n * @param now - Current time in epoch ms.\n */\nexport function estimateCacheImpact(\n last: LastRequestFacts,\n change: AgentCacheChange,\n now: number,\n): AgentCacheImpact {\n const reasons: AgentCacheImpact['reasons'] = []\n if (last.request && change.model !== undefined && change.model !== last.request.model)\n reasons.push('model')\n if (last.request && change.thinking !== undefined && change.thinking !== last.request.thinking)\n reasons.push('thinking')\n if (change.system === true)\n reasons.push('system')\n if (change.tools === true)\n reasons.push('tools')\n return {\n tokens: reasons.length > 0 ? last.promptTokens : 0,\n reasons,\n expired: last.expiresAt === null || last.expiresAt <= now,\n }\n}\n\n// ---------------------------------------------------------------------------\n// Formatting\n// ---------------------------------------------------------------------------\n\nfunction formatBreakLine(input: {\n turn: number\n turnId: string\n cacheRead: number\n cacheCreation: number\n diff: CacheDimensionDiff\n}): string {\n const names = input.diff.changed.join(', ')\n const details = input.diff.changed\n .map(d => ` ${d}: ${input.diff.details[d]}`)\n .join('\\n')\n return [\n `[zidane:cache-break] turn=${input.turn} turnId=${input.turnId} cacheRead=${input.cacheRead} cacheCreation=${input.cacheCreation}`,\n ` changed: ${names}`,\n details,\n ].join('\\n')\n}\n\nfunction formatVerboseLine(input: {\n turn: number\n turnId: string\n snapshot: CacheDimensionSnapshot\n}): string {\n const s = input.snapshot\n return `[zidane:cache] turn=${input.turn} turnId=${input.turnId} system=${hex(s.systemHash)}(${s.systemBytes}b) tools=${hex(s.toolsHash)}(${s.toolsCount}) model=${s.model} thinking=${s.thinking}/${s.thinkingBudget}${s.taskBudget ? `/task=${s.taskBudget}` : ''}`\n}\n","/**\n * Tool-result disk persistence — replace oversize `tool_result` outputs with\n * a `<persisted-output>` stub pointing at the full payload on disk.\n *\n * Why: a single 200 KB shell output sits in the prompt prefix for the rest\n * of the session and gets re-sent every turn. Persisting it shrinks the\n * inline content to a fixed-size stub (preview + path), preserves the\n * original bytes on disk so the model can `read_file` them deliberately,\n * and keeps the prompt-cache prefix byte-stable across turns.\n *\n * Wire contract:\n *\n * - Trigger: `behavior.persistThreshold` bytes (off / undefined disables).\n * - Excluded tools: `behavior.persistExcludeTools` — bypass regardless of\n * size. Built-in chat profiles use `DEFAULT_PERSIST_EXCLUDE_TOOLS`\n * (`src/chat/agents.ts`).\n * - Target: `behavior.persistDir`, one file per call id (`<callId>.txt`).\n * Atomic via write-to-`.tmp` then rename.\n * - Stub: byte-stable XML wrapper carrying tool name, byte count, path,\n * and a 2 KiB head preview. The stub itself becomes the `tool_result`\n * output that lands in `session.turns`, so re-emission on subsequent\n * turns reads back the same bytes and rides the prompt cache.\n *\n * No state. The substitution is one-shot at emit time; nothing in this\n * module persists across turns. The disk file is the source of truth for\n * \"what the model originally saw\"; the in-message stub is what gets\n * re-emitted.\n *\n * Execution-context routing: when the caller supplies `writeBlob` (the agent\n * loop passes `ctx.execution.writeFile(handle, …)`), the blob is written to the\n * SAME filesystem the model reads it back from (`read_file` →\n * `ctx.execution.readFile`). That makes docker / sandbox / remote / edge\n * contexts work — the spill lands where the model can re-read it — not just the\n * host process. Without `writeBlob` (direct SDK callers) the write falls back\n * to a local atomic write on the host `fs`. The byte cap, idempotent\n * \"already exists\" check, and session cleanup stay best-effort LOCAL\n * housekeeping (the `ExecutionContext` interface exposes no remote delete/stat);\n * remote contexts rely on their own ephemeral teardown.\n */\n\nimport type { Dirent } from 'node:fs'\nimport type { SessionContentBlock, SessionMessage, ToolResultContent } from './types'\nimport { existsSync, mkdirSync, readdirSync, renameSync, rmdirSync, statSync } from 'node:fs'\nimport { copyFile, mkdir, readdir, rm, stat, unlink } from 'node:fs/promises'\nimport { dirname, isAbsolute, join } from 'node:path'\nimport { writeFileAtomicAsync } from './atomic-write'\nimport { utf8ByteLength } from './compact/utils'\nimport { errorMessage } from './errors'\nimport { headSlice } from './tools/truncate'\nimport { toolOutputByteLength } from './types'\nimport { escapeXml } from './xml'\n\n/** Upper bound on the error message embedded in a persistence-failure stub. */\nconst MAX_PERSIST_ERROR_CHARS = 500\n\n/**\n * Bytes of head content included in the inline preview block. 2 KiB matches\n * Claude Code's `PREVIEW_SIZE_BYTES` — enough for the model to identify the\n * content class (error output / structured data / log shape) and decide\n * whether to call `read_file` on the persisted path for the full payload.\n *\n * Tail-priority preview (matching `shell`'s truncation strategy) was\n * considered but rejected: most \"what is this?\" decisions get made from\n * the head, and the path is in the stub for the rare case where the tail\n * matters.\n */\nexport const PERSISTENCE_PREVIEW_BYTES = 2 * 1024\n\n/**\n * Preview size for persist-on-elide stubs. Much smaller than\n * {@link PERSISTENCE_PREVIEW_BYTES}: this content is being COMPACTED OUT (it's\n * old), so the stub only needs a hint plus the recovery path, not a full\n * preview. Keeping it small stops the elided region from ballooning ~40× over\n * the lossy stub it replaces while still being recoverable by reading `path`.\n */\nconst ELIDE_PERSIST_PREVIEW_BYTES = 256\n\n/**\n * Byte-stable prefix every {@link buildPersistedStub} output starts with.\n * Exported so wire-level passes (tail compaction) can recognize a persisted stub and preserve its path attribute\n * rather than replacing the stub with their own — losing the pointer to\n * the on-disk blob.\n *\n * Bound to the literal opening of the XML tag; changing the stub format\n * requires updating this constant in lockstep (and shipping a migration\n * for in-flight sessions).\n */\nexport const PERSISTED_STUB_PREFIX = '<persisted-output tool=\"'\n\n/**\n * Characters that are safe to use verbatim as a filesystem segment under\n * `persistDir`. Alphanumeric + `_` + `-` + `.` covers every real-world\n * `tool_use.id` we've seen (Anthropic `toolu_…`, OpenAI `call_…`, Bun\n * `crypto.randomUUID()` style, our own short ids).\n *\n * Anything else — slashes, `..`, control chars, spaces, unicode — is\n * rejected by {@link maybePersistToolResult} so a malformed or hostile\n * `callId` can't escape `persistDir` via path traversal.\n */\nconst SAFE_CALL_ID = /^[\\w.-]+$/\n\n/**\n * Where {@link maybePersistToolResult} writes the blob of call `callId`, or\n * `undefined` when it would not (a relative `persistDir`, an unsafe id).\n * @param persistDir - The run's `behavior.persistDir`.\n * @param callId - The call's id.\n */\nexport function persistedBlobPath(persistDir: string | undefined, callId: string): string | undefined {\n if (!persistDir || !isAbsolute(persistDir) || !SAFE_CALL_ID.test(callId) || callId.includes('..'))\n return undefined\n return join(persistDir, `${callId}.txt`)\n}\n\n/**\n * Root holding every per-session artifact directory: `<userDir>/sessions/`.\n *\n * Session-first, not kind-first. The layout exists to make session DELETE a\n * single recursive remove: every artifact a session owns is one subtree, so\n * adding a fourth artifact kind later needs no change to the delete path. The\n * alternative (a `<kind>/<sessionId>/` root per kind) forces the delete path to\n * enumerate kinds, and a kind missing from that list leaks silently — which is\n * exactly the bug this layout is designed out of.\n *\n * Sits beside `sessions.db` rather than colliding with it: that's a file, this\n * is a directory.\n */\nconst SESSIONS_ROOT = 'sessions'\n\n/** Per-session artifact subdirectories under `<userDir>/sessions/<sessionId>/`. */\nconst SESSION_ARTIFACT_KINDS = ['tasks', 'mcp-warnings', 'tool-results'] as const\n\n/**\n * Resolve the root of a session's artifact subtree\n * (`<userDir>/sessions/<sessionId>/`).\n *\n * This is what session delete removes: one recursive remove reclaims every\n * artifact kind at once, so adding a kind never touches the delete path.\n *\n * @param opts - Storage directory (must be absolute) and session id (a single path segment).\n */\nexport function resolveSessionDir(opts: { userDir: string, sessionId: string }): string {\n if (!isAbsolute(opts.userDir))\n throw new Error(`resolveSessionDir: userDir must be absolute, got \"${opts.userDir}\"`)\n assertSessionSegment('resolveSessionDir', opts.sessionId)\n return join(opts.userDir, SESSIONS_ROOT, opts.sessionId)\n}\n\n/**\n * The id names ONE directory under `sessions/`: session delete removes\n * what these resolvers return recursively, so `..` (or `a/../..`) would\n * reach the user dir or above it.\n */\nfunction assertSessionSegment(fn: string, sessionId: string): void {\n if (!sessionId)\n throw new Error(`${fn}: sessionId must be a non-empty string`)\n if (sessionId === '.' || sessionId === '..' || /[/\\\\\\0]/.test(sessionId))\n throw new Error(`${fn}: sessionId must be a single path segment, got ${JSON.stringify(sessionId)}`)\n}\n\n/**\n * Resolve the per-session persistence directory under\n * `<userDir>/sessions/<sessionId>/tool-results/`.\n *\n * The chat layer calls this at session activation and forwards the result\n * via `behavior.persistDir`. Exposed as a public helper so SDK consumers\n * pick the same layout — single source of truth for \"where do blobs live\".\n *\n * NOTE for anyone tempted to migrate old blobs into this path: don't. A\n * persisted stub embeds the blob's ABSOLUTE path in the session transcript\n * (see the `path=\"…\"` attribute built in {@link buildPersistedStub}) and the\n * MODEL re-reads it by calling `read_file` on that path. Moving the bytes\n * without rewriting every transcript strands them mid-conversation. Blobs\n * written under the old `<userDir>/tool-results/<sessionId>/` therefore stay\n * put and keep resolving forever; only new writes land here, and session\n * delete sweeps both (see {@link resolveLegacyPersistDir}).\n *\n * @param opts - Storage directory (must be absolute) and session id.\n */\nexport function resolvePersistDir(opts: { userDir: string, sessionId: string }): string {\n return resolveSessionArtifactDir('resolvePersistDir', opts, 'tool-results')\n}\n\n/**\n * Resolve the per-session background-tasks directory under\n * `<userDir>/sessions/<sessionId>/tasks/`.\n *\n * The chat layer calls this at session activation and forwards the result via\n * `behavior.tasksDir`. Created on first write; cleanup is the session-delete\n * path's job — and since it lives inside the session's own subtree, that\n * cleanup is the same recursive remove that takes everything else.\n *\n * @param opts - Storage directory (must be absolute) and session id.\n */\nexport function resolveTasksDir(opts: { userDir: string, sessionId: string }): string {\n return resolveSessionArtifactDir('resolveTasksDir', opts, 'tasks')\n}\n\n/**\n * Resolve the per-session MCP diagnostic directory under\n * `<userDir>/sessions/<sessionId>/mcp-warnings/`.\n *\n * Warning logs are cache/session artifacts like background task logs:\n * useful for debugging, safe to delete, and cleaned up with the session.\n *\n * @param opts - Storage directory (must be absolute) and session id.\n */\nexport function resolveMcpWarningsDir(opts: { userDir: string, sessionId: string }): string {\n return resolveSessionArtifactDir('resolveMcpWarningsDir', opts, 'mcp-warnings')\n}\n\n/**\n * Shared body of the three resolvers above. Takes the caller's name so a\n * misuse still reports the function the host actually called.\n */\nfunction resolveSessionArtifactDir(\n fn: string,\n opts: { userDir: string, sessionId: string },\n kind: typeof SESSION_ARTIFACT_KINDS[number],\n): string {\n if (!isAbsolute(opts.userDir))\n throw new Error(`${fn}: userDir must be absolute, got \"${opts.userDir}\"`)\n assertSessionSegment(fn, opts.sessionId)\n return join(opts.userDir, SESSIONS_ROOT, opts.sessionId, kind)\n}\n\n/**\n * Top-level directory names that are roots or shared state, never a session id.\n * `tool-results` and the kind-first `tasks` / `mcp-warnings` roots are listed\n * because both are migration SOURCES that must never be mistaken for a session\n * shell and relocated into themselves.\n */\nconst ARTIFACT_ROOTS = new Set<string>([...SESSION_ARTIFACT_KINDS, SESSIONS_ROOT])\n\n/**\n * The two session-id shapes zidane stores have ever minted:\n * `ses_<base36-ts>_<base36-rand>` (src/session `generateId`) and canonical\n * UUIDs (ACP hosts). {@link migrateSessionArtifactDirs} matches POSITIVELY on\n * these instead of sweeping every top-level directory, because the storage\n * dir also holds `skills/`, `extensions/`, `daemon/`, `sessions/`, … — and a\n * skill or extension named `tasks` would otherwise look exactly like a\n * legacy session shell and get silently relocated. Mis-matching in the\n * other direction is harmless: an exotic host-minted id that fits neither\n * shape just stays where it is.\n */\nconst LEGACY_SESSION_ID = /^(?:ses_[a-z0-9]+_[a-z0-9]+|[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})$/i\n\n/**\n * Path of the pre-6.x per-session artifact shell (`<userDir>/<sessionId>/`), or\n * `undefined` when the id doesn't match a shape zidane ever minted.\n *\n * Session delete sweeps this alongside the session subtree: when\n * {@link migrateSessionArtifactDirs} hits its conflict branch (the target\n * already existed), the shell is deliberately left in place and counted as\n * `failed` — and nothing else ever removes it, so deleting the session is the\n * one moment both copies are provably garbage. The positive id match is what\n * keeps an exotic host-minted id from resolving to a root like `tasks/`.\n *\n * @param opts - Storage directory (must be absolute) and session id.\n */\nexport function resolveLegacySessionDir(opts: { userDir: string, sessionId: string }): string | undefined {\n if (!isAbsolute(opts.userDir))\n throw new Error(`resolveLegacySessionDir: userDir must be absolute, got \"${opts.userDir}\"`)\n return LEGACY_SESSION_ID.test(opts.sessionId) ? join(opts.userDir, opts.sessionId) : undefined\n}\n\n/**\n * Path of the pre-session-first blob directory (`<userDir>/tool-results/<sessionId>/`),\n * or `undefined` when the id doesn't match a shape zidane ever minted.\n *\n * These blobs are deliberately NOT migrated — a persisted stub carries the\n * blob's absolute path inside the session transcript and the model re-reads it\n * with `read_file`, so moving the bytes without rewriting every transcript\n * strands them (see {@link resolvePersistDir}). They keep resolving where they\n * are; this resolver exists so session delete still reclaims them. Same\n * positive id match, same reason.\n *\n * @param opts - Storage directory (must be absolute) and session id.\n */\nexport function resolveLegacyPersistDir(opts: { userDir: string, sessionId: string }): string | undefined {\n if (!isAbsolute(opts.userDir))\n throw new Error(`resolveLegacyPersistDir: userDir must be absolute, got \"${opts.userDir}\"`)\n return LEGACY_SESSION_ID.test(opts.sessionId) ? join(opts.userDir, 'tool-results', opts.sessionId) : undefined\n}\n\n/** Outcome of one {@link migrateSessionArtifactDirs} sweep. */\nexport interface SessionArtifactDirMigration {\n /** Artifact dirs relocated into their session subtree. */\n moved: number\n /** Emptied source shells removed (pre-6.x `<sessionId>/`, kind-first roots). */\n removed: number\n /** Relocations that failed (rename raced, permissions, target existed). */\n failed: number\n}\n\n/**\n * Fold older artifact layouts into the session-first one\n * (`<userDir>/sessions/<sessionId>/<kind>/`).\n *\n * Two source layouts are folded in:\n *\n * 1. pre-6.x `<userDir>/<sessionId>/{tasks,mcp-warnings}/` — one top-level\n * entry per session, so a few hundred sessions bury `credentials.json`\n * under noise. This is what is actually on users' disks.\n * 2. kind-first `<userDir>/{tasks,mcp-warnings}/<sessionId>/` — a shape that\n * only ever existed in dev builds between the two designs. Handled so a\n * contributor who ran one doesn't end up with artifacts in three places.\n *\n * `tool-results/<sessionId>/` is deliberately NOT a source: those blobs are\n * referenced by absolute path from inside session transcripts and re-read by\n * the model, so relocating them without rewriting every transcript would\n * strand them. See {@link resolvePersistDir} and {@link resolveLegacyPersistDir}.\n *\n * Sync + best-effort by design. It runs on the chat bootstrap path, so it\n * must not make startup fail on a read-only or half-permissioned storage\n * dir; every filesystem call is individually guarded and failures are\n * counted, not thrown. `renameSync` within one directory tree can't hit\n * EXDEV, so the moves are atomic metadata updates, not copies.\n *\n * Idempotent and cheap to re-run: one `readdirSync` of the user dir, plus one\n * of each kind-first root that still exists. A migrated tree has no sources\n * left to match, so there's no \"migration done\" marker to keep in sync — the\n * filesystem shape IS the marker.\n *\n * Conflicts are left alone: if the destination already exists, the source\n * stays put and counts as `failed` rather than having its contents merged or\n * clobbered. Nothing is ever deleted except an emptied source shell\n * (`rmdirSync`, which refuses non-empty dirs), so an unexpected layout\n * survives for the operator to inspect.\n *\n * Note that a pending conflict is re-counted on EVERY sweep: nothing but\n * session-delete can resolve it (both copies are live data), so each boot\n * legitimately re-observes it and reports `failed: 1`. The effects stay\n * idempotent — nothing moves, nothing is removed — only the counter repeats.\n *\n * Known mixed-version race, accepted: a still-running pre-migration process\n * holds its tasksDir at the old path and this sweep renames it away. Open\n * write streams keep working (the inode moves with the rename), but log paths\n * already quoted in that session's turns go stale, and the old process's\n * defensive mkdir may recreate the source dir — which the next boot\n * re-migrates. Task logs are ephemeral debug output, so a liveness heuristic\n * isn't worth the complexity.\n *\n * @param opts - Storage directory (must be absolute) to scan for older artifact layouts.\n */\nexport function migrateSessionArtifactDirs(opts: { userDir: string }): SessionArtifactDirMigration {\n if (!isAbsolute(opts.userDir))\n throw new Error(`migrateSessionArtifactDirs: userDir must be absolute, got \"${opts.userDir}\"`)\n\n const result: SessionArtifactDirMigration = { moved: 0, removed: 0, failed: 0 }\n let entries: Dirent[]\n try {\n entries = readdirSync(opts.userDir, { withFileTypes: true })\n }\n catch {\n // Storage dir doesn't exist yet (first run) or isn't readable — nothing\n // to migrate either way.\n return result\n }\n\n /** Move one artifact dir into the session subtree. Never clobbers. */\n const relocate = (from: string, sessionId: string, kind: string): boolean => {\n if (!isDirectory(from))\n return false\n const to = join(opts.userDir, SESSIONS_ROOT, sessionId, kind)\n if (existsSync(to)) {\n result.failed++\n return false\n }\n try {\n mkdirSync(dirname(to), { recursive: true })\n renameSync(from, to)\n result.moved++\n return true\n }\n catch (err) {\n result.failed++\n if (process.env.ZIDANE_DEBUG)\n process.stderr.write(`[zidane] session-dir migration: \"${from}\" → \"${to}\" failed: ${errorMessage(err)}\\n`)\n return false\n }\n }\n\n // --- Layout 1: pre-6.x per-session shells ---------------------------------\n for (const entry of entries) {\n if (!entry.isDirectory() || ARTIFACT_ROOTS.has(entry.name) || !LEGACY_SESSION_ID.test(entry.name))\n continue\n const legacyDir = join(opts.userDir, entry.name)\n let movedHere = 0\n for (const kind of SESSION_ARTIFACT_KINDS) {\n if (relocate(join(legacyDir, kind), entry.name, kind))\n movedHere++\n }\n // Reap the shell only if THIS sweep emptied it. Gating on `movedHere`\n // matters: an unconditional rmdir would also delete unrelated empty\n // top-level dirs (an `extensions/` or `logs/` the user hasn't populated\n // yet) since rmdirSync succeeds on any empty dir. A source dir holding\n // anything else (unknown artifact, conflict left behind) also stays.\n if (movedHere === 0)\n continue\n try {\n rmdirSync(legacyDir)\n result.removed++\n }\n catch {}\n }\n\n // --- Layout 2: kind-first roots (dev builds only) -------------------------\n // `tool-results` is excluded here as well as above: it is the one kind whose\n // old location stays authoritative.\n for (const kind of ['tasks', 'mcp-warnings'] as const) {\n const root = join(opts.userDir, kind)\n let children: Dirent[]\n try {\n children = readdirSync(root, { withFileTypes: true })\n }\n catch {\n continue\n }\n let movedFromRoot = 0\n for (const child of children) {\n if (!child.isDirectory() || !LEGACY_SESSION_ID.test(child.name))\n continue\n if (relocate(join(root, child.name), child.name, kind))\n movedFromRoot++\n }\n // Reap only a root THIS sweep emptied, mirroring the `movedHere` gate on\n // the pre-6.x shells above: rmdirSync succeeds on any empty dir, so an\n // unconditional reap would delete a pre-existing empty `tasks/` the sweep\n // never touched. The rmdir itself only succeeds once every child moved\n // out — a leftover conflict keeps the root alive for inspection.\n if (movedFromRoot === 0)\n continue\n try {\n rmdirSync(root)\n result.removed++\n }\n catch {}\n }\n\n return result\n}\n\nfunction isDirectory(path: string): boolean {\n try {\n return statSync(path).isDirectory()\n }\n catch {\n return false\n }\n}\n\n/**\n * Inputs to {@link maybePersistToolResult}. Kept as a struct so the loop's\n * call site stays readable and additional optional knobs (compression,\n * mime detection, …) land without re-threading every call site.\n */\nexport interface PersistInput {\n /** Canonical tool name — checked against `excludeTools`. */\n toolName: string\n /** `tool_use` id from the assistant turn. Used as the filename. */\n callId: string\n /** Result returned by the tool (post-`tool:transform`). */\n output: string | ToolResultContent[]\n /** Byte threshold; outputs at or below stay inline. */\n threshold: number\n /** Canonical tool names that bypass persistence. */\n excludeTools?: readonly string[]\n /** Persistence root directory. Created on first write. */\n persistDir: string\n /**\n * Optional cap on the total bytes of persisted blobs under `persistDir`.\n * When set (and > 0), after a successful write the helper sweeps the\n * directory and removes the oldest `*.txt` blobs (by mtime) until the\n * sum of remaining sizes is at or below the cap.\n *\n * Bound to the **current session** because `persistDir` is per-session\n * (see {@link resolvePersistDir}); eviction never crosses session\n * boundaries. The new blob is always preserved — its mtime is the\n * latest, so the LRU sort guarantees older blobs go first.\n *\n * Skipped when the value isn't a positive finite number. Also skipped when\n * {@link writeBlob} is supplied: without remote stat/delete primitives, a\n * local host sweep would inspect the wrong filesystem. Remote contexts rely\n * on their own ephemeral teardown / storage quotas instead. Eviction failures\n * (permissions, races) are surfaced through `ZIDANE_DEBUG` but never block\n * the calling tool result; an over-cap dir is a housekeeping concern, not a\n * correctness one.\n */\n maxBytes?: number\n /**\n * Optional writer that routes the blob through a specific filesystem. The\n * agent loop passes `(path, content) => ctx.execution.writeFile(handle, …)`\n * so the persisted blob lands on the SAME filesystem the model reads it back\n * from (`read_file` → `ctx.execution.readFile`) — correct for docker /\n * sandbox / remote / edge contexts, not only the host process.\n *\n * Omitted → falls back to a local atomic write (`<path>.tmp` + rename) on the\n * host `fs`. A routed write is not atomic, which is\n * immaterial here: the blob is written once and fully awaited BEFORE the stub\n * that references it is emitted, so a crash mid-write loses both halves\n * consistently — there is no torn-read window for a subsequent turn.\n */\n writeBlob?: (path: string, content: string) => Promise<void>\n /**\n * Write errors to rethrow instead of degrading to a stub: the loop passes\n * its durable runtime's `isControlError`, so a control error\n * (cancellation, suspension) from a routed write leaves the run as itself.\n */\n shouldRethrowError?: (err: unknown) => boolean\n}\n\n/** Result of {@link maybePersistToolResult}: a skip with its reason, a persisted blob with its stub, or a write failure. */\nexport type PersistOutcome\n = | { kind: 'skip', reason: 'disabled' | 'excluded' | 'under-threshold' | 'unsupported-shape' | 'unsafe-call-id' | 'invalid-persist-dir' }\n | { kind: 'persisted', output: string, originalBytes: number, persistedPath: string, evicted?: { files: number, bytes: number } }\n | { kind: 'error', reason: 'write-failed', error: Error, output: string, originalBytes: number }\n\n/**\n * Whether {@link maybePersistToolResult} would save `output` to disk with these\n * settings: persistence on, the tool not excluded, a text result over the\n * threshold. For hooks that shape a result before the loop sees it, and need\n * what they add to survive into the preview.\n *\n * @param input - Tool name, output and persistence settings, as the loop passes them.\n */\nexport function willPersistToolResult(input: {\n toolName: string\n output: string | ToolResultContent[]\n threshold?: number | undefined\n persistDir?: string | undefined\n excludeTools?: readonly string[] | undefined\n}): boolean {\n if (!input.threshold || input.threshold <= 0 || !input.persistDir || !isAbsolute(input.persistDir))\n return false\n if (input.excludeTools?.includes(input.toolName))\n return false\n const text = textForPersistence(input.output)\n return text !== null && toolOutputByteLength(text) > input.threshold\n}\n\n/**\n * Decide-and-persist for a single tool result. Pure decision + filesystem\n * side-effect; returns the new wire-level `output` string when substitution\n * happened, otherwise tells the caller to leave the result alone.\n *\n * Atomicity: the local fallback writes through `<path>.tmp` + `rename` so a\n * concurrent read (or a crash mid-write) never sees a half-written blob. A\n * routed write (`input.writeBlob`, e.g. a sandbox `writeFile`) is not atomic;\n * see the field doc for why that's safe here.\n *\n * Text-only `ToolResultContent[]` results are flattened and persisted as\n * text. Mixed structured content still bypasses persistence because the inline\n * image/document bytes are the point of the call and a mixed result is not\n * representable as a single `.txt` file without dropping media.\n *\n * @param input - Tool name, call id, output and persistence settings.\n */\nexport async function maybePersistToolResult(input: PersistInput): Promise<PersistOutcome> {\n if (!input.threshold || input.threshold <= 0)\n return { kind: 'skip', reason: 'disabled' }\n\n if (input.excludeTools?.includes(input.toolName))\n return { kind: 'skip', reason: 'excluded' }\n\n const persistableOutput = textForPersistence(input.output)\n if (persistableOutput === null)\n return { kind: 'skip', reason: 'unsupported-shape' }\n\n // Defense in depth — the chat layer always passes the absolute path\n // produced by `resolvePersistDir`, but a direct SDK consumer could pass\n // a relative path that would resolve against cwd in unexpected ways. We\n // refuse rather than create surprise files outside the intended dir.\n if (!isAbsolute(input.persistDir))\n return { kind: 'skip', reason: 'invalid-persist-dir' }\n\n // Path-traversal guard. The `callId` becomes a filename under\n // `persistDir`; an id containing `/`, `\\`, `..`, or control chars could\n // escape the dir (`../../etc/passwd.txt`) or land in subdirectories the\n // operator didn't anticipate. Real providers (Anthropic `toolu_…`,\n // OpenAI `call_…`, UUIDs) all pass the strict regex; rejecting the rest\n // is purely defensive and never bites legitimate traffic.\n if (!SAFE_CALL_ID.test(input.callId) || input.callId.includes('..'))\n return { kind: 'skip', reason: 'unsafe-call-id' }\n\n const originalBytes = toolOutputByteLength(persistableOutput)\n if (originalBytes <= input.threshold)\n return { kind: 'skip', reason: 'under-threshold' }\n\n const persistedPath = join(input.persistDir, `${input.callId}.txt`)\n try {\n await (input.writeBlob ?? writeAtomic)(persistedPath, persistableOutput)\n }\n catch (err) {\n if (input.shouldRethrowError?.(err))\n throw err\n const error = err instanceof Error ? err : new Error(String(err))\n return {\n kind: 'error',\n reason: 'write-failed',\n error,\n originalBytes,\n output: buildPersistenceUnavailableStub({\n toolName: input.toolName,\n originalBytes,\n output: persistableOutput,\n error,\n }),\n }\n }\n\n const stub = buildPersistedStub({\n toolName: input.toolName,\n originalBytes,\n persistedPath,\n output: persistableOutput,\n })\n\n // LRU enforcement runs AFTER the write so the new blob participates in\n // the sweep (and, being newest by mtime, is never evicted itself unless\n // the cap is so tight a single blob can't fit). Best-effort: a failed\n // unlink is logged under `ZIDANE_DEBUG` but never propagates — the\n // caller already has its tool result; an over-cap dir is housekeeping.\n let evicted: { files: number, bytes: number } | undefined\n if (!input.writeBlob && typeof input.maxBytes === 'number' && Number.isFinite(input.maxBytes) && input.maxBytes > 0) {\n evicted = await enforcePersistDirCap(input.persistDir, input.maxBytes)\n }\n\n return { kind: 'persisted', output: stub, originalBytes, persistedPath, ...(evicted && evicted.files > 0 ? { evicted } : {}) }\n}\n\n/**\n * Blobs younger than this are never evicted by {@link enforcePersistDirCap}\n * (override via its `graceMs` option). The \"preserve newest\" guard only\n * protects the single newest blob — when two tool calls in the same batch\n * both persist, the second writer's sweep would otherwise evict the first\n * writer's blob milliseconds after the stub referencing it was emitted.\n * A short mtime grace window protects all in-flight siblings; the cap is a\n * soft housekeeping bound, so temporarily exceeding it is acceptable.\n */\nexport const PERSIST_EVICTION_GRACE_MS = 15_000\n\n/**\n * Enforce a byte-cap on a persist directory by removing oldest `*.txt`\n * blobs (by mtime) until the remaining total is at or below `maxBytes`.\n *\n * Exported for tests + for hosts that want to run a periodic sweep\n * decoupled from the per-call hook. {@link maybePersistToolResult} calls\n * this automatically when `maxBytes` is set on its input, so production\n * callers usually don't invoke it directly.\n *\n * Failure modes:\n *\n * - `persistDir` missing → no-op (nothing to evict).\n * - `readdir` / `stat` errors → swallowed (best-effort); returns\n * `{ files: 0, bytes: 0 }`.\n * - Individual `unlink` failures → counted in the result only if they\n * succeeded; the loop continues to the next candidate so a single\n * permission blip doesn't abort the whole sweep.\n *\n * The mtime-asc sort is stable enough for our purposes: two blobs\n * written in the same millisecond are evicted in `readdir` order, which\n * is filesystem-dependent but consistent within a run. We never need\n * strict total ordering — the LRU is a soft cap, not a transactional\n * guarantee. Blobs newer than `graceMs` (default\n * {@link PERSIST_EVICTION_GRACE_MS}) are skipped entirely — see the\n * constant's doc for the same-batch-writer race this prevents.\n */\nexport async function enforcePersistDirCap(\n persistDir: string,\n maxBytes: number,\n opts: { graceMs?: number } = {},\n): Promise<{ files: number, bytes: number }> {\n if (!isAbsolute(persistDir) || !Number.isFinite(maxBytes) || maxBytes <= 0)\n return { files: 0, bytes: 0 }\n\n let entries: string[]\n try {\n entries = await readdir(persistDir)\n }\n catch {\n // Directory doesn't exist (no blobs persisted yet) or unreadable.\n // Either way: nothing to do.\n return { files: 0, bytes: 0 }\n }\n\n // `.txt` extension is the canonical shape produced by `maybePersistToolResult`.\n // Filter on it so a stray `.tmp` (crash residue) or a manually-dropped\n // sentinel file doesn't get counted toward the budget or accidentally\n // evicted.\n const txtFiles = entries.filter(name => name.endsWith('.txt'))\n\n interface FileMeta { path: string, size: number, mtime: number }\n const metas: FileMeta[] = []\n for (const name of txtFiles) {\n const path = join(persistDir, name)\n try {\n const s = await stat(path)\n if (!s.isFile())\n continue\n metas.push({ path, size: s.size, mtime: s.mtimeMs })\n }\n catch {\n // Race: file vanished between readdir and stat. Skip silently.\n }\n }\n\n const totalBytes = metas.reduce((sum, m) => sum + m.size, 0)\n if (totalBytes <= maxBytes)\n return { files: 0, bytes: 0 }\n\n // Oldest first. Keep evicting until we're under cap OR we're about to\n // touch the newest blob — that one represents the just-written result\n // the caller needs to be able to point the model at, so we preserve it\n // even if its size alone exceeds the cap. That edge case surfaces as a\n // cap exceedance in the logs; the operator's right next move is\n // raising `persistMaxBytes`.\n //\n // The \"preserve newest\" guard runs off the loop INDEX rather than the\n // successful-eviction counter: an unlink failure earlier in the sweep\n // (file vanished mid-readdir, permissions blip) must NOT shift the\n // safety boundary forward. Were we to use `evictedFiles === metas.length - 1`\n // and the very first unlink failed, we'd walk all the way to the\n // newest blob and try to evict it.\n metas.sort((a, b) => a.mtime - b.mtime)\n const graceMs = opts.graceMs ?? PERSIST_EVICTION_GRACE_MS\n const evictableBefore = Date.now() - graceMs\n let running = totalBytes\n let evictedFiles = 0\n let evictedBytes = 0\n for (let i = 0; i < metas.length; i++) {\n if (running <= maxBytes)\n break\n if (i === metas.length - 1)\n break\n const meta = metas[i]!\n // Within the grace window — and the list is mtime-ascending, so every\n // later candidate is too. Stop the sweep; the cap is soft.\n if (graceMs > 0 && meta.mtime > evictableBefore)\n break\n try {\n await unlink(meta.path)\n running -= meta.size\n evictedFiles += 1\n evictedBytes += meta.size\n }\n catch (err) {\n if (process.env.ZIDANE_DEBUG)\n process.stderr.write(`[zidane/persistence] evict \"${meta.path}\" failed: ${errorMessage(err)}\\n`)\n }\n }\n\n return { files: evictedFiles, bytes: evictedBytes }\n}\n\ninterface BuildStubInput {\n toolName: string\n originalBytes: number\n persistedPath: string\n output: string\n /** Preview cap in bytes. Default {@link PERSISTENCE_PREVIEW_BYTES}. */\n previewBytes?: number\n}\n\n/**\n * Render the byte-stable `<persisted-output>` stub the model sees in place\n * of the original `tool_result`.\n *\n * Format choices:\n * - XML wrapper because models reliably parse it as structural.\n * - Byte count + path in attributes so the model can decide whether to\n * `read_file` the persisted blob without scanning the preview.\n * - Preview always shows the head — how `shell` cuts its own output is\n * irrelevant here because the model has the full path if it needs the\n * tail.\n * - No timestamps, no random UUIDs inside the stub: every byte must be\n * reproducible from the inputs, otherwise re-emission on subsequent\n * turns would bust the prompt cache.\n *\n * Exported for tests (asserting the byte-stable contract) and for SDK\n * consumers wiring their own persistence middleware against the same\n * surface.\n *\n * @param input - Tool name, original size, persisted path and the output to preview.\n */\nexport function buildPersistedStub(input: BuildStubInput): string {\n const { slice: previewSlice, bytes: previewBytes } = headSlice(input.output, input.previewBytes ?? PERSISTENCE_PREVIEW_BYTES)\n const truncated = previewSlice.length < input.output.length\n const previewMarker = truncated\n ? `\\n…(${input.originalBytes - previewBytes} more bytes in persisted file)`\n : ''\n // Open tag built from PERSISTED_STUB_PREFIX so the stub-detection constant\n // and the stub emitter share one source of truth — changing the format\n // requires updating one place and downstream recognizers can't drift.\n return [\n `${PERSISTED_STUB_PREFIX}${escapeXml(input.toolName)}\" bytes=\"${input.originalBytes}\" path=\"${escapeXml(input.persistedPath)}\">`,\n `${previewSlice}${previewMarker}`,\n '</persisted-output>',\n ].join('\\n')\n}\n\n/**\n * Render a bounded fallback when persistence was enabled but the blob write\n * failed. The full output is intentionally NOT kept inline: when this path\n * fires, preserving the context-window guarantee is more important than\n * recoverability of a failed best-effort spill.\n */\nfunction buildPersistenceUnavailableStub(input: {\n toolName: string\n originalBytes: number\n output: string\n error: Error\n}): string {\n const { slice: previewSlice, bytes: previewBytes } = headSlice(input.output, PERSISTENCE_PREVIEW_BYTES)\n const previewMarker = previewSlice.length < input.output.length\n ? `\\n…(${input.originalBytes - previewBytes} more bytes omitted because persistence failed)`\n : ''\n // Cap the error message so the stub stays bounded even if a sandbox / FS\n // surfaces a pathologically long failure — the whole point of this path is\n // to NOT let large content ride inline.\n const reason = input.error.message.length > MAX_PERSIST_ERROR_CHARS\n ? `${input.error.message.slice(0, MAX_PERSIST_ERROR_CHARS)}…`\n : input.error.message\n return [\n `<persisted-output-unavailable tool=\"${escapeXml(input.toolName)}\" bytes=\"${input.originalBytes}\" reason=\"write-failed\">`,\n `Full output could not be saved to disk, so it was omitted from inline context. Error: ${escapeXml(reason)}`,\n '',\n 'Preview:',\n `${previewSlice}${previewMarker}`,\n '</persisted-output-unavailable>',\n ].join('\\n')\n}\n\n/**\n * Remove every persisted blob belonging to a session. Called by the chat\n * layer from its session-delete path so closing a session frees the disk\n * footprint alongside the SQLite row.\n *\n * Idempotent — missing directory (session never persisted anything) is a\n * no-op, not an error. Wraps the `rm -rf` so a permissions blip on one\n * blob doesn't propagate to the caller; the chat layer can't usefully\n * recover from \"couldn't unlink a result file\" mid-delete.\n *\n * @param persistRoot - Absolute directory that holds the session's persisted blobs.\n */\nexport async function cleanupPersistedSession(persistRoot: string): Promise<void> {\n if (!isAbsolute(persistRoot))\n throw new Error(`cleanupPersistedSession: persistRoot must be absolute, got \"${persistRoot}\"`)\n try {\n await rm(persistRoot, { recursive: true, force: true })\n }\n catch (err) {\n // Surface under ZIDANE_DEBUG; never throw. A leaked blob dir is\n // harmless (it can be `rm -rf`'d manually) — propagating the error\n // would block the SessionStore.delete() path the user is awaiting.\n if (process.env.ZIDANE_DEBUG)\n process.stderr.write(`[zidane/persistence] cleanup \"${persistRoot}\" failed: ${errorMessage(err)}\\n`)\n }\n}\n\n/**\n * Persist-on-elide: belatedly write tool results that tail compaction is\n * about to replace with the lossy `[…elided…]` stub, swapping in a\n * recoverable `<persisted-output … path=…>` stub instead. This is the lazy\n * counterpart to {@link maybePersistToolResult}'s eager (emit-time)\n * persistence — it only fires when a result is actually being compacted out,\n * so recent results stay full inline while OLD ones become recoverable rather\n * than destroyed. Closes the context-loss gap for non-read results between\n * the lossy stub and re-runnable side effects: after this, a compacted result\n * is always retrievable by `read_file`-ing its path.\n *\n * `items` are the {@link TailCompactionResult.persistableElided} entries (the\n * caller has already filtered out reads — which recover via the read-state\n * dedup re-serve — and results too small to be worth persisting). Each\n * `output` is the ORIGINAL content captured before the lossy stub replaced it.\n *\n * Idempotency: local blobs are immutable (a tool result never changes), so we\n * write `<callId>.txt` only when it's absent and otherwise just rebuild the\n * byte-stable stub. With `opts.writeBlob`, existence cannot be checked through\n * the current `ExecutionContext` interface (no remote stat), so we write the\n * same content to the same path again; this is safe and preserves correctness.\n * The session keeps the original content; only the wire copy carries the stub —\n * consistent with compaction being wire-only. Returns the messages with the\n * lossy stubs swapped; unchanged when nothing was persisted.\n */\nexport async function persistElidedToolResults(\n messages: SessionMessage[],\n items: ReadonlyArray<{ callId: string, toolName: string, output: string }>,\n opts: { persistDir: string, maxBytes?: number, writeBlob?: (path: string, content: string) => Promise<void>, shouldRethrowError?: (err: unknown) => boolean },\n): Promise<SessionMessage[]> {\n if (items.length === 0 || !isAbsolute(opts.persistDir))\n return messages\n\n const stubByCallId = new Map<string, string>()\n let wroteAny = false\n for (const item of items) {\n // Same path-traversal guard as maybePersistToolResult — a hostile or\n // malformed callId must not escape persistDir.\n if (!SAFE_CALL_ID.test(item.callId) || item.callId.includes('..'))\n continue\n const persistedPath = join(opts.persistDir, `${item.callId}.txt`)\n let exists = false\n if (!opts.writeBlob) {\n try {\n exists = (await stat(persistedPath)).isFile()\n }\n catch {\n exists = false\n }\n }\n if (!exists) {\n try {\n await (opts.writeBlob ?? writeAtomic)(persistedPath, item.output)\n wroteAny = true\n }\n catch (err) {\n if (opts.shouldRethrowError?.(err))\n throw err\n // Write failed — leave the lossy stub in place rather than emit a\n // recoverable stub pointing at a blob that isn't on disk.\n continue\n }\n }\n stubByCallId.set(item.callId, buildPersistedStub({\n toolName: item.toolName,\n originalBytes: toolOutputByteLength(item.output),\n persistedPath,\n output: item.output,\n previewBytes: ELIDE_PERSIST_PREVIEW_BYTES,\n }))\n }\n\n // LRU sweep only after a real LOCAL write, mirroring maybePersistToolResult.\n // Routed writes target the execution context's filesystem; a local sweep\n // would inspect/delete the wrong directory.\n if (!opts.writeBlob && wroteAny && typeof opts.maxBytes === 'number' && Number.isFinite(opts.maxBytes) && opts.maxBytes > 0)\n await enforcePersistDirCap(opts.persistDir, opts.maxBytes)\n\n if (stubByCallId.size === 0)\n return messages\n\n return messages.map((msg) => {\n if (!msg.content.some(b => b.type === 'tool_result' && stubByCallId.has(b.callId)))\n return msg\n return {\n ...msg,\n content: msg.content.map(b =>\n b.type === 'tool_result' && stubByCallId.has(b.callId)\n ? { ...b, output: stubByCallId.get(b.callId)! }\n : b,\n ),\n }\n })\n}\n\n/**\n * Subdirectory of the session persist dir holding blobs written by\n * {@link releaseReplacedTurnContent}. Deliberately separate from the\n * top-level `<callId>.txt` blobs: once a released stub round-trips into the\n * session store (`session.save()` is delete-all-and-reinsert), the blob is\n * the ONLY remaining copy of that content — it must never be LRU-evicted by\n * {@link enforcePersistDirCap}, whose sweep only scans top-level `*.txt`\n * files. Released blobs live and die with the session\n * ({@link cleanupPersistedSession} removes the dir recursively).\n */\nexport const RELEASED_BLOB_SUBDIR = 'released'\n\n/**\n * Disk backstop for the cap-exempt `released/` dir. Released blobs must\n * never be LRU-evicted (each is the only durable copy of its content), so\n * the only safe pressure valve is to STOP RELEASING once the dir is full:\n * further compactions keep their originals in memory instead. 256 MiB of\n * released blobs corresponds to a months-long, heavily compacted session\n * — at that point bounded disk beats bounded RAM.\n */\nexport const RELEASED_DIR_MAX_BYTES = 256 * 1024 * 1024\n\n/**\n * Post-compaction memory release — swap the in-memory bodies of turns a\n * compaction summary just replaced for recoverable `<persisted-output …>`\n * stubs, so a long-lived host process stops retaining tool output the model\n * can never see again (`applyCompactSummaryCutoff` elides these turns from\n * every future wire projection).\n *\n * MUTATES the passed turn objects in place — that is the point: the session's\n * `data.turns` is the single canonical in-memory copy, and releasing anywhere\n * else would leave it pinned. Only `tool_result` blocks with large string /\n * all-text outputs are touched (media already lives behind content refs);\n * everything else — prompts, assistant text, thinking — is kept verbatim.\n *\n * Durability contract: each released output is written to\n * `<persistDir>/released/<callId>.txt` first, so even if a host later\n * round-trips the stubbed turns to the session store, the content stays\n * retrievable from the stub's path. Blobs are always written HOST-side\n * (never through an execution context): the session store is host-local,\n * so its recovery copy must be too — a sandboxed context write would\n * strand the only durable copy inside an ephemeral container. A blob write\n * failure skips that block — the original stays in memory rather than\n * being lost.\n *\n * Opt-in via `autoCompact.releaseReplacedTurns`: hosts that need the lossless\n * inline transcript (SFT capture, exporters) keep the default-off behavior.\n */\nexport async function releaseReplacedTurnContent(\n turns: ReadonlyArray<{ id?: string, content: SessionContentBlock[] }>,\n replacedTurnIds: ReadonlySet<string>,\n opts: { persistDir: string, minBytes?: number, maxDirBytes?: number },\n): Promise<{ releasedBlocks: number, releasedBytes: number }> {\n const result = { releasedBlocks: 0, releasedBytes: 0 }\n if (replacedTurnIds.size === 0 || !isAbsolute(opts.persistDir))\n return result\n const minBytes = opts.minBytes ?? PERSISTENCE_PREVIEW_BYTES\n const maxDirBytes = opts.maxDirBytes ?? RELEASED_DIR_MAX_BYTES\n const blobDir = join(opts.persistDir, RELEASED_BLOB_SUBDIR)\n\n // Budget check up front (see {@link RELEASED_DIR_MAX_BYTES}): released\n // blobs are cap-exempt by design, so this walk is the only bound on the\n // dir. Compactions are rare (a few per session per day) and the dir\n // holds only this session's released blobs, so the stat walk is cheap.\n let dirBytes = 0\n try {\n for (const entry of await readdir(blobDir)) {\n try {\n dirBytes += (await stat(join(blobDir, entry))).size\n }\n catch {\n // raced deletion — skip\n }\n }\n }\n catch {\n // dir does not exist yet — zero usage\n }\n\n const replaced = turns.filter(t => t.id !== undefined && replacedTurnIds.has(t.id))\n\n // callId → tool name, resolved from the replaced region itself — a\n // summary always absorbs whole call/result pairs, so the matching\n // tool_call lives in a replaced assistant turn.\n const toolNameByCallId = new Map<string, string>()\n for (const turn of replaced) {\n for (const block of turn.content) {\n if (block.type === 'tool_call')\n toolNameByCallId.set(block.id, block.name)\n }\n }\n\n // Duplicate call ids DO occur in real sessions (that's why the wire path\n // has `remintDuplicateToolCallIds`) — without disambiguation the second\n // occurrence's exists-check would find the first occurrence's blob and\n // stub it with the WRONG content. The ordinal counts every tool_result\n // occurrence POSITIONALLY (before any skip guard), so numbering stays\n // stable across a crashed-and-rerun release where earlier occurrences\n // are already stubs.\n const callIdOccurrences = new Map<string, number>()\n for (const turn of replaced) {\n for (let i = 0; i < turn.content.length; i++) {\n const block = turn.content[i]\n if (block.type !== 'tool_result')\n continue\n const ordinal = (callIdOccurrences.get(block.callId) ?? 0) + 1\n callIdOccurrences.set(block.callId, ordinal)\n const text = textForPersistence(block.output)\n if (text === null || text.startsWith(PERSISTED_STUB_PREFIX))\n continue\n const bytes = utf8ByteLength(text)\n if (bytes < minBytes)\n continue\n if (!SAFE_CALL_ID.test(block.callId) || block.callId.includes('..'))\n continue\n const persistedPath = join(blobDir, ordinal === 1 ? `${block.callId}.txt` : `${block.callId}.${ordinal}.txt`)\n // Same idempotency posture as persistElidedToolResults: blobs are\n // immutable, so skip the write when the file already exists.\n let exists = false\n try {\n exists = (await stat(persistedPath)).isFile()\n }\n catch {\n exists = false\n }\n if (!exists) {\n // Refuse to release past the budget — the original stays in memory\n // (bounded disk beats bounded RAM at this scale, and eviction is\n // not an option: the blob would be the only durable copy).\n if (dirBytes + bytes > maxDirBytes)\n continue\n try {\n await writeAtomic(persistedPath, text)\n dirBytes += bytes\n }\n catch {\n continue\n }\n }\n turn.content[i] = {\n ...block,\n output: buildPersistedStub({\n toolName: toolNameByCallId.get(block.callId) ?? 'tool',\n originalBytes: bytes,\n persistedPath,\n output: text,\n previewBytes: ELIDE_PERSIST_PREVIEW_BYTES,\n }),\n }\n result.releasedBlocks++\n result.releasedBytes += bytes\n }\n }\n\n return result\n}\n\n/**\n * Re-home `<persisted-output …>` stubs when turns are copied into a NEW\n * session (fork): released blob paths are per-session\n * (`resolvePersistDir` keys on the session id), so a fork that keeps the\n * origin's paths loses its content the moment the origin session is\n * deleted ({@link cleanupPersistedSession} removes the origin's blob dir).\n * Copies each referenced blob under `fromPersistDir` into the same\n * relative location under `toPersistDir` and rewrites the stub's `path`\n * attribute. Copy-on-write: input turns are never mutated (they are\n * usually shared with the origin session's live `data.turns`); a new turn\n * object is returned only where a stub was rewritten. A missing/uncopyable\n * blob leaves that stub pointing at the origin — no worse than before.\n *\n * Prefix matching happens on the XML-escaped attribute text: `escapeXml`\n * maps characters independently, so `escapeXml(a + b)` ===\n * `escapeXml(a) + escapeXml(b)` and a prefix match on escaped text is\n * exact. Blob filenames are `SAFE_CALL_ID`-constrained (`[\\w.-]`), so the\n * relative remainder is escape-invariant.\n */\nexport async function rehomePersistedStubs<T extends { content: SessionContentBlock[] }>(\n turns: readonly T[],\n fromPersistDir: string,\n toPersistDir: string,\n): Promise<T[]> {\n if (!isAbsolute(fromPersistDir) || !isAbsolute(toPersistDir) || fromPersistDir === toPersistDir)\n return [...turns]\n const fromPrefix = `path=\"${escapeXml(fromPersistDir)}/`\n const out: T[] = []\n for (const turn of turns) {\n let content: SessionContentBlock[] | undefined\n for (let i = 0; i < turn.content.length; i++) {\n const block = turn.content[i]\n if (block.type !== 'tool_result' || typeof block.output !== 'string' || !block.output.startsWith(PERSISTED_STUB_PREFIX))\n continue\n const start = block.output.indexOf(fromPrefix)\n if (start === -1)\n continue\n const restStart = start + fromPrefix.length\n const end = block.output.indexOf('\"', restStart)\n if (end === -1)\n continue\n const relative = block.output.slice(restStart, end)\n if (relative.includes('..'))\n continue\n try {\n const target = join(toPersistDir, relative)\n await mkdir(dirname(target), { recursive: true })\n await copyFile(join(fromPersistDir, relative), target)\n }\n catch {\n continue\n }\n content ??= [...turn.content]\n content[i] = {\n ...block,\n output: `${block.output.slice(0, start)}path=\"${escapeXml(toPersistDir)}/${relative}${block.output.slice(end)}`,\n }\n }\n out.push(content ? { ...turn, content } : turn)\n }\n return out\n}\n\n// ---------------------------------------------------------------------------\n// Internal helpers\n// ---------------------------------------------------------------------------\n\n/**\n * Write-then-rename for atomicity — delegates to the shared\n * {@link writeFileAtomicAsync} helper (unique pid+counter tmp suffix,\n * fsync before rename, tmp cleanup on failure). Creates the parent\n * directory on demand so the caller doesn't have to track which\n * sessions have already initialized their dir.\n */\nasync function writeAtomic(path: string, content: string): Promise<void> {\n await writeFileAtomicAsync(path, content, { ensureDir: true })\n}\n\nfunction textForPersistence(output: string | ToolResultContent[]): string | null {\n if (typeof output === 'string')\n return output\n const parts: string[] = []\n for (const block of output) {\n if (block.type !== 'text')\n return null\n parts.push(block.text)\n }\n return parts.join('\\n')\n}\n","/**\n * History compaction transforms applied to the wire view each turn: the\n * `compact-summary` cutoff, tail compaction of older tool output, and media\n * age-out. All pure over the message list; `ctx.turns` is never rewritten.\n */\n\nimport type { LoopContext } from './loop-context'\nimport type { AgentBehavior, ModelTarget, SessionContentBlock, SessionMessage, SessionTurn, ToolResultContent } from './types'\nimport { Buffer } from 'node:buffer'\nimport { mediaAgeoutMarker, mediaPayloadBytes } from './attachment-handle'\nimport { BYTES_PER_TOKEN } from './compact'\nimport { PERSISTED_STUB_PREFIX } from './loop-persistence'\nimport { imageSizeFromBase64 } from './media/image-size'\nimport { hasAnthropicSignature } from './session/messages'\nimport { looksBinary } from './tools/binary-detect'\nimport { readFileInputPaths } from './tools/read-file-targets'\nimport { toolOutputBudgetByteLength, toolOutputByteLength } from './types'\n\n/**\n * Recover the auto-compaction hysteresis baseline from a resumed session.\n *\n * Scans backward for the newest `compact-summary` marker and returns the\n * summary call's OUTPUT tokens — the same quantity {@link maybeAutoCompact}\n * records as `lastCompactedInputTokens` after a live compaction (there the\n * value is `summary.output + restorationTokens`). The restoration portion\n * isn't persisted on the marker, so this seed UNDER-counts the true\n * post-compact size; that only weakens the cooldown slightly (it requires a\n * touch more growth before re-firing) and is strictly safer than\n * `undefined`, which would disable the cooldown entirely on every resume.\n *\n * Returns `undefined` when no marker exists (a never-compacted session) so\n * the first compaction still fires off the absolute threshold.\n */\nexport function seedCompactBaseline(turns: readonly SessionTurn[]): number | undefined {\n for (let i = turns.length - 1; i >= 0; i--) {\n const block = turns[i].content.find(b => b.type === 'compact-summary')\n if (block && block.type === 'compact-summary') {\n const output = block.usage.output\n return typeof output === 'number' && Number.isFinite(output) && output >= 0\n ? output\n : undefined\n }\n }\n return undefined\n}\n\n/**\n * Wire-level cutoff for {@link SessionContentBlock}'s `compact-summary`\n * markers.\n *\n * Elision is MONOTONE across every marker in the session: a turn whose\n * id appears in ANY marker's `replacesTurnIds` never reaches the wire\n * again — the summary that absorbed it stands in for it permanently.\n * (Honoring only the newest marker would resurrect the older marker's\n * replaced turns whenever a re-compaction failed to subsume it, e.g. after a\n * PTL head-drop. That showed up as a session re-compacting an unchanged\n * 866k-token wire on every turn.)\n *\n * Per marker:\n *\n * 1. A marker turn never passes through verbatim (providers don't\n * know the `compact-summary` block type).\n * 2. An ACTIVE marker — one not itself replaced by a newer marker —\n * renders as a synthesized plain user-text turn carrying its\n * summary, positioned at the slot of its **first replaced turn**\n * so the summary appears CHRONOLOGICALLY where the content it\n * summarizes used to live:\n * - older unreplaced turns (PTL head-drops) come first\n * - then the synthesized summary\n * - then later unreplaced turns (preserved tail + new prompts)\n * A marker with no surviving replaced slot (empty or dangling\n * `replacesTurnIds`) renders at its own chronological position.\n * 3. A SUBSUMED marker (its id is in a newer marker's replaced set —\n * i.e. its summary text fed the newer summary) contributes only\n * elision: its replaced turns stay gone, its text does not render.\n * 4. Every other turn passes through by reference, including turns\n * no marker replaced (PTL head-drops stay visible verbatim until\n * a later compaction absorbs them — the runner compacts the WIRE\n * view, so they are always at the head of the next scope).\n *\n * If no marker exists, the input array is returned unchanged.\n *\n * Note on role-alternation: when the marker is immediately followed by\n * a new user turn (the common case — user submits a prompt right after\n * compacting), the wire output ends in `[…, synthetic_user, new_user]`.\n * Anthropic folds adjacent same-role messages server-side; other\n * providers tolerate them via their own normalization passes. The\n * harness does NOT fold them here — keeping them separate preserves\n * the per-turn `turnId` tags that the TUI's select-turn mode relies on.\n *\n * Pure: a fresh array is returned only when a marker is found. Input\n * turns are never mutated. New `SessionTurn`s allocated: the synthetic\n * markers, plus a copy of every preserved assistant turn older than the\n * newest marker whose replayable thinking was stripped (see\n * {@link withoutReplayedThinking}). The output is WIRE-shaped, not\n * display-shaped: hosts rendering a transcript should read the session\n * turns, not this view.\n *\n * @param turns - Session turns in chronological order, including any `compact-summary` marker turns.\n */\nexport function applyCompactSummaryCutoff(turns: SessionTurn[]): SessionTurn[] {\n if (turns.length === 0)\n return turns\n\n interface MarkerInfo {\n idx: number\n turn: SessionTurn\n summary: string\n replaces: readonly string[]\n }\n const markers: MarkerInfo[] = []\n for (let i = 0; i < turns.length; i++) {\n const block = turns[i].content.find(b => b.type === 'compact-summary')\n if (block && block.type === 'compact-summary')\n markers.push({ idx: i, turn: turns[i], summary: block.summary, replaces: block.replacesTurnIds })\n }\n if (markers.length === 0)\n return turns\n\n // Monotone elision: the union of EVERY marker's replaced set. Once a\n // turn has been absorbed into any summary it never reaches the wire\n // again — even when the marker that absorbed it was itself replaced\n // by a newer one (the newer summary integrated the older's text).\n const replacedAll = new Set<string>()\n for (const m of markers) {\n for (const id of m.replaces)\n replacedAll.add(id)\n }\n\n // Anchor each ACTIVE marker's synthetic at its first replaced turn's\n // slot (chronological position of the content it stands in for);\n // fall back to the marker's own slot when nothing anchors it.\n const markerIdxSet = new Set(markers.map(m => m.idx))\n const syntheticAt = new Map<number, SessionTurn>()\n for (const m of markers) {\n if (replacedAll.has(m.turn.id))\n continue // subsumed — its text fed a newer summary; elision only\n const replaces = new Set(m.replaces)\n let anchor = m.idx\n for (let i = 0; i < turns.length; i++) {\n if (i !== m.idx && replaces.has(turns[i].id) && !syntheticAt.has(i)) {\n anchor = i\n break\n }\n }\n syntheticAt.set(anchor, {\n id: m.turn.id,\n role: 'user',\n content: [{ type: 'text', text: m.summary }],\n createdAt: m.turn.createdAt,\n ...(m.turn.runId ? { runId: m.turn.runId } : {}),\n })\n }\n\n // Every surviving turn older than the newest marker is a preserved tail:\n // it now sits behind a summary that was not there when the model produced\n // it. Anthropic's preserved-thinking check binds a `thinking` block to the\n // exact prefix it was produced under, so replaying those blocks behind the\n // rewritten prefix is an invalid request (400) or, with `drop_block`, a\n // server-side drop. Strip them here instead — removing a block is\n // allowed, keeping it next to a changed history is not. Turns AFTER the\n // newest marker were produced with the summary already in place and keep\n // their reasoning intact.\n //\n // The chain that was IN FLIGHT when the marker landed is exempt even though\n // it predates the marker. Autocompact fires at every turn boundary,\n // including mid tool loop, so the marker can land after a `tool_result`\n // while the assistant turn carrying the matching `tool_use` sits before it.\n // Anthropic requires that assistant turn to keep its thinking (\"a final\n // assistant message must start with a thinking block\" — an unrecoverable\n // 400 the scrub ladder deliberately never touches).\n //\n // The bound is a function of the marker's neighbourhood ONLY, never of the\n // current tail: the turns before the marker are frozen history, so the same\n // marker yields the same bound on every later request. A bound that tracked\n // the live chain (strip once the chain finishes) would rewrite that\n // assistant turn in place on the first prompt after the chain — a\n // full-suffix prompt-cache break plus a `prefix_binding_mismatch` drop for\n // every block produced after it, to remove blocks the API already drops\n // server-side, unbilled. Under `thinkingBinding: 'error'` a mid-loop\n // compaction therefore keeps 400ing on that chain's replayed blocks for the\n // rest of the session; `'error'` is the debugging mode, `drop_block` the\n // default, and the alternative is a deterministic rewrite for everyone.\n const newestMarkerIdx = markers[markers.length - 1].idx\n const stripBound = preservedChainStart(turns, newestMarkerIdx)\n\n const out: SessionTurn[] = []\n for (let i = 0; i < turns.length; i++) {\n const synthetic = syntheticAt.get(i)\n if (synthetic)\n out.push(synthetic)\n if (markerIdxSet.has(i))\n continue // marker turns never pass through verbatim\n if (replacedAll.has(turns[i].id))\n continue\n out.push(i < stripBound ? withoutReplayedThinking(turns[i]) : turns[i])\n }\n return out\n}\n\n/**\n * Strip bound for the preserved tail behind the marker at `markerIdx`: the\n * index below which pre-marker assistant turns lose their replayed thinking.\n *\n * Reads the turn immediately before the marker to tell whether a tool loop\n * was in flight when compaction fired. A `tool_result`-only user turn (or an\n * assistant turn still holding a `tool_call`) means the marker landed mid\n * loop: the bound retreats to that chain's start — the last user turn before\n * the marker carrying real, non-`tool_result` content (`compact-summary`\n * turns render as user text but are not prompts) — so the assistant turn\n * whose `tool_use` the loop is still answering keeps its thinking. Any other\n * neighbour (a text-only assistant answer, a bare prompt) means the run had\n * settled and everything before the marker is strippable. Depends only on\n * turns before the marker, so it is stable across later requests.\n */\nfunction preservedChainStart(turns: readonly SessionTurn[], markerIdx: number): number {\n const before = turns[markerIdx - 1]\n const midChain = before !== undefined && (\n (before.role === 'user' && before.content.length > 0 && before.content.every(block => block.type === 'tool_result'))\n || (before.role === 'assistant' && before.content.some(block => block.type === 'tool_call'))\n )\n if (!midChain)\n return markerIdx\n for (let i = markerIdx - 1; i >= 0; i--) {\n const turn = turns[i]\n if (turn.role !== 'user')\n continue\n if (turn.content.some(block => block.type === 'compact-summary'))\n continue\n if (turn.content.some(block => block.type !== 'tool_result'))\n return i\n }\n return markerIdx\n}\n\n/**\n * Copy of `turn` with prefix-bound reasoning removed: `redacted_thinking`,\n * and Anthropic-signed `thinking` (`hasAnthropicSignature`). OpenAI binds\n * its encrypted reasoning per item, not per prefix, and Google asks for its\n * thought signatures back as received, so both stay. Unsigned\n * thinking is left alone — it is what `reasoning_content`-style OpenAI-compat\n * providers (vLLM, DeepSeek, Arcee) echo back, and `toAnthropic` already\n * drops it on the Anthropic wire. Same predicate as the provider's\n * signature scrub. Returns the input object when nothing is removed so\n * identity-based callers see no churn. A reasoning-only turn keeps a\n * placeholder so the assistant message stays non-empty on the wire.\n */\nexport function withoutReplayedThinking<T extends { role: string, content: SessionContentBlock[] }>(turn: T): T {\n if (turn.role !== 'assistant')\n return turn\n const kept = turn.content.filter(block =>\n block.type !== 'redacted_thinking'\n && !hasAnthropicSignature(block),\n )\n if (kept.length === turn.content.length)\n return turn\n return {\n ...turn,\n content: kept.length > 0 ? kept : [{ type: 'text', text: '[historical reasoning omitted]' }],\n }\n}\n\n/** Text that replaces an older `tool_result` output elided by tail compaction. */\nconst COMPACTION_STUB = '[…elided: older tool output trimmed to fit the context budget.]'\n// UTF-8 size of the stub — `toolOutputByteLength` measures UTF-8 bytes, so\n// the \"already short enough\" comparison below must too ('…' is 3 UTF-8\n// bytes but 1 UTF-16 unit; `.length` would undercount the floor).\nconst COMPACTION_STUB_BYTES = toolOutputByteLength(COMPACTION_STUB)\n\n/**\n * Production quantization for every wire-transform frontier. Snapping a cutoff\n * to multiples of this many messages keeps the rewritten prefix byte-identical\n * for `COMPACT_CHUNK_TURNS` requests at a time, so the provider's prefix cache\n * breaks once per chunk instead of every turn. See `applyTailCompaction`'s\n * `chunkTurns` option for the cache-thrash this avoids.\n *\n * Shared by all three passes that rewrite the prefix — tail compaction,\n * media age-out, and stale-read elision — so their frontiers advance on the SAME\n * message boundary and a window costs one invalidation, not three. Exported so\n * host-behavior tests can assert their keep windows stay on this quantum.\n */\nexport const COMPACT_CHUNK_TURNS = 8\n\n/** Byte threshold tail compaction falls back to when `compactThreshold` is unset. */\nexport const DEFAULT_COMPACT_THRESHOLD_BYTES = 131_072\n\n/**\n * Effective byte threshold for client-side compaction (`'tail'` and the\n * `CompactFunction` path): the host's `compactThreshold` (default 128 KiB),\n * raised to `compactThresholdWindowFraction × contextWindow × BYTES_PER_TOKEN`\n * when both are known. Every frontier step re-bills the whole suffix at the\n * cache-write rate, so on large-context models the byte threshold alone\n * trips far too early; see `AgentBehavior.compactThresholdWindowFraction`.\n * Pure — exported for host-behavior tests.\n */\nexport function resolveTailCompactionThreshold(\n behavior: Pick<AgentBehavior, 'compactThreshold' | 'compactThresholdWindowFraction'>,\n contextWindow: number | null | undefined,\n): number {\n const base = typeof behavior.compactThreshold === 'number' && behavior.compactThreshold > 0\n ? behavior.compactThreshold\n : DEFAULT_COMPACT_THRESHOLD_BYTES\n const fraction = behavior.compactThresholdWindowFraction\n if (typeof fraction !== 'number' || !(fraction > 0) || typeof contextWindow !== 'number' || !(contextWindow > 0))\n return base\n return Math.max(base, Math.floor(fraction * contextWindow * BYTES_PER_TOKEN))\n}\n\n/**\n * Context window (tokens) of the model currently serving the run, for\n * window-relative wire budgets.\n *\n * On the primary target the host's explicit `behavior.contextWindow` (chat\n * hosts inject the picked model's window every run) wins, then the resolved\n * autocompact window, the primary {@link ModelTarget}'s window, and the\n * provider's advertised `meta.contextWindow`. Once the run has advanced down\n * the fallback chain, `behavior.contextWindow` describes the model that just\n * FAILED (1M Fable → 200k Sonnet is the realistic shape), so the active\n * target's own window and the re-based autocompact window take precedence\n * and the stale behavior value is only a last resort before provider meta.\n * `null` when nothing knows.\n */\nexport function activeContextWindow(ctx: LoopContext): number | null {\n const positive = (n: number | null | undefined): number | null => (typeof n === 'number' && n > 0 ? n : null)\n const advanced = (ctx.activeTargetIndex ?? 0) > 0\n const target = ctx.targets?.[ctx.activeTargetIndex ?? 0]\n const ordered = advanced\n ? [target?.contextWindow, ctx.autoCompact?.contextWindow, ctx.behavior.contextWindow]\n : [ctx.behavior.contextWindow, ctx.autoCompact?.contextWindow, target?.contextWindow]\n for (const candidate of ordered) {\n const n = positive(candidate)\n if (n !== null)\n return n\n }\n return positive(ctx.provider.meta.contextWindow)\n}\n\n/** Result of {@link applyTailCompaction}. */\nexport interface TailCompactionResult {\n messages: SessionMessage[]\n /**\n * Paths whose `read_file` outputs were replaced with a stub on this pass.\n * The caller routes these through `markReadStateForElidedPaths` so a\n * subsequent `read_file` misses its own dedup and re-serves the full body.\n * Otherwise the \"unchanged since the previous read\" replay stub points the\n * model at content compaction already removed from the wire — leaving it\n * with zero visible content and driving an infinite re-read loop (the\n * failure this return value exists to prevent).\n */\n elidedReadPaths: string[]\n /**\n * Non-read `tool_result`s this pass replaced with the lossy stub that are\n * large enough to be worth persisting to disk instead. The caller writes\n * each to the persist dir and swaps the lossy stub for a recoverable\n * `<persisted-output … path=…>` stub, so a compacted result stays\n * retrievable by reading its path rather than being lost. `output` is the\n * ORIGINAL content captured before the stub replaced it. Reads are excluded\n * (they recover via the read-state dedup re-serve); already-persisted stubs\n * are skipped.\n */\n persistableElided: Array<{ callId: string, toolName: string, output: string }>\n}\n\n/**\n * Cross-turn memo for `toolOutputBudgetByteLength`, keyed on the tool_result\n * block object. The wire pipeline preserves block references for unchanged\n * blocks (sanitize/alias/elision copy only what they touch), so the same\n * block objects flow through the byte-accounting loops on every turn of a\n * run. Without the memo, tail compaction re-measures the ENTIRE transcript's\n * tool output each turn — O(total transcript bytes) per turn, O(n²) per run.\n * Blocks are immutable by pipeline convention; a transform that changes an\n * output produces a new object, which simply misses the memo once.\n */\nconst toolResultBudgetBytesMemo = new WeakMap<object, number>()\n\n/** Model-visible byte size of a `tool_result` block (see `toolOutputBudgetByteLength`), memoized per block object. */\nexport function memoizedToolResultBudgetBytes(block: object & { output: string | ToolResultContent[] }): number {\n const hit = toolResultBudgetBytesMemo.get(block)\n if (hit !== undefined)\n return hit\n const bytes = toolOutputBudgetByteLength(block.output)\n toolResultBudgetBytesMemo.set(block, bytes)\n return bytes\n}\n\n/**\n * Tail-compaction for non-Anthropic providers: when the cumulative byte size\n * of `tool_result` content across the wire-level message list exceeds\n * `threshold`, replace OLDER `tool_result` outputs with a short stub while\n * keeping the largest recent suffix of tool output that still fits under\n * `threshold`. `keepTurns` is a floor — the newest `keepTurns` messages are\n * never eligible for elision even if their output alone exceeds the budget —\n * not a cap, so the model retains as much fresh tool context as the budget\n * allows rather than just the last few messages.\n *\n * Only `tool_result` blocks are touched — text and image blocks pass through\n * unchanged. Mutates a shallow-cloned message array; original `messages` is\n * not modified.\n *\n * For Anthropic users, prefer the server-side `context-management-2025-06-27`\n * beta (token-accurate, no client-side approximation). This function is the\n * client-side fallback for OpenAI-compatible / OpenRouter / Cerebras runs\n * against OSS models that lack a server-side equivalent.\n */\nexport function applyTailCompaction(\n messages: SessionMessage[],\n threshold: number,\n keepTurns: number,\n options?: {\n /**\n * call_id → file path for `read_file` calls, resolved from the canonical\n * (pre-alias) message list. Lets compaction report which stubbed results\n * were file reads so their read-state can be invalidated. Omit to skip\n * read-path tracking.\n */\n readPathByCallId?: ReadonlyMap<string, string | readonly string[]>\n /**\n * Quantize the elision frontier to multiples of this many messages so the\n * elided prefix grows in discrete jumps instead of advancing one message\n * per turn. A per-turn frontier rewrites the wire bytes at the elision\n * boundary every request, collapsing the provider's prefix cache to the\n * system prompt (observed: cached tokens oscillating ~500k→20k while the\n * model made zero progress). Default 1 (a per-turn frontier); the\n * loop passes `COMPACT_CHUNK_TURNS` in production.\n */\n chunkTurns?: number\n /**\n * call_id → tool name for every tool call (canonical, pre-alias). Lets\n * persist-on-elide label the recoverable stub with the originating tool.\n */\n toolNameByCallId?: ReadonlyMap<string, string>\n /**\n * Minimum byte size for a non-read result to be reported in\n * {@link TailCompactionResult.persistableElided}. 0 (default) disables\n * persist-on-elide reporting — every elided result uses the lossy stub.\n * The loop passes the persisted-stub preview size, below which persisting\n * wouldn't save bytes.\n */\n persistElideMinBytes?: number\n /**\n * Hysteresis low-water mark (`0 < f < 1`, see\n * `AgentBehavior.compactLowWaterFraction`). When set, the cutoff comes\n * from {@link lowWaterTailCutoff} instead of the newest→oldest budget walk.\n * Out-of-range values fall back to the walk.\n */\n lowWaterFraction?: number\n /**\n * Absolute elision frontier: stub every eligible `tool_result` in the\n * messages before this index, whatever their size. When set, `threshold`,\n * `keepTurns`, `chunkTurns` and `lowWaterFraction` are ignored. Used by\n * the context-overflow rescue, whose frontier must stay put across turns\n * instead of moving with the list's length.\n */\n cutoff?: number\n },\n): TailCompactionResult {\n const elidedReadPaths: string[] = []\n const persistableElided: TailCompactionResult['persistableElided'] = []\n const toolNameByCallId = options?.toolNameByCallId\n const persistElideMinBytes = options?.persistElideMinBytes ?? 0\n if (messages.length === 0)\n return { messages, elidedReadPaths, persistableElided }\n\n const cutoff = typeof options?.cutoff === 'number'\n ? Math.min(Math.max(0, Math.floor(options.cutoff)), messages.length)\n : budgetTailCutoff(messages, threshold, keepTurns, options)\n if (cutoff <= 0)\n return { messages, elidedReadPaths, persistableElided }\n\n const readPathByCallId = options?.readPathByCallId\n let changed = false\n // attachments (images/audio/video/documents) in a tool result flatten to a\n // short `[image: …]`-style marker via `toolOutputBudgetByteLength`. Counting\n // their full base64 length here (as `toolOutputByteLength` does) let a single\n // large screenshot/PDF/video instantly blow the byte budget and prematurely\n // elide unrelated tool outputs. The marker-based sizer keeps the elision\n // frontier driven by textual context volume, which is what compaction is for.\n const out = messages.slice()\n for (let i = 0; i < cutoff; i++) {\n const msg = out[i]\n let msgChanged = false\n const newContent = msg.content.map((block) => {\n if (block.type !== 'tool_result')\n return block\n // Already a short string — nothing to compact.\n const existingBytes = toolOutputByteLength(block.output)\n if (existingBytes <= COMPACTION_STUB_BYTES)\n return block\n // Already a disk-persisted stub (~2 KiB carrying preview + path).\n // Replacing it with COMPACTION_STUB would drop the path attribute,\n // stranding the on-disk blob: still on disk until session delete,\n // but no longer reachable from the conversation. Saving ~1.5 KiB\n // by overwriting isn't worth losing the reference.\n if (typeof block.output === 'string' && block.output.startsWith(PERSISTED_STUB_PREFIX))\n return block\n msgChanged = true\n changed = true\n const readPath = readPathByCallId?.get(block.callId)\n if (readPath !== undefined) {\n elidedReadPaths.push(...(typeof readPath === 'string' ? [readPath] : readPath))\n }\n else if (\n persistElideMinBytes > 0\n && typeof block.output === 'string'\n && existingBytes > persistElideMinBytes\n ) {\n // Non-read result big enough that persisting it to disk saves bytes\n // AND keeps it recoverable. The caller upgrades this COMPACTION_STUB\n // to a `<persisted-output … path=…>` stub; if persistence is off or\n // the write fails, the lossy stub stands.\n persistableElided.push({\n callId: block.callId,\n toolName: toolNameByCallId?.get(block.callId) ?? 'tool',\n output: block.output,\n })\n }\n return { ...block, output: COMPACTION_STUB }\n })\n if (msgChanged)\n out[i] = { ...msg, content: newContent }\n }\n return { messages: changed ? out : messages, elidedReadPaths, persistableElided }\n}\n\n/**\n * Budget-driven elision frontier of {@link applyTailCompaction}: 0 when the\n * tool output fits under `threshold` or nothing is older than the\n * `keepTurns` floor, otherwise the low-water or budget-walk cutoff.\n */\nfunction budgetTailCutoff(\n messages: SessionMessage[],\n threshold: number,\n keepTurns: number,\n options: { chunkTurns?: number, lowWaterFraction?: number } | undefined,\n): number {\n // Budget the elision decision on the MODEL-VISIBLE size, not wire bytes:\n // attachments (images/audio/video/documents) in a tool result flatten to a\n // short `[image: …]`-style marker via `toolOutputBudgetByteLength`. Counting\n // their full base64 length here (as `toolOutputByteLength` does) let a single\n // large screenshot/PDF/video instantly blow the byte budget and prematurely\n // elide unrelated tool outputs. The marker-based sizer keeps the elision\n // frontier driven by textual context volume, which is what compaction is for.\n let totalBytes = 0\n for (const msg of messages) {\n for (const block of msg.content) {\n if (block.type === 'tool_result')\n totalBytes += memoizedToolResultBudgetBytes(block)\n }\n }\n if (totalBytes <= threshold)\n return 0\n\n // `keepTurns` is a FLOOR: the trailing `keep` messages are never eligible\n // for elision. Nothing older than that → bail out.\n const keep = Math.max(0, keepTurns)\n const floorCutoff = messages.length - keep\n if (floorCutoff <= 0)\n return 0\n\n const chunk = Math.max(1, options?.chunkTurns ?? 1)\n const lowWater = options?.lowWaterFraction\n return typeof lowWater === 'number' && lowWater > 0 && lowWater < 1\n ? lowWaterTailCutoff(messages, threshold, keep, chunk, lowWater)\n : budgetWalkCutoff(messages, threshold, floorCutoff, chunk)\n}\n\n/** Tool-result budget bytes per message, the unit both cutoff policies sum. */\nfunction messageToolBytes(msg: SessionMessage): number {\n let bytes = 0\n for (const block of msg.content) {\n if (block.type === 'tool_result')\n bytes += memoizedToolResultBudgetBytes(block)\n }\n return bytes\n}\n\n/** Default tail-compaction cutoff: the largest recent suffix under `threshold`, snapped down to `chunk`. */\nfunction budgetWalkCutoff(messages: SessionMessage[], threshold: number, floorCutoff: number, chunk: number): number {\n // Byte-budget eviction: keep the LARGEST recent suffix of tool output that\n // fits under `threshold`, eliding only as far forward as needed — instead\n // of bluntly eliding everything before the last `keep` messages. The blunt\n // message-count rule discarded ~all tool context the moment a session\n // crossed `threshold` (measured: 38 of 40 results gone; a freshly-read file\n // already elided by the time the model went to edit it), starving the model\n // even though the budget had room. Walk newest→oldest accumulating tool\n // bytes; the first message that tips the kept suffix over `threshold` (and\n // everything before it) is the eviction range.\n let keptBytes = 0\n let budgetCutoff = floorCutoff\n for (let i = messages.length - 1; i >= 0; i--) {\n keptBytes += messageToolBytes(messages[i])\n if (keptBytes > threshold) {\n budgetCutoff = i + 1\n break\n }\n }\n // Floor wins: never keep fewer than `keep` trailing messages, even if their\n // tool output alone busts the budget.\n const rawCutoff = Math.min(budgetCutoff, floorCutoff)\n if (rawCutoff <= 0)\n return 0\n // Cache-stable frontier: snap the cutoff DOWN to a multiple of `chunk` so\n // the elided prefix [0, cutoff) is byte-identical across the next `chunk`\n // requests. A frontier that advanced one message per turn rewrote the wire\n // at the elision boundary every request, so the provider's prefix cache\n // collapsed to the system prompt every turn instead of holding. Rounding\n // DOWN keeps a few extra recent messages visible (mild, bounded overshoot of\n // `threshold`) — the safe direction for model context.\n return Math.floor(rawCutoff / chunk) * chunk\n}\n\n/**\n * Hysteresis cutoff for tail compaction: replay the message list oldest→newest\n * as if each prefix were a request. Whenever kept tool bytes exceed\n * `threshold`, trim from the frontier down to `lowWater × threshold` in one\n * step (never into the trailing `keep` messages of that prefix, snapped down\n * to `chunk`), then wait for the next crossing. The result depends only on\n * the prefix, so a later request reproduces every earlier step exactly and\n * the elided prefix stays byte-stable between steps. O(n) for a fixed chunk:\n * each scan restarts at most `chunk` messages behind where the last one ended.\n */\nfunction lowWaterTailCutoff(messages: SessionMessage[], threshold: number, keep: number, chunk: number, lowWater: number): number {\n const sizes = messages.map(messageToolBytes)\n const target = lowWater * threshold\n let cutoff = 0\n let kept = 0\n for (let end = 0; end < sizes.length; end++) {\n kept += sizes[end]\n if (kept <= threshold)\n continue\n const limit = end + 1 - keep\n let c = cutoff\n let k = kept\n while (c < limit && k > target) {\n k -= sizes[c]\n c++\n }\n const q = Math.max(cutoff, Math.floor(c / chunk) * chunk)\n for (let i = cutoff; i < q; i++)\n kept -= sizes[i]\n cutoff = q\n }\n return cutoff\n}\n\n/**\n * Whether `AgentBehavior.compactSkip` turns client `'tail'` compaction off for\n * this request: the provider name is listed (any when `providers` is unset)\n * and the active window reaches `minContextWindow` (any when unset; an\n * unknown window never meets a set minimum). Pure — exported for tests.\n */\nexport function tailCompactionSkipped(\n skip: AgentBehavior['compactSkip'],\n providerName: string | undefined,\n contextWindow: number | null,\n): boolean {\n if (!skip)\n return false\n if (skip.providers !== undefined && (providerName === undefined || !skip.providers.includes(providerName)))\n return false\n if (typeof skip.minContextWindow === 'number' && (contextWindow === null || contextWindow < skip.minContextWindow))\n return false\n return true\n}\n\n/** Result of {@link applyMediaAgeout} and {@link applyMediaBudget}. */\nexport interface MediaAgeoutResult {\n messages: SessionMessage[]\n /**\n * `read_file` paths whose image/document output was aged out this pass. The\n * caller routes these through `markReadStateForElidedPaths` so a subsequent\n * `read_file <path>` re-serves the full body instead of the dedup\n * \"unchanged\" stub (which would point at media no longer on the wire).\n */\n elidedReadPaths: string[]\n}\n\n/**\n * TEXTUAL document payloads above this many bytes never ride inline on the\n * wire — they are replaced with the recoverable `attachment://` marker\n * immediately, even inside the `mediaKeepTurns` window, because the model\n * can page them back losslessly via read_file's line-sliced attachment path.\n * Matches read_file's default text byte cap.\n *\n * Binary media (images, PDFs, opaque blobs) is deliberately NOT size-gated\n * inside the keep window: the model can only consume those inline, so\n * stubbing a fresh one would make it permanently unviewable and set up a\n * read → stub → re-read ping-pong. Binary keeps pure age-out semantics.\n */\nexport const MEDIA_INLINE_MAX_BYTES = 262_144\n\n/**\n * Base64 chars to decode when sniffing whether a base64 document is textual.\n * Multiple of 4 (decodes cleanly), yielding ~8 KiB — the same head-sample\n * size `looksBinary` uses, so the gate and read_file's `attachmentText`\n * reach the same verdict for the same payload.\n */\nconst TEXT_SNIFF_BASE64_CHARS = 10924\n\n/**\n * True when a document block's bytes are recoverable as paged text through\n * read_file's attachment path. Only such blocks are eligible for the\n * keep-window size gate. Kept deliberately in lockstep with `attachmentText`\n * in tools/read-file.ts: text encoding → yes; PDFs → no; base64 → decode a\n * head sample and sniff.\n */\nfunction isPagedTextRecoverable(block: { type: 'image' | 'document', mediaType: string, data: string, encoding?: 'base64' | 'text' }): boolean {\n if (block.type !== 'document')\n return false\n if (block.encoding === 'text')\n return true\n if (block.mediaType === 'application/pdf')\n return false\n // Decode only a head sample — this runs per media block per request, and\n // the payload can be megabytes. A trailing clipped multi-byte char decodes\n // to a single U+FFFD, safely under looksBinary's ≥5 replacement threshold.\n const sample = Buffer.from(block.data.slice(0, TEXT_SNIFF_BASE64_CHARS), 'base64').toString('utf-8')\n return !looksBinary(sample)\n}\n\n/**\n * Age base64 media off the wire. Replaces top-level `image` / `document`\n * blocks — and image/document parts nested in `tool_result` outputs — with a\n * short, re-resolvable text marker (`mediaAgeoutMarker`) for every message\n * older than the last `keep` messages. Wire-only: the persisted session keeps\n * the original bytes, and the marker's `attachment://<hash>` handle lets the\n * model pull any image back via `read_file`.\n *\n * This is the long-run de-bloat lever for image/document-heavy sessions —\n * complementary to `applyTailCompaction`, which only stubs `tool_result`\n * text and (deliberately) never counts or trims media bytes, so a session\n * full of screenshots would otherwise carry every base64 payload forever.\n *\n * Cache-stable: the frontier is snapped DOWN to a multiple of `chunkTurns` so\n * the aged prefix is byte-identical across `chunkTurns` requests (same\n * discipline as `applyTailCompaction`); markers are content-hash-stable, so a\n * frozen frontier yields a frozen prefix. `keep = 0` ages out ALL media — used\n * by the reactive context-overflow recovery.\n *\n * Textual documents over `options.maxInlineBytes` also become markers inside\n * the keep window (see {@link MEDIA_INLINE_MAX_BYTES}).\n *\n * Pure: returns the input reference unchanged when nothing aged out.\n */\nexport function applyMediaAgeout(\n messages: SessionMessage[],\n keep: number,\n options?: { chunkTurns?: number, readPathByCallId?: ReadonlyMap<string, string | readonly string[]>, readFileToolName?: string | null, maxInlineBytes?: number },\n): MediaAgeoutResult {\n const elidedReadPaths: string[] = []\n if (messages.length === 0)\n return { messages, elidedReadPaths }\n const readFileToolName = options?.readFileToolName ?? 'read_file'\n\n const keepFloor = Math.max(0, keep)\n const rawCutoff = messages.length - keepFloor\n const chunk = Math.max(1, options?.chunkTurns ?? 1)\n const cutoff = rawCutoff <= 0 ? 0 : Math.floor(rawCutoff / chunk) * chunk\n // Size gate: textual documents whose payload exceeds this never ride\n // inline, even inside the keep window — a multi-MB attachment on turn 1\n // would otherwise blow the context (and the process) before age-out could\n // ever help. The marker is content-hash-stable, so gating a block on its\n // first appearance keeps the prefix byte-identical on every request.\n // Binary media is exempt while fresh — see MEDIA_INLINE_MAX_BYTES.\n const maxInline = typeof options?.maxInlineBytes === 'number' && options.maxInlineBytes > 0\n ? options.maxInlineBytes\n : Infinity\n if (cutoff <= 0 && maxInline === Infinity)\n return { messages, elidedReadPaths }\n\n const isInlineMedia = (b: { type: string, data?: unknown }): b is { type: 'image' | 'document', mediaType: string, data: string, name?: string, encoding?: 'base64' | 'text' } =>\n (b.type === 'image' || b.type === 'document') && typeof b.data === 'string'\n\n const readPathByCallId = options?.readPathByCallId\n let changed = false\n const out = messages.slice()\n for (let i = 0; i < out.length; i++) {\n const aged = i < cutoff\n if (!aged && maxInline === Infinity)\n continue\n const elides = (b: { type: 'image' | 'document', mediaType: string, data: string, encoding?: 'base64' | 'text' }): boolean =>\n aged || (mediaPayloadBytes(b.data, b.encoding) > maxInline && isPagedTextRecoverable(b))\n const msg = out[i]\n let msgChanged = false\n const newContent = msg.content.map((block): SessionContentBlock => {\n // Top-level media block with inline bytes → marker. Ref-form blocks\n // (no `data`) are skipped — they're host-resolved, not recoverable here.\n if (isInlineMedia(block) && elides(block)) {\n msgChanged = true\n changed = true\n return { type: 'text', text: mediaAgeoutMarker(block, readFileToolName) }\n }\n // Media nested inside a tool_result output array (Read images, MCP\n // screenshots, attached PDFs).\n if (block.type === 'tool_result' && Array.isArray(block.output)) {\n let outputChanged = false\n const newOutput: ToolResultContent[] = block.output.map((part) => {\n if (isInlineMedia(part) && elides(part)) {\n outputChanged = true\n return { type: 'text' as const, text: mediaAgeoutMarker(part, readFileToolName) }\n }\n return part\n })\n if (outputChanged) {\n msgChanged = true\n changed = true\n const p = readPathByCallId?.get(block.callId)\n if (p !== undefined)\n elidedReadPaths.push(...(typeof p === 'string' ? [p] : p))\n return { ...block, output: newOutput }\n }\n }\n return block\n })\n if (msgChanged)\n out[i] = { ...msg, content: newContent }\n }\n return { messages: changed ? out : messages, elidedReadPaths }\n}\n\n/** Result of {@link applyOverflowCutoff}. */\nexport interface OverflowCutoffResult {\n /** The stubbed list, or the input reference when nothing changed. */\n messages: SessionMessage[]\n /** `read_file` paths whose output left the wire, for read-state invalidation. */\n elidedReadPaths: string[]\n /** Whether any base64 media became a marker. */\n media: boolean\n /** Whether any `tool_result` text became a stub. */\n toolResults: boolean\n}\n\n/**\n * The context-overflow rescue's stubbing up to an absolute frontier: base64\n * media becomes re-resolvable markers ({@link applyMediaAgeout}), then older\n * `tool_result` text becomes stubs ({@link applyTailCompaction} with its\n * `cutoff` option), for every message before `cutoff`. Media goes first\n * because a media-driven overflow can't be fixed by stubbing text (tail\n * compaction never counts media bytes). Same inputs give the same bytes, so\n * re-applying a remembered cutoff reproduces the rescued prefix exactly.\n *\n * @param messages - Wire message list.\n * @param cutoff - Absolute index: messages before it are stubbed.\n * @param options - Call maps for read-path reporting, and the wire name of `read_file` the media markers point at (`null` when the tool is absent).\n * @param options.readPathByCallId - call_id → `read_file` path.\n * @param options.toolNameByCallId - call_id → tool name.\n * @param options.readFileToolName - Wire name of `read_file`.\n * @param options.only - Run just these passes (a remembered cutoff's record of what it stubbed); both when omitted.\n * @param options.only.media - Run the media pass.\n * @param options.only.toolResults - Run the `tool_result` pass.\n */\nexport function applyOverflowCutoff(\n messages: SessionMessage[],\n cutoff: number,\n options: {\n readPathByCallId?: ReadonlyMap<string, string | readonly string[]>\n toolNameByCallId?: ReadonlyMap<string, string>\n readFileToolName?: string | null\n only?: { media: boolean, toolResults: boolean }\n },\n): OverflowCutoffResult {\n const aged = options.only?.media === false\n ? { messages, elidedReadPaths: [] }\n : applyMediaAgeout(messages, Math.max(0, messages.length - cutoff), {\n chunkTurns: 1,\n readPathByCallId: options.readPathByCallId,\n readFileToolName: options.readFileToolName,\n maxInlineBytes: MEDIA_INLINE_MAX_BYTES,\n })\n const compacted = options.only?.toolResults === false\n ? { messages: aged.messages, elidedReadPaths: [] }\n : applyTailCompaction(aged.messages, 0, 0, {\n cutoff,\n readPathByCallId: options.readPathByCallId,\n toolNameByCallId: options.toolNameByCallId,\n })\n return {\n messages: compacted.messages,\n elidedReadPaths: [...aged.elidedReadPaths, ...compacted.elidedReadPaths],\n media: aged.messages !== messages,\n toolResults: compacted.messages !== aged.messages,\n }\n}\n\n/**\n * Frontiers the context-overflow rescue tries next, in order, all past\n * `current`. The keep floors' frontiers (length minus trailing messages left\n * intact) snapped down to a multiple of `chunk` come first, so the stubbed\n * prefix grows in chunk-sized jumps and stays byte-identical for many turns;\n * the unsnapped frontiers past the last snapped one follow as a last resort,\n * for when no snapped step gets past `current` or frees enough room.\n *\n * @param length - Length of the wire message list.\n * @param current - Frontier already applied (0 when none).\n * @param keepFloors - Trailing messages to keep intact, most to least.\n * @param chunk - Snap quantum, {@link COMPACT_CHUNK_TURNS} in production.\n */\nexport function nextOverflowCutoffs(\n length: number,\n current: number,\n keepFloors: readonly number[],\n chunk: number = COMPACT_CHUNK_TURNS,\n): number[] {\n const step = Math.max(1, chunk)\n const raw = keepFloors.map(keep => Math.max(0, length - Math.max(0, keep))).sort((a, b) => a - b)\n const snapped = raw.map(c => Math.floor(c / step) * step)\n const out: number[] = []\n // A frontier at or below one already listed stubs a subset of it, so it can\n // only shrink the list if that one did: skip it.\n for (const c of [...snapped, ...raw]) {\n if (c > (out.at(-1) ?? current) && c <= length)\n out.push(c)\n }\n return out\n}\n\n/**\n * Identity of the history a remembered overflow cutoff indexes into: the\n * first turn's id plus the latest `compact-summary` marker's id. Changes\n * when the agent moves to another conversation or a compaction rewrites the\n * wire list, so a stale index is dropped instead of applied to the wrong\n * messages.\n *\n * @param turns - The run's session turns.\n */\nexport function overflowCutoffAnchor(turns: readonly SessionTurn[]): string {\n let marker = ''\n for (let i = turns.length - 1; i >= 0; i--) {\n if (turns[i].content.some(b => b.type === 'compact-summary')) {\n marker = turns[i].id\n break\n }\n }\n return `${turns[0]?.id ?? ''}|${marker}`\n}\n\n/** Longest edge above which an image is unsafe once a request holds >20 images (Anthropic). */\nexport const MANY_IMAGE_MAX_EDGE = 2000\n\n/** Image count past which Anthropic enforces {@link MANY_IMAGE_MAX_EDGE}. */\nconst MANY_IMAGE_COUNT = 20\n\n/** Budget steps are half a budget wide: one prefix rewrite per half-budget of new media. */\nconst MEDIA_BUDGET_STEP = 0.5\n\nconst imageEdgeMemo = new WeakMap<object, number>()\n\nfunction longestEdge(block: { data: string }): number {\n const hit = imageEdgeMemo.get(block)\n if (hit !== undefined)\n return hit\n const size = imageSizeFromBase64(block.data)\n const edge = size ? Math.max(size.width, size.height) : 0\n imageEdgeMemo.set(block, edge)\n return edge\n}\n\n/**\n * Budget-triggered media age-out (`behavior.mediaBudget`). Media stays inline\n * until the request nears the provider's hard limits, then the oldest items\n * age out in half-budget steps — see {@link AgentBehavior.mediaBudget}.\n *\n * The two limits are independent, as the provider's are: past `maxItems`\n * the oldest items age out in steps of half `maxItems`; past `maxBytes` in\n * steps of half `maxBytes`. The aged prefix is whichever reaches further.\n *\n * Determinism is what keeps the prompt cache warm: the aged set is a pure\n * function of the message list, it is always the OLDEST items, and how much\n * is removed only changes when a total crosses its next step. Appending media\n * therefore either leaves every earlier message byte-identical or (once per\n * step) rewrites a batch at once.\n *\n * Two positional rules ride along: textual documents over `maxInlineBytes`\n * are always markers (as in {@link applyMediaAgeout}), and once the history\n * holds more than {@link MANY_IMAGE_COUNT} images, images still over\n * {@link MANY_IMAGE_MAX_EDGE} px age out past the `keepTurns` window\n * (chunk-snapped). That lowers the odds of the many-image rejection but does\n * not rule it out: oversize images inside the window stay inline.\n */\nexport function applyMediaBudget(\n messages: SessionMessage[],\n budget: NonNullable<AgentBehavior['mediaBudget']>,\n options?: { keepTurns?: number, chunkTurns?: number, readPathByCallId?: ReadonlyMap<string, string | readonly string[]>, readFileToolName?: string | null, maxInlineBytes?: number },\n): MediaAgeoutResult {\n // Size-gate oversize textual documents exactly as the windowed pass does\n // (an unbounded keep window leaves only that rule active).\n const gated = applyMediaAgeout(messages, Number.MAX_SAFE_INTEGER, { ...options, chunkTurns: 1 })\n const elidedReadPaths = [...gated.elidedReadPaths]\n messages = gated.messages\n\n const readFileToolName = options?.readFileToolName ?? 'read_file'\n const keep = Math.max(0, options?.keepTurns ?? 8)\n const chunk = Math.max(1, options?.chunkTurns ?? 1)\n const rawCutoff = messages.length - keep\n const oversizeCutoff = rawCutoff <= 0 ? 0 : Math.floor(rawCutoff / chunk) * chunk\n\n interface Inline { type: 'image' | 'document', mediaType: string, data: string, encoding?: 'base64' | 'text' }\n const isInline = (b: { type: string, data?: unknown }): b is Inline =>\n (b.type === 'image' || b.type === 'document') && typeof b.data === 'string'\n\n // Pass 1: decide. Two independent rules whose union is the aged set: the\n // oldest-first budget prefix, and oversize images past the window. Every\n // item counts toward the totals (aged or not) so they — and therefore the\n // prefix — only grow as media is appended; excluding window-aged items\n // would let a total drop and bring an already-aged block back inline.\n const aged = new Set<object>()\n const items: Array<{ block: object, bytes: number }> = []\n const oversize: object[] = []\n let images = 0\n const consider = (block: Inline, index: number) => {\n if (block.type === 'image') {\n images++\n if (index < oversizeCutoff && longestEdge(block) > MANY_IMAGE_MAX_EDGE)\n oversize.push(block)\n }\n items.push({ block, bytes: block.data.length })\n }\n messages.forEach((msg, index) => {\n for (const block of msg.content) {\n if (isInline(block)) {\n consider(block, index)\n }\n else if (block.type === 'tool_result' && Array.isArray(block.output)) {\n for (const part of block.output) {\n if (isInline(part))\n consider(part, index)\n }\n }\n }\n })\n // The edge limit only applies past the image count; counted over every\n // image (aged or not) so appending media cannot flip it back.\n if (images > MANY_IMAGE_COUNT) {\n for (const block of oversize)\n aged.add(block)\n }\n const overflow = (total: number, max: number) => {\n const step = Math.max(1, Math.floor(max * MEDIA_BUDGET_STEP))\n return total > max ? Math.ceil((total - max) / step) * step : 0\n }\n const dropItems = overflow(items.length, Math.max(1, budget.maxItems))\n const dropBytes = overflow(items.reduce((sum, item) => sum + item.bytes, 0), Math.max(1, budget.maxBytes))\n let droppedItems = 0\n let droppedBytes = 0\n for (const item of items) {\n if (droppedItems >= dropItems && droppedBytes >= dropBytes)\n break\n aged.add(item.block)\n droppedItems++\n droppedBytes += item.bytes\n }\n if (aged.size === 0)\n return { messages, elidedReadPaths }\n\n // Pass 2: rewrite the chosen blocks to recoverable markers.\n const readPathByCallId = options?.readPathByCallId\n const out = messages.map((msg) => {\n let msgChanged = false\n const content = msg.content.map((block): SessionContentBlock => {\n if (aged.has(block)) {\n msgChanged = true\n return { type: 'text', text: mediaAgeoutMarker(block as Inline, readFileToolName) }\n }\n if (block.type === 'tool_result' && Array.isArray(block.output) && block.output.some(part => aged.has(part))) {\n msgChanged = true\n const p = readPathByCallId?.get(block.callId)\n if (p !== undefined)\n elidedReadPaths.push(...(typeof p === 'string' ? [p] : p))\n return {\n ...block,\n output: block.output.map((part): ToolResultContent =>\n aged.has(part) ? { type: 'text', text: mediaAgeoutMarker(part as Inline, readFileToolName) } : part),\n }\n }\n return block\n })\n return msgChanged ? { ...msg, content } : msg\n })\n return { messages: out, elidedReadPaths }\n}\n\n/**\n * Distinct `read_file` paths called inside the given turns (optionally\n * filtered to an id set). Canonical tool names — the alias rewrite is\n * wire-only, so session turns always carry `read_file` verbatim.\n */\nexport function readFilePathsInTurns(turns: readonly SessionTurn[], ids?: ReadonlySet<string>): string[] {\n const paths = new Set<string>()\n for (const turn of turns) {\n if (ids && !ids.has(turn.id))\n continue\n for (const block of turn.content) {\n if (block.type !== 'tool_call' || block.name !== 'read_file')\n continue\n for (const path of readFileInputPaths(block.input))\n paths.add(path)\n }\n }\n return [...paths]\n}\n\n/**\n * Build a call_id → file path map for `read_file` tool calls in `messages`.\n * Tail compaction uses it to learn which stubbed `tool_result`s were file\n * reads, so their read-state dedup can be invalidated. Resolve this from the\n * canonical, pre-alias history — call_ids are stable across the alias rewrite,\n * so the map still keys the wire-level `tool_result` blocks.\n */\nexport function collectCallMaps(messages: SessionMessage[]): {\n readPathByCallId: Map<string, string[]>\n toolNameByCallId: Map<string, string>\n} {\n const readPathByCallId = new Map<string, string[]>()\n const toolNameByCallId = new Map<string, string>()\n for (const msg of messages) {\n for (const block of msg.content) {\n if (block.type !== 'tool_call')\n continue\n toolNameByCallId.set(block.id, block.name)\n if (block.name === 'read_file') {\n const paths = readFileInputPaths(block.input)\n if (paths.length > 0)\n readPathByCallId.set(block.id, paths)\n }\n }\n }\n return { readPathByCallId, toolNameByCallId }\n}\n","/**\n * The per-run `LoopContext` contract shared by every loop module, plus the\n * context-derived primitives they all lean on: bounded hook dispatch and the\n * execution-backed blob writer.\n */\n\nimport type { Hookable } from 'hookable'\nimport type { AgentHooks, ResolvedBehavior } from './agent'\nimport type { AliasMaps } from './aliasing'\nimport type { ExecutionContext, ExecutionHandle } from './contexts'\nimport type { StepRecord } from './durable/types'\nimport type { InterceptorRegistry } from './extensions/hooks'\nimport type { ResolvedAutoCompact } from './loop-auto-compact'\nimport type { RetryClock } from './loop-recovery'\nimport type { McpConnection } from './mcp'\nimport type { Provider, StreamOptions } from './providers'\nimport type { RunDurability } from './run-durability'\nimport type { Session } from './session'\nimport type { ActiveSkill } from './skills/activation'\nimport type { SkillsConfig } from './skills/types'\nimport type { ToolCancelRegistry } from './tool-cancel'\nimport type { ToolStateController } from './tool-state'\nimport type { ReadStateMap } from './tools/read-state'\nimport type { ToolContext, ToolDef, ToolDescriptions } from './tools/types'\nimport type { AgentClock, McpServerConfig, ModelTarget, SessionTurn, ThinkingLevel, TurnUsage } from './types'\nimport { RunSuspendedError } from './durable/errors'\nimport { maybePersistToolResult, persistElidedToolResults } from './loop-persistence'\nimport { writePersistedBlob } from './persisted-blob-io'\nimport { journaledStep, LOOP_STEP_KINDS, replays } from './run-durability'\nimport { resolveTimeoutMs, settleWithinTimeout, withTimeout } from './timeout'\n\n/**\n * Default watchdog for awaited hook dispatch (`AgentBehavior.hookTimeoutMs`).\n * Generous (5 min) — bounds infinite hangs without policing slow but finite\n * host handlers. Shared with `agent-run.ts` (run lifecycle hooks) so both halves\n * resolve the same fallback.\n */\nexport const DEFAULT_HOOK_TIMEOUT_MS = 5 * 60 * 1000\n\nfunction hookTimeoutMsFor(ctx: Pick<LoopContext, 'behavior'>): number {\n return resolveTimeoutMs(ctx.behavior.hookTimeoutMs, DEFAULT_HOOK_TIMEOUT_MS)\n}\n\n/**\n * Dispatch an already-invoked hook promise under `behavior.hookTimeoutMs`,\n * surfacing a timeout as a typed `OperationTimeoutError`. Use for state-mutating\n * pre-stream hooks that gate the wire (`context:transform` / `system:transform` /\n * `turn:before`) — failing closed is safer than shipping a half-applied transform.\n */\nexport function boundedHook(ctx: LoopContext, operation: string, work: Promise<unknown> | void): Promise<void> {\n return withTimeout(Promise.resolve(work), {\n operation,\n timeoutMs: hookTimeoutMsFor(ctx),\n }) as Promise<void>\n}\n\n/**\n * Like {@link boundedHook} but swallows a timeout (logs under `ZIDANE_DEBUG`)\n * and continues. Use for observability / lifecycle hooks (`stream:start`,\n * `stream:end`, `turn:after`, `tool-results:after`, …) where a hung handler\n * must neither block forward progress nor alter the run's primary outcome.\n * Non-timeout handler errors still propagate.\n */\nexport function settledHook(ctx: Pick<LoopContext, 'behavior'>, operation: string, work: Promise<unknown> | void): Promise<void> {\n return settleWithinTimeout(operation, work, hookTimeoutMsFor(ctx))\n}\n\n/** Whether `err` is the durable runtime's control flow (a cancellation, suspension or terminal failure), see {@link rethrowControlError}. */\nexport function isControlError(ctx: Pick<LoopContext, 'durable'>, err: unknown): boolean {\n return err instanceof RunSuspendedError || ctx.durable.runtime.isControlError(err)\n}\n\n/** Stop the run here when `Agent.suspend` asked for it (`LoopContext.suspendSignal`). */\nexport function throwIfSuspended(ctx: Pick<LoopContext, 'suspendSignal'>): void {\n if (ctx.suspendSignal?.aborted)\n throw ctx.suspendSignal.reason instanceof RunSuspendedError ? ctx.suspendSignal.reason : new RunSuspendedError()\n}\n\n/**\n * Rethrow `err` as-is when it is durable-runtime control flow (whatever the\n * run's runtime `isControlError` claims). The runtime keys on the error's\n * class, so it must never be wrapped, retried, failed over or swallowed.\n */\nexport function rethrowControlError(ctx: Pick<LoopContext, 'durable'>, err: unknown): void {\n if (isControlError(ctx, err))\n throw err\n}\n\n/**\n * Decide from live state (abort, pause, the steering and follow-up queues).\n * In replay mode the decision is recorded every time this runs, so the entry\n * sits at the same journal position on replay and the replay takes the\n * recorded branch whatever its own live state is. Other modes read the live\n * state. The value must be JSON-serializable.\n */\nexport async function journaledDecision<T>(ctx: Pick<LoopContext, 'durable'>, name: string, decide: () => T): Promise<T> {\n if (!replays(ctx.durable))\n return decide()\n return journaledStep(ctx.durable, LOOP_STEP_KINDS.decision, name, async () => decide())\n}\n\n/** The run's durable scope as a tool sees it (`ToolContext.durable`). */\nexport function toolDurable(ctx: Pick<LoopContext, 'durable'>): NonNullable<ToolContext['durable']> {\n const { runtime, scope, checkpoint } = ctx.durable\n return { runId: scope.runId, mode: runtime.mode, runtime, checkpoint, awakeable: options => scope.awakeable(options) }\n}\n\n/**\n * The run clock as the retry and compaction helpers take it, its durable\n * parts routed through the run's runtime: `sleep` through the run scope (a\n * durable timer where the runtime has one, else a timer `signal` ends).\n */\nexport function durableClock(ctx: Pick<LoopContext, 'clock' | 'durable'>, signal?: AbortSignal): AgentClock & Required<RetryClock> {\n const { clock } = ctx\n return {\n now: () => clock.now(),\n randomUUID: () => clock.randomUUID(),\n replays: replays(ctx.durable),\n sleep: ms => ctx.durable.scope.sleep(ms, signal),\n }\n}\n\n/**\n * Record `work` as one step in replay mode (a compaction read the replay must\n * not redo); `undefined` otherwise, where callers just run it.\n */\nexport function compactionJournal(ctx: Pick<LoopContext, 'durable'>): (<T>(name: string, work: () => Promise<T>) => Promise<T>) | undefined {\n if (!replays(ctx.durable))\n return undefined\n return (name, work) => journaledStep(ctx.durable, LOOP_STEP_KINDS.compact, name, work)\n}\n\n/**\n * What a child agent inherits from the run that spawns it.\n *\n * The loop itself never reads these — it forwards them verbatim into the\n * `ToolContext` handed to child-spawning tools. Grouped into one envelope\n * precisely because of that: they are cargo, not loop configuration, and\n * spreading them across the loop's own context implied the loop cared about\n * MCP servers and skills when it does not.\n */\nexport interface SubagentInheritance {\n /** Agent display name — forwarded into `ToolContext.name`. */\n name?: string\n /** Agent default system prompt — forwarded into `ToolContext.system`. */\n system?: string\n /** Source agent tools (pre-MCP-merge) — forwarded into `ToolContext.tools`. */\n tools: Record<string, ToolDef>\n /** Agent tool aliases — forwarded into `ToolContext.toolAliases`. */\n toolAliases?: Record<string, string>\n /** Agent description overrides — forwarded into `ToolContext.toolDescriptions`. */\n toolDescriptions?: ToolDescriptions\n /** Agent MCP servers — forwarded into `ToolContext.mcpServers`. */\n mcpServers?: McpServerConfig[]\n /**\n * Getter for the agent's live MCP connection — forwarded into\n * `ToolContext.mcpConnection` so child-spawning tools can share the\n * parent's transports. A getter (not a snapshot) because the agent binds\n * the connection lazily; it may be null at loop start and live by the\n * time a tool executes.\n */\n mcpConnection?: () => McpConnection | null\n /** Agent skills config — forwarded into `ToolContext.skills`. */\n skills?: SkillsConfig\n}\n\n/**\n * Where a resumed checkpoint run picks up (`Agent.resume`): the loop turn\n * the process death cut off, so the resumed run asks for the same step keys.\n */\nexport interface ResumePoint {\n /** Loop turn index to start at. */\n turn: number\n /**\n * The saved assistant turn of `turn` whose tool calls have no results\n * yet: the resumed turn dispatches them instead of calling the model.\n */\n pending?: SessionTurn\n /** The run's last saved turn already ended it: nothing is left to run. */\n ended?: boolean\n /** Wall time the run spent before (`SessionRun.wallMs`): counted toward `behavior.maxWallMs`. */\n wallMs?: number\n}\n\nexport interface LoopContext {\n provider: Provider\n /**\n * Ordered provider+model fallback chain resolved from `AgentRunOptions.model`\n * (`targets[0]` matches the initial `provider`/`model` fields). When a\n * stream fails terminally on the active target with nothing streamed yet,\n * the loop advances to the next entry — reassigning `provider`, `model`,\n * `providerName`, and the wire tool list — and re-issues. Run-sticky:\n * the index never moves backwards within a run. Absent or single-entry\n * means no fallback.\n */\n targets?: readonly ModelTarget[]\n /**\n * Mutable index of the active entry in {@link targets}. Owned by the loop;\n * starts at 0 (or unset) and only ever advances.\n */\n activeTargetIndex?: number\n /**\n * Failure trail of exhausted fallback targets — one `{ provider, model,\n * err }` entry per advancement, in order. Owned by the loop. When the\n * whole chain exhausts, the terminal error appends this trail so earlier\n * failures (often the actionable one — e.g. the primary's auth error)\n * aren't hidden behind the last target's error.\n */\n targetFailures?: Array<{ provider: string, model: string, err: unknown }>\n hooks: Hookable<AgentHooks>\n /**\n * Agent + per-run behavior, already merged and defaulted by\n * `resolveBehavior`. Passed as ONE object on purpose: every knob the loop\n * reads (`maxTurns`, `compactStrategy`, `retry`, `persistDir`, the watchdog\n * timeouts, …) is a field of it, so a new behavior knob reaches the loop the\n * moment it is resolved — with no forwarding line to forget.\n *\n * Also forwarded into `ToolContext.behavior` so tools see the same resolved\n * view (per-run overrides of `dedupReads` / `requireReadBeforeEdit` / … included).\n */\n behavior: ResolvedBehavior\n /** What child agents inherit from this run. See {@link SubagentInheritance}. */\n inheritance: SubagentInheritance\n /**\n * Ignore `behavior.toolBatchExecutor` for this context's tool batches.\n *\n * Set on the per-call child context a custom batch executor runs against, so\n * the path underneath cannot re-enter the executor that is already driving\n * the batch. Deliberately a loop-side flag rather than a blanked\n * `behavior.toolBatchExecutor`: `behavior` is forwarded verbatim as\n * `ToolContext.behavior` and inherited by spawned subagents, which must keep\n * the host's real (possibly durable) scheduler.\n */\n suppressBatchExecutor?: boolean\n tools: Record<string, ToolDef>\n formattedTools: unknown[]\n /**\n * Recompute the wire-level tool list for a provider from the current state\n * of the agent's `unlocked` set. Two consumers: every iteration the loop\n * calls this so tools newly surfaced via `tool_search` advertise on the\n * next provider request, and a model fallback calls it with the NEW\n * provider so the wire shapes match the target actually serving the run.\n * Cached per provider+tail by the host, so per-turn calls are cheap.\n * When `undefined`, the loop uses {@link LoopContext.formattedTools}\n * verbatim (and a fallback keeps the previous wire list).\n */\n rebuildFormattedTools?: (provider: Provider) => unknown[]\n /**\n * The stable-tools dispatcher (`call_tool`) when the run is in\n * `toolSearch.mode: 'dispatch'`: its canonical name and the canonical\n * names of the lazy catalog tools it may carry. A well-formed envelope\n * around one of those is rewritten into the inner call BEFORE dispatch\n * (see {@link unwrapDispatchCalls}), so gating, validation, hooks and\n * events see the inner tool. Envelopes around anything else stay as\n * `call_tool` calls and its own `execute` refuses them, so eager tools are\n * always called directly and history scanners keyed on `block.name` keep\n * seeing them. `undefined` means no envelope handling: a host-defined\n * `call_tool` runs as itself.\n */\n dispatcher?: { name: string, targets: ReadonlySet<string> }\n aliasMaps: AliasMaps\n model: string\n system: string\n /**\n * The last request this run sent to the provider, after every hook and wire\n * repair, and how many `turns` existed when it was sent. Auto-compaction\n * resends it with the summary instruction appended, so the summary call\n * reads the whole conversation from the prompt cache; the agent keeps the\n * run's context after the run so `agent.compact()` can do the same.\n * `sentAt` (epoch ms, wall clock) dates the provider cache that request\n * wrote, for `agent.cacheExpiresAt()`. `undefined` until the run's first\n * request.\n */\n lastRequest?: { options: StreamOptions, turnCount: number, sentAt: number }\n thinking: ThinkingLevel\n signal: AbortSignal\n /** Stop at the next turn boundary (`AgentRunOptions.pauseSignal`). */\n pauseSignal?: AbortSignal\n /**\n * Aborted by `Agent.suspend` with a {@link RunSuspendedError}: the model\n * stream stops at once, running tool calls go on, and the run stops before\n * its next model call (see {@link throwIfSuspended}).\n */\n suspendSignal?: AbortSignal\n execution: ExecutionContext\n handle: ExecutionHandle\n steeringQueue: string[]\n /**\n * Synthetic user messages queued by middleware (tool-budget 'steer' nudges,\n * thinking-overrun nudges) for injection at the next turn boundary. Kept\n * separate from `steeringQueue` on purpose: the batch schedulers treat a\n * non-empty steering queue as \"superseded by user message\" and skip the\n * remaining sibling tool calls mid-batch. Nudges never interrupt a batch and\n * are dropped if the run ends before the next turn.\n */\n nonInterruptingNudgeQueue?: string[]\n followUpQueue: string[]\n turns: SessionTurn[]\n runId: string\n generateTurnId: () => string | Promise<string>\n /**\n * Time + UUID source for journaled metadata (turn `createdAt`, synthetic\n * ids). Resolved in `agent.run()` from per-run > agent-level > default\n * precedence. Live-only measurements (TTFT deltas, elapsed) keep\n * `Date.now()` directly.\n */\n clock: AgentClock\n /**\n * The run's durable runtime and scope. Every durability decision of the\n * loop consults it: replay-only logic (`runtime.mode === 'replay'`),\n * control errors, journaled decisions and durable sleeps. Shared by\n * reference with the derived contexts of tool batches and nested calls.\n */\n durable: RunDurability\n /**\n * Where `Agent.resume` continues the run (see {@link ResumePoint}).\n * Unset on a run that starts fresh. `executeTurn` consumes `pending`.\n */\n resume?: ResumePoint\n /**\n * While a resumed run dispatches the batch the dead process left\n * unfinished: the run's tool step records, by key, nested calls'\n * included. A call with a record passed `tool:gate` before its step\n * started: its gate runs again as `resumed`, with the `resumeState` the\n * record kept, and cannot refuse it.\n */\n resumedBatch?: { turn: number, records: ReadonlyMap<string, StepRecord> }\n /**\n * Enabled model-specific options (e.g. `{ fast: true }`). Not a plain\n * behavior field: `agent.run()` merges `AgentRunOptions.modelOptions` over\n * `behavior.modelOptions` before handing it down.\n */\n modelOptions?: Record<string, boolean>\n /**\n * Resolved loop-native auto-compaction config, or `undefined` when off.\n * Normalized from `AgentBehavior.autoCompact` (with the `provider.meta`\n * window fallback already applied) by `resolveAutoCompact` in `agent.run`.\n */\n autoCompact?: ResolvedAutoCompact\n /**\n * `AgentOptions.artifacts === false`: the reserved `metadata.artifacts`\n * namespace is ignored — nothing stored, no `artifact:recorded`.\n */\n artifactsDisabled?: boolean\n /**\n * Persist the freshly-appended tail of `ctx.turns` to the bound session\n * and fire `session:turns`. Set by `agent.run` only when a session is\n * attached AND per-turn sync is on (`persistTurns !== false`). The loop\n * calls it after appending a mid-run compaction marker so the summary is\n * durable + the host repaints immediately; in batch-persist mode it's\n * `undefined` and the run-end flush covers the marker.\n */\n persistTurns?: () => Promise<void>\n /**\n * Snapshot of the run's currently-active skills, for post-compact\n * restoration (`buildPostCompactAttachments`). Set by `agent.run` to\n * `() => skillActivationState.active()`; absent for hosts that don't wire\n * skills (restoration then re-injects files only).\n */\n getActiveSkills?: () => readonly ActiveSkill[]\n /**\n * Wall-clock start time of the run (`Date.now()` when `runLoop` was invoked).\n * Used to compute `AgentStats.timeTillFirstTokenMs`.\n */\n runStartMs: number\n /** Session bound to this run, if any. Forwarded into `ToolContext.session`. */\n session?: Session\n /**\n * Explicit read-state map. Forwarded into `ToolContext.readState` and\n * preferred over the `Session`-keyed lookup when both are present.\n * Set by `spawn`'s `shareReadState: true` opt-in (via the child agent's\n * `AgentOptions.readState`) so a sessionless child still feeds the\n * parent's `requireReadBeforeEdit` tracking.\n */\n readState?: ReadStateMap\n /**\n * Durable tool-state controller for the owning agent. Forwarded into\n * `ToolContext.state` (one staging view per call) and committed by the\n * dispatch path once the call settles — sequentially right after the\n * body, and for durable fleets in call-index order (never completion\n * order, so the store sees a deterministic write sequence). Absent for\n * hosts that never touch tool state; tools then see `ctx.state`\n * undefined.\n */\n toolState?: ToolStateController\n /**\n * Parent run id when this run is a subagent. Forwarded into\n * `ToolContext.parentRunId` and every `ToolHookContext.parentRunId`\n * / `McpToolHookContext.parentRunId` fired during the run, so\n * observability consumers can stitch sub-trees to their owners\n * without resolving the run row.\n */\n parentRunId?: string\n /**\n * Tool-call id of the `spawn` call that created this run. Forwarded into\n * `ToolContext.parentCallId` and every `ToolHookContext.parentCallId` /\n * `McpToolHookContext.parentCallId` fired during the run, so hosts can\n * attribute a child's tool call to the spawn call that owns it. Set by the\n * built-in `spawn` tool for every child regardless of session sharing\n * (unlike `parentRunId`); absent when the caller of `agent.run` didn't\n * supply it.\n */\n parentCallId?: string\n /** Subagent depth for this run. Forwarded into `ToolContext.depth`. */\n depth?: number\n /**\n * Per-tool call counter for this run. Mutated by the dispatch path; surfaced\n * (frozen snapshot) on `tool:*` and `turn:after` hook contexts. Counts every\n * call the model dispatched — including ones short-circuited by a `tool:gate`\n * `result` substitution. Excludes calls a gate explicitly `block`ed.\n *\n * Scope: per-`runId`. Resumed sessions start a fresh counter.\n */\n runToolCounts: Record<string, number>\n /** Provider name forwarded into `AgentToolPairingError` for strict-mode throws. */\n providerName?: string\n /**\n * Optional mutable mirror of the run-cumulative usage, updated after\n * every completed turn. `runLoop` returns its accumulated `AgentStats`\n * only on clean exits — when the loop THROWS (mid-stream abort, budget\n * breach), the caller would otherwise have no access to the tokens\n * already burned. `agent.run()` passes a mirror and reads it on the\n * catch paths so `agent:done` / `session.abortRun` carry real numbers\n * instead of zeros.\n */\n usageMirror?: RunUsageMirror\n /**\n * Per-callId cancellation registry shared with the agent so an external\n * `agent.cancelTool(callId)` can flip a single in-flight tool's signal\n * without aborting the whole run. The loop registers a controller for each\n * call right before gate/execute and unregisters it in a `finally` — so the\n * live set only ever holds *currently dispatching* calls. The registry also\n * applies kills parked before a call dispatched (the pre-registration race).\n *\n * When undefined, per-call cancellation is unavailable; the loop still\n * honors `ctx.signal` (run / sibling abort) the same way.\n */\n toolCancels?: ToolCancelRegistry\n /**\n * Set on the derived context a nested call (`ToolContext.callTool`) is\n * dispatched with: the id of the calling tool call. See\n * `src/loop-nested-calls.ts`.\n */\n nestedParentCallId?: string\n /**\n * On a nested call: what the caller passed for each of its calls\n * (`NestedToolCallOptions.line` / `streamProgress`), by call id.\n */\n nestedCallOptions?: (callId: string) => { line?: number, streamProgress?: boolean } | undefined\n /**\n * On a batch of nested calls: where each call's `reportStructured` value\n * goes (the batch path returns plain `ToolResult`s), by call id.\n */\n nestedStructured?: (callId: string, value: unknown) => void\n /**\n * On a nested call: tells the calling tool that this call's step answered\n * `interrupted` (a pending unsafe call, or a record of another call), so\n * the whole calling tool is reported interrupted.\n */\n nestedInterrupted?: () => void\n /**\n * Where the context-overflow rescue remembers its cutoff. Later turns\n * re-apply the same stubs before sending instead of being rejected again.\n * Pass the agent runtime's holder to keep it across runs of the same agent;\n * when absent, the loop creates one on first rescue and it lives for this\n * run only.\n */\n overflowRescue?: OverflowRescueState\n /**\n * The extension interceptor chains (`AgentOptions.extensionRuntime`).\n * Read by the retry decision, compaction and the tools' execution context;\n * absent without an extension runtime.\n */\n interceptors?: InterceptorRegistry\n}\n\n/** What the context-overflow rescue stubbed, re-applied on later turns. */\nexport interface OverflowCutoff {\n /** Absolute index into the turn's wire message list: every message before it carries the rescue's stubs. */\n index: number\n /** Whether base64 media before `index` became markers. */\n media: boolean\n /** Whether `tool_result` text before `index` became stubs. */\n toolResults: boolean\n /** History the index points into (`overflowCutoffAnchor`); a different anchor drops the cutoff. */\n anchor: string\n}\n\n/**\n * Mutable holder for the remembered {@link OverflowCutoff}, shared by\n * reference between the agent runtime and each run's {@link LoopContext}.\n */\nexport interface OverflowRescueState {\n /** The current cutoff; absent until the first rescue or after a reset. */\n cutoff?: OverflowCutoff\n}\n\n/**\n * Mutable run-usage accumulator shared between `runLoop` and its caller.\n * See {@link LoopContext.usageMirror}.\n */\nexport interface RunUsageMirror {\n totalIn: number\n totalOut: number\n totalCacheRead: number\n totalCacheCreation: number\n turns: number\n cost: number\n turnUsage: TurnUsage[]\n}\n\n/**\n * Writer that routes a persisted tool-result blob through the run's execution\n * context, so the spill lands on the SAME filesystem `read_file` reads it back\n * from (`ctx.execution.readFile`) — correct for docker / sandbox / remote /\n * edge contexts, not just the host process. Shared by the eager\n * ({@link maybePersistToolResult}) and persist-on-elide\n * ({@link persistElidedToolResults}) paths so the routing lives in one place.\n * A confined process context that refuses the path falls back to the host\n * (see {@link writePersistedBlob}).\n */\nexport function executionBlobWriter(ctx: LoopContext): (path: string, content: string) => Promise<void> {\n return (path, content) => writePersistedBlob(ctx.execution, ctx.handle, path, content, err => isControlError(ctx, err))\n}\n","/**\n * Stale-read handling: eliding `read_file` outputs superseded by a later\n * edit (`'stub'` policy), append-only staleness notices (`'notice'` policy),\n * and the read-state invalidation every eliding pass must perform.\n */\n\nimport type { ToolCall, ToolResult } from './providers'\nimport type { Session } from './session'\nimport type { ReadStateMap } from './tools/read-state'\nimport type { SessionMessage, SessionTurn, ToolResultContent } from './types'\nimport { PERSISTED_STUB_PREFIX } from './loop-persistence'\nimport { readFileInputPaths } from './tools/read-file-targets'\nimport { markReadStateElided } from './tools/read-state'\n\n/** Text that replaces a `read_file` result superseded by a later edit of the same path. */\nexport const STALE_READ_STUB = '[…elided: this file was edited later in the run, so this earlier read is stale.]'\n\nexport interface StaleReadElisionResult {\n messages: SessionMessage[]\n /**\n * Paths whose reads were stubbed this pass. The caller invalidates the\n * matching read-state entries so the next `read_file` misses its own\n * dedup (which would otherwise return the \"unchanged\" replay stub — see\n * `src/tools/read-file.ts`) and emits fresh content; the next edit's\n * read-before-edit guard fails so the model re-reads before re-editing.\n * Without this, both stubs combine to leave the model with zero visible\n * content for a path it has both read and edited.\n */\n elidedPaths: string[]\n}\n\nexport interface StaleReadElisionOptions {\n /**\n * Quantize the elision frontier to multiples of this many messages, so the\n * rewritten prefix `[0, cutoff)` is byte-identical across the next `chunk`\n * requests instead of advancing the instant a read goes stale.\n *\n * Defaults to 1 (no quantization) and THE LOOP DOES NOT SET IT. On a measured\n * 129-turn production trace quantizing was a net loss — 16 prefix rewrites and\n * 0.27M re-billed chars at `chunkTurns: 8`, against 13 and 0.25M unquantized —\n * because this pass is already self-limiting and deferring detection splits one\n * logical staleness event across frontier boundaries. See the header comment.\n *\n * Offered for workloads with the opposite shape: staleness events that are both\n * frequent and spread over many distinct paths, where batching genuinely merges\n * them. Measure before enabling.\n *\n * Rounding DOWN leaves recent reads un-stubbed, so the model may hold stale\n * content a few turns longer. Write safety does not depend on this pass —\n * `requireReadBeforeEdit` compares content hashes, so an edit built on a stale\n * read still fails its gate.\n */\n chunkTurns?: number\n}\n\n/**\n * Replace `read_file` `tool_result` blocks with a short stub when a later\n * successful `edit` / `multi_edit` / `write_file` modified the same path.\n *\n * Eliminates the common waste pattern where the model carries the pre-edit\n * file body forward across many turns. Operates on the wire-level message\n * list only — the persisted session keeps the original content.\n *\n * Detection is conservative: success is gated on the corresponding\n * tool_result starting with `Edited ` (edit / multi_edit) or `Created ` /\n * `Updated ` (write_file). Failed edits and `No change needed` writes do\n * NOT invalidate prior reads — the file content is still what the read\n * returned.\n *\n * Pure function, exported for tests and so downstream tooling can preview\n * elision without spinning up the loop.\n *\n * Cache cost, and why this pass is NOT frontier-quantized like its neighbours:\n *\n * A stub rewrites the prefix at the earliest position any stale read sits — in a\n * read-then-edit run, near message 1. A prefix cache hashes\n * tools → system → messages cumulatively, so that invalidates the whole\n * conversation, and the miss reads as a suspiciously CONSTANT `cacheRead` (the\n * scaffold still matches) rather than a zero one.\n *\n * The saving grace is that stubbing is idempotent per read: once a path's\n * earlier reads carry the stub, every later edit to that path changes nothing.\n * Real runs edit a small set of files repeatedly, so distinct staleness events\n * are rare — 13 across a measured 129-turn production trace. Snapping the\n * frontier to a chunk (as `applyTailCompaction` does, for good reason) made that\n * WORSE, not better: 16 breaks, because each advance discovers a fresh batch and\n * splits one logical event across boundaries. See the call site in the loop.\n *\n * `chunkTurns` therefore exists but defaults to off. It only pays when staleness\n * events are both frequent and spread across many distinct paths.\n */\nexport function applyStaleReadElision(\n messages: SessionMessage[],\n options?: StaleReadElisionOptions,\n): StaleReadElisionResult {\n if (messages.length === 0)\n return { messages, elidedPaths: [] }\n\n // Snap the frontier DOWN to a chunk multiple. Reads at or after the cutoff\n // stay visible even when stale, so the bytes below it don't move every turn.\n //\n // Below one full chunk the whole list is in scope (`cutoff = length`): the\n // frontier still advances every turn there, but the prefix it rewrites is a\n // handful of messages, so the cache cost is negligible — and short\n // conversations keep the immediate staleness signal.\n // Quantization only kicks in once there's a prefix worth protecting.\n const chunk = Math.max(1, options?.chunkTurns ?? 1)\n const cutoff = messages.length <= chunk\n ? messages.length\n : Math.floor(messages.length / chunk) * chunk\n\n // Map call_id → tool_result string (for success-marker checks).\n const resultByCallId = new Map<string, string>()\n for (const msg of messages) {\n for (const block of msg.content) {\n if (block.type === 'tool_result' && typeof block.output === 'string')\n resultByCallId.set(block.callId, block.output)\n }\n }\n\n // For each path, the highest message index where a successful mutation\n // landed. `read_file` tool_results whose corresponding read happened\n // BEFORE that index (for the same path) are stale.\n const maxMutationIdxByPath = new Map<string, number>()\n // call_id → { paths, msgIdx } for read_file calls (a `paths` batch reads\n // several files; the whole result goes stale when any of them does).\n const readCallInfo = new Map<string, { paths: string[], msgIdx: number }>()\n\n // Bounded by the quantized frontier on BOTH sides — reads AND mutations. If\n // only the read side were bounded, a fresh edit arriving at the tail could\n // still stale a read below the frontier and rewrite the prefix mid-chunk,\n // which is precisely the pattern quantization exists to stop (edits keep\n // landing at the tail all run). Deciding purely from information below the\n // cutoff freezes the stub set for the whole chunk.\n for (let i = 0; i < cutoff; i++) {\n for (const block of messages[i].content) {\n if (block.type !== 'tool_call')\n continue\n if (block.name === 'read_file') {\n const paths = readFileInputPaths(block.input)\n if (paths.length > 0)\n readCallInfo.set(block.id, { paths, msgIdx: i })\n continue\n }\n const path = (block.input as { path?: unknown }).path\n if (typeof path !== 'string')\n continue\n\n if (!isSuccessfulMutation(block.name, resultByCallId.get(block.id)))\n continue\n\n const prior = maxMutationIdxByPath.get(path)\n if (prior === undefined || i > prior)\n maxMutationIdxByPath.set(path, i)\n }\n }\n\n if (maxMutationIdxByPath.size === 0)\n return { messages, elidedPaths: [] }\n\n // call_ids whose read happened before that path's last successful mutation.\n const staleCallIds = new Set<string>()\n const elidedPathSet = new Set<string>()\n for (const [callId, info] of readCallInfo) {\n // `readCallInfo` and `maxMutationIdxByPath` are already frontier-bounded by\n // the scan above, so no further index check is needed here.\n const stale = info.paths.some((path) => {\n const lastMutationIdx = maxMutationIdxByPath.get(path)\n return typeof lastMutationIdx === 'number' && info.msgIdx < lastMutationIdx\n })\n if (stale) {\n staleCallIds.add(callId)\n for (const path of info.paths)\n elidedPathSet.add(path)\n }\n }\n\n if (staleCallIds.size === 0)\n return { messages, elidedPaths: [] }\n\n // Paths that ALSO have a non-stale read (i.e. a read whose msgIdx\n // is at or after the path's last mutation). These shouldn't be\n // invalidated by the caller: the fresh read already populated the\n // read-state entry with the post-mutation hash, and invalidating\n // would nuke it — making the next edit's `requireReadBeforeEdit`\n // gate fire \"has not been read\" on a file the model demonstrably\n // re-read after the previous edit. The wire-level stub for the\n // stale read still rides; only the in-memory tracking is kept.\n const pathsWithFreshRead = new Set<string>()\n for (const [callId, info] of readCallInfo) {\n if (!staleCallIds.has(callId)) {\n for (const path of info.paths)\n pathsWithFreshRead.add(path)\n }\n }\n\n let changed = false\n const out = messages.slice()\n for (let i = 0; i < out.length; i++) {\n const msg = out[i]\n let msgChanged = false\n const newContent = msg.content.map((block) => {\n if (block.type !== 'tool_result' || !staleCallIds.has(block.callId))\n return block\n // Idempotent: a second pass over an already-elided message must not\n // bump `changed`, otherwise the function would always allocate a new\n // array (no-op-but-not-stable). Match the exact stub string.\n if (block.output === STALE_READ_STUB)\n return block\n // Mirror of the `applyTailCompaction` guard in `loop-compaction.ts`:\n // a `<persisted-output …>` stub carries the path to the\n // on-disk blob. Replacing it with `STALE_READ_STUB` would drop\n // the path attribute, stranding the blob (still on disk until\n // session delete, but no longer reachable from the conversation).\n // The model already gets the staleness signal via the next\n // `read_file` call missing the read-state dedup; preserving the\n // stub keeps the persistence pointer intact.\n if (typeof block.output === 'string' && block.output.startsWith(PERSISTED_STUB_PREFIX))\n return block\n // Structured outputs (image reads via `read_file`) are intentionally\n // also collapsed to the string stub: the bytes ARE stale once the\n // path was overwritten, the marker explicitly tells the model to\n // re-read, and `output: string | ToolResultContent[]` accepts a\n // string. Downstream image-flattening for non-vision providers is\n // a no-op on strings.\n msgChanged = true\n changed = true\n return { ...block, output: STALE_READ_STUB }\n })\n if (msgChanged)\n out[i] = { ...msg, content: newContent }\n }\n return {\n messages: changed ? out : messages,\n elidedPaths: [...elidedPathSet].filter(p => !pathsWithFreshRead.has(p)),\n }\n}\n\n// ---------------------------------------------------------------------------\n// Stale reads — `'notice'` policy (append-only)\n// ---------------------------------------------------------------------------\n\n// The append-only alternative to `applyStaleReadElision`: instead of rewriting\n// the stale read's tool_result on the wire, a `<system-reminder>` naming the\n// stale paths is appended to the mutating tool's OWN result at the moment the\n// mutation succeeds. That result is brand-new transcript tail, so the notice is\n// persisted, immutable afterwards, and never touches bytes the provider has\n// already cached — the prompt cache cannot break.\n//\n// The economics that motivate this (measured against a 129-turn production\n// trace): stubbing pays `1.25x(prefix)` once per newly-stale read to save\n// `0.1x(staleBytes)` per later turn, which only breaks even after\n// `12.5 x prefix / staleBytes` turns — ~237 turns for a typical 2k-token read\n// against a 38k prefix. Keeping the stale bytes cached and telling the model\n// they are stale is strictly cheaper at realistic run lengths.\n//\n// IMPORTANT for maintainers: the notice must ride content that is (a) new this\n// turn and (b) persisted. A wire-only append to the newest message re-renders\n// WITHOUT the append on the following turn and diverges the prefix there\n// instead — the exact break this policy exists to avoid.\n\n/**\n * Whether a tool call changed its file: an edit / multi_edit / write_file\n * whose string result carries the tool's success marker — see edit.ts\n * (`Edited ${target}: replaced …`), multi-edit.ts (`Edited ${target}:\n * applied …`), write-file.ts (`Created … (N bytes)` / `Updated … (N\n * bytes)`). The TUI's `tool:transform` hook may append an `<edit-outcomes>`\n * annotation block to multi_edit results, but the prefix is preserved. Failed\n * edits and `No change needed` writes do not count. Shared by the elision and\n * notice policies so they never drift on what counts as a mutation.\n */\nfunction isSuccessfulMutation(name: string, output: unknown): boolean {\n if (typeof output !== 'string')\n return false\n if (name === 'edit' || name === 'multi_edit')\n return output.startsWith('Edited ')\n if (name === 'write_file')\n return output.startsWith('Created ') || output.startsWith('Updated ')\n return false\n}\n\n/**\n * Paths whose earlier reads were NEWLY made stale by this batch's successful\n * mutations — i.e. the prior transcript holds a `read_file` of the path that\n * is more recent than the path's last successful mutation. Reads older than\n * that mutation were already noticed when it landed, so repeated edits to the\n * same file yield exactly one notice per read→edit transition, not one per\n * edit.\n *\n * Pure; mirrors {@link applyStaleReadElision}'s detection exactly (same tool\n * names, same success markers) so the two policies never drift on WHAT counts\n * as stale — only on how the staleness is represented.\n *\n * @param priorTurns - Transcript turns that precede the current batch.\n * @param batch - Tool calls of the current batch, with their target path and output.\n */\nexport function collectNewlyStaleReadPaths(\n priorTurns: readonly Pick<SessionTurn, 'content'>[],\n batch: readonly { name: string, path: unknown, output: string | ToolResultContent[] }[],\n): string[] {\n const mutated = new Map<string, true>()\n for (const call of batch) {\n if (typeof call.path !== 'string' || mutated.has(call.path))\n continue\n if (isSuccessfulMutation(call.name, call.output))\n mutated.set(call.path, true)\n }\n if (mutated.size === 0)\n return []\n\n // Walk the prior transcript once, tracking per path whether a read has\n // landed since the last successful mutation. Order inside a message is\n // irrelevant at this granularity — reads and mutations of the same path in\n // the same message are treated as read-then-mutate, matching the elision\n // pass's index comparison.\n const resultByCallId = new Map<string, string>()\n for (const msg of priorTurns) {\n for (const block of msg.content) {\n if (block.type === 'tool_result' && typeof block.output === 'string')\n resultByCallId.set(block.callId, block.output)\n }\n }\n\n const hasUnnoticedRead = new Map<string, boolean>()\n for (const msg of priorTurns) {\n for (const block of msg.content) {\n if (block.type !== 'tool_call')\n continue\n if (block.name === 'read_file') {\n for (const readPath of readFileInputPaths(block.input)) {\n if (mutated.has(readPath))\n hasUnnoticedRead.set(readPath, true)\n }\n continue\n }\n const path = (block.input as { path?: unknown }).path\n if (typeof path !== 'string' || !mutated.has(path))\n continue\n if (isSuccessfulMutation(block.name, resultByCallId.get(block.id)))\n hasUnnoticedRead.set(path, false)\n }\n }\n\n return [...mutated.keys()].filter(path => hasUnnoticedRead.get(path) === true)\n}\n\n/**\n * The notice text appended to a mutating tool's result under the `'notice'`\n * policy. Deterministic and free of counters/timestamps — append-only content\n * cannot break the cache, but a stable template keeps transcripts diffable and\n * the tests byte-exact.\n *\n * @param paths - Stale file paths, in the order they should be listed.\n */\nexport function renderStaleReadNotice(paths: readonly string[]): string {\n const listing = paths.map(path => `- ${path}`).join('\\n')\n return `<system-reminder>Earlier read_file results for the following path(s) predate this change and are now stale:\\n${listing}\\nDo not rely on those earlier file bodies. Re-read a file (or Grep the relevant slice) before reasoning about its current content.</system-reminder>`\n}\n\n/**\n * Loop-side wiring for the `'notice'` policy: detect which paths this batch\n * newly staled and append one combined notice to the LAST successful mutating\n * result in the batch. Mutates `results` in place — they have not yet become a\n * turn, so this is the append-only window.\n *\n * Same-batch reads are excluded from staleness (a `read_file` and an `edit` of\n * the same path issued together), matching `applyStaleReadElision`, which\n * compares message indices and treats same-message reads as fresh.\n *\n * Signalling only — the re-read this notice asks for serves the fresh body\n * because the mutating tools mark their read-state entry `elided` when they\n * refresh the content hash (see `src/tools/edit.ts`), independent of any\n * stale-read policy.\n */\nexport function appendStaleReadNotices(\n priorTurns: readonly SessionTurn[],\n calls: readonly ToolCall[],\n results: ToolResult[],\n): void {\n const contentById = new Map<string, string | ToolResultContent[]>()\n for (const result of results)\n contentById.set(result.id, result.content)\n\n const batchIds = new Set(calls.map(call => call.id))\n const batch = calls.map(call => ({\n name: call.name,\n path: call.input.path,\n output: contentById.get(call.id) ?? '',\n }))\n\n const stalePaths = collectNewlyStaleReadPaths(\n priorTurns.filter(turn => !turn.content.some(b => b.type === 'tool_call' && batchIds.has(b.id))),\n batch,\n )\n if (stalePaths.length === 0)\n return\n\n // Attach to the last mutating result whose path is in the stale set, so the\n // notice sits next to the change that caused it. String results only — edit\n // and write_file produce strings by construction; anything else is left\n // alone rather than guessed at.\n for (let i = results.length - 1; i >= 0; i--) {\n const call = calls.find(c => c.id === results[i].id)\n if (!call || typeof call.input.path !== 'string' || !stalePaths.includes(call.input.path))\n continue\n if (typeof results[i].content !== 'string')\n continue\n results[i] = { ...results[i], content: `${results[i].content}\\n\\n${renderStaleReadNotice(stalePaths)}` }\n return\n }\n}\n\n/**\n * Flag read-state entries for paths whose reads got elided. Keys are\n * canonical absolute paths produced by `readStateKey(cwd, path)` (see\n * `src/tools/read-state.ts`); the loop has `ctx.handle.cwd` in scope,\n * so we re-derive each elided path's canonical key and mark by direct\n * lookup. No suffix matching, no cross-cwd ambiguity.\n *\n * Marks, does NOT delete. Deleting the entry would make the\n * `requireReadBeforeEdit` gate reject the model's very next edit on a\n * file it had just read and edited (\"has not been read in this session\"\n * on a demonstrably-read file). That failure mode defeats the guard\n * itself: models degrade to raw shell one-liner edits that bypass the\n * gate entirely. The entry must therefore survive elision — its\n * contentHash still guards against on-disk drift, which is the\n * corruption the gate exists to prevent.\n *\n * Deletion would serve `dedupReads` honesty: a post-elision\n * re-read would dedup-hit (entry hash == current disk hash) and return\n * the \"unchanged since the previous read\" stub while the only on-wire\n * read is the elision stub — leaving the model with zero visible content\n * for the path (the trap described on `StaleReadElisionResult.\n * elidedPaths`). The `elided` flag solves that more surgically:\n * `read_file`'s dedup check misses on flagged entries and serves the\n * full body again, then clears the flag. Paths the model re-read after\n * the mutation are exempt via `pathsWithFreshRead`. The marking re-fires\n * on later turns while the elided read remains the path's newest on-wire\n * read, keeping an edit-only refresh from re-arming the dedup trap.\n */\nexport function markReadStateForElidedPaths(\n ctx: { session?: Session, readState?: ReadStateMap },\n cwd: string,\n elidedPaths: readonly string[],\n): void {\n if (elidedPaths.length === 0)\n return\n if (!ctx.readState && !ctx.session)\n return\n for (const p of elidedPaths)\n markReadStateElided(ctx, cwd, p)\n}\n","import type { AgentBehavior } from '../types'\n\n/**\n * Compute the effective thinking budget for a given run-relative turn, given\n * the configured decay schedule. Pure helper exported for tests and downstream\n * tooling that wants to preview decay curves without spinning up the loop.\n *\n * - No positive `baseBudget` -> returns `baseBudget` unchanged (`undefined`\n * stays `undefined`). Decay never invents a budget.\n * - No `decay` -> identity (`baseBudget`).\n * - Function form -> `decay(turn, baseBudget)`. The return is clamped to\n * `[0, baseBudget]` so a buggy curve can't request more budget than the\n * caller explicitly opted into.\n * - Geometric form `{ afterTurn, factor, floor }` -> for `turn <= afterTurn`,\n * returns `baseBudget`. For `turn > afterTurn`, returns\n * `max(floor, baseBudget * factor^(turn - afterTurn))` clamped to\n * `[floor, baseBudget]`.\n * - Step form `{ afterTurn, floor }` (no `factor`) -> `baseBudget` through\n * `afterTurn`, then `floor` for the rest of the run. Exactly one distinct\n * value change — and therefore exactly one prompt-cache invalidation, since\n * `thinking.budget_tokens` is part of Anthropic's cache key (measured; see\n * `AgentBehavior.thinkingDecay`). Prefer it when caching is on.\n *\n * Result is rounded to the nearest integer; token counts are integers.\n */\nexport function applyThinkingDecay(\n baseBudget: number | undefined,\n decay: AgentBehavior['thinkingDecay'] | undefined,\n turn: number,\n): number | undefined {\n if (typeof baseBudget !== 'number' || baseBudget <= 0)\n return baseBudget\n if (!decay)\n return baseBudget\n\n let raw: number\n if (typeof decay === 'function') {\n raw = decay(turn, baseBudget)\n }\n else {\n if (turn <= decay.afterTurn)\n return baseBudget\n raw = typeof decay.factor === 'number'\n ? Math.max(decay.floor, baseBudget * decay.factor ** (turn - decay.afterTurn))\n : decay.floor\n }\n\n // Decay reduces; never raises above the caller's explicit budget. NaN and\n // negative values collapse to 0 so bad curves do not leak into providers.\n if (Number.isNaN(raw) || raw <= 0)\n return 0\n return Math.round(Math.min(baseBudget, raw))\n}\n","/**\n * Provider stream I/O for a single attempt: watchdog-bounded streaming,\n * Anthropic thinking-history repair, provider error wrapping, and the\n * stream-failure placeholders/metadata the turn's terminal path persists.\n */\n\nimport type { StepLive } from './durable/types'\nimport type { ClassifiedError } from './errors'\nimport type { LoopContext } from './loop-context'\nimport type { ProviderWatchdogKind } from './loop-recovery'\nimport type { HistoryRepair, Provider, TurnResult as ProviderTurnResult, StreamCallbacks, StreamOptions } from './providers'\nimport type { LiveStepWork } from './run-durability'\nimport type { InputTransformationsHookContext, JsonValue, SessionContentBlock } from './types'\nimport { withStepDecision } from './durable/errors'\nimport { AgentAbortedError, AgentContextExceededError, AgentProviderError, AgentToolPairingError, errorMessage, toTypedError } from './errors'\nimport { rethrowControlError, settledHook, throwIfSuspended } from './loop-context'\nimport { PROVIDER_WATCHDOG_OPERATIONS } from './loop-recovery'\nimport { httpFetchWrapper } from './providers/http-intercept'\nimport { LOOP_STEP_KINDS, recordsSteps } from './run-durability'\nimport { hasAnthropicSignature } from './session/messages'\nimport { linkAbortSignal, OperationTimeoutError, resolveTimeoutMs } from './timeout'\n\nconst DEFAULT_PROVIDER_STREAM_START_TIMEOUT_MS = 5 * 60 * 1000\nconst DEFAULT_PROVIDER_STREAM_TIMEOUT_MS = 30 * 60 * 1000\n\n/**\n * The typed error a provider failure surfaces as, built from the one\n * classification the loop made of it: its message the classifier's (a rate\n * limit reads `Claude rate limit reached. Resets in …`, the raw body stays\n * on `.cause`). An already typed error passes through; `trail` (see\n * {@link fallbackTrail}) goes on a new error, never on one the caller owns.\n *\n * @param err - What the provider threw.\n * @param classified - The provider's classification of `err`, or `null`.\n * @param provider - The provider that failed.\n * @param trail - Suffix naming the fallback chain's earlier failures.\n */\nexport function surfaceProviderFailure(err: unknown, classified: ClassifiedError | null, provider: Provider, trail = ''): Error {\n if (err instanceof AgentProviderError) {\n return trail\n ? new AgentProviderError(err.message + trail, { provider: err.provider, providerCode: err.providerCode, retryable: err.retryable, limit: err.limit, cause: err.cause })\n : err\n }\n if (err instanceof AgentAbortedError || err instanceof AgentContextExceededError || err instanceof AgentToolPairingError)\n return err\n const message = (classified?.message ?? errorMessage(err)) + trail\n return classified\n ? toTypedError({ ...classified, message }, provider.name, err)\n : new AgentProviderError(message, { provider: provider.name, cause: err })\n}\n\n/**\n * Chain-exhaustion visibility: the surfaced error is the LAST target's, but\n * the actionable failure is often an earlier one (the primary's auth or\n * billing error, say). A compact per-target trail lets the host see every\n * failure without wiring a `model:fallback` handler. Empty when no earlier\n * target failed.\n *\n * @param failures - The run's earlier target failures.\n */\nexport function fallbackTrail(failures: LoopContext['targetFailures']): string {\n if (!failures || failures.length === 0)\n return ''\n const trail = failures\n .map(f => `${f.provider}/${f.model}: ${errorMessage(f.err).replace(/\\s+/g, ' ').slice(0, 160)}`)\n .join('; ')\n return ` [fallback chain — earlier targets also failed: ${trail}]`\n}\n\n/** A failure outside the turn's recovery (the schema call): aborted, else surfaced with the chain's trail. */\nexport function wrapProviderError(err: unknown, ctx: LoopContext): Error {\n if (ctx.signal.aborted || (err instanceof Error && err.name === 'AbortError'))\n return new AgentAbortedError('Agent run aborted', { cause: err })\n return surfaceProviderFailure(err, ctx.provider.classifyError?.(err) ?? null, ctx.provider, fallbackTrail(ctx.targetFailures))\n}\n\n/**\n * Resolve the stream watchdog limits in ms from `behavior`. `0` disables a\n * watchdog. Each limit is capped by `behavior.maxWallMs`. The first-response\n * and total-stream limits default to 5 and 30 minutes. The idle limit\n * defaults to off.\n */\nfunction providerWatchdogTimeouts(ctx: LoopContext): {\n startTimeoutMs: number\n totalTimeoutMs: number\n idleTimeoutMs: number\n} {\n return {\n startTimeoutMs: resolveTimeoutMs(\n ctx.behavior.providerStreamStartTimeoutMs,\n DEFAULT_PROVIDER_STREAM_START_TIMEOUT_MS,\n ctx.behavior.maxWallMs,\n ),\n totalTimeoutMs: resolveTimeoutMs(\n ctx.behavior.providerStreamTimeoutMs,\n DEFAULT_PROVIDER_STREAM_TIMEOUT_MS,\n ctx.behavior.maxWallMs,\n ),\n // Disabled unless the host opts in — legitimate silent gaps exist\n // (server-side tool execution, providers that emit nothing until done).\n idleTimeoutMs: resolveTimeoutMs(\n ctx.behavior.providerStreamIdleTimeoutMs,\n 0,\n ctx.behavior.maxWallMs,\n ),\n }\n}\n\nfunction stripInvalidAnthropicThinking(content: readonly SessionContentBlock[]): {\n content: SessionContentBlock[]\n removed: number\n} {\n let removed = 0\n const kept = content.filter((block) => {\n if (block.type === 'redacted_thinking') {\n removed += 1\n return false\n }\n if (hasAnthropicSignature(block)) {\n removed += 1\n return false\n }\n return true\n })\n return {\n content: kept.length > 0\n ? kept\n : [{ type: 'text', text: '[historical reasoning omitted]' }],\n removed,\n }\n}\n\n/** In-memory outcome of one thinking-signature repair pass. */\ninterface ThinkingRepairResult {\n /** Reasoning blocks removed across runtime + session turns. */\n removed: number\n /** Ids of the turns whose content changed. */\n turnIds: Set<string>\n}\n\n/**\n * Quarantine historical Anthropic reasoning after the API proves its opaque\n * signature is invalid. Runtime turns and the bound session are separate\n * arrays on resume, so repair both — IN MEMORY ONLY. Durable persistence\n * (`session.save()`) is deliberately deferred to the stream-settle boundary\n * in {@link streamWithWatchdogs}: this function runs inside the provider's\n * `stream()` call stack, which a replay-mode durable runtime records as a\n * model step, where the runtime's context cannot be touched — an inline\n * save would silently no-op there and the session would re-poison on every\n * run.\n *\n * Turns minted by the CURRENT run are never touched: their signatures are\n * fresh (same account/model that is streaming right now), and Anthropic\n * requires the active tool-use chain's thinking blocks to be echoed back —\n * stripping them would trade one 400 for another. An invalid signature is\n * by definition historical (prior run, prior account, or a session edit).\n */\nfunction repairInvalidAnthropicThinkingHistory(\n ctx: LoopContext,\n streamOptions: StreamOptions,\n repair: HistoryRepair,\n): ThinkingRepairResult {\n const turnIds = new Set<string>()\n let removed = 0\n for (const turn of ctx.turns) {\n if (turn.runId === ctx.runId)\n continue\n const scrubbed = stripInvalidAnthropicThinking(turn.content)\n if (scrubbed.removed === 0)\n continue\n turn.content = scrubbed.content\n removed += scrubbed.removed\n if (turn.id !== undefined)\n turnIds.add(turn.id)\n }\n\n // Keep retries outside the provider (watchdog/network/fallback handling)\n // clean even though the provider's immediate internal retry already uses\n // its own scrubbed wire payload. Wire messages carry no run identity, so\n // bound the scrub by the API-reported failing index when the provider\n // parsed one — blocks after it may be this run's still-valid thinking.\n const limit = repair.wireMessageIndex\n streamOptions.messages = streamOptions.messages.map((message, index) => {\n if (limit !== undefined && index > limit)\n return message\n const scrubbed = stripInvalidAnthropicThinking(message.content)\n return scrubbed.removed > 0 ? { ...message, content: scrubbed.content } : message\n })\n\n const session = ctx.session\n if (!session)\n return { removed, turnIds }\n\n let sessionRemoved = 0\n const sessionTurns = session.turns.map((turn) => {\n if (turn.runId === ctx.runId)\n return turn\n const scrubbed = stripInvalidAnthropicThinking(turn.content)\n sessionRemoved += scrubbed.removed\n if (scrubbed.removed > 0 && turn.id !== undefined)\n turnIds.add(turn.id)\n return scrubbed.removed > 0 ? { ...turn, content: scrubbed.content } : turn\n })\n // On a simple resume, `ctx.turns` contains the SAME turn objects as\n // `session.turns`; the runtime pass above may therefore clean the session\n // objects before this map sees them. `removed > 0` still means the backing\n // store is stale and MUST be overwritten.\n if (sessionRemoved === 0 && removed === 0)\n return { removed: 0, turnIds }\n\n // In-memory replacement only — see the deferred-persistence contract in\n // the doc comment. `session:turns` is append-only notification semantics;\n // do NOT emit the full replacement snapshot there (hosts would append\n // duplicates).\n session.setTurns(sessionTurns)\n return { removed: removed + sessionRemoved, turnIds }\n}\n\n/**\n * Flush a deferred thinking-signature repair at the stream-settle boundary:\n * persist the already-repaired session and fire the host-facing\n * `history:repair` hook. Runs OUTSIDE the provider call stack (safe for\n * journaled hosts) and on both stream outcomes — a scrubbed block is\n * invalid regardless of whether the retry ultimately succeeded, and\n * persisting prevents the next run from re-poisoning.\n */\nasync function flushThinkingRepair(ctx: LoopContext, pending: ThinkingRepairResult): Promise<void> {\n let persisted = false\n // Store-less sessions THROW from `save()` by design — skip the attempt\n // (the in-memory repair is all the durability such a session has) rather\n // than routing every repair through the exception path and logging a\n // spurious \"failed\" line for expected behavior.\n if (ctx.session?.store) {\n try {\n await ctx.session.save()\n persisted = true\n }\n catch (err) {\n rethrowControlError(ctx, err)\n // The stream already recovered (or failed) on the scrubbed wire\n // payload; keep the in-memory repair and report `persisted: false`.\n if (process.env.ZIDANE_DEBUG)\n process.stderr.write(`[zidane/loop] persisting thinking-signature repair failed: ${errorMessage(err)}\\n`)\n }\n }\n await settledHook(ctx, 'hook history:repair', ctx.hooks.callHook('history:repair', {\n reason: 'invalid-anthropic-thinking-signature',\n runId: ctx.runId,\n ...(ctx.session ? { sessionId: ctx.session.id } : {}),\n turnIds: [...pending.turnIds],\n removedBlocks: pending.removed,\n persisted,\n }))\n}\n\n/**\n * The provider-facing callbacks of one watchdogged attempt: `callbacks` with\n * every observable event class feeding `markFirstObserved`, and every late\n * event dropped once the attempt has settled.\n */\nfunction watchdogCallbacks(\n callbacks: StreamCallbacks,\n isSettled: () => boolean,\n markFirstObserved: () => void,\n onServerToolActivity: (() => void) | undefined,\n): StreamCallbacks {\n return {\n ...callbacks,\n // Once the watchdog has settled (timed out, or the stream already\n // resolved/rejected), drop further deltas: a provider that ignores the\n // abort signal must not keep mutating an abandoned turn.\n onText(delta) {\n if (isSettled())\n return\n markFirstObserved()\n callbacks.onText(delta)\n },\n // Liveness handlers are subscribed UNCONDITIONALLY, whether or not\n // the caller supplied one: every observable event class must reach\n // `markFirstObserved`, otherwise a stream progressing only through\n // that class (thinking-only prefix, server-side tool execution,\n // tool-argument streaming) reads as silence and the start/idle\n // watchdogs abort an actively-progressing stream. Callers without a\n // handler still get the liveness accounting; forwarding is optional.\n onThinking(delta: string) {\n if (isSettled())\n return\n markFirstObserved()\n callbacks.onThinking?.(delta)\n },\n onServerToolUse(block: { id: string, name: string, input: Record<string, unknown> }) {\n onServerToolActivity?.()\n if (isSettled())\n return\n markFirstObserved()\n callbacks.onServerToolUse?.(block)\n },\n onServerToolResult(block: { toolUseId: string, toolName: string, content: unknown }) {\n onServerToolActivity?.()\n if (isSettled())\n return\n markFirstObserved()\n callbacks.onServerToolResult?.(block)\n },\n onToolCallDelta() {\n if (isSettled())\n return\n markFirstObserved()\n callbacks.onToolCallDelta?.()\n },\n // Not a liveness signal (usage can arrive in `message_start`, before\n // any output), but dropped after settling like the deltas: a late\n // snapshot would repopulate the abandoned turn's live usage.\n onUsage(usage) {\n if (isSettled())\n return\n callbacks.onUsage?.(usage)\n },\n }\n}\n\n/**\n * Run one `provider.stream()` attempt under the first-response, total-stream\n * and idle watchdogs. A watchdog that fires aborts the attempt and rejects with\n * an {@link OperationTimeoutError}. Any observable stream event counts as\n * activity. On an invalid Anthropic thinking signature it repairs the history\n * in memory and persists it, then fires `history:repair`, once the stream\n * settles.\n *\n * @param ctx - The run context. Its signal also aborts the attempt.\n * @param options - Provider request options. The attempt gets its own abort signal.\n * @param callbacks - Stream callbacks. Late events after a watchdog fires are dropped.\n * @param turnId - Turn id for hook contexts and timeout messages.\n * @param opts - Per-attempt overrides.\n * @param opts.startTimeoutCapMs - Tightens the first-response limit on retries.\n * @param opts.onServerToolActivity - Sees every server-tool event, even suppressed ones.\n * @param opts.onLiveFailure - Sees the provider's own error of a failed live attempt; may return the verdict to store with it.\n */\nexport async function streamWithWatchdogs(\n ctx: LoopContext,\n options: StreamOptions,\n callbacks: StreamCallbacks,\n turnId: string,\n opts?: {\n startTimeoutCapMs?: number\n /**\n * Fired for every server-tool event BEFORE the settled gate — an event\n * the provider SDK buffered past a watchdog timeout still represents a\n * tool that executed (and billed) server-side, so the retry path must\n * learn about it even though forwarding to the caller is suppressed.\n */\n onServerToolActivity?: () => void\n /**\n * Sees the provider's own error of a live attempt that failed, before\n * the step records it. Replay mode: the loop classifies that one, as the\n * error the step rejects with is rebuilt from its record. Checkpoint\n * mode: the verdict it returns is stored with the failure, for a resume.\n */\n onLiveFailure?: (err: unknown) => JsonValue | undefined\n },\n): Promise<ProviderTurnResult> {\n let { startTimeoutMs, totalTimeoutMs, idleTimeoutMs } = providerWatchdogTimeouts(ctx)\n // Tighten (never introduce) the first-response watchdog — see\n // RETRY_STREAM_START_TIMEOUT_CAP_MS. `startTimeoutMs === 0` means the\n // caller disabled the watchdog; the cap must not resurrect it.\n if (opts?.startTimeoutCapMs !== undefined && startTimeoutMs > 0)\n startTimeoutMs = Math.min(startTimeoutMs, opts.startTimeoutCapMs)\n const callerHistoryRepair = callbacks.onHistoryRepair\n // Provider-to-loop ownership boundary: providers identify a repair, the\n // loop mutates canonical turns in memory immediately (the provider's\n // scrubbed retry depends on it) and defers persistence + the\n // `history:repair` hook to the settle boundary below — this callback runs\n // inside the provider's stream() call stack, which a replay-mode runtime\n // records as a step and cannot safely persist from. Chain a host callback\n // rather than replacing it so direct loop embedders can observe the repair\n // too.\n let pendingRepair: ThinkingRepairResult | undefined\n const callerInputTransformations = callbacks.onInputTransformations\n callbacks = {\n ...callbacks,\n onDiagnostic(event) {\n void Promise.resolve(ctx.hooks.callHook('provider:diagnostic', { ...event, runId: ctx.runId, turnId })).catch(() => {})\n },\n onInputTransformations(transformations) {\n // Observational: a throwing host callback must not fail a settled turn.\n try {\n callerInputTransformations?.(transformations)\n }\n catch {}\n const info: InputTransformationsHookContext = {\n runId: ctx.runId,\n turnId,\n ...(ctx.session?.id ? { sessionId: ctx.session.id } : {}),\n transformations,\n prefixMismatches: transformations.filter(t => t.reason === 'prefix_binding_mismatch').length,\n modelMismatches: transformations.filter(t => t.reason === 'model_binding_mismatch').length,\n }\n void Promise.resolve(ctx.hooks.callHook('provider:input-transformations', info)).catch(() => {})\n },\n async onHistoryRepair(repair) {\n if (repair.type === 'invalid-anthropic-thinking-signature') {\n // The provider's scrub ladder may fire this once per retry pass;\n // merge so the settle-time flush reports the union exactly once.\n const result = repairInvalidAnthropicThinkingHistory(ctx, options, repair)\n if (result.removed > 0) {\n if (pendingRepair === undefined) {\n pendingRepair = result\n }\n else {\n pendingRepair.removed += result.removed\n for (const id of result.turnIds)\n pendingRepair.turnIds.add(id)\n }\n }\n }\n await callerHistoryRepair?.(repair)\n },\n }\n // One request under its watchdogs. On a run that records steps (replay\n // mode, or a checkpoint run) it runs as a step of the run, watchdogs\n // included, so a timeout is recorded like any other failure and a\n // replay gets the recorded outcome without asking the provider (no\n // second bill, no deltas, no timers).\n const attempt = (onProgress?: StepLive['onProgress']): Promise<ProviderTurnResult> => {\n const attemptAbort = new AbortController()\n const unlinkParentAbort = linkAbortSignal(ctx.signal, attemptAbort)\n // `Agent.suspend` stops the stream at once: the request is sent again on resume.\n const unlinkSuspend = ctx.suspendSignal ? linkAbortSignal(ctx.suspendSignal, attemptAbort) : undefined\n\n let settled = false\n let firstObserved = false\n let startTimer: ReturnType<typeof setTimeout> | undefined\n let totalTimer: ReturnType<typeof setTimeout> | undefined\n let idleTimer: ReturnType<typeof setTimeout> | undefined\n // Assigned inside the raced promise below; a no-op until the watchdogs\n // are armed so early deltas can't fire a half-initialized timeout.\n let onIdleTimeout: (() => void) | undefined\n\n const cleanup = () => {\n if (startTimer)\n clearTimeout(startTimer)\n if (totalTimer)\n clearTimeout(totalTimer)\n if (idleTimer)\n clearTimeout(idleTimer)\n unlinkParentAbort()\n unlinkSuspend?.()\n }\n\n // Every observable stream event resets the inactivity window. The idle\n // watchdog only arms after the first event: the pre-first-token window\n // belongs to `startTimeoutMs` (which retries cap tighter — the two would\n // otherwise race with conflicting semantics).\n //\n // Churn-free under high delta rates (mirrors `withInactivityTimeout`):\n // deltas only record a timestamp; the single timer lazily re-arms for the\n // remaining idle window when it wakes and finds recent activity, instead\n // of a clearTimeout/setTimeout pair per delta.\n let lastActivityAt = 0\n const armIdleTimer = (delayMs: number) => {\n idleTimer = setTimeout(() => {\n if (settled)\n return\n const idleMs = Date.now() - lastActivityAt\n if (idleMs < idleTimeoutMs) {\n armIdleTimer(idleTimeoutMs - idleMs)\n return\n }\n onIdleTimeout?.()\n }, delayMs)\n }\n const recordActivity = () => {\n if (idleTimeoutMs <= 0 || settled)\n return\n lastActivityAt = Date.now()\n if (idleTimer === undefined)\n armIdleTimer(idleTimeoutMs)\n }\n\n const markFirstObserved = () => {\n recordActivity()\n if (firstObserved)\n return\n firstObserved = true\n if (startTimer) {\n clearTimeout(startTimer)\n startTimer = undefined\n }\n }\n\n let streamPromise: Promise<ProviderTurnResult>\n try {\n // `http.*` interceptors ride the request only when one matches this provider.\n const wrapFetch = httpFetchWrapper(ctx.interceptors, ctx.provider.name)\n const request: StreamOptions = { ...options, signal: attemptAbort.signal, ...(wrapFetch ? { wrapFetch } : {}) }\n const providerCallbacks = watchdogCallbacks(withProgress(callbacks, onProgress), () => settled, markFirstObserved, opts?.onServerToolActivity)\n streamPromise = ctx.provider.stream(request, providerCallbacks)\n }\n catch (err) {\n // Full cleanup, not just the abort unlink: a provider that synchronously\n // emitted a delta before throwing may have armed the idle timer.\n cleanup()\n throw err\n }\n\n streamPromise.catch(() => {\n // If a watchdog wins the race below, the provider promise may reject later\n // after seeing the timeout abort signal. Observe it to avoid unhandled\n // rejections without changing the returned timeout error.\n })\n\n const raced = new Promise<ProviderTurnResult>((resolve, reject) => {\n const failTimeout = (kind: ProviderWatchdogKind, timeoutMs: number) => {\n if (settled)\n return\n settled = true\n // The idle kind gets its own phrasing: \"waiting for stream inactivity\"\n // reads as the opposite of what happened.\n const err = new OperationTimeoutError(\n PROVIDER_WATCHDOG_OPERATIONS[kind],\n timeoutMs,\n kind === 'stream inactivity'\n ? `Provider stream timed out: no stream events for ${timeoutMs}ms (turn ${turnId}).`\n : `Provider stream timed out waiting for ${kind} after ${timeoutMs}ms (turn ${turnId}).`,\n )\n attemptAbort.abort(err)\n cleanup()\n reject(err)\n }\n\n if (startTimeoutMs > 0) {\n startTimer = setTimeout(() => {\n if (!firstObserved)\n failTimeout('first response', startTimeoutMs)\n }, startTimeoutMs)\n }\n if (totalTimeoutMs > 0)\n totalTimer = setTimeout(failTimeout, totalTimeoutMs, 'total stream', totalTimeoutMs)\n onIdleTimeout = () => failTimeout('stream inactivity', idleTimeoutMs)\n\n streamPromise.then(\n (value) => {\n if (settled)\n return\n settled = true\n markFirstObserved()\n cleanup()\n resolve(value)\n },\n (err) => {\n if (settled)\n return\n settled = true\n markFirstObserved()\n cleanup()\n reject(err)\n },\n )\n })\n\n return raced\n }\n\n try {\n return recordsSteps(ctx.durable)\n ? await modelStep(ctx, options.model, attempt, opts?.onLiveFailure)\n : await suspendable(ctx, attempt())\n }\n finally {\n // Settle boundary: the journaled provider call (if any) is closed, so\n // persistence and host hooks are safe. Flushes on BOTH outcomes — a\n // scrubbed block is invalid whether or not the retry succeeded, and\n // persisting now prevents the next run from re-poisoning.\n if (pendingRepair !== undefined)\n await flushThinkingRepair(ctx, pendingRepair)\n }\n}\n\n/**\n * One model request as a step of a run that records steps, keyed by the\n * turn and the request's attempt. A failure rejects with the error rebuilt from its record,\n * live and on replay; `onLiveFailure` sees the provider's own error, which\n * only a live attempt has. In checkpoint mode the verdict it returns is\n * recorded with the failure.\n */\nasync function modelStep(ctx: LoopContext, model: string, attempt: (onProgress?: StepLive['onProgress']) => Promise<ProviderTurnResult>, onLiveFailure: ((err: unknown) => JsonValue | undefined) | undefined): Promise<ProviderTurnResult> {\n // The step's `onProgress` gets the streamed text and thinking: what the\n // runtime keeps as stream partials while the step runs.\n // A suspension rejects the work with a control error: the step stays pending, not failed or done with a cut-off answer.\n const work: LiveStepWork<ProviderTurnResult> = async (context) => {\n try {\n return await suspendable(ctx, attempt(context.onProgress))\n }\n catch (err) {\n throwIfSuspended(ctx)\n const decision = onLiveFailure?.(err)\n if (decision !== undefined && ctx.durable.checkpoint)\n withStepDecision(err, decision)\n throw err\n }\n }\n // The run's signal, not the attempt's: a watchdog aborting the attempt is\n // a failure to record, only a run abort is an abort.\n const outcome = await ctx.durable.scope.step<ProviderTurnResult>(\n { kind: LOOP_STEP_KINDS.model, key: ctx.durable.modelKey(), payload: { model }, replay: 'safe' },\n { callbacks: work, signal: ctx.signal },\n )\n if (outcome.status !== 'completed')\n throw new Error('model step no longer matches its record')\n return outcome.value\n}\n\n/** `attempt`'s result, unless `Agent.suspend` cut it off: then the suspension, whatever the provider made of its abort. */\nasync function suspendable(ctx: LoopContext, attempt: Promise<ProviderTurnResult>): Promise<ProviderTurnResult> {\n let result: ProviderTurnResult\n try {\n result = await attempt\n }\n catch (err) {\n throwIfSuspended(ctx)\n throw err\n }\n throwIfSuspended(ctx)\n return result\n}\n\n/** `callbacks` that also report text and thinking deltas to `onProgress`. */\nfunction withProgress(callbacks: StreamCallbacks, onProgress: StepLive['onProgress']): StreamCallbacks {\n if (!onProgress)\n return callbacks\n return {\n ...callbacks,\n onText(delta) {\n onProgress({ type: 'text', delta })\n callbacks.onText(delta)\n },\n onThinking(delta) {\n onProgress({ type: 'thinking', delta })\n callbacks.onThinking?.(delta)\n },\n }\n}\n\n/** Max bytes of provider error text inlined into the assistant turn placeholder. */\nconst ERROR_PLACEHOLDER_MAX = 280\n\n/**\n * Build the assistant-turn placeholder text when the provider throws before\n * streaming any output. Inlines the surfaced (classified) error message,\n * truncated and stripped of stack-like newlines, so the persisted turn carries a useful\n * diagnostic — the human reading the transcript sees the failure mode\n * without having to attach a debugger, and `tool_search` schema rejections\n * become self-explanatory.\n *\n * The text reads `[✗ Streaming failed before any output: <message>]`, or\n * `Streaming failed mid-output` when `midOutput` is true because text had\n * already streamed. Hosts may pattern-match on the bracketed shape. Without\n * an extractable message the text is the bare prefix, `[✗ <prefix>.]`.\n */\nexport function buildStreamErrorPlaceholder(err: unknown, midOutput = false): string {\n // Two phrasings so the marker never contradicts the turn it lands in:\n // \"before any output\" after a block of streamed text would read as\n // factually false to the next run's model.\n const prefix = midOutput ? 'Streaming failed mid-output' : 'Streaming failed before any output'\n const raw = errorMessage(err).trim()\n if (raw.length === 0)\n return `[✗ ${prefix}.]`\n // Collapse newlines so the placeholder stays on one transcript line; a\n // multi-line provider stack trace would otherwise wreck the model's\n // continuation context.\n const oneLine = raw.replace(/\\s+/g, ' ')\n const trimmed = oneLine.length > ERROR_PLACEHOLDER_MAX\n ? `${oneLine.slice(0, ERROR_PLACEHOLDER_MAX - 1).trimEnd()}…`\n : oneLine\n return `[✗ ${prefix}: ${trimmed}]`\n}\n\n/**\n * Best-effort extraction of `statusCode` / `requestId` from native provider\n * SDK exceptions, attached to `stream:error` ctx so observability handlers\n * don't have to walk `cause` chains. Recognized shapes:\n *\n * - Anthropic SDK `APIError` (`status`, `headers['request-id']`)\n * - OpenAI SDK error (`status`, `headers['x-request-id']`)\n * - OpenRouter / OpenAI-compat HTTP errors (`status`)\n * - Cerebras (`status`)\n *\n * Silent no-op for arbitrary `Error`s and primitives — the fields stay\n * undefined and the raw `err` is still forwarded for handlers that need\n * full context.\n */\nexport function extractStreamErrorMeta(err: unknown): { statusCode?: number, requestId?: string } {\n if (!err || typeof err !== 'object')\n return {}\n const e = err as Record<string, unknown>\n const out: { statusCode?: number, requestId?: string } = {}\n\n const statusCandidate = typeof e.status === 'number'\n ? e.status\n : typeof e.statusCode === 'number'\n ? e.statusCode\n : undefined\n if (typeof statusCandidate === 'number' && Number.isFinite(statusCandidate))\n out.statusCode = statusCandidate\n\n if (typeof e.requestId === 'string') {\n out.requestId = e.requestId\n }\n else {\n const headers = e.headers\n if (headers && typeof headers === 'object') {\n const h = headers as Record<string, unknown>\n const candidate = h['request-id'] ?? h['x-request-id'] ?? h.requestId\n if (typeof candidate === 'string')\n out.requestId = candidate\n }\n }\n return out\n}\n\n/**\n * First-response watchdog cap for RETRY attempts (attempt ≥ 2). The first\n * attempt gets the full `providerStreamStartTimeoutMs` window (large-prompt\n * prefill legitimately takes a while on a cold request), but a healthy\n * re-issue — fired after backoff already waited out any declared\n * rate-limit window — either starts streaming quickly or is dead. Without\n * the cap, retrying watchdog timeouts multiplies worst-case silent latency\n * (3 × 5 min for the defaults) and a stuck provider blocks a whole /ticket\n * stage for that long. Only applied when the start watchdog is enabled —\n * an explicit `0` (disabled) stays disabled on retries too.\n */\nexport const RETRY_STREAM_START_TIMEOUT_CAP_MS = 120_000\n\n/**\n * Minimum gap between `stream:progress` dispatches during a parent turn. Same\n * cadence as compaction progress: fast enough to read as live, slow enough\n * that the (possibly async, catalog-priced) hook never becomes a hot path.\n */\nexport const STREAM_PROGRESS_THROTTLE_MS = 250\n","/**\n * Tool calls as steps of a durable run: every call of a replay-mode run,\n * and of a checkpoint run (`RunDurability.checkpoint`).\n *\n * A call is one step of the run (`kind: 'tool'`, keyed by its call id), so\n * a replay answers it from its record instead of running the body again.\n * The record carries the output, the structured value the body reported,\n * a tool failure (a failed call is a completed step: the model sees the\n * error either way), and the tool-state ops the body staged, which the loop\n * commits again on replay. Tools that make their effects durable\n * themselves (`DurableToolDef.durableBody`, nested agents, nested tool\n * calls) run directly instead: a step around them would nest steps.\n *\n * On a checkpoint run, an output over {@link STEP_BLOB_THRESHOLD_BYTES} is\n * written to the call's persisted-output blob (`behavior.persistDir`) and\n * the record keeps a reference to it; a replay reads the blob back and\n * checks it holds the same bytes.\n */\n\nimport type { ExecutionContext } from './contexts'\nimport type { StepKey } from './durable/keys'\nimport type { DurableMode, StepOutcome } from './durable/types'\nimport type { LoopContext } from './loop-context'\nimport type { LiveStepWork } from './run-durability'\nimport type { Session } from './session'\nimport type { DurableToolContext, DurableToolDef, ToolContext, ToolDef, ToolPreflight } from './tools/types'\nimport type { JsonValue, ToolResultContent } from './types'\nimport { Buffer } from 'node:buffer'\nimport { createHash } from 'node:crypto'\nimport { buildAliasMaps } from './aliasing'\nimport { stableStringify } from './behaviors/repeat-guard'\nimport { suspensionOf } from './durable/errors'\nimport { applyCompactSummaryCutoff } from './loop-compaction'\nimport { executionBlobWriter, isControlError } from './loop-context'\nimport { persistedBlobPath } from './loop-persistence'\nimport { readPersistedBlobOnHost } from './persisted-blob-io'\nimport { LOOP_STEP_KINDS, recordsSteps } from './run-durability'\nimport { TOOL_USE_INTERRUPTED_MARKER } from './session/messages-pairing'\nimport { stagedToolState } from './tool-state'\nimport { ToolFailure } from './tools/failure'\nimport { hydrateReadStateFromSessionAsync } from './tools/read-state'\nimport { coerceToolResultContent, isWireTurn } from './types'\n\n/** What the model reads for a call a process death left unfinished, when the call must not run again. */\nexport const TOOL_STEP_INTERRUPTED_MESSAGE = `${TOOL_USE_INTERRUPTED_MARKER} The process running this call stopped before it finished. Its effect may or may not have happened: check before you run it again.`\n\n/** How a run that records steps executes a tool (see `DurableToolDef.durableBody`). */\nexport type ReplayExecution = 'step' | 'composite' | 'promise'\n\nexport function replayExecution(def: DurableToolDef, execution: ExecutionContext, mode: DurableMode = 'replay'): ReplayExecution {\n const body = typeof def.durableBody === 'function' ? def.durableBody(execution, mode) : def.durableBody\n if (body === 'promise')\n return 'promise'\n if (body === 'composite' || def.runsNestedAgent === true || def.callsNestedTools === true)\n return 'composite'\n return 'step'\n}\n\n/**\n * A checkpoint run's tool output over this many bytes is kept in the call's\n * persisted-output blob, its step record a {@link StepOutputRef}.\n */\nexport const STEP_BLOB_THRESHOLD_BYTES = 256 * 1024\n\n/** A tool output a step record keeps in a blob: where, and what tells the bytes read back are the ones written. */\ninterface StepOutputRef {\n path: string\n bytes: number\n sha256: string\n}\n\ntype ToolStepOutcome\n = | { output: string | ToolResultContent[], structured?: { value: unknown } }\n | { outputRef: StepOutputRef, structured?: { value: unknown } }\n | { error: { name: string, message: string } }\n\n/** The recorded value of a tool step, with what its `tool:gate` handlers kept (`resumeState`). */\ntype ToolStepValue = ToolStepOutcome & { gate?: Record<string, JsonValue> }\n\n/** What a dispatch adds to the step of a call. */\nexport interface ToolStepOptions {\n /** See {@link toolStepFingerprint}. */\n fingerprint?: string | undefined\n /** The call's `tool:gate` `resumeState`, kept with its record for a resumed run's gate. */\n gate?: Record<string, JsonValue> | undefined\n}\n\n/**\n * Fingerprint of a nested call's step (`StepRequest.fingerprint`): its tool\n * and a hash of its input as the calling script passed it. Nested calls are\n * keyed by the order the script makes them, so a rerun that takes another\n * path would otherwise get another call's record. Top-level calls are keyed\n * by their own id: none.\n */\nexport function toolStepFingerprint(ctx: LoopContext, call: { name: string, input: Record<string, unknown> }): string | undefined {\n if (ctx.nestedParentCallId === undefined)\n return undefined\n return `${call.name}:${createHash('sha256').update(stableStringify(call.input)).digest('hex').slice(0, 32)}`\n}\n\n/** Key of the record that keeps the `tool:gate` decision of a call whose body has no step (see {@link keepDirectBodyGate}). */\nexport function directBodyGateKey(ctx: LoopContext, callId: string): StepKey {\n return ctx.durable.toolKey(`${callId}#gate`)\n}\n\n/** The `resumeState` a call's `tool:gate` kept, from its step record. */\nexport function storedGateState(record: { status: string, result?: JsonValue }): Record<string, JsonValue> {\n const value = record.status === 'done' ? record.result : undefined\n const gate = value && typeof value === 'object' && !Array.isArray(value) ? value.gate : undefined\n return gate && typeof gate === 'object' && !Array.isArray(gate) ? { ...gate } : {}\n}\n\n/**\n * A started tool body: `promise` is what the run joins (the runtime's own\n * promise, untouched), `finish` turns its settlement into the call's output\n * or throws the call's failure.\n */\nexport interface StartedToolBody {\n promise: Promise<unknown>\n finish: (settled: PromiseSettledResult<unknown>) => string | ToolResultContent[]\n}\n\n/**\n * Start the body of a call of a run that records steps (replay mode, or a\n * checkpoint run). A `'step'` tool runs as a step of the run; the others\n * run directly. Nothing awaits `promise` here: the\n * runtime may need to join it with others first.\n */\nexport function startReplayToolBody(ctx: LoopContext, toolDef: ToolDef, input: Record<string, unknown>, toolCtx: ToolContext, options: ToolStepOptions = {}): StartedToolBody {\n if (replayExecution(toolDef, toolCtx.execution, ctx.durable.runtime.mode) !== 'step') {\n return {\n promise: toolDef.execute(input, toolCtx),\n finish: settled => settledValue(settled) as string | ToolResultContent[],\n }\n }\n const staged = stagedToolState(toolCtx.state)\n const gate = options.gate && Object.keys(options.gate).length > 0 ? { gate: options.gate } : {}\n // What the body threw, live: the record keeps its name and message, the live call rethrows the error itself.\n let liveError: Error | undefined\n // An output the record keeps in a blob: the live call gets it as the body returned it.\n let liveOutput: string | undefined\n const work: LiveStepWork<ToolStepValue> = async (context) => {\n liveError = undefined\n liveOutput = undefined\n if (ctx.resume)\n await hydrateReadStateOnce(ctx, toolCtx)\n // A rerun of the work (the runtime's own retry) stages from scratch.\n staged?.clear()\n let structured: { value: unknown } | undefined\n // No `durable`: an awakeable or step opened inside a step would nest\n // in its record. `clock` reads live here (see `runClock`).\n const { durable: _durable, ...plainCtx } = toolCtx\n const bodyCtx: ToolContext = toolCtx.reportStructured\n ? { ...plainCtx, reportStructured: (value) => { structured = { value } } }\n : plainCtx\n try {\n const output = coerceToolResultContent(await toolDef.execute(input, bodyCtx))\n // Cut off by a suspension's budget: what the body made of the abort is not its result, the call stays pending.\n const suspended = suspensionOf(toolCtx.signal)\n if (suspended)\n throw suspended\n context.stageToolState(staged?.pending() ?? [])\n const outputRef = await spillStepOutput(ctx, toolCtx.callId, output)\n if (outputRef) {\n liveOutput = output as string\n return { outputRef, ...(structured ? { structured } : {}), ...gate }\n }\n return { output, ...(structured ? { structured } : {}), ...gate }\n }\n catch (err) {\n // The runtime records an abort of this call's signal as one (its cause\n // is a journaled decision). An `AbortError` while the signal is live\n // (the tool's own client timing out) is an ordinary failure.\n if (isControlError(ctx, err))\n throw err\n const suspended = suspensionOf(toolCtx.signal)\n if (suspended || toolCtx.signal.aborted)\n throw suspended ?? err\n // A failed call still commits what it staged before it threw.\n context.stageToolState(staged?.pending() ?? [])\n const error = err instanceof Error ? err : new Error(String(err))\n liveError = error\n return { error: { name: error.name, message: error.message }, ...gate }\n }\n }\n const stepped = ctx.durable.scope.step<ToolStepValue>(\n {\n kind: LOOP_STEP_KINDS.tool,\n key: ctx.durable.toolKey(toolCtx.callId),\n payload: { name: toolDef.spec.name, callId: toolCtx.callId },\n replay: toolDef.replay ?? 'unsafe',\n ...(options.fingerprint !== undefined ? { fingerprint: options.fingerprint } : {}),\n },\n // A call that passed an approval (its gate kept something, or its own preflight asked) is marked started even when safe: a resume restores it instead of asking again.\n { callbacks: work, signal: toolCtx.signal, markStarted: Object.keys(gate).length > 0 || (toolDef as DurableToolDef).preflight !== undefined },\n )\n // Only checkpoint runs spill outputs; a replay-mode run joins the runtime's own promise.\n const promise = ctx.durable.checkpoint ? stepped.then(outcome => readSpilledOutput(ctx, outcome)) : stepped\n return {\n promise,\n finish: (settled) => {\n let outcome: Awaited<typeof promise>\n try {\n outcome = settledValue(settled) as Awaited<typeof promise>\n }\n catch (err) {\n // Nothing recorded this delta: it must not reach the store.\n staged?.clear()\n throw err\n }\n if (outcome.status === 'interrupted') {\n staged?.clear()\n // A calling script is interrupted with it (see `createNestedToolCaller`).\n ctx.nestedInterrupted?.()\n throw new ToolFailure(TOOL_STEP_INTERRUPTED_MESSAGE)\n }\n // The ops come from the record, live or replayed, so the commit after\n // the call writes the same thing on every attempt.\n if (staged) {\n staged.clear()\n if (outcome.toolState && outcome.toolState.length > 0)\n staged.restore([...outcome.toolState])\n }\n const value = outcome.value\n if ('error' in value)\n // A replay-mode run takes the recorded form live too, so its replay goes the same way.\n throw ctx.durable.checkpoint && !outcome.replayed && liveError ? liveError : Object.assign(new Error(value.error.message), { name: value.error.name })\n if (value.structured)\n toolCtx.reportStructured?.(value.structured.value)\n return 'output' in value ? value.output : liveOutput!\n },\n }\n}\n\n/**\n * Write a checkpoint run's text output over {@link STEP_BLOB_THRESHOLD_BYTES}\n * to the call's persisted-output blob, the file the dispatch spills the\n * call's result to (`maybePersistToolResult`), and return the reference its\n * record keeps. `undefined`: the record keeps the output itself (a smaller\n * or non-text output, a nested call, no `persistDir`, a failed write, a\n * handle other than the host process's: a sandbox or container may not\n * outlive the process, and its blob with it).\n */\nasync function spillStepOutput(ctx: LoopContext, callId: string, output: string | ToolResultContent[]): Promise<StepOutputRef | undefined> {\n if (!ctx.durable.checkpoint || ctx.nestedParentCallId !== undefined || typeof output !== 'string' || ctx.handle.type !== 'process')\n return undefined\n const path = persistedBlobPath(ctx.behavior.persistDir, callId)\n const bytes = Buffer.byteLength(output)\n if (!path || bytes <= STEP_BLOB_THRESHOLD_BYTES)\n return undefined\n try {\n await executionBlobWriter(ctx)(path, output)\n }\n catch (err) {\n if (isControlError(ctx, err))\n throw err\n return undefined\n }\n ctx.durable.spilled.set(path, output)\n return { path, bytes, sha256: createHash('sha256').update(output).digest('hex') }\n}\n\n/**\n * A replayed step whose record keeps its output in a blob: the output read\n * back, or `interrupted` when the blob is gone or holds other bytes (the\n * result can no longer be told).\n */\nasync function readSpilledOutput(ctx: LoopContext, outcome: StepOutcome<ToolStepValue>): Promise<StepOutcome<ToolStepValue>> {\n if (outcome.status !== 'completed' || !outcome.replayed || !('outputRef' in outcome.value))\n return outcome\n const { outputRef, ...rest } = outcome.value\n let text: string | undefined\n try {\n text = await ctx.execution.readFile(ctx.handle, outputRef.path)\n }\n catch {\n text = await readPersistedBlobOnHost(ctx.behavior.persistDir, ctx.handle, outputRef.path)\n }\n if (text === undefined || Buffer.byteLength(text) !== outputRef.bytes || createHash('sha256').update(text).digest('hex') !== outputRef.sha256)\n return { status: 'interrupted' }\n return { ...outcome, value: { ...rest, output: text } }\n}\n\n/** Run a call's body: as a step of the run when it records steps (see {@link startReplayToolBody}), else directly. */\nexport function executeToolBody(ctx: LoopContext, toolDef: ToolDef, input: Record<string, unknown>, toolCtx: ToolContext, options: ToolStepOptions = {}): Promise<string | ToolResultContent[]> {\n return recordsSteps(ctx.durable)\n ? runReplayToolBody(startReplayToolBody(ctx, toolDef, input, toolCtx, options))\n : toolDef.execute(input, toolCtx)\n}\n\n/**\n * A call's {@link DurableToolDef.preflight} (when `preflight` is set), then its body\n * (see {@link executeToolBody}) unless the preflight answered the call. The\n * preflight runs before the body's step is recorded: what it waits for is\n * asked again after a process death.\n */\nexport async function preflightThenBody(ctx: LoopContext, toolDef: DurableToolDef, input: Record<string, unknown>, toolCtx: ToolContext, options: ToolStepOptions = {}, preflight = true): Promise<string | ToolResultContent[]> {\n const decided: ToolPreflight = toolDef.preflight && preflight ? await toolDef.preflight(input, toolCtx) : { input }\n if ('output' in decided)\n return decided.output\n // `preflight` is off for a resumed call: its gate record, if it needs one, is already there.\n if (preflight)\n await keepDirectBodyGate(ctx, toolDef, toolCtx, options)\n // Ran here, or passed in the process that died: the body must not ask again.\n const bodyCtx: DurableToolContext = toolDef.preflight ? { ...toolCtx, preflighted: true } : toolCtx\n return executeToolBody(ctx, toolDef, decided.input, bodyCtx, options)\n}\n\n/**\n * A checkpoint run's call whose body runs directly (composite: codemode,\n * spawn), so no step record keeps what its `tool:gate` decided: once it\n * passed the gate, a small `gate` step keeps its `resumeState`. A resumed\n * run finds it and gates the call as `resumed` (restored, not asked again);\n * the body still runs again. Not a `tool` step: the call is not done.\n */\nasync function keepDirectBodyGate(ctx: LoopContext, toolDef: ToolDef, toolCtx: ToolContext, options: ToolStepOptions): Promise<void> {\n if (!ctx.durable.checkpoint || replayExecution(toolDef, toolCtx.execution, ctx.durable.runtime.mode) === 'step')\n return\n const gate = options.gate ?? {}\n const work: LiveStepWork<{ gate: Record<string, JsonValue> }> = async () => ({ gate })\n await ctx.durable.scope.step(\n {\n kind: LOOP_STEP_KINDS.gate,\n key: directBodyGateKey(ctx, toolCtx.callId),\n payload: { name: toolDef.spec.name, callId: toolCtx.callId },\n replay: 'safe',\n ...(options.fingerprint !== undefined ? { fingerprint: options.fingerprint } : {}),\n },\n { callbacks: work, signal: toolCtx.signal },\n )\n}\n\n/** Await a started body alone (a call outside a joined batch). */\nexport async function runReplayToolBody(started: StartedToolBody): Promise<string | ToolResultContent[]> {\n const [settled] = await Promise.allSettled([started.promise])\n return started.finish(settled!)\n}\n\nfunction settledValue(settled: PromiseSettledResult<unknown>): unknown {\n if (settled.status === 'rejected')\n throw settled.reason\n return settled.value\n}\n\n/**\n * Sessions whose read state this process rebuilt. A recorded `read_file`\n * of a resumed run never runs its live `rememberRead` again, so the first\n * live tool step of a resumed run rebuilds the map for read dedup\n * (`requireReadBeforeEdit` has its own run-start hydration), from the reads\n * still in the model's context only: a dedup stub must point at a result\n * the model can see. A fresh run starts with the map a run without\n * durability has.\n */\nconst HYDRATED_READ_STATE_SESSIONS = new WeakSet<Session>()\n\nasync function hydrateReadStateOnce(ctx: LoopContext, toolCtx: ToolContext): Promise<void> {\n if (!toolCtx.session || HYDRATED_READ_STATE_SESSIONS.has(toolCtx.session))\n return\n HYDRATED_READ_STATE_SESSIONS.add(toolCtx.session)\n let aliasMaps\n if (toolCtx.toolAliases) {\n try {\n aliasMaps = buildAliasMaps(toolCtx.toolAliases, Object.keys(toolCtx.tools))\n }\n catch {\n aliasMaps = undefined\n }\n }\n await hydrateReadStateFromSessionAsync(toolCtx.session, toolCtx.handle.cwd, {\n turns: applyCompactSummaryCutoff(ctx.turns).filter(isWireTurn),\n defaultLineNumbers: toolCtx.behavior?.readLineNumbers ?? true,\n ...(aliasMaps ? { aliasMaps } : {}),\n readFileForHash: async (path) => {\n try {\n return await toolCtx.execution.readFile(toolCtx.handle, path)\n }\n catch {\n return null\n }\n },\n })\n}\n","/**\n * Nested tool calls: a tool calling other tools while it runs, through\n * `ToolContext.callTool` (the `codemode` tool is the consumer).\n *\n * Each nested call goes through the same `executeSingleTool` pipeline as a\n * model-issued call — `tool:gate`, validation, `tool:before` / `tool:after` /\n * `tool:transform` / `tool:error`, tracing, per-call cancellation and the\n * tool-state commit — on a derived `LoopContext` whose\n * {@link LoopContext.nestedParentCallId} marks it. The marker lands on every\n * hook payload as `parentToolCallId` and changes three things downstream:\n *\n * - the lazy-disclosure lock does not apply (the calling tool is itself the\n * discovery path), every other gate does;\n * - result persistence and image stripping are skipped, so the caller gets\n * the full output — only the calling tool's own result is persisted;\n * - model-facing nudges / dedup behaviors ignore the call. Budgets still\n * count it.\n *\n * Nested results never become session turns: the model only sees what the\n * calling tool returns. A bounded record of the calls rides the caller's\n * persisted `tool_result` (`calls`), so a reloaded transcript can show them.\n */\n\nimport type { LoopContext } from './loop-context'\nimport type { NestedCallRecorder } from './nested-call-record'\nimport type { ToolCall, ToolResult } from './providers'\nimport type { DurableToolDef, NestedToolCallOptions, NestedToolCallResult } from './tools/types'\nimport { DEFAULT_MAX_CONCURRENT_TOOLS, executeToolBatch, resolveConcurrencySafe } from './loop-tool-batch'\nimport { TOOL_STEP_INTERRUPTED_MESSAGE } from './loop-tool-step'\nimport { createNestedCallRecorder } from './nested-call-record'\nimport { replays } from './run-durability'\nimport { linkAbortSignal } from './timeout'\nimport { toolResultToText } from './types'\n\nexport type SingleToolDispatch = (\n ctx: LoopContext,\n call: ToolCall,\n turnId: string,\n) => Promise<{ result: ToolResult, structured?: { value: unknown } }>\n\n/**\n * Readers/writer scheduling for one calling tool: concurrency-safe calls\n * share up to `max` slots, unsafe calls (edits, mutating shell) run alone,\n * in request order. Mirrors the batch scheduler's barrier semantics.\n */\nexport function createNestedScheduler(max: number): <T>(exclusive: boolean, run: () => Promise<T>) => Promise<T> {\n let running = 0\n let exclusiveRunning = false\n const queue: Array<{ exclusive: boolean, start: () => void }> = []\n\n const pump = (): void => {\n while (queue.length > 0) {\n const next = queue[0]!\n if (exclusiveRunning)\n return\n if (next.exclusive ? running > 0 : running >= max)\n return\n queue.shift()\n running++\n if (next.exclusive)\n exclusiveRunning = true\n next.start()\n }\n }\n\n return <T>(exclusive: boolean, run: () => Promise<T>): Promise<T> =>\n new Promise<T>((resolve, reject) => {\n queue.push({\n exclusive,\n start: () => {\n run().then(resolve, reject).finally(() => {\n running--\n if (exclusive)\n exclusiveRunning = false\n pump()\n })\n },\n })\n pump()\n })\n}\n\n/** What `createNestedToolCaller` hands the dispatcher for one calling tool. */\nexport interface NestedToolCaller {\n callTool: (name: string, input: Record<string, unknown>, options?: NestedToolCallOptions) => Promise<NestedToolCallResult>\n /** Wait `ms`, in order with the calls (a durable timer in replay mode). */\n sleep: (ms: number) => Promise<void>\n /** Resolves once every call issued so far has settled. */\n drain: () => Promise<void>\n /**\n * A call's step answered `interrupted` (a resumed run: a pending unsafe\n * call, or a record of another call at its position). Every later call is\n * refused without running, and the dispatcher reports the whole calling\n * tool interrupted, whatever the script did with the failure.\n */\n interrupted: () => boolean\n recorder: NestedCallRecorder\n}\n\n/**\n * Build `ToolContext.callTool` for the call `parentCallId`, plus the bounded\n * record of the calls it made (`NestedToolCallRecord`), which the dispatcher\n * attaches to the caller's result. `undefined` inside a nested call: nesting\n * is one level deep.\n *\n * Every tool is reachable except other callers of `callTool` (no scripts in\n * scripts). Nested agents (`spawn`) run like any call: spawn's own slot queue\n * applies the agent's concurrency cap to them, shared with direct spawns.\n *\n * Scheduling follows the run's, so durable runs stay replay-safe:\n * - **Replay mode, or a batch executor** (`behavior.toolBatchExecutor`):\n * calls issued together (one VM turn, see the codemode worker) form one\n * batch, run through `executeToolBatch` (in replay mode, concurrent calls\n * join on the runtime's own combinator), one batch at a time, `sleep`\n * queued between them.\n * - Otherwise: concurrency-safe calls share `maxConcurrentTools` slots,\n * unsafe ones run alone, `sleep` is a plain wait.\n */\nexport function createNestedToolCaller(\n ctx: LoopContext,\n turnId: string,\n parentCallId: string,\n parentSignal: AbortSignal,\n dispatch: SingleToolDispatch,\n): NestedToolCaller | undefined {\n if (ctx.nestedParentCallId !== undefined)\n return undefined\n let nextId = 1\n const journaled = replays(ctx.durable)\n // The record is persisted on the caller's result, which a durable run must\n // rebuild identically on replay: no wall-clock durations there.\n const recorder = createNestedCallRecorder(journaled ? () => 0 : undefined)\n const batched = journaled || ctx.behavior.toolBatchExecutor !== undefined\n const schedule = createNestedScheduler(Math.max(1, ctx.behavior.maxConcurrentTools ?? DEFAULT_MAX_CONCURRENT_TOOLS))\n /** Every call and sleep issued so far, for `drain`. */\n const inFlight = new Set<Promise<unknown>>()\n const track = <T>(promise: Promise<T>): Promise<T> => {\n inFlight.add(promise)\n void promise.finally(() => inFlight.delete(promise)).catch(() => {})\n return promise\n }\n const wait = (ms: number): Promise<void> => ctx.durable.scope.sleep(ms, parentSignal)\n let interrupted = false\n const nestedInterrupted = (): void => {\n interrupted = true\n }\n /** What the caller passed per call (`line`, `streamProgress`), until the call settles. */\n const callOptions = new Map<string, { line?: number, streamProgress?: boolean }>()\n const nestedCallOptions = (callId: string): { line?: number, streamProgress?: boolean } | undefined => callOptions.get(callId)\n const nestedCtx = (signal: AbortSignal, extra: Partial<LoopContext> = {}): LoopContext =>\n ({ ...ctx, signal, nestedParentCallId: parentCallId, nestedInterrupted, nestedCallOptions, ...extra })\n const settled = (callId: string, result: ToolResult, structured: { value: unknown } | undefined): NestedToolCallResult => {\n callOptions.delete(callId)\n recorder.finish(callId, { status: result.isError === true ? 'error' : 'ok', output: toolResultToText(result.content) })\n return {\n output: result.content,\n isError: result.isError === true,\n callId,\n ...(structured ? { structured: structured.value } : {}),\n }\n }\n const failed = (callId: string, err: unknown): never => {\n callOptions.delete(callId)\n // Otherwise the open record reads back as cancelled.\n recorder.finish(callId, { status: 'error', output: err instanceof Error ? err.message : String(err) })\n throw err\n }\n\n // Batched mode: one lane of batches and sleeps, in issue order. The\n // script's per-call abort (it fires when the script returns with calls\n // unawaited) is not applied: in replay mode a call cut short would return\n // while its step is still pending.\n let lane: Promise<void> = Promise.resolve()\n let pending: Array<{ call: ToolCall, resolve: (r: NestedToolCallResult) => void, reject: (e: unknown) => void }> | null = null\n const flush = (): void => {\n const batch = pending\n pending = null\n if (!batch)\n return\n lane = lane.then(async () => {\n if (interrupted) {\n for (const entry of batch) {\n recorder.finish(entry.call.id, { status: 'error', output: TOOL_STEP_INTERRUPTED_MESSAGE })\n entry.resolve({ output: TOOL_STEP_INTERRUPTED_MESSAGE, isError: true, callId: entry.call.id })\n }\n return\n }\n const structured = new Map<string, { value: unknown }>()\n const batchCtx = nestedCtx(parentSignal, {\n // The calling tool may itself run inside a batch; this one is its own.\n suppressBatchExecutor: false,\n nestedStructured: (id, value) => structured.set(id, { value }),\n })\n try {\n const results = await executeToolBatch(batchCtx, batch.map(entry => entry.call), turnId)\n batch.forEach((entry, i) => entry.resolve(settled(entry.call.id, results[i]!, structured.get(entry.call.id))))\n }\n catch (err) {\n for (const entry of batch) {\n try {\n failed(entry.call.id, err)\n }\n catch (error) {\n entry.reject(error)\n }\n }\n }\n })\n }\n\n const callTool = (name: string, input: Record<string, unknown>, options: NestedToolCallOptions = {}): Promise<NestedToolCallResult> => {\n const callId = `${parentCallId}/${nextId++}`\n const def: DurableToolDef | undefined = ctx.tools[name]\n recorder.start({ id: callId, name, input, runsNestedAgent: def?.runsNestedAgent === true, ...(options.line !== undefined ? { line: options.line } : {}) })\n if (options.line !== undefined || options.streamProgress)\n callOptions.set(callId, { ...(options.line !== undefined ? { line: options.line } : {}), ...(options.streamProgress ? { streamProgress: true } : {}) })\n if (def?.callsNestedTools === true) {\n const output = `Tool \"${name}\" cannot be called from another tool.`\n recorder.finish(callId, { status: 'error', output })\n return Promise.resolve({ output, isError: true, callId })\n }\n // An earlier call was interrupted: nothing after it may run.\n if (interrupted) {\n recorder.finish(callId, { status: 'error', output: TOOL_STEP_INTERRUPTED_MESSAGE })\n return Promise.resolve({ output: TOOL_STEP_INTERRUPTED_MESSAGE, isError: true, callId })\n }\n\n if (batched) {\n // Collected until the current synchronous group of calls ends.\n return track(new Promise<NestedToolCallResult>((resolve, reject) => {\n if (!pending) {\n pending = []\n queueMicrotask(flush)\n }\n pending.push({ call: { id: callId, name, input }, resolve, reject })\n }))\n }\n\n return track(schedule(!resolveConcurrencySafe(def, input), async () => {\n if (interrupted) {\n recorder.finish(callId, { status: 'error', output: TOOL_STEP_INTERRUPTED_MESSAGE })\n return { output: TOOL_STEP_INTERRUPTED_MESSAGE, isError: true, callId }\n }\n // The nested call stops with the calling tool, and with the caller's own signal.\n const controller = new AbortController()\n const unlinkParent = linkAbortSignal(parentSignal, controller)\n const unlinkOwn = options.signal ? linkAbortSignal(options.signal, controller) : () => {}\n try {\n let dispatched: Awaited<ReturnType<SingleToolDispatch>>\n try {\n dispatched = await dispatch(nestedCtx(controller.signal), { id: callId, name, input }, turnId)\n }\n catch (err) {\n return failed(callId, err)\n }\n return settled(callId, dispatched.result, dispatched.structured)\n }\n finally {\n unlinkParent()\n unlinkOwn()\n }\n }))\n }\n\n const sleep = (ms: number): Promise<void> => {\n if (batched) {\n flush()\n const done = lane.then(() => wait(ms))\n lane = done.catch(() => {})\n return track(done)\n }\n return track(wait(ms))\n }\n\n const drain = async (): Promise<void> => {\n flush()\n while (inFlight.size > 0)\n await Promise.allSettled([...inFlight])\n }\n\n return { callTool, sleep, drain, interrupted: () => interrupted, recorder }\n}\n","/**\n * Wire-shape preparation for the provider request: turn → message\n * conversion, content-ref resolution, tool_use ↔ tool_result pairing repair,\n * and capability-driven media degradation of stored tool outputs.\n */\n\nimport type { LoopContext } from './loop-context'\nimport type { Provider } from './providers'\nimport type { PairingRepair } from './session/messages'\nimport type { ResolveContentRefBlock, SessionMessage, SessionTurn, ToolResultContent } from './types'\nimport { Buffer } from 'node:buffer'\nimport { AgentToolPairingError } from './errors'\nimport { ensureToolResultPairing, resolveContentRefsInMessages } from './session/messages'\nimport { documentBlockMarker, isWireTurn } from './types'\n\nconst IMAGE_OMITTED_MARKER = '[image omitted — model does not support vision]'\nconst AUDIO_OMITTED_MARKER = '[audio omitted — model does not support audio input]'\nconst VIDEO_OMITTED_MARKER = '[video omitted — model does not support video input]'\n\nfunction documentOmittedMarker(doc: Extract<ToolResultContent, { type: 'document' }>): string {\n return documentBlockMarker(doc, 'document omitted — model does not support document attachments')\n}\n\n/**\n * Convert turns to the SessionMessage[] format providers expect. Non-wire\n * turns (`system`, display-only `command`) are dropped via the shared\n * {@link isWireTurn} guard — the single, fail-safe source of truth for what\n * reaches the model.\n */\nexport function turnsToMessages(turns: SessionTurn[]): SessionMessage[] {\n return turns\n .filter(isWireTurn)\n .map(t => ({ role: t.role, content: t.content }))\n}\n\n/**\n * Run {@link ensureToolResultPairing} with the loop's hook + strict-mode\n * context plugged in. Centralized so the pre-send path and the schema-\n * enforcement path share identical telemetry + throw semantics.\n *\n * The captured `repairs` array is what `AgentToolPairingError` carries on\n * strict-mode throws, and it's what `pairing:repair` fires from. Hook\n * notifications run AFTER the pass completes so they don't interfere with\n * the synchronous walk — and we drop them on the floor in strict mode (the\n * throw is more informative than a fire-and-forget log).\n */\nexport function applyPairingRepair(\n ctx: LoopContext,\n messages: SessionMessage[],\n turnId: string,\n): SessionMessage[] {\n const repairs: PairingRepair[] = []\n const repaired = ensureToolResultPairing(messages, {\n onRepair: repair => repairs.push(repair),\n })\n\n if (repairs.length === 0)\n return repaired\n\n if (ctx.behavior.strictToolPairing) {\n throw new AgentToolPairingError({\n message:\n `Tool pairing corruption detected (${repairs.length} repair${repairs.length === 1 ? '' : 's'}); `\n + `strict mode is on so the request was not sent.`,\n ...(ctx.providerName ? { provider: ctx.providerName } : {}),\n repairs,\n })\n }\n\n // Repair-storm circuit breaker (opt-in). A repair count this high in a\n // single wire build means the persisted transcript is systematically\n // corrupt (e.g. a provider reusing tool_use ids on every turn) — each\n // further turn would re-strip the model's work, make zero progress, and\n // grow the repair count quadratically. Abort with the same typed error\n // strict mode uses so hosts get the full repair list for diagnosis.\n // Unset / non-positive / non-finite disables (repair silently, never throw).\n const rawLimit = ctx.behavior.maxPairingRepairsPerTurn\n const limit = typeof rawLimit === 'number' && Number.isFinite(rawLimit) && rawLimit > 0\n ? rawLimit\n : Number.POSITIVE_INFINITY\n if (repairs.length > limit) {\n throw new AgentToolPairingError({\n message:\n `Pairing-repair storm: ${repairs.length} repairs in a single turn (limit ${limit}). `\n + `The transcript is systematically corrupt (likely duplicate tool_use ids from the provider); `\n + `continuing would loop without forward progress.`,\n ...(ctx.providerName ? { provider: ctx.providerName } : {}),\n repairs,\n })\n }\n\n for (const repair of repairs) {\n void Promise.resolve(ctx.hooks.callHook('pairing:repair', { ...repair, turnId })).catch(() => {})\n }\n\n return repaired\n}\n\n/**\n * Degrade media blocks inside previously-stored `tool_result` outputs to text\n * markers for the capabilities the provider lacks (vision, audio, video,\n * documents). This handles the session-resume and mid-session provider\n * switch case: a session built with a vision-capable provider resumes on a\n * text-only one, and the stored blocks would otherwise re-encode into base64\n * payloads in the new model's context.\n *\n * Scope: stored `tool_result` outputs only. User-authored media blocks are left\n * alone, since the consumer owns matching prompt parts to the provider's\n * capabilities.\n */\nexport function sanitizeStoredToolResults(\n provider: Provider,\n messages: SessionMessage[],\n): SessionMessage[] {\n // No top-level capability short-circuit here: `sanitizeToolOutputForProvider`\n // owns the fast path (it returns the output unchanged when the provider\n // accepts every media kind). A gate here that checked only\n // `vision`/`documents` would skip audio/video degradation for\n // vision+document-capable-but-audio-incapable routes (e.g. OpenRouter to a\n // PDF-capable, audio-incapable model), letting stored audio/video bytes reach\n // the wire builder and throw mid-run. Delegating to the per-block sanitizer\n // keeps the two predicates from drifting.\n return messages.map((msg) => {\n let changed = false\n const newContent = msg.content.map((block) => {\n if (block.type !== 'tool_result' || typeof block.output === 'string')\n return block\n const output = sanitizeToolOutputForProvider(provider, block.output)\n if (output === block.output)\n return block\n changed = true\n return { ...block, output }\n })\n return changed ? { ...msg, content: newContent } : msg\n })\n}\n\n/**\n * Per-run LRU for resolved content-ref payloads, keyed by `type:ref`.\n *\n * Refs are content-addressed (`attachment://<hash>` and persist-dir blobs are\n * immutable once written), so within a run the same ref always resolves to the\n * same bytes — but the wire pipeline re-resolves EVERY ref in the history on\n * EVERY turn (resolution runs before media age-out, which then discards most\n * of the resolved base64 again). Without this cache an image-heavy session\n * re-reads and re-base64s each attachment from disk once per turn, O(refs)\n * disk I/O per turn → O(turns × refs) per run.\n *\n * Keyed on the LoopContext via WeakMap so the cache dies with the run and no\n * cross-run staleness question arises. Byte-bounded (UTF-8 bytes, measured\n * once at insert — `.length` counts UTF-16 code units and would let the\n * budget retain up to 2× its nominal size on multi-byte text), evicting\n * oldest-first (Map insertion order; hits re-insert to refresh recency).\n */\nconst CONTENT_REF_CACHE_MAX_BYTES = 64 * 1024 * 1024\nconst contentRefCaches = new WeakMap<LoopContext, { bytes: number, entries: Map<string, { data: string, bytes: number }> }>()\n\n/**\n * Drop `ctx`'s content-ref cache. Called when its run ends: the agent keeps\n * that context for `agent.compact()`, which resolves through a context of its\n * own, so the cache would only hold up to its byte budget while idle.\n */\nexport function releaseContentRefCache(ctx: LoopContext): void {\n contentRefCaches.delete(ctx)\n}\n\n/** Resolve ref-form content blocks in `messages` through the `content-ref:resolve` hook, caching resolved payloads per run. */\nexport async function resolveContentRefsForWire(\n ctx: LoopContext,\n messages: readonly SessionMessage[],\n): Promise<SessionMessage[]> {\n return resolveContentRefsInMessages(messages, {\n resolveContentRef: async (block: ResolveContentRefBlock) => {\n const key = `${block.type}:${block.ref}`\n let cache = contentRefCaches.get(ctx)\n if (!cache) {\n cache = { bytes: 0, entries: new Map() }\n contentRefCaches.set(ctx, cache)\n }\n const hit = cache.entries.get(key)\n if (hit !== undefined) {\n cache.entries.delete(key)\n cache.entries.set(key, hit)\n return { data: hit.data }\n }\n const hookCtx: { block: ResolveContentRefBlock, data?: string } = { block }\n await ctx.hooks.callHook('content-ref:resolve', hookCtx)\n if (typeof hookCtx.data !== 'string')\n throw new Error(`Content ref \"${block.ref}\" (${block.type}) was not resolved by a content-ref:resolve hook.`)\n const dataBytes = Buffer.byteLength(hookCtx.data, 'utf8')\n if (dataBytes <= CONTENT_REF_CACHE_MAX_BYTES) {\n cache.entries.set(key, { data: hookCtx.data, bytes: dataBytes })\n cache.bytes += dataBytes\n for (const [k, v] of cache.entries) {\n if (cache.bytes <= CONTENT_REF_CACHE_MAX_BYTES)\n break\n cache.entries.delete(k)\n cache.bytes -= v.bytes\n }\n }\n return { data: hookCtx.data }\n },\n })\n}\n\n/**\n * Replace media blocks in a tool output with short text markers when the\n * provider lacks the capability. An image needs `capabilities.vision === false`.\n * Audio, video and document blocks need their capability to be `true`. The\n * model then sees an honest \"no image\" signal instead of JSON-stringified base64\n * it might confabulate over.\n *\n * Returns the output unchanged when:\n * - The provider accepts every media kind (`vision` not `false`, and `audio`,\n * `video` and `documents` all `true`),\n * - The output is a plain string (no media blocks to replace).\n *\n * Image blocks stay when `vision` is omitted (omitted means \"let the provider\n * try\"), while audio, video and document blocks are replaced unless the\n * provider reports the capability as `true`.\n *\n * When replacement leaves an all-text array, the result collapses to a plain\n * string to keep the downstream wire shape as narrow as possible.\n */\nexport function stripImagesForNonVision(\n provider: Provider,\n output: string | ToolResultContent[],\n): string | ToolResultContent[] {\n return sanitizeToolOutputForProvider(provider, output)\n}\n\nfunction sanitizeToolOutputForProvider(\n provider: Provider,\n output: string | ToolResultContent[],\n): string | ToolResultContent[] {\n if (typeof output === 'string')\n return output\n const caps = provider.meta.capabilities\n // Fast path: provider accepts every media kind we might carry in a tool\n // result. Preserve the historical image behavior (`vision` omitted means\n // \"let the provider try\"), but audio/video/documents are opt-in because their\n // wire shapes are less portable and wrong routing is more likely to 400.\n if (caps?.vision !== false && caps?.audio === true && caps?.video === true && caps?.documents === true)\n return output\n\n let changed = false\n const sanitized = output.map((block): ToolResultContent => {\n if (block.type === 'image' && caps?.vision === false) {\n changed = true\n return { type: 'text', text: IMAGE_OMITTED_MARKER }\n }\n if (block.type === 'audio' && caps?.audio !== true) {\n changed = true\n return { type: 'text', text: AUDIO_OMITTED_MARKER }\n }\n if (block.type === 'video' && caps?.video !== true) {\n changed = true\n return { type: 'text', text: VIDEO_OMITTED_MARKER }\n }\n if (block.type === 'document' && caps?.documents !== true) {\n changed = true\n return { type: 'text', text: documentOmittedMarker(block) }\n }\n return block\n })\n\n if (!changed)\n return output\n if (sanitized.every((block): block is Extract<ToolResultContent, { type: 'text' }> => block.type === 'text'))\n return sanitized.map(block => block.text).join('\\n')\n return sanitized\n}\n","/**\n * Apply `behavior.maxImageEdge` to the two places media enters a session:\n * tool results and prompt parts. Shrinking at entry (not on the wire) means\n * the persisted turn already holds the final bytes, so every later request\n * re-sends the same prefix and the prompt cache stays warm.\n */\n\nimport type { PromptPart, ToolResultContent } from '../types'\nimport { shrinkImageBase64 } from './png-downscale'\n\n/** `output` with oversize inline images shrunk; the same reference when nothing changed. */\nexport function shrinkToolOutputImages<T extends string | ToolResultContent[]>(output: T, maxEdge: number | undefined): T {\n if (typeof output === 'string' || !maxEdge)\n return output\n let changed = false\n const next = output.map((part) => {\n if (part.type !== 'image' || typeof part.data !== 'string')\n return part\n const shrunk = shrinkImageBase64(part.data, part.mediaType, maxEdge)\n if (!shrunk)\n return part\n changed = true\n return { ...part, ...shrunk }\n })\n return (changed ? next : output) as T\n}\n\n/** `parts` with oversize image parts shrunk; the same reference when nothing changed. */\nexport function shrinkPromptImages(parts: PromptPart[], maxEdge: number | undefined): PromptPart[] {\n if (!maxEdge)\n return parts\n let changed = false\n const next = parts.map((part) => {\n if (part.type !== 'image')\n return part\n const shrunk = shrinkImageBase64(part.data, part.mediaType, maxEdge)\n if (!shrunk)\n return part\n changed = true\n return { ...part, ...shrunk }\n })\n return changed ? next : parts\n}\n","/**\n * Single tool-call dispatch: gate → validate → `tool:before` → execute →\n * `tool:after`/`tool:transform`, with per-call cancellation, tool-state\n * commit, and artifact recording. Also the cancellation wire messages shared\n * with the batch layer.\n */\n\nimport type { AgentHooks } from './agent-hooks'\nimport type { LoopContext } from './loop-context'\nimport type { McpConnection } from './mcp'\nimport type { Provider, ToolCall, ToolResult } from './providers'\nimport type { SessionArtifactInput } from './session'\nimport type { DurableToolDef, ToolContext, ToolDef } from './tools/types'\nimport type { JsonValue, ToolHookContext, ToolOutcome, ToolProgress, ToolResultContent, ToolResultMetadata } from './types'\nimport { dirname, posix, resolve as resolvePath } from 'node:path'\nimport { executionForTools } from './agent-interceptors'\nimport { toCanonicalName, toWireName } from './aliasing'\nimport { findProjectRoot } from './chat/project-root'\nimport { suspensionOf } from './durable/errors'\nimport { executionBlobWriter, isControlError, journaledDecision, rethrowControlError, toolDurable } from './loop-context'\nimport { createNestedToolCaller } from './loop-nested-calls'\nimport { maybePersistToolResult, persistedBlobPath } from './loop-persistence'\nimport { directBodyGateKey, preflightThenBody, storedGateState, TOOL_STEP_INTERRUPTED_MESSAGE, toolStepFingerprint } from './loop-tool-step'\nimport { stripImagesForNonVision } from './loop-wire'\nimport { nonOwningMcpView } from './mcp/tool-meta'\nimport { shrinkToolOutputImages } from './media/shrink'\nimport { recordsSteps, replays } from './run-durability'\nimport { ARTIFACT_KINDS, ARTIFACTS_METADATA_KEY, normalizeArtifactInput } from './session/artifacts'\nimport { linkAbortSignal } from './timeout'\nimport { unwrapCallTool } from './tools/call-tool'\nimport { toolErrorText } from './tools/failure'\nimport { validateToolArgs } from './tools/validation'\nimport { sanitizeToolResultMetadata, toolOutputByteLength } from './types'\n\n/**\n * Canonical tool_result text emitted when a tool call is interrupted by the\n * user mid-flight (Esc / Ctrl-C / external `AbortSignal`). Mirrors Claude\n * Code's `INTERRUPT_MESSAGE_FOR_TOOL_USE` so downstream consumers can pattern\n * match a single string across both harnesses. Always paired with\n * `isError: true` on the wire — the model treats it as a failed call rather\n * than a successful tool response.\n */\nexport const INTERRUPT_MESSAGE_FOR_TOOL_USE = '[Request interrupted by user for tool use]'\n\n/**\n * Canonical tool_result text emitted when a tool call is skipped because a\n * steering message arrived between dispatches inside\n * {@link executeToolBatch}. Distinguished from\n * {@link INTERRUPT_MESSAGE_FOR_TOOL_USE} so consumers can split \"user\n * cancelled\" from \"framework superseded\".\n */\nexport const TOOL_USE_SKIPPED_MESSAGE = '[Tool use skipped — superseded by user message]'\n\n/**\n * Canonical tool_result text emitted when a single tool call is cancelled\n * mid-flight via `agent.cancelTool(callId)` (typically the TUI's\n * \"cancel this tool\" affordance). Distinguished from\n * {@link INTERRUPT_MESSAGE_FOR_TOOL_USE} (run-wide user abort) and\n * {@link TOOL_USE_SKIPPED_MESSAGE} (steered) so the model — and downstream\n * consumers — can tell the three apart by string match.\n *\n * Always paired with `isError: true` on the wire so the model treats the\n * call as failed rather than as a successful response. The remaining tool\n * calls in the batch continue running, in contrast with a full-run abort.\n */\nexport const TOOL_USE_CANCELLED_MESSAGE = '[Tool call cancelled by user]'\n\n/** Reason surfaced on `siblingAbort.signal` when a shell error cancels its fleet. */\nexport const SHELL_CASCADE_REASON = 'sibling-shell-error'\n\n/**\n * Canonical `tool_result.content` text emitted to siblings that were\n * cancelled by a `shell` error in the same batch. Distinct from\n * {@link INTERRUPT_MESSAGE_FOR_TOOL_USE} (user-issued abort) and\n * {@link TOOL_USE_SKIPPED_MESSAGE} (steered) so consumers can split\n * the three causes by string-match.\n */\nexport const SHELL_CASCADE_CANCEL_MESSAGE = 'Cancelled: a sibling `shell` call in the same batch errored; re-run independently if still needed.'\n\n/**\n * Sentinel message rejected from the per-call cancellation promise inside\n * {@link executeSingleTool}'s race. Plain-string and module-private — only\n * the surrounding code reads it (via the `perCallAbort.signal.aborted`\n * guard, NOT the message itself), so it just needs to be a stable\n * non-empty identifier the rejection can carry.\n */\nconst CANCELLED_BY_USER_SENTINEL = 'zidane:tool:cancelled-by-user'\n\n/**\n * Compose the run-scoped `ctx.signal` and a per-call abort into one child\n * signal for a tool body — WITHOUT `AbortSignal.any`.\n *\n * `AbortSignal.any([runSignal, perCall])` registers a dependent-signal\n * algorithm on each source; the run signal is long-lived (whole run), so one\n * composite per tool call accumulates on it until the composite is GC'd —\n * a slow leak across a long run with many calls. Manual `linkAbortSignal`\n * listeners removed in `dispose()` keep the run signal's listener set bounded\n * to currently-dispatching calls. `dispose()` MUST be called once the body has\n * settled. `reason` propagates from whichever source fires first (so a\n * signal-aware body still sees the per-call cancel reason).\n */\nexport function composePerCallSignal(\n runSignal: AbortSignal,\n perCallSignal: AbortSignal,\n): { signal: AbortSignal, dispose: () => void } {\n const controller = new AbortController()\n const unlinkRun = linkAbortSignal(runSignal, controller)\n const unlinkPerCall = linkAbortSignal(perCallSignal, controller)\n return {\n signal: controller.signal,\n dispose: () => {\n unlinkRun()\n unlinkPerCall()\n },\n }\n}\n\n/**\n * Grace window after a run-level abort before we force-settle a tool body that\n * hasn't returned. Well-behaved tools observe `childSignal` and finalize their\n * own bookkeeping (e.g. `spawn` awaits its child's session-persisting `finally`\n * block); they settle within this window and the forced rejection never fires.\n * Only a body that *ignores* its signal hits the timeout — that's the wedge we\n * guard against. Kept short so a real wedge doesn't stall `drain()` for long,\n * but long enough for a normal abort-driven cleanup to complete.\n *\n * Overridable via `ZIDANE_RUN_ABORT_GRACE_MS` (internal/testing only — lets\n * the wedge test exercise the forced-rejection path without a multi-second\n * real wait). Read per-use (not memoized) so tests can set it; falls back to\n * the 2s default on any non-finite value.\n */\nconst DEFAULT_RUN_ABORT_GRACE_MS = 2000\nfunction runAbortGraceMs(): number {\n const raw = Number(process.env.ZIDANE_RUN_ABORT_GRACE_MS)\n return Number.isFinite(raw) && raw >= 0 ? raw : DEFAULT_RUN_ABORT_GRACE_MS\n}\n\n/**\n * Distinct provider instances across the run's fallback targets, in chain\n * order — exposed to tools as `ToolContext.providers` so child-spawning\n * tools can route a requested model to the provider that serves it.\n * `undefined` when the run carries no target list (hand-built contexts);\n * single-provider runs return the one-element list so consumers don't\n * need a separate code path.\n */\nexport function runProvidersFor(ctx: LoopContext): readonly Provider[] | undefined {\n if (!ctx.targets || ctx.targets.length === 0)\n return undefined\n const list: Provider[] = []\n for (const t of ctx.targets) {\n if (!list.includes(t.provider))\n list.push(t.provider)\n }\n return list\n}\n\n/**\n * `ToolContext.mcpConnection` spread fragment — resolves the loop's lazy\n * connection getter at tool-call time (the agent binds MCP after loop\n * start, so a build-time snapshot would always be null on the first turn).\n * Empty object when the agent has no live connection.\n */\nexport function mcpConnectionFor(ctx: LoopContext): { mcpConnection?: McpConnection } {\n const connection = ctx.inheritance.mcpConnection?.()\n if (!connection)\n return {}\n // Non-owning view: only the owning agent's destroy path may tear down\n // transports, and a doc comment alone is too weak a guard for every tool\n // and extension that can reach ToolContext.\n return { mcpConnection: nonOwningMcpView(connection) }\n}\n\n/**\n * Build the per-call base for every `tool:*` hook ctx (and the\n * matching shape for `mcp:tool:*`). Centralized so the `runId` /\n * `parentRunId` / `depth` identity fields land uniformly on every\n * event the loop fires — without one helper they drift across ~14\n * inline construction sites. The returned object IS the\n * {@link ToolHookContext} canonical shape; specialized hook payloads\n * (`gateCtx`, `transformCtx`, etc.) spread it and append their own\n * fields.\n */\nexport function buildToolHookBase(\n ctx: LoopContext,\n turnId: string,\n callId: string,\n name: string,\n displayName: string,\n input: Record<string, unknown>,\n): ToolHookContext {\n const scriptLine = ctx.nestedCallOptions?.(callId)?.line\n return {\n turnId,\n callId,\n name,\n displayName,\n input,\n ...(ctx.runId !== undefined ? { runId: ctx.runId } : {}),\n ...(ctx.parentRunId !== undefined ? { parentRunId: ctx.parentRunId } : {}),\n ...(ctx.parentCallId !== undefined ? { parentCallId: ctx.parentCallId } : {}),\n ...(ctx.nestedParentCallId !== undefined ? { parentToolCallId: ctx.nestedParentCallId } : {}),\n ...(scriptLine !== undefined ? { scriptLine } : {}),\n ...((ctx.tools[name] as DurableToolDef | undefined)?.runsNestedAgent === true ? { runsNestedAgent: true as const } : {}),\n ...(typeof ctx.depth === 'number' ? { depth: ctx.depth } : {}),\n }\n}\n\n/**\n * Commit a settled call's staged tool state.\n *\n * A store failure must not kill the call: the tool body already ran and\n * already did its side effects, so rejecting here would swallow the\n * `tool_result` and fail the run on a bookkeeping write. The commit is\n * store-first (see `createToolStateController`), so a failure leaves neither\n * the store nor the in-memory snapshot claiming the write — the tool's state\n * write simply didn't happen.\n *\n * Reported UNCONDITIONALLY, not behind `ZIDANE_DEBUG`: a dropped state write is\n * a durable-persistence failure, and the consequence is precisely the class of\n * bug this state exists to prevent (a one-shot re-serving a payload it already\n * delivered, a cursor rewinding). The nearest precedent is the session store's\n * `updateRun` degradation in `agent-run.ts`, which also logs and continues. A\n * silent drop here would be indistinguishable from success.\n *\n * `tool-state:commit-failed` is the structured seam — it carries the ops that\n * did not land, so a host can alert or replay them. The stderr line is the\n * fallback for hosts that registered nothing; a handler setting `handled`\n * suppresses it. The hook itself is guarded: a throwing consumer must not take\n * down a dispatch path whose tool has already run.\n */\nexport async function commitToolState(ctx: LoopContext, callId: string, toolName: string): Promise<void> {\n if (!ctx.toolState)\n return\n const pending = ctx.toolState.pending(callId)\n try {\n await ctx.toolState.commit(callId)\n }\n catch (err) {\n ctx.toolState.discard(callId)\n rethrowControlError(ctx, err)\n const error = err instanceof Error ? err : new Error(String(err))\n const hookCtx = { runId: ctx.runId, callId, toolName, ops: pending, error, handled: false }\n try {\n await ctx.hooks.callHook('tool-state:commit-failed', hookCtx)\n }\n catch (hookErr) {\n console.error('[zidane] tool-state:commit-failed handler threw; continuing:', hookErr)\n }\n if (!hookCtx.handled)\n console.error(`[zidane] tool state commit for ${toolName} (${callId}) failed; the write did NOT land, continuing:`, error)\n }\n}\n\n/**\n * Rewrite every well-formed `call_tool` envelope around a lazy catalog tool\n * into the inner call it carries (same `id`, inner wire name → canonical,\n * `arguments` → `input`). No-op unless the run is in dispatch mode\n * ({@link LoopContext.dispatcher}). Left as a `call_tool` call, so the\n * dispatcher itself answers: a malformed envelope (its schema validation\n * reports the shape error) and an inner name outside the catalog (its\n * `execute` says to call the tool directly, or that it does not exist).\n */\nexport function unwrapDispatchCalls(ctx: LoopContext, calls: readonly ToolCall[]): ToolCall[] {\n const dispatcher = ctx.dispatcher\n if (!dispatcher)\n return calls.slice()\n return calls.map((call) => {\n if (call.name !== dispatcher.name)\n return call\n const inner = unwrapCallTool(call.name, call.input)\n if (!inner)\n return call\n const canonical = toCanonicalName(inner.name, ctx.aliasMaps)\n if (!dispatcher.targets.has(canonical))\n return call\n return { ...call, name: canonical, input: inner.input }\n })\n}\n\n/**\n * Dispatch one tool call: gate, validate, `tool:before`, execute, then\n * `tool:transform` and `tool:after`. Registers a per-call cancellation\n * controller for `agent.cancelTool` and removes it on every exit.\n *\n * Resolves to the wire `ToolResult`. `structured` carries the value the tool\n * passed to `ToolContext.reportStructured`, when it reported one. Only nested\n * callers (`ToolContext.callTool`) read it. Rejects only when\n * the run's durable runtime claims the error as control flow (`isControlError`).\n */\nexport async function executeSingleTool(\n ctx: LoopContext,\n call: ToolCall,\n turnId: string,\n): Promise<{ result: ToolResult, structured?: { value: unknown } }> {\n const toolDef = ctx.tools[call.name]\n const callId = call.id\n const displayName = toWireName(call.name, ctx.aliasMaps)\n\n // Frozen pre-call snapshot of run-cumulative tool counts. Shared across the\n // gate, tool:before, and tool:after hooks so consumers see a consistent view\n // for the lifecycle of this call. A consumer that wants the post-increment\n // count can add 1 to the entry for `ctx.name`.\n const runToolCounts: Readonly<Record<string, number>> = Object.freeze({ ...ctx.runToolCounts })\n\n // Per-call cancellation slot. Registered ASAP (before the gate) so a user\n // pressing \"cancel this tool\" between `tool:before` and `tool:after` finds\n // a live controller to flip. The `finally` below always removes the entry,\n // so the map only ever holds *currently dispatching* calls — never grows\n // unbounded across a run.\n //\n // The race against this controller's signal lives down in the execute\n // section; gate-blocked / substituted / unknown-tool / invalid-input paths\n // return early without ever reaching it, which is fine — those exits are\n // immediate and the user has nothing to cancel.\n const perCallAbort = new AbortController()\n ctx.toolCancels?.register(callId, perCallAbort)\n try {\n return await runSingleToolDispatch(ctx, call, turnId, {\n toolDef,\n callId,\n displayName,\n runToolCounts,\n perCallAbort,\n })\n }\n finally {\n // Best-effort remove: a concurrent unregister (the agent dropping its\n // registry on destroy) is a no-op.\n ctx.toolCancels?.unregister(callId)\n }\n}\n\n/**\n * The execution context a tool body gets: the run's own, or a view that runs\n * the `shell.env` interceptors over each command's environment.\n */\nexport function toolExecution(ctx: LoopContext): ToolContext['execution'] {\n return ctx.interceptors ? executionForTools(ctx, ctx.execution, ctx.interceptors, ctx.session?.id) : ctx.execution\n}\n\n/**\n * Fires `validation:coerce` for a coerced input. When `validation`\n * interceptors are registered and changed the input (in place, through the\n * bridge), it is validated again: the result is the input to run with, or\n * the changed input's validation error. Without them, `input` comes back as\n * it is after the hook.\n */\nexport async function fireValidationCoerce(\n ctx: LoopContext,\n hookCtx: Parameters<AgentHooks['validation:coerce']>[0],\n input: Record<string, unknown>,\n): Promise<{ input: Record<string, unknown> } | { error: string | undefined }> {\n const before = ctx.interceptors?.has('validation') ? { ...input } : undefined\n await ctx.hooks.callHook('validation:coerce', hookCtx)\n const again = before && revalidateCoercedInput(before, input, hookCtx.schema)\n if (again && !again.valid)\n return { error: again.error }\n return { input: again ? again.input : input }\n}\n\n/**\n * Validates an input again when `validation:coerce` handlers changed it\n * (compared shallowly with `before`). `undefined` when unchanged.\n */\nfunction revalidateCoercedInput(\n before: Readonly<Record<string, unknown>>,\n input: Record<string, unknown>,\n schema: ToolDef['spec']['inputSchema'],\n): { valid: true, input: Record<string, unknown> } | { valid: false, error: string | undefined } | undefined {\n const keys = Object.keys(input)\n if (keys.length === Object.keys(before).length && keys.every(key => Object.hasOwn(before, key) && before[key] === input[key]))\n return undefined\n const validation = validateToolArgs(input, schema)\n return validation.valid ? { valid: true, input: validation.coercedInput ?? input } : { valid: false, error: validation.error }\n}\n\n/**\n * `ToolContext.reportProgress` for one call, or `undefined` when nothing shows\n * its live output: present on a top-level call of a tool that calls others (a\n * codemode script), and on a nested call whose caller asked for it\n * (`NestedToolCallOptions.streamProgress`). Each report fires `tool:progress`\n * without waiting for its listeners.\n */\nexport function progressReporter(ctx: LoopContext, hookBase: () => ToolHookContext): ((progress: ToolProgress) => void) | undefined {\n const base = hookBase()\n const wanted = ctx.nestedParentCallId === undefined\n ? (ctx.tools[base.name] as DurableToolDef | undefined)?.callsNestedTools === true\n : ctx.nestedCallOptions?.(base.callId)?.streamProgress === true\n if (!wanted)\n return undefined\n return (progress) => {\n try {\n void Promise.resolve(ctx.hooks.callHook('tool:progress', { ...base, progress })).catch(() => {})\n }\n catch {\n // A listener's failure never fails the call that reported.\n }\n }\n}\n\n/**\n * The {@link ToolContext} handed to a native tool body. `toolState.begin`\n * runs here, so the caller must invoke this inside its execute `try`.\n */\nfunction buildToolContext(\n ctx: LoopContext,\n turnId: string,\n callId: string,\n childSignal: AbortSignal,\n runProviders: readonly Provider[] | undefined,\n nested: ReturnType<typeof createNestedToolCaller>,\n reportOutcome: (outcome: ToolOutcome) => void,\n reportStructured: (value: unknown) => void,\n reportProgress: ((progress: ToolProgress) => void) | undefined,\n): ToolContext {\n const callTool = nested?.callTool\n const nestedSleep = nested?.sleep\n return {\n provider: ctx.provider,\n model: ctx.model,\n ...(runProviders ? { providers: runProviders } : {}),\n signal: childSignal,\n ...(ctx.suspendSignal ? { suspendSignal: ctx.suspendSignal } : {}),\n execution: toolExecution(ctx),\n handle: ctx.handle,\n hooks: ctx.hooks,\n tools: ctx.inheritance.tools,\n ...(ctx.inheritance.name !== undefined ? { name: ctx.inheritance.name } : {}),\n ...(ctx.inheritance.system !== undefined ? { system: ctx.inheritance.system } : {}),\n ...(ctx.inheritance.toolAliases !== undefined ? { toolAliases: ctx.inheritance.toolAliases } : {}),\n ...(ctx.inheritance.toolDescriptions !== undefined ? { toolDescriptions: ctx.inheritance.toolDescriptions } : {}),\n ...(ctx.inheritance.mcpServers !== undefined ? { mcpServers: ctx.inheritance.mcpServers } : {}),\n ...(mcpConnectionFor(ctx)),\n ...(ctx.inheritance.skills !== undefined ? { skills: ctx.inheritance.skills } : {}),\n behavior: ctx.behavior,\n turnId,\n callId,\n runId: ctx.runId,\n ...(ctx.parentRunId !== undefined ? { parentRunId: ctx.parentRunId } : {}),\n ...(ctx.parentCallId !== undefined ? { parentCallId: ctx.parentCallId } : {}),\n ...(ctx.session ? { session: ctx.session } : {}),\n ...(ctx.readState ? { readState: ctx.readState } : {}),\n ...(ctx.toolState ? { state: ctx.toolState.begin(callId) } : {}),\n ...(typeof ctx.depth === 'number' ? { depth: ctx.depth } : {}),\n clock: ctx.clock,\n durable: toolDurable(ctx),\n reportOutcome,\n // Only a calling script reads structured values; elsewhere a recorded\n // step would journal them next to the output for nothing.\n ...(ctx.nestedParentCallId !== undefined ? { reportStructured } : {}),\n ...(reportProgress ? { reportProgress } : {}),\n ...(callTool ? { callTool, nestedTools: ctx.tools } : {}),\n ...(nestedSleep ? { nestedSleep } : {}),\n ...(ctx.nestedParentCallId !== undefined ? { parentToolCallId: ctx.nestedParentCallId } : {}),\n }\n}\n\n/**\n * Rejection-side contenders for the native tool-body race: a per-call\n * cancellation promise and a run-abort grace promise. `detach` removes both\n * abort listeners and the grace timer once the race has settled.\n */\nfunction armToolBodyAbortGuards(\n ctx: LoopContext,\n perCallAbort: AbortController,\n runsNestedAgent: boolean,\n): { cancellationPromise: Promise<never>, runAbortPromise: Promise<never>, detach: () => void } {\n let removeAbortListener: (() => void) | undefined\n const cancellationPromise = new Promise<never>((_, reject) => {\n if (perCallAbort.signal.aborted) {\n reject(new Error(CANCELLED_BY_USER_SENTINEL))\n return\n }\n const onAbort = () => reject(new Error(CANCELLED_BY_USER_SENTINEL))\n perCallAbort.signal.addEventListener('abort', onAbort, { once: true })\n removeAbortListener = () => perCallAbort.signal.removeEventListener('abort', onAbort)\n })\n\n // Also guard the run-level abort (`ctx.signal`). The body already gets\n // `childSignal` (= ctx.signal ∪ perCallAbort), but a body that IGNORES\n // its signal would otherwise wedge `drain()` forever on a full run-abort\n // — neither `bodyPromise` nor `cancellationPromise` (which only watches\n // perCallAbort) would ever settle.\n //\n // We do NOT reject immediately on abort: well-behaved tools observe\n // `childSignal` and finalize their own bookkeeping in an abort-driven\n // `finally` (e.g. `spawn` awaits its child's session-persisting block;\n // see `raceWithTimeout` in tools/spawn-helpers.ts). Cutting them off here would\n // orphan that cleanup. Instead we give the body `runAbortGraceMs()` to\n // settle; only a body still running after the grace hits the forced\n // rejection. The AbortError routes through `runSingleToolDispatch`'s\n // `isAbortError && ctx.signal.aborted` branch → canonical\n // interrupt/cascade message. The detached `bodyPromise` keeps running but\n // is harmless (its `.catch` in `runSingleToolDispatch` swallows the late\n // settle). NOTE: native path only: in replay mode the body's recorded\n // settlement decides (see `runSingleToolDispatch`).\n let removeRunAbortListener: (() => void) | undefined\n let runAbortTimer: ReturnType<typeof setTimeout> | undefined\n const runAbortPromise = new Promise<never>((_, reject) => {\n // Reject with an AbortError-named error so the catch branch below routes\n // it as an abort (the cascade-vs-interrupt choice reads `ctx.signal.reason`).\n const forceReject = () => reject(new DOMException('Aborted', 'AbortError'))\n const armGrace = () => {\n // A suspension's cut-off already gave the body its time\n // (`Agent.suspend`). A nested agent still gets the grace: it is\n // suspended too, and its run must save its end before this one does.\n if (suspensionOf(ctx.signal) && !runsNestedAgent) {\n forceReject()\n return\n }\n runAbortTimer = setTimeout(forceReject, runAbortGraceMs())\n // Don't keep the event loop alive solely for the forced rejection.\n runAbortTimer.unref?.()\n }\n if (ctx.signal.aborted) {\n armGrace()\n return\n }\n ctx.signal.addEventListener('abort', armGrace, { once: true })\n removeRunAbortListener = () => ctx.signal.removeEventListener('abort', armGrace)\n })\n\n return {\n cancellationPromise,\n runAbortPromise,\n detach: () => {\n removeAbortListener?.()\n removeRunAbortListener?.()\n if (runAbortTimer !== undefined)\n clearTimeout(runAbortTimer)\n },\n }\n}\n\n/** Why a tool body unwound with an AbortError; see {@link classifyAbortError}. */\nexport type AbortErrorCause = { kind: 'cancelled' } | { kind: 'aborted', message: string } | { kind: 'error' }\n\n/**\n * Why a tool body unwound with an AbortError: this call's own cancel\n * (`perCallAbort`, which wins even when the run/sibling signal also fired),\n * the run/sibling abort (with the text the model sees for it), or neither (a\n * real failure that merely looks like an abort). These are live signals, so\n * the verdict is journaled in replay mode.\n * @param ctx - The call's context; `ctx.signal` is the run/sibling signal.\n * @param perCallAbort - This call's own cancel controller.\n * @param abortedMessage - Result text for a run/sibling abort.\n */\nexport function classifyAbortError(ctx: LoopContext, perCallAbort: AbortController, abortedMessage: () => string): Promise<AbortErrorCause> {\n return journaledDecision<AbortErrorCause>(ctx, 'tool-abort', () => {\n if (perCallAbort.signal.aborted)\n return { kind: 'cancelled' }\n return ctx.signal.aborted ? { kind: 'aborted', message: abortedMessage() } : { kind: 'error' }\n })\n}\n\n/**\n * Fire `tool:gate` for a call, as `resumed` when it has a step record\n * (`LoopContext.resumedBatch`). Also returns the call's step fingerprint.\n */\nasync function runToolGate(\n ctx: LoopContext,\n call: ToolCall,\n turnId: string,\n displayName: string,\n runToolCounts: Readonly<Record<string, number>>,\n): Promise<{ gateCtx: Parameters<AgentHooks['tool:gate']>[0], fingerprint: string | undefined }> {\n const fingerprint = toolStepFingerprint(ctx, call)\n const resumed = resumedGateState(ctx, call.id, fingerprint)\n const gateCtx: Parameters<AgentHooks['tool:gate']>[0] = {\n ...buildToolHookBase(ctx, turnId, call.id, call.name, displayName, call.input),\n block: false,\n reason: 'Tool execution was blocked',\n metadata: {},\n runToolCounts,\n ...(recordsSteps(ctx.durable) ? { resumeState: resumed ?? {} } : {}),\n ...(resumed ? { resumed: true as const } : {}),\n }\n await ctx.hooks.callHook('tool:gate', gateCtx)\n if (resumed) {\n // It passed the gate in the process that died, before its step started:\n // its record answers, or it is reported interrupted, and is never refused\n // now. A safe call cut off, or a call whose body has no step (its `gate`\n // record), runs again: the deny rules as they are now (`block`) still\n // apply to that run; nobody is asked to approve it again.\n if (!rerunsResumed(ctx, call.id))\n gateCtx.block = false\n delete gateCtx.result\n }\n return { gateCtx, fingerprint }\n}\n\n/** Whether a call of a resumed batch runs its body again: its step started and never finished, and it is safe to replay; or its body has no step. */\nfunction rerunsResumed(ctx: LoopContext, callId: string): boolean {\n const record = ctx.resumedBatch?.records.get(ctx.durable.toolKey(callId))\n if (!record)\n return ctx.resumedBatch?.records.has(directBodyGateKey(ctx, callId)) === true\n return record.status === 'pending' && record.replay === 'safe'\n}\n\n/**\n * For a call of a resumed batch with a step record (`LoopContext.resumedBatch`),\n * nested calls included: the `resumeState` its gate kept. A record of\n * another call at a nested call's position (another fingerprint) still\n * passed a gate, but its state is not this call's: empty. `undefined`: no\n * record, the call is gated as usual.\n *\n * A call whose body has no step (codemode, spawn) has a `gate` record\n * instead. Its body runs again, so a `gate` record of another call at a\n * nested call's position is no answer: that call is gated as usual.\n */\nfunction resumedGateState(ctx: LoopContext, callId: string, fingerprint: string | undefined): Record<string, JsonValue> | undefined {\n const record = ctx.resumedBatch?.records.get(ctx.durable.toolKey(callId))\n if (!record) {\n const kept = ctx.resumedBatch?.records.get(directBodyGateKey(ctx, callId))\n if (!kept || (fingerprint !== undefined && kept.fingerprint !== undefined && kept.fingerprint !== fingerprint))\n return undefined\n return storedGateState(kept)\n }\n if (fingerprint !== undefined && record.fingerprint !== undefined && record.fingerprint !== fingerprint)\n return {}\n return storedGateState(record)\n}\n\n/** Let unawaited nested calls settle (nothing may still journal once the call returns), then commit its tool state. */\nasync function settleAndCommit(ctx: LoopContext, nested: ReturnType<typeof createNestedToolCaller>, callId: string, name: string): Promise<void> {\n await nested?.drain()\n await commitToolState(ctx, callId, name)\n}\n\n/**\n * The call's wire result with its nested-call record. A nested call batched by\n * its caller also hands its structured value to that batch.\n */\nfunction finishedResult(\n ctx: LoopContext,\n callId: string,\n emitted: Parameters<typeof toolResultFromEmitted>[1],\n nested: ReturnType<typeof createNestedToolCaller>,\n structured: { value: unknown } | undefined,\n): ToolResult {\n if (structured && !emitted.isError)\n ctx.nestedStructured?.(callId, structured.value)\n return withNestedCalls(toolResultFromEmitted(callId, emitted), nested)\n}\n\n/** `result` with the record of the calls the tool made through `ToolContext.callTool`, when it made any. */\nfunction withNestedCalls(result: ToolResult, nested: ReturnType<typeof createNestedToolCaller>): ToolResult {\n const calls = nested?.recorder.snapshot()\n return calls ? { ...result, calls } : result\n}\n\n/** Wire `ToolResult` for a call whose result went through {@link emitToolResult}. */\nfunction toolResultFromEmitted(\n callId: string,\n emitted: { output: string | ToolResultContent[], isError: boolean, metadata?: ToolResultMetadata },\n): ToolResult {\n return {\n id: callId,\n content: emitted.output,\n ...(emitted.isError ? { isError: true } : {}),\n ...(emitted.metadata ? { metadata: emitted.metadata } : {}),\n }\n}\n\n/**\n * Body of {@link executeSingleTool}. Lives in its own function so the\n * per-call cancel registration (which spans every exit path) can sit in a\n * tight `try / finally` at the call site. The execute body has a user-cancel\n * branch, see {@link TOOL_USE_CANCELLED_MESSAGE}.\n */\nasync function runSingleToolDispatch(\n ctx: LoopContext,\n call: ToolCall,\n turnId: string,\n fixed: {\n toolDef: ToolDef | undefined\n callId: string\n displayName: string\n runToolCounts: Readonly<Record<string, number>>\n perCallAbort: AbortController\n },\n): Promise<{ result: ToolResult, structured?: { value: unknown } }> {\n const { toolDef, callId, displayName, runToolCounts, perCallAbort } = fixed\n\n // Gate hook — handlers can `block` (refuse the call), substitute a `result`\n // (skip execute, send the substitute back as a normal tool_result), or do\n // nothing (tool runs as usual).\n const { gateCtx, fingerprint } = await runToolGate(ctx, call, turnId, displayName, runToolCounts)\n\n // Conflict resolution: block wins over result. This handles two cases\n // cleanly without forcing every middleware to defensively coordinate:\n //\n // - A consumer hook substitutes a `result` (e.g. dedup cache), then a\n // policy gate (skills allowed-tools, custom security) refuses the call\n // via `block`. The refusal must take precedence — security beats\n // convenience.\n // - A buggy single handler sets both. The call gets blocked; the spurious\n // `result` is dropped silently. The buggy code path can be caught with a\n // tool:gate observability hook downstream of the framework gates.\n if (gateCtx.block) {\n // Blocked calls do not count — the model \"asked\" but the framework refused\n // before any side effect could happen. Treating them as charged would make\n // budget guards self-defeating (block on N triggers Nth call to count).\n //\n // `tool:dispatched` fires with `outcome: 'gate-block'` so consumers\n // wanting symmetric per-call notification (chat-layer transcript\n // rebuilders, downstream message-history consumers) see every refused\n // call. `tool:after` / `tool:transform` deliberately do NOT fire here:\n // preserving their pre-existing \"tool body produced a result\" contract\n // keeps the TUI, tracing-span lifecycle, and budget-byte counters from\n // having to special-case blocked calls.\n //\n // `isError: true` on the returned tool_result so the model treats the\n // refusal as a failed attempt rather than a successful `Blocked` string.\n await fireDispatched(ctx, {\n turnId,\n callId,\n name: call.name,\n displayName,\n input: gateCtx.input,\n outcome: 'gate-block',\n reason: gateCtx.reason,\n runToolCounts,\n })\n return { result: gateBlockedResult(callId, gateCtx) }\n }\n\n // The call passed gate; record it in the run counter. Counted once here so\n // `result`-substituted calls still count — the model emitted the call.\n ctx.runToolCounts[call.name] = (ctx.runToolCounts[call.name] ?? 0) + 1\n\n // Gate substitute path. Skip validate / `tool:before` / execute and emit a\n // synthetic successful `tool_result`. `tool:after` and `tool:transform`\n // still fire so byte-budgeting, telemetry, and post-mutation hooks see\n // the substitute consistently with executed calls. `tool:transform` may\n // still flip the `isError` flag on its way through (e.g. a hook that\n // demotes a cached error reply to a graceful retry hint).\n if (gateCtx.result !== undefined) {\n await fireDispatched(ctx, {\n turnId,\n callId,\n name: call.name,\n displayName,\n input: gateCtx.input,\n outcome: 'gate-substitute',\n runToolCounts,\n })\n const emitted = await emitToolResult(ctx, {\n turnId,\n callId,\n name: call.name,\n displayName,\n input: gateCtx.input,\n output: gateCtx.result,\n isError: false,\n runToolCounts,\n })\n return { result: toolResultFromEmitted(callId, emitted) }\n }\n\n // Input that downstream hooks + execute see, after any tool:gate mutation.\n let effectiveInput = gateCtx.input\n\n if (!toolDef) {\n const result = await handleUndispatchableTool(ctx, {\n turnId,\n callId,\n name: call.name,\n displayName,\n input: effectiveInput,\n runToolCounts,\n reason: `Unknown tool: ${call.name}`,\n })\n return { result }\n }\n\n // Validate arguments (respect mutations from tool:gate hook). Auto-coerces\n // string→boolean/number/etc. for OSS models that don't always honor types.\n const rejectInvalidInput = async (error: string | undefined): Promise<{ result: ToolResult }> => {\n await ctx.hooks.callHook('validation:reject', {\n ...buildToolHookBase(ctx, turnId, callId, call.name, displayName, effectiveInput),\n reason: error ?? 'invalid input',\n schema: toolDef.spec.inputSchema,\n })\n // Symmetric `tool:dispatched`; narrow `tool:after` semantics preserved.\n await fireDispatched(ctx, { turnId, callId, name: call.name, displayName, input: effectiveInput, outcome: 'invalid-input', runToolCounts })\n return { result: { id: callId, content: `Validation error: ${error}`, isError: true } }\n }\n const validation = validateToolArgs(effectiveInput, toolDef.spec.inputSchema)\n if (!validation.valid)\n return rejectInvalidInput(validation.error)\n // Pass the coerced input to the tool — `\"true\"` is now `true`, etc.\n effectiveInput = validation.coercedInput ?? effectiveInput\n\n // Surface successful coercions so consumers can count \"model wrongness rate\".\n // Only fires when at least one field was coerced; perfectly-typed inputs stay\n // silent so the hook bus isn't noisy on the happy path.\n const coercions = validation.coercions && validation.coercions.length > 0\n ? validation.coercions\n : undefined\n if (coercions) {\n const coerced = await fireValidationCoerce(ctx, { ...buildToolHookBase(ctx, turnId, callId, call.name, displayName, effectiveInput), coercions, schema: toolDef.spec.inputSchema }, effectiveInput)\n if ('error' in coerced)\n return rejectInvalidInput(coerced.error)\n effectiveInput = coerced.input\n }\n\n await fireDispatched(ctx, {\n turnId,\n callId,\n name: call.name,\n displayName,\n input: effectiveInput,\n outcome: 'execute',\n runToolCounts,\n })\n await ctx.hooks.callHook('tool:before', {\n ...buildToolHookBase(ctx, turnId, callId, call.name, displayName, effectiveInput),\n runToolCounts,\n ...(coercions ? { coercions } : {}),\n })\n\n // `output` is set in the success branch and in the regular-error branch\n // of the catch; the user-cancel branch returns early *above* the\n // post-execute emit so it never reaches the `output` read. Initialising\n // to a never-used sentinel keeps TS happy without disabling strict mode.\n let output: string | ToolResultContent[] = ''\n let isError = false\n let cancelledByUser = false\n let abortedWithRun = false\n // Structured side-effect outcome a mutating tool reports via\n // `ctx.reportOutcome`. Captured here and stamped onto `tool:after` so hosts\n // get a byte-level signal without parsing the result prose. Last call wins.\n let reportedOutcome: ToolOutcome | undefined\n // Value for nested callers (`ToolContext.reportStructured`); only kept when\n // the body succeeded, so an error result never resolves to stale data.\n let reportedStructured: { value: unknown } | undefined\n\n // Per-call abort composes with the run-scoped / sibling-scoped `ctx.signal`\n // so the tool body sees one combined signal. The body still gets aborted\n // when the run / sibling fleet aborts; the new case the union enables is\n // a user-issued cancel of *this specific call* without unwinding the rest\n // of the batch. See {@link composePerCallSignal} for why this is manual\n // listener composition rather than `AbortSignal.any` — `dispose()` in the\n // inner `finally` below detaches it from the long-lived run signal.\n const composedSignal = composePerCallSignal(ctx.signal, perCallAbort.signal)\n const childSignal = composedSignal.signal\n\n const runProviders = runProvidersFor(ctx)\n const nested = createNestedToolCaller(ctx, turnId, callId, childSignal, executeSingleTool)\n try {\n const toolCtx = buildToolContext(ctx, turnId, callId, childSignal, runProviders, nested, (outcome) => {\n reportedOutcome = outcome\n }, (value) => {\n reportedStructured = { value }\n }, progressReporter(ctx, () => buildToolHookBase(ctx, turnId, callId, call.name, displayName, effectiveInput)))\n\n // Race the tool body against a per-call cancellation. Two design points:\n //\n // 1. The body promise is kicked off synchronously, then we attach a\n // no-op `.catch` to it so a late settle (the user cancels mid-\n // flight, we win the race with cancellation, then the body\n // eventually throws into the void) never surfaces as an unhandled\n // rejection. Misbehaving tool bodies that ignore `ctx.signal`\n // continue running in the background until they naturally finish;\n // the loop has already moved on with the cancellation marker.\n // 2. The rejection-side promise listens on `perCallAbort.signal` only.\n // Sibling / run aborts flow through `ctx.signal` into `childSignal`\n // and into the body — the existing AbortError path catches them\n // and the `cancelledByUser` guard below correctly leaves them in\n // the regular error branch (preserving the existing\n // `INTERRUPT_MESSAGE_FOR_TOOL_USE` semantics at the batch layer).\n // The tool's own gate first, outside the call's step (`DurableToolDef.preflight`); a resumed call passed it in the process that died.\n const bodyPromise = preflightThenBody(ctx, toolDef, effectiveInput, toolCtx, { fingerprint, gate: gateCtx.resumeState }, gateCtx.resumed !== true)\n bodyPromise.catch(() => {})\n\n // In replay mode the body's outcome is journaled and a replay\n // settles it at once, so a live cancel winning the race would replay as\n // the body's result instead. The body decides: it still gets\n // `childSignal`, and its settlement (abort included) is what replays.\n const guards = replays(ctx.durable) ? undefined : armToolBodyAbortGuards(ctx, perCallAbort, (toolDef as DurableToolDef).runsNestedAgent === true)\n\n try {\n output = guards\n ? await Promise.race([bodyPromise, guards.cancellationPromise, guards.runAbortPromise])\n : await bodyPromise\n }\n finally {\n // Detach both abort listeners + the grace timer on the happy path so a\n // subsequent cancel (race-condition-ish: body resolved, then user clicks\n // cancel before we've returned) doesn't reject a promise nobody awaits.\n // Disposing the composed child signal here removes the listener it placed\n // on the long-lived run signal — the body has settled, so nothing else\n // observes it.\n guards?.detach()\n composedSignal.dispose()\n }\n }\n catch (err) {\n // Classify the failure as user-cancellation vs regular error.\n //\n // Two signals say \"this was the user's per-call cancel\":\n // 1. Our cancellation promise won the race — it always rejects with\n // the sentinel-message Error `armToolBodyAbortGuards` builds. This\n // is the definitive path because it pins the cause to OUR promise;\n // no other code path produces this message.\n // 2. The body observed `ctx.signal` and threw an `AbortError`-shaped\n // rejection, AND `perCallAbort` is the one that aborted (regardless\n // of whether the sibling/run signal also aborted, which can happen\n // when shell-cascade fires after our first cancelled shell returns\n // — see `settle` in `loop-tool-batch.ts` for the cascade-skip\n // that prevents this in practice).\n //\n // A check of `(perCallAbort.signal.aborted && !ctx.signal.aborted)`\n // would be too narrow: it misreads the case where the cascade already\n // flipped `ctx.signal` between our perCallAbort and the catch, which\n // would leak the raw sentinel string to the model on parallel-cancel-all.\n const isOurSentinel = err instanceof Error && err.message === CANCELLED_BY_USER_SENTINEL\n const isAbortError = err instanceof Error && err.name === 'AbortError'\n // Whether an AbortError was the user's cancel, the run's abort, or a\n // failure reads live signals: journaled, so a replay classifies it alike.\n const abortCause = isAbortError\n ? await classifyAbortError(ctx, perCallAbort, () => ctx.signal.reason === SHELL_CASCADE_REASON ? SHELL_CASCADE_CANCEL_MESSAGE : INTERRUPT_MESSAGE_FOR_TOOL_USE)\n : undefined\n if (isOurSentinel || abortCause?.kind === 'cancelled') {\n cancelledByUser = true\n }\n else if (abortCause?.kind === 'aborted') {\n // Run-level / sibling / shell-cascade abort: the body observed\n // `ctx.signal` (here the batch's `siblingAbort` signal) and unwound with\n // an AbortError. This is NOT a tool failure, so we must NOT fire\n // `tool:error` or surface `Tool error: AbortError` to the model —\n // a signal-unaware tool on the same abort gets the canonical interrupt\n // sentinel via the batch's `fillUnstarted`, and a signal-aware tool that\n // throws must land on the same wire result. Mirror the batch's\n // `cancelMessage()`: cascade → cascade message, otherwise interrupt.\n output = abortCause.message\n isError = true\n abortedWithRun = true\n }\n else {\n const error = err instanceof Error ? err : new Error(String(err))\n if (isControlError(ctx, error)) {\n // Fatal for the run — drop staged tool state instead of committing a\n // write nobody will observe (and free the per-call view).\n ctx.toolState?.discard(callId)\n throw error\n }\n if (!nested?.interrupted()) {\n // Hook can mutate `result` to substitute a custom payload for the model —\n // e.g. OSS-model error rewriting, collapsing stack traces. Default\n // `Tool error: <msg>` is used when no handler sets it.\n const errorCtx: ToolHookContext & {\n error: Error\n result?: string | ToolResultContent[]\n } = {\n ...buildToolHookBase(ctx, turnId, callId, call.name, displayName, effectiveInput),\n error,\n }\n await ctx.hooks.callHook('tool:error', errorCtx)\n output = errorCtx.result ?? toolErrorText(error)\n isError = true\n }\n }\n }\n // A nested call was interrupted: whatever the script made of it (no `tool:error` above), the whole call is (`createNestedToolCaller`).\n if (nested?.interrupted() && !cancelledByUser && !abortedWithRun) {\n output = TOOL_STEP_INTERRUPTED_MESSAGE\n isError = true\n }\n\n // Commit this call's staged tool state now that the body has settled —\n // uniformly, whatever the outcome, so \"the tool wrote it\" and \"the store\n // has it\" never diverge on an error/cancel path. In replay mode the ops\n // came back out of the call's step record (see `startReplayToolBody`), so\n // a replay re-issues an identical write; a call whose step never finished\n // has nothing staged and commits nothing.\n await settleAndCommit(ctx, nested, callId, call.name)\n\n if (cancelledByUser) {\n const reason = typeof perCallAbort.signal.reason === 'string'\n ? perCallAbort.signal.reason\n : 'cancelled-by-user'\n await ctx.hooks.callHook('tool:cancelled', {\n ...buildToolHookBase(ctx, turnId, callId, call.name, displayName, effectiveInput),\n reason,\n runToolCounts,\n })\n return { result: withNestedCalls({ id: callId, content: TOOL_USE_CANCELLED_MESSAGE, isError: true }, nested) }\n }\n\n const emitted = await emitToolResult(ctx, {\n turnId,\n callId,\n name: call.name,\n displayName,\n input: effectiveInput,\n output,\n isError,\n runToolCounts,\n ...(coercions ? { coercions } : {}),\n ...(reportedOutcome ? { outcome: reportedOutcome } : {}),\n })\n\n const result = finishedResult(ctx, callId, emitted, nested, reportedStructured)\n return reportedStructured && !emitted.isError ? { result, structured: reportedStructured } : { result }\n}\n\n/**\n * Shared handling for calls the dispatcher cannot route to an executable\n * tool — a hallucinated / dangling tool name (model invented it, MCP\n * server dropped, alias removed). Gives consumers a chance to substitute a\n * friendly response or suppress the companion `tool:error` so the trace\n * doesn't carry a noisy \"Unknown tool\" message back to the model.\n *\n * Fires `tool:before` with `unknown: true` FIRST so UI consumers\n * (`tool:before` → render a card) still see the model's attempt. The\n * sequence is `tool:before(unknown=true) → tool:unknown → tool:error`\n * (`suppressError` skips the third).\n * See AgentHooks['tool:before'].unknown for the pairing contract.\n * `tool:dispatched` (outcome `'unknown'`) closes the sequence so the\n * \"every call closes with exactly one tool:dispatched\" invariant holds on\n * both the single-call and joined-batch paths. `tool:after` / `tool:transform`\n * deliberately do NOT fire — see the gate-block branch in\n * {@link runSingleToolDispatch} for the backward-compat rationale.\n */\nexport async function handleUndispatchableTool(\n ctx: LoopContext,\n params: {\n turnId: string\n callId: string\n name: string\n displayName: string\n input: Record<string, unknown>\n runToolCounts: Readonly<Record<string, number>>\n /** Human-readable cause — becomes the `tool:error` Error message and the `Tool error: …` result text. */\n reason: string\n },\n): Promise<ToolResult> {\n const { turnId, callId, name, displayName, input, runToolCounts, reason } = params\n\n await ctx.hooks.callHook('tool:before', {\n ...buildToolHookBase(ctx, turnId, callId, name, displayName, input),\n runToolCounts,\n unknown: true,\n })\n\n const unknownCtx: ToolHookContext & {\n result?: string | ToolResultContent[]\n suppressError: boolean\n } = {\n ...buildToolHookBase(ctx, turnId, callId, name, displayName, input),\n suppressError: false,\n }\n await ctx.hooks.callHook('tool:unknown', unknownCtx)\n\n const content = unknownCtx.result ?? `Tool error: ${reason}`\n // Treat the call as an error iff the consumer didn't substitute a\n // successful result via `tool:unknown` (which is the substitute-and-\n // recover path). A non-substituted call always carries `Tool error: …`\n // text and should ride the `is_error` channel so the model sees the\n // wire-level error flag.\n const isError = unknownCtx.result === undefined\n\n if (!unknownCtx.suppressError) {\n const err = new Error(reason)\n await ctx.hooks.callHook('tool:error', {\n ...buildToolHookBase(ctx, turnId, callId, name, displayName, input),\n error: err,\n })\n }\n await fireDispatched(ctx, {\n turnId,\n callId,\n name,\n displayName,\n input,\n outcome: 'unknown',\n runToolCounts,\n })\n return { id: callId, content, ...(isError ? { isError: true } : {}) }\n}\n\n/**\n * The tool_result of a call `tool:gate` refused: `isError` so the model\n * treats it as a failed attempt, with the metadata the gate set.\n */\nexport function gateBlockedResult(callId: string, gate: { reason: string, metadata: ToolResultMetadata }): ToolResult {\n const { metadata } = sanitizeToolResultMetadata(gate.metadata)\n return { id: callId, content: `Blocked: ${gate.reason}`, isError: true, ...(metadata ? { metadata } : {}) }\n}\n\n/**\n * Fire `tool:dispatched` with the resolved path discriminator. Every code\n * path in {@link executeSingleTool} that produces a tool_result calls this\n * exactly once — so a `tool:dispatched` precedes every terminal event. The\n * terminal that closes a dispatch depends on `outcome`: `execute` closes with\n * `tool:after` OR `tool:cancelled` (in-flight cancel), `gate-substitute` with\n * `tool:after`, and `gate-block`/`invalid-input`/`unknown` carry their result\n * on the dispatch path itself (no `tool:after`). See the `tool:dispatched`\n * hook doc in `agent-hooks.ts` for the full per-outcome pairing. The strict\n * direction holds unconditionally: no `tool:after` fires without a dispatch.\n *\n * Helper exists to centralize the optional-field plumbing for `reason`\n * (only set on `gate-block`) without sprinkling spread-conditional logic\n * across five call sites.\n */\nexport async function fireDispatched(\n ctx: LoopContext,\n params: {\n turnId: string\n callId: string\n name: string\n displayName: string\n input: Record<string, unknown>\n outcome: 'execute' | 'gate-substitute' | 'gate-block' | 'unknown' | 'invalid-input'\n reason?: string\n runToolCounts: Readonly<Record<string, number>>\n },\n): Promise<void> {\n const { turnId, callId, name, displayName, input, outcome, reason, runToolCounts } = params\n await ctx.hooks.callHook('tool:dispatched', {\n ...buildToolHookBase(ctx, turnId, callId, name, displayName, input),\n outcome,\n runToolCounts,\n ...(reason !== undefined ? { reason } : {}),\n })\n}\n\n/**\n * Shared post-output emission: fire `tool:transform` (mutate-allowed), strip\n * images for non-vision providers, fire `tool:after`. Used by both the\n * gate-substitute and post-execute paths so they stay byte-for-byte\n * identical from the consumer's perspective.\n *\n * Returns both the (possibly transformed) output and the final `isError`\n * flag — `tool:transform` listeners can flip the flag in either direction\n * (e.g. rewrite a structured error response to a graceful retry hint), and\n * the caller needs the post-transform value to populate `ToolResult.isError`\n * on the wire.\n */\nexport async function emitToolResult(\n ctx: LoopContext,\n params: {\n turnId: string\n callId: string\n name: string\n displayName: string\n input: Record<string, unknown>\n output: string | ToolResultContent[]\n isError: boolean\n runToolCounts: Readonly<Record<string, number>>\n coercions?: readonly string[]\n outcome?: ToolOutcome\n },\n): Promise<{ output: string | ToolResultContent[], isError: boolean, metadata?: ToolResultMetadata }> {\n const { turnId, callId, name, displayName, input, runToolCounts, coercions, outcome } = params\n let output = params.output\n let isError = params.isError\n\n // Transform hook — mutate ctx.result / ctx.isError to modify output. The\n // `outputBytes` field is the byte-length of the result *before* any\n // consumer mutation, so a truncation hook can decide whether to act.\n const transformCtx = {\n ...buildToolHookBase(ctx, turnId, callId, name, displayName, input),\n result: output,\n isError,\n metadata: {} as ToolResultMetadata,\n outputBytes: toolOutputByteLength(output),\n ...(coercions ? { coercions } : {}),\n }\n await ctx.hooks.callHook('tool:transform', transformCtx)\n // Shrink oversize images before persistence so the stored turn — and so\n // every later request's prefix — carries the final bytes.\n output = shrinkToolOutputImages(transformCtx.result, ctx.behavior.maxImageEdge)\n isError = transformCtx.isError\n const sanitizedMetadata = sanitizeToolResultMetadata(transformCtx.metadata)\n const metadata = sanitizedMetadata.metadata\n if (sanitizedMetadata.warnings.length > 0 && process.env.ZIDANE_DEBUG) {\n process.stderr.write(\n `[zidane/loop] sanitized tool metadata for ${name}/${callId}: ${sanitizedMetadata.warnings.join('; ')}\\n`,\n )\n }\n\n // Lift the reserved `artifacts` namespace into the session's artifact\n // store. Reads the RAW transform metadata, not the sanitized copy: the\n // sanitizer bounds the whole bag to 16 KB and drops entire keys to get\n // under it, so lifting after it would lose every artifact whenever one\n // legal-sized `meta` (or a busy sibling namespace) tipped the total.\n // `normalizeArtifactInput` bounds each entry itself (JSON round-trip,\n // per-artifact `meta` cap, count cap). Strictly best-effort: a store\n // failure never fails the tool call, and the wire payload / persisted\n // turn are byte-identical with or without it. Sessionless runs and stores\n // without artifact support no-op inside `addArtifact`.\n await recordArtifactsFromMetadata(ctx, { turnId, callId, name, metadata: transformCtx.metadata })\n\n // Defensive coercion after `tool:transform`: transforms can flip `isError`\n // in either direction, so compute the final structured outcome only after\n // the final wire error bit is known. A success outcome on an error result\n // would make host loop guards read false progress.\n const finalOutcome: ToolOutcome | undefined\n = isError && outcome && outcome !== 'failed' ? 'failed' : outcome\n\n // Disk persistence — runs AFTER `tool:transform` so consumer transforms\n // get first crack at the result (compress / redact / annotate) before\n // we decide whether the post-transform bytes blow past the threshold.\n // Substitution mutates `output` in place; `tool:after` below then sees\n // the stub's byte size, and the stub is what lands in `session.turns`,\n // so subsequent turns re-emit the same bytes and ride the prompt cache.\n //\n // The truthy-check on `threshold` + `persistDir` short-circuits when\n // persistence is fully off (saves an async hop + struct allocation per\n // tool result) AND narrows both locals to non-nullable inside the block,\n // so the helper call site stays clean. The helper still validates its\n // own inputs (isAbsolute, threshold > 0, callId shape) — single source\n // of truth for \"is this call eligible\".\n // Nested calls (`ToolContext.callTool`) hand their result to the calling\n // tool, not the transcript: no spill-to-disk stub and no image stripping —\n // the caller's own result goes through both.\n const nested = ctx.nestedParentCallId !== undefined\n const threshold = ctx.behavior.persistThreshold\n const persistDir = ctx.behavior.persistDir\n if (!nested && threshold && threshold > 0 && persistDir) {\n const outcome = await maybePersistToolResult({\n toolName: name,\n callId,\n output,\n threshold,\n persistDir,\n ...(ctx.behavior.persistExcludeTools ? { excludeTools: ctx.behavior.persistExcludeTools } : {}),\n ...(typeof ctx.behavior.persistMaxBytes === 'number' ? { maxBytes: ctx.behavior.persistMaxBytes } : {}),\n writeBlob: spilledOrWrite(ctx),\n shouldRethrowError: err => isControlError(ctx, err),\n })\n if (outcome.kind === 'persisted') {\n output = outcome.output\n }\n // `skip` outcomes leave `output` untouched. On a write failure the helper\n // still returns a bounded failure stub: substitute it so an enabled\n // persistence strategy never lets the full payload ride the next request.\n // The tool itself succeeded, so `isError` stays as the tool reported it.\n else if (outcome.kind === 'error') {\n if (process.env.ZIDANE_DEBUG)\n process.stderr.write(`[zidane/loop] persistence write failed for ${name}/${callId}: ${outcome.error.message}\\n`)\n output = outcome.output\n }\n }\n\n // The call's result is settled: what its step spilled is no longer needed in memory.\n const spilledPath = persistedBlobPath(persistDir, callId)\n if (spilledPath)\n ctx.durable.spilled.delete(spilledPath)\n\n // Strip images for non-vision providers before they hit the wire. Done\n // after the transform hook so consumers can still observe the raw\n // structured output.\n if (!nested)\n output = stripImagesForNonVision(ctx.provider, output)\n\n // `tool:after` carries the post-mutation byte size — what actually goes\n // back to the model. Telemetry consumers should prefer this over\n // recomputing.\n await ctx.hooks.callHook('tool:after', {\n ...buildToolHookBase(ctx, turnId, callId, name, displayName, input),\n result: output,\n isError,\n outputBytes: toolOutputByteLength(output),\n runToolCounts,\n ...(coercions ? { coercions } : {}),\n ...(finalOutcome ? { outcome: finalOutcome } : {}),\n })\n\n return { output, isError, ...(metadata ? { metadata } : {}) }\n}\n\n/** The run's blob writer, skipping a blob the call's step already wrote with the same text (`RunDurability.spilled`). */\nfunction spilledOrWrite(ctx: LoopContext): (path: string, content: string) => Promise<void> {\n const write = executionBlobWriter(ctx)\n return async (path, content) => {\n if (ctx.durable.spilled.get(path) !== content)\n await write(path, content)\n }\n}\n\n/** Hard bound on artifacts a single tool result may emit; the rest are dropped. */\nconst MAX_ARTIFACTS_PER_TOOL_RESULT = 50\n\nasync function recordArtifactsFromMetadata(\n ctx: LoopContext,\n params: { turnId: string, callId: string, name: string, metadata: Record<string, unknown> | undefined },\n): Promise<void> {\n const raw = params.metadata?.[ARTIFACTS_METADATA_KEY]\n if (ctx.artifactsDisabled || !Array.isArray(raw) || raw.length === 0 || !ctx.session)\n return\n const inputs: SessionArtifactInput[] = []\n for (const entry of raw.slice(0, MAX_ARTIFACTS_PER_TOOL_RESULT)) {\n const normalized = normalizeArtifactInput(entry)\n if (normalized)\n inputs.push(canonicalizeFileArtifact(normalized, ctx))\n }\n for (const input of inputs) {\n try {\n const artifact = await ctx.session.addArtifact(input, { runId: ctx.runId, turnId: params.turnId })\n if (artifact) {\n await ctx.hooks.callHook('artifact:recorded', {\n runId: ctx.runId,\n turnId: params.turnId,\n callId: params.callId,\n name: params.name,\n artifact,\n })\n }\n }\n catch (err) {\n rethrowControlError(ctx, err)\n if (process.env.ZIDANE_DEBUG)\n process.stderr.write(`[zidane/loop] artifact record failed for ${params.name}/${params.callId}: ${String(err)}\\n`)\n }\n }\n}\n\n/**\n * `file:<path>` → `file://<abs path>`, resolved against the execution cwd\n * (detectors only see the model's input, which is usually relative). The\n * artifact's `projectRoot` is the git root the file actually landed in —\n * a worktree or sibling checkout differs from the session's root — but\n * only when the execution runs on the host: under docker / remote the\n * path isn't on this filesystem, so we keep the session default.\n */\nfunction canonicalizeFileArtifact(input: SessionArtifactInput, ctx: LoopContext): SessionArtifactInput {\n if (input.kind !== ARTIFACT_KINDS.file)\n return input\n let path = input.uri\n if (path.startsWith('file://'))\n path = path.slice('file://'.length)\n else if (path.startsWith('file:'))\n path = path.slice('file:'.length)\n if (!path)\n return input\n // Local process handles resolve with the host platform's path rules\n // (win32 cwd like `C:\\repo`); docker / remote handles are always posix.\n const local = ctx.handle.type === 'process'\n const abs = local ? resolvePath(ctx.handle.cwd, path) : posix.resolve(ctx.handle.cwd, path)\n const out: SessionArtifactInput = { ...input, uri: `file://${abs}` }\n if (!out.projectRoot && local) {\n // The project the file belongs to (a linked worktree's main checkout),\n // so project-scoped artifact lists span every worktree of the repo.\n const root = findProjectRoot(dirname(abs))\n if (root)\n out.projectRoot = root\n }\n return out\n}\n","/**\n * Tool batch execution for one assistant turn: concurrency-safe fan-out with\n * unsafe barriers, shell-error cascade, and the journaled scheduler of a\n * replay-mode run.\n */\n\nimport type { AgentHooks } from './agent-hooks'\nimport type { LoopContext } from './loop-context'\nimport type { StartedToolBody } from './loop-tool-step'\nimport type { ToolCall, ToolResult } from './providers'\nimport type { ToolContext, ToolDef } from './tools/types'\nimport type { ToolBatchExecutionContext, ToolBatchExecutor, ToolHookContext, ToolOutcome, ToolResultContent } from './types'\nimport { toWireName } from './aliasing'\nimport { errorMessage } from './errors'\nimport { isControlError, journaledDecision, throwIfSuspended, toolDurable } from './loop-context'\nimport { buildToolHookBase, classifyAbortError, commitToolState, composePerCallSignal, emitToolResult, executeSingleTool, fireDispatched, fireValidationCoerce, gateBlockedResult, handleUndispatchableTool, INTERRUPT_MESSAGE_FOR_TOOL_USE, mcpConnectionFor, progressReporter, runProvidersFor, SHELL_CASCADE_CANCEL_MESSAGE, SHELL_CASCADE_REASON, TOOL_USE_CANCELLED_MESSAGE, TOOL_USE_SKIPPED_MESSAGE, toolExecution } from './loop-tool-dispatch'\nimport { replayExecution, startReplayToolBody, toolStepFingerprint } from './loop-tool-step'\nimport { replays } from './run-durability'\nimport { OperationTimeoutError, withTimeout } from './timeout'\nimport { toolErrorText } from './tools/failure'\nimport { validateToolArgs } from './tools/validation'\n\n/** Default cap on in-flight tools per turn. Mirrors Claude Code's `CLAUDE_CODE_MAX_TOOL_USE_CONCURRENCY`. */\nexport const DEFAULT_MAX_CONCURRENT_TOOLS = 10\n\n/** Canonical name of the shell tool — referenced for cascade-cancel semantics. */\nconst SHELL_TOOL_NAME = 'shell'\n\ninterface JoinedToolStart {\n index: number\n call: ToolCall\n turnId: string\n callId: string\n name: string\n displayName: string\n input: Record<string, unknown>\n runToolCounts: Readonly<Record<string, number>>\n perCallAbort: AbortController\n /** Detach the composed child signal from the long-lived run signal; called once the call settles. */\n disposeSignal: () => void\n coercions?: readonly string[]\n body: StartedToolBody\n reportedOutcome: () => ToolOutcome | undefined\n /** What the body passed to `reportStructured` (nested calls only). */\n reportedStructured: () => { value: unknown } | undefined\n}\n\n/**\n * Resolve a tool's concurrency-safety verdict for a specific call.\n *\n * - Missing toolDef (unknown tool) → `false`. `executeSingleTool` handles\n * the unknown-tool path itself; barriering it keeps the unknown-tool\n * error from racing with siblings.\n * - Static `true` / `false` → use as-is.\n * - Function → invoke; any throw is treated as `false` (fail-closed) so a\n * buggy predicate can't accidentally widen the safety window.\n *\n * Pure / sync — pre-computed once per call before dispatch begins, so the\n * scheduler's hot path stays branch-light.\n */\nexport function resolveConcurrencySafe(\n def: ToolDef | undefined,\n input: Record<string, unknown>,\n): boolean {\n if (!def)\n return false\n const flag = def.isConcurrencySafe\n if (flag === undefined)\n return false\n if (typeof flag === 'boolean')\n return flag\n try {\n return flag(input) === true\n }\n catch {\n return false\n }\n}\n\n/**\n * Unified per-turn tool dispatcher.\n *\n * Walks `toolCalls` in submission order. For each call:\n *\n * - **Concurrency-safe + fleet is all safe + room under the cap** → fires\n * asynchronously and the loop advances to the next call. The fleet runs\n * in parallel up to `behavior.maxConcurrentTools` (default {@link\n * DEFAULT_MAX_CONCURRENT_TOOLS}).\n * - **Unsafe** (or the in-flight fleet contains anything unsafe) → acts\n * as a barrier: waits for the fleet to drain, then runs alone, then\n * unblocks the queue.\n *\n * Results are written into a fixed `results[index]` array on completion\n * and yielded back in submission order, so the model sees deterministic\n * adjacency regardless of which call finished first.\n *\n * **Failure modes:**\n *\n * - **Hook throws / tool body throws** — captured per-call into a\n * `tool_result` so the assistant turn's `tool_use` IDs always have\n * matching `tool_result` IDs (providers reject orphan IDs).\n * - **Parent abort** mid-batch — drains the in-flight fleet (their\n * `AbortError` becomes `INTERRUPT_MESSAGE_FOR_TOOL_USE`), then synthesizes\n * interrupt results for any unstarted calls so the turn closes cleanly.\n * - **Steering queue populated** between dispatches — same drain + a\n * `TOOL_USE_SKIPPED_MESSAGE` result for unstarted calls. The outer loop\n * picks up the steer at the next checkpoint.\n * - **Shell error in a fleet** — `siblingAbort.abort('sibling-shell-error')`\n * tears down concurrently-running siblings. Mirrors the convention that\n * shell commands often chain (`mkdir foo && cd foo`); one failing\n * sibling commonly invalidates the rest. Non-shell errors are isolated.\n *\n * A child `AbortController` (`siblingAbort`) forwards the parent abort\n * AND carries the shell-cascade signal — siblings see one signal source.\n */\nexport async function executeToolBatch(\n ctx: LoopContext,\n toolCalls: ToolCall[],\n turnId: string,\n): Promise<ToolResult[]> {\n if (ctx.behavior.toolBatchExecutor && !ctx.suppressBatchExecutor)\n return executeCustomToolBatch(ctx, toolCalls, turnId, ctx.behavior.toolBatchExecutor)\n if (replays(ctx.durable))\n return executeReplayToolBatch(ctx, toolCalls, turnId)\n return executeNativeToolBatch(ctx, toolCalls, turnId)\n}\n\n/**\n * Everything a tool batch needs that is NOT scheduling.\n *\n * The two batch executors differ only in how they order dispatches (the native\n * sliding window vs. a host-supplied executor over the same calls). Abort\n * plumbing, concurrency-safety verdicts, the shell cascade, and the mapping\n * from a thrown tool error to a `ToolResult` are identical, so they live here\n * once — a cascade or listener-leak fix lands in one place for both paths.\n */\ninterface ToolBatchHarness {\n /** Per-call context: same as `ctx` but on the sibling-scoped signal. */\n readonly childCtx: LoopContext\n /** Batch-wide controller: the shell cascade and executor timeouts trip it. */\n readonly siblingAbort: AbortController\n /** Pre-resolved concurrency-safety verdict per call index. */\n readonly safe: readonly boolean[]\n /** Effective in-flight cap (`>= 1`). */\n readonly maxConcurrent: number\n /** Cancellation text for an aborted call — distinguishes cascade from user abort. */\n cancelMessage: () => string\n /**\n * Execute one call to a settled `ToolResult`, applying the shell cascade and\n * turning a thrown tool error into an error result. Rejects only when\n * the run's durable runtime claims the error as control flow (`isControlError`).\n */\n settle: (index: number) => Promise<ToolResult>\n /** Detach the parent-abort listener. Idempotent; always call in a `finally`. */\n dispose: () => void\n}\n\nfunction createToolBatchHarness(\n ctx: LoopContext,\n toolCalls: ToolCall[],\n turnId: string,\n options: { suppressBatchExecutor?: boolean } = {},\n): ToolBatchHarness {\n const N = toolCalls.length\n const maxConcurrent = Math.max(1, ctx.behavior.maxConcurrentTools ?? DEFAULT_MAX_CONCURRENT_TOOLS)\n\n // Pre-resolve every call's safety verdict so a scheduler's main loop doesn't\n // re-invoke (potentially throwing) predicates inside its hot path. Indices\n // line up with `toolCalls`.\n const safe: boolean[] = Array.from({ length: N })\n for (let i = 0; i < N; i++)\n safe[i] = resolveConcurrencySafe(ctx.tools[toolCalls[i].name], toolCalls[i].input)\n\n // One controller for the whole batch — siblings share it. The parent abort is\n // forwarded via a single listener that we MUST clean up when the batch\n // returns: `ctx.signal` is the run-scoped `agent.run()` signal that outlives\n // this batch, so a never-removed listener would accumulate one entry per\n // batch over a multi-turn run. `{ once: true }` short-circuits the listener if\n // the abort fires, but we still need to remove it on the (typical) non-abort\n // exit — hence `dispose()`.\n const siblingAbort = new AbortController()\n let parentAbortListener: (() => void) | undefined\n if (ctx.signal.aborted) {\n siblingAbort.abort(ctx.signal.reason ?? 'parent-aborted')\n }\n else {\n parentAbortListener = () => siblingAbort.abort(ctx.signal.reason ?? 'parent-aborted')\n ctx.signal.addEventListener('abort', parentAbortListener, { once: true })\n }\n\n // Tools see the sibling-scoped signal — a shell cascade cancels them without\n // unwinding the parent. Spreading `ctx` keeps every other field (hooks,\n // behavior, readState, parentRunId, …) reaching tools.\n //\n // `suppressBatchExecutor` is a LOOP-side flag, deliberately NOT a blanked\n // `behavior.toolBatchExecutor`: `ctx.behavior` is what `executeSingleTool`\n // forwards as `ToolContext.behavior`, which `spawn` copies into the child\n // agent's preset. Editing it here would hand every subagent spawned from\n // inside a custom batch a `toolBatchExecutor: undefined` — silently\n // downgrading durable hosts to the native scheduler. The suppression is only\n // about this loop not re-entering the executor it is already inside.\n const childCtx: LoopContext = {\n ...ctx,\n signal: siblingAbort.signal,\n ...(options.suppressBatchExecutor ? { suppressBatchExecutor: true } : {}),\n }\n\n /**\n * Distinguish a shell-cascade kill from a user-issued abort so the model sees\n * actionable text. When BOTH the parent signal and the sibling signal are\n * aborted, the parent wins — user-issued aborts take precedence (the model is\n * being interrupted by the human, not by a sibling's failure).\n */\n const cancelMessage = (): string => {\n if (ctx.signal.aborted)\n return INTERRUPT_MESSAGE_FOR_TOOL_USE\n if (siblingAbort.signal.reason === SHELL_CASCADE_REASON)\n return SHELL_CASCADE_CANCEL_MESSAGE\n return INTERRUPT_MESSAGE_FOR_TOOL_USE\n }\n\n /*\n * Each call's wall time, saved on its `tool_result` so a reloaded transcript\n * shows how long it ran. Not in replay mode: a durable run rebuilds its\n * turns identically on replay (as nested-call records do).\n */\n const timed = !replays(ctx.durable)\n const settleUntimed = async (index: number): Promise<ToolResult> => {\n const call = toolCalls[index]\n try {\n const { result } = await executeSingleTool(childCtx, call, turnId)\n // Cascade-cancel only for shell, and only on the first error that lands\n // in a still-live fleet — keeps the abort reason pinned to the first\n // culprit. We deliberately EXCLUDE user-cancelled results: a\n // `agent.cancelTool('A')` on a shell means \"I'm done with A\", not \"A\n // failed in a way that invalidates B and C\". Without this exclusion,\n // cancelling one shell would cascade-kill its siblings (surprising and\n // wrong — the user only cancelled one), and `cancel all` on a fleet of\n // shells would mis-classify B and C as cascade-aborts instead of\n // user-cancellations, leaking the internal sentinel string to the wire.\n const contentIsString = typeof result.content === 'string'\n const isUserCancel = contentIsString && result.content === TOOL_USE_CANCELLED_MESSAGE\n if (\n result.isError\n && !isUserCancel\n && call.name === SHELL_TOOL_NAME\n && !siblingAbort.signal.aborted\n ) {\n siblingAbort.abort(SHELL_CASCADE_REASON)\n }\n return result\n }\n catch (err) {\n if (isControlError(ctx, err))\n throw err\n const isAbort = siblingAbort.signal.aborted\n || ctx.signal.aborted\n || (err instanceof Error && err.name === 'AbortError')\n return {\n id: call.id,\n content: isAbort ? cancelMessage() : `Error: ${errorMessage(err)}`,\n isError: true,\n }\n }\n }\n const settle = async (index: number): Promise<ToolResult> => {\n // Suspended (`Agent.suspend`): a call not started yet stays pending for the resume, whatever scheduler asks.\n throwIfSuspended(ctx)\n const startedAt = timed ? Date.now() : 0\n const result = await settleUntimed(index)\n return timed ? { ...result, durationMs: Math.max(0, Date.now() - startedAt) } : result\n }\n\n return {\n childCtx,\n siblingAbort,\n safe,\n maxConcurrent,\n cancelMessage,\n settle,\n dispose: () => {\n if (parentAbortListener) {\n ctx.signal.removeEventListener('abort', parentAbortListener)\n parentAbortListener = undefined\n }\n },\n }\n}\n\nasync function executeCustomToolBatch(\n ctx: LoopContext,\n toolCalls: ToolCall[],\n turnId: string,\n executor: ToolBatchExecutor,\n): Promise<ToolResult[]> {\n if (toolCalls.length === 0)\n return []\n\n const harness = createToolBatchHarness(ctx, toolCalls, turnId, { suppressBatchExecutor: true })\n const { siblingAbort, safe, maxConcurrent } = harness\n\n const executionCtx: ToolBatchExecutionContext = {\n toolCalls,\n turnId,\n maxConcurrentTools: maxConcurrent,\n signal: ctx.signal,\n steeringQueue: ctx.steeringQueue,\n isConcurrencySafe: index => safe[index] === true,\n execute: harness.settle,\n interruptedResult: index => ({\n id: toolCalls[index].id,\n content: INTERRUPT_MESSAGE_FOR_TOOL_USE,\n isError: true,\n }),\n skippedResult: index => ({\n id: toolCalls[index].id,\n content: TOOL_USE_SKIPPED_MESSAGE,\n isError: true,\n }),\n }\n\n const timeoutMs = typeof ctx.behavior.toolBatchTimeoutMs === 'number' && Number.isFinite(ctx.behavior.toolBatchTimeoutMs) && ctx.behavior.toolBatchTimeoutMs > 0\n ? ctx.behavior.toolBatchTimeoutMs\n : 0\n\n try {\n if (timeoutMs <= 0)\n return await executor(executionCtx)\n return await withTimeout(executor(executionCtx), {\n operation: 'custom tool batch executor',\n timeoutMs,\n onTimeout: () => siblingAbort.abort(new OperationTimeoutError('custom tool batch executor', timeoutMs)),\n message: `Custom tool batch executor timed out after ${timeoutMs}ms.`,\n })\n }\n catch (err) {\n if (!(err instanceof OperationTimeoutError))\n throw err\n return toolCalls.map(call => ({\n id: call.id,\n content: `Error: ${err.message}`,\n isError: true,\n }))\n }\n finally {\n harness.dispose()\n }\n}\n\n/**\n * The batch scheduler of a replay-mode run. Abort and steering are live state\n * a replay does not see, so every gate's decision is recorded and replays\n * verbatim. Calls run one at a time, except a run of concurrency-safe calls\n * whose bodies the runtime can join (steps, `durableBody: 'promise'`): up to\n * `maxConcurrentTools` of them start together and join in one\n * `RunScope.allSettled`, which a replay runtime turns into its own durable\n * combinator (one park per batch, never two operations awaited apart).\n */\nasync function executeReplayToolBatch(\n ctx: LoopContext,\n toolCalls: ToolCall[],\n turnId: string,\n): Promise<ToolResult[]> {\n const N = toolCalls.length\n if (N === 0)\n return []\n const harness = createToolBatchHarness(ctx, toolCalls, turnId)\n const { safe, maxConcurrent } = harness\n const results: ToolResult[] = []\n const joinable = (index: number): boolean => {\n const def = ctx.tools[toolCalls[index].name]\n return safe[index] === true && def !== undefined && replayExecution(def, ctx.execution, ctx.durable.runtime.mode) !== 'composite'\n }\n const liveGate = (): 'continue' | 'interrupt' | 'skip' => {\n if (ctx.signal.aborted)\n return 'interrupt'\n if (ctx.steeringQueue.length > 0)\n return 'skip'\n return 'continue'\n }\n const fill = (from: number, content: string): ToolResult[] => {\n for (let j = from; j < N; j++)\n results[j] = { id: toolCalls[j].id, content, isError: true }\n return results\n }\n try {\n for (let i = 0; i < N;) {\n const decision = await journaledDecision(ctx, 'tool-gate', liveGate)\n if (decision === 'interrupt')\n return fill(i, INTERRUPT_MESSAGE_FOR_TOOL_USE)\n if (decision === 'skip')\n return fill(i, TOOL_USE_SKIPPED_MESSAGE)\n const fleet = [i++]\n while (joinable(fleet[0]!) && i < N && joinable(i) && fleet.length < maxConcurrent)\n fleet.push(i++)\n if (fleet.length === 1) {\n results[fleet[0]!] = await harness.settle(fleet[0]!)\n continue\n }\n const settled = await executeJoinedFleet(harness, toolCalls, turnId, fleet)\n fleet.forEach((index, k) => {\n results[index] = settled[k]!\n })\n }\n return results\n }\n finally {\n harness.dispose()\n }\n}\n\n/**\n * Run a fleet of joinable calls: each call's gate, validation and\n * `tool:before` in order, then every body at once, joined by the run scope,\n * then each result in call order.\n */\nasync function executeJoinedFleet(\n harness: ToolBatchHarness,\n toolCalls: ToolCall[],\n turnId: string,\n indices: readonly number[],\n): Promise<ToolResult[]> {\n const { childCtx, siblingAbort, cancelMessage } = harness\n const starts: JoinedToolStart[] = []\n const results = new Map<number, ToolResult>()\n try {\n for (const index of indices) {\n const started = await startJoinedToolCall(childCtx, toolCalls[index], turnId, index)\n if (started.kind === 'result')\n results.set(index, started.result)\n else\n starts.push(started.start)\n }\n // The bodies' own promises, untouched: a `then` or `catch` here would\n // start a second consumer of a runtime promise that the join consumes.\n const settlements = starts.length > 0\n ? await childCtx.durable.scope.allSettled(starts.map(start => start.body.promise))\n : []\n for (const [k, start] of starts.entries()) {\n let result: ToolResult\n try {\n const output = start.body.finish(settlements[k]!)\n result = await completeJoinedToolCall(childCtx, start, output)\n }\n catch (err) {\n result = await failJoinedToolCall(childCtx, start, err, cancelMessage)\n }\n results.set(start.index, result)\n // The fleet already settled, so this cancels nothing in flight: it\n // stamps the cascade reason so later failures read as cascade aborts.\n const isUserCancel = typeof result.content === 'string' && result.content === TOOL_USE_CANCELLED_MESSAGE\n if (result.isError && !isUserCancel && start.call.name === SHELL_TOOL_NAME && !siblingAbort.signal.aborted)\n siblingAbort.abort(SHELL_CASCADE_REASON)\n }\n return indices.map(index => results.get(index) ?? {\n id: toolCalls[index].id,\n content: 'Error: the tool call did not produce a result',\n isError: true,\n })\n }\n finally {\n for (const start of starts) {\n childCtx.toolCancels?.unregister(start.callId)\n start.disposeSignal()\n // No-op once the call committed (commit drops the view); this only\n // catches starts that never reached completion, so views can't accumulate.\n childCtx.toolState?.discard(start.callId)\n }\n }\n}\n\nasync function startJoinedToolCall(\n ctx: LoopContext,\n call: ToolCall,\n turnId: string,\n index: number,\n): Promise<{ kind: 'result', result: ToolResult } | { kind: 'start', start: JoinedToolStart }> {\n const toolDef = ctx.tools[call.name]\n const callId = call.id\n const displayName = toWireName(call.name, ctx.aliasMaps)\n const runToolCounts: Readonly<Record<string, number>> = Object.freeze({ ...ctx.runToolCounts })\n const perCallAbort = new AbortController()\n ctx.toolCancels?.register(callId, perCallAbort)\n\n const cleanupResult = (result: ToolResult): { kind: 'result', result: ToolResult } => {\n ctx.toolCancels?.unregister(callId)\n return { kind: 'result', result }\n }\n\n const gateCtx: Parameters<AgentHooks['tool:gate']>[0] = {\n ...buildToolHookBase(ctx, turnId, callId, call.name, displayName, call.input),\n block: false,\n reason: 'Tool execution was blocked',\n metadata: {},\n runToolCounts,\n }\n await ctx.hooks.callHook('tool:gate', gateCtx)\n\n if (gateCtx.block) {\n await fireDispatched(ctx, {\n turnId,\n callId,\n name: call.name,\n displayName,\n input: gateCtx.input,\n outcome: 'gate-block',\n reason: gateCtx.reason,\n runToolCounts,\n })\n return cleanupResult(gateBlockedResult(callId, gateCtx))\n }\n\n ctx.runToolCounts[call.name] = (ctx.runToolCounts[call.name] ?? 0) + 1\n\n if (gateCtx.result !== undefined) {\n await fireDispatched(ctx, {\n turnId,\n callId,\n name: call.name,\n displayName,\n input: gateCtx.input,\n outcome: 'gate-substitute',\n runToolCounts,\n })\n const emitted = await emitToolResult(ctx, {\n turnId,\n callId,\n name: call.name,\n displayName,\n input: gateCtx.input,\n output: gateCtx.result,\n isError: false,\n runToolCounts,\n })\n return cleanupResult({\n id: callId,\n content: emitted.output,\n ...(emitted.isError ? { isError: true } : {}),\n ...(emitted.metadata ? { metadata: emitted.metadata } : {}),\n })\n }\n\n let effectiveInput = gateCtx.input\n\n if (!toolDef) {\n // Same hook sequence as the single-call unknown-tool path, so every call\n // still closes with exactly one `tool:dispatched`.\n return cleanupResult(await handleUndispatchableTool(ctx, {\n turnId,\n callId,\n name: call.name,\n displayName,\n input: effectiveInput,\n runToolCounts,\n reason: `Unknown tool: ${call.name}`,\n }))\n }\n\n const rejectInvalidInput = async (error: string | undefined) => {\n await ctx.hooks.callHook('validation:reject', {\n ...buildToolHookBase(ctx, turnId, callId, call.name, displayName, effectiveInput),\n reason: error ?? 'invalid input',\n schema: toolDef.spec.inputSchema,\n })\n await fireDispatched(ctx, {\n turnId,\n callId,\n name: call.name,\n displayName,\n input: effectiveInput,\n outcome: 'invalid-input',\n runToolCounts,\n })\n return cleanupResult({ id: callId, content: `Validation error: ${error}`, isError: true })\n }\n const validation = validateToolArgs(effectiveInput, toolDef.spec.inputSchema)\n if (!validation.valid)\n return rejectInvalidInput(validation.error)\n\n effectiveInput = validation.coercedInput ?? effectiveInput\n const coercions = validation.coercions && validation.coercions.length > 0\n ? validation.coercions\n : undefined\n if (coercions) {\n const coerced = await fireValidationCoerce(ctx, {\n ...buildToolHookBase(ctx, turnId, callId, call.name, displayName, effectiveInput),\n coercions,\n schema: toolDef.spec.inputSchema,\n }, effectiveInput)\n if ('error' in coerced)\n return rejectInvalidInput(coerced.error)\n effectiveInput = coerced.input\n }\n\n await fireDispatched(ctx, {\n turnId,\n callId,\n name: call.name,\n displayName,\n input: effectiveInput,\n outcome: 'execute',\n runToolCounts,\n })\n await ctx.hooks.callHook('tool:before', {\n ...buildToolHookBase(ctx, turnId, callId, call.name, displayName, effectiveInput),\n runToolCounts,\n ...(coercions ? { coercions } : {}),\n })\n\n // Manual signal composition (not `AbortSignal.any`) — see\n // {@link composePerCallSignal}. Disposed in the fleet's `finally`\n // once the call settles, so it never accumulates on the long-lived run signal.\n const composedSignal = composePerCallSignal(ctx.signal, perCallAbort.signal)\n const childSignal = composedSignal.signal\n let reportedOutcome: ToolOutcome | undefined\n let reportedStructured: { value: unknown } | undefined\n const runProviders = runProvidersFor(ctx)\n const reportProgress = progressReporter(ctx, () => buildToolHookBase(ctx, turnId, callId, call.name, displayName, effectiveInput))\n const toolCtx: ToolContext = {\n provider: ctx.provider,\n model: ctx.model,\n ...(runProviders ? { providers: runProviders } : {}),\n signal: childSignal,\n execution: toolExecution(ctx),\n handle: ctx.handle,\n hooks: ctx.hooks,\n tools: ctx.inheritance.tools,\n ...(ctx.inheritance.name !== undefined ? { name: ctx.inheritance.name } : {}),\n ...(ctx.inheritance.system !== undefined ? { system: ctx.inheritance.system } : {}),\n ...(ctx.inheritance.toolAliases !== undefined ? { toolAliases: ctx.inheritance.toolAliases } : {}),\n ...(ctx.inheritance.toolDescriptions !== undefined ? { toolDescriptions: ctx.inheritance.toolDescriptions } : {}),\n ...(ctx.inheritance.mcpServers !== undefined ? { mcpServers: ctx.inheritance.mcpServers } : {}),\n ...(mcpConnectionFor(ctx)),\n ...(ctx.inheritance.skills !== undefined ? { skills: ctx.inheritance.skills } : {}),\n behavior: ctx.behavior,\n turnId,\n callId,\n runId: ctx.runId,\n ...(ctx.parentRunId !== undefined ? { parentRunId: ctx.parentRunId } : {}),\n ...(ctx.parentCallId !== undefined ? { parentCallId: ctx.parentCallId } : {}),\n ...(ctx.session ? { session: ctx.session } : {}),\n ...(ctx.readState ? { readState: ctx.readState } : {}),\n ...(ctx.toolState ? { state: ctx.toolState.begin(callId) } : {}),\n ...(typeof ctx.depth === 'number' ? { depth: ctx.depth } : {}),\n clock: ctx.clock,\n durable: toolDurable(ctx),\n reportOutcome: (outcome: ToolOutcome) => {\n reportedOutcome = outcome\n },\n // A nested call (codemode's `tools.*`) batched here: it reads as one, and\n // its structured value reaches the calling script.\n ...(ctx.nestedParentCallId !== undefined ? { parentToolCallId: ctx.nestedParentCallId } : {}),\n ...(reportProgress ? { reportProgress } : {}),\n ...(ctx.nestedStructured\n ? { reportStructured: (value: unknown) => { reportedStructured = { value } } }\n : {}),\n }\n\n return {\n kind: 'start',\n start: {\n index,\n call,\n turnId,\n callId,\n name: call.name,\n displayName,\n input: effectiveInput,\n runToolCounts,\n perCallAbort,\n disposeSignal: composedSignal.dispose,\n ...(coercions ? { coercions } : {}),\n body: startReplayToolBody(ctx, toolDef, effectiveInput, toolCtx, fingerprintOption(ctx, call)),\n reportedOutcome: () => reportedOutcome,\n reportedStructured: () => reportedStructured,\n },\n }\n}\n\nfunction fingerprintOption(ctx: LoopContext, call: ToolCall): { fingerprint?: string } {\n const fingerprint = toolStepFingerprint(ctx, call)\n return fingerprint !== undefined ? { fingerprint } : {}\n}\n\nasync function completeJoinedToolCall(\n ctx: LoopContext,\n start: JoinedToolStart,\n output: string | ToolResultContent[],\n): Promise<ToolResult> {\n // Committed here rather than at settlement time: the fleet walks `starts`\n // in call-index order, so the store sees a deterministic write sequence\n // even when the join settles out of order.\n await commitToolState(ctx, start.callId, start.name)\n const reportedOutcome = start.reportedOutcome()\n const emitted = await emitToolResult(ctx, {\n turnId: start.turnId,\n callId: start.callId,\n name: start.name,\n displayName: start.displayName,\n input: start.input,\n output,\n isError: false,\n runToolCounts: start.runToolCounts,\n ...(start.coercions ? { coercions: start.coercions } : {}),\n ...(reportedOutcome ? { outcome: reportedOutcome } : {}),\n })\n const structured = start.reportedStructured()\n if (structured && !emitted.isError)\n ctx.nestedStructured?.(start.callId, structured.value)\n\n return {\n id: start.callId,\n content: emitted.output,\n ...(emitted.isError ? { isError: true } : {}),\n ...(emitted.metadata ? { metadata: emitted.metadata } : {}),\n }\n}\n\nasync function failJoinedToolCall(\n ctx: LoopContext,\n start: JoinedToolStart,\n err: unknown,\n cancelMessage: () => string,\n): Promise<ToolResult> {\n if (isControlError(ctx, err)) {\n ctx.toolState?.discard(start.callId)\n throw err\n }\n // Same rule as the single-call path: a settled call commits whatever it\n // staged (a failed step still records its ops).\n await commitToolState(ctx, start.callId, start.name)\n const isAbortError = err instanceof Error && err.name === 'AbortError'\n // Runs after the fleet join, so a journaled verdict never overlaps an\n // in-flight runtime operation.\n const abortCause = isAbortError ? await classifyAbortError(ctx, start.perCallAbort, cancelMessage) : undefined\n if (abortCause?.kind === 'cancelled') {\n const reason = typeof start.perCallAbort.signal.reason === 'string'\n ? start.perCallAbort.signal.reason\n : 'cancelled-by-user'\n await ctx.hooks.callHook('tool:cancelled', {\n ...buildToolHookBase(ctx, start.turnId, start.callId, start.name, start.displayName, start.input),\n reason,\n runToolCounts: start.runToolCounts,\n })\n return { id: start.callId, content: TOOL_USE_CANCELLED_MESSAGE, isError: true }\n }\n // Only an AbortError-shaped failure is a cancellation: a real tool failure\n // keeps its own text even when the signal is already aborted.\n if (abortCause?.kind === 'aborted') {\n return {\n id: start.callId,\n content: abortCause.message,\n isError: true,\n }\n }\n const error = err instanceof Error ? err : new Error(String(err))\n const errorCtx: ToolHookContext & {\n error: Error\n result?: string | ToolResultContent[]\n } = {\n ...buildToolHookBase(ctx, start.turnId, start.callId, start.name, start.displayName, start.input),\n error,\n }\n await ctx.hooks.callHook('tool:error', errorCtx)\n const emitted = await emitToolResult(ctx, {\n turnId: start.turnId,\n callId: start.callId,\n name: start.name,\n displayName: start.displayName,\n input: start.input,\n output: errorCtx.result ?? toolErrorText(error),\n isError: true,\n runToolCounts: start.runToolCounts,\n ...(start.coercions ? { coercions: start.coercions } : {}),\n })\n return {\n id: start.callId,\n content: emitted.output,\n ...(emitted.isError ? { isError: true } : {}),\n ...(emitted.metadata ? { metadata: emitted.metadata } : {}),\n }\n}\n\nasync function executeNativeToolBatch(\n ctx: LoopContext,\n toolCalls: ToolCall[],\n turnId: string,\n): Promise<ToolResult[]> {\n if (toolCalls.length === 0)\n return []\n\n const N = toolCalls.length\n const results: (ToolResult | undefined)[] = Array.from({ length: N })\n\n const harness = createToolBatchHarness(ctx, toolCalls, turnId)\n const { safe, maxConcurrent } = harness\n\n /** Indices currently in flight. Tracked for fleet-safety + cap checks. */\n const inFlight = new Map<number, Promise<void>>()\n\n const dispatch = (index: number): Promise<void> => {\n return harness.settle(index).then((result) => {\n results[index] = result\n }).finally(() => {\n inFlight.delete(index)\n })\n }\n\n const drain = async (): Promise<void> => {\n if (inFlight.size > 0)\n await Promise.all([...inFlight.values()])\n }\n\n /**\n * Free a SINGLE slot: wait for the first in-flight call to settle rather\n * than the whole fleet. Used when an all-safe fleet hits `maxConcurrent` —\n * a sliding window dispatches the next safe call the moment ANY sibling\n * finishes, instead of stalling the entire batch on the slowest one (which\n * a full `drain()` would do). `dispatch()` never rejects (it captures both\n * outcomes into `results[]`), so `Promise.race` here can't throw. Each\n * dispatched promise carries a `.finally` that deletes its own slot from\n * `inFlight` BEFORE the promise resolves, so on return `inFlight.size` has\n * dropped by at least one and a dispatch is guaranteed to fit under the cap.\n */\n const waitForSlot = async (): Promise<void> => {\n if (inFlight.size > 0)\n await Promise.race([...inFlight.values()])\n }\n\n /** Whether every in-flight call is concurrency-safe. */\n const fleetAllSafe = (): boolean => {\n for (const idx of inFlight.keys()) {\n if (!safe[idx])\n return false\n }\n return true\n }\n\n /**\n * Fill all unstarted slots (`results[j]` still undefined) with the\n * canonical text + `isError: true`. Used at every short-circuit\n * branch (abort / steer) so the assistant turn's `tool_use` IDs\n * always have matching `tool_result` IDs — providers reject orphan\n * IDs loudly.\n */\n const fillUnstarted = (from: number, content: string): void => {\n for (let j = from; j < N; j++) {\n if (!results[j])\n results[j] = { id: toolCalls[j].id, content, isError: true }\n }\n }\n\n const liveGate = (): 'continue' | 'interrupt' | 'skip' | 'suspend' => {\n if (ctx.suspendSignal?.aborted)\n return 'suspend'\n if (ctx.signal.aborted)\n return 'interrupt'\n if (ctx.steeringQueue.length > 0)\n return 'skip'\n return 'continue'\n }\n\n try {\n for (let i = 0; i < N; i++) {\n // Barrier semantics: an unsafe call (or an unsafe-poisoned fleet)\n // flushes everything in-flight before dispatching. After the drain,\n // the fleet is empty and the unsafe call runs alone; subsequent safe\n // calls re-form a new fleet behind it.\n if (!safe[i] || !fleetAllSafe())\n await drain()\n // All-safe fleet at the cap: free just one slot (sliding window) so\n // the next safe call dispatches as soon as ANY sibling finishes,\n // rather than barriering on the slowest. Without this, N safe calls\n // with N > maxConcurrent run as fixed batches and each batch waits on\n // its slowest member — turning a parallel fan-out into staircased\n // latency. The barrier branch above already handled the unsafe cases.\n else if (inFlight.size >= maxConcurrent)\n await waitForSlot()\n\n // Re-check abort + steer AFTER any drain — tools that resolved\n // during the drain may have flipped either signal (e.g. a tool\n // calls `agent.abort()` from its body, or `tool:after` enqueues\n // a steer). Checking only at the top of the iteration would\n // miss these and dispatch one extra tool. Cheap re-check, no I/O.\n //\n // On either early-return path we MUST drain the live fleet\n // first: dispatched-but-unresolved promises still own slots in\n // `results[]`, so returning before they finish would leave\n // those slots `undefined` and the caller would see orphan\n // `tool_use` IDs without paired `tool_result`s. Aborted tools\n // propagate through `siblingAbort.signal` and resolve with an\n // error result; steered tools complete normally (the steer is\n // a post-batch concern, not an in-flight kill).\n const decision = liveGate()\n // Suspended: the calls already running finish (or meet the cut-off), the rest stay pending with no results turn.\n if (decision === 'suspend') {\n await drain()\n throwIfSuspended(ctx)\n }\n if (decision === 'interrupt') {\n await drain()\n fillUnstarted(i, INTERRUPT_MESSAGE_FOR_TOOL_USE)\n return results as ToolResult[]\n }\n if (decision === 'skip') {\n await drain()\n fillUnstarted(i, TOOL_USE_SKIPPED_MESSAGE)\n return results as ToolResult[]\n }\n\n inFlight.set(i, dispatch(i))\n }\n\n // Drain the trailing fleet — last call may have been safe + non-\n // blocking. After the drain, results may still contain interrupt\n // messages from dispatch's onrejected branch for tools that saw a\n // mid-flight abort.\n await drain()\n return results as ToolResult[]\n }\n catch (err) {\n // A control error (a suspension, a takeover) ends the batch: the calls still running settle first, so none outlives the run.\n await Promise.allSettled([...inFlight.values()])\n throw err\n }\n finally {\n harness.dispose()\n }\n}\n","/**\n * A turn's streaming phase: the stream observer (accumulated output, hook\n * chain, throttled `stream:progress`), recovery from a failed attempt by\n * backoff-retry, reactive overflow compaction or fallback to the next target,\n * and the terminal failure that persists the placeholder turn and throws.\n */\n\nimport type { ClassifiedError } from './errors'\nimport type { collectCallMaps } from './loop-compaction'\nimport type { LoopContext } from './loop-context'\nimport type { StreamFailureAssessment } from './loop-recovery'\nimport type { TurnResult as ProviderTurnResult, StreamCallbacks, StreamOptions } from './providers'\nimport type { JsonValue, SessionMessage, SessionTurn, StreamUsageSnapshot, TurnUsage } from './types'\nimport { interceptRetry } from './agent-interceptors'\nimport { toWireName } from './aliasing'\nimport { estimateTokens } from './compact/utils'\nimport { stepDecision } from './durable/errors'\nimport { AgentAbortedError, errorMessage } from './errors'\nimport { lastAssistantUsage } from './loop-auto-compact'\nimport { applyOverflowCutoff, nextOverflowCutoffs, overflowCutoffAnchor } from './loop-compaction'\nimport { durableClock, journaledDecision, rethrowControlError, settledHook } from './loop-context'\nimport { assessStreamFailure, backoffSleep, computeRetryDelayMs, resolveRetryConfig, retryJitter } from './loop-recovery'\nimport { markReadStateForElidedPaths } from './loop-stale-reads'\nimport { buildStreamErrorPlaceholder, extractStreamErrorMeta, fallbackTrail, RETRY_STREAM_START_TIMEOUT_CAP_MS, STREAM_PROGRESS_THROTTLE_MS, streamWithWatchdogs, surfaceProviderFailure } from './loop-stream'\nimport { applyPairingRepair, sanitizeStoredToolResults } from './loop-wire'\nimport { fillEstimatedCost } from './providers/cost'\nimport { replays } from './run-durability'\nimport { ensureEndsWithUserMessage } from './session/messages'\n\nexport interface RunUsageSnapshot {\n input: number\n output: number\n cacheRead: number\n cacheCreation: number\n priorCost: number\n priorTurns: number\n}\n\nexport function buildCumulativeUsage(prior: RunUsageSnapshot, turnUsage: TurnUsage): Readonly<{\n input: number\n output: number\n cacheRead: number\n cacheCreation: number\n cost?: number\n turns: number\n}> {\n const cost = prior.priorCost + (turnUsage.cost ?? 0)\n return Object.freeze({\n input: prior.input + turnUsage.input,\n output: prior.output + turnUsage.output,\n cacheRead: prior.cacheRead + (turnUsage.cacheRead ?? 0),\n cacheCreation: prior.cacheCreation + (turnUsage.cacheCreation ?? 0),\n ...(cost > 0 ? { cost } : {}),\n turns: prior.priorTurns + 1,\n })\n}\n\n/**\n * Reactive context-overflow recovery schedule. When a turn is rejected with\n * `context_exceeded` (pre-stream — the request was too big for the model's\n * window), the loop stubs older media and `tool_result` bodies up to a\n * frontier ({@link applyOverflowCutoff}) and re-issues, instead of surfacing\n * the error.\n *\n * Each entry is a floor of trailing messages left intact: 4, then 1, then\n * none. {@link nextOverflowCutoffs} turns them into frontiers snapped to\n * `COMPACT_CHUNK_TURNS`, so the model loses as little fresh context as\n * possible while the stubbed prefix only moves in chunk-sized jumps. The\n * frontier is remembered (`LoopContext.overflowRescue`) and re-applied up\n * front on later turns. Runs regardless of `behavior.compactStrategy` (calls\n * the compactor directly), so it protects runs that never opted into\n * compaction.\n */\nconst CONTEXT_OVERFLOW_KEEP_TURNS = [4, 1, 0] as const\n\n/**\n * Advance the run to the next provider+model target and rebind the prepared\n * request to it.\n *\n * Caller contract: only invoke when `assessStreamFailure` returned\n * `canFallback` — that verdict guarantees an untried target exists, so the\n * index arithmetic here needs no bounds check of its own.\n *\n * Run-sticky: `activeTargetIndex` only advances, so later turns of this run\n * stay on the fallback target. The next `run()` resolves a fresh target list\n * starting from the primary.\n */\nasync function advanceToFallbackTarget(\n ctx: LoopContext,\n streamOptions: StreamOptions,\n turnId: string,\n err: Error,\n discardedThinking: boolean,\n): Promise<void> {\n const targets = ctx.targets!\n const fromIndex = ctx.activeTargetIndex ?? 0\n const nextIndex = fromIndex + 1\n const from = targets[fromIndex]\n const to = targets[nextIndex]\n\n ctx.activeTargetIndex = nextIndex\n ctx.provider = to.provider\n ctx.model = to.model\n ctx.providerName = to.provider.name\n if (ctx.rebuildFormattedTools)\n ctx.formattedTools = ctx.rebuildFormattedTools(to.provider)\n\n // Record the exhausted target's failure — if the whole chain ends up\n // exhausting, the terminal error appends this trail so earlier failures stay\n // diagnosable (see `fallbackTrail`).\n ;(ctx.targetFailures ??= []).push({ provider: from.provider.name, model: from.model, err })\n\n // The auto-compact trigger measures the ACTIVE target's window.\n // Preference order for the new window:\n // 1. The target's own `contextWindow` (host catalog value carried on the\n // chain entry) — trusted even over an explicit host-set window, because\n // it IS host-set, for exactly this model.\n // 2. Provider meta — only when the current value was meta-sourced (never\n // silently override an explicit host-set window).\n // When neither yields a usable number, the previous value stays — a stale\n // estimate still beats an inert trigger.\n if (ctx.autoCompact) {\n const nextWindow = to.contextWindow\n ?? (ctx.autoCompact.contextWindowFromProviderMeta ? to.provider.meta.contextWindow : undefined)\n if (nextWindow !== undefined && Number.isFinite(nextWindow) && nextWindow > 0)\n ctx.autoCompact.contextWindow = nextWindow\n }\n\n // Rebind the prepared request to the new target: model id, wire tool shapes,\n // and a re-sanitize pass so capability skew (media the new provider can't\n // accept) degrades to markers. Messages stay as-is — the alias rewrite\n // upstream is keyed on the agent-level aliasMaps, not the provider, so\n // they're valid for any target (sanitize is the only provider-dependent\n // pass, and it only degrades one way: media flattened for an earlier\n // non-vision target is not resurrected for a vision-capable one).\n //\n // Deliberately NOT rebound: `maxTokens` and the thinking budget. They were\n // sized for the primary model and there's no portable provider-meta field to\n // clamp against. A target whose ceiling is below the carried budget rejects\n // the request and the chain simply advances again — self-correcting, at the\n // cost of one wasted attempt. Hosts that mix models with very different\n // output ceilings should size budgets for the smallest target.\n streamOptions.model = to.model\n streamOptions.tools = ctx.formattedTools\n streamOptions.messages = sanitizeStoredToolResults(to.provider, streamOptions.messages)\n\n await settledHook(ctx, 'hook model:fallback', ctx.hooks.callHook('model:fallback', {\n turnId,\n from: { provider: from.provider.name, model: from.model },\n to: { provider: to.provider.name, model: to.model },\n targetIndex: nextIndex,\n err,\n ...(discardedThinking ? { discardedThinking: true as const } : {}),\n }))\n}\n\n/** Lazily-built call_id maps over the turn's canonical history (see {@link buildTurnWireMessages}). */\nexport type TurnCallMaps = () => ReturnType<typeof collectCallMaps>\n\n/**\n * Everything the turn observes from the provider stream across attempts:\n * accumulated text/thinking, server-tool activity, per-turn TTFT, the\n * serialized stream-hook chain, and the throttled `stream:progress` emitter.\n * Built by {@link createTurnStreamObserver}.\n */\ninterface TurnStreamObserver {\n text: string\n thinking: string\n /**\n * Server-side tool execution observed this turn (across attempts). Tracked\n * separately from text/thinking because it blocks retry and fallback: the\n * provider already ran (and billed) the tool and the\n * `stream:server_tool_use` hooks fired, so a re-issue would double-execute\n * and re-emit under the same turnId.\n */\n serverToolActivity: boolean\n /**\n * Tool-call content started streaming this turn (across attempts). Blocks\n * retry and fallback: hosts may already show the call.\n */\n toolCallActivity: boolean\n readonly streamStartedAt: number\n turnTtftMs: number | undefined\n liveUsage: StreamUsageSnapshot | undefined\n progressTimer: ReturnType<typeof setTimeout> | undefined\n /** Serialized stream-callback hook handlers; never rejects. */\n hookChain: Promise<void>\n /** Fresh provider callbacks for one stream attempt. */\n callbacks: () => StreamCallbacks\n emitProgress: () => Promise<void>\n endProgress: () => void\n}\n\nfunction createTurnStreamObserver(\n ctx: LoopContext,\n turnId: string,\n streamOptions: StreamOptions,\n streamStartedAt: number,\n): TurnStreamObserver {\n // Live `stream:progress` — throttled like `compact:progress`, with a\n // trailing dispatch so the last delta before a quiet spell still lands, and\n // one forced dispatch before `stream:end`. Fire-and-forget: a slow listener\n // must never stall the stream. `progressEnded` gates the tail so nothing\n // fires after the turn's terminal hook.\n let lastProgressAt = 0\n let progressEnded = false\n const priorTurnUsage = lastAssistantUsage(ctx.turns)\n\n const obs: TurnStreamObserver = {\n text: '',\n thinking: '',\n serverToolActivity: false,\n toolCallActivity: false,\n streamStartedAt,\n // Per-turn TTFT — earliest of first text/thinking delta. Tool-first turns\n // (no surface stream content) inherit `undefined` and let the metric\n // histogram skip them rather than reporting `0` (provider returned before\n // anything observable streamed; a no-op turn shouldn't pollute the bucket).\n turnTtftMs: undefined,\n liveUsage: undefined,\n progressTimer: undefined,\n hookChain: Promise.resolve(),\n callbacks,\n emitProgress,\n endProgress,\n }\n\n function markTurnTtft(): void {\n if (obs.turnTtftMs === undefined)\n obs.turnTtftMs = Date.now() - streamStartedAt\n }\n\n // Stream-callback hooks fire from synchronous provider callbacks, so they\n // can't be awaited inline. Serialize them onto a single chain so:\n // 1. handler rejections are observed (a throwing `stream:text` handler\n // would otherwise become an unhandled promise rejection), and\n // 2. async handlers run in delta order and are fully settled before\n // `stream:end` fires (no interleaving past the stream boundary).\n // Handler errors never kill the stream — they're observability concerns;\n // surfaced under ZIDANE_DEBUG only.\n function enqueueStreamHook(fire: () => Promise<unknown> | void): void {\n obs.hookChain = obs.hookChain.then(fire).then(\n () => {},\n (err) => {\n if (process.env.ZIDANE_DEBUG)\n process.stderr.write(`[zidane/loop] stream hook handler threw: ${errorMessage(err)}\\n`)\n },\n )\n }\n\n async function emitProgress(): Promise<void> {\n if (progressEnded)\n return\n // Provider count when the wire has sent one, else the character\n // heuristic. Anthropic reports the prompt side at `message_start` but the\n // running output count only in the final `message_delta`, so a snapshot\n // without `outputTokens` must NOT freeze the counter — the estimate keeps\n // it moving and the provider figure snaps it at the end.\n const providerOutput = obs.liveUsage?.outputTokens\n const outputTokens = providerOutput ?? estimateTokens(obs.text + obs.thinking)\n const promptSide = obs.liveUsage?.inputTokens !== undefined\n ? { input: obs.liveUsage.inputTokens, cacheRead: obs.liveUsage.cacheRead, cacheCreation: obs.liveUsage.cacheCreation }\n : priorTurnUsage\n ? { input: priorTurnUsage.input, cacheRead: priorTurnUsage.cacheRead, cacheCreation: priorTurnUsage.cacheCreation }\n : { input: 0 }\n let estCostUsd: number | undefined\n if (obs.liveUsage?.billable !== false) {\n const priced = await fillEstimatedCost(\n { ...promptSide, output: outputTokens, modelId: streamOptions.model },\n ctx.provider.name,\n undefined,\n ctx.behavior.modelCatalog,\n )\n estCostUsd = priced.cost\n }\n if (progressEnded)\n return\n await ctx.hooks.callHook('stream:progress', {\n turnId,\n elapsedMs: Date.now() - streamStartedAt,\n outputTokens,\n ...(obs.liveUsage?.inputTokens !== undefined ? { inputTokens: obs.liveUsage.inputTokens } : {}),\n ...(obs.liveUsage?.cacheRead !== undefined ? { cacheRead: obs.liveUsage.cacheRead } : {}),\n ...(obs.liveUsage?.cacheCreation !== undefined ? { cacheCreation: obs.liveUsage.cacheCreation } : {}),\n estimated: providerOutput === undefined,\n ...(estCostUsd !== undefined ? { estCostUsd } : {}),\n })\n }\n function fireProgress(): void {\n lastProgressAt = Date.now()\n void emitProgress().catch((err) => {\n if (process.env.ZIDANE_DEBUG)\n process.stderr.write(`[zidane/loop] stream:progress handler threw: ${errorMessage(err)}\\n`)\n })\n }\n function scheduleProgress(): void {\n if (progressEnded)\n return\n const wait = STREAM_PROGRESS_THROTTLE_MS - (Date.now() - lastProgressAt)\n if (wait <= 0) {\n if (obs.progressTimer) {\n clearTimeout(obs.progressTimer)\n obs.progressTimer = undefined\n }\n fireProgress()\n return\n }\n if (!obs.progressTimer) {\n obs.progressTimer = setTimeout(() => {\n obs.progressTimer = undefined\n fireProgress()\n }, wait)\n }\n }\n function endProgress(): void {\n progressEnded = true\n if (obs.progressTimer) {\n clearTimeout(obs.progressTimer)\n obs.progressTimer = undefined\n }\n }\n\n function callbacks(): StreamCallbacks {\n return {\n onText(delta) {\n markTurnTtft()\n obs.text += delta\n // Snapshot the accumulated text now — the chained handler may\n // run after later deltas have already grown `obs.text`.\n const text = obs.text\n enqueueStreamHook(() => ctx.hooks.callHook('stream:text', { delta, text, turnId }))\n scheduleProgress()\n },\n onThinking(delta) {\n markTurnTtft()\n obs.thinking += delta\n const thinking = obs.thinking\n enqueueStreamHook(() => ctx.hooks.callHook('stream:thinking', { delta, thinking, turnId }))\n scheduleProgress()\n },\n onUsage(usage) {\n obs.liveUsage = usage\n scheduleProgress()\n },\n onToolCallDelta() {\n obs.toolCallActivity = true\n },\n onServerToolUse({ id, name, input }) {\n enqueueStreamHook(() => ctx.hooks.callHook('stream:server_tool_use', { id, name, input, turnId }))\n },\n onServerToolResult({ toolUseId, toolName, content }) {\n enqueueStreamHook(() => ctx.hooks.callHook('stream:server_tool_result', { toolUseId, toolName, content, turnId }))\n },\n onOAuthRefresh(refreshCtx) {\n return ctx.hooks.callHook('oauth:refresh', refreshCtx)\n },\n }\n }\n\n return obs\n}\n\n/**\n * Reactive context-overflow shrink. Tries the frontiers past the remembered\n * cutoff ({@link nextOverflowCutoffs}) in order and returns the first list\n * that actually shrank, with the elided read paths, or `undefined` when\n * nothing can shrink further. Records the new frontier in\n * `ctx.overflowRescue` so later turns re-apply it before sending\n * (`buildTurnWireMessages`) instead of being rejected again.\n */\nfunction shrinkForContextOverflow(\n ctx: LoopContext,\n messages: SessionMessage[],\n callMaps: TurnCallMaps,\n): { messages: SessionMessage[], elidedReadPaths: string[] } | undefined {\n const rescue = (ctx.overflowRescue ??= {})\n const anchor = overflowCutoffAnchor(ctx.turns)\n const prior = rescue.cutoff?.anchor === anchor && rescue.cutoff.index <= messages.length\n ? rescue.cutoff\n : undefined\n const { readPathByCallId, toolNameByCallId } = callMaps()\n const readFileToolName = ctx.tools.read_file ? toWireName('read_file', ctx.aliasMaps) : null\n for (const index of nextOverflowCutoffs(messages.length, prior?.index ?? 0, CONTEXT_OVERFLOW_KEEP_TURNS)) {\n const stubbed = applyOverflowCutoff(messages, index, { readPathByCallId, toolNameByCallId, readFileToolName })\n if (stubbed.messages !== messages) {\n rescue.cutoff = {\n index,\n media: stubbed.media || (prior?.media ?? false),\n toolResults: stubbed.toolResults || (prior?.toolResults ?? false),\n anchor,\n }\n return { messages: stubbed.messages, elidedReadPaths: stubbed.elidedReadPaths }\n }\n }\n return undefined\n}\n\n/**\n * Drop the reasoning of an attempt that is about to be re-sent. The next\n * attempt streams its own: without this its `stream:thinking` snapshots, its\n * progress estimate and the turn's TTFT would include the abandoned attempt.\n * The persisted turn is built from the provider result of the attempt that\n * succeeds, so nothing else of the abandoned attempt reaches it.\n */\nfunction discardAbandonedThinking(obs: TurnStreamObserver): void {\n if (obs.thinking === '')\n return\n obs.thinking = ''\n // Only reasoning can have set it: a re-sent attempt streamed no text.\n obs.turnTtftMs = undefined\n}\n\n/** What the loop decided about a failed attempt, as journaled in replay mode. */\ninterface StreamFailureVerdict {\n failure: StreamFailureAssessment\n /** Backoff before the re-issue; set when the verdict is to retry. */\n delayMs?: number\n /** Text the attempt streamed before it failed (the error turn keeps it). */\n text?: string\n}\n\n/** Turn identity + run ledger the streaming phase needs for its terminal `turn:after`. */\nexport interface TurnStreamScope {\n turn: number\n turnId: string\n priorUsage: RunUsageSnapshot\n callMaps: TurnCallMaps\n}\n\n/**\n * Terminal stream failure: persist a placeholder assistant turn, fire\n * `stream:error` (unless aborted) and the synthetic `turn:after`, then throw\n * the surfaced provider error, or `AgentAbortedError` when the run was\n * cancelled, even by a hook while these ran.\n */\nasync function failStreamedTurn(\n ctx: LoopContext,\n scope: TurnStreamScope,\n obs: TurnStreamObserver,\n terminalErr: unknown,\n classified: ClassifiedError | null,\n wasAborted: boolean,\n): Promise<never> {\n const { turn, turnId, priorUsage } = scope\n // Terminal failure path: ensure turn:after fires even when the provider throws.\n //\n // Persisted turns must always carry at least one content block — both\n // Anthropic and OpenAI reject `content: []` on resume. When the\n // provider blew up before any text streamed, drop in a placeholder\n // text block so the turn round-trips cleanly through any session\n // store and a subsequent `agent.run()` doesn't reject the history.\n //\n // Two distinct placeholders so the transcript reads correctly to\n // both the human and the model:\n // - Abort: user cancelled mid-stream. Friendly + clearly a system\n // marker, so the model reads it as \"the user interrupted\n // me\" rather than \"I produced this content\".\n // - Error: provider threw before any output. The bracketed marker\n // carries the underlying provider message (truncated) so\n // both the transcript and any host UI watching `turns[]`\n // can diagnose without walking the thrown `.cause` chain.\n // Without it, consumers reading the persisted turn would not\n // see the message (the thrown `AgentProviderError` carries it\n // on its cause).\n // Settle any in-flight stream-callback handlers before the terminal\n // hooks fire — `stream:error` / `turn:after` must not race a still-\n // running `stream:text` handler. The chain never rejects.\n // Progress ends first: a throttled `stream:progress` must not fire after\n // `stream:error` / `turn:after` while those hooks are awaited.\n obs.endProgress()\n await obs.hookChain\n\n // Surfaced once, from the loop's own abort verdict (never the live signal):\n // the placeholder (a subagent's output, the parent's stop notice) and the\n // thrown error read the classifier's words.\n const surfaced = wasAborted ? undefined : surfaceProviderFailure(terminalErr, classified, ctx.provider, fallbackTrail(ctx.targetFailures))\n const errorUsage: TurnUsage = { input: 0, output: 0 }\n const placeholderText = surfaced\n ? buildStreamErrorPlaceholder(surfaced, obs.text !== '')\n : '[⏹ Streaming was aborted.]'\n // Partial text streamed before the failure: keep it, and append the\n // marker blank-line-separated in the SAME text block — the persisted\n // turn must carry the failure evidence (without it the next run's\n // model sees a turn that just stops mid-sentence, and hosts\n // pattern-matching the placeholder never observe this case), but a\n // second text block would make openai-compat serialize assistant\n // content as a parts array on resume, which strict chat-completions\n // backends reject.\n const errorContent = [{\n type: 'text' as const,\n text: obs.text ? `${obs.text}\\n\\n${placeholderText}` : placeholderText,\n }]\n const errorTurn: SessionTurn = {\n id: turnId,\n runId: ctx.runId,\n role: 'assistant',\n content: errorContent,\n usage: errorUsage,\n createdAt: await ctx.clock.now(),\n }\n ctx.turns.push(errorTurn)\n // Fire `stream:error` BEFORE the synthetic `turn:after` so observers\n // see the raw provider error first. On an abort we skip `stream:error`\n // (a cancel is not a provider error); the abort itself surfaces as\n // `agent:abort`, fired at the run boundary in `agent-run.ts` after this\n // throw propagates out (the loop's between-turn checks are skipped on a\n // mid-stream abort).\n if (!wasAborted) {\n const meta = extractStreamErrorMeta(terminalErr)\n await settledHook(ctx, 'hook stream:error', ctx.hooks.callHook('stream:error', { err: terminalErr, turnId, ...meta }))\n }\n await settledHook(ctx, 'hook turn:after', ctx.hooks.callHook('turn:after', {\n turn,\n turnId,\n usage: errorUsage,\n message: errorTurn,\n aborted: wasAborted,\n toolCounts: { turn: Object.freeze({}), run: Object.freeze({ ...ctx.runToolCounts }) },\n cumulativeUsage: buildCumulativeUsage(priorUsage, errorUsage),\n }))\n throw surfaced && !ctx.signal.aborted ? surfaced : new AgentAbortedError('Agent run aborted', { cause: terminalErr })\n}\n\n/**\n * Stream the prepared request, recovering from failures by backoff-retry,\n * reactive overflow compaction, or fallback to the next target. Settles the\n * stream hooks and fires `stream:end` before returning; a terminal failure\n * goes through {@link failStreamedTurn} and throws.\n */\nexport async function streamTurnWithRecovery(\n ctx: LoopContext,\n streamOptions: StreamOptions,\n scope: TurnStreamScope,\n): Promise<{ result: ProviderTurnResult, obs: TurnStreamObserver }> {\n const { turnId } = scope\n const streamStartedAt = Date.now()\n await settledHook(ctx, 'hook stream:start', ctx.hooks.callHook('stream:start', { turnId, startedAt: streamStartedAt }))\n const obs = createTurnStreamObserver(ctx, turnId, streamOptions, streamStartedAt)\n\n const retryCfg = resolveRetryConfig(ctx.behavior.retry)\n let result\n let attempt = 0\n // Reactive context-overflow recoveries this turn, reported as the\n // `context:overflow` attempt. Separate from `attempt` (network retry) so an\n // overflow recovery doesn't consume the backoff budget and vice-versa.\n // Bounded by the rescue itself: each pass moves the frontier strictly forward.\n let overflowRecoveries = 0\n // Bounded retry-with-backoff. Triggers only when:\n // 1. The provider classifies the error as `retryable: true`, AND\n // 2. No text, tool-call content, or server-tool activity has streamed\n // (reasoning alone is dropped and regenerated, see `assessStreamFailure`).\n // Condition (2) avoids replaying over partial output the user already saw;\n // the proper fix for that case is prefill-continuation (replay with the\n // partial assistant response prefilled so the model continues from there),\n // which is a separate, larger change.\n while (true) {\n attempt += 1\n // Per attempt: overflow recovery and fallback rewrite `streamOptions`, and the\n // compaction prefix must match what the provider actually accepted.\n ctx.lastRequest = { options: { ...streamOptions }, turnCount: ctx.turns.length, sentAt: Date.now() }\n // Replay mode: the provider's own error of this attempt, when it ran live.\n let liveFailure: unknown\n // Which recoveries this failure entitles us to, and its one\n // classification. Pure: see `assessStreamFailure` for the rules and\n // their rationale.\n const decide = (err: unknown): StreamFailureVerdict => {\n const assessed = assessStreamFailure({\n err,\n runAborted: ctx.signal.aborted,\n classifyError: ctx.provider.classifyError?.bind(ctx.provider),\n progress: { text: obs.text, thinking: obs.thinking, serverToolActivity: obs.serverToolActivity, toolCallActivity: obs.toolCallActivity },\n attempt,\n retry: retryCfg,\n hasNextTarget: ctx.targets !== undefined\n && (ctx.activeTargetIndex ?? 0) + 1 < ctx.targets.length,\n })\n return {\n failure: assessed,\n ...(assessed.canRetry && !assessed.preferFallbackOverRetry\n ? { delayMs: computeRetryDelayMs(attempt, retryCfg, assessed.retryAfterMs, retryJitter(durableClock(ctx))) }\n : {}),\n ...(obs.text !== '' ? { text: obs.text } : {}),\n }\n }\n try {\n result = await streamWithWatchdogs(\n ctx,\n streamOptions,\n obs.callbacks(),\n turnId,\n {\n ...(attempt > 1 ? { startTimeoutCapMs: RETRY_STREAM_START_TIMEOUT_CAP_MS } : {}),\n // Pre-settled-gate path: a server-tool event the SDK delivers\n // after a watchdog fired must still block a re-issue.\n onServerToolActivity: () => {\n obs.serverToolActivity = true\n },\n onLiveFailure: (err) => {\n liveFailure = err\n return ctx.durable.checkpoint ? decide(err) as unknown as JsonValue : undefined\n },\n },\n )\n break\n }\n catch (caught) {\n rethrowControlError(ctx, caught)\n // `terminalErr` is what eventually feeds the placeholder/`stream:error`/\n // `failStreamedTurn` path. Starts as the caught error; gets replaced by\n // a synthesized AbortError when `agent.abort()` lands mid-backoff so the\n // existing abort handling (`AgentAbortedError`, abort placeholder) kicks in.\n let terminalErr: unknown = caught\n // A failed attempt's mid-stream snapshot must not survive into a retry or\n // fallback (the next attempt reports its own), nor keep a trailing\n // progress timer alive past a terminal error.\n obs.liveUsage = undefined\n if (obs.progressTimer) {\n clearTimeout(obs.progressTimer)\n obs.progressTimer = undefined\n }\n // The verdict, with the backoff and the streamed text. A replay or a\n // resumed checkpoint run has neither the provider's own error nor the\n // stream's progress, so it takes the recorded verdict: journaled in\n // replay mode, stored with the failed model step in checkpoint mode.\n const recorded = ctx.durable.checkpoint ? stepDecision(caught) as unknown as StreamFailureVerdict | undefined : undefined\n const verdict = recorded ?? await journaledDecision(ctx, 'stream-failure', () => decide(liveFailure ?? caught))\n const { failure, text } = verdict\n let { delayMs } = verdict\n // `retry` interceptors may veto the retry or change its backoff. Live\n // runs only (a recorded verdict already holds the decision); journaled\n // in replay mode so a replay takes the same branch.\n if (delayMs !== undefined && !recorded && ctx.interceptors?.has('retry')) {\n const interceptors = ctx.interceptors\n const computed = delayMs\n delayMs = await journaledDecision(ctx, 'retry-interceptor', () => interceptRetry(interceptors, {\n attempt,\n error: errorMessage(liveFailure ?? caught),\n provider: ctx.provider.name,\n model: ctx.model,\n }, computed).then(next => next ?? null)) ?? undefined\n }\n if (replays(ctx.durable) || recorded)\n obs.text = text ?? ''\n // Live abort flag. Starts from the verdict but is re-raised by the\n // backoff branch below when `agent.abort()` lands mid-sleep — every guard\n // after that point must read THIS, not `failure.wasAborted`, or a\n // cancelled run still gets recovered.\n let wasAborted = failure.wasAborted\n\n // Backoff-and-re-issue. Skipped when the server declared a wait long\n // enough that failing over to the next target beats waiting it out\n // (`preferFallbackOverRetry`); `canRetry` implies `reissuable`, so the\n // fallback branch below is guaranteed to take it.\n if (delayMs !== undefined) {\n const meta = extractStreamErrorMeta(caught)\n discardAbandonedThinking(obs)\n await settledHook(ctx, 'hook stream:retry', ctx.hooks.callHook('stream:retry', {\n turnId,\n attempt,\n nextAttempt: attempt + 1,\n maxAttempts: retryCfg.maxAttempts,\n delayMs,\n err: caught,\n ...meta,\n ...(failure.streamedThinking ? { discardedThinking: true as const } : {}),\n }))\n let sleepAborted = false\n try {\n await backoffSleep(delayMs, ctx.signal, durableClock(ctx, ctx.signal))\n }\n catch (sleepErr) {\n rethrowControlError(ctx, sleepErr)\n sleepAborted = true\n }\n // The abort raced a durable timer: a replay finds the timer done\n // and must still stop.\n if (!(await journaledDecision(ctx, 'backoff-abort', () => sleepAborted)))\n continue\n // Aborted mid-backoff. Fall through to the terminal-error path\n // below with a synthesized AbortError so the existing handling\n // takes over (placeholder turn, AgentAbortedError).\n const abortErr = new Error('Agent run aborted')\n abortErr.name = 'AbortError'\n terminalErr = abortErr\n wasAborted = true\n }\n\n // Reactive context-overflow recovery. The request was rejected for\n // exceeding the model's window (`context_exceeded` is pre-stream, so\n // `cleanSlate` always holds here). Stub older media and `tool_result`\n // bodies up to a further frontier and re-issue — works even when\n // `compactStrategy` is off, since we call the compactors directly. They\n // return the SAME array reference when nothing was elided, our reliable\n // \"did it shrink?\" signal: when no frontier can shrink further\n // (text-heavy overflow), fall through to the terminal path so the error\n // still surfaces (no infinite loop).\n if (!wasAborted && failure.canRecoverOverflow) {\n const recovered = shrinkForContextOverflow(ctx, streamOptions.messages, scope.callMaps)\n if (recovered) {\n overflowRecoveries += 1\n // Invalidate read-state dedup for elided reads so a subsequent\n // `read_file` re-serves the full body instead of an \"unchanged\" stub\n // pointing at content no longer on the wire (mirrors the tail path).\n markReadStateForElidedPaths(ctx, ctx.handle.cwd, recovered.elidedReadPaths)\n // Stubbing rewrote tool_result bodies; re-run the wire-safety passes\n // so the shrunk list still pairs cleanly and ends on a user message.\n let repaired = applyPairingRepair(ctx, recovered.messages, turnId)\n repaired = ensureEndsWithUserMessage(repaired, ctx.provider)\n streamOptions.messages = repaired\n await settledHook(ctx, 'hook context:overflow', ctx.hooks.callHook('context:overflow', { turnId, attempt: overflowRecoveries, err: caught }))\n continue\n }\n }\n\n // Provider/model fallback. The active target failed terminally (the\n // retry budget above is exhausted or the error was never retryable)\n // and no answer content has streamed (reasoning at most) — advance to\n // the next entry of the run's fallback chain and re-issue instead of\n // surfacing the error.\n // Eligibility (including which classifications are excluded) is decided\n // by `assessStreamFailure`; `wasAborted` is re-checked live because an\n // abort during the retry backoff must drop to the terminal path rather\n // than burn a fallback target on a run the user already cancelled.\n if (!wasAborted && failure.canFallback) {\n discardAbandonedThinking(obs)\n // Surfaced against the failing target, before the switch rebinds `ctx.provider`.\n await advanceToFallbackTarget(ctx, streamOptions, turnId, surfaceProviderFailure(caught, failure.classified, ctx.provider), failure.streamedThinking)\n // Fresh retry budget for the new target.\n attempt = 0\n continue\n }\n\n return failStreamedTurn(ctx, scope, obs, terminalErr, failure.classified, wasAborted)\n }\n }\n\n // Settle the serialized stream-callback handlers before `stream:end` so\n // an async `stream:text` handler can never resolve after the end event.\n await obs.hookChain\n\n // Final progress tick: unthrottled, awaited, and it closes the gate so no\n // trailing timer lands after `stream:end`. Only when something streamed —\n // a tool-only turn has no counter to settle.\n if (obs.progressTimer || obs.text || obs.thinking || obs.liveUsage) {\n if (obs.progressTimer) {\n clearTimeout(obs.progressTimer)\n obs.progressTimer = undefined\n }\n await settledHook(ctx, 'hook stream:progress', obs.emitProgress())\n }\n obs.endProgress()\n\n if (obs.text) {\n await settledHook(ctx, 'hook stream:end', ctx.hooks.callHook('stream:end', { text: obs.text, turnId }))\n }\n\n return { result, obs }\n}\n","/**\n * One model turn: build the request, stream it (with retry, overflow\n * recovery and fallback), persist the assistant turn, apply the stop-reason\n * recoveries, and dispatch tool calls. Also the schema-enforcement call.\n */\n\nimport type { LoopContext } from './loop-context'\nimport type { RunUsageSnapshot, TurnCallMaps } from './loop-turn-stream'\nimport type { TurnResult as ProviderTurnResult, StreamOptions, ToolCall, ToolResult, ToolSpec } from './providers'\nimport type { Session } from './session'\nimport type { InjectedTurnReason, SessionContentBlock, SessionMessage, SessionTurn, TurnUsage } from './types'\nimport { rewriteContentToCanonical, rewriteMessagesToWire, toCanonicalName, toWireName } from './aliasing'\nimport { applyThinkingDecay } from './behaviors/thinking-decay'\nimport { suspensionOf } from './durable/errors'\nimport { activeContextWindow, applyCompactSummaryCutoff, applyMediaAgeout, applyMediaBudget, applyOverflowCutoff, applyTailCompaction, collectCallMaps, COMPACT_CHUNK_TURNS, MEDIA_INLINE_MAX_BYTES, memoizedToolResultBudgetBytes, overflowCutoffAnchor, resolveTailCompactionThreshold, tailCompactionSkipped, withoutReplayedThinking } from './loop-compaction'\nimport { boundedHook, executionBlobWriter, isControlError, journaledDecision, rethrowControlError, settledHook } from './loop-context'\nimport { persistElidedToolResults, PERSISTENCE_PREVIEW_BYTES } from './loop-persistence'\nimport { appendStaleReadNotices, applyStaleReadElision, markReadStateForElidedPaths } from './loop-stale-reads'\nimport { streamWithWatchdogs, wrapProviderError } from './loop-stream'\nimport { executeToolBatch } from './loop-tool-batch'\nimport { unwrapDispatchCalls } from './loop-tool-dispatch'\nimport { buildCumulativeUsage, streamTurnWithRecovery } from './loop-turn-stream'\nimport { applyPairingRepair, resolveContentRefsForWire, sanitizeStoredToolResults, turnsToMessages } from './loop-wire'\nimport { LOOP_STEP_KINDS } from './run-durability'\nimport { ensureEndsWithUserMessage, remintDuplicateToolCallIds } from './session/messages'\nimport { toolOutputBudgetByteLength } from './types'\n\n// ---------------------------------------------------------------------------\n// Schema enforcement\n// ---------------------------------------------------------------------------\n\n/**\n * Force one provider call whose only tool is the synthetic `__output__`\n * spec built from `behavior.schema`, with `toolChoice` pinned to it, so\n * the model must emit a schema-conforming payload. Fires the `output`\n * hook and appends the schema turn to `ctx.turns`; the caller accounts\n * the returned usage into its own ledger.\n *\n * Two call sites:\n *\n * - `executeTurn`'s natural end (the provider result is `done`). The schema usage is\n * merged into the final turn's `TurnUsage`.\n * - `runLoop`'s exhausted exit (`maxTurns` or a stop-recovery cap). Without\n * this, a schema-enforced run that ended on a tool turn could never\n * produce a conforming verdict. Aborts stay exempt: a cancel means\n * \"stop now\", not \"spend one more provider call\".\n *\n * Message-shaping notes (apply to both call sites):\n *\n * Apply the same compact-summary cutoff as the main path — without\n * this, a session compacted before schema enforcement would leak\n * the `compact-summary` block type to the provider. Same pairing\n * repair too, so the synthetic `__output__` tool_call doesn't 400\n * on its own (the schema turn legitimately has no matching\n * tool_result; mode 2 inserts one).\n * Same two-pass defense the main wire-send uses: pair-repair fills\n * orphan `tool_use` adjacency; ensureEndsWithUserMessage covers the\n * plain assistant-text-tail case (a text-only assistant turn lands\n * here with an assistant-terminated history — pairing repair can't\n * fix it because pairing is already valid).\n */\nexport async function enforceSchemaOutput(\n ctx: LoopContext,\n turnId: string,\n): Promise<{ output?: Record<string, unknown>, usage: TurnUsage, turnId: string }> {\n const outputSpec: ToolSpec = {\n name: '__output__',\n description: 'Return the final structured output matching the required schema.',\n inputSchema: ctx.behavior.schema!,\n }\n // Replayed thinking is bound to the `tools` array it was produced under;\n // this call swaps the whole array for `__output__`, so every signed block\n // in history would be invalid here. Removing blocks is always valid and\n // nothing later depends on this one-shot terminal call, so strip them\n // instead of paying a server-side drop (or a 400 without `drop_block`).\n const schemaCanonicalMessages = await resolveContentRefsForWire(\n ctx,\n turnsToMessages(applyCompactSummaryCutoff(ctx.turns)).map(withoutReplayedThinking),\n )\n const schemaMessages = ensureEndsWithUserMessage(\n applyPairingRepair(\n ctx,\n rewriteMessagesToWire(\n schemaCanonicalMessages,\n ctx.aliasMaps,\n ),\n turnId,\n ),\n ctx.provider,\n )\n let schemaResult\n try {\n // Same first-response / total-stream watchdogs as the main turn — the\n // forced-tool-choice schema-extraction call is just as prone to a provider\n // that never settles, and would otherwise leave `agent.run()` pending.\n schemaResult = await streamWithWatchdogs(\n ctx,\n {\n model: ctx.model,\n system: ctx.system,\n tools: ctx.provider.formatTools([outputSpec]),\n messages: schemaMessages,\n maxTokens: ctx.behavior.maxTokens,\n ...(ctx.behavior.modelCatalog ? { modelCatalog: ctx.behavior.modelCatalog } : {}),\n toolChoice: { type: 'tool', name: '__output__' },\n },\n {\n onText: () => {},\n onOAuthRefresh(refreshCtx) {\n return ctx.hooks.callHook('oauth:refresh', refreshCtx)\n },\n },\n turnId,\n )\n }\n catch (err) {\n rethrowControlError(ctx, err)\n throw wrapProviderError(err, ctx)\n }\n\n const output = schemaResult.toolCalls.find(tc => tc.name === '__output__')?.input\n\n if (output) {\n await ctx.hooks.callHook('output', { output, schema: ctx.behavior.schema! })\n }\n\n const schemaTurn: SessionTurn = {\n id: ctx.clock.randomUUID(),\n runId: ctx.runId,\n role: 'assistant',\n content: schemaResult.assistantMessage.content,\n usage: schemaResult.usage,\n createdAt: await ctx.clock.now(),\n }\n ctx.turns.push(schemaTurn)\n\n return { output, usage: schemaResult.usage, turnId: schemaTurn.id }\n}\n\n// ---------------------------------------------------------------------------\n// Single turn\n// ---------------------------------------------------------------------------\n\nexport interface TurnResult {\n ended: boolean\n turnId: string\n usage: TurnUsage\n output?: Record<string, unknown>\n /**\n * The turn dispatched the saved calls of a resumed run (no model request):\n * its usage is the saved assistant turn's, already in the run's totals.\n */\n resumedCalls?: true\n /**\n * Set to `true` when the turn produced no tool calls, no text, no thinking,\n * and the provider stop reason was `pause_turn` — the case the\n * \"Please continue.\" recovery exists for. `runLoop` uses this signal to\n * count consecutive empty pauses and end the run with `finishReason: 'pause'`\n * after `maxConsecutivePauseTurns` (default `0`, unlimited) to stop pause\n * loops on Anthropic 4.6+ streaming edge cases.\n *\n * `undefined` when the turn produced ANY visible output (tool calls,\n * text, or thinking) — including a non-empty pause turn (the loop\n * counter resets in that case).\n */\n pauseEmpty?: true\n /**\n * Set when `resumeOnMaxTokens` is enabled and the turn hit the output cap\n * (`finishReason: 'length'`) with no completed tool call, triggering a\n * \"Please continue.\" resume. `runLoop` counts consecutive resumes and ends\n * the run once `maxConsecutiveLengthResumes` is reached, leaving the last turn's\n * `finishReason: 'length'` visible in `stats`.\n */\n lengthTruncated?: true\n /**\n * Set alongside `lengthTruncated` when the truncated turn produced no\n * visible text (thinking-only or fully empty). `runLoop` bounds these\n * much tighter than text-producing truncations — consecutive empty\n * length turns do not assemble an answer, so after 2 the run fails\n * with `AgentLengthResumeExhaustedError` instead of spinning on.\n */\n lengthEmpty?: true\n /**\n * Set when the provider cut the turn off with `finishReason: 'content-filter'`\n * (e.g. Anthropic `stop_reason: refusal`) and no tool calls completed,\n * triggering a synthetic-continue resume. Without this recovery the run\n * would silently \"complete\" with an empty assistant turn — the classic\n * stalled-session symptom. `runLoop` counts consecutive refusal resumes\n * and ends the run once `maxConsecutiveRefusalResumes` is reached, leaving the last\n * turn's `finishReason: 'content-filter'` visible in `stats` so hosts can\n * surface it.\n */\n refusalResumed?: true\n}\n\n/**\n * Copy what the loop recorded about each call onto its persisted\n * `tool_result` block: the `calls` it made (`ToolContext.callTool`) and its\n * `durationMs`. Done here, once, so providers keep building blocks from the\n * wire fields only and never see either.\n */\nfunction withCallRecords(content: SessionContentBlock[], results: readonly ToolResult[]): SessionContentBlock[] {\n const byId = new Map(results.filter(r => r.calls || r.durationMs !== undefined).map(r => [r.id, r] as const))\n if (byId.size === 0)\n return content\n return content.map((block) => {\n if (block.type !== 'tool_result')\n return block\n const result = byId.get(block.callId)\n if (!result)\n return block\n return {\n ...block,\n ...(result.calls ? { calls: result.calls } : {}),\n ...(result.durationMs !== undefined ? { durationMs: result.durationMs } : {}),\n }\n })\n}\n\n/**\n * Build the turn's provider-bound message list from `ctx.turns`: summary\n * cutoff, content-ref resolution, stale-read elision, alias rewrite, media\n * sanitization, client-side compaction, media age-out, and the\n * context-overflow rescue's remembered stubs. `ctx.turns` is never\n * rewritten. Also returns the lazy call maps so the overflow recovery can\n * reuse them. Auto-compaction also calls it to build the summarizer's\n * request when it can't resend the last request the run sent.\n *\n * @param ctx - Loop context of the run.\n */\nexport async function buildTurnWireMessages(ctx: LoopContext): Promise<{ messages: SessionMessage[], callMaps: TurnCallMaps }> {\n // Build provider-bound messages: apply outbound alias rewrite so the LLM sees\n // tool_call blocks with their wire (aliased) names. Canonical names stay in ctx.turns.\n //\n // Order of operations is load-bearing:\n // 1. `applyCompactSummaryCutoff` first — turns before the latest\n // `compact-summary` marker never reach the provider, so every\n // transform below sees a smaller, marker-free slice. Operating on\n // `SessionTurn[]` lets the cutoff identify the marker block type\n // without leaking the type into the wire-level path.\n // 2. `turnsToMessages` second — converts the post-cutoff turns into\n // the `SessionMessage[]` shape providers expect.\n // 3. Resolve content refs for wire use only. This must happen before\n // repair/sanitization/provider formatting, but never writes back to\n // `ctx.turns`.\n // 4. `applyStaleReadElision` walks tool_calls + tool_results to\n // replace pre-edit `read_file` outputs. Runs BEFORE alias rewrite\n // so the function never has to learn about the alias map.\n // 5. Alias rewrite, image sanitization, tail compaction follow.\n const turnsAfterCutoff = applyCompactSummaryCutoff(ctx.turns)\n let canonicalMessages = turnsToMessages(turnsAfterCutoff)\n canonicalMessages = await resolveContentRefsForWire(ctx, canonicalMessages)\n\n if (ctx.behavior.elideStaleReads === true || ctx.behavior.elideStaleReads === 'stub') {\n /**\n * Deliberately UNQUANTIZED, unlike tail compaction and media age-out below.\n *\n * This pass rewrites the prefix at the earliest stale read, so quantizing its\n * frontier looks like it should help. Measured against a 129-turn production\n * trace, it does the opposite: 13 breaks / 0.25M re-billed chars unquantized\n * versus 16 / 0.27M at `chunkTurns: 8`.\n *\n * The reason is that this pass is already self-limiting. Stubbing is\n * idempotent per read, so once a path's earlier reads are stubbed, every\n * later edit to that path is a no-op — and real runs edit a small set of\n * files repeatedly, so distinct staleness events are rare. Deferring\n * detection to a frontier instead makes each advance discover a fresh batch,\n * which SPLITS one logical event across boundaries and adds breaks.\n *\n * Quantization only pays when staleness events are frequent AND spread over\n * many distinct paths, so batching can merge them. That is not the shape of\n * a coding run.\n */\n const elision = applyStaleReadElision(canonicalMessages)\n canonicalMessages = elision.messages\n // Defeat the dedup stub for the elided paths — the model can no\n // longer see the original read in the message history, so the next\n // re-read must serve the full body. Registration survives: the\n // read-before-edit gate keeps passing on the post-edit hash.\n markReadStateForElidedPaths(ctx, ctx.handle.cwd, elision.elidedPaths)\n }\n\n const wireMessages = rewriteMessagesToWire(canonicalMessages, ctx.aliasMaps)\n // Flatten any stored structured tool_result images to text markers when the\n // provider is non-vision. No-op on vision-capable providers and on sessions\n // without structured outputs. See `sanitizeStoredToolResults` for scope.\n let sanitizedMessages = sanitizeStoredToolResults(ctx.provider, wireMessages)\n\n // Client-side compaction. Non-Anthropic OSS-model fallback for what the\n // `context-management-2025-06-27` beta gives Anthropic users server-side.\n // Three modes: `'tail'` (built-in elision), a {@link CompactFunction}\n // (pluggable host strategy — LLM summarizer, semantic compactor, etc.),\n // or `'off'` / `undefined` (skip).\n //\n // Function path is async-aware so an LLM summarizer can do a real\n // provider round-trip; we forward the same `threshold`/`keepTurns`\n // knobs `'tail'` uses plus the pre-compaction byte total so the\n // function can short-circuit cheaply on under-threshold inputs.\n // Resolve call_id → read_file path and call_id → tool name from the\n // canonical (pre-alias) history. call_ids survive the alias rewrite, so\n // they still match the wire-level tool_result blocks tail compaction\n // operates on — letting compaction report which stubbed results were file\n // reads, and label persist-on-elide stubs with their originating tool.\n // Computed lazily and shared between tail compaction and media age-out —\n // both need the same maps, and each build is a full O(history) walk.\n let callMapsMemo: ReturnType<typeof collectCallMaps> | undefined\n const callMaps = () => (callMapsMemo ??= collectCallMaps(canonicalMessages))\n const tailWindow = ctx.behavior.compactStrategy === 'tail' ? activeContextWindow(ctx) : null\n // `compactSkip` matches on the serving provider's `name` (tracks fallback,\n // like the window), the same key `resolveToolSearchMode` uses.\n if (ctx.behavior.compactStrategy === 'tail' && !tailCompactionSkipped(ctx.behavior.compactSkip, ctx.provider.name, tailWindow)) {\n const threshold = resolveTailCompactionThreshold(ctx.behavior, tailWindow)\n const keep = typeof ctx.behavior.compactKeepTurns === 'number' && ctx.behavior.compactKeepTurns >= 0\n ? ctx.behavior.compactKeepTurns\n : 4\n const { readPathByCallId, toolNameByCallId } = callMaps()\n const compacted = applyTailCompaction(sanitizedMessages, threshold, keep, {\n readPathByCallId,\n toolNameByCallId,\n chunkTurns: COMPACT_CHUNK_TURNS,\n lowWaterFraction: ctx.behavior.compactLowWaterFraction,\n // Persist-on-elide non-read results large enough that a disk stub saves\n // bytes — only when a persist dir is configured. Below this size the\n // recoverable stub would be as big as the content, so the lossy stub is\n // used instead.\n persistElideMinBytes: ctx.behavior.persistDir ? PERSISTENCE_PREVIEW_BYTES : 0,\n })\n sanitizedMessages = compacted.messages\n // Invalidate the read-state dedup for any file whose body tail\n // compaction just stubbed — same rationale as stale-read elision above:\n // the model can no longer see the original read, so the next re-read\n // must serve the full body instead of the \"unchanged\" replay stub that\n // would otherwise point it at content no longer on the wire. Run\n // unconditionally (not gated on `elideStaleReads`): tail compaction\n // elides regardless of that setting.\n markReadStateForElidedPaths(ctx, ctx.handle.cwd, compacted.elidedReadPaths)\n // Persist-on-elide: upgrade the lossy stub to a recoverable\n // `<persisted-output … path=…>` stub for non-read results, so a compacted\n // result stays retrievable by reading its path rather than being lost.\n if (ctx.behavior.persistDir && compacted.persistableElided.length > 0) {\n sanitizedMessages = await persistElidedToolResults(sanitizedMessages, compacted.persistableElided, {\n persistDir: ctx.behavior.persistDir,\n maxBytes: ctx.behavior.persistMaxBytes,\n writeBlob: executionBlobWriter(ctx),\n shouldRethrowError: err => isControlError(ctx, err),\n })\n }\n }\n else if (typeof ctx.behavior.compactStrategy === 'function') {\n const threshold = resolveTailCompactionThreshold(ctx.behavior, activeContextWindow(ctx))\n const keep = typeof ctx.behavior.compactKeepTurns === 'number' && ctx.behavior.compactKeepTurns >= 0\n ? ctx.behavior.compactKeepTurns\n : 4\n // Model-visible size (attachments → short markers), matching\n // `applyTailCompaction`'s budget so custom strategies see the same number\n // and aren't tripped by large base64 attachments in tool results.\n let totalBytes = 0\n for (const msg of sanitizedMessages) {\n for (const block of msg.content) {\n if (block.type === 'tool_result')\n totalBytes += memoizedToolResultBudgetBytes(block)\n }\n }\n try {\n const compacted = await ctx.behavior.compactStrategy(sanitizedMessages, {\n threshold,\n keepTurns: keep,\n totalBytes,\n })\n if (Array.isArray(compacted))\n sanitizedMessages = compacted\n }\n catch (err) {\n rethrowControlError(ctx, err)\n // Compactor failures should not kill the turn — degrade to the\n // uncompacted payload. The pair-repair pass downstream still has\n // a chance to fix any structural damage. There is no dedicated\n // hook for host-strategy failures (`stream:error` is reserved for\n // provider stream errors), so the error is logged to stderr only.\n console.error('[zidane] compactStrategy function threw:', err)\n }\n }\n\n // Media age-out (wire-only): drop base64 for image/document blocks older\n // than the keep window, replacing each with a re-resolvable marker. Runs\n // independently of `compactStrategy` — that path only stubs `tool_result`\n // text and never trims media bytes, so without this an image-heavy session\n // re-sends every screenshot's base64 on every turn. The model can pull any\n // aged-out image back via `read_file path=\"attachment://<hash>\"`.\n //\n // An explicit `mediaKeepTurns` window wins; otherwise `mediaBudget` keeps\n // media inline until the request nears the provider's hard limits, so the\n // prefix isn't rewritten once per image. The budget isn't gated on\n // `read_file`: those limits reject the whole request, so aging out is\n // required even when the marker can't be resolved.\n const mediaKeepTurns = ctx.behavior.mediaKeepTurns\n if (typeof mediaKeepTurns === 'number') {\n if (mediaKeepTurns >= 0 && ctx.tools.read_file) {\n const { readPathByCallId } = callMaps()\n const aged = applyMediaAgeout(sanitizedMessages, mediaKeepTurns, {\n chunkTurns: COMPACT_CHUNK_TURNS,\n readPathByCallId,\n readFileToolName: toWireName('read_file', ctx.aliasMaps),\n maxInlineBytes: MEDIA_INLINE_MAX_BYTES,\n })\n sanitizedMessages = aged.messages\n markReadStateForElidedPaths(ctx, ctx.handle.cwd, aged.elidedReadPaths)\n }\n }\n else if (ctx.behavior.mediaBudget) {\n const { readPathByCallId } = callMaps()\n const providerCap = ctx.provider.meta.capabilities?.maxMediaPerRequest\n const budget = typeof providerCap === 'number' && providerCap > 0 && providerCap < ctx.behavior.mediaBudget.maxItems\n ? { ...ctx.behavior.mediaBudget, maxItems: providerCap }\n : ctx.behavior.mediaBudget\n const aged = applyMediaBudget(sanitizedMessages, budget, {\n keepTurns: COMPACT_CHUNK_TURNS,\n chunkTurns: COMPACT_CHUNK_TURNS,\n readPathByCallId,\n readFileToolName: toWireName('read_file', ctx.aliasMaps),\n maxInlineBytes: MEDIA_INLINE_MAX_BYTES,\n })\n sanitizedMessages = aged.messages\n markReadStateForElidedPaths(ctx, ctx.handle.cwd, aged.elidedReadPaths)\n }\n\n // Re-apply the context-overflow rescue's remembered frontier so this\n // request goes out already fitting, with the same stubbed prefix the\n // rescued request had. A compaction (new summary marker) or another\n // conversation changes the anchor, and a shorter list means the index no\n // longer points where it did: drop the cutoff then.\n const rescue = ctx.overflowRescue\n if (rescue?.cutoff) {\n if (rescue.cutoff.anchor !== overflowCutoffAnchor(ctx.turns) || rescue.cutoff.index > sanitizedMessages.length) {\n rescue.cutoff = undefined\n }\n else {\n const { readPathByCallId, toolNameByCallId } = callMaps()\n const stubbed = applyOverflowCutoff(sanitizedMessages, rescue.cutoff.index, {\n readPathByCallId,\n toolNameByCallId,\n readFileToolName: ctx.tools.read_file ? toWireName('read_file', ctx.aliasMaps) : null,\n only: rescue.cutoff,\n })\n sanitizedMessages = stubbed.messages\n markReadStateForElidedPaths(ctx, ctx.handle.cwd, stubbed.elidedReadPaths)\n }\n }\n\n return { messages: sanitizedMessages, callMaps }\n}\n\n/**\n * The turn's provider request options around the prepared wire messages.\n *\n * @param ctx - Loop context of the run.\n * @param turn - The loop's 0-indexed turn counter (drives thinking decay).\n * @param messages - Wire messages from {@link buildTurnWireMessages}.\n */\nexport function buildTurnStreamOptions(ctx: LoopContext, turn: number, messages: SessionMessage[]): StreamOptions {\n // Decay shrinks the per-turn thinking budget. It is skipped only when the\n // active provider treats `adaptive` + `thinkingBudget` as a whole-response\n // envelope cap (Anthropic — `adaptiveBudgetIsEnvelope`): decaying that would\n // strangle text and tool-call output, not just thinking. Providers where\n // adaptive + `thinkingBudget` is a genuine per-turn thinking budget (e.g.\n // openai-compat `reasoning.max_tokens`) still decay. `taskBudget` is a\n // whole-task cap and is never routed through decay.\n // `turn` is the loop's 0-indexed counter; decay's `runTurn` contract is\n // 1-indexed (`afterTurn: 5` = turns 1-5 keep the base budget).\n const adaptiveEnvelopeCap = ctx.thinking === 'adaptive'\n && ctx.provider.meta.capabilities?.adaptiveBudgetIsEnvelope === true\n const effectiveThinkingBudget = adaptiveEnvelopeCap\n ? ctx.behavior.thinkingBudget\n : applyThinkingDecay(ctx.behavior.thinkingBudget, ctx.behavior.thinkingDecay, turn + 1)\n\n // Lazy tool disclosure — when active, rebuild the tool list each turn so\n // tools surfaced through `tool_search` since the last provider call land\n // in this request. The set only grows within a run (entries are appended,\n // never reordered or removed), so the prefix-cache breakpoint advances\n // monotonically rather than thrashing.\n const formattedTools = ctx.rebuildFormattedTools\n ? ctx.rebuildFormattedTools(ctx.provider)\n : ctx.formattedTools\n\n return {\n model: ctx.model,\n system: ctx.system,\n tools: formattedTools,\n messages,\n ...(ctx.session ? { sessionId: ctx.session.id } : {}),\n // Pass through unset: providers resolve a model-driven default (Anthropic\n // → model max output; OpenAI-style → omit so the model runs to a natural\n // stop). A hard cap only applies when the caller set `behavior.maxTokens`.\n maxTokens: ctx.behavior.maxTokens,\n // Shadows the process-wide catalog for this turn; providers thread it into\n // every model lookup (ceiling, cost rates, model resolution).\n ...(ctx.behavior.modelCatalog ? { modelCatalog: ctx.behavior.modelCatalog } : {}),\n thinking: ctx.thinking,\n thinkingBudget: effectiveThinkingBudget,\n ...(ctx.behavior.taskBudget !== undefined ? { taskBudget: ctx.behavior.taskBudget } : {}),\n ...(ctx.behavior.effortHint !== undefined ? { effortHint: ctx.behavior.effortHint } : {}),\n ...(ctx.modelOptions ? { modelOptions: ctx.modelOptions } : {}),\n cache: ctx.behavior.cache ?? true,\n ...(ctx.behavior.cacheTtl !== undefined ? { cacheTtl: ctx.behavior.cacheTtl } : {}),\n signal: ctx.signal,\n }\n}\n\n/**\n * Canonical (post-alias) tool calls and assistant content for a finished\n * stream: inbound alias rewrite, persist-time duplicate-id healing, and\n * `call_tool` envelope unwrapping.\n */\nfunction canonicalizeTurnOutput(\n ctx: LoopContext,\n result: ProviderTurnResult,\n turnId: string,\n): { toolCalls: ToolCall[], content: SessionContentBlock[] } {\n // Inbound alias → canonical rewrite. After this, tool calls and assistant\n // content blocks use canonical names everywhere downstream (turns, dispatch, hooks).\n let canonicalToolCalls = result.toolCalls.map(tc => ({\n ...tc,\n name: toCanonicalName(tc.name, ctx.aliasMaps),\n }))\n let canonicalContent = rewriteContentToCanonical(\n result.assistantMessage?.content ?? [],\n ctx.aliasMaps,\n )\n\n // Persist-time duplicate-id healing. Providers that reuse tool_use ids\n // across turns (per-turn `call_0` counters, retry-replay hosts, Kimi-style\n // deployments) would otherwise persist a collision the wire-time pairing\n // pass can only repair by STRIPPING — erasing the call + result from the\n // model's view every subsequent turn (no forward progress) and\n // re-accumulating repairs quadratically. Re-minting here keeps the pair\n // intact end-to-end: dispatch, the persisted assistant turn, and the\n // tool_result all carry the fresh id.\n //\n // Disabled in strict mode: `strictToolPairing` consumers (training-data\n // collectors) contract on duplicate-id corruption THROWING at the next\n // wire send so the transcript can be quarantined — silently healing it\n // here would swallow that signal. Non-strict runs get the heal.\n if (canonicalToolCalls.length > 0 && !ctx.behavior.strictToolPairing) {\n const priorIds = new Set<string>()\n for (const t of ctx.turns) {\n for (const block of t.content) {\n if (block.type === 'tool_call')\n priorIds.add(block.id)\n }\n }\n const reminted = remintDuplicateToolCallIds(canonicalToolCalls, canonicalContent, priorIds)\n if (reminted.reminted.length > 0) {\n canonicalToolCalls = reminted.toolCalls\n canonicalContent = reminted.content\n for (const r of reminted.reminted) {\n void Promise.resolve(ctx.hooks.callHook('pairing:repair', {\n mode: 'duplicate-tool-use-remint',\n callId: r.oldId,\n messageIndex: ctx.turns.length,\n turnId,\n })).catch(() => {})\n }\n }\n }\n\n // Stable-tools dispatch: a `call_tool { name, arguments }` envelope becomes\n // the inner call for everything downstream — turn counts, gate, validation\n // against the inner schema, hooks, events, dedup, budgets. The PERSISTED\n // assistant content above keeps the envelope as the model emitted it (the\n // wire history must reference tools the provider was actually sent), and\n // the tool_result pairs by id, which the rewrite preserves.\n canonicalToolCalls = unwrapDispatchCalls(ctx, canonicalToolCalls)\n\n return { toolCalls: canonicalToolCalls, content: canonicalContent }\n}\n\n/**\n * A loop-injected user turn, stamped with why it was injected so hosts never\n * mistake it for a typed prompt. The caller awaits `id` and `createdAt` (in\n * that order) so the journaled id and clock reads keep that order.\n */\nfunction syntheticUserTurn(\n ctx: LoopContext,\n message: { role: SessionTurn['role'], content: SessionTurn['content'] },\n injected: InjectedTurnReason,\n id: string,\n createdAt: number,\n): SessionTurn {\n return {\n id,\n runId: ctx.runId,\n role: message.role,\n content: message.content,\n createdAt,\n injected,\n }\n}\n\n/**\n * Combine the main turn's usage with the schema call's. Spread the\n * main usage first so non-additive metadata (finishReason, modelId,\n * timeToFirstTokenMs) survives, then sum every additive numeric\n * field across both calls — dropping cost/cache numbers here would\n * under-count `maxCostUsd` budget checks, cache stats, and the\n * `cumulativeUsage` consumers accumulate from this return.\n */\nfunction mergeSchemaEnforcementUsage(main: TurnUsage, schema: TurnUsage): TurnUsage {\n const sumOptional = (a: number | undefined, b: number | undefined): { has: boolean, value: number } =>\n ({ has: a !== undefined || b !== undefined, value: (a ?? 0) + (b ?? 0) })\n const cacheRead = sumOptional(main.cacheRead, schema.cacheRead)\n const cacheCreation = sumOptional(main.cacheCreation, schema.cacheCreation)\n const thinkingTokens = sumOptional(main.thinking, schema.thinking)\n const cost = sumOptional(main.cost, schema.cost)\n return {\n ...main,\n input: main.input + schema.input,\n output: main.output + schema.output,\n ...(cacheRead.has ? { cacheRead: cacheRead.value } : {}),\n ...(cacheCreation.has ? { cacheCreation: cacheCreation.value } : {}),\n ...(thinkingTokens.has ? { thinking: thinkingTokens.value } : {}),\n ...(cost.has ? { cost: cost.value } : {}),\n }\n}\n\n/**\n * Text-equivalent bytes of this turn's tool results for the per-turn\n * `toolOutputBudget`, skipping tools listed in `toolOutputBudgetExcludeTools`.\n */\nfunction toolOutputBudgetBytes(\n ctx: LoopContext,\n canonicalToolCalls: readonly ToolCall[],\n toolResults: readonly ToolResult[],\n): number {\n const excludeSet = ctx.behavior.toolOutputBudgetExcludeTools && ctx.behavior.toolOutputBudgetExcludeTools.length > 0\n ? new Set(ctx.behavior.toolOutputBudgetExcludeTools)\n : undefined\n const nameById = excludeSet\n ? new Map(canonicalToolCalls.map(c => [c.id, c.name]))\n : undefined\n return toolResults.reduce(\n (sum, r) => {\n if (excludeSet && nameById) {\n const name = nameById.get(r.id)\n if (typeof name === 'string' && excludeSet.has(name))\n return sum\n }\n return sum + toolOutputBudgetByteLength(r.content)\n },\n 0,\n )\n}\n\n/**\n * Dispatch the turn's tool calls and persist their results as a user turn:\n * stale-read notices, `tool-results:after`, and the per-turn output budget.\n */\nasync function dispatchTurnToolCalls(\n ctx: LoopContext,\n turn: number,\n turnId: string,\n canonicalToolCalls: ToolCall[],\n): Promise<void> {\n // Execute tool calls (canonical names after inbound rewrite). One\n // unified dispatcher: concurrency-safe tools fan out, unsafe tools\n // act as barriers. See `executeToolBatch` for the contract.\n const toolResults = await executeToolBatch(ctx, canonicalToolCalls, turnId)\n // A suspension cut the batch off: no results turn, so a resume reports the calls left pending interrupted.\n const suspended = suspensionOf(ctx.signal)\n if (suspended)\n throw suspended\n\n // `'notice'` stale-read policy — append-only staleness signalling. Runs\n // BEFORE the results become a turn so the notice rides the persisted\n // transcript tail: content that is new this turn and immutable afterwards\n // cannot break the provider's prefix cache. (A wire-only append to the\n // newest message would re-render without the append next turn and diverge\n // the prefix there instead — the exact break this policy exists to avoid.)\n if (ctx.behavior.elideStaleReads === 'notice') {\n // Signalling only. Dedup honesty for the mutated paths is NOT this\n // policy's job: the mutating tools themselves set the read-state `elided`\n // flag at the moment they refresh the content hash (see `edit.ts` /\n // `write-file.ts`), so the re-read the notice asks for serves the fresh\n // body in every mode — including `elideStaleReads: false`.\n appendStaleReadNotices(ctx.turns, canonicalToolCalls, toolResults)\n }\n\n // Tool results as a user turn\n const toolResultMsg = ctx.provider.toolResultsMessage(toolResults)\n const toolResultsTurn: SessionTurn = {\n id: ctx.clock.randomUUID(),\n runId: ctx.runId,\n role: toolResultMsg.role,\n content: withCallRecords(toolResultMsg.content, toolResults),\n createdAt: await ctx.clock.now(),\n }\n ctx.turns.push(toolResultsTurn)\n\n // Fire `tool-results:after` so persistence layers can durably store the\n // tool_use ↔ tool_result pair together — closes the crash window between\n // `turn:after` (assistant turn persisted) and the next loop iteration's\n // `turn:after` (where these tool results would otherwise piggyback). A\n // process death in that window left the DB with an orphan tool_use that\n // Anthropic rejects on resume.\n await settledHook(ctx, 'hook tool-results:after', ctx.hooks.callHook('tool-results:after', {\n turn,\n turnId,\n message: toolResultsTurn,\n results: toolResults,\n }))\n\n // Enforce per-turn text-output budget. Sum the post-transform text-equivalent\n // bytes of every tool result; attachment blocks count as short markers so\n // vision/PDF reads do not trip the text summarization nudge by themselves.\n //\n // Tools listed in `toolOutputBudgetExcludeTools` are skipped entirely:\n // `tool_search` / `skills_use` exist to LOAD context into the conversation,\n // so counting their bytes against the budget would steer the model away\n // from the very call it needs to make progress (the \"summarize before\n // calling more tools\" message is nonsensical for schema-loading tools).\n // Lookup is canonical-name keyed because `canonicalToolCalls` was already\n // alias-rewritten upstream; map result id → canonical name so the filter\n // works for parallel batches where order in `toolResults` is dispatch\n // order, not call order.\n if (typeof ctx.behavior.toolOutputBudget === 'number' && ctx.behavior.toolOutputBudget > 0) {\n const totalBytes = toolOutputBudgetBytes(ctx, canonicalToolCalls, toolResults)\n if (totalBytes > ctx.behavior.toolOutputBudget) {\n const warning = `[Tool output budget exceeded: ${totalBytes} text-equivalent bytes returned in this turn (cap: ${ctx.behavior.toolOutputBudget}). Summarize the salient findings before calling more tools.]`\n const userMsg = ctx.provider.userMessage(warning)\n ctx.turns.push(syntheticUserTurn(ctx, userMsg, 'tool-output-budget', await ctx.generateTurnId(), await ctx.clock.now()))\n await ctx.hooks.callHook('budget:exceeded', {\n turn,\n turnId,\n bytes: totalBytes,\n budget: ctx.behavior.toolOutputBudget,\n })\n }\n }\n}\n\n/** The saved assistant turn a resumed run dispatches at `turn` (see `LoopContext.resume`), taken once. */\nfunction takeResumedCalls(ctx: LoopContext, turn: number): SessionTurn | undefined {\n const pending = ctx.resume?.turn === turn ? ctx.resume.pending : undefined\n if (pending)\n ctx.resume = { turn }\n return pending\n}\n\n/**\n * The first turn of a resumed run that died between saving an assistant\n * turn and saving its tool results: dispatch the saved calls (their steps\n * answer from their records or follow their replay policy) instead of\n * asking the model again. The model's usage was counted by the dead process.\n */\nasync function dispatchResumedCalls(ctx: LoopContext, turn: number, assistant: SessionTurn): Promise<TurnResult> {\n const calls: ToolCall[] = assistant.content.flatMap(b => (b.type === 'tool_call' ? [{ id: b.id, name: b.name, input: b.input }] : []))\n await announceResumedBatch(ctx, turn, assistant.id, calls)\n try {\n await dispatchTurnToolCalls(ctx, turn, assistant.id, calls)\n }\n finally {\n delete ctx.resumedBatch\n }\n return { ended: false, turnId: assistant.id, usage: { input: 0, output: 0 }, resumedCalls: true }\n}\n\n/**\n * Before a resumed batch runs again: which of its calls the dead process\n * finished (a `done` or `failed` step record: answered from it) and which\n * are still to settle, as `tool-batch:resumed`. Every call with a record,\n * nested calls included, passed the gate before its step started, so the\n * dispatch runs its gate as `resumed` (`LoopContext.resumedBatch`): a done\n * call is not put to the user a second time, and an unsafe one that will be\n * reported interrupted is not either. A call whose body has no step of its\n * own (codemode, spawn) has a `gate` record instead: it is restored, not\n * asked again, and still resuming (its body runs again).\n */\nasync function announceResumedBatch(ctx: LoopContext, turn: number, turnId: string, calls: readonly ToolCall[]): Promise<void> {\n const stored = ctx.durable.checkpoint ? await ctx.durable.scope.storedSteps?.() : undefined\n if (!stored)\n return\n const records = new Map(stored.filter(s => s.kind === LOOP_STEP_KINDS.tool || s.kind === LOOP_STEP_KINDS.gate).map(s => [s.key, s]))\n const done: string[] = []\n const resuming: string[] = []\n for (const call of calls) {\n const record = records.get(ctx.durable.toolKey(call.id))\n if (record && record.status !== 'pending')\n done.push(call.id)\n else\n resuming.push(call.id)\n }\n ctx.resumedBatch = { turn, records }\n await settledHook(ctx, 'hook tool-batch:resumed', ctx.hooks.callHook('tool-batch:resumed', {\n runId: ctx.runId,\n turn,\n turnId,\n done: Object.freeze(done),\n resuming: Object.freeze(resuming),\n }))\n}\n\n/**\n * The live abort flag as a journaled decision (see {@link journaledDecision}).\n * Callers check it last, after the deterministic conditions, so an entry is\n * only recorded where the abort can change the branch.\n */\nfunction runAborted(ctx: LoopContext): Promise<boolean> {\n return journaledDecision(ctx, 'turn-abort', () => ctx.signal.aborted)\n}\n\n/**\n * Run one model turn: build and repair the wire messages, run the\n * `context:transform`, `system:transform` and `turn:before` hooks, stream the\n * response with recovery, push the assistant turn, fire `turn:after`, then\n * apply the length, refusal and pause recoveries, schema enforcement or tool\n * dispatch.\n *\n * @param ctx - The run context. `ctx.turns` gains the assistant turn, and the tool-result turn when tools ran.\n * @param turn - 0-indexed turn counter of the run.\n * @param priorUsage - Run-cumulative usage before this turn, for `cumulativeUsage` on `turn:after`.\n * @returns The turn's usage and whether the run ended, plus the recovery flags `runLoop` counts.\n */\nexport async function executeTurn(\n ctx: LoopContext,\n turn: number,\n priorUsage: RunUsageSnapshot,\n): Promise<TurnResult> {\n const pending = takeResumedCalls(ctx, turn)\n if (pending)\n return dispatchResumedCalls(ctx, turn, pending)\n\n // Generate turn ID early so streaming hooks have access to it. From the\n // run clock, which a replay-mode runtime makes replay-stable.\n const turnId = ctx.clock.randomUUID()\n\n const wire = await buildTurnWireMessages(ctx)\n const streamOptions = buildTurnStreamOptions(ctx, turn, wire.messages)\n\n // Context transform hook — lets consumers prune/modify messages before LLM call\n // ctx.messages here is the wire-level view (aliases applied) so transformations are\n // consistent with what the provider actually sees.\n const transformCtx = { messages: streamOptions.messages }\n await boundedHook(ctx, 'hook context:transform', ctx.hooks.callHook('context:transform', transformCtx))\n streamOptions.messages = await resolveContentRefsForWire(ctx, transformCtx.messages)\n\n // Last line of defense before the wire: repair any `tool_use` ↔\n // `tool_result` adjacency violations. Anthropic 400s on orphans loudly\n // (`'tool_use' ids were found without 'tool_result' blocks immediately\n // after`, `tool_result must be preceded by a tool_call with the same\n // toolCallId`); OpenAI is more forgiving but still rejects most\n // mismatches. Common sources: interrupted runs persisted mid-pair, the\n // schema-enforcement `__output__` tail, `context:transform` hooks that\n // prune messages without preserving pairing, duplicate tool_use ids\n // surfaced by buggy providers, compaction passes that strand assistant\n // half of a pair.\n //\n // Strict mode (`behavior.strictToolPairing`) collects every repair and\n // throws `AgentToolPairingError` instead of patching the wire — for\n // training-data collectors that need to reject corrupted transcripts\n // rather than ship synthetic placeholders.\n streamOptions.messages = applyPairingRepair(ctx, streamOptions.messages, turnId)\n\n // Final defense: guarantee the wire ends with a user message. Pair-repair\n // mode 2 already appends a synthetic `tool_result` user turn for orphan\n // `tool_use`s, but a *plain* assistant text tail (no tool_use blocks)\n // slips through — typically when a `context:transform` hook trims the\n // last user turn. Models that don't support assistant prefill (opus 4.7,\n // o-series translation layers) 400 with \"This model does not support\n // assistant message prefill. The conversation must end with a user\n // message.\" Idempotent on a healthy tail.\n streamOptions.messages = ensureEndsWithUserMessage(streamOptions.messages, ctx.provider)\n\n // System transform hook — runtime-derived system-prompt sections. Fires\n // after `context:transform` so handlers can branch on the wire-level\n // message list.\n //\n // Cache breakpoints are applied inside the provider after this point, which\n // means whatever a handler writes here is INSIDE the prefix that every\n // message-level breakpoint hashes. Per-turn churn in `ctx.system` therefore\n // invalidates the whole conversation, not just the system block — see the\n // warning on `AgentHooks['system:transform']`. Byte-stable sections only.\n const systemCtx: {\n system: string\n messages: readonly SessionMessage[]\n turn: number\n turnId: string\n session?: Session\n } = {\n system: streamOptions.system,\n messages: streamOptions.messages,\n turn,\n turnId,\n ...(ctx.session ? { session: ctx.session } : {}),\n }\n await boundedHook(ctx, 'hook system:transform', ctx.hooks.callHook('system:transform', systemCtx))\n streamOptions.system = systemCtx.system\n\n await boundedHook(ctx, 'hook turn:before', ctx.hooks.callHook('turn:before', { turn, turnId, options: streamOptions }))\n\n // Defense-in-depth: `turn:before` exposes mutable `options.messages` for\n // hosts that need to splice last-mile context (per-turn reminders,\n // dynamic system-as-user injections, audit-tag wrappers). Any such\n // mutation lands AFTER the earlier `applyPairingRepair` + tail guard, so\n // re-run both. Both are idempotent on healthy input (return the same\n // reference, fire zero `pairing:repair` events) — when the hook didn't\n // touch messages, this is free. When it did, this is the difference\n // between a clean wire send and a `tool_result must be preceded by a\n // tool_call with the same toolCallId` 400 from a corrupted re-splice.\n streamOptions.messages = await resolveContentRefsForWire(ctx, streamOptions.messages)\n streamOptions.messages = applyPairingRepair(ctx, streamOptions.messages, turnId)\n streamOptions.messages = ensureEndsWithUserMessage(streamOptions.messages, ctx.provider)\n const { result, obs } = await streamTurnWithRecovery(ctx, streamOptions, { turn, turnId, priorUsage, callMaps: wire.callMaps })\n\n // Tool-only turns (no text / no thinking deltas) still need a TTFT\n // number — the stream returned silently with just tool_use blocks. Use\n // the wall-clock duration of `provider.stream()` as the proxy. Tool\n // dispatch fires `tool:before` later, but that's post-stream and would\n // double-count provider latency.\n if (obs.turnTtftMs === undefined && result.toolCalls.length > 0)\n obs.turnTtftMs = Date.now() - obs.streamStartedAt\n\n const { toolCalls: canonicalToolCalls, content: canonicalContent } = canonicalizeTurnOutput(ctx, result, turnId)\n\n // Stamp per-turn TTFT onto the usage record so the assistant turn\n // carries it through session persistence (downstream consumers reading\n // `SessionTurn.usage` for postmortem analysis get it without re-running\n // the loop) and the hook ctx exposes it for metrics histograms.\n if (obs.turnTtftMs !== undefined && result.usage.timeToFirstTokenMs === undefined)\n result.usage.timeToFirstTokenMs = obs.turnTtftMs\n // And the full round trip, so consumers can derive generation speed\n // (`output / (streamDurationMs − timeToFirstTokenMs)`) without re-running.\n if (result.usage.streamDurationMs === undefined)\n result.usage.streamDurationMs = Date.now() - obs.streamStartedAt\n\n // Build the assistant turn and push BEFORE firing turn:after\n const assistantTurn: SessionTurn = {\n id: turnId,\n runId: ctx.runId,\n role: 'assistant',\n content: result.done\n ? (canonicalContent.length > 0 ? canonicalContent : [{ type: 'text', text: obs.text }])\n : canonicalContent,\n usage: result.usage,\n createdAt: await ctx.clock.now(),\n }\n ctx.turns.push(assistantTurn)\n\n // Per-turn tool counts: how many of each tool the model emitted in this\n // assistant turn. Counts emissions, not dispatches — `turn:after` fires\n // before tool dispatch, so blocked calls are counted here too. For \"actually\n // dispatched\" cumulative numbers, use `toolCounts.run`.\n const turnCounts: Record<string, number> = {}\n for (const tc of canonicalToolCalls)\n turnCounts[tc.name] = (turnCounts[tc.name] ?? 0) + 1\n\n await settledHook(ctx, 'hook turn:after', ctx.hooks.callHook('turn:after', {\n turn,\n turnId,\n usage: result.usage,\n message: assistantTurn,\n // `signal.aborted` captured at fire time. On this (post-stream, pre-tool-\n // dispatch) path it's true only when an abort already landed by now — an\n // external cancel or a `stream:end`/hook-driven `agent.abort()` in the\n // window since the stream closed. The streaming-abort case is carried by\n // the error-path `turn:after` above (`aborted: wasAborted`); a tool-gate /\n // repeat-guard abort trips AFTER this fires (during the tool batch below)\n // and is observed by the loop's post-turn check, which fires `agent:abort`\n // — that turn's `turn:after` carries `finishReason: 'tool-calls'`, never\n // `'stop'`, so a Stop-hook consumer keyed on `'stop'` won't misfire on it.\n aborted: ctx.signal.aborted,\n toolCounts: { turn: Object.freeze(turnCounts), run: Object.freeze({ ...ctx.runToolCounts }) },\n cumulativeUsage: buildCumulativeUsage(priorUsage, result.usage),\n }))\n\n // Continue-on-length recovery (opt-in via `behavior.resumeOnMaxTokens`): the\n // model hit the output cap (`max_tokens`) without completing a tool call, so\n // ending here would truncate the trajectory mid-output. Push a synthetic\n // continue — symmetric with the pause recovery below — so the model finishes\n // instead of the run silently stopping between turns. `runLoop` bounds\n // consecutive resumes so a model that can't make progress can't loop forever.\n // Context-window exhaustion ALSO surfaces as `finishReason: 'length'`; we\n // don't special-case it because the resumed turn's pre-stream auto-compaction\n // shrinks the prompt before the next call. This MUST precede the `result.done`\n // short-circuit below: the provider marks a no-tool length turn `done`, and\n // we're pre-empting exactly that early return.\n if (\n ctx.behavior.resumeOnMaxTokens\n && (ctx.behavior.maxConsecutiveLengthResumes ?? 8) > 0\n && result.usage.finishReason === 'length'\n && canonicalToolCalls.length === 0\n && !(await runAborted(ctx))\n ) {\n const continueMsg = ctx.provider.userMessage('Please continue.')\n ctx.turns.push(syntheticUserTurn(ctx, continueMsg, 'length-resume', await ctx.generateTurnId(), await ctx.clock.now()))\n return {\n ended: false,\n turnId,\n usage: result.usage,\n lengthTruncated: true as const,\n ...(obs.text.length === 0 ? { lengthEmpty: true as const } : {}),\n }\n }\n\n // Refusal recovery (`finishReason: 'content-filter'`, e.g. Anthropic\n // `stop_reason: refusal`): the provider's safety layer cut the turn off —\n // typically with zero visible output — and the provider marks such a turn\n // `done`, so without this pre-emption the run would end here looking\n // successfully completed while actually stalling mid-task. Observed in the\n // wild with PDF-heavy sessions where Anthropic intermittently refuses right\n // after a document tool result. Push a synthetic continue — symmetric with\n // the pause recovery below — and let `runLoop` bound consecutive refusal\n // resumes so a hard refusal can't ping-pong forever at full input cost.\n // This MUST precede the `result.done` short-circuit for the same reason the\n // length recovery above does.\n if (\n result.usage.finishReason === 'content-filter'\n && canonicalToolCalls.length === 0\n && (ctx.behavior.maxConsecutiveRefusalResumes ?? 3) > 0\n && !(await runAborted(ctx))\n ) {\n const continueMsg = ctx.provider.userMessage('The previous response was interrupted by the provider (refusal stop). Please continue with the task.')\n ctx.turns.push(syntheticUserTurn(ctx, continueMsg, 'refusal-retry', await ctx.generateTurnId(), await ctx.clock.now()))\n return { ended: false, turnId, usage: result.usage, refusalResumed: true as const }\n }\n\n if (result.done) {\n // Schema enforcement: force one more call with a synthetic output tool\n if (ctx.behavior.schema && !(await runAborted(ctx))) {\n const enforcement = await enforceSchemaOutput(ctx, turnId)\n return {\n ended: true,\n turnId,\n usage: mergeSchemaEnforcementUsage(result.usage, enforcement.usage),\n output: enforcement.output,\n }\n }\n\n return { ended: true, turnId, usage: result.usage }\n }\n\n // Pause-turn recovery (Anthropic 4.6+ `pause_turn`): the model stopped\n // mid-turn for a server-side pause but no tools were requested. Push a\n // synthetic continue prompt as a user message so the next turn resumes\n // with valid (non-empty) input — Anthropic rejects empty user content.\n // Gated on `finishReason === 'pause'` to avoid masking provider bugs that\n // legitimately produce zero tool calls and zero text.\n //\n // We also classify the turn as `pauseEmpty: true` here. `runLoop` reads\n // that flag to track consecutive empty pauses and end the run with\n // `finishReason: 'pause'` after `behavior.maxConsecutivePauseTurns`, so\n // a stuck model returning empty pauses indefinitely doesn't burn tokens\n // forever. A pause turn that DID produce text or thinking is not\n // classified empty — those resume cleanly without a cap.\n const finishedEmptyPause = canonicalToolCalls.length === 0\n && result.usage.finishReason === 'pause'\n && obs.text.length === 0\n && obs.thinking.length === 0\n if (canonicalToolCalls.length === 0 && result.usage.finishReason === 'pause') {\n const continueMsg = ctx.provider.userMessage('Please continue.')\n ctx.turns.push(syntheticUserTurn(ctx, continueMsg, 'pause-resume', await ctx.generateTurnId(), await ctx.clock.now()))\n return {\n ended: false,\n turnId,\n usage: result.usage,\n ...(finishedEmptyPause ? { pauseEmpty: true as const } : {}),\n }\n }\n\n await dispatchTurnToolCalls(ctx, turn, turnId, canonicalToolCalls)\n\n return { ended: false, turnId, usage: result.usage }\n}\n","/**\n * Compaction of a conversation into a `compact-summary` marker: the\n * threshold-gated turn-boundary trigger (auto-compaction) and the ungated\n * pass it shares with `agent.compact()`.\n */\n\nimport type { CompactOptions } from './compact'\nimport type { LoopContext } from './loop-context'\nimport type { Provider, StreamOptions } from './providers'\nimport type { AutoCompact, CompactHookContext, SessionMessage, SessionTurn, TurnUsage } from './types'\nimport { hashMessages } from './cache-telemetry'\nimport { AUTO_COMPACT_MIN_GROWTH_FRACTION, buildPostCompactAttachments, compactConversation, CompactInvalidInputError, selectFilesFromSession, shouldAutoCompact, summaryToTurn } from './compact'\nimport { DEFAULT_MAX_OUTPUT_TOKENS } from './compact/compact'\nimport { errorMessage } from './errors'\nimport { applyCompactSummaryCutoff, readFilePathsInTurns } from './loop-compaction'\nimport { compactionJournal, durableClock, isControlError, journaledDecision, settledHook } from './loop-context'\nimport { releaseReplacedTurnContent } from './loop-persistence'\nimport { markReadStateForElidedPaths } from './loop-stale-reads'\nimport { buildTurnStreamOptions, buildTurnWireMessages } from './loop-turn'\nimport { httpFetchWrapper } from './providers/http-intercept'\nimport { journaledStep, LOOP_STEP_KINDS, replays } from './run-durability'\nimport { effectiveInputFromTurn } from './stats'\n\n/** Default fire threshold for loop-native auto-compaction (fraction of effective window). */\nconst DEFAULT_AUTO_COMPACT_THRESHOLD = 0.85\n/** Default consecutive-failure circuit-breaker budget for auto-compaction. */\nconst DEFAULT_AUTO_COMPACT_MAX_FAILURES = 2\n\n/**\n * Minimum gap between `compact:progress` hook dispatches. Provider deltas\n * arrive far faster than any UI needs — 4/s keeps the counter feeling live\n * without turning the hook into a hot path.\n */\nconst COMPACT_PROGRESS_THROTTLE_MS = 250\n\n/**\n * Prompt-side proxy for a live cost estimate when the provider hasn't reported\n * mid-stream usage: the previous assistant turn's split. Consecutive turns\n * ride nearly the same prefix, so its fresh/cached/written breakdown is a far\n * better guess than \"all fresh input\" (which would overprice a cached prompt\n * ten-fold). `undefined` on the first turn of a session — the estimate then\n * prices output only until `turn:after` settles it.\n */\nexport function lastAssistantUsage(turns: readonly SessionTurn[]): TurnUsage | undefined {\n for (let i = turns.length - 1; i >= 0; i--) {\n const t = turns[i]!\n if (t.role === 'assistant' && t.usage && (t.usage.input + (t.usage.cacheRead ?? 0) + (t.usage.cacheCreation ?? 0)) > 0)\n return t.usage\n }\n return undefined\n}\n\n/** Normalized {@link AutoCompact} config the loop consumes. See {@link resolveAutoCompact}. */\nexport interface ResolvedAutoCompact {\n threshold: number\n /** Raw context window in tokens, or `null` when no source resolved one (trigger inert). */\n contextWindow: number | null\n /**\n * `true` when {@link contextWindow} came from the `provider.meta.contextWindow`\n * fallback rather than explicit host config. A model fallback re-resolves\n * the window from the newly active provider in that case — the trigger\n * should measure the window of the target actually serving the run —\n * while an explicit host-set window is never overridden.\n */\n contextWindowFromProviderMeta: boolean\n keepTurns: number\n minGrowthFraction: number\n restore: boolean\n maxFailures: number\n /** Summarizer provider override, or `null` — use the run's main provider. */\n provider: Provider | null\n /** Summarizer model override, or `null` — use the run's main model. */\n model: string | null\n /** Release in-memory bodies of summary-replaced turns to persist-dir stubs. */\n releaseReplacedTurns: boolean\n}\n\n/**\n * Normalize `behavior.autoCompact` into the loop's {@link ResolvedAutoCompact}\n * shape, or `undefined` when disabled (`false` / unset). Applies the\n * `provider.meta.contextWindow` fallback and inherits `compactKeepTurns` for\n * the preserved tail. Pure — exported so `agent.run` builds the LoopContext\n * field and tests can assert the defaults.\n */\nexport function resolveAutoCompact(\n raw: AutoCompact | undefined,\n opts: { fallbackContextWindow?: number | null, compactKeepTurns?: number } = {},\n): ResolvedAutoCompact | undefined {\n if (raw === undefined || raw === false)\n return undefined\n const cfg = raw === true ? {} : raw\n\n const explicitWindow = typeof cfg.contextWindow === 'number' && Number.isFinite(cfg.contextWindow) && cfg.contextWindow > 0\n ? cfg.contextWindow\n : null\n const fallbackWindow = typeof opts.fallbackContextWindow === 'number' && Number.isFinite(opts.fallbackContextWindow) && opts.fallbackContextWindow > 0\n ? opts.fallbackContextWindow\n : null\n\n const keepTurns = typeof cfg.keepTurns === 'number' && Number.isFinite(cfg.keepTurns) && cfg.keepTurns >= 0\n ? Math.floor(cfg.keepTurns)\n : (typeof opts.compactKeepTurns === 'number' && Number.isFinite(opts.compactKeepTurns) && opts.compactKeepTurns >= 0\n ? Math.floor(opts.compactKeepTurns)\n : 4)\n\n return {\n threshold: typeof cfg.threshold === 'number' ? cfg.threshold : DEFAULT_AUTO_COMPACT_THRESHOLD,\n contextWindow: explicitWindow ?? fallbackWindow,\n contextWindowFromProviderMeta: explicitWindow === null && fallbackWindow !== null,\n keepTurns,\n minGrowthFraction: typeof cfg.minGrowthFraction === 'number' ? cfg.minGrowthFraction : AUTO_COMPACT_MIN_GROWTH_FRACTION,\n restore: cfg.restore !== false,\n maxFailures: typeof cfg.maxFailures === 'number' && Number.isFinite(cfg.maxFailures) && cfg.maxFailures > 0\n ? Math.floor(cfg.maxFailures)\n : DEFAULT_AUTO_COMPACT_MAX_FAILURES,\n provider: cfg.provider ?? null,\n model: typeof cfg.model === 'string' && cfg.model.length > 0 ? cfg.model : null,\n releaseReplacedTurns: cfg.releaseReplacedTurns === true,\n }\n}\n\n/**\n * Mutable per-run state for loop-native auto-compaction. Lives in `runLoop`'s\n * scope; threaded into {@link maybeAutoCompact} on each turn boundary.\n */\nexport interface AutoCompactRunState {\n /**\n * Effective input-token estimate observed right after the most recent\n * successful compaction — the hysteresis baseline `shouldAutoCompact`\n * compares against so a post-compact bounce doesn't immediately re-fire.\n */\n lastCompactedInputTokens: number | undefined\n /** Consecutive failed compaction attempts this run (reset on success). */\n consecutiveFailures: number\n /** Latched once the circuit breaker trips — no further attempts this run. */\n disabled: boolean\n}\n\n/**\n * The request the summary call resends, minus its signal (`compactConversation`\n * supplies one). Built on the last request the run sent: its system, tools\n * and messages already went through every hook and wire repair, so the\n * provider reads all of it from cache. When the next turn's messages extend\n * those messages unchanged, they replace them, so the summarizer sees the\n * reply to the user's last message rather than an unanswered request it might\n * answer instead of summarizing. Otherwise the sent request is resent as is\n * while the turns after it fit in the kept tail, which stays verbatim after\n * the summary, and the next turn's request is built outright when they don't.\n * A host compaction function is never run an extra time for this. `undefined`\n * when nothing applies: the standalone summary call still works.\n *\n * `requireSentPrefix` (`agent.compact()` between runs, where the host may\n * have edited the history since) drops the turn-count shortcut: the sent\n * request is used only when the current messages start with its messages.\n *\n * @param ctx - Loop context whose `turns` hold the history to compact.\n * @param turn - Loop turn that sent the cached request (keeps a decaying thinking budget equal).\n * @param keepTurns - Turns kept verbatim after the summary.\n * @param options - Prefix options.\n * @param options.requireSentPrefix - Use the sent request only when the current messages start with its messages.\n */\nexport async function buildPrefixRequest(\n ctx: LoopContext,\n turn: number,\n keepTurns: number,\n options: { requireSentPrefix?: boolean } = {},\n): Promise<Omit<StreamOptions, 'signal'> | undefined> {\n const last = ctx.lastRequest && ctx.lastRequest.options.model === ctx.model ? ctx.lastRequest : undefined\n const sentFits = !options.requireSentPrefix && last !== undefined && ctx.turns.length - last.turnCount <= keepTurns\n const sent = last ? withoutSignal(last.options) : undefined\n if (typeof ctx.behavior.compactStrategy === 'function')\n return sentFits ? sent : undefined\n try {\n const { messages } = await buildTurnWireMessages(ctx)\n if (sent && extendsMessages(messages, sent.messages))\n return { ...sent, messages }\n if (sentFits)\n return sent\n return withoutSignal(buildTurnStreamOptions(ctx, turn, messages))\n }\n catch (err) {\n if (isControlError(ctx, err))\n throw err\n if (process.env.ZIDANE_DEBUG)\n console.error('[zidane] compaction could not build the prefix-cache request:', err)\n return sentFits ? sent : undefined\n }\n}\n\nfunction withoutSignal(options: StreamOptions): Omit<StreamOptions, 'signal'> {\n const { signal: _signal, ...request } = options\n return request\n}\n\n/** Whether `next` starts with exactly the messages of `sent` (positional content hashes). */\nfunction extendsMessages(next: readonly SessionMessage[], sent: readonly SessionMessage[]): boolean {\n if (next.length < sent.length)\n return false\n const a = hashMessages(next.slice(0, sent.length) as SessionMessage[])\n const b = hashMessages(sent as SessionMessage[])\n return a.every((h, i) => h === b[i])\n}\n\n/**\n * In replay mode a summary stream would re-run on replay and write a\n * different summary than the journaled conversation saw: journal each of its\n * calls as a step. An `http.*` interceptor that matches the provider rides\n * its calls (`StreamOptions.wrapFetch`), as on the run's own turns.\n */\nfunction journaledSummarizer(provider: Provider, ctx: Pick<LoopContext, 'durable' | 'interceptors'>): Provider {\n const wrapFetch = httpFetchWrapper(ctx.interceptors, provider.name)\n const base: Provider = wrapFetch ? { ...provider, stream: (options, callbacks) => provider.stream({ ...options, wrapFetch }, callbacks) } : provider\n if (!replays(ctx.durable))\n return base\n return {\n ...base,\n stream: (options, callbacks) => journaledStep(ctx.durable, LOOP_STEP_KINDS.compact, 'compact-summary', () => base.stream(options, callbacks)),\n }\n}\n\n/**\n * `compactConversation`'s `summarize` over the extension `compaction`\n * chain: an interceptor that answers `{ summary }` supplies the summary.\n * Journaled in replay mode, so a replay reuses the summary the live run got.\n */\nfunction compactionInterceptor(ctx: CompactionContext, interceptors: NonNullable<CompactionContext['interceptors']>, hook: CompactHookContext): NonNullable<CompactOptions['summarize']> {\n return async ({ messages }) => await journaledDecision(ctx, 'compaction-interceptor', async () => await interceptors.runInterceptors('compaction', {\n messages,\n reason: hook.reason,\n ...(hook.sessionId !== undefined ? { sessionId: hook.sessionId } : {}),\n }, undefined) ?? null)\n}\n\n/**\n * Whether the prefix-cache summary call fits the context window. It resends\n * the whole prompt with max_tokens = thinking budget + summary cap, and a\n * provider rejects prompt + max_tokens over the window, so a call that can't\n * fit would only fail and fall back. `inputTokens` (the last request's\n * prompt) is a lower bound for the prefix prompt.\n */\nfunction prefixFitsWindow(request: Omit<StreamOptions, 'signal'>, inputTokens: number, contextWindow: number | null): boolean {\n return contextWindow === null\n || inputTokens + (request.thinkingBudget ?? 0) + DEFAULT_MAX_OUTPUT_TOKENS <= contextWindow\n}\n\n/**\n * The parts of a run's {@link LoopContext} one compaction pass reads and\n * writes. `agent.compact()` builds one between runs, where no run id exists.\n */\nexport type CompactionContext = Pick<LoopContext, 'provider' | 'model' | 'behavior' | 'turns' | 'session' | 'readState' | 'handle' | 'execution' | 'signal' | 'clock' | 'durable' | 'hooks' | 'getActiveSkills' | 'persistTurns' | 'interceptors'> & {\n /** Run the compaction belongs to. Absent between runs. */\n runId?: string\n}\n\n/** Inputs of one {@link performCompaction} pass besides its context. */\nexport interface CompactionPass {\n /** Resolved compaction config: kept tail, restoration, summarizer overrides, window. */\n cfg: ResolvedAutoCompact\n /** Coordinates every hook of the pass carries. */\n hook: CompactHookContext\n /** Window measurements for `compact:start`: how full the window was when the pass started. */\n measured: { usedFraction: number, effectiveWindow: number }\n /** Effective input tokens of the last request: the lower bound the window check uses. */\n inputTokens: number\n /**\n * Builds the conversation's own request to resend with the summary\n * instruction (see {@link buildPrefixRequest}). Called only when the summary\n * runs on the context's own provider and model.\n */\n buildPrefixRequest?: () => Promise<Omit<StreamOptions, 'signal'> | undefined>\n}\n\n/** What a successful {@link performCompaction} pass did. */\nexport interface CompactionOutcome {\n /** The `compact-summary` marker turn appended to the history. */\n summaryTurn: SessionTurn\n /** Turn ids the summary replaced on the wire. */\n replacedCount: number\n /** Turns dropped by `prompt_too_long` head-truncation (not summarized). */\n droppedCount: number\n /** Files re-injected by post-compact restoration. */\n restoredFiles: number\n /** Skills re-injected by post-compact restoration. */\n restoredSkills: number\n /** Model that wrote the summary. */\n summaryModel: string\n /** Usage of the summary call. */\n usage: TurnUsage\n /** Estimated context size on the next turn: summary output plus restored content. */\n effectiveTokens: number\n}\n\n/**\n * One compaction pass, with no threshold or cooldown gate: summarize the\n * older turns of `ctx.turns` (`compactConversation`, `scope: 'tail'`),\n * append a `compact-summary` marker plus optional file/skill restoration to\n * `ctx.turns`, and persist. The next `executeTurn` runs\n * `applyCompactSummaryCutoff` over the turns, so the provider sees the\n * summary + preserved tail with no extra wiring.\n *\n * Fires `compact:start`, throttled `compact:progress`, and exactly one\n * `compact:end`. Rejects with the failure (abort included) after the\n * `compact:end` error hook; the turns are left untouched then.\n *\n * @param ctx - The history and the run or agent state the pass uses.\n * @param pass - Config, hook coordinates and the cached-request builder.\n */\nexport async function performCompaction(ctx: CompactionContext, pass: CompactionPass): Promise<CompactionOutcome> {\n const { cfg, hook: base } = pass\n const startedAt = Date.now()\n await settledHook(ctx, 'hook compact:start', ctx.hooks.callHook('compact:start', { ...base, ...pass.measured }))\n\n // Live progress → `compact:progress` hook, throttled so provider-cadence\n // deltas don't turn into a hook storm (hooks can be async / expensive).\n // Fire-and-forget: progress is observational, a slow listener must never\n // stall the summary stream. `ended` gates the tail — the last throttled\n // dispatch must not land after the paired `compact:end`.\n let lastProgressAt = 0\n let ended = false\n const onProgress = (p: { estOutputTokens: number }) => {\n const now = Date.now()\n if (ended || now - lastProgressAt < COMPACT_PROGRESS_THROTTLE_MS)\n return\n lastProgressAt = now\n void Promise.resolve(ctx.hooks.callHook('compact:progress', {\n ...base,\n estOutputTokens: p.estOutputTokens,\n })).catch(() => {})\n }\n\n try {\n // Summarizer overrides: config may point compaction at a different\n // provider/model than the one driving the conversation (cheaper or\n // larger-window summarizers). A bare `model` override resolves\n // against the run's main provider.\n //\n // CRITICAL: compact the WIRE view, not the raw session turns. Raw\n // turns still contain everything prior markers already replaced, so\n // a re-compaction would re-summarize the same ~full history on every\n // trigger (observed: identical 866k-token summary calls back-to-back)\n // while the wire never shrinks. The cutoff view is exactly what the\n // model sees — prior summaries inlined, replaced turns gone — so a\n // re-compaction absorbs the PTL-dropped head + prior summary + tail\n // and the wire size converges.\n const ownProvider = !cfg.provider || cfg.provider === ctx.provider\n const provider = journaledSummarizer(ownProvider ? ctx.provider : cfg.provider!, ctx)\n const model = cfg.model ?? ctx.model\n // Summarizing on the conversation's own provider + model: resend its own\n // request, so the provider serves it from its prompt cache instead of\n // re-reading it. A different summarizer can't share the cache and keeps\n // the standalone call, as does a request too large for the window (see\n // prefixFitsWindow).\n const built = ownProvider && model === ctx.model\n ? await pass.buildPrefixRequest?.()\n : undefined\n const prefixRequest = built && prefixFitsWindow(built, pass.inputTokens, cfg.contextWindow) ? built : undefined\n const result = await compactConversation({\n provider,\n model,\n ...(prefixRequest ? { prefixRequest } : {}),\n turns: applyCompactSummaryCutoff(ctx.turns),\n scope: 'tail',\n keepTurns: cfg.keepTurns,\n signal: ctx.signal,\n clock: durableClock(ctx, ctx.signal),\n onProgress,\n shouldRethrowError: err => isControlError(ctx, err),\n ...(ctx.behavior.providerStreamTimeoutMs !== undefined ? { providerStreamTimeoutMs: ctx.behavior.providerStreamTimeoutMs } : {}),\n ...(ctx.interceptors?.has('compaction') ? { summarize: compactionInterceptor(ctx, ctx.interceptors, base) } : {}),\n })\n\n // The run clock (journaled in replay mode), so the marker turn (id +\n // createdAt + the block's `compactedAt`) is byte-identical on replay.\n const summaryTurn = summaryToTurn({\n summary: result.summary,\n replacesTurnIds: result.summarizedTurnIds,\n model: result.model,\n usage: result.usage,\n compactedAt: await ctx.clock.now(),\n id: ctx.clock.randomUUID(),\n })\n\n // Post-compact restoration — re-inject recently-read files + active\n // skills as synthetic tool_call/tool_result pairs so the model keeps its\n // working set. Canonical tool names; the per-turn `rewriteMessagesToWire`\n // handles aliasing. Best-effort: a restoration failure never blocks the\n // summary (the marker still lands).\n let restoredFiles = 0\n let restoredSkills = 0\n let restorationTurns: readonly SessionTurn[] = []\n let restorationTokens = 0\n if (cfg.restore) {\n try {\n const recentFiles = ctx.session ? selectFilesFromSession(ctx.session, ctx.handle.cwd) : []\n const activeSkills = ctx.getActiveSkills?.() ?? []\n const built = await buildPostCompactAttachments({\n recentFiles,\n activeSkills,\n execution: ctx.execution,\n handle: ctx.handle,\n signal: ctx.signal,\n clock: durableClock(ctx, ctx.signal),\n ...(compactionJournal(ctx) ? { journal: compactionJournal(ctx) } : {}),\n ...(ctx.runId ? { runId: ctx.runId } : {}),\n shouldRethrowError: err => isControlError(ctx, err),\n })\n restorationTurns = built.turns\n restoredFiles = built.restoredFiles\n restoredSkills = built.restoredSkills\n restorationTokens = built.estimatedTokens\n }\n catch (err) {\n if (isControlError(ctx, err))\n throw err\n if (process.env.ZIDANE_DEBUG)\n process.stderr.write(`[zidane/loop] post-compact restoration failed: ${errorMessage(err)}\\n`)\n }\n }\n\n // Land the marker + restoration in the live turns, then persist so the\n // summary is durable and hosts repaint now (the persist callback fires\n // `session:turns`). In batch-persist mode the callback is absent and the\n // run-end flush covers these turns.\n ctx.turns.push(summaryTurn, ...restorationTurns)\n await ctx.persistTurns?.()\n\n // Opt-in memory release: the turns this summary absorbed never reach\n // the wire again (`applyCompactSummaryCutoff` elides them permanently),\n // so a long-lived host would otherwise retain their full tool outputs\n // for the process's life. Swap large text results for recoverable\n // persist-dir stubs. Runs AFTER persistTurns so the marker is durable\n // first; best-effort — a failure leaves originals in memory. Blobs are\n // written host-side (NOT via `executionBlobWriter`): the session store\n // is host-local, and a sandboxed context write would strand the only\n // durable copy inside an ephemeral container.\n if (cfg.releaseReplacedTurns && ctx.behavior.persistDir && result.summarizedTurnIds.length > 0) {\n try {\n await releaseReplacedTurnContent(ctx.turns, new Set(result.summarizedTurnIds), {\n persistDir: ctx.behavior.persistDir,\n })\n }\n catch (err) {\n if (isControlError(ctx, err))\n throw err\n if (process.env.ZIDANE_DEBUG)\n process.stderr.write(`[zidane/loop] post-compact turn release failed: ${errorMessage(err)}\\n`)\n }\n }\n\n // Defeat the read-dedup stub for reads the summary just absorbed (or\n // PTL-dropped) — same rationale as tail compaction's invalidation:\n // those `read_file` outputs no longer reach the wire, so a post-compact\n // re-read must serve the full body instead of an \"unchanged — prior\n // result above\" stub pointing at content the model can no longer see.\n // Exempt paths whose newest read IS still on the wire — the post-cutoff\n // view (all markers applied, restoration turns included) is exactly\n // what the model sees, so a file re-read in the kept tail or re-injected\n // by the restoration pass keeps its honest stub instead of paying one\n // pointless full re-read per compaction. Mirrors `applyStaleReadElision`'s\n // `pathsWithFreshRead` exemption.\n const absorbedIds = new Set([...result.summarizedTurnIds, ...result.droppedDueToPtl])\n const onWireReads = new Set(readFilePathsInTurns(applyCompactSummaryCutoff(ctx.turns)))\n markReadStateForElidedPaths(\n ctx,\n ctx.handle.cwd,\n readFilePathsInTurns(ctx.turns, absorbedIds).filter(p => !onWireReads.has(p)),\n )\n\n // Estimate the post-compact effective size for the hysteresis baseline +\n // the host's context indicator: the summary's own output tokens plus the\n // restored attachment estimate. Under-counts the system prompt + tail,\n // both small; the next real `turn:after` corrects it precisely.\n const effectiveTokens = (result.usage.output ?? 0) + restorationTokens\n const outcome: CompactionOutcome = {\n summaryTurn,\n replacedCount: result.summarizedTurnIds.length,\n droppedCount: result.droppedDueToPtl.length,\n restoredFiles,\n restoredSkills,\n summaryModel: result.model,\n usage: result.usage,\n effectiveTokens,\n }\n\n await settledHook(ctx, 'hook compact:end', ctx.hooks.callHook('compact:end', {\n ...base,\n status: 'success',\n replacedCount: outcome.replacedCount,\n droppedCount: outcome.droppedCount,\n restoredFiles,\n restoredSkills,\n summaryModel: outcome.summaryModel,\n effectiveTokens,\n durationMs: Date.now() - startedAt,\n }))\n return outcome\n }\n catch (err) {\n await settledHook(ctx, 'hook compact:end', ctx.hooks.callHook('compact:end', {\n ...base,\n status: 'error',\n error: err,\n durationMs: Date.now() - startedAt,\n }))\n throw err\n }\n finally {\n ended = true\n }\n}\n\n/**\n * Loop-native auto-compaction, evaluated at a turn boundary.\n *\n * When the last turn's EFFECTIVE input usage (`input + cacheRead +\n * cacheCreation`, so prompt caching doesn't mask a full window) crosses the\n * configured fraction of the effective context window, and the post-compact\n * cooldown has passed, run one {@link performCompaction} pass.\n *\n * A compaction failure never throws — failures (including aborts and \"nothing\n * to compact\") are swallowed: the run continues on the un-compacted history (the reactive\n * `context_exceeded` net still applies) and the circuit breaker counts the\n * failure so a persistently-failing compaction can't stall the run.\n */\nexport async function maybeAutoCompact(\n ctx: LoopContext,\n turn: number,\n lastTurnUsage: TurnUsage,\n state: AutoCompactRunState,\n): Promise<void> {\n const cfg = ctx.autoCompact\n if (!cfg || state.disabled)\n return\n\n const inputTokens = effectiveInputFromTurn(lastTurnUsage)\n const decision = shouldAutoCompact({\n enabled: true,\n threshold: cfg.threshold,\n inputTokens,\n rawContextWindow: cfg.contextWindow,\n alreadyCompacting: false,\n ...(state.lastCompactedInputTokens !== undefined ? { lastCompactedInputTokens: state.lastCompactedInputTokens } : {}),\n minGrowthFraction: cfg.minGrowthFraction,\n })\n if (decision.kind !== 'fire')\n return\n\n // Cheap structural skip: nothing summarizable beyond the preserved tail.\n // Avoids a doomed provider round-trip (and a spurious start/end pair) for\n // the degenerate \"one giant turn nearly fills the window\" case.\n if (ctx.turns.length <= cfg.keepTurns + 1)\n return\n\n // Last, so in replay mode it is recorded only when compaction would fire:\n // a replay that missed the abort would otherwise journal a summary call.\n if (await journaledDecision(ctx, 'compact-abort', () => ctx.signal.aborted))\n return\n\n const sessionId = ctx.session?.id\n try {\n const outcome = await performCompaction(ctx, {\n cfg,\n hook: { runId: ctx.runId, ...(sessionId ? { sessionId } : {}), turn, reason: 'auto' },\n measured: { usedFraction: decision.usedFraction, effectiveWindow: decision.effectiveWindow },\n inputTokens,\n // `turn` (not `turn + 1`) keeps a decaying thinking budget equal to the\n // request that wrote the cache.\n buildPrefixRequest: () => buildPrefixRequest(ctx, turn, cfg.keepTurns),\n })\n state.lastCompactedInputTokens = outcome.effectiveTokens\n state.consecutiveFailures = 0\n }\n catch (err) {\n // A durable runtime's control error (suspension, cancellation) must end\n // the invocation, not be counted as a failed compaction.\n if (isControlError(ctx, err))\n throw err\n // Aborts end the run on the next loop check — don't burn the breaker on\n // them. Every other failure (provider error, prompt_too_long exhausted,\n // \"nothing to compact\") counts toward the breaker so a persistently-\n // failing trigger goes quiet instead of re-firing every turn.\n const aborted = ctx.signal.aborted || (err instanceof Error && err.name === 'AbortError')\n if (!aborted) {\n state.consecutiveFailures += 1\n if (state.consecutiveFailures >= cfg.maxFailures || err instanceof CompactInvalidInputError)\n state.disabled = true\n }\n }\n}\n","/**\n * `agent.compact()`: a compaction pass between runs, through the loop's own\n * compaction routine (`performCompaction`) and, when it still matches the\n * history, the last request a run sent.\n */\n\nimport type { AgentRuntime } from './agent-runtime'\nimport type { AgentCompactOptions, AgentCompactResult } from './agent-types'\nimport type { CompactionContext } from './loop-auto-compact'\nimport type { LoopContext } from './loop-context'\nimport type { RunDurability } from './run-durability'\nimport type { SessionTurn } from './types'\nimport { DEFAULT_SPAWN_TIMEOUT_MS, resolveBehavior } from './agent-behavior'\nimport { ensureExecutionHandle } from './agent-bootstrap'\nimport { runtimeForRun } from './agent-durable'\nimport { applyBehaviorTransforms } from './agent-extensions'\nimport { selectSeedTurns } from './agent-history'\nimport { interceptBehavior } from './agent-interceptors'\nimport { resetRunScope } from './agent-runtime'\nimport { CompactInvalidInputError, sliceForCompaction } from './compact'\nimport { effectiveContextWindow } from './compact/policy'\nimport { buildPrefixRequest, lastAssistantUsage, performCompaction, resolveAutoCompact } from './loop-auto-compact'\nimport { applyCompactSummaryCutoff } from './loop-compaction'\nimport { settledHook } from './loop-context'\nimport { resolveModelTargets } from './model-targets'\nimport { openRunDurability, runClock } from './run-durability'\nimport { withExtensionSession } from './session'\nimport { effectiveInputFromTurn } from './stats'\nimport { resolveTimeoutMs } from './timeout'\nimport { DEFAULT_AGENT_CLOCK } from './types'\n\n/**\n * Compact the agent's session now. See {@link Agent.compact} for the contract.\n *\n * Run-less: no run record, no `agent:start` / `agent:done`. It still holds\n * the run slot (`running`, the idle gate, the abort controller) so `run()`,\n * `reset()` and a second `compact()` can't interleave with it, and\n * `agent.abort()` cancels it.\n */\nexport function compactAgent(rt: AgentRuntime, options: AgentCompactOptions = {}): Promise<AgentCompactResult> {\n return withExtensionSession(rt.session, () => compactWithinSession(rt, options))\n}\n\nasync function compactWithinSession(rt: AgentRuntime, options: AgentCompactOptions): Promise<AgentCompactResult> {\n if (rt.running)\n throw new Error('Agent is running. Call `await agent.waitForIdle()` before `agent.compact()`.')\n if (options.keepTurns !== undefined && !(Number.isInteger(options.keepTurns) && options.keepTurns >= 0))\n throw new RangeError(`compact: keepTurns must be a non-negative integer, got ${options.keepTurns}`)\n const { session, hooks } = rt\n // Without a session no history carries over to the next run, so there is\n // nothing a summary could shorten.\n if (!session)\n return { compacted: false, reason: 'no-session' }\n\n // The history the next run would start from, copied: the pass appends to it.\n const turns: SessionTurn[] = (selectSeedTurns({ session, options: {}, resumeFilteredTurns: undefined }) ?? []).slice()\n\n // Reuse the last run's context only when the summary runs on its model:\n // its cached request and wire builders are tied to that provider + model.\n const last = rt.lastRunContext\n const warm = last && (options.model === undefined || options.model === last.ctx.model) ? last : null\n const target = warm ? { provider: warm.ctx.provider, model: warm.ctx.model } : resolveModelTargets(rt.providers, options.model)[0]\n let behavior = warm?.ctx.behavior ?? applyBehaviorTransforms(resolveBehavior(rt.agentBehavior), rt.behaviorTransforms, undefined)\n // `behavior` interceptors after the registry's behavior transforms, as a run\n // applies them. Awaited only\n // when one is registered; the running check is repeated across the await.\n if (!warm && rt.interceptors?.has('behavior')) {\n behavior = await interceptBehavior(rt.interceptors, behavior, undefined)\n if (rt.running)\n throw new Error('Agent is running. Call `await agent.waitForIdle()` before `agent.compact()`.')\n }\n const contextWindow = target.provider.meta.contextWindow\n const resolved = warm?.ctx.autoCompact ?? resolveAutoCompact(behavior.autoCompact || true, {\n ...(contextWindow !== undefined ? { fallbackContextWindow: contextWindow } : {}),\n ...(behavior.compactKeepTurns !== undefined ? { compactKeepTurns: behavior.compactKeepTurns } : {}),\n })!\n const cfg = options.keepTurns === undefined ? resolved : { ...resolved, keepTurns: options.keepTurns }\n\n // Same preflight `compactConversation` runs, before any hook or provider call.\n try {\n sliceForCompaction(applyCompactSummaryCutoff(turns), 'tail', cfg.keepTurns)\n }\n catch (err) {\n if (err instanceof CompactInvalidInputError)\n return { compacted: false, reason: 'nothing-to-compact' }\n throw err\n }\n\n rt.running = true\n const abortController = new AbortController()\n rt.abortController = abortController\n rt.idlePromise = new Promise<void>((resolve) => {\n rt.idleResolve = resolve\n })\n const external = options.signal\n const onExternalAbort = (): void => abortController.abort(external?.reason)\n if (external?.aborted)\n onExternalAbort()\n else\n external?.addEventListener('abort', onExternalAbort, { once: true })\n\n let durability: RunDurability | undefined\n try {\n const handle = await ensureExecutionHandle(rt, resolveTimeoutMs(behavior.spawnTimeoutMs, DEFAULT_SPAWN_TIMEOUT_MS, behavior.maxWallMs))\n const persistedCount = turns.length\n durability = await openRunDurability(\n runtimeForRun(rt),\n { sessionId: session.id, runId: warm?.ctx.runId ?? session.runs.at(-1)?.id ?? 'compact' },\n )\n const clock = runClock(durability, rt.agentClock ?? DEFAULT_AGENT_CLOCK)\n const ctx: CompactionContext = {\n ...target,\n behavior,\n turns,\n session,\n ...(rt.agentReadState ? { readState: rt.agentReadState } : {}),\n handle,\n execution: rt.executionContext,\n signal: abortController.signal,\n clock,\n durable: durability,\n hooks,\n getActiveSkills: () => rt.skillActivationState.active(),\n ...(rt.interceptors ? { interceptors: rt.interceptors } : {}),\n persistTurns: async () => {\n const added = turns.slice(persistedCount)\n await session.appendTurns(added)\n await settledHook(ctx, 'hook session:turns', hooks.callHook('session:turns', { sessionId: session.id, turns: added, count: session.turns.length }))\n },\n }\n const usage = lastAssistantUsage(turns)\n const inputTokens = usage ? effectiveInputFromTurn(usage) : 0\n const effectiveWindow = effectiveContextWindow(cfg.contextWindow) ?? 0\n const outcome = await performCompaction(ctx, {\n cfg,\n // Between runs: the hooks name the latest run and its last turn.\n hook: { runId: warm?.ctx.runId ?? session.runs.at(-1)?.id ?? '', sessionId: session.id, turn: warm?.turn ?? 0, reason: 'manual' },\n measured: { usedFraction: effectiveWindow > 0 ? inputTokens / effectiveWindow : 0, effectiveWindow },\n inputTokens,\n ...(warm\n ? {\n // The last run's context over the current history: its cached\n // request is used only when the history still starts with its\n // messages, else the next turn's request is built from it.\n buildPrefixRequest: () => buildPrefixRequest({ ...warm.ctx, ...ctx, runId: warm.ctx.runId } satisfies LoopContext, warm.turn, cfg.keepTurns, { requireSentPrefix: true }),\n }\n : {}),\n })\n rt.conversationTurns = turns\n return {\n compacted: true,\n summaryTurnId: outcome.summaryTurn.id,\n replacedCount: outcome.replacedCount,\n droppedCount: outcome.droppedCount,\n restoredFiles: outcome.restoredFiles,\n restoredSkills: outcome.restoredSkills,\n model: outcome.summaryModel,\n usage: outcome.usage,\n effectiveTokens: outcome.effectiveTokens,\n }\n }\n catch (err) {\n if (abortController.signal.aborted)\n return { compacted: false, reason: 'aborted' }\n throw err\n }\n finally {\n external?.removeEventListener('abort', onExternalAbort)\n resetRunScope(rt)\n await durability?.scope.close()\n }\n}\n","/**\n * Context breakdown support: the per-run `ContextAssembly` snapshot and the\n * helpers that materialize it and collect extension-contributed sections.\n */\n\nimport type { AgentRuntime } from './agent-runtime'\nimport type { ContextBreakdown, ContextBreakdownContributor, ContextBreakdownOptions, ContextExactCounts, ContextExtensionSection, ContextMcpGroup } from './chat/context-breakdown'\nimport type { ContextSegment, ContextSegmentFile } from './chat/context-segments'\nimport type { ToolSpec } from './providers'\nimport type { SessionMessage, SessionTurn, TurnUsage } from './types'\nimport { ensureSkillsResolved } from './agent-bootstrap'\nimport { applyToolCatalogTransforms, applyToolDescriptionOverrides, toolResultMetadataSections } from './agent-extensions'\nimport { childRunIdSet } from './agent-history'\nimport { applyCatalogTools } from './agent-interceptors'\nimport { buildMcpToolNameSeparatorAliases, renderMcpInstructionsSection, resolveMcpToolParts } from './agent-mcp-naming'\nimport { buildSanitizedWireAliases } from './aliasing'\nimport { buildContextBreakdown } from './chat/context-breakdown'\nimport { buildContextSegments } from './chat/context-segments'\nimport { OUTPUT_RESERVE_TOKENS } from './compact/policy'\nimport { errorMessage } from './errors'\nimport { effectiveInputFromTurn } from './stats'\nimport { appendStaticSection, renderSystemForWire } from './system-prompt'\n\n// ---------------------------------------------------------------------------\n// Context assembly snapshot\n// ---------------------------------------------------------------------------\n\n/**\n * A disclosed tool's raw inputs, captured for the context breakdown. The\n * JSON byte-sizing is deferred (see {@link materializeAssemblyTools}) so the\n * per-run snapshot stays off the hot path — only `getContextBreakdown()`\n * pays the `JSON.stringify`.\n */\nexport interface DisclosedToolInput {\n /** Wire (alias-rewritten) name — the bytes the provider sends. */\n name: string\n description: string\n inputSchema: unknown\n /** MCP group key when this tool came from an MCP server; absent for native tools. */\n mcpServer?: string\n}\n\n/** A deferred (lazy, not-yet-disclosed) tool's raw inputs. */\nexport interface DeferredToolInput {\n name: string\n description: string\n inputSchema: unknown\n /** Source MCP server, when applicable. */\n server?: string\n}\n\n/**\n * Snapshot of a run's assembled prompt pieces (system, wire tools, deferred\n * tools, MCP groups, skills/subagent catalogs) + the model used. Captured in\n * `run()` right after the prompt is finalized; read on demand by\n * `getContextBreakdown()`.\n *\n * Tool byte-sizing (`toolsJson` / `mcpGroups` / deferred variants) is NOT\n * computed here — only the raw `disclosedTools` / `deferredEntries` inputs are\n * stored. {@link materializeAssemblyTools} does the `JSON.stringify` lazily so\n * a normal run/subagent never pays for breakdown serialization it won't read.\n */\nexport interface ContextAssembly {\n modelId: string\n /** Full rendered system prompt (base + all appended catalogs), wire form. */\n system: string\n /**\n * Host-composed base system BEFORE the agent's appends (doctrine + rules\n * + env). The breakdown subtracts the rules block from this to get the\n * \"Base system\" bucket.\n */\n baseSystem: string\n /** Rendered AGENTS.md/CLAUDE.md block + its source files (the \"Rules\" bucket). */\n rulesBlock?: string\n rulesFiles?: { path: string, source: string }[]\n /** Disclosed tools (raw); stringified lazily by {@link materializeAssemblyTools}. */\n disclosedTools: DisclosedToolInput[]\n /** Deferred (lazy) tools (raw); stringified lazily. */\n deferredEntries: DeferredToolInput[]\n mcpInstructions?: string\n skillsCatalog?: string\n /** Searchable / subagent (spawn) tool catalog text appended to system. */\n subagentDefs?: string\n /**\n * The disclosed tools in PROVIDER WIRE SHAPE (`provider.formatTools`\n * output) — what `countTokens` must receive for an exact count. Distinct\n * from `disclosedTools`, which carries the internal shape used only for\n * heuristic byte-sizing + categorization.\n */\n wireTools: unknown[]\n}\n\n/**\n * Single builder for a {@link ContextAssembly}, shared by the per-run snapshot\n * and the pre-run assembly so the two can't drift on optionality / field\n * ordering. Callers pass every piece (optional fields may be `undefined` or\n * empty); optional fields are left off the result when they are empty.\n */\nexport function assembleContextSnapshot(input: {\n modelId: string\n system: string\n baseSystem: string\n rulesBlock?: string | null\n rulesFiles?: { path: string, source: string }[]\n disclosedTools: DisclosedToolInput[]\n deferredEntries: DeferredToolInput[]\n mcpInstructions?: string | null\n skillsCatalog?: string | null\n subagentDefs?: string | null\n wireTools: unknown[]\n}): ContextAssembly {\n return {\n modelId: input.modelId,\n system: input.system,\n baseSystem: input.baseSystem,\n ...(input.rulesBlock ? { rulesBlock: input.rulesBlock } : {}),\n ...(input.rulesFiles?.length ? { rulesFiles: input.rulesFiles } : {}),\n disclosedTools: input.disclosedTools,\n deferredEntries: input.deferredEntries,\n ...(input.mcpInstructions ? { mcpInstructions: input.mcpInstructions } : {}),\n ...(input.skillsCatalog ? { skillsCatalog: input.skillsCatalog } : {}),\n ...(input.subagentDefs ? { subagentDefs: input.subagentDefs } : {}),\n wireTools: input.wireTools,\n }\n}\n\n/**\n * Lazily serialize an assembly's tool inputs into the byte-sized buckets the\n * context breakdown consumes. Deferred so the per-run snapshot stays cheap —\n * the `JSON.stringify` here only runs when `getContextBreakdown()` is called.\n *\n * MCP grouping preserves first-seen server order; native tools stay flat.\n */\nexport function materializeAssemblyTools(assembly: ContextAssembly): {\n toolsJson: string[]\n toolItems: { name: string, json: string, description?: string }[]\n deferredToolsJson: string[]\n mcpGroups: ContextMcpGroup[]\n deferredMcpGroups: ContextMcpGroup[]\n} {\n const toolsJson: string[] = []\n const toolItems: { name: string, json: string, description?: string }[] = []\n const disclosedMcp = new Map<string, { name: string, json: string, description?: string }[]>()\n for (const t of assembly.disclosedTools) {\n const json = JSON.stringify({ name: t.name, description: t.description, inputSchema: t.inputSchema })\n const description = typeof t.description === 'string' && t.description ? { description: t.description } : {}\n if (t.mcpServer !== undefined) {\n const bucket = disclosedMcp.get(t.mcpServer) ?? []\n bucket.push({ name: t.name, json, ...description })\n disclosedMcp.set(t.mcpServer, bucket)\n }\n else {\n toolsJson.push(json)\n toolItems.push({ name: t.name, json, ...description })\n }\n }\n\n const deferredToolsJson: string[] = []\n const deferredMcp = new Map<string, { name: string, json: string, description?: string }[]>()\n for (const entry of assembly.deferredEntries) {\n const json = JSON.stringify({ name: entry.name, description: entry.description, inputSchema: entry.inputSchema })\n if (entry.server !== undefined) {\n const bucket = deferredMcp.get(entry.server) ?? []\n bucket.push({ name: entry.name, json, ...(typeof entry.description === 'string' && entry.description ? { description: entry.description } : {}) })\n deferredMcp.set(entry.server, bucket)\n }\n else {\n deferredToolsJson.push(json)\n }\n }\n\n const toGroups = (m: Map<string, { name: string, json: string, description?: string }[]>): ContextMcpGroup[] =>\n [...m.entries()].map(([server, list]) => ({ server, tools: list }))\n\n return {\n toolsJson,\n toolItems,\n deferredToolsJson,\n mcpGroups: toGroups(disclosedMcp),\n deferredMcpGroups: toGroups(deferredMcp),\n }\n}\n\nconst warnedContextBreakdownContributors = new WeakSet<ContextBreakdownContributor>()\n\nexport function cloneTurnsForContextBreakdown(turns: readonly SessionTurn[]): SessionTurn[] {\n try {\n return structuredClone(turns) as SessionTurn[]\n }\n catch {\n return turns.map(turn => ({\n ...turn,\n content: turn.content.map(block =>\n block && typeof block === 'object'\n ? { ...block }\n : block,\n ) as SessionTurn['content'],\n }))\n }\n}\n\nexport function isContextExtensionSection(value: unknown): value is ContextExtensionSection {\n if (!value || typeof value !== 'object')\n return false\n const section = value as { id?: unknown, label?: unknown, accentColor?: unknown, rows?: unknown }\n return typeof section.id === 'string'\n && typeof section.label === 'string'\n && (section.accentColor === undefined || typeof section.accentColor === 'string')\n && Array.isArray(section.rows)\n && section.rows.every(row =>\n row\n && typeof row === 'object'\n && typeof (row as { label?: unknown }).label === 'string'\n && typeof (row as { value?: unknown }).value === 'string',\n )\n}\n\nexport function warnContextContributorFailureOnce(contributor: ContextBreakdownContributor, err: unknown): void {\n if (warnedContextBreakdownContributors.has(contributor))\n return\n warnedContextBreakdownContributors.add(contributor)\n if (!process.env.ZIDANE_DEBUG)\n return\n const extension = (contributor as { __zidaneExtensionName?: unknown }).__zidaneExtensionName\n const owner = typeof extension === 'string' ? ` extension=${extension}` : ''\n process.stderr.write(`[zidane/agent] context breakdown contributor failed${owner}: ${errorMessage(err)}\\n`)\n}\n\n/**\n * Last parent-run `TurnUsage` from the in-memory conversation — mirrors\n * `lastContextSizeFromTurns` (chat/store) but reads the live agent turns and\n * returns the full usage so callers can break out cache read/write/input.\n * Skips subagent (child run) turns and turns with zero effective input.\n */\nfunction lastTurnUsage(rt: AgentRuntime): TurnUsage | null {\n const { session } = rt\n const childRunIds = childRunIdSet(session)\n for (let i = rt.conversationTurns.length - 1; i >= 0; i--) {\n const turn = rt.conversationTurns[i]\n if (turn.role !== 'assistant' || !turn.usage)\n continue\n if (turn.runId && childRunIds.has(turn.runId))\n continue\n const size = effectiveInputFromTurn(turn.usage)\n if (size === 0)\n continue\n return turn.usage\n }\n return null\n}\n\nasync function extensionContextSections(rt: AgentRuntime): Promise<ContextExtensionSection[]> {\n const { contextBreakdownSections, toolResultMetadata } = rt\n if (!contextBreakdownSections?.length)\n return []\n // Cloned on first read only, then shared by every contributor of this\n // call: the clone copies the whole transcript (base64 included), and a\n // contributor that never looks at `turns` should not pay for it.\n let turns: SessionTurn[] | undefined\n const sharedTurns = () => turns ??= cloneTurnsForContextBreakdown(rt.conversationTurns)\n const out: ContextExtensionSection[] = []\n for (const contributor of contextBreakdownSections) {\n try {\n const result = await contributor({ get turns() { return sharedTurns() } })\n const sections = Array.isArray(result) ? result : result ? [result] : []\n for (const section of sections) {\n if (isContextExtensionSection(section) && section.rows.length > 0)\n out.push(section)\n }\n }\n catch (err) {\n // Context breakdown is observational; a broken extension section\n // should not make the whole panel unavailable.\n warnContextContributorFailureOnce(contributor, err)\n }\n }\n out.push(...toolResultMetadataSections(toolResultMetadata, toolResultMetadata?.length ? sharedTurns() : []))\n return out\n}\n\n/**\n * Best-effort context assembly BEFORE the first run, so the breakdown is\n * available the moment the chat screen opens (no \"send a message first\").\n *\n * Resolves skills only (it does not call `warmup()`, so no MCP server is\n * connected), then assembles the same static pieces `run()` captures — system\n * prompt (with skills catalog + MCP instructions), the wire tool specs, and\n * MCP groupings. MCP tools and instructions appear only when `mcpConnection`\n * already holds them. The disclosure subtleties don't matter pre-run (nothing\n * has been unlocked yet); we treat every native + MCP tool as disclosed,\n * matching the eager seed of a fresh run. Returns `null` after `destroy()`.\n */\nasync function buildPreRunAssembly(rt: AgentRuntime, modelOverride?: string): Promise<ContextAssembly | null> {\n const { provider, sourceTools, agentSystem, toolAliases, toolDescriptions, agentBehavior, mcpServers, toolCatalogTransforms } = rt\n if (rt.destroyed)\n return null\n // Resolve SKILLS only (local, cheap) — deliberately do NOT call `warmup()`,\n // which would connect MCP servers (spawn stdio processes, possibly trigger\n // OAuth) just to render a read-only popover. MCP tools surface in the\n // breakdown once a real run (or an explicit `warmup()`) has connected them;\n // until then we reflect whatever `mcpConnection` already holds (often null).\n try {\n await ensureSkillsResolved(rt)\n }\n catch {\n // Skills resolution failed — fall through with whatever resolved.\n }\n\n const model = modelOverride ?? provider.meta.defaultModel\n const base = agentSystem || 'You are a helpful assistant.'\n const baseSystem = renderSystemForWire(base)\n let system = base\n if (rt.skillsCatalog)\n system = appendStaticSection(system, rt.skillsCatalog)\n\n const baseTools = rt.mcpConnection ? { ...sourceTools, ...rt.mcpConnection.tools } : sourceTools\n const mcpNames = new Set(rt.mcpConnection ? Object.keys(rt.mcpConnection.tools) : [])\n const transformedTools = applyToolCatalogTransforms(baseTools, toolCatalogTransforms, 'pre-run', mcpNames)\n const sessionId = rt.session?.id ?? rt.sessionId\n const preRunTools = applyToolDescriptionOverrides(\n rt.toolsCatalog\n ? applyCatalogTools(rt.toolsCatalog, transformedTools, { phase: 'pre-run', ...(sessionId !== undefined ? { sessionId } : {}), mcpToolNames: mcpNames, mcpServers })\n : transformedTools,\n toolDescriptions,\n mcpNames,\n mcpServers,\n )\n\n // Mirror run()'s wire-name pipeline so the pre-run estimate matches what a\n // real turn sends: separator aliases + host toolAliases + the invalid-name\n // sanitizer (which keeps e.g. `mcp_SSH Ipseity_exec` as a valid wire name\n // instead of letting the provider-level drop guard discard it). Canonical\n // names still drive server attribution; only the emitted `name` is wire.\n const preRunSeparatorAliases = buildMcpToolNameSeparatorAliases(mcpNames, mcpServers, agentBehavior?.mcpToolNameSeparator ?? '_')\n const preRunBaseAliases = preRunSeparatorAliases\n ? { ...preRunSeparatorAliases, ...(toolAliases ?? {}) }\n : toolAliases\n const preRunSanitizedAliases = buildSanitizedWireAliases(mcpNames, preRunBaseAliases)\n const preRunAliases = preRunSanitizedAliases\n ? { ...(preRunBaseAliases ?? {}), ...preRunSanitizedAliases }\n : preRunBaseAliases\n const wireNameFor = (canonical: string): string => preRunAliases?.[canonical] ?? canonical\n\n // Pre-run treats every native + MCP tool as disclosed (nothing unlocked\n // yet). Native tools first, then MCP — matching the wire order below.\n const disclosedTools: DisclosedToolInput[] = []\n const nativeSpecs: ToolSpec[] = []\n const mcpSpecs: ToolSpec[] = []\n const mcpServerByIndex: string[] = []\n for (const t of Object.values(preRunTools)) {\n const canonical = t.spec.name\n const spec: ToolSpec = { name: wireNameFor(canonical), description: t.spec.description || '', inputSchema: t.spec.inputSchema }\n if (mcpNames.has(canonical)) {\n mcpSpecs.push(spec)\n // Attribution parses the CANONICAL name (`mcp_<server>_<tool>`); the\n // sanitized wire name would no longer match a configured server prefix.\n mcpServerByIndex.push(resolveMcpToolParts(canonical, mcpServers)?.server ?? 'mcp')\n }\n else {\n nativeSpecs.push(spec)\n }\n }\n for (const spec of nativeSpecs)\n disclosedTools.push({ name: spec.name, description: spec.description || '', inputSchema: spec.inputSchema })\n for (let i = 0; i < mcpSpecs.length; i++) {\n const spec = mcpSpecs[i]!\n disclosedTools.push({ name: spec.name, description: spec.description || '', inputSchema: spec.inputSchema, mcpServer: mcpServerByIndex[i]! })\n }\n\n const wireTools = (nativeSpecs.length + mcpSpecs.length) > 0\n ? provider.formatTools([...nativeSpecs, ...mcpSpecs])\n : []\n\n const mcpInstructionsText = (rt.mcpConnection?.instructions && rt.mcpConnection.instructions.size > 0)\n ? renderMcpInstructionsSection(rt.mcpConnection.instructions)\n : undefined\n if (mcpInstructionsText)\n system = appendStaticSection(system, mcpInstructionsText)\n\n return assembleContextSnapshot({\n modelId: model,\n system: renderSystemForWire(system),\n baseSystem,\n disclosedTools,\n deferredEntries: [],\n mcpInstructions: mcpInstructionsText,\n skillsCatalog: rt.skillsCatalog,\n wireTools,\n })\n}\n\nexport async function getContextSegments(\n rt: AgentRuntime,\n opts?: { rulesFiles?: readonly ContextSegmentFile[], rulesBlock?: string, systemPath?: string },\n): Promise<ContextSegment[] | null> {\n // Same destroyed-guard + snapshot-or-pre-run fallback as\n // `getContextBreakdown`, so the two views can never disagree about which\n // assembly they're describing.\n if (rt.destroyed)\n return null\n const assembly = rt.lastContextAssembly ?? await buildPreRunAssembly(rt)\n if (!assembly)\n return null\n // Host-supplied block wins: the assembly only carries one when the host\n // threaded `contextSections` into `run()`, which not every host does. Without\n // it the base-prompt segment can't subtract the instructions and would\n // double-report them — once inline, once as their own file rows.\n const rulesBlock = opts?.rulesBlock ?? assembly.rulesBlock\n return buildContextSegments({\n system: assembly.system,\n baseSystem: assembly.baseSystem,\n ...(rulesBlock ? { rulesBlock } : {}),\n // Host-supplied: the assembly's own `rulesFiles` carry paths but no text\n // (the agent never reads those files), so they'd shape into empty\n // segments that `buildContextSegments` drops. The host passes the files\n // it actually loaded, text included.\n ...(opts?.rulesFiles?.length ? { rulesFiles: opts.rulesFiles } : {}),\n // Also host-supplied, same reason: the agent receives a composed system\n // string and can't know a `SYSTEM.md` override produced it.\n ...(opts?.systemPath !== undefined ? { systemPath: opts.systemPath } : {}),\n ...(assembly.skillsCatalog ? { skillsCatalog: assembly.skillsCatalog } : {}),\n ...(assembly.mcpInstructions ? { mcpInstructions: assembly.mcpInstructions } : {}),\n ...(assembly.subagentDefs ? { subagentDefs: assembly.subagentDefs } : {}),\n })\n}\n\nexport async function getContextBreakdown(rt: AgentRuntime, opts?: ContextBreakdownOptions): Promise<ContextBreakdown | null> {\n const { provider, skillActivationState } = rt\n // Post-destroy: nothing to report, and `countTokens` would run against a\n // torn-down provider. Matches `buildPreRunAssembly`'s `destroyed` guard.\n if (rt.destroyed)\n return null\n // Use the live run snapshot when present; otherwise assemble a pre-run view\n // so the context breakdown is ready the moment the chat screen opens.\n const assembly = rt.lastContextAssembly ?? await buildPreRunAssembly(rt, opts?.model)\n if (!assembly)\n return null\n\n const usage = lastTurnUsage(rt)\n const used = effectiveInputFromTurn(usage)\n const effectiveWindow = opts?.effectiveWindow ?? used\n // When an auto-compact threshold is set, the buffer is the whole tail from\n // the threshold to the end of the window (so the bar/row show where\n // compaction fires); otherwise it's the reserved-output tokens.\n const autocompactBuffer\n = opts?.compactThreshold !== undefined && opts.compactThreshold > 0 && opts.compactThreshold < 1\n ? Math.max(0, Math.round((1 - opts.compactThreshold) * effectiveWindow))\n : opts?.autocompactBuffer ?? OUTPUT_RESERVE_TOKENS\n\n // Exact path — provider counts (system-only, system+tools). Best effort:\n // any failure leaves `exact` undefined and the heuristic fills the buckets.\n let exact: ContextExactCounts | undefined\n if (typeof provider.countTokens === 'function') {\n // Pass the provider-wire tool specs (already through `formatTools`) — the\n // count endpoint validates the real wire shape, so the internal `ToolSpec`\n // form would be rejected.\n //\n // count_tokens requires at least one message, so every probe carries a\n // constant 1-token dummy user message. Differencing cancels the dummy's\n // fixed overhead from every derived bucket:\n // system = count(sys + dummy) − count(BASELINE + dummy)\n // tools = count(sys + tools + dummy) − count(sys + dummy)\n //\n // The baseline uses a 1-char placeholder system (`BASELINE`) rather than\n // an empty string so that provider-specific system scaffolding stays\n // symmetric across the two probes — notably the Anthropic OAuth path,\n // which injects a synthetic user/assistant pair ONLY when the system is\n // non-empty. An empty baseline would skip that scaffolding and inflate the\n // system bucket; a non-empty baseline keeps it on both sides so it cancels.\n const BASELINE = '.'\n const dummy: SessionMessage[] = [{ role: 'user', content: [{ type: 'text', text: '.' }] }]\n const count = (system: string, tools: unknown[]) =>\n provider.countTokens!({ model: assembly.modelId, system, tools, messages: dummy }, opts?.signal)\n try {\n const [base, sysProbe, sysToolsProbe] = await Promise.all([\n count(BASELINE, []),\n count(assembly.system, []),\n count(assembly.system, assembly.wireTools),\n ])\n // Partial success is fine: a resolved `null` from one probe (the\n // documented \"unavailable\" return) just leaves that field off `exact`,\n // and the builder falls back to the heuristic for it. A thrown error\n // (rejection) is all-or-nothing via `Promise.all` → `catch` below.\n if (base !== null && sysProbe !== null) {\n exact = {\n system: Math.max(0, sysProbe - base),\n ...(sysToolsProbe !== null\n ? { systemAndTools: Math.max(0, sysToolsProbe - base) }\n : {}),\n }\n }\n }\n catch {\n exact = undefined\n }\n }\n\n const materializedTools = materializeAssemblyTools(assembly)\n const extensionSections = await extensionContextSections(rt)\n return buildContextBreakdown({\n modelId: assembly.modelId,\n system: assembly.system,\n baseSystem: assembly.baseSystem,\n ...(assembly.rulesBlock ? { rulesBlock: assembly.rulesBlock } : {}),\n ...(assembly.rulesFiles?.length ? { rulesFiles: assembly.rulesFiles } : {}),\n toolsJson: materializedTools.toolsJson,\n toolItems: materializedTools.toolItems,\n deferredToolsJson: materializedTools.deferredToolsJson,\n mcpGroups: materializedTools.mcpGroups,\n deferredMcpGroups: materializedTools.deferredMcpGroups,\n ...(assembly.mcpInstructions ? { mcpInstructions: assembly.mcpInstructions } : {}),\n ...(assembly.skillsCatalog ? { skillsCatalog: assembly.skillsCatalog } : {}),\n ...(assembly.subagentDefs ? { subagentDefs: assembly.subagentDefs } : {}),\n used,\n effectiveWindow,\n autocompactBuffer,\n ...(exact ? { exact } : {}),\n ...(usage\n ? {\n usage: {\n input: usage.input ?? 0,\n cacheRead: usage.cacheRead ?? 0,\n cacheCreation: usage.cacheCreation ?? 0,\n output: usage.output ?? 0,\n },\n }\n : {}),\n ...(extensionSections.length ? { extensionSections } : {}),\n ...(skillActivationState.active().length > 0\n ? { activeSkills: skillActivationState.active().map(s => s.skill.name) }\n : {}),\n })\n}\n","/**\n * Agent operations outside a run: abort / steer / follow-up queuing,\n * per-call and background-task cancellation, reset, explicit skill\n * (de)activation, session hook wiring, and destroy.\n */\n\nimport type { AgentRuntime } from './agent-runtime'\nimport { DEFAULT_DESTROY_TIMEOUT_MS } from './agent-behavior'\nimport { ensureSkillsResolved } from './agent-bootstrap'\nimport { syncRunCounter } from './agent-runtime'\nimport { RunSuspendedError } from './durable/errors'\nimport { createSession, loadSession } from './session'\nimport { resolveTimeoutMs, settleWithinTimeout, withTimeout } from './timeout'\n\nexport function abortRun(rt: AgentRuntime): void {\n if (rt.pendingRun)\n rt.pendingRun.aborted = true\n rt.abortController?.abort()\n}\n\n/**\n * `agent.suspend()`: stop the run so `Agent.resume` continues it. The model\n * stream stops at once; running tool calls may finish within `graceMs`\n * (unset: they all finish), then the run is cut off and those calls stay\n * pending (a resume reports an unsafe one interrupted). Resolves once the run\n * stopped. A resume that has not started its run yet returns without running\n * it. A replay-mode run, which continues by running its invocation again, is\n * aborted.\n */\nexport async function suspendRun(rt: AgentRuntime, options: { graceMs?: number } = {}): Promise<void> {\n const pending = rt.pendingRun\n if (!rt.running && pending) {\n pending.suspended = true\n return pending.settled\n }\n const run = rt.abortController\n if (!rt.running || !run)\n return\n const suspend = rt.suspendController\n if (!suspend) {\n run.abort()\n return waitForIdle(rt)\n }\n const reason = suspend.signal.reason instanceof RunSuspendedError ? suspend.signal.reason : new RunSuspendedError()\n if (!suspend.signal.aborted)\n suspend.abort(reason)\n const idle = waitForIdle(rt)\n const { graceMs } = options\n const timer = graceMs !== undefined && Number.isFinite(graceMs) ? setTimeout(() => run.abort(reason), Math.max(0, graceMs)) : undefined\n try {\n await idle\n }\n finally {\n clearTimeout(timer)\n }\n}\n\nexport function cancelTool(rt: AgentRuntime, callId: string, reason?: string): boolean {\n const { toolCancels } = rt\n return toolCancels.cancel(callId, reason)\n}\n\nexport async function killBackgroundTask(rt: AgentRuntime, taskId: string): Promise<boolean> {\n const { executionContext } = rt\n if (!rt.executionHandle)\n return false\n if (!executionContext.killBackground)\n return false\n const info = await executionContext.killBackground(rt.executionHandle, taskId)\n // `null` is the context's \"no such task\" return — surface as `false`\n // so the host UI can distinguish \"kill happened\" from \"id was unknown\".\n return info !== null\n}\n\nexport function steer(rt: AgentRuntime, message: string): boolean {\n const { steeringQueue } = rt\n // Refuse while idle: the queue is only drained inside a live run and is\n // cleared in `run()`'s finally — but only at the END of a run. A message\n // queued BETWEEN runs would silently survive into the next `run()` and,\n // because the batch scheduler treats a populated steering queue as\n // \"superseded by user message\", skip the entire first turn's tool calls.\n // Callers wanting to influence the next run should put the content in\n // its prompt instead.\n if (!rt.running)\n return false\n // Refuse once aborted: the loop checks `signal.aborted` before it drains\n // either queue, so a post-abort enqueue would never be delivered anyway —\n // returning false makes that explicit and stops a Stop-hook host from\n // leaking a message into a dead run.\n if (rt.abortController?.signal.aborted)\n return false\n steeringQueue.push(message)\n return true\n}\n\nexport function followUp(rt: AgentRuntime, message: string): boolean {\n const { followUpQueue } = rt\n if (rt.abortController?.signal.aborted)\n return false\n followUpQueue.push(message)\n return true\n}\n\nexport function waitForIdle(rt: AgentRuntime): Promise<void> {\n const pending = rt.pendingRun\n if (pending)\n return pending.settled.then(() => waitForIdle(rt))\n return rt.idlePromise ?? Promise.resolve()\n}\n\nexport async function reset(rt: AgentRuntime): Promise<void> {\n const { hooks, steeringQueue, nonInterruptingNudgeQueue, followUpQueue, pendingTaskNotifications, pendingStallNotifications, skillActivationState } = rt\n // Reject mid-run resets explicitly. The loop holds its own reference to\n // the in-flight `turns` array (built per-`run()`), so clearing\n // `conversationTurns` here would have left the loop's view untouched\n // and the next `turn:after` would re-link it back to the unflushed\n // buffer — silently making the call a no-op. Throwing forces callers\n // to `await agent.waitForIdle()` first so reset's invariant\n // (\"everything cleared\") actually holds.\n if (rt.running) {\n throw new Error(\n 'Cannot reset() while the agent is running. Call `agent.abort()` and `await agent.waitForIdle()` first.',\n )\n }\n rt.conversationTurns = []\n steeringQueue.length = 0\n nonInterruptingNudgeQueue.length = 0\n followUpQueue.length = 0\n // Drop the cached context-breakdown snapshot — it describes the prior\n // session's system/tools/MCP and would otherwise be served stale (the\n // `?? buildPreRunAssembly()` fallback only fires when this is null).\n rt.lastContextAssembly = null\n // The prior run's cache window, request, and overflow cutoff describe the wiped conversation.\n rt.lastRunContext = null\n rt.overflowRescue.cutoff = undefined\n // Background-task notifications are agent-scoped (they survive\n // `run()` boundaries). A `reset()` is a hard wipe — drop them too\n // so the next run starts clean.\n //\n // `notifiedTaskIds` is deliberately NOT cleared: terminated tasks\n // stay in the execution context's registry until the context is\n // destroyed, so wiping the latch here would let the next run's\n // pull-based reconcile resurrect notifications for exits the model\n // (or a prior conversation) was already told about. Running tasks\n // are unaffected — their eventual exits aren't latched yet and\n // notify normally. The latch is cleared in `destroy()`, where the\n // registry it mirrors is torn down too.\n pendingTaskNotifications.clear()\n pendingStallNotifications.clear()\n // Activation state is agent-scoped — a reset should clear it too.\n // We fire `skills:deactivate` with reason='reset' for each previously active\n // skill so consumer telemetry stays consistent. The hook is awaited so a\n // listener's rejection surfaces rather than silently breaking the invariant\n // \"reset clears activation\".\n const cleared = skillActivationState.clear()\n for (const record of cleared)\n await hooks.callHook('skills:deactivate', { skill: record.skill, reason: 'reset' })\n}\n\nexport async function activateSkill(rt: AgentRuntime, name: string): Promise<void> {\n const { hooks, skillsConfig, skillActivationState } = rt\n // Resolve the catalog on demand so hosts can `activateSkill` at any\n // point in the agent lifecycle — including before the first `run()`.\n // Idempotent and concurrency-safe (see `ensureSkillsResolved`).\n await ensureSkillsResolved(rt)\n if (!rt.resolvedSkills) {\n throw new Error(\n `Can't activate skill \"${name}\": skills are off for this agent.`,\n )\n }\n const skill = rt.resolvedSkills.find(s => s.name === name)\n if (!skill) {\n const available = rt.resolvedSkills.map(s => s.name).join(', ') || '<none>'\n throw new Error(`Unknown skill \"${name}\". Available skills: ${available}.`)\n }\n const outcome = skillActivationState.activate(skill, 'explicit')\n if (outcome === 'cap-reached') {\n throw new Error(\n `Can't activate skill \"${name}\": the maxActive limit of ${skillsConfig?.maxActive} has been reached.`,\n )\n }\n if (outcome === 'ok')\n await hooks.callHook('skills:activate', { skill, via: 'explicit' })\n}\n\nexport async function deactivateSkill(rt: AgentRuntime, name: string): Promise<void> {\n const { hooks, skillActivationState } = rt\n const removed = skillActivationState.deactivate(name)\n if (removed)\n await hooks.callHook('skills:deactivate', { skill: removed.skill, reason: 'explicit' })\n}\n\nexport async function destroy(rt: AgentRuntime): Promise<void> {\n const { executionContext, toolCancels, executionHandleInjected, pendingTaskNotifications, pendingStallNotifications, notifiedTaskIds, agentBehavior } = rt\n // Idempotent: a host may call destroy() in a `finally` block AND a\n // process-level signal handler; racing double-frees crash the MCP SDK.\n if (rt.destroyed)\n return\n rt.destroyed = true\n rt.destroyGeneration++\n\n // Teardown ordering rule: first the things that were HAPPENING\n // INSIDE the session (background tasks, in-flight tool cancels);\n // then the things the session DEPENDED ON (MCP, execution handle,\n // skills cache). Background tasks must flush their output streams\n // before the execution handle disappears underneath them.\n\n // ① INSIDE-the-session — work the session was producing.\n // Background tasks: walk the execution context's registry and let\n // the context's own `destroy(handle)` SIGTERM each task's process\n // group, flush its output stream, and clear the entry. We can't\n // walk it ourselves (the registry is private to the context) —\n // the context's destroy path handles all of this. We call it via\n // the executionHandle below; the ORDERING here just ensures we\n // don't tear down MCP first.\n //\n // The notification queue is local to this agent — drop it\n // unconditionally so a session swap that reconstructs the agent\n // doesn't replay stale notifications on the next run.\n pendingTaskNotifications.clear()\n pendingStallNotifications.clear()\n\n // Run-level abort FIRST: if destroy races a live run, flip the run's\n // own signal so the in-flight LLM stream and the loop start unwinding —\n // the per-tool cancels below only stop tool bodies, not the streaming\n // request (which listens on the run signal). No-op when idle\n // (`abortController` is undefined between runs) or already aborted.\n //\n // Do NOT `await waitForIdle()` here: destroy can be called from a hook\n // during the run. Awaiting idle from that hook would deadlock (the run is\n // waiting for the hook to return while destroy is waiting for the run).\n if (rt.abortController && !rt.abortController.signal.aborted)\n rt.abortController.abort('agent-destroyed')\n\n // Per-call cancels: flip every still-pending one as part of\n // teardown. Without this, a destroy mid-tool would leave tool\n // bodies running against an execution context the loop is about to\n // tear down — the cancel signal gives them one last chance to\n // unwind cleanly. The loop's `finally` also drops these entries,\n // but it may not have run yet if destroy races a still-awaiting\n // call. `abortAll` also drops any parked pre-registration kills.\n toolCancels.abortAll('agent-destroyed')\n\n // Each teardown await below is bounded by `destroyTimeoutMs`: hosts\n // await `destroy()` BEFORE releasing their own run gate (TUI session\n // switch), so a custom connector / sandbox whose `close()` never settles\n // would strand that gate and block session switching. A timed-out step is\n // abandoned (logged under ZIDANE_DEBUG) and teardown continues.\n const destroyTimeoutMs = resolveTimeoutMs(agentBehavior?.destroyTimeoutMs, DEFAULT_DESTROY_TIMEOUT_MS)\n\n // If destroy races with a still-pending warmup, wait for it to finish\n // before closing. Otherwise `mcpConnection` could be populated after\n // destroy() returns and leak clients past the agent's lifetime.\n if (rt.mcpWarmupPromise) {\n try {\n await withTimeout(rt.mcpWarmupPromise, { operation: 'destroy: mcp warmup', timeoutMs: destroyTimeoutMs })\n }\n catch {\n // Bootstrap failure / timeout already surfaced to the warmup caller;\n // destroy path just wants to clean up whatever partial state exists.\n }\n }\n\n // ② NEEDED-for-the-session — infra the session was sitting on.\n if (rt.mcpConnection) {\n await settleWithinTimeout('destroy: mcp close', rt.mcpConnection.close(), destroyTimeoutMs)\n rt.mcpConnection = null\n }\n if (rt.executionHandle && !executionHandleInjected) {\n // `executionContext.destroy(handle)` is what walks the context's\n // own task registry, kills survivors, flushes their streams, and\n // drops the handle. The ordering here is what makes it safe for\n // tasks to call back into the handle while we're draining.\n //\n // Skipped for a host-injected handle: the host owns that lifecycle\n // (it drove the spawn and re-attaches across invocations), so the\n // agent must not tear down a sandbox/container the host still needs.\n await settleWithinTimeout('destroy: execution destroy', executionContext.destroy(rt.executionHandle), destroyTimeoutMs)\n rt.executionHandle = null\n }\n // Defensive re-clear: the `background:exit` hook listener stays\n // registered for the agent's lifetime, so the SIGTERMs `destroy()`\n // just issued may have re-populated the queue while we were\n // awaiting `executionContext.destroy()`. Without this, the queue\n // ends up holding entries that will never drain (no more `run()`)\n // — purely cosmetic at runtime but confuses telemetry consumers\n // that snapshot agent state post-destroy.\n pendingTaskNotifications.clear()\n pendingStallNotifications.clear()\n notifiedTaskIds.clear()\n // Remove the inline-skills temp directory if one was materialized.\n // No-op when `skills.write` was unused.\n rt.skillsCleanup()\n rt.skillsCleanup = () => {}\n // Drop the cached context-breakdown snapshot so a post-destroy\n // `getContextBreakdown()` can't serve stale data (it's also `destroyed`-\n // guarded in `./agent-context` as a belt-and-suspenders).\n rt.lastContextAssembly = null\n // Last: a save made while teardown runs (a run unwinding from the abort\n // above) still fires `session:save`.\n rt.unbindSession?.()\n rt.unbindSession = null\n}\n\n/** Whether {@link ensureAgentSession} has a session to load. */\nexport function sessionToLoad(rt: AgentRuntime): boolean {\n return !rt.session && rt.sessionId !== undefined && rt.durable !== undefined\n}\n\n/**\n * Bind the session `AgentOptions.sessionId` names, once: loaded from\n * `durable.stores.session`, or created and saved there (a header row from\n * the start, so the run's incremental writes land). No-op with `session`\n * or without `sessionId`. A failed load is retried by the next call.\n */\nexport function ensureAgentSession(rt: AgentRuntime): Promise<void> {\n const { sessionId, durable } = rt\n if (rt.session || sessionId === undefined || !durable)\n return Promise.resolve()\n rt.sessionLoad ??= (async () => {\n const store = durable.stores.session\n let session = await loadSession(store, sessionId)\n if (!session) {\n session = await createSession({ store, id: sessionId })\n await session.save()\n }\n rt.session = session\n rt.conversationTurns = session.turns.slice()\n bindSessionHooks(rt)\n syncRunCounter(rt)\n })().catch((err: unknown) => {\n rt.sessionLoad = null\n throw err\n })\n return rt.sessionLoad\n}\n\n/**\n * Fire `session:save` / `session:meta` from the bound session's listeners.\n * Subscribed, not patched onto the session: a persisted subagent shares its\n * parent's session, and `destroy` unsubscribes so a finished child's hooks\n * don't stay reachable from (and fire on) every later save.\n */\nexport function bindSessionHooks(rt: AgentRuntime): void {\n const { hooks, session } = rt\n // Not refused once destroyed: a run after destroy() is supported (the agent\n // revives), and binds again here; destroy() unbinds.\n if (!session || rt.unbindSession)\n return\n const offSaved = session.onSaved(async () => {\n await hooks.callHook('session:save', { sessionId: session.id })\n })\n const offMeta = session.onMeta((key, value) => {\n // `setMeta` is synchronous and its write already happened: log a rejecting\n // listener rather than leak an unhandled rejection or throw at the caller.\n void Promise.resolve(hooks.callHook('session:meta', { sessionId: session.id, key, value })).catch((err: unknown) => {\n console.error('[zidane] session:meta listener rejected:', err)\n })\n })\n rt.unbindSession = () => {\n offSaved()\n offMeta()\n }\n}\n","/**\n * The run-record side of checkpoint runs (`zidane/durable`, checkpoint mode):\n * marking a run resumable while it is in progress, finding the run\n * `Agent.resume` continues, and where in the loop it picks up.\n */\n\nimport type { DurableRuntime, StreamPartialRecord } from './durable/types'\nimport type { ResumePoint } from './loop-context'\nimport type { Session, SessionRun, StoredRunOptions } from './session'\nimport type { AgentRunOptions, SessionContentBlock, SessionTurn } from './types'\n\n/** Finish reasons of an assistant turn after which the loop goes on without tool calls (it pushes a synthetic continue). */\nconst CONTINUED_FINISH_REASONS = new Set(['length', 'pause', 'content-filter'])\n\n/**\n * The run `Agent.resume` continues: `runId`, or the session's last top-level\n * run still marked resumable (`SessionRun.resumable`). `undefined` when\n * there is none, including a run that crashed without step checkpoints\n * (never marked).\n */\nexport function findResumableRun(session: Session, runId?: string): SessionRun | undefined {\n const run = runId !== undefined\n ? session.runs.find(r => r.id === runId)\n : session.runs.findLast(r => r.resumable === true && !r.parentRunId)\n return run?.resumable ? run : undefined\n}\n\n/** Why {@link assertResumable} refused a run (`resume:mismatch`). */\nexport interface ResumeMismatch {\n resumeTurn: number\n storedTurns: readonly number[]\n reason: string\n}\n\n/**\n * Put a resumed run back in progress (a load shows a run whose process died\n * as `aborted`) and return its prompt label, as `startSessionRun` does for a\n * fresh run.\n */\nexport function reopenSessionRun(session: Session | undefined, runId: string): string {\n const run = session?.runs.find(r => r.id === runId)\n if (!run)\n return ''\n run.status = 'running'\n delete run.endedAt\n delete run.error\n delete run.errorDetail\n return run.prompt\n}\n\n/**\n * Before a fresh top-level checkpoint run: close the tool calls an earlier\n * run left without results (`healInterruptedToolCalls`) and\n * drop the resumable mark of earlier runs, which this run supersedes, with\n * their durable records in the same write. Then mark this one. A spawned\n * child (`parentRunId`) shares a session whose parent is still running its\n * spawn call: it only marks its own run, and keeps its options for a resume\n * (`SessionRun.options`, saved with the run record). Returns whether the\n * heal changed the session's turns.\n */\nexport async function prepareCheckpointRun(session: Session, run: SessionRun | undefined, options: { root: boolean, options: AgentRunOptions }): Promise<boolean> {\n let healed = false\n if (options.root) {\n healed = await session.healInterruptedToolCalls()\n // A spawned child's mark goes too: its parent is superseded with it.\n for (const other of session.runs) {\n if (other === run || !other.resumable)\n continue\n delete other.resumable\n await session.updateRun(other, { pruneSteps: { runId: other.id } })\n }\n }\n if (run) {\n run.resumable = true\n run.options = storedRunOptions(options.options)\n }\n return healed\n}\n\n/** Caps a checkpoint run keeps (`StoredRunOptions.behavior`). */\nconst STORED_CAPS = ['maxTurns', 'maxTokens', 'maxCostUsd', 'maxTotalTokens', 'maxWallMs', 'retry', 'resumeOnMaxTokens'] as const\n\n/** What a checkpoint run keeps of `options` on its record (`SessionRun.options`): an empty object when it has none of them. */\nexport function storedRunOptions(options: AgentRunOptions): StoredRunOptions {\n const behavior: NonNullable<StoredRunOptions['behavior']> = {}\n for (const key of STORED_CAPS) {\n if (options.behavior?.[key] !== undefined)\n Object.assign(behavior, { [key]: structuredClone(options.behavior[key]) })\n }\n const stored: StoredRunOptions = {\n ...(Object.keys(behavior).length > 0 ? { behavior } : {}),\n ...(options.model !== undefined ? { model: structuredClone(options.model) } : {}),\n ...(options.thinking !== undefined ? { thinking: options.thinking } : {}),\n ...(options.modelOptions !== undefined ? { modelOptions: { ...options.modelOptions } } : {}),\n }\n return stored\n}\n\n/** The options `Agent.resume` runs `run` with: what it kept (`SessionRun.options`), under what the caller passed. */\nexport function resumedRunOptions(run: SessionRun, options: AgentRunOptions): AgentRunOptions {\n const stored = run.options\n if (!stored)\n return options\n const { behavior, ...rest } = stored\n return {\n ...structuredClone(rest),\n ...options,\n ...(behavior || options.behavior ? { behavior: { ...structuredClone(behavior), ...options.behavior } } : {}),\n }\n}\n\n/**\n * Where the resumed run `runId` picks up: the loop turn its record keeps\n * (`SessionRun.loopTurn`, the turn of its last saved turn), or the next one\n * once that turn's tool calls have saved results. A last saved assistant\n * turn whose calls have none is that turn itself (they are dispatched\n * first). A record without `loopTurn` counts the run's assistant turns\n * instead.\n *\n * `turns` is the run's seeded history, which drops an assistant turn with\n * unanswered calls: that turn is put back so the dispatch pairs with it.\n * The wall time the run spent before (`SessionRun.wallMs`) comes with it.\n */\nexport function resumePointFor(session: Session, runId: string, turns: SessionTurn[]): ResumePoint {\n const point = resumePosition(session, runId)\n const pending = point.pending\n if (pending && !turns.some(t => t.id === pending.id))\n turns.push(pending)\n const wallMs = session.runs.find(r => r.id === runId)?.wallMs\n return typeof wallMs === 'number' && wallMs > 0 ? { ...point, wallMs } : point\n}\n\nfunction resumePosition(session: Session, runId: string): ResumePoint {\n const own = session.turns.filter(t => t.runId === runId && !t.aborted)\n const last = own.at(-1)\n // The loop turn of the last saved turn, from the run record; a record\n // without it falls back to counting assistant turns.\n const stored = session.runs.find(r => r.id === runId)?.loopTurn\n const current = stored ?? own.filter(t => t.role === 'assistant').length - 1\n if (last?.role !== 'assistant')\n return { turn: last && stored !== undefined ? stored + 1 : current + 1 }\n if (!last.content.some(b => b.type === 'tool_call')) {\n return CONTINUED_FINISH_REASONS.has(last.usage?.finishReason ?? '')\n ? { turn: current + 1 }\n : { turn: current, ended: true }\n }\n return { turn: current, pending: last }\n}\n\n/**\n * Before `Agent.resume` continues `run`: the model output a process death\n * cut off (its stream partials) becomes an `aborted` assistant turn, shown\n * in the transcript and left out of the model context (`isWireTurn`); the\n * request is sent again. The turn and the deletion of the partials commit in\n * one write. Only the last streaming step's partials make the text: an\n * earlier failed attempt of the same turn streamed into a turn of its own.\n */\nexport async function joinStreamPartials(runtime: DurableRuntime, session: Session, run: SessionRun): Promise<void> {\n const scope = await runtime.openRun({ sessionId: session.id, runId: run.id, handlers: {} })\n let rows: StreamPartialRecord[]\n try {\n rows = await scope.storedPartials?.() ?? []\n }\n finally {\n await scope.close()\n }\n const last = rows.at(-1)?.stepKey\n if (last === undefined)\n return\n const own = rows.filter(r => r.stepKey === last)\n const text = own.map(r => r.text).join('')\n const thinking = own.map(r => r.thinking ?? '').join('')\n const content: SessionContentBlock[] = [\n ...(thinking ? [{ type: 'thinking' as const, text: thinking }] : []),\n ...(text ? [{ type: 'text' as const, text }] : []),\n ]\n const turns: SessionTurn[] = content.length > 0\n ? [{ id: await session.generateTurnId(), role: 'assistant', content, runId: run.id, createdAt: Date.now(), aborted: true }]\n : []\n await session.appendTurns(turns, { dropPartials: { runId: run.id } })\n}\n\n/**\n * Before `Agent.resume` continues `run`: its stored step records must be of\n * the turn its saved turns resume at, the only turn they ever cover. Any\n * other turn means the count of saved turns no longer matches the loop's\n * (an aborted turn the loop went past, a history rewrite), and the resumed\n * run would ask for other keys: a pending unsafe call would run again.\n * Then the run stops being resumable, its records go, and its dangling tool\n * calls are healed (`healInterruptedToolCalls`); the returned\n * {@link ResumeMismatch} says why.\n * `undefined`: the run can resume.\n * A spawned child (`parentRunId`) is not healed: the heal closes every\n * dangling call of the session, and its parent is resuming the spawn call\n * right now. The next fresh top-level run heals the child's calls.\n */\nexport async function assertResumable(runtime: DurableRuntime, session: Session, run: SessionRun): Promise<ResumeMismatch | undefined> {\n const scope = await runtime.openRun({ sessionId: session.id, runId: run.id, handlers: {} })\n let stored: number[]\n try {\n stored = await scope.storedTurns?.() ?? []\n }\n finally {\n await scope.close()\n }\n const { turn } = resumePosition(session, run.id)\n const unanswered = callsUnansweredBeforeLast(session, run.id)\n if (!unanswered && stored.every(t => t === turn))\n return undefined\n delete run.resumable\n await session.updateRun(run, { pruneSteps: { runId: run.id } })\n if (!run.parentRunId)\n await session.healInterruptedToolCalls()\n return {\n resumeTurn: turn,\n storedTurns: stored,\n reason: unanswered\n ? 'its saved turns leave a tool call unanswered before their last turn'\n : `it resumes at turn ${turn} but its step records are of turn ${stored.join(', ')}`,\n }\n}\n\n/**\n * Whether a saved assistant turn of the run other than its last has tool\n * calls no later turn of the run answers: the saved turns were rewritten\n * after the loop saved them (a placeholder appended, a history edit), so\n * where the loop stopped can no longer be told from them.\n */\nfunction callsUnansweredBeforeLast(session: Session, runId: string): boolean {\n const own = session.turns.filter(t => t.runId === runId && !t.aborted)\n const answered = new Set(own.flatMap(t => t.content.flatMap(b => (b.type === 'tool_result' ? [b.callId] : []))))\n return own.slice(0, -1).some(t => t.role === 'assistant' && t.content.some(b => b.type === 'tool_call' && !answered.has(b.id)))\n}\n","/**\n * The lease a checkpoint run holds on its session (`DurableLease`): claimed\n * when a top-level run starts or resumes, renewed while it runs, released\n * when it ends. Every claim bumps the session's epoch and fences its writes\n * (`src/session/run-fence.ts`): once another process claims the run, this\n * one's next write is refused and the run stops at once, with no final save.\n */\n\nimport type { AgentRuntime } from './agent-runtime'\nimport { checkpointsRuns } from './agent-durable'\nimport { RunLeaseHeldError, StaleEpochError } from './durable/errors'\nimport { LEASE_STALE_MS } from './durable/lease'\n\n/**\n * How often a run renews its lease by default\n * (`AgentRunOptions.leaseRenewMs`), well inside the time after which\n * another process may take a quiet lease over (the chat host's 5-minute\n * stale marker). Also how soon a run that lost its lease while idle in a long\n * tool call (a laptop waking from sleep) notices.\n */\nexport const LEASE_RENEW_MS = 60 * 1000\n\nexport interface RunLease {\n readonly epoch: number\n /** The refusal that ended the run's hold, once another process claimed it. */\n takenOver: () => StaleEpochError | undefined\n /** Stop renewing and give the lease up (a no-op on the store once taken over). Idempotent. */\n release: () => Promise<void>\n}\n\n/**\n * Take the lease of the run starting now, when it is a top-level checkpoint\n * run on a runtime with a lease; `undefined` otherwise (a spawned child runs\n * under its parent's claim). The claim takes over only a lease nobody holds:\n * released, not renewed for `LEASE_STALE_MS`, held by a dead process, or\n * this process's own (the chat host's `claimRun` marker). A live run of\n * another process refuses it, and the run fails before its first write. A\n * takeover aborts `controller` with the {@link StaleEpochError}. `renewMs`:\n * the renewal period, default {@link LEASE_RENEW_MS}.\n */\nexport async function claimRunLease(rt: AgentRuntime, options: { root: boolean, controller: AbortController, renewMs?: number }): Promise<RunLease | undefined> {\n const lease = rt.durable?.lease\n const session = rt.session\n if (!options.root || !lease || !session || !checkpointsRuns(rt))\n return undefined\n let stale: StaleEpochError | undefined\n const onStale = (error: StaleEpochError): void => {\n if (stale)\n return\n stale = error\n options.controller.abort(error)\n }\n const claim = await lease.claim(session.id, { staleAt: Date.now() - LEASE_STALE_MS, onStale })\n if (!claim.claimed)\n throw new RunLeaseHeldError(session.id, claim.owner)\n const { epoch } = claim\n const timer = setInterval(() => {\n void lease.renew(session.id, epoch).then((held) => {\n if (!held)\n onStale(new StaleEpochError(session.id, epoch))\n }, () => {})\n }, options.renewMs ?? LEASE_RENEW_MS)\n ;(timer as { unref?: () => void }).unref?.()\n let released: Promise<void> | undefined\n return {\n epoch,\n takenOver: () => stale,\n release: () => {\n released ??= (async () => {\n clearInterval(timer)\n await lease.release(session.id, epoch).catch(() => {})\n })()\n return released\n },\n }\n}\n","/**\n * Run persistence and finalization: incremental turn sync, the run-end\n * flush, run-end skill deactivation, and the single `finishRun` exit path.\n */\n\nimport type { Hookable } from 'hookable'\nimport type { AgentHooks } from './agent-hooks'\nimport type { RunErrorDetail } from './errors'\nimport type { RunUsageMirror } from './loop'\nimport type { Provider } from './providers'\nimport type { AppendTurnsOptions, Session, SessionRun } from './session'\nimport type { SkillActivationState } from './skills/activation'\nimport type { AgentClock, AgentStats, ChildRunStats, SessionEndStatus, SessionTurn } from './types'\nimport { SpawnDestroyedError } from './agent-bootstrap'\nimport { synthesizeMissingToolResults } from './agent-history'\nimport { AgentAbortedError } from './errors'\nimport { settleWithinTimeout } from './timeout'\n\n/**\n * This run's turn persistence: the incremental per-turn append (hook\n * handler), the one-shot run-record re-upsert, and the run-end flush with\n * orphan tool_use repair. `persistedTurnCount` is the high-water mark into\n * `turns` (see the snapshot comment at the call site).\n */\nexport function createTurnPersistence(input: {\n session: Session | undefined\n hooks: Hookable<AgentHooks>\n turns: SessionTurn[]\n runId: string\n runProvider: Provider\n clock: AgentClock\n mintTurnId: () => Promise<string>\n sessionRun: SessionRun | undefined\n hookTimeoutMs: number\n /**\n * Step records a turn commit makes obsolete (`committedSteps`), pruned in\n * the same store write as the turns. Unset or `undefined`: the run keeps\n * no step checkpoints.\n */\n committedSteps?: () => AppendTurnsOptions['pruneSteps']\n /** The run's wall time so far, kept on its record with each turn of a checkpoint run (`SessionRun.wallMs`). */\n wallElapsed?: () => number\n}): {\n persistedTurnCount: number\n persistPendingTurns: () => Promise<void>\n flushTurns: (opts?: { failureFallback?: boolean }) => Promise<void>\n /** The run-end flush of a suspended run (`Agent.suspend`): no placeholder results, and the step records it still needs stay. */\n flushSuspended: () => Promise<void>\n /** Persist and emit the turns seeded before the loop (the prompt), ahead of the first `turn:before`. */\n persistSeededTurns: () => Promise<void>\n} {\n const { session, hooks, turns, runId, runProvider, clock, mintTurnId, sessionRun, hookTimeoutMs, committedSteps, wallElapsed } = input\n const appendOptions = (pruneSteps: AppendTurnsOptions['pruneSteps'], run?: SessionRun): AppendTurnsOptions | undefined =>\n pruneSteps || run ? { ...(pruneSteps ? { pruneSteps } : {}), ...(run ? { run } : {}) } : undefined\n /**\n * A checkpoint run's record as of the turns being saved, written with them\n * (`AppendTurnsOptions.run`): its wall time so far, for a resume's budget,\n * and the loop turn they belong to, where a resume picks up.\n */\n const checkpointRecord = (loopTurn: number | undefined): SessionRun | undefined => {\n if (!sessionRun || !wallElapsed || loopTurn === undefined)\n return undefined\n sessionRun.wallMs = wallElapsed()\n sessionRun.loopTurn = loopTurn\n return { ...sessionRun }\n }\n const persistence = {\n persistedTurnCount: turns.length,\n persistPendingTurns,\n flushTurns,\n flushSuspended,\n persistSeededTurns,\n }\n\n // Incremental turn persistence — fires after both the assistant turn\n // (`turn:after`) and the tool-results user turn (`tool-results:after`),\n // so a tool_use block is always durable alongside its matching\n // tool_result. Subscribing to `turn:after` alone would leave a crash\n // window where a persisted assistant turn references tool_use IDs that\n // have no on-disk counterpart — and Anthropic rejects orphan tool_use\n // blocks on resume.\n //\n // Serialized: the hook call sites bound this with `settledHook`, which stops\n // waiting on timeout while the append keeps running. Without the queue the\n // next call would slice from the not-yet-advanced high-water mark and append\n // the same turns twice.\n let pending: Promise<void> = Promise.resolve()\n // See `reupsertRunRecordOnce`.\n let runRecordReupserted = false\n function serialized(work: () => Promise<void>): Promise<void> {\n const run = pending.then(work)\n pending = run.catch(() => {})\n return run\n }\n\n function persistPendingTurns(): Promise<void> {\n if (!session)\n return Promise.resolve()\n // Read at the call, not when the queued write runs: a write left behind by\n // a hook timeout runs while the loop is on a later turn, whose step rows\n // (an unsafe tool done or pending) must survive it.\n const end = turns.length\n const pruneSteps = committedSteps?.()\n return serialized(async () => {\n const newTurns = turns.slice(persistence.persistedTurnCount, end)\n if (newTurns.length === 0)\n return\n await session.appendTurns(newTurns, appendOptions(pruneSteps, checkpointRecord(pruneSteps?.throughTurn)))\n persistence.persistedTurnCount = end\n await reupsertRunRecordOnce()\n await hooks.callHook('session:turns', { sessionId: session.id, turns: newTurns, count: end })\n })\n }\n\n async function persistSeededTurns(): Promise<void> {\n if (!session || turns.length <= persistence.persistedTurnCount)\n return\n const seededTurns = turns.slice(persistence.persistedTurnCount)\n await session.appendTurns(seededTurns)\n persistence.persistedTurnCount = turns.length\n // A checkpoint run must be findable by `Agent.resume` before its first\n // step: on a fresh session the run-start record write had no header yet.\n if (committedSteps?.())\n await reupsertRunRecordOnce()\n await hooks.callHook('session:turns', { sessionId: session.id, turns: seededTurns, count: turns.length })\n }\n\n // One-shot follow-up to the run-start record write. For a FRESH\n // session the start write no-ops on stores that refuse unknown\n // session ids (e.g. sqlite's updateRun won't auto-create a header —\n // deletion-race safety); the first `appendTurns` above creates the\n // header, so one re-upsert here makes the `'running'` record\n // durable for run #1 too. Best-effort: crash durability must never\n // fail the turn that triggered it.\n async function reupsertRunRecordOnce(): Promise<void> {\n if (runRecordReupserted || !session || !sessionRun)\n return\n runRecordReupserted = true\n await settleWithinTimeout('session.updateRun', session.updateRun(sessionRun), hookTimeoutMs)\n .catch((err) => {\n if (process.env.ZIDANE_DEBUG)\n console.error('[zidane] session.updateRun re-upsert failed; continuing:', err)\n })\n }\n\n // Persist any turns not yet synced to the session store.\n //\n // Orphan-tool_use guard (`failureFallback: true`): when called from the\n // run-loop's catch path the trailing assistant turn may carry tool_use\n // blocks whose matching tool_result was never produced (the throw\n // happened during dispatch or before the tool-results turn was pushed).\n // Persisting it as-is leaves the DB with an unanswered tool_use that\n // Anthropic rejects on resume. We synthesize a tool_result carrying\n // `SYNTHETIC_TOOL_RESULT_PLACEHOLDER` for every dangling tool_use ID and\n // push that as the next\n // user turn before persisting — adjacency restored, resume works.\n async function flushTurns(opts: { failureFallback?: boolean } = {}): Promise<void> {\n if (!session)\n return\n // Let an in-flight incremental append land first (bounded: a hung store\n // must not strand the run-end cleanup that follows this flush).\n await settleWithinTimeout('session.appendTurns', pending, hookTimeoutMs)\n if (opts.failureFallback) {\n const turnId = await mintTurnId()\n await synthesizeMissingToolResults(turns, turnId, runId, runProvider, hooks, clock)\n }\n const end = turns.length\n const remaining = turns.slice(persistence.persistedTurnCount, end)\n // The run ends here: whatever step records it still has are obsolete.\n const pruneSteps = committedSteps?.() ? { runId } : undefined\n if (remaining.length > 0) {\n // Advance before the bounded wait so a late incremental persist cannot\n // re-append these turns if the store outlives the timeout.\n persistence.persistedTurnCount = end\n // Bounded so a hung custom session store can't strand the run-scope\n // reset that runs after this in the exit paths / finally.\n await settleWithinTimeout('session.appendTurns', session.appendTurns(remaining, appendOptions(pruneSteps)), hookTimeoutMs)\n await reupsertRunRecordOnce()\n await settleWithinTimeout('hook session:turns', hooks.callHook('session:turns', { sessionId: session.id, turns: remaining, count: end }), hookTimeoutMs)\n }\n else if (pruneSteps) {\n await settleWithinTimeout('session.appendTurns', session.appendTurns([], { pruneSteps }), hookTimeoutMs)\n }\n }\n\n async function flushSuspended(): Promise<void> {\n if (!session)\n return\n await settleWithinTimeout('session.appendTurns', pending, hookTimeoutMs)\n const end = turns.length\n const remaining = turns.slice(persistence.persistedTurnCount, end)\n if (remaining.length === 0)\n return\n persistence.persistedTurnCount = end\n // A trailing assistant turn's calls have no results yet: its turn's records are what the resume answers them from.\n const committed = committedSteps?.()\n const last = remaining.at(-1)\n const callsPending = last?.role === 'assistant' && last.content.some(b => b.type === 'tool_call')\n const through = committed?.throughTurn\n const pruneSteps = committed && callsPending\n ? (through !== undefined && through > 0 ? { runId: committed.runId, throughTurn: through - 1 } : undefined)\n : committed\n await settleWithinTimeout('session.appendTurns', session.appendTurns(remaining, appendOptions(pruneSteps, checkpointRecord(through))), hookTimeoutMs)\n await settleWithinTimeout('hook session:turns', hooks.callHook('session:turns', { sessionId: session.id, turns: remaining, count: end }), hookTimeoutMs)\n }\n\n return persistence\n}\n\n// Deactivate every active skill with `reason: 'run-end'`. Called at each\n// natural run boundary regardless of status (completed / aborted / error).\n//\n// Runs in the inner `finally`, RIGHT before `resetRunScope()` clears the\n// `running` gate — so it must neither hang nor throw, or the gate strands\n// (`agent.run()` then throws \"already running\" forever and TUI/GUI hosts\n// enqueue submits silently). Each `skills:deactivate` is bounded AND its\n// throw is caught so cleanup always reaches the reset.\nexport async function deactivateAllSkills(\n skillActivationState: SkillActivationState,\n hooks: Hookable<AgentHooks>,\n hookTimeoutMs: number,\n): Promise<void> {\n for (const record of skillActivationState.clear()) {\n try {\n await settleWithinTimeout('hook skills:deactivate', hooks.callHook('skills:deactivate', { skill: record.skill, reason: 'run-end' }), hookTimeoutMs)\n }\n catch (err) {\n if (process.env.ZIDANE_DEBUG)\n console.error('[zidane] skills:deactivate handler threw during run-end cleanup:', err)\n }\n }\n}\n\n/**\n * How a run ended, in the two dimensions the finalizer branches on: which\n * session-record call to make, and which `session:end` status to report.\n *\n * `loopStats` is always the PARENT-LOOP view (this run's own turns, no\n * children) — the session ledger is written from it so per-run records\n * stay additive with the children's own persisted runs. `finishRun` folds\n * children in for the returned/hooked `AgentStats` only.\n */\ninterface RunDispositionBase {\n loopStats: AgentStats\n /** Cost attributable to this run's own turns (session ledger). */\n parentCost: number\n}\nexport type RunDisposition\n = | (RunDispositionBase & { kind: 'completed' })\n | (RunDispositionBase & { kind: 'aborted' })\n // `Agent.suspend`: recorded as aborted, but still resumable.\n | (RunDispositionBase & { kind: 'suspended' })\n // Discriminated so `session.errorRun` can never be handed a placeholder:\n // the next exit path added here has to supply a real message.\n | (RunDispositionBase & { kind: 'error', failure: string, detail?: RunErrorDetail })\n\n/**\n * Run finalization: the loop-view stats fallback and the single exit path\n * (`finishRun`) every terminal branch goes through.\n */\nexport function createRunFinisher(input: {\n session: Session | undefined\n hooks: Hookable<AgentHooks>\n runId: string\n runTurnStart: number\n turns: SessionTurn[]\n clock: AgentClock\n hookTimeoutMs: number\n childrenStats: ChildRunStats[]\n usageMirror: RunUsageMirror\n wallStartMs: number\n}): {\n mirroredLoopStats: () => AgentStats\n finishRun: (disposition: RunDisposition) => Promise<AgentStats>\n} {\n const { session, hooks, runId, runTurnStart, turns, clock, hookTimeoutMs, childrenStats, usageMirror, wallStartMs } = input\n\n // Finalize session: persist run status and fire session:end. Each await\n // is bounded so a hung store / `session:end` handler can't block the\n // run-scope reset that follows in the exit paths.\n async function finalizeSession(status: SessionEndStatus): Promise<void> {\n if (!session)\n return\n const run = session.runs.find(r => r.id === runId)\n if (run)\n await settleWithinTimeout('session.updateRun', session.updateRun(run), hookTimeoutMs)\n await settleWithinTimeout('session.updateStatus', session.updateStatus(status === 'aborted' ? 'idle' : status), hookTimeoutMs)\n await settleWithinTimeout('hook session:end', hooks.callHook('session:end', { sessionId: session.id, runId, status, turnRange: [runTurnStart, turns.length - 1] }), hookTimeoutMs)\n }\n\n async function stampSessionRunEnd(): Promise<void> {\n const run = session?.runs.find(r => r.id === runId)\n if (run)\n run.endedAt = await clock.now()\n }\n\n /**\n * Loop-view stats synthesized from the live usage mirror.\n *\n * Used by every exit that did NOT get a clean `AgentStats` back from\n * `runLoop` (mid-stream abort, budget breach, hard failure): the mirror\n * carries the usage of every turn that completed before the throw, so the\n * persisted record and `agent:done` report real spend instead of zeros.\n * Wall time comes from `wallStartMs` (a real clock) rather than the\n * possibly-journaled `runStartedAt`, matching `runLoop`'s own accounting.\n */\n function mirroredLoopStats(): AgentStats {\n return {\n totalIn: usageMirror.totalIn,\n totalOut: usageMirror.totalOut,\n totalCacheRead: usageMirror.totalCacheRead,\n totalCacheCreation: usageMirror.totalCacheCreation,\n turns: usageMirror.turns,\n elapsed: Date.now() - wallStartMs,\n turnUsage: usageMirror.turnUsage,\n ...(usageMirror.cost > 0 ? { cost: usageMirror.cost } : {}),\n }\n }\n\n /**\n * The single exit path for a run. Every terminal branch — completed,\n * clean-break abort, mid-stream abort, budget breach, hard error — routes\n * through here so all five report identically: children folded into the\n * returned totals, session ledger written from the loop-only view, run row\n * stamped, `session:end` fired, then `agent:done` with the final stats.\n *\n * Callers that must propagate an error still `throw` after awaiting this;\n * the finalization itself is outcome-independent.\n */\n async function finishRun(disposition: RunDisposition): Promise<AgentStats> {\n const { kind, loopStats, parentCost } = disposition\n\n // Roll children's already-cumulative totals into the parent. Each\n // child's `stats.totalIn/Out/cost/totalCacheRead/totalCacheCreation`\n // was finalized through this same path before bubbling up via\n // `spawn:complete`, so a single-level sum lands grandchildren\n // transitively.\n let childrenIn = 0\n let childrenOut = 0\n let childrenCost = 0\n let childrenCacheRead = 0\n let childrenCacheCreation = 0\n for (const c of childrenStats) {\n childrenIn += c.stats.totalIn\n childrenOut += c.stats.totalOut\n childrenCost += c.stats.cost ?? 0\n childrenCacheRead += c.stats.totalCacheRead\n childrenCacheCreation += c.stats.totalCacheCreation\n }\n const cumulativeCost = parentCost + childrenCost\n\n const finalStats: AgentStats = {\n ...loopStats,\n totalIn: loopStats.totalIn + childrenIn,\n totalOut: loopStats.totalOut + childrenOut,\n totalCacheRead: loopStats.totalCacheRead + childrenCacheRead,\n totalCacheCreation: loopStats.totalCacheCreation + childrenCacheCreation,\n ...(cumulativeCost > 0 ? { cost: cumulativeCost } : {}),\n children: childrenStats.length > 0 ? childrenStats : undefined,\n ...(kind === 'suspended' ? { suspended: true } : {}),\n }\n\n // Session ledger: loop-only view. Children are persisted as their own\n // runs in the same session, so folding cumulative numbers in here would\n // double-count.\n if (session) {\n const ledger = {\n turns: loopStats.turns,\n tokensIn: loopStats.totalIn,\n tokensOut: loopStats.totalOut,\n turnUsage: loopStats.turnUsage,\n ...(parentCost > 0 ? { cost: parentCost } : {}),\n }\n // Ended for good: nothing left for `Agent.resume`. A suspended run is what it is for.\n const run = session.runs.find(r => r.id === runId)\n if (run && kind !== 'suspended')\n delete run.resumable\n if (disposition.kind === 'completed')\n session.completeRun(runId, ledger)\n else if (disposition.kind === 'aborted' || disposition.kind === 'suspended')\n session.abortRun(runId, ledger)\n else\n session.errorRun(runId, disposition.failure, ledger, disposition.detail)\n }\n\n await stampSessionRunEnd()\n await finalizeSession(kind === 'suspended' ? 'aborted' : kind)\n await settleWithinTimeout('hook agent:done', hooks.callHook('agent:done', finalStats), hookTimeoutMs)\n return finalStats\n }\n\n return { mirroredLoopStats, finishRun }\n}\n\n/**\n * True when a setup throw IS the run's own abort — the signal's reason, an\n * abort-shaped error, or `destroy()` racing the execution spawn — rather\n * than a genuine failure that merely coincided with an aborted signal.\n */\nexport function isRunAbortCause(error: unknown, signal: AbortSignal | undefined): boolean {\n if (!signal?.aborted)\n return false\n return error === signal.reason\n || error instanceof SpawnDestroyedError\n || error instanceof AgentAbortedError\n || (error as { name?: unknown } | null)?.name === 'AbortError'\n}\n\n/**\n * Close the lifecycle `agent:start` opened for a run whose SETUP its own\n * abort cut short, in the loop abort branch's order: `agent:abort`, the\n * session record (`persist`, where `finishRun` writes it), `session:end`,\n * then `agent:done` with zero stats — so the metrics `runs.active` gauge\n * decrements and the tracing root span ends.\n */\nexport async function endSetupAbortedRun(input: {\n hooks: Hookable<AgentHooks>\n session: Session | undefined\n runId: string\n signal: AbortSignal\n hookTimeoutMs: number\n startedAtMs: number\n persist: () => Promise<void>\n}): Promise<AgentStats> {\n const { hooks, session, runId, signal, hookTimeoutMs, startedAtMs, persist } = input\n const reason = signal.reason\n await settleWithinTimeout('hook agent:abort', hooks.callHook('agent:abort', {\n runId,\n ...(typeof reason === 'string' && reason.length > 0 ? { reason } : {}),\n }), hookTimeoutMs)\n await persist()\n if (session) {\n const end = session.turns.length\n await settleWithinTimeout('hook session:end', hooks.callHook('session:end', { sessionId: session.id, runId, status: 'aborted', turnRange: [end, end - 1] }), hookTimeoutMs)\n }\n const stats = zeroRunStats(startedAtMs)\n await settleWithinTimeout('hook agent:done', hooks.callHook('agent:done', stats), hookTimeoutMs)\n return stats\n}\n\n/** Stats for a run that ended before its first turn. */\nexport function zeroRunStats(startedAtMs: number): AgentStats {\n return { totalIn: 0, totalOut: 0, totalCacheRead: 0, totalCacheCreation: 0, turns: 0, elapsed: Date.now() - startedAtMs, turnUsage: [] }\n}\n","/**\n * Progressive tool disclosure: eager vs lazy partitioning, the\n * `tool_search` unlock state, the searchable catalog, and the gates that\n * enforce and rehydrate unlocks.\n */\n\nimport type { Hookable } from 'hookable'\n\nimport type { AgentHooks } from './agent-hooks'\nimport type { Session } from './session'\nimport type { LazyToolEntry } from './tools/tool-search'\nimport type { ToolDef, ToolDescriptions } from './tools/types'\nimport type { AgentBehavior, McpServerConfig, SessionTurn } from './types'\nimport { applyToolDescriptionOverrides } from './agent-extensions'\nimport { resolveServerForTool } from './agent-mcp-naming'\nimport { CALL_TOOL_NAME, createCallToolTool } from './tools/call-tool'\nimport { applyToolSearchToUnlocked, createToolSearchTool } from './tools/tool-search'\nimport { escapeXml } from './xml'\n\n// ---------------------------------------------------------------------------\n// Tool disclosure (progressive)\n// ---------------------------------------------------------------------------\n\n/**\n * Per-run progressive-disclosure state: which tools are visible now, which can\n * be surfaced later, and the bookkeeping that keeps the wire-level tool list\n * prompt-cache stable as tools unlock mid-run.\n */\ninterface RunDisclosureState {\n disclosure: DisclosureResult\n /** Live set of canonical names the model may call. Grows via `recordUnlock`. */\n unlocked: Set<string>\n /**\n * Snapshot of the eager seed — never mutated. `buildFormattedTools` walks the\n * registry filtered by this set for the cache-stable prefix (phase 1) and then\n * appends entries from {@link dynamicUnlockOrder} (phase 2). Splitting the\n * seed from the live `unlocked` set is what lets us emit dynamic unlocks at\n * the END of the wire-level tools array regardless of where they sit in\n * registry insertion order — without it, an MCP tool surfaced by\n * `tool_search` would land at its registry position and shift every\n * subsequent tool's byte offset, invalidating the provider's tool-list prefix\n * cache.\n */\n initialUnlocked: Set<string>\n /** Effective unlock order for the phase-2 tail. */\n dynamicUnlockOrder: string[]\n /**\n * Record a dynamic unlock. Idempotent on repeats; used by both the\n * `tool_search` runtime path and the resume-replay path so the log reflects\n * the EFFECTIVE unlock order regardless of source.\n */\n recordUnlock: (canonical: string) => void\n /** The run's final registry — `tools` plus an auto-injected `tool_search`. */\n tools: Record<string, ToolDef>\n /** Whether the framework injected its own `tool_search` for this run. */\n injectedToolSearch: boolean\n /** Whether the host registered their own `tool_search` (they own the unlock state machine). */\n hostDefinedToolSearch: boolean\n /**\n * `toolSearch.mode === 'dispatch'` with a live lazy catalog: surfaced tools\n * are called through the injected `call_tool` envelope and the wire tools\n * array never grows (see `src/tools/call-tool.ts`).\n */\n dispatchMode: boolean\n}\n\ninterface DisclosureStateInput {\n tools: Record<string, ToolDef>\n mcpToolNames: ReadonlySet<string>\n mcpServers: readonly McpServerConfig[] | undefined\n toolDisclosure: NonNullable<AgentBehavior['toolDisclosure']>\n toolSearch: AgentBehavior['toolSearch']\n toolAliases: Record<string, string> | undefined\n /**\n * `AgentOptions.toolDescriptions`, re-applied here to the framework-injected\n * `tool_search` / `call_tool` only — `baseTools` already carries the rest\n * (see `buildRunToolRegistry`).\n */\n toolDescriptions: ToolDescriptions | undefined\n /** `true` when `AgentRunOptions.tools` replaced the registry wholesale. */\n hasRunToolOverride: boolean\n}\n\n/**\n * Resolve the effective `toolSearch.mode`. An explicit host value always\n * wins; unset resolves to `'dispatch'` on every provider. Unlock mode's\n * tail append rewrites the whole prompt cache once per discovery wave (and\n * on Anthropic drops every replayed thinking block, which is bound to the\n * exact `tools` array), while a live eval found non-Anthropic models drive\n * the `call_tool` envelope as reliably as a directly-unlocked tool.\n */\nexport function resolveToolSearchMode(toolSearch: AgentBehavior['toolSearch']): 'unlock' | 'dispatch' {\n return toolSearch?.mode ?? 'dispatch'\n}\n\n/**\n * Partition the registry into eager vs lazy buckets and build the per-run\n * unlock bookkeeping the loop reads when rebuilding the wire-level tool list.\n *\n * Native (non-MCP) tools are always eager; `tool_search` itself must be eager\n * too (the discovery path can't gate on its own surfacing). The `unlocked` set\n * seeds with every eager canonical tool name and grows as the model surfaces\n * lazy tools through `tool_search`.\n *\n * Aliases are passed through so lazy entries carry their wire-level display\n * name — what the catalog and `tool_search` results show to the model — while\n * keeping the canonical name on the entry for unlock-set membership and\n * dispatch-map lookup.\n */\nexport function buildRunDisclosureState(input: DisclosureStateInput): RunDisclosureState {\n const { tools: baseTools, mcpToolNames, mcpServers, toolDisclosure, toolSearch, toolAliases, toolDescriptions, hasRunToolOverride } = input\n const toolSearchMode = resolveToolSearchMode(toolSearch)\n\n const disclosure = partitionToolDisclosure(baseTools, mcpToolNames, mcpServers, toolDisclosure, toolAliases)\n const unlocked = new Set<string>(disclosure.eagerCanonicalNames)\n const initialUnlocked = new Set<string>(disclosure.eagerCanonicalNames)\n const dynamicUnlockOrder: string[] = []\n // Separate membership Set keyed on names already in the dynamic log.\n // `unlocked.has()` is NOT a reliable repeat-check because callers\n // (`tool_search.execute`, `applyToolSearchToUnlocked`) write into `unlocked`\n // BEFORE calling the `addUnlock` callback, for hosts that only pass a Set\n // — using `unlocked.has()` here would short-circuit every first call and the\n // dynamic log would stay empty.\n const dynamicUnlockSeen = new Set<string>()\n const recordUnlock = (canonical: string): void => {\n if (initialUnlocked.has(canonical))\n return\n if (dynamicUnlockSeen.has(canonical))\n return\n dynamicUnlockSeen.add(canonical)\n unlocked.add(canonical)\n dynamicUnlockOrder.push(canonical)\n }\n\n const hostDefinedToolSearch = !!baseTools.tool_search\n const injectedToolSearch\n = !hasRunToolOverride\n && (toolDisclosure === 'lazy' || disclosure.lazyEntries.length > 0)\n && toolSearch?.tool !== false\n && !hostDefinedToolSearch\n\n // Dispatch mode only means something when the framework owns BOTH ends: a\n // host-defined `tool_search` owns the unlock state machine and the wire list\n // with it, a host-defined `call_tool` has its own shape the loop must not\n // rewrite (it runs as itself, in unlock mode), and without lazy entries\n // there is nothing to dispatch to.\n const dispatchMode = injectedToolSearch\n && toolSearchMode === 'dispatch'\n && disclosure.lazyEntries.length > 0\n && !baseTools[CALL_TOOL_NAME]\n\n let tools = baseTools\n if (injectedToolSearch) {\n const toolSearchTool = createToolSearchTool({\n catalog: disclosure.lazyEntries,\n unlocked,\n addUnlock: recordUnlock,\n ...(toolSearch?.limit !== undefined ? { defaultLimit: toolSearch.limit } : {}),\n ...(dispatchMode ? { dispatcherName: CALL_TOOL_NAME } : {}),\n })\n tools = { ...baseTools, [toolSearchTool.spec.name]: toolSearchTool }\n unlocked.add(toolSearchTool.spec.name)\n // `tool_search` itself is part of the cache-stable prefix — it never gets\n // unlocked dynamically and we want its position to stay fixed at the end of\n // the registry-order block, before any dynamic unlocks tail.\n initialUnlocked.add(toolSearchTool.spec.name)\n if (dispatchMode) {\n const lazyWireNames = new Set(disclosure.lazyEntries.map(entry => entry.name))\n const callTool = createCallToolTool({\n discoveryToolName: toolSearchTool.spec.name,\n isDispatchable: name => lazyWireNames.has(name),\n })\n tools = { ...tools, [CALL_TOOL_NAME]: callTool }\n unlocked.add(CALL_TOOL_NAME)\n initialUnlocked.add(CALL_TOOL_NAME)\n }\n // Only the tools injected above: `baseTools` already had overrides\n // applied, and re-running a function-form override there would\n // double-apply it.\n const injected: Record<string, ToolDef> = {}\n for (const name of Object.keys(tools)) {\n if (!baseTools[name])\n injected[name] = tools[name]!\n }\n tools = { ...tools, ...applyToolDescriptionOverrides(injected, toolDescriptions, mcpToolNames, mcpServers) }\n }\n\n return { disclosure, unlocked, initialUnlocked, dynamicUnlockOrder, recordUnlock, tools, injectedToolSearch, hostDefinedToolSearch, dispatchMode }\n}\n\n/**\n * Replay every resolved `tool_search` from a resumed history into the per-run\n * `unlocked` set.\n *\n * Without this seeding a resumed conversation shows the model \"These tools are\n * now callable\" in the prior tool_result, but the next turn's `formattedTools`\n * and the `tool:gate` hook still treat the tools as locked — every subsequent\n * `tool_use` is blocked until the model calls `tool_search` again, which\n * costs a fresh round-trip.\n *\n * Only replays calls whose result the model actually consumed: a `tool_call`\n * without a matching successful `tool_result` is either an unresolved pair\n * `filterUnresolvedToolUses` already stripped or a structural error — either\n * way, unlocking from it would be speculative.\n */\nexport function replayToolSearchUnlocks(\n seededTurns: readonly SessionTurn[],\n lazyEntries: readonly LazyToolEntry[],\n unlocked: Set<string>,\n limit: number | undefined,\n recordUnlock: (name: string) => void,\n): void {\n const resolvedCallIds = new Set<string>()\n for (const turn of seededTurns) {\n for (const block of turn.content) {\n if (block.type === 'tool_result' && !block.isError)\n resolvedCallIds.add(block.callId)\n }\n }\n for (const turn of seededTurns) {\n for (const block of turn.content) {\n if (block.type !== 'tool_call')\n continue\n if (block.name !== 'tool_search')\n continue\n if (!resolvedCallIds.has(block.id))\n continue\n applyToolSearchToUnlocked(lazyEntries, block.input, unlocked, limit, recordUnlock)\n }\n }\n}\n\nexport interface DisclosureResult {\n /** Canonical names of tools that get full schemas in every turn's wire-level tool list. */\n eagerCanonicalNames: Set<string>\n /** Canonical names of every lazy tool — kept as a `Set` for fast O(1) gate lookup. */\n lazyCanonicalNames: Set<string>\n /** Lazy entries the catalog + `tool_search` advertise to the model (wire names). */\n lazyEntries: LazyToolEntry[]\n}\n\n/**\n * Partition a tool registry into eager and lazy buckets.\n *\n * Native + skill tools always end up in the eager bucket — only MCP tools\n * are eligible for lazy disclosure. The `tool_search` tool itself, when\n * registered, must be eager (otherwise the model has no way to discover\n * anything).\n *\n * Lazy entries carry both the wire (`name`, alias-rewritten) and the\n * canonical (`canonicalName`) so:\n * - The catalog and `tool_search` results show wire names — the only names\n * the model ever sees on the provider side.\n * - The unlock set is keyed by canonical names — the loop's `ctx.tools` map\n * and the dispatch path are alias-stable.\n */\nfunction partitionToolDisclosure(\n toolsBySpecName: Record<string, ToolDef>,\n mcpToolNames: ReadonlySet<string>,\n servers: readonly McpServerConfig[] | undefined,\n globalMode: 'eager' | 'lazy',\n toolAliases: Record<string, string> | undefined,\n): DisclosureResult {\n const eagerCanonicalNames = new Set<string>()\n const lazyCanonicalNames = new Set<string>()\n const lazyEntries: LazyToolEntry[] = []\n\n function wireFor(canonical: string): string {\n const aliased = toolAliases?.[canonical]\n return typeof aliased === 'string' && aliased.length > 0 ? aliased : canonical\n }\n\n for (const [canonicalName, def] of Object.entries(toolsBySpecName)) {\n if (!mcpToolNames.has(canonicalName)) {\n eagerCanonicalNames.add(canonicalName)\n continue\n }\n const server = resolveServerForTool(canonicalName, servers)\n const mode = server?.disclosure ?? globalMode\n if (mode === 'lazy') {\n lazyCanonicalNames.add(canonicalName)\n lazyEntries.push({\n name: wireFor(canonicalName),\n canonicalName,\n description: def.spec.description || '',\n inputSchema: (def.spec.inputSchema ?? { type: 'object', properties: {} }) as Record<string, unknown>,\n ...(server ? { server: server.name } : {}),\n })\n }\n else {\n eagerCanonicalNames.add(canonicalName)\n }\n }\n\n return { eagerCanonicalNames, lazyCanonicalNames, lazyEntries }\n}\n\ninterface BuildCatalogOptions {\n /**\n * When `'tool_search'` (or another wire name), the catalog's preface tells\n * the model to call that tool. When `null`, no call-to-action is emitted —\n * useful when the host opted out of the auto-injected `tool_search` and\n * wants the catalog text to stay non-misleading.\n */\n discoveryToolName: string | null\n /**\n * Dispatch mode: surfaced tools are invoked through this envelope tool\n * instead of appearing in the tools array. The preface says so, or the\n * model would try a direct `tool_use` the provider has never heard of.\n */\n dispatcherName?: string\n /**\n * `'names'` lists tool names per server instead of every description, for\n * runs whose discovery reads the descriptions on demand (codemode's\n * `searchTools()` / `describeTool()`, or `tool_search` under\n * `toolSearch.catalog: 'names'`). Default `'full'`.\n */\n detail?: 'full' | 'names'\n /** First line of a `'names'` catalog: how to look the tools up. */\n namesNote?: string\n}\n\n/**\n * Heads a names-only catalog (`toolSearch.catalog: 'names'`): descriptions\n * are left out, so point the model at the discovery tool for them.\n *\n * @param discoveryToolName - Wire name of the discovery tool (`tool_search` or the host's alias).\n */\nexport function toolSearchCatalogNote(discoveryToolName: string): string {\n return `Tool names only. Call \\`${discoveryToolName}\\` with a topic (\\`query\\`) or exact \\`names\\` to read a tool's description before using it.`\n}\n\n/**\n * Render the `<searchable_tools>` catalog text appended to the system prompt:\n * a preface that points at the discovery tool (and the dispatcher in dispatch\n * mode), then the lazy tools grouped by server in alphabetical server order.\n * Tools with no server land after the groups. `detail: 'names'` lists names only.\n */\nexport function buildSearchableCatalog(\n entries: readonly LazyToolEntry[],\n options: BuildCatalogOptions,\n): string {\n // Group by server so the model sees a coherent \"what's available where\"\n // view. Tools without a server attribution (no configured server name\n // prefixes the tool name) land in an \"ungrouped\" bucket at the end.\n const byServer = new Map<string, LazyToolEntry[]>()\n const ungrouped: LazyToolEntry[] = []\n for (const entry of entries) {\n if (!entry.server) {\n ungrouped.push(entry)\n continue\n }\n const list = byServer.get(entry.server) ?? []\n list.push(entry)\n byServer.set(entry.server, list)\n }\n\n // Stable alphabetical group order so the catalog text doesn't shift between\n // runs based on parallel-bootstrap completion ordering. The system-prompt\n // cache breakpoint depends on byte-stability across turns/runs; without\n // this, a re-bootstrap could thrash the cache for no semantic reason.\n const serverNames = [...byServer.keys()].sort()\n\n const parts: string[] = []\n if (options.discoveryToolName) {\n // The catalog block is computed once at run start and embedded into the\n // system prompt so the system-prompt cache breakpoint stays byte-stable\n // across turns. After `tool_search` unlocks a tool, it still appears in\n // this catalog (stale by design) but its full schema is also in the\n // request's `tools` array — there's no duplicate schema definition.\n // The \"if you have not already surfaced it\" caveat keeps the model\n // from re-calling `tool_search` for tools it has already loaded.\n parts.push(\n 'The following tools are available but their input schemas are NOT loaded in your context.',\n `Call the \\`${options.discoveryToolName}\\` tool to load schemas for any tool below that you have not already surfaced. Surfaced tools persist for the rest of the run.`,\n )\n if (options.dispatcherName) {\n parts.push(\n `Surfaced tools are invoked through \\`${options.dispatcherName}\\` with \\`name\\` set to the tool name and \\`arguments\\` matching the loaded schema; they are never added to your tool list directly.`,\n )\n }\n parts.push('')\n }\n if (options.detail === 'names') {\n if (options.namesNote)\n parts.push(options.namesNote, '')\n parts.push('<searchable_tools>')\n for (const server of serverNames)\n parts.push(` <server name=\"${escapeXml(server)}\">${byServer.get(server)!.map(entry => escapeXml(entry.name)).join(', ')}</server>`)\n if (ungrouped.length > 0)\n parts.push(` <tools>${ungrouped.map(entry => escapeXml(entry.name)).join(', ')}</tools>`)\n parts.push('</searchable_tools>')\n return parts.join('\\n')\n }\n parts.push('<searchable_tools>')\n for (const server of serverNames) {\n parts.push(` <server name=\"${escapeXml(server)}\">`)\n for (const entry of byServer.get(server)!)\n parts.push(` <tool name=\"${escapeXml(entry.name)}\">${escapeXml(entry.description)}</tool>`)\n parts.push(' </server>')\n }\n for (const entry of ungrouped)\n parts.push(` <tool name=\"${escapeXml(entry.name)}\">${escapeXml(entry.description)}</tool>`)\n parts.push('</searchable_tools>')\n return parts.join('\\n')\n}\n\n/**\n * Install a `tool:gate` listener that refuses dispatch on lazy tools the\n * model hasn't surfaced via `tool_search` yet. Production providers\n * (Anthropic, OpenAI) already enforce this server-side because the model\n * can only emit `tool_use` for tools in the request's `tools` list — but\n * relying on that alone leaves custom / OSS / mock providers (and any\n * future lenient validator) able to bypass the gate by quoting a name from\n * the catalog. The middleware closes the gap so lazy disclosure is a real\n * boundary, not just an advertisement filter.\n *\n * Returns an uninstall function the run-end teardown calls so handlers\n * never leak across runs.\n */\nexport function installLazyDisclosureGate(\n hooks: Hookable<AgentHooks>,\n lazyCanonicalNames: ReadonlySet<string>,\n unlocked: ReadonlySet<string>,\n discoveryToolName: string | null,\n dispatcherName?: string,\n): () => void {\n if (lazyCanonicalNames.size === 0)\n return () => {}\n return hooks.hook('tool:gate', (ctx) => {\n if (ctx.block)\n return\n // Nested calls (`ToolContext.callTool`) come from a tool that does its own\n // discovery (codemode's `searchTools` / `describeTool`): the lock guards\n // the model's wire list, not the registry.\n if (ctx.parentToolCallId !== undefined)\n return\n if (!lazyCanonicalNames.has(ctx.name))\n return\n if (unlocked.has(ctx.name))\n return\n ctx.block = true\n const reissue = dispatcherName ? `re-issue the call through \\`${dispatcherName}\\`` : 're-issue the call'\n ctx.reason = discoveryToolName\n ? `Tool \"${ctx.name}\" is listed in <searchable_tools> but its schema has not been loaded. Call the \\`${discoveryToolName}\\` tool with names: [\"${ctx.name}\"] first, then ${reissue}.`\n : `Tool \"${ctx.name}\" is listed in <searchable_tools> but its schema has not been loaded.`\n })\n}\n\n/**\n * Lazy-tool-disclosure unlock pre-hydration, as a `tool:gate` hook. Same hazard\n * shape again: `tool_search`'s LIVE body adds matched tools to the in-memory\n * `unlocked` set, but under durable replay a `tool_search` from earlier in the\n * SAME run is replayed from the journal (its `unlocked.add` never re-runs) and\n * the run-start resume replay only covered pre-run turns. So `installLazyDisclosureGate`\n * would then see the tool as locked and refuse it — diverging from the original\n * (live) execution that ran it.\n *\n * Registered BEFORE `installLazyDisclosureGate` so its rebuild lands before the\n * block decision. When a locked lazy tool is dispatched, it replays every\n * successfully-resolved `tool_search` in the in-memory `session.turns` back\n * through `applyToolSearchToUnlocked` (idempotent), so the unlock set reflects\n * what the model was already shown.\n */\nexport function installLazyDisclosureHydrationGate(\n hooks: Hookable<AgentHooks>,\n deps: {\n enabled: boolean\n session: Session | undefined\n lazyCanonicalNames: ReadonlySet<string>\n lazyEntries: readonly LazyToolEntry[]\n unlocked: Set<string>\n recordUnlock: (canonical: string) => void\n defaultLimit: number | undefined\n },\n): () => void {\n const { enabled, session, lazyCanonicalNames, lazyEntries, unlocked, recordUnlock, defaultLimit } = deps\n if (!enabled || !session || lazyCanonicalNames.size === 0)\n return () => {}\n return hooks.hook('tool:gate', (ctx) => {\n if (ctx.block || ctx.parentToolCallId !== undefined)\n return\n if (!lazyCanonicalNames.has(ctx.name) || unlocked.has(ctx.name))\n return\n // Locked lazy tool — rebuild the unlock set from the durable transcript.\n // Only replay `tool_search` calls whose result the model actually consumed\n // (mirrors the run-start resume replay), so a stranded/errored search can't\n // speculatively unlock anything.\n const resolvedCallIds = new Set<string>()\n for (const turn of session.turns) {\n for (const block of turn.content) {\n if (block.type === 'tool_result' && !block.isError)\n resolvedCallIds.add(block.callId)\n }\n }\n for (const turn of session.turns) {\n for (const block of turn.content) {\n if (block.type !== 'tool_call' || block.name !== 'tool_search')\n continue\n if (!resolvedCallIds.has(block.id))\n continue\n applyToolSearchToUnlocked(lazyEntries, block.input, unlocked, defaultLimit, recordUnlock)\n }\n }\n })\n}\n","/**\n * `dedup-tools` middleware — generic per-tool argument deduplication on top\n * of the `tool:gate` writable-`result` / writable-`block` slots.\n *\n * Mirrors the WeakMap-keyed-on-Session pattern that backs `read_file` dedup\n * (`src/tools/read-state.ts`), generalized to arbitrary tools whose hasher\n * is supplied by the consumer via `behavior.dedupTools`.\n *\n * Two modes (see `DedupToolConfig`):\n * - `'replay'` (default) — identical re-calls replay the prior result.\n * Cheap, but doesn't break the loop — the model keeps seeing the same\n * tool_result and keeps trying.\n * - `'block-after'` — replay identical calls until their total count\n * (the first call, its replays and the current call) reaches `threshold`\n * (default 4, minimum 2), then refuse with `Blocked: <reason>` via `tool:gate`. Sticky: every\n * subsequent identical call also blocks until a different input resets\n * the counter for that tool.\n *\n * Wiring:\n * 1. `tool:gate` — compute hash, compare to prior `(name → entry)`.\n * - Hash miss: record the hash on the per-call `pending` map so\n * `tool:after` writes the entry with `repeats: 0`.\n * - Hash hit, replay mode: set `ctx.result`, bump `pending.repeats`.\n * The `result` substitute path fires `tool:after`; the handler reads\n * `pending.repeats` and persists it. The model sees the cached\n * payload again.\n * - Hash hit, block-after mode AND `count >= threshold`: set\n * `ctx.block` + `ctx.reason`, persist the bumped counter on\n * `state` directly (block path skips `tool:after`).\n * - Hash hit, block-after mode AND `count < threshold`: same as\n * replay (the cache is still warm, we just haven't crossed the\n * ceiling yet).\n * 2. `tool:after` — record `(hash, result, repeats)` for the dispatched\n * OR replayed call. Recorded post-`tool:transform`, i.e. the payload\n * the model actually saw — replaying a pre-transform value would\n * give the model different content on the dedup hit than on the\n * original call. Failure and noop verdicts are recorded with\n * `failed: true`: never replayed (a failure is a state-dependent\n * verdict, and replaying it traps the model — see `afterHandler`),\n * but still counted so `block-after` breaks identical-failure loops.\n *\n * No-session runs are silent no-ops: there's nowhere to record state.\n *\n * State scoping (`DedupToolConfig.scope`):\n * - `'session'` (default) — `(session, toolName)`. Right for pure tools.\n * - `'run'` — `(session, runId, toolName)`. Keeps a parent and its\n * subagents from sharing a dedup entry, so an identical re-call only\n * counts/replays within the run that issued it. `todowrite` uses this\n * so its `block-after` loop-breaker is run-local.\n */\n\nimport type { Hookable } from 'hookable'\nimport type { AgentHooks } from '../agent'\nimport type { Session } from '../session'\nimport type { AgentBehavior, ToolHookContext, ToolResultContent } from '../types'\nimport { getToolDedupState } from '../tools/read-state'\nimport { isReadOnlyShellCommand } from '../tools/shell-classify'\n\n/**\n * Whether a finished call may have changed the workspace. Replay caches for\n * discovery tools (`grep` / `glob` / `list_files`) describe the tree as it was,\n * so any such call invalidates them. Mutating built-ins report it via\n * `outcome`; `shell` is judged by the same read-only predicate the scheduler\n * uses (fail-closed: anything it can't classify counts as a mutation).\n */\nfunction mayHaveMutatedWorkspace(ctx: Parameters<AgentHooks['tool:after']>[0]): boolean {\n if (ctx.outcome === 'created' || ctx.outcome === 'updated' || ctx.outcome === 'edited')\n return true\n return ctx.name === 'shell' && !isReadOnlyShellCommand(ctx.input.command)\n}\n\n/**\n * Install the per-tool argument-dedup middleware on a hook bus.\n * `getDedupTools` returns the resolved per-tool hashers (run override merged\n * with agent defaults). `getSession` does the same for the session-bound\n * state. Both are called lazily so handlers attached after install (e.g. via\n * MCP bootstrap completion) can take effect.\n *\n * Returns an `uninstall` fn — the agent calls this in `finally` so handlers\n * never leak across runs.\n */\nexport function installDedupToolsGate(\n hooks: Hookable<AgentHooks>,\n getDedupTools: () => AgentBehavior['dedupTools'] | undefined,\n getSession: () => Session | undefined,\n): () => void {\n // Track the hash *we* selected per `(callId, name)` so the corresponding\n // `tool:after` records the right entry. Necessary because `ctx.input` on\n // `tool:after` could in principle differ from the gate snapshot if a\n // `tool:gate` mutation rewrote `input` — and re-hashing there would emit a\n // dedup entry against a different fingerprint than the model's input.\n //\n // Cleared in the same `tool:after` handler after recording. Entries leak\n // when `tool:after` never fires for a call this gate saw — three known\n // paths: a downstream `tool:gate` listener sets `block: true`, validation\n // rejects the (post-gate) input, or a `tool:before` handler throws. All\n // bounded by run lifetime: the closure-local map dies with the run when\n // `uninstall()` clears it (called from the agent's run-end `finally`).\n interface PendingEntry {\n hash: string\n /**\n * Number of replay-hits this call has accumulated against the prior\n * `state` entry. `0` means the gate took the fresh-dispatch path\n * (hash miss). Persisted into `state.repeats` on `tool:after`.\n */\n repeats: number\n /**\n * Resolved state-map key (`name` or `runId::name`) the gate selected.\n * Carried so `tool:after` records against the exact same slot the\n * gate read — re-deriving there would risk drift if the scope inputs\n * ever differ between the two hooks.\n */\n key: string\n }\n const pending = new Map<string, PendingEntry>()\n\n function pendingKey(callId: string, name: string): string {\n return `${callId}::${name}`\n }\n\n /**\n * Resolve the hasher-only form vs the config-object form to\n * the same internal shape. Centralised so the gate/after handlers stay\n * single-branch. Returns `null` when the tool has no dedup config.\n */\n function resolveConfig(name: string): {\n hasher: (input: Record<string, unknown>) => string | undefined\n mode: 'replay' | 'block-after'\n threshold: number\n reason: string | ((input: Record<string, unknown>, count: number) => string) | undefined\n scope: 'session' | 'run'\n } | null {\n const dedupTools = getDedupTools()\n const raw = dedupTools?.[name]\n if (!raw)\n return null\n if (typeof raw === 'function')\n return { hasher: raw, mode: 'replay', threshold: Infinity, reason: undefined, scope: 'session' }\n // Threshold floor: `Math.max(2, Math.floor(raw.threshold))`. Values\n // `<= 1` would block the very first call (or first replay), which is\n // indistinguishable from never registering the hasher at all. We\n // clamp to 2 (block on the 2nd identical call) instead of silently\n // failing closed. Non-numbers / NaN fall through to the\n // mode-conditional default. Floats are floored AFTER the clamp so\n // `threshold: 1.5` produces 2, not 1.\n const rawThreshold = typeof raw.threshold === 'number' && Number.isFinite(raw.threshold)\n ? Math.max(2, Math.floor(raw.threshold))\n : undefined\n const threshold = rawThreshold\n ?? (raw.mode === 'block-after' ? 4 : Infinity)\n return {\n hasher: raw.hasher,\n mode: raw.mode ?? 'replay',\n threshold,\n reason: raw.reason,\n scope: raw.scope === 'run' ? 'run' : 'session',\n }\n }\n\n /**\n * State-map key for a tool's dedup entry. Session-scoped tools key on\n * the bare canonical name. Run-scoped tools\n * prefix the owning `runId` so a parent and a subagent never share an\n * entry — falling back to the bare name when no `runId` is present\n * (hand-built contexts), which keeps the session-scope semantics for\n * those callers.\n */\n function stateKey(name: string, scope: 'session' | 'run', runId: string | undefined): string {\n if (scope === 'run' && runId)\n return `${runId}::${name}`\n return name\n }\n\n function formatReason(\n reason: string | ((input: Record<string, unknown>, count: number) => string) | undefined,\n toolName: string,\n input: Record<string, unknown>,\n count: number,\n ): string {\n if (typeof reason === 'string')\n return reason\n if (typeof reason === 'function') {\n try {\n const out = reason(input, count)\n if (typeof out === 'string' && out.length > 0)\n return out\n }\n catch {\n // Fall through to default\n }\n }\n return `Identical \\`${toolName}\\` call repeated ${count} times — break the loop by changing your approach or moving on to a different step.`\n }\n\n function gateHandler(ctx: ToolHookContext & {\n block: boolean\n reason: string\n result?: string | ToolResultContent[]\n runToolCounts: Readonly<Record<string, number>>\n }) {\n // Don't override prior gate handlers (block, or another middleware that\n // already substituted a result). Nested calls (`ToolContext.callTool`)\n // are read by the calling tool, which needs the real output, not a replay.\n // `afterHandler` still sees them, so a nested mutation invalidates replays.\n if (ctx.block || ctx.result !== undefined || ctx.parentToolCallId !== undefined)\n return\n\n const config = resolveConfig(ctx.name)\n if (!config)\n return\n\n const session = getSession()\n const state = getToolDedupState(session)\n if (!state)\n return\n\n let hash: string | undefined\n try {\n hash = config.hasher(ctx.input)\n }\n catch {\n // A throwing hasher disables dedup for this call only — never\n // surface it as a tool failure. The model still gets the real\n // execution, telemetry consumers see no surprise.\n return\n }\n if (typeof hash !== 'string' || hash.length === 0)\n return\n\n const key = stateKey(ctx.name, config.scope, ctx.runId)\n const prior = state.get(key)\n if (prior && prior.hash === hash) {\n // Replay-hit. `repeats` in state is the count of replays BEFORE\n // this call (0 right after a fresh dispatch). The total identical\n // calls counting this one = (prior.repeats ?? 0) + 1 + 1 = the\n // first dispatch plus all replays inclusive. We compute that as\n // `count` for both threshold checks and reason-formatting.\n const priorRepeats = prior.repeats ?? 0\n const count = priorRepeats + 2 // dispatch + earlier replays + this one\n if (config.mode === 'block-after' && count >= config.threshold) {\n // Block. The block path skips `tool:after`, so we MUST persist\n // the bumped counter here to keep subsequent identical calls\n // blocking. We do NOT overwrite `prior.result` — keeping the\n // last-seen payload (and its `failed` flag) around lets the host\n // inspect it post-hoc, and a hash change later resets the counter\n // anyway.\n ctx.block = true\n ctx.reason = formatReason(config.reason, ctx.name, ctx.input, count)\n state.set(key, { ...prior, repeats: priorRepeats + 1 })\n return\n }\n // A prior FAILED / noop verdict is state-dependent — never replay\n // it. Let the call re-execute so fresh state (a corrective read, a\n // fixed file, a recovered network) can produce a fresh verdict. The\n // bumped `pending.repeats` still flows into the recorded entry, so\n // identical failing calls keep counting toward `block-after`.\n if (prior.failed) {\n pending.set(pendingKey(ctx.callId, ctx.name), { hash, repeats: priorRepeats + 1, key })\n return\n }\n // Replay — feed the cached payload back through the `result` substitute\n // path. `tool:after` fires and records the bumped counter via\n // `pending`.\n ctx.result = prior.result\n pending.set(pendingKey(ctx.callId, ctx.name), { hash, repeats: priorRepeats + 1, key })\n return\n }\n\n // Miss — remember the hash + zero repeats so the matching\n // `tool:after` records a fresh state entry.\n pending.set(pendingKey(ctx.callId, ctx.name), { hash, repeats: 0, key })\n }\n\n /**\n * Drop every `replay`-mode entry. A replay after a workspace change would\n * serve a pre-change listing/search as current. `block-after` entries are\n * loop-breakers keyed on the input alone, so they survive.\n */\n function invalidateReplays(state: NonNullable<ReturnType<typeof getToolDedupState>>) {\n for (const key of [...state.keys()]) {\n const name = key.includes('::') ? key.slice(key.lastIndexOf('::') + 2) : key\n if (resolveConfig(name)?.mode === 'replay')\n state.delete(key)\n }\n }\n\n function afterHandler(ctx: Parameters<AgentHooks['tool:after']>[0]) {\n if (mayHaveMutatedWorkspace(ctx)) {\n const state = getToolDedupState(getSession())\n if (state)\n invalidateReplays(state)\n }\n\n const key = pendingKey(ctx.callId, ctx.name)\n const entry = pending.get(key)\n if (entry === undefined)\n return\n pending.delete(key)\n\n const session = getSession()\n const state = getToolDedupState(session)\n if (!state)\n return\n\n // Failure results are state-dependent verdicts, not stable payloads —\n // record them with `failed: true` so the gate never replays them.\n // Caching-and-replaying one turns a transient failure into a permanent\n // one: e.g. an `edit` rejected by the read-before-edit gate (\"has not\n // been read in this session\") got cached under hash(path+old_string);\n // the model then obeyed the error, read the file, and retried the SAME\n // edit — which dedup served the cached rejection for, forever, until\n // the model degraded to a full `write_file` rewrite. A failed call must\n // always re-execute so fresh state (the read, a fixed file, a\n // recovered network) can produce a fresh verdict. The entry still\n // exists (vs. not recording at all) so identical failing calls keep\n // counting toward `block-after` thresholds — the loop-breaker must\n // engage on failure loops too.\n //\n // Three signals: `isError` catches thrown/wire-level errors;\n // `outcome === 'failed'` catches built-in mutating tools (edit /\n // multi_edit / write_file) that report failure via `reportOutcome` but\n // return the refusal as plain prose with `isError: false`; and\n // `outcome === 'noop'` catches verdicts like edit's \"replacement\n // produced no change\", which share the same trap shape — the file can\n // change on disk while hash(path::old_string) stays identical.\n const failed = ctx.isError || ctx.outcome === 'failed' || ctx.outcome === 'noop'\n\n state.set(entry.key, {\n hash: entry.hash,\n result: ctx.result,\n repeats: entry.repeats,\n ...(failed ? { failed: true } : {}),\n })\n }\n\n const unregisterGate = hooks.hook('tool:gate', gateHandler)\n const unregisterAfter = hooks.hook('tool:after', afterHandler)\n\n return function uninstall() {\n unregisterGate()\n unregisterAfter()\n pending.clear()\n }\n}\n","import { resolve as pathResolve } from 'node:path'\n\nexport type Unregister = () => void\n\nexport function noopUnregister(): void {}\n\n/**\n * Clamp an optional knob to a positive integer, falling back when the value is\n * missing or non-finite. Shared by the behavior installers that accept caps\n * like `maxNudges` / `maxSuggestions`.\n */\nexport function clampPositiveInt(value: number | undefined, fallback: number): number {\n return typeof value === 'number' && Number.isFinite(value)\n ? Math.max(1, Math.floor(value))\n : fallback\n}\n\n/**\n * Resolve a `string | ((args) => string)` message knob with a built-in\n * fallback. A function that throws or returns a blank string falls through to\n * `fallback`, so a buggy host callback can never erase the steering text.\n */\nexport function resolveCustomMessage<Args>(\n custom: string | ((args: Args) => string) | undefined,\n args: Args,\n fallback: () => string,\n): string {\n if (typeof custom === 'function') {\n try {\n const out = custom(args)\n if (typeof out === 'string' && out.trim())\n return out\n }\n catch {\n // Fall through to the built-in message.\n }\n }\n if (typeof custom === 'string' && custom.trim())\n return custom\n return fallback()\n}\n\nfunction hasWildcard(pattern: string): boolean {\n return pattern.startsWith('*') || pattern.endsWith('*')\n}\n\nfunction canonicalizePath(cwd: string, path: string): string {\n return pathResolve(cwd, path)\n}\n\nfunction matchOnePath(path: string, pattern: string): boolean {\n if (pattern === path)\n return true\n if (pattern.endsWith('*'))\n return path.startsWith(pattern.slice(0, -1))\n if (pattern.startsWith('*'))\n return path.endsWith(pattern.slice(1))\n return false\n}\n\nexport function matchPathPattern(path: string, cwd: string, patterns: readonly string[] | undefined): boolean {\n if (!patterns || patterns.length === 0)\n return false\n const canonical = canonicalizePath(cwd, path)\n return patterns.some((pattern) => {\n if (matchOnePath(path, pattern) || matchOnePath(canonical, pattern))\n return true\n if (!hasWildcard(pattern))\n return canonical === canonicalizePath(cwd, pattern)\n if (pattern.endsWith('*') && !pattern.startsWith('*')) {\n const prefix = pattern.slice(0, -1)\n const separator = prefix.endsWith('/') || prefix.endsWith('\\\\') ? '/' : ''\n const canonicalPattern = `${canonicalizePath(cwd, prefix)}${separator}*`\n return matchOnePath(canonical, canonicalPattern)\n }\n return false\n })\n}\n","import type { AgentBehavior } from '../types'\nimport { resolveCustomMessage } from './shared'\n\nexport interface MaxTurnsWarningContext {\n remaining: number\n maxTurns: number\n}\n\nexport function formatMaxTurnsWarning(\n message: AgentBehavior['maxTurnsWarningMessage'],\n ctx: MaxTurnsWarningContext,\n): string {\n return resolveCustomMessage(\n message,\n ctx,\n () => `[Turn limit approaching: ${ctx.remaining} of ${ctx.maxTurns} turns remaining. Stop exploring, finish the most important concrete path, and summarize what you did and what is left.]`,\n )\n}\n","import type { Hookable } from 'hookable'\nimport type { AgentHooks } from '../agent'\nimport type { AgentBehavior, ProgressNudgeKind } from '../types'\nimport type { Unregister } from './shared'\nimport { isToolFailure } from '../tools/failure'\nimport { clampPositiveInt, noopUnregister, resolveCustomMessage } from './shared'\n\nconst DEFAULT_READ_ONLY_TURNS = 4\nconst DEFAULT_FAILED_MUTATIONS = 3\nconst DEFAULT_NOOP_MUTATIONS = 3\nconst DEFAULT_VALIDATION_REJECTS = 3\nconst DEFAULT_TOOL_ERRORS = 3\nconst DEFAULT_SINGLE_CALL_TURNS = 3\nconst DEFAULT_MAX_NUDGES = 3\n\nconst DEFAULT_READ_ONLY_TOOLS = new Set([\n 'read_file',\n 'grep',\n 'glob',\n 'list_files',\n 'web_search',\n 'fetch_url',\n 'read_chat_turns',\n 'tool_search',\n 'skills_read',\n 'todoread',\n])\n\n/**\n * Discovery chains are inherently sequential — each call's input needs the\n * prior result (`tool_search` → load → call, `skills_read` after `skills_use`)\n * and `todoread` is a singleton by nature. Their single-call turns are not\n * \"unbatched\", so they reset the streak instead of extending it.\n */\nconst SINGLE_CALL_EXEMPT_TOOLS = new Set(['tool_search', 'skills_read', 'todoread'])\n\nfunction threshold(value: number | false | undefined, fallback: number): number | false {\n if (value === false)\n return false\n return clampPositiveInt(value, fallback)\n}\n\nfunction defaultMessage(kind: ProgressNudgeKind): string {\n switch (kind) {\n case 'readOnlyTurns':\n return 'You have spent several turns gathering context without changing approach. Use the information already collected to take the smallest concrete next step, or summarize the blocker clearly.'\n case 'failedMutations':\n return 'Several edit/write attempts failed without changing files. Stop retrying the same shape: re-read the target context, choose a smaller change, then apply one focused edit.'\n case 'noopMutations':\n return 'Several mutation calls produced no file changes. Check whether the requested state is already reached; if so, report that instead of issuing more edits.'\n case 'validationRejects':\n return 'Several tool calls had invalid arguments. Re-check the advertised tool schema and emit one well-formed native tool call.'\n case 'toolErrors':\n return 'Several tool calls errored. Pivot from repeating the failing call: inspect the error, adjust the input or approach, then continue with one concrete action.'\n case 'singleCallTurns':\n return 'You are issuing one tool call per response. Independent read-only calls (file reads, searches, listings) have no dependencies between them — batch all of them into a single response instead of one per turn. Only sequence calls whose inputs depend on a previous result.'\n }\n}\n\nfunction messageFor(\n config: Exclude<AgentBehavior['progressNudges'], false | undefined>,\n kind: ProgressNudgeKind,\n count: number,\n): string {\n return resolveCustomMessage(config.messages?.[kind], { kind, count }, () => defaultMessage(kind))\n}\n\nexport function installProgressNudges(\n hooks: Hookable<AgentHooks>,\n config: AgentBehavior['progressNudges'],\n deps: { enqueueNudge: (message: string) => void },\n): Unregister {\n if (!config || (config.mode ?? 'steer') !== 'steer')\n return noopUnregister\n const resolvedConfig = config\n\n const maxNudges = clampPositiveInt(resolvedConfig.maxNudges, DEFAULT_MAX_NUDGES)\n const readOnlyTurns = threshold(resolvedConfig.readOnlyTurns, DEFAULT_READ_ONLY_TURNS)\n const failedMutations = threshold(resolvedConfig.failedMutations, DEFAULT_FAILED_MUTATIONS)\n const noopMutations = threshold(resolvedConfig.noopMutations, DEFAULT_NOOP_MUTATIONS)\n const validationRejects = threshold(resolvedConfig.validationRejects, DEFAULT_VALIDATION_REJECTS)\n const toolErrors = threshold(resolvedConfig.toolErrors, DEFAULT_TOOL_ERRORS)\n // Off by default: only fires when the host opts in with a number.\n const singleCallTurns = resolvedConfig.singleCallTurns === undefined ? false : threshold(resolvedConfig.singleCallTurns, DEFAULT_SINGLE_CALL_TURNS)\n const readOnlyTools = new Set([...(resolvedConfig.readOnlyTools ?? DEFAULT_READ_ONLY_TOOLS)])\n\n let nudgeCount = 0\n const fired = new Set<ProgressNudgeKind>()\n let consecutiveReadOnlyTurns = 0\n let consecutiveSingleCallTurns = 0\n let consecutiveFailedMutations = 0\n let consecutiveNoopMutations = 0\n let validationRejectCount = 0\n let toolErrorCount = 0\n // `tool:error` fires immediately before this call's `tool:after`; tracking\n // the errored call ids lets `tool:after` reset the consecutive error counter\n // only for calls that actually executed cleanly (concurrency-safe).\n const erroredCallIds = new Set<string>()\n\n function maybeNudge(kind: ProgressNudgeKind, count: number, at: number | false): void {\n if (at === false || count < at || nudgeCount >= maxNudges || fired.has(kind))\n return\n fired.add(kind)\n nudgeCount++\n deps.enqueueNudge(messageFor(resolvedConfig, kind, count))\n }\n\n // Nested calls (`ToolContext.callTool`) are not the model's own attempts:\n // their failures surface through the calling tool's result.\n const unhooks = [\n hooks.hook('tool:after', (ctx) => {\n if (ctx.parentToolCallId !== undefined)\n return\n // Any `tool:after` means a call cleared validation, so a run of invalid\n // arguments is broken. A call that did not error also breaks a run of\n // tool errors; the errored-id set distinguishes the error's own\n // `tool:after` (which must not reset the counter).\n validationRejectCount = 0\n if (erroredCallIds.delete(ctx.callId))\n return\n toolErrorCount = 0\n\n // `ToolOutcome` only contains mutation outcomes, so a present value is\n // always a mutation result; read-only tools report none.\n if (ctx.outcome === undefined)\n return\n if (ctx.outcome === 'failed') {\n consecutiveFailedMutations++\n maybeNudge('failedMutations', consecutiveFailedMutations, failedMutations)\n return\n }\n consecutiveFailedMutations = 0\n\n if (ctx.outcome === 'noop') {\n consecutiveNoopMutations++\n maybeNudge('noopMutations', consecutiveNoopMutations, noopMutations)\n return\n }\n consecutiveNoopMutations = 0\n }),\n hooks.hook('validation:reject', (ctx) => {\n if (ctx.parentToolCallId !== undefined)\n return\n validationRejectCount++\n maybeNudge('validationRejects', validationRejectCount, validationRejects)\n }),\n hooks.hook('tool:error', (ctx) => {\n // A `ToolFailure` is an expected failure the model reads (\"Edit error: …\"):\n // `tool:after` counts it like any result, mutation outcome included.\n if (ctx.parentToolCallId !== undefined || isToolFailure(ctx.error))\n return\n erroredCallIds.add(ctx.callId)\n toolErrorCount++\n maybeNudge('toolErrors', toolErrorCount, toolErrors)\n }),\n hooks.hook('turn:after', (ctx) => {\n const entries = Object.entries(ctx.toolCounts.turn).filter(([, count]) => count > 0)\n if (entries.length === 0) {\n // A tool-less (text/thinking-only) turn breaks the consecutive streak.\n consecutiveSingleCallTurns = 0\n return\n }\n const readOnly = entries.every(([tool]) => readOnlyTools.has(tool))\n const totalCalls = entries.reduce((sum, [, count]) => sum + count, 0)\n // A single read-only call per turn is the unbatched pattern; a turn with\n // 2+ calls (or any mutation, which legitimately sequences) breaks the\n // run, as do inherently-sequential discovery tools.\n if (readOnly && totalCalls === 1 && !SINGLE_CALL_EXEMPT_TOOLS.has(entries[0]![0])) {\n consecutiveSingleCallTurns++\n maybeNudge('singleCallTurns', consecutiveSingleCallTurns, singleCallTurns)\n }\n else {\n consecutiveSingleCallTurns = 0\n }\n if (!readOnly) {\n consecutiveReadOnlyTurns = 0\n return\n }\n consecutiveReadOnlyTurns++\n maybeNudge('readOnlyTurns', consecutiveReadOnlyTurns, readOnlyTurns)\n }),\n ]\n\n return () => {\n for (const unhook of unhooks)\n unhook()\n }\n}\n","/**\n * Caps on the one-line notes some tools append to their results (shell nudges,\n * codemode's direct-call note) count the notes the conversation already holds\n * instead of keeping counters in memory. The cap then holds across agent\n * rebuilds, and replays identically under durable execution, where hooks run\n * again over the journaled turns.\n */\n\nimport type { SessionTurn } from '../types'\nimport { toolResultToText } from '../types'\n\ninterface NoteScan {\n /** Turns scanned so far, and the first one's id: a shorter array or a new first turn means a rewrite (compaction). */\n scanned: number\n firstId: string | undefined\n /** Calls to the watched tools whose result has not been scanned yet. */\n pending: Set<string>\n count: number\n}\n\nconst SCANS = new WeakMap<readonly SessionTurn[], Map<string, NoteScan>>()\n\n/**\n * How many results of calls named in `toolNames` carry a note, per `hasNote`.\n * Memoized per turns array and `key`: a call scans only the turns added since\n * the previous one, and starts over when the array was rewritten.\n *\n * @param turns - The conversation the model sees (`AgentRuntime.conversationTurns`).\n * @param key - Names the note being counted, for the memo.\n * @param toolNames - Names those calls can carry in the transcript: canonical and wire.\n * @param hasNote - Whether a result's text carries the note.\n */\nexport function countNotedResults(\n turns: readonly SessionTurn[],\n key: string,\n toolNames: ReadonlySet<string>,\n hasNote: (text: string) => boolean,\n): number {\n let scans = SCANS.get(turns)\n if (!scans) {\n scans = new Map()\n SCANS.set(turns, scans)\n }\n let scan = scans.get(key)\n if (!scan || turns.length < scan.scanned || turns[0]?.id !== scan.firstId) {\n scan = { scanned: 0, firstId: turns[0]?.id, pending: new Set(), count: 0 }\n scans.set(key, scan)\n }\n for (let i = scan.scanned; i < turns.length; i++) {\n for (const block of turns[i]!.content) {\n if (block.type === 'tool_call' && toolNames.has(block.name))\n scan.pending.add(block.id)\n else if (block.type === 'tool_result' && scan.pending.delete(block.callId) && hasNote(toolResultToText(block.output)))\n scan.count++\n }\n }\n scan.scanned = turns.length\n return scan.count\n}\n","/**\n * `behavior.shellToolNudges` — when a `shell` call does work a dedicated tool\n * covers, append one factual line naming that tool to the result.\n *\n * Reactive instead of system-prompted: the line appears only when the model\n * actually reaches for shell, until the conversation holds `maxPerKind` of\n * that kind (`countNotedResults`), so it costs nothing until the habit shows up\n * and fades once seen.\n * Appended in `tool:transform`, i.e. to brand-new transcript tail, so it never\n * rewrites cached prompt bytes.\n */\n\nimport type { Hookable } from 'hookable'\nimport type { AgentHooks } from '../agent'\nimport type { AliasMaps } from '../aliasing'\nimport type { AgentBehavior, SessionTurn } from '../types'\nimport type { Unregister } from './shared'\nimport { toWireName } from '../aliasing'\nimport { classifyShellCommand } from '../tools/shell-classify'\nimport { clampPositiveInt, noopUnregister } from './shared'\nimport { countNotedResults } from './transcript-notes'\n\nexport type ShellNudgeKind = 'read' | 'search' | 'edit'\n\nconst DEFAULT_MAX_PER_KIND = 2\n\n/**\n * The nudge a command earns: reads, searches and scripted edits have a\n * dedicated tool. A build or test chained in never earns one.\n */\nexport function shellNudgeKind(command: string): ShellNudgeKind | null {\n const kind = classifyShellCommand(command)\n return kind === 'read' || kind === 'search' || kind === 'edit' ? kind : null\n}\n\nfunction nudgeText(kind: ShellNudgeKind, aliasMaps: AliasMaps): string {\n const name = (canonical: string) => `\\`${toWireName(canonical, aliasMaps)}\\``\n switch (kind) {\n case 'read':\n return `(note: ${name('read_file')} reads files and line ranges directly, several per call via \\`paths\\`; a negative \\`offset\\` reads from the end.)`\n case 'search':\n return `(note: ${name('grep')} runs these searches directly: several \\`patterns\\` or \\`paths\\` per call, context lines, \\`exclude\\` for noise, \\`head_limit\\` to cap.)`\n case 'edit':\n return `(note: ${name('edit')} / ${name('multi_edit')} apply exact replacements with per-hunk results and are tracked as file edits; scripted edits are not.)`\n }\n}\n\nconst TOOLS_FOR_KIND: Record<ShellNudgeKind, string[]> = {\n read: ['read_file'],\n search: ['grep'],\n edit: ['edit', 'multi_edit'],\n}\n\nexport function installShellToolNudges(\n hooks: Hookable<AgentHooks>,\n config: AgentBehavior['shellToolNudges'],\n deps: {\n /** The conversation the model sees: nudges already in it count toward `maxPerKind`. */\n getTurns: () => readonly SessionTurn[]\n advertisedToolNames: () => string[]\n aliasMaps: AliasMaps\n },\n): Unregister {\n if (!config)\n return noopUnregister\n const maxPerKind = clampPositiveInt(typeof config === 'object' ? config.maxPerKind : undefined, DEFAULT_MAX_PER_KIND)\n const shellNames: ReadonlySet<string> = new Set(['shell', toWireName('shell', deps.aliasMaps)])\n\n return hooks.hook('tool:transform', (ctx) => {\n // Nested calls: the calling tool parses this output, a nudge would corrupt it.\n if (ctx.name !== 'shell' || ctx.isError || typeof ctx.result !== 'string' || ctx.parentToolCallId !== undefined)\n return\n const command = ctx.input.command\n if (typeof command !== 'string')\n return\n const kind = shellNudgeKind(command)\n if (!kind)\n return\n const advertised = new Set(deps.advertisedToolNames())\n if (!TOOLS_FOR_KIND[kind].some(canonical => advertised.has(toWireName(canonical, deps.aliasMaps))))\n return\n const nudge = nudgeText(kind, deps.aliasMaps)\n // Counted from earlier turns: calls in one batch all see the same count.\n if (countNotedResults(deps.getTurns(), `shell-nudge:${kind}`, shellNames, text => text.includes(nudge)) >= maxPerKind)\n return\n ctx.result = `${ctx.result}\\n${nudge}`\n })\n}\n","import type { Hookable } from 'hookable'\nimport type { AgentHooks } from '../agent'\nimport type { AgentBehavior } from '../types'\nimport type { Unregister } from './shared'\nimport { noopUnregister } from './shared'\n\n// The literal markers (XML/Liquid tags, fenced-block hints, JSON keys) are all\n// lowercase, so no `/i` flag — keeping the generic call clause anchored to an\n// uppercase initial avoids matching ordinary prose like `read_file(path='a')`.\nconst TOOL_CALL_TEXT_RE = /<tool_call\\b|<\\/tool_call>|<\\|tool_call_(?:start|end)\\|>|```(?:json|tool|function_call)|\\{\\s*\"(?:name|tool|tool_name|function|arguments)\"\\s*:|\\b[A-Z]\\w*\\s*\\([^)]*=/\n\nexport function installTextToolCallRescue(\n hooks: Hookable<AgentHooks>,\n config: AgentBehavior['textToolCallRescue'],\n deps: { enqueueSteer: (message: string) => void },\n): Unregister {\n if (!config || config.mode !== 'steer')\n return noopUnregister\n let sent = false\n return hooks.hook('turn:after', (ctx) => {\n if (sent)\n return\n const hasToolCall = ctx.message.content.some(block => block.type === 'tool_call')\n if (hasToolCall)\n return\n const text = ctx.message.content.map((block) => {\n if (block.type === 'text' || block.type === 'thinking')\n return block.text\n return ''\n }).join('\\n')\n if (!TOOL_CALL_TEXT_RE.test(text))\n return\n sent = true\n deps.enqueueSteer('I saw a tool call written as text/markup. Re-emit it using the native tool-call interface with one of the advertised tool names; do not wrap it in markdown, XML, JSON, or Liquid-style markers.')\n })\n}\n","import type { Hookable } from 'hookable'\nimport type { AgentHooks } from '../agent'\nimport type { AgentBehavior } from '../types'\nimport type { Unregister } from './shared'\nimport { estimateTokens } from '../compact/utils'\nimport { noopUnregister } from './shared'\n\nexport function installThinkingOverrunPolicy(\n hooks: Hookable<AgentHooks>,\n policy: AgentBehavior['thinkingOverrunPolicy'],\n deps: { baseBudget?: number, enqueueNudge: (message: string) => void },\n): Unregister {\n const mode = typeof policy === 'string' ? policy : policy?.mode\n if (!mode || mode === 'off')\n return noopUnregister\n const threshold = typeof policy === 'object' ? policy.thresholdTokens ?? deps.baseBudget : deps.baseBudget\n if (!threshold || threshold <= 0)\n return noopUnregister\n const message = typeof policy === 'object' && policy.message\n ? policy.message\n : 'Thinking budget is exhausted. Stop deliberating and take the smallest concrete next action now.'\n let fired = false\n return hooks.hook('stream:thinking', (ctx) => {\n if (fired)\n return\n if (estimateTokens(ctx.thinking) >= threshold) {\n fired = true\n deps.enqueueNudge(message)\n }\n })\n}\n","/**\n * `tool-budgets` middleware — per-tool soft call caps on top of the\n * `tool:gate` writable-`block`/`result` slots and the run-cumulative\n * `runToolCounts`.\n *\n * Two modes:\n *\n * - `'block'` — refuse the over-budget call via `ctx.block = true`. The model\n * sees a `Blocked: <message>` tool result.\n * - `'steer'` — let the call run, but enqueue a synthetic user message for\n * the NEXT turn so the model sees the budget warning before deciding to\n * call again. Rides the loop's non-interrupting nudge queue, NOT the user\n * `steeringQueue` — the batch schedulers skip remaining sibling tool calls\n * when the steering queue is non-empty, and a budget nudge must never kill\n * the over-budget call's siblings.\n *\n * `hardMax` adds a hard ceiling to steer mode: steer-mode approvals keep\n * counting past `max`, and once the count reaches `hardMax` the gate\n * force-blocks — the escape hatch for models that ignore the nudge and\n * keep calling the tool until an external cap kills the run.\n *\n * Either mode fires `tool-budget:exceeded` so observability layers can react.\n */\n\nimport type { Hookable } from 'hookable'\nimport type { AgentHooks } from '../agent'\nimport type { AgentBehavior, ToolHookContext, ToolResultContent } from '../types'\n\n/**\n * Install the per-tool soft-budget middleware on a hook bus.\n * `getToolBudgets` returns the resolved per-tool budgets (run override merged\n * with agent defaults). `enqueueSteer` pushes a synthetic user message into\n * the run's non-interrupting nudge queue so the loop drains it at the next\n * turn boundary (without superseding in-flight sibling tool calls).\n *\n * The middleware maintains its OWN approval counter (`approvedCounts`),\n * incremented at gate-time — independent of the loop's `runToolCounts`,\n * which is incremented after gate completes. This gives atomic per-call\n * reservation in parallel batches: when a batch of N calls all fire\n * `tool:gate` before any increments propagate, each gate handler still\n * sees the prior approvals and refuses past `max`.\n *\n * Returns an `uninstall` fn.\n */\nexport function installToolBudgetsGate(\n hooks: Hookable<AgentHooks>,\n getToolBudgets: () => AgentBehavior['toolBudgets'] | undefined,\n enqueueSteer: (message: string) => void,\n): () => void {\n // Per-run set of tools that have ALREADY had a steer fired. Without this,\n // every call past `max` queues another nudge and the conversation drowns\n // in identical reminders. Cleared on uninstall (run-end).\n const steeredOnce = new Set<string>()\n\n // Per-tool approval counter the middleware owns. Incremented synchronously\n // when a call passes gate, so within-batch ordering is preserved even when\n // the loop's `runToolCounts` lags (handlers across a parallel batch can\n // fire before any of the batch's calls have been incremented loop-side).\n const approvedCounts: Record<string, number> = {}\n\n async function gateHandler(ctx: ToolHookContext & {\n block: boolean\n reason: string\n result?: string | ToolResultContent[]\n runToolCounts: Readonly<Record<string, number>>\n }) {\n // Don't override prior gate handlers.\n if (ctx.block || ctx.result !== undefined)\n return\n\n const toolBudgets = getToolBudgets()\n const budget = toolBudgets?.[ctx.name]\n if (!budget)\n return\n\n const max = budget.max\n if (typeof max !== 'number' || max <= 0)\n return\n\n // Read our internal approval counter — independent of the loop's\n // `runToolCounts` so within-batch ordering is correct even in parallel\n // mode. Each gate that approves a call increments this synchronously.\n const count = approvedCounts[ctx.name] ?? 0\n if (count < max) {\n // Approve atomically: bump the counter now, before yielding to the\n // next handler in the chain. Subsequent calls in the same parallel\n // batch see this approval and may refuse if the budget is depleted.\n approvedCounts[ctx.name] = count + 1\n return\n }\n\n // Resolve mode + message. Function form runs untrusted consumer code —\n // a throw would crash the hook bus, so we fall back to the default\n // 'steer' shape on error rather than poisoning the run.\n const onExceed = budget.onExceed ?? 'steer'\n let mode: 'steer' | 'block'\n let message: string\n if (typeof onExceed === 'function') {\n try {\n const out = onExceed({ tool: ctx.name, count, max })\n mode = out.mode\n message = out.message\n }\n catch {\n mode = 'steer'\n message = defaultSteerMessage(ctx.name, count, max)\n }\n }\n else if (onExceed === 'block') {\n mode = 'block'\n message = defaultBlockMessage(ctx.name, max)\n }\n else {\n mode = 'steer'\n message = defaultSteerMessage(ctx.name, count, max)\n }\n\n // Hard ceiling for steer mode: steer is advisory and models can ignore\n // the nudge indefinitely (the call keeps executing). Past `hardMax`,\n // force-block regardless of how the mode resolved above. Counts keep\n // semantics: `count` is approved (executed) calls so far, so steer-mode\n // approvals march it from `max` toward `hardMax`.\n const hardMax = budget.hardMax\n if (\n mode === 'steer'\n && typeof hardMax === 'number' && Number.isFinite(hardMax) && hardMax > 0\n && count >= hardMax\n ) {\n mode = 'block'\n message = defaultHardBlockMessage(ctx.name, count, hardMax)\n }\n else if (mode === 'steer') {\n // Steer lets the call run — it still counts as an approval so the\n // hard ceiling (and `runToolCounts`) keep advancing.\n approvedCounts[ctx.name] = count + 1\n }\n\n if (mode === 'block') {\n ctx.block = true\n ctx.reason = message\n await hooks.callHook('tool-budget:exceeded', {\n tool: ctx.name,\n count,\n max,\n turnId: ctx.turnId,\n mode: 'block',\n })\n return\n }\n\n // Steer mode — let the call go through, but queue a single nudge per\n // tool so the model sees the budget warning before its next turn.\n if (!steeredOnce.has(ctx.name)) {\n steeredOnce.add(ctx.name)\n enqueueSteer(message)\n await hooks.callHook('tool-budget:exceeded', {\n tool: ctx.name,\n count,\n max,\n turnId: ctx.turnId,\n mode: 'steer',\n })\n }\n }\n\n const unregister = hooks.hook('tool:gate', gateHandler)\n\n return function uninstall() {\n unregister()\n steeredOnce.clear()\n }\n}\n\nfunction defaultSteerMessage(tool: string, count: number, max: number): string {\n return `[Tool budget reached: '${tool}' has been called ${count} times this run (cap: ${max}). Avoid calling it again unless strictly necessary; commit to a result and move on.]`\n}\n\nfunction defaultBlockMessage(tool: string, max: number): string {\n return `Tool '${tool}' has reached its per-run budget of ${max} calls; further invocations are refused.`\n}\n\nfunction defaultHardBlockMessage(tool: string, count: number, hardMax: number): string {\n return `Tool '${tool}' has been called ${count} times this run, past its hard ceiling of ${hardMax} — `\n + `the earlier budget warning was not heeded. Further invocations are refused; `\n + `finish the task with the information you already have.`\n}\n","import type { Hookable } from 'hookable'\nimport type { AgentHooks } from '../agent'\nimport type { AgentBehavior } from '../types'\nimport type { Unregister } from './shared'\nimport { clampPositiveInt, noopUnregister, resolveCustomMessage } from './shared'\n\nconst DEFAULT_MAX_SUGGESTIONS = 3\nconst DEFAULT_MAX_NUDGES = 2\n\nfunction editDistance(a: string, b: string): number {\n const aa = a.toLowerCase()\n const bb = b.toLowerCase()\n const prev = Array.from({ length: bb.length + 1 }, (_, i) => i)\n const curr = Array.from({ length: bb.length + 1 }).fill(0) as number[]\n for (let i = 1; i <= aa.length; i++) {\n curr[0] = i\n for (let j = 1; j <= bb.length; j++) {\n const cost = aa.charCodeAt(i - 1) === bb.charCodeAt(j - 1) ? 0 : 1\n curr[j] = Math.min(\n prev[j] + 1,\n curr[j - 1] + 1,\n prev[j - 1] + cost,\n )\n }\n for (let j = 0; j <= bb.length; j++)\n prev[j] = curr[j]\n }\n return prev[bb.length]\n}\n\nfunction scoreSuggestion(input: string, candidate: string): number {\n const a = input.toLowerCase()\n const b = candidate.toLowerCase()\n const dist = editDistance(a, b)\n const maxLen = Math.max(a.length, b.length, 1)\n let score = dist / maxLen\n if (a && b.includes(a))\n score -= 0.35\n if (a[0] && a[0] === b[0])\n score -= 0.1\n return score\n}\n\nfunction suggestionsFor(input: string, tools: readonly string[], maxSuggestions: number): string[] {\n const unique = [...new Set(tools)].filter(Boolean)\n return unique\n .map(name => ({ name, score: scoreSuggestion(input, name) }))\n .sort((a, b) => a.score - b.score || a.name.localeCompare(b.name))\n .slice(0, maxSuggestions)\n .map(item => item.name)\n}\n\nfunction buildMessage(\n called: string,\n suggestions: readonly string[],\n custom: Exclude<AgentBehavior['unknownToolRecovery'], false | undefined>['message'] | undefined,\n): string {\n return resolveCustomMessage(custom, { called, suggestions }, () => {\n const suffix = suggestions.length > 0\n ? ` Closest advertised tools: ${suggestions.map(s => `\\`${s}\\``).join(', ')}.`\n : ' No close advertised tool names were found.'\n return `Unknown tool \"${called}\" was called.${suffix} Re-emit the call with one advertised tool name; do not invent tool names.`\n })\n}\n\nexport function installUnknownToolRecovery(\n hooks: Hookable<AgentHooks>,\n config: AgentBehavior['unknownToolRecovery'],\n deps: {\n advertisedToolNames: () => readonly string[]\n enqueueNudge: (message: string) => void\n },\n): Unregister {\n if (!config || (config.mode ?? 'steer') !== 'steer')\n return noopUnregister\n\n const sent = new Set<string>()\n let nudgeCount = 0\n const maxSuggestions = clampPositiveInt(config.maxSuggestions, DEFAULT_MAX_SUGGESTIONS)\n const maxNudges = clampPositiveInt(config.maxNudges, DEFAULT_MAX_NUDGES)\n\n return hooks.hook('tool:unknown', (ctx) => {\n // A nested call (`ToolContext.callTool`) must fail as an error; a\n // substituted hint would resolve as a successful result.\n if (nudgeCount >= maxNudges || ctx.parentToolCallId !== undefined)\n return\n const called = ctx.displayName || ctx.name\n const key = called.toLowerCase()\n if (sent.has(key))\n return\n sent.add(key)\n nudgeCount++\n\n const suggestions = suggestionsFor(called, deps.advertisedToolNames(), maxSuggestions)\n deps.enqueueNudge(buildMessage(called, suggestions, config.message))\n })\n}\n","import type { Hookable } from 'hookable'\nimport type { AgentHooks } from '../agent'\nimport type { AliasMaps } from '../aliasing'\nimport type { ExecutionContext, ExecutionHandle } from '../contexts'\nimport type { AgentBehavior } from '../types'\nimport type { Unregister } from './shared'\nimport { toWireName } from '../aliasing'\nimport { matchPathPattern, noopUnregister } from './shared'\n\nexport function installWriteFileExistingPolicy(\n hooks: Hookable<AgentHooks>,\n policy: AgentBehavior['writeFileExistingPolicy'],\n deps: { execution: ExecutionContext, getHandle: () => ExecutionHandle | undefined, aliasMaps: AliasMaps },\n): Unregister {\n const mode = typeof policy === 'string' ? policy : policy?.mode\n if (mode !== 'block-with-edit-recipe')\n return noopUnregister\n return hooks.hook('tool:gate', async (ctx) => {\n if (ctx.block || ctx.name !== 'write_file')\n return\n const path = typeof ctx.input.path === 'string' ? ctx.input.path : ''\n if (!path)\n return\n const handle = deps.getHandle()\n if (!handle)\n return\n const cwd = handle.cwd\n if (matchPathPattern(path, cwd, typeof policy === 'object' ? policy.allowPaths : undefined))\n return\n if (typeof policy === 'object' && policy.denyPaths && !matchPathPattern(path, cwd, policy.denyPaths))\n return\n try {\n await deps.execution.readFile(handle, path)\n }\n catch {\n return\n }\n ctx.block = true\n const readFileName = toWireName('read_file', deps.aliasMaps)\n const editName = toWireName('edit', deps.aliasMaps)\n const multiEditName = toWireName('multi_edit', deps.aliasMaps)\n ctx.reason = [\n `Existing file writes are disabled for ${path}.`,\n `Read the file first, then use ${editName} or ${multiEditName} for the smallest safe change.`,\n `Next action: ${readFileName}({ \"path\": ${JSON.stringify(path)} })`,\n ].join(' ')\n })\n}\n","/**\n * Codemode configuration and the helpers its modules share: the tool's name\n * and defaults, `AgentBehavior.codemode` normalized, and which tools a\n * script can call under which names.\n */\n\nimport type { DurableToolDef, ToolDef } from '../types'\n\n/** Name of the codemode tool. */\nexport const CODEMODE_TOOL_NAME = 'codemode'\n\n/** Default `max_output_tokens`. */\nexport const DEFAULT_CODEMODE_MAX_OUTPUT_TOKENS = 10_000\n\n/** Default budget for tool declarations in the description (`'only'` mode), in estimated tokens. */\nexport const DEFAULT_CODEMODE_INLINE_BUDGET = 3000\n\n/** Rough characters per token, for budgets measured in tokens. */\nexport const CHARS_PER_TOKEN = 4\n\n/** The built-in tool `sh()` calls in scripts. */\nexport const SHELL_TOOL = 'shell'\n\n/** The built-in file reader. */\nexport const READ_FILE_TOOL = 'read_file'\n\n/** The built-in content search. */\nexport const GREP_TOOL = 'grep'\n\n/** Tools scripts never see: this tool, discovery tools a script does not need. */\nconst HIDDEN_FROM_SCRIPTS: ReadonlySet<string> = new Set([CODEMODE_TOOL_NAME, 'tool_search', 'call_tool'])\n\n/** `'on'` keeps the other tools declared to the model. `'only'` takes them off the wire and declares them in the codemode description. */\nexport type CodemodeMode = 'on' | 'only'\n\n/** How the system prompt lists lazy (MCP) tools while codemode is on. */\nexport type CodemodeCatalog = 'names' | 'full'\n\n/** `AgentBehavior.codemode` normalized, or `undefined` when off. */\nexport function resolveCodemodeConfig(\n value: boolean | { mode?: CodemodeMode, inlineBudget?: number, catalog?: CodemodeCatalog, directCallNotes?: boolean, streamProgress?: boolean } | undefined,\n): { mode: CodemodeMode, inlineBudget?: number, catalog: CodemodeCatalog, directCallNotes: boolean, streamProgress: boolean } | undefined {\n if (value === undefined || value === false)\n return undefined\n if (value === true)\n return { mode: 'on', catalog: 'names', directCallNotes: true, streamProgress: false }\n return {\n mode: value.mode === 'only' ? 'only' : 'on',\n catalog: value.catalog === 'full' ? 'full' : 'names',\n directCallNotes: value.directCallNotes !== false,\n streamProgress: value.streamProgress === true,\n ...(typeof value.inlineBudget === 'number' && Number.isFinite(value.inlineBudget) && value.inlineBudget >= 0\n ? { inlineBudget: value.inlineBudget }\n : {}),\n }\n}\n\n/**\n * Heads the names-only lazy-tool catalog while codemode is on: scripts call\n * those tools directly and look them up instead of reading full descriptions.\n */\nexport const CODEMODE_CATALOG_NOTE = 'Tool names only. In codemode scripts, `describeTool(name)` gives a tool\\'s declaration and `searchTools(query)` finds tools by topic.'\n\n/**\n * Canonical names of the tools a script can call, out of a registry: every\n * tool but this one, discovery tools, and other callers of `callTool`.\n * Subagent tools (`spawn`) are included: their workers show under the\n * script's row. In `'only'` mode these are the tools that leave the wire.\n */\nexport function codemodeCallableNames(tools: Readonly<Record<string, ToolDef>>): string[] {\n return callableNames(tools)\n}\n\n/** Options for {@link createCodemodeDescription} and the codemode tool. */\nexport interface CodemodeToolOptions {\n /**\n * `'on'` (default): the other tools stay declared to the model, and this\n * description only names how scripts call them. `'only'`: the host hides\n * the other tools from the wire and this description carries their\n * TypeScript declarations (within {@link inlineBudget}).\n */\n mode?: CodemodeMode\n /**\n * Tools to describe in the description, by canonical name. Usually the\n * run's eager native tools; MCP and lazy tools are found at run time with\n * `searchTools()` / `describeTool()`, which keeps this description\n * byte-stable as MCP servers connect.\n */\n tools?: Readonly<Record<string, ToolDef>>\n /** Canonical → wire names, so declarations use the names the model sees. */\n toolAliases?: Readonly<Record<string, string>>\n /** Token budget for declarations in `'only'` mode. Default {@link DEFAULT_CODEMODE_INLINE_BUDGET}. */\n inlineBudget?: number\n /**\n * Whether the agent has MCP servers: the description then covers MCP\n * namespaces and calling MCP tools without loading them. Default `true`.\n */\n mcp?: boolean\n /** Override the sandbox's QuickJS wasm / worker, for bundled hosts (Bun executables). */\n sandbox?: { wasmPath?: string, workerUrl?: string | URL }\n /**\n * Report the script's progress live through `ToolContext.reportProgress`\n * (`tool:progress`): what it prints, as it prints it, and the output of its\n * shell calls as they run. Its calls also carry the script line that made\n * them (`NestedToolCallOptions.line`). The model's result does not change.\n * Default: off.\n */\n streamProgress?: boolean\n}\n\n/** Whether `value` is a non-null, non-array object. */\nexport function isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value)\n}\n\n/** Canonical names of the registry tools a script can call: all but the hidden ones and other callers of `callTool`. */\nexport function callableNames(tools: Readonly<Record<string, ToolDef>>): string[] {\n return Object.keys(tools).filter((name) => {\n const def: DurableToolDef = tools[name]!\n return !HIDDEN_FROM_SCRIPTS.has(name) && def.callsNestedTools !== true\n })\n}\n\n/** The wire name for a canonical tool name, or the canonical name when no alias applies. */\nexport function wireName(canonical: string, aliases: Readonly<Record<string, string>> | undefined): string {\n return aliases?.[canonical] ?? canonical\n}\n\n/** The JSON value a script call resolves to (`'string'` without an output schema). */\nexport function outputSchemaOf(def: ToolDef): Record<string, unknown> {\n return def.spec.outputSchema ?? { type: 'string' }\n}\n\n/** A tool as declarations render it: wire name, description and schemas. */\nexport function declarationOf(def: ToolDef, name: string) {\n return {\n name,\n description: def.spec.description,\n inputSchema: def.spec.inputSchema,\n outputSchema: outputSchemaOf(def),\n }\n}\n\n/** A description's first paragraph. */\nexport function firstParagraph(text: string): string {\n const trimmed = text.trim()\n const end = trimmed.indexOf('\\n\\n')\n return end === -1 ? trimmed : trimmed.slice(0, end)\n}\n","/**\n * The `codemode` tool description: how scripts work, then the tools they\n * call, as one line per tool (`'on'` mode) or one-line TypeScript\n * signatures (`'only'` mode, where the tools are off the wire).\n */\n\nimport type { ToolDef } from '../types'\nimport type { CodemodeToolOptions } from './config'\nimport { renderToolOutputType, renderToolSignature } from '../../codemode/declarations'\nimport { toCodemodeIdentifier } from '../../codemode/identifier'\nimport { callableNames, CHARS_PER_TOKEN, DEFAULT_CODEMODE_INLINE_BUDGET, firstParagraph, GREP_TOOL, outputSchemaOf, READ_FILE_TOOL, SHELL_TOOL, wireName } from './config'\n\nconst INTRO_HEAD = `Run JavaScript that calls other tools. Give each call a \\`description\\`: a very short, non-technical line (3-6 words, in sentence case) saying what the script does, shown to the user as the call's label. The \\`code\\` is raw JavaScript (not JSON, no code fence), run as an async function body in a QuickJS sandbox: top-level \\`await\\` and \\`return\\` work. No Node, file system, network, or timers (\\`setTimeout\\`, \\`URLSearchParams\\` and the like do not exist): wait with \\`await sleep(ms)\\` (max 60s). \\`Date.now()\\` is constant within a script.\n- \\`await tools.<name>({ ...args })\\` calls a tool with its usual arguments and resolves to its text output, or to an object for tools that declare one; printing that object (\\`return r\\`, \\`text(r)\\`) shows the text a direct call returns, and attaches the images it returned. A tool with one required string argument also takes it bare: \\`tools.<name>(\"…\", { ...rest })\\`. A failed, blocked, or invalid call rejects with an Error carrying the tool's error text; use \\`Promise.allSettled()\\` to keep the calls that succeed. Calls are real: nothing is undone when the script fails. Calls still running when the script ends are cancelled.\n- Tools run in the session's working directory, exactly like direct calls: use relative paths, and don't \\`cd\\` into the project or spell out absolute paths in commands.\n- Text with backticks, \\`\\${\\` or backslashes, such as file content or a shell command, goes in a JSON string, not a template literal.\n- Optional first line: \\`// @options: {\"timeout_ms\": 60000}\\`\n- Output: \\`text(value)\\`, \\`console.log(...)\\`, and top-level \\`return\\` add text (other objects as JSON); \\`image(value)\\` adds an image from a data URL, an image block, or every image in a tool result; \\`exit()\\` ends the script. Only this output reaches you, so filter large results in the script; output past the run's limit keeps its start and end, and the full text goes to a file.\n- \\`store(key, value)\\` / \\`load(key)\\` keep small JSON values across codemode calls (written only when the script succeeds).`\n\nconst DISCOVERY_NATIVE = '- Discovery: `ALL_TOOLS` lists every callable tool as `{ name, description }` objects; `await searchTools(query, { limit? })` ranks them; `await describeTool(name)` gives a tool\\'s TypeScript declaration.'\n\nconst DISCOVERY_MCP = '- Discovery: `ALL_TOOLS` lists every callable tool as `{ name, description }` objects; `await searchTools(query, { limit?, namespace? })` ranks them; `await describeTool(name)` gives a tool\\'s TypeScript declaration; `await describeNamespace(server)` lists an MCP server\\'s tools. MCP tools are callable here without loading them first.'\n\nconst INTRO_CLOSING = 'Use codemode to batch independent calls, chain dependent ones, or process many items, instead of many separate tool calls. A script around a single call costs a turn like the direct call: put the steps that follow in the same script.'\n\n/** How scripts work; the MCP parts of discovery only when the agent has MCP servers. */\nfunction describeIntro(mcp: boolean): string {\n return `${INTRO_HEAD}\\n${mcp ? DISCOVERY_MCP : DISCOVERY_NATIVE}\\n${INTRO_CLOSING}`\n}\n\n/**\n * One line per tool: how a script calls it and what it resolves to. For\n * `'on'` mode, where the model already has the tools' own declarations.\n */\nfunction describeCallLines(tools: Readonly<Record<string, ToolDef>>, aliases: CodemodeToolOptions['toolAliases']): string {\n const lines = callableNames(tools).map((canonical) => {\n const def = tools[canonical]!\n const type = renderToolOutputType(outputSchemaOf(def), { comments: false })\n return `- \\`tools.${toCodemodeIdentifier(wireName(canonical, aliases))}(args)\\` → \\`${type}\\``\n })\n return lines.length > 0 ? `Your declared tools, called from scripts:\\n${lines.join('\\n')}` : ''\n}\n\n/**\n * TypeScript declarations for `'only'` mode: one block with a summary line and a\n * one-line signature per tool, in declaration order, while the budget lasts.\n * Tools left out are named and stay reachable through `describeTool()`.\n */\nfunction describeDeclarations(\n tools: Readonly<Record<string, ToolDef>>,\n aliases: CodemodeToolOptions['toolAliases'],\n budget: number,\n): string {\n const members: string[] = []\n const omitted: string[] = []\n let remaining = budget\n for (const canonical of callableNames(tools)) {\n const def = tools[canonical]!\n const name = wireName(canonical, aliases)\n const summary = firstSentence(def.spec.description)\n const signature = renderToolSignature({ name, inputSchema: def.spec.inputSchema, outputSchema: outputSchemaOf(def) }, { comments: false })\n const member = `${summary ? ` // ${summary}\\n` : ''} ${signature}`\n const cost = Math.ceil(member.length / CHARS_PER_TOKEN)\n if (cost > remaining) {\n omitted.push(toCodemodeIdentifier(name))\n continue\n }\n members.push(member)\n remaining -= cost\n }\n if (members.length === 0 && omitted.length === 0)\n return ''\n const block = members.length > 0 ? `\\n\\n\\`\\`\\`ts\\ndeclare const tools: {\\n${members.join('\\n')}\\n};\\n\\`\\`\\`` : ''\n const note = omitted.length > 0 ? `\\n\\nAlso callable, see \\`describeTool(name)\\`: ${omitted.join(', ')}.` : ''\n return `These tools are declared only here: call them from codemode scripts, not as direct tool calls. Put the steps you already know in one script; start another only when the next step needs a result.${block}${note}`\n}\n\n/**\n * Lines about callable built-ins: the `sh()` shortcut for `shell` and what\n * printing its result shows, the text `read_file` returns inside scripts (no\n * line-number prefixes by default), and, with `grep` too, how to explore in\n * one script instead of one shell read per turn.\n */\nfunction describeToolNotes(tools: Readonly<Record<string, ToolDef>>, aliases: CodemodeToolOptions['toolAliases']): string {\n const callable = callableNames(tools)\n const id = (name: string): string => `tools.${toCodemodeIdentifier(wireName(name, aliases))}`\n const lines: string[] = []\n if (callable.includes(SHELL_TOOL))\n lines.push(`\\`sh(command, options?)\\` is short for \\`${id(SHELL_TOOL)}(command, options?)\\`; every other tool is only on \\`tools\\`. \\`return await sh(cmd)\\` shows stdout, stderr and the exit code; returning \\`.stdout\\` alone hides a failure.`)\n if (callable.includes(READ_FILE_TOOL))\n lines.push(`Inside scripts, \\`${id(READ_FILE_TOOL)}\\` returns plain text, with no line-number prefixes unless the call passes \\`lineNumbers: true\\`.`)\n if (callable.includes(READ_FILE_TOOL) && callable.includes(GREP_TOOL)) {\n lines.push(`Explore in one script: search, read the hits, filter in JavaScript, and return only what matters. E.g. \\`const files = (await ${id(GREP_TOOL)}({ pattern: \"createAgent\", output_mode: \"files_with_matches\" })).split(\"\\\\n\").filter(line => line && !line.startsWith(\"…\")); return await ${id(READ_FILE_TOOL)}({ paths: files.slice(0, 5).map(path => ({ path, limit: 60 })) })\\`.`\n + ` Prefer \\`${id(GREP_TOOL)}\\` and \\`${id(READ_FILE_TOOL)}\\` to shell \\`grep\\`, \\`sed -n\\` or \\`cat\\`: they skip ignored files and return text ready to filter.`)\n }\n return lines.join('\\n')\n}\n\n/** Longest one-line tool summary in `'only'` mode, in characters. */\nconst SUMMARY_MAX_CHARS = 120\n\n/** A description's first sentence, on one line, cut at a word past {@link SUMMARY_MAX_CHARS}. */\nfunction firstSentence(description: string | undefined): string {\n const paragraph = firstParagraph(description ?? '').replace(/\\s+/g, ' ')\n const sentence = (/^.+?[.!?](?=\\s|$)/.exec(paragraph)?.[0] ?? paragraph).trim()\n if (sentence.length <= SUMMARY_MAX_CHARS)\n return sentence\n const cut = sentence.slice(0, SUMMARY_MAX_CHARS)\n return `${cut.slice(0, cut.lastIndexOf(' ') > 0 ? cut.lastIndexOf(' ') : cut.length)}…`\n}\n\n/**\n * Build the codemode tool description: how scripts work, notes on `sh()` and\n * `read_file` when they are callable, then the tool listing for the chosen mode.\n *\n * @param options - Mode, tools to describe, aliases, inline budget and MCP flag.\n */\nexport function createCodemodeDescription(options: CodemodeToolOptions = {}): string {\n const tools = options.tools ?? {}\n const listing = options.mode === 'only'\n ? describeDeclarations(tools, options.toolAliases, options.inlineBudget ?? DEFAULT_CODEMODE_INLINE_BUDGET)\n : describeCallLines(tools, options.toolAliases)\n return [describeIntro(options.mcp ?? true), describeToolNotes(tools, options.toolAliases), listing].filter(Boolean).join('\\n\\n')\n}\n","/**\n * What scripts discover tools with: the catalog of callable tools, and the\n * `searchTools` / `describeTool` / `describeNamespace` globals over it.\n */\n\nimport type { CodemodeTool } from '../../codemode/types'\nimport type { LazyToolEntry } from '../tool-search'\nimport type { ToolContext, ToolDef } from '../types'\nimport { resolveServerForTool } from '../../agent-mcp-naming'\nimport { renderToolSample } from '../../codemode/declarations'\nimport { toCodemodeIdentifier } from '../../codemode/identifier'\nimport { CodemodeValue } from '../../codemode/value'\nimport { selectToolSearchMatches } from '../tool-search'\nimport { callableNames, declarationOf, firstParagraph, isRecord, wireName } from './config'\n\ninterface ScriptToolInfo { name: string, description: string }\n\n/** The tools a script can call, by wire name, with their MCP server. */\nexport function buildCatalog(ctx: ToolContext, tools: Readonly<Record<string, ToolDef>>): LazyToolEntry[] {\n return callableNames(tools).map((canonical) => {\n const def = tools[canonical]!\n const server = resolveServerForTool(canonical, ctx.mcpServers)?.name\n return {\n name: wireName(canonical, ctx.toolAliases),\n canonicalName: canonical,\n description: def.spec.description,\n inputSchema: def.spec.inputSchema,\n ...(server ? { server } : {}),\n }\n })\n}\n\n/**\n * Build the `searchTools`, `describeTool` and `describeNamespace` script\n * globals over a catalog. `searchTools` returns at most 8 matches unless the\n * script passes `limit`.\n *\n * @param entries - Catalog from {@link buildCatalog}.\n * @param defs - Tool definitions by canonical name, used to render declarations.\n */\nexport function createDiscoveryGlobals(entries: readonly LazyToolEntry[], defs: Readonly<Record<string, ToolDef>>): CodemodeTool[] {\n const byName = new Map(entries.map(entry => [entry.name, entry]))\n const byIdentifier = new Map(entries.map(entry => [toCodemodeIdentifier(entry.name), entry]))\n const info = (entry: LazyToolEntry): ScriptToolInfo => ({\n name: toCodemodeIdentifier(entry.name),\n description: firstParagraph(entry.description),\n })\n return [\n {\n name: 'searchTools',\n spread: true,\n execute: (args) => {\n const [query, opts] = Array.isArray(args) ? args : []\n const options = isRecord(opts) ? opts : {}\n const { shown } = selectToolSearchMatches(entries, {\n ...(typeof query === 'string' ? { query } : {}),\n ...(typeof options.namespace === 'string' ? { server: options.namespace } : {}),\n limit: typeof options.limit === 'number' ? options.limit : 8,\n })\n return shown.map(info)\n },\n },\n {\n name: 'describeTool',\n spread: true,\n execute: (args) => {\n const [name] = Array.isArray(args) ? args : []\n if (typeof name !== 'string')\n return undefined\n const entry = byName.get(name) ?? byIdentifier.get(name)\n if (!entry)\n return undefined\n const declaration = renderToolSample(declarationOf(defs[entry.canonicalName]!, entry.name)).trim()\n // Prints, and reads inside a string, as the declaration.\n return new CodemodeValue({\n name: toCodemodeIdentifier(entry.name),\n ...(entry.server ? { namespace: entry.server } : {}),\n declaration,\n }, declaration)\n },\n },\n {\n name: 'describeNamespace',\n spread: true,\n execute: (args) => {\n const [name] = Array.isArray(args) ? args : []\n const tools = entries.filter(entry => entry.server !== undefined && entry.server === name)\n return tools.length > 0 ? { name, tools: tools.map(info) } : undefined\n },\n },\n ]\n}\n","/**\n * A script's result as the model reads it: output in order, the error and\n * call summary when it failed, kept under the run's inline limit with the\n * full text saved where the model can read it in ranges.\n */\n\nimport type { CodemodeError, CodemodeOutputItem, CodemodeResult } from '../../codemode/types'\nimport type { ToolContext } from '../types'\nimport type { ScriptCallIssue } from './script-api'\nimport { utf8ByteLength } from '../../compact/utils'\nimport { writePersistedBlob } from '../../persisted-blob-io'\nimport { middleTruncate } from '../truncate'\nimport { CHARS_PER_TOKEN, CODEMODE_TOOL_NAME } from './config'\n\nconst CALL_SUMMARY_LIMIT = 20\nconst ISSUE_FOOTER_LIMIT = 3\n\nfunction formatValue(value: unknown): string {\n if (typeof value === 'string')\n return value\n try {\n return JSON.stringify(value, null, 2) ?? String(value)\n }\n catch {\n return String(value)\n }\n}\n\nfunction formatCallSummary(result: CodemodeResult, timed: boolean): string {\n if (result.calls.length === 0)\n return ''\n const shown = result.calls.slice(-CALL_SUMMARY_LIMIT)\n const lines = shown.map(call => `- ${call.name}: ${call.status}${timed ? ` (${Math.round(call.durationMs)}ms)` : ''}`)\n const omitted = result.calls.length - shown.length\n return `Tool calls${omitted > 0 ? ` (last ${shown.length} of ${result.calls.length})` : ''}:\\n${lines.join('\\n')}`\n}\n\n/** Text of the script's output, in order, with `==> text N/M <==` separators when there are several. */\nfunction renderText(texts: string[], consoleLines: string[]): string {\n const parts = texts.length > 1\n ? texts.map((text, i) => `==> text ${i + 1}/${texts.length} <==\\n${text}`)\n : texts\n if (consoleLines.length > 0)\n parts.push(`<console_output>\\n${consoleLines.join('\\n')}\\n</console_output>`)\n return parts.join('\\n')\n}\n\n/** The gap marker of a cut output, naming the spill file. */\nfunction spillMarker(omittedChars: number, spillNote: string): string {\n return `\\n…[${omittedChars} characters omitted. Filter or summarize in the script and run it again rather than reading more; ${spillNote}]…\\n`\n}\n\n/** Keep the start and end of `text` within `maxBytes`, naming the spill file in the gap. The marker comes on top. */\nfunction truncateMiddle(text: string, maxBytes: number, spillNote: string): string {\n return middleTruncate(text, maxBytes, { marker: omitted => spillMarker(omitted.chars, spillNote) })\n}\n\n/** {@link truncateMiddle} with the marker inside `maxBytes`, so the result fits it. */\nfunction truncateMiddleWithin(text: string, maxBytes: number, spillNote: string): string {\n return truncateMiddle(text, Math.max(1, maxBytes - utf8ByteLength(spillMarker(text.length, spillNote))), spillNote)\n}\n\n/**\n * The size, in bytes, past which the run swaps a tool result for a file and a short preview\n * (`behavior.persistThreshold` with a `persistDir`), or `undefined` when results stay inline.\n */\nfunction inlineLimit(ctx: ToolContext): number | undefined {\n const behavior = ctx.behavior\n const threshold = behavior?.persistThreshold\n if (typeof threshold !== 'number' || threshold <= 0 || !behavior?.persistDir || behavior.persistExcludeTools?.includes(CODEMODE_TOOL_NAME))\n return undefined\n return threshold\n}\n\n/**\n * Where a truncated script's full output goes: `behavior.persistDir` when set\n * (the same directory spilled tool results use), else the temp dir. Kept free\n * of `node:os` so the core graph stays edge-safe.\n */\nfunction spillDir(ctx: ToolContext): string {\n const configured = ctx.behavior?.persistDir\n if (typeof configured === 'string' && configured.length > 0)\n return configured\n const tmp = ctx.handle.type === 'process' && typeof process !== 'undefined' ? process.env.TMPDIR : undefined\n return tmp && tmp.length > 0 ? tmp : '/tmp'\n}\n\nasync function spill(ctx: ToolContext, text: string): Promise<string> {\n const dir = spillDir(ctx).replace(/[/\\\\]+$/, '')\n const path = `${dir}/codemode-${ctx.callId.replace(/[^\\w-]/g, '_')}.txt`\n try {\n // Only `persistDir` spills fall back to the host: read_file reads those back, not temp files.\n if (ctx.behavior?.persistDir)\n await writePersistedBlob(ctx.execution, ctx.handle, path, text)\n else\n await ctx.execution.writeFile(ctx.handle, path, text)\n return `full output, if you need it: ${path} (read it in ranges)`\n }\n catch (error) {\n return `full output could not be saved: ${error instanceof Error ? error.message : String(error)}`\n }\n}\n\n/** What {@link buildResult} needs besides the result itself. */\nexport interface BuildResultOptions {\n /** Wall-clock run time; `undefined` in replay mode (see `execute`). */\n durationMs: number | undefined\n /** Estimated token budget for the output text, at 4 characters per token. */\n maxOutputTokens: number\n /** Error text when the `store()` writes were refused, else `undefined`. */\n storeError: string | undefined\n /** The script, for the syntax hint. */\n code: string\n /** Identifiers of the tools the script could call, for the bare-name hint. */\n toolIds: ReadonlySet<string>\n /** Failed calls and non-zero exits during the run, for the footer of a successful script. */\n issues?: readonly ScriptCallIssue[]\n}\n\n/**\n * Footer for a script that succeeded although some of its calls failed or\n * exited non-zero, and its output doesn't show it (a caught rejection, a\n * script returning `r.stdout` only). Empty when everything went fine or the\n * output already carries the evidence.\n */\nfunction issueFooter(issues: readonly ScriptCallIssue[], body: string): string {\n const counts = new Map<string, number>()\n for (const issue of issues) {\n if (!issue.evidence.some(text => body.includes(text)))\n counts.set(issue.line, (counts.get(issue.line) ?? 0) + 1)\n }\n if (counts.size === 0)\n return ''\n const hidden = [...counts]\n const shown = hidden.slice(0, ISSUE_FOOTER_LIMIT).map(([line, count]) => `- ${line}${count > 1 ? ` (${count} times)` : ''}`)\n if (hidden.length > shown.length)\n shown.push(`- …and ${hidden.length - shown.length} more`)\n return `Not shown in the output above:\\n${shown.join('\\n')}`\n}\n\n/**\n * Whether the line a script error points at, or the line before it, holds a backtick: file\n * content that breaks a template literal fails there. Without a location, whether the code holds one.\n */\nfunction nearBacktick(code: string, stack: string | undefined): boolean {\n const line = Number(stack?.match(/codemode\\.js:(\\d+):\\d+/)?.[1])\n if (!Number.isInteger(line) || line < 1)\n return code.includes('`')\n const lines = code.split('\\n')\n return [lines[line - 1], lines[line - 2]].some(source => source?.includes('`') === true)\n}\n\n/**\n * One-line hints for failures a script can fix by itself: a tool called as a\n * bare global, or file content breaking a template literal. Shown only when\n * they apply, so they cost no prompt tokens.\n */\nfunction errorHints(error: CodemodeError, code: string, toolIds: ReadonlySet<string>, calls: CodemodeResult['calls']): string[] {\n if (error.kind === 'timeout')\n return [timeoutHint(calls)]\n if (error.kind !== 'script')\n return []\n if (error.name === 'ReferenceError') {\n const missing = /^(\\S+) is not defined/.exec(error.message)?.[1]\n if (missing === undefined)\n return []\n if (toolIds.has(missing))\n return [`\\`${missing}\\` is a tool: call it as \\`tools.${missing}(...)\\`.`]\n const hint = missingGlobalHint(missing, toolIds)\n return hint ? [hint] : []\n }\n // A runtime SyntaxError from `JSON.parse` is about the data, not the script's source.\n if (error.name === 'SyntaxError' && !error.stack?.includes('at parse (native)') && nearBacktick(code, error.stack))\n return ['Hint: file content inside a template literal needs its ` and ${ escaped (\\\\` and \\\\${), or pass it as a JSON string.']\n return []\n}\n\n/** Node globals scripts reach for; the sandbox is QuickJS, without any of them. */\nconst NODE_GLOBALS = new Set(['process', 'require', 'module', 'exports', '__dirname', '__filename', 'Buffer', 'fs', 'path', 'os', 'child_process', 'global'])\nconst TIMER_GLOBALS = new Set(['setTimeout', 'setInterval', 'setImmediate', 'clearTimeout', 'clearInterval'])\n\n/** What to use instead of a global the sandbox lacks, or `undefined` when it isn't a known one. */\nfunction missingGlobalHint(name: string, toolIds: ReadonlySet<string>): string | undefined {\n if (NODE_GLOBALS.has(name))\n return `Hint: scripts run in QuickJS, not Node: there is no \\`${name}\\`. Reach files, the environment and processes through tools${toolIds.has('shell') ? ' (`sh(...)`, `tools.read_file`)' : ''}; paths are relative to the working directory.`\n if (TIMER_GLOBALS.has(name))\n return 'Hint: scripts have no timers: wait with `await sleep(ms)`.'\n if (name === 'fetch' || name === 'XMLHttpRequest' || name === 'WebSocket')\n return `Hint: scripts have no network access${toolIds.has('fetch_url') ? ': use `tools.fetch_url`' : ''}.`\n return undefined\n}\n\n/** Which call the deadline cut short (else the slowest one), and how to give it room. */\nfunction timeoutHint(calls: CodemodeResult['calls']): string {\n const cut = calls.find(call => call.status === 'cancelled')\n ?? calls.reduce<CodemodeResult['calls'][number] | undefined>((slowest, call) => (!slowest || call.durationMs > slowest.durationMs ? call : slowest), undefined)\n const which = cut ? ` while \\`${cut.name}\\` was running` : ''\n return `Hint: the script hit its \\`timeout_ms\\`${which}. Raise it on the first line (\\`// @options: {\"timeout_ms\": …}\\`) or drop it, or start long commands in the background and wait on them in a later script.`\n}\n\n/**\n * Format a script result for the model: a header, the output, then the error,\n * hints and call summary on failure. Output past the run's inline limit, or\n * past `maxOutputTokens`, is cut in the middle and the full text is saved to a file.\n *\n * @param ctx - Tool context, used to pick the spill directory and write the file.\n * @param result - The script result.\n * @param options - Timing, output budget, store error, script source and tool identifiers.\n * @param options.durationMs - Wall-clock run time, or `undefined` in replay mode.\n * @param options.maxOutputTokens - Estimated token budget for the output text.\n * @param options.storeError - Error text when the `store()` writes were refused.\n * @param options.code - The script source, for the syntax hint.\n * @param options.toolIds - Identifiers of the tools the script could call.\n * @param options.issues - Failed calls and non-zero exits, for the footer of a successful script.\n */\nexport async function buildResult(\n ctx: ToolContext,\n result: CodemodeResult,\n { durationMs, maxOutputTokens, storeError, code, toolIds, issues = [] }: BuildResultOptions,\n): Promise<{ text: string, images: Array<Extract<CodemodeOutputItem, { type: 'image' }>> }> {\n const texts: string[] = []\n const consoleLines: string[] = []\n const images: Array<Extract<CodemodeOutputItem, { type: 'image' }>> = []\n for (const item of result.output) {\n if (item.type === 'image')\n images.push(item)\n else if (item.console)\n consoleLines.push(item.text)\n else\n texts.push(item.text)\n }\n if (result.ok && result.value !== undefined)\n texts.push(formatValue(result.value))\n\n const body = renderText(texts, consoleLines)\n const timing = durationMs === undefined ? '' : ` (${(durationMs / 1000).toFixed(2)}s)`\n const header = `Script ${result.ok ? 'completed' : 'failed'}${timing}`\n const after: string[] = []\n if (images.length > 0)\n after.push(`(${images.length} image${images.length === 1 ? '' : 's'} attached)`)\n if (!result.ok) {\n const error = result.error\n after.push(`Script error: ${error.kind === 'script' ? (error.stack ?? error.message) : `${error.kind}: ${error.message}`}`)\n if (error.excerpt)\n after.push(error.excerpt)\n after.push(...errorHints(error, code, toolIds, result.calls))\n const calls = formatCallSummary(result, durationMs !== undefined)\n if (calls)\n after.push(calls)\n }\n else {\n const footer = issueFooter(issues, body)\n if (footer)\n after.push(footer)\n }\n if (storeError)\n after.push(`store() writes were not saved: ${storeError}`)\n const compose = (shown: string): string => [header, shown, ...after].filter(part => part !== '').join('\\n')\n\n const full = compose(body)\n const limit = inlineLimit(ctx)\n if (limit !== undefined && utf8ByteLength(full) > limit) {\n // Past the run's inline limit, keep as much of the start and end as fits it, so the run\n // leaves the result alone; the spill file holds the whole text. `compose` joins a\n // non-empty body with one more newline.\n const note = await spill(ctx, full)\n const bounded = compose(truncateMiddleWithin(body, limit - utf8ByteLength(compose('')) - 1, note))\n return { text: utf8ByteLength(bounded) <= limit ? bounded : truncateMiddleWithin(full, limit, note), images }\n }\n const maxChars = maxOutputTokens * CHARS_PER_TOKEN\n return { text: utf8ByteLength(body) > maxChars ? compose(truncateMiddle(body, maxChars, await spill(ctx, body))) : full, images }\n}\n","/**\n * What a script sees besides discovery: the run's tools wrapping nested\n * calls, `sleep`, advice for tools kept out of scripts, and the `sh` shortcut.\n */\n\nimport type { CodemodeTool } from '../../codemode/types'\nimport type { LazyToolEntry } from '../tool-search'\nimport type { DurableToolDef, NestedToolCallResult, ToolContext, ToolDef } from '../types'\nimport { toCodemodeIdentifier } from '../../codemode/identifier'\nimport { CodemodeValue } from '../../codemode/value'\nimport { toolResultToText } from '../../types'\nimport { interpretShellResult } from '../shell-semantics'\nimport { CODEMODE_TOOL_NAME, firstParagraph, isRecord, SHELL_TOOL, wireName } from './config'\n\n/** Wait `ms`, or until `signal` aborts. */\nexport function abortableDelay(ms: number, signal: AbortSignal): Promise<void> {\n return new Promise((resolve) => {\n if (signal.aborted)\n return resolve()\n const timer = setTimeout(done, ms)\n function done() {\n clearTimeout(timer)\n signal.removeEventListener('abort', done)\n resolve()\n }\n signal.addEventListener('abort', done, { once: true })\n })\n}\n\n/** Longest `sleep(ms)` a script gets per call. */\nexport const MAX_SLEEP_MS = 60_000\n\n/**\n * `await sleep(ms)`: the one way a script waits (no timers in the VM), e.g.\n * for a server it just started. Host-side and capped at {@link MAX_SLEEP_MS};\n * the script's own deadline and the run's abort still apply. Inside a run the\n * wait goes through `ordered` (`ToolContext.nestedSleep`): a durable timer\n * on a replay runtime, so a replay of the script does not wait again.\n */\nexport function sleepGlobal(ordered: ((ms: number) => Promise<void>) | undefined): CodemodeTool {\n return {\n name: 'sleep',\n spread: true,\n signature: '(ms: number): Promise<void>',\n description: `Wait \\`ms\\` milliseconds (at most ${MAX_SLEEP_MS}).`,\n execute: async (args, { signal }) => {\n const [ms] = Array.isArray(args) ? args : []\n const wait = typeof ms === 'number' && Number.isFinite(ms) ? Math.min(Math.max(0, ms), MAX_SLEEP_MS) : 0\n // In order with the script's calls, so a journaled sleep never overlaps one.\n if (ordered)\n await ordered(wait)\n else\n await abortableDelay(wait, signal)\n },\n }\n}\n\n/**\n * Advice for scripts that reach for a tool kept out of them, by the member\n * name a script would use (wire name and identifier).\n */\nexport function scriptToolHints(tools: Readonly<Record<string, ToolDef>>, aliases: Readonly<Record<string, string>> | undefined): Record<string, string> {\n const hints: Record<string, string> = {}\n for (const [canonical, def] of Object.entries(tools)) {\n let hint: string | undefined\n if (canonical === CODEMODE_TOOL_NAME)\n hint = 'Scripts cannot start other scripts.'\n else if (canonical === 'call_tool')\n hint = 'Inside scripts, call any tool directly as `tools.<name>(args)`, MCP tools included; no envelope.'\n else if (canonical === 'tool_search')\n hint = 'Use `searchTools(query)` or `describeTool(name)` inside scripts.'\n else if ((def as DurableToolDef).callsNestedTools === true)\n hint = `\\`${wireName(canonical, aliases)}\\` cannot be called from a script: call it directly, outside codemode.`\n if (!hint)\n continue\n const name = wireName(canonical, aliases)\n hints[name] = hint\n hints[toCodemodeIdentifier(name)] = hint\n }\n return hints\n}\n\n/**\n * What `tools.<name>()` resolves to: the reported structured value, which prints\n * as the text a direct call returns, else the text output, else (non-text\n * content) the blocks, images in the MCP shape `image()` accepts. Blocks print\n * as their text, and the images among them attach as images (the prelude's\n * `printedImages`): `return r` shows a generated image, not its base64.\n */\nfunction toScriptValue(result: NestedToolCallResult): unknown {\n if ('structured' in result)\n return new CodemodeValue(result.structured, toolResultToText(result.output))\n const { output } = result\n if (typeof output === 'string')\n return output\n if (output.every(block => block.type === 'text'))\n return toolResultToText(output)\n const blocks = output.map((block) => {\n if (block.type === 'image' && 'data' in block && typeof block.data === 'string')\n return { type: 'image', data: block.data, mimeType: block.mediaType }\n return block\n })\n const text = output.flatMap(block => block.type === 'text' ? [block.text] : []).join('\\n')\n return new CodemodeValue(blocks, text)\n}\n\n/**\n * A nested call that went wrong: it failed (the script may have caught the\n * rejection), or it reported a non-zero `exit_code` (a shell command).\n * `evidence` is text that, when present in the script's output, shows the\n * model already saw the problem.\n */\nexport interface ScriptCallIssue {\n /** One line naming the call and what went wrong. */\n line: string\n /** Texts, any of which in the output means the issue is already shown. */\n evidence: string[]\n}\n\nconst ISSUE_DETAIL_CHARS = 160\n\nfunction firstLine(text: string): string {\n const line = text.split('\\n').find(part => part.trim() !== '')?.trim() ?? ''\n return line.length > ISSUE_DETAIL_CHARS ? `${line.slice(0, ISSUE_DETAIL_CHARS)}…` : line\n}\n\n/**\n * The issue a non-zero `exit_code` in a structured result reports, if any.\n * Exits the shell reads as normal (`grep` with no match, `diff` finding a\n * difference) are not issues.\n */\nfunction exitIssue(name: string, args: Record<string, unknown>, structured: unknown): ScriptCallIssue | undefined {\n if (!isRecord(structured) || typeof structured.exit_code !== 'number' || structured.exit_code === 0)\n return undefined\n const code = structured.exit_code\n if (typeof args.command === 'string' && !interpretShellResult(args.command, code).isError)\n return undefined\n const command = typeof args.command === 'string' ? ` (${firstLine(args.command).slice(0, 60)})` : ''\n const stderr = typeof structured.stderr === 'string' ? firstLine(structured.stderr) : ''\n return { line: `${name}${command} exited ${code}${stderr ? `: ${stderr}` : ''}`, evidence: [`Exit code ${code}`, `exit ${code}`, `\"exit_code\": ${code}`] }\n}\n\n/**\n * The run's tools as script calls: each goes through `callTool`, failures\n * reject. Failed calls and non-zero exits are pushed to `issues`, so the\n * result can say so when the script's own output hides them. With\n * `streamProgress`, each call carries its script line and reports its live\n * output.\n */\nexport function createScriptTools(\n entries: readonly LazyToolEntry[],\n tools: Readonly<Record<string, ToolDef>>,\n callTool: NonNullable<ToolContext['callTool']>,\n issues: ScriptCallIssue[] = [],\n streamProgress = false,\n): CodemodeTool[] {\n return entries.map((entry) => {\n const inputSchema = tools[entry.canonicalName]?.spec.inputSchema\n return {\n name: entry.name,\n description: firstParagraph(entry.description),\n ...(inputSchema ? { inputSchema } : {}),\n execute: async (args, { signal, line }) => {\n if (args !== undefined && !isRecord(args))\n throw new Error(`tools.${toCodemodeIdentifier(entry.name)}() takes an object of named arguments, not ${Array.isArray(args) ? 'an array' : `a ${typeof args}`}.`)\n const result = await callTool(entry.canonicalName, args ?? {}, {\n signal,\n ...(line !== undefined ? { line } : {}),\n ...(streamProgress ? { streamProgress: true } : {}),\n })\n if (result.isError) {\n const message = toolResultToText(result.output).trim() || `${entry.name} failed`\n if (!signal?.aborted)\n issues.push({ line: `${entry.name} failed: ${firstLine(message)}`, evidence: [firstLine(message)] })\n throw new Error(message)\n }\n const issue = 'structured' in result ? exitIssue(entry.name, args ?? {}, result.structured) : undefined\n if (issue)\n issues.push(issue)\n return toScriptValue(result)\n },\n }\n })\n}\n\n/** `sh()` for the built-in shell tool, when the script can call it. */\nexport function scriptShortcuts(entries: readonly LazyToolEntry[]): Record<string, string> | undefined {\n const shell = entries.find(entry => entry.canonicalName === SHELL_TOOL)\n return shell ? { sh: shell.name } : undefined\n}\n","/**\n * `store(key, value)` / `load(key)`: small JSON values a script keeps across\n * calls, in `ToolContext.state`, staged only when the script succeeds.\n */\n\nimport type { ToolContext } from '../types'\n\n/** Key prefix of `store()` values in `ToolContext.state`. */\nexport const CODEMODE_STORE_PREFIX = 'codemode:'\n\n/** The values earlier scripts stored, by key. */\nexport function readStore(ctx: ToolContext): Record<string, unknown> {\n const state = ctx.state\n if (!state)\n return {}\n const store: Record<string, unknown> = {}\n for (const key of state.keys()) {\n if (key.startsWith(CODEMODE_STORE_PREFIX))\n store[key.slice(CODEMODE_STORE_PREFIX.length)] = state.get(key)\n }\n return store\n}\n\n/** Stage a successful script's writes. Returns the error text when the state store refused one. */\nexport function writeStore(ctx: ToolContext, writes: { set: Record<string, unknown>, delete: string[] }): string | undefined {\n const state = ctx.state\n if (!state)\n return Object.keys(writes.set).length > 0 || writes.delete.length > 0 ? 'no tool state is available in this run' : undefined\n try {\n for (const key of writes.delete)\n state.delete(CODEMODE_STORE_PREFIX + key)\n for (const [key, value] of Object.entries(writes.set))\n state.set(CODEMODE_STORE_PREFIX + key, value)\n return undefined\n }\n catch (error) {\n return error instanceof Error ? error.message : String(error)\n }\n}\n","/**\n * Codemode `'only'` mode declares the tools scripts call in the codemode\n * description instead of on the wire, but keeps them in the registry so script\n * calls resolve. A model still calls one directly now and then, with a name\n * from those declarations. The call runs as usual: refusing it cost a turn and,\n * for a file write, generating the whole content again. Its result gets one\n * line naming the script form instead, until the conversation holds two such\n * notes for that tool. Appended in `tool:transform`, to brand-new transcript\n * tail like the shell nudges, so it never rewrites cached prompt bytes.\n */\n\nimport type { Hookable } from 'hookable'\nimport type { AgentHooks } from '../../agent-hooks'\nimport type { SessionTurn } from '../../types'\nimport { countNotedResults } from '../../behaviors/transcript-notes'\nimport { toCodemodeIdentifier } from '../../codemode/identifier'\nimport { READ_FILE_TOOL, wireName } from './config'\n\nconst MAX_NOTES_PER_TOOL = 2\n\n/** `read_file` results never get the note: read-state hydration parses them back into the file's text to rebuild its hash. */\nconst UNNOTED_TOOLS: ReadonlySet<string> = new Set([READ_FILE_TOOL])\n\nfunction noteFor(name: string): string {\n return `(note: in this run tools are called from codemode scripts, as \\`tools.${toCodemodeIdentifier(name)}({ ... })\\`; one script can batch several calls.)`\n}\n\n/**\n * Whether `text` is a JSON document. Those results stay parseable: the TUI and\n * GUI read `present_plan` and `ask_user` results as JSON, and so may anything\n * that consumes a tool's structured answer.\n */\nfunction isJsonDocument(text: string): boolean {\n const first = text.trimStart()[0]\n if (first !== '{' && first !== '[')\n return false\n try {\n JSON.parse(text)\n return true\n }\n catch {\n return false\n }\n}\n\n/** What {@link installDirectCallNotes} reads from the run. */\nexport interface DirectCallNoteDeps {\n /** The conversation the model sees: notes already in it count toward the cap. */\n getTurns: () => readonly SessionTurn[]\n /** Whether the loop will save a result to disk and show the model only its start. */\n savesToDisk: (name: string, result: string) => boolean\n /** Canonical to wire names, so the note names what scripts call. */\n aliases?: Readonly<Record<string, string>> | undefined\n}\n\n/**\n * Note direct calls to `scriptOnly` tools, as a `tool:transform` hook. Calls a\n * script makes (`parentToolCallId` set) are left alone: the script parses\n * their output. Only text results that are not JSON get the note, and it goes\n * first when the loop will save the result to disk, so the preview shows it.\n * Returns the uninstall function.\n *\n * @param hooks - The agent's hook bus.\n * @param scriptOnly - Canonical names of the tools this run declares for scripts only.\n * @param deps - The conversation, the loop's save-to-disk check, and the wire names.\n */\nexport function installDirectCallNotes(hooks: Hookable<AgentHooks>, scriptOnly: ReadonlySet<string>, deps: DirectCallNoteDeps): () => void {\n if (scriptOnly.size === 0)\n return () => {}\n return hooks.hook('tool:transform', (ctx) => {\n if (ctx.parentToolCallId !== undefined || !scriptOnly.has(ctx.name) || UNNOTED_TOOLS.has(ctx.name) || typeof ctx.result !== 'string' || isJsonDocument(ctx.result))\n return\n const name = wireName(ctx.name, deps.aliases)\n const note = noteFor(name)\n // Counted from earlier turns: calls in one batch all see the same count.\n if (countNotedResults(deps.getTurns(), `codemode-direct-call:${ctx.name}`, new Set([ctx.name, name]), text => text.includes(note)) >= MAX_NOTES_PER_TOOL)\n return\n const appended = `${ctx.result}\\n${note}`\n ctx.result = deps.savesToDisk(ctx.name, appended) ? `${note}\\n${ctx.result}` : appended\n })\n}\n","/**\n * `codemode` — the model writes JavaScript that calls the run's other tools.\n *\n * The script runs in the QuickJS sandbox of `src/codemode/` (no Node, file\n * system, network or timers) and reaches the outside only through\n * `tools.<name>(args)`, which goes through `ToolContext.callTool`: the same\n * gate / validation / hooks pipeline as a model-issued call (see\n * `src/loop-nested-calls.ts`). Only the script's output reaches the model, so\n * a script can fan calls out, chain them, and filter large results first.\n *\n * Opt-in (`behavior.codemode`); never part of the default tool set.\n *\n * Script globals beyond the sandbox's own (`tools`, `ALL_TOOLS`, `text`,\n * `image`, `console`, `exit`, `store` / `load`):\n * - `searchTools(query, { limit?, namespace? })`, `describeTool(name)`,\n * `describeNamespace(name)` — discovery over every callable tool, MCP\n * tools included, so the description stays byte-stable as servers connect.\n *\n * `store` / `load` live in `ToolContext.state` under {@link CODEMODE_STORE_PREFIX}\n * and are staged only when the script succeeds, so they follow the loop's\n * commit (and durable journal) semantics.\n *\n * Determinism: the VM's clock and random source are pinned per call (from\n * `ToolContext.clock` and the call id), so in replay mode a re-run\n * script that sees the same tool results takes the same path. `Date.now()`\n * is therefore constant within one script.\n */\n\nimport type { CodemodeOutputItem, CodemodeResult } from '../../codemode/types'\nimport type { ToolResultContent } from '../../types'\nimport type { DurableToolDef, ToolDef } from '../types'\nimport type { CodemodeToolOptions } from './config'\nimport type { ScriptCallIssue } from './script-api'\nimport { toCodemodeIdentifier } from '../../codemode/identifier'\nimport { CodemodeSourceError, parseCodemodeSource } from '../../codemode/source'\nimport { lazyAsync } from '../../lazy'\nimport { CODEMODE_TOOL_NAME, DEFAULT_CODEMODE_MAX_OUTPUT_TOKENS } from './config'\nimport { createCodemodeDescription } from './description'\nimport { buildCatalog, createDiscoveryGlobals } from './discovery'\nimport { buildResult } from './output'\nimport { abortableDelay, createScriptTools, scriptShortcuts, scriptToolHints, sleepGlobal } from './script-api'\nimport { readStore, writeStore } from './store'\n\nexport {\n CODEMODE_CATALOG_NOTE,\n CODEMODE_TOOL_NAME,\n codemodeCallableNames,\n type CodemodeCatalog,\n type CodemodeMode,\n type CodemodeToolOptions,\n DEFAULT_CODEMODE_INLINE_BUDGET,\n DEFAULT_CODEMODE_MAX_OUTPUT_TOKENS,\n resolveCodemodeConfig,\n} from './config'\nexport { createCodemodeDescription } from './description'\nexport { installDirectCallNotes } from './direct-calls'\nexport { MAX_SLEEP_MS } from './script-api'\nexport { CODEMODE_STORE_PREFIX } from './store'\n\n/**\n * A script's VM heap. Without a cap a script can grow to wasm32's 4 GiB and\n * take the host down; overruns throw `InternalError: out of memory` inside it.\n */\nconst CODEMODE_MEMORY_LIMIT_BYTES = 256 * 1024 * 1024\n\n/** How long a missing worker file is retried (a dev build rewriting `dist/`). */\nconst WORKER_MISSING_RETRY_MS = 20_000\nconst WORKER_MISSING_RETRY_INTERVAL_MS = 1_000\n\n/**\n * A run that failed only because the worker entry was not on disk. Not a\n * QuickJS load failure (`Failed to load QuickJS: …`, e.g. `quickjs-wasi` not\n * installed): that one is permanent and must fail at once.\n */\nfunction isWorkerMissing(result: CodemodeResult): boolean {\n if (result.ok || result.error.kind !== 'sandbox' || result.calls.length > 0)\n return false\n const message = result.error.message\n return !message.startsWith('Failed to load QuickJS') && /ENOENT|Cannot find module/i.test(message)\n}\n\nconst loadSandbox = lazyAsync(() => import('../../codemode/runtime/host'))\nconst loadWasm = lazyAsync(() => import('../../codemode/wasm'))\n\n/** FNV-1a of the call id: the per-call random seed. */\nfunction seedOf(text: string): number {\n let hash = 0x811C9DC5\n for (let i = 0; i < text.length; i++) {\n hash ^= text.charCodeAt(i)\n hash = Math.imul(hash, 0x01000193)\n }\n return hash >>> 0\n}\n\n/**\n * Build the `codemode` tool. Its `execute` runs the model's script in the\n * sandbox and returns the script output as text, plus image blocks when the\n * script attached images. A failed script throws {@link CodemodeScriptError}.\n * Throws when the tool runs outside an agent run (`ToolContext.callTool` is\n * missing) or when the script source is invalid.\n *\n * @param options - Mode, tools to describe, aliases, inline budget, MCP flag and sandbox overrides.\n */\nexport function createCodemodeTool(options: CodemodeToolOptions = {}): ToolDef {\n const tool: DurableToolDef = {\n spec: {\n name: CODEMODE_TOOL_NAME,\n description: createCodemodeDescription(options),\n inputSchema: {\n type: 'object',\n // `description` first, so it streams before the script and the UI can\n // label the call while the code is still being written.\n properties: {\n description: {\n type: 'string',\n description: 'What the script does, for the person watching: one short line in sentence case, a few plain words, no code or tool names. E.g. \"Rank open issues by frustration\", \"Check every page for broken links\".',\n },\n code: { type: 'string', description: 'Raw JavaScript source, run as an async function body.' },\n },\n required: ['description', 'code'],\n },\n },\n // Nested calls journal individually under durable runtimes; see `DurableToolDef.callsNestedTools`.\n callsNestedTools: true,\n async execute(input, ctx) {\n const { callTool, nestedTools } = ctx\n if (!callTool || !nestedTools)\n throw new Error('codemode can only run inside an agent run (ToolContext.callTool is missing).')\n\n let source: ReturnType<typeof parseCodemodeSource>\n try {\n source = parseCodemodeSource(typeof input.code === 'string' ? input.code : '')\n }\n catch (error) {\n if (error instanceof CodemodeSourceError)\n throw new Error(`Invalid codemode script: ${error.message}`)\n throw error\n }\n\n // Live progress needs someone to report to: `reportProgress` is absent on a hand-built context.\n const reportProgress = options.streamProgress ? ctx.reportProgress : undefined\n const streamProgress = reportProgress !== undefined\n const entries = buildCatalog(ctx, nestedTools)\n const shortcuts = scriptShortcuts(entries)\n\n const issues: ScriptCallIssue[] = []\n const [{ CodemodeSandbox }, wasmModule] = await Promise.all([loadSandbox(), loadWasm()])\n const sandbox = new CodemodeSandbox({\n tools: createScriptTools(entries, nestedTools, callTool, issues, streamProgress),\n globals: [...createDiscoveryGlobals(entries, nestedTools), sleepGlobal(ctx.nestedSleep)],\n toolHints: scriptToolHints(nestedTools, ctx.toolAliases),\n ...(shortcuts ? { shortcuts } : {}),\n timeoutMs: source.options.timeoutMs ?? Number.POSITIVE_INFINITY,\n memoryLimitBytes: CODEMODE_MEMORY_LIMIT_BYTES,\n wasm: wasmModule.loadQuickJSWasm(options.sandbox?.wasmPath),\n ...(options.sandbox?.workerUrl !== undefined ? { workerUrl: options.sandbox.workerUrl } : {}),\n })\n\n const startedAt = Date.now()\n const nowMs = await (ctx.clock?.now() ?? Date.now())\n let result: CodemodeResult\n try {\n const run = () => sandbox.execute(source.code, {\n signal: ctx.signal,\n store: readStore(ctx),\n determinism: { nowMs, seed: seedOf(ctx.callId) },\n ...(reportProgress\n ? {\n trackLines: true,\n onOutput: (item: CodemodeOutputItem) => {\n if (item.type === 'text')\n reportProgress({ stream: item.console ? 'console' : 'output', text: item.text })\n },\n }\n : {}),\n })\n result = await run()\n // The worker file can vanish for a few seconds while a dev build\n // rewrites `dist/` under a running host. Nothing ran yet, so retry.\n const deadline = Date.now() + WORKER_MISSING_RETRY_MS\n while (isWorkerMissing(result) && Date.now() < deadline && !ctx.signal.aborted) {\n await abortableDelay(WORKER_MISSING_RETRY_INTERVAL_MS, ctx.signal)\n result = await run()\n }\n }\n finally {\n await sandbox.close()\n }\n const durationMs = Date.now() - startedAt\n\n // A sandbox failure (missing quickjs-wasi, worker crash) is the tool failing, not the script.\n if (!result.ok && result.error.kind === 'sandbox' && result.calls.length === 0)\n throw new Error(`codemode sandbox failed: ${result.error.message}`)\n\n const storeError = result.ok ? writeStore(ctx, result.storeWrites) : undefined\n // A durable run replays this result into a session state it already\n // wrote: wall-clock timings would differ on replay and fail the\n // runtime's determinism check, so replay mode gets none.\n const { text, images } = await buildResult(ctx, result, {\n durationMs: ctx.durable?.mode === 'replay' ? undefined : durationMs,\n maxOutputTokens: source.options.maxOutputTokens ?? DEFAULT_CODEMODE_MAX_OUTPUT_TOKENS,\n storeError,\n code: source.code,\n toolIds: new Set(entries.map(entry => toCodemodeIdentifier(entry.name))),\n issues,\n })\n if (!result.ok)\n throw new CodemodeScriptError(text)\n if (images.length === 0)\n return text\n const content: ToolResultContent[] = [{ type: 'text', text }]\n for (const image of images)\n content.push({ type: 'image', mediaType: image.mimeType, data: image.data })\n return content\n },\n }\n return tool\n}\n\n/**\n * A failed script. Thrown so the result carries the error bit; the message\n * is the full formatted result (partial output, error, call summary).\n */\nexport class CodemodeScriptError extends Error {\n /**\n * Creates the error.\n *\n * @param message - The full formatted script result.\n */\n constructor(message: string) {\n super(message)\n this.name = 'CodemodeScriptError'\n }\n}\n","/**\n * Per-run behavior gates: skills allowed-tools, write policy, unknown-tool\n * recovery, budgets, repeat guard, dedup, lazy disclosure, and the\n * hydration / nudge middlewares.\n */\n\nimport type { ResolvedBehavior } from './agent-behavior'\nimport type { RunToolset } from './agent-run-prompt'\nimport type { AgentRuntime } from './agent-runtime'\nimport type { AliasMaps } from './aliasing'\nimport { installReadBeforeEditHydrationGate, installSkillsActivationHydrationGate } from './agent-history'\nimport { installLazyDisclosureGate, installLazyDisclosureHydrationGate } from './agent-tool-disclosure'\nimport { installDedupToolsGate, installProgressNudges, installRepeatGuard, installShellToolNudges, installTextToolCallRescue, installThinkingOverrunPolicy, installToolBudgetsGate, installUnknownToolRecovery, installWriteFileExistingPolicy } from './behaviors'\nimport { willPersistToolResult } from './loop-persistence'\nimport { installAllowedToolsGate } from './skills/allowed-tools'\nimport { CALL_TOOL_NAME } from './tools/call-tool'\nimport { installDirectCallNotes, resolveCodemodeConfig } from './tools/codemode'\n\n/**\n * Install this run's behavior gates on the agent hook bus, pushing each\n * disposer onto `perRunUnregisters`. Install order encodes gate precedence\n * (see the comments below) and must not change.\n */\nexport function installRunGates(\n rt: AgentRuntime,\n input: {\n perRunUnregisters: Array<() => void>\n resolvedBehavior: ResolvedBehavior\n toolset: RunToolset\n aliasMaps: AliasMaps\n advertisedToolNames: () => string[]\n },\n): void {\n const { perRunUnregisters, resolvedBehavior, toolset, aliasMaps, advertisedToolNames } = input\n const { hooks, executionContext, steeringQueue, nonInterruptingNudgeQueue, skillActivationState, session } = rt\n const { writeFileExistingPolicy, unknownToolRecovery, toolBudgets, repeatGuard, dedupTools, thinkingOverrunPolicy, thinkingBudget, textToolCallRescue, progressNudges, toolSearch } = resolvedBehavior\n const { shouldInjectToolSearch, disclosure, unlocked, recordDynamicUnlock, discoveryToolName, dispatchMode, scriptOnlyToolNames, effectiveToolAliases } = toolset\n // Install the skill allowed-tools gate for this run; remove it in `finally`\n // so tool:gate listeners never leak across runs.\n perRunUnregisters.push(installAllowedToolsGate(hooks, skillActivationState))\n\n const getExecutionHandle = () => rt.executionHandle ?? undefined\n\n perRunUnregisters.push(installWriteFileExistingPolicy(\n hooks,\n writeFileExistingPolicy,\n {\n execution: executionContext,\n getHandle: getExecutionHandle,\n aliasMaps,\n },\n ))\n perRunUnregisters.push(installUnknownToolRecovery(\n hooks,\n unknownToolRecovery,\n {\n advertisedToolNames,\n enqueueNudge: message => nonInterruptingNudgeQueue.push(message),\n },\n ))\n\n // Per-tool soft call budgets. Installed BEFORE repeat-guard + dedup so\n // a budget block wins over a dedup hit — otherwise a model spamming a\n // dedup-eligible tool would bypass the cap entirely (every dedup hit\n // short-circuits budgets that fire later in the chain). Order:\n // allowed-tools → write policy → budgets → repeat-guard → dedup → lazy\n // disclosure. The middleware owns its own per-tool approval counter so\n // within-batch ordering is correct in parallel mode.\n perRunUnregisters.push(installToolBudgetsGate(\n hooks,\n () => toolBudgets,\n msg => nonInterruptingNudgeQueue.push(msg),\n ))\n\n // Consecutive-identical repeat guard. Installed AFTER budgets (a budget\n // block wins) and BEFORE dedup (so a streak block beats a dedup replay\n // short-circuit — otherwise a model spamming a dedup-eligible payload\n // would replay forever and never trip the abort). At the abort threshold\n // the gate calls `abortController.abort()`; the loop's existing post-turn\n // `signal.aborted` check then fires `agent:abort` and ends the run — the\n // same path a user-driven cancel takes.\n perRunUnregisters.push(installRepeatGuard(\n hooks,\n () => repeatGuard,\n () => rt.abortController?.abort(),\n ))\n\n // Per-tool argument-dedup middleware. No-op when `behavior.dedupTools` is\n // empty/unset or when the run is sessionless. Behavior is the field-merged\n // resolution of agent + run defaults — same precedence as every other\n // behavior knob.\n perRunUnregisters.push(installDedupToolsGate(\n hooks,\n () => dedupTools,\n () => session ?? undefined,\n ))\n\n // Lazy-disclosure unlock pre-hydration — MUST register before\n // `installLazyDisclosureGate` so a within-run `tool_search` whose live\n // `unlocked.add` was lost to durable replay is rebuilt from the transcript\n // before the hard gate decides to block (see the function doc).\n perRunUnregisters.push(installLazyDisclosureHydrationGate(\n hooks,\n {\n enabled: shouldInjectToolSearch && disclosure.lazyEntries.length > 0,\n session: session ?? undefined,\n lazyCanonicalNames: disclosure.lazyCanonicalNames,\n lazyEntries: disclosure.lazyEntries,\n unlocked,\n recordUnlock: recordDynamicUnlock,\n defaultLimit: toolSearch?.limit,\n },\n ))\n\n // Hard gate for lazy tools — refuses dispatch on canonical names not yet\n // in `unlocked`. Production providers already enforce this via their\n // tool-list validator, but the middleware closes the gap for custom /\n // mock / lenient providers and for any path where a model quotes a name\n // straight from the catalog.\n //\n // Registered after the allowed-tools, budgets, repeat-guard and dedup\n // gates so its handler fires after them. Lazy gate early-returns when an\n // upstream gate already set `ctx.block` (see `installLazyDisclosureGate`\n // body), so a skill refusal or budget block always wins over a \"load\n // via tool_search\" message. The early-return turns the order into a\n // safety net rather than a hard invariant — but the order-and-the-\n // early-return together make the precedence regression-proof.\n //\n // Codemode `'only'` mode has no `tool_search`: scripts call lazy tools\n // without loading them, and a direct call to one runs too (with a note,\n // `installDirectCallNotes`), so the gate leaves those tools alone.\n const gatedLazyNames = scriptOnlyToolNames.size > 0\n ? new Set([...disclosure.lazyCanonicalNames].filter(name => !scriptOnlyToolNames.has(name)))\n : disclosure.lazyCanonicalNames\n perRunUnregisters.push(installLazyDisclosureGate(\n hooks,\n gatedLazyNames,\n unlocked,\n discoveryToolName,\n dispatchMode ? CALL_TOOL_NAME : undefined,\n ))\n\n // Read-before-edit pre-hydration gate — keeps the `requireReadBeforeEdit`\n // verdict correct under durable/replay runtimes regardless of how the\n // consumer wraps tools (see `installReadBeforeEditHydrationGate`).\n perRunUnregisters.push(installReadBeforeEditHydrationGate(\n hooks,\n resolvedBehavior.requireReadBeforeEdit === true,\n {\n session: session ?? undefined,\n getHandle: () => rt.executionHandle,\n execution: executionContext,\n aliasMaps,\n defaultLineNumbers: resolvedBehavior.readLineNumbers ?? true,\n },\n ))\n\n // Skill-activation pre-hydration gate — keeps `skills_read` /\n // `skills_run_script` from journaling a spurious \"not active\" refusal when\n // a same-run `skills_use` was lost to durable replay (see the function doc).\n perRunUnregisters.push(installSkillsActivationHydrationGate(\n hooks,\n {\n session: session ?? undefined,\n getResolvedSkills: () => rt.resolvedSkills,\n state: skillActivationState,\n },\n ))\n\n perRunUnregisters.push(installThinkingOverrunPolicy(hooks, thinkingOverrunPolicy, {\n baseBudget: thinkingBudget,\n enqueueNudge: message => nonInterruptingNudgeQueue.push(message),\n }))\n perRunUnregisters.push(installTextToolCallRescue(hooks, textToolCallRescue, {\n enqueueSteer: message => steeringQueue.push(message),\n }))\n perRunUnregisters.push(installProgressNudges(hooks, progressNudges, {\n enqueueNudge: message => nonInterruptingNudgeQueue.push(message),\n }))\n perRunUnregisters.push(installShellToolNudges(hooks, resolvedBehavior.shellToolNudges, {\n getTurns: () => rt.conversationTurns,\n advertisedToolNames,\n aliasMaps,\n }))\n // Codemode `'only'` mode: a direct call to a tool declared for scripts only\n // still runs; its result gets a note naming the script form, unless\n // `codemode.directCallNotes` is false.\n const directCallNotes = resolveCodemodeConfig(resolvedBehavior.codemode)?.directCallNotes !== false\n perRunUnregisters.push(installDirectCallNotes(hooks, directCallNotes ? scriptOnlyToolNames : new Set(), {\n getTurns: () => rt.conversationTurns,\n savesToDisk: (name, result) => willPersistToolResult({\n toolName: name,\n output: result,\n threshold: resolvedBehavior.persistThreshold,\n persistDir: resolvedBehavior.persistDir,\n excludeTools: resolvedBehavior.persistExcludeTools,\n }),\n aliases: effectiveToolAliases,\n }))\n}\n","/**\n * Per-run tool registry: merging native, MCP, and auto-injected tools\n * (shell, skills, tool search) under the run's catalog transforms.\n */\n\nimport type { Hookable } from 'hookable'\n\nimport type { ResolvedBehavior } from './agent-behavior'\nimport type { AgentHooks } from './agent-hooks'\nimport type { AgentExtensionRuntime } from './agent-interceptors'\nimport type { ExecutionContext } from './contexts'\nimport type { ExtensionOrderedContribution, ExtensionToolCatalogTransform } from './extensions'\nimport type { McpConnection } from './mcp'\nimport type { SkillActivationState } from './skills/activation'\nimport type { SkillConfig, SkillsConfig } from './skills/types'\nimport type { ToolDef, ToolDescriptions } from './tools/types'\nimport type { AgentBehavior, McpServerConfig } from './types'\nimport { applyToolCatalogTransforms, applyToolDescriptionOverrides } from './agent-extensions'\nimport { applyCatalogTools } from './agent-interceptors'\nimport { buildMcpToolNameSeparatorAliases } from './agent-mcp-naming'\nimport { buildSanitizedWireAliases } from './aliasing'\nimport { resolveDetachedTasksCapability } from './contexts'\nimport { CODEMODE_TOOL_NAME, createCodemodeTool, resolveCodemodeConfig } from './tools/codemode'\nimport { shell as builtinShell, createShellTool } from './tools/shell'\nimport { shellKill as builtinShellKill } from './tools/shell-kill'\nimport { createSkillsReadTool } from './tools/skills-read'\nimport { createSkillsRunScriptTool } from './tools/skills-run-script'\nimport { createSkillsUseTool } from './tools/skills-use'\nimport { waitTask as builtinWaitTask } from './tools/wait-task'\n\n/**\n * Inputs to {@link buildRunToolRegistry}. Everything the run's tool catalog is\n * a function of — and nothing else. The explicit list is the point: it makes\n * visible that catalog assembly depends on no run bookkeeping (no run id, no\n * session, no abort controller), which is why it can be reasoned about, and\n * changed, on its own.\n */\ninterface RunToolRegistryInput {\n /** `AgentRunOptions.tools` — a run-level override replaces agent + MCP tools wholesale. */\n runOverrideTools: Record<string, ToolDef> | undefined\n /** Agent-level tools (pre-MCP-merge). */\n sourceTools: Record<string, ToolDef>\n mcpConnection: McpConnection | null\n mcpServers: readonly McpServerConfig[] | undefined\n mcpToolNameSeparator: NonNullable<AgentBehavior['mcpToolNameSeparator']>\n /** Agent-level alias record, before MCP separator + wire sanitization. */\n toolAliases: Record<string, string> | undefined\n resolvedSkills: SkillConfig[] | null\n skillsConfig: SkillsConfig | undefined\n skillActivationState: SkillActivationState\n hooks: Hookable<AgentHooks>\n toolCatalogTransforms: readonly ExtensionOrderedContribution<ExtensionToolCatalogTransform>[] | undefined\n /** The extension tools catalog, replayed after `toolCatalogTransforms`; absent without an extension runtime. */\n toolsCatalog?: NonNullable<AgentExtensionRuntime['catalogs']>['tools']\n /** The agent's session, for the extension catalog read. */\n sessionId?: string\n /** `AgentOptions.toolDescriptions` — applied last, after every built-in rewrite. */\n toolDescriptions: ToolDescriptions | undefined\n executionContext: ExecutionContext\n behavior: ResolvedBehavior\n}\n\ninterface RunToolRegistry {\n /** Spec-name-indexed registry — models call tools by spec name, not map key. */\n tools: Record<string, ToolDef>\n /** Which tools came from MCP. Only these are eligible for lazy disclosure. */\n mcpToolNames: ReadonlySet<string>\n /** Alias record after MCP separator aliases + wire-name sanitization. */\n toolAliases: Record<string, string> | undefined\n}\n\n/**\n * Assemble the tool registry a single run advertises.\n *\n * Pipeline: resolve the base set (run override > agent + MCP) → derive the\n * wire-name aliases → inject the skills tools → apply extension catalog\n * transforms → index by spec name → rewrite the built-in `shell` for this\n * run's capabilities → apply host `toolDescriptions` overrides → add the\n * opt-in `codemode` tool.\n */\nexport function buildRunToolRegistry(input: RunToolRegistryInput): RunToolRegistry {\n const {\n runOverrideTools,\n sourceTools,\n mcpConnection,\n mcpServers,\n mcpToolNameSeparator,\n toolAliases,\n resolvedSkills,\n skillsConfig,\n skillActivationState,\n hooks,\n toolCatalogTransforms,\n toolsCatalog,\n sessionId,\n toolDescriptions,\n executionContext,\n behavior,\n } = input\n\n // Tool resolution: run-level override > agent tools + MCP tools\n const runBaseTools = runOverrideTools !== undefined\n ? runOverrideTools\n : (mcpConnection\n ? { ...sourceTools, ...mcpConnection.tools }\n : sourceTools)\n\n // Track which tools came from MCP — only these are eligible for lazy\n // disclosure. A run-level `tools` override skips MCP entirely so the set\n // stays empty in that case.\n const mcpToolNames: ReadonlySet<string>\n = runOverrideTools === undefined && mcpConnection\n ? new Set(Object.keys(mcpConnection.tools))\n : new Set<string>()\n const generatedMcpToolAliases = buildMcpToolNameSeparatorAliases(mcpToolNames, mcpServers, mcpToolNameSeparator)\n const baseToolAliases = generatedMcpToolAliases\n ? { ...generatedMcpToolAliases, ...(toolAliases ?? {}) }\n : toolAliases\n // Coerce any MCP tool name that violates the provider name constraint\n // (e.g. a server configured as \"SSH Ipseity\" → `mcp_SSH Ipseity_exec`)\n // into a valid wire name. Injected into the alias record so the\n // `tool_search` catalog AND the `tools` array see the same sanitized\n // name — the model never gets an invalid name to echo, and the request\n // never 400s on `tools.N.custom.name`. Sanitized entries win over a\n // host/separator alias only when that alias is itself invalid.\n const sanitizedWireAliases = buildSanitizedWireAliases(mcpToolNames, baseToolAliases)\n const effectiveToolAliases = sanitizedWireAliases\n ? { ...(baseToolAliases ?? {}), ...sanitizedWireAliases }\n : baseToolAliases\n\n // Auto-inject `skills_use` / `skills_read` / `skills_run_script` when the\n // resolved skills catalog is non-empty. Opt out via `SkillsConfig.tool: false`.\n //\n // Skill tools are merged at the same tier as agent/MCP — a run-level\n // `tools: {}` override still wins (consistent with \"no tools means no tools\").\n // Agent-defined tools with the same name win over auto-injected ones.\n // They form a framework tail placed AFTER the agent/MCP tools so the head\n // of the tool list (a cached prefix) doesn't shift when skills come and go.\n const shouldInjectSkillTools\n = runOverrideTools === undefined\n && !!resolvedSkills\n && resolvedSkills.length > 0\n && skillsConfig?.tool !== false\n\n const injectedSkillTools: Record<string, ToolDef> = shouldInjectSkillTools\n ? {\n skills_use: createSkillsUseTool({\n catalog: resolvedSkills!,\n state: skillActivationState,\n hooks,\n // Gate for `!`cmd`` shell interpolation in skill bodies. On by\n // default; `allowShellInterpolation: false` neutralizes the\n // patterns with a placeholder. `approveShellInterpolation`, when\n // provided, gates each command through host confirmation.\n allowShellInterpolation: skillsConfig?.allowShellInterpolation,\n approveShellInterpolation: skillsConfig?.approveShellInterpolation,\n }),\n skills_read: createSkillsReadTool({\n catalog: resolvedSkills!,\n state: skillActivationState,\n }),\n skills_run_script: createSkillsRunScriptTool({\n catalog: resolvedSkills!,\n state: skillActivationState,\n scriptTimeoutMs: skillsConfig?.scriptTimeoutMs,\n }),\n }\n : {}\n\n const baseSpecNames = new Set(Object.values(runBaseTools).map(tool => tool.spec.name))\n const skillTail: Record<string, ToolDef> = {}\n for (const [name, tool] of Object.entries(injectedSkillTools)) {\n if (!baseSpecNames.has(tool.spec.name) && !(name in runBaseTools))\n skillTail[name] = tool\n }\n const mergedWithSkills = { ...runBaseTools, ...skillTail }\n\n const v1ToolCatalog = applyToolCatalogTransforms(\n mergedWithSkills,\n toolCatalogTransforms,\n 'run',\n mcpToolNames,\n )\n const transformedToolCatalog = toolsCatalog\n ? applyCatalogTools(toolsCatalog, v1ToolCatalog, { phase: 'run', ...(sessionId !== undefined ? { sessionId } : {}), mcpToolNames, mcpServers })\n : v1ToolCatalog\n\n // Build a spec-name-indexed map for the loop (models call tools by spec name, not map key)\n const tools: Record<string, ToolDef> = {}\n for (const tool of Object.values(transformedToolCatalog)) {\n tools[tool.spec.name] = tool\n }\n // A catalog transform may reorder; keep the skill tail last.\n for (const tool of Object.values(skillTail)) {\n const name = tool.spec.name\n const kept = tools[name]\n if (kept) {\n delete tools[name]\n tools[name] = kept\n }\n }\n\n // Per-run rewrite of the built-in `shell` tool. Two adjustments\n // ride on the same identity check:\n //\n // 1. Background-mode gate. Strips `run_in_background` from the\n // schema and the background-related paragraphs from the\n // description when:\n // - `behavior.tasksDir` is unset (no log dir wired), OR\n // - `behavior.disableBackgroundTasks: true` (explicit opt-out), OR\n // - `behavior.disableBackgroundTasks: 'non-durable'` and the\n // execution context's `detachedTasks` capability is below\n // `'durable'` (durable-runtime hosts), OR\n // - the context's capability is `'none'` (no backgrounding\n // at all — schema would advertise a dead flag).\n // So the model never sees a flag it can't use. The built-in\n // `shell_kill` / `wait_task` go too: they only act on background\n // tasks, and their descriptions point at `run_in_background`.\n //\n // 2. Dedicated-tool nudge. When the agent also registers siblings\n // like `read_file`, `glob`, `grep`, `list_files`, `edit`, or\n // `write_file`, the description gains a \"prefer the dedicated\n // tool\" block for each one that's present — targeting the\n // `ls`/`cat`-to-re-verify loop some models fall into when both\n // a dedicated tool and `shell` are visible. Aliases are\n // threaded through so the printed name matches the wire-level\n // name the model sees in the tool spec.\n //\n // Only the framework's identity-equal built-in `shell` is rewritten —\n // host-customized shell-named tools are left alone (the host owns\n // the spec they registered). Hosts who want explicit control can\n // register `createShellTool({ ... })` directly.\n if (tools.shell === builtinShell) {\n const detachedTasks = resolveDetachedTasksCapability(executionContext)\n const bgDisabled = behavior.disableBackgroundTasks === true\n || (behavior.disableBackgroundTasks === 'non-durable' && detachedTasks !== 'durable')\n const bgAllowed = typeof behavior.tasksDir === 'string'\n && behavior.tasksDir.length > 0\n && !bgDisabled\n && detachedTasks !== 'none'\n if (!bgAllowed) {\n if (tools.shell_kill === builtinShellKill)\n delete tools.shell_kill\n if (tools.wait_task === builtinWaitTask)\n delete tools.wait_task\n }\n tools.shell = createShellTool({\n allowBackground: bgAllowed,\n registeredCanonicals: new Set(Object.keys(tools)),\n ...(effectiveToolAliases ? { toolAliases: effectiveToolAliases } : {}),\n })\n }\n\n // Host description overrides go last so a function-form override sees the\n // final framework text (including the per-run `shell` rewrite above).\n const described = applyToolDescriptionOverrides(tools, toolDescriptions, mcpToolNames, mcpServers)\n\n // Opt-in `codemode` (`behavior.codemode`). Built from the final native\n // tools so `'only'` declarations carry the overridden descriptions; MCP\n // tools are discovered by scripts at run time instead, which keeps the\n // description byte-stable as servers connect. Same tier rules as the\n // skills tools: a run-level `tools` override or a host `codemode` wins.\n const codemode = resolveCodemodeConfig(behavior.codemode)\n if (codemode && runOverrideTools === undefined && !described[CODEMODE_TOOL_NAME]) {\n const native: Record<string, ToolDef> = {}\n for (const [name, def] of Object.entries(described)) {\n if (!mcpToolNames.has(name))\n native[name] = def\n }\n const tool = createCodemodeTool({\n mode: codemode.mode,\n tools: native,\n ...(codemode.inlineBudget !== undefined ? { inlineBudget: codemode.inlineBudget } : {}),\n ...(effectiveToolAliases ? { toolAliases: effectiveToolAliases } : {}),\n mcp: (mcpServers?.length ?? 0) > 0,\n ...(codemode.streamProgress ? { streamProgress: true } : {}),\n })\n Object.assign(described, applyToolDescriptionOverrides({ [CODEMODE_TOOL_NAME]: tool }, toolDescriptions, mcpToolNames, mcpServers))\n }\n\n return { tools: described, mcpToolNames, toolAliases: effectiveToolAliases }\n}\n","/**\n * Per-run prompt composition: tool registry + disclosure, the system\n * prompt and its appended catalogs, the wire tool list, and the context\n * snapshot `getContextBreakdown()` reads.\n */\n\nimport type { ResolvedBehavior } from './agent-behavior'\nimport type { ContextAssembly, DeferredToolInput, DisclosedToolInput } from './agent-context'\nimport type { AgentRuntime } from './agent-runtime'\nimport type { AliasMaps } from './aliasing'\nimport type { Provider, ToolSpec } from './providers'\nimport type { DurableToolDef } from './tools/types'\nimport type { AgentRunOptions, FrozenPromptSections } from './types'\nimport { assembleContextSnapshot } from './agent-context'\nimport { renderMcpInstructionsSection, resolveMcpToolParts } from './agent-mcp-naming'\nimport { buildRunDisclosureState, buildSearchableCatalog, toolSearchCatalogNote } from './agent-tool-disclosure'\nimport { buildRunToolRegistry } from './agent-tool-registry'\nimport { augmentMcpDoubleUnderscoreAliases, buildAliasMaps, toWireName } from './aliasing'\nimport { appendStaticSection, renderSystemForWire } from './system-prompt'\nimport { CALL_TOOL_NAME } from './tools/call-tool'\nimport { CODEMODE_CATALOG_NOTE, CODEMODE_TOOL_NAME, codemodeCallableNames, resolveCodemodeConfig } from './tools/codemode'\n\n/**\n * The run's tool registry and disclosure state: native + MCP + injected\n * tools, the eager/lazy partition, the unlock log, and which discovery tool\n * the catalog prose points at.\n */\nexport function composeRunToolset(\n rt: AgentRuntime,\n options: AgentRunOptions,\n resolvedBehavior: ResolvedBehavior,\n) {\n const { hooks, executionContext, sourceTools, skillsConfig, skillActivationState, toolAliases, toolDescriptions, mcpServers, toolCatalogTransforms } = rt\n const { mcpToolNameSeparator, toolDisclosure, toolSearch } = resolvedBehavior\n const { tools: toolsPreSearch, mcpToolNames, toolAliases: effectiveToolAliases } = buildRunToolRegistry({\n runOverrideTools: options.tools,\n sourceTools,\n mcpConnection: rt.mcpConnection,\n mcpServers,\n mcpToolNameSeparator,\n toolAliases,\n resolvedSkills: rt.resolvedSkills,\n skillsConfig,\n skillActivationState,\n hooks,\n toolCatalogTransforms,\n ...(rt.toolsCatalog ? { toolsCatalog: rt.toolsCatalog } : {}),\n ...(rt.toolsCatalog && (rt.session?.id ?? rt.sessionId) !== undefined ? { sessionId: rt.session?.id ?? rt.sessionId } : {}),\n toolDescriptions,\n executionContext,\n behavior: resolvedBehavior,\n })\n\n // `codemode` injected, so the framework owns it. In `'only'` mode scripts are\n // the discovery path, so no `tool_search` / `call_tool`, and the tools\n // scripts can call leave the wire below.\n const codemode = (toolsPreSearch[CODEMODE_TOOL_NAME] as DurableToolDef | undefined)?.callsNestedTools === true\n ? resolveCodemodeConfig(resolvedBehavior.codemode)\n : undefined\n const codemodeOnly = codemode?.mode === 'only'\n\n const {\n disclosure,\n unlocked,\n initialUnlocked,\n dynamicUnlockOrder,\n recordUnlock: recordDynamicUnlock,\n tools,\n injectedToolSearch: shouldInjectToolSearch,\n hostDefinedToolSearch,\n dispatchMode,\n } = buildRunDisclosureState({\n tools: toolsPreSearch,\n mcpToolNames,\n mcpServers,\n toolDisclosure,\n toolSearch: codemodeOnly ? { ...toolSearch, tool: false } : toolSearch,\n toolAliases: effectiveToolAliases,\n toolDescriptions,\n hasRunToolOverride: options.tools !== undefined,\n })\n\n // In `'only'` mode, declared inside the `codemode` description instead. Still\n // in the registry, so script calls resolve; a direct call runs too, with a\n // note (`installDirectCallNotes`).\n const scriptOnlyToolNames: ReadonlySet<string> = new Set(codemodeOnly ? codemodeCallableNames(tools) : [])\n for (const name of scriptOnlyToolNames) {\n initialUnlocked.delete(name)\n unlocked.delete(name)\n }\n\n // Decide which discovery-tool name (if any) the catalog text should\n // point at. `tool_search` when we auto-injected, the host's tool when\n // they brought their own (we use the wire/alias name in both cases —\n // that's what the model is told to call), and `null` when they fully\n // opted out so the catalog stays accurate without misleading prose.\n const discoveryToolName: string | null = shouldInjectToolSearch\n ? 'tool_search'\n : (hostDefinedToolSearch\n ? (effectiveToolAliases?.tool_search ?? 'tool_search')\n : null)\n\n return {\n tools,\n mcpToolNames,\n effectiveToolAliases,\n disclosure,\n unlocked,\n initialUnlocked,\n dynamicUnlockOrder,\n recordDynamicUnlock,\n shouldInjectToolSearch,\n hostDefinedToolSearch,\n dispatchMode,\n discoveryToolName,\n scriptOnlyToolNames,\n ...resolveCatalogDetail(codemode?.catalog, toolSearch?.catalog, discoveryToolName),\n }\n}\n\n/**\n * How the lazy-tool catalog renders, and the note heading a names-only one.\n * Codemode decides while it is on (scripts read descriptions through\n * `searchTools()` / `describeTool()`); otherwise `toolSearch.catalog`, and\n * only with a discovery tool the model can ask for the descriptions.\n */\nfunction resolveCatalogDetail(\n codemodeCatalog: 'names' | 'full' | undefined,\n toolSearchCatalog: 'names' | 'full' | undefined,\n discoveryToolName: string | null,\n): { catalogDetail: 'full' | 'names', catalogNote?: string } {\n if (codemodeCatalog)\n return codemodeCatalog === 'names' ? { catalogDetail: 'names', catalogNote: CODEMODE_CATALOG_NOTE } : { catalogDetail: 'full' }\n if (toolSearchCatalog === 'names' && discoveryToolName)\n return { catalogDetail: 'names', catalogNote: toolSearchCatalogNote(discoveryToolName) }\n return { catalogDetail: 'full' }\n}\n\n/** Output of {@link composeRunToolset}. */\nexport type RunToolset = ReturnType<typeof composeRunToolset>\n\n/**\n * The run's system prompt: run option > agent default > fallback, plus the\n * skills catalog, the searchable-tool catalog, and MCP server instructions\n * appended to its static half. `sections` holds those appended texts.\n */\nexport function composeRunSystemPrompt(\n rt: AgentRuntime,\n options: AgentRunOptions,\n toolset: RunToolset,\n surfaceMcpInstructions: ResolvedBehavior['surfaceMcpInstructions'],\n): { system: string, baseSystemForBreakdown: string, searchableCatalogText: string | undefined, sections: FrozenPromptSections } {\n const { agentSystem } = rt\n const { disclosure, discoveryToolName, dispatchMode, catalogDetail, catalogNote } = toolset\n // System prompt: run-time option > agent default > fallback\n let system = options.system || agentSystem || 'You are a helpful assistant.'\n // Snapshot the host-composed base (doctrine + rules + env) BEFORE the\n // agent appends skills / searchable-tools / MCP-instructions catalogs, so\n // the context breakdown can attribute each appended section separately.\n const baseSystemForBreakdown = renderSystemForWire(system)\n const sections: FrozenPromptSections = {}\n\n // Append skills catalog to the STATIC half of the system prompt. The\n // catalog is built once per run and stays byte-stable for the duration,\n // so it belongs in the cached prefix. When the caller embedded a\n // `SYSTEM_PROMPT_BOUNDARY` marker, the catalog lands above it; without\n // a marker, the append is a plain string concat.\n if (rt.skillsCatalog) {\n system = appendStaticSection(system, rt.skillsCatalog)\n sections.skills = rt.skillsCatalog\n }\n\n // Append the lazy-tool catalog AFTER the skills catalog so both use the\n // same anchor point — the catalog text is stable across turns and rides\n // the system-prompt cache breakpoint. Lands in the STATIC half when a\n // boundary marker is present (so per-turn dynamic content sits below).\n let searchableCatalogText: string | undefined\n if (disclosure.lazyEntries.length > 0) {\n searchableCatalogText = buildSearchableCatalog(disclosure.lazyEntries, {\n discoveryToolName,\n ...(dispatchMode ? { dispatcherName: CALL_TOOL_NAME } : {}),\n ...(catalogDetail === 'names' ? { detail: 'names' as const, ...(catalogNote ? { namesNote: catalogNote } : {}) } : {}),\n })\n system = appendStaticSection(system, searchableCatalogText)\n sections.tools = searchableCatalogText\n }\n\n // MCP server `instructions` block. Each server returns this field on\n // the `initialize` handshake and the SDK exposes it via\n // `client.getInstructions()`; we render it as `# MCP Server\n // Instructions` here so the model sees the server's own guidance\n // (e.g. \"the database is provisioned, use `apply_migration` directly\")\n // before it commits to a tool call. Without this, OSS models routinely\n // try to bootstrap state the server already advertises as ready.\n //\n // Appended via `appendStaticSection` so the block lands on the\n // CACHED half of the system prompt (above any `SYSTEM_PROMPT_BOUNDARY`\n // marker the host injected for env / cwd / mtimes). Server insertion\n // order in the Map matches `mcpServers` config order, which keeps the\n // rendered text byte-stable across runs and rides the system-prompt\n // cache breakpoint alongside the skills + searchable-tools catalogs.\n if (surfaceMcpInstructions && rt.mcpConnection?.instructions && rt.mcpConnection.instructions.size > 0) {\n const section = renderMcpInstructionsSection(rt.mcpConnection.instructions)\n if (section.length > 0) {\n system = appendStaticSection(system, section)\n sections.mcp = section\n }\n }\n\n return { system, baseSystemForBreakdown, searchableCatalogText, sections }\n}\n\n/**\n * Alias maps and the wire-level tool list for the run: `buildFormattedTools`\n * (memoized per provider + unlock-tail length) and the advertised names.\n */\nexport function createRunWireTools(runProvider: Provider, toolset: RunToolset): {\n aliasMaps: AliasMaps\n buildFormattedTools: (forProvider?: Provider) => unknown[]\n advertisedToolNames: () => string[]\n} {\n const { tools, effectiveToolAliases, initialUnlocked, dynamicUnlockOrder, dispatchMode } = toolset\n // Build alias maps once per run. Throws on alias collisions.\n const aliasMaps = buildAliasMaps(effectiveToolAliases, Object.keys(tools))\n // Auto-accept the Claude Code `mcp__server__tool` double-underscore\n // naming form as an inbound alias for every MCP tool. Models trained\n // on Anthropic's SDK routinely emit the double form even when the\n // tool catalog advertises single — without this, every such call\n // tripped `tool:unknown` and burnt a turn on a correction round-trip.\n // Inbound-only by design: outbound wire still shows the canonical\n // single form, so tool-list bytes (and the prompt cache) are\n // unaffected. See `augmentMcpDoubleUnderscoreAliases` for the rule.\n augmentMcpDoubleUnderscoreAliases(aliasMaps, Object.keys(tools))\n\n // Closure that recomputes the wire-level tool list from the current\n // unlock state. Called once up-front for the seed value and again\n // per-iteration in the loop when lazy disclosure may have grown the\n // dynamic-unlock log. Safe to call repeatedly — `provider.formatTools`\n // returns the same output for the same specs.\n //\n // Cache-stable emission: phase 1 walks the registry in insertion\n // order, emitting tools in `initialUnlocked` (every eager native +\n // skill_* + tool_search). This block is byte-stable across the entire\n // run — no element is added or moved, so providers that cache on the\n // tools-array bytes (Anthropic ephemeral cache, OpenRouter passthrough)\n // hit cache turn after turn for the prefix.\n //\n // Phase 2 appends entries from `dynamicUnlockOrder` (tools surfaced\n // by `tool_search` or resume-replay) in the order they were unlocked.\n // The log only grows — entries are never reordered or removed — so the\n // tools-array PREFIX (every tool the model already had) stays\n // byte-identical. Note what that does NOT buy: providers hash the\n // request prefix as `tools → system → messages`, so a grown tail still\n // re-bills the system prompt and every message on that turn. Only\n // `toolSearch.mode: 'dispatch'` avoids that — the tail is never emitted\n // and surfaced tools are called through `call_tool` instead.\n //\n // Iterating `Object.values(tools)` filtered by `unlocked` instead would\n // follow registry insertion order, which puts a newly-unlocked tool at its\n // REGISTRY POSITION (somewhere in the middle of the MCP block), shifting\n // every later entry's bytes and invalidating the full tool-list cache on\n // every discovery wave. Two phases avoid that.\n //\n // Memoize across turns keyed by `dynamicUnlockOrder.length`. The eager\n // prefix is byte-stable for the whole run and the dynamic tail is\n // append-only (never reordered/removed), so the formatted array is fully\n // determined by the tail length. Most turns unlock nothing, so this\n // skips the full registry walk + `provider.formatTools` on the hot path\n // while still recomputing the entire array — never splicing — when\n // a `tool_search` grows the tail, which keeps providers with non-mapping\n // `formatTools` (e.g. Anthropic's `web_search` rewrite) correct.\n // Cache keyed per provider: with a fallback chain the loop can reformat\n // the same spec list through a different provider's `formatTools`\n // mid-run, and each provider's wire shape is distinct.\n // Dispatch mode: the tail is never advertised. The unlock log still\n // grows (it gates which schemas the model has actually seen), but the\n // wire array is the eager prefix alone, for the whole run.\n const wireTailLength = (): number => (dispatchMode ? 0 : dynamicUnlockOrder.length)\n const formattedToolsCache = new Map<Provider, { tailLen: number, value: unknown[] }>()\n function buildFormattedTools(forProvider: Provider = runProvider): unknown[] {\n const cached = formattedToolsCache.get(forProvider)\n if (cached && cached.tailLen === wireTailLength())\n return cached.value\n const specs: ToolSpec[] = []\n for (const t of Object.values(tools)) {\n if (!initialUnlocked.has(t.spec.name))\n continue\n specs.push({\n name: aliasMaps.aliasByCanonical.get(t.spec.name) ?? t.spec.name,\n description: t.spec.description || '',\n inputSchema: t.spec.inputSchema,\n })\n }\n for (const canonical of dispatchMode ? [] : dynamicUnlockOrder) {\n const t = tools[canonical]\n if (!t)\n continue\n specs.push({\n name: aliasMaps.aliasByCanonical.get(t.spec.name) ?? t.spec.name,\n description: t.spec.description || '',\n inputSchema: t.spec.inputSchema,\n })\n }\n const value = specs.length > 0 ? forProvider.formatTools(specs) : []\n formattedToolsCache.set(forProvider, { tailLen: wireTailLength(), value })\n return value\n }\n\n function advertisedToolNames(): string[] {\n const names: string[] = []\n for (const t of Object.values(tools)) {\n if (initialUnlocked.has(t.spec.name))\n names.push(toWireName(t.spec.name, aliasMaps))\n }\n for (const canonical of dispatchMode ? [] : dynamicUnlockOrder) {\n if (tools[canonical])\n names.push(toWireName(canonical, aliasMaps))\n }\n return names\n }\n\n return { aliasMaps, buildFormattedTools, advertisedToolNames }\n}\n\n/**\n * Capture a context snapshot for `getContextBreakdown()`. Split the\n * disclosed wire tools into native vs MCP (by `mcpToolNames`) and group\n * the MCP ones; the deferred (lazy, not-yet-disclosed) entries come from\n * `disclosure.lazyEntries` and carry their own `server`. Each tool is\n * sized by its JSON byte footprint — the same bytes the provider sends.\n */\nexport function captureRunContextAssembly(\n rt: AgentRuntime,\n input: {\n options: AgentRunOptions\n toolset: RunToolset\n aliasMaps: AliasMaps\n model: string\n system: string\n baseSystemForBreakdown: string\n searchableCatalogText: string | undefined\n formattedTools: unknown[]\n surfaceMcpInstructions: ResolvedBehavior['surfaceMcpInstructions']\n /** `system` is a frozen prompt (`systemFreeze.system`), not the one composed from the pieces above. */\n frozen?: boolean\n },\n): ContextAssembly {\n const { options, toolset, aliasMaps, model, system, baseSystemForBreakdown, searchableCatalogText, formattedTools, surfaceMcpInstructions, frozen } = input\n const { mcpServers } = rt\n const { tools, mcpToolNames, disclosure, unlocked, initialUnlocked, dispatchMode } = toolset\n // Capture raw tool inputs only — the JSON byte-sizing is deferred to\n // `materializeAssemblyTools` inside `getContextBreakdown()`, so a normal\n // run never pays the per-tool `JSON.stringify`. Disclosed-tool order\n // matches the registry walk filtered by `unlocked`; deferred order\n // matches `disclosure.lazyEntries`.\n const disclosedTools: DisclosedToolInput[] = []\n // In dispatch mode resume-replayed unlocks sit in `unlocked` but never\n // reach the wire — the breakdown mirrors the bytes actually sent.\n const onWire = dispatchMode ? initialUnlocked : unlocked\n for (const t of Object.values(tools)) {\n if (!onWire.has(t.spec.name))\n continue\n const wireName = aliasMaps.aliasByCanonical.get(t.spec.name) ?? t.spec.name\n // Attribute MCP tools to their actual server (canonical names are\n // `mcp_<server>_<tool>`); 'mcp' only as a last-resort fallback for\n // names no configured server matches.\n disclosedTools.push({\n name: wireName,\n description: t.spec.description || '',\n inputSchema: t.spec.inputSchema,\n ...(mcpToolNames.has(t.spec.name)\n ? { mcpServer: resolveMcpToolParts(t.spec.name, mcpServers)?.server ?? 'mcp' }\n : {}),\n })\n }\n\n const deferredEntries: DeferredToolInput[] = disclosure.lazyEntries.map(entry => ({\n name: entry.name,\n description: entry.description || '',\n inputSchema: entry.inputSchema,\n ...(entry.server ? { server: entry.server } : {}),\n }))\n\n const mcpInstructionsText = (surfaceMcpInstructions && rt.mcpConnection?.instructions && rt.mcpConnection.instructions.size > 0)\n ? renderMcpInstructionsSection(rt.mcpConnection.instructions)\n : undefined\n\n // Mirror the wire bytes — strip the cache boundary marker.\n const wireSystem = renderSystemForWire(system)\n // A frozen prompt can predate the live pieces: attribute only the ones it\n // still carries, and size the base from what is actually sent.\n const carried = (piece: string | null | undefined): string | undefined =>\n piece && (!frozen || wireSystem.includes(piece)) ? piece : undefined\n const rulesBlock = carried(options.contextSections?.rulesBlock)\n const rulesFiles = rulesBlock ? options.contextSections?.rulesFiles : undefined\n const skillsCatalog = carried(rt.skillsCatalog)\n const subagentDefs = carried(searchableCatalogText)\n const mcpInstructions = carried(mcpInstructionsText)\n const baseSystem = frozen\n ? [skillsCatalog, subagentDefs, mcpInstructions].reduce<string>((base, piece) => piece ? base.replace(piece, '') : base, wireSystem)\n : baseSystemForBreakdown\n\n return assembleContextSnapshot({\n modelId: model,\n system: wireSystem,\n baseSystem,\n rulesBlock,\n rulesFiles,\n disclosedTools,\n deferredEntries,\n mcpInstructions,\n skillsCatalog,\n subagentDefs,\n // Provider-wire tool specs for the exact `countTokens` path.\n wireTools: formattedTools,\n })\n}\n\n/**\n * Compose the run's prompt pieces in order — toolset, system prompt, wire\n * tools — and record the context snapshot on `rt.lastContextAssembly`.\n */\nexport function composeRunPrompt(\n rt: AgentRuntime,\n input: { options: AgentRunOptions, resolvedBehavior: ResolvedBehavior, runProvider: Provider, model: string },\n): {\n toolset: RunToolset\n /** What the run sends: the frozen prompt (`systemFreeze.system`) when there is one, else `freshSystem`. */\n system: string\n /** `system` is a frozen prompt rather than `freshSystem`. */\n frozen: boolean\n /** The prompt composed for this run from the live inputs. */\n freshSystem: string\n /** The sections the SDK appended to `freshSystem`. */\n freshSections: FrozenPromptSections\n aliasMaps: AliasMaps\n buildFormattedTools: (forProvider?: Provider) => unknown[]\n advertisedToolNames: () => string[]\n formattedTools: unknown[]\n} {\n const { options, resolvedBehavior, runProvider, model } = input\n const { surfaceMcpInstructions } = resolvedBehavior\n const toolset = composeRunToolset(rt, options, resolvedBehavior)\n const { system: freshSystem, baseSystemForBreakdown, searchableCatalogText, sections: freshSections } = composeRunSystemPrompt(rt, options, toolset, surfaceMcpInstructions)\n const freeze = options.systemFreeze?.system\n const frozenSystem = (typeof freeze === 'function' ? freeze(freshSystem, freshSections) : freeze) || undefined\n const system = frozenSystem ?? freshSystem\n const { aliasMaps, buildFormattedTools, advertisedToolNames } = createRunWireTools(runProvider, toolset)\n const formattedTools = buildFormattedTools()\n rt.lastContextAssembly = captureRunContextAssembly(rt, {\n options,\n toolset,\n aliasMaps,\n model,\n system,\n baseSystemForBreakdown,\n searchableCatalogText,\n formattedTools,\n surfaceMcpInstructions,\n frozen: frozenSystem !== undefined,\n })\n return { toolset, system, frozen: frozenSystem !== undefined, freshSystem, freshSections, aliasMaps, buildFormattedTools, advertisedToolNames, formattedTools }\n}\n","/**\n * Background-task notifications: rendering `<task-notification>` /\n * stall blocks and draining them into the next run's seeded user turn.\n */\n\nimport type { Hookable } from 'hookable'\nimport type { ResolvedBehavior } from './agent-behavior'\nimport type { AgentHooks } from './agent-hooks'\nimport type { AgentRuntime } from './agent-runtime'\nimport type { ExecutionContext, ExecutionHandle, TaskExitInfo, TaskStallInfo } from './contexts'\nimport type { Session } from './session'\nimport type { SessionContentBlock, SessionTurn } from './types'\nimport { resolve as pathResolve } from 'node:path'\nimport { formatTaskSummary } from './chat/format'\nimport { readFileInputPaths } from './tools/read-file-targets'\nimport { WAIT_TASK_TIMED_OUT_PREFIX } from './tools/wait-task'\nimport { toolResultToText } from './types'\nimport { escapeXml } from './xml'\n\n/**\n * Canonical XML wire format for a background-task completion notification.\n *\n * Rendered as a leading `text` content block in the next user-turn so\n * the model can pattern-match on the outer tag. The shape uses kebab-case\n * tags (matching zidane's other XML conventions). Every field is\n * structured — `<summary>` is a derived display string, NOT the source\n * of truth for the underlying data (replay reads `<command>` /\n * `<duration-ms>` / etc. directly, never the summary, so changing the\n * summary format can't break replay).\n *\n * Field-level escaping uses {@link escapeXml} so commands containing\n * `<` / `>` / `&` round-trip cleanly through persistence + replay.\n */\nfunction renderTaskNotificationXml(info: TaskExitInfo): string {\n // Display-only summary — short, single-line, formatted by\n // `formatTaskSummary` so the wire format matches the TUI banner +\n // shell_kill tool output exactly. Replay does NOT parse this string\n // back; the structured fields below carry the canonical data.\n const summary = formatTaskSummary(info)\n const lines = [\n '<task-notification>',\n ` <task-id>${escapeXml(info.taskId)}</task-id>`,\n ` <status>${info.status}</status>`,\n ` <exit-code>${info.exitCode}</exit-code>`,\n ...(info.signal ? [` <signal>${escapeXml(info.signal)}</signal>`] : []),\n ` <command>${escapeXml(info.command)}</command>`,\n ` <output-file>${escapeXml(info.outputPath)}</output-file>`,\n ` <duration-ms>${info.durationMs}</duration-ms>`,\n ` <summary>${escapeXml(summary)}</summary>`,\n '</task-notification>',\n ]\n return lines.join('\\n')\n}\n\n/**\n * Acknowledgment evidence recoverable from persisted turn history —\n * which background tasks the model has ALREADY been told about (or\n * learned about itself) in prior runs of this session.\n *\n * The agent's in-memory `notifiedTaskIds` latch only lives as long as\n * the agent instance. Durable-execution hosts reconstruct the agent on\n * every handler invocation while the remote\n * context's task registry — and its terminated entries — survive. Without\n * a durable record, every new invocation's pull-based reconcile would\n * re-notify the same exits. The session history IS that durable record:\n * the drained `<task-notification>` blocks, `shell_kill` calls,\n * successful `wait_task` results, and `read_file` calls against a task's\n * output path are all persisted turns. Scanning them re-derives the\n * latch with zero extra state.\n *\n * Callers pass the FULL persisted history (`session.turns`), not the\n * runtime-filtered view: subagent-run turns (filtered from the resumed\n * conversation) still carry acks, and the built-in compaction contract\n * is marker-based (`compact-summary` elides turns at the wire level\n * only) so the evidence is append-only by design. Hosts that rewrite\n * `session.turns` destructively forfeit this dedupe — same assumption\n * the lazy-disclosure replay and read-state hydration already make.\n */\ninterface TaskAckHistory {\n /** Task ids notified, killed, or successfully waited on in prior turns. */\n taskIds: Set<string>\n /**\n * `path.resolve`-normalized paths the model read via `read_file` /\n * `read`, mapped to the LATEST `turn.createdAt` of such a read. A read\n * only acknowledges a task's exit when it happened AFTER the task\n * ended (`readAt >= entry.endedAt + skew margin`) — reading a\n * still-running task's log (progress check, stall inspection) must not\n * swallow the exit notification that hasn't happened yet. Mirrors the\n * live `tool:after` listener, which only deletes PENDING (i.e.\n * already-exited) entries.\n */\n outputPaths: Map<string, number>\n}\n\n/**\n * Safety margin for the read-ack ordering comparison, which crosses two\n * clock domains: `turn.createdAt` comes from the host's `AgentClock`\n * (the durable runtime's on a replaying run) while `TaskEntry.endedAt`\n * comes from the execution context's wall clock (possibly a remote runner). The turn\n * timestamp already UNDERSTATES the actual read time (the assistant turn\n * is created before its tool executes), so the only false-suppression\n * window is the runner clock lagging the host clock. Requiring the read\n * to land this many ms after the exit absorbs that skew: within the\n * margin we fail open (redundant notification — harmless), and false\n * suppression needs cross-machine skew beyond it (broken NTP territory).\n */\nconst READ_ACK_CLOCK_SKEW_MARGIN_MS = 5_000\n\nfunction collectTaskAcksFromTurns(turns: readonly SessionTurn[]): TaskAckHistory {\n const taskIds = new Set<string>()\n const outputPaths = new Map<string, number>()\n // wait_task call ids → task ids, resolved against their tool_result:\n // only a wait that RETURNED exit info counts as an acknowledgment\n // (timeouts leave the eventual exit un-delivered — see the live\n // `tool:after` suppression listener, whose semantics this mirrors).\n const pendingWaits = new Map<string, string>()\n for (const turn of turns) {\n for (const block of turn.content) {\n if (block.type === 'text') {\n if (block.text.startsWith('<task-notification>')) {\n const match = block.text.match(/<task-id>([^<]+)<\\/task-id>/)\n if (match)\n taskIds.add(match[1]!)\n }\n continue\n }\n if (block.type === 'tool_call') {\n if (block.name === 'shell_kill' && typeof block.input.task_id === 'string') {\n taskIds.add(block.input.task_id)\n }\n else if (block.name === 'wait_task' && typeof block.input.task_id === 'string') {\n pendingWaits.set(block.id, block.input.task_id)\n }\n else if (block.name === 'read_file' || block.name === 'read') {\n for (const readPath of readFileInputPaths(block.input)) {\n const path = pathResolve(readPath)\n outputPaths.set(path, Math.max(outputPaths.get(path) ?? 0, turn.createdAt))\n }\n }\n continue\n }\n if (block.type === 'tool_result' && !block.isError) {\n const waitedTaskId = pendingWaits.get(block.callId)\n if (waitedTaskId !== undefined) {\n const text = typeof block.output === 'string' ? block.output : toolResultToText(block.output)\n if (text.startsWith('Task '))\n taskIds.add(waitedTaskId)\n }\n }\n }\n }\n return { taskIds, outputPaths }\n}\n\n/**\n * Wire format for a stall-watchdog signal. Distinct outer tag from\n * `<task-notification>` so the model can tell \"still running, but quiet\"\n * apart from \"terminated\". Fields mirror {@link TaskStallInfo}.\n */\nfunction renderTaskStallXml(info: TaskStallInfo): string {\n return [\n '<task-stall>',\n ` <task-id>${escapeXml(info.taskId)}</task-id>`,\n ` <command>${escapeXml(info.command)}</command>`,\n ` <output-file>${escapeXml(info.outputPath)}</output-file>`,\n ` <stalled-for-ms>${info.stalledForMs}</stalled-for-ms>`,\n ` <bytes-written>${info.bytesWritten}</bytes-written>`,\n ` <hint>The task is still running but has produced no output for the reported window. It may be stuck at an interactive prompt — read the output file tail; if it ends in a question, kill it with shell_kill and re-run with piped input or a --yes flag.</hint>`,\n '</task-stall>',\n ].join('\\n')\n}\n\n/**\n * Agent-scoped notification state {@link drainTaskNotifications} reads and\n * updates. Passed explicitly rather than closed over so the mutation set is\n * visible at the call site: three collections in, one list of content blocks\n * out.\n */\ninterface TaskNotificationState {\n /** PUSH source: exits queued by `background:exit` since the last run. */\n pending: Map<string, TaskExitInfo>\n /** Stall notices queued by the background watchdog. */\n pendingStalls: Map<string, TaskStallInfo>\n /** Latch of task ids the model has already been told about. */\n notified: Set<string>\n}\n\ninterface DrainTaskNotificationsInput {\n state: TaskNotificationState\n executionContext: ExecutionContext\n executionHandle: ExecutionHandle | null | undefined\n behavior: ResolvedBehavior\n /**\n * Runs the live `listBackground` poll: through the run's durable runtime,\n * which journals it in replay mode.\n */\n journalSweep: <T>(sweep: () => Promise<T>) => Promise<T>\n session: Session | null | undefined\n /** Runtime turn view, used as the ack source when no session is bound. */\n turns: readonly SessionTurn[]\n hooks: Hookable<AgentHooks>\n}\n\n/**\n * Reconcile + drain pending background-task notifications.\n *\n * Each exit becomes a `<task-notification>` text block prepended to the user\n * turn so the model sees task completions on its very next prompt, without\n * polling. Two sources, merged by taskId:\n *\n * 1. PUSH — the agent-scoped queue populated by `background:exit` since the\n * last `run()` (in-process contexts fire `onExit`).\n * 2. PULL — a `listBackground` sweep for terminated tasks the model hasn't\n * been told about. This is what makes remote / durable contexts work:\n * they have no legal way to push from a timer into the host (journal\n * rules), so the loop polls at the run boundary instead.\n * `endedAt - startedAt` reproduces `durationMs` without depending on\n * sweep timing.\n *\n * The `background:reconcile` hook fires on the merged list INSIDE the run()\n * await chain — the journalable seam for durable hosts (see the hook's doc).\n * Entries suppressed earlier (`shell_kill`, `read_file`, `wait_task`) are\n * absent from both sources via the `notified` latch. See\n * `docs/RUN_IN_BACKGROUND.md` §Completion delivery.\n *\n * In replay mode the live `listBackground` poll goes through `journalSweep` so it\n * records as one journaled side effect (replay returns the recorded snapshot,\n * keeping `exits.length` — and therefore the conditional hook's journal\n * position — stable across attempts). Everything downstream of the snapshot is\n * pure over journaled / replayed inputs (session-turn acks, duration\n * derivation), so journaling the poll is enough to make the whole reconcile\n * deterministic.\n */\nexport async function drainTaskNotifications(input: DrainTaskNotificationsInput): Promise<SessionContentBlock[]> {\n const { state, executionContext, executionHandle, behavior, journalSweep, session, turns, hooks } = input\n\n const reconciled = new Map<string, TaskExitInfo>(state.pending)\n state.pending.clear()\n\n if (executionContext.listBackground && executionHandle\n && typeof behavior.tasksDir === 'string' && behavior.tasksDir.length > 0) {\n try {\n const listBackground = executionContext.listBackground\n const handle = executionHandle\n const entries = await journalSweep(() => listBackground(handle))\n // Durable dedupe: the in-memory `notified` latch dies with this agent\n // instance, but durable hosts reconstruct the agent per invocation while\n // the remote registry keeps its terminated entries. The persisted turn\n // history carries the acknowledgments (notification blocks, kills, waits,\n // reads) — re-derive the latch from it so a fresh agent on a resumed\n // session never re-notifies. See {@link collectTaskAcksFromTurns}.\n //\n // Scan the FULL persisted history (`session.turns`), not the\n // runtime-filtered `turns` view: the runtime view drops subagent-run\n // turns (a subagent's `shell_kill` still counts as an ack) and unresolved\n // tool_uses, and the built-in compaction is marker-based\n // (`compact-summary` replaces turns at the WIRE level only — originals\n // stay persisted), so the evidence survives compaction by contract.\n const acks = entries.some(e => e.status !== 'running')\n ? collectTaskAcksFromTurns(session ? session.turns : turns)\n : undefined\n for (const entry of entries) {\n if (entry.status === 'running' || state.notified.has(entry.taskId) || reconciled.has(entry.taskId))\n continue\n if (acks) {\n if (acks.taskIds.has(entry.taskId))\n continue\n // A historical read of the output file acks the exit only when it\n // happened after the task ended, with a skew margin because the two\n // timestamps come from different clock domains (see\n // READ_ACK_CLOCK_SKEW_MARGIN_MS). Without `endedAt` we can't order\n // the two — fail open (redundant notification beats false\n // suppression).\n const readAt = acks.outputPaths.get(pathResolve(entry.outputPath))\n if (readAt !== undefined && entry.endedAt !== undefined\n && readAt >= entry.endedAt + READ_ACK_CLOCK_SKEW_MARGIN_MS) {\n continue\n }\n }\n reconciled.set(entry.taskId, {\n taskId: entry.taskId,\n status: entry.status,\n exitCode: entry.exitCode ?? 0,\n ...(entry.signal ? { signal: entry.signal } : {}),\n outputPath: entry.outputPath,\n durationMs: Math.max(0, (entry.endedAt ?? entry.startedAt) - entry.startedAt),\n command: entry.command,\n })\n }\n }\n catch (err) {\n // A failing sweep must not block the run — push-fed entries still drain;\n // the pull side retries next run.\n if (process.env.ZIDANE_DEBUG)\n process.stderr.write(`[zidane/agent] background reconcile failed: ${err instanceof Error ? err.message : String(err)}\\n`)\n }\n }\n\n const reconcileCtx = { exits: [...reconciled.values()] }\n if (reconcileCtx.exits.length > 0)\n await hooks.callHook('background:reconcile', reconcileCtx)\n // Latch on the PRE-hook set: a handler that filters an exit out is deciding\n // the model never sees it — without the latch the pull sweep would resurface\n // the same exit on every subsequent run.\n for (const taskId of reconciled.keys()) {\n state.notified.add(taskId)\n // An exit supersedes any still-pending stall for the same task.\n state.pendingStalls.delete(taskId)\n }\n\n const drained: SessionContentBlock[] = []\n for (const notif of reconcileCtx.exits) {\n drained.push({ type: 'text', text: renderTaskNotificationXml(notif) })\n }\n if (state.pendingStalls.size > 0) {\n for (const stall of state.pendingStalls.values()) {\n drained.push({ type: 'text', text: renderTaskStallXml(stall) })\n }\n state.pendingStalls.clear()\n }\n return drained\n}\n\n/**\n * Agent-lifetime background-task tracking: enqueue exit / stall\n * notifications and suppress the ones the model already learned about.\n */\nexport function installBackgroundTaskTracking(rt: AgentRuntime): void {\n const { hooks, pendingTaskNotifications, pendingStallNotifications, notifiedTaskIds } = rt\n // Background-task plumbing.\n //\n // Two listeners, both registered for the agent's lifetime:\n //\n // 1. `background:exit` → enqueue a notification keyed by `taskId`.\n // The shell tool body fires this hook from its `execBackground`\n // `onExit` callback; the context-owned `child.on('close')` is what\n // settles the lifecycle. Map.set overwrites by id so a duplicate\n // enqueue (defensive — shouldn't happen with the context's at-most-\n // once settle latch) doesn't multiply notifications.\n //\n // 2. `tool:after` → suppress the would-be notification when the model\n // already learned about the exit through other means:\n // - `shell_kill`: the tool's own return value tells the model the\n // task is dead. Delete by `task_id` from the call's input.\n // - `wait_task`: a wait that returned exit info tells the model the\n // outcome. A timed-out wait does not suppress.\n // - `read_file` / `read`: the model reading the task's output file\n // is a strong \"I'm aware of this task\" signal. Delete by\n // matching the `path` argument against any pending notification's\n // outputPath.\n //\n // Suppression fires AFTER the body settled, so the enqueue (in onExit)\n // and the delete (in tool:after) happen in that order — Map.delete is\n // idempotent against a missing key. See `docs/RUN_IN_BACKGROUND.md`\n // §Completion delivery.\n hooks.hook('background:exit', (ctx) => {\n pendingTaskNotifications.set(ctx.taskId, {\n taskId: ctx.taskId,\n status: ctx.status,\n exitCode: ctx.exitCode,\n ...(ctx.signal ? { signal: ctx.signal } : {}),\n outputPath: ctx.outputPath,\n durationMs: ctx.durationMs,\n command: ctx.command,\n })\n // The exit supersedes a pending \"no output for a while\" signal —\n // showing both would read as contradictory state to the model.\n pendingStallNotifications.delete(ctx.taskId)\n })\n hooks.hook('background:stall', (ctx) => {\n pendingStallNotifications.set(ctx.taskId, {\n taskId: ctx.taskId,\n command: ctx.command,\n outputPath: ctx.outputPath,\n stalledForMs: ctx.stalledForMs,\n bytesWritten: ctx.bytesWritten,\n })\n })\n // Suppression marks the task as notified IN ADDITION to deleting the\n // pending entry — the pull-based reconcile at the next run start would\n // otherwise re-discover the terminated task and re-notify.\n const suppressTaskNotification = (taskId: string): void => {\n pendingTaskNotifications.delete(taskId)\n pendingStallNotifications.delete(taskId)\n notifiedTaskIds.add(taskId)\n }\n hooks.hook('tool:after', (ctx) => {\n if (ctx.name === 'shell_kill') {\n const taskId = ctx.input?.task_id\n if (typeof taskId === 'string')\n suppressTaskNotification(taskId)\n return\n }\n if (ctx.name === 'wait_task') {\n // Only a wait that RETURNED exit info means the model knows the\n // outcome. Timeouts leave the task running — its eventual exit is\n // still news, so the pending entry must survive.\n const taskId = ctx.input?.task_id\n const timedOut = typeof ctx.result === 'string' && ctx.result.startsWith(WAIT_TASK_TIMED_OUT_PREFIX)\n if (typeof taskId === 'string' && !timedOut && typeof ctx.result === 'string' && ctx.result.startsWith('Task '))\n suppressTaskNotification(taskId)\n return\n }\n if (ctx.name === 'read_file' || ctx.name === 'read') {\n for (const rawPath of readFileInputPaths(ctx.input))\n suppressForRead(rawPath)\n }\n })\n\n function suppressForRead(rawPath: string): void {\n // The shell tool returns absolute paths in its background-mode\n // result, so the model normally reads back with the same absolute\n // string. But a paranoid model (or a slash-command, or copy-paste\n // typo) can hand us a relative / `~/…` / non-canonical path that\n // resolves to the same file. Normalize both sides via\n // `path.resolve` so suppression survives those cases.\n //\n // `resolve` against `process.cwd()` matches the read_file tool's\n // own resolution behavior (it joins against the execution\n // handle's cwd, which equals process.cwd() for the default\n // process context). For sandbox/docker contexts the handle's\n // cwd may differ; the worst-case there is a missed suppression\n // (model gets a redundant notification it can ignore) — never a\n // false suppression.\n const requested = pathResolve(rawPath)\n for (const notif of pendingTaskNotifications.values()) {\n if (pathResolve(notif.outputPath) === requested) {\n suppressTaskNotification(notif.taskId)\n return\n }\n }\n // Reading a STALLED (still-running) task's log clears the stall\n // signal only — no `notifiedTaskIds` latch, the task's eventual\n // exit is still news the model must receive.\n for (const stall of pendingStallNotifications.values()) {\n if (pathResolve(stall.outputPath) === requested) {\n pendingStallNotifications.delete(stall.taskId)\n return\n }\n }\n }\n}\n","/**\n * Agent run loop: drives turns until the run ends, and owns the\n * between-turn policy — stop-reason recovery, usage / budget accounting,\n * auto-compaction, steering injection, follow-up messages, and abort.\n *\n * One turn's execution lives in `loop-turn` (provider streaming in\n * `loop-stream`, tool dispatch and batching in `loop-tool-*`).\n */\n\nimport type { AutoCompactRunState } from './loop-auto-compact'\nimport type { LoopContext } from './loop-context'\nimport type { TurnResult } from './loop-turn'\nimport type { AgentStats, TurnUsage } from './types'\nimport { formatMaxTurnsWarning } from './behaviors/max-turns-warning'\nimport { AgentBudgetExceededError, AgentLengthResumeExhaustedError } from './errors'\nimport { maybeAutoCompact } from './loop-auto-compact'\nimport { seedCompactBaseline } from './loop-compaction'\nimport { journaledDecision, throwIfSuspended } from './loop-context'\nimport { enforceSchemaOutput, executeTurn } from './loop-turn'\n\nexport { applyThinkingDecay } from './behaviors/thinking-decay'\nexport type { ResolvedAutoCompact } from './loop-auto-compact'\nexport { resolveAutoCompact } from './loop-auto-compact'\nexport type { MediaAgeoutResult, TailCompactionResult } from './loop-compaction'\nexport { applyCompactSummaryCutoff, applyMediaAgeout, applyMediaBudget, applyTailCompaction, COMPACT_CHUNK_TURNS, DEFAULT_COMPACT_THRESHOLD_BYTES, MEDIA_INLINE_MAX_BYTES, resolveTailCompactionThreshold } from './loop-compaction'\nexport type { LoopContext, RunUsageMirror, SubagentInheritance } from './loop-context'\nexport { DEFAULT_HOOK_TIMEOUT_MS } from './loop-context'\nexport type { StaleReadElisionOptions, StaleReadElisionResult } from './loop-stale-reads'\nexport { applyStaleReadElision, collectNewlyStaleReadPaths, renderStaleReadNotice, STALE_READ_STUB } from './loop-stale-reads'\nexport { INTERRUPT_MESSAGE_FOR_TOOL_USE, SHELL_CASCADE_CANCEL_MESSAGE, TOOL_USE_CANCELLED_MESSAGE, TOOL_USE_SKIPPED_MESSAGE, unwrapDispatchCalls } from './loop-tool-dispatch'\n\n/**\n * Build the `agent:abort` ctx, attaching the run id and (when present) the\n * string reason carried on `signal.reason` — lets telemetry correlate the\n * abort with its run and distinguish a reasoned abort (e.g. a guard) from a\n * bare `agent.abort()`.\n */\nfunction buildAbortCtx(ctx: LoopContext): { runId?: string, reason?: string } {\n const reason = ctx.signal.reason\n return {\n ...(ctx.runId ? { runId: ctx.runId } : {}),\n ...(typeof reason === 'string' && reason.length > 0 ? { reason } : {}),\n }\n}\n\n/**\n * Consecutive stop-reason recovery counters and their bounds, owned by one\n * `runLoop` invocation. See {@link createStopRecoveryCaps} for what each\n * bound means and {@link stopRecoveryCapReached} for how they trip.\n */\ninterface StopRecoveryCaps {\n pauseCap: number\n consecutiveEmptyPauseTurns: number\n maxConsecutiveLengthResumes: number\n consecutiveLengthResumes: number\n maxConsecutiveEmptyLengthResumes: number\n consecutiveEmptyLengthResumes: number\n maxConsecutiveRefusalResumes: number\n consecutiveRefusalResumes: number\n}\n\nfunction createStopRecoveryCaps(ctx: LoopContext): StopRecoveryCaps {\n return {\n // Consecutive `pause_turn` recovery counter — incremented every time a\n // turn returns `pauseEmpty: true` (Anthropic 4.6+ stopped with no tools\n // and no text), reset on any turn that produces visible output. When\n // the counter REACHES `maxConsecutivePauseTurns`, the loop ends the run with\n // the last turn's `finishReason: 'pause'` instead of injecting another\n // \"Please continue.\" Defaults to 0 (UNLIMITED): empty pauses are vanishingly\n // rare in practice and silently ending a live trajectory is worse than the\n // tail risk of a spin. Set a positive value to re-arm the cap; the budget\n // breakers (`maxCostUsd`/`maxTotalTokens`) are the precise runaway backstop.\n pauseCap: ctx.behavior.maxConsecutivePauseTurns ?? 0,\n consecutiveEmptyPauseTurns: 0,\n\n // Consecutive output-cap (`max_tokens`) resume counter + bound. Armed only\n // when the caller opted into `behavior.resumeOnMaxTokens`. Bounds how many\n // times in a row the loop injects a continue after a `finishReason: 'length'`\n // turn so a model that can't make progress can't loop forever. 8 × the\n // model's max output is an enormous single response — generous enough to\n // assemble any real answer, finite enough to stop a pathological spin.\n maxConsecutiveLengthResumes: ctx.behavior.maxConsecutiveLengthResumes ?? 8,\n consecutiveLengthResumes: 0,\n\n // Tighter sub-bound for length turns with no visible text and no tool\n // calls — the pure reasoning spin. A text-producing truncation makes\n // progress on every resume (the halves concatenate), so the generous\n // bound above fits it; a reasoning-only turn makes none on providers\n // that drop prior reasoning (the resume restarts thinking from scratch\n // on an 8-token \"Please continue.\"), so each extra resume just re-burns\n // the full output budget. Two spins are enough to distinguish \"unlucky\n // truncation\" from \"stuck\"; the trip throws instead of breaking cleanly\n // because the run has provably produced nothing a consumer could use.\n maxConsecutiveEmptyLengthResumes: 2,\n consecutiveEmptyLengthResumes: 0,\n\n // Consecutive refusal (`content-filter`) resume counter + bound. Unlike the\n // pause/length recoveries this one is armed by default: a refusal stop with\n // no recovery ends the run silently mid-task (empty assistant turn, status\n // \"completed\"), which reads as a stalled session. Refusals are often\n // transient — a retry with a synthetic continue usually resumes the\n // trajectory — but a hard refusal repeats forever at full input cost, so\n // the bound stays small (`behavior.maxConsecutiveRefusalResumes`, default 3;\n // `0` disables the recovery — the gate lives in `executeTurn`). When it\n // trips, the loop breaks cleanly and the last turn's\n // `finishReason: 'content-filter'` stays visible in stats.\n maxConsecutiveRefusalResumes: ctx.behavior.maxConsecutiveRefusalResumes ?? 3,\n consecutiveRefusalResumes: 0,\n }\n}\n\n/**\n * Advance the stop-reason recovery counters for a finished turn. Returns\n * `true` when a bound tripped and the loop must `break`; throws\n * `AgentLengthResumeExhaustedError` on a reasoning-only length spin.\n */\nfunction stopRecoveryCapReached(caps: StopRecoveryCaps, result: TurnResult): boolean {\n // Pause-turn cap. Increment on consecutive empty pauses, reset on\n // any productive turn. The check is post-`usage` so the offending\n // turn's tokens are billed back to the run AND the `usage` hook\n // fires for that turn before the loop exits — telemetry consumers\n // never see a missing-usage event for an in-`turnUsages` entry.\n // When the cap trips, we `break` cleanly: the last entry in\n // `turnUsages` carries `finishReason: 'pause'`, so consumers can\n // detect pause exhaustion from `stats` alone. We do NOT fire\n // `agent:abort` here — this is graceful loop termination, not a\n // user-driven cancel, and host code keyed on `agent:abort` would\n // misclassify it as such.\n if (result.pauseEmpty) {\n caps.consecutiveEmptyPauseTurns += 1\n if (caps.pauseCap > 0 && caps.consecutiveEmptyPauseTurns >= caps.pauseCap)\n return true\n }\n else {\n caps.consecutiveEmptyPauseTurns = 0\n }\n\n // Output-cap (`max_tokens`) resume bound — mirror of the pause cap for\n // the opt-in continue-on-length path. `executeTurn` only returns\n // `lengthTruncated` when `resumeOnMaxTokens` is set, so this is inert\n // otherwise. Breaks cleanly (no `agent:abort`) leaving the last turn's\n // `finishReason: 'length'` visible in `turnUsages`.\n if (result.lengthTruncated) {\n caps.consecutiveLengthResumes += 1\n caps.consecutiveEmptyLengthResumes = result.lengthEmpty ? caps.consecutiveEmptyLengthResumes + 1 : 0\n if (caps.consecutiveEmptyLengthResumes >= caps.maxConsecutiveEmptyLengthResumes)\n throw new AgentLengthResumeExhaustedError({ consecutiveEmptyTurns: caps.consecutiveEmptyLengthResumes })\n if (caps.consecutiveLengthResumes >= caps.maxConsecutiveLengthResumes)\n return true\n }\n else {\n caps.consecutiveLengthResumes = 0\n caps.consecutiveEmptyLengthResumes = 0\n }\n\n // Refusal (`content-filter`) resume bound — mirror of the caps above.\n // Breaks cleanly (no `agent:abort`) leaving the last turn's\n // `finishReason: 'content-filter'` visible in `turnUsages` so consumers\n // (e.g. the TUI's run-end banner) can tell the user why the run ended.\n if (result.refusalResumed) {\n caps.consecutiveRefusalResumes += 1\n if (caps.consecutiveRefusalResumes >= caps.maxConsecutiveRefusalResumes)\n return true\n }\n else {\n caps.consecutiveRefusalResumes = 0\n }\n return false\n}\n\n/**\n * Fire `steer:inject` and append the message as a user turn. The id and clock\n * reads stay in this order: durable hosts journal both.\n */\nasync function injectUserMessage(ctx: LoopContext, message: string): Promise<void> {\n await ctx.hooks.callHook('steer:inject', { message })\n const userMsg = ctx.provider.userMessage(message)\n ctx.turns.push({\n id: await ctx.generateTurnId(),\n runId: ctx.runId,\n role: userMsg.role,\n content: userMsg.content,\n createdAt: await ctx.clock.now(),\n })\n}\n\n/**\n * Consume a queued message the boundary decision took. On a durable replay the\n * decision comes from the journal and the live queue may not hold it (or holds\n * it again because a deterministic producer such as middleware re-queued it),\n * so only a matching head is removed.\n */\nfunction takeHead(queue: string[], message: string): void {\n if (queue[0] === message)\n queue.shift()\n}\n\n/**\n * A resumed run's usage so far: its turns the dead process saved, counted\n * once, so the run's totals (a spawned child's reported spend, the run\n * record) read as they would have without the process death. Mirrored to\n * `ctx.usageMirror`.\n */\nfunction savedRunUsage(ctx: LoopContext): { totalIn: number, totalOut: number, totalCacheRead: number, totalCacheCreation: number, totalCost: number, turnUsages: TurnUsage[] } {\n const saved = { totalIn: 0, totalOut: 0, totalCacheRead: 0, totalCacheCreation: 0, totalCost: 0, turnUsages: [] as TurnUsage[] }\n if (!ctx.resume)\n return saved\n for (const t of ctx.turns) {\n if (t.runId !== ctx.runId || t.role !== 'assistant' || t.aborted || !t.usage)\n continue\n saved.totalIn += t.usage.input\n saved.totalOut += t.usage.output\n saved.totalCacheRead += t.usage.cacheRead ?? 0\n saved.totalCacheCreation += t.usage.cacheCreation ?? 0\n saved.totalCost += t.usage.cost ?? 0\n saved.turnUsages.push(t.usage)\n }\n if (ctx.usageMirror) {\n ctx.usageMirror.totalIn = saved.totalIn\n ctx.usageMirror.totalOut = saved.totalOut\n ctx.usageMirror.totalCacheRead = saved.totalCacheRead\n ctx.usageMirror.totalCacheCreation = saved.totalCacheCreation\n ctx.usageMirror.cost += saved.totalCost\n ctx.usageMirror.turnUsage.push(...saved.turnUsages)\n }\n return saved\n}\n\n/**\n * Drive turns until the run ends and return the run's stats.\n *\n * The loop ends when a turn ends the run with no queued follow-up, when\n * `behavior.maxTurns` runs out, when a stop-recovery cap trips, on abort,\n * or on `Agent.suspend` (throws `RunSuspendedError`). It also enforces the\n * run budgets and runs auto-compaction between turns.\n *\n * @param ctx - The per-run context. `ctx.turns` gains every turn the run produces.\n * @returns Cumulative token totals, turn count, elapsed ms and per-turn usage. `output` is set for schema-enforced runs.\n * @throws {AgentBudgetExceededError} When `maxCostUsd`, `maxTotalTokens` or `maxWallMs` is crossed after a turn.\n * @throws {AgentLengthResumeExhaustedError} After repeated length-truncated turns that produced no text.\n */\nexport async function runLoop(ctx: LoopContext): Promise<AgentStats> {\n // A resumed run starts from the usage its saved turns carry; a fresh one from zero.\n const saved = savedRunUsage(ctx)\n let { totalIn, totalOut, totalCacheRead, totalCacheCreation, totalCost } = saved\n const turnUsages = saved.turnUsages\n const startTime = Date.now()\n // Default to no cap — runs are bounded by `result.ended` and the abort\n // signal. Callers wanting a runaway-loop safety net set `behavior.maxTurns`.\n const maxTurns = ctx.behavior.maxTurns ?? Number.POSITIVE_INFINITY\n let turnsCompleted = 0\n // Set when the loop breaks on an abort decision, so the exit path reuses\n // that (journaled) verdict instead of re-reading the live signal.\n let abortedBreak = false\n const stopCaps = createStopRecoveryCaps(ctx)\n\n // Wall-clock deadline anchor. Read through `ctx.clock` (NOT `Date.now()`)\n // so a replaying run gets a replay-stable start: the same invocation\n // replays with the same anchor and the breach trips at the same turn\n // boundary every time. Only sampled when the knob is set: on a replay\n // runtime each `clock.now()` call can cost a journal entry, and we don't\n // spend one on runs that never check the deadline.\n const wallDeadlineActive = typeof ctx.behavior.maxWallMs === 'number' && Number.isFinite(ctx.behavior.maxWallMs) && ctx.behavior.maxWallMs > 0\n // A resumed run counts the wall time it spent before the process death.\n const wallStartMs = wallDeadlineActive ? (await ctx.clock.now()) - (ctx.resume?.wallMs ?? 0) : 0\n\n // Remaining-turn threshold for the wrap-up warning. Validated once:\n // requires a finite cap, a positive warning value strictly below it.\n const maxTurnsWarnAt\n = Number.isFinite(maxTurns)\n && typeof ctx.behavior.maxTurnsWarning === 'number'\n && Number.isFinite(ctx.behavior.maxTurnsWarning)\n && ctx.behavior.maxTurnsWarning > 0\n && ctx.behavior.maxTurnsWarning < maxTurns\n ? Math.floor(ctx.behavior.maxTurnsWarning)\n : undefined\n let maxTurnsWarned = false\n\n // Track time-to-first-token across the entire run. Earliest of the first\n // stream:text, stream:thinking, or tool:before event latches the value.\n const ttft = { mark: undefined as number | undefined }\n const markTtft = () => {\n if (ttft.mark === undefined)\n ttft.mark = Date.now() - ctx.runStartMs\n }\n const unregisterTtftText = ctx.hooks.hook('stream:text', markTtft)\n const unregisterTtftThinking = ctx.hooks.hook('stream:thinking', markTtft)\n const unregisterTtftTool = ctx.hooks.hook('tool:before', markTtft)\n\n // Loop-native auto-compaction state (see `maybeAutoCompact`). Circuit\n // breaker resets every fresh run, but the hysteresis baseline is SEEDED\n // from the latest persisted `compact-summary` marker so the post-compact\n // cooldown survives a resume. Without the seed, a resumed run starts with\n // `lastCompactedInputTokens === undefined` → cooldown disabled → a session\n // that is still over threshold immediately re-compacts over the prior\n // summary (summary-of-a-summary degradation). See `seedCompactBaseline`.\n const autoCompactState: AutoCompactRunState = {\n lastCompactedInputTokens: seedCompactBaseline(ctx.turns),\n consecutiveFailures: 0,\n disabled: false,\n }\n\n try {\n // A resumed run whose last saved turn already ended it has nothing left to do.\n if (ctx.resume?.ended)\n return { totalIn, totalOut, totalCacheRead, totalCacheCreation, turns: 0, elapsed: Date.now() - startTime, turnUsage: turnUsages }\n // A resumed run keeps its turn indices: they are the `turn` of its step keys.\n for (let turn = ctx.resume?.turn ?? 0; turn < maxTurns; turn++) {\n ctx.durable.turn = turn\n throwIfSuspended(ctx)\n if (await journaledDecision(ctx, 'loop-abort', () => ctx.signal.aborted)) {\n abortedBreak = true\n await ctx.hooks.callHook('agent:abort', buildAbortCtx(ctx))\n break\n }\n\n // Pass the run-cumulative usage state into the turn so its\n // `turn:after` hook can carry `cumulativeUsage` (priorUsage + this\n // turn's usage) without consumers re-accumulating. Includes the\n // current turn count (1-indexed including this one) so dashboards\n // can plot per-turn deltas without an external counter.\n const result = await executeTurn(ctx, turn, {\n input: totalIn,\n output: totalOut,\n cacheRead: totalCacheRead,\n cacheCreation: totalCacheCreation,\n priorCost: totalCost,\n priorTurns: turnsCompleted,\n })\n turnsCompleted = turn + 1\n\n totalIn += result.usage.input\n totalOut += result.usage.output\n totalCacheRead += result.usage.cacheRead ?? 0\n totalCacheCreation += result.usage.cacheCreation ?? 0\n totalCost += result.usage.cost ?? 0\n if (!result.resumedCalls)\n turnUsages.push(result.usage)\n\n // Keep the caller-visible mirror in sync per turn so throw paths\n // (budget breach below, mid-stream abort inside `executeTurn`)\n // still expose the partial spend. See `LoopContext.usageMirror`.\n if (ctx.usageMirror) {\n ctx.usageMirror.totalIn = totalIn\n ctx.usageMirror.totalOut = totalOut\n ctx.usageMirror.totalCacheRead = totalCacheRead\n ctx.usageMirror.totalCacheCreation = totalCacheCreation\n ctx.usageMirror.turns = turnsCompleted\n ctx.usageMirror.cost += result.usage.cost ?? 0\n if (!result.resumedCalls)\n ctx.usageMirror.turnUsage.push(result.usage)\n }\n\n await ctx.hooks.callHook('usage', { turn, turnId: result.turnId, usage: result.usage, totalIn, totalOut })\n\n // Suspended while the turn's tool calls ran: they finished and their results are saved, the next model call waits for the resume.\n if (!result.ended)\n throwIfSuspended(ctx)\n\n if (stopRecoveryCapReached(stopCaps, result))\n break\n\n // Check abort after turn completes. This also catches a repeat-guard\n // abort: the guard's `tool:gate` handler called `abortController.abort()`\n // when a tracked tool's consecutive-identical streak hit its threshold,\n // which flips `ctx.signal.aborted`. A `repeat-guard:exceeded` event with\n // `action: 'abort'` fired first, so consumers can distinguish it from a\n // user-driven cancel.\n if (await journaledDecision(ctx, 'loop-abort', () => ctx.signal.aborted)) {\n abortedBreak = true\n await ctx.hooks.callHook('agent:abort', buildAbortCtx(ctx))\n break\n }\n\n // Run-level budget circuit breaker. Post-turn so the breaching\n // turn's usage is visible to consumers via `turn:after` + `usage`\n // hooks before the throw lands — a host can log the spend that\n // tripped the cap and then handle the typed error without scraping\n // a stats blob from a half-built `AgentStats`.\n //\n // Token ledger here sums `input + output` only. Cache reads/creates\n // are billed at a discount; including them at par would shift the\n // semantic away from \"what does this run cost in tokens\" toward\n // \"how much context did we shovel through\", which is rarely the\n // operator's actual concern. Cost path uses provider-reported\n // numbers directly so the discount is already baked in.\n const breach = checkRunBudget({\n maxCostUsd: ctx.behavior.maxCostUsd,\n maxTotalTokens: ctx.behavior.maxTotalTokens,\n maxWallMs: ctx.behavior.maxWallMs,\n cost: totalCost,\n tokens: totalIn + totalOut,\n // Same journaled-clock source as the anchor — replay-stable pairs.\n elapsedMs: wallDeadlineActive ? (await ctx.clock.now()) - wallStartMs : 0,\n })\n if (breach) {\n throw new AgentBudgetExceededError(breach)\n }\n\n // Loop-native auto-compaction. Evaluated at every turn boundary —\n // mid-run tool loops AND the final turn, so a resumed session starts\n // already compacted. Runs AFTER abort/budget checks so compaction never\n // spends an extra summary call when the just-finished turn already ended\n // the run. No-op unless `behavior.autoCompact` is enabled and the last\n // turn's effective input crossed the threshold; never throws (failures\n // fall through to the reactive `context_exceeded` net). When it fires it\n // appends a `compact-summary` marker to `ctx.turns`, which the next\n // `executeTurn`'s `applyCompactSummaryCutoff` acts on.\n await maybeAutoCompact(ctx, turn, result.usage, autoCompactState)\n\n // Pause and steering are one boundary decision: a pause leaves the\n // steering queue for the next run. The steering text rides the decision\n // so a durable replay injects what the live run did.\n const boundary = await journaledDecision(ctx, 'loop-boundary', () => {\n const paused = ctx.pauseSignal?.aborted === true && !result.ended\n return { paused, steer: paused ? null : ctx.steeringQueue[0] ?? null }\n })\n\n // Pause at this boundary: the turn and its tool results are saved, the\n // model has more to do. A run that just ended has nothing to pause.\n if (boundary.paused) {\n return {\n totalIn,\n totalOut,\n totalCacheRead,\n totalCacheCreation,\n turns: turn + 1,\n elapsed: Date.now() - startTime,\n turnUsage: turnUsages,\n paused: true,\n ...(ttft.mark !== undefined ? { timeTillFirstTokenMs: ttft.mark } : {}),\n }\n }\n\n // Check steering queue after tool execution\n if (boundary.steer !== null) {\n takeHead(ctx.steeringQueue, boundary.steer)\n await injectUserMessage(ctx, boundary.steer)\n continue\n }\n\n // Read before the nudge drain, which also depends on it. Only an\n // ended run consumes a follow-up, so only then is it a decision.\n const followUp = result.ended\n ? await journaledDecision(ctx, 'loop-follow-up', () => ctx.followUpQueue[0] ?? null)\n : null\n\n // Drain non-interrupting middleware nudges at the turn\n // boundary. These ride their own queue — see the\n // `nonInterruptingNudgeQueue` doc on `LoopContext` for why pushing them\n // into `steeringQueue` would skip sibling tool calls mid-batch.\n // Only drop them when the run is truly over (ended with no queued\n // follow-up): a follow-up continues the run, and the model may\n // resume calling the over-budget tool, so the nudge stays relevant.\n if (ctx.nonInterruptingNudgeQueue && ctx.nonInterruptingNudgeQueue.length > 0) {\n if (result.ended && followUp === null) {\n ctx.nonInterruptingNudgeQueue.length = 0\n }\n else {\n while (ctx.nonInterruptingNudgeQueue.length > 0) {\n const nudge = ctx.nonInterruptingNudgeQueue.shift()!\n await injectUserMessage(ctx, nudge)\n }\n }\n }\n\n // Turn-cap proximity warning (opt-in via `maxTurnsWarning`). Fires\n // once, after the first non-ended turn that leaves at most `maxTurnsWarnAt`\n // turns remaining, so the model gets a deterministic chance to wrap\n // up instead of being killed mid-loop by the cap with no closing\n // summary. `<=` + the fired flag (not `===`): a user-steer `continue`\n // above can skip this check on the exact threshold turn, and a\n // strict-equality match would then never fire at all.\n if (!result.ended && !maxTurnsWarned && maxTurnsWarnAt !== undefined && maxTurns - (turn + 1) <= maxTurnsWarnAt) {\n maxTurnsWarned = true\n const remaining = maxTurns - (turn + 1)\n const warning = formatMaxTurnsWarning(ctx.behavior.maxTurnsWarningMessage, { remaining, maxTurns })\n await injectUserMessage(ctx, warning)\n }\n\n if (result.ended) {\n // Check follow-up queue before finishing\n if (followUp !== null) {\n takeHead(ctx.followUpQueue, followUp)\n await injectUserMessage(ctx, followUp)\n continue\n }\n\n return {\n totalIn,\n totalOut,\n totalCacheRead,\n totalCacheCreation,\n turns: turn + 1,\n elapsed: Date.now() - startTime,\n turnUsage: turnUsages,\n output: result.output,\n ...(ttft.mark !== undefined ? { timeTillFirstTokenMs: ttft.mark } : {}),\n }\n }\n }\n\n // Exhausted exit — `maxTurns` ran out, a stop-recovery cap tripped, or an\n // abort `break` landed above. Schema-enforced runs must still produce\n // a verdict here, not only on the natural `result.ended` path: a run\n // that hits the turn cap mid-investigation would otherwise end\n // verdict-less. Aborts are exempt (a cancel means \"stop now\"),\n // and a zero-turn run has nothing to synthesize from.\n let exhaustedOutput: Record<string, unknown> | undefined\n if (\n ctx.behavior.schema\n && turnsCompleted > 0\n && !abortedBreak\n && !(await journaledDecision(ctx, 'loop-abort', () => ctx.signal.aborted))\n ) {\n const enforcement = await enforceSchemaOutput(ctx, ctx.clock.randomUUID())\n exhaustedOutput = enforcement.output\n totalIn += enforcement.usage.input\n totalOut += enforcement.usage.output\n totalCacheRead += enforcement.usage.cacheRead ?? 0\n totalCacheCreation += enforcement.usage.cacheCreation ?? 0\n turnUsages.push(enforcement.usage)\n if (ctx.usageMirror) {\n ctx.usageMirror.totalIn = totalIn\n ctx.usageMirror.totalOut = totalOut\n ctx.usageMirror.totalCacheRead = totalCacheRead\n ctx.usageMirror.totalCacheCreation = totalCacheCreation\n ctx.usageMirror.cost += enforcement.usage.cost ?? 0\n ctx.usageMirror.turnUsage.push(enforcement.usage)\n }\n // Same telemetry contract as in-loop turns: every `turnUsages` entry\n // gets a `usage` event. `turn` is the would-be next index.\n await ctx.hooks.callHook('usage', { turn: turnsCompleted, turnId: enforcement.turnId, usage: enforcement.usage, totalIn, totalOut })\n }\n\n return {\n totalIn,\n totalOut,\n totalCacheRead,\n totalCacheCreation,\n turns: turnsCompleted,\n elapsed: Date.now() - startTime,\n turnUsage: turnUsages,\n ...(exhaustedOutput !== undefined ? { output: exhaustedOutput } : {}),\n ...(ttft.mark !== undefined ? { timeTillFirstTokenMs: ttft.mark } : {}),\n }\n }\n finally {\n unregisterTtftText()\n unregisterTtftThinking()\n unregisterTtftTool()\n }\n}\n\n/**\n * Pure predicate for the run-level budget circuit breaker. Returns a\n * structured breach descriptor when the cost, token, or wall-clock ledger\n * has crossed its configured ceiling, otherwise `null`.\n *\n * Order of checks: cost first when both are set, because cost is the\n * direct dollar accounting operators set ceilings against — emitting a\n * `'tokens'` breach when both knobs would have tripped on the same turn\n * would hide the more user-actionable signal.\n *\n * `undefined` / `0` / non-positive / non-finite ceilings disable the\n * corresponding axis without protest, matching the established\n * `behavior.toolOutputBudget` semantic. Exported only for tests; the\n * loop is the sole production caller.\n */\nexport function checkRunBudget(input: {\n maxCostUsd?: number\n maxTotalTokens?: number\n maxWallMs?: number\n cost: number\n tokens: number\n elapsedMs?: number\n}): { limit: 'cost' | 'tokens' | 'wallClock', limitValue: number, actualValue: number } | null {\n const { maxCostUsd, maxTotalTokens, maxWallMs, cost, tokens, elapsedMs } = input\n if (typeof maxCostUsd === 'number' && Number.isFinite(maxCostUsd) && maxCostUsd > 0 && cost >= maxCostUsd) {\n return { limit: 'cost', limitValue: maxCostUsd, actualValue: cost }\n }\n if (typeof maxTotalTokens === 'number' && Number.isFinite(maxTotalTokens) && maxTotalTokens > 0 && tokens >= maxTotalTokens) {\n return { limit: 'tokens', limitValue: maxTotalTokens, actualValue: tokens }\n }\n if (typeof maxWallMs === 'number' && Number.isFinite(maxWallMs) && maxWallMs > 0 && typeof elapsedMs === 'number' && elapsedMs >= maxWallMs) {\n return { limit: 'wallClock', limitValue: maxWallMs, actualValue: elapsedMs }\n }\n return null\n}\n","/**\n * `agent.run()`: run setup (session record, hooks, bootstrap, prompt and\n * tool composition, behavior gates), the loop, and finalization on every\n * exit path.\n */\n\nimport type { Hookable } from 'hookable'\nimport type { ResolvedBehavior } from './agent-behavior'\nimport type { AgentHooks } from './agent-hooks'\nimport type { RunLease } from './agent-lease'\nimport type { RunDisposition } from './agent-run-finalize'\nimport type { RunToolset } from './agent-run-prompt'\nimport type { AgentRuntime } from './agent-runtime'\nimport type { AliasMaps } from './aliasing'\nimport type { InterceptorRegistry } from './extensions/hooks'\nimport type { LoopContext, ResolvedAutoCompact, RunUsageMirror } from './loop'\nimport type { Provider } from './providers'\nimport type { RunDurability } from './run-durability'\nimport type { Session, SessionRun } from './session'\nimport type { AgentClock, AgentRunOptions, AgentStats, ChildRunStats, FrozenPromptSections, ModelTarget, SessionContentBlock, SessionMessage, SessionTurn, SystemNote, ThinkingLevel } from './types'\nimport { DEFAULT_SPAWN_TIMEOUT_MS, resolveBehavior } from './agent-behavior'\nimport { ensureExecutionHandle, ensureSkillsResolved, warmup } from './agent-bootstrap'\nimport { openAgentRunDurability } from './agent-durable'\nimport { applyBehaviorTransforms, applyRunTransforms, applySkillPolicies } from './agent-extensions'\nimport { rehydrateActiveSkillsFromTurns, selectSeedTurns, validateAndPrepareResume } from './agent-history'\nimport { isKnownHookEvent } from './agent-hooks'\nimport { interceptBehavior, interceptRunOptions, interceptSkillActivation } from './agent-interceptors'\nimport { claimRunLease } from './agent-lease'\nimport { bindSessionHooks } from './agent-lifecycle'\nimport { prepareCheckpointRun, reopenSessionRun, resumePointFor } from './agent-resume'\nimport { createRunFinisher, createTurnPersistence, deactivateAllSkills, endSetupAbortedRun, isRunAbortCause, zeroRunStats } from './agent-run-finalize'\nimport { installRunGates } from './agent-run-gates'\nimport { composeRunPrompt } from './agent-run-prompt'\nimport { resetRunScope, syncRunCounter } from './agent-runtime'\nimport { drainTaskNotifications } from './agent-task-notifications'\nimport { replayToolSearchUnlocks } from './agent-tool-disclosure'\nimport { StaleEpochError } from './durable/errors'\nimport { AgentAbortedError, AgentBudgetExceededError, errorMessage, runErrorDetail } from './errors'\nimport { DEFAULT_HOOK_TIMEOUT_MS, resolveAutoCompact, runLoop } from './loop'\nimport { releaseContentRefCache } from './loop-wire'\nimport { shrinkPromptImages } from './media/shrink'\nimport { resolveModelTargets } from './model-targets'\nimport { buildPromptMessage, canonicalizePrompt } from './prompt'\nimport { committedSteps, journaledStep, LOOP_STEP_KINDS, replays, runClock } from './run-durability'\nimport { resumeChainRunIds, withExtensionSession } from './session'\nimport { resolveTimeoutMs, settleWithinTimeout } from './timeout'\nimport { CALL_TOOL_NAME } from './tools/call-tool'\nimport { DEFAULT_AGENT_CLOCK } from './types'\n\n/**\n * `agent.run()`: one full run — setup, the loop, and finalization on every\n * exit path.\n */\nexport function runAgent(rt: AgentRuntime, options: AgentRunOptions, resume?: ResumedRun): Promise<AgentStats> {\n // Bind the active session for `ctx.session` reads/writes for the whole run\n // (run-scoped, not process-global) so concurrent agents stay isolated.\n return withExtensionSession(rt.session, () => runWithinSession(rt, options, resume))\n}\n\n/**\n * `run` interceptors, after the registry's run transforms (`runTransforms`). Only called when one is\n * registered, so without one the running check and the claim of the run slot\n * stay in one tick; across this await the check is made again.\n */\nasync function interceptRunBeforeClaim(rt: AgentRuntime, interceptors: InterceptorRegistry, options: AgentRunOptions): Promise<AgentRunOptions> {\n const next = await interceptRunOptions(interceptors, options)\n if (rt.running)\n throw new Error('Agent is already running. Use steer() or followUp() to queue messages, or waitForIdle().')\n return next\n}\n\n/** The run `Agent.resume` continues (`findResumableRun`): it keeps its id, record and saved turns. */\nexport interface ResumedRun {\n runId: string\n}\n\nasync function runWithinSession(rt: AgentRuntime, options: AgentRunOptions, resume?: ResumedRun): Promise<AgentStats> {\n const { providers, hooks, toolCancels, pendingTaskNotifications, agentName, agentBehavior, session, agentClock, runTransforms, behaviorTransforms } = rt\n if (rt.running) {\n throw new Error('Agent is already running. Use steer() or followUp() to queue messages, or waitForIdle().')\n }\n options = applyRunTransforms(options, runTransforms)\n if (rt.interceptors?.has('run'))\n options = await interceptRunBeforeClaim(rt, rt.interceptors, options)\n\n // Resolve the run's provider+model fallback chain. `targets[0]` is the\n // primary target this run starts on; the loop advances down the list on\n // terminal stream failures (run-sticky — the next run resolves afresh\n // and starts from the primary again). Throws on unknown provider names\n // before any run bookkeeping happens.\n const targets = resolveModelTargets(providers, options.model)\n const runProvider = targets[0].provider\n\n // Validate the prompt/resume preconditions and compute the filtered resume\n // view once (reused below in the seed block). Throws on an unrecoverable\n // resume request; see {@link validateAndPrepareResume}.\n let resumeFilteredTurns = resume ? undefined : validateAndPrepareResume(session, options.prompt, pendingTaskNotifications.size > 0)\n // Child-run resume preconditions (`AgentRunOptions.resumeRunId`) —\n // validated before any run bookkeeping so a bad reference fails loudly\n // instead of silently starting a fresh conversation.\n assertResumableRunId(session, options)\n\n // Resolve effective clock for this run. Run-level wins over agent-level;\n // both fall back to `DEFAULT_AGENT_CLOCK`. A replay-mode runtime swaps in\n // its own clock once the run scope is open (`runClock`), so every\n // session-metadata callsite uses the same replay-stable source.\n const baseClock: AgentClock = options.clock ?? agentClock ?? DEFAULT_AGENT_CLOCK\n\n // Capture the external-signal listener at outer scope so the `finally`\n // below can always remove it. `{ once: true }` alone only detaches the\n // listener on abort, which would leave it attached for the full lifetime\n // of a long-lived `options.signal` and pin every `abortController`\n // instance through the closure.\n let externalAbortListener: (() => void) | undefined\n const externalSignal = options.signal\n\n // Outer try/finally guarantees `running` always resets, idle promise\n // always resolves, and the external-signal listener is always removed —\n // even when setup below `running = true` throws (warmup failure, skills\n // resolution, alias collision, unknown hook event, seed appendTurns\n // I/O). Without it, a setup throw would leave `running = true`, every\n // subsequent `agent.run()` would die on \"Agent is already running\", and\n // `agent.waitForIdle()` would block forever.\n rt.running = true\n // A run after destroy() revives the agent: its session hooks fire again.\n bindSessionHooks(rt)\n // Drop any kills parked before this run began (the pre-registration FIFO).\n // They could only target a previous run's call ids; clearing here keeps a\n // stale kill from landing on a fresh call that happens to reuse an id.\n toolCancels.clearPending()\n // Declared OUTSIDE the try so the outer `finally` can drain it. Run setup\n // registers hooks long before the inner try opens (`options.hooks`, the\n // spawn-stats listener, every behavior gate), and that stretch does real\n // throwable work — `ensureExecutionHandle` can time out, `buildAliasMaps`\n // throws on alias collisions, MCP connect can fail. Scoped inside the try,\n // the drain would be skipped on exactly those paths and a long-lived agent\n // would accumulate one full set of stale gates per failed run on its\n // agent-scoped hook bus.\n const perRunUnregisters: Array<() => void> = []\n // The run's durable scope, opened once the run has an id; closed in the outer `finally`.\n let durability: RunDurability | undefined\n // The session lease of a top-level checkpoint run; released in the outer `finally`.\n let lease: RunLease | undefined\n let finalizeSetupFailure: ((error: unknown, aborted: boolean) => Promise<void>) | undefined\n // Until the loop owns finalization: a throw before then is a setup failure.\n let inSetup = true\n const setupStartedAt = Date.now()\n // Set once `agent:start` fired: a setup abort past that point owes its consumers the run's end.\n let closeSetupAbort: ((persist: () => Promise<void>) => Promise<AgentStats>) | undefined\n try {\n const abortController = openRunControllers(rt)\n // Create the idle gate BEFORE the first await below. `running` is\n // already true, so a `waitForIdle()` issued in this setup window\n // (session bookkeeping, `agent:start` handlers are all async) must\n // get a promise pinned to THIS run. A gate created later would let\n // `waitForIdle()` return an already-resolved promise while `isRunning`\n // reports true.\n rt.idlePromise = new Promise<void>((resolve) => {\n rt.idleResolve = resolve\n })\n // Re-sync runCounter against the session BEFORE minting. Each\n // agent has its OWN counter closure — sufficient when one agent\n // owns the session, but the `spawn` tool spins up a CHILD agent\n // that ALSO mints into the SAME session. Without this re-sync\n // the child mints, say, `run_17`, then back on the parent the\n // next user prompt re-mints `run_17` because the parent's\n // closure never saw the child's increment. The resulting\n // duplicate ids confuse `eventsFromTurns` (runById collapses\n // multiple entries into one, ancestryOf returns the wrong\n // depth, the transcript renders subagent markers at the wrong\n // indent, etc — exactly the \"weird display\" rendering bug).\n // `syncRunCounter` scans BOTH session.runs and\n // session.turns[].runId (incrementally), so any sibling agent's mint\n // that has either landed in runs[] OR persisted a turn is visible.\n syncRunCounter(rt)\n const runId = resume?.runId ?? `run_${++rt.runCounter}`\n\n // Register the id in `session.runs` BEFORE the first await. Sibling\n // agents sharing the session (parallel spawn children) mint off the\n // same `session.runs` scan; with an await between mint and `startRun`\n // two children starting together both minted `run_1`, and the second\n // run record overwrote the first in the store.\n const promptLabel = resume ? reopenSessionRun(session, runId) : startSessionRun(session, runId, options)\n\n // Before the run's first write: from here every write of the session is fenced by the claimed epoch.\n lease = await claimRunLease(rt, { root: !options.parentRunId, controller: abortController, ...(options.leaseRenewMs !== undefined ? { renewMs: options.leaseRenewMs } : {}) })\n durability = await openAgentRunDurability(rt, runId)\n const runDurability = durability\n rt.activeDurability = durability\n unsuspendableOnReplay(rt, durability, abortController)\n const clock = runClock(durability, baseClock)\n const runStartedAt = await clock.now()\n const mintTurnId = async () => session ? await session.generateTurnId() : clock.randomUUID()\n\n // Resolve behavior up-front so the run-setup + teardown hook bounds, the\n // spawn watchdog, and the loop all read one merged view. Pure field-merge — no side effects.\n const transformedBehavior = applyBehaviorTransforms(resolveBehavior(agentBehavior, options.behavior), behaviorTransforms, options.behavior)\n // `behavior` interceptors after the registry's behavior transforms.\n const resolvedBehavior = replayDefaults(durability, rt.interceptors?.has('behavior') ? await interceptBehavior(rt.interceptors, transformedBehavior, options.behavior) : transformedBehavior)\n // Generous anti-hang bound for every awaited hook in the run lifecycle.\n // A host handler that never resolves would otherwise hang the first\n // turn (run-setup hooks) or strand the `running` gate (teardown hooks).\n const hookTimeoutMs = resolveTimeoutMs(resolvedBehavior.hookTimeoutMs, DEFAULT_HOOK_TIMEOUT_MS)\n\n // Run registered in the session above (before the first await); stamp\n // the clock-sourced start time now that it resolved. `promptLabel` is\n // the string form `session:start` also expects.\n const sessionRun = session?.runs.find(r => r.id === runId)\n if (sessionRun && !resume)\n sessionRun.startedAt = runStartedAt\n // A heal replaced the turns the seed view above was filtered from.\n if (session && durability.checkpoint && !resume && await prepareCheckpointRun(session, sessionRun, { root: !options.parentRunId, options }))\n resumeFilteredTurns = undefined\n if (session) {\n finalizeSetupFailure = createSetupFailureFinalizer(session, runId, sessionRun, clock, hookTimeoutMs, { fresh: !resume })\n // Persist the run record at START, not only at finalize. Without\n // this, a killed process (crash, SIGKILL, dev-loop restart) loses\n // the record while the run's TURNS survive via `appendTurns` —\n // and replay then has orphan runIds it must guess about\n // (`eventsFromTurns` synthesis mis-classified top-level runs as\n // `child-N` when the previous run died with unresolved\n // tool_calls). Upsert semantics make the finalize-time\n // `updateRun` refresh this same row. Stale `'running'` records\n // from killed processes are demoted on load by\n // `demoteStaleRunningStatus`.\n //\n // Best-effort on BOTH failure axes: a hung store is bounded by\n // `settleWithinTimeout`, and a REJECTING store is swallowed here\n // — this write is a durability bonus, not a run precondition\n // (finalize's `updateRun` lands the record regardless). Note the\n // write can also silently no-op on stores that refuse unknown\n // session ids (fresh session, header not yet created); the\n // first turn flush re-upserts to cover that case.\n await persistRunStart(session, sessionRun, hookTimeoutMs)\n await session.updateStatus('running')\n await settleWithinTimeout('hook session:start', hooks.callHook('session:start', { sessionId: session.id, runId, prompt: promptLabel }), hookTimeoutMs)\n }\n\n // Run-start observability event. Fires once per `agent.run()`,\n // symmetric with `agent:done`. Carries the tracingContext carrier\n // (W3C `traceparent`, vendor variants) propagated from the spawning\n // agent so child tracers stitch this root span as a continuation of\n // the parent's spawn span. Absent / empty on top-level runs.\n await settleWithinTimeout('hook agent:start', hooks.callHook('agent:start', {\n runId,\n ...(options.parentRunId ? { parentRunId: options.parentRunId } : {}),\n depth: typeof options.depth === 'number' ? options.depth : 0,\n ...(agentName ? { agentName } : {}),\n ...(runProvider.name ? { providerName: runProvider.name } : {}),\n startedAt: runStartedAt,\n ...(options.tracingContext ? { tracingContext: Object.freeze({ ...options.tracingContext }) } : {}),\n }), hookTimeoutMs)\n closeSetupAbort = persist => endSetupAbortedRun({ hooks, session, runId, signal: abortController.signal, hookTimeoutMs, startedAtMs: setupStartedAt, persist })\n\n // If an external signal is provided, wire it to our internal controller.\n // Listener captured in `externalAbortListener` (outer scope) so the\n // outer-`finally` can detach it on every exit — completion as well as\n // abort. Otherwise `{ once: true }` leaks the listener across runs.\n externalAbortListener = linkExternalSignal(rt, abortController, externalSignal)\n\n // Collect child agent stats reported via spawn:complete hook\n const childrenStats: ChildRunStats[] = []\n perRunUnregisters.push(hooks.hook('spawn:complete', (ctx) => {\n childrenStats.push(ctx)\n }))\n\n // Per-run hook registrations. Registered before runLoop, unregistered in finally,\n // so handlers never leak across runs even on throw paths.\n //\n // A typed hook registration interface is exposed on `options.hooks` so TS\n // catches signature mismatches at the call-site; here we have to cross the\n // `Object.entries` (string-keyed) barrier, so we validate the event name\n // against the known hook surface at runtime. Unknown keys would otherwise\n // silently never fire.\n registerRunHooks(hooks, options.hooks, perRunUnregisters)\n\n await bootstrapRun(rt, options, resolvedBehavior)\n\n const thinking = options.thinking ?? 'off'\n const model = targets[0].model\n // When the provider clears tool results server-side (Anthropic's\n // context-management beta), the client can't tell when a read's body\n // left the wire — so the read_file dedup would replay its \"unchanged\"\n // stub for content the model can no longer see, stranding it. Force\n // dedup off in that mode; server-side clearing bounds the context\n // without it. Honors an explicit `dedupReads: false` already.\n if (runProvider.meta.clearsContextServerSide)\n resolvedBehavior.dedupReads = false\n\n // Last write to `resolvedBehavior` — seal it.\n //\n // This object is not a snapshot anyone can poke: it IS what the\n // loop reads on every turn (`ctx.behavior`), what every tool receives as\n // `ToolContext.behavior`, and what child agents inherit. An in-place write\n // from a tool or extension would silently re-configure the live loop;\n // freezing turns that into a loud `TypeError` at the offending write.\n //\n // What this does NOT cover: a caller building a MODIFIED COPY\n // (`{ ...behavior, x: undefined }`) and handing that to the loop —\n // spreading a frozen object is legal and yields an unfrozen result. That\n // class is prevented structurally instead, by keeping per-batch overrides\n // off the behavior object entirely (see `suppressBatchExecutor` in\n // `loop.ts`).\n //\n // Safe to freeze: `resolveBehavior` always allocates a fresh literal and\n // `applyBehaviorTransforms` returns it or a spread copy, so this never\n // aliases a host-owned `AgentBehavior` (hosts keep mutating theirs between\n // runs). Shallow by design — it covers the scalar knobs and the executor\n // reference, which is the class that actually gets written by accident.\n Object.freeze(resolvedBehavior)\n\n // Only the knobs `agent.run()` itself consumes — building the tool\n // catalog, installing the behavior gates, resolving auto-compaction.\n // Everything the LOOP reads travels as `resolvedBehavior` in one piece\n // (see the `runLoop({ behavior })` call below), so this list stays short\n // and adding an `AgentBehavior` option needs no change here at all.\n const { modelOptions: behaviorModelOptions, compactKeepTurns, autoCompact, toolSearch, persistTurns } = resolvedBehavior\n // Per-run options win over the behavior-level default outright (no merge —\n // a run that passes `modelOptions` fully replaces the agent default).\n const modelOptions = options.modelOptions ?? behaviorModelOptions\n\n const { toolset, system, frozen, freshSystem, freshSections, aliasMaps, buildFormattedTools, advertisedToolNames, formattedTools } = composeRunPrompt(rt, { options, resolvedBehavior, runProvider, model })\n\n // Build initial turns — carry forward existing session history if resuming\n const turns = seedRunTurns(session, options, resumeFilteredTurns, toolset, toolSearch, resume?.runId)\n const resumePoint = resume && session ? resumePointFor(session, runId, turns) : undefined\n\n // Track where this run's turns start (after any resumed turns)\n const runTurnStart = resume ? Math.max(0, turns.findIndex(t => t.runId === runId)) : turns.length\n\n if (options.system) {\n await hooks.callHook('system:before', { system: options.system })\n }\n\n const drainedNotifications = await drainRunTaskNotifications(rt, resolvedBehavior, durability, turns)\n\n // Snapshot the high-water mark BEFORE pushing the seeded user\n // turn for this run. Every entry currently in `turns` came from\n // the resume path (they were in `session.turns` when we loaded),\n // so they're already durable. The seeded user turn (next) and\n // subsequent assistant / tool-results turns are NEW, and the\n // persistence loop below uses `turns.slice(persistence.persistedTurnCount)`\n // to figure out what to write.\n //\n // Subtle: we must NOT use `session.turns.length` here. When the\n // session carries subagent turns from a prior run, the resume\n // path FILTERS them out of `turns` (subagent runs are top-level-\n // invisible per the `childRunIds` filter above), so `turns.length`\n // is smaller than `session.turns.length`. Using\n // session.turns.length as the high-water mark would make `turns.slice(N)`\n // return empty for every subsequent persist call, and the\n // entire follow-up run would silently fail to persist (the seeded\n // user turn never lands in `session.turns`, the loop produces\n // assistant turns that never persist either, the user's\n // transcript sees a frozen session with no apparent error). The\n // local-count high-water mark sidesteps this entirely.\n // Wall time counts from here, plus what the run spent before a process death.\n const wallAnchorMs = Date.now() - (resumePoint?.wallMs ?? 0)\n const persistence = createTurnPersistence({ session, hooks, turns, runId, runProvider, clock, mintTurnId, sessionRun, hookTimeoutMs, committedSteps: () => committedSteps(runDurability), wallElapsed: () => Date.now() - wallAnchorMs })\n\n const seedPrompt = buildSeedPrompt(runProvider, options.prompt, drainedNotifications, resolvedBehavior.maxImageEdge, [...await resolveSystemFreeze(options.systemFreeze, frozen, freshSystem, freshSections), ...(options.systemNotes ?? [])])\n const promptFailure = seedPrompt?.promptFailure\n if (seedPrompt) {\n turns.push({\n id: await mintTurnId(),\n runId,\n role: seedPrompt.role,\n content: seedPrompt.content,\n createdAt: await clock.now(),\n })\n }\n\n rt.conversationTurns = turns\n\n // Persist + emit the seeded user turn before any assistant `turn:before` fires.\n // Without this, the seeded turn would persist only after the first `turn:after`,\n // so DB rows ordered by `created_at` would place the user turn AFTER its assistant\n // response. Consumers already dedupe `session:turns` payloads, so emitting the\n // seeded turn separately is safe.\n await persistence.persistSeededTurns()\n\n // `persistTurns: false` drops the incremental per-turn append hooks; the\n // run-end `flushTurns()` (every exit path) still persists the whole run\n // in one append. Trades mid-run crash granularity for O(1) store writes\n // per run. The store stays attached — resume / `session.save()` unchanged.\n const perTurnSync = session && persistTurns !== false\n if (perTurnSync) {\n perRunUnregisters.push(hooks.hook('turn:after', persistence.persistPendingTurns))\n perRunUnregisters.push(hooks.hook('tool-results:after', persistence.persistPendingTurns))\n }\n\n installRunGates(rt, {\n perRunUnregisters,\n resolvedBehavior,\n toolset,\n aliasMaps,\n advertisedToolNames,\n })\n\n // Live mirror of the loop's run-cumulative usage. `runLoop` returns\n // stats only on clean exits — when it THROWS (mid-stream abort,\n // budget breach) the catch paths below read this mirror so\n // `agent:done` / `session.abortRun` report the tokens actually\n // burned instead of all-zeros. Wall-clock start is captured\n // separately from `runStartedAt` (which may come from a journaled /\n // mock clock) so `elapsed` stays a real-duration measurement,\n // matching `runLoop`'s own `Date.now()`-based accounting.\n const usageMirror: RunUsageMirror = {\n totalIn: 0,\n totalOut: 0,\n totalCacheRead: 0,\n totalCacheCreation: 0,\n turns: 0,\n cost: 0,\n turnUsage: [],\n }\n const wallStartMs = Date.now()\n\n // Normalize loop-native auto-compaction once per run. Window source:\n // explicit `autoCompact.contextWindow` → `provider.meta.contextWindow`\n // fallback (chat hosts inject the picked model's window via the former).\n // `undefined` when disabled, so the LoopContext field stays absent.\n const providerContextWindow = runProvider.meta.contextWindow\n const resolvedAutoCompact = resolveAutoCompact(autoCompact, {\n ...(providerContextWindow !== undefined ? { fallbackContextWindow: providerContextWindow } : {}),\n ...(compactKeepTurns !== undefined ? { compactKeepTurns } : {}),\n })\n\n const { mirroredLoopStats, finishRun } = createRunFinisher({\n session,\n hooks,\n runId,\n runTurnStart,\n turns,\n clock,\n hookTimeoutMs,\n childrenStats,\n usageMirror,\n wallStartMs,\n })\n\n // The loop owns finalization from here, including failures in its cleanup.\n finalizeSetupFailure = undefined\n inSetup = false\n return await executePreparedRun(rt, {\n options,\n targets,\n runProvider,\n resolvedBehavior,\n toolset,\n aliasMaps,\n buildFormattedTools,\n formattedTools,\n model,\n system,\n thinking,\n modelOptions,\n resolvedAutoCompact,\n abortController,\n turns,\n runId,\n mintTurnId,\n clock,\n runStartedAt,\n perTurnSync,\n persistence,\n usageMirror,\n promptFailure,\n mirroredLoopStats,\n finishRun,\n perRunUnregisters,\n hookTimeoutMs,\n durability,\n resumePoint,\n lease,\n })\n }\n catch (error) {\n // Another process took the run over during setup: it owns the session now, nothing is saved.\n rethrowTakeover(lease, error)\n /*\n * Setup cut short by this run's own abort is an abort, not a failure —\n * the rule the loop's catch applies. `destroy()` flips the run signal\n * before a spawn it races returns and rejects, so a host draining\n * mid-spawn ends the run `aborted` like a drain at any later point.\n * Only a throw the abort CAUSED counts: a genuine setup error that\n * merely coincides with an aborted signal (a pre-aborted\n * `options.signal`) still rejects with that error.\n */\n const aborted = inSetup && isRunAbortCause(error, rt.abortController?.signal)\n const persistSetupFailure = async (): Promise<void> => {\n try {\n await finalizeSetupFailure?.(error, aborted)\n }\n catch (persistenceError) {\n // A secondary store failure must not replace the original setup exception.\n if (process.env.ZIDANE_DEBUG)\n console.error('[zidane] session finalization after setup failure failed:', persistenceError)\n }\n }\n if (aborted && closeSetupAbort)\n return await closeSetupAbort(persistSetupFailure)\n await persistSetupFailure()\n if (aborted)\n return zeroRunStats(setupStartedAt)\n throw error\n }\n finally {\n // Outer finally — runs even if setup above the inner try threw, so\n // global state never gets stranded. Idempotent with the inner finally\n // on the happy path: the disposer stack was emptied there so this loop\n // is a no-op, re-clearing already-cleared state is a no-op, and\n // `removeEventListener` of a never-registered listener is also a no-op.\n await releaseRun(rt, { perRunUnregisters, externalSignal, externalAbortListener, durability, lease })\n }\n}\n\n/**\n * The run's abort and suspend controllers, both from the start: a suspend in\n * setup stops the run before its first model call. Returns the abort one.\n */\nfunction openRunControllers(rt: AgentRuntime): AbortController {\n const abortController = new AbortController()\n rt.abortController = abortController\n rt.suspendController = new AbortController()\n return abortController\n}\n\n/** A replay-mode run continues by running its invocation again: it is not suspended, and a suspend asked for in setup aborts it. */\nfunction unsuspendableOnReplay(rt: AgentRuntime, durability: RunDurability, abortController: AbortController): void {\n if (!replays(durability))\n return\n if (rt.suspendController?.signal.aborted)\n abortController.abort()\n rt.suspendController = undefined\n}\n\n/** The run record written at run start: best-effort, bounded (see the call site). */\nasync function persistRunStart(session: Session, sessionRun: SessionRun | undefined, hookTimeoutMs: number): Promise<void> {\n if (!sessionRun)\n return\n await settleWithinTimeout('session.updateRun', session.updateRun(sessionRun), hookTimeoutMs)\n .catch((err) => {\n if (process.env.ZIDANE_DEBUG)\n console.error('[zidane] session.updateRun at run start failed; continuing:', err)\n })\n}\n\n/** Throw the takeover that ended a run's hold on its session, if one did (`claimRunLease`). */\nfunction rethrowTakeover(lease: RunLease | undefined, error: unknown): void {\n const takenOver = lease?.takenOver() ?? (error instanceof StaleEpochError ? error : undefined)\n if (takenOver)\n throw takenOver\n}\n\n/**\n * The outer `finally` of a run: drain the run-scoped registrations, reset the\n * run scope, detach the external-signal listener, close the durable scope and\n * give the session lease up.\n */\nasync function releaseRun(rt: AgentRuntime, { perRunUnregisters, externalSignal, externalAbortListener, durability, lease }: {\n perRunUnregisters: Array<() => void>\n externalSignal: AbortSignal | undefined\n externalAbortListener: (() => void) | undefined\n durability: RunDurability | undefined\n lease: RunLease | undefined\n}): Promise<void> {\n for (const unregister of perRunUnregisters)\n unregister()\n perRunUnregisters.length = 0\n resetRunScope(rt)\n if (rt.activeDurability === durability)\n rt.activeDurability = undefined\n if (externalSignal && externalAbortListener)\n externalSignal.removeEventListener('abort', externalAbortListener)\n await durability?.scope.close()\n await lease?.release()\n}\n\n/**\n * Behavior defaults of a replay-mode run: background tasks only on an\n * execution context whose detached tasks survive a process death, since a\n * replay cannot reattach to a host-local one.\n */\nfunction replayDefaults(durability: RunDurability, behavior: ResolvedBehavior): ResolvedBehavior {\n if (!replays(durability) || behavior.disableBackgroundTasks !== undefined)\n return behavior\n return { ...behavior, disableBackgroundTasks: 'non-durable' }\n}\n\n/** Throws when `options.resumeRunId` can't be resumed from `session`. */\nfunction assertResumableRunId(session: Session | undefined, options: AgentRunOptions): void {\n if (options.resumeRunId) {\n if (!session)\n throw new Error('resumeRunId requires a session (the prior run\\'s turns live there)')\n if (!options.prompt)\n throw new Error('resumeRunId needs a prompt: pass the instruction to continue with')\n const chain = resumeChainRunIds(session.runs, options.resumeRunId)\n if (!session.turns.some(t => t.runId !== undefined && chain.has(t.runId)))\n throw new Error(`resumeRunId \"${options.resumeRunId}\" has no saved turns in this session, so there is nothing to resume`)\n }\n}\n\n/**\n * Register `runId` in `session.runs` and return the prompt's string label\n * (what `session:start` expects).\n */\nfunction startSessionRun(session: Session | undefined, runId: string, options: AgentRunOptions): string {\n const promptLabel = typeof options.prompt === 'string'\n ? options.prompt\n : Array.isArray(options.prompt)\n ? options.prompt\n .filter((p): p is { type: 'text', text: string } => p.type === 'text')\n .map(p => p.text)\n .join('\\n')\n : ''\n // Default depth to 0 for top-level runs so the `runs` list always has a\n // numeric depth — lets consumers group/filter by level without null-checking.\n session?.startRun(runId, promptLabel, {\n ...(options.parentRunId ? { parentRunId: options.parentRunId } : {}),\n depth: typeof options.depth === 'number' ? options.depth : 0,\n ...(options.resumeRunId ? { resumedFromRunId: options.resumeRunId } : {}),\n ...(options.runLabel ? { label: options.runLabel } : {}),\n ...(options.runAgent ? { agent: options.runAgent } : {}),\n ...(options.parentRunId && options.parentCallId ? { parentCallId: options.parentCallId } : {}),\n })\n return promptLabel\n}\n\n/**\n * Session finalization for a run whose SETUP threw (before the loop owns\n * finalization): marks the run aborted/errored and settles the store. A\n * fresh run never reached its prompt, so it is not resumable: its mark\n * goes. A resumed one keeps it, to be resumed again.\n */\nfunction createSetupFailureFinalizer(\n runSession: Session,\n runId: string,\n sessionRun: SessionRun | undefined,\n clock: AgentClock,\n hookTimeoutMs: number,\n { fresh }: { fresh: boolean },\n): (error: unknown, aborted: boolean) => Promise<void> {\n return async (error, aborted) => {\n if (aborted)\n runSession.abortRun(runId)\n else\n runSession.errorRun(runId, errorMessage(error))\n if (fresh && sessionRun)\n delete sessionRun.resumable\n // Before the first turn, updateRun has no header to update. The\n // append path creates it without replacing shared session history.\n if (runSession.isEmpty)\n await settleWithinTimeout('session.appendTurns', runSession.appendTurns([]), hookTimeoutMs)\n if (sessionRun) {\n sessionRun.endedAt = await clock.now()\n await settleWithinTimeout('session.updateRun', runSession.updateRun(sessionRun), hookTimeoutMs)\n }\n await settleWithinTimeout('session.updateStatus', runSession.updateStatus(aborted ? 'idle' : 'error'), hookTimeoutMs)\n }\n}\n\n/**\n * Wire the caller's `options.signal` to the run's controller. Returns the\n * listener to detach in the run's outer `finally` (undefined when nothing\n * was attached).\n */\nfunction linkExternalSignal(\n rt: AgentRuntime,\n abortController: AbortController,\n externalSignal: AbortSignal | undefined,\n): (() => void) | undefined {\n let externalAbortListener: (() => void) | undefined\n if (externalSignal) {\n if (externalSignal.aborted) {\n abortController.abort(externalSignal.reason)\n }\n else {\n externalAbortListener = () => rt.abortController?.abort(externalSignal.reason)\n externalSignal.addEventListener('abort', externalAbortListener, { once: true })\n }\n }\n return externalAbortListener\n}\n\n/** Register `options.hooks` for this run, pushing each disposer onto `perRunUnregisters`. */\nfunction registerRunHooks(\n hooks: Hookable<AgentHooks>,\n runHooks: AgentRunOptions['hooks'],\n perRunUnregisters: Array<() => void>,\n): void {\n if (runHooks) {\n for (const [event, handler] of Object.entries(runHooks)) {\n if (!isKnownHookEvent(event)) {\n throw new Error(\n `Unknown hook event \"${event}\" passed to run(). See AgentHooks for valid events.`,\n )\n }\n const handlerList = Array.isArray(handler) ? handler : [handler]\n for (const fn of handlerList) {\n if (typeof fn !== 'function')\n continue\n // Safe cast: event was validated via isKnownHookEvent. Handler arity\n // is host-validated via the AgentRunOptions['hooks'] surface type.\n perRunUnregisters.push(hooks.hook(event, fn as AgentHooks[typeof event]))\n }\n }\n }\n}\n\n/** Everything run setup hands to {@link executePreparedRun}. */\ninterface PreparedRun {\n options: AgentRunOptions\n targets: ModelTarget[]\n runProvider: Provider\n resolvedBehavior: ResolvedBehavior\n toolset: RunToolset\n aliasMaps: AliasMaps\n buildFormattedTools: (forProvider?: Provider) => unknown[]\n formattedTools: unknown[]\n model: string\n system: string\n thinking: ThinkingLevel\n modelOptions: AgentRunOptions['modelOptions']\n resolvedAutoCompact: ResolvedAutoCompact | undefined\n abortController: AbortController\n turns: SessionTurn[]\n runId: string\n mintTurnId: () => Promise<string>\n clock: AgentClock\n runStartedAt: number\n perTurnSync: boolean | undefined\n persistence: ReturnType<typeof createTurnPersistence>\n usageMirror: RunUsageMirror\n promptFailure: { error: unknown } | undefined\n mirroredLoopStats: () => AgentStats\n finishRun: (disposition: RunDisposition) => Promise<AgentStats>\n perRunUnregisters: Array<() => void>\n hookTimeoutMs: number\n durability: RunDurability\n /** Where `Agent.resume` continues the run; unset on a fresh run. */\n resumePoint: LoopContext['resume']\n /** The session lease of a top-level checkpoint run (`claimRunLease`). */\n lease: RunLease | undefined\n}\n\n/**\n * The loop phase of a run: hydrate tool state, run the loop, and finalize\n * through `finishRun` on every exit path; the `finally` deactivates skills,\n * drains the run-scoped registrations, and resets the run scope.\n */\nasync function executePreparedRun(rt: AgentRuntime, run: PreparedRun): Promise<AgentStats> {\n const { hooks, executionContext, sourceTools, toolStateController, toolCancels, allMcpServers, steeringQueue, nonInterruptingNudgeQueue, followUpQueue, skillActivationState, agentName, agentSystem, toolDescriptions, session, agentReadState, agentSkills, artifactsOption } = rt\n const { options, targets, runProvider, resolvedBehavior, toolset, aliasMaps, buildFormattedTools, formattedTools, model, system, thinking, modelOptions, resolvedAutoCompact, abortController, turns, runId, mintTurnId, clock, runStartedAt, perTurnSync, persistence, usageMirror, promptFailure, mirroredLoopStats, finishRun, perRunUnregisters, hookTimeoutMs, durability, resumePoint, lease } = run\n const { effectiveToolAliases, tools, dispatchMode, disclosure } = toolset\n const runStartMs = runStartedAt\n\n const runDepth = typeof options.depth === 'number' ? options.depth : 0\n let loopCtx: LoopContext | undefined\n const suspendSignal = rt.suspendController?.signal\n\n try {\n if (promptFailure)\n throw promptFailure.error\n // Hydrate durable tool state before the loop starts, the only place the\n // store can load: `ToolContext.state` reads are synchronous (a tool body\n // may be running inside a recorded step, where durable reads are illegal), and the position must be\n // deterministic across replays. No-op when no store is configured, so\n // agents that never touch tool state pay nothing.\n //\n // INSIDE the try on purpose: the session run row is already marked\n // `running` by now, so a rejecting store must take the same exit as\n // any other run failure (errorRun + `agent:done`) instead of\n // stranding the row and leaking the run span. Unlike `commit`, a\n // failed `load` is NOT swallowed — proceeding on an empty snapshot\n // would re-arm exactly the one-shot bugs this state exists to stop.\n await toolStateController.hydrate()\n loopCtx = {\n provider: runProvider,\n targets,\n hooks,\n // The whole resolved view in one field: every knob the loop reads is\n // a property of it, so a new `AgentBehavior` option reaches the loop\n // the moment `resolveBehavior` learns it — no forwarding line to add\n // and none to forget. Also what tools see as `ToolContext.behavior`.\n behavior: resolvedBehavior,\n inheritance: {\n ...(agentName !== undefined ? { name: agentName } : {}),\n ...(agentSystem !== undefined ? { system: agentSystem } : {}),\n tools: sourceTools,\n ...(effectiveToolAliases !== undefined ? { toolAliases: effectiveToolAliases } : {}),\n ...(toolDescriptions !== undefined ? { toolDescriptions } : {}),\n // The transformed list (`applyMcpConfigTransforms`), not the raw\n // option: the live connection was built from it, and a child needs\n // matching configs or its `allMcpServers.length > 0` gate never\n // invokes the shared connector (e.g. transform-added servers with\n // an empty raw config).\n ...(allMcpServers.length > 0 ? { mcpServers: allMcpServers } : {}),\n // Getter, not a snapshot: `mcpConnection` is bound lazily (`ensureMcpConnected`)\n // and this closure must observe the live binding at tool-call time.\n mcpConnection: () => rt.mcpConnection,\n ...(agentSkills !== undefined ? { skills: agentSkills } : {}),\n },\n tools,\n formattedTools,\n // Always passed (not just for lazy disclosure): a model fallback\n // needs it to reformat the tool list for the new provider's wire\n // shape. Per-provider+tail caching makes the per-turn call cheap.\n rebuildFormattedTools: buildFormattedTools,\n ...(dispatchMode ? { dispatcher: { name: CALL_TOOL_NAME, targets: disclosure.lazyCanonicalNames } } : {}),\n aliasMaps,\n model,\n system,\n thinking,\n signal: abortController.signal,\n ...(options.pauseSignal ? { pauseSignal: options.pauseSignal } : {}),\n ...(suspendSignal ? { suspendSignal } : {}),\n execution: executionContext,\n handle: rt.executionHandle!,\n steeringQueue,\n nonInterruptingNudgeQueue,\n followUpQueue,\n turns,\n runId,\n generateTurnId: mintTurnId,\n clock,\n durable: durability,\n ...(resumePoint ? { resume: resumePoint } : {}),\n ...(modelOptions ? { modelOptions } : {}),\n ...(resolvedAutoCompact ? { autoCompact: resolvedAutoCompact } : {}),\n ...(session ? { session } : {}),\n ...(artifactsOption === false ? { artifactsDisabled: true } : {}),\n ...(agentReadState ? { readState: agentReadState } : {}),\n toolState: toolStateController,\n ...(options.parentRunId ? { parentRunId: options.parentRunId } : {}),\n ...(options.parentCallId ? { parentCallId: options.parentCallId } : {}),\n depth: runDepth,\n // Persist a mid-run compaction marker promptly (+ fire session:turns\n // so hosts repaint) — only when per-turn sync is on; batch mode lets\n // the run-end flush cover it.\n ...(perTurnSync ? { persistTurns: persistence.persistPendingTurns } : {}),\n // Active-skill snapshot for post-compact restoration.\n getActiveSkills: () => skillActivationState.active(),\n providerName: runProvider.name,\n runStartMs,\n runToolCounts: {},\n overflowRescue: rt.overflowRescue,\n toolCancels,\n usageMirror,\n ...(rt.interceptors ? { interceptors: rt.interceptors } : {}),\n }\n rt.activeRunContext = loopCtx\n const stats = await runLoop(loopCtx)\n\n // `stats` is the parent-loop view returned by `runLoop` —\n // `totalIn/Out/turnUsage` cover this run's loop only. `finishRun` folds\n // the `spawn:complete` children into the RETURNED stats and writes the\n // session ledger from this loop-only view.\n const parentTurnCost = stats.turnUsage\n ?.reduce((sum, t) => sum + (t.cost ?? 0), 0) ?? 0\n\n // A takeover aborts the run, which can then end like a clean-break abort: no final save either way.\n const takenOver = lease?.takenOver()\n if (takenOver)\n throw takenOver\n\n await persistence.flushTurns()\n\n // A clean-break abort (the loop returned rather than threw) and a\n // completed run differ only in which session-record call fires — both\n // have real loop stats in hand.\n return await finishRun({\n kind: abortController.signal.aborted ? 'aborted' : 'completed',\n loopStats: stats,\n parentCost: parentTurnCost,\n })\n }\n catch (err) {\n /*\n * Another process claimed the run (a write was refused, or the lease\n * could not be renewed): it owns the session now. Stop at once with no\n * final save, so nothing lands over what the new owner writes; the\n * observers still get `agent:done`.\n */\n const takenOver = lease?.takenOver() ?? (err instanceof StaleEpochError ? err : undefined)\n if (takenOver) {\n await settleWithinTimeout('hook agent:done', hooks.callHook('agent:done', mirroredLoopStats()), hookTimeoutMs).catch(() => {})\n throw takenOver\n }\n\n /*\n * `Agent.suspend` stopped the run: it keeps its step records and its\n * resumable mark, its dangling calls get no placeholder results, and\n * `Agent.resume` continues it from its last committed step.\n */\n if (suspendSignal?.aborted && !(err instanceof AgentBudgetExceededError)) {\n await persistence.flushSuspended()\n return await finishRun({\n kind: 'suspended',\n loopStats: mirroredLoopStats(),\n parentCost: usageMirror.cost,\n })\n }\n\n // Synthesize tool_result fallbacks for any orphaned tool_use blocks on\n // the trailing assistant turn — see `synthesizeMissingToolResults` for\n // why this matters (resume rejects orphan tool_use).\n await persistence.flushTurns({ failureFallback: true })\n\n // If aborted, provider may throw — return gracefully. Fire\n // `agent:abort` here: a cancel that lands MID-STREAM throws straight\n // out of `executeTurn` and skips the loop's between-turn\n // `signal.aborted` checks (the only place the loop fires it), so\n // without this the most common interactive cancel would never reach an\n // `agent:abort` consumer. The clean-loop-break abort path (above) is\n // already covered by the loop's fire and must NOT fire again here —\n // these two branches are mutually exclusive (throw vs clean return), so\n // there's no double-fire. A durable-runtime control error (a\n // cancellation, a suspension) is never a graceful abort: it takes the\n // error path below so the runtime receives it. In replay mode the loop's\n // own abort verdict counts too: it was journaled, the live signal of a\n // replay never aborts.\n const loopAborted = replays(durability) && err instanceof AgentAbortedError\n if ((abortController.signal.aborted || loopAborted) && !durability.runtime.isControlError(err)) {\n const abortReason = abortController.signal.reason\n await hooks.callHook('agent:abort', {\n ...(runId ? { runId } : {}),\n ...(typeof abortReason === 'string' && abortReason.length > 0 ? { reason: abortReason } : {}),\n })\n // The mirror carries the usage of every COMPLETED turn before the\n // abort landed — pass it through so the persisted run record and\n // `agent:done` reflect real spend, matching the clean-break abort\n // path above (which has the loop's returned `stats` in hand).\n return await finishRun({\n kind: 'aborted',\n loopStats: mirroredLoopStats(),\n parentCost: usageMirror.cost,\n })\n }\n\n // Budget circuit breaker — semantically a \"clean stop\", not an\n // error. Finalize the run as `aborted` (matching the abort path\n // above) so the persisted record reflects the operator-imposed\n // cap rather than mis-attributing the trip to a runtime failure,\n // then re-throw so callers can branch on the typed class. The\n // breaching spend comes from `usageMirror` — the loop updates it\n // after every completed turn (the budget predicate fires\n // post-turn), so the persisted record and `agent:done` carry the\n // tokens / cost that actually tripped the cap.\n if (err instanceof AgentBudgetExceededError) {\n await finishRun({\n kind: 'aborted',\n loopStats: mirroredLoopStats(),\n parentCost: usageMirror.cost,\n })\n throw err\n }\n\n // Fire `agent:done` on the error path too — symmetric with the abort /\n // budget branches above and the documented \"all exit paths\" contract.\n // Without it a hard failure (provider 402, network tear-down, …) skips\n // every run-boundary consumer: the terminal session summary (incl. the\n // session id) never prints, metrics' `runs.active` gauge never\n // decrements, and tracing run spans leak. Stats come from `usageMirror`\n // (real spend up to the throw); the re-throw still surfaces the error.\n await finishRun({\n kind: 'error',\n loopStats: mirroredLoopStats(),\n parentCost: usageMirror.cost,\n failure: errorMessage(err),\n detail: runErrorDetail(err),\n })\n throw err\n }\n finally {\n // Keep the context of a run that reached the provider, on every exit\n // path, so `agent.compact()` can resend its last request.\n if (loopCtx) {\n releaseContentRefCache(loopCtx)\n if (loopCtx.lastRequest)\n rt.lastRunContext = { ctx: loopCtx, turn: Math.max(0, usageMirror.turns - 1) }\n }\n rt.activeRunContext = null\n // Deactivate every skill active at run end. Runs on every exit path —\n // completed, aborted, or thrown — so activation state never leaks across\n // run boundaries. Explicit activation via `agent.activateSkill()` is\n // subject to the same rule: it lives until the next run boundary.\n await deactivateAllSkills(skillActivationState, hooks, hookTimeoutMs)\n\n // Teardown every run-scoped registration in one pass. All of them —\n // the behavior gates, the skill hydration gates, the `options.hooks`\n // registrations, the spawn/turn-sync listeners — share one lifetime and\n // one disposer stack, so a newly installed gate can never be forgotten\n // here. Unregister order is irrelevant (install order is what encodes\n // gate precedence; see the comments at the install sites).\n //\n // Drained here rather than only in the outer `finally` so it lands\n // before `resetRunScope()`, after `deactivateAllSkills()` above has had\n // its hooks observed by the still-live gates. The outer drain is the\n // safety net for throws during setup.\n for (const unregister of perRunUnregisters)\n unregister()\n perRunUnregisters.length = 0\n steeringQueue.length = 0\n nonInterruptingNudgeQueue.length = 0\n followUpQueue.length = 0\n resetRunScope(rt)\n }\n}\n\n/**\n * Per-run bootstrap: execution handle, MCP connection, skills resolution,\n * extension skill policies, and resume-time skill rehydration.\n */\nasync function bootstrapRun(rt: AgentRuntime, options: AgentRunOptions, resolvedBehavior: ResolvedBehavior): Promise<void> {\n const { hooks, allMcpServers, skillActivationState, session, skillPolicies } = rt\n // Spawn execution context (shared seam — see `ensureExecutionHandle`).\n // Bounded on the first run: docker / sandbox / e2b / daytona contexts do\n // daemon + network round-trips here with no inherent timeout, so a hung\n // daemon would leave `agent.run()` pending forever (the provider\n // watchdog hasn't started yet). The process context spawns\n // synchronously, so the generous default never bites it.\n await ensureExecutionHandle(rt, resolveTimeoutMs(resolvedBehavior.spawnTimeoutMs, DEFAULT_SPAWN_TIMEOUT_MS, resolvedBehavior.maxWallMs))\n\n // Connect MCP servers lazily on first run. Delegated to `warmup()` so the\n // fast-path (\"already connected\") and the slow-path (\"pending warmup from\n // `eager: true` or a concurrent `agent.warmup()` call\") share one promise\n // and one outcome.\n if (allMcpServers.length > 0 && !rt.mcpConnection) {\n await warmup(rt, { mcpConnectTimeoutMs: resolvedBehavior.mcpConnectTimeoutMs, maxWallMs: resolvedBehavior.maxWallMs })\n }\n // A pooled server retired since the last run (its config, toggle or\n // sign-in changed) moves to its current instance before this run's first call.\n else if (rt.mcpConnection?.refresh) {\n await rt.mcpConnection.refresh()\n }\n\n // Skills bootstrap. Idempotent — a no-op when `warmup()` already\n // resolved them (eager bootstrap or explicit pre-warm); pays the\n // cost here on the first run otherwise.\n await ensureSkillsResolved(rt)\n await applySkillPolicies({\n policies: skillPolicies,\n skills: rt.resolvedSkills ?? [],\n options,\n activate: async (skill) => {\n if (skillActivationState.activate(skill, 'explicit') === 'ok')\n await hooks.callHook('skills:activate', { skill, via: 'explicit' })\n },\n })\n // `skills.activate` interceptors after the registry's skill policies.\n if (rt.interceptors?.has('skills.activate')) {\n await interceptSkillActivation(rt.interceptors, {\n skills: rt.resolvedSkills ?? [],\n options,\n activate: async (skill) => {\n if (skillActivationState.activate(skill, 'explicit') === 'ok')\n await hooks.callHook('skills:activate', { skill, via: 'explicit' })\n },\n })\n }\n\n // Session-resume rehydration: when resuming a session with prior turns,\n // scan for `skills_use` tool_call blocks and rebuild activation state\n // from the *most recent* mode per skill. A model-side\n // `skills_use({ mode: \"deactivate\", name })` is a load-bearing intent\n // — without honoring it, the next run would silently re-activate the\n // skill (because the catalog still lists it and an earlier `activate`\n // block is still in history) and the user's earlier \"unstuck\" gesture\n // would silently undo itself. The fix is order-aware: walk chronologically\n // and keep only the last mode per skill, then activate the skills\n // whose last mode is `'activate'`. Bad / missing `mode` is treated as\n // `'activate'` for backward compatibility with the pre-deactivate\n // schema.\n //\n // Fires `skills:activate` with `via: 'resume'` so consumers can\n // distinguish a fresh activation from a rehydrated one. Does NOT\n // fire `skills:deactivate` for skills with a trailing deactivate\n // block — there's nothing to deactivate (the state started empty),\n // and emitting a spurious `'resume'`-flavored deactivate would\n // confuse listeners expecting deactivate to follow activate.\n if (rt.resolvedSkills && session && session.turns.length > 0 && skillActivationState.active().length === 0) {\n // Child-run resume: scope rehydration to the resume lineage so\n // activation state matches the seeded conversation — scanning the\n // whole shared session would absorb `skills_use` calls the parent\n // or sibling runs made, activating skills this child's transcript\n // never shows.\n let rehydrationTurns: readonly SessionTurn[] = session.turns\n if (options.resumeRunId) {\n const chain = resumeChainRunIds(session.runs, options.resumeRunId)\n rehydrationTurns = session.turns.filter(t => t.runId !== undefined && chain.has(t.runId))\n }\n await rehydrateActiveSkillsFromTurns(rehydrationTurns, rt.resolvedSkills, skillActivationState, hooks)\n }\n}\n\n/**\n * The run's initial turns: the resumed session history (when resuming),\n * with its `tool_search` unlocks replayed into the disclosure state.\n */\nfunction seedRunTurns(\n session: Session | undefined,\n options: AgentRunOptions,\n resumeFilteredTurns: ReturnType<typeof validateAndPrepareResume>,\n toolset: RunToolset,\n toolSearch: ResolvedBehavior['toolSearch'],\n resumedRunId: string | undefined,\n): SessionTurn[] {\n const { disclosure, unlocked, recordDynamicUnlock, shouldInjectToolSearch } = toolset\n const turns: SessionTurn[] = []\n\n // Resume: prepend prior conversation turns from session.\n const seededTurns = selectSeedTurns({ session, options, resumeFilteredTurns, ...(resumedRunId !== undefined ? { resumedRunId } : {}) })\n\n if (seededTurns) {\n turns.push(...seededTurns)\n\n // Lazy disclosure — replay the resumed history's `tool_search` unlocks.\n // Gated on `shouldInjectToolSearch`: when the host wires their own\n // discovery tool they own the unlock state machine, and re-running our\n // matcher against `tool_search` calls they didn't emit would be\n // incorrect.\n if (shouldInjectToolSearch && disclosure.lazyEntries.length > 0) {\n replayToolSearchUnlocks(\n seededTurns,\n disclosure.lazyEntries,\n unlocked,\n toolSearch?.limit,\n recordDynamicUnlock,\n )\n }\n }\n\n return turns\n}\n\n/** Drain pending background-task notifications into this run (see {@link drainTaskNotifications}). */\nfunction drainRunTaskNotifications(\n rt: AgentRuntime,\n resolvedBehavior: ResolvedBehavior,\n durability: RunDurability,\n turns: SessionTurn[],\n): Promise<SessionContentBlock[]> {\n const { hooks, executionContext, pendingTaskNotifications, pendingStallNotifications, notifiedTaskIds, session } = rt\n return drainTaskNotifications({\n state: {\n pending: pendingTaskNotifications,\n pendingStalls: pendingStallNotifications,\n notified: notifiedTaskIds,\n },\n executionContext,\n executionHandle: rt.executionHandle,\n behavior: resolvedBehavior,\n journalSweep: sweep => journaledStep(durability, LOOP_STEP_KINDS.reconcile, 'background-reconcile', sweep),\n session,\n turns,\n hooks,\n })\n}\n\n/**\n * The seeded user turn's role + content: drained task notifications ahead of\n * the prompt, system notes after it. `undefined` when there is neither\n * notification nor prompt (the notes alone seed nothing). A prompt the\n * provider can't build is preserved verbatim and reported as `promptFailure`.\n */\nfunction buildSeedPrompt(\n runProvider: Provider,\n prompt: AgentRunOptions['prompt'],\n drainedNotifications: SessionContentBlock[],\n maxImageEdge: number | undefined,\n systemNotes: AgentRunOptions['systemNotes'],\n): { role: SessionTurn['role'], content: SessionContentBlock[], promptFailure: { error: unknown } | undefined } | undefined {\n const canonical = canonicalizePrompt(prompt)\n const promptParts = canonical && shrinkPromptImages(canonical, maxImageEdge)\n if (!promptParts && drainedNotifications.length === 0)\n return undefined\n let promptFailure: { error: unknown } | undefined\n let promptMsg: SessionMessage | null = null\n if (promptParts) {\n try {\n promptMsg = buildPromptMessage(runProvider, promptParts)\n }\n catch (error) {\n // Preserve the original submission, then finalize through the normal error path.\n promptFailure = { error }\n promptMsg = { role: 'user', content: promptParts.map(part => ({ ...part })) }\n }\n }\n // Prepend the notifications BEFORE the prompt content so the\n // model reads them as ambient context before the user's actual\n // request. Multiple notifications stack in completion order\n // (Map preserves insertion order; insertion order = onExit\n // arrival order from `background:exit`).\n const content: SessionContentBlock[] = [\n ...drainedNotifications,\n ...(promptMsg ? promptMsg.content : []),\n ...(systemNotes ?? []).map(systemNoteBlock),\n ]\n return { role: promptMsg ? promptMsg.role : 'user', content, promptFailure }\n}\n\n/**\n * Apply `systemFreeze` once the run's fresh prompt is composed: when the run\n * sends a frozen prompt, the notes announcing what changed since; otherwise,\n * hand the fresh prompt and its SDK-appended sections to `onCapture` (no notes).\n */\nasync function resolveSystemFreeze(freeze: AgentRunOptions['systemFreeze'], frozen: boolean, fresh: string, sections: FrozenPromptSections): Promise<ReadonlyArray<SystemNote & { text: string }>> {\n if (!freeze)\n return []\n if (frozen)\n return await freeze.notes?.(fresh, sections) ?? []\n await freeze.onCapture?.(fresh, sections)\n return []\n}\n\n/** A run option's system note as a content block, carrying only the metadata it defines. */\nfunction systemNoteBlock(note: NonNullable<AgentRunOptions['systemNotes']>[number]): SessionContentBlock {\n const systemNote: SystemNote = { kind: note.kind }\n if (note.label !== undefined)\n systemNote.label = note.label\n if (note.digest !== undefined)\n systemNote.digest = note.digest\n if (note.effort !== undefined)\n systemNote.effort = note.effort\n return { type: 'text', text: note.text, systemNote }\n}\n","/**\n * Agent creation and state management.\n */\n\nimport type { AgentHookBus } from './agent-hooks'\nimport type { AgentRuntime, PendingRun } from './agent-runtime'\nimport type { Agent, AgentCacheChange, AgentCacheImpact, AgentCompactOptions, AgentOptions } from './agent-types'\nimport type { ContextBreakdownOptions } from './chat/context-breakdown'\nimport type { ContextSegmentFile } from './chat/context-segments'\nimport type { DurableResumeOptions } from './durable/types'\nimport type { AgentRunOptions, AgentStats } from './types'\nimport { DEFAULT_SPAWN_TIMEOUT_MS } from './agent-behavior'\nimport { ensureExecutionHandle, warmup } from './agent-bootstrap'\nimport { compactAgent } from './agent-compact'\nimport { getContextBreakdown, getContextSegments } from './agent-context'\nimport { abortRun, activateSkill, bindSessionHooks, cancelTool, deactivateSkill, destroy as destroyAgent, ensureAgentSession, followUp, killBackgroundTask, reset, sessionToLoad, steer, suspendRun, waitForIdle } from './agent-lifecycle'\nimport { assertResumable, findResumableRun, joinStreamPartials, resumedRunOptions } from './agent-resume'\nimport { runAgent } from './agent-run'\nimport { zeroRunStats } from './agent-run-finalize'\nimport { createAgentRuntime } from './agent-runtime'\nimport { installBackgroundTaskTracking } from './agent-task-notifications'\nimport { estimateCacheExpiresAt, estimateCacheImpact, registerCachePromptSections } from './cache-telemetry'\nimport { LEASE_STALE_MS } from './durable/lease'\nimport { resolveTimeoutMs } from './timeout'\n\nexport type { ResolvedBehavior } from './agent-behavior'\nexport type { ContextAssembly } from './agent-context'\nexport type { AgentHookBus, AgentHookHandlers, AgentHookMap, AgentHooks, DecideHookContext, ToolGateResumeFields } from './agent-hooks'\nexport { resolveToolSearchMode } from './agent-tool-disclosure'\nexport type { Agent, AgentCacheChange, AgentCacheImpact, AgentCompactOptions, AgentCompactResult, AgentOptions, AgentToolState, McpConnector, McpToolMeta, McpToolWrap } from './agent-types'\n\n// ---------------------------------------------------------------------------\n// createAgent\n// ---------------------------------------------------------------------------\n\n/**\n * Creates an agent: a provider, tools, hooks and optional session behind one `run()` call.\n *\n * Setup is synchronous. MCP servers and skills connect on the first `run()` or `warmup()`,\n * or in the background when `eager` is set. Throws when `provider` is an empty array or\n * a multi-provider list has blank or duplicate provider names.\n *\n * @param rawOptions - Agent options. Only `provider` is required.\n * @returns The {@link Agent}. Call `agent.destroy()` when you are done to release the execution context.\n *\n * @example\n * ~~~ts\n * import { createAgent } from 'zidane'\n * import { anthropic } from 'zidane/providers/anthropic'\n *\n * const agent = createAgent({\n * provider: anthropic({ apiKey: process.env.ANTHROPIC_API_KEY }),\n * system: 'You are a helpful assistant.',\n * })\n *\n * const stats = await agent.run({ prompt: 'Say hello.' })\n * console.log(`Done in ${stats.turns} turns`)\n * await agent.destroy()\n * ~~~\n */\nexport function createAgent(rawOptions: AgentOptions): Agent {\n const rt = createAgentRuntime(rawOptions)\n const { hooks, allMcpServers, skillsDisabled, skillsConfig, eager, provider, toolStateController, executionContext, agentBehavior } = rt\n\n installBackgroundTaskTracking(rt)\n bindSessionHooks(rt)\n registerCachePromptSections(hooks, () => {\n const assembly = rt.lastContextAssembly\n if (!assembly)\n return undefined\n return {\n skillsCatalog: assembly.skillsCatalog,\n toolsCatalog: assembly.subagentDefs,\n mcpInstructions: assembly.mcpInstructions,\n rules: assembly.rulesBlock,\n }\n })\n\n const destroy = (): Promise<void> => destroyAgent(rt)\n\n // Eager bootstrap: kick off MCP connection + skills resolution in the\n // background so the first `run()` doesn't pay the full bootstrap cost.\n // A `warmup()` / `run()` that awaits the same in-flight promise observes\n // a rejection. This detached `.catch` swallows it to prevent Node's\n // unhandled-rejection warning; after a failure the cached promise is\n // dropped, so the next `warmup()` / `run()` retries.\n const eagerHasWork = allMcpServers.length > 0 || (!skillsDisabled && !!skillsConfig)\n if (eager && eagerHasWork) {\n void (sessionToLoad(rt) ? ensureAgentSession(rt).then(() => warmup(rt)) : warmup(rt)).catch(() => {})\n }\n\n return {\n // Same instance; `AgentHookBus` only re-types registration so handler\n // contexts carry the `decide` that `installDecideInjection` attaches.\n hooks: hooks as AgentHookBus,\n decide: rt.decider.forRun(undefined),\n run: (options: AgentRunOptions) => runOrResumeFirst(rt, options),\n resume: (options?: DurableResumeOptions) => resumeAgent(rt, options),\n abort: () => abortRun(rt),\n suspend: (options?: { graceMs?: number }) => suspendRun(rt, options),\n compact: (options?: AgentCompactOptions) => sessionToLoad(rt) ? ensureAgentSession(rt).then(() => compactAgent(rt, options)) : compactAgent(rt, options),\n cancelTool: (callId: string, reason?: string) => cancelTool(rt, callId, reason),\n killBackgroundTask: (taskId: string) => killBackgroundTask(rt, taskId),\n get hasPendingTaskNotifications() { return rt.pendingTaskNotifications.size > 0 },\n steer: (message: string) => steer(rt, message),\n followUp: (message: string) => followUp(rt, message),\n waitForIdle: () => waitForIdle(rt),\n reset: () => reset(rt),\n destroy,\n warmup: (options: { mcpConnectTimeoutMs?: number, maxWallMs?: number } = {}) => sessionToLoad(rt) ? ensureAgentSession(rt).then(() => warmup(rt, options)) : warmup(rt, options),\n activateSkill: (name: string) => activateSkill(rt, name),\n deactivateSkill: (name: string) => deactivateSkill(rt, name),\n get isRunning() { return rt.running || rt.pendingRun !== undefined },\n get mcpConnection() { return rt.mcpConnection },\n get mcpServers() { return allMcpServers },\n get turns() { return rt.conversationTurns },\n get execution() { return executionContext },\n get handle() { return rt.executionHandle },\n ensureExecution: async () =>\n ensureExecutionHandle(rt, resolveTimeoutMs(agentBehavior?.spawnTimeoutMs, DEFAULT_SPAWN_TIMEOUT_MS, agentBehavior?.maxWallMs)),\n get session() { return rt.session ?? null },\n get activeSkills() { return rt.skillActivationState.active() },\n // Frozen copy of provider.meta. A mutable view would let a host write\n // (e.g. `agent.meta.defaultModel = …`) into state shared by every agent\n // that uses the same provider instance. To override model or capabilities,\n // construct a new provider.\n meta: Object.freeze({ ...provider.meta }),\n // Read-only window over the controller's committed state. Reads resolve\n // at call time (not frozen at construction) so a host read after a turn\n // sees that turn's commits. No `set`: see `AgentToolState`.\n toolState: toolStateController.committed,\n getContextBreakdown: (opts?: ContextBreakdownOptions) => getContextBreakdown(rt, opts),\n getContextSegments: (opts?: { rulesFiles?: readonly ContextSegmentFile[], rulesBlock?: string, systemPath?: string }) => getContextSegments(rt, opts),\n cacheExpiresAt: () => cacheExpiresAt(rt),\n cacheImpact: (change: AgentCacheChange) => cacheImpact(rt, change),\n // TC39 explicit-resource-management hook. `destroy` is already\n // idempotent + async, so aliasing it here is sufficient — no extra\n // wrapping needed.\n [Symbol.asyncDispose]: destroy,\n }\n}\n\nconst ALREADY_RUNNING = 'Agent is already running. Use steer() or followUp() to queue messages, or waitForIdle().'\n\n/**\n * `agent.run()`: with `durable.onInterrupted: 'resume'`, first continue the\n * session's run a dead process left (`resumeAgent`), then run the prompt,\n * unless the resumed run was aborted or suspended.\n */\nfunction runOrResumeFirst(rt: AgentRuntime, options: AgentRunOptions): Promise<AgentStats> {\n if (rt.pendingRun)\n return Promise.reject(new Error(ALREADY_RUNNING))\n const resumesFirst = rt.onInterrupted === 'resume' && !rt.running && options.resumeRunId === undefined && options.parentRunId === undefined\n // Nothing to wait for: the run starts in this tick.\n if (!resumesFirst && !sessionToLoad(rt))\n return runAgent(rt, options)\n return withPendingRun(rt, async (pending) => {\n await ensureAgentSession(rt)\n const interrupted = resumesFirst ? await interruptedRunId(rt) : undefined\n if (interrupted !== undefined) {\n const resumed = await continueRun(rt, pending, {\n runId: interrupted,\n ...(options.signal ? { signal: options.signal } : {}),\n ...(options.pauseSignal ? { run: { pauseSignal: options.pauseSignal } } : {}),\n })\n if (resumed && (resumed.suspended || pending.aborted || options.signal?.aborted))\n return resumed\n }\n return stoppedBeforeRun(pending) ?? runAgent(rt, options)\n })\n}\n\n/**\n * The run of the agent's session a dead process left, for `run()` to resume\n * first: the last top-level run still marked resumable, when the runtime's\n * lease lists it (`DurableLease.resumable`: its owner is gone, and it is not\n * parked on a prompt nobody answered). A run that is not listed is left to\n * the new run, which supersedes it, as with `'heal'`.\n */\nasync function interruptedRunId(rt: AgentRuntime): Promise<string | undefined> {\n const { durable, session } = rt\n if (durable?.mode !== 'checkpoint' || !session)\n return undefined\n const run = findResumableRun(session)\n if (!run || !durable.lease)\n return run?.id\n const listed = await durable.lease.resumable({ staleAt: Date.now() - LEASE_STALE_MS, sessionId: session.id })\n return listed.some(r => r.runId === run.id) ? run.id : undefined\n}\n\n/** Run `body` as the agent's pending run (`AgentRuntime.pendingRun`): the agent counts as running until it returns. */\nasync function withPendingRun<R>(rt: AgentRuntime, body: (pending: PendingRun) => Promise<R>): Promise<R> {\n const settled = Promise.withResolvers<void>()\n const pending: PendingRun = { suspended: false, aborted: false, settled: settled.promise }\n rt.pendingRun = pending\n try {\n return await body(pending)\n }\n finally {\n if (rt.pendingRun === pending)\n rt.pendingRun = undefined\n settled.resolve()\n }\n}\n\n/** The stats of a pending run a suspend or abort stopped before its run started; `undefined` when neither did. */\nfunction stoppedBeforeRun(pending: PendingRun): AgentStats | undefined {\n if (pending.suspended)\n return { ...zeroRunStats(Date.now()), suspended: true }\n if (pending.aborted)\n return zeroRunStats(Date.now())\n}\n\n/** `agent.resume()`: continue the session's checkpoint run a process death left unfinished; `null` when there is none to continue. */\nfunction resumeAgent(rt: AgentRuntime, options: DurableResumeOptions = {}): Promise<AgentStats | null> {\n if (rt.durable?.mode !== 'checkpoint')\n return Promise.reject(new Error('agent.resume() needs a checkpoint-mode durable runtime (createAgent({ durable })). A replay-mode runtime continues a run by running the same invocation again.'))\n if (rt.pendingRun)\n return Promise.reject(new Error(ALREADY_RUNNING))\n return withPendingRun(rt, pending => continueRun(rt, pending, options))\n}\n\nasync function continueRun(rt: AgentRuntime, pending: PendingRun, options: DurableResumeOptions): Promise<AgentStats | null> {\n const durable = rt.durable!\n await ensureAgentSession(rt)\n if (!rt.session)\n throw new Error('agent.resume() needs a session: the run continues from its saved turns.')\n const session = rt.session\n const run = findResumableRun(session, options.runId)\n if (!run)\n return null\n const mismatch = await assertResumable(durable, session, run)\n if (mismatch) {\n await rt.hooks.callHook('resume:mismatch', { sessionId: session.id, runId: run.id, ...mismatch })\n return null\n }\n await joinStreamPartials(durable, session, run)\n // Suspended or aborted before its run started (a host draining): nothing ran, the run stays resumable.\n return stoppedBeforeRun(pending) ?? runAgent(rt, resumedRunOptions(run, { ...options.run, ...(options.signal ? { signal: options.signal } : {}) }), { runId: run.id })\n}\n\n/** The last request this agent sent: from the run in progress, else from the latest run that sent one. */\nfunction lastRequestOf(rt: AgentRuntime) {\n return rt.activeRunContext?.lastRequest ?? rt.lastRunContext?.ctx.lastRequest\n}\n\nfunction cacheExpiresAt(rt: AgentRuntime): number | null {\n const request = lastRequestOf(rt)\n return estimateCacheExpiresAt(request && { sentAt: request.sentAt, cacheTtl: request.options.cacheTtl })\n}\n\nfunction cacheImpact(rt: AgentRuntime, change: AgentCacheChange): AgentCacheImpact {\n const request = lastRequestOf(rt)\n let promptTokens = 0\n for (let i = rt.conversationTurns.length - 1; i >= 0; i--) {\n const usage = rt.conversationTurns[i]?.role === 'assistant' ? rt.conversationTurns[i]?.usage : undefined\n if (usage) {\n promptTokens = usage.input + (usage.cacheRead ?? 0) + (usage.cacheCreation ?? 0)\n break\n }\n }\n return estimateCacheImpact({\n ...(request ? { request: { model: request.options.model, thinking: request.options.thinking ?? 'off' } } : {}),\n promptTokens,\n expiresAt: cacheExpiresAt(rt),\n }, change, Date.now())\n}\n"],"mappings":"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"}