@namzu/sdk 0.1.8 → 0.3.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 (626) hide show
  1. package/CHANGELOG.md +69 -2
  2. package/dist/agents/ReactiveAgent.d.ts.map +1 -1
  3. package/dist/agents/ReactiveAgent.js +5 -2
  4. package/dist/agents/ReactiveAgent.js.map +1 -1
  5. package/dist/agents/RouterAgent.d.ts.map +1 -1
  6. package/dist/agents/RouterAgent.js +3 -0
  7. package/dist/agents/RouterAgent.js.map +1 -1
  8. package/dist/agents/SupervisorAgent.d.ts.map +1 -1
  9. package/dist/agents/SupervisorAgent.js +21 -5
  10. package/dist/agents/SupervisorAgent.js.map +1 -1
  11. package/dist/bridge/a2a/index.d.ts +1 -1
  12. package/dist/bridge/a2a/index.d.ts.map +1 -1
  13. package/dist/bridge/a2a/index.js +1 -1
  14. package/dist/bridge/a2a/index.js.map +1 -1
  15. package/dist/bridge/a2a/mapper.d.ts.map +1 -1
  16. package/dist/bridge/a2a/mapper.js +6 -0
  17. package/dist/bridge/a2a/mapper.js.map +1 -1
  18. package/dist/bridge/a2a/message.d.ts +0 -2
  19. package/dist/bridge/a2a/message.d.ts.map +1 -1
  20. package/dist/bridge/a2a/message.js +0 -26
  21. package/dist/bridge/a2a/message.js.map +1 -1
  22. package/dist/bridge/a2a/task.d.ts +5 -4
  23. package/dist/bridge/a2a/task.d.ts.map +1 -1
  24. package/dist/bridge/a2a/task.js +4 -4
  25. package/dist/bridge/a2a/task.js.map +1 -1
  26. package/dist/bridge/sse/mapper.d.ts.map +1 -1
  27. package/dist/bridge/sse/mapper.js +6 -0
  28. package/dist/bridge/sse/mapper.js.map +1 -1
  29. package/dist/constants/a2a/index.d.ts +2 -2
  30. package/dist/constants/a2a/index.d.ts.map +1 -1
  31. package/dist/constants/a2a/index.js.map +1 -1
  32. package/dist/contracts/api.d.ts +14 -27
  33. package/dist/contracts/api.d.ts.map +1 -1
  34. package/dist/contracts/ids.d.ts +1 -1
  35. package/dist/contracts/ids.d.ts.map +1 -1
  36. package/dist/contracts/index.d.ts +3 -3
  37. package/dist/contracts/index.d.ts.map +1 -1
  38. package/dist/contracts/index.js +1 -1
  39. package/dist/contracts/index.js.map +1 -1
  40. package/dist/contracts/schemas.d.ts +1 -31
  41. package/dist/contracts/schemas.d.ts.map +1 -1
  42. package/dist/contracts/schemas.js +1 -7
  43. package/dist/contracts/schemas.js.map +1 -1
  44. package/dist/gateway/local.d.ts.map +1 -1
  45. package/dist/gateway/local.js +6 -0
  46. package/dist/gateway/local.js.map +1 -1
  47. package/dist/index.d.ts +6 -3
  48. package/dist/index.d.ts.map +1 -1
  49. package/dist/index.js +6 -3
  50. package/dist/index.js.map +1 -1
  51. package/dist/manager/agent/__tests__/lifecycle.test.d.ts +2 -0
  52. package/dist/manager/agent/__tests__/lifecycle.test.d.ts.map +1 -0
  53. package/dist/manager/agent/__tests__/lifecycle.test.js +316 -0
  54. package/dist/manager/agent/__tests__/lifecycle.test.js.map +1 -0
  55. package/dist/manager/agent/lifecycle.d.ts +67 -3
  56. package/dist/manager/agent/lifecycle.d.ts.map +1 -1
  57. package/dist/manager/agent/lifecycle.js +375 -14
  58. package/dist/manager/agent/lifecycle.js.map +1 -1
  59. package/dist/manager/index.d.ts +2 -0
  60. package/dist/manager/index.d.ts.map +1 -1
  61. package/dist/manager/index.js +1 -0
  62. package/dist/manager/index.js.map +1 -1
  63. package/dist/manager/run/persistence.d.ts +10 -1
  64. package/dist/manager/run/persistence.d.ts.map +1 -1
  65. package/dist/manager/run/persistence.js +20 -0
  66. package/dist/manager/run/persistence.js.map +1 -1
  67. package/dist/manager/thread/__tests__/lifecycle.test.d.ts +2 -0
  68. package/dist/manager/thread/__tests__/lifecycle.test.d.ts.map +1 -0
  69. package/dist/manager/thread/__tests__/lifecycle.test.js +216 -0
  70. package/dist/manager/thread/__tests__/lifecycle.test.js.map +1 -0
  71. package/dist/manager/thread/lifecycle.d.ts +105 -0
  72. package/dist/manager/thread/lifecycle.d.ts.map +1 -0
  73. package/dist/manager/thread/lifecycle.js +186 -0
  74. package/dist/manager/thread/lifecycle.js.map +1 -0
  75. package/dist/rag/retriever.js +2 -2
  76. package/dist/run/reporter.d.ts.map +1 -1
  77. package/dist/run/reporter.js +25 -0
  78. package/dist/run/reporter.js.map +1 -1
  79. package/dist/runtime/query/__tests__/context.test.d.ts +2 -0
  80. package/dist/runtime/query/__tests__/context.test.d.ts.map +1 -0
  81. package/dist/runtime/query/__tests__/context.test.js +85 -0
  82. package/dist/runtime/query/__tests__/context.test.js.map +1 -0
  83. package/dist/runtime/query/context-cache.d.ts +3 -3
  84. package/dist/runtime/query/context-cache.d.ts.map +1 -1
  85. package/dist/runtime/query/context-cache.js +2 -2
  86. package/dist/runtime/query/context-cache.js.map +1 -1
  87. package/dist/runtime/query/context.d.ts +45 -1
  88. package/dist/runtime/query/context.d.ts.map +1 -1
  89. package/dist/runtime/query/context.js +50 -8
  90. package/dist/runtime/query/context.js.map +1 -1
  91. package/dist/runtime/query/events.d.ts.map +1 -1
  92. package/dist/runtime/query/events.js +8 -0
  93. package/dist/runtime/query/events.js.map +1 -1
  94. package/dist/runtime/query/index.d.ts +22 -1
  95. package/dist/runtime/query/index.d.ts.map +1 -1
  96. package/dist/runtime/query/index.js +11 -0
  97. package/dist/runtime/query/index.js.map +1 -1
  98. package/dist/session/__tests__/integration/_fixtures.d.ts +122 -0
  99. package/dist/session/__tests__/integration/_fixtures.d.ts.map +1 -0
  100. package/dist/session/__tests__/integration/_fixtures.js +215 -0
  101. package/dist/session/__tests__/integration/_fixtures.js.map +1 -0
  102. package/dist/session/__tests__/integration/archive-gate.test.d.ts +15 -0
  103. package/dist/session/__tests__/integration/archive-gate.test.d.ts.map +1 -0
  104. package/dist/session/__tests__/integration/archive-gate.test.js +214 -0
  105. package/dist/session/__tests__/integration/archive-gate.test.js.map +1 -0
  106. package/dist/session/__tests__/integration/capacity-caps.test.d.ts +13 -0
  107. package/dist/session/__tests__/integration/capacity-caps.test.d.ts.map +1 -0
  108. package/dist/session/__tests__/integration/capacity-caps.test.js +123 -0
  109. package/dist/session/__tests__/integration/capacity-caps.test.js.map +1 -0
  110. package/dist/session/__tests__/integration/e2e-spawn.test.d.ts +18 -0
  111. package/dist/session/__tests__/integration/e2e-spawn.test.d.ts.map +1 -0
  112. package/dist/session/__tests__/integration/e2e-spawn.test.js +238 -0
  113. package/dist/session/__tests__/integration/e2e-spawn.test.js.map +1 -0
  114. package/dist/session/__tests__/integration/event-stream-ordering.test.d.ts +15 -0
  115. package/dist/session/__tests__/integration/event-stream-ordering.test.d.ts.map +1 -0
  116. package/dist/session/__tests__/integration/event-stream-ordering.test.js +330 -0
  117. package/dist/session/__tests__/integration/event-stream-ordering.test.js.map +1 -0
  118. package/dist/session/__tests__/integration/handoff-broadcast-e2e.test.d.ts +12 -0
  119. package/dist/session/__tests__/integration/handoff-broadcast-e2e.test.d.ts.map +1 -0
  120. package/dist/session/__tests__/integration/handoff-broadcast-e2e.test.js +182 -0
  121. package/dist/session/__tests__/integration/handoff-broadcast-e2e.test.js.map +1 -0
  122. package/dist/session/__tests__/integration/handoff-illegal-transition.test.d.ts +18 -0
  123. package/dist/session/__tests__/integration/handoff-illegal-transition.test.d.ts.map +1 -0
  124. package/dist/session/__tests__/integration/handoff-illegal-transition.test.js +156 -0
  125. package/dist/session/__tests__/integration/handoff-illegal-transition.test.js.map +1 -0
  126. package/dist/session/__tests__/integration/handoff-single-e2e.test.d.ts +15 -0
  127. package/dist/session/__tests__/integration/handoff-single-e2e.test.d.ts.map +1 -0
  128. package/dist/session/__tests__/integration/handoff-single-e2e.test.js +179 -0
  129. package/dist/session/__tests__/integration/handoff-single-e2e.test.js.map +1 -0
  130. package/dist/session/__tests__/integration/hierarchy-lifecycle.test.d.ts +12 -0
  131. package/dist/session/__tests__/integration/hierarchy-lifecycle.test.d.ts.map +1 -0
  132. package/dist/session/__tests__/integration/hierarchy-lifecycle.test.js +158 -0
  133. package/dist/session/__tests__/integration/hierarchy-lifecycle.test.js.map +1 -0
  134. package/dist/session/__tests__/integration/migration-filesystem.test.d.ts +11 -0
  135. package/dist/session/__tests__/integration/migration-filesystem.test.d.ts.map +1 -0
  136. package/dist/session/__tests__/integration/migration-filesystem.test.js +140 -0
  137. package/dist/session/__tests__/integration/migration-filesystem.test.js.map +1 -0
  138. package/dist/session/__tests__/integration/migration-id-prefix.test.d.ts +13 -0
  139. package/dist/session/__tests__/integration/migration-id-prefix.test.d.ts.map +1 -0
  140. package/dist/session/__tests__/integration/migration-id-prefix.test.js +84 -0
  141. package/dist/session/__tests__/integration/migration-id-prefix.test.js.map +1 -0
  142. package/dist/session/__tests__/integration/prev-artifact-dag.test.d.ts +14 -0
  143. package/dist/session/__tests__/integration/prev-artifact-dag.test.d.ts.map +1 -0
  144. package/dist/session/__tests__/integration/prev-artifact-dag.test.js +242 -0
  145. package/dist/session/__tests__/integration/prev-artifact-dag.test.js.map +1 -0
  146. package/dist/session/__tests__/integration/retention-archive.test.d.ts +12 -0
  147. package/dist/session/__tests__/integration/retention-archive.test.d.ts.map +1 -0
  148. package/dist/session/__tests__/integration/retention-archive.test.js +187 -0
  149. package/dist/session/__tests__/integration/retention-archive.test.js.map +1 -0
  150. package/dist/session/__tests__/integration/spawn-rollback.test.d.ts +26 -0
  151. package/dist/session/__tests__/integration/spawn-rollback.test.d.ts.map +1 -0
  152. package/dist/session/__tests__/integration/spawn-rollback.test.js +236 -0
  153. package/dist/session/__tests__/integration/spawn-rollback.test.js.map +1 -0
  154. package/dist/session/__tests__/integration/summary-materialization-e2e.test.d.ts +18 -0
  155. package/dist/session/__tests__/integration/summary-materialization-e2e.test.d.ts.map +1 -0
  156. package/dist/session/__tests__/integration/summary-materialization-e2e.test.js +201 -0
  157. package/dist/session/__tests__/integration/summary-materialization-e2e.test.js.map +1 -0
  158. package/dist/session/__tests__/integration/tenant-isolation.test.d.ts +14 -0
  159. package/dist/session/__tests__/integration/tenant-isolation.test.d.ts.map +1 -0
  160. package/dist/session/__tests__/integration/tenant-isolation.test.js +189 -0
  161. package/dist/session/__tests__/integration/tenant-isolation.test.js.map +1 -0
  162. package/dist/session/errors.d.ts +139 -0
  163. package/dist/session/errors.d.ts.map +1 -0
  164. package/dist/session/errors.js +107 -0
  165. package/dist/session/errors.js.map +1 -0
  166. package/dist/session/events/index.d.ts +4 -0
  167. package/dist/session/events/index.d.ts.map +1 -0
  168. package/dist/session/events/index.js +8 -0
  169. package/dist/session/events/index.js.map +1 -0
  170. package/dist/session/events/schema-version.d.ts +13 -0
  171. package/dist/session/events/schema-version.d.ts.map +1 -0
  172. package/dist/session/events/schema-version.js +12 -0
  173. package/dist/session/events/schema-version.js.map +1 -0
  174. package/dist/session/events/types.d.ts +64 -0
  175. package/dist/session/events/types.d.ts.map +1 -0
  176. package/dist/session/events/types.js +2 -0
  177. package/dist/session/events/types.js.map +1 -0
  178. package/dist/session/handoff/__tests__/broadcast.test.d.ts +2 -0
  179. package/dist/session/handoff/__tests__/broadcast.test.d.ts.map +1 -0
  180. package/dist/session/handoff/__tests__/broadcast.test.js +261 -0
  181. package/dist/session/handoff/__tests__/broadcast.test.js.map +1 -0
  182. package/dist/session/handoff/__tests__/capacity.test.d.ts +2 -0
  183. package/dist/session/handoff/__tests__/capacity.test.d.ts.map +1 -0
  184. package/dist/session/handoff/__tests__/capacity.test.js +103 -0
  185. package/dist/session/handoff/__tests__/capacity.test.js.map +1 -0
  186. package/dist/session/handoff/__tests__/single.test.d.ts +2 -0
  187. package/dist/session/handoff/__tests__/single.test.d.ts.map +1 -0
  188. package/dist/session/handoff/__tests__/single.test.js +239 -0
  189. package/dist/session/handoff/__tests__/single.test.js.map +1 -0
  190. package/dist/session/handoff/assignment.d.ts +71 -0
  191. package/dist/session/handoff/assignment.d.ts.map +1 -0
  192. package/dist/session/handoff/assignment.js +11 -0
  193. package/dist/session/handoff/assignment.js.map +1 -0
  194. package/dist/session/handoff/broadcast.d.ts +54 -0
  195. package/dist/session/handoff/broadcast.d.ts.map +1 -0
  196. package/dist/session/handoff/broadcast.js +311 -0
  197. package/dist/session/handoff/broadcast.js.map +1 -0
  198. package/dist/session/handoff/capacity.d.ts +66 -0
  199. package/dist/session/handoff/capacity.d.ts.map +1 -0
  200. package/dist/session/handoff/capacity.js +60 -0
  201. package/dist/session/handoff/capacity.js.map +1 -0
  202. package/dist/session/handoff/events.d.ts +66 -0
  203. package/dist/session/handoff/events.d.ts.map +1 -0
  204. package/dist/session/handoff/events.js +13 -0
  205. package/dist/session/handoff/events.js.map +1 -0
  206. package/dist/session/handoff/index.d.ts +12 -0
  207. package/dist/session/handoff/index.d.ts.map +1 -0
  208. package/dist/session/handoff/index.js +9 -0
  209. package/dist/session/handoff/index.js.map +1 -0
  210. package/dist/session/handoff/single.d.ts +69 -0
  211. package/dist/session/handoff/single.d.ts.map +1 -0
  212. package/dist/session/handoff/single.js +229 -0
  213. package/dist/session/handoff/single.js.map +1 -0
  214. package/dist/session/handoff/version.d.ts +52 -0
  215. package/dist/session/handoff/version.d.ts.map +1 -0
  216. package/dist/session/handoff/version.js +36 -0
  217. package/dist/session/handoff/version.js.map +1 -0
  218. package/dist/session/hierarchy/__tests__/session.test.d.ts +2 -0
  219. package/dist/session/hierarchy/__tests__/session.test.d.ts.map +1 -0
  220. package/dist/session/hierarchy/__tests__/session.test.js +69 -0
  221. package/dist/session/hierarchy/__tests__/session.test.js.map +1 -0
  222. package/dist/session/hierarchy/actor.d.ts +26 -0
  223. package/dist/session/hierarchy/actor.d.ts.map +1 -0
  224. package/dist/session/hierarchy/actor.js +2 -0
  225. package/dist/session/hierarchy/actor.js.map +1 -0
  226. package/dist/session/hierarchy/index.d.ts +9 -0
  227. package/dist/session/hierarchy/index.d.ts.map +1 -0
  228. package/dist/session/hierarchy/index.js +4 -0
  229. package/dist/session/hierarchy/index.js.map +1 -0
  230. package/dist/session/hierarchy/lineage.d.ts +15 -0
  231. package/dist/session/hierarchy/lineage.d.ts.map +1 -0
  232. package/dist/session/hierarchy/lineage.js +2 -0
  233. package/dist/session/hierarchy/lineage.js.map +1 -0
  234. package/dist/session/hierarchy/project.d.ts +40 -0
  235. package/dist/session/hierarchy/project.d.ts.map +1 -0
  236. package/dist/session/hierarchy/project.js +2 -0
  237. package/dist/session/hierarchy/project.js.map +1 -0
  238. package/dist/session/hierarchy/session.d.ts +71 -0
  239. package/dist/session/hierarchy/session.d.ts.map +1 -0
  240. package/dist/session/hierarchy/session.js +51 -0
  241. package/dist/session/hierarchy/session.js.map +1 -0
  242. package/dist/session/hierarchy/sub-session.d.ts +76 -0
  243. package/dist/session/hierarchy/sub-session.d.ts.map +1 -0
  244. package/dist/session/hierarchy/sub-session.js +2 -0
  245. package/dist/session/hierarchy/sub-session.js.map +1 -0
  246. package/dist/session/hierarchy/tenant.d.ts +13 -0
  247. package/dist/session/hierarchy/tenant.d.ts.map +1 -0
  248. package/dist/session/hierarchy/tenant.js +2 -0
  249. package/dist/session/hierarchy/tenant.js.map +1 -0
  250. package/dist/session/hierarchy/thread.d.ts +54 -0
  251. package/dist/session/hierarchy/thread.d.ts.map +1 -0
  252. package/dist/session/hierarchy/thread.js +2 -0
  253. package/dist/session/hierarchy/thread.js.map +1 -0
  254. package/dist/session/index.d.ts +10 -0
  255. package/dist/session/index.d.ts.map +1 -0
  256. package/dist/session/index.js +15 -0
  257. package/dist/session/index.js.map +1 -0
  258. package/dist/session/intervention/__tests__/prev-artifact.test.d.ts +2 -0
  259. package/dist/session/intervention/__tests__/prev-artifact.test.d.ts.map +1 -0
  260. package/dist/session/intervention/__tests__/prev-artifact.test.js +179 -0
  261. package/dist/session/intervention/__tests__/prev-artifact.test.js.map +1 -0
  262. package/dist/session/intervention/index.d.ts +3 -0
  263. package/dist/session/intervention/index.d.ts.map +1 -0
  264. package/dist/session/intervention/index.js +8 -0
  265. package/dist/session/intervention/index.js.map +1 -0
  266. package/dist/session/intervention/prev-artifact.d.ts +103 -0
  267. package/dist/session/intervention/prev-artifact.d.ts.map +1 -0
  268. package/dist/session/intervention/prev-artifact.js +112 -0
  269. package/dist/session/intervention/prev-artifact.js.map +1 -0
  270. package/dist/session/migration/__tests__/filesystem.test.d.ts +2 -0
  271. package/dist/session/migration/__tests__/filesystem.test.d.ts.map +1 -0
  272. package/dist/session/migration/__tests__/filesystem.test.js +188 -0
  273. package/dist/session/migration/__tests__/filesystem.test.js.map +1 -0
  274. package/dist/session/migration/__tests__/id-prefix.test.d.ts +2 -0
  275. package/dist/session/migration/__tests__/id-prefix.test.d.ts.map +1 -0
  276. package/dist/session/migration/__tests__/id-prefix.test.js +83 -0
  277. package/dist/session/migration/__tests__/id-prefix.test.js.map +1 -0
  278. package/dist/session/migration/__tests__/marker.test.d.ts +2 -0
  279. package/dist/session/migration/__tests__/marker.test.d.ts.map +1 -0
  280. package/dist/session/migration/__tests__/marker.test.js +75 -0
  281. package/dist/session/migration/__tests__/marker.test.js.map +1 -0
  282. package/dist/session/migration/errors.d.ts +26 -0
  283. package/dist/session/migration/errors.d.ts.map +1 -0
  284. package/dist/session/migration/errors.js +22 -0
  285. package/dist/session/migration/errors.js.map +1 -0
  286. package/dist/session/migration/filesystem.d.ts +94 -0
  287. package/dist/session/migration/filesystem.d.ts.map +1 -0
  288. package/dist/session/migration/filesystem.js +319 -0
  289. package/dist/session/migration/filesystem.js.map +1 -0
  290. package/dist/session/migration/id-prefix.d.ts +93 -0
  291. package/dist/session/migration/id-prefix.d.ts.map +1 -0
  292. package/dist/session/migration/id-prefix.js +111 -0
  293. package/dist/session/migration/id-prefix.js.map +1 -0
  294. package/dist/session/migration/index.d.ts +8 -0
  295. package/dist/session/migration/index.d.ts.map +1 -0
  296. package/dist/session/migration/index.js +8 -0
  297. package/dist/session/migration/index.js.map +1 -0
  298. package/dist/session/migration/marker.d.ts +57 -0
  299. package/dist/session/migration/marker.d.ts.map +1 -0
  300. package/dist/session/migration/marker.js +111 -0
  301. package/dist/session/migration/marker.js.map +1 -0
  302. package/dist/session/retention/__tests__/archive.test.d.ts +2 -0
  303. package/dist/session/retention/__tests__/archive.test.d.ts.map +1 -0
  304. package/dist/session/retention/__tests__/archive.test.js +253 -0
  305. package/dist/session/retention/__tests__/archive.test.js.map +1 -0
  306. package/dist/session/retention/__tests__/disk-backend.test.d.ts +2 -0
  307. package/dist/session/retention/__tests__/disk-backend.test.d.ts.map +1 -0
  308. package/dist/session/retention/__tests__/disk-backend.test.js +154 -0
  309. package/dist/session/retention/__tests__/disk-backend.test.js.map +1 -0
  310. package/dist/session/retention/archive-backend-ref.d.ts +18 -0
  311. package/dist/session/retention/archive-backend-ref.d.ts.map +1 -0
  312. package/dist/session/retention/archive-backend-ref.js +2 -0
  313. package/dist/session/retention/archive-backend-ref.js.map +1 -0
  314. package/dist/session/retention/archive.d.ts +130 -0
  315. package/dist/session/retention/archive.d.ts.map +1 -0
  316. package/dist/session/retention/archive.js +203 -0
  317. package/dist/session/retention/archive.js.map +1 -0
  318. package/dist/session/retention/backend.d.ts +101 -0
  319. package/dist/session/retention/backend.d.ts.map +1 -0
  320. package/dist/session/retention/backend.js +15 -0
  321. package/dist/session/retention/backend.js.map +1 -0
  322. package/dist/session/retention/disk-backend.d.ts +59 -0
  323. package/dist/session/retention/disk-backend.d.ts.map +1 -0
  324. package/dist/session/retention/disk-backend.js +236 -0
  325. package/dist/session/retention/disk-backend.js.map +1 -0
  326. package/dist/session/retention/index.d.ts +9 -0
  327. package/dist/session/retention/index.d.ts.map +1 -0
  328. package/dist/session/retention/index.js +6 -0
  329. package/dist/session/retention/index.js.map +1 -0
  330. package/dist/session/retention/policy.d.ts +49 -0
  331. package/dist/session/retention/policy.d.ts.map +1 -0
  332. package/dist/session/retention/policy.js +21 -0
  333. package/dist/session/retention/policy.js.map +1 -0
  334. package/dist/session/summary/__tests__/materialize.test.d.ts +2 -0
  335. package/dist/session/summary/__tests__/materialize.test.d.ts.map +1 -0
  336. package/dist/session/summary/__tests__/materialize.test.js +270 -0
  337. package/dist/session/summary/__tests__/materialize.test.js.map +1 -0
  338. package/dist/session/summary/deliverable.d.ts +74 -0
  339. package/dist/session/summary/deliverable.d.ts.map +1 -0
  340. package/dist/session/summary/deliverable.js +20 -0
  341. package/dist/session/summary/deliverable.js.map +1 -0
  342. package/dist/session/summary/index.d.ts +6 -0
  343. package/dist/session/summary/index.d.ts.map +1 -0
  344. package/dist/session/summary/index.js +9 -0
  345. package/dist/session/summary/index.js.map +1 -0
  346. package/dist/session/summary/materialize.d.ts +82 -0
  347. package/dist/session/summary/materialize.d.ts.map +1 -0
  348. package/dist/session/summary/materialize.js +117 -0
  349. package/dist/session/summary/materialize.js.map +1 -0
  350. package/dist/session/summary/ref.d.ts +91 -0
  351. package/dist/session/summary/ref.d.ts.map +1 -0
  352. package/dist/session/summary/ref.js +51 -0
  353. package/dist/session/summary/ref.js.map +1 -0
  354. package/dist/session/workspace/__tests__/git-worktree.test.d.ts +2 -0
  355. package/dist/session/workspace/__tests__/git-worktree.test.d.ts.map +1 -0
  356. package/dist/session/workspace/__tests__/git-worktree.test.js +244 -0
  357. package/dist/session/workspace/__tests__/git-worktree.test.js.map +1 -0
  358. package/dist/session/workspace/__tests__/path-builder.test.d.ts +2 -0
  359. package/dist/session/workspace/__tests__/path-builder.test.d.ts.map +1 -0
  360. package/dist/session/workspace/__tests__/path-builder.test.js +37 -0
  361. package/dist/session/workspace/__tests__/path-builder.test.js.map +1 -0
  362. package/dist/session/workspace/driver.d.ts +55 -0
  363. package/dist/session/workspace/driver.d.ts.map +1 -0
  364. package/dist/session/workspace/driver.js +12 -0
  365. package/dist/session/workspace/driver.js.map +1 -0
  366. package/dist/session/workspace/git-worktree.d.ts +65 -0
  367. package/dist/session/workspace/git-worktree.d.ts.map +1 -0
  368. package/dist/session/workspace/git-worktree.js +156 -0
  369. package/dist/session/workspace/git-worktree.js.map +1 -0
  370. package/dist/session/workspace/index.d.ts +8 -0
  371. package/dist/session/workspace/index.d.ts.map +1 -0
  372. package/dist/session/workspace/index.js +7 -0
  373. package/dist/session/workspace/index.js.map +1 -0
  374. package/dist/session/workspace/path-builder.d.ts +50 -0
  375. package/dist/session/workspace/path-builder.d.ts.map +1 -0
  376. package/dist/session/workspace/path-builder.js +50 -0
  377. package/dist/session/workspace/path-builder.js.map +1 -0
  378. package/dist/session/workspace/ref.d.ts +46 -0
  379. package/dist/session/workspace/ref.d.ts.map +1 -0
  380. package/dist/session/workspace/ref.js +11 -0
  381. package/dist/session/workspace/ref.js.map +1 -0
  382. package/dist/session/workspace/registry.d.ts +26 -0
  383. package/dist/session/workspace/registry.d.ts.map +1 -0
  384. package/dist/session/workspace/registry.js +35 -0
  385. package/dist/session/workspace/registry.js.map +1 -0
  386. package/dist/store/index.d.ts +0 -2
  387. package/dist/store/index.d.ts.map +1 -1
  388. package/dist/store/index.js +0 -1
  389. package/dist/store/index.js.map +1 -1
  390. package/dist/store/session/__tests__/disk.test.d.ts +2 -0
  391. package/dist/store/session/__tests__/disk.test.d.ts.map +1 -0
  392. package/dist/store/session/__tests__/disk.test.js +267 -0
  393. package/dist/store/session/__tests__/disk.test.js.map +1 -0
  394. package/dist/store/session/__tests__/memory.test.d.ts +2 -0
  395. package/dist/store/session/__tests__/memory.test.d.ts.map +1 -0
  396. package/dist/store/session/__tests__/memory.test.js +258 -0
  397. package/dist/store/session/__tests__/memory.test.js.map +1 -0
  398. package/dist/store/session/disk.d.ts +86 -0
  399. package/dist/store/session/disk.d.ts.map +1 -0
  400. package/dist/store/session/disk.js +818 -0
  401. package/dist/store/session/disk.js.map +1 -0
  402. package/dist/store/session/index.d.ts +7 -0
  403. package/dist/store/session/index.d.ts.map +1 -0
  404. package/dist/store/session/index.js +10 -0
  405. package/dist/store/session/index.js.map +1 -0
  406. package/dist/store/session/linkage.d.ts +38 -0
  407. package/dist/store/session/linkage.d.ts.map +1 -0
  408. package/dist/store/session/linkage.js +64 -0
  409. package/dist/store/session/linkage.js.map +1 -0
  410. package/dist/store/session/memory.d.ts +49 -0
  411. package/dist/store/session/memory.d.ts.map +1 -0
  412. package/dist/store/session/memory.js +335 -0
  413. package/dist/store/session/memory.js.map +1 -0
  414. package/dist/store/session/messages.d.ts +20 -0
  415. package/dist/store/session/messages.d.ts.map +1 -0
  416. package/dist/store/session/messages.js +12 -0
  417. package/dist/store/session/messages.js.map +1 -0
  418. package/dist/store/thread/disk.d.ts +41 -0
  419. package/dist/store/thread/disk.d.ts.map +1 -0
  420. package/dist/store/thread/disk.js +229 -0
  421. package/dist/store/thread/disk.js.map +1 -0
  422. package/dist/store/thread/index.d.ts +4 -0
  423. package/dist/store/thread/index.d.ts.map +1 -0
  424. package/dist/store/thread/index.js +6 -0
  425. package/dist/store/thread/index.js.map +1 -0
  426. package/dist/store/thread/memory.d.ts +23 -0
  427. package/dist/store/thread/memory.d.ts.map +1 -0
  428. package/dist/store/thread/memory.js +90 -0
  429. package/dist/store/thread/memory.js.map +1 -0
  430. package/dist/tools/builtins/__tests__/structuredOutput.example.d.ts +1 -1
  431. package/dist/types/agent/base.d.ts +24 -1
  432. package/dist/types/agent/base.d.ts.map +1 -1
  433. package/dist/types/agent/factory.d.ts +8 -2
  434. package/dist/types/agent/factory.d.ts.map +1 -1
  435. package/dist/types/agent/task.d.ts +57 -2
  436. package/dist/types/agent/task.d.ts.map +1 -1
  437. package/dist/types/agent/task.js.map +1 -1
  438. package/dist/types/ids/index.d.ts +22 -3
  439. package/dist/types/ids/index.d.ts.map +1 -1
  440. package/dist/types/ids/index.js +8 -1
  441. package/dist/types/ids/index.js.map +1 -1
  442. package/dist/types/invocation/__tests__/state.test.js +36 -29
  443. package/dist/types/invocation/__tests__/state.test.js.map +1 -1
  444. package/dist/types/invocation/index.d.ts +20 -4
  445. package/dist/types/invocation/index.d.ts.map +1 -1
  446. package/dist/types/invocation/index.js +10 -7
  447. package/dist/types/invocation/index.js.map +1 -1
  448. package/dist/types/rag/retrieval.d.ts +4 -3
  449. package/dist/types/rag/retrieval.d.ts.map +1 -1
  450. package/dist/types/run/config.d.ts +12 -1
  451. package/dist/types/run/config.d.ts.map +1 -1
  452. package/dist/types/run/events.d.ts +26 -1
  453. package/dist/types/run/events.d.ts.map +1 -1
  454. package/dist/types/run/index.d.ts.map +1 -1
  455. package/dist/types/run/index.js +8 -0
  456. package/dist/types/run/index.js.map +1 -1
  457. package/dist/types/run/metadata.d.ts +12 -2
  458. package/dist/types/run/metadata.d.ts.map +1 -1
  459. package/dist/types/run/status.d.ts +26 -0
  460. package/dist/types/run/status.d.ts.map +1 -0
  461. package/dist/types/run/status.js +2 -0
  462. package/dist/types/run/status.js.map +1 -0
  463. package/dist/types/session/ids.d.ts +9 -0
  464. package/dist/types/session/ids.d.ts.map +1 -0
  465. package/dist/types/session/ids.js +9 -0
  466. package/dist/types/session/ids.js.map +1 -0
  467. package/dist/types/session/index.d.ts +3 -0
  468. package/dist/types/session/index.d.ts.map +1 -0
  469. package/dist/types/session/index.js +5 -0
  470. package/dist/types/session/index.js.map +1 -0
  471. package/dist/types/session/store.d.ts +210 -0
  472. package/dist/types/session/store.d.ts.map +1 -0
  473. package/dist/types/session/store.js +9 -0
  474. package/dist/types/session/store.js.map +1 -0
  475. package/dist/types/thread/index.d.ts +2 -0
  476. package/dist/types/thread/index.d.ts.map +1 -0
  477. package/dist/types/thread/index.js +5 -0
  478. package/dist/types/thread/index.js.map +1 -0
  479. package/dist/types/thread/store.d.ts +86 -0
  480. package/dist/types/thread/store.d.ts.map +1 -0
  481. package/dist/types/thread/store.js +22 -0
  482. package/dist/types/thread/store.js.map +1 -0
  483. package/dist/utils/id.d.ts +8 -2
  484. package/dist/utils/id.d.ts.map +1 -1
  485. package/dist/utils/id.js +22 -4
  486. package/dist/utils/id.js.map +1 -1
  487. package/package.json +6 -11
  488. package/src/agents/ReactiveAgent.ts +7 -2
  489. package/src/agents/RouterAgent.ts +5 -0
  490. package/src/agents/SupervisorAgent.ts +29 -6
  491. package/src/bridge/a2a/index.ts +0 -1
  492. package/src/bridge/a2a/mapper.ts +7 -0
  493. package/src/bridge/a2a/message.ts +0 -32
  494. package/src/bridge/a2a/task.ts +9 -8
  495. package/src/bridge/sse/mapper.ts +8 -1
  496. package/src/constants/a2a/index.ts +2 -2
  497. package/src/contracts/api.ts +14 -30
  498. package/src/contracts/ids.ts +1 -1
  499. package/src/contracts/index.ts +3 -7
  500. package/src/contracts/schemas.ts +1 -8
  501. package/src/gateway/local.ts +6 -0
  502. package/src/index.ts +14 -4
  503. package/src/manager/agent/__tests__/lifecycle.test.ts +473 -0
  504. package/src/manager/agent/lifecycle.ts +515 -21
  505. package/src/manager/index.ts +3 -0
  506. package/src/manager/run/persistence.ts +26 -1
  507. package/src/manager/thread/__tests__/lifecycle.test.ts +286 -0
  508. package/src/manager/thread/lifecycle.ts +217 -0
  509. package/src/rag/retriever.ts +2 -2
  510. package/src/run/reporter.ts +28 -0
  511. package/src/runtime/query/__tests__/context.test.ts +102 -0
  512. package/src/runtime/query/context-cache.ts +4 -4
  513. package/src/runtime/query/context.ts +98 -9
  514. package/src/runtime/query/events.ts +8 -0
  515. package/src/runtime/query/index.ts +38 -1
  516. package/src/session/__tests__/integration/_fixtures.ts +310 -0
  517. package/src/session/__tests__/integration/archive-gate.test.ts +288 -0
  518. package/src/session/__tests__/integration/capacity-caps.test.ts +171 -0
  519. package/src/session/__tests__/integration/e2e-spawn.test.ts +296 -0
  520. package/src/session/__tests__/integration/event-stream-ordering.test.ts +410 -0
  521. package/src/session/__tests__/integration/handoff-broadcast-e2e.test.ts +271 -0
  522. package/src/session/__tests__/integration/handoff-illegal-transition.test.ts +214 -0
  523. package/src/session/__tests__/integration/handoff-single-e2e.test.ts +251 -0
  524. package/src/session/__tests__/integration/hierarchy-lifecycle.test.ts +240 -0
  525. package/src/session/__tests__/integration/migration-filesystem.test.ts +209 -0
  526. package/src/session/__tests__/integration/migration-id-prefix.test.ts +101 -0
  527. package/src/session/__tests__/integration/prev-artifact-dag.test.ts +325 -0
  528. package/src/session/__tests__/integration/retention-archive.test.ts +233 -0
  529. package/src/session/__tests__/integration/spawn-rollback.test.ts +313 -0
  530. package/src/session/__tests__/integration/summary-materialization-e2e.test.ts +239 -0
  531. package/src/session/__tests__/integration/tenant-isolation.test.ts +292 -0
  532. package/src/session/errors.ts +159 -0
  533. package/src/session/events/index.ts +16 -0
  534. package/src/session/events/schema-version.ts +13 -0
  535. package/src/session/events/types.ts +71 -0
  536. package/src/session/handoff/__tests__/broadcast.test.ts +378 -0
  537. package/src/session/handoff/__tests__/capacity.test.ts +129 -0
  538. package/src/session/handoff/__tests__/single.test.ts +333 -0
  539. package/src/session/handoff/assignment.ts +74 -0
  540. package/src/session/handoff/broadcast.ts +406 -0
  541. package/src/session/handoff/capacity.ts +121 -0
  542. package/src/session/handoff/events.ts +72 -0
  543. package/src/session/handoff/index.ts +29 -0
  544. package/src/session/handoff/single.ts +310 -0
  545. package/src/session/handoff/version.ts +59 -0
  546. package/src/session/hierarchy/__tests__/session.test.ts +100 -0
  547. package/src/session/hierarchy/actor.ts +17 -0
  548. package/src/session/hierarchy/index.ts +18 -0
  549. package/src/session/hierarchy/lineage.ts +15 -0
  550. package/src/session/hierarchy/project.ts +41 -0
  551. package/src/session/hierarchy/session.ts +109 -0
  552. package/src/session/hierarchy/sub-session.ts +92 -0
  553. package/src/session/hierarchy/tenant.ts +13 -0
  554. package/src/session/hierarchy/thread.ts +55 -0
  555. package/src/session/index.ts +15 -0
  556. package/src/session/intervention/__tests__/prev-artifact.test.ts +234 -0
  557. package/src/session/intervention/index.ts +16 -0
  558. package/src/session/intervention/prev-artifact.ts +180 -0
  559. package/src/session/migration/__tests__/filesystem.test.ts +263 -0
  560. package/src/session/migration/__tests__/id-prefix.test.ts +101 -0
  561. package/src/session/migration/__tests__/marker.test.ts +84 -0
  562. package/src/session/migration/errors.ts +23 -0
  563. package/src/session/migration/filesystem.ts +401 -0
  564. package/src/session/migration/id-prefix.ts +141 -0
  565. package/src/session/migration/index.ts +38 -0
  566. package/src/session/migration/marker.ts +131 -0
  567. package/src/session/retention/__tests__/archive.test.ts +318 -0
  568. package/src/session/retention/__tests__/disk-backend.test.ts +180 -0
  569. package/src/session/retention/archive-backend-ref.ts +17 -0
  570. package/src/session/retention/archive.ts +281 -0
  571. package/src/session/retention/backend.ts +107 -0
  572. package/src/session/retention/disk-backend.ts +304 -0
  573. package/src/session/retention/index.ts +16 -0
  574. package/src/session/retention/policy.ts +53 -0
  575. package/src/session/summary/__tests__/materialize.test.ts +343 -0
  576. package/src/session/summary/deliverable.ts +84 -0
  577. package/src/session/summary/index.ts +31 -0
  578. package/src/session/summary/materialize.ts +169 -0
  579. package/src/session/summary/ref.ts +104 -0
  580. package/src/session/workspace/__tests__/git-worktree.test.ts +258 -0
  581. package/src/session/workspace/__tests__/path-builder.test.ts +51 -0
  582. package/src/session/workspace/driver.ts +60 -0
  583. package/src/session/workspace/git-worktree.ts +209 -0
  584. package/src/session/workspace/index.ts +25 -0
  585. package/src/session/workspace/path-builder.ts +71 -0
  586. package/src/session/workspace/ref.ts +50 -0
  587. package/src/session/workspace/registry.ts +42 -0
  588. package/src/store/index.ts +0 -3
  589. package/src/store/session/__tests__/disk.test.ts +397 -0
  590. package/src/store/session/__tests__/memory.test.ts +402 -0
  591. package/src/store/session/disk.ts +976 -0
  592. package/src/store/session/index.ts +13 -0
  593. package/src/store/session/linkage.ts +80 -0
  594. package/src/store/session/memory.ts +412 -0
  595. package/src/store/session/messages.ts +21 -0
  596. package/src/store/thread/disk.ts +261 -0
  597. package/src/store/thread/index.ts +7 -0
  598. package/src/store/thread/memory.ts +104 -0
  599. package/src/types/agent/base.ts +27 -1
  600. package/src/types/agent/factory.ts +8 -3
  601. package/src/types/agent/task.ts +66 -2
  602. package/src/types/ids/index.ts +34 -3
  603. package/src/types/invocation/__tests__/state.test.ts +37 -29
  604. package/src/types/invocation/index.ts +26 -10
  605. package/src/types/rag/retrieval.ts +4 -3
  606. package/src/types/run/config.ts +13 -1
  607. package/src/types/run/events.ts +36 -1
  608. package/src/types/run/index.ts +8 -0
  609. package/src/types/run/metadata.ts +12 -2
  610. package/src/types/run/status.ts +33 -0
  611. package/src/types/session/ids.ts +23 -0
  612. package/src/types/session/index.ts +27 -0
  613. package/src/types/session/store.ts +252 -0
  614. package/src/types/thread/index.ts +5 -0
  615. package/src/types/thread/store.ts +92 -0
  616. package/src/utils/id.ts +34 -4
  617. package/dist/store/conversation/memory.d.ts +0 -21
  618. package/dist/store/conversation/memory.d.ts.map +0 -1
  619. package/dist/store/conversation/memory.js +0 -86
  620. package/dist/store/conversation/memory.js.map +0 -1
  621. package/dist/types/conversation/index.d.ts +0 -7
  622. package/dist/types/conversation/index.d.ts.map +0 -1
  623. package/dist/types/conversation/index.js +0 -2
  624. package/dist/types/conversation/index.js.map +0 -1
  625. package/src/store/conversation/memory.ts +0 -121
  626. package/src/types/conversation/index.ts +0 -8
@@ -1,10 +1,11 @@
1
1
  import { EMPTY_TOKEN_USAGE } from '../../constants/limits.js'
2
2
  import { RunDiskStore } from '../../store/run/disk.js'
3
3
  import { type CostInfo, type TokenUsage, accumulateTokenUsage } from '../../types/common/index.js'
4
- import type { RunId } from '../../types/ids/index.js'
4
+ import type { RunId, SessionId, TenantId } from '../../types/ids/index.js'
5
5
  import type { AssistantMessage, Message } from '../../types/message/index.js'
6
6
  import type { EmergencySaveData } from '../../types/run/emergency.js'
7
7
  import type { AgentRun, RunPersistenceConfig, StopReason } from '../../types/run/index.js'
8
+ import type { ProjectId, ThreadId } from '../../types/session/ids.js'
8
9
  import { type ModelPricing, ZERO_COST, accumulateCost } from '../../utils/cost.js'
9
10
  import { generateEmergencySaveId } from '../../utils/id.js'
10
11
  import type { Logger } from '../../utils/logger.js'
@@ -14,10 +15,18 @@ export class RunPersistence {
14
15
  private runStore: RunDiskStore
15
16
  private pricing?: ModelPricing
16
17
  private log: Logger
18
+ private readonly _sessionId: SessionId
19
+ private readonly _threadId: ThreadId
20
+ private readonly _tenantId: TenantId
21
+ private readonly _projectId: ProjectId
17
22
 
18
23
  constructor(config: RunPersistenceConfig) {
19
24
  this.pricing = config.pricing
20
25
  this.log = config.log
26
+ this._sessionId = config.sessionId
27
+ this._threadId = config.threadId
28
+ this._tenantId = config.tenantId
29
+ this._projectId = config.projectId
21
30
 
22
31
  this.runStore = new RunDiskStore({
23
32
  baseDir: config.outputDir,
@@ -47,6 +56,22 @@ export class RunPersistence {
47
56
  return this.run.id
48
57
  }
49
58
 
59
+ get sessionId(): SessionId {
60
+ return this._sessionId
61
+ }
62
+
63
+ get threadId(): ThreadId {
64
+ return this._threadId
65
+ }
66
+
67
+ get tenantId(): TenantId {
68
+ return this._tenantId
69
+ }
70
+
71
+ get projectId(): ProjectId {
72
+ return this._projectId
73
+ }
74
+
50
75
  get status() {
51
76
  return this.run.status
52
77
  }
@@ -0,0 +1,286 @@
1
+ import { describe, expect, it } from 'vitest'
2
+ import { ThreadClosedError, ThreadNotEmptyError } from '../../../session/errors.js'
3
+ import type { ActorRef } from '../../../session/hierarchy/actor.js'
4
+ import { InMemorySessionStore } from '../../../store/session/memory.js'
5
+ import { InMemoryThreadStore } from '../../../store/thread/memory.js'
6
+ import type { AgentId, TenantId, UserId } from '../../../types/ids/index.js'
7
+ import type { ThreadId } from '../../../types/session/ids.js'
8
+ import { ThreadManager } from '../lifecycle.js'
9
+
10
+ const MISSING_THREAD_ID = 'thd_missing' as ThreadId
11
+
12
+ const tenantA = 'tnt_alpha' as TenantId
13
+ const tenantB = 'tnt_beta' as TenantId
14
+
15
+ function userActor(tenantId: TenantId): ActorRef {
16
+ return { kind: 'user', userId: 'usr_a' as UserId, tenantId }
17
+ }
18
+
19
+ function agentActor(tenantId: TenantId): ActorRef {
20
+ return { kind: 'agent', agentId: 'agt_a' as AgentId, tenantId }
21
+ }
22
+
23
+ async function harness(tenantId: TenantId = tenantA) {
24
+ const threadStore = new InMemoryThreadStore()
25
+ const sessionStore = new InMemorySessionStore()
26
+ const project = await sessionStore.createProject({ tenantId, name: 'p1' }, tenantId)
27
+ const thread = await threadStore.createThread({ projectId: project.id, title: 't' }, tenantId)
28
+ const manager = new ThreadManager({ threadStore, sessionStore })
29
+ return { threadStore, sessionStore, project, thread, manager }
30
+ }
31
+
32
+ describe('ThreadManager', () => {
33
+ describe('requireOpen', () => {
34
+ it('returns the thread when open', async () => {
35
+ const { thread, manager } = await harness()
36
+ await expect(manager.requireOpen(thread.id, tenantA)).resolves.toMatchObject({
37
+ id: thread.id,
38
+ status: 'open',
39
+ })
40
+ })
41
+
42
+ it('throws ThreadClosedError when archived', async () => {
43
+ const { thread, manager, threadStore } = await harness()
44
+ await threadStore.updateThread({ ...thread, status: 'archived' }, tenantA)
45
+ await expect(manager.requireOpen(thread.id, tenantA)).rejects.toBeInstanceOf(
46
+ ThreadClosedError,
47
+ )
48
+ })
49
+
50
+ it('throws when the thread does not exist', async () => {
51
+ const { manager } = await harness()
52
+ await expect(manager.requireOpen(MISSING_THREAD_ID, tenantA)).rejects.toThrow(/not found/)
53
+ })
54
+ })
55
+
56
+ describe('archive', () => {
57
+ it('flips status to archived and bumps ownerVersion', async () => {
58
+ const { thread, manager } = await harness()
59
+ const archived = await manager.archive(thread.id, tenantA)
60
+ expect(archived.status).toBe('archived')
61
+ expect(archived.ownerVersion).toBe(thread.ownerVersion + 1)
62
+ })
63
+
64
+ it('is idempotent on an already-archived thread (no store write)', async () => {
65
+ const { thread, manager, threadStore } = await harness()
66
+ await threadStore.updateThread({ ...thread, status: 'archived' }, tenantA)
67
+ const before = await threadStore.getThread(thread.id, tenantA)
68
+
69
+ const result = await manager.archive(thread.id, tenantA)
70
+ expect(result.status).toBe('archived')
71
+ // Re-archival must NOT advance ownerVersion — the store would have
72
+ // rejected a second updateThread as stale anyway; we assert the
73
+ // short-circuit path held instead.
74
+ expect(result.ownerVersion).toBe(before?.ownerVersion)
75
+ })
76
+
77
+ it('throws when the thread does not exist', async () => {
78
+ const { manager } = await harness()
79
+ await expect(manager.archive(MISSING_THREAD_ID, tenantA)).rejects.toThrow(/not found/)
80
+ })
81
+
82
+ it('rejects with ThreadNotEmptyError when a session is active', async () => {
83
+ const { thread, project, manager, sessionStore } = await harness()
84
+ const session = await sessionStore.createSession(
85
+ {
86
+ threadId: thread.id,
87
+ projectId: project.id,
88
+ currentActor: userActor(tenantA),
89
+ },
90
+ tenantA,
91
+ )
92
+ await sessionStore.updateSession({ ...session, status: 'active' }, tenantA)
93
+
94
+ await expect(manager.archive(thread.id, tenantA)).rejects.toMatchObject({
95
+ name: 'ThreadNotEmptyError',
96
+ details: {
97
+ threadId: thread.id,
98
+ tenantId: tenantA,
99
+ op: 'archive',
100
+ totalBlockingSessions: 1,
101
+ blockingSessions: [{ sessionId: session.id, status: 'active' }],
102
+ },
103
+ })
104
+ })
105
+
106
+ it('defensive re-check: already-archived thread with a smuggled active session still rejects', async () => {
107
+ // Flip the thread to archived directly (bypassing manager.archive so
108
+ // no check runs), then attach an active session via direct store
109
+ // mutation. A subsequent manager.archive() must surface the offender
110
+ // as ThreadNotEmptyError, not short-circuit as "already archived".
111
+ const { thread, project, manager, sessionStore, threadStore } = await harness()
112
+ await threadStore.updateThread({ ...thread, status: 'archived' }, tenantA)
113
+ const smuggled = await sessionStore.createSession(
114
+ {
115
+ threadId: thread.id,
116
+ projectId: project.id,
117
+ currentActor: userActor(tenantA),
118
+ },
119
+ tenantA,
120
+ )
121
+ await sessionStore.updateSession({ ...smuggled, status: 'active' }, tenantA)
122
+
123
+ await expect(manager.archive(thread.id, tenantA)).rejects.toMatchObject({
124
+ name: 'ThreadNotEmptyError',
125
+ details: {
126
+ op: 'archive',
127
+ totalBlockingSessions: 1,
128
+ blockingSessions: [{ sessionId: smuggled.id, status: 'active' }],
129
+ },
130
+ })
131
+ })
132
+
133
+ it.each(['locked', 'awaiting_hitl', 'awaiting_merge'] as const)(
134
+ 'rejects when a session is %s',
135
+ async (status) => {
136
+ const { thread, project, manager, sessionStore } = await harness()
137
+ const session = await sessionStore.createSession(
138
+ {
139
+ threadId: thread.id,
140
+ projectId: project.id,
141
+ currentActor: userActor(tenantA),
142
+ },
143
+ tenantA,
144
+ )
145
+ await sessionStore.updateSession({ ...session, status }, tenantA)
146
+
147
+ await expect(manager.archive(thread.id, tenantA)).rejects.toBeInstanceOf(
148
+ ThreadNotEmptyError,
149
+ )
150
+ },
151
+ )
152
+
153
+ it('allows archival when every session is quiescent (idle / failed / archived)', async () => {
154
+ const { thread, project, manager, sessionStore } = await harness()
155
+ // `createSession` defaults to `idle`; force the others via updateSession.
156
+ await sessionStore.createSession(
157
+ {
158
+ threadId: thread.id,
159
+ projectId: project.id,
160
+ currentActor: userActor(tenantA),
161
+ },
162
+ tenantA,
163
+ )
164
+ const sFailed = await sessionStore.createSession(
165
+ {
166
+ threadId: thread.id,
167
+ projectId: project.id,
168
+ currentActor: agentActor(tenantA),
169
+ },
170
+ tenantA,
171
+ )
172
+ await sessionStore.updateSession({ ...sFailed, status: 'failed' }, tenantA)
173
+
174
+ const archived = await manager.archive(thread.id, tenantA)
175
+ expect(archived.status).toBe('archived')
176
+ })
177
+
178
+ it('ignores sessions attached to a sibling thread', async () => {
179
+ const { thread, project, manager, sessionStore, threadStore } = await harness()
180
+ const other = await threadStore.createThread(
181
+ { projectId: project.id, title: 'other' },
182
+ tenantA,
183
+ )
184
+ // Active session under the OTHER thread must not block archival of
185
+ // `thread`.
186
+ const otherSession = await sessionStore.createSession(
187
+ {
188
+ threadId: other.id,
189
+ projectId: project.id,
190
+ currentActor: userActor(tenantA),
191
+ },
192
+ tenantA,
193
+ )
194
+ await sessionStore.updateSession({ ...otherSession, status: 'active' }, tenantA)
195
+
196
+ await expect(manager.archive(thread.id, tenantA)).resolves.toMatchObject({
197
+ status: 'archived',
198
+ })
199
+ })
200
+
201
+ it('does not leak cross-tenant sessions into the precondition', async () => {
202
+ // Shared stores across tenants (production shape). A session with
203
+ // the same threadId string under tenantB must not block archival
204
+ // of tenantA's thread.
205
+ const threadStore = new InMemoryThreadStore()
206
+ const sessionStore = new InMemorySessionStore()
207
+ const manager = new ThreadManager({ threadStore, sessionStore })
208
+
209
+ const pA = await sessionStore.createProject({ tenantId: tenantA, name: 'pa' }, tenantA)
210
+ const pB = await sessionStore.createProject({ tenantId: tenantB, name: 'pb' }, tenantB)
211
+ const tA = await threadStore.createThread({ projectId: pA.id, title: 'ta' }, tenantA)
212
+
213
+ // Cross-tenant session with the same threadId string as tA.
214
+ const bSession = await sessionStore.createSession(
215
+ { threadId: tA.id, projectId: pB.id, currentActor: userActor(tenantB) },
216
+ tenantB,
217
+ )
218
+ await sessionStore.updateSession({ ...bSession, status: 'active' }, tenantB)
219
+
220
+ await expect(manager.archive(tA.id, tenantA)).resolves.toMatchObject({
221
+ status: 'archived',
222
+ })
223
+ })
224
+ })
225
+
226
+ describe('delete', () => {
227
+ it('deletes an empty thread', async () => {
228
+ const { thread, manager, threadStore } = await harness()
229
+ await manager.delete(thread.id, tenantA)
230
+ expect(await threadStore.getThread(thread.id, tenantA)).toBeNull()
231
+ })
232
+
233
+ it('rejects with ThreadNotEmptyError when any session references the thread', async () => {
234
+ const { thread, project, manager, sessionStore } = await harness()
235
+ const session = await sessionStore.createSession(
236
+ {
237
+ threadId: thread.id,
238
+ projectId: project.id,
239
+ currentActor: userActor(tenantA),
240
+ },
241
+ tenantA,
242
+ )
243
+ // Idle — allowed under archive, still blocks delete.
244
+ await expect(manager.delete(thread.id, tenantA)).rejects.toMatchObject({
245
+ name: 'ThreadNotEmptyError',
246
+ details: {
247
+ threadId: thread.id,
248
+ tenantId: tenantA,
249
+ op: 'delete',
250
+ totalBlockingSessions: 1,
251
+ blockingSessions: [{ sessionId: session.id, status: 'idle' }],
252
+ },
253
+ })
254
+ })
255
+
256
+ it('detects orphaned sessions referencing a missing thread', async () => {
257
+ // Thread record is destroyed via the store directly, but a session
258
+ // still carries its threadId. Manager.delete must reject rather
259
+ // than silently succeed on the "thread is already gone" short-cut
260
+ // (the session scan runs unconditionally).
261
+ const { thread, project, manager, sessionStore, threadStore } = await harness()
262
+ const orphan = await sessionStore.createSession(
263
+ {
264
+ threadId: thread.id,
265
+ projectId: project.id,
266
+ currentActor: userActor(tenantA),
267
+ },
268
+ tenantA,
269
+ )
270
+ await threadStore.deleteThread(thread.id, tenantA)
271
+
272
+ await expect(manager.delete(thread.id, tenantA)).rejects.toMatchObject({
273
+ name: 'ThreadNotEmptyError',
274
+ details: {
275
+ op: 'delete',
276
+ blockingSessions: [{ sessionId: orphan.id, status: 'idle' }],
277
+ },
278
+ })
279
+ })
280
+
281
+ it('is idempotent for an absent thread with no orphans', async () => {
282
+ const { manager } = await harness()
283
+ await expect(manager.delete(MISSING_THREAD_ID, tenantA)).resolves.toBeUndefined()
284
+ })
285
+ })
286
+ })
@@ -0,0 +1,217 @@
1
+ /**
2
+ * ThreadManager — thin orchestrator over {@link ThreadStore} and
3
+ * {@link SessionStore}.
4
+ *
5
+ * Owns user-facing lifecycle operations on the Thread topic layer plus the
6
+ * archive-gate contract enforced at session-creation ingress sites.
7
+ *
8
+ * Phase 2.6 wired `ThreadManager.requireOpen` into three ingress paths:
9
+ * - {@link AgentManager.provisionSpawn} (child session creation)
10
+ * - `executeSingleHandoff` (recipient session creation)
11
+ * - `executeBroadcastHandoff` (N recipient sessions per fan-out)
12
+ * Those call sites depend on this manager, so the one-method indirection
13
+ * stopped being "structural overhead" the moment archive/delete needed the
14
+ * session-presence cross-check anyway.
15
+ *
16
+ * Archive + delete require cross-store preconditions (session-presence
17
+ * checks) — enforced here where both stores are in scope. The stores
18
+ * themselves stay unaware of each other's layout (Convention #0), which is
19
+ * why the gate lives at the manager layer rather than as a universal store
20
+ * interceptor (see `archive` JSDoc for the direct-store-bypass boundary).
21
+ */
22
+
23
+ import {
24
+ THREAD_NOT_EMPTY_SAMPLE_LIMIT,
25
+ ThreadClosedError,
26
+ ThreadNotEmptyError,
27
+ } from '../../session/errors.js'
28
+ import type { Session, SessionStatus } from '../../session/hierarchy/session.js'
29
+ import type { Thread } from '../../session/hierarchy/thread.js'
30
+ import type { TenantId } from '../../types/ids/index.js'
31
+ import type { ProjectId, ThreadId } from '../../types/session/ids.js'
32
+ import type { SessionStore } from '../../types/session/store.js'
33
+ import type { CreateThreadParams, ThreadStore } from '../../types/thread/store.js'
34
+
35
+ export interface ThreadManagerDeps {
36
+ readonly threadStore: ThreadStore
37
+ readonly sessionStore: SessionStore
38
+ }
39
+
40
+ /**
41
+ * Session statuses that block Thread archival. A session in any of these
42
+ * states has live work in-flight (mid-run, mid-handoff, blocked on human
43
+ * input, or orchestrating a broadcast merge) — freezing the Thread while any
44
+ * of them are active would strand resumable work.
45
+ *
46
+ * `idle`, `failed`, and `archived` are archival-compatible: they are
47
+ * quiescent or already-terminal, so a newly-frozen Thread can safely contain
48
+ * them. This list mirrors the `SessionStatus` discriminants that represent
49
+ * "not-yet-done" work (session-hierarchy.md §5.1).
50
+ */
51
+ const ARCHIVAL_BLOCKING_STATUSES: ReadonlySet<SessionStatus> = new Set([
52
+ 'active',
53
+ 'locked',
54
+ 'awaiting_hitl',
55
+ 'awaiting_merge',
56
+ ])
57
+
58
+ export class ThreadManager {
59
+ private readonly deps: ThreadManagerDeps
60
+
61
+ constructor(deps: ThreadManagerDeps) {
62
+ this.deps = deps
63
+ }
64
+
65
+ /** Persist a new Thread. Thin passthrough for uniformity at the manager surface. */
66
+ create(params: CreateThreadParams, tenantId: TenantId): Promise<Thread> {
67
+ return this.deps.threadStore.createThread(params, tenantId)
68
+ }
69
+
70
+ /** Read a Thread by id; returns `null` when absent for the tenant. */
71
+ get(threadId: ThreadId, tenantId: TenantId): Promise<Thread | null> {
72
+ return this.deps.threadStore.getThread(threadId, tenantId)
73
+ }
74
+
75
+ /**
76
+ * CAS update on a Thread. Propagates {@link import('../../session/errors.js').StaleThreadError}
77
+ * from the store on `ownerVersion` mismatch — callers re-read, re-apply,
78
+ * and retry.
79
+ */
80
+ update(thread: Thread, tenantId: TenantId): Promise<void> {
81
+ return this.deps.threadStore.updateThread(thread, tenantId)
82
+ }
83
+
84
+ /** List Threads under a Project, ordered by `createdAt` ascending. */
85
+ list(projectId: ProjectId, tenantId: TenantId): Promise<readonly Thread[]> {
86
+ return this.deps.threadStore.listThreads(projectId, tenantId)
87
+ }
88
+
89
+ /**
90
+ * Load a Thread and assert it is in `'open'` state. Used by the spawn path
91
+ * as a precondition — a SubSession cannot be created under an archived
92
+ * Thread. Throws on absence and on archival; returns the loaded Thread on
93
+ * success so callers can avoid the second round-trip.
94
+ *
95
+ * Convention #5: deny-by-default. A missing Thread is a hard error, not a
96
+ * silent "assume archived".
97
+ */
98
+ async requireOpen(threadId: ThreadId, tenantId: TenantId): Promise<Thread> {
99
+ const thread = await this.deps.threadStore.getThread(threadId, tenantId)
100
+ if (!thread) {
101
+ throw new Error(`Thread ${threadId} not found`)
102
+ }
103
+ if (thread.status === 'archived') {
104
+ throw new ThreadClosedError({ threadId, op: 'require-open' })
105
+ }
106
+ return thread
107
+ }
108
+
109
+ /**
110
+ * Flip a Thread to `'archived'` via CAS on {@link Thread.ownerVersion}.
111
+ *
112
+ * Preconditions (checked in order):
113
+ * 1. Thread exists for the tenant (throws on absence).
114
+ * 2. No attached Session is in a non-terminal state (see
115
+ * {@link ARCHIVAL_BLOCKING_STATUSES}). The presence check runs
116
+ * **before** the idempotent-archive short-circuit so that an already
117
+ * archived thread harboring a live session still surfaces as
118
+ * {@link ThreadNotEmptyError} rather than a silent success.
119
+ * 3. If the thread is already `'archived'` the method short-circuits
120
+ * without an `updateThread` write (idempotent re-archival). The
121
+ * returned record reflects the current persisted state.
122
+ *
123
+ * On a fresh archive transition the underlying
124
+ * {@link ThreadStore.updateThread} call commits with `ownerVersion + 1`.
125
+ * A {@link import('../../session/errors.js').StaleThreadError} from a
126
+ * concurrent writer propagates unchanged — the caller is expected to
127
+ * re-read + retry (mirrors the `updateThread` contract).
128
+ *
129
+ * Gate scope (Phase 2.6): `ThreadManager.requireOpen` is wired into
130
+ * `AgentManager.provisionSpawn` and both handoff flows, so the production
131
+ * ingress paths cannot attach new sessions under an archived thread.
132
+ * `SessionStore.createSession` / `updateSession` remain public and
133
+ * ungated at the store layer — a direct caller can still mutate a
134
+ * session after archival (the store has no `ThreadStore` handle by
135
+ * design; cross-store awareness lives in the manager). The defensive
136
+ * re-check above catches a smuggled live session on a subsequent
137
+ * archive call, but does not prevent the direct-store write from
138
+ * landing. That's an acceptable boundary — kernel callers must go
139
+ * through the ingress paths; direct store consumers are out of scope
140
+ * for the archive invariant.
141
+ */
142
+ async archive(threadId: ThreadId, tenantId: TenantId): Promise<Thread> {
143
+ const thread = await this.deps.threadStore.getThread(threadId, tenantId)
144
+ if (!thread) {
145
+ throw new Error(`Thread ${threadId} not found`)
146
+ }
147
+
148
+ // Always enforce the blocking-session invariant — even on re-archival.
149
+ // If the thread is already archived but somehow gained a live session
150
+ // (direct store mutation, concurrent spawn before a write-barrier
151
+ // existed), surfacing that via ThreadNotEmptyError is more useful to
152
+ // operators than a silent idempotent success.
153
+ const sessions = await this.deps.sessionStore.listSessions(threadId, tenantId)
154
+ const blocking = sessions.filter((s) => ARCHIVAL_BLOCKING_STATUSES.has(s.status))
155
+ if (blocking.length > 0) {
156
+ throw new ThreadNotEmptyError({
157
+ threadId,
158
+ tenantId,
159
+ op: 'archive',
160
+ blockingSessions: summarizeBlocking(blocking),
161
+ totalBlockingSessions: blocking.length,
162
+ })
163
+ }
164
+
165
+ if (thread.status === 'archived') {
166
+ // Idempotent: already archived, no live sessions attached. Skip the
167
+ // write (updateThread would still bump ownerVersion for no semantic
168
+ // change).
169
+ return thread
170
+ }
171
+
172
+ const next: Thread = { ...thread, status: 'archived' }
173
+ await this.deps.threadStore.updateThread(next, tenantId)
174
+ // updateThread advances ownerVersion + updatedAt; re-read so the returned
175
+ // record reflects the persisted state (callers rely on version monotonicity).
176
+ const reloaded = await this.deps.threadStore.getThread(threadId, tenantId)
177
+ if (!reloaded) {
178
+ throw new Error(`Thread ${threadId} vanished between archive and read-back`)
179
+ }
180
+ return reloaded
181
+ }
182
+
183
+ /**
184
+ * Hard-delete a Thread record. Rejects with {@link ThreadNotEmptyError}
185
+ * (`op: 'delete'`) when ANY Session still references the Thread —
186
+ * deletion is stricter than archival, which tolerates quiescent sessions.
187
+ * Callers must first delete or archive-and-tombstone every attached
188
+ * session (via {@link SessionStore.deleteSession}) before invoking.
189
+ *
190
+ * The session scan runs unconditionally, so orphaned sessions pointing at
191
+ * a missing thread are still detected and reject the delete. Idempotent
192
+ * for genuinely absent threads (no sessions, no thread record) — missing
193
+ * thread + empty session list is a no-op at the store layer. Convention
194
+ * #5: deny-by-default; no implicit cascade into SessionStore.
195
+ */
196
+ async delete(threadId: ThreadId, tenantId: TenantId): Promise<void> {
197
+ const sessions = await this.deps.sessionStore.listSessions(threadId, tenantId)
198
+ if (sessions.length > 0) {
199
+ throw new ThreadNotEmptyError({
200
+ threadId,
201
+ tenantId,
202
+ op: 'delete',
203
+ blockingSessions: summarizeBlocking(sessions),
204
+ totalBlockingSessions: sessions.length,
205
+ })
206
+ }
207
+ await this.deps.threadStore.deleteThread(threadId, tenantId)
208
+ }
209
+ }
210
+
211
+ function summarizeBlocking(
212
+ sessions: readonly Session[],
213
+ ): ReadonlyArray<{ sessionId: Session['id']; status: SessionStatus }> {
214
+ return sessions
215
+ .slice(0, THREAD_NOT_EMPTY_SAMPLE_LIMIT)
216
+ .map((s) => ({ sessionId: s.id, status: s.status }))
217
+ }
@@ -57,11 +57,11 @@ export class DefaultRetriever implements Retriever {
57
57
  }
58
58
 
59
59
  private expandQuery(query: RetrievalQuery): string {
60
- if (!query.threadMessages || query.threadMessages.length === 0) {
60
+ if (!query.recentMessages || query.recentMessages.length === 0) {
61
61
  return query.text
62
62
  }
63
63
 
64
- const recentContext = query.threadMessages.slice(-3).join(' ')
64
+ const recentContext = query.recentMessages.slice(-3).join(' ')
65
65
  return `${query.text}\n\nContext: ${recentContext}`
66
66
  }
67
67
 
@@ -194,6 +194,34 @@ export function createRunReporter(parentLogger?: Logger): RunReporter {
194
194
  })
195
195
  break
196
196
 
197
+ case 'subsession_spawned':
198
+ log.debug('Sub-session spawned', {
199
+ runId: event.runId,
200
+ subSessionId: event.subSessionId,
201
+ parentSessionId: event.parentSessionId,
202
+ depth: event.lineage.depth,
203
+ })
204
+ break
205
+
206
+ case 'subsession_messaged':
207
+ log.debug('Sub-session message', {
208
+ runId: event.runId,
209
+ subSessionId: event.subSessionId,
210
+ parentSessionId: event.parentSessionId,
211
+ messageId: event.messageId,
212
+ depth: event.lineage.depth,
213
+ })
214
+ break
215
+
216
+ case 'subsession_idled':
217
+ log.debug('Sub-session idled', {
218
+ runId: event.runId,
219
+ subSessionId: event.subSessionId,
220
+ parentSessionId: event.parentSessionId,
221
+ depth: event.lineage.depth,
222
+ })
223
+ break
224
+
197
225
  default: {
198
226
  const _exhaustive: never = event
199
227
  throw new Error(`Unhandled run event type: ${(_exhaustive as RunEvent).type}`)