@draht/agent-core 2026.7.30 → 2026.10.4-2

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 (456) hide show
  1. package/dist/agent-loop.d.ts +27 -2
  2. package/dist/agent-loop.d.ts.map +1 -1
  3. package/dist/agent-loop.js +181 -63
  4. package/dist/agent-loop.js.map +1 -1
  5. package/dist/agent.d.ts +14 -4
  6. package/dist/agent.d.ts.map +1 -1
  7. package/dist/agent.js +68 -19
  8. package/dist/agent.js.map +1 -1
  9. package/dist/harness/agent-harness.d.ts +713 -91
  10. package/dist/harness/agent-harness.d.ts.map +1 -1
  11. package/dist/harness/agent-harness.js +5 -950
  12. package/dist/harness/agent-harness.js.map +1 -1
  13. package/dist/harness/compaction/branch-summarization.d.ts +23 -10
  14. package/dist/harness/compaction/branch-summarization.d.ts.map +1 -1
  15. package/dist/harness/compaction/branch-summarization.js +39 -36
  16. package/dist/harness/compaction/branch-summarization.js.map +1 -1
  17. package/dist/harness/compaction/compaction.d.ts +37 -18
  18. package/dist/harness/compaction/compaction.d.ts.map +1 -1
  19. package/dist/harness/compaction/compaction.js +74 -97
  20. package/dist/harness/compaction/compaction.js.map +1 -1
  21. package/dist/harness/config.d.ts +9 -0
  22. package/dist/harness/config.d.ts.map +1 -0
  23. package/dist/harness/config.js +35 -0
  24. package/dist/harness/config.js.map +1 -0
  25. package/dist/harness/context.d.ts +9 -0
  26. package/dist/harness/context.d.ts.map +1 -0
  27. package/dist/harness/context.js +13 -0
  28. package/dist/harness/context.js.map +1 -0
  29. package/dist/harness/env/nodejs.d.ts +25 -27
  30. package/dist/harness/env/nodejs.d.ts.map +1 -1
  31. package/dist/harness/env/nodejs.js +355 -110
  32. package/dist/harness/env/nodejs.js.map +1 -1
  33. package/dist/harness/events.d.ts +24 -0
  34. package/dist/harness/events.d.ts.map +1 -0
  35. package/dist/harness/events.js +233 -0
  36. package/dist/harness/events.js.map +1 -0
  37. package/dist/harness/execution/assistant.d.ts +42 -0
  38. package/dist/harness/execution/assistant.d.ts.map +1 -0
  39. package/dist/harness/execution/assistant.js +82 -0
  40. package/dist/harness/execution/assistant.js.map +1 -0
  41. package/dist/harness/execution/effect-gate.d.ts +22 -0
  42. package/dist/harness/execution/effect-gate.d.ts.map +1 -0
  43. package/dist/harness/execution/effect-gate.js +49 -0
  44. package/dist/harness/execution/effect-gate.js.map +1 -0
  45. package/dist/harness/execution/tools.d.ts +67 -0
  46. package/dist/harness/execution/tools.d.ts.map +1 -0
  47. package/dist/harness/execution/tools.js +119 -0
  48. package/dist/harness/execution/tools.js.map +1 -0
  49. package/dist/harness/hooks.d.ts +38 -0
  50. package/dist/harness/hooks.d.ts.map +1 -0
  51. package/dist/harness/hooks.js +406 -0
  52. package/dist/harness/hooks.js.map +1 -0
  53. package/dist/harness/messages.d.ts +4 -4
  54. package/dist/harness/messages.d.ts.map +1 -1
  55. package/dist/harness/messages.js +4 -3
  56. package/dist/harness/messages.js.map +1 -1
  57. package/dist/harness/pico3/bash.d.ts +10 -0
  58. package/dist/harness/pico3/bash.d.ts.map +1 -0
  59. package/dist/harness/pico3/bash.js +25 -0
  60. package/dist/harness/pico3/bash.js.map +1 -0
  61. package/dist/harness/pico3/bounded.d.ts +21 -0
  62. package/dist/harness/pico3/bounded.d.ts.map +1 -0
  63. package/dist/harness/pico3/bounded.js +98 -0
  64. package/dist/harness/pico3/bounded.js.map +1 -0
  65. package/dist/harness/pico3/chord.d.ts +41 -0
  66. package/dist/harness/pico3/chord.d.ts.map +1 -0
  67. package/dist/harness/pico3/chord.js +147 -0
  68. package/dist/harness/pico3/chord.js.map +1 -0
  69. package/dist/harness/pico3/context.d.ts +16 -0
  70. package/dist/harness/pico3/context.d.ts.map +1 -0
  71. package/dist/harness/pico3/context.js +88 -0
  72. package/dist/harness/pico3/context.js.map +1 -0
  73. package/dist/harness/pico3/harness.d.ts +198 -0
  74. package/dist/harness/pico3/harness.d.ts.map +1 -0
  75. package/dist/harness/pico3/harness.js +654 -0
  76. package/dist/harness/pico3/harness.js.map +1 -0
  77. package/dist/harness/pico3/hooks.d.ts +10 -0
  78. package/dist/harness/pico3/hooks.d.ts.map +1 -0
  79. package/dist/harness/pico3/hooks.js +33 -0
  80. package/dist/harness/pico3/hooks.js.map +1 -0
  81. package/dist/harness/pico3/index.d.ts +19 -0
  82. package/dist/harness/pico3/index.d.ts.map +1 -0
  83. package/dist/harness/pico3/index.js +15 -0
  84. package/dist/harness/pico3/index.js.map +1 -0
  85. package/dist/harness/pico3/jsonl.d.ts +58 -0
  86. package/dist/harness/pico3/jsonl.d.ts.map +1 -0
  87. package/dist/harness/pico3/jsonl.js +325 -0
  88. package/dist/harness/pico3/jsonl.js.map +1 -0
  89. package/dist/harness/pico3/kinds/collapse.d.ts +49 -0
  90. package/dist/harness/pico3/kinds/collapse.d.ts.map +1 -0
  91. package/dist/harness/pico3/kinds/collapse.js +191 -0
  92. package/dist/harness/pico3/kinds/collapse.js.map +1 -0
  93. package/dist/harness/pico3/kinds/entries.d.ts +78 -0
  94. package/dist/harness/pico3/kinds/entries.d.ts.map +1 -0
  95. package/dist/harness/pico3/kinds/entries.js +13 -0
  96. package/dist/harness/pico3/kinds/entries.js.map +1 -0
  97. package/dist/harness/pico3/kinds/frames.d.ts +9 -0
  98. package/dist/harness/pico3/kinds/frames.d.ts.map +1 -0
  99. package/dist/harness/pico3/kinds/frames.js +75 -0
  100. package/dist/harness/pico3/kinds/frames.js.map +1 -0
  101. package/dist/harness/pico3/kinds/generation.d.ts +94 -0
  102. package/dist/harness/pico3/kinds/generation.d.ts.map +1 -0
  103. package/dist/harness/pico3/kinds/generation.js +504 -0
  104. package/dist/harness/pico3/kinds/generation.js.map +1 -0
  105. package/dist/harness/pico3/kinds/job.d.ts +44 -0
  106. package/dist/harness/pico3/kinds/job.d.ts.map +1 -0
  107. package/dist/harness/pico3/kinds/job.js +143 -0
  108. package/dist/harness/pico3/kinds/job.js.map +1 -0
  109. package/dist/harness/pico3/kinds/plugin.d.ts +15 -0
  110. package/dist/harness/pico3/kinds/plugin.d.ts.map +1 -0
  111. package/dist/harness/pico3/kinds/plugin.js +35 -0
  112. package/dist/harness/pico3/kinds/plugin.js.map +1 -0
  113. package/dist/harness/pico3/kinds/post-tools.d.ts +22 -0
  114. package/dist/harness/pico3/kinds/post-tools.d.ts.map +1 -0
  115. package/dist/harness/pico3/kinds/post-tools.js +145 -0
  116. package/dist/harness/pico3/kinds/post-tools.js.map +1 -0
  117. package/dist/harness/pico3/kinds/task-api.d.ts +3 -0
  118. package/dist/harness/pico3/kinds/task-api.d.ts.map +1 -0
  119. package/dist/harness/pico3/kinds/task-api.js +45 -0
  120. package/dist/harness/pico3/kinds/task-api.js.map +1 -0
  121. package/dist/harness/pico3/kinds/tool.d.ts +43 -0
  122. package/dist/harness/pico3/kinds/tool.d.ts.map +1 -0
  123. package/dist/harness/pico3/kinds/tool.js +373 -0
  124. package/dist/harness/pico3/kinds/tool.js.map +1 -0
  125. package/dist/harness/pico3/legacy-tracker.d.ts +11 -0
  126. package/dist/harness/pico3/legacy-tracker.d.ts.map +1 -0
  127. package/dist/harness/pico3/legacy-tracker.js +41 -0
  128. package/dist/harness/pico3/legacy-tracker.js.map +1 -0
  129. package/dist/harness/pico3/membrane.d.ts +23 -0
  130. package/dist/harness/pico3/membrane.d.ts.map +1 -0
  131. package/dist/harness/pico3/membrane.js +141 -0
  132. package/dist/harness/pico3/membrane.js.map +1 -0
  133. package/dist/harness/pico3/memory.d.ts +53 -0
  134. package/dist/harness/pico3/memory.d.ts.map +1 -0
  135. package/dist/harness/pico3/memory.js +264 -0
  136. package/dist/harness/pico3/memory.js.map +1 -0
  137. package/dist/harness/pico3/scheduler.d.ts +49 -0
  138. package/dist/harness/pico3/scheduler.d.ts.map +1 -0
  139. package/dist/harness/pico3/scheduler.js +438 -0
  140. package/dist/harness/pico3/scheduler.js.map +1 -0
  141. package/dist/harness/pico3/session.d.ts +264 -0
  142. package/dist/harness/pico3/session.d.ts.map +1 -0
  143. package/dist/harness/pico3/session.js +1348 -0
  144. package/dist/harness/pico3/session.js.map +1 -0
  145. package/dist/harness/pico3/system.d.ts +126 -0
  146. package/dist/harness/pico3/system.d.ts.map +1 -0
  147. package/dist/harness/pico3/system.js +244 -0
  148. package/dist/harness/pico3/system.js.map +1 -0
  149. package/dist/harness/pico3/types.d.ts +973 -0
  150. package/dist/harness/pico3/types.d.ts.map +1 -0
  151. package/dist/harness/pico3/types.js +106 -0
  152. package/dist/harness/pico3/types.js.map +1 -0
  153. package/dist/harness/pico3/view.d.ts +34 -0
  154. package/dist/harness/pico3/view.d.ts.map +1 -0
  155. package/dist/harness/pico3/view.js +411 -0
  156. package/dist/harness/pico3/view.js.map +1 -0
  157. package/dist/harness/prompt-templates.d.ts +3 -2
  158. package/dist/harness/prompt-templates.d.ts.map +1 -1
  159. package/dist/harness/prompt-templates.js +18 -23
  160. package/dist/harness/prompt-templates.js.map +1 -1
  161. package/dist/harness/result.d.ts +133 -0
  162. package/dist/harness/result.d.ts.map +1 -0
  163. package/dist/harness/result.js +81 -0
  164. package/dist/harness/result.js.map +1 -0
  165. package/dist/harness/runtime/drive/boundary.d.ts +28 -0
  166. package/dist/harness/runtime/drive/boundary.d.ts.map +1 -0
  167. package/dist/harness/runtime/drive/boundary.js +173 -0
  168. package/dist/harness/runtime/drive/boundary.js.map +1 -0
  169. package/dist/harness/runtime/drive/checkpoint.d.ts +8 -0
  170. package/dist/harness/runtime/drive/checkpoint.d.ts.map +1 -0
  171. package/dist/harness/runtime/drive/checkpoint.js +133 -0
  172. package/dist/harness/runtime/drive/checkpoint.js.map +1 -0
  173. package/dist/harness/runtime/drive/deferred.d.ts +15 -0
  174. package/dist/harness/runtime/drive/deferred.d.ts.map +1 -0
  175. package/dist/harness/runtime/drive/deferred.js +179 -0
  176. package/dist/harness/runtime/drive/deferred.js.map +1 -0
  177. package/dist/harness/runtime/drive/generation.d.ts +8 -0
  178. package/dist/harness/runtime/drive/generation.d.ts.map +1 -0
  179. package/dist/harness/runtime/drive/generation.js +205 -0
  180. package/dist/harness/runtime/drive/generation.js.map +1 -0
  181. package/dist/harness/runtime/drive/reconcile.d.ts +5 -0
  182. package/dist/harness/runtime/drive/reconcile.d.ts.map +1 -0
  183. package/dist/harness/runtime/drive/reconcile.js +140 -0
  184. package/dist/harness/runtime/drive/reconcile.js.map +1 -0
  185. package/dist/harness/runtime/drive/recovery.d.ts +8 -0
  186. package/dist/harness/runtime/drive/recovery.d.ts.map +1 -0
  187. package/dist/harness/runtime/drive/recovery.js +85 -0
  188. package/dist/harness/runtime/drive/recovery.js.map +1 -0
  189. package/dist/harness/runtime/drive/response.d.ts +23 -0
  190. package/dist/harness/runtime/drive/response.d.ts.map +1 -0
  191. package/dist/harness/runtime/drive/response.js +394 -0
  192. package/dist/harness/runtime/drive/response.js.map +1 -0
  193. package/dist/harness/runtime/drive/retry.d.ts +4 -0
  194. package/dist/harness/runtime/drive/retry.d.ts.map +1 -0
  195. package/dist/harness/runtime/drive/retry.js +34 -0
  196. package/dist/harness/runtime/drive/retry.js.map +1 -0
  197. package/dist/harness/runtime/drive/structural.d.ts +32 -0
  198. package/dist/harness/runtime/drive/structural.d.ts.map +1 -0
  199. package/dist/harness/runtime/drive/structural.js +929 -0
  200. package/dist/harness/runtime/drive/structural.js.map +1 -0
  201. package/dist/harness/runtime/drive/terminal.d.ts +7 -0
  202. package/dist/harness/runtime/drive/terminal.d.ts.map +1 -0
  203. package/dist/harness/runtime/drive/terminal.js +49 -0
  204. package/dist/harness/runtime/drive/terminal.js.map +1 -0
  205. package/dist/harness/runtime/drive/tool-placement.d.ts +14 -0
  206. package/dist/harness/runtime/drive/tool-placement.d.ts.map +1 -0
  207. package/dist/harness/runtime/drive/tool-placement.js +219 -0
  208. package/dist/harness/runtime/drive/tool-placement.js.map +1 -0
  209. package/dist/harness/runtime/drive/tools.d.ts +6 -0
  210. package/dist/harness/runtime/drive/tools.d.ts.map +1 -0
  211. package/dist/harness/runtime/drive/tools.js +449 -0
  212. package/dist/harness/runtime/drive/tools.js.map +1 -0
  213. package/dist/harness/runtime/drive.d.ts +6 -0
  214. package/dist/harness/runtime/drive.d.ts.map +1 -0
  215. package/dist/harness/runtime/drive.js +93 -0
  216. package/dist/harness/runtime/drive.js.map +1 -0
  217. package/dist/harness/runtime/harness.d.ts +59 -0
  218. package/dist/harness/runtime/harness.d.ts.map +1 -0
  219. package/dist/harness/runtime/harness.js +311 -0
  220. package/dist/harness/runtime/harness.js.map +1 -0
  221. package/dist/harness/runtime/index.d.ts +2 -0
  222. package/dist/harness/runtime/index.d.ts.map +1 -0
  223. package/dist/harness/runtime/index.js +2 -0
  224. package/dist/harness/runtime/index.js.map +1 -0
  225. package/dist/harness/runtime/lane.d.ts +118 -0
  226. package/dist/harness/runtime/lane.d.ts.map +1 -0
  227. package/dist/harness/runtime/lane.js +1575 -0
  228. package/dist/harness/runtime/lane.js.map +1 -0
  229. package/dist/harness/runtime/progress.d.ts +15 -0
  230. package/dist/harness/runtime/progress.d.ts.map +1 -0
  231. package/dist/harness/runtime/progress.js +66 -0
  232. package/dist/harness/runtime/progress.js.map +1 -0
  233. package/dist/harness/runtime/reducer.d.ts +5 -0
  234. package/dist/harness/runtime/reducer.d.ts.map +1 -0
  235. package/dist/harness/runtime/reducer.js +240 -0
  236. package/dist/harness/runtime/reducer.js.map +1 -0
  237. package/dist/harness/runtime/restore.d.ts +24 -0
  238. package/dist/harness/runtime/restore.d.ts.map +1 -0
  239. package/dist/harness/runtime/restore.js +117 -0
  240. package/dist/harness/runtime/restore.js.map +1 -0
  241. package/dist/harness/runtime/transcript.d.ts +21 -0
  242. package/dist/harness/runtime/transcript.d.ts.map +1 -0
  243. package/dist/harness/runtime/transcript.js +72 -0
  244. package/dist/harness/runtime/transcript.js.map +1 -0
  245. package/dist/harness/runtime/types.d.ts +105 -0
  246. package/dist/harness/runtime/types.d.ts.map +1 -0
  247. package/dist/harness/runtime/types.js +61 -0
  248. package/dist/harness/runtime/types.js.map +1 -0
  249. package/dist/harness/session/commit.d.ts +53 -0
  250. package/dist/harness/session/commit.d.ts.map +1 -0
  251. package/dist/harness/session/commit.js +57 -0
  252. package/dist/harness/session/commit.js.map +1 -0
  253. package/dist/harness/session/context.d.ts +10 -0
  254. package/dist/harness/session/context.d.ts.map +1 -0
  255. package/dist/harness/session/context.js +49 -0
  256. package/dist/harness/session/context.js.map +1 -0
  257. package/dist/harness/session/fork-policy.d.ts +21 -0
  258. package/dist/harness/session/fork-policy.d.ts.map +1 -0
  259. package/dist/harness/session/fork-policy.js +55 -0
  260. package/dist/harness/session/fork-policy.js.map +1 -0
  261. package/dist/harness/session/fork.d.ts +16 -0
  262. package/dist/harness/session/fork.d.ts.map +1 -0
  263. package/dist/harness/session/fork.js +79 -0
  264. package/dist/harness/session/fork.js.map +1 -0
  265. package/dist/harness/session/in-memory-storage-state.d.ts +39 -0
  266. package/dist/harness/session/in-memory-storage-state.d.ts.map +1 -0
  267. package/dist/harness/session/in-memory-storage-state.js +276 -0
  268. package/dist/harness/session/in-memory-storage-state.js.map +1 -0
  269. package/dist/harness/session/index.d.ts +11 -0
  270. package/dist/harness/session/index.d.ts.map +1 -0
  271. package/dist/harness/session/index.js +9 -0
  272. package/dist/harness/session/index.js.map +1 -0
  273. package/dist/harness/session/jsonl/codec.d.ts +21 -0
  274. package/dist/harness/session/jsonl/codec.d.ts.map +1 -0
  275. package/dist/harness/session/jsonl/codec.js +45 -0
  276. package/dist/harness/session/jsonl/codec.js.map +1 -0
  277. package/dist/harness/session/jsonl/fork.d.ts +38 -0
  278. package/dist/harness/session/jsonl/fork.d.ts.map +1 -0
  279. package/dist/harness/session/jsonl/fork.js +264 -0
  280. package/dist/harness/session/jsonl/fork.js.map +1 -0
  281. package/dist/harness/session/jsonl/index.d.ts +4 -0
  282. package/dist/harness/session/jsonl/index.d.ts.map +1 -0
  283. package/dist/harness/session/jsonl/index.js +4 -0
  284. package/dist/harness/session/jsonl/index.js.map +1 -0
  285. package/dist/harness/session/jsonl/io.d.ts +14 -0
  286. package/dist/harness/session/jsonl/io.d.ts.map +1 -0
  287. package/dist/harness/session/jsonl/io.js +86 -0
  288. package/dist/harness/session/jsonl/io.js.map +1 -0
  289. package/dist/harness/session/jsonl/legacy-v3.d.ts +44 -0
  290. package/dist/harness/session/jsonl/legacy-v3.d.ts.map +1 -0
  291. package/dist/harness/session/jsonl/legacy-v3.js +462 -0
  292. package/dist/harness/session/jsonl/legacy-v3.js.map +1 -0
  293. package/dist/harness/session/jsonl/repo.d.ts +35 -0
  294. package/dist/harness/session/jsonl/repo.d.ts.map +1 -0
  295. package/dist/harness/session/jsonl/repo.js +301 -0
  296. package/dist/harness/session/jsonl/repo.js.map +1 -0
  297. package/dist/harness/session/jsonl/storage.d.ts +41 -0
  298. package/dist/harness/session/jsonl/storage.d.ts.map +1 -0
  299. package/dist/harness/session/jsonl/storage.js +200 -0
  300. package/dist/harness/session/jsonl/storage.js.map +1 -0
  301. package/dist/harness/session/jsonl/types.d.ts +39 -0
  302. package/dist/harness/session/jsonl/types.d.ts.map +1 -0
  303. package/dist/harness/session/jsonl/types.js +3 -0
  304. package/dist/harness/session/jsonl/types.js.map +1 -0
  305. package/dist/harness/session/memory.d.ts +48 -0
  306. package/dist/harness/session/memory.d.ts.map +1 -0
  307. package/dist/harness/session/memory.js +369 -0
  308. package/dist/harness/session/memory.js.map +1 -0
  309. package/dist/harness/session/mutation-line.d.ts +8 -0
  310. package/dist/harness/session/mutation-line.d.ts.map +1 -0
  311. package/dist/harness/session/mutation-line.js +21 -0
  312. package/dist/harness/session/mutation-line.js.map +1 -0
  313. package/dist/harness/session/session.d.ts +79 -46
  314. package/dist/harness/session/session.d.ts.map +1 -1
  315. package/dist/harness/session/session.js +320 -220
  316. package/dist/harness/session/session.js.map +1 -1
  317. package/dist/harness/session/testing/benchmark/datasets.d.ts +12 -0
  318. package/dist/harness/session/testing/benchmark/datasets.d.ts.map +1 -0
  319. package/dist/harness/session/testing/benchmark/datasets.js +24 -0
  320. package/dist/harness/session/testing/benchmark/datasets.js.map +1 -0
  321. package/dist/harness/session/testing/benchmark/session-repo.d.ts +42 -0
  322. package/dist/harness/session/testing/benchmark/session-repo.d.ts.map +1 -0
  323. package/dist/harness/session/testing/benchmark/session-repo.js +127 -0
  324. package/dist/harness/session/testing/benchmark/session-repo.js.map +1 -0
  325. package/dist/harness/session/testing/benchmark/storage.d.ts +25 -0
  326. package/dist/harness/session/testing/benchmark/storage.d.ts.map +1 -0
  327. package/dist/harness/session/testing/benchmark/storage.js +114 -0
  328. package/dist/harness/session/testing/benchmark/storage.js.map +1 -0
  329. package/dist/harness/session/testing/conformance/session-repo.d.ts +23 -0
  330. package/dist/harness/session/testing/conformance/session-repo.d.ts.map +1 -0
  331. package/dist/harness/session/testing/conformance/session-repo.js +809 -0
  332. package/dist/harness/session/testing/conformance/session-repo.js.map +1 -0
  333. package/dist/harness/session/testing/conformance/storage.d.ts +4 -0
  334. package/dist/harness/session/testing/conformance/storage.d.ts.map +1 -0
  335. package/dist/harness/session/testing/conformance/storage.js +600 -0
  336. package/dist/harness/session/testing/conformance/storage.js.map +1 -0
  337. package/dist/harness/session/testing/gating-storage.d.ts +26 -0
  338. package/dist/harness/session/testing/gating-storage.d.ts.map +1 -0
  339. package/dist/harness/session/testing/gating-storage.js +100 -0
  340. package/dist/harness/session/testing/gating-storage.js.map +1 -0
  341. package/dist/harness/session/testing/index.d.ts +10 -0
  342. package/dist/harness/session/testing/index.d.ts.map +1 -0
  343. package/dist/harness/session/testing/index.js +9 -0
  344. package/dist/harness/session/testing/index.js.map +1 -0
  345. package/dist/harness/session/testing/instrumented-storage.d.ts +11 -0
  346. package/dist/harness/session/testing/instrumented-storage.d.ts.map +1 -0
  347. package/dist/harness/session/testing/instrumented-storage.js +16 -0
  348. package/dist/harness/session/testing/instrumented-storage.js.map +1 -0
  349. package/dist/harness/session/testing/storage-decorator.d.ts +20 -0
  350. package/dist/harness/session/testing/storage-decorator.d.ts.map +1 -0
  351. package/dist/harness/session/testing/storage-decorator.js +41 -0
  352. package/dist/harness/session/testing/storage-decorator.js.map +1 -0
  353. package/dist/harness/session/testing/types.d.ts +12 -0
  354. package/dist/harness/session/testing/types.d.ts.map +1 -0
  355. package/dist/harness/session/testing/types.js +2 -0
  356. package/dist/harness/session/testing/types.js.map +1 -0
  357. package/dist/harness/session/types.d.ts +512 -0
  358. package/dist/harness/session/types.d.ts.map +1 -0
  359. package/dist/harness/session/types.js +9 -0
  360. package/dist/harness/session/types.js.map +1 -0
  361. package/dist/harness/session/values.d.ts +95 -0
  362. package/dist/harness/session/values.d.ts.map +1 -0
  363. package/dist/harness/session/values.js +81 -0
  364. package/dist/harness/session/values.js.map +1 -0
  365. package/dist/harness/skills.d.ts +6 -4
  366. package/dist/harness/skills.d.ts.map +1 -1
  367. package/dist/harness/skills.js +59 -44
  368. package/dist/harness/skills.js.map +1 -1
  369. package/dist/harness/telemetry.d.ts +1242 -0
  370. package/dist/harness/telemetry.d.ts.map +1 -0
  371. package/dist/harness/telemetry.js +527 -0
  372. package/dist/harness/telemetry.js.map +1 -0
  373. package/dist/harness/tools/bash.d.ts +4 -4
  374. package/dist/harness/tools/bash.d.ts.map +1 -1
  375. package/dist/harness/tools/bash.js +66 -93
  376. package/dist/harness/tools/bash.js.map +1 -1
  377. package/dist/harness/tools/edit.d.ts.map +1 -1
  378. package/dist/harness/tools/edit.js +24 -11
  379. package/dist/harness/tools/edit.js.map +1 -1
  380. package/dist/harness/tools/file-mutation-queue.d.ts +2 -1
  381. package/dist/harness/tools/file-mutation-queue.d.ts.map +1 -1
  382. package/dist/harness/tools/file-mutation-queue.js +5 -5
  383. package/dist/harness/tools/file-mutation-queue.js.map +1 -1
  384. package/dist/harness/tools/image.js +1 -1
  385. package/dist/harness/tools/image.js.map +1 -1
  386. package/dist/harness/tools/path-utils.d.ts +3 -2
  387. package/dist/harness/tools/path-utils.d.ts.map +1 -1
  388. package/dist/harness/tools/path-utils.js +5 -5
  389. package/dist/harness/tools/path-utils.js.map +1 -1
  390. package/dist/harness/tools/read.d.ts +2 -1
  391. package/dist/harness/tools/read.d.ts.map +1 -1
  392. package/dist/harness/tools/read.js +4 -6
  393. package/dist/harness/tools/read.js.map +1 -1
  394. package/dist/harness/tools/write.d.ts.map +1 -1
  395. package/dist/harness/tools/write.js +7 -7
  396. package/dist/harness/tools/write.js.map +1 -1
  397. package/dist/harness/types.d.ts +126 -502
  398. package/dist/harness/types.d.ts.map +1 -1
  399. package/dist/harness/types.js +10 -16
  400. package/dist/harness/types.js.map +1 -1
  401. package/dist/harness/utils/adaptive-publisher.d.ts +24 -0
  402. package/dist/harness/utils/adaptive-publisher.d.ts.map +1 -0
  403. package/dist/harness/utils/adaptive-publisher.js +79 -0
  404. package/dist/harness/utils/adaptive-publisher.js.map +1 -0
  405. package/dist/harness/utils/output-capture.d.ts +31 -0
  406. package/dist/harness/utils/output-capture.d.ts.map +1 -0
  407. package/dist/harness/utils/output-capture.js +217 -0
  408. package/dist/harness/utils/output-capture.js.map +1 -0
  409. package/dist/harness/utils/shell-output.d.ts +12 -5
  410. package/dist/harness/utils/shell-output.d.ts.map +1 -1
  411. package/dist/harness/utils/shell-output.js +64 -174
  412. package/dist/harness/utils/shell-output.js.map +1 -1
  413. package/dist/harness/utils/truncate.d.ts +1 -0
  414. package/dist/harness/utils/truncate.d.ts.map +1 -1
  415. package/dist/harness/utils/truncate.js +1 -1
  416. package/dist/harness/utils/truncate.js.map +1 -1
  417. package/dist/harness/utils/usage.d.ts +4 -0
  418. package/dist/harness/utils/usage.d.ts.map +1 -0
  419. package/dist/harness/utils/usage.js +33 -0
  420. package/dist/harness/utils/usage.js.map +1 -0
  421. package/dist/index.d.ts +13 -9
  422. package/dist/index.d.ts.map +1 -1
  423. package/dist/index.js +9 -13
  424. package/dist/index.js.map +1 -1
  425. package/dist/proxy.d.ts +6 -3
  426. package/dist/proxy.d.ts.map +1 -1
  427. package/dist/proxy.js +42 -10
  428. package/dist/proxy.js.map +1 -1
  429. package/dist/search/index.d.ts +29 -0
  430. package/dist/search/index.d.ts.map +1 -0
  431. package/dist/search/index.js +2 -0
  432. package/dist/search/index.js.map +1 -0
  433. package/dist/types.d.ts +113 -31
  434. package/dist/types.d.ts.map +1 -1
  435. package/dist/types.js.map +1 -1
  436. package/package.json +50 -4
  437. package/dist/harness/session/jsonl-repo.d.ts +0 -26
  438. package/dist/harness/session/jsonl-repo.d.ts.map +0 -1
  439. package/dist/harness/session/jsonl-repo.js +0 -100
  440. package/dist/harness/session/jsonl-repo.js.map +0 -1
  441. package/dist/harness/session/jsonl-storage.d.ts +0 -42
  442. package/dist/harness/session/jsonl-storage.d.ts.map +0 -1
  443. package/dist/harness/session/jsonl-storage.js +0 -286
  444. package/dist/harness/session/jsonl-storage.js.map +0 -1
  445. package/dist/harness/session/memory-repo.d.ts +0 -18
  446. package/dist/harness/session/memory-repo.d.ts.map +0 -1
  447. package/dist/harness/session/memory-repo.js +0 -44
  448. package/dist/harness/session/memory-repo.js.map +0 -1
  449. package/dist/harness/session/memory-storage.d.ts +0 -33
  450. package/dist/harness/session/memory-storage.d.ts.map +0 -1
  451. package/dist/harness/session/memory-storage.js +0 -163
  452. package/dist/harness/session/memory-storage.js.map +0 -1
  453. package/dist/harness/session/repo-utils.d.ts +0 -11
  454. package/dist/harness/session/repo-utils.d.ts.map +0 -1
  455. package/dist/harness/session/repo-utils.js +0 -39
  456. package/dist/harness/session/repo-utils.js.map +0 -1
@@ -2,8 +2,8 @@
2
2
  * Agent loop that works with AgentMessage throughout.
3
3
  * Transforms to Message[] only at the LLM call boundary.
4
4
  */
5
- import { EventStream } from "@draht/ai";
6
- import type { AgentContext, AgentEvent, AgentLoopConfig, AgentMessage, StreamFn } from "./types.ts";
5
+ import { type AssistantMessage, EventStream } from "@draht/ai";
6
+ import type { AgentContext, AgentEvent, AgentLoopConfig, AgentMessage, AgentTool, AgentToolCall, AgentToolCallOutcome, AgentToolResult, StreamFn } from "./types.ts";
7
7
  export type AgentEventSink = (event: AgentEvent) => Promise<void> | void;
8
8
  /**
9
9
  * Start an agent loop with a new prompt message.
@@ -21,4 +21,29 @@ export declare function agentLoop(prompts: AgentMessage[], context: AgentContext
21
21
  export declare function agentLoopContinue(context: AgentContext, config: AgentLoopConfig, signal: AbortSignal | undefined, streamFn: StreamFn): EventStream<AgentEvent, AgentMessage[]>;
22
22
  export declare function runAgentLoop(prompts: AgentMessage[], context: AgentContext, config: AgentLoopConfig, emit: AgentEventSink, signal: AbortSignal | undefined, streamFn: StreamFn): Promise<AgentMessage[]>;
23
23
  export declare function runAgentLoopContinue(context: AgentContext, config: AgentLoopConfig, emit: AgentEventSink, signal: AbortSignal | undefined, streamFn: StreamFn): Promise<AgentMessage[]>;
24
+ /** The `beforeToolCall` and `afterToolCall` hooks of {@link AgentLoopConfig}. */
25
+ export type ToolCallHooks = Pick<AgentLoopConfig, "beforeToolCall" | "afterToolCall">;
26
+ type ToolUpdateSink = (partialResult: AgentToolResult<any>) => Promise<void> | void;
27
+ /** Options for {@link runToolCall}. */
28
+ export interface RunToolCallOptions extends ToolCallHooks {
29
+ /** Tools the call resolves against. */
30
+ tools: readonly AgentTool<any>[];
31
+ /** Passed to the hooks as the message that issued the call. */
32
+ assistantMessage: AssistantMessage;
33
+ /** Passed to the hooks as the current agent context. */
34
+ context: AgentContext;
35
+ signal?: AbortSignal;
36
+ onUpdate?: ToolUpdateSink;
37
+ }
38
+ /**
39
+ * Run one tool call through the same steps as a model-issued call: argument preparation, schema
40
+ * validation, `beforeToolCall`, execution, and `afterToolCall`. Emits no events and adds no
41
+ * messages. Tools that call other tools use this so the hooks (for example permission checks)
42
+ * apply to those calls too.
43
+ *
44
+ * Never rejects for tool failures: unknown tools, validation errors, blocked calls, and thrown
45
+ * errors come back as `isError: true`.
46
+ */
47
+ export declare function runToolCall(toolCall: AgentToolCall, options: RunToolCallOptions): Promise<AgentToolCallOutcome>;
48
+ export {};
24
49
  //# sourceMappingURL=agent-loop.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"agent-loop.d.ts","sourceRoot":"","sources":["../src/agent-loop.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAGN,WAAW,EAGX,MAAM,WAAW,CAAC;AAEnB,OAAO,KAAK,EACX,YAAY,EACZ,UAAU,EACV,eAAe,EACf,YAAY,EAIZ,QAAQ,EACR,MAAM,YAAY,CAAC;AAEpB,MAAM,MAAM,cAAc,GAAG,CAAC,KAAK,EAAE,UAAU,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;AAEzE;;;GAGG;AACH,wBAAgB,SAAS,CACxB,OAAO,EAAE,YAAY,EAAE,EACvB,OAAO,EAAE,YAAY,EACrB,MAAM,EAAE,eAAe,EACvB,MAAM,EAAE,WAAW,GAAG,SAAS,EAC/B,QAAQ,EAAE,QAAQ,GAChB,WAAW,CAAC,UAAU,EAAE,YAAY,EAAE,CAAC,CAiBzC;AAED;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAChC,OAAO,EAAE,YAAY,EACrB,MAAM,EAAE,eAAe,EACvB,MAAM,EAAE,WAAW,GAAG,SAAS,EAC/B,QAAQ,EAAE,QAAQ,GAChB,WAAW,CAAC,UAAU,EAAE,YAAY,EAAE,CAAC,CAwBzC;AAED,wBAAsB,YAAY,CACjC,OAAO,EAAE,YAAY,EAAE,EACvB,OAAO,EAAE,YAAY,EACrB,MAAM,EAAE,eAAe,EACvB,IAAI,EAAE,cAAc,EACpB,MAAM,EAAE,WAAW,GAAG,SAAS,EAC/B,QAAQ,EAAE,QAAQ,GAChB,OAAO,CAAC,YAAY,EAAE,CAAC,CAgBzB;AAED,wBAAsB,oBAAoB,CACzC,OAAO,EAAE,YAAY,EACrB,MAAM,EAAE,eAAe,EACvB,IAAI,EAAE,cAAc,EACpB,MAAM,EAAE,WAAW,GAAG,SAAS,EAC/B,QAAQ,EAAE,QAAQ,GAChB,OAAO,CAAC,YAAY,EAAE,CAAC,CAiBzB"}
1
+ {"version":3,"file":"agent-loop.d.ts","sourceRoot":"","sources":["../src/agent-loop.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EACN,KAAK,gBAAgB,EACrB,WAAW,EASX,MAAM,WAAW,CAAC;AAEnB,OAAO,KAAK,EACX,YAAY,EACZ,UAAU,EACV,eAAe,EACf,YAAY,EACZ,SAAS,EACT,aAAa,EACb,oBAAoB,EACpB,eAAe,EAEf,QAAQ,EACR,MAAM,YAAY,CAAC;AAEpB,MAAM,MAAM,cAAc,GAAG,CAAC,KAAK,EAAE,UAAU,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;AAEzE;;;GAGG;AACH,wBAAgB,SAAS,CACxB,OAAO,EAAE,YAAY,EAAE,EACvB,OAAO,EAAE,YAAY,EACrB,MAAM,EAAE,eAAe,EACvB,MAAM,EAAE,WAAW,GAAG,SAAS,EAC/B,QAAQ,EAAE,QAAQ,GAChB,WAAW,CAAC,UAAU,EAAE,YAAY,EAAE,CAAC,CAiBzC;AAED;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAChC,OAAO,EAAE,YAAY,EACrB,MAAM,EAAE,eAAe,EACvB,MAAM,EAAE,WAAW,GAAG,SAAS,EAC/B,QAAQ,EAAE,QAAQ,GAChB,WAAW,CAAC,UAAU,EAAE,YAAY,EAAE,CAAC,CAwBzC;AAED,wBAAsB,YAAY,CACjC,OAAO,EAAE,YAAY,EAAE,EACvB,OAAO,EAAE,YAAY,EACrB,MAAM,EAAE,eAAe,EACvB,IAAI,EAAE,cAAc,EACpB,MAAM,EAAE,WAAW,GAAG,SAAS,EAC/B,QAAQ,EAAE,QAAQ,GAChB,OAAO,CAAC,YAAY,EAAE,CAAC,CAiBzB;AAED,wBAAsB,oBAAoB,CACzC,OAAO,EAAE,YAAY,EACrB,MAAM,EAAE,eAAe,EACvB,IAAI,EAAE,cAAc,EACpB,MAAM,EAAE,WAAW,GAAG,SAAS,EAC/B,QAAQ,EAAE,QAAQ,GAChB,OAAO,CAAC,YAAY,EAAE,CAAC,CAiBzB;AAmhBD,iFAAiF;AACjF,MAAM,MAAM,aAAa,GAAG,IAAI,CAAC,eAAe,EAAE,gBAAgB,GAAG,eAAe,CAAC,CAAC;AAEtF,KAAK,cAAc,GAAG,CAAC,aAAa,EAAE,eAAe,CAAC,GAAG,CAAC,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;AAwGpF,uCAAuC;AACvC,MAAM,WAAW,kBAAmB,SAAQ,aAAa;IACxD,uCAAuC;IACvC,KAAK,EAAE,SAAS,SAAS,CAAC,GAAG,CAAC,EAAE,CAAC;IACjC,+DAA+D;IAC/D,gBAAgB,EAAE,gBAAgB,CAAC;IACnC,wDAAwD;IACxD,OAAO,EAAE,YAAY,CAAC;IACtB,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,QAAQ,CAAC,EAAE,cAAc,CAAC;CAC1B;AAED;;;;;;;;GAQG;AACH,wBAAsB,WAAW,CAAC,QAAQ,EAAE,aAAa,EAAE,OAAO,EAAE,kBAAkB,GAAG,OAAO,CAAC,oBAAoB,CAAC,CAQrH"}
@@ -2,7 +2,7 @@
2
2
  * Agent loop that works with AgentMessage throughout.
3
3
  * Transforms to Message[] only at the LLM call boundary.
4
4
  */
5
- import { EventStream, validateToolArguments, } from "@draht/ai";
5
+ import { EventStream, getCurrentTools, getToolStateChanges, normalizeContext, toToolDeclaration, validateToolArguments, } from "@draht/ai";
6
6
  import { getDefaultStreamFn } from "./stream-fn.js";
7
7
  /**
8
8
  * Start an agent loop with a new prompt message.
@@ -41,16 +41,17 @@ export function agentLoopContinue(context, config, signal, streamFn) {
41
41
  return stream;
42
42
  }
43
43
  export async function runAgentLoop(prompts, context, config, emit, signal, streamFn) {
44
- const newMessages = [...prompts];
44
+ const initialMessages = declareToolChanges(context, prompts);
45
+ const newMessages = [...initialMessages];
45
46
  const currentContext = {
46
47
  ...context,
47
- messages: [...context.messages, ...prompts],
48
+ messages: [...context.messages, ...initialMessages],
48
49
  };
49
50
  await emit({ type: "agent_start" });
50
51
  await emit({ type: "turn_start" });
51
- for (const prompt of prompts) {
52
- await emit({ type: "message_start", message: prompt });
53
- await emit({ type: "message_end", message: prompt });
52
+ for (const message of initialMessages) {
53
+ await emit({ type: "message_start", message });
54
+ await emit({ type: "message_end", message });
54
55
  }
55
56
  await runLoop(currentContext, newMessages, config, signal, emit, streamFn ?? getDefaultStreamFn());
56
57
  return newMessages;
@@ -78,7 +79,8 @@ function createAgentStream() {
78
79
  async function runLoop(initialContext, newMessages, initialConfig, signal, emit, streamFunction) {
79
80
  let currentContext = initialContext;
80
81
  let config = initialConfig;
81
- let firstTurn = true;
82
+ let lastCompletedTurn;
83
+ let explicitContinuation = false;
82
84
  // Check for steering messages at start (user may have typed while waiting)
83
85
  let pendingMessages = (await config.getSteeringMessages?.()) || [];
84
86
  // Outer loop: continues when queued follow-up messages arrive after agent would stop
@@ -86,26 +88,66 @@ async function runLoop(initialContext, newMessages, initialConfig, signal, emit,
86
88
  let hasMoreToolCalls = true;
87
89
  // Inner loop: process tool calls and steering messages
88
90
  while (hasMoreToolCalls || pendingMessages.length > 0) {
89
- if (!firstTurn) {
91
+ let preparedMessages = [];
92
+ if (lastCompletedTurn) {
93
+ const nextTurnSnapshot = await config.prepareNextTurn?.(lastCompletedTurn);
94
+ if (nextTurnSnapshot) {
95
+ currentContext = nextTurnSnapshot.context ?? currentContext;
96
+ preparedMessages = nextTurnSnapshot.messages ?? [];
97
+ config = {
98
+ ...config,
99
+ model: nextTurnSnapshot.model ?? config.model,
100
+ reasoning: nextTurnSnapshot.thinkingLevel === undefined
101
+ ? config.reasoning
102
+ : nextTurnSnapshot.thinkingLevel === "off"
103
+ ? undefined
104
+ : nextTurnSnapshot.thinkingLevel,
105
+ };
106
+ }
107
+ // Preparation can be long-running (for example, compaction). Pick up steering
108
+ // queued while it ran. Only poll again if the earlier poll returned nothing;
109
+ // otherwise one-at-a-time mode would deliver two messages in this turn.
110
+ if (pendingMessages.length === 0) {
111
+ pendingMessages = (await config.getSteeringMessages?.()) || [];
112
+ }
90
113
  await emit({ type: "turn_start" });
91
114
  }
92
- else {
93
- firstTurn = false;
115
+ // Process prepared and queued messages before the next assistant response.
116
+ for (const message of declareToolChanges(currentContext, [...preparedMessages, ...pendingMessages])) {
117
+ await emit({ type: "message_start", message });
118
+ await emit({ type: "message_end", message });
119
+ currentContext.messages.push(message);
120
+ newMessages.push(message);
94
121
  }
95
- // Process pending messages (inject before next assistant response)
96
- if (pendingMessages.length > 0) {
97
- for (const message of pendingMessages) {
98
- await emit({ type: "message_start", message });
99
- await emit({ type: "message_end", message });
100
- currentContext.messages.push(message);
101
- newMessages.push(message);
102
- }
103
- pendingMessages = [];
122
+ pendingMessages = [];
123
+ const requestUpdate = await config.prepareRequest?.({
124
+ context: currentContext,
125
+ model: config.model,
126
+ thinkingLevel: config.reasoning ?? "off",
127
+ }, signal);
128
+ if (requestUpdate) {
129
+ currentContext = requestUpdate.context ?? currentContext;
130
+ config = {
131
+ ...config,
132
+ model: requestUpdate.model ?? config.model,
133
+ reasoning: requestUpdate.thinkingLevel === undefined
134
+ ? config.reasoning
135
+ : requestUpdate.thinkingLevel === "off"
136
+ ? undefined
137
+ : requestUpdate.thinkingLevel,
138
+ };
104
139
  }
105
140
  // Stream assistant response
106
141
  const message = await streamAssistantResponse(currentContext, config, signal, emit, streamFunction);
107
142
  newMessages.push(message);
108
143
  if (message.stopReason === "error" || message.stopReason === "aborted") {
144
+ lastCompletedTurn = {
145
+ message,
146
+ toolResults: [],
147
+ context: currentContext,
148
+ newMessages,
149
+ };
150
+ await config.finishTurn?.(lastCompletedTurn, signal);
109
151
  await emit({ type: "turn_end", message, toolResults: [] });
110
152
  await emit({ type: "agent_end", messages: newMessages });
111
153
  return;
@@ -128,49 +170,89 @@ async function runLoop(initialContext, newMessages, initialConfig, signal, emit,
128
170
  newMessages.push(result);
129
171
  }
130
172
  }
131
- await emit({ type: "turn_end", message, toolResults });
132
- const nextTurnContext = {
173
+ lastCompletedTurn = {
133
174
  message,
134
175
  toolResults,
135
176
  context: currentContext,
136
177
  newMessages,
137
178
  };
138
- const nextTurnSnapshot = await config.prepareNextTurn?.(nextTurnContext);
139
- if (nextTurnSnapshot) {
140
- currentContext = nextTurnSnapshot.context ?? currentContext;
141
- config = {
142
- ...config,
143
- model: nextTurnSnapshot.model ?? config.model,
144
- reasoning: nextTurnSnapshot.thinkingLevel === undefined
145
- ? config.reasoning
146
- : nextTurnSnapshot.thinkingLevel === "off"
147
- ? undefined
148
- : nextTurnSnapshot.thinkingLevel,
149
- };
150
- }
151
- if (await config.shouldStopAfterTurn?.({
152
- message,
153
- toolResults,
154
- context: currentContext,
155
- newMessages,
156
- })) {
179
+ const decision = await config.finishTurn?.(lastCompletedTurn, signal);
180
+ await emit({ type: "turn_end", message, toolResults });
181
+ if (decision?.action === "end") {
157
182
  await emit({ type: "agent_end", messages: newMessages });
158
183
  return;
159
184
  }
185
+ explicitContinuation = decision?.action === "continue";
160
186
  pendingMessages = (await config.getSteeringMessages?.()) || [];
187
+ if (hasMoreToolCalls || pendingMessages.length > 0) {
188
+ explicitContinuation = false;
189
+ }
161
190
  }
162
191
  // Agent would stop here. Check for follow-up messages.
163
192
  const followUpMessages = (await config.getFollowUpMessages?.()) || [];
164
193
  if (followUpMessages.length > 0) {
165
194
  // Set as pending so inner loop processes them
195
+ explicitContinuation = false;
166
196
  pendingMessages = followUpMessages;
167
197
  continue;
168
198
  }
199
+ // No natural request was selected, so fulfill the continuation decision with one context-only turn.
200
+ if (explicitContinuation) {
201
+ explicitContinuation = false;
202
+ continue;
203
+ }
169
204
  // No more messages, exit
170
205
  break;
171
206
  }
172
207
  await emit({ type: "agent_end", messages: newMessages });
173
208
  }
209
+ /**
210
+ * Declare tool loadout changes to the model.
211
+ *
212
+ * `context.tools` is what the runtime can execute; the transcript's system messages declare
213
+ * what the model may call. Before each request the difference becomes `toolsAdded` and
214
+ * `toolsRemoved` on a system message. When a pending system message exists, its tool fields
215
+ * are treated as intent and replaced with the delta between the committed transcript and
216
+ * the executable set, so replay always yields exactly `context.tools`. Otherwise a new
217
+ * system message is inserted before the first non-system pending message.
218
+ */
219
+ function declareToolChanges(context, pendingMessages) {
220
+ let systemIndex = -1;
221
+ for (let i = pendingMessages.length - 1; i >= 0; i--) {
222
+ if (pendingMessages[i].role === "system") {
223
+ systemIndex = i;
224
+ break;
225
+ }
226
+ }
227
+ const pending = pendingMessages[systemIndex];
228
+ const baseline = pending
229
+ ? pendingMessages.map((message, index) => index === systemIndex ? withToolChanges(pending, NO_CHANGES) : message)
230
+ : pendingMessages;
231
+ const changes = getToolStateChanges(getCurrentTools([...context.messages, ...baseline]), (context.tools ?? []).map(toToolDeclaration));
232
+ const unchanged = changes.toolsAdded.length === 0 && changes.toolsRemoved.length === 0;
233
+ if (pending) {
234
+ // Keep the caller's message object when it already declares no tool changes.
235
+ if (unchanged && !pending.toolsAdded?.length && !pending.toolsRemoved?.length)
236
+ return pendingMessages;
237
+ return baseline.map((message, index) => (index === systemIndex ? withToolChanges(pending, changes) : message));
238
+ }
239
+ if (unchanged)
240
+ return pendingMessages;
241
+ const update = withToolChanges({ role: "system", content: "", timestamp: Date.now() }, changes);
242
+ const insertIndex = pendingMessages.findIndex((message) => message.role !== "system");
243
+ const index = insertIndex === -1 ? pendingMessages.length : insertIndex;
244
+ return [...pendingMessages.slice(0, index), update, ...pendingMessages.slice(index)];
245
+ }
246
+ const NO_CHANGES = { toolsAdded: [], toolsRemoved: [] };
247
+ /** Copy a system message with its tool fields replaced by `changes`; empty lists omit the field. */
248
+ function withToolChanges(message, { toolsAdded, toolsRemoved }) {
249
+ const { toolsAdded: _added, toolsRemoved: _removed, ...rest } = message;
250
+ return {
251
+ ...rest,
252
+ ...(toolsAdded.length > 0 ? { toolsAdded } : {}),
253
+ ...(toolsRemoved.length > 0 ? { toolsRemoved } : {}),
254
+ };
255
+ }
174
256
  /**
175
257
  * Stream an assistant response from the LLM.
176
258
  * This is where AgentMessage[] gets transformed to Message[] for the LLM.
@@ -183,12 +265,7 @@ async function streamAssistantResponse(context, config, signal, emit, streamFunc
183
265
  }
184
266
  // Convert to LLM-compatible messages (AgentMessage[] → Message[])
185
267
  const llmMessages = await config.convertToLlm(messages);
186
- // Build LLM context
187
- const llmContext = {
188
- systemPrompt: context.systemPrompt,
189
- messages: llmMessages,
190
- tools: context.tools,
191
- };
268
+ const llmContext = normalizeContext({ messages: llmMessages });
192
269
  // Resolve API key (important for expiring tokens)
193
270
  const resolvedApiKey = (config.getApiKey ? await config.getApiKey(config.model.provider) : undefined) || config.apiKey;
194
271
  const response = await streamFunction(config.model, llmContext, {
@@ -196,6 +273,8 @@ async function streamAssistantResponse(context, config, signal, emit, streamFunc
196
273
  apiKey: resolvedApiKey,
197
274
  signal,
198
275
  });
276
+ // Record the requested level, whichever stream function answered.
277
+ const result = async () => Object.assign(await response.result(), { thinkingLevel: config.reasoning ?? "off" });
199
278
  let partialMessage = null;
200
279
  let addedPartial = false;
201
280
  for await (const event of response) {
@@ -227,7 +306,7 @@ async function streamAssistantResponse(context, config, signal, emit, streamFunc
227
306
  break;
228
307
  case "done":
229
308
  case "error": {
230
- const finalMessage = await response.result();
309
+ const finalMessage = await result();
231
310
  if (addedPartial) {
232
311
  context.messages[context.messages.length - 1] = finalMessage;
233
312
  }
@@ -242,7 +321,7 @@ async function streamAssistantResponse(context, config, signal, emit, streamFunc
242
321
  }
243
322
  }
244
323
  }
245
- const finalMessage = await response.result();
324
+ const finalMessage = await result();
246
325
  if (addedPartial) {
247
326
  context.messages[context.messages.length - 1] = finalMessage;
248
327
  }
@@ -312,7 +391,7 @@ async function executeToolCallsSequential(currentContext, assistantMessage, tool
312
391
  };
313
392
  }
314
393
  else {
315
- const executed = await executePreparedToolCall(preparation, signal, emit);
394
+ const executed = await executePreparedToolCall(preparation, signal, emitToolExecutionUpdate(toolCall, emit));
316
395
  finalized = await finalizeExecutedToolCall(currentContext, assistantMessage, preparation, executed, config, signal);
317
396
  }
318
397
  await emitToolExecutionEnd(finalized, emit);
@@ -353,7 +432,16 @@ async function executeToolCallsParallel(currentContext, assistantMessage, toolCa
353
432
  continue;
354
433
  }
355
434
  finalizedCalls.push(async () => {
356
- const executed = await executePreparedToolCall(preparation, signal, emit);
435
+ if (signal?.aborted) {
436
+ const finalized = {
437
+ toolCall,
438
+ result: createErrorToolResult("Operation aborted"),
439
+ isError: true,
440
+ };
441
+ await emitToolExecutionEnd(finalized, emit);
442
+ return finalized;
443
+ }
444
+ const executed = await executePreparedToolCall(preparation, signal, emitToolExecutionUpdate(toolCall, emit));
357
445
  const finalized = await finalizeExecutedToolCall(currentContext, assistantMessage, preparation, executed, config, signal);
358
446
  await emitToolExecutionEnd(finalized, emit);
359
447
  return finalized;
@@ -390,8 +478,8 @@ function prepareToolCallArguments(tool, toolCall) {
390
478
  arguments: preparedArguments,
391
479
  };
392
480
  }
393
- async function prepareToolCall(currentContext, assistantMessage, toolCall, config, signal) {
394
- const tool = currentContext.tools?.find((t) => t.name === toolCall.name);
481
+ async function prepareToolCall(currentContext, assistantMessage, toolCall, config, signal, tools = currentContext.tools ?? []) {
482
+ const tool = tools.find((t) => t.name === toolCall.name);
395
483
  if (!tool) {
396
484
  return {
397
485
  kind: "immediate",
@@ -417,9 +505,13 @@ async function prepareToolCall(currentContext, assistantMessage, toolCall, confi
417
505
  };
418
506
  }
419
507
  if (beforeResult?.block) {
508
+ const result = createErrorToolResult(beforeResult.reason || "Tool execution was blocked");
509
+ if (beforeResult.terminate === true) {
510
+ result.terminate = true;
511
+ }
420
512
  return {
421
513
  kind: "immediate",
422
- result: createErrorToolResult(beforeResult.reason || "Tool execution was blocked"),
514
+ result,
423
515
  isError: true,
424
516
  };
425
517
  }
@@ -446,24 +538,45 @@ async function prepareToolCall(currentContext, assistantMessage, toolCall, confi
446
538
  };
447
539
  }
448
540
  }
449
- async function executePreparedToolCall(prepared, signal, emit) {
541
+ function emitToolExecutionUpdate(toolCall, emit) {
542
+ return (partialResult) => emit({
543
+ type: "tool_execution_update",
544
+ toolCallId: toolCall.id,
545
+ toolName: toolCall.name,
546
+ args: toolCall.arguments,
547
+ partialResult,
548
+ });
549
+ }
550
+ /**
551
+ * Run one tool call through the same steps as a model-issued call: argument preparation, schema
552
+ * validation, `beforeToolCall`, execution, and `afterToolCall`. Emits no events and adds no
553
+ * messages. Tools that call other tools use this so the hooks (for example permission checks)
554
+ * apply to those calls too.
555
+ *
556
+ * Never rejects for tool failures: unknown tools, validation errors, blocked calls, and thrown
557
+ * errors come back as `isError: true`.
558
+ */
559
+ export async function runToolCall(toolCall, options) {
560
+ const { assistantMessage, context, signal } = options;
561
+ const preparation = await prepareToolCall(context, assistantMessage, toolCall, options, signal, options.tools);
562
+ if (preparation.kind === "immediate") {
563
+ return { toolCall, result: preparation.result, isError: preparation.isError };
564
+ }
565
+ const executed = await executePreparedToolCall(preparation, signal, options.onUpdate ?? (() => { }));
566
+ return finalizeExecutedToolCall(context, assistantMessage, preparation, executed, options, signal);
567
+ }
568
+ async function executePreparedToolCall(prepared, signal, onUpdate) {
450
569
  const updateEvents = [];
451
570
  let acceptingUpdates = true;
452
571
  try {
453
572
  const result = await prepared.tool.execute(prepared.toolCall.id, prepared.args, signal, (partialResult) => {
454
573
  if (!acceptingUpdates)
455
574
  return;
456
- updateEvents.push(Promise.resolve(emit({
457
- type: "tool_execution_update",
458
- toolCallId: prepared.toolCall.id,
459
- toolName: prepared.toolCall.name,
460
- args: prepared.toolCall.arguments,
461
- partialResult,
462
- })));
575
+ updateEvents.push(Promise.resolve(onUpdate(partialResult)));
463
576
  });
464
577
  acceptingUpdates = false;
465
578
  await Promise.all(updateEvents);
466
- return { result, isError: false };
579
+ return { result, isError: result.isError === true };
467
580
  }
468
581
  catch (error) {
469
582
  acceptingUpdates = false;
@@ -491,6 +604,8 @@ async function finalizeExecutedToolCall(currentContext, assistantMessage, prepar
491
604
  context: currentContext,
492
605
  }, signal);
493
606
  if (afterResult) {
607
+ // Structured content not replaced along with the content may no longer match it.
608
+ const structuredContent = afterResult.structuredContent ?? (afterResult.content ? undefined : result.structuredContent);
494
609
  result = {
495
610
  ...result,
496
611
  content: afterResult.content ?? result.content,
@@ -498,6 +613,10 @@ async function finalizeExecutedToolCall(currentContext, assistantMessage, prepar
498
613
  usage: afterResult.usage ?? result.usage,
499
614
  terminate: afterResult.terminate ?? result.terminate,
500
615
  };
616
+ if (structuredContent === undefined)
617
+ delete result.structuredContent;
618
+ else
619
+ result.structuredContent = structuredContent;
501
620
  isError = afterResult.isError ?? isError;
502
621
  }
503
622
  }
@@ -537,7 +656,6 @@ function createToolResultMessage(finalized) {
537
656
  content: finalized.result.content ?? [],
538
657
  details: finalized.result.details,
539
658
  usage: finalized.result.usage,
540
- ...(finalized.result.addedToolNames?.length ? { addedToolNames: finalized.result.addedToolNames } : {}),
541
659
  isError: finalized.isError,
542
660
  timestamp: Date.now(),
543
661
  };