@namzu/sdk 49.0.0 → 50.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 (737) hide show
  1. package/CHANGELOG.md +507 -0
  2. package/README.md +137 -125
  3. package/dist/agents/QueryAgent.d.ts.map +1 -1
  4. package/dist/agents/QueryAgent.js +1 -0
  5. package/dist/agents/QueryAgent.js.map +1 -1
  6. package/dist/agents/examples/SupervisorAgent.d.ts.map +1 -1
  7. package/dist/agents/examples/SupervisorAgent.js +1 -0
  8. package/dist/agents/examples/SupervisorAgent.js.map +1 -1
  9. package/dist/agents/runAgent.d.ts +2 -0
  10. package/dist/agents/runAgent.d.ts.map +1 -1
  11. package/dist/agents/runAgent.js +1 -0
  12. package/dist/agents/runAgent.js.map +1 -1
  13. package/dist/authorization/shell-lexer.d.ts.map +1 -1
  14. package/dist/authorization/shell-lexer.js +16 -1
  15. package/dist/authorization/shell-lexer.js.map +1 -1
  16. package/dist/bridge/acp/permission.d.ts +8 -2
  17. package/dist/bridge/acp/permission.d.ts.map +1 -1
  18. package/dist/bridge/acp/permission.js +1 -0
  19. package/dist/bridge/acp/permission.js.map +1 -1
  20. package/dist/bridge/acp/server.d.ts +25 -1
  21. package/dist/bridge/acp/server.d.ts.map +1 -1
  22. package/dist/bridge/acp/server.js +205 -21
  23. package/dist/bridge/acp/server.js.map +1 -1
  24. package/dist/bridge/acp/tasks.d.ts +5 -0
  25. package/dist/bridge/acp/tasks.d.ts.map +1 -0
  26. package/dist/bridge/acp/tasks.js +19 -0
  27. package/dist/bridge/acp/tasks.js.map +1 -0
  28. package/dist/bridge/acp/update.d.ts.map +1 -1
  29. package/dist/bridge/acp/update.js +148 -13
  30. package/dist/bridge/acp/update.js.map +1 -1
  31. package/dist/config/runtime.d.ts +31 -31
  32. package/dist/connector/mcp/adapter.d.ts.map +1 -1
  33. package/dist/connector/mcp/adapter.js +11 -4
  34. package/dist/connector/mcp/adapter.js.map +1 -1
  35. package/dist/connector/mcp/client.d.ts.map +1 -1
  36. package/dist/connector/mcp/client.js +6 -3
  37. package/dist/connector/mcp/client.js.map +1 -1
  38. package/dist/constants/acp/index.d.ts +3 -0
  39. package/dist/constants/acp/index.d.ts.map +1 -1
  40. package/dist/constants/acp/index.js +3 -0
  41. package/dist/constants/acp/index.js.map +1 -1
  42. package/dist/contracts/a2a.d.ts +80 -80
  43. package/dist/contracts/schemas.d.ts +2 -2
  44. package/dist/contracts/session/schemas.d.ts +10 -10
  45. package/dist/manager/agent/lifecycle.d.ts +11 -0
  46. package/dist/manager/agent/lifecycle.d.ts.map +1 -1
  47. package/dist/manager/agent/lifecycle.js +178 -3
  48. package/dist/manager/agent/lifecycle.js.map +1 -1
  49. package/dist/manager/plan/lifecycle.d.ts +7 -8
  50. package/dist/manager/plan/lifecycle.d.ts.map +1 -1
  51. package/dist/manager/plan/lifecycle.js +7 -8
  52. package/dist/manager/plan/lifecycle.js.map +1 -1
  53. package/dist/manager/resident/consumption.d.ts +8 -8
  54. package/dist/manager/resident/learning-cycle.d.ts +2 -2
  55. package/dist/manager/resident/learning-observation.d.ts +12 -12
  56. package/dist/manager/resident/learning.d.ts +82 -82
  57. package/dist/manager/resident/outbox.d.ts +8 -8
  58. package/dist/manager/resident/proposal.d.ts +2 -2
  59. package/dist/manager/resident/store.d.ts +10 -10
  60. package/dist/manager/session/attribution.d.ts +1 -0
  61. package/dist/manager/session/attribution.d.ts.map +1 -1
  62. package/dist/manager/session/attribution.js +9 -1
  63. package/dist/manager/session/attribution.js.map +1 -1
  64. package/dist/manager/session/streamed-message-identity.d.ts +6 -0
  65. package/dist/manager/session/streamed-message-identity.d.ts.map +1 -0
  66. package/dist/manager/session/streamed-message-identity.js +14 -0
  67. package/dist/manager/session/streamed-message-identity.js.map +1 -0
  68. package/dist/manager/session/turn-recorder.d.ts.map +1 -1
  69. package/dist/manager/session/turn-recorder.js +4 -3
  70. package/dist/manager/session/turn-recorder.js.map +1 -1
  71. package/dist/pals/activity/causality.d.ts +23 -0
  72. package/dist/pals/activity/causality.d.ts.map +1 -0
  73. package/dist/pals/activity/causality.js +205 -0
  74. package/dist/pals/activity/causality.js.map +1 -0
  75. package/dist/pals/activity/projection.d.ts +5 -0
  76. package/dist/pals/activity/projection.d.ts.map +1 -0
  77. package/dist/pals/activity/projection.js +79 -0
  78. package/dist/pals/activity/projection.js.map +1 -0
  79. package/dist/pals/activity/source.d.ts +16 -0
  80. package/dist/pals/activity/source.d.ts.map +1 -0
  81. package/dist/pals/activity/source.js +235 -0
  82. package/dist/pals/activity/source.js.map +1 -0
  83. package/dist/pals/activity/subscription-policy.d.ts +38 -0
  84. package/dist/pals/activity/subscription-policy.d.ts.map +1 -0
  85. package/dist/pals/activity/subscription-policy.js +183 -0
  86. package/dist/pals/activity/subscription-policy.js.map +1 -0
  87. package/dist/pals/activity/subscription-schema.d.ts +353 -0
  88. package/dist/pals/activity/subscription-schema.d.ts.map +1 -0
  89. package/dist/pals/activity/subscription-schema.js +24 -0
  90. package/dist/pals/activity/subscription-schema.js.map +1 -0
  91. package/dist/pals/activity/subscription-store.d.ts +25 -0
  92. package/dist/pals/activity/subscription-store.d.ts.map +1 -0
  93. package/dist/pals/activity/subscription-store.js +152 -0
  94. package/dist/pals/activity/subscription-store.js.map +1 -0
  95. package/dist/pals/activity/subscription-types.d.ts +42 -0
  96. package/dist/pals/activity/subscription-types.d.ts.map +1 -0
  97. package/dist/pals/activity/subscription-types.js +2 -0
  98. package/dist/pals/activity/subscription-types.js.map +1 -0
  99. package/dist/pals/activity/subscriptions.d.ts +32 -0
  100. package/dist/pals/activity/subscriptions.d.ts.map +1 -0
  101. package/dist/pals/activity/subscriptions.js +151 -0
  102. package/dist/pals/activity/subscriptions.js.map +1 -0
  103. package/dist/pals/activity/types.d.ts +77 -0
  104. package/dist/pals/activity/types.d.ts.map +1 -0
  105. package/dist/pals/activity/types.js +2 -0
  106. package/dist/pals/activity/types.js.map +1 -0
  107. package/dist/pals/channels/ingress.d.ts +9 -0
  108. package/dist/pals/channels/ingress.d.ts.map +1 -0
  109. package/dist/pals/channels/ingress.js +131 -0
  110. package/dist/pals/channels/ingress.js.map +1 -0
  111. package/dist/pals/channels/routes.d.ts +20 -0
  112. package/dist/pals/channels/routes.d.ts.map +1 -0
  113. package/dist/pals/channels/routes.js +111 -0
  114. package/dist/pals/channels/routes.js.map +1 -0
  115. package/dist/pals/channels/routing.d.ts +37 -0
  116. package/dist/pals/channels/routing.d.ts.map +1 -0
  117. package/dist/pals/channels/routing.js +150 -0
  118. package/dist/pals/channels/routing.js.map +1 -0
  119. package/dist/pals/channels/schema.d.ts +234 -0
  120. package/dist/pals/channels/schema.d.ts.map +1 -0
  121. package/dist/pals/channels/schema.js +94 -0
  122. package/dist/pals/channels/schema.js.map +1 -0
  123. package/dist/pals/channels/types.d.ts +115 -0
  124. package/dist/pals/channels/types.d.ts.map +1 -0
  125. package/dist/pals/channels/types.js +2 -0
  126. package/dist/pals/channels/types.js.map +1 -0
  127. package/dist/pals/communication/broker.d.ts +8 -0
  128. package/dist/pals/communication/broker.d.ts.map +1 -0
  129. package/dist/pals/communication/broker.js +121 -0
  130. package/dist/pals/communication/broker.js.map +1 -0
  131. package/dist/pals/communication/dispatch.d.ts +4 -0
  132. package/dist/pals/communication/dispatch.d.ts.map +1 -0
  133. package/dist/pals/communication/dispatch.js +57 -0
  134. package/dist/pals/communication/dispatch.js.map +1 -0
  135. package/dist/pals/communication/inbound.d.ts +9 -0
  136. package/dist/pals/communication/inbound.d.ts.map +1 -0
  137. package/dist/pals/communication/inbound.js +155 -0
  138. package/dist/pals/communication/inbound.js.map +1 -0
  139. package/dist/pals/communication/ingress-dispatch.d.ts +5 -0
  140. package/dist/pals/communication/ingress-dispatch.d.ts.map +1 -0
  141. package/dist/pals/communication/ingress-dispatch.js +51 -0
  142. package/dist/pals/communication/ingress-dispatch.js.map +1 -0
  143. package/dist/pals/communication/ingress-inbound.d.ts +9 -0
  144. package/dist/pals/communication/ingress-inbound.d.ts.map +1 -0
  145. package/dist/pals/communication/ingress-inbound.js +222 -0
  146. package/dist/pals/communication/ingress-inbound.js.map +1 -0
  147. package/dist/pals/communication/ingress-schema.d.ts +7829 -0
  148. package/dist/pals/communication/ingress-schema.d.ts.map +1 -0
  149. package/dist/pals/communication/ingress-schema.js +479 -0
  150. package/dist/pals/communication/ingress-schema.js.map +1 -0
  151. package/dist/pals/communication/ingress-types.d.ts +187 -0
  152. package/dist/pals/communication/ingress-types.d.ts.map +1 -0
  153. package/dist/pals/communication/ingress-types.js +73 -0
  154. package/dist/pals/communication/ingress-types.js.map +1 -0
  155. package/dist/pals/communication/operator.d.ts +75 -0
  156. package/dist/pals/communication/operator.d.ts.map +1 -0
  157. package/dist/pals/communication/operator.js +217 -0
  158. package/dist/pals/communication/operator.js.map +1 -0
  159. package/dist/pals/communication/policy.d.ts +41 -0
  160. package/dist/pals/communication/policy.d.ts.map +1 -0
  161. package/dist/pals/communication/policy.js +138 -0
  162. package/dist/pals/communication/policy.js.map +1 -0
  163. package/dist/pals/communication/schema.d.ts +2000 -0
  164. package/dist/pals/communication/schema.d.ts.map +1 -0
  165. package/dist/pals/communication/schema.js +170 -0
  166. package/dist/pals/communication/schema.js.map +1 -0
  167. package/dist/pals/communication/store.d.ts +61 -0
  168. package/dist/pals/communication/store.d.ts.map +1 -0
  169. package/dist/pals/communication/store.js +450 -0
  170. package/dist/pals/communication/store.js.map +1 -0
  171. package/dist/pals/communication/tools.d.ts +23 -0
  172. package/dist/pals/communication/tools.d.ts.map +1 -0
  173. package/dist/pals/communication/tools.js +107 -0
  174. package/dist/pals/communication/tools.js.map +1 -0
  175. package/dist/pals/communication/types.d.ts +168 -0
  176. package/dist/pals/communication/types.d.ts.map +1 -0
  177. package/dist/pals/communication/types.js +24 -0
  178. package/dist/pals/communication/types.js.map +1 -0
  179. package/dist/pals/communication/verify.d.ts +22 -0
  180. package/dist/pals/communication/verify.d.ts.map +1 -0
  181. package/dist/pals/communication/verify.js +142 -0
  182. package/dist/pals/communication/verify.js.map +1 -0
  183. package/dist/pals/lifecycle.d.ts +37 -0
  184. package/dist/pals/lifecycle.d.ts.map +1 -0
  185. package/dist/pals/lifecycle.js +22 -0
  186. package/dist/pals/lifecycle.js.map +1 -0
  187. package/dist/pals/prompt.d.ts +30 -0
  188. package/dist/pals/prompt.d.ts.map +1 -0
  189. package/dist/pals/prompt.js +65 -0
  190. package/dist/pals/prompt.js.map +1 -0
  191. package/dist/pals/reference-images.d.ts +44 -0
  192. package/dist/pals/reference-images.d.ts.map +1 -0
  193. package/dist/pals/reference-images.js +248 -0
  194. package/dist/pals/reference-images.js.map +1 -0
  195. package/dist/pals/runtime.d.ts +46 -0
  196. package/dist/pals/runtime.d.ts.map +1 -0
  197. package/dist/pals/runtime.js +624 -0
  198. package/dist/pals/runtime.js.map +1 -0
  199. package/dist/pals/store.d.ts +26 -0
  200. package/dist/pals/store.d.ts.map +1 -0
  201. package/dist/pals/store.js +334 -0
  202. package/dist/pals/store.js.map +1 -0
  203. package/dist/pals/types.d.ts +145 -0
  204. package/dist/pals/types.d.ts.map +1 -0
  205. package/dist/pals/types.js +2 -0
  206. package/dist/pals/types.js.map +1 -0
  207. package/dist/peers/envelope.js +1 -1
  208. package/dist/peers/envelope.js.map +1 -1
  209. package/dist/peers/protocol.d.ts +83 -83
  210. package/dist/peers/record.d.ts +10 -10
  211. package/dist/plugin/shell-hook.d.ts.map +1 -1
  212. package/dist/plugin/shell-hook.js +7 -2
  213. package/dist/plugin/shell-hook.js.map +1 -1
  214. package/dist/process/kill-tree.d.ts.map +1 -1
  215. package/dist/process/kill-tree.js +9 -1
  216. package/dist/process/kill-tree.js.map +1 -1
  217. package/dist/provider/errors.d.ts +19 -0
  218. package/dist/provider/errors.d.ts.map +1 -1
  219. package/dist/provider/errors.js +123 -2
  220. package/dist/provider/errors.js.map +1 -1
  221. package/dist/public-runtime.d.ts +41 -13
  222. package/dist/public-runtime.d.ts.map +1 -1
  223. package/dist/public-runtime.js +35 -7
  224. package/dist/public-runtime.js.map +1 -1
  225. package/dist/public-tools.d.ts +8 -3
  226. package/dist/public-tools.d.ts.map +1 -1
  227. package/dist/public-tools.js +8 -3
  228. package/dist/public-tools.js.map +1 -1
  229. package/dist/public-types.d.ts +27 -7
  230. package/dist/public-types.d.ts.map +1 -1
  231. package/dist/registry/tool/presentation.d.ts +1 -0
  232. package/dist/registry/tool/presentation.d.ts.map +1 -1
  233. package/dist/registry/tool/presentation.js +9 -7
  234. package/dist/registry/tool/presentation.js.map +1 -1
  235. package/dist/runtime/harness-session/index.d.ts +5 -0
  236. package/dist/runtime/harness-session/index.d.ts.map +1 -0
  237. package/dist/runtime/harness-session/index.js +928 -0
  238. package/dist/runtime/harness-session/index.js.map +1 -0
  239. package/dist/runtime/harness-session/journal.d.ts +37 -0
  240. package/dist/runtime/harness-session/journal.d.ts.map +1 -0
  241. package/dist/runtime/harness-session/journal.js +177 -0
  242. package/dist/runtime/harness-session/journal.js.map +1 -0
  243. package/dist/runtime/harness-session/saved-view.d.ts +8 -0
  244. package/dist/runtime/harness-session/saved-view.d.ts.map +1 -0
  245. package/dist/runtime/harness-session/saved-view.js +112 -0
  246. package/dist/runtime/harness-session/saved-view.js.map +1 -0
  247. package/dist/runtime/jobs/awaited-jobs.d.ts +2 -1
  248. package/dist/runtime/jobs/awaited-jobs.d.ts.map +1 -1
  249. package/dist/runtime/jobs/awaited-jobs.js +2 -1
  250. package/dist/runtime/jobs/awaited-jobs.js.map +1 -1
  251. package/dist/runtime/jobs/registry.d.ts +56 -1
  252. package/dist/runtime/jobs/registry.d.ts.map +1 -1
  253. package/dist/runtime/jobs/registry.js +351 -34
  254. package/dist/runtime/jobs/registry.js.map +1 -1
  255. package/dist/runtime/query/abandon-turn.d.ts +12 -1
  256. package/dist/runtime/query/abandon-turn.d.ts.map +1 -1
  257. package/dist/runtime/query/abandon-turn.js +3 -1
  258. package/dist/runtime/query/abandon-turn.js.map +1 -1
  259. package/dist/runtime/query/checkpoint.d.ts +4 -0
  260. package/dist/runtime/query/checkpoint.d.ts.map +1 -1
  261. package/dist/runtime/query/checkpoint.js +10 -0
  262. package/dist/runtime/query/checkpoint.js.map +1 -1
  263. package/dist/runtime/query/durable-inbound.d.ts +5 -0
  264. package/dist/runtime/query/durable-inbound.d.ts.map +1 -0
  265. package/dist/runtime/query/durable-inbound.js +89 -0
  266. package/dist/runtime/query/durable-inbound.js.map +1 -0
  267. package/dist/runtime/query/events.d.ts +4 -0
  268. package/dist/runtime/query/events.d.ts.map +1 -1
  269. package/dist/runtime/query/events.js +22 -5
  270. package/dist/runtime/query/events.js.map +1 -1
  271. package/dist/runtime/query/executor/tool-call-admission.d.ts +5 -1
  272. package/dist/runtime/query/executor/tool-call-admission.d.ts.map +1 -1
  273. package/dist/runtime/query/executor/tool-call-admission.js +85 -13
  274. package/dist/runtime/query/executor/tool-call-admission.js.map +1 -1
  275. package/dist/runtime/query/executor.d.ts +41 -18
  276. package/dist/runtime/query/executor.d.ts.map +1 -1
  277. package/dist/runtime/query/executor.js +227 -114
  278. package/dist/runtime/query/executor.js.map +1 -1
  279. package/dist/runtime/query/index.d.ts +3 -0
  280. package/dist/runtime/query/index.d.ts.map +1 -1
  281. package/dist/runtime/query/index.js +21 -4
  282. package/dist/runtime/query/index.js.map +1 -1
  283. package/dist/runtime/query/iteration/index.d.ts +18 -6
  284. package/dist/runtime/query/iteration/index.d.ts.map +1 -1
  285. package/dist/runtime/query/iteration/index.js +144 -67
  286. package/dist/runtime/query/iteration/index.js.map +1 -1
  287. package/dist/runtime/query/iteration/outstanding-work.d.ts +9 -5
  288. package/dist/runtime/query/iteration/outstanding-work.d.ts.map +1 -1
  289. package/dist/runtime/query/iteration/outstanding-work.js +61 -6
  290. package/dist/runtime/query/iteration/outstanding-work.js.map +1 -1
  291. package/dist/runtime/query/iteration/phases/context.d.ts +4 -0
  292. package/dist/runtime/query/iteration/phases/context.d.ts.map +1 -1
  293. package/dist/runtime/query/iteration/phases/context.js.map +1 -1
  294. package/dist/runtime/query/iteration/phases/tool-review.d.ts.map +1 -1
  295. package/dist/runtime/query/iteration/phases/tool-review.js +99 -16
  296. package/dist/runtime/query/iteration/phases/tool-review.js.map +1 -1
  297. package/dist/runtime/query/observation-context.d.ts +2 -2
  298. package/dist/runtime/query/observation-context.d.ts.map +1 -1
  299. package/dist/runtime/query/observation-context.js +20 -13
  300. package/dist/runtime/query/observation-context.js.map +1 -1
  301. package/dist/runtime/query/prepare-turn.js +2 -2
  302. package/dist/runtime/query/prepare-turn.js.map +1 -1
  303. package/dist/runtime/query/prompt-cache.d.ts +1 -0
  304. package/dist/runtime/query/prompt-cache.d.ts.map +1 -1
  305. package/dist/runtime/query/prompt-cache.js +2 -0
  306. package/dist/runtime/query/prompt-cache.js.map +1 -1
  307. package/dist/runtime/query/prompt.d.ts +2 -0
  308. package/dist/runtime/query/prompt.d.ts.map +1 -1
  309. package/dist/runtime/query/prompt.js +23 -1
  310. package/dist/runtime/query/prompt.js.map +1 -1
  311. package/dist/runtime/query/repeat-call.d.ts +12 -3
  312. package/dist/runtime/query/repeat-call.d.ts.map +1 -1
  313. package/dist/runtime/query/repeat-call.js +33 -10
  314. package/dist/runtime/query/repeat-call.js.map +1 -1
  315. package/dist/runtime/query/resume-pending.d.ts +5 -6
  316. package/dist/runtime/query/resume-pending.d.ts.map +1 -1
  317. package/dist/runtime/query/resume-pending.js +30 -3
  318. package/dist/runtime/query/resume-pending.js.map +1 -1
  319. package/dist/runtime/query/resume-session.js +1 -1
  320. package/dist/runtime/query/resume-session.js.map +1 -1
  321. package/dist/runtime/query/review-policy.d.ts +8 -1
  322. package/dist/runtime/query/review-policy.d.ts.map +1 -1
  323. package/dist/runtime/query/review-policy.js +6 -0
  324. package/dist/runtime/query/review-policy.js.map +1 -1
  325. package/dist/runtime/query/saved-presentation.d.ts +13 -0
  326. package/dist/runtime/query/saved-presentation.d.ts.map +1 -0
  327. package/dist/runtime/query/saved-presentation.js +63 -0
  328. package/dist/runtime/query/saved-presentation.js.map +1 -0
  329. package/dist/runtime/query/steering.d.ts +6 -9
  330. package/dist/runtime/query/steering.d.ts.map +1 -1
  331. package/dist/runtime/query/steering.js.map +1 -1
  332. package/dist/runtime/query/tool-executions.d.ts +7 -3
  333. package/dist/runtime/query/tool-executions.d.ts.map +1 -1
  334. package/dist/runtime/query/tool-executions.js +89 -9
  335. package/dist/runtime/query/tool-executions.js.map +1 -1
  336. package/dist/runtime/query/tooling.d.ts +3 -1
  337. package/dist/runtime/query/tooling.d.ts.map +1 -1
  338. package/dist/runtime/query/tooling.js +3 -0
  339. package/dist/runtime/query/tooling.js.map +1 -1
  340. package/dist/scheduler/completion-inbox.d.ts +25 -1
  341. package/dist/scheduler/completion-inbox.d.ts.map +1 -1
  342. package/dist/scheduler/completion-inbox.js +102 -8
  343. package/dist/scheduler/completion-inbox.js.map +1 -1
  344. package/dist/scheduler/delegating.d.ts.map +1 -1
  345. package/dist/scheduler/delegating.js +5 -0
  346. package/dist/scheduler/delegating.js.map +1 -1
  347. package/dist/scheduler/local.d.ts.map +1 -1
  348. package/dist/scheduler/local.js +2 -0
  349. package/dist/scheduler/local.js.map +1 -1
  350. package/dist/session/summary/materialize.d.ts +10 -6
  351. package/dist/session/summary/materialize.d.ts.map +1 -1
  352. package/dist/session/summary/materialize.js +41 -8
  353. package/dist/session/summary/materialize.js.map +1 -1
  354. package/dist/store/budget/ledger.d.ts +9 -0
  355. package/dist/store/budget/ledger.d.ts.map +1 -1
  356. package/dist/store/budget/ledger.js +58 -6
  357. package/dist/store/budget/ledger.js.map +1 -1
  358. package/dist/store/evidence/index-page.d.ts +12 -12
  359. package/dist/store/evidence/source-text.d.ts +4 -4
  360. package/dist/store/session/disk.d.ts +9 -4
  361. package/dist/store/session/disk.d.ts.map +1 -1
  362. package/dist/store/session/disk.js +57 -11
  363. package/dist/store/session/disk.js.map +1 -1
  364. package/dist/store/session/memory.d.ts +5 -3
  365. package/dist/store/session/memory.d.ts.map +1 -1
  366. package/dist/store/session/memory.js +24 -7
  367. package/dist/store/session/memory.js.map +1 -1
  368. package/dist/store/session-log/core.d.ts +26 -6
  369. package/dist/store/session-log/core.d.ts.map +1 -1
  370. package/dist/store/session-log/core.js +61 -8
  371. package/dist/store/session-log/core.js.map +1 -1
  372. package/dist/store/session-log/disk.d.ts +2 -2
  373. package/dist/store/session-log/disk.d.ts.map +1 -1
  374. package/dist/store/session-log/disk.js +1 -0
  375. package/dist/store/session-log/disk.js.map +1 -1
  376. package/dist/store/session-log/fold.d.ts +7 -0
  377. package/dist/store/session-log/fold.d.ts.map +1 -1
  378. package/dist/store/session-log/fold.js +21 -0
  379. package/dist/store/session-log/fold.js.map +1 -1
  380. package/dist/store/session-log/index.d.ts +5 -3
  381. package/dist/store/session-log/index.d.ts.map +1 -1
  382. package/dist/store/session-log/index.js +3 -1
  383. package/dist/store/session-log/index.js.map +1 -1
  384. package/dist/store/session-log/memory.d.ts +1 -1
  385. package/dist/store/session-log/memory.d.ts.map +1 -1
  386. package/dist/store/session-log/memory.js +1 -0
  387. package/dist/store/session-log/memory.js.map +1 -1
  388. package/dist/store/session-log/spill.d.ts +10 -3
  389. package/dist/store/session-log/spill.d.ts.map +1 -1
  390. package/dist/store/session-log/spill.js +70 -5
  391. package/dist/store/session-log/spill.js.map +1 -1
  392. package/dist/store/session-log/structured-result.d.ts +21 -0
  393. package/dist/store/session-log/structured-result.d.ts.map +1 -0
  394. package/dist/store/session-log/structured-result.js +67 -0
  395. package/dist/store/session-log/structured-result.js.map +1 -0
  396. package/dist/store/task/disk.d.ts +11 -0
  397. package/dist/store/task/disk.d.ts.map +1 -1
  398. package/dist/store/task/disk.js +41 -2
  399. package/dist/store/task/disk.js.map +1 -1
  400. package/dist/store/task/memory.d.ts.map +1 -1
  401. package/dist/store/task/memory.js +15 -3
  402. package/dist/store/task/memory.js.map +1 -1
  403. package/dist/tools/admit-facts.d.ts +13 -0
  404. package/dist/tools/admit-facts.d.ts.map +1 -0
  405. package/dist/tools/admit-facts.js +142 -0
  406. package/dist/tools/admit-facts.js.map +1 -0
  407. package/dist/tools/builtins/bash.d.ts +4 -1
  408. package/dist/tools/builtins/bash.d.ts.map +1 -1
  409. package/dist/tools/builtins/bash.js +108 -22
  410. package/dist/tools/builtins/bash.js.map +1 -1
  411. package/dist/tools/builtins/browser.d.ts +10 -10
  412. package/dist/tools/builtins/computer-use.d.ts +90 -90
  413. package/dist/tools/builtins/edit.d.ts +17 -0
  414. package/dist/tools/builtins/edit.d.ts.map +1 -1
  415. package/dist/tools/builtins/edit.js +34 -0
  416. package/dist/tools/builtins/edit.js.map +1 -1
  417. package/dist/tools/builtins/file-write-result.d.ts.map +1 -1
  418. package/dist/tools/builtins/file-write-result.js +13 -0
  419. package/dist/tools/builtins/file-write-result.js.map +1 -1
  420. package/dist/tools/builtins/glob.d.ts.map +1 -1
  421. package/dist/tools/builtins/glob.js +12 -0
  422. package/dist/tools/builtins/glob.js.map +1 -1
  423. package/dist/tools/builtins/grep.d.ts.map +1 -1
  424. package/dist/tools/builtins/grep.js +14 -0
  425. package/dist/tools/builtins/grep.js.map +1 -1
  426. package/dist/tools/builtins/index.d.ts +2 -0
  427. package/dist/tools/builtins/index.d.ts.map +1 -1
  428. package/dist/tools/builtins/index.js +1 -0
  429. package/dist/tools/builtins/index.js.map +1 -1
  430. package/dist/tools/builtins/job.d.ts.map +1 -1
  431. package/dist/tools/builtins/job.js +4 -1
  432. package/dist/tools/builtins/job.js.map +1 -1
  433. package/dist/tools/builtins/lsp.d.ts +2 -2
  434. package/dist/tools/builtins/read-file.d.ts.map +1 -1
  435. package/dist/tools/builtins/read-file.js +49 -0
  436. package/dist/tools/builtins/read-file.js.map +1 -1
  437. package/dist/tools/builtins/view-image.d.ts +24 -0
  438. package/dist/tools/builtins/view-image.d.ts.map +1 -0
  439. package/dist/tools/builtins/view-image.js +385 -0
  440. package/dist/tools/builtins/view-image.js.map +1 -0
  441. package/dist/tools/builtins/wait-for-job-bounds.d.ts +2 -0
  442. package/dist/tools/builtins/wait-for-job-bounds.d.ts.map +1 -1
  443. package/dist/tools/builtins/wait-for-job-bounds.js +1 -0
  444. package/dist/tools/builtins/wait-for-job-bounds.js.map +1 -1
  445. package/dist/tools/builtins/wait-for-job.d.ts +2 -0
  446. package/dist/tools/builtins/wait-for-job.d.ts.map +1 -1
  447. package/dist/tools/builtins/wait-for-job.js +104 -6
  448. package/dist/tools/builtins/wait-for-job.js.map +1 -1
  449. package/dist/tools/builtins/write-file.d.ts.map +1 -1
  450. package/dist/tools/builtins/write-file.js +1 -0
  451. package/dist/tools/builtins/write-file.js.map +1 -1
  452. package/dist/tools/command-shell.d.ts +37 -2
  453. package/dist/tools/command-shell.d.ts.map +1 -1
  454. package/dist/tools/command-shell.js +100 -3
  455. package/dist/tools/command-shell.js.map +1 -1
  456. package/dist/tools/coordinator/agent.d.ts +9 -19
  457. package/dist/tools/coordinator/agent.d.ts.map +1 -1
  458. package/dist/tools/coordinator/agent.js.map +1 -1
  459. package/dist/tools/coordinator/index.d.ts.map +1 -1
  460. package/dist/tools/coordinator/index.js +127 -67
  461. package/dist/tools/coordinator/index.js.map +1 -1
  462. package/dist/tools/coordinator/wait-with-idle-bound.d.ts +2 -0
  463. package/dist/tools/coordinator/wait-with-idle-bound.d.ts.map +1 -1
  464. package/dist/tools/coordinator/wait-with-idle-bound.js +1 -1
  465. package/dist/tools/coordinator/wait-with-idle-bound.js.map +1 -1
  466. package/dist/tools/defineTool.d.ts.map +1 -1
  467. package/dist/tools/defineTool.js +4 -0
  468. package/dist/tools/defineTool.js.map +1 -1
  469. package/dist/tools/failure-facts.d.ts +8 -0
  470. package/dist/tools/failure-facts.d.ts.map +1 -0
  471. package/dist/tools/failure-facts.js +24 -0
  472. package/dist/tools/failure-facts.js.map +1 -0
  473. package/dist/tools/host-output.d.ts +24 -0
  474. package/dist/tools/host-output.d.ts.map +1 -0
  475. package/dist/tools/host-output.js +117 -0
  476. package/dist/tools/host-output.js.map +1 -0
  477. package/dist/tools/oem-code-pages.d.ts +8 -0
  478. package/dist/tools/oem-code-pages.d.ts.map +1 -0
  479. package/dist/tools/oem-code-pages.js +23 -0
  480. package/dist/tools/oem-code-pages.js.map +1 -0
  481. package/dist/tools/schedules/schedule-tool.d.ts.map +1 -1
  482. package/dist/tools/schedules/schedule-tool.js +35 -6
  483. package/dist/tools/schedules/schedule-tool.js.map +1 -1
  484. package/dist/tools/schedules/types.d.ts +23 -3
  485. package/dist/tools/schedules/types.d.ts.map +1 -1
  486. package/dist/tools/task/list.d.ts.map +1 -1
  487. package/dist/tools/task/list.js +14 -6
  488. package/dist/tools/task/list.js.map +1 -1
  489. package/dist/tools/task/present.d.ts.map +1 -1
  490. package/dist/tools/task/present.js +26 -6
  491. package/dist/tools/task/present.js.map +1 -1
  492. package/dist/tools/task/update.d.ts.map +1 -1
  493. package/dist/tools/task/update.js +12 -5
  494. package/dist/tools/task/update.js.map +1 -1
  495. package/dist/tools/text-window.d.ts +19 -0
  496. package/dist/tools/text-window.d.ts.map +1 -0
  497. package/dist/tools/text-window.js +83 -0
  498. package/dist/tools/text-window.js.map +1 -0
  499. package/dist/toolsets/manager.d.ts +11 -0
  500. package/dist/toolsets/manager.d.ts.map +1 -1
  501. package/dist/toolsets/manager.js +45 -1
  502. package/dist/toolsets/manager.js.map +1 -1
  503. package/dist/types/acp/index.d.ts +137 -1
  504. package/dist/types/acp/index.d.ts.map +1 -1
  505. package/dist/types/agent/base.d.ts +3 -0
  506. package/dist/types/agent/base.d.ts.map +1 -1
  507. package/dist/types/agent/manager.d.ts +8 -23
  508. package/dist/types/agent/manager.d.ts.map +1 -1
  509. package/dist/types/agent/scheduler.d.ts +10 -1
  510. package/dist/types/agent/scheduler.d.ts.map +1 -1
  511. package/dist/types/agent/task.d.ts +4 -0
  512. package/dist/types/agent/task.d.ts.map +1 -1
  513. package/dist/types/authorization/index.d.ts +30 -30
  514. package/dist/types/connector/mcp.d.ts +7 -0
  515. package/dist/types/connector/mcp.d.ts.map +1 -1
  516. package/dist/types/errors/catalog.d.ts.map +1 -1
  517. package/dist/types/errors/catalog.js +4 -2
  518. package/dist/types/errors/catalog.js.map +1 -1
  519. package/dist/types/harness/schema.d.ts +354 -0
  520. package/dist/types/harness/schema.d.ts.map +1 -0
  521. package/dist/types/harness/schema.js +203 -0
  522. package/dist/types/harness/schema.js.map +1 -0
  523. package/dist/types/harness/session.d.ts +278 -0
  524. package/dist/types/harness/session.d.ts.map +1 -0
  525. package/dist/types/harness/session.js +2 -0
  526. package/dist/types/harness/session.js.map +1 -0
  527. package/dist/types/hitl/index.d.ts +12 -0
  528. package/dist/types/hitl/index.d.ts.map +1 -1
  529. package/dist/types/hitl/index.js.map +1 -1
  530. package/dist/types/job/index.d.ts +47 -0
  531. package/dist/types/job/index.d.ts.map +1 -0
  532. package/dist/types/job/index.js +2 -0
  533. package/dist/types/job/index.js.map +1 -0
  534. package/dist/types/message/inbound-delivery.d.ts +44 -0
  535. package/dist/types/message/inbound-delivery.d.ts.map +1 -0
  536. package/dist/types/message/inbound-delivery.js +14 -0
  537. package/dist/types/message/inbound-delivery.js.map +1 -0
  538. package/dist/types/message/index.d.ts +4 -1
  539. package/dist/types/message/index.d.ts.map +1 -1
  540. package/dist/types/message/index.js +5 -1
  541. package/dist/types/message/index.js.map +1 -1
  542. package/dist/types/plugin/index.d.ts +6 -6
  543. package/dist/types/sandbox/index.d.ts +39 -2
  544. package/dist/types/sandbox/index.d.ts.map +1 -1
  545. package/dist/types/sandbox/index.js.map +1 -1
  546. package/dist/types/session/checkpoint.d.ts +24 -17
  547. package/dist/types/session/checkpoint.d.ts.map +1 -1
  548. package/dist/types/session/checkpoint.js +1 -0
  549. package/dist/types/session/checkpoint.js.map +1 -1
  550. package/dist/types/session/events.d.ts +23 -1
  551. package/dist/types/session/events.d.ts.map +1 -1
  552. package/dist/types/session/events.js.map +1 -1
  553. package/dist/types/session/records.d.ts +1514 -565
  554. package/dist/types/session/records.d.ts.map +1 -1
  555. package/dist/types/session/records.js +89 -1
  556. package/dist/types/session/records.js.map +1 -1
  557. package/dist/types/session/step.d.ts +2 -0
  558. package/dist/types/session/step.d.ts.map +1 -1
  559. package/dist/types/session/step.js.map +1 -1
  560. package/dist/types/session/store.d.ts +19 -10
  561. package/dist/types/session/store.d.ts.map +1 -1
  562. package/dist/types/session/tool-execution.d.ts +6 -0
  563. package/dist/types/session/tool-execution.d.ts.map +1 -1
  564. package/dist/types/structured-output/index.d.ts +12 -2
  565. package/dist/types/structured-output/index.d.ts.map +1 -1
  566. package/dist/types/summary/ref.d.ts +3 -1
  567. package/dist/types/summary/ref.d.ts.map +1 -1
  568. package/dist/types/tool/index.d.ts +32 -4
  569. package/dist/types/tool/index.d.ts.map +1 -1
  570. package/dist/types/tool/index.js.map +1 -1
  571. package/dist/types/tool/presentation.d.ts +106 -0
  572. package/dist/types/tool/presentation.d.ts.map +1 -1
  573. package/dist/utils/json-snapshot.d.ts +6 -2
  574. package/dist/utils/json-snapshot.d.ts.map +1 -1
  575. package/dist/utils/json-snapshot.js +19 -9
  576. package/dist/utils/json-snapshot.js.map +1 -1
  577. package/dist/utils/structured-result-json.d.ts +5 -0
  578. package/dist/utils/structured-result-json.d.ts.map +1 -0
  579. package/dist/utils/structured-result-json.js +10 -0
  580. package/dist/utils/structured-result-json.js.map +1 -0
  581. package/package.json +1 -1
  582. package/src/agents/QueryAgent.ts +1 -0
  583. package/src/agents/examples/SupervisorAgent.ts +1 -0
  584. package/src/agents/runAgent.ts +3 -0
  585. package/src/authorization/shell-lexer.ts +16 -1
  586. package/src/bridge/acp/permission.ts +17 -3
  587. package/src/bridge/acp/server.ts +271 -25
  588. package/src/bridge/acp/tasks.ts +23 -0
  589. package/src/bridge/acp/update.ts +167 -13
  590. package/src/connector/mcp/adapter.ts +16 -4
  591. package/src/connector/mcp/client.ts +6 -2
  592. package/src/constants/acp/index.ts +4 -0
  593. package/src/manager/agent/lifecycle.ts +230 -3
  594. package/src/manager/plan/lifecycle.ts +11 -9
  595. package/src/manager/session/attribution.ts +12 -2
  596. package/src/manager/session/streamed-message-identity.ts +21 -0
  597. package/src/manager/session/turn-recorder.ts +4 -3
  598. package/src/pals/activity/causality.ts +261 -0
  599. package/src/pals/activity/projection.ts +89 -0
  600. package/src/pals/activity/source.ts +240 -0
  601. package/src/pals/activity/subscription-policy.ts +230 -0
  602. package/src/pals/activity/subscription-schema.ts +27 -0
  603. package/src/pals/activity/subscription-store.ts +172 -0
  604. package/src/pals/activity/subscription-types.ts +48 -0
  605. package/src/pals/activity/subscriptions.ts +209 -0
  606. package/src/pals/activity/types.ts +108 -0
  607. package/src/pals/channels/ingress.ts +153 -0
  608. package/src/pals/channels/routes.ts +118 -0
  609. package/src/pals/channels/routing.ts +197 -0
  610. package/src/pals/channels/schema.ts +108 -0
  611. package/src/pals/channels/types.ts +156 -0
  612. package/src/pals/communication/broker.ts +131 -0
  613. package/src/pals/communication/dispatch.ts +66 -0
  614. package/src/pals/communication/inbound.ts +193 -0
  615. package/src/pals/communication/ingress-dispatch.ts +63 -0
  616. package/src/pals/communication/ingress-inbound.ts +269 -0
  617. package/src/pals/communication/ingress-schema.ts +526 -0
  618. package/src/pals/communication/ingress-types.ts +336 -0
  619. package/src/pals/communication/operator.ts +315 -0
  620. package/src/pals/communication/policy.ts +174 -0
  621. package/src/pals/communication/schema.ts +173 -0
  622. package/src/pals/communication/store.ts +577 -0
  623. package/src/pals/communication/tools.ts +139 -0
  624. package/src/pals/communication/types.ts +227 -0
  625. package/src/pals/communication/verify.ts +220 -0
  626. package/src/pals/lifecycle.ts +54 -0
  627. package/src/pals/prompt.ts +101 -0
  628. package/src/pals/reference-images.ts +322 -0
  629. package/src/pals/runtime.ts +670 -0
  630. package/src/pals/store.ts +369 -0
  631. package/src/pals/types.ts +157 -0
  632. package/src/peers/envelope.ts +1 -1
  633. package/src/plugin/shell-hook.ts +8 -2
  634. package/src/process/kill-tree.ts +10 -1
  635. package/src/provider/errors.ts +135 -2
  636. package/src/public-runtime.ts +117 -12
  637. package/src/public-tools.ts +13 -1
  638. package/src/public-types.ts +69 -7
  639. package/src/registry/tool/presentation.ts +9 -4
  640. package/src/runtime/harness-session/index.ts +1125 -0
  641. package/src/runtime/harness-session/journal.ts +209 -0
  642. package/src/runtime/harness-session/saved-view.ts +122 -0
  643. package/src/runtime/jobs/awaited-jobs.ts +2 -1
  644. package/src/runtime/jobs/registry.ts +397 -41
  645. package/src/runtime/query/abandon-turn.ts +18 -2
  646. package/src/runtime/query/checkpoint.ts +11 -0
  647. package/src/runtime/query/durable-inbound.ts +101 -0
  648. package/src/runtime/query/events.ts +22 -5
  649. package/src/runtime/query/executor/tool-call-admission.ts +125 -32
  650. package/src/runtime/query/executor.ts +316 -130
  651. package/src/runtime/query/index.ts +24 -4
  652. package/src/runtime/query/iteration/index.ts +218 -104
  653. package/src/runtime/query/iteration/outstanding-work.ts +55 -7
  654. package/src/runtime/query/iteration/phases/context.ts +4 -0
  655. package/src/runtime/query/iteration/phases/tool-review.ts +118 -21
  656. package/src/runtime/query/observation-context.ts +22 -16
  657. package/src/runtime/query/prepare-turn.ts +2 -2
  658. package/src/runtime/query/prompt-cache.ts +3 -0
  659. package/src/runtime/query/prompt.ts +32 -1
  660. package/src/runtime/query/repeat-call.ts +40 -10
  661. package/src/runtime/query/resume-pending.ts +60 -7
  662. package/src/runtime/query/resume-session.ts +1 -1
  663. package/src/runtime/query/review-policy.ts +23 -2
  664. package/src/runtime/query/saved-presentation.ts +70 -0
  665. package/src/runtime/query/steering.ts +6 -9
  666. package/src/runtime/query/tool-executions.ts +108 -9
  667. package/src/runtime/query/tooling.ts +6 -1
  668. package/src/scheduler/completion-inbox.ts +108 -7
  669. package/src/scheduler/delegating.ts +5 -0
  670. package/src/scheduler/local.ts +2 -0
  671. package/src/session/summary/materialize.ts +51 -9
  672. package/src/store/budget/ledger.ts +60 -5
  673. package/src/store/session/disk.ts +77 -10
  674. package/src/store/session/memory.ts +32 -7
  675. package/src/store/session-log/core.ts +118 -11
  676. package/src/store/session-log/disk.ts +9 -2
  677. package/src/store/session-log/fold.ts +22 -0
  678. package/src/store/session-log/index.ts +5 -0
  679. package/src/store/session-log/memory.ts +2 -1
  680. package/src/store/session-log/spill.ts +89 -6
  681. package/src/store/session-log/structured-result.ts +96 -0
  682. package/src/store/task/disk.ts +46 -2
  683. package/src/store/task/memory.ts +13 -3
  684. package/src/tools/admit-facts.ts +145 -0
  685. package/src/tools/builtins/bash.ts +132 -24
  686. package/src/tools/builtins/edit.ts +42 -0
  687. package/src/tools/builtins/file-write-result.ts +14 -0
  688. package/src/tools/builtins/glob.ts +12 -0
  689. package/src/tools/builtins/grep.ts +14 -0
  690. package/src/tools/builtins/index.ts +2 -0
  691. package/src/tools/builtins/job.ts +4 -1
  692. package/src/tools/builtins/read-file.ts +57 -0
  693. package/src/tools/builtins/view-image.ts +409 -0
  694. package/src/tools/builtins/wait-for-job-bounds.ts +3 -0
  695. package/src/tools/builtins/wait-for-job.ts +141 -32
  696. package/src/tools/builtins/write-file.ts +4 -2
  697. package/src/tools/command-shell.ts +132 -5
  698. package/src/tools/coordinator/agent.ts +9 -19
  699. package/src/tools/coordinator/index.ts +150 -75
  700. package/src/tools/coordinator/wait-with-idle-bound.ts +3 -1
  701. package/src/tools/defineTool.ts +4 -0
  702. package/src/tools/failure-facts.ts +24 -0
  703. package/src/tools/host-output.ts +136 -0
  704. package/src/tools/oem-code-pages.ts +22 -0
  705. package/src/tools/schedules/schedule-tool.ts +38 -5
  706. package/src/tools/schedules/types.ts +23 -3
  707. package/src/tools/task/list.ts +15 -7
  708. package/src/tools/task/present.ts +37 -7
  709. package/src/tools/task/update.ts +12 -5
  710. package/src/tools/text-window.ts +87 -0
  711. package/src/toolsets/manager.ts +58 -1
  712. package/src/types/acp/index.ts +150 -4
  713. package/src/types/agent/base.ts +3 -0
  714. package/src/types/agent/manager.ts +8 -23
  715. package/src/types/agent/scheduler.ts +10 -1
  716. package/src/types/agent/task.ts +4 -0
  717. package/src/types/connector/mcp.ts +7 -0
  718. package/src/types/errors/catalog.ts +4 -2
  719. package/src/types/harness/schema.ts +203 -0
  720. package/src/types/harness/session.ts +306 -0
  721. package/src/types/hitl/index.ts +17 -1
  722. package/src/types/job/index.ts +42 -0
  723. package/src/types/message/inbound-delivery.ts +63 -0
  724. package/src/types/message/index.ts +8 -1
  725. package/src/types/sandbox/index.ts +46 -0
  726. package/src/types/session/checkpoint.ts +4 -1
  727. package/src/types/session/events.ts +23 -1
  728. package/src/types/session/records.ts +114 -2
  729. package/src/types/session/step.ts +2 -0
  730. package/src/types/session/store.ts +23 -9
  731. package/src/types/session/tool-execution.ts +6 -0
  732. package/src/types/structured-output/index.ts +13 -2
  733. package/src/types/summary/ref.ts +3 -1
  734. package/src/types/tool/index.ts +39 -5
  735. package/src/types/tool/presentation.ts +121 -0
  736. package/src/utils/json-snapshot.ts +26 -9
  737. package/src/utils/structured-result-json.ts +10 -0
@@ -77,6 +77,11 @@ const OWNED_WORK_DISPLAY_LIMIT = 16
77
77
  export class CompletionInbox {
78
78
  private readonly unheard = new Map<TaskId, TaskHandle>()
79
79
  private readonly claimed = new Set<TaskId>()
80
+ /** Persistence that must settle before an owned result may be delivered. */
81
+ private readonly deliveryGates = new Map<
82
+ TaskId,
83
+ { settled: Promise<void>; state: 'pending' | 'ready' | 'failed'; error?: unknown }
84
+ >()
80
85
  /** Launched with nothing waiting on it, and not settled yet. */
81
86
  private readonly outstanding = new Set<TaskId>()
82
87
  /**
@@ -136,6 +141,8 @@ export class CompletionInbox {
136
141
  */
137
142
  private readonly unowned = new Map<TaskId, TaskHandle>()
138
143
  private readonly arrivals = new Set<() => void>()
144
+ private readonly drains = new Set<() => void>()
145
+ private lifecycle = 0
139
146
  private detach?: () => void
140
147
  /** Kept for {@link launched}: the source of truth about a task's state. */
141
148
  private gateway?: TaskScheduler
@@ -173,7 +180,10 @@ export class CompletionInbox {
173
180
  this.markSettled(handle.taskId)
174
181
  if (this.claimed.has(handle.taskId)) return
175
182
  this.unheard.set(handle.taskId, handle)
176
- for (const wake of this.arrivals) wake()
183
+ if (this.hasUnheard) for (const wake of this.arrivals) wake()
184
+ if (this.deliveryGates.get(handle.taskId)?.state === 'failed') {
185
+ for (const finish of [...this.drains]) finish()
186
+ }
177
187
  })
178
188
  return this.detach
179
189
  }
@@ -261,6 +271,47 @@ export class CompletionInbox {
261
271
  for (const wake of [...this.arrivals]) wake()
262
272
  }
263
273
 
274
+ /**
275
+ * Hold delivery until this owned task's tracking writes have settled.
276
+ *
277
+ * Register synchronously after `launched`, before handing control back to
278
+ * a consumer. The promise receives no worker output from this inbox.
279
+ * Rejections are retained and reported by either drain; the result stays
280
+ * queued rather than being announced with stale tracking state.
281
+ */
282
+ deferDelivery(taskId: TaskId, settlement: Promise<void>): void {
283
+ if (!this.ours.has(taskId) || this.claimed.has(taskId)) {
284
+ throw new Error('Delivery may only be deferred for an owned, undelivered task')
285
+ }
286
+ if (this.deliveryGates.has(taskId)) {
287
+ throw new Error('This task already has a delivery settlement')
288
+ }
289
+ const gate: {
290
+ settled: Promise<void>
291
+ state: 'pending' | 'ready' | 'failed'
292
+ error?: unknown
293
+ } = { settled: Promise.resolve(), state: 'pending' }
294
+ gate.settled = settlement
295
+ .then(
296
+ () => {
297
+ gate.state = 'ready'
298
+ },
299
+ (error: unknown) => {
300
+ gate.state = 'failed'
301
+ gate.error = error
302
+ },
303
+ )
304
+ .then(() => {
305
+ if (this.deliveryGates.get(taskId) === gate && this.unheard.has(taskId)) {
306
+ for (const wake of [...this.arrivals]) wake()
307
+ // A known tracking failure must not wait behind another row's
308
+ // stalled write. Drains report it without consuming any result.
309
+ if (gate.state === 'failed') for (const finish of [...this.drains]) finish()
310
+ }
311
+ })
312
+ this.deliveryGates.set(taskId, gate)
313
+ }
314
+
264
315
  /**
265
316
  * Move an owned task from {@link runningOwned} to {@link settledOwned}.
266
317
  *
@@ -308,8 +359,8 @@ export class CompletionInbox {
308
359
  */
309
360
  waitForArrival(timeoutMs: number, signal?: AbortSignal): Promise<void> {
310
361
  if (signal?.aborted) return Promise.resolve()
311
- if (this.unheard.size > 0) return Promise.resolve()
312
- if (this.outstanding.size === 0) return Promise.resolve()
362
+ if (this.hasUnheard) return Promise.resolve()
363
+ if (!this.hasPendingWork) return Promise.resolve()
313
364
 
314
365
  return new Promise((resolve) => {
315
366
  const finish = (): void => {
@@ -338,6 +389,7 @@ export class CompletionInbox {
338
389
  claim(taskId: TaskId): void {
339
390
  this.claimed.add(taskId)
340
391
  this.unheard.delete(taskId)
392
+ this.deliveryGates.delete(taskId)
341
393
  this.outstanding.delete(taskId)
342
394
  // A tool only claims a result it is already holding, so a claim is
343
395
  // itself proof of settlement — independent of whether the gateway's
@@ -350,7 +402,9 @@ export class CompletionInbox {
350
402
 
351
403
  /** Whether anything is waiting to be told. */
352
404
  get hasUnheard(): boolean {
353
- return this.unheard.size > 0
405
+ return [...this.unheard.keys()].some(
406
+ (taskId) => this.deliveryGates.get(taskId)?.state !== 'pending',
407
+ )
354
408
  }
355
409
 
356
410
  /**
@@ -410,16 +464,22 @@ export class CompletionInbox {
410
464
  }
411
465
 
412
466
  /**
413
- * Take every unheard completion, leaving the inbox empty.
467
+ * Take unheard completions whose tracking settlement has succeeded.
468
+ * Pending gates stay queued; a rejected gate throws without consuming any
469
+ * result. Use `drainAsync` to await tracking for results already in hand.
414
470
  *
415
471
  * Draining rather than peeking: a notification that stays queued after
416
472
  * being delivered is the duplicate-delivery bug in a different costume.
417
473
  */
418
474
  drain(): TaskHandle[] {
419
475
  if (this.unheard.size === 0) return []
420
- const handles = [...this.unheard.values()]
421
- this.unheard.clear()
476
+ this.checkDeliveryFailures()
477
+ const handles = [...this.unheard.values()].filter(
478
+ (handle) => this.deliveryGates.get(handle.taskId)?.state !== 'pending',
479
+ )
422
480
  for (const handle of handles) {
481
+ this.unheard.delete(handle.taskId)
482
+ this.deliveryGates.delete(handle.taskId)
423
483
  this.claimed.add(handle.taskId)
424
484
  // A delivered result is not pending WORK, and `outstanding` can
425
485
  // still be holding this id — the listener clears it, but only if
@@ -438,6 +498,43 @@ export class CompletionInbox {
438
498
  return handles
439
499
  }
440
500
 
501
+ private checkDeliveryFailures(): void {
502
+ for (const taskId of this.unheard.keys()) {
503
+ const gate = this.deliveryGates.get(taskId)
504
+ if (gate?.state === 'failed') throw gate.error
505
+ }
506
+ }
507
+
508
+ /**
509
+ * Await tracking for completions already queued, then deliver once.
510
+ * Running workers are never awaited here. Concurrent drains share gates
511
+ * and the existing claim set, so only one consumer receives each result.
512
+ * Aborting releases only this wait and returns no results; tracking and
513
+ * queued completions remain available for a later drain.
514
+ */
515
+ async drainAsync(signal?: AbortSignal): Promise<TaskHandle[]> {
516
+ const lifecycle = this.lifecycle
517
+ if (signal?.aborted) return []
518
+ this.checkDeliveryFailures()
519
+ const settlements = [...this.unheard.keys()].flatMap((taskId) => {
520
+ const gate = this.deliveryGates.get(taskId)
521
+ return gate ? [gate.settled] : []
522
+ })
523
+ if (settlements.length === 0) return this.drain()
524
+ await new Promise<void>((resolve) => {
525
+ const finish = (): void => {
526
+ signal?.removeEventListener('abort', finish)
527
+ this.drains.delete(finish)
528
+ resolve()
529
+ }
530
+ this.drains.add(finish)
531
+ signal?.addEventListener('abort', finish, { once: true })
532
+ void Promise.all(settlements).then(finish)
533
+ if (signal?.aborted) finish()
534
+ })
535
+ return signal?.aborted || lifecycle !== this.lifecycle ? [] : this.drain()
536
+ }
537
+
441
538
  /**
442
539
  * Stop expecting a task that is never going to arrive.
443
540
  *
@@ -480,10 +577,12 @@ export class CompletionInbox {
480
577
  * stops it existing.
481
578
  */
482
579
  close(): void {
580
+ this.lifecycle++
483
581
  this.detach?.()
484
582
  this.detach = undefined
485
583
  this.gateway = undefined
486
584
  this.unheard.clear()
585
+ this.deliveryGates.clear()
487
586
  this.outstanding.clear()
488
587
  this.ours.clear()
489
588
  this.runningOwned.clear()
@@ -494,6 +593,8 @@ export class CompletionInbox {
494
593
  // them to their own deadline for a completion that can no longer come.
495
594
  for (const wake of [...this.arrivals]) wake()
496
595
  this.arrivals.clear()
596
+ for (const finish of [...this.drains]) finish()
597
+ this.drains.clear()
497
598
  }
498
599
  }
499
600
 
@@ -171,6 +171,11 @@ export class DelegatingTaskScheduler implements TaskScheduler {
171
171
  if (!this.config.local) throw new NoDelegateError({ agentId: options.agentId })
172
172
  return await this.config.local.createTask(options)
173
173
  }
174
+ if (options.resumeSessionId)
175
+ throw new DelegateCapabilityError({
176
+ id: delegate.id,
177
+ capability: 'child conversation continuation',
178
+ })
174
179
 
175
180
  if (this.budget) {
176
181
  throw new Error(
@@ -112,6 +112,7 @@ export class LocalTaskScheduler implements TaskScheduler {
112
112
  const task = await this.agentManager.sendMessage(
113
113
  {
114
114
  agentId: options.agentId,
115
+ ...(options.resumeSessionId ? { resumeSessionId: options.resumeSessionId } : {}),
115
116
  beforeStart: options.beforeStart,
116
117
  ...(options.workspace ? { workspace: options.workspace } : {}),
117
118
  ...(options.planId ? { planId: options.planId } : {}),
@@ -469,6 +470,7 @@ function toHandle(task: import('../types/agent/task.js').AgentTask): TaskHandle
469
470
  result: task.result,
470
471
  createdAt: task.createdAt,
471
472
  completedAt: task.completedAt,
473
+ ...(task.childSessionId ? { childSessionId: task.childSessionId } : {}),
472
474
  ...(task.workspace ? { workspace: task.workspace } : {}),
473
475
  }
474
476
  }
@@ -18,7 +18,7 @@
18
18
  * `generateSummaryId` from `utils/id.ts`.
19
19
  */
20
20
 
21
- import type { SessionId, TenantId } from '../../types/ids/index.js'
21
+ import type { SessionId, TenantId, TurnId } from '../../types/ids/index.js'
22
22
  import type { Session } from '../../types/session/entity.js'
23
23
  import type { SummaryId } from '../../types/session/ids.js'
24
24
  import type { SessionStore } from '../../types/session/store.js'
@@ -29,6 +29,7 @@ import {
29
29
  type SessionSummaryOutcome,
30
30
  type SessionSummaryRef,
31
31
  } from '../../types/summary/ref.js'
32
+ import { StaleSessionError } from '../errors.js'
32
33
  import { AgentSummaryTooLongError, SessionAlreadySummarizedError } from './errors.js'
33
34
 
34
35
  /**
@@ -50,6 +51,10 @@ export interface SessionSummaryMaterializerDeps {
50
51
  */
51
52
  export interface MaterializeInput {
52
53
  readonly sessionId: SessionId
54
+ /** Seal this invocation independently of the legacy conversation summary. */
55
+ readonly turnId?: TurnId
56
+ /** Keep this terminalization attributed to the admitted owner, if supplied. */
57
+ readonly expectedOwnerVersion?: number
53
58
  readonly tenantId: TenantId
54
59
  readonly finalOutcome: SessionSummaryOutcome
55
60
  readonly agentSummary: string
@@ -84,19 +89,31 @@ export class SessionSummaryMaterializer {
84
89
  * - {@link AgentSummaryTooLongError} — `agentSummary` exceeds the max char
85
90
  * cap ({@link AGENT_SUMMARY_MAX_CHARS}).
86
91
  * - `TenantIsolationError` — session is owned by a different tenant.
87
- * - {@link SessionAlreadySummarizedError} — the session already has a
88
- * persisted summary. Re-materialization would duplicate history; the
89
- * caller should instead open an intervention sub-session (§4.5).
92
+ * - {@link SessionAlreadySummarizedError} — this conversation-summary key
93
+ * or explicit invocation key already has a sealed summary. A new child
94
+ * invocation uses its fresh `turnId`; it never replaces the old summary.
90
95
  */
91
96
  async materialize(input: MaterializeInput): Promise<SessionSummaryRef> {
92
97
  this.assertSummaryLength(input.agentSummary)
98
+ if (input.turnId && this.deps.store.supportsInvocationSummaries !== true)
99
+ throw new Error('Session store does not support invocation summaries')
93
100
 
94
101
  const session = await this.deps.store.getSession(input.sessionId, input.tenantId)
95
102
  if (!session) {
96
103
  throw new Error(`Session ${input.sessionId} not found`)
97
104
  }
105
+ if (input.expectedOwnerVersion !== undefined) {
106
+ if (this.deps.store.supportsOwnerVersionCas !== true)
107
+ throw new Error('Session store does not support owner-version CAS')
108
+ if (session.ownerVersion !== input.expectedOwnerVersion)
109
+ throw new StaleSessionError({
110
+ sessionId: input.sessionId,
111
+ expectedVersion: input.expectedOwnerVersion,
112
+ actualVersion: session.ownerVersion,
113
+ })
114
+ }
98
115
 
99
- const existing = await this.deps.store.getSummary(input.sessionId, input.tenantId)
116
+ const existing = await this.deps.store.getSummary(input.sessionId, input.tenantId, input.turnId)
100
117
  if (existing) {
101
118
  throw new SessionAlreadySummarizedError({
102
119
  sessionId: input.sessionId,
@@ -107,6 +124,7 @@ export class SessionSummaryMaterializer {
107
124
  const summary: SessionSummaryRef = {
108
125
  id: this.deps.generateSummaryId(),
109
126
  sessionRef: input.sessionId,
127
+ ...(input.turnId ? { turnRef: input.turnId } : {}),
110
128
  tenantId: input.tenantId,
111
129
  outcome: input.finalOutcome,
112
130
  deliverables: input.declaredDeliverables,
@@ -116,13 +134,29 @@ export class SessionSummaryMaterializer {
116
134
  materializedBy: 'kernel',
117
135
  }
118
136
 
119
- await this.deps.store.recordSummary(summary, input.tenantId)
137
+ const legacy = input.turnId
138
+ ? await this.deps.store.getSummary(input.sessionId, input.tenantId)
139
+ : undefined
140
+ if (input.expectedOwnerVersion === undefined)
141
+ await this.deps.store.recordSummary(summary, input.tenantId)
142
+ else await this.deps.store.recordSummary(summary, input.tenantId, input.expectedOwnerVersion)
143
+ if (input.turnId) {
144
+ const stored = await this.deps.store.getSummary(input.sessionId, input.tenantId, input.turnId)
145
+ const afterLegacy = await this.deps.store.getSummary(input.sessionId, input.tenantId)
146
+ if (
147
+ stored?.id !== summary.id ||
148
+ stored.sessionRef !== input.sessionId ||
149
+ stored.turnRef !== input.turnId ||
150
+ afterLegacy?.id !== legacy?.id
151
+ )
152
+ throw new Error('Session store did not preserve the invocation summary contract')
153
+ }
120
154
  return summary
121
155
  }
122
156
 
123
157
  /**
124
158
  * Recovery path. Called at boot (or explicitly by the lifecycle manager)
125
- * for sessions whose `summary.json` is persisted but whose `session.json`
159
+ * for sessions whose selected summary is persisted but whose `session.json`
126
160
  * still reports a non-terminal status — the crash window between the two
127
161
  * atomic writes on disk.
128
162
  *
@@ -133,9 +167,17 @@ export class SessionSummaryMaterializer {
133
167
  * mint a new ID, only re-triggers the store's status flip via
134
168
  * `recordSummary` when it detects the dangling session.
135
169
  */
136
- async recover(sessionId: SessionId, tenantId: TenantId): Promise<SessionSummaryRef | null> {
137
- const summary = await this.deps.store.getSummary(sessionId, tenantId)
170
+ async recover(
171
+ sessionId: SessionId,
172
+ tenantId: TenantId,
173
+ turnId?: TurnId,
174
+ ): Promise<SessionSummaryRef | null> {
175
+ if (turnId && this.deps.store.supportsInvocationSummaries !== true)
176
+ throw new Error('Session store does not support invocation summaries')
177
+ const summary = await this.deps.store.getSummary(sessionId, tenantId, turnId)
138
178
  if (!summary) return null
179
+ if (turnId && (summary.turnRef !== turnId || summary.sessionRef !== sessionId))
180
+ throw new Error('Session store returned a different invocation summary')
139
181
 
140
182
  const session = await this.deps.store.getSession(sessionId, tenantId)
141
183
  if (!session) return summary
@@ -434,7 +434,7 @@ export class SessionTokenBudget {
434
434
  persistence?: SessionTokenBudgetPersistence,
435
435
  ): SessionTokenBudget {
436
436
  const state = validateSessionTokenBudgetSnapshot(snapshot)
437
- return new SessionTokenBudget(
437
+ const restored = new SessionTokenBudget(
438
438
  {
439
439
  rootAccountId: state.rootAccountId,
440
440
  scope: { rootSessionId: state.rootSessionId, rootTurnId: state.rootTurnId },
@@ -449,6 +449,27 @@ export class SessionTokenBudget {
449
449
  },
450
450
  state.rootAccountId,
451
451
  )
452
+ // A request that was in flight when a process stopped has no receipt. On an
453
+ // unbounded account it stays recorded as unknown spend, but it no longer
454
+ // counts as work in progress, so the turn can ask again.
455
+ for (const request of [...restored.ledger.requests.values()]) {
456
+ if (!restored.account(request.accountId).bounded) restored.retainUnresolved(request)
457
+ }
458
+ return restored
459
+ }
460
+
461
+ /**
462
+ * Whether this account, or any account above it, carries a finite limit. A bounded
463
+ * account cannot be admitted past unknown spend, because the unknown amount may
464
+ * already exceed the limit. An unbounded one has no limit to exceed: its unknown
465
+ * spend stays recorded (never as zero) and does not stop the next request.
466
+ */
467
+ get bounded(): boolean {
468
+ for (let cursor: SessionTokenBudgetAccountSnapshot | undefined = this.node; cursor; ) {
469
+ if (cursor.limit > 0) return true
470
+ cursor = cursor.parentId === undefined ? undefined : this.requireAccount(cursor.parentId)
471
+ }
472
+ return false
452
473
  }
453
474
 
454
475
  get limit(): number {
@@ -590,7 +611,16 @@ export class SessionTokenBudget {
590
611
  }
591
612
 
592
613
  async finishRequest(requestId: string, usage: TokenUsage): Promise<void> {
593
- if (this.hasReceipt(requestId)) return this.flush()
614
+ if (this.hasReceipt(requestId)) {
615
+ // A request retained as unknown spend can still be answered late. The
616
+ // measured usage is evidence and is kept; the unknown marker stays until
617
+ // an explicit reconciliation clears it.
618
+ const receipt = this.ledger.finishedRequests.get(
619
+ requestId,
620
+ ) as SessionTokenBudgetRequestSnapshot
621
+ if (receipt.unresolved === true) return this.failRequest(requestId, usage)
622
+ return this.flush()
623
+ }
594
624
  const request = this.requireRequest(requestId)
595
625
  try {
596
626
  this.recordRequestUsage(request, usage)
@@ -608,7 +638,25 @@ export class SessionTokenBudget {
608
638
 
609
639
  /** Unknown spend cannot be converted into a refund, even after cancellation. */
610
640
  async failRequest(requestId: string, usage?: TokenUsage): Promise<void> {
611
- if (this.hasReceipt(requestId)) return this.flush()
641
+ if (this.hasReceipt(requestId)) {
642
+ // An unbounded account retains a failed request as a receipt; usage that
643
+ // arrives late is still evidence of spend and is kept.
644
+ const receipt = this.ledger.finishedRequests.get(
645
+ requestId,
646
+ ) as SessionTokenBudgetRequestSnapshot
647
+ if (usage !== undefined && receipt.unresolved === true) {
648
+ try {
649
+ this.recordRequestUsage(receipt, usage)
650
+ } catch (error) {
651
+ this.ledger.poisoned = true
652
+ this.persist()
653
+ await this.flush()
654
+ throw error
655
+ }
656
+ this.persist()
657
+ }
658
+ return this.flush()
659
+ }
612
660
  const request = this.requireRequest(requestId)
613
661
  request.unresolved = true
614
662
  try {
@@ -619,6 +667,7 @@ export class SessionTokenBudget {
619
667
  await this.flush()
620
668
  throw error
621
669
  }
670
+ if (!this.bounded) this.retainUnresolved(request)
622
671
  this.persist()
623
672
  await this.flush()
624
673
  }
@@ -713,6 +762,12 @@ export class SessionTokenBudget {
713
762
  if (this.ledger.persistenceError !== undefined) throw this.ledger.persistenceError
714
763
  }
715
764
 
765
+ /** Move a request with no receipt out of flight, keeping its unknown-spend marker. */
766
+ private retainUnresolved(request: SessionTokenBudgetRequestSnapshot): void {
767
+ request.unresolved = true
768
+ this.ledger.requests.delete(request.id)
769
+ this.ledger.finishedRequests.set(request.id, request)
770
+ }
716
771
  private uncertainRequests(): SessionTokenBudgetRequestSnapshot[] {
717
772
  return [...this.ledger.requests.values(), ...this.ledger.finishedRequests.values()].filter(
718
773
  (request) => request.unresolved === true,
@@ -722,8 +777,8 @@ export class SessionTokenBudget {
722
777
  if (this.ledger.poisoned || this.ledger.persistenceError !== undefined) return true
723
778
  const uncertain = this.uncertainRequests()
724
779
  if (uncertain.length === 0) return false
725
- // An account cannot resume its own uncertain request, even without a cap.
726
- if (uncertain.some((request) => request.accountId === this.accountId)) return true
780
+ // Unknown spend blocks only through a finite limit at or above this account,
781
+ // where it could already have been exceeded; see `bounded`.
727
782
  let cursor = this.node
728
783
  for (;;) {
729
784
  if (cursor.limit > 0) {
@@ -36,7 +36,7 @@
36
36
 
37
37
  import { createHash } from 'node:crypto'
38
38
  import { mkdir, rm } from 'node:fs/promises'
39
- import { join } from 'node:path'
39
+ import { join, resolve } from 'node:path'
40
40
  import {
41
41
  ProjectRootPathTakenError,
42
42
  StaleProjectError,
@@ -44,7 +44,7 @@ import {
44
44
  TenantIsolationError,
45
45
  } from '../../session/errors.js'
46
46
  import { SessionAlreadySummarizedError } from '../../session/summary/errors.js'
47
- import type { SessionId, TenantId } from '../../types/ids/index.js'
47
+ import type { SessionId, TenantId, TurnId } from '../../types/ids/index.js'
48
48
  import type { Project, ProjectStatus } from '../../types/project/entity.js'
49
49
  import type { Session } from '../../types/session/entity.js'
50
50
  import type { ProjectId, SubSessionId, SummaryId, TopicId } from '../../types/session/ids.js'
@@ -68,6 +68,7 @@ import {
68
68
  asSessionId,
69
69
  asSubSessionId,
70
70
  asTopicId,
71
+ asTurnId,
71
72
  generateProjectId,
72
73
  generateSessionId,
73
74
  generateSubSessionId,
@@ -237,6 +238,7 @@ interface PersistedSubSession {
237
238
  interface PersistedSummary {
238
239
  id: SummaryId
239
240
  sessionRef: SessionId
241
+ turnRef?: TurnId
240
242
  tenantId: TenantId
241
243
  outcome: SessionSummaryOutcome
242
244
  deliverables: readonly DeliverableRef[]
@@ -257,6 +259,10 @@ const SUMMARY_TERMINAL_FLIP_STATUSES: ReadonlySet<Session['status']> = new Set([
257
259
  'awaiting_merge',
258
260
  ])
259
261
 
262
+ // Share the in-process writer guard across store instances addressing the same
263
+ // root. This is not a cross-process lease; external writers remain a host concern.
264
+ const sessionWriters = new Map<string, Promise<void>>()
265
+
260
266
  /**
261
267
  * Index of projectId → its directory path. Built lazily on lookup via
262
268
  * {@link DiskSessionStore.resolveProjectDir}; populated by create / getProject.
@@ -276,6 +282,8 @@ interface SessionIndexEntry {
276
282
  }
277
283
 
278
284
  export class DiskSessionStore implements SessionStore {
285
+ readonly supportsInvocationSummaries: boolean = true
286
+ readonly supportsOwnerVersionCas: boolean = true
279
287
  private readonly rootDir: string
280
288
  private readonly projectIndex = new Map<ProjectId, ProjectIndexEntry>()
281
289
  private readonly sessionIndex = new Map<SessionId, SessionIndexEntry>()
@@ -288,6 +296,24 @@ export class DiskSessionStore implements SessionStore {
288
296
  this.rootDir = config.rootDir
289
297
  }
290
298
 
299
+ private async withSessionWrite<T>(sessionId: SessionId, operation: () => Promise<T>): Promise<T> {
300
+ const key = resolve(this.rootDir, sessionId)
301
+ const previous = sessionWriters.get(key) ?? Promise.resolve()
302
+ let release = () => {}
303
+ const held = new Promise<void>((resolveWrite) => {
304
+ release = resolveWrite
305
+ })
306
+ const tail = previous.then(() => held)
307
+ sessionWriters.set(key, tail)
308
+ await previous
309
+ try {
310
+ return await operation()
311
+ } finally {
312
+ release()
313
+ if (sessionWriters.get(key) === tail) sessionWriters.delete(key)
314
+ }
315
+ }
316
+
291
317
  // Project CRUD ------------------------------------------------------------
292
318
 
293
319
  async createProject(params: CreateProjectParams, tenantId: TenantId): Promise<Project> {
@@ -654,6 +680,16 @@ export class DiskSessionStore implements SessionStore {
654
680
  session: Session,
655
681
  tenantId: TenantId,
656
682
  expectedOwnerVersion?: number,
683
+ ): Promise<void> {
684
+ await this.withSessionWrite(session.id, () =>
685
+ this.updateSessionUnlocked(session, tenantId, expectedOwnerVersion),
686
+ )
687
+ }
688
+
689
+ private async updateSessionUnlocked(
690
+ session: Session,
691
+ tenantId: TenantId,
692
+ expectedOwnerVersion?: number,
657
693
  ): Promise<void> {
658
694
  const located = await this.locateSession(session.id)
659
695
  if (!located) {
@@ -669,10 +705,8 @@ export class DiskSessionStore implements SessionStore {
669
705
  if (existing) {
670
706
  this.assertTenant(existing.tenantId, tenantId, `session(${session.id})`)
671
707
  }
672
- // Against what is on disk, not against the payload. The write itself is
673
- // atomic; this read-compare-write is NOT a critical section, so two
674
- // processes can still both pass — see the contract note on
675
- // `SessionStore.updateSession`. In one process it is the real lock.
708
+ // Against the stored version, under the shared in-process writer guard.
709
+ // Other processes can still both pass; see SessionStore.updateSession.
676
710
  if (
677
711
  expectedOwnerVersion !== undefined &&
678
712
  existing !== null &&
@@ -862,11 +896,22 @@ export class DiskSessionStore implements SessionStore {
862
896
  * leaves summary present + session still non-terminal — recovery replays
863
897
  * the flip via {@link SessionSummaryMaterializer.recover}. Idempotent when
864
898
  * the same summary is re-presented (recovery path); rejects a *different*
865
- * summary for the same session as {@link SessionAlreadySummarizedError}.
899
+ * summary at the same conversation or invocation key as {@link SessionAlreadySummarizedError}.
866
900
  */
867
901
  async recordSummary(
868
902
  summary: SessionSummaryRef & { materializedBy: 'kernel' },
869
903
  tenantId: TenantId,
904
+ expectedOwnerVersion?: number,
905
+ ): Promise<void> {
906
+ await this.withSessionWrite(summary.sessionRef, () =>
907
+ this.recordSummaryUnlocked(summary, tenantId, expectedOwnerVersion),
908
+ )
909
+ }
910
+
911
+ private async recordSummaryUnlocked(
912
+ summary: SessionSummaryRef & { materializedBy: 'kernel' },
913
+ tenantId: TenantId,
914
+ expectedOwnerVersion?: number,
870
915
  ): Promise<void> {
871
916
  if (summary.tenantId !== tenantId) {
872
917
  throw new TenantIsolationError({
@@ -884,8 +929,15 @@ export class DiskSessionStore implements SessionStore {
884
929
  throw new Error(`Session ${summary.sessionRef} not found on disk`)
885
930
  }
886
931
  this.assertTenant(sessionRaw.tenantId, tenantId, `session(${summary.sessionRef})`)
932
+ if (expectedOwnerVersion !== undefined && sessionRaw.ownerVersion !== expectedOwnerVersion) {
933
+ throw new StaleSessionError({
934
+ sessionId: summary.sessionRef,
935
+ expectedVersion: expectedOwnerVersion,
936
+ actualVersion: sessionRaw.ownerVersion,
937
+ })
938
+ }
887
939
 
888
- const summaryPath = join(located.path, 'summary.json')
940
+ const summaryPath = summaryFile(located.path, summary.turnRef)
889
941
  const existingRaw = await records.read<PersistedSummary>(summaryPath)
890
942
  if (existingRaw) {
891
943
  this.assertTenant(existingRaw.tenantId, tenantId, `summary(${existingRaw.id})`)
@@ -899,6 +951,8 @@ export class DiskSessionStore implements SessionStore {
899
951
  // to the status flip so crash-between-writes is recovered.
900
952
  } else {
901
953
  // Step 1: persist summary.
954
+ if (summary.turnRef)
955
+ await mkdir(join(located.path, 'turn-summaries'), { recursive: true, mode: 0o700 })
902
956
  await records.write(summaryPath, serializeSummary(summary))
903
957
  }
904
958
 
@@ -913,10 +967,15 @@ export class DiskSessionStore implements SessionStore {
913
967
  }
914
968
  }
915
969
 
916
- async getSummary(sessionId: SessionId, tenantId: TenantId): Promise<SessionSummaryRef | null> {
970
+ async getSummary(
971
+ sessionId: SessionId,
972
+ tenantId: TenantId,
973
+ turnId?: TurnId,
974
+ ): Promise<SessionSummaryRef | null> {
975
+ if (turnId !== undefined) asTurnId(turnId)
917
976
  const located = await this.locateSession(sessionId)
918
977
  if (!located) return null
919
- const raw = await records.read<PersistedSummary>(join(located.path, 'summary.json'))
978
+ const raw = await records.read<PersistedSummary>(summaryFile(located.path, turnId))
920
979
  if (!raw) return null
921
980
  this.assertTenant(raw.tenantId, tenantId, `summary(${raw.id})`)
922
981
  return deserializeSummary(raw)
@@ -1161,6 +1220,7 @@ function serializeSummary(s: SessionSummaryRef): PersistedSummary {
1161
1220
  return {
1162
1221
  id: s.id,
1163
1222
  sessionRef: s.sessionRef,
1223
+ ...(s.turnRef ? { turnRef: s.turnRef } : {}),
1164
1224
  tenantId: s.tenantId,
1165
1225
  outcome: s.outcome,
1166
1226
  deliverables: s.deliverables,
@@ -1182,6 +1242,7 @@ function deserializeSummary(s: PersistedSummary): SessionSummaryRef {
1182
1242
  return {
1183
1243
  id: s.id,
1184
1244
  sessionRef: s.sessionRef,
1245
+ ...(s.turnRef ? { turnRef: asTurnId(s.turnRef) } : {}),
1185
1246
  tenantId: s.tenantId,
1186
1247
  outcome: s.outcome,
1187
1248
  deliverables: s.deliverables,
@@ -1191,3 +1252,9 @@ function deserializeSummary(s: PersistedSummary): SessionSummaryRef {
1191
1252
  materializedBy: 'kernel',
1192
1253
  }
1193
1254
  }
1255
+
1256
+ function summaryFile(directory: string, turnId?: TurnId): string {
1257
+ return turnId === undefined
1258
+ ? join(directory, 'summary.json')
1259
+ : join(directory, 'turn-summaries', `${asTurnId(turnId)}.json`)
1260
+ }