@namzu/sdk 34.2.0 → 35.0.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 (637) hide show
  1. package/CHANGELOG.md +133 -0
  2. package/README.md +2 -6
  3. package/dist/agents/PipelineAgent.d.ts.map +1 -1
  4. package/dist/agents/PipelineAgent.js +118 -100
  5. package/dist/agents/PipelineAgent.js.map +1 -1
  6. package/dist/agents/ReactiveAgent.d.ts.map +1 -1
  7. package/dist/agents/ReactiveAgent.js +2 -0
  8. package/dist/agents/ReactiveAgent.js.map +1 -1
  9. package/dist/agents/RouterAgent.d.ts.map +1 -1
  10. package/dist/agents/RouterAgent.js +105 -61
  11. package/dist/agents/RouterAgent.js.map +1 -1
  12. package/dist/agents/SupervisorAgent.d.ts.map +1 -1
  13. package/dist/agents/SupervisorAgent.js +8 -4
  14. package/dist/agents/SupervisorAgent.js.map +1 -1
  15. package/dist/agents/budget.d.ts +6 -0
  16. package/dist/agents/budget.d.ts.map +1 -0
  17. package/dist/agents/budget.js +33 -0
  18. package/dist/agents/budget.js.map +1 -0
  19. package/dist/agents/explore.d.ts +20 -0
  20. package/dist/agents/explore.d.ts.map +1 -0
  21. package/dist/agents/explore.js +26 -0
  22. package/dist/agents/explore.js.map +1 -0
  23. package/dist/agents/file-definitions.d.ts +80 -0
  24. package/dist/agents/file-definitions.d.ts.map +1 -0
  25. package/dist/agents/file-definitions.js +179 -0
  26. package/dist/agents/file-definitions.js.map +1 -0
  27. package/dist/agents/index.d.ts +3 -0
  28. package/dist/agents/index.d.ts.map +1 -1
  29. package/dist/agents/index.js +2 -0
  30. package/dist/agents/index.js.map +1 -1
  31. package/dist/bridge/a2a/mapper.d.ts.map +1 -1
  32. package/dist/bridge/a2a/mapper.js +6 -0
  33. package/dist/bridge/a2a/mapper.js.map +1 -1
  34. package/dist/bridge/sse/mapper.d.ts.map +1 -1
  35. package/dist/bridge/sse/mapper.js +22 -0
  36. package/dist/bridge/sse/mapper.js.map +1 -1
  37. package/dist/bus/lock.d.ts.map +1 -1
  38. package/dist/bus/lock.js +1 -10
  39. package/dist/bus/lock.js.map +1 -1
  40. package/dist/compaction/consolidation.d.ts +31 -0
  41. package/dist/compaction/consolidation.d.ts.map +1 -0
  42. package/dist/compaction/consolidation.js +63 -0
  43. package/dist/compaction/consolidation.js.map +1 -0
  44. package/dist/compaction/factory.d.ts.map +1 -1
  45. package/dist/compaction/factory.js +3 -0
  46. package/dist/compaction/factory.js.map +1 -1
  47. package/dist/compaction/index.d.ts +6 -1
  48. package/dist/compaction/index.d.ts.map +1 -1
  49. package/dist/compaction/index.js +6 -0
  50. package/dist/compaction/index.js.map +1 -1
  51. package/dist/compaction/manager.d.ts +7 -0
  52. package/dist/compaction/manager.d.ts.map +1 -1
  53. package/dist/compaction/manager.js +31 -0
  54. package/dist/compaction/manager.js.map +1 -1
  55. package/dist/compaction/plan.d.ts +23 -0
  56. package/dist/compaction/plan.d.ts.map +1 -1
  57. package/dist/compaction/plan.js +41 -24
  58. package/dist/compaction/plan.js.map +1 -1
  59. package/dist/compaction/salience/bm25.d.ts +26 -0
  60. package/dist/compaction/salience/bm25.d.ts.map +1 -0
  61. package/dist/compaction/salience/bm25.js +56 -0
  62. package/dist/compaction/salience/bm25.js.map +1 -0
  63. package/dist/compaction/salience/goal.d.ts +21 -0
  64. package/dist/compaction/salience/goal.d.ts.map +1 -0
  65. package/dist/compaction/salience/goal.js +32 -0
  66. package/dist/compaction/salience/goal.js.map +1 -0
  67. package/dist/compaction/salience/index.d.ts +4 -0
  68. package/dist/compaction/salience/index.d.ts.map +1 -0
  69. package/dist/compaction/salience/index.js +4 -0
  70. package/dist/compaction/salience/index.js.map +1 -0
  71. package/dist/compaction/salience/minhash.d.ts +17 -0
  72. package/dist/compaction/salience/minhash.d.ts.map +1 -0
  73. package/dist/compaction/salience/minhash.js +54 -0
  74. package/dist/compaction/salience/minhash.js.map +1 -0
  75. package/dist/compaction/salience/score.d.ts +64 -0
  76. package/dist/compaction/salience/score.d.ts.map +1 -0
  77. package/dist/compaction/salience/score.js +256 -0
  78. package/dist/compaction/salience/score.js.map +1 -0
  79. package/dist/compaction/salience/tokenize.d.ts +20 -0
  80. package/dist/compaction/salience/tokenize.d.ts.map +1 -0
  81. package/dist/compaction/salience/tokenize.js +92 -0
  82. package/dist/compaction/salience/tokenize.js.map +1 -0
  83. package/dist/compaction/salience/working-set.d.ts +59 -0
  84. package/dist/compaction/salience/working-set.d.ts.map +1 -0
  85. package/dist/compaction/salience/working-set.js +137 -0
  86. package/dist/compaction/salience/working-set.js.map +1 -0
  87. package/dist/compaction/serializer.d.ts +2 -0
  88. package/dist/compaction/serializer.d.ts.map +1 -1
  89. package/dist/compaction/serializer.js +15 -0
  90. package/dist/compaction/serializer.js.map +1 -1
  91. package/dist/compaction/token-estimate.d.ts +13 -0
  92. package/dist/compaction/token-estimate.d.ts.map +1 -0
  93. package/dist/compaction/token-estimate.js +58 -0
  94. package/dist/compaction/token-estimate.js.map +1 -0
  95. package/dist/compaction/tool-result-editing.d.ts +10 -2
  96. package/dist/compaction/tool-result-editing.d.ts.map +1 -1
  97. package/dist/compaction/tool-result-editing.js +22 -24
  98. package/dist/compaction/tool-result-editing.js.map +1 -1
  99. package/dist/compaction/types.d.ts +22 -1
  100. package/dist/compaction/types.d.ts.map +1 -1
  101. package/dist/compaction/wire.d.ts +3 -1
  102. package/dist/compaction/wire.d.ts.map +1 -1
  103. package/dist/compaction/wire.js +2 -0
  104. package/dist/compaction/wire.js.map +1 -1
  105. package/dist/config/runtime.d.ts +58 -28
  106. package/dist/config/runtime.d.ts.map +1 -1
  107. package/dist/config/runtime.js +13 -1
  108. package/dist/config/runtime.js.map +1 -1
  109. package/dist/connector/builtins/http.d.ts.map +1 -1
  110. package/dist/connector/builtins/http.js +2 -8
  111. package/dist/connector/builtins/http.js.map +1 -1
  112. package/dist/connector/builtins/webhook.js +2 -2
  113. package/dist/connector/builtins/webhook.js.map +1 -1
  114. package/dist/connector/mcp/adapter.d.ts +2 -0
  115. package/dist/connector/mcp/adapter.d.ts.map +1 -1
  116. package/dist/connector/mcp/adapter.js +30 -0
  117. package/dist/connector/mcp/adapter.js.map +1 -1
  118. package/dist/connector/tools/adapter.js +2 -2
  119. package/dist/connector/tools/adapter.js.map +1 -1
  120. package/dist/connector/tools/definitions.js +2 -2
  121. package/dist/connector/tools/definitions.js.map +1 -1
  122. package/dist/constants/compaction/index.d.ts +1 -0
  123. package/dist/constants/compaction/index.d.ts.map +1 -1
  124. package/dist/constants/compaction/index.js +1 -0
  125. package/dist/constants/compaction/index.js.map +1 -1
  126. package/dist/constants/telemetry/index.d.ts +0 -1
  127. package/dist/constants/telemetry/index.d.ts.map +1 -1
  128. package/dist/constants/telemetry/index.js +0 -1
  129. package/dist/constants/telemetry/index.js.map +1 -1
  130. package/dist/contracts/a2a.d.ts +5 -5
  131. package/dist/contracts/api.d.ts +4 -2
  132. package/dist/contracts/api.d.ts.map +1 -1
  133. package/dist/contracts/schemas.d.ts +1 -15
  134. package/dist/contracts/schemas.d.ts.map +1 -1
  135. package/dist/contracts/schemas.js +5 -20
  136. package/dist/contracts/schemas.js.map +1 -1
  137. package/dist/invariants/index.d.ts +1 -1
  138. package/dist/manager/agent/lifecycle.d.ts +2 -18
  139. package/dist/manager/agent/lifecycle.d.ts.map +1 -1
  140. package/dist/manager/agent/lifecycle.js +373 -340
  141. package/dist/manager/agent/lifecycle.js.map +1 -1
  142. package/dist/manager/run/persistence.d.ts +3 -0
  143. package/dist/manager/run/persistence.d.ts.map +1 -1
  144. package/dist/manager/run/persistence.js +35 -5
  145. package/dist/manager/run/persistence.js.map +1 -1
  146. package/dist/plugin/index.d.ts +2 -0
  147. package/dist/plugin/index.d.ts.map +1 -1
  148. package/dist/plugin/index.js +1 -0
  149. package/dist/plugin/index.js.map +1 -1
  150. package/dist/plugin/shell-hook.d.ts +128 -0
  151. package/dist/plugin/shell-hook.d.ts.map +1 -0
  152. package/dist/plugin/shell-hook.js +299 -0
  153. package/dist/plugin/shell-hook.js.map +1 -0
  154. package/dist/prompt/coding-agent-doctrine.d.ts +63 -0
  155. package/dist/prompt/coding-agent-doctrine.d.ts.map +1 -0
  156. package/dist/prompt/coding-agent-doctrine.js +100 -0
  157. package/dist/prompt/coding-agent-doctrine.js.map +1 -0
  158. package/dist/prompt/index.d.ts +2 -0
  159. package/dist/prompt/index.d.ts.map +1 -1
  160. package/dist/prompt/index.js +1 -0
  161. package/dist/prompt/index.js.map +1 -1
  162. package/dist/provider/errors.d.ts +1 -1
  163. package/dist/provider/errors.js +1 -1
  164. package/dist/provider/fallback.d.ts +2 -0
  165. package/dist/provider/fallback.d.ts.map +1 -1
  166. package/dist/provider/fallback.js +3 -1
  167. package/dist/provider/fallback.js.map +1 -1
  168. package/dist/provider/retry.d.ts +2 -0
  169. package/dist/provider/retry.d.ts.map +1 -1
  170. package/dist/provider/retry.js +3 -1
  171. package/dist/provider/retry.js.map +1 -1
  172. package/dist/provider/token-budget.d.ts +13 -0
  173. package/dist/provider/token-budget.d.ts.map +1 -0
  174. package/dist/provider/token-budget.js +102 -0
  175. package/dist/provider/token-budget.js.map +1 -0
  176. package/dist/public-runtime.d.ts +12 -12
  177. package/dist/public-runtime.d.ts.map +1 -1
  178. package/dist/public-runtime.js +14 -9
  179. package/dist/public-runtime.js.map +1 -1
  180. package/dist/public-tools.d.ts +2 -0
  181. package/dist/public-tools.d.ts.map +1 -1
  182. package/dist/public-tools.js +2 -0
  183. package/dist/public-tools.js.map +1 -1
  184. package/dist/public-types.d.ts +12 -2
  185. package/dist/public-types.d.ts.map +1 -1
  186. package/dist/registry/command/kernel-commands.d.ts.map +1 -1
  187. package/dist/registry/command/kernel-commands.js +18 -6
  188. package/dist/registry/command/kernel-commands.js.map +1 -1
  189. package/dist/registry/tool/execute.d.ts.map +1 -1
  190. package/dist/registry/tool/execute.js +4 -1
  191. package/dist/registry/tool/execute.js.map +1 -1
  192. package/dist/run/LimitChecker.js +1 -1
  193. package/dist/run/LimitChecker.js.map +1 -1
  194. package/dist/run/drain.js +1 -1
  195. package/dist/run/reporter.d.ts.map +1 -1
  196. package/dist/run/reporter.js +15 -0
  197. package/dist/run/reporter.js.map +1 -1
  198. package/dist/run/token-budget.d.ts +108 -0
  199. package/dist/run/token-budget.d.ts.map +1 -0
  200. package/dist/run/token-budget.js +591 -0
  201. package/dist/run/token-budget.js.map +1 -0
  202. package/dist/runtime/jobs/registry.d.ts +29 -0
  203. package/dist/runtime/jobs/registry.d.ts.map +1 -1
  204. package/dist/runtime/jobs/registry.js +98 -18
  205. package/dist/runtime/jobs/registry.js.map +1 -1
  206. package/dist/runtime/query/checkpoint.d.ts.map +1 -1
  207. package/dist/runtime/query/checkpoint.js +10 -3
  208. package/dist/runtime/query/checkpoint.js.map +1 -1
  209. package/dist/runtime/query/context.d.ts +2 -26
  210. package/dist/runtime/query/context.d.ts.map +1 -1
  211. package/dist/runtime/query/context.js +1 -29
  212. package/dist/runtime/query/context.js.map +1 -1
  213. package/dist/runtime/query/executor.d.ts +12 -9
  214. package/dist/runtime/query/executor.d.ts.map +1 -1
  215. package/dist/runtime/query/executor.js +95 -46
  216. package/dist/runtime/query/executor.js.map +1 -1
  217. package/dist/runtime/query/guard.d.ts.map +1 -1
  218. package/dist/runtime/query/guard.js +8 -0
  219. package/dist/runtime/query/guard.js.map +1 -1
  220. package/dist/runtime/query/index.d.ts +35 -4
  221. package/dist/runtime/query/index.d.ts.map +1 -1
  222. package/dist/runtime/query/index.js +152 -52
  223. package/dist/runtime/query/index.js.map +1 -1
  224. package/dist/runtime/query/iteration/index.d.ts.map +1 -1
  225. package/dist/runtime/query/iteration/index.js +16 -5
  226. package/dist/runtime/query/iteration/index.js.map +1 -1
  227. package/dist/runtime/query/iteration/phases/compaction.d.ts.map +1 -1
  228. package/dist/runtime/query/iteration/phases/compaction.js +98 -30
  229. package/dist/runtime/query/iteration/phases/compaction.js.map +1 -1
  230. package/dist/runtime/query/iteration/phases/context.d.ts +2 -0
  231. package/dist/runtime/query/iteration/phases/context.d.ts.map +1 -1
  232. package/dist/runtime/query/iteration/phases/context.js.map +1 -1
  233. package/dist/runtime/query/iteration/phases/tool-review.d.ts.map +1 -1
  234. package/dist/runtime/query/iteration/phases/tool-review.js +29 -7
  235. package/dist/runtime/query/iteration/phases/tool-review.js.map +1 -1
  236. package/dist/runtime/query/iteration/phases/working-memory.d.ts.map +1 -1
  237. package/dist/runtime/query/iteration/phases/working-memory.js +25 -15
  238. package/dist/runtime/query/iteration/phases/working-memory.js.map +1 -1
  239. package/dist/runtime/query/plugin-hooks.d.ts +1 -1
  240. package/dist/runtime/query/plugin-hooks.d.ts.map +1 -1
  241. package/dist/runtime/query/plugin-hooks.js +20 -1
  242. package/dist/runtime/query/plugin-hooks.js.map +1 -1
  243. package/dist/runtime/query/repeat-call.d.ts +20 -2
  244. package/dist/runtime/query/repeat-call.d.ts.map +1 -1
  245. package/dist/runtime/query/repeat-call.js +35 -7
  246. package/dist/runtime/query/repeat-call.js.map +1 -1
  247. package/dist/runtime/query/result.d.ts.map +1 -1
  248. package/dist/runtime/query/result.js +9 -0
  249. package/dist/runtime/query/result.js.map +1 -1
  250. package/dist/runtime/query/review-policy.d.ts +142 -0
  251. package/dist/runtime/query/review-policy.d.ts.map +1 -0
  252. package/dist/runtime/query/review-policy.js +144 -0
  253. package/dist/runtime/query/review-policy.js.map +1 -0
  254. package/dist/runtime/query/run-state.d.ts.map +1 -1
  255. package/dist/runtime/query/run-state.js +4 -0
  256. package/dist/runtime/query/run-state.js.map +1 -1
  257. package/dist/runtime/query/steering.d.ts +4 -0
  258. package/dist/runtime/query/steering.d.ts.map +1 -1
  259. package/dist/runtime/query/steering.js +29 -0
  260. package/dist/runtime/query/steering.js.map +1 -1
  261. package/dist/runtime/query/token-budget.d.ts +7 -0
  262. package/dist/runtime/query/token-budget.d.ts.map +1 -0
  263. package/dist/runtime/query/token-budget.js +101 -0
  264. package/dist/runtime/query/token-budget.js.map +1 -0
  265. package/dist/runtime/query/tool-output-budget.d.ts +2 -0
  266. package/dist/runtime/query/tool-output-budget.d.ts.map +1 -1
  267. package/dist/runtime/query/tool-output-budget.js +29 -11
  268. package/dist/runtime/query/tool-output-budget.js.map +1 -1
  269. package/dist/runtime/query/tool-pause.d.ts.map +1 -1
  270. package/dist/runtime/query/tool-pause.js +4 -2
  271. package/dist/runtime/query/tool-pause.js.map +1 -1
  272. package/dist/runtime/query/tooling.d.ts +4 -0
  273. package/dist/runtime/query/tooling.d.ts.map +1 -1
  274. package/dist/runtime/query/tooling.js +4 -0
  275. package/dist/runtime/query/tooling.js.map +1 -1
  276. package/dist/sandbox/provider/local.d.ts +3 -1
  277. package/dist/sandbox/provider/local.d.ts.map +1 -1
  278. package/dist/sandbox/provider/local.js +112 -12
  279. package/dist/sandbox/provider/local.js.map +1 -1
  280. package/dist/scheduler/delegating.d.ts +1 -0
  281. package/dist/scheduler/delegating.d.ts.map +1 -1
  282. package/dist/scheduler/delegating.js +29 -12
  283. package/dist/scheduler/delegating.js.map +1 -1
  284. package/dist/scheduler/local.d.ts +1 -0
  285. package/dist/scheduler/local.d.ts.map +1 -1
  286. package/dist/scheduler/local.js +4 -7
  287. package/dist/scheduler/local.js.map +1 -1
  288. package/dist/session/index.d.ts +0 -1
  289. package/dist/session/index.d.ts.map +1 -1
  290. package/dist/session/index.js +0 -1
  291. package/dist/session/index.js.map +1 -1
  292. package/dist/session/workspace/path-builder.d.ts.map +1 -1
  293. package/dist/session/workspace/path-builder.js +5 -4
  294. package/dist/session/workspace/path-builder.js.map +1 -1
  295. package/dist/store/feedback/disk.d.ts.map +1 -1
  296. package/dist/store/feedback/disk.js +4 -6
  297. package/dist/store/feedback/disk.js.map +1 -1
  298. package/dist/store/index.d.ts +2 -0
  299. package/dist/store/index.d.ts.map +1 -1
  300. package/dist/store/index.js +1 -0
  301. package/dist/store/index.js.map +1 -1
  302. package/dist/store/memory/disk.d.ts.map +1 -1
  303. package/dist/store/memory/disk.js +3 -12
  304. package/dist/store/memory/disk.js.map +1 -1
  305. package/dist/store/run/checkpoint-disk.d.ts +3 -3
  306. package/dist/store/run/checkpoint-disk.d.ts.map +1 -1
  307. package/dist/store/run/checkpoint-disk.js +14 -26
  308. package/dist/store/run/checkpoint-disk.js.map +1 -1
  309. package/dist/store/run/claim-disk.js +1 -1
  310. package/dist/store/run/conformance.d.ts +1 -1
  311. package/dist/store/run/conformance.d.ts.map +1 -1
  312. package/dist/store/run/conformance.js +41 -33
  313. package/dist/store/run/conformance.js.map +1 -1
  314. package/dist/store/run/disk.d.ts.map +1 -1
  315. package/dist/store/run/disk.js +20 -4
  316. package/dist/store/run/disk.js.map +1 -1
  317. package/dist/store/run/token-budget-disk.d.ts +37 -0
  318. package/dist/store/run/token-budget-disk.d.ts.map +1 -0
  319. package/dist/store/run/token-budget-disk.js +208 -0
  320. package/dist/store/run/token-budget-disk.js.map +1 -0
  321. package/dist/store/session/disk.d.ts +4 -13
  322. package/dist/store/session/disk.d.ts.map +1 -1
  323. package/dist/store/session/disk.js +34 -31
  324. package/dist/store/session/disk.js.map +1 -1
  325. package/dist/store/session/memory.d.ts +2 -0
  326. package/dist/store/session/memory.d.ts.map +1 -1
  327. package/dist/store/session/memory.js +41 -2
  328. package/dist/store/session/memory.js.map +1 -1
  329. package/dist/store/task/disk.d.ts.map +1 -1
  330. package/dist/store/task/disk.js +7 -8
  331. package/dist/store/task/disk.js.map +1 -1
  332. package/dist/store/topic/memory.d.ts +2 -0
  333. package/dist/store/topic/memory.d.ts.map +1 -1
  334. package/dist/store/topic/memory.js +13 -1
  335. package/dist/store/topic/memory.js.map +1 -1
  336. package/dist/test-support/ids.d.ts +4 -19
  337. package/dist/test-support/ids.d.ts.map +1 -1
  338. package/dist/test-support/ids.js +51 -59
  339. package/dist/test-support/ids.js.map +1 -1
  340. package/dist/tools/advisory/index.d.ts.map +1 -1
  341. package/dist/tools/advisory/index.js +3 -1
  342. package/dist/tools/advisory/index.js.map +1 -1
  343. package/dist/tools/builtins/bash.d.ts +2 -0
  344. package/dist/tools/builtins/bash.d.ts.map +1 -1
  345. package/dist/tools/builtins/bash.js +9 -11
  346. package/dist/tools/builtins/bash.js.map +1 -1
  347. package/dist/tools/builtins/computer-use.d.ts +2 -2
  348. package/dist/tools/builtins/computer-use.d.ts.map +1 -1
  349. package/dist/tools/builtins/computer-use.js +4 -2
  350. package/dist/tools/builtins/computer-use.js.map +1 -1
  351. package/dist/tools/builtins/edit.js +2 -2
  352. package/dist/tools/builtins/edit.js.map +1 -1
  353. package/dist/tools/builtins/glob.js +3 -3
  354. package/dist/tools/builtins/glob.js.map +1 -1
  355. package/dist/tools/builtins/grep.js +2 -2
  356. package/dist/tools/builtins/grep.js.map +1 -1
  357. package/dist/tools/builtins/ls.js +2 -2
  358. package/dist/tools/builtins/ls.js.map +1 -1
  359. package/dist/tools/builtins/lsp.js +2 -2
  360. package/dist/tools/builtins/lsp.js.map +1 -1
  361. package/dist/tools/builtins/read-file.js +2 -2
  362. package/dist/tools/builtins/read-file.js.map +1 -1
  363. package/dist/tools/builtins/write-file.js +2 -2
  364. package/dist/tools/builtins/write-file.js.map +1 -1
  365. package/dist/tools/coordinator/ask-user-question.d.ts +33 -0
  366. package/dist/tools/coordinator/ask-user-question.d.ts.map +1 -0
  367. package/dist/tools/coordinator/ask-user-question.js +237 -0
  368. package/dist/tools/coordinator/ask-user-question.js.map +1 -0
  369. package/dist/tools/coordinator/index.d.ts +1 -2
  370. package/dist/tools/coordinator/index.d.ts.map +1 -1
  371. package/dist/tools/coordinator/index.js +4 -220
  372. package/dist/tools/coordinator/index.js.map +1 -1
  373. package/dist/tools/memory/read.d.ts.map +1 -1
  374. package/dist/tools/memory/read.js +2 -4
  375. package/dist/tools/memory/read.js.map +1 -1
  376. package/dist/tools/paths.d.ts +13 -0
  377. package/dist/tools/paths.d.ts.map +1 -1
  378. package/dist/tools/paths.js +53 -0
  379. package/dist/tools/paths.js.map +1 -1
  380. package/dist/tools/roster.d.ts +27 -0
  381. package/dist/tools/roster.d.ts.map +1 -0
  382. package/dist/tools/roster.js +42 -0
  383. package/dist/tools/roster.js.map +1 -0
  384. package/dist/types/agent/base.d.ts +5 -0
  385. package/dist/types/agent/base.d.ts.map +1 -1
  386. package/dist/types/agent/pipeline.d.ts +3 -0
  387. package/dist/types/agent/pipeline.d.ts.map +1 -1
  388. package/dist/types/agent/router.d.ts +2 -3
  389. package/dist/types/agent/router.d.ts.map +1 -1
  390. package/dist/types/agent/scheduler.d.ts +3 -0
  391. package/dist/types/agent/scheduler.d.ts.map +1 -1
  392. package/dist/types/agent/task.d.ts +5 -16
  393. package/dist/types/agent/task.d.ts.map +1 -1
  394. package/dist/types/agent/task.js.map +1 -1
  395. package/dist/types/common/index.d.ts.map +1 -1
  396. package/dist/types/common/index.js +3 -0
  397. package/dist/types/common/index.js.map +1 -1
  398. package/dist/types/computer-use/index.d.ts +8 -0
  399. package/dist/types/computer-use/index.d.ts.map +1 -1
  400. package/dist/types/computer-use/index.js.map +1 -1
  401. package/dist/types/hitl/index.d.ts +5 -0
  402. package/dist/types/hitl/index.d.ts.map +1 -1
  403. package/dist/types/hitl/index.js.map +1 -1
  404. package/dist/types/ids/brand.d.ts +5 -47
  405. package/dist/types/ids/brand.d.ts.map +1 -1
  406. package/dist/types/ids/brand.js +2 -39
  407. package/dist/types/ids/brand.js.map +1 -1
  408. package/dist/types/ids/index.d.ts +59 -69
  409. package/dist/types/ids/index.d.ts.map +1 -1
  410. package/dist/types/ids/index.js +12 -10
  411. package/dist/types/ids/index.js.map +1 -1
  412. package/dist/types/permission/index.d.ts +9 -0
  413. package/dist/types/permission/index.d.ts.map +1 -1
  414. package/dist/types/permission/index.js +9 -1
  415. package/dist/types/permission/index.js.map +1 -1
  416. package/dist/types/plugin/index.d.ts +45 -4
  417. package/dist/types/plugin/index.d.ts.map +1 -1
  418. package/dist/types/plugin/index.js +7 -0
  419. package/dist/types/plugin/index.js.map +1 -1
  420. package/dist/types/run/config.d.ts +3 -0
  421. package/dist/types/run/config.d.ts.map +1 -1
  422. package/dist/types/run/emergency.d.ts +5 -0
  423. package/dist/types/run/emergency.d.ts.map +1 -1
  424. package/dist/types/run/emergency.js.map +1 -1
  425. package/dist/types/run/entity.d.ts +6 -2
  426. package/dist/types/run/entity.d.ts.map +1 -1
  427. package/dist/types/run/events.d.ts +35 -0
  428. package/dist/types/run/events.d.ts.map +1 -1
  429. package/dist/types/run/events.js.map +1 -1
  430. package/dist/types/run/index.d.ts +1 -0
  431. package/dist/types/run/index.d.ts.map +1 -1
  432. package/dist/types/run/index.js +1 -0
  433. package/dist/types/run/index.js.map +1 -1
  434. package/dist/types/run/state.d.ts +16 -15
  435. package/dist/types/run/state.d.ts.map +1 -1
  436. package/dist/types/run/state.js +41 -22
  437. package/dist/types/run/state.js.map +1 -1
  438. package/dist/types/run/stop-reason.d.ts +3 -14
  439. package/dist/types/run/stop-reason.d.ts.map +1 -1
  440. package/dist/types/run/token-budget-store.d.ts +29 -0
  441. package/dist/types/run/token-budget-store.d.ts.map +1 -0
  442. package/dist/types/run/token-budget-store.js +25 -0
  443. package/dist/types/run/token-budget-store.js.map +1 -0
  444. package/dist/types/sandbox/index.d.ts +27 -2
  445. package/dist/types/sandbox/index.d.ts.map +1 -1
  446. package/dist/types/sandbox/index.js.map +1 -1
  447. package/dist/types/session/store.d.ts +8 -0
  448. package/dist/types/session/store.d.ts.map +1 -1
  449. package/dist/types/tool/index.d.ts +15 -0
  450. package/dist/types/tool/index.d.ts.map +1 -1
  451. package/dist/types/tool/index.js.map +1 -1
  452. package/dist/utils/frontmatter.d.ts +1 -1
  453. package/dist/utils/frontmatter.js +1 -1
  454. package/dist/utils/id-format.d.ts +3 -0
  455. package/dist/utils/id-format.d.ts.map +1 -0
  456. package/dist/utils/id-format.js +9 -0
  457. package/dist/utils/id-format.js.map +1 -0
  458. package/dist/utils/id.d.ts +65 -32
  459. package/dist/utils/id.d.ts.map +1 -1
  460. package/dist/utils/id.js +168 -148
  461. package/dist/utils/id.js.map +1 -1
  462. package/dist/utils/log/exception.js +1 -1
  463. package/dist/utils/log/exception.js.map +1 -1
  464. package/dist/utils/log/index.d.ts.map +1 -1
  465. package/dist/utils/log/index.js +1 -2
  466. package/dist/utils/log/index.js.map +1 -1
  467. package/dist/utils/log/templates.d.ts.map +1 -1
  468. package/dist/utils/log/templates.js +0 -1
  469. package/dist/utils/log/templates.js.map +1 -1
  470. package/package.json +1 -1
  471. package/src/agents/AGENTS.md +1 -1
  472. package/src/agents/PipelineAgent.ts +129 -109
  473. package/src/agents/ReactiveAgent.ts +2 -0
  474. package/src/agents/RouterAgent.ts +120 -73
  475. package/src/agents/SupervisorAgent.ts +12 -4
  476. package/src/agents/budget.ts +42 -0
  477. package/src/agents/explore.ts +29 -0
  478. package/src/agents/file-definitions.ts +237 -0
  479. package/src/agents/index.ts +15 -0
  480. package/src/bridge/a2a/mapper.ts +6 -0
  481. package/src/bridge/sse/mapper.ts +22 -0
  482. package/src/bus/lock.ts +1 -10
  483. package/src/compaction/consolidation.ts +79 -0
  484. package/src/compaction/factory.ts +3 -0
  485. package/src/compaction/index.ts +34 -4
  486. package/src/compaction/manager.ts +39 -1
  487. package/src/compaction/plan.ts +52 -21
  488. package/src/compaction/salience/bm25.ts +72 -0
  489. package/src/compaction/salience/goal.ts +44 -0
  490. package/src/compaction/salience/index.ts +19 -0
  491. package/src/compaction/salience/minhash.ts +53 -0
  492. package/src/compaction/salience/score.ts +305 -0
  493. package/src/compaction/salience/tokenize.ts +89 -0
  494. package/src/compaction/salience/working-set.ts +187 -0
  495. package/src/compaction/serializer.ts +16 -0
  496. package/src/compaction/token-estimate.ts +57 -0
  497. package/src/compaction/tool-result-editing.ts +28 -26
  498. package/src/compaction/types.ts +24 -1
  499. package/src/compaction/wire.ts +5 -1
  500. package/src/config/runtime.ts +13 -1
  501. package/src/connector/builtins/http.ts +2 -8
  502. package/src/connector/builtins/webhook.ts +2 -2
  503. package/src/connector/mcp/adapter.ts +32 -0
  504. package/src/connector/tools/adapter.ts +2 -2
  505. package/src/connector/tools/definitions.ts +2 -2
  506. package/src/constants/compaction/index.ts +1 -0
  507. package/src/constants/telemetry/index.ts +0 -1
  508. package/src/contracts/api.ts +5 -1
  509. package/src/contracts/schemas.ts +6 -20
  510. package/src/invariants/index.ts +1 -1
  511. package/src/manager/agent/lifecycle.ts +380 -352
  512. package/src/manager/run/persistence.ts +35 -5
  513. package/src/plugin/index.ts +19 -0
  514. package/src/plugin/shell-hook.ts +403 -0
  515. package/src/prompt/coding-agent-doctrine.ts +118 -0
  516. package/src/prompt/index.ts +8 -0
  517. package/src/provider/errors.ts +1 -1
  518. package/src/provider/fallback.ts +4 -1
  519. package/src/provider/retry.ts +4 -1
  520. package/src/provider/token-budget.ts +114 -0
  521. package/src/public-runtime.ts +54 -27
  522. package/src/public-tools.ts +5 -0
  523. package/src/public-types.ts +65 -0
  524. package/src/registry/command/kernel-commands.ts +16 -6
  525. package/src/registry/tool/execute.ts +4 -1
  526. package/src/run/LimitChecker.ts +1 -1
  527. package/src/run/drain.ts +1 -1
  528. package/src/run/reporter.ts +15 -0
  529. package/src/run/token-budget.ts +692 -0
  530. package/src/runtime/jobs/registry.ts +123 -17
  531. package/src/runtime/query/checkpoint.ts +10 -3
  532. package/src/runtime/query/context.ts +3 -57
  533. package/src/runtime/query/executor.ts +128 -58
  534. package/src/runtime/query/guard.ts +8 -0
  535. package/src/runtime/query/index.ts +201 -62
  536. package/src/runtime/query/iteration/index.ts +24 -6
  537. package/src/runtime/query/iteration/phases/compaction.ts +130 -31
  538. package/src/runtime/query/iteration/phases/context.ts +2 -0
  539. package/src/runtime/query/iteration/phases/tool-review.ts +39 -7
  540. package/src/runtime/query/iteration/phases/working-memory.ts +23 -14
  541. package/src/runtime/query/plugin-hooks.ts +24 -2
  542. package/src/runtime/query/repeat-call.ts +42 -7
  543. package/src/runtime/query/result.ts +9 -0
  544. package/src/runtime/query/review-policy.ts +231 -0
  545. package/src/runtime/query/run-state.ts +4 -0
  546. package/src/runtime/query/steering.ts +32 -0
  547. package/src/runtime/query/token-budget.ts +127 -0
  548. package/src/runtime/query/tool-output-budget.ts +33 -10
  549. package/src/runtime/query/tool-pause.ts +4 -2
  550. package/src/runtime/query/tooling.ts +8 -0
  551. package/src/sandbox/provider/local.ts +123 -13
  552. package/src/scheduler/delegating.ts +35 -13
  553. package/src/scheduler/local.ts +5 -7
  554. package/src/session/index.ts +0 -1
  555. package/src/session/workspace/path-builder.ts +5 -4
  556. package/src/store/feedback/disk.ts +4 -6
  557. package/src/store/index.ts +2 -0
  558. package/src/store/memory/disk.ts +3 -11
  559. package/src/store/run/checkpoint-disk.ts +14 -27
  560. package/src/store/run/claim-disk.ts +1 -1
  561. package/src/store/run/conformance.ts +55 -39
  562. package/src/store/run/disk.ts +19 -4
  563. package/src/store/run/token-budget-disk.ts +247 -0
  564. package/src/store/session/disk.ts +36 -29
  565. package/src/store/session/memory.ts +38 -1
  566. package/src/store/task/disk.ts +7 -8
  567. package/src/store/topic/memory.ts +13 -1
  568. package/src/test-support/ids.ts +62 -59
  569. package/src/tools/advisory/index.ts +3 -1
  570. package/src/tools/builtins/bash.ts +11 -12
  571. package/src/tools/builtins/computer-use.ts +6 -2
  572. package/src/tools/builtins/edit.ts +2 -2
  573. package/src/tools/builtins/glob.ts +3 -3
  574. package/src/tools/builtins/grep.ts +2 -2
  575. package/src/tools/builtins/ls.ts +2 -2
  576. package/src/tools/builtins/lsp.ts +2 -2
  577. package/src/tools/builtins/read-file.ts +2 -2
  578. package/src/tools/builtins/write-file.ts +2 -2
  579. package/src/tools/coordinator/ask-user-question.ts +284 -0
  580. package/src/tools/coordinator/index.ts +5 -248
  581. package/src/tools/memory/read.ts +2 -4
  582. package/src/tools/paths.ts +64 -0
  583. package/src/tools/roster.ts +46 -0
  584. package/src/types/agent/base.ts +6 -0
  585. package/src/types/agent/pipeline.ts +3 -0
  586. package/src/types/agent/router.ts +2 -3
  587. package/src/types/agent/scheduler.ts +4 -0
  588. package/src/types/agent/task.ts +5 -18
  589. package/src/types/common/index.ts +3 -0
  590. package/src/types/computer-use/index.ts +8 -0
  591. package/src/types/hitl/index.ts +5 -0
  592. package/src/types/ids/brand.ts +5 -48
  593. package/src/types/ids/index.ts +66 -75
  594. package/src/types/permission/index.ts +11 -0
  595. package/src/types/plugin/index.ts +49 -1
  596. package/src/types/run/config.ts +3 -0
  597. package/src/types/run/emergency.ts +5 -0
  598. package/src/types/run/entity.ts +6 -2
  599. package/src/types/run/events.ts +37 -0
  600. package/src/types/run/index.ts +1 -0
  601. package/src/types/run/state.ts +58 -30
  602. package/src/types/run/stop-reason.ts +3 -14
  603. package/src/types/run/token-budget-store.ts +54 -0
  604. package/src/types/sandbox/index.ts +32 -0
  605. package/src/types/session/store.ts +8 -0
  606. package/src/types/tool/index.ts +15 -0
  607. package/src/utils/frontmatter.ts +1 -1
  608. package/src/utils/id-format.ts +9 -0
  609. package/src/utils/id.ts +222 -181
  610. package/src/utils/log/exception.ts +1 -1
  611. package/src/utils/log/index.ts +1 -2
  612. package/src/utils/log/templates.ts +0 -1
  613. package/dist/session/migration/errors.d.ts +0 -26
  614. package/dist/session/migration/errors.d.ts.map +0 -1
  615. package/dist/session/migration/errors.js +0 -22
  616. package/dist/session/migration/errors.js.map +0 -1
  617. package/dist/session/migration/filesystem.d.ts +0 -122
  618. package/dist/session/migration/filesystem.d.ts.map +0 -1
  619. package/dist/session/migration/filesystem.js +0 -379
  620. package/dist/session/migration/filesystem.js.map +0 -1
  621. package/dist/session/migration/id-prefix.d.ts +0 -113
  622. package/dist/session/migration/id-prefix.d.ts.map +0 -1
  623. package/dist/session/migration/id-prefix.js +0 -132
  624. package/dist/session/migration/id-prefix.js.map +0 -1
  625. package/dist/session/migration/index.d.ts +0 -12
  626. package/dist/session/migration/index.d.ts.map +0 -1
  627. package/dist/session/migration/index.js +0 -12
  628. package/dist/session/migration/index.js.map +0 -1
  629. package/dist/session/migration/marker.d.ts +0 -57
  630. package/dist/session/migration/marker.d.ts.map +0 -1
  631. package/dist/session/migration/marker.js +0 -123
  632. package/dist/session/migration/marker.js.map +0 -1
  633. package/src/session/migration/errors.ts +0 -23
  634. package/src/session/migration/filesystem.ts +0 -468
  635. package/src/session/migration/id-prefix.ts +0 -166
  636. package/src/session/migration/index.ts +0 -41
  637. package/src/session/migration/marker.ts +0 -142
@@ -1,5 +1,4 @@
1
1
  import { AGENT_MANAGER_DEFAULTS } from '../../constants/agent/index.js';
2
- import { EMPTY_TOKEN_USAGE } from '../../constants/limits.js';
3
2
  import { GENAI } from '../../constants/telemetry/index.js';
4
3
  import { DelegationCapacityExceeded, } from '../../session/handoff/capacity.js';
5
4
  import { isTerminalAgentTaskState } from '../../types/agent/task.js';
@@ -80,274 +79,373 @@ export class AgentManager {
80
79
  const definitionForSpawn = this.registry.getOrThrow(options.agentId);
81
80
  const sharedAgent = definitionForSpawn.typedAgent;
82
81
  const agent = definitionForSpawn.createAgent?.() ?? sharedAgent.forRun?.() ?? sharedAgent;
83
- const childAbortController = createChildAbortController(context.parentAbortController);
84
- // The allocation is computed INSIDE the spawn lock, not here. Reading
85
- // the parent's remaining budget at this point and debiting it after
86
- // `provisionSpawn` put the two halves of a read-modify-write on either
87
- // side of an await — so N siblings launched from one turn all read the
88
- // same undebited number and each took a fraction of it. Measured: four
89
- // concurrent children were handed 50 000 + 50 000 + 50 000 + 50 000
90
- // from a pool of 100 000.
91
- //
92
- // `create_task`'s own description instructs exactly this shape ("'fan
93
- // out 8 specialists' is one assistant message with 8 create_task
94
- // blocks"), so the documented usage was the reproduction.
95
- //
96
- // Nothing pinned it because the only concurrent test built a fresh
97
- // context per call — each spawn got its own tracker, which measures
98
- // width and not budget.
99
- // Phase 6: SubSession + child Session + WorkspaceRef triple. Happens
100
- // before taskId minting so a capacity failure short-circuits cleanly
101
- // with no observable state change.
102
- //
103
- // The allocation now travels with it, because the read and the debit
104
- // have to be on the same side of every await to mean anything.
105
- const { spawnRecord, allocatedTokens } = await this.provisionSpawn(options, context);
106
- const taskId = generateTaskId();
107
- const childParentActor = {
108
- kind: 'agent',
109
- agentId: context.parentAgentId,
110
- tenantId: context.tenantId,
111
- parentActor: context.parentActor,
112
- };
113
- // The union of every deny along the chain, plus this spawn's own.
114
- //
115
- // Without it, NZ-GATE-09's scope stopped at one level: a child denied
116
- // `bash` could spawn a grandchild naming no scope, and the grandchild
117
- // got bash back. A restriction that a descendant can shed by
118
- // delegating is not a restriction.
119
- //
120
- // No containment CHECK here, deliberately. The obvious shape is to
121
- // confirm with `isDescendantOfActor` that the child really sits under
122
- // the actor whose scope is being inherited — but `childParentActor`
123
- // is built two statements up FROM `context.parentActor`, so the
124
- // answer is yes by construction and the branch could never be taken.
125
- // A check that cannot fail reads as a safeguard and is not one. The
126
- // predicate is exported for the callers that do face an actor they
127
- // did not construct: an audit walking a subtree, a host asking
128
- // whether one run's actor is contained by another's.
129
- //
130
- // Union, not replace, and not "innermost wins": a descendant may
131
- // narrow further and may never widen.
132
- const inheritedDenies = context.toolDenies ?? [];
133
- const ownDenies = options.toolScope?.deny ?? [];
134
- const resolvedDenies = [...new Set([...inheritedDenies, ...ownDenies])];
135
- const childContext = {
136
- parentRunId: context.parentRunId,
137
- parentAgentId: context.parentAgentId,
138
- parentAbortController: context.parentAbortController,
139
- depth: context.depth + 1,
140
- budgetTracker: context.budgetTracker,
141
- factoryOptions: context.factoryOptions,
142
- tenantId: context.tenantId,
143
- topicId: context.topicId,
144
- sessionId: spawnRecord.childSessionId,
145
- projectId: context.projectId,
146
- parentActor: childParentActor,
147
- ...(resolvedDenies.length > 0 ? { toolDenies: resolvedDenies } : {}),
148
- };
149
- const agentTask = {
150
- taskId,
151
- agentId: options.agentId,
152
- agent,
153
- childAbortController,
154
- context: childContext,
155
- state: 'pending',
156
- budgetReservation: allocatedTokens,
157
- pendingMessages: [],
158
- createdAt: Date.now(),
159
- runEventListener: listener,
160
- };
161
- this.instances.set(taskId, agentTask);
162
- if (resolvedDenies.length > 0)
163
- spawnRecord.resolvedToolDenies = resolvedDenies;
164
- this.spawnRecords.set(taskId, spawnRecord);
165
- this.emit({
166
- type: 'pending',
167
- taskId,
168
- agentId: options.agentId,
169
- parentAgentId: context.parentAgentId,
170
- depth: context.depth,
171
- });
172
- if (listener) {
173
- listener({
174
- type: 'agent_pending',
175
- runId: context.parentRunId,
176
- taskId,
177
- parentAgentId: context.parentAgentId,
178
- childAgentId: options.agentId,
179
- depth: context.depth,
180
- });
181
- const lineage = {
182
- parentSessionId: spawnRecord.parentSessionId,
183
- rootSessionId: spawnRecord.rootSessionId,
184
- depth: spawnRecord.childDepth,
185
- };
186
- listener({
187
- type: 'subsession_spawned',
188
- runId: context.parentRunId,
189
- subSessionId: spawnRecord.subSessionId,
190
- parentSessionId: spawnRecord.parentSessionId,
191
- spawnedBy: context.parentActor,
192
- lineage,
193
- schemaVersion: RUN_EVENT_SCHEMA_VERSION,
194
- at: new Date(),
82
+ context.parentAbortController.signal.throwIfAborted();
83
+ // Reserve synchronously before provisioning yields. The authority is shared
84
+ // across managers and nested sessions, while the session lock below only
85
+ // serializes filesystem capacity checks.
86
+ const remaining = context.budget.remaining;
87
+ const maxAllocation = Number.isFinite(remaining)
88
+ ? Math.floor(remaining * this.config.maxBudgetFraction)
89
+ : (options.budgetAllocation?.tokenBudget ??
90
+ (options.configOverrides?.tokenBudget === 0
91
+ ? 200_000
92
+ : (options.configOverrides?.tokenBudget ?? 200_000)));
93
+ const allocatedTokens = Math.min(options.budgetAllocation?.tokenBudget ?? maxAllocation, maxAllocation);
94
+ if (!Number.isSafeInteger(allocatedTokens) || allocatedTokens <= 0) {
95
+ throw new NamzuError({
96
+ code: 'invalid_config',
97
+ message: `Cannot spawn "${options.agentId}": the parent has ${remaining} tokens remaining; a child allocation must be a finite positive integer.`,
195
98
  });
196
99
  }
197
- this.log.info('Agent task pending', {
198
- 'namzu.agent.task_id': taskId,
199
- 'namzu.agent.definition_id': options.agentId,
200
- 'namzu.agent.depth': context.depth,
201
- });
202
- const definition = this.registry.getOrThrow(options.agentId);
203
- let childConfig;
204
- if (definition.configBuilder) {
205
- // Call the configBuilder regardless of whether factoryOptions were
206
- // supplied. BYO-provider flows (ambient cloud credentials, a custom registry)
207
- // commonly omit factoryOptions because the provider resolves its own
208
- // credentials; the builder still needs to run to wire provider+tools.
209
- // Defaults: empty factoryOptions when omitted; configOverrides win.
210
- childConfig = await definition.configBuilder({
211
- ...(context.factoryOptions ?? {}),
212
- tokenBudget: allocatedTokens,
213
- timeoutMs: options.budgetAllocation?.timeoutMs ?? this.config.childTimeoutMs,
100
+ const childBudget = context.budget.reserve(allocatedTokens);
101
+ let spawnRecord;
102
+ try {
103
+ await childBudget.flush();
104
+ spawnRecord = await this.provisionSpawn(options, context);
105
+ }
106
+ catch (error) {
107
+ childBudget.settle(0);
108
+ await childBudget.flush();
109
+ throw error;
110
+ }
111
+ let childAbortController;
112
+ let agentTask;
113
+ try {
114
+ childAbortController = createChildAbortController(context.parentAbortController);
115
+ const taskId = generateTaskId();
116
+ const childParentActor = {
117
+ kind: 'agent',
118
+ agentId: context.parentAgentId,
119
+ tenantId: context.tenantId,
120
+ parentActor: context.parentActor,
121
+ };
122
+ // The union of every deny along the chain, plus this spawn's own.
123
+ //
124
+ // Without it, NZ-GATE-09's scope stopped at one level: a child denied
125
+ // `bash` could spawn a grandchild naming no scope, and the grandchild
126
+ // got bash back. A restriction that a descendant can shed by
127
+ // delegating is not a restriction.
128
+ //
129
+ // No containment CHECK here, deliberately. The obvious shape is to
130
+ // confirm with `isDescendantOfActor` that the child really sits under
131
+ // the actor whose scope is being inherited — but `childParentActor`
132
+ // is built two statements up FROM `context.parentActor`, so the
133
+ // answer is yes by construction and the branch could never be taken.
134
+ // A check that cannot fail reads as a safeguard and is not one. The
135
+ // predicate is exported for the callers that do face an actor they
136
+ // did not construct: an audit walking a subtree, a host asking
137
+ // whether one run's actor is contained by another's.
138
+ //
139
+ // Union, not replace, and not "innermost wins": a descendant may
140
+ // narrow further and may never widen.
141
+ const inheritedDenies = context.toolDenies ?? [];
142
+ const ownDenies = options.toolScope?.deny ?? [];
143
+ const resolvedDenies = [...new Set([...inheritedDenies, ...ownDenies])];
144
+ const childContext = {
214
145
  parentRunId: context.parentRunId,
146
+ parentAgentId: context.parentAgentId,
147
+ parentAbortController: context.parentAbortController,
215
148
  depth: context.depth + 1,
216
- ...options.configOverrides,
149
+ budget: childBudget,
150
+ factoryOptions: context.factoryOptions,
151
+ tenantId: context.tenantId,
152
+ topicId: context.topicId,
153
+ sessionId: spawnRecord.childSessionId,
154
+ projectId: context.projectId,
155
+ parentActor: childParentActor,
156
+ ...(resolvedDenies.length > 0 ? { toolDenies: resolvedDenies } : {}),
157
+ };
158
+ agentTask = {
159
+ taskId,
160
+ agentId: options.agentId,
161
+ agent,
162
+ childAbortController,
163
+ context: childContext,
164
+ state: 'pending',
165
+ pendingMessages: [],
166
+ createdAt: Date.now(),
167
+ runEventListener: listener,
168
+ };
169
+ childAbortController.signal.throwIfAborted();
170
+ this.instances.set(taskId, agentTask);
171
+ if (resolvedDenies.length > 0)
172
+ spawnRecord.resolvedToolDenies = resolvedDenies;
173
+ this.spawnRecords.set(taskId, spawnRecord);
174
+ this.emit({
175
+ type: 'pending',
176
+ taskId,
177
+ agentId: options.agentId,
178
+ parentAgentId: context.parentAgentId,
179
+ depth: context.depth,
217
180
  });
218
- if (!childConfig.contextLevel && definition.contextLevel) {
219
- childConfig.contextLevel = definition.contextLevel;
181
+ if (listener) {
182
+ await listener({
183
+ type: 'agent_pending',
184
+ runId: context.parentRunId,
185
+ taskId,
186
+ parentAgentId: context.parentAgentId,
187
+ childAgentId: options.agentId,
188
+ depth: context.depth,
189
+ });
190
+ const lineage = {
191
+ parentSessionId: spawnRecord.parentSessionId,
192
+ rootSessionId: spawnRecord.rootSessionId,
193
+ depth: spawnRecord.childDepth,
194
+ };
195
+ await listener({
196
+ type: 'subsession_spawned',
197
+ runId: context.parentRunId,
198
+ subSessionId: spawnRecord.subSessionId,
199
+ parentSessionId: spawnRecord.parentSessionId,
200
+ spawnedBy: context.parentActor,
201
+ lineage,
202
+ schemaVersion: RUN_EVENT_SCHEMA_VERSION,
203
+ at: new Date(),
204
+ });
220
205
  }
221
- // Propagate session-hierarchy scoping onto the child config. The
222
- // configBuilder may not have been updated to emit these yet; we
223
- // stamp them here so query() sees them regardless.
224
- childConfig.sessionId = spawnRecord?.childSessionId ?? context.sessionId;
225
- childConfig.topicId = context.topicId;
226
- childConfig.projectId = context.projectId;
227
- childConfig.tenantId = context.tenantId;
228
- // Stamp the trace parent the same way, rather than trusting every
229
- // configBuilder to forward an option it may not know about.
230
- if (options.configOverrides?.parentSpan) {
231
- childConfig.parentSpan = options.configOverrides.parentSpan;
206
+ this.log.info('Agent task pending', {
207
+ 'namzu.agent.task_id': taskId,
208
+ 'namzu.agent.definition_id': options.agentId,
209
+ 'namzu.agent.depth': context.depth,
210
+ });
211
+ const definition = this.registry.getOrThrow(options.agentId);
212
+ let childConfig;
213
+ if (definition.configBuilder) {
214
+ // Call the configBuilder regardless of whether factoryOptions were
215
+ // supplied. BYO-provider flows (ambient cloud credentials, a custom registry)
216
+ // commonly omit factoryOptions because the provider resolves its own
217
+ // credentials; the builder still needs to run to wire provider+tools.
218
+ // Defaults: empty factoryOptions when omitted; configOverrides win.
219
+ childConfig = {
220
+ ...(await definition.configBuilder({
221
+ ...(context.factoryOptions ?? {}),
222
+ tokenBudget: allocatedTokens,
223
+ timeoutMs: options.budgetAllocation?.timeoutMs ?? this.config.childTimeoutMs,
224
+ parentRunId: context.parentRunId,
225
+ depth: context.depth + 1,
226
+ ...options.configOverrides,
227
+ })),
228
+ };
229
+ if (!childConfig.contextLevel && definition.contextLevel) {
230
+ childConfig.contextLevel = definition.contextLevel;
231
+ }
232
+ // Propagate session-hierarchy scoping onto the child config. The
233
+ // configBuilder may not have been updated to emit these yet; we
234
+ // stamp them here so query() sees them regardless.
235
+ childConfig.sessionId = spawnRecord?.childSessionId ?? context.sessionId;
236
+ childConfig.topicId = context.topicId;
237
+ childConfig.projectId = context.projectId;
238
+ childConfig.tenantId = context.tenantId;
239
+ // Stamp the trace parent the same way, rather than trusting every
240
+ // configBuilder to forward an option it may not know about.
241
+ if (options.configOverrides?.parentSpan) {
242
+ childConfig.parentSpan = options.configOverrides.parentSpan;
243
+ }
244
+ // Stamped for the same reason as the trace parent above: a
245
+ // `configBuilder` is written by whoever registered the agent and
246
+ // cannot be trusted to forward something it was never told about.
247
+ // An explicit override still wins, so a host can hand one child a
248
+ // different channel — or none.
249
+ //
250
+ // Without this every delegated child fell through to
251
+ // `autoApproveHandler`, so a host's "ask before acting" gate
252
+ // covered the top-level run and nothing it delegated.
253
+ const inheritedHandler = options.configOverrides?.resumeHandler ?? context.resumeHandler;
254
+ if (inheritedHandler)
255
+ childConfig.resumeHandler = inheritedHandler;
256
+ // And the environment, for the third time and the same reason.
257
+ //
258
+ // The bare-config branch below has always carried `env`; this one
259
+ // never did, so a delegate registered WITH a `configBuilder` — the
260
+ // normal way, and what every host in this repo does — silently ran
261
+ // with none of the environment its parent had been given. The
262
+ // builder is written by whoever registered the agent and cannot be
263
+ // expected to forward a field it was never told about, which is
264
+ // exactly why `parentSpan` and `resumeHandler` are stamped here too.
265
+ //
266
+ // Merged per key rather than replaced. `configOverrides` is a
267
+ // `Partial`, so assigning the whole map would drop every key the
268
+ // builder set and the caller did not restate — the override wins per
269
+ // key, the same direction it already wins for `model` and `effort`.
270
+ const inheritedEnv = mergeEnv(childConfig.env, options.configOverrides?.env);
271
+ if (inheritedEnv)
272
+ childConfig.env = inheritedEnv;
273
+ // A builder may ignore a newly-added factory option. The requested root
274
+ // policy is an execution boundary, so stamp an explicit child override
275
+ // after the builder rather than silently falling back to ephemeral.
276
+ if (options.configOverrides?.sandbox) {
277
+ childConfig.sandbox = options.configOverrides.sandbox;
278
+ }
279
+ }
280
+ else {
281
+ this.log.warn('No configBuilder, using bare config', {
282
+ [GENAI.AGENT_ID]: options.agentId,
283
+ });
284
+ childConfig = {
285
+ model: options.configOverrides?.model ?? 'default',
286
+ tokenBudget: allocatedTokens,
287
+ timeoutMs: options.budgetAllocation?.timeoutMs ?? this.config.childTimeoutMs,
288
+ streamIdleTimeoutMs: options.configOverrides?.streamIdleTimeoutMs,
289
+ maxRequestRichContentBytes: options.configOverrides?.maxRequestRichContentBytes,
290
+ attachmentResolveTimeoutMs: options.configOverrides?.attachmentResolveTimeoutMs,
291
+ temperature: options.configOverrides?.temperature,
292
+ parentSpan: options.configOverrides?.parentSpan,
293
+ maxIterations: options.configOverrides?.maxIterations,
294
+ maxResponseTokens: options.configOverrides?.maxResponseTokens,
295
+ // A delegate spawned without a configBuilder lands here, and this
296
+ // list is the only thing it inherits. Omitting these meant a child
297
+ // silently ran at the default depth and effort its parent had
298
+ // deliberately moved off.
299
+ thinking: options.configOverrides?.thinking,
300
+ effort: options.configOverrides?.effort,
301
+ env: options.configOverrides?.env,
302
+ sandbox: options.configOverrides?.sandbox,
303
+ sessionId: spawnRecord.childSessionId,
304
+ topicId: context.topicId,
305
+ projectId: context.projectId,
306
+ tenantId: context.tenantId,
307
+ parentRunId: context.parentRunId,
308
+ depth: context.depth + 1,
309
+ resumeHandler: options.configOverrides?.resumeHandler ?? context.resumeHandler,
310
+ };
232
311
  }
233
- // Stamped for the same reason as the trace parent above: a
234
- // `configBuilder` is written by whoever registered the agent and
235
- // cannot be trusted to forward something it was never told about.
236
- // An explicit override still wins, so a host can hand one child a
237
- // different channel — or none.
312
+ // Lineage is assigned by the spawning manager, not proposed by the
313
+ // child definition. A fixed configBuilder can ignore its inputs and
314
+ // configOverrides is caller-authored; neither may turn a child back
315
+ // into depth zero or attach it to a different parent run.
316
+ childConfig.parentRunId = context.parentRunId;
317
+ childConfig.depth = context.depth + 1;
318
+ childConfig.budget = childBudget;
319
+ // The reservation is the execution ceiling, regardless of a builder's
320
+ // defaults or configOverrides. Zero means unlimited to query(), so it
321
+ // must inherit the finite allocation rather than erase that ceiling.
322
+ if (!Number.isFinite(childConfig.tokenBudget) || childConfig.tokenBudget < 0) {
323
+ throw new NamzuError({
324
+ code: 'invalid_config',
325
+ message: `Invalid child token budget for "${options.agentId}": ${childConfig.tokenBudget}`,
326
+ });
327
+ }
328
+ childConfig.tokenBudget =
329
+ childConfig.tokenBudget === 0
330
+ ? allocatedTokens
331
+ : Math.min(childConfig.tokenBudget, allocatedTokens);
332
+ childBudget.narrow(childConfig.tokenBudget);
333
+ // Stamped AFTER the builder, for the fourth time and the same reason:
334
+ // a `configBuilder` is written by whoever registered the agent and
335
+ // cannot forward a field it was never told about. A scope applied
336
+ // before it would be silently discarded by every builder that returns
337
+ // a fixed config — which is most of them.
238
338
  //
239
- // Without this every delegated child fell through to
240
- // `autoApproveHandler`, so a host's "ask before acting" gate
241
- // covered the top-level run and nothing it delegated.
242
- const inheritedHandler = options.configOverrides?.resumeHandler ?? context.resumeHandler;
243
- if (inheritedHandler)
244
- childConfig.resumeHandler = inheritedHandler;
245
- // And the environment, for the third time and the same reason.
339
+ // OUTSIDE the branch, unlike the four stamps above, and that is the
340
+ // point. Written inside the `configBuilder` arm it read correctly and
341
+ // left the bare-config arm below ignoring `toolScope` entirely — a
342
+ // caller that asked for a narrower child got a wider one, silently,
343
+ // and in the only direction that matters. Every other field here is
344
+ // an inheritance, where missing it costs the child something; this
345
+ // one is a restriction, where missing it costs the CALLER something.
346
+ //
347
+ // Narrowing only: the deny list is SUBTRACTED from whatever the child
348
+ // would otherwise have. `allowedTools` absent means "every registered
349
+ // tool", so a deny with no existing allow-list has to be resolved
350
+ // against the registry at the run rather than here — which `query()`
351
+ // does, and which is why this appends to `deniedTools` rather than
352
+ // synthesising an allow-list.
353
+ if (resolvedDenies.length > 0) {
354
+ childConfig.deniedTools = [
355
+ ...new Set([...(childConfig.deniedTools ?? []), ...resolvedDenies]),
356
+ ];
357
+ }
358
+ if (options.personaOverride)
359
+ childConfig.persona = options.personaOverride;
360
+ // Outside the branch, like the scope above it and for the same reason:
361
+ // a `configBuilder` cannot forward a field it was never told about.
246
362
  //
247
- // The bare-config branch below has always carried `env`; this one
248
- // never did, so a delegate registered WITH a `configBuilder` the
249
- // normal way, and what every host in this repo does — silently ran
250
- // with none of the environment its parent had been given. The
251
- // builder is written by whoever registered the agent and cannot be
252
- // expected to forward a field it was never told about, which is
253
- // exactly why `parentSpan` and `resumeHandler` are stamped here too.
363
+ // Bound to the taskId rather than to the task object, so a drain after
364
+ // the task is gone throws where the caller is instead of returning an
365
+ // empty array from a closure over a corpse.
254
366
  //
255
- // Merged per key rather than replaced. `configOverrides` is a
256
- // `Partial`, so assigning the whole map would drop every key the
257
- // builder set and the caller did not restate the override wins per
258
- // key, the same direction it already wins for `model` and `effort`.
259
- const inheritedEnv = mergeEnv(childConfig.env, options.configOverrides?.env);
260
- if (inheritedEnv)
261
- childConfig.env = inheritedEnv;
262
- // A builder may ignore a newly-added factory option. The requested root
263
- // policy is an execution boundary, so stamp an explicit child override
264
- // after the builder rather than silently falling back to ephemeral.
265
- if (options.configOverrides?.sandbox) {
266
- childConfig.sandbox = options.configOverrides.sandbox;
367
+ // This is the delivery point `pendingMessages` never had.
368
+ // `continueTask` and `queueMessage` pushed onto it and nothing in the
369
+ // kernel drained it the manager interface's own docblock said "the
370
+ // runtime does not deliver it", and `continue_task` was unmounted from
371
+ // the coordinator tools because of that.
372
+ childConfig.inboundMessages = () => this.drainMessages(taskId);
373
+ childAbortController.signal.throwIfAborted();
374
+ await childBudget.flush();
375
+ childAbortController.signal.throwIfAborted();
376
+ this.runChild(agentTask, options, childConfig, listener).catch(async (err) => {
377
+ // A thrown invocation supplied no final usage receipt. Keep its
378
+ // reservation, including when its task handle was canceled or evicted.
379
+ let failure = err;
380
+ try {
381
+ await childBudget.flush();
382
+ }
383
+ catch (writeError) {
384
+ failure = writeError;
385
+ }
386
+ this.markFailed(taskId, toErrorMessage(failure));
387
+ });
388
+ return agentTask;
389
+ }
390
+ catch (err) {
391
+ // No child invocation has been admitted: all reserved tokens and all
392
+ // provisioned resources are still ours to return. A builder/listener
393
+ // failure must not strand a pending task the caller never received.
394
+ if (agentTask) {
395
+ await this.rollbackUnstartedSpawn(agentTask, spawnRecord, err);
267
396
  }
397
+ else {
398
+ childAbortController?.abort();
399
+ childBudget.settle(0);
400
+ await childBudget.flush();
401
+ await this.rollbackSpawnResources(spawnRecord);
402
+ }
403
+ throw err;
268
404
  }
269
- else {
270
- this.log.warn('No configBuilder, using bare config', {
271
- [GENAI.AGENT_ID]: options.agentId,
272
- });
273
- childConfig = {
274
- model: options.configOverrides?.model ?? 'default',
275
- tokenBudget: allocatedTokens,
276
- timeoutMs: options.budgetAllocation?.timeoutMs ?? this.config.childTimeoutMs,
277
- streamIdleTimeoutMs: options.configOverrides?.streamIdleTimeoutMs,
278
- maxRequestRichContentBytes: options.configOverrides?.maxRequestRichContentBytes,
279
- attachmentResolveTimeoutMs: options.configOverrides?.attachmentResolveTimeoutMs,
280
- temperature: options.configOverrides?.temperature,
281
- parentSpan: options.configOverrides?.parentSpan,
282
- maxIterations: options.configOverrides?.maxIterations,
283
- maxResponseTokens: options.configOverrides?.maxResponseTokens,
284
- // A delegate spawned without a configBuilder lands here, and this
285
- // list is the only thing it inherits. Omitting these meant a child
286
- // silently ran at the default depth and effort its parent had
287
- // deliberately moved off.
288
- thinking: options.configOverrides?.thinking,
289
- effort: options.configOverrides?.effort,
290
- env: options.configOverrides?.env,
291
- sandbox: options.configOverrides?.sandbox,
292
- sessionId: spawnRecord.childSessionId,
293
- topicId: context.topicId,
294
- projectId: context.projectId,
295
- tenantId: context.tenantId,
296
- parentRunId: context.parentRunId,
297
- depth: context.depth + 1,
298
- resumeHandler: options.configOverrides?.resumeHandler ?? context.resumeHandler,
299
- };
405
+ }
406
+ async rollbackUnstartedSpawn(agentTask, spawnRecord, reason) {
407
+ agentTask.childAbortController.abort();
408
+ agentTask.context.budget.settle(0);
409
+ await agentTask.context.budget.flush();
410
+ if (!isTerminalAgentTaskState(agentTask.state)) {
411
+ agentTask.state = 'failed';
412
+ const error = toErrorMessage(reason);
413
+ this.emit({ type: 'failed', taskId: agentTask.taskId, error });
414
+ try {
415
+ await agentTask.runEventListener?.({
416
+ type: 'agent_failed',
417
+ runId: agentTask.context.parentRunId,
418
+ taskId: agentTask.taskId,
419
+ error,
420
+ });
421
+ }
422
+ catch (err) {
423
+ this.log.warn('Unstarted child failure notification failed', {
424
+ 'namzu.task.id': agentTask.taskId,
425
+ 'exception.message': toErrorMessage(err),
426
+ });
427
+ }
300
428
  }
301
- // Lineage is assigned by the spawning manager, not proposed by the
302
- // child definition. A fixed configBuilder can ignore its inputs and
303
- // configOverrides is caller-authored; neither may turn a child back
304
- // into depth zero or attach it to a different parent run.
305
- childConfig.parentRunId = context.parentRunId;
306
- childConfig.depth = context.depth + 1;
307
- // Stamped AFTER the builder, for the fourth time and the same reason:
308
- // a `configBuilder` is written by whoever registered the agent and
309
- // cannot forward a field it was never told about. A scope applied
310
- // before it would be silently discarded by every builder that returns
311
- // a fixed config which is most of them.
312
- //
313
- // OUTSIDE the branch, unlike the four stamps above, and that is the
314
- // point. Written inside the `configBuilder` arm it read correctly and
315
- // left the bare-config arm below ignoring `toolScope` entirely — a
316
- // caller that asked for a narrower child got a wider one, silently,
317
- // and in the only direction that matters. Every other field here is
318
- // an inheritance, where missing it costs the child something; this
319
- // one is a restriction, where missing it costs the CALLER something.
320
- //
321
- // Narrowing only: the deny list is SUBTRACTED from whatever the child
322
- // would otherwise have. `allowedTools` absent means "every registered
323
- // tool", so a deny with no existing allow-list has to be resolved
324
- // against the registry at the run rather than here — which `query()`
325
- // does, and which is why this appends to `deniedTools` rather than
326
- // synthesising an allow-list.
327
- if (resolvedDenies.length > 0) {
328
- childConfig.deniedTools = [
329
- ...new Set([...(childConfig.deniedTools ?? []), ...resolvedDenies]),
330
- ];
429
+ this.clearEvictionTimer(agentTask.taskId);
430
+ this.instances.delete(agentTask.taskId);
431
+ this.spawnRecords.delete(agentTask.taskId);
432
+ this.resolveCompletionCallbacks(agentTask.taskId);
433
+ await this.rollbackSpawnResources(spawnRecord);
434
+ }
435
+ async rollbackSpawnResources(spawnRecord) {
436
+ await this.disposeChildWorkspace(spawnRecord);
437
+ try {
438
+ // The edge must be removed before its child: stores reject deletion
439
+ // of a session that still has a subsession reference.
440
+ await this.deps.sessionStore.deleteSubSession(spawnRecord.subSessionId, spawnRecord.tenantId);
441
+ await this.deps.sessionStore.deleteSession(spawnRecord.childSessionId, spawnRecord.tenantId);
442
+ }
443
+ catch (err) {
444
+ this.log.warn('Unstarted child rollback failed', {
445
+ 'namzu.sub_session.id': spawnRecord.subSessionId,
446
+ 'exception.message': toErrorMessage(err),
447
+ });
331
448
  }
332
- if (options.personaOverride)
333
- childConfig.persona = options.personaOverride;
334
- // Outside the branch, like the scope above it and for the same reason:
335
- // a `configBuilder` cannot forward a field it was never told about.
336
- //
337
- // Bound to the taskId rather than to the task object, so a drain after
338
- // the task is gone throws where the caller is instead of returning an
339
- // empty array from a closure over a corpse.
340
- //
341
- // This is the delivery point `pendingMessages` never had.
342
- // `continueTask` and `queueMessage` pushed onto it and nothing in the
343
- // kernel drained it — the manager interface's own docblock said "the
344
- // runtime does not deliver it", and `continue_task` was unmounted from
345
- // the coordinator tools because of that.
346
- childConfig.inboundMessages = () => this.drainMessages(taskId);
347
- this.runChild(agentTask, options, childConfig, listener).catch((err) => {
348
- this.markFailed(taskId, toErrorMessage(err));
349
- });
350
- return agentTask;
351
449
  }
352
450
  cancel(taskId, cause) {
353
451
  const agentTask = this.instances.get(taskId);
@@ -494,34 +592,6 @@ export class AgentManager {
494
592
  }
495
593
  }
496
594
  async provisionSpawnUnlocked(options, context) {
497
- // Read the parent's remaining budget HERE, inside the lock, so that
498
- // concurrent siblings queue behind one another rather than all reading
499
- // the same untouched number. The debit at the end of this method closes
500
- // the pair: read and write are now on the same side of every await.
501
- const maxAllocation = Math.floor(context.budgetTracker.remaining * this.config.maxBudgetFraction);
502
- const allocatedTokens = Math.min(options.budgetAllocation?.tokenBudget ?? maxAllocation, maxAllocation);
503
- // Budget exhaustion must not INVERT into no budget at all. Downstream,
504
- // `tokenBudget: 0` means "uncapped" (`LimitChecker`: `tokenBudget > 0
505
- // && total >= tokenBudget`), and `maxAllocation` floors to 0 as soon as
506
- // the parent's remaining drops below `1 / maxBudgetFraction`. So the
507
- // most depleted parent in the tree was the one that spawned an
508
- // unlimited child. Refuse instead: a caller that wants an uncapped
509
- // child can say so explicitly with its own `budgetAllocation`.
510
- //
511
- // Refusing before any provisioning work also preserves the property the
512
- // debit's placement was chosen for: a spawn this call rejects makes no
513
- // state change at all, and burns no allocation.
514
- if (allocatedTokens <= 0) {
515
- throw new NamzuError({
516
- code: 'invalid_config',
517
- message: `Cannot spawn "${options.agentId}": the parent has ${context.budgetTracker.remaining} tokens remaining, which allocates 0 to the child — and a token budget of 0 means UNLIMITED downstream.`,
518
- details: {
519
- agentId: options.agentId,
520
- parentRemaining: context.budgetTracker.remaining,
521
- maxBudgetFraction: this.config.maxBudgetFraction,
522
- },
523
- });
524
- }
525
595
  // Phase 9: deps are unconditional required. Every spawn produces a
526
596
  // SubSession + Session + WorkspaceRef triple (Convention #0: no
527
597
  // partial/legacy path).
@@ -635,6 +705,12 @@ export class AgentManager {
635
705
  }
636
706
  }
637
707
  catch (err) {
708
+ if (workspaceRef && subSession) {
709
+ await this.disposeChildWorkspace({
710
+ workspaceRef,
711
+ subSessionId: subSession.id,
712
+ });
713
+ }
638
714
  // Compensating rollback order is mandated by the store's
639
715
  // deny-by-default cascade policy (Convention #5): `deleteSession`
640
716
  // throws when any subsession still references it, so the subsession
@@ -651,23 +727,14 @@ export class AgentManager {
651
727
  await store.deleteSession(childSession.id, context.tenantId).catch(() => undefined);
652
728
  throw err;
653
729
  }
654
- // Debited only now, with the provisioning committed. Every path that
655
- // could still have thrown is behind us, so a rejected spawn leaves the
656
- // parent's budget untouched — the property the debit's original
657
- // placement was chosen for, kept while closing the race that placement
658
- // opened.
659
- context.budgetTracker.remaining -= allocatedTokens;
660
730
  return {
661
- spawnRecord: {
662
- subSessionId: subSession.id,
663
- childSessionId: childSession.id,
664
- tenantId: context.tenantId,
665
- parentSessionId: options.parentSessionId,
666
- rootSessionId,
667
- childDepth,
668
- workspaceRef,
669
- },
670
- allocatedTokens,
731
+ subSessionId: subSession.id,
732
+ childSessionId: childSession.id,
733
+ tenantId: context.tenantId,
734
+ parentSessionId: options.parentSessionId,
735
+ rootSessionId,
736
+ childDepth,
737
+ workspaceRef,
671
738
  };
672
739
  }
673
740
  async runChild(agentTask, options, childConfig, listener) {
@@ -680,6 +747,9 @@ export class AgentManager {
680
747
  const spawnRecord = this.spawnRecords.get(agentTask.taskId);
681
748
  const childListener = this.wrapChildListener(listener, spawnRecord);
682
749
  const result = await agentTask.agent.run(input, childConfig, childListener);
750
+ agentTask.context.budget.bindRun(result.runId);
751
+ agentTask.context.budget.settle(result.usage?.totalTokens);
752
+ await agentTask.context.budget.flush();
683
753
  await this.finalizeChild(agentTask, result);
684
754
  }
685
755
  /**
@@ -795,44 +865,10 @@ export class AgentManager {
795
865
  }
796
866
  this.markCompleted(agentTask.taskId, result);
797
867
  }
798
- /**
799
- * Return the unspent part of a settled child's reservation.
800
- *
801
- * The debit at spawn reserves headroom so siblings cannot each be
802
- * promised the same tokens. Nothing returned it, so a pool shrank by
803
- * the full allocation on every spawn no matter what the child used: at
804
- * a half-pool fraction, ten delegations left a parent with a
805
- * thousandth of its budget and the next spawn was refused for a budget
806
- * that had barely been spent.
807
- *
808
- * Idempotent — the reservation is cleared as it is returned, so a
809
- * second terminal transition for the same task cannot credit twice.
810
- * Spend above the reservation returns nothing rather than going
811
- * negative; the child was capped at its allocation, so that case means
812
- * the accounting was already wrong and inventing headroom would hide
813
- * it.
814
- */
815
- releaseBudget(agentTask, spent) {
816
- const reserved = agentTask.budgetReservation;
817
- if (reserved === undefined)
818
- return;
819
- agentTask.budgetReservation = undefined;
820
- const unused = Math.max(0, reserved - Math.max(0, spent));
821
- if (unused === 0)
822
- return;
823
- agentTask.context.budgetTracker.remaining += unused;
824
- this.log.debug('Returned unspent child budget', {
825
- 'namzu.task.id': agentTask.taskId,
826
- 'namzu.manager.reserved': reserved,
827
- 'namzu.manager.spent': spent,
828
- 'namzu.manager.returned': unused,
829
- });
830
- }
831
868
  markCompleted(taskId, result) {
832
869
  const agentTask = this.instances.get(taskId);
833
870
  if (!agentTask || isTerminalAgentTaskState(agentTask.state))
834
871
  return;
835
- this.releaseBudget(agentTask, result.usage?.totalTokens ?? 0);
836
872
  agentTask.result = result;
837
873
  agentTask.completedAt = Date.now();
838
874
  this.updateState(taskId, 'completed');
@@ -851,15 +887,12 @@ export class AgentManager {
851
887
  const agentTask = this.instances.get(taskId);
852
888
  if (!agentTask || isTerminalAgentTaskState(agentTask.state))
853
889
  return;
854
- // A child that failed still spent whatever it spent, and holding the
855
- // rest of its reservation would punish the parent twice for one
856
- // failure.
857
- this.releaseBudget(agentTask, agentTask.result?.usage?.totalTokens ?? 0);
858
890
  agentTask.result = {
859
- runId: agentTask.context.parentRunId,
891
+ runId: agentTask.context.budget.runId ?? agentTask.context.parentRunId,
860
892
  status: 'failed',
861
- usage: { ...EMPTY_TOKEN_USAGE },
862
- cost: { ...ZERO_COST },
893
+ usage: agentTask.context.budget.ownUsage,
894
+ budget: agentTask.context.budget.summary(),
895
+ cost: { ...ZERO_COST, unpricedTokens: agentTask.context.budget.ownTokens },
863
896
  iterations: 0,
864
897
  durationMs: Date.now() - agentTask.createdAt,
865
898
  messages: [],