@namzu/sdk 30.2.0 → 31.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 (718) hide show
  1. package/CHANGELOG.md +562 -0
  2. package/README.md +43 -2
  3. package/dist/advisory/executor.d.ts +2 -1
  4. package/dist/advisory/executor.d.ts.map +1 -1
  5. package/dist/advisory/executor.js +4 -1
  6. package/dist/advisory/executor.js.map +1 -1
  7. package/dist/agents/ReactiveAgent.d.ts.map +1 -1
  8. package/dist/agents/ReactiveAgent.js +12 -0
  9. package/dist/agents/ReactiveAgent.js.map +1 -1
  10. package/dist/agents/RouterAgent.d.ts.map +1 -1
  11. package/dist/agents/RouterAgent.js +21 -3
  12. package/dist/agents/RouterAgent.js.map +1 -1
  13. package/dist/agents/SupervisorAgent.d.ts.map +1 -1
  14. package/dist/agents/SupervisorAgent.js +34 -11
  15. package/dist/agents/SupervisorAgent.js.map +1 -1
  16. package/dist/agents/runAgent.d.ts +12 -0
  17. package/dist/agents/runAgent.d.ts.map +1 -1
  18. package/dist/agents/runAgent.js +26 -2
  19. package/dist/agents/runAgent.js.map +1 -1
  20. package/dist/authorization/command-line.d.ts +81 -0
  21. package/dist/authorization/command-line.d.ts.map +1 -0
  22. package/dist/authorization/command-line.js +347 -0
  23. package/dist/authorization/command-line.js.map +1 -0
  24. package/dist/authorization/rules.d.ts.map +1 -1
  25. package/dist/authorization/rules.js +22 -1
  26. package/dist/authorization/rules.js.map +1 -1
  27. package/dist/bridge/a2a/client.d.ts +23 -5
  28. package/dist/bridge/a2a/client.d.ts.map +1 -1
  29. package/dist/bridge/a2a/client.js +320 -73
  30. package/dist/bridge/a2a/client.js.map +1 -1
  31. package/dist/bridge/a2a/mapper.d.ts.map +1 -1
  32. package/dist/bridge/a2a/mapper.js +4 -0
  33. package/dist/bridge/a2a/mapper.js.map +1 -1
  34. package/dist/bridge/acp/server.d.ts +13 -1
  35. package/dist/bridge/acp/server.d.ts.map +1 -1
  36. package/dist/bridge/acp/server.js +150 -44
  37. package/dist/bridge/acp/server.js.map +1 -1
  38. package/dist/bridge/mcp/connector/adapter.d.ts +3 -2
  39. package/dist/bridge/mcp/connector/adapter.d.ts.map +1 -1
  40. package/dist/bridge/mcp/connector/adapter.js +17 -21
  41. package/dist/bridge/mcp/connector/adapter.js.map +1 -1
  42. package/dist/bridge/sse/mapper.d.ts.map +1 -1
  43. package/dist/bridge/sse/mapper.js +3 -0
  44. package/dist/bridge/sse/mapper.js.map +1 -1
  45. package/dist/compaction/dangling.d.ts +29 -2
  46. package/dist/compaction/dangling.d.ts.map +1 -1
  47. package/dist/compaction/dangling.js +172 -35
  48. package/dist/compaction/dangling.js.map +1 -1
  49. package/dist/compaction/index.d.ts +3 -2
  50. package/dist/compaction/index.d.ts.map +1 -1
  51. package/dist/compaction/index.js +1 -1
  52. package/dist/compaction/index.js.map +1 -1
  53. package/dist/compaction/manual.d.ts +11 -1
  54. package/dist/compaction/manual.d.ts.map +1 -1
  55. package/dist/compaction/manual.js +89 -14
  56. package/dist/compaction/manual.js.map +1 -1
  57. package/dist/compaction/plan.d.ts +19 -6
  58. package/dist/compaction/plan.d.ts.map +1 -1
  59. package/dist/compaction/plan.js +18 -4
  60. package/dist/compaction/plan.js.map +1 -1
  61. package/dist/compaction/retention.d.ts +10 -7
  62. package/dist/compaction/retention.d.ts.map +1 -1
  63. package/dist/compaction/retention.js +26 -8
  64. package/dist/compaction/retention.js.map +1 -1
  65. package/dist/compaction/summary.d.ts +4 -4
  66. package/dist/compaction/summary.js +4 -4
  67. package/dist/compaction/verifier.d.ts +19 -1
  68. package/dist/compaction/verifier.d.ts.map +1 -1
  69. package/dist/compaction/verifier.js +20 -1
  70. package/dist/compaction/verifier.js.map +1 -1
  71. package/dist/config/runtime.d.ts +6 -6
  72. package/dist/connector/BaseConnector.d.ts +6 -4
  73. package/dist/connector/BaseConnector.d.ts.map +1 -1
  74. package/dist/connector/BaseConnector.js +8 -2
  75. package/dist/connector/BaseConnector.js.map +1 -1
  76. package/dist/connector/builtins/http.d.ts +16 -4
  77. package/dist/connector/builtins/http.d.ts.map +1 -1
  78. package/dist/connector/builtins/http.js +177 -44
  79. package/dist/connector/builtins/http.js.map +1 -1
  80. package/dist/connector/builtins/webhook.d.ts +15 -4
  81. package/dist/connector/builtins/webhook.d.ts.map +1 -1
  82. package/dist/connector/builtins/webhook.js +165 -45
  83. package/dist/connector/builtins/webhook.js.map +1 -1
  84. package/dist/connector/execution-contract.d.ts +11 -0
  85. package/dist/connector/execution-contract.d.ts.map +1 -0
  86. package/dist/connector/execution-contract.js +14 -0
  87. package/dist/connector/execution-contract.js.map +1 -0
  88. package/dist/connector/http-operation.d.ts +48 -0
  89. package/dist/connector/http-operation.d.ts.map +1 -0
  90. package/dist/connector/http-operation.js +205 -0
  91. package/dist/connector/http-operation.js.map +1 -0
  92. package/dist/connector/mcp/adapter.d.ts.map +1 -1
  93. package/dist/connector/mcp/adapter.js +8 -3
  94. package/dist/connector/mcp/adapter.js.map +1 -1
  95. package/dist/connector/mcp/client.d.ts +14 -8
  96. package/dist/connector/mcp/client.d.ts.map +1 -1
  97. package/dist/connector/mcp/client.js +160 -44
  98. package/dist/connector/mcp/client.js.map +1 -1
  99. package/dist/connector/mcp/http-sse.d.ts +8 -2
  100. package/dist/connector/mcp/http-sse.d.ts.map +1 -1
  101. package/dist/connector/mcp/http-sse.js +70 -17
  102. package/dist/connector/mcp/http-sse.js.map +1 -1
  103. package/dist/connector/mcp/prompt-adapter.d.ts.map +1 -1
  104. package/dist/connector/mcp/prompt-adapter.js +9 -2
  105. package/dist/connector/mcp/prompt-adapter.js.map +1 -1
  106. package/dist/connector/mcp/stdio.d.ts +2 -2
  107. package/dist/connector/mcp/stdio.d.ts.map +1 -1
  108. package/dist/connector/mcp/stdio.js +14 -50
  109. package/dist/connector/mcp/stdio.js.map +1 -1
  110. package/dist/connector/mcp/streamable-http.d.ts +7 -2
  111. package/dist/connector/mcp/streamable-http.d.ts.map +1 -1
  112. package/dist/connector/mcp/streamable-http.js +66 -18
  113. package/dist/connector/mcp/streamable-http.js.map +1 -1
  114. package/dist/connector/tools/adapter.d.ts +2 -2
  115. package/dist/connector/tools/adapter.d.ts.map +1 -1
  116. package/dist/connector/tools/adapter.js +23 -14
  117. package/dist/connector/tools/adapter.js.map +1 -1
  118. package/dist/connector/tools/definitions.d.ts.map +1 -1
  119. package/dist/connector/tools/definitions.js +5 -2
  120. package/dist/connector/tools/definitions.js.map +1 -1
  121. package/dist/connector/tools/result.d.ts +4 -0
  122. package/dist/connector/tools/result.d.ts.map +1 -0
  123. package/dist/connector/tools/result.js +20 -0
  124. package/dist/connector/tools/result.js.map +1 -0
  125. package/dist/connector/web/guarded-fetch.d.ts +4 -2
  126. package/dist/connector/web/guarded-fetch.d.ts.map +1 -1
  127. package/dist/connector/web/guarded-fetch.js +157 -43
  128. package/dist/connector/web/guarded-fetch.js.map +1 -1
  129. package/dist/constants/sandbox/index.d.ts +3 -2
  130. package/dist/constants/sandbox/index.d.ts.map +1 -1
  131. package/dist/constants/sandbox/index.js +3 -2
  132. package/dist/constants/sandbox/index.js.map +1 -1
  133. package/dist/contracts/api.d.ts +2 -0
  134. package/dist/contracts/api.d.ts.map +1 -1
  135. package/dist/contracts/schemas.d.ts +38 -12
  136. package/dist/contracts/schemas.d.ts.map +1 -1
  137. package/dist/contracts/schemas.js +7 -0
  138. package/dist/contracts/schemas.js.map +1 -1
  139. package/dist/directory/derive-supervisor.d.ts.map +1 -1
  140. package/dist/directory/derive-supervisor.js +8 -0
  141. package/dist/directory/derive-supervisor.js.map +1 -1
  142. package/dist/directory/derive.d.ts.map +1 -1
  143. package/dist/directory/derive.js +8 -0
  144. package/dist/directory/derive.js.map +1 -1
  145. package/dist/directory/load.d.ts.map +1 -1
  146. package/dist/directory/load.js +2 -0
  147. package/dist/directory/load.js.map +1 -1
  148. package/dist/directory/types.d.ts +4 -0
  149. package/dist/directory/types.d.ts.map +1 -1
  150. package/dist/eval/experiment.d.ts +10 -10
  151. package/dist/eval/experiment.d.ts.map +1 -1
  152. package/dist/eval/experiment.js +121 -91
  153. package/dist/eval/experiment.js.map +1 -1
  154. package/dist/eval/judge.d.ts +6 -0
  155. package/dist/eval/judge.d.ts.map +1 -1
  156. package/dist/eval/judge.js +7 -2
  157. package/dist/eval/judge.js.map +1 -1
  158. package/dist/eval/types.d.ts +7 -1
  159. package/dist/eval/types.d.ts.map +1 -1
  160. package/dist/manager/agent/lifecycle.d.ts +12 -10
  161. package/dist/manager/agent/lifecycle.d.ts.map +1 -1
  162. package/dist/manager/agent/lifecycle.js +16 -3
  163. package/dist/manager/agent/lifecycle.js.map +1 -1
  164. package/dist/manager/connector/environment.d.ts +2 -2
  165. package/dist/manager/connector/environment.d.ts.map +1 -1
  166. package/dist/manager/connector/environment.js +2 -2
  167. package/dist/manager/connector/environment.js.map +1 -1
  168. package/dist/manager/connector/lifecycle.d.ts +10 -2
  169. package/dist/manager/connector/lifecycle.d.ts.map +1 -1
  170. package/dist/manager/connector/lifecycle.js +273 -24
  171. package/dist/manager/connector/lifecycle.js.map +1 -1
  172. package/dist/manager/connector/tenant.d.ts +5 -4
  173. package/dist/manager/connector/tenant.d.ts.map +1 -1
  174. package/dist/manager/connector/tenant.js +47 -22
  175. package/dist/manager/connector/tenant.js.map +1 -1
  176. package/dist/manager/goal/activation.d.ts +23 -0
  177. package/dist/manager/goal/activation.d.ts.map +1 -0
  178. package/dist/manager/goal/activation.js +41 -0
  179. package/dist/manager/goal/activation.js.map +1 -0
  180. package/dist/manager/index.d.ts +3 -2
  181. package/dist/manager/index.d.ts.map +1 -1
  182. package/dist/manager/index.js.map +1 -1
  183. package/dist/manager/run/persistence.d.ts +2 -0
  184. package/dist/manager/run/persistence.d.ts.map +1 -1
  185. package/dist/manager/run/persistence.js +5 -1
  186. package/dist/manager/run/persistence.js.map +1 -1
  187. package/dist/manager/topic/dependency.d.ts +24 -0
  188. package/dist/manager/topic/dependency.d.ts.map +1 -0
  189. package/dist/manager/topic/dependency.js +13 -0
  190. package/dist/manager/topic/dependency.js.map +1 -0
  191. package/dist/manager/topic/lifecycle.d.ts +9 -21
  192. package/dist/manager/topic/lifecycle.d.ts.map +1 -1
  193. package/dist/manager/topic/lifecycle.js +17 -29
  194. package/dist/manager/topic/lifecycle.js.map +1 -1
  195. package/dist/plugin/index.d.ts +1 -0
  196. package/dist/plugin/index.d.ts.map +1 -1
  197. package/dist/plugin/index.js.map +1 -1
  198. package/dist/plugin/lifecycle.d.ts +15 -0
  199. package/dist/plugin/lifecycle.d.ts.map +1 -1
  200. package/dist/plugin/lifecycle.js +144 -38
  201. package/dist/plugin/lifecycle.js.map +1 -1
  202. package/dist/plugin/loader.d.ts +3 -3
  203. package/dist/plugin/loader.d.ts.map +1 -1
  204. package/dist/plugin/loader.js +58 -12
  205. package/dist/plugin/loader.js.map +1 -1
  206. package/dist/provider/collect-chat-completion.d.ts.map +1 -1
  207. package/dist/provider/collect-chat-completion.js +4 -0
  208. package/dist/provider/collect-chat-completion.js.map +1 -1
  209. package/dist/provider/fallback.d.ts +3 -1
  210. package/dist/provider/fallback.d.ts.map +1 -1
  211. package/dist/provider/fallback.js +62 -10
  212. package/dist/provider/fallback.js.map +1 -1
  213. package/dist/provider/idle-timeout.d.ts +4 -0
  214. package/dist/provider/idle-timeout.d.ts.map +1 -1
  215. package/dist/provider/idle-timeout.js +131 -15
  216. package/dist/provider/idle-timeout.js.map +1 -1
  217. package/dist/provider/index.d.ts +2 -0
  218. package/dist/provider/index.d.ts.map +1 -1
  219. package/dist/provider/index.js +1 -0
  220. package/dist/provider/index.js.map +1 -1
  221. package/dist/provider/instrumentation.d.ts.map +1 -1
  222. package/dist/provider/instrumentation.js +1 -0
  223. package/dist/provider/instrumentation.js.map +1 -1
  224. package/dist/provider/retry.d.ts.map +1 -1
  225. package/dist/provider/retry.js +13 -1
  226. package/dist/provider/retry.js.map +1 -1
  227. package/dist/public-runtime.d.ts +57 -24
  228. package/dist/public-runtime.d.ts.map +1 -1
  229. package/dist/public-runtime.js +42 -35
  230. package/dist/public-runtime.js.map +1 -1
  231. package/dist/public-tools.d.ts +1 -0
  232. package/dist/public-tools.d.ts.map +1 -1
  233. package/dist/public-tools.js +5 -0
  234. package/dist/public-tools.js.map +1 -1
  235. package/dist/public-types.d.ts +33 -12
  236. package/dist/public-types.d.ts.map +1 -1
  237. package/dist/rag/embedding.d.ts +8 -3
  238. package/dist/rag/embedding.d.ts.map +1 -1
  239. package/dist/rag/embedding.js +120 -9
  240. package/dist/rag/embedding.js.map +1 -1
  241. package/dist/rag/index.d.ts +1 -1
  242. package/dist/rag/index.d.ts.map +1 -1
  243. package/dist/rag/index.js +1 -1
  244. package/dist/rag/index.js.map +1 -1
  245. package/dist/rag/ingestion.d.ts +2 -2
  246. package/dist/rag/ingestion.d.ts.map +1 -1
  247. package/dist/rag/ingestion.js +15 -3
  248. package/dist/rag/ingestion.js.map +1 -1
  249. package/dist/rag/knowledge-base.d.ts +3 -3
  250. package/dist/rag/knowledge-base.d.ts.map +1 -1
  251. package/dist/rag/knowledge-base.js +8 -4
  252. package/dist/rag/knowledge-base.js.map +1 -1
  253. package/dist/rag/operation.d.ts +10 -0
  254. package/dist/rag/operation.d.ts.map +1 -0
  255. package/dist/rag/operation.js +26 -0
  256. package/dist/rag/operation.js.map +1 -0
  257. package/dist/rag/rag-tool.d.ts.map +1 -1
  258. package/dist/rag/rag-tool.js +6 -3
  259. package/dist/rag/rag-tool.js.map +1 -1
  260. package/dist/rag/retriever.d.ts +2 -2
  261. package/dist/rag/retriever.d.ts.map +1 -1
  262. package/dist/rag/retriever.js +31 -15
  263. package/dist/rag/retriever.js.map +1 -1
  264. package/dist/rag/vector-store.d.ts +3 -3
  265. package/dist/rag/vector-store.d.ts.map +1 -1
  266. package/dist/rag/vector-store.js +4 -2
  267. package/dist/rag/vector-store.js.map +1 -1
  268. package/dist/registry/command/kernel-commands.d.ts +16 -4
  269. package/dist/registry/command/kernel-commands.d.ts.map +1 -1
  270. package/dist/registry/command/kernel-commands.js +171 -0
  271. package/dist/registry/command/kernel-commands.js.map +1 -1
  272. package/dist/run/reporter.d.ts.map +1 -1
  273. package/dist/run/reporter.js +9 -0
  274. package/dist/run/reporter.js.map +1 -1
  275. package/dist/run-query/index.d.ts +15 -1
  276. package/dist/run-query/index.d.ts.map +1 -1
  277. package/dist/run-query/index.js +69 -15
  278. package/dist/run-query/index.js.map +1 -1
  279. package/dist/runtime/query/context.d.ts.map +1 -1
  280. package/dist/runtime/query/context.js +10 -3
  281. package/dist/runtime/query/context.js.map +1 -1
  282. package/dist/runtime/query/executor.d.ts +3 -0
  283. package/dist/runtime/query/executor.d.ts.map +1 -1
  284. package/dist/runtime/query/executor.js +80 -18
  285. package/dist/runtime/query/executor.js.map +1 -1
  286. package/dist/runtime/query/guard.d.ts +9 -0
  287. package/dist/runtime/query/guard.d.ts.map +1 -1
  288. package/dist/runtime/query/guard.js +11 -0
  289. package/dist/runtime/query/guard.js.map +1 -1
  290. package/dist/runtime/query/index.d.ts +30 -1
  291. package/dist/runtime/query/index.d.ts.map +1 -1
  292. package/dist/runtime/query/index.js +548 -95
  293. package/dist/runtime/query/index.js.map +1 -1
  294. package/dist/runtime/query/iteration/index.d.ts.map +1 -1
  295. package/dist/runtime/query/iteration/index.js +74 -14
  296. package/dist/runtime/query/iteration/index.js.map +1 -1
  297. package/dist/runtime/query/iteration/phases/compaction.d.ts.map +1 -1
  298. package/dist/runtime/query/iteration/phases/compaction.js +94 -53
  299. package/dist/runtime/query/iteration/phases/compaction.js.map +1 -1
  300. package/dist/runtime/query/iteration/phases/context.d.ts +3 -0
  301. package/dist/runtime/query/iteration/phases/context.d.ts.map +1 -1
  302. package/dist/runtime/query/iteration/phases/context.js.map +1 -1
  303. package/dist/runtime/query/iteration/phases/tool-review.d.ts.map +1 -1
  304. package/dist/runtime/query/iteration/phases/tool-review.js +21 -0
  305. package/dist/runtime/query/iteration/phases/tool-review.js.map +1 -1
  306. package/dist/runtime/query/iteration/stream-turn.d.ts.map +1 -1
  307. package/dist/runtime/query/iteration/stream-turn.js +4 -0
  308. package/dist/runtime/query/iteration/stream-turn.js.map +1 -1
  309. package/dist/runtime/query/project-instructions.d.ts +69 -0
  310. package/dist/runtime/query/project-instructions.d.ts.map +1 -0
  311. package/dist/runtime/query/project-instructions.js +137 -0
  312. package/dist/runtime/query/project-instructions.js.map +1 -0
  313. package/dist/runtime/query/request-rich-content.d.ts +22 -0
  314. package/dist/runtime/query/request-rich-content.d.ts.map +1 -0
  315. package/dist/runtime/query/request-rich-content.js +122 -0
  316. package/dist/runtime/query/request-rich-content.js.map +1 -0
  317. package/dist/runtime/query/result.d.ts.map +1 -1
  318. package/dist/runtime/query/result.js +12 -1
  319. package/dist/runtime/query/result.js.map +1 -1
  320. package/dist/runtime/query/resume-pending.d.ts.map +1 -1
  321. package/dist/runtime/query/resume-pending.js +19 -20
  322. package/dist/runtime/query/resume-pending.js.map +1 -1
  323. package/dist/runtime/query/resume-run.d.ts.map +1 -1
  324. package/dist/runtime/query/resume-run.js +54 -8
  325. package/dist/runtime/query/resume-run.js.map +1 -1
  326. package/dist/runtime/query/run-state.d.ts +5 -0
  327. package/dist/runtime/query/run-state.d.ts.map +1 -1
  328. package/dist/runtime/query/run-state.js +6 -1
  329. package/dist/runtime/query/run-state.js.map +1 -1
  330. package/dist/runtime/query/sandbox-lifecycle.d.ts +54 -0
  331. package/dist/runtime/query/sandbox-lifecycle.d.ts.map +1 -0
  332. package/dist/runtime/query/sandbox-lifecycle.js +167 -0
  333. package/dist/runtime/query/sandbox-lifecycle.js.map +1 -0
  334. package/dist/sandbox/isolation.d.ts.map +1 -1
  335. package/dist/sandbox/isolation.js +9 -0
  336. package/dist/sandbox/isolation.js.map +1 -1
  337. package/dist/sandbox/provider/local.d.ts +56 -6
  338. package/dist/sandbox/provider/local.d.ts.map +1 -1
  339. package/dist/sandbox/provider/local.js +181 -76
  340. package/dist/sandbox/provider/local.js.map +1 -1
  341. package/dist/sandbox/terminal.d.ts +13 -5
  342. package/dist/sandbox/terminal.d.ts.map +1 -1
  343. package/dist/sandbox/terminal.js +11 -3
  344. package/dist/sandbox/terminal.js.map +1 -1
  345. package/dist/session/errors.d.ts +28 -29
  346. package/dist/session/errors.d.ts.map +1 -1
  347. package/dist/session/errors.js +28 -29
  348. package/dist/session/errors.js.map +1 -1
  349. package/dist/session/handoff/broadcast.d.ts +5 -8
  350. package/dist/session/handoff/broadcast.d.ts.map +1 -1
  351. package/dist/session/handoff/broadcast.js +16 -6
  352. package/dist/session/handoff/broadcast.js.map +1 -1
  353. package/dist/session/handoff/single.d.ts +5 -8
  354. package/dist/session/handoff/single.d.ts.map +1 -1
  355. package/dist/session/handoff/single.js +7 -4
  356. package/dist/session/handoff/single.js.map +1 -1
  357. package/dist/store/attachment/index.d.ts +11 -3
  358. package/dist/store/attachment/index.d.ts.map +1 -1
  359. package/dist/store/attachment/index.js +49 -4
  360. package/dist/store/attachment/index.js.map +1 -1
  361. package/dist/store/feedback/conformance.d.ts.map +1 -1
  362. package/dist/store/feedback/conformance.js +32 -0
  363. package/dist/store/feedback/conformance.js.map +1 -1
  364. package/dist/store/feedback/disk.d.ts +8 -6
  365. package/dist/store/feedback/disk.d.ts.map +1 -1
  366. package/dist/store/feedback/disk.js +111 -76
  367. package/dist/store/feedback/disk.js.map +1 -1
  368. package/dist/store/goal/index.d.ts +111 -0
  369. package/dist/store/goal/index.d.ts.map +1 -0
  370. package/dist/store/goal/index.js +436 -0
  371. package/dist/store/goal/index.js.map +1 -0
  372. package/dist/store/index.d.ts +1 -1
  373. package/dist/store/index.d.ts.map +1 -1
  374. package/dist/store/index.js +1 -1
  375. package/dist/store/index.js.map +1 -1
  376. package/dist/store/kv/revision-record-store.d.ts +70 -0
  377. package/dist/store/kv/revision-record-store.d.ts.map +1 -0
  378. package/dist/store/kv/revision-record-store.js +290 -0
  379. package/dist/store/kv/revision-record-store.js.map +1 -0
  380. package/dist/store/memory/disk.d.ts +9 -7
  381. package/dist/store/memory/disk.d.ts.map +1 -1
  382. package/dist/store/memory/disk.js +256 -98
  383. package/dist/store/memory/disk.js.map +1 -1
  384. package/dist/store/run/disk.d.ts +10 -2
  385. package/dist/store/run/disk.d.ts.map +1 -1
  386. package/dist/store/run/disk.js +70 -4
  387. package/dist/store/run/disk.js.map +1 -1
  388. package/dist/store/run/memory.d.ts +4 -2
  389. package/dist/store/run/memory.d.ts.map +1 -1
  390. package/dist/store/run/memory.js +15 -1
  391. package/dist/store/run/memory.js.map +1 -1
  392. package/dist/store/session/disk.d.ts +9 -0
  393. package/dist/store/session/disk.d.ts.map +1 -1
  394. package/dist/store/session/disk.js +57 -5
  395. package/dist/store/session/disk.js.map +1 -1
  396. package/dist/store/session/memory.d.ts +1 -0
  397. package/dist/store/session/memory.d.ts.map +1 -1
  398. package/dist/store/session/memory.js +14 -0
  399. package/dist/store/session/memory.js.map +1 -1
  400. package/dist/store/topic/memory.d.ts +1 -2
  401. package/dist/store/topic/memory.d.ts.map +1 -1
  402. package/dist/store/topic/memory.js +4 -5
  403. package/dist/store/topic/memory.js.map +1 -1
  404. package/dist/store/topic/objective.d.ts +8 -4
  405. package/dist/store/topic/objective.d.ts.map +1 -1
  406. package/dist/store/topic/objective.js +185 -100
  407. package/dist/store/topic/objective.js.map +1 -1
  408. package/dist/store/topic/state.d.ts +1 -2
  409. package/dist/store/topic/state.d.ts.map +1 -1
  410. package/dist/store/topic/state.js +50 -62
  411. package/dist/store/topic/state.js.map +1 -1
  412. package/dist/tools/builtins/bash.d.ts.map +1 -1
  413. package/dist/tools/builtins/bash.js +20 -0
  414. package/dist/tools/builtins/bash.js.map +1 -1
  415. package/dist/tools/builtins/computer-use.d.ts +9 -1
  416. package/dist/tools/builtins/computer-use.d.ts.map +1 -1
  417. package/dist/tools/builtins/computer-use.js.map +1 -1
  418. package/dist/tools/builtins/content-fingerprint.d.ts +8 -7
  419. package/dist/tools/builtins/content-fingerprint.d.ts.map +1 -1
  420. package/dist/tools/builtins/content-fingerprint.js +9 -10
  421. package/dist/tools/builtins/content-fingerprint.js.map +1 -1
  422. package/dist/tools/builtins/edit.d.ts +6 -1
  423. package/dist/tools/builtins/edit.d.ts.map +1 -1
  424. package/dist/tools/builtins/edit.js +166 -27
  425. package/dist/tools/builtins/edit.js.map +1 -1
  426. package/dist/tools/builtins/write-file.d.ts.map +1 -1
  427. package/dist/tools/builtins/write-file.js +45 -19
  428. package/dist/tools/builtins/write-file.js.map +1 -1
  429. package/dist/tools/command-arguments.d.ts +43 -0
  430. package/dist/tools/command-arguments.d.ts.map +1 -0
  431. package/dist/tools/command-arguments.js +52 -0
  432. package/dist/tools/command-arguments.js.map +1 -0
  433. package/dist/tools/coordinator/index.d.ts +2 -0
  434. package/dist/tools/coordinator/index.d.ts.map +1 -1
  435. package/dist/tools/coordinator/index.js +3 -1
  436. package/dist/tools/coordinator/index.js.map +1 -1
  437. package/dist/tools/defineTool.d.ts +10 -0
  438. package/dist/tools/defineTool.d.ts.map +1 -1
  439. package/dist/tools/defineTool.js +1 -0
  440. package/dist/tools/defineTool.js.map +1 -1
  441. package/dist/tools/env-scrub.d.ts +7 -5
  442. package/dist/tools/env-scrub.d.ts.map +1 -1
  443. package/dist/tools/env-scrub.js +7 -5
  444. package/dist/tools/env-scrub.js.map +1 -1
  445. package/dist/tools/goal/index.d.ts +20 -0
  446. package/dist/tools/goal/index.d.ts.map +1 -0
  447. package/dist/tools/goal/index.js +104 -0
  448. package/dist/tools/goal/index.js.map +1 -0
  449. package/dist/tools/memory/index.d.ts +16 -0
  450. package/dist/tools/memory/index.d.ts.map +1 -1
  451. package/dist/tools/memory/index.js +6 -2
  452. package/dist/tools/memory/index.js.map +1 -1
  453. package/dist/tools/memory/search.d.ts +4 -1
  454. package/dist/tools/memory/search.d.ts.map +1 -1
  455. package/dist/tools/memory/search.js +10 -2
  456. package/dist/tools/memory/search.js.map +1 -1
  457. package/dist/types/agent/base.d.ts +11 -3
  458. package/dist/types/agent/base.d.ts.map +1 -1
  459. package/dist/types/agent/factory.d.ts +2 -0
  460. package/dist/types/agent/factory.d.ts.map +1 -1
  461. package/dist/types/agent/reactive.d.ts +2 -0
  462. package/dist/types/agent/reactive.d.ts.map +1 -1
  463. package/dist/types/agent/supervisor.d.ts +6 -0
  464. package/dist/types/agent/supervisor.d.ts.map +1 -1
  465. package/dist/types/agent/task.d.ts +6 -2
  466. package/dist/types/agent/task.d.ts.map +1 -1
  467. package/dist/types/connector/core.d.ts +13 -8
  468. package/dist/types/connector/core.d.ts.map +1 -1
  469. package/dist/types/connector/definition.d.ts +37 -18
  470. package/dist/types/connector/definition.d.ts.map +1 -1
  471. package/dist/types/connector/http.d.ts +6 -0
  472. package/dist/types/connector/http.d.ts.map +1 -1
  473. package/dist/types/connector/mcp.d.ts +24 -6
  474. package/dist/types/connector/mcp.d.ts.map +1 -1
  475. package/dist/types/connector/tenant.d.ts +17 -7
  476. package/dist/types/connector/tenant.d.ts.map +1 -1
  477. package/dist/types/connector/webhook.d.ts +6 -0
  478. package/dist/types/connector/webhook.d.ts.map +1 -1
  479. package/dist/types/goal/index.d.ts +46 -0
  480. package/dist/types/goal/index.d.ts.map +1 -0
  481. package/dist/types/goal/index.js +2 -0
  482. package/dist/types/goal/index.js.map +1 -0
  483. package/dist/types/ids/index.d.ts +2 -0
  484. package/dist/types/ids/index.d.ts.map +1 -1
  485. package/dist/types/ids/index.js.map +1 -1
  486. package/dist/types/message/index.d.ts +79 -13
  487. package/dist/types/message/index.d.ts.map +1 -1
  488. package/dist/types/message/index.js +49 -3
  489. package/dist/types/message/index.js.map +1 -1
  490. package/dist/types/plugin/index.d.ts +7 -5
  491. package/dist/types/plugin/index.d.ts.map +1 -1
  492. package/dist/types/plugin/index.js.map +1 -1
  493. package/dist/types/provider/chat.d.ts +27 -4
  494. package/dist/types/provider/chat.d.ts.map +1 -1
  495. package/dist/types/provider/index.d.ts +1 -1
  496. package/dist/types/provider/index.d.ts.map +1 -1
  497. package/dist/types/provider/interface.d.ts +18 -7
  498. package/dist/types/provider/interface.d.ts.map +1 -1
  499. package/dist/types/provider/model.d.ts +12 -0
  500. package/dist/types/provider/model.d.ts.map +1 -1
  501. package/dist/types/provider/stream.d.ts +6 -0
  502. package/dist/types/provider/stream.d.ts.map +1 -1
  503. package/dist/types/rag/embedding.d.ts +15 -2
  504. package/dist/types/rag/embedding.d.ts.map +1 -1
  505. package/dist/types/rag/ingestion.d.ts +2 -2
  506. package/dist/types/rag/ingestion.d.ts.map +1 -1
  507. package/dist/types/rag/knowledge-base.d.ts +3 -3
  508. package/dist/types/rag/knowledge-base.d.ts.map +1 -1
  509. package/dist/types/rag/retrieval.d.ts +2 -2
  510. package/dist/types/rag/retrieval.d.ts.map +1 -1
  511. package/dist/types/rag/scope.d.ts +4 -0
  512. package/dist/types/rag/scope.d.ts.map +1 -1
  513. package/dist/types/rag/vector.d.ts +5 -2
  514. package/dist/types/rag/vector.d.ts.map +1 -1
  515. package/dist/types/run/config.d.ts +20 -0
  516. package/dist/types/run/config.d.ts.map +1 -1
  517. package/dist/types/run/events.d.ts +25 -1
  518. package/dist/types/run/events.d.ts.map +1 -1
  519. package/dist/types/run/events.js.map +1 -1
  520. package/dist/types/run/metadata.d.ts +2 -0
  521. package/dist/types/run/metadata.d.ts.map +1 -1
  522. package/dist/types/run/step.d.ts +2 -6
  523. package/dist/types/run/step.d.ts.map +1 -1
  524. package/dist/types/run/step.js.map +1 -1
  525. package/dist/types/run/store.d.ts +55 -2
  526. package/dist/types/run/store.d.ts.map +1 -1
  527. package/dist/types/sandbox/index.d.ts +47 -6
  528. package/dist/types/sandbox/index.d.ts.map +1 -1
  529. package/dist/types/sandbox/index.js +23 -10
  530. package/dist/types/sandbox/index.js.map +1 -1
  531. package/dist/types/session/store.d.ts +13 -0
  532. package/dist/types/session/store.d.ts.map +1 -1
  533. package/dist/types/tool/index.d.ts +33 -11
  534. package/dist/types/tool/index.d.ts.map +1 -1
  535. package/dist/types/tool/index.js.map +1 -1
  536. package/dist/types/topic/entity.d.ts +3 -4
  537. package/dist/types/topic/entity.d.ts.map +1 -1
  538. package/dist/types/topic/store.d.ts +3 -3
  539. package/dist/utils/id.d.ts +3 -1
  540. package/dist/utils/id.d.ts.map +1 -1
  541. package/dist/utils/id.js +4 -0
  542. package/dist/utils/id.js.map +1 -1
  543. package/dist/utils/process-environment.d.ts +26 -0
  544. package/dist/utils/process-environment.d.ts.map +1 -0
  545. package/dist/utils/process-environment.js +78 -0
  546. package/dist/utils/process-environment.js.map +1 -0
  547. package/dist/vault/InMemoryCredentialVault.d.ts +2 -0
  548. package/dist/vault/InMemoryCredentialVault.d.ts.map +1 -1
  549. package/dist/vault/InMemoryCredentialVault.js +24 -4
  550. package/dist/vault/InMemoryCredentialVault.js.map +1 -1
  551. package/dist/vault/instrumentation.d.ts.map +1 -1
  552. package/dist/vault/instrumentation.js +15 -0
  553. package/dist/vault/instrumentation.js.map +1 -1
  554. package/package.json +1 -1
  555. package/src/advisory/executor.ts +4 -1
  556. package/src/agents/ReactiveAgent.ts +12 -0
  557. package/src/agents/RouterAgent.ts +25 -3
  558. package/src/agents/SupervisorAgent.ts +33 -11
  559. package/src/agents/runAgent.ts +38 -2
  560. package/src/authorization/command-line.ts +390 -0
  561. package/src/authorization/rules.ts +22 -1
  562. package/src/bridge/a2a/client.ts +384 -97
  563. package/src/bridge/a2a/mapper.ts +5 -0
  564. package/src/bridge/acp/server.ts +184 -42
  565. package/src/bridge/mcp/connector/adapter.ts +28 -20
  566. package/src/bridge/sse/mapper.ts +3 -0
  567. package/src/compaction/dangling.ts +203 -38
  568. package/src/compaction/index.ts +9 -2
  569. package/src/compaction/manual.ts +125 -18
  570. package/src/compaction/plan.ts +42 -11
  571. package/src/compaction/retention.ts +23 -8
  572. package/src/compaction/summary.ts +4 -4
  573. package/src/compaction/verifier.ts +66 -0
  574. package/src/connector/BaseConnector.ts +19 -4
  575. package/src/connector/builtins/http.ts +236 -46
  576. package/src/connector/builtins/webhook.ts +207 -47
  577. package/src/connector/execution-contract.ts +27 -0
  578. package/src/connector/http-operation.ts +238 -0
  579. package/src/connector/mcp/adapter.ts +8 -3
  580. package/src/connector/mcp/client.ts +207 -58
  581. package/src/connector/mcp/http-sse.ts +91 -23
  582. package/src/connector/mcp/prompt-adapter.ts +8 -2
  583. package/src/connector/mcp/stdio.ts +21 -46
  584. package/src/connector/mcp/streamable-http.ts +86 -22
  585. package/src/connector/tools/adapter.ts +23 -14
  586. package/src/connector/tools/definitions.ts +5 -2
  587. package/src/connector/tools/result.ts +21 -0
  588. package/src/connector/web/guarded-fetch.ts +188 -48
  589. package/src/constants/sandbox/index.ts +3 -2
  590. package/src/contracts/api.ts +2 -0
  591. package/src/contracts/schemas.ts +7 -0
  592. package/src/directory/derive-supervisor.ts +8 -0
  593. package/src/directory/derive.ts +8 -0
  594. package/src/directory/load.ts +2 -0
  595. package/src/directory/types.ts +4 -0
  596. package/src/eval/experiment.ts +160 -111
  597. package/src/eval/judge.ts +13 -2
  598. package/src/eval/types.ts +7 -1
  599. package/src/manager/agent/lifecycle.ts +28 -12
  600. package/src/manager/connector/environment.ts +3 -1
  601. package/src/manager/connector/lifecycle.ts +364 -24
  602. package/src/manager/connector/tenant.ts +56 -23
  603. package/src/manager/goal/activation.ts +52 -0
  604. package/src/manager/index.ts +10 -2
  605. package/src/manager/run/persistence.ts +6 -1
  606. package/src/manager/topic/dependency.ts +39 -0
  607. package/src/manager/topic/lifecycle.ts +19 -31
  608. package/src/plugin/index.ts +1 -0
  609. package/src/plugin/lifecycle.ts +180 -39
  610. package/src/plugin/loader.ts +70 -13
  611. package/src/provider/collect-chat-completion.ts +3 -0
  612. package/src/provider/fallback.ts +79 -11
  613. package/src/provider/idle-timeout.ts +143 -17
  614. package/src/provider/index.ts +2 -0
  615. package/src/provider/instrumentation.ts +1 -0
  616. package/src/provider/retry.ts +16 -1
  617. package/src/public-runtime.ts +190 -32
  618. package/src/public-tools.ts +5 -0
  619. package/src/public-types.ts +85 -11
  620. package/src/rag/embedding.ts +147 -19
  621. package/src/rag/index.ts +1 -1
  622. package/src/rag/ingestion.ts +16 -2
  623. package/src/rag/knowledge-base.ts +13 -4
  624. package/src/rag/operation.ts +28 -0
  625. package/src/rag/rag-tool.ts +6 -3
  626. package/src/rag/retriever.ts +62 -11
  627. package/src/rag/vector-store.ts +8 -2
  628. package/src/registry/command/kernel-commands.ts +223 -4
  629. package/src/run/reporter.ts +10 -0
  630. package/src/run-query/index.ts +84 -15
  631. package/src/runtime/query/context.ts +13 -3
  632. package/src/runtime/query/executor.ts +90 -17
  633. package/src/runtime/query/guard.ts +12 -0
  634. package/src/runtime/query/index.ts +652 -103
  635. package/src/runtime/query/iteration/index.ts +89 -13
  636. package/src/runtime/query/iteration/phases/compaction.ts +120 -55
  637. package/src/runtime/query/iteration/phases/context.ts +4 -0
  638. package/src/runtime/query/iteration/phases/tool-review.ts +28 -0
  639. package/src/runtime/query/iteration/stream-turn.ts +3 -0
  640. package/src/runtime/query/project-instructions.ts +212 -0
  641. package/src/runtime/query/request-rich-content.ts +153 -0
  642. package/src/runtime/query/result.ts +12 -1
  643. package/src/runtime/query/resume-pending.ts +20 -18
  644. package/src/runtime/query/resume-run.ts +52 -8
  645. package/src/runtime/query/run-state.ts +11 -1
  646. package/src/runtime/query/sandbox-lifecycle.ts +210 -0
  647. package/src/sandbox/isolation.ts +9 -0
  648. package/src/sandbox/provider/local.ts +255 -90
  649. package/src/sandbox/terminal.ts +13 -5
  650. package/src/session/errors.ts +68 -42
  651. package/src/session/handoff/broadcast.ts +20 -14
  652. package/src/session/handoff/single.ts +14 -13
  653. package/src/store/attachment/index.ts +65 -3
  654. package/src/store/feedback/conformance.ts +39 -0
  655. package/src/store/feedback/disk.ts +128 -82
  656. package/src/store/goal/index.ts +594 -0
  657. package/src/store/index.ts +1 -1
  658. package/src/store/kv/revision-record-store.ts +346 -0
  659. package/src/store/memory/disk.ts +288 -113
  660. package/src/store/run/disk.ts +96 -5
  661. package/src/store/run/memory.ts +22 -2
  662. package/src/store/session/disk.ts +93 -6
  663. package/src/store/session/memory.ts +22 -0
  664. package/src/store/topic/memory.ts +4 -5
  665. package/src/store/topic/objective.ts +215 -100
  666. package/src/store/topic/state.ts +100 -63
  667. package/src/tools/builtins/bash.ts +21 -0
  668. package/src/tools/builtins/computer-use.ts +9 -1
  669. package/src/tools/builtins/content-fingerprint.ts +9 -12
  670. package/src/tools/builtins/edit.ts +190 -27
  671. package/src/tools/builtins/write-file.ts +55 -19
  672. package/src/tools/command-arguments.ts +54 -0
  673. package/src/tools/coordinator/index.ts +4 -1
  674. package/src/tools/defineTool.ts +11 -0
  675. package/src/tools/env-scrub.ts +7 -5
  676. package/src/tools/goal/index.ts +129 -0
  677. package/src/tools/memory/index.ts +26 -3
  678. package/src/tools/memory/search.ts +20 -3
  679. package/src/types/agent/base.ts +12 -3
  680. package/src/types/agent/factory.ts +2 -0
  681. package/src/types/agent/reactive.ts +2 -0
  682. package/src/types/agent/supervisor.ts +6 -0
  683. package/src/types/agent/task.ts +6 -2
  684. package/src/types/connector/core.ts +13 -8
  685. package/src/types/connector/definition.ts +54 -20
  686. package/src/types/connector/http.ts +7 -0
  687. package/src/types/connector/mcp.ts +27 -6
  688. package/src/types/connector/tenant.ts +21 -7
  689. package/src/types/connector/webhook.ts +7 -0
  690. package/src/types/goal/index.ts +50 -0
  691. package/src/types/ids/index.ts +2 -0
  692. package/src/types/message/index.ts +147 -12
  693. package/src/types/plugin/index.ts +7 -5
  694. package/src/types/provider/chat.ts +35 -4
  695. package/src/types/provider/index.ts +1 -1
  696. package/src/types/provider/interface.ts +22 -7
  697. package/src/types/provider/model.ts +13 -0
  698. package/src/types/provider/stream.ts +6 -0
  699. package/src/types/rag/embedding.ts +16 -2
  700. package/src/types/rag/ingestion.ts +2 -1
  701. package/src/types/rag/knowledge-base.ts +7 -3
  702. package/src/types/rag/retrieval.ts +2 -1
  703. package/src/types/rag/scope.ts +5 -0
  704. package/src/types/rag/vector.ts +5 -2
  705. package/src/types/run/config.ts +20 -0
  706. package/src/types/run/events.ts +28 -3
  707. package/src/types/run/metadata.ts +2 -0
  708. package/src/types/run/step.ts +2 -7
  709. package/src/types/run/store.ts +60 -2
  710. package/src/types/sandbox/index.ts +57 -14
  711. package/src/types/session/store.ts +18 -0
  712. package/src/types/tool/index.ts +33 -11
  713. package/src/types/topic/entity.ts +3 -4
  714. package/src/types/topic/store.ts +3 -3
  715. package/src/utils/id.ts +6 -0
  716. package/src/utils/process-environment.ts +101 -0
  717. package/src/vault/InMemoryCredentialVault.ts +29 -4
  718. package/src/vault/instrumentation.ts +24 -0
@@ -8,7 +8,11 @@ import {
8
8
  } from '../../advisory/index.js'
9
9
  import { drainQueuedMessages } from '../../agents/handle.js'
10
10
  import { AuthorizationGate } from '../../authorization/gate.js'
11
- import { findDanglingMessages, removeDanglingMessages } from '../../compaction/dangling.js'
11
+ import {
12
+ type ToolHistoryRepairReport,
13
+ repairToolMessageHistory,
14
+ toolHistoryRepairChanged,
15
+ } from '../../compaction/dangling.js'
12
16
  import { extractFromUserMessage } from '../../compaction/extractor.js'
13
17
  import { WorkingStateManager } from '../../compaction/manager.js'
14
18
  import type { ContextReducer } from '../../compaction/reducer.js'
@@ -26,6 +30,7 @@ import {
26
30
  type ServingMember,
27
31
  withProviderFallback,
28
32
  } from '../../provider/fallback.js'
33
+ import { resolveStreamIdleTimeoutMs, withStreamIdleTimeout } from '../../provider/idle-timeout.js'
29
34
  import { type ProviderRetryConfig, withProviderRetry } from '../../provider/retry.js'
30
35
  import { DefaultFilesystemMigrator, loggingMigrationSink } from '../../session/migration/index.js'
31
36
  import type { PathBuilder } from '../../session/workspace/path-builder.js'
@@ -37,6 +42,7 @@ import {
37
42
  parentContext,
38
43
  serializeSpan,
39
44
  } from '../../telemetry/attributes.js'
45
+ import type { SerializedSpanContext } from '../../telemetry/attributes.js'
40
46
  import { recordRunDuration } from '../../telemetry/metrics.js'
41
47
  import { getTracer } from '../../telemetry/runtime-accessors.js'
42
48
  import { buildAdvisoryTools } from '../../tools/advisory/index.js'
@@ -61,7 +67,12 @@ import {
61
67
  } from '../../types/hitl/index.js'
62
68
  import type { RunId, SessionId, TenantId } from '../../types/ids/index.js'
63
69
  import type { InvocationState } from '../../types/invocation/index.js'
64
- import { type Message, createSystemMessage } from '../../types/message/index.js'
70
+ import {
71
+ type AssistantMessage,
72
+ type Message,
73
+ type UserMessage,
74
+ createSystemMessage,
75
+ } from '../../types/message/index.js'
65
76
  import type { AgentPersona } from '../../types/persona/index.js'
66
77
  import type { LLMProvider } from '../../types/provider/index.js'
67
78
  import type { TaskRouterConfig } from '../../types/router/index.js'
@@ -81,6 +92,7 @@ import type {
81
92
  } from '../../types/run/index.js'
82
93
  import type { PromoteMemory } from '../../types/run/memory-promotion.js'
83
94
  import { memoryCandidateFor } from '../../types/run/memory-promotion.js'
95
+ import type { RunState } from '../../types/run/state.js'
84
96
  import type { RunStore } from '../../types/run/store.js'
85
97
  import type { Sandbox, SandboxProvider } from '../../types/sandbox/index.js'
86
98
  import type { ProjectId, TopicId } from '../../types/session/ids.js'
@@ -107,11 +119,18 @@ import { IterationOrchestrator } from './iteration/index.js'
107
119
  import { isCompactionMessage } from './iteration/phases/compaction.js'
108
120
  import { isWorkingMemoryMessage } from './iteration/phases/working-memory.js'
109
121
  import { applyLifecycleHookResults } from './plugin-hooks.js'
122
+ import {
123
+ type ProjectInstructionContext,
124
+ awaitProjectInstructionCallback,
125
+ collapseProjectInstructionSnapshots,
126
+ replaceProjectInstructionSnapshot,
127
+ } from './project-instructions.js'
110
128
  import type { PromptCache } from './prompt-cache.js'
111
129
  import { PromptBuilder } from './prompt.js'
112
130
  import type { PromptSegments } from './prompt.js'
113
131
  import { PendingAnswers, QuestionParkBinding } from './question-park.js'
114
132
  import { RepeatCallTracker } from './repeat-call.js'
133
+ import { resolveMaxRequestRichContentBytes } from './request-rich-content.js'
115
134
  import { ResultAssembler } from './result.js'
116
135
  import {
117
136
  type PendingResumePlan,
@@ -121,6 +140,11 @@ import {
121
140
  recoverCompletedCalls,
122
141
  unansweredToolCalls,
123
142
  } from './resume-pending.js'
143
+ import {
144
+ acquireSandbox,
145
+ resolveSandboxTeardownTimeoutMs,
146
+ teardownSandbox,
147
+ } from './sandbox-lifecycle.js'
124
148
  import type { SteeringChannel } from './steering.js'
125
149
  import { ToolGrantSet } from './tool-grants.js'
126
150
  import { createToolPause } from './tool-pause.js'
@@ -243,7 +267,9 @@ export interface QueryParams {
243
267
  * Host-owned so it can outlive one run — a registry built per run could
244
268
  * never be the thing that kills a run's jobs when the run is already
245
269
  * gone. This run's jobs are torn down in the `finally` below; another
246
- * run's are untouched.
270
+ * run's are untouched. The registry launches host processes, so a run
271
+ * that also supplies a {@link sandboxProvider} does not expose it to tools:
272
+ * background execution is refused rather than silently bypassing the sandbox.
247
273
  */
248
274
  backgroundJobs?: BackgroundJobRegistry
249
275
 
@@ -615,6 +641,12 @@ export interface QueryParams {
615
641
  */
616
642
  inboundMessages?: () => import('../../types/message/index.js').Message[]
617
643
 
644
+ /**
645
+ * Live project policy for this run. Unlike `inboundMessages`, snapshot
646
+ * replacement is durable state and never implies another model turn.
647
+ */
648
+ projectInstructionContext?: ProjectInstructionContext
649
+
618
650
  /**
619
651
  * Where this conversation's durable state lives.
620
652
  *
@@ -631,7 +663,9 @@ export interface QueryParams {
631
663
  * approval hook, and that is not this function. Sharing the object is
632
664
  * what lets an approved plan leave plan mode in the SAME run.
633
665
  */
634
- permissionModeRef?: { current: import('../../types/permission/index.js').PermissionMode }
666
+ permissionModeRef?: {
667
+ current: import('../../types/permission/index.js').PermissionMode
668
+ }
635
669
 
636
670
  /**
637
671
  * A name for the policy `resumeHandler` implements.
@@ -700,6 +734,16 @@ export interface QueryParams {
700
734
 
701
735
  sandboxProvider?: SandboxProvider
702
736
 
737
+ /**
738
+ * Maximum time the run waits for sandbox teardown, in milliseconds.
739
+ *
740
+ * Defaults to 30 seconds. A fresh private signal is passed to `destroy()`;
741
+ * the run also races the returned promise so an implementation that ignores
742
+ * cancellation cannot pin `drainQuery()`. Set `0` to retain an unbounded
743
+ * teardown wait.
744
+ */
745
+ sandboxTeardownTimeoutMs?: number
746
+
703
747
  invocationState?: InvocationState
704
748
 
705
749
  /**
@@ -715,6 +759,12 @@ export interface QueryParams {
715
759
  strictCapabilities?: boolean
716
760
  }
717
761
 
762
+ type SelectedResumeState = RunState & {
763
+ readonly checkpointId: CheckpointId
764
+ readonly traceContext?: SerializedSpanContext
765
+ }
766
+ const selectedResumeStates = new WeakMap<QueryParams, SelectedResumeState>()
767
+
718
768
  /**
719
769
  * Refuse to price a run whose tokens two differently-priced members may produce.
720
770
  *
@@ -810,11 +860,49 @@ async function resolveProviderContextWindow(
810
860
  provider: LLMProvider,
811
861
  model: string | undefined,
812
862
  signal: AbortSignal | undefined,
863
+ timeoutMs: number,
813
864
  log: Logger,
814
865
  ): Promise<number | undefined> {
815
866
  if (!provider.resolveContextWindow || !model) return undefined
867
+ if (signal?.aborted) return undefined
868
+
869
+ // The resolver is an optional optimisation that runs before RunContext
870
+ // owns its child controller. Give it a private deadline signal and fuse
871
+ // caller cancellation into that transport in the safe direction: neither
872
+ // outcome aborts the caller's controller. Passing a signal is necessary
873
+ // but not sufficient, because a third-party driver can accept it and still
874
+ // leave its promise pending; the race below makes fallback independent of
875
+ // driver cooperation. Promise.race keeps the losing provider promise
876
+ // observed, so a later rejection cannot become unhandled.
877
+ const deadline = new AbortController()
878
+ const resolverSignal = signal ? AbortSignal.any([signal, deadline.signal]) : deadline.signal
879
+ const interrupted = Symbol('provider-context-window-interrupted')
880
+ let onAbort: (() => void) | undefined
881
+ const interruption = new Promise<typeof interrupted>((resolve) => {
882
+ onAbort = () => resolve(interrupted)
883
+ resolverSignal.addEventListener('abort', onAbort, { once: true })
884
+ })
885
+ // Wire and directory config validation already limit this field to one
886
+ // hour. The clamp also keeps a direct QueryParams caller from triggering
887
+ // Node's >2^31-1 one-millisecond timer coercion and turning a huge run
888
+ // budget into an immediate metadata fallback.
889
+ const deadlineMs = Math.min(Math.max(0, timeoutMs), 2_147_483_647)
890
+ const timer = setTimeout(() => {
891
+ deadline.abort(new Error(`Provider context-window lookup exceeded ${deadlineMs}ms`))
892
+ }, deadlineMs)
893
+
816
894
  try {
817
- const reported = await provider.resolveContextWindow(model, signal)
895
+ const resolution = provider.resolveContextWindow(model, resolverSignal)
896
+ const reported = await Promise.race([resolution, interruption])
897
+ if (reported === interrupted) {
898
+ if (deadline.signal.aborted) {
899
+ log.debug('Provider context-window lookup timed out; using the table', {
900
+ 'namzu.model.id': model,
901
+ 'namzu.runtime.timeout_ms': deadlineMs,
902
+ })
903
+ }
904
+ return undefined
905
+ }
818
906
  return typeof reported === 'number' && reported > 0 ? reported : undefined
819
907
  } catch (err) {
820
908
  log.debug('Provider could not report a context window; using the table', {
@@ -822,10 +910,76 @@ async function resolveProviderContextWindow(
822
910
  'namzu.error.message': toErrorMessage(err),
823
911
  })
824
912
  return undefined
913
+ } finally {
914
+ clearTimeout(timer)
915
+ if (onAbort) resolverSignal.removeEventListener('abort', onAbort)
916
+ }
917
+ }
918
+
919
+ interface PendingHistoryRepairEvent {
920
+ readonly source: 'fresh-history' | 'abandoned-checkpoint'
921
+ readonly report: ToolHistoryRepairReport
922
+ }
923
+
924
+ /**
925
+ * Project historical system messages exactly as a new run will persist them.
926
+ *
927
+ * Arbitrary historical prompt floors are rebuilt for this run and therefore
928
+ * never reach its provider-bound conversation. Repair must happen AFTER that
929
+ * removal: treating a soon-to-be-dropped system message as a tool-result
930
+ * boundary can replace an exact real result with an invented unknown outcome.
931
+ * The two state-bearing system forms survive; fresh inherited compaction is
932
+ * pinned until this run can prove it reconstructed equivalent state.
933
+ */
934
+ function projectStateBearingHistory(
935
+ messages: readonly Message[],
936
+ options: { readonly pinCompaction: boolean },
937
+ ): Message[] {
938
+ const projected: Message[] = []
939
+ for (const message of messages) {
940
+ if (message.role !== 'system') {
941
+ projected.push(message)
942
+ continue
943
+ }
944
+ if (isCompactionMessage(message.content)) {
945
+ projected.push(options.pinCompaction ? { ...message, retain: true } : message)
946
+ } else if (isWorkingMemoryMessage(message.content)) {
947
+ projected.push(message)
948
+ }
825
949
  }
950
+ return collapseProjectInstructionSnapshots(projected)
951
+ }
952
+
953
+ /**
954
+ * Remove the incomplete turn still owned by a durable resume plan.
955
+ *
956
+ * The plan re-appends the exact assistant with real/denied/recovered results.
957
+ * Generic history repair must not synthesize a competing result first. Any
958
+ * partial results for that turn are removed too; the executor reconstructs
959
+ * them from the durable run transcript through `recoveredResults`.
960
+ */
961
+ function withoutOwnedResumeTurn(
962
+ messages: readonly Message[],
963
+ assistant: AssistantMessage,
964
+ ): Message[] {
965
+ const ownerIndex = messages.lastIndexOf(assistant)
966
+ if (ownerIndex < 0) {
967
+ throw new NamzuError({
968
+ code: 'invalid_config',
969
+ message: 'A pending checkpoint resume plan does not own a message in its checkpoint.',
970
+ })
971
+ }
972
+ const ownedIds = new Set((assistant.toolCalls ?? []).map((call) => call.id))
973
+ return messages.filter(
974
+ (message, index) =>
975
+ index !== ownerIndex &&
976
+ !(index > ownerIndex && message.role === 'tool' && ownedIds.has(message.toolCallId)),
977
+ )
826
978
  }
827
979
 
828
980
  export async function* query(params: QueryParams): AsyncGenerator<RunEvent, Run> {
981
+ const selectedResumeState = selectedResumeStates.get(params)
982
+ selectedResumeStates.delete(params)
829
983
  // Resolved at the DOOR, before a run id exists or a logger is built.
830
984
  // A caller who set both spellings of a renamed field has a config bug,
831
985
  // and refusing it here costs them nothing; refusing it at the read site
@@ -833,6 +987,20 @@ export async function* query(params: QueryParams): AsyncGenerator<RunEvent, Run>
833
987
  // provider call has been paid for and a partial transcript written.
834
988
  const promptCache = params.promptCache
835
989
  const taskScheduler = params.taskScheduler
990
+ const streamIdleTimeoutMs = resolveStreamIdleTimeoutMs(params.runConfig.streamIdleTimeoutMs)
991
+ const maxRequestRichContentBytes = resolveMaxRequestRichContentBytes(
992
+ params.runConfig.maxRequestRichContentBytes,
993
+ )
994
+ const sandboxTeardownTimeoutMs = resolveSandboxTeardownTimeoutMs(params.sandboxTeardownTimeoutMs)
995
+ // Persist the EFFECTIVE value, not only an override. A run replayed after a
996
+ // later release must be able to explain which liveness policy settled it;
997
+ // an absent field whose meaning follows the currently-installed default
998
+ // would rewrite that evidence at read time.
999
+ const runConfig: AgentRunConfig = {
1000
+ ...params.runConfig,
1001
+ streamIdleTimeoutMs,
1002
+ maxRequestRichContentBytes,
1003
+ }
836
1004
 
837
1005
  // The run's one correlated logger, built before anything below needs
838
1006
  // one — the migration check, the retry/fallback wrappers and `ctx`
@@ -846,7 +1014,7 @@ export async function* query(params: QueryParams): AsyncGenerator<RunEvent, Run>
846
1014
  const runId = params.runId ?? generateRunId()
847
1015
  const log = RunContextFactory.buildLogger({
848
1016
  agentName: params.agentName,
849
- runConfig: params.runConfig,
1017
+ runConfig,
850
1018
  runId,
851
1019
  parentRunId: params.parentRunId,
852
1020
  sessionId: params.sessionId,
@@ -901,9 +1069,11 @@ export async function* query(params: QueryParams): AsyncGenerator<RunEvent, Run>
901
1069
  // call site — so without it the "failed, retrying" and "failed, giving
902
1070
  // up" lines were dead code and a backoff left no trace anywhere.
903
1071
  //
904
- // With a chain declared, the same sentence holds one level out: retry is
905
- // applied per MEMBER and the fallback decorator wraps the result, so the
906
- // composition is `fallback(retry(m0), retry(m1), …)`. That order is not a
1072
+ // With a chain declared, the same sentence holds two levels out. The idle
1073
+ // watchdog is applied to each raw member, retry wraps that, and fallback
1074
+ // wraps the members: `fallback(retry(idle(m0)), retry(idle(m1)), …)`. The
1075
+ // idle layer cannot sit outside retry, because its timer would then count a
1076
+ // legitimate backoff as provider silence. This order is not a
907
1077
  // preference. Assembled the other way round — which is what a host gets if
908
1078
  // it wraps its own chain and hands the result in, because this function
909
1079
  // would then wrap THAT in retry — an exhausted chain gets restarted from
@@ -916,8 +1086,15 @@ export async function* query(params: QueryParams): AsyncGenerator<RunEvent, Run>
916
1086
  ]
917
1087
  assertCostIsAttributable(chain, params.pricing)
918
1088
  assertBudgetIsMeasurable(params)
919
- const withRetry = (provider: LLMProvider): LLMProvider =>
920
- params.retry === false ? provider : withProviderRetry(provider, { config: params.retry, log })
1089
+ const withRecovery = (provider: LLMProvider): LLMProvider => {
1090
+ const withIdleBound = withStreamIdleTimeout(provider, {
1091
+ idleTimeoutMs: streamIdleTimeoutMs,
1092
+ log,
1093
+ })
1094
+ return params.retry === false
1095
+ ? withIdleBound
1096
+ : withProviderRetry(withIdleBound, { config: params.retry, log })
1097
+ }
921
1098
  // Who is serving right now, for the run RECORD rather than for the request.
922
1099
  //
923
1100
  // It starts at the head and moves only when the chain does, which is the
@@ -929,7 +1106,10 @@ export async function* query(params: QueryParams): AsyncGenerator<RunEvent, Run>
929
1106
  current: { index: 0, providerId: params.provider.id },
930
1107
  }
931
1108
  const resilientProvider = withProviderFallback(
932
- chain.map((member) => ({ ...member, provider: withRetry(member.provider) })),
1109
+ chain.map((member) => ({
1110
+ ...member,
1111
+ provider: withRecovery(member.provider),
1112
+ })),
933
1113
  {
934
1114
  log,
935
1115
  onSwap: (to) => {
@@ -950,8 +1130,9 @@ export async function* query(params: QueryParams): AsyncGenerator<RunEvent, Run>
950
1130
  // window is an optimisation over a working default, not a prerequisite.
951
1131
  const providerContextWindow = await resolveProviderContextWindow(
952
1132
  resilientProvider,
953
- params.runConfig.model,
1133
+ runConfig.model,
954
1134
  params.signal,
1135
+ runConfig.timeoutMs,
955
1136
  log,
956
1137
  )
957
1138
 
@@ -1005,14 +1186,91 @@ export async function* query(params: QueryParams): AsyncGenerator<RunEvent, Run>
1005
1186
  // image is a model answering about a picture it never saw.
1006
1187
  const seeded: Message[] =
1007
1188
  queuedForThisRun.length > 0 ? [...queuedForThisRun, ...params.messages] : params.messages
1008
- const initialMessages: Message[] = [...(await resolveAttachments(seeded, params.attachmentStore))]
1189
+ let resolvedInitialMessages: Message[]
1190
+ let attachmentResolutionCancelled = false
1191
+ try {
1192
+ resolvedInitialMessages = [
1193
+ ...(await resolveAttachments(seeded, params.attachmentStore, {
1194
+ signal: params.signal,
1195
+ })),
1196
+ ]
1197
+ params.signal?.throwIfAborted()
1198
+ } catch (error) {
1199
+ // Attachment materialization precedes RunContext construction so stored
1200
+ // bytes never enter a live run's checkpoints. Cancellation still belongs
1201
+ // to that run: preserve the exact input refs, build the context below, and
1202
+ // let its normal terminal path classify/persist a cancelled Run. Every
1203
+ // other store failure remains a pre-run refusal.
1204
+ if (!params.signal?.aborted || error !== params.signal.reason) throw error
1205
+ resolvedInitialMessages = [...seeded]
1206
+ attachmentResolutionCancelled = true
1207
+ }
1208
+ if (!attachmentResolutionCancelled && params.projectInstructionContext?.prepareInitialSnapshot) {
1209
+ const preparationSignal = params.signal ?? new AbortController().signal
1210
+ let snapshot: UserMessage | null | undefined
1211
+ try {
1212
+ const prepared = await awaitProjectInstructionCallback(preparationSignal, () =>
1213
+ params.projectInstructionContext?.prepareInitialSnapshot?.({
1214
+ messages: [...resolvedInitialMessages],
1215
+ signal: preparationSignal,
1216
+ }),
1217
+ )
1218
+ // The callback promise can settle, remove its listener, and queue this
1219
+ // continuation immediately before a queued abort. Publication is a
1220
+ // separate authority boundary, so fence it too.
1221
+ preparationSignal.throwIfAborted()
1222
+ snapshot = prepared
1223
+ } catch (error) {
1224
+ // This callback runs before RunContext owns its child controller. A
1225
+ // caller cancellation here still belongs to the run: publish no late
1226
+ // snapshot and let the context below settle the normal cancelled Run.
1227
+ // Compare the exact reason: a callback failure that won first must not
1228
+ // be erased merely because cancellation arrived before this catch ran.
1229
+ if (!preparationSignal.aborted || error !== preparationSignal.reason) throw error
1230
+ }
1231
+ if (snapshot !== undefined) {
1232
+ resolvedInitialMessages = replaceProjectInstructionSnapshot(
1233
+ resolvedInitialMessages,
1234
+ snapshot,
1235
+ 'before-latest-user',
1236
+ )
1237
+ }
1238
+ }
1239
+ const pendingHistoryRepairs: PendingHistoryRepairEvent[] = []
1240
+ const projectedInitialMessages = collapseProjectInstructionSnapshots(
1241
+ params.resumeFromCheckpoint || params.continuationMode
1242
+ ? resolvedInitialMessages
1243
+ : projectStateBearingHistory(resolvedInitialMessages, {
1244
+ pinCompaction: true,
1245
+ }),
1246
+ )
1247
+ const initialRepair = params.resumeFromCheckpoint
1248
+ ? { messages: projectedInitialMessages, report: undefined }
1249
+ : repairToolMessageHistory(projectedInitialMessages)
1250
+ const initialMessages = initialRepair.messages
1251
+ if (initialRepair.report && toolHistoryRepairChanged(initialRepair.report)) {
1252
+ pendingHistoryRepairs.push({
1253
+ source: 'fresh-history',
1254
+ report: initialRepair.report,
1255
+ })
1256
+ log.warn('Repaired provider-invalid tool history before starting the run', {
1257
+ [NAMZU.RUN_ID]: runId,
1258
+ 'namzu.history.source': 'fresh-history',
1259
+ 'namzu.history.duplicate_tool_results_removed':
1260
+ initialRepair.report.duplicateToolResultsRemoved,
1261
+ 'namzu.history.orphaned_tool_results_removed':
1262
+ initialRepair.report.orphanedToolResultsRemoved,
1263
+ 'namzu.history.synthetic_tool_results_inserted':
1264
+ initialRepair.report.syntheticToolResultsInserted,
1265
+ })
1266
+ }
1009
1267
 
1010
1268
  const ctx = RunContextFactory.build({
1011
1269
  ...(topicState ? { topicPermissionMode: topicState.permissionMode } : {}),
1012
1270
  ...(params.permissionModeRef ? { permissionModeRef: params.permissionModeRef } : {}),
1013
1271
  agentId: params.agentId,
1014
1272
  agentName: params.agentName,
1015
- runConfig: params.runConfig,
1273
+ runConfig,
1016
1274
  provider: resilientProvider,
1017
1275
  workingDirectory: params.workingDirectory,
1018
1276
  pricing: params.pricing,
@@ -1102,6 +1360,108 @@ export async function* query(params: QueryParams): AsyncGenerator<RunEvent, Run>
1102
1360
  const eventTranslator = new EventTranslator(ctx.runMgr, undefined, ctx.log)
1103
1361
  eventTranslator.wireActivityStore(ctx.activityStore, ctx.runId)
1104
1362
  eventTranslator.wirePlanManager(ctx.planManager, ctx.runId)
1363
+ eventTranslator.setGeneration(params.claimFence)
1364
+
1365
+ if (attachmentResolutionCancelled) {
1366
+ // Attachment materialization happens before RunContext exists. Once it
1367
+ // observes cancellation, do only the work required to leave an honest
1368
+ // durable run: initialize the record, retain the unresolved references,
1369
+ // and settle through the ordinary cancellation classifier. Prompt
1370
+ // contributions/cache, host callbacks, tools, plugins, sandbox, guardrails,
1371
+ // advisors, and providers are all authority-bearing work and stay out.
1372
+ if (params.resumeFromCheckpoint && !selectedResumeState) {
1373
+ // The canonical resume surface hands query the checkpoint state it
1374
+ // already selected. A raw resume query has no such snapshot; after
1375
+ // cancellation, reading the store again could hang without a signal,
1376
+ // while persisting without it would erase the existing transcript.
1377
+ // Refuse before binding/persisting rather than choose either failure.
1378
+ ctx.abortController.signal.throwIfAborted()
1379
+ }
1380
+
1381
+ const cancelledPrompt = params.systemPrompt ?? ''
1382
+ const cancelledAssembler = new ResultAssembler({
1383
+ runMgr: ctx.runMgr,
1384
+ planManager: ctx.planManager,
1385
+ activityStore: ctx.activityStore,
1386
+ log: ctx.log,
1387
+ emitEvent: eventTranslator.emitEvent,
1388
+ drainPending: () => eventTranslator.drainPending(),
1389
+ signal: ctx.abortController.signal,
1390
+ })
1391
+ const rootSpan = getTracer().startSpan(
1392
+ agentRunSpanName(params.agentName),
1393
+ {},
1394
+ parentContext(params.parentSpan ?? selectedResumeState?.traceContext),
1395
+ )
1396
+ rootSpan.setAttributes({
1397
+ [NAMZU.RUN_ID]: ctx.runMgr.id,
1398
+ [GENAI.AGENT_NAME]: params.agentName,
1399
+ [GENAI.AGENT_ID]: params.agentId,
1400
+ [GENAI.REQUEST_MODEL]: runConfig.model,
1401
+ [GENAI.SYSTEM]: params.provider.id,
1402
+ })
1403
+
1404
+ try {
1405
+ await ctx.runMgr.init()
1406
+ if (selectedResumeState) {
1407
+ ctx.runMgr.restoreUsage(
1408
+ selectedResumeState.tokenUsage,
1409
+ selectedResumeState.costInfo,
1410
+ selectedResumeState.currentIteration,
1411
+ )
1412
+ for (const message of selectedResumeState.messages) ctx.runMgr.pushMessage(message)
1413
+ for (const queued of queuedForThisRun) ctx.runMgr.pushMessage(queued)
1414
+ } else if (params.continuationMode) {
1415
+ for (const message of initialMessages) ctx.runMgr.pushMessage(message)
1416
+ } else {
1417
+ ctx.runMgr.pushMessage(createSystemMessage(cancelledPrompt, 'cache'))
1418
+ for (const message of initialMessages) ctx.runMgr.pushMessage(message)
1419
+ }
1420
+ if (params.eventCursor) {
1421
+ yield* catchUpFromCursor(
1422
+ ctx.runMgr,
1423
+ params.eventCursor,
1424
+ params.onEventReplay,
1425
+ params.claimFence,
1426
+ (error) => {
1427
+ ctx.log.warn('Replay observer failed after attachment cancellation', {
1428
+ 'exception.message': toErrorMessage(error),
1429
+ })
1430
+ },
1431
+ )
1432
+ }
1433
+ if (selectedResumeState) {
1434
+ await eventTranslator.emitEvent({
1435
+ type: 'run_resuming',
1436
+ runId: ctx.runId,
1437
+ fromCheckpointId: selectedResumeState.checkpointId,
1438
+ })
1439
+ yield* eventTranslator.drainPending()
1440
+ }
1441
+ ctx.runMgr.markRunning()
1442
+ await eventTranslator.emitEvent({
1443
+ type: 'run_started',
1444
+ runId: ctx.runId,
1445
+ systemPrompt: cancelledPrompt,
1446
+ })
1447
+ yield* eventTranslator.drainPending()
1448
+ ctx.abortController.signal.throwIfAborted()
1449
+ } catch (error) {
1450
+ // Attachment resolution has already observed the caller's abort. A
1451
+ // reconnect callback can still throw while replay is being reported,
1452
+ // but it cannot replace that terminal cause or turn a cancelled run
1453
+ // into an unpersisted rejection.
1454
+ const terminalError = ctx.abortController.signal.aborted
1455
+ ? ctx.abortController.signal.reason
1456
+ : error
1457
+ yield* cancelledAssembler.handleError(terminalError, rootSpan)
1458
+ } finally {
1459
+ rootSpan.end()
1460
+ }
1461
+
1462
+ return await cancelledAssembler.finalize()
1463
+ }
1464
+
1105
1465
  const unsubscribeTaskStore = params.taskStore
1106
1466
  ? eventTranslator.wireTaskStore(params.taskStore, ctx.runId)
1107
1467
  : undefined
@@ -1161,7 +1521,11 @@ export async function* query(params: QueryParams): AsyncGenerator<RunEvent, Run>
1161
1521
  throw new NamzuError({
1162
1522
  code: 'capability_unavailable',
1163
1523
  message,
1164
- details: { providerId: params.provider.id, capability: 'tools', registeredToolCount },
1524
+ details: {
1525
+ providerId: params.provider.id,
1526
+ capability: 'tools',
1527
+ registeredToolCount,
1528
+ },
1165
1529
  })
1166
1530
  }
1167
1531
  ctx.log.warn('Capability mismatch: the provider declares no tool support', {
@@ -1177,7 +1541,11 @@ export async function* query(params: QueryParams): AsyncGenerator<RunEvent, Run>
1177
1541
  throw new NamzuError({
1178
1542
  code: 'capability_unavailable',
1179
1543
  message,
1180
- details: { providerId: params.provider.id, capability: 'vision', attachmentMessageCount },
1544
+ details: {
1545
+ providerId: params.provider.id,
1546
+ capability: 'vision',
1547
+ attachmentMessageCount,
1548
+ },
1181
1549
  })
1182
1550
  }
1183
1551
  ctx.log.warn('Capability mismatch: the provider declares no vision support', {
@@ -1193,7 +1561,11 @@ export async function* query(params: QueryParams): AsyncGenerator<RunEvent, Run>
1193
1561
  throw new NamzuError({
1194
1562
  code: 'capability_unavailable',
1195
1563
  message,
1196
- details: { providerId: params.provider.id, capability: 'documents', documentMessageCount },
1564
+ details: {
1565
+ providerId: params.provider.id,
1566
+ capability: 'documents',
1567
+ documentMessageCount,
1568
+ },
1197
1569
  })
1198
1570
  }
1199
1571
  ctx.log.warn('Capability mismatch: the provider declares no document support', {
@@ -1253,7 +1625,7 @@ export async function* query(params: QueryParams): AsyncGenerator<RunEvent, Run>
1253
1625
  runId: ctx.runId,
1254
1626
  workingDirectory: ctx.cwd,
1255
1627
  permissionMode: () => ctx.permissionMode.current,
1256
- env: params.runConfig.env ?? {},
1628
+ env: runConfig.env ?? {},
1257
1629
  abortSignal: ctx.abortController.signal,
1258
1630
  allowedTools: effectiveAllowedTools,
1259
1631
  invocationState: params.invocationState,
@@ -1319,10 +1691,10 @@ export async function* query(params: QueryParams): AsyncGenerator<RunEvent, Run>
1319
1691
  })
1320
1692
 
1321
1693
  const guard = new GuardCoordinator({
1322
- tokenBudget: params.runConfig.tokenBudget,
1323
- timeoutMs: params.runConfig.timeoutMs,
1324
- costLimitUsd: params.runConfig.costLimitUsd,
1325
- maxIterations: params.runConfig.maxIterations,
1694
+ tokenBudget: runConfig.tokenBudget,
1695
+ timeoutMs: runConfig.timeoutMs,
1696
+ costLimitUsd: runConfig.costLimitUsd,
1697
+ maxIterations: runConfig.maxIterations,
1326
1698
  })
1327
1699
 
1328
1700
  const checkpointMgr = new CheckpointManager(
@@ -1358,14 +1730,29 @@ export async function* query(params: QueryParams): AsyncGenerator<RunEvent, Run>
1358
1730
 
1359
1731
  let advisoryCtx: AdvisoryContext | undefined
1360
1732
  if (params.advisory && params.advisory.advisors.length > 0) {
1361
- const advisorRegistry = new AdvisorRegistry(
1362
- params.advisory.advisors,
1363
- params.advisory.defaultAdvisorId,
1364
- )
1733
+ // Advisors are model calls owned by this run even when they use a
1734
+ // different provider. Sending the raw definitions into the registry
1735
+ // lets a triggered or model-requested consultation bypass both the
1736
+ // finite stream-silence bound and Stop. Bind every advisor provider at
1737
+ // the query boundary, where the effective timeout and run signal are
1738
+ // already known; standalone AdvisoryExecutor callers retain their
1739
+ // explicitly chosen provider/cancellation policy.
1740
+ const boundedAdvisors = params.advisory.advisors.map((advisor) => ({
1741
+ ...advisor,
1742
+ provider: withStreamIdleTimeout(advisor.provider, {
1743
+ idleTimeoutMs: streamIdleTimeoutMs,
1744
+ log: ctx.log,
1745
+ }),
1746
+ }))
1747
+ const advisorRegistry = new AdvisorRegistry(boundedAdvisors, params.advisory.defaultAdvisorId)
1365
1748
  // A budget the runtime cannot measure is refused here rather than
1366
1749
  // silently ignored for the length of the run.
1367
1750
  assertBudgetEnforceable(params.advisory)
1368
- const advisoryExecutor = new AdvisoryExecutor(ctx.log, params.advisory.budget)
1751
+ const advisoryExecutor = new AdvisoryExecutor(
1752
+ ctx.log,
1753
+ params.advisory.budget,
1754
+ ctx.abortController.signal,
1755
+ )
1369
1756
  const triggerEvaluator = new TriggerEvaluator(
1370
1757
  params.advisory.triggers ?? [],
1371
1758
  params.advisory.budget,
@@ -1422,7 +1809,7 @@ export async function* query(params: QueryParams): AsyncGenerator<RunEvent, Run>
1422
1809
  const iterationOrchestrator = new IterationOrchestrator({
1423
1810
  provider: resilientProvider,
1424
1811
  servingMember: () => serving.current,
1425
- runConfig: params.runConfig,
1812
+ runConfig,
1426
1813
  ...(params.stopWhen ? { stopWhen: params.stopWhen } : {}),
1427
1814
  ...(params.prepareStep ? { prepareStep: params.prepareStep } : {}),
1428
1815
  ...(params.beforeStep ? { beforeStep: params.beforeStep } : {}),
@@ -1463,6 +1850,9 @@ export async function* query(params: QueryParams): AsyncGenerator<RunEvent, Run>
1463
1850
  ...(params.repeatCallAdvisory === false ? {} : { repeatCalls: new RepeatCallTracker() }),
1464
1851
  compactionConfig: params.compactionConfig,
1465
1852
  ...(params.inboundMessages ? { inboundMessages: params.inboundMessages } : {}),
1853
+ ...(params.projectInstructionContext
1854
+ ? { projectInstructionContext: params.projectInstructionContext }
1855
+ : {}),
1466
1856
  ...(providerContextWindow !== undefined ? { providerContextWindow } : {}),
1467
1857
  workingStateManager,
1468
1858
  taskRouter: params.taskRouter,
@@ -1494,9 +1884,11 @@ export async function* query(params: QueryParams): AsyncGenerator<RunEvent, Run>
1494
1884
  // waterfall, and for a replay fork (which mints a new run id) not
1495
1885
  // even that. An explicit caller-supplied parent still wins: it is
1496
1886
  // the more specific statement about where this run belongs.
1497
- const resumedTrace = params.resumeFromCheckpoint
1498
- ? await checkpointMgr.readTraceContext(params.resumeFromCheckpoint)
1499
- : undefined
1887
+ const resumedTrace = selectedResumeState
1888
+ ? selectedResumeState.traceContext
1889
+ : params.resumeFromCheckpoint
1890
+ ? await checkpointMgr.readTraceContext(params.resumeFromCheckpoint)
1891
+ : undefined
1500
1892
 
1501
1893
  const rootSpan = tracer.startSpan(
1502
1894
  agentRunSpanName(params.agentName),
@@ -1510,16 +1902,11 @@ export async function* query(params: QueryParams): AsyncGenerator<RunEvent, Run>
1510
1902
  checkpointMgr.setTraceSource(() => serializeSpan(rootSpan))
1511
1903
  // And every park it records carries an absolute deadline, so an
1512
1904
  // unanswered approval cannot outlive the worker that asked for it.
1513
- checkpointMgr.setParkTtl(params.runConfig.hitlParkTtlMs)
1905
+ checkpointMgr.setParkTtl(runConfig.hitlParkTtlMs)
1514
1906
  // The claim this worker holds, if it took one. Without this hop the
1515
1907
  // fence exists, the refusal exists, and no checkpoint a RUN writes ever
1516
1908
  // carries a number — so a stalled worker is refused nowhere.
1517
1909
  checkpointMgr.setClaimFence(params.claimFence)
1518
- // And every EVENT it records carries the same fence as its generation,
1519
- // so a consumer whose cursor was minted under an older holding is told
1520
- // the sequence space changed rather than handed a splice from it.
1521
- eventTranslator.setGeneration(params.claimFence)
1522
-
1523
1910
  // A question raised from inside a tool becomes a real checkpoint
1524
1911
  // here. It used to park under a synthetic id nothing ever wrote, so
1525
1912
  // the checkpoint did not exist: nothing on disk said a human owed
@@ -1581,7 +1968,7 @@ export async function* query(params: QueryParams): AsyncGenerator<RunEvent, Run>
1581
1968
  [NAMZU.RUN_ID]: ctx.runMgr.id,
1582
1969
  [GENAI.AGENT_NAME]: params.agentName,
1583
1970
  [GENAI.AGENT_ID]: params.agentId,
1584
- [GENAI.REQUEST_MODEL]: params.runConfig.model,
1971
+ [GENAI.REQUEST_MODEL]: runConfig.model,
1585
1972
  [GENAI.SYSTEM]: params.provider.id,
1586
1973
  })
1587
1974
 
@@ -1607,29 +1994,19 @@ export async function* query(params: QueryParams): AsyncGenerator<RunEvent, Run>
1607
1994
  params.eventCursor,
1608
1995
  params.onEventReplay,
1609
1996
  params.claimFence,
1997
+ (error) => {
1998
+ ctx.log.warn('Replay observer failed', {
1999
+ 'exception.message': toErrorMessage(error),
2000
+ })
2001
+ },
1610
2002
  )
1611
2003
  }
1612
2004
 
1613
- // Handed over here, and the position is load-bearing in BOTH
1614
- // directions. It has to follow `wirePlanManager`, or a host that
1615
- // builds its plan in this callback — which is what the callback is
1616
- // for — does it into silence: `plan_ready`, `plan_approved` and
1617
- // every `plan_step_updated` are emitted with nothing subscribed,
1618
- // and the host then watches a stream that never mentions the plan
1619
- // it just created. It also has to follow `runMgr.init()`, because
1620
- // emitting appends to the run store and an uninitialised store
1621
- // throws — moving it up to the wiring alone traded a silent drop
1622
- // for 25 unhandled rejections.
1623
- //
1624
- // Still before the iteration loop, which is the guarantee the
1625
- // callback actually makes.
1626
- params.onContextCreated?.({ planManager: ctx.planManager })
1627
-
1628
2005
  ctx.log.info('Starting query', {
1629
2006
  [NAMZU.RUN_ID]: ctx.runMgr.id,
1630
2007
  'namzu.runtime.agent': params.agentName,
1631
- [GENAI.REQUEST_MODEL]: params.runConfig.model,
1632
- 'namzu.runtime.token_budget': params.runConfig.tokenBudget,
2008
+ [GENAI.REQUEST_MODEL]: runConfig.model,
2009
+ 'namzu.runtime.token_budget': runConfig.tokenBudget,
1633
2010
  'namzu.runtime.activity_tracking': ctx.activityStore.enabled,
1634
2011
  'namzu.runtime.permission_mode': ctx.permissionMode.current,
1635
2012
  'namzu.runtime.resume_from_checkpoint': params.resumeFromCheckpoint ?? null,
@@ -1665,6 +2042,12 @@ export async function* query(params: QueryParams): AsyncGenerator<RunEvent, Run>
1665
2042
 
1666
2043
  if (params.resumeFromCheckpoint) {
1667
2044
  const checkpoint = await checkpointMgr.restore(params.resumeFromCheckpoint)
2045
+ const projectedCheckpoint = {
2046
+ ...checkpoint,
2047
+ messages: projectStateBearingHistory(checkpoint.messages, {
2048
+ pinCompaction: false,
2049
+ }),
2050
+ }
1668
2051
  await eventTranslator.emitEvent({
1669
2052
  type: 'run_resuming',
1670
2053
  runId: ctx.runMgr.id,
@@ -1718,8 +2101,8 @@ export async function* query(params: QueryParams): AsyncGenerator<RunEvent, Run>
1718
2101
  // re-decides, so "yes, delete that row" degrades into "ask
1719
2102
  // again and hope it asks for the same thing".
1720
2103
  pendingResume =
1721
- params.pendingDecision && checkpoint.pending
1722
- ? planPendingResume(checkpoint, params.pendingDecision, ctx.log)
2104
+ params.pendingDecision && projectedCheckpoint.pending
2105
+ ? planPendingResume(projectedCheckpoint, params.pendingDecision, ctx.log)
1723
2106
  : null
1724
2107
 
1725
2108
  // Results of tools that finished before the process died. The
@@ -1728,7 +2111,7 @@ export async function* query(params: QueryParams): AsyncGenerator<RunEvent, Run>
1728
2111
  // durable all along — it was simply never read back, and the
1729
2112
  // resumed run re-ran calls that had already charged a card or
1730
2113
  // sent an email.
1731
- const unanswered = unansweredToolCalls(checkpoint.messages)
2114
+ const unanswered = unansweredToolCalls(projectedCheckpoint.messages)
1732
2115
  recoveredResults =
1733
2116
  unanswered.length > 0
1734
2117
  ? await recoverCompletedCalls(ctx.runMgr, unanswered, ctx.log)
@@ -1740,32 +2123,35 @@ export async function* query(params: QueryParams): AsyncGenerator<RunEvent, Run>
1740
2123
  // the transcript proves execution had begun — a tool-review
1741
2124
  // park has no completions and keeps the cheap repair below.
1742
2125
  if (!pendingResume && recoveredResults.size > 0) {
1743
- pendingResume = planCrashResume(checkpoint, recoveredResults, ctx.log)
2126
+ pendingResume = planCrashResume(projectedCheckpoint, recoveredResults, ctx.log)
1744
2127
  }
1745
2128
 
1746
- // A checkpoint taken at a tool-review park snapshots the
1747
- // assistant turn AFTER its `tool_use` blocks but BEFORE any
1748
- // `tool_result` exists, so replaying it verbatim would send a
1749
- // malformed request on the first model call of the resumed
1750
- // run. Repair the incomplete turn rather than inheriting it:
1751
- // the model re-decides from the last valid state.
1752
- //
1753
- // The pending-decision path uses the SAME repair: it strips
1754
- // the unanswered turn here and `applyPendingResume` re-appends
1755
- // it together with the results that answer it, so the history
1756
- // stays well-formed either way.
1757
- const dangling = findDanglingMessages(checkpoint.messages)
1758
- const restoredMessages = dangling.isValid
1759
- ? checkpoint.messages
1760
- : removeDanglingMessages(checkpoint.messages)
1761
- if (!dangling.isValid && !pendingResume) {
1762
- ctx.log.warn('Checkpoint contained unanswered tool calls repaired on restore', {
2129
+ // An incomplete turn with a durable owner is NOT abandoned. A
2130
+ // pending decision or crash-resume plan re-appends that exact
2131
+ // assistant with real/denied/recovered results below. Remove it
2132
+ // from the generic pass so no synthetic result competes with the
2133
+ // authority that still owns the call. Everything else is abandoned
2134
+ // history and is repaired conservatively rather than deleted.
2135
+ const abandonedCheckpointMessages = pendingResume
2136
+ ? withoutOwnedResumeTurn(projectedCheckpoint.messages, pendingResume.assistant)
2137
+ : projectedCheckpoint.messages
2138
+ const checkpointRepair = repairToolMessageHistory(abandonedCheckpointMessages)
2139
+ const restoredMessages = checkpointRepair.messages
2140
+ if (toolHistoryRepairChanged(checkpointRepair.report)) {
2141
+ pendingHistoryRepairs.push({
2142
+ source: 'abandoned-checkpoint',
2143
+ report: checkpointRepair.report,
2144
+ })
2145
+ ctx.log.warn('Repaired abandoned tool history while restoring a checkpoint', {
1763
2146
  [NAMZU.RUN_ID]: ctx.runMgr.id,
1764
2147
  'namzu.checkpoint.id': checkpoint.id,
1765
- 'namzu.runtime.unanswered_assistant_turns':
1766
- dangling.assistantsWithUnmatchedCalls.length,
1767
- 'namzu.runtime.orphaned_tool_messages': dangling.orphanedToolMessages.length,
1768
- 'namzu.runtime.removed': checkpoint.messages.length - restoredMessages.length,
2148
+ 'namzu.history.source': 'abandoned-checkpoint',
2149
+ 'namzu.history.duplicate_tool_results_removed':
2150
+ checkpointRepair.report.duplicateToolResultsRemoved,
2151
+ 'namzu.history.orphaned_tool_results_removed':
2152
+ checkpointRepair.report.orphanedToolResultsRemoved,
2153
+ 'namzu.history.synthetic_tool_results_inserted':
2154
+ checkpointRepair.report.syntheticToolResultsInserted,
1769
2155
  })
1770
2156
  }
1771
2157
 
@@ -1802,7 +2188,21 @@ export async function* query(params: QueryParams): AsyncGenerator<RunEvent, Run>
1802
2188
  pushSystemMessages()
1803
2189
  let isFirstUserMessage = true
1804
2190
  for (const msg of initialMessages) {
1805
- if (msg.role === 'system') continue
2191
+ if (msg.role === 'system') {
2192
+ // A fresh run rebuilds its current static/dynamic prompt above,
2193
+ // so arbitrary historical system messages stay out. These two
2194
+ // are different: they are conversation STATE, and dropping them
2195
+ // deletes the only surviving record of compacted history or the
2196
+ // produced-artifact ledger. A compaction summary arriving from a
2197
+ // prior run is pinned because this new WorkingStateManager cannot
2198
+ // prove it has reconstructed equivalent state yet.
2199
+ if (isCompactionMessage(msg.content)) {
2200
+ ctx.runMgr.pushMessage({ ...msg, retain: true })
2201
+ } else if (isWorkingMemoryMessage(msg.content)) {
2202
+ ctx.runMgr.pushMessage(msg)
2203
+ }
2204
+ continue
2205
+ }
1806
2206
  ctx.runMgr.pushMessage(msg)
1807
2207
 
1808
2208
  if (workingStateManager && msg.role === 'user' && msg.content) {
@@ -1825,6 +2225,25 @@ export async function* query(params: QueryParams): AsyncGenerator<RunEvent, Run>
1825
2225
  })
1826
2226
  yield* eventTranslator.drainPending()
1827
2227
 
2228
+ // Pre-run materialization can observe cancellation before RunContext
2229
+ // exists. The exact input has now been seeded and the run is writable;
2230
+ // hand the cancellation to the normal terminal path before invoking
2231
+ // any host callback, guardrail, plugin, sandbox, or provider. Those
2232
+ // boundaries are not all cooperative and must not regain withdrawn
2233
+ // authority merely because the run record still had to be created.
2234
+ ctx.abortController.signal.throwIfAborted()
2235
+
2236
+ // Handed over here, and the position is load-bearing in three
2237
+ // directions. It has to follow `wirePlanManager`, or a host that
2238
+ // builds its plan in this callback does it into silence. It has to
2239
+ // follow `runMgr.init()` and `run_started`, because plan events append
2240
+ // to that durable run. It also has to follow the pre-model abort fence:
2241
+ // a callback invoked after attachment resolution observed cancellation
2242
+ // would regain withdrawn authority and could replace the cancellation
2243
+ // with its own failure. This is still before the iteration loop, which
2244
+ // is the guarantee the callback makes.
2245
+ params.onContextCreated?.({ planManager: ctx.planManager })
2246
+
1828
2247
  // The box is handed out HERE, after `run_started`, and the position
1829
2248
  // is load-bearing rather than tidy. It moved twice:
1830
2249
  //
@@ -1842,6 +2261,21 @@ export async function* query(params: QueryParams): AsyncGenerator<RunEvent, Run>
1842
2261
  // being writable.
1843
2262
  params.onApprovalPolicy?.(approvalPolicy)
1844
2263
 
2264
+ // History repair happens before the run manager sees the first model
2265
+ // request, but its durable event cannot precede run_started: there is no
2266
+ // writable run log until that event initializes it. Emit the measured
2267
+ // counts here, still before any provider call, so hosts can tell that the
2268
+ // model received a repaired projection rather than the raw history.
2269
+ for (const repair of pendingHistoryRepairs) {
2270
+ await eventTranslator.emitEvent({
2271
+ type: 'message_history_repaired',
2272
+ runId: ctx.runMgr.id,
2273
+ source: repair.source,
2274
+ ...repair.report,
2275
+ })
2276
+ yield* eventTranslator.drainPending()
2277
+ }
2278
+
1845
2279
  // Surface capability degradation to the host as run events —
1846
2280
  // explicit, not silent (the log.warn above fires at setup time;
1847
2281
  // this is the machine-readable channel).
@@ -1865,11 +2299,21 @@ export async function* query(params: QueryParams): AsyncGenerator<RunEvent, Run>
1865
2299
  })
1866
2300
  yield* eventTranslator.drainPending()
1867
2301
  }
2302
+ if (documentMessageCount > 0) {
2303
+ await eventTranslator.emitEvent({
2304
+ type: 'capability_warning',
2305
+ runId: ctx.runMgr.id,
2306
+ capability: 'documents',
2307
+ providerId: params.provider.id,
2308
+ message: `Provider '${params.provider.id}' does not support documents — document attachments on ${documentMessageCount} user message(s) will not reach the model.`,
2309
+ })
2310
+ yield* eventTranslator.drainPending()
2311
+ }
1868
2312
 
1869
2313
  if (params.pluginManager) {
1870
2314
  const hookResults = await params.pluginManager.executeHooks(
1871
2315
  'run_start',
1872
- { runId: ctx.runId },
2316
+ { runId: ctx.runId, signal: ctx.abortController.signal },
1873
2317
  eventTranslator.emitEvent,
1874
2318
  )
1875
2319
  applyLifecycleHookResults('run_start', hookResults)
@@ -1878,7 +2322,7 @@ export async function* query(params: QueryParams): AsyncGenerator<RunEvent, Run>
1878
2322
 
1879
2323
  // --- Sandbox lifecycle: create before iteration loop ---
1880
2324
  if (params.sandboxProvider) {
1881
- const rootAtCwd = params.runConfig.sandbox?.workspace === 'working-directory'
2325
+ const rootAtCwd = runConfig.sandbox?.workspace === 'working-directory'
1882
2326
  // Checked against what the CALLER passed, not against `ctx.cwd`.
1883
2327
  // `ctx.cwd` falls back to `process.cwd()`, so reading it here
1884
2328
  // would silently root the sandbox at whatever directory the
@@ -1897,12 +2341,54 @@ export async function* query(params: QueryParams): AsyncGenerator<RunEvent, Run>
1897
2341
  details: { workspace: 'working-directory' },
1898
2342
  })
1899
2343
  }
1900
- sandbox = await params.sandboxProvider.create({
1901
- ...(rootAtCwd ? { workingDirectory: ctx.cwd } : {}),
1902
- timeoutMs: params.runConfig.sandbox?.timeoutMs,
1903
- memoryLimitMb: params.runConfig.sandbox?.memoryLimitMb,
1904
- maxProcesses: params.runConfig.sandbox?.maxProcesses,
2344
+ const acquisition = await acquireSandbox({
2345
+ provider: params.sandboxProvider,
2346
+ config: {
2347
+ ...(rootAtCwd ? { workingDirectory: ctx.cwd } : {}),
2348
+ timeoutMs: runConfig.sandbox?.timeoutMs,
2349
+ memoryLimitMb: runConfig.sandbox?.memoryLimitMb,
2350
+ maxProcesses: runConfig.sandbox?.maxProcesses,
2351
+ },
2352
+ signal: ctx.abortController.signal,
2353
+ timeoutMs: guard.remainingUntilTimeoutMs(),
2354
+ teardownTimeoutMs: sandboxTeardownTimeoutMs,
2355
+ onLateTeardown: (result) => {
2356
+ if (result.kind === 'destroyed') {
2357
+ ctx.log.info('Late sandbox allocation was destroyed after the run stopped', {
2358
+ [NAMZU.RUN_ID]: ctx.runId,
2359
+ })
2360
+ return
2361
+ }
2362
+ ctx.log.error('Late sandbox allocation did not stop cleanly', {
2363
+ [NAMZU.RUN_ID]: ctx.runId,
2364
+ ...errorAttributes(result.error),
2365
+ })
2366
+ },
1905
2367
  })
2368
+ if (acquisition.kind !== 'created') {
2369
+ if (acquisition.createPending) {
2370
+ ctx.log.warn(
2371
+ 'Sandbox creation was unsettled when the run stopped; any returned handle will be released, but a remote allocation hidden behind a lost response requires provider-side reconciliation or a fleet reaper',
2372
+ {
2373
+ [NAMZU.RUN_ID]: ctx.runId,
2374
+ 'namzu.sandbox.provider_id': params.sandboxProvider.id,
2375
+ },
2376
+ )
2377
+ }
2378
+ if (acquisition.kind === 'cancelled') {
2379
+ ctx.runMgr.markCancelled()
2380
+ } else {
2381
+ ctx.runMgr.setStopReason('timeout')
2382
+ ctx.log.warn('Sandbox creation exhausted the run timeout', {
2383
+ [NAMZU.RUN_ID]: ctx.runId,
2384
+ 'namzu.sandbox.provider_id': params.sandboxProvider.id,
2385
+ ...errorAttributes(acquisition.error),
2386
+ })
2387
+ }
2388
+ yield* resultAssembler.completeRun(rootSpan)
2389
+ return await resultAssembler.finalize()
2390
+ }
2391
+ sandbox = acquisition.sandbox
1906
2392
  toolExecutor.setSandbox(sandbox)
1907
2393
 
1908
2394
  await eventTranslator.emitEvent({
@@ -2022,7 +2508,7 @@ export async function* query(params: QueryParams): AsyncGenerator<RunEvent, Run>
2022
2508
  if (params.pluginManager) {
2023
2509
  const hookResults = await params.pluginManager.executeHooks(
2024
2510
  'run_end',
2025
- { runId: ctx.runId },
2511
+ { runId: ctx.runId, signal: ctx.abortController.signal },
2026
2512
  eventTranslator.emitEvent,
2027
2513
  )
2028
2514
  applyLifecycleHookResults('run_end', hookResults)
@@ -2148,19 +2634,19 @@ export async function* query(params: QueryParams): AsyncGenerator<RunEvent, Run>
2148
2634
  // --- Sandbox lifecycle: destroy after run ---
2149
2635
  if (sandbox) {
2150
2636
  const sandboxId = sandbox.id
2151
- try {
2152
- await sandbox.destroy()
2637
+ const teardown = await teardownSandbox(sandbox, sandboxTeardownTimeoutMs)
2638
+ if (teardown.kind === 'destroyed') {
2153
2639
  await eventTranslator.emitEvent({
2154
2640
  type: 'sandbox_destroyed',
2155
2641
  runId: ctx.runId,
2156
2642
  sandboxId,
2157
2643
  })
2644
+ yield* eventTranslator.drainPending()
2158
2645
  ctx.log.info('Sandbox destroyed', { 'namzu.sandbox.id': sandboxId })
2159
- } catch (destroyErr) {
2646
+ } else {
2160
2647
  ctx.log.error('Sandbox destroy failed', {
2161
2648
  'namzu.sandbox.id': sandboxId,
2162
- 'exception.message':
2163
- destroyErr instanceof Error ? destroyErr.message : String(destroyErr),
2649
+ ...errorAttributes(teardown.error),
2164
2650
  })
2165
2651
  }
2166
2652
  }
@@ -2193,28 +2679,43 @@ async function* catchUpFromCursor(
2193
2679
  cursor: RunEventCursor,
2194
2680
  onEventReplay: ((replay: RunEventReplay) => void) | undefined,
2195
2681
  generation: FencingToken | undefined,
2682
+ onReplayObserverError: (error: unknown) => void,
2196
2683
  ): AsyncGenerator<RunEvent, void> {
2197
2684
  const missed = await runMgr.getRunStore().readEvents({ sinceSeq: cursor.sinceSeq })
2198
2685
  const replay = resolveRunEventReplay(
2199
2686
  cursor,
2200
- { lastSeq: runMgr.lastEventSeq, ...(generation !== undefined ? { generation } : {}) },
2687
+ {
2688
+ lastSeq: runMgr.lastEventSeq,
2689
+ ...(generation !== undefined ? { generation } : {}),
2690
+ },
2201
2691
  missed,
2202
2692
  )
2203
2693
 
2204
- onEventReplay?.(replay)
2694
+ if (onEventReplay) {
2695
+ try {
2696
+ // A callback typed `void` may still be implemented with `async` in
2697
+ // TypeScript. Observe that runtime Promise so a late rejection cannot
2698
+ // become process-wide, but never await host code here: replay delivery
2699
+ // and an already-cancelled run must not inherit observer liveness.
2700
+ const settlement = onEventReplay(replay)
2701
+ void Promise.resolve(settlement).catch(onReplayObserverError)
2702
+ } catch (error) {
2703
+ onReplayObserverError(error)
2704
+ }
2705
+ }
2205
2706
 
2206
2707
  if (replay.status !== 'replayed') return
2207
2708
  for (const event of replay.events) yield event
2208
2709
  }
2209
2710
 
2210
- export async function drainQuery(
2211
- params: Omit<QueryParams, 'resumeHandler'> & { resumeHandler?: ResumeHandler },
2711
+ type DrainQueryParams = Omit<QueryParams, 'resumeHandler'> & {
2712
+ resumeHandler?: ResumeHandler
2713
+ }
2714
+
2715
+ async function drainPreparedQuery(
2716
+ fullParams: QueryParams,
2212
2717
  listener?: RunEventListener,
2213
2718
  ): Promise<Run> {
2214
- const fullParams: QueryParams = {
2215
- ...params,
2216
- resumeHandler: params.resumeHandler ?? autoApproveHandler,
2217
- }
2218
2719
  const gen = query(fullParams)
2219
2720
  let result = await gen.next()
2220
2721
 
@@ -2228,6 +2729,54 @@ export async function drainQuery(
2228
2729
  return result.value
2229
2730
  }
2230
2731
 
2732
+ export async function drainQuery(
2733
+ params: Omit<QueryParams, 'resumeHandler'> & {
2734
+ resumeHandler?: ResumeHandler
2735
+ },
2736
+ listener?: RunEventListener,
2737
+ ): Promise<Run> {
2738
+ const fullParams: QueryParams = {
2739
+ ...params,
2740
+ resumeHandler: params.resumeHandler ?? autoApproveHandler,
2741
+ }
2742
+ return await drainPreparedQuery(fullParams, listener)
2743
+ }
2744
+
2745
+ /** @internal Canonical resume state already selected by `resumeRun`. */
2746
+ export async function drainQueryWithSelectedResumeState(
2747
+ params: DrainQueryParams,
2748
+ state: SelectedResumeState,
2749
+ listener?: RunEventListener,
2750
+ ): Promise<Run> {
2751
+ const fullParams: QueryParams = {
2752
+ ...params,
2753
+ resumeHandler: params.resumeHandler ?? autoApproveHandler,
2754
+ }
2755
+ if (fullParams.resumeFromCheckpoint !== state.checkpointId) {
2756
+ throw new Error('The selected resume state does not match the requested checkpoint.')
2757
+ }
2758
+ assertSelectedResumeAttribution(fullParams, state)
2759
+ selectedResumeStates.set(fullParams, state)
2760
+ return await drainPreparedQuery(fullParams, listener)
2761
+ }
2762
+
2763
+ function assertSelectedResumeAttribution(params: QueryParams, state: SelectedResumeState): void {
2764
+ const mismatchedFields: string[] = []
2765
+ if (params.runId !== state.runId) mismatchedFields.push('runId')
2766
+ if (params.sessionId !== state.sessionId) mismatchedFields.push('sessionId')
2767
+ if (params.topicId !== state.topicId) mismatchedFields.push('topicId')
2768
+ if (params.projectId !== state.projectId) mismatchedFields.push('projectId')
2769
+ if (params.tenantId !== state.tenantId) mismatchedFields.push('tenantId')
2770
+ if (params.parentRunId !== state.parentRunId) mismatchedFields.push('parentRunId')
2771
+ if (mismatchedFields.length === 0) return
2772
+
2773
+ throw new NamzuError({
2774
+ code: 'invalid_config',
2775
+ message: 'The selected resume state does not match the run attribution supplied to the query.',
2776
+ details: { fields: mismatchedFields },
2777
+ })
2778
+ }
2779
+
2231
2780
  function withDeferredDiscoveryTool(
2232
2781
  tools: ToolRegistryContract,
2233
2782
  allowedTools?: string[],