@namzu/sdk 2.0.0 → 3.1.0

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 (1526) hide show
  1. package/CHANGELOG.md +2311 -0
  2. package/README.md +49 -53
  3. package/dist/__tests__/default-path-conformance.test.d.ts +2 -0
  4. package/dist/__tests__/default-path-conformance.test.d.ts.map +1 -0
  5. package/dist/__tests__/default-path-conformance.test.js +262 -0
  6. package/dist/__tests__/default-path-conformance.test.js.map +1 -0
  7. package/dist/__tests__/shipped-defaults.test.d.ts +2 -0
  8. package/dist/__tests__/shipped-defaults.test.d.ts.map +1 -0
  9. package/dist/__tests__/shipped-defaults.test.js +97 -0
  10. package/dist/__tests__/shipped-defaults.test.js.map +1 -0
  11. package/dist/advisory/__tests__/budget-enforcement.test.d.ts +2 -0
  12. package/dist/advisory/__tests__/budget-enforcement.test.d.ts.map +1 -0
  13. package/dist/advisory/__tests__/budget-enforcement.test.js +159 -0
  14. package/dist/advisory/__tests__/budget-enforcement.test.js.map +1 -0
  15. package/dist/advisory/__tests__/structured-response.test.d.ts +2 -0
  16. package/dist/advisory/__tests__/structured-response.test.d.ts.map +1 -0
  17. package/dist/advisory/__tests__/structured-response.test.js +99 -0
  18. package/dist/advisory/__tests__/structured-response.test.js.map +1 -0
  19. package/dist/advisory/budget.d.ts +15 -0
  20. package/dist/advisory/budget.d.ts.map +1 -0
  21. package/dist/advisory/budget.js +21 -0
  22. package/dist/advisory/budget.js.map +1 -0
  23. package/dist/advisory/context.d.ts +2 -0
  24. package/dist/advisory/context.d.ts.map +1 -1
  25. package/dist/advisory/context.js +16 -0
  26. package/dist/advisory/context.js.map +1 -1
  27. package/dist/advisory/executor.d.ts +14 -11
  28. package/dist/advisory/executor.d.ts.map +1 -1
  29. package/dist/advisory/executor.js +36 -24
  30. package/dist/advisory/executor.js.map +1 -1
  31. package/dist/advisory/executor.test.d.ts +8 -6
  32. package/dist/advisory/executor.test.d.ts.map +1 -1
  33. package/dist/advisory/executor.test.js +12 -8
  34. package/dist/advisory/executor.test.js.map +1 -1
  35. package/dist/advisory/index.d.ts +2 -0
  36. package/dist/advisory/index.d.ts.map +1 -1
  37. package/dist/advisory/index.js +2 -0
  38. package/dist/advisory/index.js.map +1 -1
  39. package/dist/advisory/parse.d.ts +23 -0
  40. package/dist/advisory/parse.d.ts.map +1 -0
  41. package/dist/advisory/parse.js +56 -0
  42. package/dist/advisory/parse.js.map +1 -0
  43. package/dist/agents/AbstractAgent.d.ts +48 -0
  44. package/dist/agents/AbstractAgent.d.ts.map +1 -1
  45. package/dist/agents/AbstractAgent.js +77 -0
  46. package/dist/agents/AbstractAgent.js.map +1 -1
  47. package/dist/agents/PipelineAgent.d.ts +10 -0
  48. package/dist/agents/PipelineAgent.d.ts.map +1 -1
  49. package/dist/agents/PipelineAgent.js +12 -0
  50. package/dist/agents/PipelineAgent.js.map +1 -1
  51. package/dist/agents/ReactiveAgent.d.ts +10 -0
  52. package/dist/agents/ReactiveAgent.d.ts.map +1 -1
  53. package/dist/agents/ReactiveAgent.js +40 -0
  54. package/dist/agents/ReactiveAgent.js.map +1 -1
  55. package/dist/agents/RouterAgent.d.ts +10 -0
  56. package/dist/agents/RouterAgent.d.ts.map +1 -1
  57. package/dist/agents/RouterAgent.js +23 -2
  58. package/dist/agents/RouterAgent.js.map +1 -1
  59. package/dist/agents/SupervisorAgent.d.ts +11 -1
  60. package/dist/agents/SupervisorAgent.d.ts.map +1 -1
  61. package/dist/agents/SupervisorAgent.js +23 -1
  62. package/dist/agents/SupervisorAgent.js.map +1 -1
  63. package/dist/agents/__tests__/idempotency-key.test.d.ts +2 -0
  64. package/dist/agents/__tests__/idempotency-key.test.d.ts.map +1 -0
  65. package/dist/agents/__tests__/idempotency-key.test.js +149 -0
  66. package/dist/agents/__tests__/idempotency-key.test.js.map +1 -0
  67. package/dist/agents/__tests__/invocation-lock.test.d.ts +2 -0
  68. package/dist/agents/__tests__/invocation-lock.test.d.ts.map +1 -0
  69. package/dist/agents/__tests__/invocation-lock.test.js +126 -0
  70. package/dist/agents/__tests__/invocation-lock.test.js.map +1 -0
  71. package/dist/agents/__tests__/reachability.test.d.ts +2 -0
  72. package/dist/agents/__tests__/reachability.test.d.ts.map +1 -0
  73. package/dist/agents/__tests__/reachability.test.js +173 -0
  74. package/dist/agents/__tests__/reachability.test.js.map +1 -0
  75. package/dist/agents/__tests__/supervisor-ledger.test.js +1 -1
  76. package/dist/agents/__tests__/supervisor-ledger.test.js.map +1 -1
  77. package/dist/agents/index.d.ts +1 -1
  78. package/dist/agents/index.d.ts.map +1 -1
  79. package/dist/agents/lock.d.ts +0 -1
  80. package/dist/agents/lock.d.ts.map +1 -1
  81. package/dist/agents/lock.js.map +1 -1
  82. package/dist/bridge/a2a/late-events.test.d.ts +2 -0
  83. package/dist/bridge/a2a/late-events.test.d.ts.map +1 -0
  84. package/dist/bridge/a2a/late-events.test.js +70 -0
  85. package/dist/bridge/a2a/late-events.test.js.map +1 -0
  86. package/dist/bridge/a2a/mapper.d.ts.map +1 -1
  87. package/dist/bridge/a2a/mapper.js +55 -3
  88. package/dist/bridge/a2a/mapper.js.map +1 -1
  89. package/dist/bridge/a2a/mapper.test.js +1 -1
  90. package/dist/bridge/a2a/mapper.test.js.map +1 -1
  91. package/dist/bridge/a2a/message.d.ts.map +1 -1
  92. package/dist/bridge/a2a/message.js +5 -1
  93. package/dist/bridge/a2a/message.js.map +1 -1
  94. package/dist/bridge/sse/late-events.test.d.ts +2 -0
  95. package/dist/bridge/sse/late-events.test.d.ts.map +1 -0
  96. package/dist/bridge/sse/late-events.test.js +163 -0
  97. package/dist/bridge/sse/late-events.test.js.map +1 -0
  98. package/dist/bridge/sse/mapper.d.ts.map +1 -1
  99. package/dist/bridge/sse/mapper.js +100 -0
  100. package/dist/bridge/sse/mapper.js.map +1 -1
  101. package/dist/compaction/__tests__/cleared-result-recovery.test.d.ts +2 -0
  102. package/dist/compaction/__tests__/cleared-result-recovery.test.d.ts.map +1 -0
  103. package/dist/compaction/__tests__/cleared-result-recovery.test.js +101 -0
  104. package/dist/compaction/__tests__/cleared-result-recovery.test.js.map +1 -0
  105. package/dist/compaction/__tests__/context-window.test.d.ts +2 -0
  106. package/dist/compaction/__tests__/context-window.test.d.ts.map +1 -0
  107. package/dist/compaction/__tests__/context-window.test.js +62 -0
  108. package/dist/compaction/__tests__/context-window.test.js.map +1 -0
  109. package/dist/compaction/__tests__/dangling.test.js +16 -5
  110. package/dist/compaction/__tests__/dangling.test.js.map +1 -1
  111. package/dist/compaction/__tests__/lossiness.test.d.ts +2 -0
  112. package/dist/compaction/__tests__/lossiness.test.d.ts.map +1 -0
  113. package/dist/compaction/__tests__/lossiness.test.js +163 -0
  114. package/dist/compaction/__tests__/lossiness.test.js.map +1 -0
  115. package/dist/compaction/__tests__/state-across-resume.test.d.ts +2 -0
  116. package/dist/compaction/__tests__/state-across-resume.test.d.ts.map +1 -0
  117. package/dist/compaction/__tests__/state-across-resume.test.js +88 -0
  118. package/dist/compaction/__tests__/state-across-resume.test.js.map +1 -0
  119. package/dist/compaction/__tests__/tool-result-editing.test.d.ts +2 -0
  120. package/dist/compaction/__tests__/tool-result-editing.test.d.ts.map +1 -0
  121. package/dist/compaction/__tests__/tool-result-editing.test.js +184 -0
  122. package/dist/compaction/__tests__/tool-result-editing.test.js.map +1 -0
  123. package/dist/compaction/__tests__/trim-opens-on-user.test.d.ts +2 -0
  124. package/dist/compaction/__tests__/trim-opens-on-user.test.d.ts.map +1 -0
  125. package/dist/compaction/__tests__/trim-opens-on-user.test.js +109 -0
  126. package/dist/compaction/__tests__/trim-opens-on-user.test.js.map +1 -0
  127. package/dist/compaction/__tests__/verifier-model.test.d.ts +2 -0
  128. package/dist/compaction/__tests__/verifier-model.test.d.ts.map +1 -0
  129. package/dist/compaction/__tests__/verifier-model.test.js +58 -0
  130. package/dist/compaction/__tests__/verifier-model.test.js.map +1 -0
  131. package/dist/compaction/context-window.d.ts +44 -0
  132. package/dist/compaction/context-window.d.ts.map +1 -0
  133. package/dist/compaction/context-window.js +97 -0
  134. package/dist/compaction/context-window.js.map +1 -0
  135. package/dist/compaction/dangling.js +48 -1
  136. package/dist/compaction/dangling.js.map +1 -1
  137. package/dist/compaction/extractor.d.ts.map +1 -1
  138. package/dist/compaction/extractor.js +55 -1
  139. package/dist/compaction/extractor.js.map +1 -1
  140. package/dist/compaction/index.d.ts +5 -0
  141. package/dist/compaction/index.d.ts.map +1 -1
  142. package/dist/compaction/index.js +3 -0
  143. package/dist/compaction/index.js.map +1 -1
  144. package/dist/compaction/manager.d.ts +25 -0
  145. package/dist/compaction/manager.d.ts.map +1 -1
  146. package/dist/compaction/manager.js +42 -8
  147. package/dist/compaction/manager.js.map +1 -1
  148. package/dist/compaction/managers/structured.d.ts.map +1 -1
  149. package/dist/compaction/managers/structured.js +7 -3
  150. package/dist/compaction/managers/structured.js.map +1 -1
  151. package/dist/compaction/retention.d.ts +15 -0
  152. package/dist/compaction/retention.d.ts.map +1 -0
  153. package/dist/compaction/retention.js +89 -0
  154. package/dist/compaction/retention.js.map +1 -0
  155. package/dist/compaction/serializer.d.ts.map +1 -1
  156. package/dist/compaction/serializer.js +28 -11
  157. package/dist/compaction/serializer.js.map +1 -1
  158. package/dist/compaction/tool-result-editing.d.ts +54 -0
  159. package/dist/compaction/tool-result-editing.d.ts.map +1 -0
  160. package/dist/compaction/tool-result-editing.js +164 -0
  161. package/dist/compaction/tool-result-editing.js.map +1 -0
  162. package/dist/compaction/types.d.ts +10 -0
  163. package/dist/compaction/types.d.ts.map +1 -1
  164. package/dist/compaction/verifier.d.ts +20 -1
  165. package/dist/compaction/verifier.d.ts.map +1 -1
  166. package/dist/compaction/verifier.js +11 -2
  167. package/dist/compaction/verifier.js.map +1 -1
  168. package/dist/compaction/wire.d.ts +54 -0
  169. package/dist/compaction/wire.d.ts.map +1 -0
  170. package/dist/compaction/wire.js +45 -0
  171. package/dist/compaction/wire.js.map +1 -0
  172. package/dist/config/runtime.d.ts +161 -45
  173. package/dist/config/runtime.d.ts.map +1 -1
  174. package/dist/config/runtime.js +61 -19
  175. package/dist/config/runtime.js.map +1 -1
  176. package/dist/connector/builtins/http.d.ts.map +1 -1
  177. package/dist/connector/builtins/http.js +14 -1
  178. package/dist/connector/builtins/http.js.map +1 -1
  179. package/dist/connector/builtins/http.test.js +12 -0
  180. package/dist/connector/builtins/http.test.js.map +1 -1
  181. package/dist/connector/mcp/__tests__/discovery-policy.test.d.ts +2 -0
  182. package/dist/connector/mcp/__tests__/discovery-policy.test.d.ts.map +1 -0
  183. package/dist/connector/mcp/__tests__/discovery-policy.test.js +109 -0
  184. package/dist/connector/mcp/__tests__/discovery-policy.test.js.map +1 -0
  185. package/dist/connector/mcp/__tests__/list-pagination.test.d.ts +2 -0
  186. package/dist/connector/mcp/__tests__/list-pagination.test.d.ts.map +1 -0
  187. package/dist/connector/mcp/__tests__/list-pagination.test.js +81 -0
  188. package/dist/connector/mcp/__tests__/list-pagination.test.js.map +1 -0
  189. package/dist/connector/mcp/__tests__/policy.test.d.ts +2 -0
  190. package/dist/connector/mcp/__tests__/policy.test.d.ts.map +1 -0
  191. package/dist/connector/mcp/__tests__/policy.test.js +86 -0
  192. package/dist/connector/mcp/__tests__/policy.test.js.map +1 -0
  193. package/dist/connector/mcp/__tests__/protocol-negotiation.test.d.ts +2 -0
  194. package/dist/connector/mcp/__tests__/protocol-negotiation.test.d.ts.map +1 -0
  195. package/dist/connector/mcp/__tests__/protocol-negotiation.test.js +81 -0
  196. package/dist/connector/mcp/__tests__/protocol-negotiation.test.js.map +1 -0
  197. package/dist/connector/mcp/__tests__/schema-fidelity.test.d.ts +2 -0
  198. package/dist/connector/mcp/__tests__/schema-fidelity.test.d.ts.map +1 -0
  199. package/dist/connector/mcp/__tests__/schema-fidelity.test.js +206 -0
  200. package/dist/connector/mcp/__tests__/schema-fidelity.test.js.map +1 -0
  201. package/dist/connector/mcp/__tests__/structured-result.test.d.ts +2 -0
  202. package/dist/connector/mcp/__tests__/structured-result.test.d.ts.map +1 -0
  203. package/dist/connector/mcp/__tests__/structured-result.test.js +112 -0
  204. package/dist/connector/mcp/__tests__/structured-result.test.js.map +1 -0
  205. package/dist/connector/mcp/adapter.d.ts +14 -0
  206. package/dist/connector/mcp/adapter.d.ts.map +1 -1
  207. package/dist/connector/mcp/adapter.js +292 -18
  208. package/dist/connector/mcp/adapter.js.map +1 -1
  209. package/dist/connector/mcp/client.d.ts +38 -0
  210. package/dist/connector/mcp/client.d.ts.map +1 -1
  211. package/dist/connector/mcp/client.js +138 -12
  212. package/dist/connector/mcp/client.js.map +1 -1
  213. package/dist/connector/mcp/client.test.d.ts +2 -0
  214. package/dist/connector/mcp/client.test.d.ts.map +1 -0
  215. package/dist/connector/mcp/client.test.js +105 -0
  216. package/dist/connector/mcp/client.test.js.map +1 -0
  217. package/dist/connector/mcp/discovery.d.ts +32 -1
  218. package/dist/connector/mcp/discovery.d.ts.map +1 -1
  219. package/dist/connector/mcp/discovery.js +41 -4
  220. package/dist/connector/mcp/discovery.js.map +1 -1
  221. package/dist/connector/mcp/http-sse.d.ts.map +1 -1
  222. package/dist/connector/mcp/http-sse.js +15 -1
  223. package/dist/connector/mcp/http-sse.js.map +1 -1
  224. package/dist/connector/mcp/index.d.ts +3 -0
  225. package/dist/connector/mcp/index.d.ts.map +1 -1
  226. package/dist/connector/mcp/index.js +1 -0
  227. package/dist/connector/mcp/index.js.map +1 -1
  228. package/dist/connector/mcp/policy.d.ts +57 -0
  229. package/dist/connector/mcp/policy.d.ts.map +1 -0
  230. package/dist/connector/mcp/policy.js +84 -0
  231. package/dist/connector/mcp/policy.js.map +1 -0
  232. package/dist/connector/mcp/schema-refs.d.ts +26 -0
  233. package/dist/connector/mcp/schema-refs.d.ts.map +1 -0
  234. package/dist/connector/mcp/schema-refs.js +111 -0
  235. package/dist/connector/mcp/schema-refs.js.map +1 -0
  236. package/dist/constants/agent/index.d.ts.map +1 -1
  237. package/dist/constants/agent/index.js +3 -0
  238. package/dist/constants/agent/index.js.map +1 -1
  239. package/dist/constants/compaction/index.js +1 -1
  240. package/dist/constants/compaction/index.js.map +1 -1
  241. package/dist/constants/continuation.d.ts +4 -4
  242. package/dist/constants/continuation.js +4 -4
  243. package/dist/constants/mcp/index.d.ts +31 -0
  244. package/dist/constants/mcp/index.d.ts.map +1 -1
  245. package/dist/constants/mcp/index.js +31 -0
  246. package/dist/constants/mcp/index.js.map +1 -1
  247. package/dist/constants/plugin/index.d.ts +23 -2
  248. package/dist/constants/plugin/index.d.ts.map +1 -1
  249. package/dist/constants/plugin/index.js +23 -2
  250. package/dist/constants/plugin/index.js.map +1 -1
  251. package/dist/constants/sandbox/index.d.ts +2 -3
  252. package/dist/constants/sandbox/index.d.ts.map +1 -1
  253. package/dist/constants/sandbox/index.js +6 -5
  254. package/dist/constants/sandbox/index.js.map +1 -1
  255. package/dist/constants/telemetry/index.d.ts +7 -0
  256. package/dist/constants/telemetry/index.d.ts.map +1 -1
  257. package/dist/constants/telemetry/index.js +7 -0
  258. package/dist/constants/telemetry/index.js.map +1 -1
  259. package/dist/constants/tools/index.d.ts +16 -0
  260. package/dist/constants/tools/index.d.ts.map +1 -1
  261. package/dist/constants/tools/index.js +16 -0
  262. package/dist/constants/tools/index.js.map +1 -1
  263. package/dist/contracts/a2a.d.ts +94 -94
  264. package/dist/contracts/api.d.ts +40 -2
  265. package/dist/contracts/api.d.ts.map +1 -1
  266. package/dist/contracts/run-status.d.ts +17 -0
  267. package/dist/contracts/run-status.d.ts.map +1 -0
  268. package/dist/contracts/run-status.js +41 -0
  269. package/dist/contracts/run-status.js.map +1 -0
  270. package/dist/contracts/schemas.d.ts +6 -6
  271. package/dist/eval/__tests__/case-deadline.test.d.ts +2 -0
  272. package/dist/eval/__tests__/case-deadline.test.d.ts.map +1 -0
  273. package/dist/eval/__tests__/case-deadline.test.js +128 -0
  274. package/dist/eval/__tests__/case-deadline.test.js.map +1 -0
  275. package/dist/eval/__tests__/end-to-end.test.d.ts +2 -0
  276. package/dist/eval/__tests__/end-to-end.test.d.ts.map +1 -0
  277. package/dist/eval/__tests__/end-to-end.test.js +223 -0
  278. package/dist/eval/__tests__/end-to-end.test.js.map +1 -0
  279. package/dist/eval/__tests__/harness-honesty.test.d.ts +2 -0
  280. package/dist/eval/__tests__/harness-honesty.test.d.ts.map +1 -0
  281. package/dist/eval/__tests__/harness-honesty.test.js +85 -0
  282. package/dist/eval/__tests__/harness-honesty.test.js.map +1 -0
  283. package/dist/eval/__tests__/harness.test.d.ts +2 -0
  284. package/dist/eval/__tests__/harness.test.d.ts.map +1 -0
  285. package/dist/eval/__tests__/harness.test.js +207 -0
  286. package/dist/eval/__tests__/harness.test.js.map +1 -0
  287. package/dist/eval/__tests__/judge.test.d.ts +2 -0
  288. package/dist/eval/__tests__/judge.test.d.ts.map +1 -0
  289. package/dist/eval/__tests__/judge.test.js +255 -0
  290. package/dist/eval/__tests__/judge.test.js.map +1 -0
  291. package/dist/eval/__tests__/scorer-gates.test.d.ts +2 -0
  292. package/dist/eval/__tests__/scorer-gates.test.d.ts.map +1 -0
  293. package/dist/eval/__tests__/scorer-gates.test.js +136 -0
  294. package/dist/eval/__tests__/scorer-gates.test.js.map +1 -0
  295. package/dist/eval/experiment.d.ts +54 -0
  296. package/dist/eval/experiment.d.ts.map +1 -0
  297. package/dist/eval/experiment.js +263 -0
  298. package/dist/eval/experiment.js.map +1 -0
  299. package/dist/eval/from-run.d.ts +30 -0
  300. package/dist/eval/from-run.d.ts.map +1 -0
  301. package/dist/eval/from-run.js +46 -0
  302. package/dist/eval/from-run.js.map +1 -0
  303. package/dist/eval/index.d.ts +8 -0
  304. package/dist/eval/index.d.ts.map +1 -0
  305. package/dist/eval/index.js +5 -0
  306. package/dist/eval/index.js.map +1 -0
  307. package/dist/eval/judge.d.ts +63 -0
  308. package/dist/eval/judge.d.ts.map +1 -0
  309. package/dist/eval/judge.js +136 -0
  310. package/dist/eval/judge.js.map +1 -0
  311. package/dist/eval/scorers.d.ts +40 -0
  312. package/dist/eval/scorers.d.ts.map +1 -0
  313. package/dist/eval/scorers.js +151 -0
  314. package/dist/eval/scorers.js.map +1 -0
  315. package/dist/eval/types.d.ts +150 -0
  316. package/dist/eval/types.d.ts.map +1 -0
  317. package/dist/eval/types.js +2 -0
  318. package/dist/eval/types.js.map +1 -0
  319. package/dist/execution/local.d.ts.map +1 -1
  320. package/dist/execution/local.js +6 -1
  321. package/dist/execution/local.js.map +1 -1
  322. package/dist/execution/local.test.d.ts +2 -0
  323. package/dist/execution/local.test.d.ts.map +1 -0
  324. package/dist/execution/local.test.js +37 -0
  325. package/dist/execution/local.test.js.map +1 -0
  326. package/dist/gateway/__tests__/list-survives-eviction.test.d.ts +2 -0
  327. package/dist/gateway/__tests__/list-survives-eviction.test.d.ts.map +1 -0
  328. package/dist/gateway/__tests__/list-survives-eviction.test.js +102 -0
  329. package/dist/gateway/__tests__/list-survives-eviction.test.js.map +1 -0
  330. package/dist/gateway/local.d.ts +42 -2
  331. package/dist/gateway/local.d.ts.map +1 -1
  332. package/dist/gateway/local.js +110 -3
  333. package/dist/gateway/local.js.map +1 -1
  334. package/dist/manager/agent/__tests__/dispose-cancels.test.d.ts +2 -0
  335. package/dist/manager/agent/__tests__/dispose-cancels.test.d.ts.map +1 -0
  336. package/dist/manager/agent/__tests__/dispose-cancels.test.js +88 -0
  337. package/dist/manager/agent/__tests__/dispose-cancels.test.js.map +1 -0
  338. package/dist/manager/agent/__tests__/lifecycle.test.js +230 -0
  339. package/dist/manager/agent/__tests__/lifecycle.test.js.map +1 -1
  340. package/dist/manager/agent/lifecycle.d.ts +35 -0
  341. package/dist/manager/agent/lifecycle.d.ts.map +1 -1
  342. package/dist/manager/agent/lifecycle.js +117 -7
  343. package/dist/manager/agent/lifecycle.js.map +1 -1
  344. package/dist/manager/run/persistence.d.ts +90 -1
  345. package/dist/manager/run/persistence.d.ts.map +1 -1
  346. package/dist/manager/run/persistence.js +120 -0
  347. package/dist/manager/run/persistence.js.map +1 -1
  348. package/dist/plugin/__tests__/enable-contributions.test.js +3 -3
  349. package/dist/plugin/__tests__/enable-contributions.test.js.map +1 -1
  350. package/dist/plugin/__tests__/hook-ordering.test.d.ts +2 -0
  351. package/dist/plugin/__tests__/hook-ordering.test.d.ts.map +1 -0
  352. package/dist/plugin/__tests__/hook-ordering.test.js +227 -0
  353. package/dist/plugin/__tests__/hook-ordering.test.js.map +1 -0
  354. package/dist/plugin/__tests__/install-time-refusal.test.d.ts +2 -0
  355. package/dist/plugin/__tests__/install-time-refusal.test.d.ts.map +1 -0
  356. package/dist/plugin/__tests__/install-time-refusal.test.js +49 -0
  357. package/dist/plugin/__tests__/install-time-refusal.test.js.map +1 -0
  358. package/dist/plugin/__tests__/lifecycle.test.js +95 -68
  359. package/dist/plugin/__tests__/lifecycle.test.js.map +1 -1
  360. package/dist/plugin/lifecycle.d.ts +15 -1
  361. package/dist/plugin/lifecycle.d.ts.map +1 -1
  362. package/dist/plugin/lifecycle.js +67 -20
  363. package/dist/plugin/lifecycle.js.map +1 -1
  364. package/dist/plugin/loader.d.ts +15 -0
  365. package/dist/plugin/loader.d.ts.map +1 -1
  366. package/dist/plugin/loader.js +33 -1
  367. package/dist/plugin/loader.js.map +1 -1
  368. package/dist/probe/registry.d.ts.map +1 -1
  369. package/dist/probe/registry.js +19 -1
  370. package/dist/probe/registry.js.map +1 -1
  371. package/dist/probe/registry.test.d.ts +9 -3
  372. package/dist/probe/registry.test.d.ts.map +1 -1
  373. package/dist/probe/registry.test.js +44 -6
  374. package/dist/probe/registry.test.js.map +1 -1
  375. package/dist/provider/__tests__/mock-script.test.d.ts +2 -0
  376. package/dist/provider/__tests__/mock-script.test.d.ts.map +1 -0
  377. package/dist/provider/__tests__/mock-script.test.js +151 -0
  378. package/dist/provider/__tests__/mock-script.test.js.map +1 -0
  379. package/dist/provider/__tests__/retry-visibility.test.d.ts +2 -0
  380. package/dist/provider/__tests__/retry-visibility.test.d.ts.map +1 -0
  381. package/dist/provider/__tests__/retry-visibility.test.js +137 -0
  382. package/dist/provider/__tests__/retry-visibility.test.js.map +1 -0
  383. package/dist/provider/__tests__/retry.test.d.ts +2 -0
  384. package/dist/provider/__tests__/retry.test.d.ts.map +1 -0
  385. package/dist/provider/__tests__/retry.test.js +259 -0
  386. package/dist/provider/__tests__/retry.test.js.map +1 -0
  387. package/dist/provider/capabilities.d.ts +1 -0
  388. package/dist/provider/capabilities.d.ts.map +1 -1
  389. package/dist/provider/capabilities.js +2 -0
  390. package/dist/provider/capabilities.js.map +1 -1
  391. package/dist/provider/collect.d.ts +1 -1
  392. package/dist/provider/collect.js +1 -1
  393. package/dist/provider/collect.test.d.ts +1 -1
  394. package/dist/provider/collect.test.js +1 -1
  395. package/dist/provider/index.d.ts +3 -0
  396. package/dist/provider/index.d.ts.map +1 -1
  397. package/dist/provider/index.js +2 -0
  398. package/dist/provider/index.js.map +1 -1
  399. package/dist/provider/mock-register.d.ts.map +1 -1
  400. package/dist/provider/mock-register.js +5 -2
  401. package/dist/provider/mock-register.js.map +1 -1
  402. package/dist/provider/mock.d.ts +35 -5
  403. package/dist/provider/mock.d.ts.map +1 -1
  404. package/dist/provider/mock.js +104 -32
  405. package/dist/provider/mock.js.map +1 -1
  406. package/dist/provider/retry.d.ts +42 -0
  407. package/dist/provider/retry.d.ts.map +1 -0
  408. package/dist/provider/retry.js +161 -0
  409. package/dist/provider/retry.js.map +1 -0
  410. package/dist/public-runtime.d.ts +26 -7
  411. package/dist/public-runtime.d.ts.map +1 -1
  412. package/dist/public-runtime.js +55 -7
  413. package/dist/public-runtime.js.map +1 -1
  414. package/dist/public-types.d.ts +5 -1
  415. package/dist/public-types.d.ts.map +1 -1
  416. package/dist/rag/__tests__/retrieval-math.test.d.ts +2 -0
  417. package/dist/rag/__tests__/retrieval-math.test.d.ts.map +1 -0
  418. package/dist/rag/__tests__/retrieval-math.test.js +46 -0
  419. package/dist/rag/__tests__/retrieval-math.test.js.map +1 -0
  420. package/dist/rag/chunking.d.ts +12 -0
  421. package/dist/rag/chunking.d.ts.map +1 -1
  422. package/dist/rag/chunking.js +32 -1
  423. package/dist/rag/chunking.js.map +1 -1
  424. package/dist/rag/embedding.d.ts +4 -4
  425. package/dist/rag/embedding.d.ts.map +1 -1
  426. package/dist/rag/embedding.js +23 -3
  427. package/dist/rag/embedding.js.map +1 -1
  428. package/dist/rag/embedding.test.d.ts +1 -1
  429. package/dist/rag/embedding.test.js +59 -10
  430. package/dist/rag/embedding.test.js.map +1 -1
  431. package/dist/rag/index.d.ts +1 -1
  432. package/dist/rag/index.d.ts.map +1 -1
  433. package/dist/rag/index.js +1 -1
  434. package/dist/rag/index.js.map +1 -1
  435. package/dist/rag/retriever.d.ts +0 -1
  436. package/dist/rag/retriever.d.ts.map +1 -1
  437. package/dist/rag/retriever.js +75 -22
  438. package/dist/rag/retriever.js.map +1 -1
  439. package/dist/rag/vector-store.test.d.ts +1 -1
  440. package/dist/rag/vector-store.test.js +2 -2
  441. package/dist/rag/vector-store.test.js.map +1 -1
  442. package/dist/registry/ManagedRegistry.test.d.ts +1 -1
  443. package/dist/registry/ManagedRegistry.test.js +1 -1
  444. package/dist/registry/Registry.test.d.ts +1 -1
  445. package/dist/registry/Registry.test.js +1 -1
  446. package/dist/registry/connector/definitions.test.d.ts +1 -1
  447. package/dist/registry/connector/definitions.test.js +1 -1
  448. package/dist/registry/tool/__tests__/schema.test.d.ts +2 -0
  449. package/dist/registry/tool/__tests__/schema.test.d.ts.map +1 -0
  450. package/dist/registry/tool/__tests__/schema.test.js +176 -0
  451. package/dist/registry/tool/__tests__/schema.test.js.map +1 -0
  452. package/dist/registry/tool/__tests__/tool-name-validation.test.d.ts +2 -0
  453. package/dist/registry/tool/__tests__/tool-name-validation.test.d.ts.map +1 -0
  454. package/dist/registry/tool/__tests__/tool-name-validation.test.js +70 -0
  455. package/dist/registry/tool/__tests__/tool-name-validation.test.js.map +1 -0
  456. package/dist/registry/tool/execute.d.ts +37 -0
  457. package/dist/registry/tool/execute.d.ts.map +1 -1
  458. package/dist/registry/tool/execute.js +91 -21
  459. package/dist/registry/tool/execute.js.map +1 -1
  460. package/dist/registry/tool/schema.d.ts +26 -0
  461. package/dist/registry/tool/schema.d.ts.map +1 -0
  462. package/dist/registry/tool/schema.js +77 -0
  463. package/dist/registry/tool/schema.js.map +1 -0
  464. package/dist/registry/toolset/catalog.d.ts.map +1 -1
  465. package/dist/registry/toolset/catalog.js +0 -1
  466. package/dist/registry/toolset/catalog.js.map +1 -1
  467. package/dist/registry/toolset/catalog.test.js +0 -1
  468. package/dist/registry/toolset/catalog.test.js.map +1 -1
  469. package/dist/run/reporter.d.ts.map +1 -1
  470. package/dist/run/reporter.js +76 -0
  471. package/dist/run/reporter.js.map +1 -1
  472. package/dist/runtime/bidi/__tests__/session.test.d.ts +2 -0
  473. package/dist/runtime/bidi/__tests__/session.test.d.ts.map +1 -0
  474. package/dist/runtime/bidi/__tests__/session.test.js +201 -0
  475. package/dist/runtime/bidi/__tests__/session.test.js.map +1 -0
  476. package/dist/runtime/bidi/index.d.ts +5 -0
  477. package/dist/runtime/bidi/index.d.ts.map +1 -0
  478. package/dist/runtime/bidi/index.js +3 -0
  479. package/dist/runtime/bidi/index.js.map +1 -0
  480. package/dist/runtime/bidi/mock.d.ts +34 -0
  481. package/dist/runtime/bidi/mock.d.ts.map +1 -0
  482. package/dist/runtime/bidi/mock.js +60 -0
  483. package/dist/runtime/bidi/mock.js.map +1 -0
  484. package/dist/runtime/bidi/session.d.ts +44 -0
  485. package/dist/runtime/bidi/session.d.ts.map +1 -0
  486. package/dist/runtime/bidi/session.js +154 -0
  487. package/dist/runtime/bidi/session.js.map +1 -0
  488. package/dist/runtime/decision/parser.d.ts.map +1 -1
  489. package/dist/runtime/decision/parser.js +8 -1
  490. package/dist/runtime/decision/parser.js.map +1 -1
  491. package/dist/runtime/decision/parser.test.d.ts +2 -0
  492. package/dist/runtime/decision/parser.test.d.ts.map +1 -0
  493. package/dist/runtime/decision/parser.test.js +37 -0
  494. package/dist/runtime/decision/parser.test.js.map +1 -0
  495. package/dist/runtime/query/__tests__/answer-review.test.d.ts +2 -0
  496. package/dist/runtime/query/__tests__/answer-review.test.d.ts.map +1 -0
  497. package/dist/runtime/query/__tests__/answer-review.test.js +141 -0
  498. package/dist/runtime/query/__tests__/answer-review.test.js.map +1 -0
  499. package/dist/runtime/query/__tests__/capability-negotiation.test.js +77 -105
  500. package/dist/runtime/query/__tests__/capability-negotiation.test.js.map +1 -1
  501. package/dist/runtime/query/__tests__/checkpoint-store.test.js +12 -44
  502. package/dist/runtime/query/__tests__/checkpoint-store.test.js.map +1 -1
  503. package/dist/runtime/query/__tests__/checkpoint.test.js +2 -10
  504. package/dist/runtime/query/__tests__/checkpoint.test.js.map +1 -1
  505. package/dist/runtime/query/__tests__/citations.test.d.ts +2 -0
  506. package/dist/runtime/query/__tests__/citations.test.d.ts.map +1 -0
  507. package/dist/runtime/query/__tests__/citations.test.js +85 -0
  508. package/dist/runtime/query/__tests__/citations.test.js.map +1 -0
  509. package/dist/runtime/query/__tests__/content-budget.test.d.ts +2 -0
  510. package/dist/runtime/query/__tests__/content-budget.test.d.ts.map +1 -0
  511. package/dist/runtime/query/__tests__/content-budget.test.js +69 -0
  512. package/dist/runtime/query/__tests__/content-budget.test.js.map +1 -0
  513. package/dist/runtime/query/__tests__/context.test.js +3 -2
  514. package/dist/runtime/query/__tests__/context.test.js.map +1 -1
  515. package/dist/runtime/query/__tests__/deferred-tools.test.js +21 -130
  516. package/dist/runtime/query/__tests__/deferred-tools.test.js.map +1 -1
  517. package/dist/runtime/query/__tests__/delegation-resume.test.d.ts +2 -0
  518. package/dist/runtime/query/__tests__/delegation-resume.test.d.ts.map +1 -0
  519. package/dist/runtime/query/__tests__/delegation-resume.test.js +111 -0
  520. package/dist/runtime/query/__tests__/delegation-resume.test.js.map +1 -0
  521. package/dist/runtime/query/__tests__/document-attachments.test.d.ts +2 -0
  522. package/dist/runtime/query/__tests__/document-attachments.test.d.ts.map +1 -0
  523. package/dist/runtime/query/__tests__/document-attachments.test.js +92 -0
  524. package/dist/runtime/query/__tests__/document-attachments.test.js.map +1 -0
  525. package/dist/runtime/query/__tests__/durable-park-and-trace.test.d.ts +2 -0
  526. package/dist/runtime/query/__tests__/durable-park-and-trace.test.d.ts.map +1 -0
  527. package/dist/runtime/query/__tests__/durable-park-and-trace.test.js +194 -0
  528. package/dist/runtime/query/__tests__/durable-park-and-trace.test.js.map +1 -0
  529. package/dist/runtime/query/__tests__/durable-question-park.test.d.ts +2 -0
  530. package/dist/runtime/query/__tests__/durable-question-park.test.d.ts.map +1 -0
  531. package/dist/runtime/query/__tests__/durable-question-park.test.js +253 -0
  532. package/dist/runtime/query/__tests__/durable-question-park.test.js.map +1 -0
  533. package/dist/runtime/query/__tests__/durable-run-state.test.d.ts +2 -0
  534. package/dist/runtime/query/__tests__/durable-run-state.test.d.ts.map +1 -0
  535. package/dist/runtime/query/__tests__/durable-run-state.test.js +158 -0
  536. package/dist/runtime/query/__tests__/durable-run-state.test.js.map +1 -0
  537. package/dist/runtime/query/__tests__/executor-plugin-hooks.test.js +24 -20
  538. package/dist/runtime/query/__tests__/executor-plugin-hooks.test.js.map +1 -1
  539. package/dist/runtime/query/__tests__/finish-reason-vs-tool-calls.test.d.ts +2 -0
  540. package/dist/runtime/query/__tests__/finish-reason-vs-tool-calls.test.d.ts.map +1 -0
  541. package/dist/runtime/query/__tests__/finish-reason-vs-tool-calls.test.js +187 -0
  542. package/dist/runtime/query/__tests__/finish-reason-vs-tool-calls.test.js.map +1 -0
  543. package/dist/runtime/query/__tests__/grant-cannot-overrule-the-gate.test.d.ts +2 -0
  544. package/dist/runtime/query/__tests__/grant-cannot-overrule-the-gate.test.d.ts.map +1 -0
  545. package/dist/runtime/query/__tests__/grant-cannot-overrule-the-gate.test.js +95 -0
  546. package/dist/runtime/query/__tests__/grant-cannot-overrule-the-gate.test.js.map +1 -0
  547. package/dist/runtime/query/__tests__/guardrails-e2e.test.d.ts +2 -0
  548. package/dist/runtime/query/__tests__/guardrails-e2e.test.d.ts.map +1 -0
  549. package/dist/runtime/query/__tests__/guardrails-e2e.test.js +132 -0
  550. package/dist/runtime/query/__tests__/guardrails-e2e.test.js.map +1 -0
  551. package/dist/runtime/query/__tests__/guardrails.test.d.ts +2 -0
  552. package/dist/runtime/query/__tests__/guardrails.test.d.ts.map +1 -0
  553. package/dist/runtime/query/__tests__/guardrails.test.js +163 -0
  554. package/dist/runtime/query/__tests__/guardrails.test.js.map +1 -0
  555. package/dist/runtime/query/__tests__/hook-model-visibility.test.d.ts +2 -0
  556. package/dist/runtime/query/__tests__/hook-model-visibility.test.d.ts.map +1 -0
  557. package/dist/runtime/query/__tests__/hook-model-visibility.test.js +119 -0
  558. package/dist/runtime/query/__tests__/hook-model-visibility.test.js.map +1 -0
  559. package/dist/runtime/query/__tests__/long-document-flow.test.js +9 -2
  560. package/dist/runtime/query/__tests__/long-document-flow.test.js.map +1 -1
  561. package/dist/runtime/query/__tests__/memory-promotion.test.d.ts +2 -0
  562. package/dist/runtime/query/__tests__/memory-promotion.test.d.ts.map +1 -0
  563. package/dist/runtime/query/__tests__/memory-promotion.test.js +119 -0
  564. package/dist/runtime/query/__tests__/memory-promotion.test.js.map +1 -0
  565. package/dist/runtime/query/__tests__/orphan-task-turn-end.test.js +5 -27
  566. package/dist/runtime/query/__tests__/orphan-task-turn-end.test.js.map +1 -1
  567. package/dist/runtime/query/__tests__/overflow-relief.test.d.ts +2 -0
  568. package/dist/runtime/query/__tests__/overflow-relief.test.d.ts.map +1 -0
  569. package/dist/runtime/query/__tests__/overflow-relief.test.js +119 -0
  570. package/dist/runtime/query/__tests__/overflow-relief.test.js.map +1 -0
  571. package/dist/runtime/query/__tests__/partial-batch-resume.test.d.ts +2 -0
  572. package/dist/runtime/query/__tests__/partial-batch-resume.test.d.ts.map +1 -0
  573. package/dist/runtime/query/__tests__/partial-batch-resume.test.js +205 -0
  574. package/dist/runtime/query/__tests__/partial-batch-resume.test.js.map +1 -0
  575. package/dist/runtime/query/__tests__/plugin-hooks.test.js +0 -1
  576. package/dist/runtime/query/__tests__/plugin-hooks.test.js.map +1 -1
  577. package/dist/runtime/query/__tests__/prepare-step-chain.test.d.ts +2 -0
  578. package/dist/runtime/query/__tests__/prepare-step-chain.test.d.ts.map +1 -0
  579. package/dist/runtime/query/__tests__/prepare-step-chain.test.js +104 -0
  580. package/dist/runtime/query/__tests__/prepare-step-chain.test.js.map +1 -0
  581. package/dist/runtime/query/__tests__/prepare-step.test.d.ts +2 -0
  582. package/dist/runtime/query/__tests__/prepare-step.test.d.ts.map +1 -0
  583. package/dist/runtime/query/__tests__/prepare-step.test.js +194 -0
  584. package/dist/runtime/query/__tests__/prepare-step.test.js.map +1 -0
  585. package/dist/runtime/query/__tests__/probe-veto-is-error.test.d.ts +2 -0
  586. package/dist/runtime/query/__tests__/probe-veto-is-error.test.d.ts.map +1 -0
  587. package/dist/runtime/query/__tests__/probe-veto-is-error.test.js +111 -0
  588. package/dist/runtime/query/__tests__/probe-veto-is-error.test.js.map +1 -0
  589. package/dist/runtime/query/__tests__/prompt.test.js +1 -1
  590. package/dist/runtime/query/__tests__/prompt.test.js.map +1 -1
  591. package/dist/runtime/query/__tests__/provider-fault-pauses.test.d.ts +2 -0
  592. package/dist/runtime/query/__tests__/provider-fault-pauses.test.d.ts.map +1 -0
  593. package/dist/runtime/query/__tests__/provider-fault-pauses.test.js +86 -0
  594. package/dist/runtime/query/__tests__/provider-fault-pauses.test.js.map +1 -0
  595. package/dist/runtime/query/__tests__/reasoning-stream.test.d.ts +2 -0
  596. package/dist/runtime/query/__tests__/reasoning-stream.test.d.ts.map +1 -0
  597. package/dist/runtime/query/__tests__/reasoning-stream.test.js +146 -0
  598. package/dist/runtime/query/__tests__/reasoning-stream.test.js.map +1 -0
  599. package/dist/runtime/query/__tests__/recoverable-settle.test.d.ts +2 -0
  600. package/dist/runtime/query/__tests__/recoverable-settle.test.d.ts.map +1 -0
  601. package/dist/runtime/query/__tests__/recoverable-settle.test.js +119 -0
  602. package/dist/runtime/query/__tests__/recoverable-settle.test.js.map +1 -0
  603. package/dist/runtime/query/__tests__/resume-budget.test.d.ts +2 -0
  604. package/dist/runtime/query/__tests__/resume-budget.test.d.ts.map +1 -0
  605. package/dist/runtime/query/__tests__/resume-budget.test.js +130 -0
  606. package/dist/runtime/query/__tests__/resume-budget.test.js.map +1 -0
  607. package/dist/runtime/query/__tests__/resume-pending.test.d.ts +2 -0
  608. package/dist/runtime/query/__tests__/resume-pending.test.d.ts.map +1 -0
  609. package/dist/runtime/query/__tests__/resume-pending.test.js +226 -0
  610. package/dist/runtime/query/__tests__/resume-pending.test.js.map +1 -0
  611. package/dist/runtime/query/__tests__/rich-content-budget-wiring.test.d.ts +2 -0
  612. package/dist/runtime/query/__tests__/rich-content-budget-wiring.test.d.ts.map +1 -0
  613. package/dist/runtime/query/__tests__/rich-content-budget-wiring.test.js +89 -0
  614. package/dist/runtime/query/__tests__/rich-content-budget-wiring.test.js.map +1 -0
  615. package/dist/runtime/query/__tests__/stop-condition.test.d.ts +2 -0
  616. package/dist/runtime/query/__tests__/stop-condition.test.d.ts.map +1 -0
  617. package/dist/runtime/query/__tests__/stop-condition.test.js +205 -0
  618. package/dist/runtime/query/__tests__/stop-condition.test.js.map +1 -0
  619. package/dist/runtime/query/__tests__/structured-output.test.d.ts +2 -0
  620. package/dist/runtime/query/__tests__/structured-output.test.d.ts.map +1 -0
  621. package/dist/runtime/query/__tests__/structured-output.test.js +219 -0
  622. package/dist/runtime/query/__tests__/structured-output.test.js.map +1 -0
  623. package/dist/runtime/query/__tests__/structured-run-failure.test.d.ts +2 -0
  624. package/dist/runtime/query/__tests__/structured-run-failure.test.d.ts.map +1 -0
  625. package/dist/runtime/query/__tests__/structured-run-failure.test.js +117 -0
  626. package/dist/runtime/query/__tests__/structured-run-failure.test.js.map +1 -0
  627. package/dist/runtime/query/__tests__/terminal-tool.test.d.ts +2 -0
  628. package/dist/runtime/query/__tests__/terminal-tool.test.d.ts.map +1 -0
  629. package/dist/runtime/query/__tests__/terminal-tool.test.js +119 -0
  630. package/dist/runtime/query/__tests__/terminal-tool.test.js.map +1 -0
  631. package/dist/runtime/query/__tests__/tool-grants.test.d.ts +2 -0
  632. package/dist/runtime/query/__tests__/tool-grants.test.d.ts.map +1 -0
  633. package/dist/runtime/query/__tests__/tool-grants.test.js +85 -0
  634. package/dist/runtime/query/__tests__/tool-grants.test.js.map +1 -0
  635. package/dist/runtime/query/__tests__/tool-output-budget.test.d.ts +2 -0
  636. package/dist/runtime/query/__tests__/tool-output-budget.test.d.ts.map +1 -0
  637. package/dist/runtime/query/__tests__/tool-output-budget.test.js +0 -0
  638. package/dist/runtime/query/__tests__/tool-output-budget.test.js.map +1 -0
  639. package/dist/runtime/query/__tests__/tool-pause.test.d.ts +2 -0
  640. package/dist/runtime/query/__tests__/tool-pause.test.d.ts.map +1 -0
  641. package/dist/runtime/query/__tests__/tool-pause.test.js +165 -0
  642. package/dist/runtime/query/__tests__/tool-pause.test.js.map +1 -0
  643. package/dist/runtime/query/__tests__/tool-progress.test.d.ts +2 -0
  644. package/dist/runtime/query/__tests__/tool-progress.test.d.ts.map +1 -0
  645. package/dist/runtime/query/__tests__/tool-progress.test.js +122 -0
  646. package/dist/runtime/query/__tests__/tool-progress.test.js.map +1 -0
  647. package/dist/runtime/query/__tests__/tool-repair-retry.test.d.ts +2 -0
  648. package/dist/runtime/query/__tests__/tool-repair-retry.test.d.ts.map +1 -0
  649. package/dist/runtime/query/__tests__/tool-repair-retry.test.js +196 -0
  650. package/dist/runtime/query/__tests__/tool-repair-retry.test.js.map +1 -0
  651. package/dist/runtime/query/__tests__/tool-result-wire.test.d.ts +2 -0
  652. package/dist/runtime/query/__tests__/tool-result-wire.test.d.ts.map +1 -0
  653. package/dist/runtime/query/__tests__/tool-result-wire.test.js +106 -0
  654. package/dist/runtime/query/__tests__/tool-result-wire.test.js.map +1 -0
  655. package/dist/runtime/query/__tests__/tool-timeout.test.d.ts +2 -0
  656. package/dist/runtime/query/__tests__/tool-timeout.test.d.ts.map +1 -0
  657. package/dist/runtime/query/__tests__/tool-timeout.test.js +184 -0
  658. package/dist/runtime/query/__tests__/tool-timeout.test.js.map +1 -0
  659. package/dist/runtime/query/__tests__/trace-parenting.test.d.ts +2 -0
  660. package/dist/runtime/query/__tests__/trace-parenting.test.d.ts.map +1 -0
  661. package/dist/runtime/query/__tests__/trace-parenting.test.js +111 -0
  662. package/dist/runtime/query/__tests__/trace-parenting.test.js.map +1 -0
  663. package/dist/runtime/query/__tests__/wiring-seams.test.d.ts +2 -0
  664. package/dist/runtime/query/__tests__/wiring-seams.test.d.ts.map +1 -0
  665. package/dist/runtime/query/__tests__/wiring-seams.test.js +237 -0
  666. package/dist/runtime/query/__tests__/wiring-seams.test.js.map +1 -0
  667. package/dist/runtime/query/checkpoint.d.ts +124 -6
  668. package/dist/runtime/query/checkpoint.d.ts.map +1 -1
  669. package/dist/runtime/query/checkpoint.js +207 -6
  670. package/dist/runtime/query/checkpoint.js.map +1 -1
  671. package/dist/runtime/query/events.js +2 -2
  672. package/dist/runtime/query/events.js.map +1 -1
  673. package/dist/runtime/query/executor.d.ts +225 -7
  674. package/dist/runtime/query/executor.d.ts.map +1 -1
  675. package/dist/runtime/query/executor.js +672 -36
  676. package/dist/runtime/query/executor.js.map +1 -1
  677. package/dist/runtime/query/guard.d.ts +18 -0
  678. package/dist/runtime/query/guard.d.ts.map +1 -1
  679. package/dist/runtime/query/guard.js +16 -1
  680. package/dist/runtime/query/guard.js.map +1 -1
  681. package/dist/runtime/query/guardrail-presets.d.ts +36 -0
  682. package/dist/runtime/query/guardrail-presets.d.ts.map +1 -0
  683. package/dist/runtime/query/guardrail-presets.js +96 -0
  684. package/dist/runtime/query/guardrail-presets.js.map +1 -0
  685. package/dist/runtime/query/guardrails.d.ts +35 -0
  686. package/dist/runtime/query/guardrails.d.ts.map +1 -0
  687. package/dist/runtime/query/guardrails.js +102 -0
  688. package/dist/runtime/query/guardrails.js.map +1 -0
  689. package/dist/runtime/query/index.d.ts +213 -2
  690. package/dist/runtime/query/index.d.ts.map +1 -1
  691. package/dist/runtime/query/index.js +458 -10
  692. package/dist/runtime/query/index.js.map +1 -1
  693. package/dist/runtime/query/iteration/__tests__/cancel-settles-turn.test.d.ts +2 -0
  694. package/dist/runtime/query/iteration/__tests__/cancel-settles-turn.test.d.ts.map +1 -0
  695. package/dist/runtime/query/iteration/__tests__/cancel-settles-turn.test.js +131 -0
  696. package/dist/runtime/query/iteration/__tests__/cancel-settles-turn.test.js.map +1 -0
  697. package/dist/runtime/query/iteration/index.d.ts +76 -1
  698. package/dist/runtime/query/iteration/index.d.ts.map +1 -1
  699. package/dist/runtime/query/iteration/index.js +594 -29
  700. package/dist/runtime/query/iteration/index.js.map +1 -1
  701. package/dist/runtime/query/iteration/phases/advisory.d.ts.map +1 -1
  702. package/dist/runtime/query/iteration/phases/advisory.js +14 -2
  703. package/dist/runtime/query/iteration/phases/advisory.js.map +1 -1
  704. package/dist/runtime/query/iteration/phases/advisory.test.d.ts +1 -1
  705. package/dist/runtime/query/iteration/phases/advisory.test.js +4 -1
  706. package/dist/runtime/query/iteration/phases/advisory.test.js.map +1 -1
  707. package/dist/runtime/query/iteration/phases/checkpoint.js +2 -2
  708. package/dist/runtime/query/iteration/phases/checkpoint.js.map +1 -1
  709. package/dist/runtime/query/iteration/phases/compaction-safe-cut.test.js +1 -1
  710. package/dist/runtime/query/iteration/phases/compaction-safe-cut.test.js.map +1 -1
  711. package/dist/runtime/query/iteration/phases/compaction.d.ts +22 -1
  712. package/dist/runtime/query/iteration/phases/compaction.d.ts.map +1 -1
  713. package/dist/runtime/query/iteration/phases/compaction.js +297 -64
  714. package/dist/runtime/query/iteration/phases/compaction.js.map +1 -1
  715. package/dist/runtime/query/iteration/phases/context-measurement.test.d.ts +21 -0
  716. package/dist/runtime/query/iteration/phases/context-measurement.test.d.ts.map +1 -0
  717. package/dist/runtime/query/iteration/phases/context-measurement.test.js +161 -0
  718. package/dist/runtime/query/iteration/phases/context-measurement.test.js.map +1 -0
  719. package/dist/runtime/query/iteration/phases/context.d.ts +62 -2
  720. package/dist/runtime/query/iteration/phases/context.d.ts.map +1 -1
  721. package/dist/runtime/query/iteration/phases/context.js +87 -0
  722. package/dist/runtime/query/iteration/phases/context.js.map +1 -1
  723. package/dist/runtime/query/iteration/phases/hitl-answer-question.test.js +3 -1
  724. package/dist/runtime/query/iteration/phases/hitl-answer-question.test.js.map +1 -1
  725. package/dist/runtime/query/iteration/phases/overflow-escalation.test.d.ts +15 -0
  726. package/dist/runtime/query/iteration/phases/overflow-escalation.test.d.ts.map +1 -0
  727. package/dist/runtime/query/iteration/phases/overflow-escalation.test.js +130 -0
  728. package/dist/runtime/query/iteration/phases/overflow-escalation.test.js.map +1 -0
  729. package/dist/runtime/query/iteration/phases/plan.d.ts.map +1 -1
  730. package/dist/runtime/query/iteration/phases/plan.js +8 -2
  731. package/dist/runtime/query/iteration/phases/plan.js.map +1 -1
  732. package/dist/runtime/query/iteration/phases/retained-messages.test.d.ts +2 -0
  733. package/dist/runtime/query/iteration/phases/retained-messages.test.d.ts.map +1 -0
  734. package/dist/runtime/query/iteration/phases/retained-messages.test.js +180 -0
  735. package/dist/runtime/query/iteration/phases/retained-messages.test.js.map +1 -0
  736. package/dist/runtime/query/iteration/phases/tool-review-denials.test.d.ts +2 -0
  737. package/dist/runtime/query/iteration/phases/tool-review-denials.test.d.ts.map +1 -0
  738. package/dist/runtime/query/iteration/phases/tool-review-denials.test.js +224 -0
  739. package/dist/runtime/query/iteration/phases/tool-review-denials.test.js.map +1 -0
  740. package/dist/runtime/query/iteration/phases/tool-review.d.ts +29 -1
  741. package/dist/runtime/query/iteration/phases/tool-review.d.ts.map +1 -1
  742. package/dist/runtime/query/iteration/phases/tool-review.js +114 -44
  743. package/dist/runtime/query/iteration/phases/tool-review.js.map +1 -1
  744. package/dist/runtime/query/iteration/phases/working-memory-compaction.test.js +20 -9
  745. package/dist/runtime/query/iteration/phases/working-memory-compaction.test.js.map +1 -1
  746. package/dist/runtime/query/iteration/stream-turn.d.ts +2 -26
  747. package/dist/runtime/query/iteration/stream-turn.d.ts.map +1 -1
  748. package/dist/runtime/query/iteration/stream-turn.js +254 -16
  749. package/dist/runtime/query/iteration/stream-turn.js.map +1 -1
  750. package/dist/runtime/query/plugin-hooks.d.ts.map +1 -1
  751. package/dist/runtime/query/plugin-hooks.js +6 -2
  752. package/dist/runtime/query/plugin-hooks.js.map +1 -1
  753. package/dist/runtime/query/prompt.d.ts.map +1 -1
  754. package/dist/runtime/query/prompt.js +25 -1
  755. package/dist/runtime/query/prompt.js.map +1 -1
  756. package/dist/runtime/query/question-park.d.ts +85 -0
  757. package/dist/runtime/query/question-park.d.ts.map +1 -0
  758. package/dist/runtime/query/question-park.js +71 -0
  759. package/dist/runtime/query/question-park.js.map +1 -0
  760. package/dist/runtime/query/result.d.ts +9 -0
  761. package/dist/runtime/query/result.d.ts.map +1 -1
  762. package/dist/runtime/query/result.js +49 -0
  763. package/dist/runtime/query/result.js.map +1 -1
  764. package/dist/runtime/query/resume-pending.d.ts +106 -0
  765. package/dist/runtime/query/resume-pending.d.ts.map +1 -0
  766. package/dist/runtime/query/resume-pending.js +312 -0
  767. package/dist/runtime/query/resume-pending.js.map +1 -0
  768. package/dist/runtime/query/run-state.d.ts +52 -0
  769. package/dist/runtime/query/run-state.d.ts.map +1 -0
  770. package/dist/runtime/query/run-state.js +87 -0
  771. package/dist/runtime/query/run-state.js.map +1 -0
  772. package/dist/runtime/query/tool-grants.d.ts +44 -0
  773. package/dist/runtime/query/tool-grants.d.ts.map +1 -0
  774. package/dist/runtime/query/tool-grants.js +63 -0
  775. package/dist/runtime/query/tool-grants.js.map +1 -0
  776. package/dist/runtime/query/tool-output-budget.d.ts +83 -0
  777. package/dist/runtime/query/tool-output-budget.d.ts.map +1 -0
  778. package/dist/runtime/query/tool-output-budget.js +147 -0
  779. package/dist/runtime/query/tool-output-budget.js.map +1 -0
  780. package/dist/runtime/query/tool-pause.d.ts +41 -0
  781. package/dist/runtime/query/tool-pause.d.ts.map +1 -0
  782. package/dist/runtime/query/tool-pause.js +94 -0
  783. package/dist/runtime/query/tool-pause.js.map +1 -0
  784. package/dist/runtime/query/tooling.d.ts +10 -1
  785. package/dist/runtime/query/tooling.d.ts.map +1 -1
  786. package/dist/runtime/query/tooling.js +13 -0
  787. package/dist/runtime/query/tooling.js.map +1 -1
  788. package/dist/sandbox/__tests__/isolation.test.d.ts +2 -0
  789. package/dist/sandbox/__tests__/isolation.test.d.ts.map +1 -0
  790. package/dist/sandbox/__tests__/isolation.test.js +139 -0
  791. package/dist/sandbox/__tests__/isolation.test.js.map +1 -0
  792. package/dist/sandbox/__tests__/output-truncation.test.d.ts +2 -0
  793. package/dist/sandbox/__tests__/output-truncation.test.d.ts.map +1 -0
  794. package/dist/sandbox/__tests__/output-truncation.test.js +88 -0
  795. package/dist/sandbox/__tests__/output-truncation.test.js.map +1 -0
  796. package/dist/sandbox/__tests__/resource-limits.test.d.ts +2 -0
  797. package/dist/sandbox/__tests__/resource-limits.test.d.ts.map +1 -0
  798. package/dist/sandbox/__tests__/resource-limits.test.js +86 -0
  799. package/dist/sandbox/__tests__/resource-limits.test.js.map +1 -0
  800. package/dist/sandbox/factory.js +1 -1
  801. package/dist/sandbox/factory.js.map +1 -1
  802. package/dist/sandbox/index.d.ts +2 -0
  803. package/dist/sandbox/index.d.ts.map +1 -1
  804. package/dist/sandbox/index.js +1 -0
  805. package/dist/sandbox/index.js.map +1 -1
  806. package/dist/sandbox/isolation.d.ts +15 -0
  807. package/dist/sandbox/isolation.d.ts.map +1 -0
  808. package/dist/sandbox/isolation.js +53 -0
  809. package/dist/sandbox/isolation.js.map +1 -0
  810. package/dist/sandbox/provider/local.d.ts +51 -2
  811. package/dist/sandbox/provider/local.d.ts.map +1 -1
  812. package/dist/sandbox/provider/local.js +139 -69
  813. package/dist/sandbox/provider/local.js.map +1 -1
  814. package/dist/session/__tests__/integration/spawn-rollback.test.d.ts +1 -1
  815. package/dist/session/__tests__/integration/spawn-rollback.test.js +1 -1
  816. package/dist/session/handoff/broadcast.js +3 -3
  817. package/dist/session/handoff/broadcast.js.map +1 -1
  818. package/dist/session/migration/__tests__/filesystem.test.js +5 -1
  819. package/dist/session/migration/__tests__/filesystem.test.js.map +1 -1
  820. package/dist/session/migration/filesystem.d.ts.map +1 -1
  821. package/dist/session/migration/filesystem.js +7 -13
  822. package/dist/session/migration/filesystem.js.map +1 -1
  823. package/dist/session/migration/marker.d.ts.map +1 -1
  824. package/dist/session/migration/marker.js +5 -10
  825. package/dist/session/migration/marker.js.map +1 -1
  826. package/dist/session/retention/disk-backend.d.ts.map +1 -1
  827. package/dist/session/retention/disk-backend.js +5 -12
  828. package/dist/session/retention/disk-backend.js.map +1 -1
  829. package/dist/session/workspace/__tests__/git-worktree.test.js +6 -2
  830. package/dist/session/workspace/__tests__/git-worktree.test.js.map +1 -1
  831. package/dist/session/workspace/__tests__/shared-run.test.js +15 -0
  832. package/dist/session/workspace/__tests__/shared-run.test.js.map +1 -1
  833. package/dist/session/workspace/shared-run.js +8 -1
  834. package/dist/session/workspace/shared-run.js.map +1 -1
  835. package/dist/skills/__tests__/frontmatter.test.d.ts +2 -0
  836. package/dist/skills/__tests__/frontmatter.test.d.ts.map +1 -0
  837. package/dist/skills/__tests__/frontmatter.test.js +106 -0
  838. package/dist/skills/__tests__/frontmatter.test.js.map +1 -0
  839. package/dist/skills/loader.d.ts.map +1 -1
  840. package/dist/skills/loader.js +42 -3
  841. package/dist/skills/loader.js.map +1 -1
  842. package/dist/store/__tests__/checkpoint-integrity.test.d.ts +2 -0
  843. package/dist/store/__tests__/checkpoint-integrity.test.d.ts.map +1 -0
  844. package/dist/store/__tests__/checkpoint-integrity.test.js +112 -0
  845. package/dist/store/__tests__/checkpoint-integrity.test.js.map +1 -0
  846. package/dist/store/__tests__/checkpoint-versioning.test.d.ts +2 -0
  847. package/dist/store/__tests__/checkpoint-versioning.test.d.ts.map +1 -0
  848. package/dist/store/__tests__/checkpoint-versioning.test.js +151 -0
  849. package/dist/store/__tests__/checkpoint-versioning.test.js.map +1 -0
  850. package/dist/store/__tests__/schema-adoption.test.d.ts +2 -0
  851. package/dist/store/__tests__/schema-adoption.test.d.ts.map +1 -0
  852. package/dist/store/__tests__/schema-adoption.test.js +90 -0
  853. package/dist/store/__tests__/schema-adoption.test.js.map +1 -0
  854. package/dist/store/__tests__/schema.test.d.ts +2 -0
  855. package/dist/store/__tests__/schema.test.d.ts.map +1 -0
  856. package/dist/store/__tests__/schema.test.js +93 -0
  857. package/dist/store/__tests__/schema.test.js.map +1 -0
  858. package/dist/store/memory/disk.d.ts.map +1 -1
  859. package/dist/store/memory/disk.js +16 -16
  860. package/dist/store/memory/disk.js.map +1 -1
  861. package/dist/store/run/disk.d.ts +23 -0
  862. package/dist/store/run/disk.d.ts.map +1 -1
  863. package/dist/store/run/disk.js +148 -23
  864. package/dist/store/run/disk.js.map +1 -1
  865. package/dist/store/schema.d.ts +73 -0
  866. package/dist/store/schema.d.ts.map +1 -0
  867. package/dist/store/schema.js +103 -0
  868. package/dist/store/schema.js.map +1 -0
  869. package/dist/store/session/disk.d.ts.map +1 -1
  870. package/dist/store/session/disk.js +25 -13
  871. package/dist/store/session/disk.js.map +1 -1
  872. package/dist/store/task/__tests__/lookup-across-runs.test.d.ts +2 -0
  873. package/dist/store/task/__tests__/lookup-across-runs.test.d.ts.map +1 -0
  874. package/dist/store/task/__tests__/lookup-across-runs.test.js +60 -0
  875. package/dist/store/task/__tests__/lookup-across-runs.test.js.map +1 -0
  876. package/dist/store/task/disk.d.ts +18 -0
  877. package/dist/store/task/disk.d.ts.map +1 -1
  878. package/dist/store/task/disk.js +61 -16
  879. package/dist/store/task/disk.js.map +1 -1
  880. package/dist/store/thread/disk.d.ts.map +1 -1
  881. package/dist/store/thread/disk.js +20 -11
  882. package/dist/store/thread/disk.js.map +1 -1
  883. package/dist/streaming/coalesce.d.ts +1 -1
  884. package/dist/streaming/coalesce.js +1 -1
  885. package/dist/telemetry/__tests__/latency-instruments.test.d.ts +2 -0
  886. package/dist/telemetry/__tests__/latency-instruments.test.d.ts.map +1 -0
  887. package/dist/telemetry/__tests__/latency-instruments.test.js +82 -0
  888. package/dist/telemetry/__tests__/latency-instruments.test.js.map +1 -0
  889. package/dist/telemetry/__tests__/metrics.test.d.ts +2 -0
  890. package/dist/telemetry/__tests__/metrics.test.d.ts.map +1 -0
  891. package/dist/telemetry/__tests__/metrics.test.js +112 -0
  892. package/dist/telemetry/__tests__/metrics.test.js.map +1 -0
  893. package/dist/telemetry/__tests__/span-hierarchy.test.d.ts +2 -0
  894. package/dist/telemetry/__tests__/span-hierarchy.test.d.ts.map +1 -0
  895. package/dist/telemetry/__tests__/span-hierarchy.test.js +84 -0
  896. package/dist/telemetry/__tests__/span-hierarchy.test.js.map +1 -0
  897. package/dist/telemetry/attributes.d.ts +44 -0
  898. package/dist/telemetry/attributes.d.ts.map +1 -1
  899. package/dist/telemetry/attributes.js +80 -0
  900. package/dist/telemetry/attributes.js.map +1 -1
  901. package/dist/telemetry/metrics.d.ts +41 -0
  902. package/dist/telemetry/metrics.d.ts.map +1 -0
  903. package/dist/telemetry/metrics.js +160 -0
  904. package/dist/telemetry/metrics.js.map +1 -0
  905. package/dist/test-setup.d.ts +3 -3
  906. package/dist/test-setup.js +3 -3
  907. package/dist/test-support/paths.d.ts +14 -0
  908. package/dist/test-support/paths.d.ts.map +1 -0
  909. package/dist/test-support/paths.js +16 -0
  910. package/dist/test-support/paths.js.map +1 -0
  911. package/dist/tools/__tests__/path-containment.test.d.ts +2 -0
  912. package/dist/tools/__tests__/path-containment.test.d.ts.map +1 -0
  913. package/dist/tools/__tests__/path-containment.test.js +133 -0
  914. package/dist/tools/__tests__/path-containment.test.js.map +1 -0
  915. package/dist/tools/__tests__/posix-path.test.d.ts +2 -0
  916. package/dist/tools/__tests__/posix-path.test.d.ts.map +1 -0
  917. package/dist/tools/__tests__/posix-path.test.js +67 -0
  918. package/dist/tools/__tests__/posix-path.test.js.map +1 -0
  919. package/dist/tools/__tests__/sandboxed-search.test.d.ts +2 -0
  920. package/dist/tools/__tests__/sandboxed-search.test.d.ts.map +1 -0
  921. package/dist/tools/__tests__/sandboxed-search.test.js +114 -0
  922. package/dist/tools/__tests__/sandboxed-search.test.js.map +1 -0
  923. package/dist/tools/builtins/__tests__/computer-use.test.js +12 -2
  924. package/dist/tools/builtins/__tests__/computer-use.test.js.map +1 -1
  925. package/dist/tools/builtins/__tests__/edit-commits-atomically.test.d.ts +2 -0
  926. package/dist/tools/builtins/__tests__/edit-commits-atomically.test.d.ts.map +1 -0
  927. package/dist/tools/builtins/__tests__/edit-commits-atomically.test.js +78 -0
  928. package/dist/tools/builtins/__tests__/edit-commits-atomically.test.js.map +1 -0
  929. package/dist/tools/builtins/__tests__/edit.test.js +52 -17
  930. package/dist/tools/builtins/__tests__/edit.test.js.map +1 -1
  931. package/dist/tools/builtins/__tests__/payload-budget.test.js +16 -30
  932. package/dist/tools/builtins/__tests__/payload-budget.test.js.map +1 -1
  933. package/dist/tools/builtins/__tests__/read-file.test.js +23 -1
  934. package/dist/tools/builtins/__tests__/read-file.test.js.map +1 -1
  935. package/dist/tools/builtins/__tests__/stale-file-refusal.test.d.ts +2 -0
  936. package/dist/tools/builtins/__tests__/stale-file-refusal.test.d.ts.map +1 -0
  937. package/dist/tools/builtins/__tests__/stale-file-refusal.test.js +187 -0
  938. package/dist/tools/builtins/__tests__/stale-file-refusal.test.js.map +1 -0
  939. package/dist/tools/builtins/__tests__/write-file.test.js +13 -37
  940. package/dist/tools/builtins/__tests__/write-file.test.js.map +1 -1
  941. package/dist/tools/builtins/atomic-write-file.d.ts +1 -1
  942. package/dist/tools/builtins/atomic-write-file.d.ts.map +1 -1
  943. package/dist/tools/builtins/atomic-write-file.js +31 -2
  944. package/dist/tools/builtins/atomic-write-file.js.map +1 -1
  945. package/dist/tools/builtins/bash.d.ts.map +1 -1
  946. package/dist/tools/builtins/bash.js +33 -4
  947. package/dist/tools/builtins/bash.js.map +1 -1
  948. package/dist/tools/builtins/computer-use.d.ts +22 -22
  949. package/dist/tools/builtins/computer-use.d.ts.map +1 -1
  950. package/dist/tools/builtins/computer-use.js +7 -1
  951. package/dist/tools/builtins/computer-use.js.map +1 -1
  952. package/dist/tools/builtins/content-fingerprint.d.ts +23 -0
  953. package/dist/tools/builtins/content-fingerprint.d.ts.map +1 -0
  954. package/dist/tools/builtins/content-fingerprint.js +30 -0
  955. package/dist/tools/builtins/content-fingerprint.js.map +1 -0
  956. package/dist/tools/builtins/edit.d.ts +5 -2
  957. package/dist/tools/builtins/edit.d.ts.map +1 -1
  958. package/dist/tools/builtins/edit.js +218 -57
  959. package/dist/tools/builtins/edit.js.map +1 -1
  960. package/dist/tools/builtins/glob.d.ts +1 -1
  961. package/dist/tools/builtins/glob.d.ts.map +1 -1
  962. package/dist/tools/builtins/glob.js +63 -6
  963. package/dist/tools/builtins/glob.js.map +1 -1
  964. package/dist/tools/builtins/grep.d.ts.map +1 -1
  965. package/dist/tools/builtins/grep.js +61 -8
  966. package/dist/tools/builtins/grep.js.map +1 -1
  967. package/dist/tools/builtins/index.js +6 -6
  968. package/dist/tools/builtins/index.js.map +1 -1
  969. package/dist/tools/builtins/ls.d.ts.map +1 -1
  970. package/dist/tools/builtins/ls.js +4 -2
  971. package/dist/tools/builtins/ls.js.map +1 -1
  972. package/dist/tools/builtins/read-file.d.ts +1 -1
  973. package/dist/tools/builtins/read-file.d.ts.map +1 -1
  974. package/dist/tools/builtins/read-file.js +43 -6
  975. package/dist/tools/builtins/read-file.js.map +1 -1
  976. package/dist/tools/builtins/write-file.d.ts +2 -1
  977. package/dist/tools/builtins/write-file.d.ts.map +1 -1
  978. package/dist/tools/builtins/write-file.js +47 -25
  979. package/dist/tools/builtins/write-file.js.map +1 -1
  980. package/dist/tools/coordinator/__tests__/agent.test.d.ts +1 -1
  981. package/dist/tools/coordinator/__tests__/agent.test.js +2 -2
  982. package/dist/tools/coordinator/__tests__/agent.test.js.map +1 -1
  983. package/dist/tools/coordinator/__tests__/ask-user-question.test.js +55 -0
  984. package/dist/tools/coordinator/__tests__/ask-user-question.test.js.map +1 -1
  985. package/dist/tools/coordinator/agent.d.ts +20 -9
  986. package/dist/tools/coordinator/agent.d.ts.map +1 -1
  987. package/dist/tools/coordinator/agent.js +2 -1
  988. package/dist/tools/coordinator/agent.js.map +1 -1
  989. package/dist/tools/coordinator/index.d.ts +20 -0
  990. package/dist/tools/coordinator/index.d.ts.map +1 -1
  991. package/dist/tools/coordinator/index.js +142 -36
  992. package/dist/tools/coordinator/index.js.map +1 -1
  993. package/dist/tools/defineTool.d.ts +16 -0
  994. package/dist/tools/defineTool.d.ts.map +1 -1
  995. package/dist/tools/defineTool.js +4 -0
  996. package/dist/tools/defineTool.js.map +1 -1
  997. package/dist/tools/glob-match.d.ts +18 -0
  998. package/dist/tools/glob-match.d.ts.map +1 -0
  999. package/dist/tools/glob-match.js +50 -0
  1000. package/dist/tools/glob-match.js.map +1 -0
  1001. package/dist/tools/paths.d.ts +20 -0
  1002. package/dist/tools/paths.d.ts.map +1 -0
  1003. package/dist/tools/paths.js +41 -0
  1004. package/dist/tools/paths.js.map +1 -0
  1005. package/dist/tools/posix-path.d.ts +24 -0
  1006. package/dist/tools/posix-path.d.ts.map +1 -0
  1007. package/dist/tools/posix-path.js +67 -0
  1008. package/dist/tools/posix-path.js.map +1 -0
  1009. package/dist/types/advisory/config.d.ts +21 -3
  1010. package/dist/types/advisory/config.d.ts.map +1 -1
  1011. package/dist/types/advisory/result.d.ts +12 -10
  1012. package/dist/types/advisory/result.d.ts.map +1 -1
  1013. package/dist/types/agent/base.d.ts +20 -2
  1014. package/dist/types/agent/base.d.ts.map +1 -1
  1015. package/dist/types/agent/factory.d.ts +15 -9
  1016. package/dist/types/agent/factory.d.ts.map +1 -1
  1017. package/dist/types/agent/gateway.d.ts +18 -0
  1018. package/dist/types/agent/gateway.d.ts.map +1 -1
  1019. package/dist/types/agent/manager.d.ts +19 -0
  1020. package/dist/types/agent/manager.d.ts.map +1 -1
  1021. package/dist/types/agent/reactive.d.ts +48 -0
  1022. package/dist/types/agent/reactive.d.ts.map +1 -1
  1023. package/dist/types/agent/router.d.ts +11 -0
  1024. package/dist/types/agent/router.d.ts.map +1 -1
  1025. package/dist/types/agent/supervisor.d.ts +2 -2
  1026. package/dist/types/agent/task.d.ts +24 -0
  1027. package/dist/types/agent/task.d.ts.map +1 -1
  1028. package/dist/types/bidi/index.d.ts +140 -0
  1029. package/dist/types/bidi/index.d.ts.map +1 -0
  1030. package/dist/types/bidi/index.js +2 -0
  1031. package/dist/types/bidi/index.js.map +1 -0
  1032. package/dist/types/common/__tests__/numeric-correctness.test.d.ts +2 -0
  1033. package/dist/types/common/__tests__/numeric-correctness.test.d.ts.map +1 -0
  1034. package/dist/types/common/__tests__/numeric-correctness.test.js +108 -0
  1035. package/dist/types/common/__tests__/numeric-correctness.test.js.map +1 -0
  1036. package/dist/types/common/index.d.ts +1 -1
  1037. package/dist/types/common/index.d.ts.map +1 -1
  1038. package/dist/types/common/index.js +15 -4
  1039. package/dist/types/common/index.js.map +1 -1
  1040. package/dist/types/connector/mcp.d.ts +29 -0
  1041. package/dist/types/connector/mcp.d.ts.map +1 -1
  1042. package/dist/types/errors/__tests__/catalog.test.d.ts +2 -0
  1043. package/dist/types/errors/__tests__/catalog.test.d.ts.map +1 -0
  1044. package/dist/types/errors/__tests__/catalog.test.js +106 -0
  1045. package/dist/types/errors/__tests__/catalog.test.js.map +1 -0
  1046. package/dist/types/errors/__tests__/errors.test.d.ts +2 -0
  1047. package/dist/types/errors/__tests__/errors.test.d.ts.map +1 -0
  1048. package/dist/types/errors/__tests__/errors.test.js +104 -0
  1049. package/dist/types/errors/__tests__/errors.test.js.map +1 -0
  1050. package/dist/types/errors/catalog.d.ts +83 -0
  1051. package/dist/types/errors/catalog.d.ts.map +1 -0
  1052. package/dist/types/errors/catalog.js +148 -0
  1053. package/dist/types/errors/catalog.js.map +1 -0
  1054. package/dist/types/errors/index.d.ts +73 -0
  1055. package/dist/types/errors/index.d.ts.map +1 -0
  1056. package/dist/types/errors/index.js +70 -0
  1057. package/dist/types/errors/index.js.map +1 -0
  1058. package/dist/types/guardrail/index.d.ts +57 -0
  1059. package/dist/types/guardrail/index.d.ts.map +1 -0
  1060. package/dist/types/guardrail/index.js +2 -0
  1061. package/dist/types/guardrail/index.js.map +1 -0
  1062. package/dist/types/hitl/index.d.ts +97 -14
  1063. package/dist/types/hitl/index.d.ts.map +1 -1
  1064. package/dist/types/hitl/index.js.map +1 -1
  1065. package/dist/types/ids/index.d.ts +2 -2
  1066. package/dist/types/message/content.d.ts +22 -0
  1067. package/dist/types/message/content.d.ts.map +1 -0
  1068. package/dist/types/message/content.js +49 -0
  1069. package/dist/types/message/content.js.map +1 -0
  1070. package/dist/types/message/index.d.ts +193 -8
  1071. package/dist/types/message/index.d.ts.map +1 -1
  1072. package/dist/types/message/index.js +19 -4
  1073. package/dist/types/message/index.js.map +1 -1
  1074. package/dist/types/plugin/index.d.ts +78 -3
  1075. package/dist/types/plugin/index.d.ts.map +1 -1
  1076. package/dist/types/plugin/index.js +0 -1
  1077. package/dist/types/plugin/index.js.map +1 -1
  1078. package/dist/types/provider/__tests__/cause-chain.test.d.ts +2 -0
  1079. package/dist/types/provider/__tests__/cause-chain.test.d.ts.map +1 -0
  1080. package/dist/types/provider/__tests__/cause-chain.test.js +108 -0
  1081. package/dist/types/provider/__tests__/cause-chain.test.js.map +1 -0
  1082. package/dist/types/provider/__tests__/declared-retryable.test.d.ts +2 -0
  1083. package/dist/types/provider/__tests__/declared-retryable.test.d.ts.map +1 -0
  1084. package/dist/types/provider/__tests__/declared-retryable.test.js +70 -0
  1085. package/dist/types/provider/__tests__/declared-retryable.test.js.map +1 -0
  1086. package/dist/types/provider/__tests__/overflow-classification.test.d.ts +2 -0
  1087. package/dist/types/provider/__tests__/overflow-classification.test.d.ts.map +1 -0
  1088. package/dist/types/provider/__tests__/overflow-classification.test.js +80 -0
  1089. package/dist/types/provider/__tests__/overflow-classification.test.js.map +1 -0
  1090. package/dist/types/provider/chat.d.ts +27 -1
  1091. package/dist/types/provider/chat.d.ts.map +1 -1
  1092. package/dist/types/provider/config.d.ts +83 -2
  1093. package/dist/types/provider/config.d.ts.map +1 -1
  1094. package/dist/types/provider/errors.d.ts +102 -0
  1095. package/dist/types/provider/errors.d.ts.map +1 -0
  1096. package/dist/types/provider/errors.js +393 -0
  1097. package/dist/types/provider/errors.js.map +1 -0
  1098. package/dist/types/provider/index.d.ts +3 -2
  1099. package/dist/types/provider/index.d.ts.map +1 -1
  1100. package/dist/types/provider/stream.d.ts +59 -3
  1101. package/dist/types/provider/stream.d.ts.map +1 -1
  1102. package/dist/types/rag/embedding.d.ts +11 -2
  1103. package/dist/types/rag/embedding.d.ts.map +1 -1
  1104. package/dist/types/run/__tests__/step.test.d.ts +2 -0
  1105. package/dist/types/run/__tests__/step.test.d.ts.map +1 -0
  1106. package/dist/types/run/__tests__/step.test.js +107 -0
  1107. package/dist/types/run/__tests__/step.test.js.map +1 -0
  1108. package/dist/types/run/answer-review.d.ts +46 -0
  1109. package/dist/types/run/answer-review.d.ts.map +1 -0
  1110. package/dist/types/run/answer-review.js +2 -0
  1111. package/dist/types/run/answer-review.js.map +1 -0
  1112. package/dist/types/run/config.d.ts +33 -0
  1113. package/dist/types/run/config.d.ts.map +1 -1
  1114. package/dist/types/run/derive-status.d.ts +29 -0
  1115. package/dist/types/run/derive-status.d.ts.map +1 -0
  1116. package/dist/types/run/derive-status.js +49 -0
  1117. package/dist/types/run/derive-status.js.map +1 -0
  1118. package/dist/types/run/entity.d.ts +16 -0
  1119. package/dist/types/run/entity.d.ts.map +1 -1
  1120. package/dist/types/run/events.d.ts +228 -4
  1121. package/dist/types/run/events.d.ts.map +1 -1
  1122. package/dist/types/run/events.js +7 -0
  1123. package/dist/types/run/events.js.map +1 -1
  1124. package/dist/types/run/index.d.ts +5 -0
  1125. package/dist/types/run/index.d.ts.map +1 -1
  1126. package/dist/types/run/index.js +3 -0
  1127. package/dist/types/run/index.js.map +1 -1
  1128. package/dist/types/run/memory-promotion.d.ts +90 -0
  1129. package/dist/types/run/memory-promotion.d.ts.map +1 -0
  1130. package/dist/types/run/memory-promotion.js +38 -0
  1131. package/dist/types/run/memory-promotion.js.map +1 -0
  1132. package/dist/types/run/prepare-step.d.ts +100 -0
  1133. package/dist/types/run/prepare-step.d.ts.map +1 -0
  1134. package/dist/types/run/prepare-step.js +2 -0
  1135. package/dist/types/run/prepare-step.js.map +1 -0
  1136. package/dist/types/run/state.d.ts +85 -0
  1137. package/dist/types/run/state.d.ts.map +1 -0
  1138. package/dist/types/run/state.js +33 -0
  1139. package/dist/types/run/state.js.map +1 -0
  1140. package/dist/types/run/step.d.ts +77 -0
  1141. package/dist/types/run/step.d.ts.map +1 -0
  1142. package/dist/types/run/step.js +26 -0
  1143. package/dist/types/run/step.js.map +1 -0
  1144. package/dist/types/run/stop-reason.d.ts +31 -3
  1145. package/dist/types/run/stop-reason.d.ts.map +1 -1
  1146. package/dist/types/sandbox/index.d.ts +82 -10
  1147. package/dist/types/sandbox/index.d.ts.map +1 -1
  1148. package/dist/types/sandbox/index.js +13 -1
  1149. package/dist/types/sandbox/index.js.map +1 -1
  1150. package/dist/types/structured-output/index.d.ts +6 -5
  1151. package/dist/types/structured-output/index.d.ts.map +1 -1
  1152. package/dist/types/thread/entity.d.ts +2 -3
  1153. package/dist/types/thread/entity.d.ts.map +1 -1
  1154. package/dist/types/tool/index.d.ts +210 -2
  1155. package/dist/types/tool/index.d.ts.map +1 -1
  1156. package/dist/types/tool/index.js +1 -1
  1157. package/dist/types/tool/index.js.map +1 -1
  1158. package/dist/types/tool/repair.d.ts +49 -0
  1159. package/dist/types/tool/repair.d.ts.map +1 -0
  1160. package/dist/types/tool/repair.js +2 -0
  1161. package/dist/types/tool/repair.js.map +1 -0
  1162. package/dist/types/toolset/index.d.ts +2 -5
  1163. package/dist/types/toolset/index.d.ts.map +1 -1
  1164. package/dist/utils/__tests__/atomic-write.test.d.ts +2 -0
  1165. package/dist/utils/__tests__/atomic-write.test.d.ts.map +1 -0
  1166. package/dist/utils/__tests__/atomic-write.test.js +91 -0
  1167. package/dist/utils/__tests__/atomic-write.test.js.map +1 -0
  1168. package/dist/utils/__tests__/shell-compress.test.d.ts +2 -0
  1169. package/dist/utils/__tests__/shell-compress.test.d.ts.map +1 -0
  1170. package/dist/utils/__tests__/shell-compress.test.js +41 -0
  1171. package/dist/utils/__tests__/shell-compress.test.js.map +1 -0
  1172. package/dist/utils/atomic-write.d.ts +10 -0
  1173. package/dist/utils/atomic-write.d.ts.map +1 -0
  1174. package/dist/utils/atomic-write.js +83 -0
  1175. package/dist/utils/atomic-write.js.map +1 -0
  1176. package/dist/utils/shell-compress.d.ts.map +1 -1
  1177. package/dist/utils/shell-compress.js +12 -1
  1178. package/dist/utils/shell-compress.js.map +1 -1
  1179. package/dist/verification/presets.d.ts +6 -3
  1180. package/dist/verification/presets.d.ts.map +1 -1
  1181. package/dist/verification/presets.js +6 -3
  1182. package/dist/verification/presets.js.map +1 -1
  1183. package/package.json +3 -3
  1184. package/src/__tests__/default-path-conformance.test.ts +306 -0
  1185. package/src/__tests__/shipped-defaults.test.ts +111 -0
  1186. package/src/advisory/__tests__/budget-enforcement.test.ts +208 -0
  1187. package/src/advisory/__tests__/structured-response.test.ts +128 -0
  1188. package/src/advisory/budget.ts +27 -0
  1189. package/src/advisory/context.ts +19 -0
  1190. package/src/advisory/executor.test.ts +12 -8
  1191. package/src/advisory/executor.ts +37 -25
  1192. package/src/advisory/index.ts +2 -0
  1193. package/src/advisory/parse.ts +63 -0
  1194. package/src/agents/AbstractAgent.ts +82 -0
  1195. package/src/agents/PipelineAgent.ts +19 -0
  1196. package/src/agents/ReactiveAgent.ts +47 -0
  1197. package/src/agents/RouterAgent.ts +32 -2
  1198. package/src/agents/SupervisorAgent.ts +31 -1
  1199. package/src/agents/__tests__/idempotency-key.test.ts +177 -0
  1200. package/src/agents/__tests__/invocation-lock.test.ts +154 -0
  1201. package/src/agents/__tests__/reachability.test.ts +224 -0
  1202. package/src/agents/__tests__/supervisor-ledger.test.ts +1 -1
  1203. package/src/agents/index.ts +1 -1
  1204. package/src/agents/lock.ts +0 -2
  1205. package/src/bridge/a2a/late-events.test.ts +84 -0
  1206. package/src/bridge/a2a/mapper.test.ts +1 -1
  1207. package/src/bridge/a2a/mapper.ts +70 -5
  1208. package/src/bridge/a2a/message.ts +5 -1
  1209. package/src/bridge/sse/late-events.test.ts +182 -0
  1210. package/src/bridge/sse/mapper.ts +109 -0
  1211. package/src/compaction/__tests__/cleared-result-recovery.test.ts +118 -0
  1212. package/src/compaction/__tests__/context-window.test.ts +77 -0
  1213. package/src/compaction/__tests__/dangling.test.ts +16 -6
  1214. package/src/compaction/__tests__/lossiness.test.ts +187 -0
  1215. package/src/compaction/__tests__/state-across-resume.test.ts +99 -0
  1216. package/src/compaction/__tests__/tool-result-editing.test.ts +213 -0
  1217. package/src/compaction/__tests__/trim-opens-on-user.test.ts +118 -0
  1218. package/src/compaction/__tests__/verifier-model.test.ts +83 -0
  1219. package/src/compaction/context-window.ts +107 -0
  1220. package/src/compaction/dangling.ts +48 -1
  1221. package/src/compaction/extractor.ts +56 -1
  1222. package/src/compaction/index.ts +16 -0
  1223. package/src/compaction/manager.ts +53 -8
  1224. package/src/compaction/managers/structured.ts +7 -6
  1225. package/src/compaction/retention.ts +89 -0
  1226. package/src/compaction/serializer.ts +42 -11
  1227. package/src/compaction/tool-result-editing.ts +229 -0
  1228. package/src/compaction/types.ts +10 -0
  1229. package/src/compaction/verifier.ts +24 -1
  1230. package/src/compaction/wire.ts +91 -0
  1231. package/src/config/runtime.ts +63 -19
  1232. package/src/connector/builtins/http.test.ts +13 -0
  1233. package/src/connector/builtins/http.ts +15 -1
  1234. package/src/connector/mcp/__tests__/discovery-policy.test.ts +133 -0
  1235. package/src/connector/mcp/__tests__/list-pagination.test.ts +98 -0
  1236. package/src/connector/mcp/__tests__/policy.test.ts +100 -0
  1237. package/src/connector/mcp/__tests__/protocol-negotiation.test.ts +105 -0
  1238. package/src/connector/mcp/__tests__/schema-fidelity.test.ts +250 -0
  1239. package/src/connector/mcp/__tests__/structured-result.test.ts +143 -0
  1240. package/src/connector/mcp/adapter.ts +306 -19
  1241. package/src/connector/mcp/client.test.ts +159 -0
  1242. package/src/connector/mcp/client.ts +160 -13
  1243. package/src/connector/mcp/discovery.ts +74 -5
  1244. package/src/connector/mcp/http-sse.ts +16 -1
  1245. package/src/connector/mcp/index.ts +4 -0
  1246. package/src/connector/mcp/policy.ts +134 -0
  1247. package/src/connector/mcp/schema-refs.ts +126 -0
  1248. package/src/constants/agent/index.ts +3 -0
  1249. package/src/constants/compaction/index.ts +1 -1
  1250. package/src/constants/continuation.ts +4 -4
  1251. package/src/constants/mcp/index.ts +34 -0
  1252. package/src/constants/plugin/index.ts +24 -2
  1253. package/src/constants/sandbox/index.ts +6 -5
  1254. package/src/constants/telemetry/index.ts +8 -0
  1255. package/src/constants/tools/index.ts +20 -0
  1256. package/src/contracts/api.ts +40 -0
  1257. package/src/contracts/run-status.ts +43 -0
  1258. package/src/eval/__tests__/case-deadline.test.ts +147 -0
  1259. package/src/eval/__tests__/end-to-end.test.ts +259 -0
  1260. package/src/eval/__tests__/harness-honesty.test.ts +99 -0
  1261. package/src/eval/__tests__/harness.test.ts +249 -0
  1262. package/src/eval/__tests__/judge.test.ts +306 -0
  1263. package/src/eval/__tests__/scorer-gates.test.ts +156 -0
  1264. package/src/eval/experiment.ts +335 -0
  1265. package/src/eval/from-run.ts +48 -0
  1266. package/src/eval/index.ts +21 -0
  1267. package/src/eval/judge.ts +240 -0
  1268. package/src/eval/scorers.ts +169 -0
  1269. package/src/eval/types.ts +157 -0
  1270. package/src/execution/local.test.ts +46 -0
  1271. package/src/execution/local.ts +6 -1
  1272. package/src/gateway/__tests__/list-survives-eviction.test.ts +124 -0
  1273. package/src/gateway/local.ts +117 -3
  1274. package/src/manager/agent/__tests__/dispose-cancels.test.ts +104 -0
  1275. package/src/manager/agent/__tests__/lifecycle.test.ts +297 -0
  1276. package/src/manager/agent/lifecycle.ts +127 -7
  1277. package/src/manager/run/persistence.ts +132 -1
  1278. package/src/plugin/__tests__/enable-contributions.test.ts +3 -3
  1279. package/src/plugin/__tests__/hook-ordering.test.ts +252 -0
  1280. package/src/plugin/__tests__/install-time-refusal.test.ts +68 -0
  1281. package/src/plugin/__tests__/lifecycle.test.ts +95 -73
  1282. package/src/plugin/lifecycle.ts +76 -22
  1283. package/src/plugin/loader.ts +37 -1
  1284. package/src/probe/registry.test.ts +49 -6
  1285. package/src/probe/registry.ts +21 -1
  1286. package/src/provider/__tests__/mock-script.test.ts +179 -0
  1287. package/src/provider/__tests__/registry.test.ts +1 -1
  1288. package/src/provider/__tests__/retry-visibility.test.ts +160 -0
  1289. package/src/provider/__tests__/retry.test.ts +296 -0
  1290. package/src/provider/capabilities.ts +4 -0
  1291. package/src/provider/collect.test.ts +1 -1
  1292. package/src/provider/collect.ts +1 -1
  1293. package/src/provider/index.ts +8 -0
  1294. package/src/provider/mock-register.ts +5 -2
  1295. package/src/provider/mock.ts +117 -34
  1296. package/src/provider/retry.ts +199 -0
  1297. package/src/public-runtime.ts +118 -7
  1298. package/src/public-types.ts +5 -1
  1299. package/src/rag/__tests__/retrieval-math.test.ts +54 -0
  1300. package/src/rag/chunking.ts +32 -1
  1301. package/src/rag/embedding.test.ts +65 -10
  1302. package/src/rag/embedding.ts +26 -5
  1303. package/src/rag/index.ts +1 -1
  1304. package/src/rag/retriever.ts +92 -21
  1305. package/src/rag/vector-store.test.ts +2 -2
  1306. package/src/registry/ManagedRegistry.test.ts +1 -1
  1307. package/src/registry/Registry.test.ts +1 -1
  1308. package/src/registry/connector/definitions.test.ts +1 -1
  1309. package/src/registry/tool/__tests__/schema.test.ts +208 -0
  1310. package/src/registry/tool/__tests__/tool-name-validation.test.ts +88 -0
  1311. package/src/registry/tool/execute.ts +104 -22
  1312. package/src/registry/tool/schema.ts +80 -0
  1313. package/src/registry/toolset/catalog.test.ts +0 -1
  1314. package/src/registry/toolset/catalog.ts +0 -1
  1315. package/src/run/reporter.ts +84 -0
  1316. package/src/runtime/bidi/__tests__/session.test.ts +232 -0
  1317. package/src/runtime/bidi/index.ts +4 -0
  1318. package/src/runtime/bidi/mock.ts +90 -0
  1319. package/src/runtime/bidi/session.ts +205 -0
  1320. package/src/runtime/decision/parser.test.ts +46 -0
  1321. package/src/runtime/decision/parser.ts +8 -1
  1322. package/src/runtime/query/__tests__/answer-review.test.ts +172 -0
  1323. package/src/runtime/query/__tests__/capability-negotiation.test.ts +88 -123
  1324. package/src/runtime/query/__tests__/checkpoint-store.test.ts +13 -50
  1325. package/src/runtime/query/__tests__/checkpoint.test.ts +2 -10
  1326. package/src/runtime/query/__tests__/citations.test.ts +111 -0
  1327. package/src/runtime/query/__tests__/content-budget.test.ts +83 -0
  1328. package/src/runtime/query/__tests__/context.test.ts +3 -2
  1329. package/src/runtime/query/__tests__/deferred-tools.test.ts +23 -148
  1330. package/src/runtime/query/__tests__/delegation-resume.test.ts +159 -0
  1331. package/src/runtime/query/__tests__/document-attachments.test.ts +125 -0
  1332. package/src/runtime/query/__tests__/durable-park-and-trace.test.ts +245 -0
  1333. package/src/runtime/query/__tests__/durable-question-park.test.ts +305 -0
  1334. package/src/runtime/query/__tests__/durable-run-state.test.ts +194 -0
  1335. package/src/runtime/query/__tests__/executor-plugin-hooks.test.ts +24 -20
  1336. package/src/runtime/query/__tests__/finish-reason-vs-tool-calls.test.ts +206 -0
  1337. package/src/runtime/query/__tests__/grant-cannot-overrule-the-gate.test.ts +115 -0
  1338. package/src/runtime/query/__tests__/guardrails-e2e.test.ts +164 -0
  1339. package/src/runtime/query/__tests__/guardrails.test.ts +236 -0
  1340. package/src/runtime/query/__tests__/hook-model-visibility.test.ts +143 -0
  1341. package/src/runtime/query/__tests__/long-document-flow.test.ts +9 -2
  1342. package/src/runtime/query/__tests__/memory-promotion.test.ts +148 -0
  1343. package/src/runtime/query/__tests__/orphan-task-turn-end.test.ts +5 -31
  1344. package/src/runtime/query/__tests__/overflow-relief.test.ts +139 -0
  1345. package/src/runtime/query/__tests__/partial-batch-resume.test.ts +264 -0
  1346. package/src/runtime/query/__tests__/plugin-hooks.test.ts +0 -1
  1347. package/src/runtime/query/__tests__/prepare-step-chain.test.ts +127 -0
  1348. package/src/runtime/query/__tests__/prepare-step.test.ts +233 -0
  1349. package/src/runtime/query/__tests__/probe-veto-is-error.test.ts +145 -0
  1350. package/src/runtime/query/__tests__/prompt.test.ts +1 -1
  1351. package/src/runtime/query/__tests__/provider-fault-pauses.test.ts +104 -0
  1352. package/src/runtime/query/__tests__/reasoning-stream.test.ts +177 -0
  1353. package/src/runtime/query/__tests__/recoverable-settle.test.ts +145 -0
  1354. package/src/runtime/query/__tests__/resume-budget.test.ts +158 -0
  1355. package/src/runtime/query/__tests__/resume-pending.test.ts +273 -0
  1356. package/src/runtime/query/__tests__/rich-content-budget-wiring.test.ts +109 -0
  1357. package/src/runtime/query/__tests__/stop-condition.test.ts +265 -0
  1358. package/src/runtime/query/__tests__/structured-output.test.ts +268 -0
  1359. package/src/runtime/query/__tests__/structured-run-failure.test.ts +144 -0
  1360. package/src/runtime/query/__tests__/terminal-tool.test.ts +148 -0
  1361. package/src/runtime/query/__tests__/tool-grants.test.ts +102 -0
  1362. package/src/runtime/query/__tests__/tool-output-budget.test.ts +0 -0
  1363. package/src/runtime/query/__tests__/tool-pause.test.ts +209 -0
  1364. package/src/runtime/query/__tests__/tool-progress.test.ts +154 -0
  1365. package/src/runtime/query/__tests__/tool-repair-retry.test.ts +255 -0
  1366. package/src/runtime/query/__tests__/tool-result-wire.test.ts +135 -0
  1367. package/src/runtime/query/__tests__/tool-timeout.test.ts +230 -0
  1368. package/src/runtime/query/__tests__/trace-parenting.test.ts +128 -0
  1369. package/src/runtime/query/__tests__/wiring-seams.test.ts +288 -0
  1370. package/src/runtime/query/checkpoint.ts +242 -10
  1371. package/src/runtime/query/events.ts +2 -2
  1372. package/src/runtime/query/executor.ts +856 -40
  1373. package/src/runtime/query/guard.ts +26 -1
  1374. package/src/runtime/query/guardrail-presets.ts +124 -0
  1375. package/src/runtime/query/guardrails.ts +144 -0
  1376. package/src/runtime/query/index.ts +759 -12
  1377. package/src/runtime/query/iteration/__tests__/cancel-settles-turn.test.ts +177 -0
  1378. package/src/runtime/query/iteration/index.ts +674 -31
  1379. package/src/runtime/query/iteration/phases/advisory.test.ts +4 -1
  1380. package/src/runtime/query/iteration/phases/advisory.ts +14 -2
  1381. package/src/runtime/query/iteration/phases/checkpoint.ts +2 -2
  1382. package/src/runtime/query/iteration/phases/compaction-safe-cut.test.ts +3 -1
  1383. package/src/runtime/query/iteration/phases/compaction.ts +329 -64
  1384. package/src/runtime/query/iteration/phases/context-measurement.test.ts +196 -0
  1385. package/src/runtime/query/iteration/phases/context.ts +155 -2
  1386. package/src/runtime/query/iteration/phases/hitl-answer-question.test.ts +3 -1
  1387. package/src/runtime/query/iteration/phases/overflow-escalation.test.ts +167 -0
  1388. package/src/runtime/query/iteration/phases/plan.ts +10 -2
  1389. package/src/runtime/query/iteration/phases/retained-messages.test.ts +226 -0
  1390. package/src/runtime/query/iteration/phases/tool-review-denials.test.ts +270 -0
  1391. package/src/runtime/query/iteration/phases/tool-review.ts +140 -51
  1392. package/src/runtime/query/iteration/phases/working-memory-compaction.test.ts +21 -9
  1393. package/src/runtime/query/iteration/stream-turn.ts +285 -15
  1394. package/src/runtime/query/plugin-hooks.ts +6 -2
  1395. package/src/runtime/query/prompt.ts +26 -1
  1396. package/src/runtime/query/question-park.ts +120 -0
  1397. package/src/runtime/query/result.ts +64 -0
  1398. package/src/runtime/query/resume-pending.ts +394 -0
  1399. package/src/runtime/query/run-state.ts +124 -0
  1400. package/src/runtime/query/tool-grants.ts +83 -0
  1401. package/src/runtime/query/tool-output-budget.ts +183 -0
  1402. package/src/runtime/query/tool-pause.ts +119 -0
  1403. package/src/runtime/query/tooling.ts +23 -1
  1404. package/src/sandbox/__tests__/isolation.test.ts +164 -0
  1405. package/src/sandbox/__tests__/output-truncation.test.ts +106 -0
  1406. package/src/sandbox/__tests__/resource-limits.test.ts +106 -0
  1407. package/src/sandbox/factory.ts +1 -1
  1408. package/src/sandbox/index.ts +2 -0
  1409. package/src/sandbox/isolation.ts +72 -0
  1410. package/src/sandbox/provider/local.ts +173 -74
  1411. package/src/session/__tests__/integration/spawn-rollback.test.ts +1 -1
  1412. package/src/session/handoff/broadcast.ts +3 -3
  1413. package/src/session/migration/__tests__/filesystem.test.ts +26 -19
  1414. package/src/session/migration/filesystem.ts +7 -12
  1415. package/src/session/migration/marker.ts +5 -9
  1416. package/src/session/retention/disk-backend.ts +5 -11
  1417. package/src/session/workspace/__tests__/git-worktree.test.ts +6 -2
  1418. package/src/session/workspace/__tests__/shared-run.test.ts +18 -0
  1419. package/src/session/workspace/shared-run.ts +7 -1
  1420. package/src/skills/__tests__/frontmatter.test.ts +135 -0
  1421. package/src/skills/loader.ts +47 -3
  1422. package/src/store/__tests__/checkpoint-integrity.test.ts +134 -0
  1423. package/src/store/__tests__/checkpoint-versioning.test.ts +194 -0
  1424. package/src/store/__tests__/schema-adoption.test.ts +118 -0
  1425. package/src/store/__tests__/schema.test.ts +119 -0
  1426. package/src/store/memory/disk.ts +17 -16
  1427. package/src/store/run/disk.ts +169 -22
  1428. package/src/store/schema.ts +135 -0
  1429. package/src/store/session/disk.ts +30 -21
  1430. package/src/store/task/__tests__/lookup-across-runs.test.ts +77 -0
  1431. package/src/store/task/disk.ts +59 -15
  1432. package/src/store/thread/disk.ts +21 -10
  1433. package/src/streaming/coalesce.ts +1 -1
  1434. package/src/telemetry/__tests__/latency-instruments.test.ts +120 -0
  1435. package/src/telemetry/__tests__/metrics.test.ts +160 -0
  1436. package/src/telemetry/__tests__/span-hierarchy.test.ts +94 -0
  1437. package/src/telemetry/attributes.ts +109 -0
  1438. package/src/telemetry/metrics.ts +190 -0
  1439. package/src/test-setup.ts +3 -3
  1440. package/src/test-support/paths.ts +17 -0
  1441. package/src/tools/__tests__/path-containment.test.ts +167 -0
  1442. package/src/tools/__tests__/posix-path.test.ts +83 -0
  1443. package/src/tools/__tests__/sandboxed-search.test.ts +140 -0
  1444. package/src/tools/builtins/__tests__/computer-use.test.ts +15 -2
  1445. package/src/tools/builtins/__tests__/edit-commits-atomically.test.ts +103 -0
  1446. package/src/tools/builtins/__tests__/edit.test.ts +80 -17
  1447. package/src/tools/builtins/__tests__/payload-budget.test.ts +20 -40
  1448. package/src/tools/builtins/__tests__/read-file.test.ts +29 -1
  1449. package/src/tools/builtins/__tests__/stale-file-refusal.test.ts +258 -0
  1450. package/src/tools/builtins/__tests__/write-file.test.ts +13 -52
  1451. package/src/tools/builtins/atomic-write-file.ts +30 -2
  1452. package/src/tools/builtins/bash.ts +34 -4
  1453. package/src/tools/builtins/computer-use.ts +7 -1
  1454. package/src/tools/builtins/content-fingerprint.ts +33 -0
  1455. package/src/tools/builtins/edit.ts +258 -60
  1456. package/src/tools/builtins/glob.ts +71 -6
  1457. package/src/tools/builtins/grep.ts +82 -8
  1458. package/src/tools/builtins/index.ts +6 -6
  1459. package/src/tools/builtins/ls.ts +4 -2
  1460. package/src/tools/builtins/read-file.ts +45 -6
  1461. package/src/tools/builtins/write-file.ts +52 -25
  1462. package/src/tools/coordinator/__tests__/agent.test.ts +2 -2
  1463. package/src/tools/coordinator/__tests__/ask-user-question.test.ts +68 -0
  1464. package/src/tools/coordinator/agent.ts +23 -10
  1465. package/src/tools/coordinator/index.ts +213 -72
  1466. package/src/tools/defineTool.ts +20 -0
  1467. package/src/tools/glob-match.ts +50 -0
  1468. package/src/tools/paths.ts +44 -0
  1469. package/src/tools/posix-path.ts +73 -0
  1470. package/src/types/advisory/config.ts +21 -3
  1471. package/src/types/advisory/result.ts +12 -7
  1472. package/src/types/agent/base.ts +22 -2
  1473. package/src/types/agent/factory.ts +15 -9
  1474. package/src/types/agent/gateway.ts +20 -0
  1475. package/src/types/agent/manager.ts +19 -0
  1476. package/src/types/agent/reactive.ts +50 -0
  1477. package/src/types/agent/router.ts +11 -0
  1478. package/src/types/agent/supervisor.ts +2 -2
  1479. package/src/types/agent/task.ts +26 -0
  1480. package/src/types/bidi/index.ts +119 -0
  1481. package/src/types/common/__tests__/numeric-correctness.test.ts +123 -0
  1482. package/src/types/common/index.ts +16 -4
  1483. package/src/types/computer-use/index.ts +1 -1
  1484. package/src/types/connector/mcp.ts +29 -0
  1485. package/src/types/errors/__tests__/catalog.test.ts +130 -0
  1486. package/src/types/errors/__tests__/errors.test.ts +118 -0
  1487. package/src/types/errors/catalog.ts +211 -0
  1488. package/src/types/errors/index.ts +121 -0
  1489. package/src/types/guardrail/index.ts +62 -0
  1490. package/src/types/hitl/index.ts +102 -20
  1491. package/src/types/ids/index.ts +2 -2
  1492. package/src/types/message/content.ts +50 -0
  1493. package/src/types/message/index.ts +210 -9
  1494. package/src/types/plugin/index.ts +82 -2
  1495. package/src/types/provider/__tests__/cause-chain.test.ts +132 -0
  1496. package/src/types/provider/__tests__/declared-retryable.test.ts +85 -0
  1497. package/src/types/provider/__tests__/overflow-classification.test.ts +113 -0
  1498. package/src/types/provider/chat.ts +29 -1
  1499. package/src/types/provider/config.ts +83 -2
  1500. package/src/types/provider/errors.ts +472 -0
  1501. package/src/types/provider/index.ts +5 -0
  1502. package/src/types/provider/stream.ts +63 -3
  1503. package/src/types/rag/embedding.ts +11 -2
  1504. package/src/types/run/__tests__/step.test.ts +123 -0
  1505. package/src/types/run/answer-review.ts +51 -0
  1506. package/src/types/run/config.ts +35 -0
  1507. package/src/types/run/derive-status.ts +62 -0
  1508. package/src/types/run/entity.ts +18 -0
  1509. package/src/types/run/events.ts +230 -3
  1510. package/src/types/run/index.ts +5 -0
  1511. package/src/types/run/memory-promotion.ts +112 -0
  1512. package/src/types/run/prepare-step.ts +109 -0
  1513. package/src/types/run/state.ts +111 -0
  1514. package/src/types/run/step.ts +95 -0
  1515. package/src/types/run/stop-reason.ts +29 -1
  1516. package/src/types/sandbox/index.ts +93 -12
  1517. package/src/types/structured-output/index.ts +6 -5
  1518. package/src/types/thread/entity.ts +2 -3
  1519. package/src/types/tool/index.ts +221 -2
  1520. package/src/types/tool/repair.ts +54 -0
  1521. package/src/types/toolset/index.ts +2 -6
  1522. package/src/utils/__tests__/atomic-write.test.ts +108 -0
  1523. package/src/utils/__tests__/shell-compress.test.ts +49 -0
  1524. package/src/utils/atomic-write.ts +85 -0
  1525. package/src/utils/shell-compress.ts +12 -1
  1526. package/src/verification/presets.ts +6 -3
package/CHANGELOG.md CHANGED
@@ -1,5 +1,2316 @@
1
1
  # Changelog
2
2
 
3
+ ## 3.1.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 8b84fdb: Refuse a file mutation computed against a body that has since moved, and stop writing over symlinks.
8
+
9
+ Two gaps the restored mutation lock does not cover, both standard practice in file-editing agents and both absent here.
10
+
11
+ **Drift between the read and the write.** The lock serializes this runtime's own writers. It cannot see a person editing in an editor, another process, or a second agent run — and an edit computed against a body that has since changed is a lost update whichever of those did the moving. Worse, it was actively misreported: an `old_string` that no longer matched came back as _"not found in file — make sure the string matches exactly"_, which tells the agent its input was wrong when the file changed underneath it, so it retries the same edit against the same moved file.
12
+
13
+ `FileReadTracker.recordRead` now optionally takes the body it read and fingerprints it, and `edit` consults that fingerprint when — and only when — its anchor fails to match. An anchor that still matches uniquely is well defined however much changed elsewhere, so a version check on the success path would reject safe edits every time anyone touched an unrelated line; the fingerprint is a diagnosis, not a gate. When the anchor does fail, it separates 'your text is wrong' from 'the file moved', and the second says what happened, that nothing was written, and to read again. A successful edit re-fingerprints, so a second edit in the same turn is not mistaken for someone else's drift. Both the extra parameter and the new `fingerprint()` accessor are optional, so a host that only needs the read-before-overwrite guard keeps its existing implementation and its existing behaviour.
14
+
15
+ **Writing over a symlink instead of through it.** `rename` replaces whatever sits at the destination, so committing onto a link path swapped the link for a regular file — the link gone, and every other path that pointed through it left reading stale content. The atomic writer resolves the destination first, so the link survives and its target is updated. A path that does not exist yet resolves to itself.
16
+
17
+ ### Patch Changes
18
+
19
+ - 8b84fdb: Close the `ask_user_question` contract, and prove the enforcement hint reaches the wire.
20
+
21
+ The second half of the same revert. `ask_user_question` lost `.strict()` on both its root object and its option items, along with `modelInputSchema`, `enforceModelInput` and `validationErrorHint`.
22
+
23
+ The failure that specifically motivated them is a model serializing `options` — sending `"[{\"label\":\"Board\"}]"` where an array belongs. A model that does it once tends to keep doing it, and the parse error it gets back never says the array was the problem. The closed schema makes a capable provider refuse at generation time, and the recovery hint names the shape to retry with. Without `.strict()` an unknown key was silently stripped, so a misspelled field became a no-op nobody could see.
24
+
25
+ The enforcement path is now covered end to end: a request carries `enforceToolInputSchema` naming exactly the tools that opted in, follows the allowed set rather than everything registered, and omits the field entirely when nothing opted in — an empty array would read as "enforce nothing" rather than "nothing asked", and a driver cannot tell those apart. That coverage is what was missing when the producer was deleted and three drivers went on reading a field nothing set.
26
+
27
+ - ce15b6e: Restore two provider-classification helpers that 3.0.0 dropped by accident.
28
+
29
+ `classifyProviderHttpStatus` and `bodySaysContextOverflow` were part of `@namzu/sdk`'s public surface in 2.0.0. Reconciling a long-running branch resolved a conflict in `public-runtime.ts` in the branch's favour, which discarded both exports, and 3.0.0 shipped without them. They are back.
30
+
31
+ Neither was removed on purpose and nothing in 3.0.0's notes claims otherwise. They exist for a driver outside this repo that needs the classification the first-party drivers use: a status code alone does not separate a context overflow from an ordinary bad request, and re-deriving that per driver is how classifications drift apart.
32
+
33
+ The gate that should have caught this now does. It compares `baseline - current`, so a name that never entered the baseline was invisible to the removal check — it could be added, dropped, and still report "intact", which is exactly what happened. Widening the surface is now a failure that demands the baseline be regenerated in the same commit, rather than a warning that let the baseline go stale.
34
+
35
+ - 2175f85: Restore the file-mutation safety that 3.0.0 reverted.
36
+
37
+ Reconciling a long-running branch with `-X ours` resolved conflicts in the branch's favour, and the branch had been cut before four hardening commits landed on `main`. The result shipped: `edit.ts` and `write-file.ts` went out byte-identical to their shape from before that work, and both modules it depended on were left in the tree with zero importers.
38
+
39
+ What came back, with a test that fails without it:
40
+
41
+ - **Crash-atomic commits.** Both tools wrote with a bare `writeFile`, so a failure partway through left the destination truncated — the user's own file, in the tool that exists to avoid exactly that. They commit through `atomicWriteFile` again (temp file beside the destination, fsync, rename).
42
+ - **Same-path serialization.** Two concurrent edits to one path interleaved their reads and the second write landed on content the first had already replaced, so one edit vanished and the loser reported `old_string not found` — blaming the model for a race. `withFileMutationLock` wraps both the sandbox and local branches again. For `write`, the lock also closes the gap between the exists-check and the write, which is a check-then-act pair.
43
+ - **Closed input contracts.** `.strict()` was gone, so zod's default silently STRIPPED an unknown key: a misspelled or hallucinated field became a no-op instead of an error. `edit`, `write` and `ask_user_question` reject the unknown again — while still accepting the `oldStr`/`newStr` aliases and `insertLine`, which are declared. Closed is not the same as narrow.
44
+ - **`modelInputSchema` and `enforceModelInput`.** The model-facing schemas are back, and so is the producer: `enforcedModelInputToolNames()` had been deleted, so **nothing** populated `enforceToolInputSchema` and all three drivers that read it were reading a permanently undefined field.
45
+ - **CRLF/LF reconciliation**, so an `old_string` that is right in every visible way still matches a file whose line endings differ.
46
+
47
+ Also fixes `atomicWriteFile` on Windows, where it had never run: it fsyncs the directory after the rename, which that platform refuses with `EPERM`, and the error was not caught — so every atomic write failed after correctly writing the file. That sync is best-effort now, and only after the commit has already landed.
48
+
49
+ ## 3.0.0
50
+
51
+ ### Major Changes
52
+
53
+ - 935b8f3: Retire the declarations that promised behaviour nothing implemented, and implement the ones worth keeping.
54
+
55
+ Seven fields were declared on exported types and read by nothing. Each was a contract a host could satisfy and get no result from — the worst kind of gap, because the only signal is that nothing happens.
56
+
57
+ **Implemented**
58
+
59
+ - `maxToolContentBytes` capped the rich channel of a tool result, and no caller could set it: `ToolingBootstrapConfig` had no such field, so the cap was always `0` and the capping branch was unreachable. It is now settable on `ReactiveAgentConfig` and on query params, and reaches the executor through the same chain `maxToolOutputChars` already had.
60
+ - `AdvisoryResult.warnings` and `.decisions` had two consumers each — the advisory phase folds decisions into working state so they survive compaction, and renders warnings back to the executing agent — and no producer at all. Advisors are now told the convention their answer is read with, and `parseAdvisoryResponse` lifts `<warnings>` / `<decisions>` blocks out of the prose. The contract is appended to a host-written prompt and a persona-assembled one too, not only the default; an advisor never told the convention would have had its warnings silently discarded.
61
+ - `AdvisoryBudget.maxCostPerRun` is enforced before each call against real accumulated spend, and `maxTokensPerCall` clamps the advisor's own response ceiling. Cost is now computed from a new optional `AdvisorDefinition.pricing`, and a run that sets a cost cap over unpriced advisors is **refused at construction** rather than left with a cap that could never be reached.
62
+
63
+ **Removed** — declared, never read, and not worth building:
64
+
65
+ - `AdvisoryBudget.maxCallsPerSession` and `maxCostPerSession`: the advisory stack is built once per run, so no accumulator outlived one and a per-session cap could only ever be decoration. `maxCostPerCall` went with them — a per-call cap can only be checked after the spend, which is a log line, not a budget.
66
+ - `AdvisoryResult.plan`, `.modelSuggestion`, `.toolGuidance`: no producer and no consumer.
67
+ - `ToolsetDefinition.toolPolicies`: stored on the toolset and never consulted, so a per-tool `{ enabled: false }` override was inert.
68
+ - `SandboxConfig.cleanupOnDestroy`: defaulted to `true` and read by nothing; `destroy()` removes unconditionally either way.
69
+ - `StructuredOutputConfig.enforceToolChoice`: documented a tool-choice mechanism no code implemented.
70
+ - `RuntimeConfig.promptCache`: caching is unconditional at both model calls, and no surface accepts a `RuntimeConfig`, so nothing could set it even in principle.
71
+
72
+ Also ports the telemetry provider to the current tracing API — `Resource` became a type with a factory, and span processors moved to the provider constructor — and lifts a run deadline inside the long-document flow test that aborted the run at 5s and read as a broken flow rather than a busy machine.
73
+
74
+ - 935b8f3: Three controls a caller could set that the runtime then quietly declined to apply.
75
+
76
+ - **`toolChoice: 'none'` permitted tool calls on two drivers.** It means the model must not call a tool. One driver mapped it to the wire's "auto" and the other to `{ type: 'auto' }` — both of which say the model _may_. A caller that had forbidden tool use got a request that allowed it, with nothing in the response to say so. The runtime depends on the guarantee: an advisory consultation passes `'none'` so the advisor answers in prose, into a turn where no executor is waiting for a tool call. Both drivers now answer `'none'` by sending no tools at all, which no wire format can misread.
77
+
78
+ - **`memoryLimitMb` and `maxProcesses` were dropped by the stronger isolation tiers.** They were applied inside the unconfined tier's branch only, so asking for namespace or profile isolation silently removed the blast-radius caps — a control failing in the one direction nobody checks. They are the same shell builtin on every tier; the stronger tiers now apply them one level in, inside the wrapper they already spawn through, and keep doing their own job. The sibling backend in the sandbox package already refuses per-sandbox controls it cannot enforce rather than ignoring them; this is the same rule, satisfied by enforcing.
79
+
80
+ - **`AgentManager.dispose()` cancelled nothing.** It called `cancelAll('' as RunId)`, and `cancelAll` filters by parent run — no task has an empty parent, so it matched nothing, and the next lines cleared the instance map. Every live child was released without its abort controller firing: the work kept running, the budget kept draining, and nothing was left holding a reference to stop it. It now cancels every live child before dropping them. `cancelAll` stays scoped to one parent, which is its actual job.
81
+
82
+ `toBedrockToolConfig` and `buildLimitedSpawn` are exported so the mapping and the spawn shape can be asserted directly rather than through a live process.
83
+
84
+ - 935b8f3: Three public identifiers named a vendor where the code was generic. Renamed,
85
+ and in two cases the naming was hiding a design problem worth fixing.
86
+
87
+ **`OpenRouterEmbeddingProvider` → `HttpEmbeddingProvider`** (config type
88
+ likewise). Nothing about the class was vendor-specific: it POSTs to
89
+ `{baseUrl}/embeddings` with a bearer key and reads back
90
+ `{ data: [{ index, embedding }] }` — the shape every hosted embeddings
91
+ service speaks. Only the name and a default host said otherwise.
92
+
93
+ `baseUrl` is now **required**. It defaulted to one vendor's host, which
94
+ meant a caller who never named an endpoint still shipped its text to one. A
95
+ default network destination is a decision the caller has to make out loud.
96
+ A trailing slash is now tolerated rather than producing a doubled path.
97
+
98
+ **`AgentFactoryOptions.provider`** was `'openrouter' | 'bedrock'` — a closed
99
+ two-member union in a generic factory, naming two specific services that the
100
+ provider registry has never been limited to and that no caller could extend.
101
+ It is now `string`: any registered provider type.
102
+
103
+ **`AgentFactoryOptions.bedrockConfig`** is replaced by
104
+ `providerConfig?: Record<string, unknown>`, passed through untouched. The
105
+ old field existed for exactly one service and had no construction site
106
+ anywhere in the workspace.
107
+
108
+ **`StorageProviderId`**: the `'anthropic-files'` member is now
109
+ `'provider-files'`.
110
+
111
+ - 935b8f3: A model-graded judge, and a failed measurement that stops reading as a zero.
112
+
113
+ Every scorer in the harness was a pure function over the run, which is what
114
+ makes them reproducible — and what makes them unable to say whether an
115
+ answer is _good_. `containsScorer` can check that a required phrase appears;
116
+ it cannot tell a correct explanation from a fluent wrong one. The dimension
117
+ most worth guarding had no scorer behind it.
118
+
119
+ **`judgeScorer`** grades an open-ended answer with a model. Four choices in
120
+ it are deliberate, because each is where these usually go wrong:
121
+
122
+ - The **rubric is required**. A judge asked to rate "quality" rates fluency,
123
+ which correlates with little worth measuring and drifts whenever the judge
124
+ model changes. It throws rather than run without one.
125
+ - An **ordinal scale, not a 0..1 float**. Models place a continuous score
126
+ poorly and cluster on round numbers; a short scale against a written
127
+ rubric is a judgement they can make. The default of 4 is even on purpose —
128
+ an odd scale has a midpoint, and a midpoint is where an uncertain judge
129
+ parks.
130
+ - **Temperature 0**, because sampling noise is indistinguishable from a
131
+ regression.
132
+ - **Truncation disclosed in the prompt**, so the judge does not mark an
133
+ answer down for an ending the harness removed.
134
+
135
+ A grade outside the scale it was given is an error rather than a clamp: a
136
+ judge that misread the scale did not apply the rubric either.
137
+ `details.judgeTokens` carries what the judging cost.
138
+
139
+ **A failed measurement is no longer a measurement of zero.** A judge is a
140
+ network call, so it can fail to answer at all — and scoring that `0` says
141
+ "the run was bad" when the truth is "we do not know". One rate limit would
142
+ turn a green suite red and send somebody hunting a regression that never
143
+ happened.
144
+
145
+ - `Score.unavailable` marks a judgement that could not be produced. It is
146
+ excluded from the case mean's numerator **and** denominator.
147
+ - `CaseResult.status` is `'passed' | 'failed' | 'inconclusive'`, and a case
148
+ where every scorer was unavailable is inconclusive rather than failed.
149
+ `CaseResult.passed` remains, true only for `'passed'`.
150
+ - `ExperimentReport.inconclusive` counts them, and `formatReport` surfaces
151
+ that count **above** the failures — it means every number below covers
152
+ less evidence than it appears to.
153
+ - `byScorer` averages each scorer over the cases it actually judged, and
154
+ omits one that was never available rather than reporting it as `0`.
155
+
156
+ A run that **threw** still scores zero: that is a real failure of the thing
157
+ under test, not of the measurement.
158
+
159
+ Breaking: `CaseResult` gains a required `status`, `ExperimentReport` gains a
160
+ required `inconclusive`, and a scorer that throws now reports as unavailable
161
+ instead of scoring zero.
162
+
163
+ - 935b8f3: **Breaking:** `ActiveNodeInfo` and `BranchStackEntry`, and the `activeNode` / `branchStack` checkpoint fields that carried them, are removed.
164
+
165
+ Both types described where a multi-node run stood — which agent was active, how deep, what each branch decided — and nothing ever wrote either one. `CheckpointManager.save` accepted them as optional `extra` arguments no caller passed, so every checkpoint ever written left both `undefined`, and a resume that consulted them would have found nothing to consult.
166
+
167
+ Resuming a fan-out is already covered, and by a general mechanism rather than a topology-specific one: delegation blocks and returns the worker's output as its own tool result, so a delegation is an ordinary tool call whose completion the transcript records — and the crash-resume path that answers already-executed tool calls answers delegations too. A worker that already ran does not run twice. That behaviour is now pinned by tests, so if delegation ever stops blocking, they fail.
168
+
169
+ - 935b8f3: **Breaking:** three public types that promised behaviour the runtime does
170
+ not have are removed.
171
+
172
+ A public type that describes an absent capability is a worse defect than an
173
+ absent type. It reads as a feature, gets designed around, and the discovery
174
+ that it does nothing happens at runtime — usually in the one code path
175
+ nobody exercised until production.
176
+
177
+ - **`PluginHookResult`'s `{ action: 'resume' }`** — declared as a hook
178
+ outcome and rejected with "unsupported action" at every one of its three
179
+ consumers: the lifecycle-event applier, the `pre_tool_use` path and the
180
+ `post_tool_use` path. A plugin author reading the union had every reason
181
+ to think a hook could resume something. Nothing could.
182
+ - **`ConcurrencyMode`** (`'throw' | 'queue'`) — no API accepts it, nothing
183
+ calls the lock it was meant to configure, and the `queue` half describes
184
+ a mode that was never built. It promised a choice about concurrent
185
+ invocation where there is exactly one behaviour.
186
+ - **`ToolPermissionPolicy`** and `ToolsetPolicy.permissionPolicy` — written
187
+ once with a constant `'default'` and read by no runtime code. A host
188
+ setting `'always_ask'` on a toolset got no prompt and no error.
189
+
190
+ Migration: nothing consumed any of them, so nothing should break. If your
191
+ code sets `permissionPolicy`, delete the field — it never did anything; the
192
+ verification gate (`allow_by_name`, `custom_pattern`, `target: 'args'`) is
193
+ the surface that actually decides. If a hook returns `{ action: 'resume' }`,
194
+ it was already throwing at every call site.
195
+
196
+ Kept, and documented instead of removed: `AgentManager.continueTask` /
197
+ `queueMessage` / `drainMessages`. The queue they maintain is read by
198
+ nothing in the iteration loop — the consumer that once drained it was
199
+ removed — so a caller who assumes `continueTask` reaches a running agent is
200
+ filling a buffer only `drainMessages` empties. That is now stated on the
201
+ interface, along with the two mid-run routes that DO work (feedback inside
202
+ a tool result; `prepareStep`'s `system` string). Deleting `drainMessages`
203
+ would have removed the only way a host can pick those messages up and left
204
+ the trap in place.
205
+
206
+ - 935b8f3: Close every open code-scanning finding
207
+
208
+ **Breaking:** `LocalExecutionContext.executeCommand` no longer interprets its arguments as shell syntax. `shell` defaulted to `true`, and spawning with a shell re-joins the command and its argument array into a single `sh -c` string — so every metacharacter inside an argument became syntax. An `args` array reads argv-safe and was not. The default is now `false`; `shell: true` remains available where a caller genuinely wants a pipeline. A consumer passing `"ls -la"` as one command string, or relying on glob expansion without asking for a shell, must now pass `shell: true`.
209
+
210
+ **A sandbox timeout is bounded, and an out-of-range one is refused.** The bash tool's `timeout` argument is a number the model writes, with no ceiling of its own, and it reached both sandbox transports unmodified — so a single call could pin a container or a guest for as long as the platform's timer honours. Both transports now refuse a non-finite, non-positive or over-thirty-minute request rather than clamping it: running under a deadline the caller never chose, and never learns about, is the "accepted and silently not applied" failure this codebase treats as worse than not offering the control at all.
211
+
212
+ **Seven quadratic-backtracking regexes are now linear scans**, each on a path an attacker can reach: shell output the agent captured, a tenant-supplied connector URL, a host-supplied workspace root, a model completion, and three endpoint strings that cross the same trust boundary. The worst measured over thirty seconds on a single pathological input, on a shared event loop. Three of the seven were not flagged by the scanner — the same pattern, the same boundary — and were fixed with the rest rather than left to be rediscovered.
213
+
214
+ - 935b8f3: namzu's own vocabulary, everywhere.
215
+
216
+ Comments across the kernel explained namzu's design by naming another
217
+ product: "mirrors X's container architecture", "reference: X's
218
+ `normalizePathForSandbox()`", "which is what Y and Z both do", "Claude Code
219
+ uses 2000 for the same reason". Behaviour was correct throughout — this is
220
+ about what the code says it is. A kernel that explains itself by citation
221
+ reads as a reimplementation of something else, and namzu is not one.
222
+
223
+ Every such comment now states the reason directly. Where a rule exists
224
+ because a provider requires it, the comment says what the requirement is
225
+ rather than whose it is — which is also more useful, since the same
226
+ requirement usually holds for more than one provider, and a reader who has
227
+ never used the named one can still follow it.
228
+
229
+ **Breaking (types only, no runtime behaviour):**
230
+
231
+ - `ToolCatalogSurface`: the `'cowork'` member is now `'supervised'`.
232
+ - `ToolSource.skill.type`: `'anthropic' | 'custom'` is now
233
+ `'published' | 'custom'`.
234
+
235
+ Both are descriptive metadata with no construction site anywhere in the
236
+ workspace, so nothing internal moved. An external consumer that names
237
+ either value gets a compile error pointing at the line.
238
+
239
+ **Deliberately unchanged**, because these are addresses rather than
240
+ borrowed naming: model-id prefixes in the context-window table (data the
241
+ runtime matches against), API-key detection patterns in the guardrail
242
+ presets (a pattern is worthless if you cannot tell what it detects),
243
+ namzu's own provider package names, and the credential-store integration in
244
+ the CLI, whose service name and file path are literally the other tool's.
245
+
246
+ - 935b8f3: Tool names are validated, and a paged remote catalogue is read to the end.
247
+
248
+ **Every plugin-contributed tool name was illegal.** A tool name reaches the
249
+ provider verbatim and the major message APIs accept `[a-zA-Z0-9_-]` up to 64
250
+ characters — but the plugin namespace separator was `:`, so every tool a
251
+ plugin contributed carried a name the wire rejects. Nothing checked: names
252
+ are derived by concatenation at three separate construction sites and none
253
+ validated the result.
254
+
255
+ The rejection is a 400 on the **whole request**, not on that tool. Those
256
+ tools are registered deferred, so it fired the moment something activated
257
+ one, with nothing naming the culprit.
258
+
259
+ - `assertToolName` runs at registration, where a bad name can still be
260
+ attributed and costs the run nothing.
261
+ - **Breaking:** `PLUGIN_NAMESPACE_SEPARATOR` is now `__`, which renames every
262
+ plugin-contributed tool id — `fs-plugin:mcp__fs__read_file` becomes
263
+ `fs-plugin__mcp__fs__read_file`. A host that names one of these in an
264
+ allowlist, a permission rule or a preserve-list must update it. The two
265
+ changes have to land together: adding the check without the rename would
266
+ refuse every plugin tool.
267
+
268
+ One driver had already ratified passing names through untouched, on the
269
+ grounds that a confusing name is "a naming problem to fix in the registry,
270
+ not something to paper over" — which is precisely why the registry has to be
271
+ the one that checks.
272
+
273
+ **A paged remote catalogue is now read to the end.** `tools/list`,
274
+ `resources/list` and `resources/templates/list` each sent an empty params
275
+ object and returned the first page — never sending a cursor, never reading
276
+ the one that came back. A server that pages its catalogue contributed only
277
+ its first page: the rest were never registered, never namespaced, never
278
+ advertised, with no error and no warning. Drift detection did not help
279
+ either, since it compared page one against page one.
280
+
281
+ The symptom is a model that never uses a tool it was told about, which reads
282
+ as model incompetence rather than a client bug. Both clients — the SDK's and
283
+ the CLI's — now thread the cursor. A server whose cursor never ends is
284
+ refused after 100 pages rather than looping forever or stopping silently,
285
+ since stopping silently is the failure being fixed.
286
+
287
+ ### Minor Changes
288
+
289
+ - 935b8f3: An answer can cite the document it came from
290
+
291
+ Sending a document buys the provider's native handling of it — page structure, built-in OCR, and the ability to say which passage an answer rests on. namzu could send the document and could not receive the third: an answer about a contract arrived as prose, and checking it meant reading the contract again by hand. A citation is the difference between an answer you trust and one you verify.
292
+
293
+ `citations: true` on a document attachment asks for them; they come back on the assistant message as `Citation[]`. Opt-in per document, because the provider splits the document into citable units and the answer carries the passages it leaned on — tokens a turn that never wanted a citation should not pay.
294
+
295
+ The location is a union — `page`, `char` or `block` — rather than a page number, because providers segment differently and the segmentation is theirs. Flattening all three would invent a page number for the two that have none. Web-search and search-result citations are deliberately dropped: they point at something that was never in the request, so there is no attachment to resolve them against, and a citation the reader cannot go and look at is worse than none.
296
+
297
+ Citations ride with the turn that made them, like reasoning blocks, so compaction takes a turn's evidence with it rather than leaving citations pointing at prose that is gone.
298
+
299
+ - 935b8f3: A finished run can leave something behind
300
+
301
+ The SDK could store a memory and could not form one. `MemoryStore` and its disk implementation have been here all along, and the only path into them was the model calling `save_memory` — so a run that worked out a durable fact and never thought to write it down lost it at settle, along with everything the compaction pass had already extracted and structured on the way.
302
+
303
+ The extraction was already built: compaction distils the transcript into decisions, discoveries, requirements and failures precisely because a list of facts is worth more than a summary of prose. That structure was serialized into one system message and then dropped when the run ended. `promoteMemory` is called once, at settle, with it.
304
+
305
+ A callback rather than a store the runtime writes into — what is worth remembering is a policy question the host owns, and a runtime that decided it would write a row for every run whether or not anything happened. It is called for a failed run too (the approach that failed is exactly what a later run should not pay for twice), it is awaited rather than fire-and-forget (a one-shot process exits as soon as the run returns), and a throw is swallowed and logged, because a memory that failed to form must not retract an answer that was already produced.
306
+
307
+ - 935b8f3: A host can judge the **answer**, and one agent instance runs one thing at a
308
+ time.
309
+
310
+ **`reviewAnswer` closes the verify-then-fix loop.** `stopWhen` is evaluated
311
+ after each step's _tools_ have run, so it had nothing to say at the moment
312
+ the model stopped calling them — the run finalized with whatever it had
313
+ produced. Running the build, feeding the failure back, and letting the
314
+ model try again meant starting a whole new run and re-supplying the context
315
+ the first one had already assembled.
316
+
317
+ The reviewer sees the answer and the history, and either accepts or returns
318
+ feedback that becomes the next user turn. Three properties carry it:
319
+
320
+ - **Bounded** by `maxAnswerReviews` (default 3), stopping with
321
+ `stopReason: 'answer_rejected'`. The distinct reason matters: without it
322
+ a reviewer that never accepts ends the run on `max_iterations`, naming
323
+ the resource it exhausted rather than the judgement that exhausted it,
324
+ and the reader goes looking for a loop instead of at the reviewer.
325
+ - **Never on the forced-final turn**, which exists to extract a closing
326
+ summary under pressure. Rejecting it would spend budget the run has
327
+ already run out of.
328
+ - **A reviewer that throws ACCEPTS** — the opposite of the safety gates,
329
+ deliberately. Those are asked "is this dangerous", where failing closed
330
+ costs one refused operation; this is asked "is this good enough", where
331
+ failing closed hands the answer back forever and turns every run into a
332
+ loop. One unreviewed answer is the cheaper failure, and the throw is
333
+ logged at `error` so it is never mistaken for approval.
334
+
335
+ Shaped after the structured-output re-prompt directly above it in the loop,
336
+ which solves the same problem for one specific judge.
337
+
338
+ **The invocation lock now has a caller.** `InvocationLock`,
339
+ `ConcurrentInvocationError` and `acquireInvocationLock` were all defined and
340
+ exported, and no agent ever acquired the lock — so concurrent invocations of
341
+ one instance were not prevented and the error type could not be thrown by
342
+ anything.
343
+
344
+ They are genuinely unsafe: `abortController` and `currentRunId` are
345
+ _instance_ state. Two overlapping runs share one abort controller, so
346
+ cancelling either kills both, and the second clobbers the first's run id, so
347
+ a later `cancel()` cancels the wrong run. Neither failure announces itself —
348
+ the first run simply stops, or the wrong one does. A host that wants
349
+ parallelism constructs a second instance, which is cheap; sharing one was
350
+ never the supported shape, it merely was not refused.
351
+
352
+ This is the other half of `ConcurrencyMode`, removed earlier in this release
353
+ as an unreachable type promising a `queue` mode that was never built.
354
+
355
+ - 935b8f3: Any tool can raise a durable pause
356
+
357
+ The pause-for-a-human machinery is durable and complete, and it was reachable from exactly four kernel-owned points: the plan gate, the tool-review gate, the iteration cadence, and the built-in question tool. A host-authored tool had no seam to it — the operations that most want their own confirmation with their own wording, a spend, an outbound post, a destructive migration, had to settle for the generic tool-review gate or hand-thread a recorder and a resume callback into a private builder, which nothing in `ToolContext` suggested was possible.
358
+
359
+ `context.requestPause({ name, prompt, options })` is that machinery behind one function. The pause is written as a real checkpoint, so it appears on every surface a tool-review park appears on and survives the process dying, and on resume the answer routes back **by name** — several tools pausing in one batch each get their own, and one call may pause more than once.
360
+
361
+ The outcome is `answered`, `unanswered`, or `aborted`. Silence is deliberately not a variant of `answered` with an empty selection: a tool that asks "may I charge this card" and reads silence as yes is worse than one that never asked, so the absence of an answer has its own shape and cannot be destructured into consent. An option id the tool never offered is dropped for the same reason.
362
+
363
+ `requestPause` is optional on the context, because a host calling a tool directly provides no route to a human.
364
+
365
+ - 935b8f3: Four places where namzu knew something and told no one.
366
+
367
+ **A backoff is now visible.** `withProviderRetry` logged and slept. There
368
+ was no run event, no wire event, and — worse than that — the sole
369
+ production call site never passed a logger, and every warn in the decorator
370
+ is guarded behind it, so the log lines were dead code too. A run could sit
371
+ silent for the better part of a minute between `iteration_started` and the
372
+ next event, or up to the 60s server-directed cap, with no signal and no
373
+ keepalive: a backoff was indistinguishable from a hang, and a host's
374
+ watchdog would cancel a run that was about to succeed.
375
+
376
+ A `provider_retry` run event now carries the attempt, the ceiling, the
377
+ delay, the classified code and whether the server asked for it, mapped to
378
+ `provider.retry` on the SSE wire and to a `running` status update over A2A.
379
+ It is emitted **before** the sleep, so the delay it names is still ahead —
380
+ which is also why it rides the stream as a delta-less chunk rather than an
381
+ out-of-band callback: the consumer is blocked inside the provider's
382
+ iterator, so a callback could not reach it until the wait was already over.
383
+ The omission was never principled; `tool_progress` exists to answer "is it
384
+ still working?" and the wire contract justifies the reasoning events on
385
+ exactly the same grounds.
386
+
387
+ **Two latency measurements that could not be recovered from the data.**
388
+ `gen_ai.client.time_to_first_token` is recorded at the first delta of any
389
+ kind. namzu streams, so perceived latency is dominated by that number, and
390
+ the one existing latency histogram measures the whole request — it cannot
391
+ tell a fast-first-token long generation from a stalled one, and no host
392
+ could reconstruct the difference in any form.
393
+ `gen_ai.tool.call.duration` records what the executor has measured since
394
+ its first version: the value was already in scope one frame above the call
395
+ site, emitted per call on `tool_completed`, and had no instrument. It
396
+ carries the same attributes as the tool-call counter, so "which tool is
397
+ slow" and "which tool fails" are one query rather than two that cannot be
398
+ joined.
399
+
400
+ **`run_failed` carries the classification it always had.** The event was a
401
+ bare string, and the run boundary flattened the throwable into it,
402
+ discarding `code`, `status`, `retryAfterMs`, `retryable`, `details` and the
403
+ cause chain. This was never a missing taxonomy: the provider-boundary
404
+ classifier already walks all of that, so a fully-populated error arrived at
405
+ the boundary and was thrown away one line later — and `toPlatformError`,
406
+ the projection written for exactly this, had no callers outside its own
407
+ test. `run_failed` now carries `failure` alongside `error`; the A2A bridge
408
+ sends it as event metadata (a peer deciding whether to retry needs the
409
+ flag, not prose to pattern-match) and the CLI prefixes the code. Nothing
410
+ had to change at the hundreds of `throw` sites.
411
+
412
+ Not fixed, and worth naming: the advisory `on_error` trigger still
413
+ substring-matches. Its input is tool output from the message history, which
414
+ has no structured code to preserve — that needs a tool-side error catalog,
415
+ not this change.
416
+
417
+ **The published attribute constants can no longer drift.**
418
+ `@namzu/telemetry/attributes` restated the attribute bags by hand and had
419
+ already lost `GENAI.TOKEN_TYPE`, the dimension that splits the token
420
+ counter by kind. The consequence was narrow — namzu emits through the
421
+ canonical module, so the dimension is on the data regardless — but this is
422
+ the entry point the observability docs steer consumers to, the package had
423
+ no tests at all, and the public-surface verifier only loads the SDK bundle.
424
+ It is now a re-export, with a parity test so a future hand-copy fails
425
+ immediately.
426
+
427
+ - 935b8f3: Add programmable stop conditions and a per-step record.
428
+
429
+ `GuardCoordinator` was the loop's only halt, and it consumes
430
+ `{aborted, totalTokens, totalCost, currentIteration, startTime}` — it never
431
+ sees messages, tool calls or results. So a terminal `submit_answer` /
432
+ `verify_outputs` tool could not end a run: the model had to be prompt-begged to
433
+ stop, with `maxIterations: 200` or the token budget as the only backstop, which
434
+ meant a finished task still burned its whole envelope. "Stop after three steps
435
+ without progress" and "stop when the plan is complete" were inexpressible.
436
+
437
+ **`StepResult`** records what each iteration did — model, message id, content,
438
+ tool calls, tool results, finish reason, per-step usage and cost delta, start
439
+ time, total duration and time spent inside tools. Every field was already
440
+ computed somewhere in the loop; none of it was reachable, because neither `Run`
441
+ nor `BaseAgentResult` had a `steps[]`. A host that persisted the returned `Run`
442
+ — the natural thing — permanently lost per-step attribution, and answering
443
+ "which step cost the most" meant correlating raw `RunEvent`s by iteration number
444
+ and diffing cumulative counters.
445
+
446
+ - `Run.steps` carries the record, including on a failed run.
447
+ - `onStepFinish(step)` fires as each step completes.
448
+ - `stopWhen` is evaluated **after** the step's tools have run, so a predicate
449
+ sees what they returned. That ordering is what lets a terminal tool end the
450
+ run _after_ executing rather than instead of executing — its output is still
451
+ recorded and still reaches the model's history.
452
+ - Helpers: `stepCountIs(n)`, `hasToolCall(...names)`, `anyOf(...conditions)`.
453
+ Conditions may be async.
454
+ - A predicate that throws is logged and treated as "do not stop": failing open
455
+ leaves the existing budgets in charge rather than killing a healthy run.
456
+ - New `StopReason: 'stop_condition'`.
457
+
458
+ `runToolReview` now returns its tool outcomes alongside its decision, so the
459
+ loop builds the step record from what actually ran instead of re-deriving it
460
+ from the messages it just pushed.
461
+
462
+ - 935b8f3: Durable run state: a parked approval now survives a process boundary.
463
+
464
+ A HITL park used to exist only as a suspended `await` inside one process.
465
+ The checkpoint written just before it looked identical to any mid-run
466
+ checkpoint, so nothing in durable state said a human owed the run an
467
+ answer — an approval queue could not be rebuilt, and a serverless host
468
+ could not park a run at all, because the container holding the promise had
469
+ to stay alive.
470
+
471
+ - `IterationCheckpoint.pending` records the `HITLDecisionRequest` verbatim,
472
+ plus the answer once it arrives (kept as evidence, not erased).
473
+ - `findPendingCheckpoint(store, scope)` — the read an approval queue is
474
+ built from, in any process.
475
+ - `RunState` + `captureRunState` / `loadRunState` / `parseRunState`: a
476
+ flat, JSON-safe snapshot with a version guard, so a snapshot written by
477
+ one deployment cannot silently half-restore in another.
478
+ - `QueryParams.pendingDecision` applies a decision collected out-of-band to
479
+ the exact tool calls the human was shown. Without it a resumed run
480
+ repaired the unanswered `tool_use` blocks away and let the model
481
+ re-decide, so "yes, delete that row" degraded into "ask the model again
482
+ and hope it asks for the same thing". The decision is ignored (and the
483
+ repair path runs) when the checkpoint's calls no longer match the
484
+ recorded request — consent to one batch is not consent to another.
485
+ - A `pause` decision keeps the park outstanding; every other action
486
+ resolves it. A host that cannot block answers `pause` immediately and
487
+ comes back in another process.
488
+ - Park recording is lazy (`parkRecordDelayMs`, default 250ms) so a
489
+ programmatic handler never pays for it — except `pause`, which is always
490
+ recorded because it means the decision is still owed.
491
+
492
+ - 935b8f3: Retry works on a wrapped error, and the runtime actually emits metrics.
493
+
494
+ **Every error signal is now read across the whole cause chain.** It was read
495
+ off the error handed in, so one layer of wrapping hid it — and wrapping is
496
+ the normal case, not an edge one: a vendor SDK wraps its transport error and
497
+ the runtime wraps again on the way out. A rate limit wrapped **once**
498
+ classified as `unknown`, which is treated as non-retryable, so the retry
499
+ policy was dead for every failure that was not the outermost throwable. A
500
+ socket reset two levels down was likewise unknown — the one class of failure
501
+ where retrying is almost always right.
502
+
503
+ Status, transport errno, `Retry-After`, and message text are all searched
504
+ along the chain now, outermost first, with a `seen` set so a cause cycle
505
+ (easy to build by accident when errors are re-wrapped in a retry loop)
506
+ terminates instead of hanging. Precedence is unchanged — status, then errno,
507
+ then message — and an unwrapped error classifies exactly as before.
508
+
509
+ **The runtime emitted spans and not one measurement.** Metrics lived in a
510
+ bag a host was expected to construct, and nothing in the workspace ever
511
+ constructed one. Worse, the bag bound its instruments eagerly, so one built
512
+ before `registerTelemetry()` captured the no-op meter and discarded every
513
+ write for the rest of its life — silently, forever, from a line of call
514
+ order.
515
+
516
+ - The instruments now live beside the code that records them, and the
517
+ runtime records token usage and model latency per call, tool outcomes per
518
+ call, and run duration per run.
519
+ - Instruments resolve **lazily** and re-resolve when a real provider is
520
+ installed, so registration order no longer decides whether anything is
521
+ measured.
522
+ - One token metric split by `gen_ai.token.type`, not two under two names
523
+ with the second invented — a dashboard aggregating the conventional name
524
+ was getting input tokens only and under-reporting usage by roughly half.
525
+ - Cache reads and writes are recorded as their own token types. They bill
526
+ differently, so a total that hides them cannot explain a bill.
527
+ - Tool calls carry an error type, so a broken tool can be told apart from
528
+ one whose input the model keeps getting wrong.
529
+ - `createPlatformMetrics()` still works and now delegates to the same
530
+ instruments, so host and runtime measurements aggregate instead of
531
+ describing the same events under two names.
532
+
533
+ - 935b8f3: A delegated run now joins the trace it belongs to.
534
+
535
+ Every run started its own ROOT span, including a spawned sub-agent's. A
536
+ supervisor delegating to three children produced four disconnected traces
537
+ instead of one tree — the same defect that made a 20-turn run show up as 21
538
+ roots before iterations were parented, except across the spawn boundary,
539
+ where the delegation structure is exactly what a trace is for.
540
+
541
+ `QueryParams.parentSpan` (and `ReactiveAgentConfig.parentSpan`) parents the
542
+ run span when a caller supplies one. The spawning tool passes its own span,
543
+ so a child run lands inside the turn that asked for it:
544
+
545
+ tool span → child run → child iterations → child tool spans
546
+
547
+ A top-level run with no parent still starts its own root, which is correct:
548
+ it IS the root, and forcing one would be wrong.
549
+
550
+ The parent is stamped onto the child config after `configBuilder` runs
551
+ rather than relying on every builder to forward an option it may not know
552
+ about.
553
+
554
+ - 935b8f3: A conversation with no turn boundary
555
+
556
+ Every other seam in this kernel is turn-based by construction: a run has iterations, an iteration sends a complete message list and reads a stream back, and a checkpoint is taken between two of them. That shape cannot describe a duplex session, where input keeps arriving while output is still being produced and "the turn" is not something either side can point at.
557
+
558
+ `BidiProvider` / `BidiSession` is a second contract rather than a widening of the first — bending `chatStream` to accept a live input channel would put a half-duplex assumption inside every consumer of the turn-based path in exchange for a duplex path that still would not fit. `startBidiRun` is the loop that runs tools against it.
559
+
560
+ Two properties matter here that the turn-based loop never needs. A tool must not block the stream: awaiting one inline would stall the very events an interruption arrives on, so calls start and are not awaited. And an interruption invalidates work in flight: a call still running when the human speaks over the model is abandoned rather than delivered, because a stale answer in a conversation that has moved on is worse than no answer.
561
+
562
+ Audio capture and playback are not here — the types carry audio, but the microphone belongs to the host. Neither is checkpoint/resume: a duplex session's state lives on the far side of a socket with no boundary to snapshot at, and checkpoints that cannot restore would be worse than none. The contract ships with a scripted driver, which is how the turn-based path is developed too.
563
+
564
+ - 935b8f3: Seven places where state, consent or a verdict did not survive the boundary
565
+ it needed to cross.
566
+
567
+ **A checkpoint is versioned on disk, and its budgets are checked.** It was
568
+ written bare and read with a cast. Unstamped is read as version 1 by
569
+ definition, which is correct only while version 1 is the only version there
570
+ has ever been — the moment a second exists, a file written by the newer
571
+ build is read by the older one as if it were the older shape, and the
572
+ refusal that exists to prevent exactly that never fires. There was no chain
573
+ to hang a migration on. Separately, the read validated `id`, `iteration`,
574
+ `createdAt` and `messages` and skipped `tokenUsage` / `costInfo` /
575
+ `guardState` — which a resume dereferences before its first iteration. A
576
+ run recalled at $4.80 of a $5 cap whose cost came back malformed continued
577
+ with `NaN`, which compares false against every limit, so the guard that
578
+ exists to stop it never stopped it. Both read paths now refuse.
579
+
580
+ **A resumed run joins the trace it crashed inside.** `parentContext`
581
+ accepted only a live in-memory span, so a parent that had to survive a
582
+ process boundary could not be expressed. A run that crashed at iteration 12
583
+ and resumed produced two traces with different ids and no link. The run id
584
+ correlated them well enough to find both by query and not well enough to
585
+ see one waterfall — and for a replay fork, which mints a new run id, not
586
+ even that. Checkpoints now record a serialized span context, read back
587
+ _before_ the root span is minted because a parent can only be set at
588
+ creation. An all-zero or malformed id is refused rather than emitted, since
589
+ an exporter drops those silently and that would be worse than the
590
+ disconnected traces it replaces.
591
+
592
+ **A park can expire.** `runConfig.hitlParkTtlMs` writes an ABSOLUTE
593
+ deadline. Every timer in the SDK is an in-process `setTimeout` and the
594
+ park-record delay is deliberately `unref`'d, so nothing in memory outlives
595
+ a redeploy: a run parked for approval, the worker was replaced, nobody
596
+ answered, and the checkpoint stayed outstanding forever with every
597
+ approval-queue reader serving it. The run timeout cannot cover it — it is
598
+ checked between iterations and a park suspends mid-iteration, so a
599
+ long-lived process hard-stops the run immediately _after_ the human
600
+ approves, while across a restart the restored clock excludes parked time
601
+ entirely. `findPendingCheckpoint` skips an expired park, `listExpiredParks`
602
+ lets a host sweep, and `expire` records the expiry rather than deleting the
603
+ evidence.
604
+
605
+ **Two reserved statuses finally have producers.** `deriveRunStatus`
606
+ projects a run plus its park onto the session-layer `RunStatus`, which was
607
+ consumed by session derivation and handoff gating and produced by nothing —
608
+ `awaiting_hitl_resolution` in particular documented a "persisted wait after
609
+ a HITL timeout" for a timeout nothing could raise. `toWireRunStatus`
610
+ implements the domain→wire collapse that `WireRunStatus` had documented and
611
+ never had as code.
612
+
613
+ **An approval can be remembered, at a scope the approver chooses.**
614
+ Approving recorded nothing anywhere. `bash` is unconditionally
615
+ non-read-only and in no allowlist, so `bash: git status` re-prompted on
616
+ every batch forever, and the only escape was a blanket session grant
617
+ covering every destructive call. `approve_tools` now takes `remember`,
618
+ `toolGrantKeys(call)` offers a narrow (this exact invocation) and a wide
619
+ (this tool) key, and a batch fully covered by recorded grants skips the
620
+ park. Non-reuse stays the default — nothing is remembered unless an
621
+ explicit approval says so, and grants are run-scoped, never persisted.
622
+ Argument key order is normalised so the same call is not asked about twice.
623
+
624
+ **An eval case can fail on a gate, not just on an average.** The verdict
625
+ was one unweighted mean against one suite-wide threshold. At the default of
626
+ 1 the harness never reports a false pass, but a trajectory F1 and a graded
627
+ judge can essentially never reach 1 — so every real suite lowers it, and
628
+ every step down buys the deterministic scorers the same tolerance as the
629
+ fuzzy ones. At 0.75, trajectory 0 alongside three perfect scores averages
630
+ to 0.75 and reports **passed**. `Scorer.severity: 'gate'` fails the case
631
+ outright; `threshold` is per-scorer. `completionScorer` and
632
+ `containsScorer` ship as gates. An unavailable gate does not fail a case —
633
+ it did not judge the run, which is the inconclusive path.
634
+
635
+ **A provider's own retryable flag is listened to, and a plugin that cannot
636
+ enable is refused at install.** Retryability was derived solely from
637
+ namzu's code set, a second-hand inference that necessarily lags every new
638
+ failure shape a vendor invents; a flag declared anywhere on the cause chain
639
+ now decides, while the code still decides what the failure _is_. And the
640
+ plugin manifest accepted `skills` / `connectors` / `personas` with per-type
641
+ caps that enabling then refused wholesale — so a plugin shipping four tools
642
+ and one skill validated clean, installed clean, was persisted as
643
+ `installed`, and contributed zero tools. The refusal moved to load time,
644
+ with the enable-time check kept as a backstop that transitions the plugin
645
+ to `error` rather than leaving a status that says it is fine.
646
+
647
+ - 935b8f3: The two gaps that were deferred as needing their own design session.
648
+
649
+ **A question raised inside a tool is now durable, and the answer reaches
650
+ the tool that asked.** `ask_user_question` parked through the raw handler
651
+ under a synthetic `cp_question_<toolUseId>` id that was never written
652
+ anywhere. The checkpoint did not exist: nothing on disk said a human owed
653
+ this run an answer, the pending-checkpoint lookup could never return it,
654
+ and a remote host could not even _observe_ the question except through the
655
+ in-process callback. Kill the process while somebody is looking at the card
656
+ and the answer could never be applied — the restore path stripped the whole
657
+ assistant turn, discarding work that sibling tools in the same batch had
658
+ already finished, and re-billed the turn.
659
+
660
+ The park is now a real checkpoint, with `user_question_asked` /
661
+ `user_question_answered` on the event stream, `question.asked` /
662
+ `question.answered` on the SSE wire, and an `input-required` A2A status —
663
+ the same surfaces a tool-review park has always had.
664
+
665
+ The re-entry contract was the deferred half, and it turned out to reuse
666
+ machinery that already exists. A question checkpoint is written
667
+ mid-execution, so it holds the assistant turn with its `tool_use` blocks
668
+ unanswered — the same shape a tool-review park leaves. Re-executing that
669
+ batch is _how_ the asking tool gets re-entered; a carried-answer registry
670
+ is what makes the re-entry return the recorded answer instead of parking a
671
+ second time; and every sibling that already completed is answered from the
672
+ transcript by the crash-resume recovery, so nothing runs twice. An answer
673
+ that does not name a call in this turn is refused rather than delivered to
674
+ whichever tool now holds that slot.
675
+
676
+ **The egress policy has a boundary to be enforced at.** Two of its four
677
+ shapes were honourable nowhere: the container backend refused a host
678
+ allowlist outright because it had nothing to filter through, so `deny-all`
679
+ and `allow-all` were the whole spectrum — all or nothing.
680
+
681
+ `EgressProxy` enforces the other two. Matching has exactly two forms —
682
+ exact host, and `.example.com` for a domain and its subdomains — and
683
+ substring is deliberately not one of them: `host.includes(entry)` would
684
+ admit `example.com.attacker.net`, and plain suffix matching would admit
685
+ `notexample.com`. A policy that cannot be read denies, because an allowlist
686
+ that fails open is not an allowlist. A request addressed to the proxy
687
+ itself is refused rather than forwarded — found by a test that hung instead
688
+ of failing, which is exactly the shape that failure takes in production.
689
+
690
+ `Sandbox.setNetworkPolicy` narrows or widens a **live** sandbox, so "clone
691
+ with a token, then drop to deny-all before running untrusted build scripts"
692
+ is expressible; it was not, because the policy was frozen at provider
693
+ construction. A backend that cannot enforce it throws.
694
+
695
+ And `brokeredCredentials` settles where the token lives. Any credential the
696
+ agent needed to reach an allowed host had to be inside the sandbox, in the
697
+ environment, readable by the untrusted code it is meant to be isolated from
698
+ — via `/proc/self/environ`, or via a prompt injection that exfiltrates it
699
+ over the very egress the policy permits. The real value is now held
700
+ host-side and applied at the boundary, scoped per host: a credential
701
+ attached to every request is a credential handed to whichever host the
702
+ agent was talked into contacting.
703
+
704
+ One limit, stated rather than hidden: a credential cannot be injected into
705
+ a CONNECT tunnel, because reading those bytes would mean terminating TLS
706
+ with a CA the sandbox trusts — a strictly larger risk than the one being
707
+ mitigated. A workload that needs brokering speaks plain HTTP to the proxy
708
+ and lets it upgrade upstream. The allowlist is enforced on CONNECT either
709
+ way, since the target names the host in clear text.
710
+
711
+ - 935b8f3: Two findings from a fit-gap against another agent SDK.
712
+
713
+ **A tool veto that throws now denies.** namzu has several places that can
714
+ stop a run, and they disagreed on what happens when the check _itself_
715
+ throws: a content guardrail that threw blocked the run — with a comment
716
+ saying why, "safety is unknown" — while a tool veto that threw was skipped
717
+ and the call proceeded. The same policy inverted its security posture
718
+ depending on which surface it was written on.
719
+
720
+ An observer probe that throws is still skipped, and that asymmetry IS
721
+ deliberate: an observer was never asked a question, so it has no answer to
722
+ withhold, and taking a run down because a metrics handler crashed would be
723
+ the same mistake pointing the other way.
724
+
725
+ The exposure this trades against is real and is the one the guardrail
726
+ already accepted: a buggy veto can refuse every call. The refusal names the
727
+ probe, so it is diagnosable; a wrongly permitted destructive call is not
728
+ recoverable at all. `docs/sdk/architecture/safety.md` now states the rule
729
+ for all four surfaces in one table.
730
+
731
+ The old behaviour was pinned by a test that described it and never argued
732
+ for it, under a header pointing at a design document that had since been
733
+ frozen and removed — so the instruction to "update it first" could not be
734
+ followed, and the fail-open kept its ratified status with no surviving
735
+ justification. The pointer now names a document a reader can open.
736
+
737
+ **A truncated tool result says what it took with it.** The output budget
738
+ takes `output: string` only, so the rich channel was never bounded — and
739
+ when the text half truncated, the rich half was dropped with it, silently.
740
+ Dropping is right, since the preview is no longer the tool's own payload
741
+ and an image alongside it would be illustrating something the model can no
742
+ longer read. Doing it silently is not: the model saw a preview with no way
743
+ to know an image had ever existed, and reasoned as though the tool returned
744
+ text only. The result now names what went, so the agent can ask for a
745
+ smaller region instead of retrying the same call.
746
+
747
+ `maxToolContentBytes` caps the rich channel, and is **off by default** on
748
+ purpose. The right number depends on what a host's tools return and on the
749
+ model's own image budget; inventing one here would either break screenshot
750
+ workflows or be so generous it bounds nothing. Over the cap the channel is
751
+ refused whole rather than trimmed — half a base64 payload is not a smaller
752
+ image, it is a corrupt one.
753
+
754
+ - 935b8f3: Reclaim context by clearing stale tool output, before summarizing
755
+ destructively.
756
+
757
+ Compaction was all-or-nothing: once the threshold hit, every older message
758
+ became a summary and the agent's own reasoning — the decisions, the false
759
+ starts it learned from, the exact wording of a plan — was paraphrased away
760
+ with it. That is a heavy price for a context problem usually caused by
761
+ something much dumber: a handful of enormous tool outputs the agent already
762
+ read, took what it needed from, and moved past.
763
+
764
+ `clearStaleToolResults` replaces the OUTPUT of old, large tool results with
765
+ a short placeholder that names the tool and its original size, so a result
766
+ that turns out to still be needed is one tool call away rather than lost.
767
+ It is safe where trimming is not, because nothing moves — the `tool` message
768
+ keeps its position and its `toolCallId`, so `tool_use` ↔ `tool_result`
769
+ pairing is intact by construction.
770
+
771
+ It runs first in `runCompactionCheck`; if it gets the context back under
772
+ `triggerThreshold`, summarization is skipped entirely and the history stays
773
+ verbatim. New `CompactionConfig` fields: `clearToolResults` (default
774
+ `true`), `keepRecentToolResults` (3), `minToolResultCharsToClear` (1000),
775
+ `preserveToolResultsFrom`.
776
+
777
+ Never clears an error result (the error is what steers the next turn), the
778
+ most recent N results (still in use), or anything below the size floor
779
+ (the placeholder would cost as much). Image payloads are measured by their
780
+ base64 size — a screenshot is the largest thing a tool result can carry and
781
+ exactly the kind of output an agent reads once.
782
+
783
+ - 935b8f3: Wire up emergency crash-save, and correct the README's claim about it.
784
+
785
+ `EmergencySaveManager.attach()` had zero call sites: the handler that writes
786
+ `emergency/<runId>.json` was never installed, so `replay({ fromCheckpoint:
787
+ 'emergency' })` read a file nothing ever produced — while the README marketed
788
+ "Emergency save on signal" as a differentiator against six competitors and
789
+ stated "there is no reliance on the user remembering to catch signals; the
790
+ kernel does it."
791
+
792
+ `query()` now installs the handlers when you pass `emergencySave: true`, and
793
+ removes them when the run settles.
794
+
795
+ It is opt-in rather than automatic, which is a deliberate narrowing of the old
796
+ README claim. `attach()` calls `process.on('SIGINT' | 'SIGTERM' |
797
+ 'uncaughtException')` with handlers that `process.exit()`; a library must not
798
+ seize its host's termination path by default, and an API server has its own
799
+ drain sequence. The manager is also a singleton whose `attach` detaches
800
+ whoever held it before, so under concurrent runs an automatic attach would
801
+ silently make the last-started run the only one ever saved. Both READMEs now
802
+ say so.
803
+
804
+ The `namzu` CLI opts in — it owns its process end to end, so Ctrl-C mid-run
805
+ leaves a dump under `.namzu/emergency/` instead of losing the turn.
806
+
807
+ - 935b8f3: Five fixes where a subsystem reported more than it delivered.
808
+
809
+ **A sandbox tier now says what it actually enforces.** The local provider
810
+ reported `id = 'local'` / `name = 'Local Sandbox'` and logged at `info` at
811
+ every detected tier, but the tiers are not equivalent: one installs a
812
+ deny-default, deny-network profile; one unshares namespaces without
813
+ remounting anything, so the child still sees the whole host filesystem; and
814
+ one confines nothing at all. A host that deliberately turned isolation
815
+ **on** got a tier-dependent amount of it under one undifferentiated name,
816
+ and no guard, test or doc anywhere keyed on the weakest tier.
817
+
818
+ - `isolationOf(environment)` states per-tier what is enforced —
819
+ `filesystem`, `network`, `process` — deliberately pessimistic. The
820
+ namespace tier reports `filesystem: false`, because a private mount table
821
+ is not confinement.
822
+ - `sandbox.requireIsolation` (also `new LocalSandboxProvider(log, {…})`)
823
+ **throws** when the host cannot supply a control the caller named.
824
+ Refusing is the point: a control that is accepted and then not applied is
825
+ worse than one never offered, because the caller stops looking. Empty by
826
+ default, so best-effort callers are unaffected.
827
+ - Detection now runs the flags it will spawn under instead of checking that
828
+ a binary exists — a host with unprivileged user namespaces disabled
829
+ answers `unshare --version` happily and then fails every spawn. The
830
+ other platform's probe already ran its sandbox for real.
831
+ - The namespace tier also unshares the network, which it previously left
832
+ wide open while the other tier denied it unconditionally.
833
+ - Constructing at the unconfined tier logs a **warning** naming it as such.
834
+
835
+ **Compaction stopped measuring the context one turn late.** The provider's
836
+ prompt measurement describes the request as it was sent, so the assistant
837
+ message and every tool result the turn appended fell outside it — and the
838
+ reading was taken verbatim. Separately, the tool catalogue is assembled
839
+ apart from the message array and never entered the fallback estimate at
840
+ all; a 30-tool registry is easily 10-20k tokens of JSON Schema. Both errors
841
+ point the same way, under-count, so the trigger did not jitter around the
842
+ threshold — it sat systematically late, worst on the turns that grew the
843
+ context the most.
844
+
845
+ **A remote tool's schema keeps its shape.** `$ref` reached the converter's
846
+ permissive branch and became "anything": no type, no shape. Since that node
847
+ is inherently optional in Zod, a `$ref`'d field the server listed as
848
+ `required` stopped being enforced too — an empty payload validated clean and
849
+ was forwarded to the server instead of being rejected with the hint the
850
+ executor already builds. `$defs` + `$ref` is the default output of several
851
+ common schema generators, so a server that did everything right had its
852
+ main argument shown to the model as `{}`. Local pointers are now inlined
853
+ first (cycles cut at the repeat, dangling and non-local pointers left
854
+ permissive), `allOf` is flattened, and `pattern`, the length and range
855
+ bounds, `multipleOf` and the `email`/`uri`/`uuid`/`date-time` formats are
856
+ carried onto the converted node — shown to the model _and_ enforced. The
857
+ conversion is also depth-bounded: a remote schema is untrusted input.
858
+
859
+ **A declared return shape reaches the model, and a structured result is not
860
+ lost.** Servers publish `outputSchema` on a tool listing regardless of
861
+ negotiated protocol revision and it had no slot in the type, so the return
862
+ shape never reached the model at all. It is now carried verbatim —
863
+ shown, never validated — and appended to the description, since no
864
+ provider's tool format has a field for it. `ToolDefinition.outputSchema`
865
+ takes JSON Schema for the same reason. A server that answers with
866
+ `structuredContent` and omits the compatibility text block previously
867
+ produced an EMPTY tool result for a call that succeeded, with no diagnostic
868
+ anywhere; that payload is now serialized into the output, with the raw pair
869
+ available on `result.data`.
870
+
871
+ **A tool batch killed part-way through is resumed, not repeated.** Results
872
+ reach the history only when the whole batch settles, so a hard kill lost
873
+ everything that had already come back and the resumed run re-executed those
874
+ calls — for a `write_file` that is waste, for a payment or an email it is a
875
+ second one. Nothing new had to be recorded: the executor already awaits a
876
+ `tool_completed` per tool, inline, and the transcript already persists it.
877
+ `RunDiskStore.readCompletedTools()` reads it back and `executeBatch` accepts
878
+ those results, so an already-executed call is answered from the record
879
+ while the calls that never ran execute for the first time through the
880
+ ordinary executor — every guard and permission check still applies. The
881
+ discriminator is whether the transcript holds any completion for the turn:
882
+ a tool-review park records its checkpoint _before_ execution, so it has
883
+ none and keeps the existing repair, where re-deciding costs only a round
884
+ trip.
885
+
886
+ - 935b8f3: Show extensions the model call they fire around
887
+
888
+ `pre_llm_call` and `post_llm_call` fired directly beside the request and the reply and were handed neither — only a run id and an iteration number. An extension could observe THAT a call was happening and nothing about what it was, so a prompt audit, a redaction pass, or a per-tenant token ledger had no way to do its job from a hook.
889
+
890
+ `PluginHookContext` now carries `request` on `pre_llm_call` (`model`, `messages`, `toolNames`, `temperature`, `maxTokens`) and `response` on `post_llm_call` (`content`, `toolNames`, `finishReason`, `usage`). Both are projections rather than the wire objects, so driver-specific parameters do not become part of the plugin contract by accident, and tools appear as names because an audit asks which capabilities were offered, not what their schemas look like.
891
+
892
+ Both are read-only and frozen, and the messages are frozen copies. A hook that reshaped the request would change what every later hook sees, making the outcome depend on installation order — shaping a call stays with `prepareStep`, which has one writer by contract.
893
+
894
+ - 935b8f3: Hook order is declared, and a hook deadline stops holding the process open.
895
+
896
+ **Order was install order** — neither declared nor stable, since it depends
897
+ on when each plugin happened to be installed. That is fine for a hook that
898
+ only observes and wrong for one that decides: `executeHooks` short-circuits
899
+ on `skip` and `error`, so a hook that denies a dangerous command only gets
900
+ to deny it if it runs before whatever else stops the chain. A guard that
901
+ fires depending on installation history is not a guard.
902
+
903
+ `PluginHookDefinition.priority` — lower runs first, default `100`, ties
904
+ keeping registration order so a plugin that sets nothing behaves exactly as
905
+ before. Convention: guards below 100, observers above. `post_*` hooks still
906
+ unwind, so a guard at priority 1 runs first on `pre_tool_use` and last on
907
+ `post_tool_use` — the wrapping order a guard needs.
908
+
909
+ **The deadline timer was never cleared.** `setTimeout` was armed per hook
910
+ invocation and left running after the hook resolved, and an armed timer
911
+ keeps the Node event loop alive. Hooks fire on every tool call and every
912
+ model call, so a run of twenty tool calls left twenty live timers and the
913
+ process could not exit until the last one expired. Nothing failed — it just
914
+ hung, for up to the timeout, every time.
915
+
916
+ **`PluginHookContext.signal`** aborts when that deadline expires. The
917
+ runtime stops waiting on a slow hook either way, but without a signal the
918
+ hook never learns it was abandoned: a request inside it keeps a socket open
919
+ and its eventual result is written into a run that moved on.
920
+
921
+ **`registerHook(pluginId, hook)`** attaches a hook without installing a
922
+ plugin from disk. Registration was reachable only through `enable()`, which
923
+ loads a manifest and imports modules by path, so a host that wanted one
924
+ in-process guard had to lay out a plugin directory to get it — and this
925
+ class's own tests were reaching into a private map to work around it,
926
+ constructing entries the real path would never produce.
927
+
928
+ - 935b8f3: A retried invocation can be deduplicated
929
+
930
+ A request goes out, the connection drops, the client retries. Without a key that retry is a second full run — a second set of model calls, and a second set of whatever the tools did. The invocation lock does not help: refusing the retry with `ConcurrentInvocationError` is not what the caller wanted either, because they wanted the answer.
931
+
932
+ `AgentRunConfig.idempotencyKey` makes a duplicate arriving while the first is still running await it and receive its result — the error included, because both callers asked the same question once and telling one of them something different would make the key a lie.
933
+
934
+ In-flight only. A retry that arrives after the first has settled runs again: keeping the answer would turn deduplication into caching, and how stale an answer may be is the host's judgement, not the SDK's. Instance-scoped, like the lock — deduplicating across processes needs somewhere durable to record the key, which is a store the host owns.
935
+
936
+ - 935b8f3: Widen the message model to content blocks: multimodal tool results, `is_error`,
937
+ and reasoning replay.
938
+
939
+ `ToolMessage.content` was `string` and `AssistantMessage` had no slot for
940
+ reasoning, so three separate things died at the provider boundary. Doing them
941
+ as one migration is deliberate — all three need the same widening, and every
942
+ stored transcript, checkpoint and `messages.json` is written in the narrow
943
+ shape, so the cost only grows.
944
+
945
+ **Tool results can carry non-text content.** `ToolResultContent` is
946
+ `string | ToolResultBlock[]`, where a block is text, image or document. String
947
+ stays first-class: the common case is unchanged and every existing tool and
948
+ driver compiles untouched. `@namzu/computer-use`'s `screenshot` returned
949
+ ~400 KB–2.7 MB of base64 **as text** — roughly 100k–670k tokens of characters
950
+ no model can decode — so computer use was effectively non-functional; it now
951
+ returns an image block with a short textual description. MCP `image` and
952
+ inline `resource` blocks are passed through instead of being filtered out.
953
+
954
+ **Failures are marked on the wire.** The executor computed `isError`, routed it
955
+ to the SSE bridge, the A2A bridge and the TUI, then dropped it at the provider
956
+ boundary — so the model's trained tool-failure recovery never fired. The
957
+ Anthropic driver now sends `is_error: true`, and the value survives the
958
+ executor's result tuple, which previously narrowed to `{toolCallId, output}`
959
+ before the message was built.
960
+
961
+ **Reasoning is representable and replayed verbatim.** `AssistantMessage.reasoning`
962
+ holds opaque `ReasoningBlock`s (thinking / redacted, with signature or encrypted
963
+ payload). The Anthropic driver used to rebuild every assistant turn as
964
+ `[text?, ...tool_use]` — precisely the pattern the verbatim-echo contract
965
+ prohibits when a `tool_result` follows — and now emits stored reasoning blocks
966
+ first, signature intact.
967
+
968
+ Drivers that cannot express non-text tool results (`@namzu/openai`,
969
+ `@namzu/ollama`) degrade through `toolResultToText`, which renders an explicit
970
+ `[image: …]` placeholder rather than dumping base64 or silently dropping it.
971
+
972
+ This is the outbound half. The Anthropic driver does not yet parse thinking
973
+ blocks out of the stream and `ChatCompletionParams` has no `thinking` field,
974
+ so `reasoning` is populated only when a caller supplies it.
975
+
976
+ - 935b8f3: Make `MockLLMProvider` a scriptable test model that can emit tool calls.
977
+
978
+ The mock accepted `{ model, responseText, responseDelayMs }` and emitted 8-char
979
+ text slices. It never yielded `delta.toolCalls`, and `MOCK_CAPABILITIES`
980
+ declared `supportsTools: false`, so capability negotiation stripped the tool
981
+ surface before a request was even built. A consumer writing a custom tool had
982
+ no supported way to test that the agent loop calls it, that its error string
983
+ comes back as a `tool_result`, or that the model retries — and namzu's own
984
+ maintainers hand-rolled **eight** `implements LLMProvider` fakes across seven
985
+ test files to work around it, each re-implementing the delta bucketing and
986
+ `toolCallEnd` framing that `streamProviderTurn` exists to hide.
987
+
988
+ `MockProviderConfig` now takes `turns: MockTurn[]`, where a turn carries text,
989
+ tool calls, a finish reason, usage, and failure injection. Tool calls are
990
+ emitted with the frame sequence a real driver produces — per-tool `index`, id
991
+ and name first, then argument fragments, then the block-close signal — so a
992
+ test exercises the real consumer path instead of a shortcut through it.
993
+
994
+ - `truncateArguments` reproduces a tool call cut off mid-JSON at `max_tokens`.
995
+ - `error` fails the request with a status (for retry tests);
996
+ `throwAfterChunks` fails mid-stream (for recovery tests).
997
+ - `nextTurn(params, i)` decides each turn from the request that triggered it;
998
+ `onRequest` and `provider.requests` capture what the runtime actually sent,
999
+ so a test can assert on `tools`, `toolChoice` or `cacheControl`.
1000
+ - A script shorter than the run repeats its last turn, so a loop bug reads as
1001
+ repetition rather than an exhausted-script crash.
1002
+ - `supportsTools` / `supportsFunctionCalling` are now `true`.
1003
+
1004
+ The old `responseText` shorthand still works and becomes a one-turn script.
1005
+
1006
+ - 935b8f3: Parse reasoning out of the stream, and let a run request extended thinking.
1007
+
1008
+ This completes the reasoning work: the previous release added storage and
1009
+ verbatim replay, but nothing populated it. `StreamChunk.delta` carried only
1010
+ `content` and `toolCalls`, so the Anthropic driver's `thinking_delta` and
1011
+ `signature_delta` events fell through its `default: // ignore` — the blocks
1012
+ could not be captured even in principle. Two consequences: the verbatim-echo
1013
+ contract was unsatisfiable in practice, and a streaming UI showed a
1014
+ multi-second stall with zero events while the model was demonstrably working.
1015
+
1016
+ - `StreamChunk.delta.reasoning` carries fragments bucketed by block index,
1017
+ exactly like `toolCalls[].index`, closed by `done`.
1018
+ - `streamProviderTurn` accumulates them and attaches the finished blocks to
1019
+ the response in **stream-index order**, not arrival order — a provider may
1020
+ interleave blocks, and the echo contract is about the original ordering.
1021
+ - New `reasoning_started` / `reasoning_delta` / `reasoning_completed` run
1022
+ events, wire-mapped as `reasoning.*`. The delta is ephemeral, so the
1023
+ transcript records the completed block rather than every fragment.
1024
+ - The Anthropic driver handles `content_block_start` for
1025
+ `thinking`/`redacted_thinking`, forwards `thinking_delta` and
1026
+ `signature_delta`, and closes the block on `content_block_stop`.
1027
+ - `AgentRunConfig.thinking` (`ThinkingConfig`) is forwarded on every model
1028
+ call. The Anthropic driver maps it to `thinking` and **omits
1029
+ temperature/top_p/top_k while it is enabled**, because the API rejects them
1030
+ together — sending a request known to 400 is worse than dropping a sampling
1031
+ knob the caller did not prioritise.
1032
+
1033
+ Reasoning rides on the assistant message it belongs to, so the replay contract
1034
+ holds automatically: trimming or compacting that message takes its thinking
1035
+ blocks with it, and no separate atomicity rule is needed in `findSafeTrimIndex`.
1036
+
1037
+ - 935b8f3: Add a provider failure taxonomy and retry transient model-call failures.
1038
+
1039
+ No driver in the estate retried anything: a single `429`, `503` or dropped
1040
+ socket terminated the run. Nor could one be added, because every driver threw
1041
+ its vendor SDK's raw error and the runtime had no way to tell a rate limit
1042
+ from a malformed request — classification is the substrate a retry policy
1043
+ stands on.
1044
+
1045
+ `ProviderError` gives failures a `code` (`rate_limit`, `overloaded`,
1046
+ `server_error`, `timeout`, `network`, `auth`, `invalid_request`,
1047
+ `context_length_exceeded`, `content_filter`, `not_found`, `unknown`), a
1048
+ `retryable` flag, the HTTP `status`, and a server-directed `retryAfterMs`
1049
+ parsed from `Retry-After` (both delta-seconds and HTTP-date forms).
1050
+ `classifyProviderError` derives it from status, then transport errno, then
1051
+ message text — so a window overflow arriving as a `400` is filed as
1052
+ `context_length_exceeded` rather than a generic invalid request, because the
1053
+ caller can act on one and not the other.
1054
+
1055
+ `withProviderRetry` wraps any `LLMProvider` with exponential backoff and full
1056
+ jitter, honouring `Retry-After` up to a sanity cap. It retries **only before
1057
+ the first content chunk**: once a delta has been yielded the consumer has
1058
+ already emitted `text_delta` events, so restarting would duplicate output.
1059
+ Aborts propagate untouched, so a Stop still settles the run as `cancelled`.
1060
+
1061
+ `query()` wraps its provider by default; pass `retry: false` to opt out, or a
1062
+ partial config to tune it. The wrapper is transparent to `id`, `name` and
1063
+ `capabilities`, so capability negotiation is unaffected.
1064
+
1065
+ - 935b8f3: Make compaction actually fire, and make it observable.
1066
+
1067
+ The trigger divided the current context size by `runConfig.tokenBudget` whenever
1068
+ `contextWindowTokens` was absent — which was always, since nothing in the estate
1069
+ ever set it. Those are different quantities: `tokenBudget` is a cumulative spend
1070
+ cap, and comparing a live window against it is self-defeating, because the guard
1071
+ force-finalizes at 0.9x that number while compaction needs 0.7x of it. With the
1072
+ shipped CLI's `tokenBudget: 1_000_000` the trigger sat at ~700k. The entire
1073
+ subsystem — working state, extractor, serializer, dangling repair, verifier —
1074
+ was armed and never fired.
1075
+
1076
+ - The divisor is now always a context **window**: `contextWindowTokens` when the
1077
+ host sets one, otherwise resolved from the model id via a new
1078
+ `resolveContextWindow` / `lookupContextWindow`, otherwise a conservative
1079
+ 128k default. `tokenBudget` is never the divisor.
1080
+ - Context size prefers the provider's own `promptTokens` from the last turn — a
1081
+ measurement that includes tool schemas, system blocks and image tokens — over
1082
+ the chars/4 heuristic, which remains the fallback before the first turn
1083
+ reports. `RunPersistence.recordTurnUsage()` records it; side-channel calls
1084
+ keep using `accumulateUsage()` so they cannot corrupt the signal.
1085
+ - Two guards (the thrash guard and prior-summary replacement) were gated behind
1086
+ `contextWindowTokens != null` to preserve the legacy path byte-for-byte. That
1087
+ path's actual behavior was "never fires", so the gates are removed — otherwise
1088
+ a consumer that now compacts would accumulate one redundant summary per pass.
1089
+ - New `compaction_completed` run event (wire: `compaction.completed`) carrying
1090
+ before/after message counts and token sizes, whether the size was measured or
1091
+ estimated, and which window was used. Compaction deletes history
1092
+ irrecoverably and previously emitted nothing at all.
1093
+
1094
+ - 935b8f3: Let `MockLLMProvider` declare capabilities and fail mid-tool-arguments.
1095
+
1096
+ Two small additions that let the scriptable mock absorb the last of the
1097
+ hand-rolled test providers:
1098
+
1099
+ - `capabilities` overrides the declaration for one instance. Capability
1100
+ negotiation degrades a run when a driver says it cannot do something, and
1101
+ testing that path means being able to _say_ it — a fixed registry-level
1102
+ declaration cannot express "a driver with no vision".
1103
+ - `rawArguments` emits a raw string instead of serializing `args`, and
1104
+ `throwAfterArguments` throws mid-tool-block. Together they script a provider
1105
+ going idle while streaming tool JSON, which is precisely the failure the
1106
+ truncated-tool-input recovery path exists for — otherwise that path can only
1107
+ be tested by hand-rolling a provider, which is what everyone was doing.
1108
+
1109
+ Six of the eight `implements LLMProvider` fakes across the test suite are now
1110
+ gone. The two that remain are in `registry.test.ts`, which checks that the
1111
+ registry accepts arbitrary provider _constructors_; collapsing those would
1112
+ defeat what they test.
1113
+
1114
+ - 935b8f3: Persisted state carries a schema version, and a record from the future is
1115
+ refused instead of half-read.
1116
+
1117
+ Every read from disk was `JSON.parse(raw) as T` — an unchecked cast with no
1118
+ idea which version of the shape it was looking at. Three things followed,
1119
+ all of them silent:
1120
+
1121
+ - A record written by an **older** build was read as the current shape.
1122
+ Fields added since arrived as `undefined` and flowed into the runtime as
1123
+ though they had been there.
1124
+ - A record written by a **newer** build was read by an older one, which
1125
+ understood some fields and dropped the rest. Write it back and the rest
1126
+ are gone — the only one of these that destroys data.
1127
+ - None of it produced an error, a warning, or a log line. A resumed session
1128
+ that quietly lost half its state looked exactly like one that never had
1129
+ it.
1130
+
1131
+ The version is stamped as a field on the record rather than wrapping it in
1132
+ an envelope, so **every file already on disk stays readable**: a record with
1133
+ no stamp _is_ version 1, which is exactly what those files are.
1134
+
1135
+ - `defineSchema` / `stamp` / `migrate` in `store/schema.ts`, adopted by the
1136
+ session, thread, run, task and memory disk stores. Each store versions its
1137
+ on-disk format as a unit, so no call site carries schema plumbing.
1138
+ - A record from a version this build does not understand throws
1139
+ `SchemaVersionError` naming what it found and what is supported. Refusing
1140
+ is recoverable by upgrading; a partial read that gets written back is not.
1141
+ - A gap in the migration chain is rejected when the schema is **declared**,
1142
+ not when a stale file finally shows up — a gap found at read time is found
1143
+ in production, by a user whose session will not open.
1144
+ - Each line of the append-only message log carries its own stamp: such a log
1145
+ is written by many builds over its lifetime and its lines can legitimately
1146
+ differ in version. A line the build cannot read is refused rather than
1147
+ skipped, because silently dropping one hands the model a conversation with
1148
+ a hole in it.
1149
+
1150
+ Known limitation, stated rather than papered over: a file whose top level is
1151
+ an array has nowhere to put a stamp that survives `JSON.stringify`, so it
1152
+ stays unversioned. A store that needs to migrate one has to move it under an
1153
+ object first.
1154
+
1155
+ - 935b8f3: `prepareStep` — shape each step before the model is called.
1156
+
1157
+ `stopWhen` let a run decide TO STOP from what its steps produced. This is
1158
+ the other half: deciding how the next step should look. Without it, the
1159
+ tool surface and the model were fixed at `query()` time, so a phased agent
1160
+ — research with search tools, write with file tools, verify with a cheaper
1161
+ model — had to be built as three separate runs, each starting blind to the
1162
+ last one's context.
1163
+
1164
+ The hook receives the run id, the step number, the full message history and
1165
+ every completed `StepResult`, and may return `activeTools`, `model`,
1166
+ `system` (one-step guidance), `temperature` and `maxResponseTokens`. Any
1167
+ omitted field keeps the run's configured value.
1168
+
1169
+ - `system` guidance is appended to the REQUEST, never pushed onto the run's
1170
+ history — otherwise a long run accumulates one stale phase instruction
1171
+ per iteration.
1172
+ - `activeTools` does NOT touch `tool_choice`. Anthropic has no
1173
+ `allowed_tools`, and moving `tool_choice` invalidates cached MESSAGE
1174
+ blocks as well — a strictly worse trade for the same effect. Narrowing
1175
+ still costs the prompt-cache prefix, since tools render at position 0;
1176
+ that is inherent, and worth paying at a real phase boundary rather than
1177
+ every step.
1178
+ - Unregistered tool names are dropped with a warning: a phase list that
1179
+ outlives a tool rename should narrow the surface, not kill the agent
1180
+ mid-run.
1181
+ - Fails OPEN. A throwing hook leaves the step with the run's configuration
1182
+ — same reasoning as `stopWhen`, and deliberately opposite to a guardrail,
1183
+ because nothing unsafe gets through when step shaping is skipped.
1184
+
1185
+ - 935b8f3: Give runtime failures a code a host can branch on.
1186
+
1187
+ `PlatformError` was declared and never constructed — a shape nothing
1188
+ produced and nothing consumed — while the runtime threw bare `Error`
1189
+ everywhere. A caller catching a failure from `query()` could not tell "the
1190
+ model rate-limited us" from "the run was configured wrong" from "that
1191
+ checkpoint does not exist"; matching on message text was the only recourse,
1192
+ and message text is not an interface.
1193
+
1194
+ - `NamzuError` implements `PlatformError` and extends `Error`, so it still
1195
+ behaves like one everywhere that only knows about `Error` — stack,
1196
+ `instanceof`, `cause`.
1197
+ - `NamzuErrorCode` stays small on purpose: each member exists because a
1198
+ caller does something different about it (`invalid_config`,
1199
+ `provider_error`, `tool_error`, `not_found`, `plugin_error`,
1200
+ `capability_unavailable`, `storage_error`, `unknown`).
1201
+ - `toPlatformError(unknown)` normalizes ANYTHING thrown into the declared
1202
+ shape — a `NamzuError`, a `ProviderError`, a plain `Error` from a
1203
+ dependency, or a thrown string. Without it, "handle errors from the SDK"
1204
+ means writing the same `instanceof` ladder in every caller. A
1205
+ `ProviderError` keeps its own classification (its code lands in
1206
+ `details.providerCode` and its `retryable` verdict is preserved, not
1207
+ recomputed).
1208
+
1209
+ Adopted at the runtime sites a host would actually branch on: strict
1210
+ capability failures, provider stream errors, checkpoint-not-found, and
1211
+ plugin hook errors. Exhaustiveness guards stay plain `Error` — those are
1212
+ programmer bugs, not conditions to handle.
1213
+
1214
+ - 935b8f3: Step shaping composes
1215
+
1216
+ `prepareStep` was a single slot: enough for one concern and no help with two. A host with a per-tenant system prefix _and_ a cost-based model downgrade had to hand-compose them into one callback, which puts the ordering in the host's own code where nothing can see it and makes each concern's failure the other's problem.
1217
+
1218
+ It now accepts an array. Stages run in **declaration order** — not registration order, and that distinction is the whole reason this is safe where a plugin-style fan-out would not be: the author writes the order down, so "who wins" is a line of their code rather than an accident of install history. Each stage sees what the ones before it decided through `context.prepared`, which is how a later stage refines an earlier one instead of guessing at it.
1219
+
1220
+ A stage that throws is skipped and the rest still run, because one broken concern must not silently disable the others it was declared beside. A single function behaves exactly as before.
1221
+
1222
+ - 935b8f3: Add input/output guardrails to `query()`.
1223
+
1224
+ namzu had three gates on tool calls — probe veto, `VerificationGate`, HITL
1225
+ review — and all three point the same way: they protect the world from the
1226
+ agent. Nothing protected the user from the agent's own output, and nothing
1227
+ looked at the prompt before a run started.
1228
+
1229
+ - `inputGuardrails` run before the first model call. A block settles the run
1230
+ as `input_guardrail` having spent nothing.
1231
+ - `outputGuardrails` run against the final result. A block settles as
1232
+ `output_guardrail`; a `rewrite` replaces the text, so a redaction policy
1233
+ can clean an answer instead of discarding it. Rewrites compose.
1234
+ - A guardrail that throws **fails closed** — deliberately the opposite of
1235
+ `stopWhen`. A broken halt predicate should not kill a healthy run; a broken
1236
+ safety check must not wave content through.
1237
+ - New `guardrail_triggered` run event (wire: `guardrail.triggered`).
1238
+ - Presets: `secretRedactionGuardrail` (prefix-anchored credential patterns,
1239
+ redact or block) and `promptInjectionGuardrail` (partial, by design).
1240
+
1241
+ These gate the result, not the stream: `text_delta` events have already
1242
+ reached the host, so a rewrite arrives as a correction alongside the event.
1243
+
1244
+ - 935b8f3: Make the loop-control surface reachable from the Agent classes, and stop
1245
+ gating environment context on built-in tool names.
1246
+
1247
+ Found by auditing the one application in the estate that actually consumes
1248
+ `@namzu/sdk`, rather than by reading the SDK again.
1249
+
1250
+ - **`ReactiveAgent` forwarded none of the loop-control seams.** It is what
1251
+ `AgentManager` spawns and what real applications call, and it passed only
1252
+ provider/tools/runConfig — so `toolTimeoutMs`, `retry`, `emergencySave`,
1253
+ `stopWhen`, `onStepFinish`, `prepareStep`, `structuredOutput`,
1254
+ guardrails, `repairToolCall`, `maxToolConcurrency`, `maxToolOutputChars`,
1255
+ `resumeHandler` and `checkpointStore` were reachable only by dropping to
1256
+ `query()` and rebuilding the run wiring by hand. A feature a consumer
1257
+ cannot reach is a feature that does not exist for them.
1258
+
1259
+ - **The `<env>` block keyed on four hardcoded tool names.** A host
1260
+ registering a filesystem tool called `read_file` — declaring
1261
+ `category: 'filesystem'` and `permissions: ['file_read']` correctly — got
1262
+ no environment context at all, so the model was never told its working
1263
+ directory and the host hand-encoded paths into its system prompt. The
1264
+ gate now reads what a tool declares, keeping the name set as a fallback.
1265
+
1266
+ - **Providers were handed the run's live message array.** `runMgr.messages`
1267
+ is the live array and the loop pushes onto it after the call returns, so
1268
+ a driver that retained its input — to log it, cache it, or replay it on
1269
+ retry — watched it grow new turns underneath. A capture provider in the
1270
+ estate recorded every turn as identical to the last for exactly this
1271
+ reason. The array is now copied at the provider boundary.
1272
+
1273
+ - 935b8f3: Five places where namzu gave up, or claimed to recover, too early.
1274
+
1275
+ **A transient failure now pauses instead of failing.** A 503 that survived
1276
+ every in-turn recovery — retry with jitter, the one-shot compaction relief,
1277
+ mid-stream salvage — settled the run as `failed`, identically to a bad API
1278
+ key. The host could not tell them apart, and recovering meant knowing about
1279
+ checkpoints and driving replay itself. The state was never the problem:
1280
+ checkpoints are written every iteration by default and the failed run is
1281
+ persisted with full messages. Only the settle and the signal were missing.
1282
+
1283
+ A retryable failure with a checkpoint to resume from now emits `run_paused`
1284
+ naming that checkpoint, leaves the span OK rather than ERROR, and sets
1285
+ `stopReason: 'paused'`. Both conditions are required — pausing on a
1286
+ permanent error would invite a resume that cannot work, and pausing with
1287
+ nowhere to resume from produces a run nobody can ever pick up.
1288
+
1289
+ **A forced compaction pass can no longer decline to do anything.** A forced
1290
+ pass runs because the provider _rejected_ the prompt as too long, and two
1291
+ things let it treat that as advisory. It re-applied the chars/4 estimate
1292
+ after clearing stale tool results — the estimate the provider had just
1293
+ refuted — and returned early if that said the context was fine. And relief
1294
+ reported success on ANY positive shed, so clearing one short result counted
1295
+ and the retry burned a whole model call to be told the same thing. The
1296
+ early return is now force-gated, and a shed has to clear a floor (a
1297
+ fraction of the prompt, at least a couple of thousand characters) to count.
1298
+
1299
+ Separately, the relief latch is per **stuck point**, not per run. It exists
1300
+ to stop a second overflow immediately after a successful compaction from
1301
+ looping; as a run-scoped flag it meant one relief at iteration 3 disarmed
1302
+ the mechanism for the rest of the run, leaving iteration 40 to die with
1303
+ obvious moves left. It is now cleared by a turn that actually succeeded.
1304
+
1305
+ **An eval case can no longer hang the suite.** `executeCase` was a bare
1306
+ await, so a `run` closure that never settled blocked its worker and
1307
+ `runExperiment` never returned — no report, no partial results, nothing to
1308
+ read. `ExperimentConfig.timeoutMs` bounds a case and hands `run` an
1309
+ `AbortSignal` as a third argument; a timed-out case is reported and the
1310
+ suite continues, exactly like a case that threw, with its real elapsed time
1311
+ rather than zero. Unset means no deadline, which is today's behaviour. The
1312
+ documented path already inherits deadlines from the runtime it drives; this
1313
+ covers what those cannot see — a closure that does not go through
1314
+ `query()`, and a mid-iteration provider stall.
1315
+
1316
+ **A malformed content block is named, not smuggled.** One driver built an
1317
+ image block by calling `String()` on whatever `data` and `mediaType`
1318
+ happened to be, behind only a truthiness check — so a non-string `data`
1319
+ became the literal `"[object Object]"` as the base64 payload, and the wire
1320
+ rejected the whole request with nothing naming the block at fault. That is
1321
+ reachable: a remote tool result is cast without validation on the way in.
1322
+ It now type- and media-type-guards and degrades to a named placeholder,
1323
+ matching the sibling driver that already did, and without inlining the
1324
+ payload it refused to send.
1325
+
1326
+ **Failures have somewhere to grow remediation.** A stale API key surfaced
1327
+ as whatever prose the vendor SDK happened to write: no id to grep in logs,
1328
+ no instruction on what to change, and no growth point — a newly-observed
1329
+ failure shape could only be given curated copy by editing the classifier.
1330
+ `explainError` adds an ordered, id-keyed rule layer matching on
1331
+ **structural** signals (code, status, an explicit hint) rather than
1332
+ volatile vendor prose. `run_failed` carries the result as `explanation`;
1333
+ `withHint(err, '…')` lets a throw site attach what only it knows, and
1334
+ outranks every generic rule. It returns `null` when no rule claims the
1335
+ failure — inventing advice for something uncharacterised is worse than
1336
+ saying nothing, because it sends the reader somewhere specific and wrong.
1337
+ The container backend's readiness, port-mapping and worker-fetch failures
1338
+ now carry hints.
1339
+
1340
+ - 935b8f3: A context overflow now shortens the prompt and retries instead of killing
1341
+ the run.
1342
+
1343
+ `context_length_exceeded` was classified precisely and consumed by nothing.
1344
+ It is correctly non-retryable — resending the identical prompt cannot help
1345
+ — so the run died, holding a compaction subsystem that could have made
1346
+ room.
1347
+
1348
+ This is not a hypothetical failure. Compaction fires on an ESTIMATE of how
1349
+ full the context is, and an estimate can read low: a run carrying images,
1350
+ or text in a language the chars-per-token ratio does not fit, reaches the
1351
+ real window while still looking comfortable. The provider then reports
1352
+ exactly what is wrong, which is stronger evidence than the estimate that
1353
+ was just proven wrong.
1354
+
1355
+ - `relieveOverflow` forces a compaction pass, bypassing the threshold.
1356
+ - It reports whether anything was actually shed. When nothing was — no
1357
+ compaction configured, or nothing left to compact — the error proceeds,
1358
+ because retrying would send the same prompt and reach the same error.
1359
+ - Relief is attempted once per run. A second overflow after a successful
1360
+ compaction means the prompt is irreducible, and looping would burn the
1361
+ budget to arrive at the same place.
1362
+
1363
+ - 935b8f3: A message can be pinned against eviction
1364
+
1365
+ Everything a run protected from compaction was protected by **position**: the leading system messages, the working-memory slot, the last N turns, the most recent tool results. A standing constraint stated in the middle of a conversation — "the account id is 4471; never bill a different one" — therefore aged out at the same rate as chatter. No positional rule could express it, and the working-memory slot could not either: it is host-rendered each turn and does not know what the user said.
1366
+
1367
+ `retain: true` on a message says it directly. The summarization rebuild carries pinned turns over verbatim, in order, between the summary and the recent window, and the in-place tool-result clearing pass leaves their content alone — clearing keeps the message and replaces its content, which is exactly the loss the marker was asked to prevent.
1368
+
1369
+ Protection is transitive across a tool pair: pinning a `tool_result` pins the assistant turn that issued the call, and pinning that turn pins every result answering it. Half a pair is not a smaller history, it is one the provider rejects.
1370
+
1371
+ Nothing caps how much may be pinned. Pinned turns are exempt from the reclaim that keeps a long run alive, so this is a budget the setter spends — a cap would have to guess which pin mattered, and dropping the wrong one quietly is worse than a run that overflows in the open.
1372
+
1373
+ - 935b8f3: Add structured final output — and fix two bugs it uncovered on the tool-result
1374
+ wire path.
1375
+
1376
+ **Structured output.** Both leaf pieces already shipped and neither was
1377
+ reachable: `createStructuredOutputTool` is excluded from `getBuiltinTools()`
1378
+ because it needs a schema, and `StructuredOutputConfig` was referenced by
1379
+ exactly one non-test line — the barrel re-export. A host needing
1380
+ `{verdict, findings}` from an agent that also uses tools had to register the
1381
+ tool by hand and hope: nothing forced the call, nothing stopped the loop when
1382
+ it came, and a schema mismatch surfaced as a `ZodError` _after_ the run had
1383
+ paid for itself.
1384
+
1385
+ `query({ structuredOutput: { schema } })` registers the tool **from iteration
1386
+ zero** — tools render at prefix position 0, so late injection would invalidate
1387
+ the prompt cache for the rest of the run — validates the call, lands the parsed
1388
+ value on `Run.structuredOutput`, and ends the run there rather than paying for
1389
+ another turn that would only restate it. A model that answers in prose is
1390
+ re-prompted, bounded by `maxRetries` (default 2), after which the run settles
1391
+ with the new `StopReason: 'structured_output_failed'` instead of grinding
1392
+ against `maxIterations`.
1393
+
1394
+ **Two bugs found while testing it**, both on the path between what a tool
1395
+ returns and what reaches the provider, and both introduced by the content-block
1396
+ migration:
1397
+
1398
+ - `ToolExecutor`'s final return omitted `isError`, so a failed tool was never
1399
+ marked as failed on the message and `is_error` could not reach the wire.
1400
+ - The executor's local `result` was typed as a narrowed literal that dropped
1401
+ `content`, so a tool returning an image block had it discarded before the
1402
+ mapper built to carry it ever saw it.
1403
+
1404
+ The mapper tests passed throughout because they set those fields by hand. A new
1405
+ suite covers the executor→message seam directly, which is where both lived.
1406
+
1407
+ - 935b8f3: A fan-out can now declare what a failed child means for its siblings.
1408
+
1409
+ The primitive to stop them already existed — every child holds an abort
1410
+ controller chained to the parent's, and `AgentManager.cancel` uses it — but
1411
+ nothing connected a failure to it. A supervisor that fanned out five tasks
1412
+ and watched one die had no way to say the other four were now pointless:
1413
+ they ran to completion, spending budget on work whose premise had gone.
1414
+
1415
+ `LocalTaskGateway` takes a `SiblingFailurePolicy`:
1416
+
1417
+ - `'continue'` — the default, and deliberately unchanged. Partial results
1418
+ are usually worth having, and cancelling healthy siblings on any failure
1419
+ would let one flaky child waste four good ones.
1420
+ - `'cancel-siblings'` — for a fan-out whose parts only mean something
1421
+ together, where one dead leg makes the rest an answer nobody can use.
1422
+
1423
+ Failure is judged from the result as well as the task state. A child whose
1424
+ spawn machinery threw lands in state `'failed'`, but a child that RAN and
1425
+ returned `status: 'failed'` is marked completed and carries the failure in
1426
+ its result — so reading only the state would have caught the exceptional
1427
+ case and missed the ordinary one.
1428
+
1429
+ - 935b8f3: Cap model-visible tool output, and spill the overflow instead of losing it.
1430
+
1431
+ Nothing bounded tool output. `read` returned a whole file when `limit` was
1432
+ omitted, `bash` allowed a 100 MB buffer, and the MCP adapter joined every text
1433
+ block uncapped — so a `read` of a 2 MB lockfile became ~500k tokens in one
1434
+ `tool_result`, the provider rejected the request, and with no retry the run
1435
+ died with everything lost. The one existing reducer, `compressShellOutput`,
1436
+ early-returns for any tool whose category is not `shell` and has no absolute
1437
+ size cap at all.
1438
+
1439
+ - `maxToolOutputChars` (default 40k ≈ 10k tokens), overridable per run. Output
1440
+ over budget is written to `<runDir>/tool-output/<toolUseId>.txt` and replaced
1441
+ with a head+tail preview naming the path. Spilling beats truncating on every
1442
+ axis: nothing is lost, tokens are paid only if the agent decides the rest is
1443
+ worth re-reading, and retrieval uses `read`/`grep` — tools it already has.
1444
+ Without a run directory it degrades to middle-elision rather than being
1445
+ unbounded.
1446
+ - `read` defaults to a 2000-line window instead of the entire file, and any
1447
+ partial read now ends with a `[PARTIAL view — lines X-Y of Z]` notice naming
1448
+ the exact next call. A truncated read used to be indistinguishable from a
1449
+ short file, so the agent reasoned about a fragment as if it were the whole
1450
+ thing.
1451
+ - `bash` surfaces the sandbox's `stdoutTruncated` / `stderrTruncated` flags,
1452
+ which were computed by the backend and dropped at the `SandboxExecResult`
1453
+ type boundary — the model saw a complete-looking result that had silently
1454
+ lost its tail. Both flags are now part of the contract, along with
1455
+ `SandboxExecOptions.signal` so a cancelled run can reach the process.
1456
+ - `tool_completed` carries `durationMs` (computed since the first version of
1457
+ the executor but only ever logged), plus `outputLength`, `outputTruncated`
1458
+ and `outputSpillPath`.
1459
+
1460
+ - 935b8f3: Compaction's working state now rides the checkpoint, so a resumed run stops
1461
+ deleting its own history.
1462
+
1463
+ Compaction replaces older messages with a summary and drops any prior
1464
+ `[COMPACTED CONTEXT]` block, on the grounds that `serializeState` is
1465
+ cumulative so the newer summary supersedes it. That holds inside one
1466
+ process. Across a resume it did not: `WorkingStateManager` was constructed
1467
+ fresh on every `query()` with no restore path, so the second compaction of
1468
+ a resumed run produced a summary covering only post-resume activity — and
1469
+ deleted the block that held everything before it.
1470
+
1471
+ The restore path deliberately carries that block forward, calling it the
1472
+ only surviving record of the history the first pass deleted. The next pass
1473
+ then destroyed it. This is what made the two halves agree.
1474
+
1475
+ - `IterationCheckpoint.workingState` — optional, so checkpoints written
1476
+ before this field exists restore exactly as they do today.
1477
+ - `snapshotWorkingState` / `restoreWorkingState` handle the wire shape.
1478
+ `WorkingState.files` is a `Map`, which JSON renders as `{}`, so a naive
1479
+ snapshot would have silently lost every tracked file. Eviction counters
1480
+ round-trip too: a resumed summary that forgot what it had already dropped
1481
+ would claim a completeness it does not have.
1482
+ - State is restored directly rather than by replaying extractors over the
1483
+ restored messages — the messages the first pass compacted away are gone,
1484
+ so re-extraction is both lossy and non-idempotent.
1485
+
1486
+ - 935b8f3: Harden the MCP boundary: the host decides what enters the tool registry,
1487
+ and a server that changes its mind is noticed.
1488
+
1489
+ - `MCPToolDiscovery` takes per-server `allow`/`deny` policies (`'*'` for
1490
+ servers without an entry). Discovery previously admitted whatever the
1491
+ server offered, which put the REMOTE side in charge of what the agent
1492
+ can call — the exact inversion of least privilege. Deny beats allow, so
1493
+ a self-contradicting config resolves restrictively.
1494
+ - Drift detection: the admitted tool set is fingerprinted (name +
1495
+ description + input schema) and compared on each discovery, with an
1496
+ `onDrift` callback reporting `added` / `removed` / `changed`. The
1497
+ fingerprint covers descriptions and schemas, not just names, because the
1498
+ attack shape is advertising something benign at approval time and
1499
+ swapping its meaning afterwards — the name never moves. Reported rather
1500
+ than blocked: a dev server legitimately changes between runs, and only
1501
+ the host knows which kind it is looking at.
1502
+ - Protocol negotiation is checked. A server answers `initialize` with the
1503
+ version IT will speak; the client ignored that answer entirely, so a
1504
+ version it could not speak looked like a healthy connection until
1505
+ something downstream broke oddly. It now refuses a version outside
1506
+ `MCP_SUPPORTED_PROTOCOL_VERSIONS` and names what it can speak. An
1507
+ ABSENT version is still tolerated — a missing field is a sloppy server,
1508
+ an unsupported version is a real incompatibility.
1509
+
1510
+ `MCP_PROTOCOL_VERSION` deliberately stays at the version namzu actually
1511
+ implements. Advertising a newer one whose requirements are unimplemented is
1512
+ worse than advertising an older one honestly, because the server tailors
1513
+ its behavior to the claim. Raising it is a conformance task.
1514
+
1515
+ Hosts that configure no policy see no behavior change.
1516
+
1517
+ - 935b8f3: Recover from a bad tool call without spending a model round trip on it.
1518
+
1519
+ - `QueryParams.repairToolCall` — a last chance to fix a call the model got
1520
+ wrong, before the error reaches it. A malformed call otherwise costs a
1521
+ full round trip: the error goes back as a `tool_result`, the model
1522
+ re-reads the whole context, and issues a second inference to add a
1523
+ missing brace. The hook sees the reason (`invalid_json`,
1524
+ `schema_validation`, `unknown_tool`), the tool's JSON Schema and every
1525
+ registered tool name, and may rewrite the arguments and the tool name —
1526
+ nothing else. It is tried exactly once, a throw is caught, and declining
1527
+ is normal: the original error simply proceeds as before.
1528
+ - `ToolDefinition.maxRetries` (default `0`) + `ToolResult.retryable` — a
1529
+ transient tool failure can now be retried in-loop instead of going back
1530
+ to the model to be re-decided. Strictly opt-in per tool, because the SDK
1531
+ cannot know a tool is idempotent, and only for failures the tool marked
1532
+ retryable.
1533
+ - `PluginHookResult` `{action:'retry'}` finally does something. It was a
1534
+ declared variant that threw at every site that consumed it; in
1535
+ `post_tool_use` it now re-runs the tool, bounded by the same per-tool
1536
+ budget so a plugin cannot spin the executor. It remains an error in
1537
+ `pre_tool_use`, where nothing has run yet for it to mean anything.
1538
+
1539
+ With no repairer configured and no tool opting into retries, behavior is
1540
+ unchanged.
1541
+
1542
+ - 935b8f3: Bound tool execution: per-tool deadlines, real cancellation, and a fan-out cap.
1543
+
1544
+ `ToolContext.abortSignal` was produced by the executor and consumed by nothing —
1545
+ a repo-wide grep found only the two producer sites. A Stop tore down the model
1546
+ stream and then parked inside `Promise.all` waiting for a tool that had no idea
1547
+ it should quit, and there was no framework-level deadline at all: `bash`
1548
+ defaulted to **one hour**, and the MCP stdio transport to forever.
1549
+
1550
+ - `ToolDefinition.timeoutMs` and `ToolExecutorConfig.toolTimeoutMs` (default
1551
+ 120s). On expiry the executor stops waiting and returns a model-visible
1552
+ error result, so a slow dependency becomes something the agent can route
1553
+ around rather than a turn that never comes back.
1554
+ - The tool's `context.abortSignal` now really fires — on the deadline and on a
1555
+ run abort — so cooperative tools stop working instead of merely being
1556
+ detached. `bash` passes it to the child process.
1557
+ - `bash`'s default timeout drops from 1 hour to 2 minutes. The model can still
1558
+ request longer through the tool's own `timeout` argument.
1559
+ - `ToolExecutorConfig.maxToolConcurrency` (default 8) bounds the parallel
1560
+ branch of `executeBatch`, which previously fanned out without limit.
1561
+ - MCP: `MCPClientConfig.requestTimeoutMs` (default 30s) bounds every JSON-RPC
1562
+ round trip; in-flight requests are now rejected when the transport closes or
1563
+ errors, not only on an explicit `disconnect()`; and a server-initiated
1564
+ request (`sampling/createMessage`, `elicitation/create`, `roots/list`,
1565
+ `ping`) gets a `-32601` reply instead of being silently discarded, which
1566
+ used to leave the server waiting forever.
1567
+
1568
+ - 935b8f3: A tool can declare that its output IS the answer
1569
+
1570
+ Every delegation path is blocking: the worker's final text comes back as the dispatching call's result. The loop then went round once more purely to restate what the worker had already said — a full model call at the parent's context size, the most expensive call in the run. It is also lossy, because the parent paraphrases the worker's answer through its own compacted view, so the caller receives the summary rather than the answer. For a router agent, whose entire job is to pick a specialist, that doubled the cost of every request.
1571
+
1572
+ `terminal: true` on a tool settles the run with that tool's output — the rule `structured_output` has always had, now available to any tool. `buildAgentTool({ terminal: true })` sets it on the built-in delegation tool.
1573
+
1574
+ It is honoured only when the terminal call is the only call in the turn and it did not fail. A model that asked for other work in the same turn meant to see those results, and settling would discard answers it requested; an error is not an answer either, and the model is the one that should read it. Both cases take the ordinary path and log the reason rather than quietly costing the relay the flag was set to avoid.
1575
+
1576
+ `defineTool` also gained `maxRetries` and `outputSchema` passthrough. Both fields were already read by the runtime, and the sanctioned way to author a tool had no way to set either — the documented "the tool author opts in, per tool" was reachable only by hand-writing the interface.
1577
+
1578
+ - 935b8f3: A long-running tool can report progress.
1579
+
1580
+ Tools get a deadline of up to two minutes by default, and before this they
1581
+ were silent for all of it: a host could show that a build, a test run or a
1582
+ long fetch had started, and then nothing at all until it finished or timed
1583
+ out.
1584
+
1585
+ - `ToolContext.report(message, fraction?)` — fire-and-forget, returns void,
1586
+ never throws back into the tool, so it can be called without wrapping.
1587
+ - `tool_progress` run event (wire: `tool.progress`), carrying the tool name
1588
+ and `toolUseId` so a host rendering a concurrent batch knows whose
1589
+ progress it is. A `fraction` outside [0,1] is clamped rather than passed
1590
+ on.
1591
+ - Ephemeral, like `text_delta` — excluded from `transcript.jsonl`, so a
1592
+ tool reporting every file it compiles cannot bloat the durable record.
1593
+
1594
+ The model never sees these. Progress answers "is it still working?", which
1595
+ is a question only a human asks, and putting it in the conversation would
1596
+ spend tokens telling the model something it cannot act on.
1597
+
1598
+ - 935b8f3: Add an evaluation harness with trajectory scoring.
1599
+
1600
+ There was no evaluation harness of any kind — no dataset, no scorer, no judge,
1601
+ no trajectory assertion. So namzu's most load-bearing behavior was tuned by
1602
+ constants nobody could measure: `search_tools` activates the top 5 deferred
1603
+ tools, compaction fires at 0.7 of the window, six state lists cap at 25. Change
1604
+ any of them, or a builtin tool description, or the deferred-tools prompt block,
1605
+ and there was no way to learn the agent now takes four tool calls where it took
1606
+ one — short of a user hitting it.
1607
+
1608
+ ```ts
1609
+ import {
1610
+ runExperiment,
1611
+ trajectoryScorer,
1612
+ completionScorer,
1613
+ evalRunFromQuery,
1614
+ } from "@namzu/sdk";
1615
+
1616
+ const report = await runExperiment({
1617
+ name: "file-editing",
1618
+ cases: [
1619
+ {
1620
+ name: "edits after reading",
1621
+ input: msgs,
1622
+ expectedTools: ["read", "edit"],
1623
+ },
1624
+ ],
1625
+ scorers: [trajectoryScorer(), completionScorer()],
1626
+ run: (input) =>
1627
+ evalRunFromQuery(query({ provider, tools, messages: input /* … */ })),
1628
+ });
1629
+ ```
1630
+
1631
+ - **`trajectoryScorer`** scores the tool sequence as F1 over the longest common
1632
+ _subsequence_. Subsequence, not set intersection: reading a file before
1633
+ editing it is not the same run as editing then reading. Extra calls cut
1634
+ precision, missing calls cut recall — so "did the right thing wastefully" and
1635
+ "skipped a step" get different scores, which a final-answer assertion
1636
+ collapses into one.
1637
+ - `completionScorer`, `stepBudgetScorer`, `containsScorer`, and `customScorer`
1638
+ for anything else — including a model-graded judge, which is just an async
1639
+ predicate that calls a provider.
1640
+ - **Every `Score` carries a required `reason`.** A bare number tells you a run
1641
+ got worse without telling you how, which is exactly when you need to know;
1642
+ `formatReport` prints those reasons for failures rather than a bare mean.
1643
+ - A case that throws is a _result_, not a crash: a suite whose first broken
1644
+ case aborts tells you nothing about the other forty. Same for a scorer that
1645
+ throws.
1646
+ - `evalRunFromRun` / `evalRunFromQuery` bridge a finished `Run` into the shape
1647
+ scorers consume. That bridge is three lines of mapping only because
1648
+ `Run.steps` exists — otherwise a trajectory scorer would have to correlate
1649
+ raw `RunEvent`s by iteration number and diff cumulative counters.
1650
+
1651
+ - 935b8f3: A user message can carry a document
1652
+
1653
+ Documents existed in the type system only in the tool-result direction, and both first-party drivers mapped images only on the input side. So "here is the contract, answer questions about it" — a mainstream workload — was reachable only by having a tool read the file and stringify it. That loses the provider's native document handling (page structure, built-in OCR, citations) and pays the text cost instead.
1654
+
1655
+ `UserMessage.attachments` is now `MessageAttachment[]`: an image or a document. The discriminant is optional and stays optional — an attachment without one is an image, which is what every attachment was before, so no existing caller changes.
1656
+
1657
+ `supportsDocuments` sits beside `supportsVision` in the driver capability declaration, and the runtime checks it the same way: a document sent to a driver that declares `false` warns before the request, or throws under `strictCapabilities`, instead of letting the model answer about a file it never saw. The two are counted separately because they are separate wire shapes and a driver can map one without the other.
1658
+
1659
+ The two first-party drivers map documents natively. The remaining five map images only and now say so; a document reaching them degrades to a named placeholder that says which kind was dropped, rather than one that calls a document an image.
1660
+
1661
+ - 935b8f3: Stop compaction from quietly degrading the state it produces, and implement
1662
+ `resetThreshold`.
1663
+
1664
+ What survives compaction is the only record of the history it replaced, so
1665
+ silently shrinking it is the one thing that structure must not do. Three fixes:
1666
+
1667
+ **Capped lists keep their head.** Eviction used `shift()` — oldest-first — so
1668
+ on a long run the 26th assistant note deleted the 1st, and "the structured
1669
+ state that survives compaction" degraded into a rolling window over recent
1670
+ activity. The early entries are the load-bearing ones (the original
1671
+ requirement, the decision that set the approach); the recent ones are still in
1672
+ the un-compacted tail of the conversation. The first `keepFirstEntries`
1673
+ (default 3) are now pinned and eviction takes from the middle. Tool results
1674
+ keep oldest-first eviction, because there recency genuinely wins: an old `read`
1675
+ of a since-edited file is worse than useless.
1676
+
1677
+ **The summary admits what it lost.** Evictions are counted per slot and
1678
+ rendered as `_(N entries dropped to stay within the state budget)_`. A summary
1679
+ that presents a gap as complete is worse than one that admits the gap — the
1680
+ model reasons about a fragment as if it were the whole record.
1681
+
1682
+ **Unrecognised tools get a useful summary.** Every MCP tool, custom tool and
1683
+ connector-bridged tool fell into a flat 120-character head slice, which on JSON
1684
+ spends the entire budget on syntax: `Ran: {"results":[{"id":"a1b2` and nothing
1685
+ else. Unknown tools are the ones a summary can say least about from the name,
1686
+ so they now get 400 characters and a structure-aware slice — array length and
1687
+ element shape, or object keys — falling back to head-and-tail for plain text.
1688
+
1689
+ **`resetThreshold` is implemented rather than deleted.** It was declared, set
1690
+ by the shipped CLI, and read by nothing. It is hysteresis: a pass that only
1691
+ moves the context from 0.72 to 0.71 of the window leaves the trigger armed, so
1692
+ the next iteration compacts again, paying a summarization call and busting the
1693
+ prompt-cache prefix each time for nothing. A pass that cannot reach the reset
1694
+ level now logs the shortfall, and `compaction_completed` carries
1695
+ `reachedResetThreshold`.
1696
+
1697
+ ### Patch Changes
1698
+
1699
+ - 935b8f3: Atomic writes stop sharing one scratch file.
1700
+
1701
+ The rename is what makes a write atomic — a reader sees the old file or the
1702
+ new one, never a half-written one. The sidecar it renames _from_ has to be
1703
+ private to that write, and in seven places it was a fixed `${path}.tmp`.
1704
+
1705
+ Two writers of the same record then shared one scratch file: both opened it,
1706
+ both wrote into it, and the first rename published whatever mixture had
1707
+ landed while the second renamed a file that was no longer there. That is the
1708
+ exact failure atomic writes exist to prevent, reached through the mechanism
1709
+ meant to prevent it.
1710
+
1711
+ Not hypothetical for this SDK: the cross-process park and unpark handoff —
1712
+ one process suspending a run, another resuming it — is a design where two
1713
+ processes legitimately touch the same records, and it is the feature these
1714
+ stores exist to serve. One store already picked a private name; the other
1715
+ seven inherited the fixed one.
1716
+
1717
+ - One `atomicWriteFile` in `utils/`, used by the session, thread, run, task
1718
+ and memory stores, the retention backend and both migration writers. The
1719
+ sidecar carries the process id, a per-process counter and random bytes —
1720
+ distinct within a millisecond, within a process, and across hosts sharing
1721
+ a network mount.
1722
+ - It lives in `utils/` rather than `store/` because one of those writers was
1723
+ _deliberately_ duplicated to avoid an inbound dependency on the store
1724
+ layer. That instinct was right, and it is also why that copy kept the
1725
+ fixed name after the others were fixed; somewhere everything may depend on
1726
+ leaves nothing to duplicate.
1727
+ - A rename contended by a concurrent writer is retried briefly. Replacing an
1728
+ existing file by rename is unconditional on POSIX and not on Windows,
1729
+ where a concurrent writer holding the target fails the call for as long as
1730
+ the other rename takes — and two processes writing one record is precisely
1731
+ what this helper is for. Bounded to five attempts, so a genuine permission
1732
+ error still fails immediately instead of hanging.
1733
+
1734
+ - 935b8f3: The third-party-name audit now covers prose, not just source
1735
+
1736
+ The rule namzu holds is that nothing here takes its naming from another system and no brand appears in prose. The guard that enforces it scanned `.ts` only — so the largest prose surface in the repository, every README and published page, was never checked, and it had accumulated exactly what the rule refuses: a competitor feature grid, a scoring table, "in the spirit of X", "our tool names mirror Y's table verbatim", and a sandbox tier matrix written as market positioning.
1737
+
1738
+ Markdown is scanned now, with the same distinction the source side already draws. An inline code span, a fenced block, a link target and YAML frontmatter are values a reader types verbatim — a package path, a model id, a keychain item — and they are exempt. A published page may also name a service namzu ships a driver for, because telling an operator what it connects to is the page's job; source comments get no such licence, since a vendor is never the reason namzu's own code has its shape.
1739
+
1740
+ - 935b8f3: Four defects an adversarial audit confirmed
1741
+
1742
+ **A task could be created and then never found again.** `DiskTaskStore` writes under the run that created it and read only under the store's default run, so every lookup missed as soon as the two differed — the normal case, since the task tools are built with the live run id while a long-lived host constructs the store once with a fixed default. `create` succeeded, `list` succeeded, and `update`, `delete`, `claim` and every dependency link answered "not found" for a task the caller could see. The in-memory store keys by task id alone, which is why nothing caught it.
1743
+
1744
+ **A sub-agent's token reservation was never returned.** The debit at spawn reserves headroom so siblings cannot each be promised the same tokens, and nothing credited back the unused part — so a pool shrank by the full allocation on every spawn no matter what the child used. At a half-pool fraction, ten delegations left a parent with a thousandth of its budget and the next spawn was refused for a budget that had barely been spent. The debit also ran before provisioning, so a spawn rejected for capacity still burned its allocation — the one state change the comment there promised would not happen.
1745
+
1746
+ **A failed sandbox create leaked a proxy holding real credentials.** The egress proxy starts before the container and its only close was in `destroy()`, which a create that never returned can never reach. Every failure in between left a listening server on loopback stamping credential headers, plus a retained event-loop handle, one per retry.
1747
+
1748
+ **A remembered approval could overrule the operator.** The grant check ran before the verification gate and returned, so a remembered approval skipped the gate entirely — and because a tool-scoped grant matches any arguments, approving one harmless invocation authorised every other one, past a rule written to stop exactly that. The gate now runs first, and a grant can satisfy a review but never a denial.
1749
+
1750
+ - 935b8f3: Retry now works on the bedrock driver, and the shared classifier reads a
1751
+ status wherever a vendor hides it.
1752
+
1753
+ An unclassified error is treated as non-retryable, which is the right
1754
+ default — but it meant the retry policy was effectively dead on this
1755
+ driver, and the one failure most worth backing off from was the one that
1756
+ killed the run. The service reports failures as named exception classes,
1757
+ and the classifier looked at neither the name nor the status, because the
1758
+ status lives in a metadata bag rather than on the error.
1759
+
1760
+ - `classifyProviderError` now also reads `$metadata.httpStatusCode`. A
1761
+ status is a status wherever it hides, and this helps any driver — first
1762
+ or third party — whose SDK reports it that way.
1763
+ - The bedrock driver maps its own exception vocabulary to provider error
1764
+ codes: throttling and quota to `rate_limit`, unavailable and not-ready to
1765
+ `overloaded`, internal and stream faults to `server_error`, and the
1766
+ non-retryable ones (`ValidationException`, `AccessDeniedException`,
1767
+ `ResourceNotFoundException`) to their exact codes so they fail fast
1768
+ instead of burning the retry budget.
1769
+
1770
+ The vocabulary lives in the driver rather than the shared classifier: a
1771
+ driver knows its own vendor's error names, and the classifier should stay
1772
+ generic. An unrecognised exception passes through untouched — an honest
1773
+ unknown beats a confident wrong classification.
1774
+
1775
+ - 935b8f3: A cancelled turn records what it spent before it stopped.
1776
+
1777
+ Cancel re-threw from inside the chunk loop, so everything past that point
1778
+ was unreachable — and everything past that point is the turn's bookkeeping.
1779
+
1780
+ - **Silent cost under-reporting**, the load-bearing one: the usage the
1781
+ stream had already merged was discarded wholesale, so `Run.tokenUsage`
1782
+ and `costInfo` under-reported every cancelled turn. A cancelled turn is
1783
+ not a free turn; the tokens were spent.
1784
+ - The `chat {model}` span opened for the call was started and never ended,
1785
+ so it never exported at all.
1786
+ - The message the turn announced never got a terminator, so a host
1787
+ consuming the message lifecycle saw a message begin and never end.
1788
+ - The streamed text was absent from the run's messages and steps.
1789
+
1790
+ The stream-**error** path a few lines away already settled all of this.
1791
+ Cancel was the one exit that skipped it, which is the opposite of what its
1792
+ frequency deserves.
1793
+
1794
+ `MessageStopReason` gains `'cancelled'` so the terminator can be
1795
+ well-formed. Settling is best-effort and never replaces the reason the turn
1796
+ ended: the cancellation still propagates, so the run loop still settles as
1797
+ cancelled.
1798
+
1799
+ - 935b8f3: A damaged checkpoint is refused instead of skipped.
1800
+
1801
+ A checkpoint file is the **only** durable record of a park — there is no
1802
+ separate approval store. So an unreadable one that gets logged and skipped
1803
+ does not merely lose a resume point: `findPendingCheckpoint` reports "not
1804
+ parked" and drops an approval a human already granted.
1805
+
1806
+ `listCheckpoints` wrapped every per-file read in a `catch` that warned and
1807
+ continued, returning a silently short list that four callers treat as
1808
+ complete:
1809
+
1810
+ - `'latest'` resolution and `newest()` quietly resume from an **older**
1811
+ checkpoint, so the run re-executes a full iteration of tool calls;
1812
+ - `findPendingCheckpoint` loses the park, as above;
1813
+ - `prune` under-deletes, because a file the keep-count cannot see is
1814
+ immortal.
1815
+
1816
+ The only signal was a `log.warn` on a line nobody watches — and the by-id
1817
+ read next door was already strict. Two read paths disagreeing about whether
1818
+ damage matters is how the lenient one gets trusted.
1819
+
1820
+ Both paths now refuse. Both also **check** the parsed shape rather than
1821
+ casting it: `JSON.parse(content) as IterationCheckpoint` let `{}` through
1822
+ and failed much later at the point of use, where the message names a
1823
+ missing property rather than a damaged file.
1824
+
1825
+ Absent stays distinguishable from damaged: no checkpoints still returns an
1826
+ empty list, and an unknown id still returns `null`.
1827
+
1828
+ - 935b8f3: Compaction no longer leaves the conversation opening on an assistant turn.
1829
+
1830
+ After compaction the kept tail **is** the conversation: the summary is
1831
+ written as a system message and every driver hoists system messages into
1832
+ their own request parameter, so the first kept message becomes the first
1833
+ message on the wire. A conversation that opens on an assistant turn is
1834
+ rejected.
1835
+
1836
+ `findSafeTrimIndex` advanced past an orphaned `tool` message and never past
1837
+ an `assistant` one. How often that bit depends on the shape of the history,
1838
+ and the shape that matters most is the worst: in a **multi-step turn** — the
1839
+ agent working through several tool calls without the user speaking in
1840
+ between — the tail alternates assistant and tool with no user message in it
1841
+ at all, so essentially every boundary landed wrong.
1842
+
1843
+ The failure was unrecoverable. The resulting rejection is not classified as
1844
+ an overflow, so relief never fires and the run dies — compaction, whose
1845
+ entire job is keeping a long run alive, becoming the thing that ends it.
1846
+
1847
+ The boundary now advances to a `user` turn. Where none lies ahead it falls
1848
+ back to the nearest one behind **whose own tail is free of dangling tool
1849
+ pairs**: two wire invariants are in play, and satisfying one by breaking the
1850
+ other is not a fix. Where no boundary satisfies both, the input was already
1851
+ unsendable and no cut makes it otherwise, so the prior behaviour stands
1852
+ rather than a different invalid conversation being invented to replace it.
1853
+
1854
+ Also fixed alongside: the structured manager took
1855
+ `Math.min(safeTrimIndex, desiredTrimPoint)`, and since the safe index only
1856
+ ever moves forward of the desired one, that minimum resolved back to the
1857
+ desired point every time — discarding the entire safety search. Whatever the
1858
+ guard was reaching for, what it did was undo the line above it.
1859
+
1860
+ - 935b8f3: Four arithmetic defects, each pinned by a computed counterexample.
1861
+
1862
+ - **`mergeTokenUsage` maxed `totalTokens` as an independent field.** It is
1863
+ derived (`input + output`), and Anthropic reports the input on
1864
+ `message_start` and the output on `message_delta` — so the two frames
1865
+ carry totals of 1200 and 350, and the max returns the larger _component_
1866
+ rather than the sum. Merged: 1200. Correct: 1550. Every completion token
1867
+ was invisible to the token-budget hard stop, which reads only
1868
+ `totalTokens`. The merge now also takes `prompt + completion`, so it is
1869
+ monotone and can never under-report.
1870
+
1871
+ - **The compaction estimator counted array-shaped tool results by block
1872
+ count.** `msg.content.length` on `ToolResultBlock[]` is the number of
1873
+ blocks, so a tool result carrying a 400 KB screenshot contributed **1**
1874
+ character — and the estimate that decides when to compact read near zero
1875
+ for exactly the runs that need compacting most.
1876
+
1877
+ - **`toolsHash` omitted `annotations`.** Those carry `readOnlyHint` and
1878
+ `destructiveHint`, which become `isReadOnly` / `isDestructive` and drive
1879
+ whether a human reviews the call. A server could flip a tool from
1880
+ destructive to read-only — same name, same schema, silently removed from
1881
+ review — and the fingerprint built to catch that rug-pull produced an
1882
+ identical hash.
1883
+
1884
+ - **Sub-agent budget exhaustion inverted into no budget.**
1885
+ `floor(remaining * maxBudgetFraction)` reaches 0 once the parent drops
1886
+ below `1 / maxBudgetFraction`, and `tokenBudget: 0` means _uncapped_
1887
+ downstream (`LimitChecker`: `tokenBudget > 0 && …`). So the most depleted
1888
+ parent in the tree was the one that spawned an unlimited child. Spawning
1889
+ now refuses with a clear error; a caller who wants an uncapped child says
1890
+ so explicitly.
1891
+
1892
+ - 935b8f3: Parent the OpenTelemetry spans, and emit the missing `chat` span.
1893
+
1894
+ Every span was a root. A repo-wide grep for `context.with` / `trace.setSpan`
1895
+ returned zero hits, so a single 20-iteration run landed in Honeycomb as 21
1896
+ disconnected root spans plus N orphan tool spans — no waterfall, no way to see
1897
+ which iteration a slow tool belonged to. There was no span around the model
1898
+ call at all: `chatSpanName` existed with zero call sites, so traces carried no
1899
+ LLM latency, and the token counts were stamped on the iteration span instead of
1900
+ the operation that produced them.
1901
+
1902
+ The fix is explicit parent contexts rather than `startActiveSpan`. Every
1903
+ span-owning body in the run loop is an async **generator**, and a generator
1904
+ resumes on its consumer's async context — so the ambient parent is already gone
1905
+ by the time a child span is created, and the naive conversion silently parents
1906
+ nothing. `parentContext(span)` threads it as a value instead.
1907
+
1908
+ - Iteration spans parent to the run span; tool spans parent to the iteration
1909
+ that requested them, via a new optional `ToolContext.parentSpan` (already
1910
+ threaded to exactly the right place).
1911
+ - A `chat {model}` span carries `gen_ai.operation.name`, request model,
1912
+ temperature and max tokens, and on completion the response model, id,
1913
+ finish reasons, token usage and the cache-read/write counts.
1914
+ - `@namzu/telemetry` switches from `SimpleSpanProcessor` to
1915
+ `BatchSpanProcessor`, so exporting a span no longer puts network latency
1916
+ inline on the agent loop.
1917
+
1918
+ Adds the first telemetry tests in the repo.
1919
+
1920
+ - 935b8f3: Carry budgets across a checkpoint resume, and count the side-channel model calls.
1921
+
1922
+ Budget enforcement was neither durable nor total.
1923
+
1924
+ **Durable.** `IterationCheckpoint` faithfully persisted `tokenUsage`, `costInfo`
1925
+ and `guardState`, and the resume path replayed messages only — the numbers were
1926
+ written and then discarded on the way back in. A run checkpointed at $4.80 of a
1927
+ $5 cap came back with a brand-new $5 and a brand-new timeout clock, so a task
1928
+ that parked five times spent 5x its cap while every invocation truthfully
1929
+ reported itself in budget. `RunPersistence.restoreUsage()` and
1930
+ `GuardCoordinator.restoreElapsed()` (also available as `elapsedMsOffset` at
1931
+ construction) seed both from the checkpoint before the first iteration, so a
1932
+ resumed run that is already over budget stops immediately.
1933
+
1934
+ **Total.** Three `chatStream` call sites bypassed `accumulateUsage` entirely, so
1935
+ a run with `tokenBudget: 200_000` could send well past 200k and never trip
1936
+ `token_budget`:
1937
+
1938
+ - the advisory phase — its usage was already captured for reporting and simply
1939
+ never reached the accountant;
1940
+ - the compaction verifier — the worst offender, since it fires exactly when the
1941
+ context is largest. It now takes an optional `UsageSink`;
1942
+ - `RouterAgent` — routing runs before any `RunPersistence` exists, so
1943
+ `RoutingDecision` now carries the routing call's `usage` (summed across
1944
+ retries) and the router folds it into the result instead of reporting the
1945
+ delegate's usage alone.
1946
+
1947
+ - 935b8f3: namzu takes its naming from nobody, and now there is a gate that proves it.
1948
+
1949
+ `scripts/audit-external-names.mjs` refuses a third-party product name in a
1950
+ comment or an identifier, and runs in CI. It found 31 real ones — most of
1951
+ them in the TUI, where the design was being explained as "modelled on how X
1952
+ presents text", "X-style grouping", "like X / Y".
1953
+
1954
+ That is the failure the rule exists for. A design explained by reference to
1955
+ somebody else's product has handed over its rationale: the next reader
1956
+ reaches for that product's model instead of asking what namzu is trying to
1957
+ achieve, and when the reference changes the comment becomes a claim nobody
1958
+ can check. Each one now states the same decision on its own terms — what it
1959
+ accomplishes, and what breaks without it.
1960
+
1961
+ The kernel had eleven, all in prose explaining a wire behaviour by naming
1962
+ the vendor whose endpoint exhibits it. A 400 for an unanswered `tool_use`
1963
+ is a property of the protocol, not of a company; several function-calling
1964
+ endpoints report `stop` alongside populated tool calls, and which ones is
1965
+ not the point.
1966
+
1967
+ The identity prompt named the products it told the model not to be. It now
1968
+ says the stronger thing without them: the underlying model is an
1969
+ implementation detail of how namzu runs, not who it is.
1970
+
1971
+ What the audit deliberately does NOT flag, because a rule that cries wolf
1972
+ gets switched off: wire values and the files that carry them. A
1973
+ context-window table keyed by model id must contain real model ids or it
1974
+ resolves nothing; a driver package is named after the service it drives.
1975
+ The exemption is per path and narrow, and the script says where the line
1976
+ falls. Scanning string literals was tried and rejected in the same spirit —
1977
+ it flagged driver ids in switch statements and model ids in test fixtures
1978
+ everywhere, which would have meant exempting half the tree.
1979
+
1980
+ Two matcher details worth keeping: the camelCase check is case-SENSITIVE,
1981
+ because an `i` flag turns `[A-Z]` into `[A-Za-z]` and the rule starts
1982
+ rejecting `coherent` for `cohere` and `strands` for the English verb. And
1983
+ `cursor` is absent from the list entirely — it collides with the pagination
1984
+ cursor this codebase threads through every list call.
1985
+
1986
+ - 935b8f3: `glob`, `grep` and `ls` stay inside the working directory, and inside the
1987
+ sandbox when there is one.
1988
+
1989
+ Two independent failures, both in tools that are in the default set.
1990
+
1991
+ **The path escape needed no sandbox at all.** All three resolved a
1992
+ caller-supplied `path` against the working directory bare, so
1993
+ `path: "../../.."` landed wherever that pointed and the tool read it
1994
+ happily. The containment rule already existed — in one private function
1995
+ inside the local sandbox provider — and these never reached it. `grep`
1996
+ returns file **content**, so what escaped was not a listing. For `glob` the
1997
+ same escape also rides in on the _pattern_, since the base directory lifted
1998
+ out of `"../../**/*.pem"` is caller-supplied too.
1999
+
2000
+ A refusal now reaches the model as a failed tool result carrying the reason,
2001
+ rather than a throw, so it can correct itself.
2002
+
2003
+ **The sandbox was not a read boundary.** `glob` and `grep` called
2004
+ `node:fs/promises` against the host working directory and referenced
2005
+ `context.sandbox` nowhere, while every sibling builtin already remembered
2006
+ the branch. With a container backend wired in they read the SDK process's
2007
+ own filesystem. The paths they returned were host-relative too, while
2008
+ `read` resolves what it is handed _inside_ the sandbox — so every
2009
+ search-to-read handoff either failed or opened a different file. The two
2010
+ roots genuinely diverge: the executor passes `workingDirectory` through
2011
+ unchanged alongside the sandbox.
2012
+
2013
+ Both now route through `context.sandbox` when present. `grep` abstracts only
2014
+ the file _source_ — enumerate and read — so matching, context lines and the
2015
+ caps stay one implementation; duplicating the substantive half is how the
2016
+ two paths would drift, and the sandboxed one is the one nobody runs by
2017
+ accident.
2018
+
2019
+ **Sandbox paths are no longer run through the host's path module.** A
2020
+ sandbox is a POSIX filesystem whatever the host runs, so resolving its paths
2021
+ host-side rewrites them whenever the two disagree — on a Windows host
2022
+ `resolve('/workspace')` becomes `C:\workspace`, and a container path stops
2023
+ being a container path. This was found by the new tests, which returned no
2024
+ results at all until it was fixed.
2025
+
2026
+ - 935b8f3: Fix five wiring defects found by auditing the previous wave rather than
2027
+ trusting it. All five had passing unit tests, because those tests
2028
+ constructed the internal class directly and so proved the helper worked
2029
+ while proving nothing about whether `query()` ever reached it.
2030
+
2031
+ - **`query({ repairToolCall })` was a no-op.** The field was spread into
2032
+ `ToolingBootstrap.init`, whose config type has no such field and whose
2033
+ `init` enumerates what it forwards. Object spread bypasses excess-property
2034
+ checking, so it type-checked and did nothing.
2035
+ - **A truncated tool-input stream never reached the repairer** — the case
2036
+ the hook exists for. `executeSingle` answered `inputTruncated` with a
2037
+ generic hint and returned before repair ran. The partial buffer is now
2038
+ preserved (`ToolCall.metadata.partialArguments`) and offered to the
2039
+ repairer, because one handed an empty object has nothing to work from.
2040
+ - **`{action:'retry'}` from `post_tool_use` was silently discarded.** It was
2041
+ read inside a loop bounded by the tool's `maxRetries`, which defaults to
2042
+ 0, so the loop body never ran. Hook-requested retries now get their own
2043
+ bounded budget (`HOOK_RETRY_BUDGET`): the hook is host code reacting to
2044
+ one specific result, a more specific signal than the tool's blanket
2045
+ idempotency declaration.
2046
+ - **A cross-process HITL resume never cleared the park.** The approved batch
2047
+ executed and the checkpoint kept `pending` with no `resolvedAt`, so an
2048
+ approval queue re-served a destructive call that had already run — the
2049
+ exact failure recording the park exists to prevent.
2050
+ - **Configuring an output guardrail rewrote the run's outcome.** The branch
2051
+ called `markCompleted()` purely to materialize the produced text, so a
2052
+ cancelled run reported `completed` merely because a safety check was
2053
+ present. Reading and settling are now separate (`materializeResult`), and
2054
+ `setResult` is sticky so the later `resolveResult` cannot re-expand a
2055
+ redaction back to the raw model output.
2056
+
2057
+ - 935b8f3: Fix five defects in the eval harness and RAG retrieval — all plain bugs
2058
+ with correct answers, not design trade-offs.
2059
+
2060
+ **Eval harness — it could report green on a broken suite.**
2061
+
2062
+ - A case whose run THREW scored 1.0. `executeCase` catches the failure and
2063
+ returns an empty run, and an empty run walks into every scorer's happy
2064
+ path: `stepBudgetScorer` sees 0 steps against its allowance and returns
2065
+ 1, `trajectoryScorer` sees "no tools expected, none called" and returns
2066
+ 1. The failure was recorded on `run.error` and nothing consulted it. Any
2067
+ run that failed now scores 0, with the error as the reason.
2068
+ - Two scorers sharing a name silently collapsed. Scores are keyed by name,
2069
+ so a second `containsScorer(...)` — also called `contains` — overwrote
2070
+ the first, and the case mean's denominator became the count of distinct
2071
+ NAMES rather than scorers run. With one scoring 0 and one scoring 1 the
2072
+ suite reported 1.0 where the honest answer is 0.5. Duplicate names now
2073
+ throw.
2074
+
2075
+ **RAG retrieval.**
2076
+
2077
+ - `bm25Score` implemented only the term-frequency saturation half and no
2078
+ IDF at all — the half that discriminates. Without it every matched term
2079
+ weighs the same, so a chunk matching three common words outranks the one
2080
+ chunk containing the rare term the query was about. It also normalized
2081
+ document length against a hardcoded `avgDl = 256` rather than the corpus
2082
+ in front of it. Both now computed from the candidate set.
2083
+ - `hybridSearch` blended bounded cosine with unbounded BM25 linearly, so
2084
+ `hybridAlpha` did not weight the two halves — whichever scale happened to
2085
+ be larger won. Each ranking is normalized to [0,1] first.
2086
+ - The recursive chunker used `text.split(sep)`, which DELETES the
2087
+ separator: splitting on `'. '` stripped every sentence terminator and
2088
+ `'\n\n'` stripped every paragraph break, so the chunk shown to the model
2089
+ was not what the document said.
2090
+
2091
+ - 935b8f3: A tool call a probe vetoed now says it failed.
2092
+
2093
+ The probe-veto branch was the only result-producing branch in the executor
2094
+ that left `isError` off, and `isError` being optional meant the compiler
2095
+ could not catch it. Five lines above, the `tool_completed` event for the
2096
+ same veto carried `isError: true` — so a run's event stream and the result
2097
+ it returned disagreed about the same call, in the same function.
2098
+
2099
+ Four things degraded off that one omission:
2100
+
2101
+ - Two drivers emit their failure marker only when this is true, so the model
2102
+ read a **successful** result whose body begins `Error: Probe "x" vetoed…`
2103
+ and the failure-recovery path it was trained on never fired.
2104
+ - The persisted step recorded a literal `isError: false`, so the run record
2105
+ contradicted its own event stream.
2106
+ - Compaction guards error results from being cleared; a vetoed result was
2107
+ silently excluded from that protection.
2108
+
2109
+ - 935b8f3: A provider fault keeps the classification its driver produced
2110
+
2111
+ The stream turn flattened a classified `ProviderError` to its message and threw a fresh error in its place, so `retryable`, `status` and `retryAfterMs` were all discarded — and `NamzuError`'s default for `provider_error` is not-retryable. A 429 or 529 that had exhausted its backoff therefore settled the run **failed**, where the documented behaviour is a **pause** with a checkpoint to resume from. `toPlatformError` already projects the right shape; it was simply never handed one.
2112
+
2113
+ The asymmetry was visible in the codebase: the same fault raised inside the compaction verifier propagates untouched and does pause, so identical faults settled oppositely depending on whether compaction happened to run that iteration. A classified failure is now rethrown as itself, and an unclassified one keeps its cause.
2114
+
2115
+ - 935b8f3: Four places where the runtime lost information it was holding, or admitted a limit it had already exceeded.
2116
+
2117
+ - **A clipped sandbox stream said nothing.** `SandboxExecResult` carries `stdoutTruncated` / `stderrTruncated`, added when the other backend needed to report a clipped stream. The local backend clipped at the same cap and never set them, so the model read a complete-looking result whose tail was gone — against the contract's own note that the kernel does not truncate silently. The tool layer already renders the flag; nothing raised it. The accumulator is now a small `CappedStream` that reports hitting its cap, and reports it at the first byte past it rather than at exactly the cap.
2118
+
2119
+ - **Two concurrent spawns could both take the last delegation slot.** The width cap counted a parent's children and then created one, with every other provisioning step in between. Two spawns under the same parent both read the same count, both saw room, and both created, so a cap of N admitted N+1. Provisioning is now serialized per parent session — the narrowest key that makes the check and the write one critical section; spawns under different parents never contend. In-process only, which is the honest scope: cross-process capacity belongs to the store.
2120
+
2121
+ - **`agent_task_list` forgot finished workers.** Terminal tasks leave the manager 30 seconds after they settle, and the gateway's list was rebuilt by looking each tracked id back up — so a task that finished a minute ago vanished from the exact tool whose description says to call it before declaring multi-worker work done. A supervisor could not tell an evicted task from one that never launched; both read as absence. The gateway now snapshots each task's settled summary while the manager still holds it, and prefers the live record whenever there is one.
2122
+
2123
+ - **The compaction summary hid its dropped tool results.** Every capped section in the working-state summary appends a line naming what it evicted — except tool results, which counted their evictions and rendered without them. The section carrying the most volume was the only one presenting a fragment as the whole record.
2124
+
2125
+ - 935b8f3: Clearing a tool result no longer destroys the way back to it, and skill
2126
+ frontmatter fails loudly instead of quietly.
2127
+
2128
+ **A cleared tool result kept its recovery pointer.** When a result exceeds
2129
+ the output budget its full text is written to disk and a line pointing at
2130
+ the file is embedded _in_ the result. Compaction then replaced the whole
2131
+ content with a placeholder — deleting that line for exactly the largest
2132
+ outputs, and advising the model to "call the tool again", which is advice to
2133
+ re-run something that returned megabytes. The spill line now survives, along
2134
+ with the `read`/`grep` instruction that goes with it.
2135
+
2136
+ A head and tail survive too. Clearing was total, so a result just over the
2137
+ 1,000-character minimum lost 100% of itself — including the few lines the
2138
+ agent was actively reasoning from — to reclaim a few hundred characters. A
2139
+ result shorter than the head and tail together is kept whole, since eliding
2140
+ it would drop content while saving nothing.
2141
+
2142
+ **The skill frontmatter fence is anchored to a line.** An unanchored search
2143
+ for `---` cut the frontmatter at the first occurrence anywhere — inside a
2144
+ quoted value, inside a URL — which both truncated the metadata and spilled
2145
+ the remainder into the body, where it reaches the system prompt verbatim.
2146
+
2147
+ **YAML this reader does not implement is refused rather than mangled.** The
2148
+ reader is a flat key/value splitter and the documented contract says "YAML
2149
+ frontmatter" with no restriction, so an author has every reason to write a
2150
+ block scalar or a flow sequence. `description: >-` produced the literal
2151
+ string `">-"`, which passed validation and registered with no warning — the
2152
+ skill existed and was never selected, because its description said nothing.
2153
+ `[Read, Grep]` became that literal text and was interpolated into the
2154
+ prompt. Both now name the file and the field.
2155
+
2156
+ That is worse for exactly one skill — the one already silently broken — and
2157
+ better for everyone looking for it.
2158
+
2159
+ - 935b8f3: **Breaking:** `@namzu/sandbox` declares only the backends it has.
2160
+
2161
+ Four of the shapes this package offered could type-check and then throw: a `process` tier, a `passthrough` tier, and two adapters to third-party managed schedulers, none of which was ever written. Each demanded required configuration for a call that was never made — the `self-hosted` microvm arm went further and required three fields belonging to a local-daemon path that does not exist, while the two fields the working path needs were optional. So the only configuration that ran had to supply three values nothing reads, and omitting the two that matter compiled its way to a runtime throw.
2162
+
2163
+ `SandboxTier` is now `container | microvm`. `MicroVMBackendConfig` is one shape whose `orchestratorEndpoint` and `getToken` are required. `SandboxBackendNotImplementedError` stays exported and thrown: a JS host that invents a tier gets a named refusal rather than a provider that confines nothing.
2164
+
2165
+ The `sandbox.platform` health check now asks the provider what this host enforces instead of answering from a table keyed on the OS name. That table had drifted both ways — it called the Linux probe unimplemented long after the provider began probing real flags, and it told a Windows operator that sandboxing is "not supported", which is true of the in-process tier and silent about the container tier that runs there. Every non-passing result now names the missing controls and what to do about them.
2166
+
2167
+ `SANDBOX_ISOLATION_CONTROLS` is exported as a value from `@namzu/sdk`. It was reachable only through `export type *`, so importing it type-checked and then failed on the first line of a built binary.
2168
+
2169
+ - 29f35c8: Constrain `ask_user_question` to its canonical JSON object-array input on
2170
+ supported providers and reject malformed compatibility shapes at runtime.
2171
+ - 935b8f3: Overflow reaches the rescue that exists for it.
2172
+
2173
+ Overflow is the one 4xx the runtime can act on: it sheds history and
2174
+ retries. Everything else in the 400 family is surfaced. So the rescue is
2175
+ gated on the code being **exactly** `context_length_exceeded`, and anything
2176
+ that misses that gate dies holding the remedy.
2177
+
2178
+ Three things missed it. Measured before and after, five of six realistic
2179
+ overflow shapes never reached relief; now all six do.
2180
+
2181
+ - **The structural code was extracted and then discarded.** The cause-chain
2182
+ walk returned the first `code` it found and fed it only to the two
2183
+ transport-errno sets, so a provider that said `context_length_exceeded` in
2184
+ the one field designed to say it was answered with a substring search that
2185
+ did not match. A structural code is now consulted **before** the status,
2186
+ because it is strictly more specific: a 400 is a category, the code is the
2187
+ diagnosis. The gateway `type` discriminator and a nested error envelope
2188
+ are read the same way.
2189
+ - **The phrase list missed the common wordings.** "too long for", "maximum
2190
+ length", "exceeds the maximum", "input is too large" all fell through to a
2191
+ plain non-retryable invalid request.
2192
+ - **The Converse driver pre-filed `ValidationException` as
2193
+ `invalid_request`.** That name covers both a malformed request and a
2194
+ prompt past the model's window, and only one of those is recoverable — so
2195
+ guessing from the name made the recoverable case unrecoverable by
2196
+ construction, because the shared classifier short-circuits on an error
2197
+ that already carries a code and never read the body. It now hands that one
2198
+ name to the classifier. The result is still a `ProviderError`, so the
2199
+ driver's contract is unchanged; it just stops answering a question it
2200
+ cannot answer from the name alone.
2201
+
2202
+ The rate-limit half of the same class is fixed alongside: a provider that
2203
+ reports `rate_limit_exceeded` structurally under a 400 is now retryable
2204
+ instead of being filed as a bad request.
2205
+
2206
+ - 935b8f3: Answer every `tool_use` block, and stop a human approval from overriding a gate denial.
2207
+
2208
+ Four tool-review paths — verification-gate all-deny, human `reject_tools`,
2209
+ `modify_tools` with everything denied, and `modify_tools` with a _partial_
2210
+ deny — returned without producing a `tool_result` for the calls they refused.
2211
+ The assistant turn stayed unanswered, so the next provider request was
2212
+ malformed (`400 … Did not find 1 tool_result block(s)`) and the run died.
2213
+ Any host wiring a rejection decision (including the `namzu` TUI's permission
2214
+ prompt) hit this on the first decline.
2215
+
2216
+ `ToolExecutor.executeBatch` now takes an optional denial map and answers
2217
+ _every_ call in the batch: refused calls get a synthetic error `tool_result`
2218
+ carrying the reason instead of being executed. Because there is one place
2219
+ that turns tool calls into messages, the invariant now holds by construction.
2220
+ The refusal reason travels inside the `tool_result` rather than as a trailing
2221
+ `[SYSTEM]` user message, so a rejection steers the model instead of only
2222
+ stopping it.
2223
+
2224
+ Alongside it, a policy-bypass fix: on the gate's _mixed_-decision path a human
2225
+ `approve_tools` replayed the full, unfiltered response and executed the calls
2226
+ the gate had denied. Gate denials are now threaded through every downstream
2227
+ execution, and a `modify_tools` rewrite can no longer resurrect a denied call.
2228
+
2229
+ Checkpoint resume repairs unanswered tool calls (`removeDanglingMessages`)
2230
+ before replaying history, so a run parked at a tool-review checkpoint and
2231
+ resumed in a fresh process no longer fails on its first model call.
2232
+
2233
+ - 935b8f3: Fix three defects in delegation and compaction that unit tests could not
2234
+ see, because the numbers involved stay plausible-looking until you check
2235
+ their units and their object identity.
2236
+
2237
+ - **A child agent's wall-clock deadline was a TOKEN count.** The fallback
2238
+ was `context.budgetTracker.remaining` read as `timeoutMs`. It hid because
2239
+ a six-figure token budget lands in a plausible range of milliseconds; it
2240
+ bit at the edges, where an unlimited budget (`0`) produced a child that
2241
+ was out of time on arrival. There is now an explicit
2242
+ `AgentManagerConfig.childTimeoutMs` (default 5 minutes).
2243
+ - **Sibling sub-agents each got a full share of the same pool.**
2244
+ `LocalTaskGateway` handed every spawn a _cloned_ budget tracker, so
2245
+ `AgentManager.spawn`'s `remaining -= allocatedTokens` debited a throwaway
2246
+ object. N children were each allocated `maxBudgetFraction` of the
2247
+ untouched parent total — N × 50% of a budget that only had 100% in it.
2248
+ The tracker is shared, as the debit always assumed.
2249
+ - **The compaction verifier sent `model: ''`.** Some drivers quietly
2250
+ substitute a default and others reject outright — on Bedrock the model id
2251
+ IS the endpoint. So compaction's LLM verifier failed exactly on the
2252
+ providers where a long run most needs it, and the failure surfaced as
2253
+ compaction killing the run it exists to save. It now receives the run's
2254
+ model.
2255
+
2256
+ Each fix ships with a test that was confirmed to fail against the old code.
2257
+
2258
+ - 935b8f3: Normalize and memoize the tool schema that goes on the wire, and stop
2259
+ losing MCP schemas in translation.
2260
+
2261
+ - `$schema` (`http://json-schema.org/draft-07/schema#`) was stamped on
2262
+ every tool's parameters and sent on every request. No provider reads it,
2263
+ and it rides in the tools block — position 0, inside the cached prefix.
2264
+ Stripped.
2265
+ - `toLLMTools` re-walked every registered tool's Zod tree once per
2266
+ iteration. Rendering is now memoized on the schema object and deeply
2267
+ frozen, so it is both free and byte-identical across iterations — the
2268
+ tools block heads the prompt-cache prefix, and a single reordered key
2269
+ invalidates the whole run's cache.
2270
+ - `mcpJsonSchemaToZod` collapsed `array` to `z.array(z.unknown())` and
2271
+ `object` to `z.record(z.unknown())`. Because a bridged tool's schema
2272
+ round-trips (server JSON Schema → Zod → JSON Schema on the wire), every
2273
+ MCP tool taking a structured argument was shown to the model as "an
2274
+ array of anything" or "an object with any keys" — nested properties,
2275
+ item types, enums and descriptions all gone. It is now recursive and
2276
+ faithful: nested objects, array items, enums, `const`, `anyOf`/`oneOf`,
2277
+ nullable (`type: ['string','null']`), descriptions and defaults survive.
2278
+ - MCP objects default to closed (`additionalProperties: false`) instead of
2279
+ `.passthrough()`, so the model is no longer told it may invent arguments
2280
+ the server never declared. A server that explicitly sets
2281
+ `additionalProperties: true` is still honored.
2282
+
2283
+ - 935b8f3: A turn that asked for tools no longer ends because the provider said it
2284
+ didn't.
2285
+
2286
+ The iteration loop ended the turn on `finishReason === 'stop'` **before**
2287
+ looking at whether the model had asked for tools. Endpoints on the OpenAI
2288
+ wire shape — gateways and local servers especially — routinely report `stop`
2289
+ on the same response that carries a populated `tool_calls`, and three of
2290
+ this repo's drivers passed that value straight through.
2291
+
2292
+ The damage was total and silent: every requested call skipped, an assistant
2293
+ turn left carrying `tool_use` blocks nothing ever answered, and the run
2294
+ settling as though it had finished the work it never started.
2295
+
2296
+ - **The runtime now treats tool calls as the fact and the finish reason as
2297
+ the summary.** When they disagree, the calls win. This is the load-bearing
2298
+ fix: it protects every driver, including ones this repo does not ship.
2299
+ - **The three drivers that cast the reason raw now report it honestly** —
2300
+ a stream that produced a tool call reports `tool_calls`, whatever the
2301
+ endpoint called it. Defence in depth, and it makes the reported reason
2302
+ true for anyone else reading it.
2303
+
2304
+ The existing suite could not catch this: the scripted mock reports
2305
+ `tool_calls` whenever it emits one, which is what an honest provider does
2306
+ and therefore never the case that breaks.
2307
+
2308
+ - 935b8f3: The question a run asked and the answer that resolved it match on the same key
2309
+
2310
+ `user_question_asked` carried a `question_id` and `user_question_answered` did not, so a client that keyed on the question id — the natural key, since it is what routes an answer back on resume — could not match the two halves without also having stored the checkpoint id. The answered event now carries it whenever the resolution named one.
2311
+
2312
+ Twelve event mappings across the SSE and agent-to-agent bridges shipped with no test: the nine event kinds added since those mappers were first written, plus the failure-classification and message-role paths. A wire transform with no test is a contract nobody checked — the field names are what a remote consumer parses, and the transforms return `Record<string, unknown>`, so renaming one is a break type-checking cannot see.
2313
+
3
2314
  ## 2.0.0
4
2315
 
5
2316
  ### Major Changes