@qjp88995/agent-runtime 0.0.0-stage → 0.1.1

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 (477) hide show
  1. package/dist/agent-extensions.d.ts +30 -0
  2. package/dist/agent-extensions.d.ts.map +1 -0
  3. package/dist/agent-extensions.js +4 -0
  4. package/dist/agent-extensions.js.map +1 -0
  5. package/dist/builtins/ask-outcome.d.ts +49 -0
  6. package/dist/builtins/ask-outcome.d.ts.map +1 -0
  7. package/dist/builtins/ask-outcome.js +128 -0
  8. package/dist/builtins/ask-outcome.js.map +1 -0
  9. package/dist/builtins/ask-schema.d.ts +110 -0
  10. package/dist/builtins/ask-schema.d.ts.map +1 -0
  11. package/dist/builtins/ask-schema.js +124 -0
  12. package/dist/builtins/ask-schema.js.map +1 -0
  13. package/dist/builtins/ask.service.d.ts +210 -0
  14. package/dist/builtins/ask.service.d.ts.map +1 -0
  15. package/dist/builtins/ask.service.js +373 -0
  16. package/dist/builtins/ask.service.js.map +1 -0
  17. package/dist/builtins/ask.tool.d.ts +49 -0
  18. package/dist/builtins/ask.tool.d.ts.map +1 -0
  19. package/dist/builtins/ask.tool.js +109 -0
  20. package/dist/builtins/ask.tool.js.map +1 -0
  21. package/dist/builtins/index.d.ts +8 -0
  22. package/dist/builtins/index.d.ts.map +1 -0
  23. package/dist/builtins/index.js +8 -0
  24. package/dist/builtins/index.js.map +1 -0
  25. package/dist/builtins/todo-schema.d.ts +90 -0
  26. package/dist/builtins/todo-schema.d.ts.map +1 -0
  27. package/dist/builtins/todo-schema.js +97 -0
  28. package/dist/builtins/todo-schema.js.map +1 -0
  29. package/dist/builtins/todo-settle.hook.d.ts +110 -0
  30. package/dist/builtins/todo-settle.hook.d.ts.map +1 -0
  31. package/dist/builtins/todo-settle.hook.js +174 -0
  32. package/dist/builtins/todo-settle.hook.js.map +1 -0
  33. package/dist/builtins/todo.tool.d.ts +59 -0
  34. package/dist/builtins/todo.tool.d.ts.map +1 -0
  35. package/dist/builtins/todo.tool.js +107 -0
  36. package/dist/builtins/todo.tool.js.map +1 -0
  37. package/dist/context/context-budget-tracker.d.ts +185 -0
  38. package/dist/context/context-budget-tracker.d.ts.map +1 -0
  39. package/dist/context/context-budget-tracker.js +400 -0
  40. package/dist/context/context-budget-tracker.js.map +1 -0
  41. package/dist/context/context-budget.d.ts +48 -0
  42. package/dist/context/context-budget.d.ts.map +1 -0
  43. package/dist/context/context-budget.js +89 -0
  44. package/dist/context/context-budget.js.map +1 -0
  45. package/dist/context/index.d.ts +3 -0
  46. package/dist/context/index.d.ts.map +1 -0
  47. package/dist/context/index.js +3 -0
  48. package/dist/context/index.js.map +1 -0
  49. package/dist/extensions/repeat-call.hook.d.ts +32 -0
  50. package/dist/extensions/repeat-call.hook.d.ts.map +1 -0
  51. package/dist/extensions/repeat-call.hook.js +54 -0
  52. package/dist/extensions/repeat-call.hook.js.map +1 -0
  53. package/dist/hooks/index.d.ts +3 -0
  54. package/dist/hooks/index.d.ts.map +1 -0
  55. package/dist/hooks/index.js +3 -0
  56. package/dist/hooks/index.js.map +1 -0
  57. package/dist/hooks/turn-hook.registry.d.ts +51 -0
  58. package/dist/hooks/turn-hook.registry.d.ts.map +1 -0
  59. package/dist/hooks/turn-hook.registry.js +233 -0
  60. package/dist/hooks/turn-hook.registry.js.map +1 -0
  61. package/dist/hooks/turn-hook.types.d.ts +179 -0
  62. package/dist/hooks/turn-hook.types.d.ts.map +1 -0
  63. package/dist/hooks/turn-hook.types.js +48 -0
  64. package/dist/hooks/turn-hook.types.js.map +1 -0
  65. package/dist/images/byte-cache.d.ts +24 -0
  66. package/dist/images/byte-cache.d.ts.map +1 -0
  67. package/dist/images/byte-cache.js +51 -0
  68. package/dist/images/byte-cache.js.map +1 -0
  69. package/dist/images/delivery.d.ts +115 -0
  70. package/dist/images/delivery.d.ts.map +1 -0
  71. package/dist/images/delivery.js +321 -0
  72. package/dist/images/delivery.js.map +1 -0
  73. package/dist/images/index.d.ts +5 -0
  74. package/dist/images/index.d.ts.map +1 -0
  75. package/dist/images/index.js +5 -0
  76. package/dist/images/index.js.map +1 -0
  77. package/dist/images/prompt.d.ts +151 -0
  78. package/dist/images/prompt.d.ts.map +1 -0
  79. package/dist/images/prompt.js +172 -0
  80. package/dist/images/prompt.js.map +1 -0
  81. package/dist/images/vendor-files.d.ts +93 -0
  82. package/dist/images/vendor-files.d.ts.map +1 -0
  83. package/dist/images/vendor-files.js +156 -0
  84. package/dist/images/vendor-files.js.map +1 -0
  85. package/dist/in-process/conversation-store.d.ts +64 -0
  86. package/dist/in-process/conversation-store.d.ts.map +1 -0
  87. package/dist/in-process/conversation-store.js +222 -0
  88. package/dist/in-process/conversation-store.js.map +1 -0
  89. package/dist/in-process/coordination.d.ts +54 -0
  90. package/dist/in-process/coordination.d.ts.map +1 -0
  91. package/dist/in-process/coordination.js +137 -0
  92. package/dist/in-process/coordination.js.map +1 -0
  93. package/dist/in-process/image-source.d.ts +15 -0
  94. package/dist/in-process/image-source.d.ts.map +1 -0
  95. package/dist/in-process/image-source.js +27 -0
  96. package/dist/in-process/image-source.js.map +1 -0
  97. package/dist/in-process/index.d.ts +36 -0
  98. package/dist/in-process/index.d.ts.map +1 -0
  99. package/dist/in-process/index.js +37 -0
  100. package/dist/in-process/index.js.map +1 -0
  101. package/dist/in-process/question-store.d.ts +28 -0
  102. package/dist/in-process/question-store.d.ts.map +1 -0
  103. package/dist/in-process/question-store.js +122 -0
  104. package/dist/in-process/question-store.js.map +1 -0
  105. package/dist/in-process/run-store.d.ts +36 -0
  106. package/dist/in-process/run-store.d.ts.map +1 -0
  107. package/dist/in-process/run-store.js +81 -0
  108. package/dist/in-process/run-store.js.map +1 -0
  109. package/dist/in-process/session-store.d.ts +33 -0
  110. package/dist/in-process/session-store.d.ts.map +1 -0
  111. package/dist/in-process/session-store.js +93 -0
  112. package/dist/in-process/session-store.js.map +1 -0
  113. package/dist/in-process/stream-bus.d.ts +52 -0
  114. package/dist/in-process/stream-bus.d.ts.map +1 -0
  115. package/dist/in-process/stream-bus.js +200 -0
  116. package/dist/in-process/stream-bus.js.map +1 -0
  117. package/dist/in-process/vendor-file-cache.d.ts +11 -0
  118. package/dist/in-process/vendor-file-cache.d.ts.map +1 -0
  119. package/dist/in-process/vendor-file-cache.js +47 -0
  120. package/dist/in-process/vendor-file-cache.js.map +1 -0
  121. package/dist/index.d.ts +21 -0
  122. package/dist/index.d.ts.map +1 -0
  123. package/dist/index.js +21 -0
  124. package/dist/index.js.map +1 -0
  125. package/dist/loop/active-tick.registry.d.ts +31 -0
  126. package/dist/loop/active-tick.registry.d.ts.map +1 -0
  127. package/dist/loop/active-tick.registry.js +45 -0
  128. package/dist/loop/active-tick.registry.js.map +1 -0
  129. package/dist/loop/index.d.ts +6 -0
  130. package/dist/loop/index.d.ts.map +1 -0
  131. package/dist/loop/index.js +6 -0
  132. package/dist/loop/index.js.map +1 -0
  133. package/dist/loop/loop-driver.d.ts +127 -0
  134. package/dist/loop/loop-driver.d.ts.map +1 -0
  135. package/dist/loop/loop-driver.js +199 -0
  136. package/dist/loop/loop-driver.js.map +1 -0
  137. package/dist/loop/message-hub.d.ts +236 -0
  138. package/dist/loop/message-hub.d.ts.map +1 -0
  139. package/dist/loop/message-hub.js +439 -0
  140. package/dist/loop/message-hub.js.map +1 -0
  141. package/dist/loop/orphan-run.sweeper.d.ts +79 -0
  142. package/dist/loop/orphan-run.sweeper.d.ts.map +1 -0
  143. package/dist/loop/orphan-run.sweeper.js +145 -0
  144. package/dist/loop/orphan-run.sweeper.js.map +1 -0
  145. package/dist/loop/root-host.d.ts +51 -0
  146. package/dist/loop/root-host.d.ts.map +1 -0
  147. package/dist/loop/root-host.js +65 -0
  148. package/dist/loop/root-host.js.map +1 -0
  149. package/dist/ports/context-store.d.ts +69 -0
  150. package/dist/ports/context-store.d.ts.map +1 -0
  151. package/dist/ports/context-store.js +2 -0
  152. package/dist/ports/context-store.js.map +1 -0
  153. package/dist/ports/conversation-store.d.ts +144 -0
  154. package/dist/ports/conversation-store.d.ts.map +1 -0
  155. package/dist/ports/conversation-store.js +2 -0
  156. package/dist/ports/conversation-store.js.map +1 -0
  157. package/dist/ports/coordination.d.ts +76 -0
  158. package/dist/ports/coordination.d.ts.map +1 -0
  159. package/dist/ports/coordination.js +12 -0
  160. package/dist/ports/coordination.js.map +1 -0
  161. package/dist/ports/image-source.d.ts +26 -0
  162. package/dist/ports/image-source.d.ts.map +1 -0
  163. package/dist/ports/image-source.js +2 -0
  164. package/dist/ports/image-source.js.map +1 -0
  165. package/dist/ports/index.d.ts +11 -0
  166. package/dist/ports/index.d.ts.map +1 -0
  167. package/dist/ports/index.js +4 -0
  168. package/dist/ports/index.js.map +1 -0
  169. package/dist/ports/logger.d.ts +14 -0
  170. package/dist/ports/logger.d.ts.map +1 -0
  171. package/dist/ports/logger.js +23 -0
  172. package/dist/ports/logger.js.map +1 -0
  173. package/dist/ports/question-store.d.ts +91 -0
  174. package/dist/ports/question-store.d.ts.map +1 -0
  175. package/dist/ports/question-store.js +8 -0
  176. package/dist/ports/question-store.js.map +1 -0
  177. package/dist/ports/run-store.d.ts +66 -0
  178. package/dist/ports/run-store.d.ts.map +1 -0
  179. package/dist/ports/run-store.js +2 -0
  180. package/dist/ports/run-store.js.map +1 -0
  181. package/dist/ports/session-store.d.ts +72 -0
  182. package/dist/ports/session-store.d.ts.map +1 -0
  183. package/dist/ports/session-store.js +9 -0
  184. package/dist/ports/session-store.js.map +1 -0
  185. package/dist/ports/stream-bus.d.ts +52 -0
  186. package/dist/ports/stream-bus.d.ts.map +1 -0
  187. package/dist/ports/stream-bus.js +2 -0
  188. package/dist/ports/stream-bus.js.map +1 -0
  189. package/dist/ports/vendor-file-cache.d.ts +46 -0
  190. package/dist/ports/vendor-file-cache.d.ts.map +1 -0
  191. package/dist/ports/vendor-file-cache.js +2 -0
  192. package/dist/ports/vendor-file-cache.js.map +1 -0
  193. package/dist/schema/agent-event.d.ts +35 -0
  194. package/dist/schema/agent-event.d.ts.map +1 -0
  195. package/dist/schema/agent-event.js +46 -0
  196. package/dist/schema/agent-event.js.map +1 -0
  197. package/dist/schema/agent-run.d.ts +23 -0
  198. package/dist/schema/agent-run.d.ts.map +1 -0
  199. package/dist/schema/agent-run.js +37 -0
  200. package/dist/schema/agent-run.js.map +1 -0
  201. package/dist/schema/index.d.ts +4 -0
  202. package/dist/schema/index.d.ts.map +1 -0
  203. package/dist/schema/index.js +4 -0
  204. package/dist/schema/index.js.map +1 -0
  205. package/dist/schema/message-part.d.ts +73 -0
  206. package/dist/schema/message-part.d.ts.map +1 -0
  207. package/dist/schema/message-part.js +90 -0
  208. package/dist/schema/message-part.js.map +1 -0
  209. package/dist/subagent/delegate.tool.d.ts +145 -0
  210. package/dist/subagent/delegate.tool.d.ts.map +1 -0
  211. package/dist/subagent/delegate.tool.js +329 -0
  212. package/dist/subagent/delegate.tool.js.map +1 -0
  213. package/dist/subagent/index.d.ts +10 -0
  214. package/dist/subagent/index.d.ts.map +1 -0
  215. package/dist/subagent/index.js +10 -0
  216. package/dist/subagent/index.js.map +1 -0
  217. package/dist/subagent/milestone-body.d.ts +82 -0
  218. package/dist/subagent/milestone-body.d.ts.map +1 -0
  219. package/dist/subagent/milestone-body.js +112 -0
  220. package/dist/subagent/milestone-body.js.map +1 -0
  221. package/dist/subagent/output-scan.d.ts +14 -0
  222. package/dist/subagent/output-scan.d.ts.map +1 -0
  223. package/dist/subagent/output-scan.js +41 -0
  224. package/dist/subagent/output-scan.js.map +1 -0
  225. package/dist/subagent/registry-spawn-policy.d.ts +32 -0
  226. package/dist/subagent/registry-spawn-policy.d.ts.map +1 -0
  227. package/dist/subagent/registry-spawn-policy.js +48 -0
  228. package/dist/subagent/registry-spawn-policy.js.map +1 -0
  229. package/dist/subagent/roster-block.d.ts +45 -0
  230. package/dist/subagent/roster-block.d.ts.map +1 -0
  231. package/dist/subagent/roster-block.js +69 -0
  232. package/dist/subagent/roster-block.js.map +1 -0
  233. package/dist/subagent/situation-block.d.ts +16 -0
  234. package/dist/subagent/situation-block.d.ts.map +1 -0
  235. package/dist/subagent/situation-block.js +71 -0
  236. package/dist/subagent/situation-block.js.map +1 -0
  237. package/dist/subagent/spawn-guards.d.ts +32 -0
  238. package/dist/subagent/spawn-guards.d.ts.map +1 -0
  239. package/dist/subagent/spawn-guards.js +39 -0
  240. package/dist/subagent/spawn-guards.js.map +1 -0
  241. package/dist/subagent/subagent-registry.d.ts +150 -0
  242. package/dist/subagent/subagent-registry.d.ts.map +1 -0
  243. package/dist/subagent/subagent-registry.js +167 -0
  244. package/dist/subagent/subagent-registry.js.map +1 -0
  245. package/dist/subagent/subagent-sessions.d.ts +213 -0
  246. package/dist/subagent/subagent-sessions.d.ts.map +1 -0
  247. package/dist/subagent/subagent-sessions.js +295 -0
  248. package/dist/subagent/subagent-sessions.js.map +1 -0
  249. package/dist/testing/contracts.d.ts +37 -0
  250. package/dist/testing/contracts.d.ts.map +1 -0
  251. package/dist/testing/contracts.js +607 -0
  252. package/dist/testing/contracts.js.map +1 -0
  253. package/dist/testing/index.d.ts +5 -0
  254. package/dist/testing/index.d.ts.map +1 -0
  255. package/dist/testing/index.js +5 -0
  256. package/dist/testing/index.js.map +1 -0
  257. package/dist/testing/stub.d.ts +28 -0
  258. package/dist/testing/stub.d.ts.map +1 -0
  259. package/dist/testing/stub.js +3 -0
  260. package/dist/testing/stub.js.map +1 -0
  261. package/dist/tools/agent-tool.base.d.ts +186 -0
  262. package/dist/tools/agent-tool.base.d.ts.map +1 -0
  263. package/dist/tools/agent-tool.base.js +243 -0
  264. package/dist/tools/agent-tool.base.js.map +1 -0
  265. package/dist/tools/agent-tool.interface.d.ts +95 -0
  266. package/dist/tools/agent-tool.interface.d.ts.map +1 -0
  267. package/dist/tools/agent-tool.interface.js +2 -0
  268. package/dist/tools/agent-tool.interface.js.map +1 -0
  269. package/dist/tools/builtin-names.d.ts +18 -0
  270. package/dist/tools/builtin-names.d.ts.map +1 -0
  271. package/dist/tools/builtin-names.js +20 -0
  272. package/dist/tools/builtin-names.js.map +1 -0
  273. package/dist/tools/index.d.ts +9 -0
  274. package/dist/tools/index.d.ts.map +1 -0
  275. package/dist/tools/index.js +6 -0
  276. package/dist/tools/index.js.map +1 -0
  277. package/dist/tools/tool-definition.d.ts +18 -0
  278. package/dist/tools/tool-definition.d.ts.map +1 -0
  279. package/dist/tools/tool-definition.js +77 -0
  280. package/dist/tools/tool-definition.js.map +1 -0
  281. package/dist/tools/tool-meta.d.ts +55 -0
  282. package/dist/tools/tool-meta.d.ts.map +1 -0
  283. package/dist/tools/tool-meta.js +2 -0
  284. package/dist/tools/tool-meta.js.map +1 -0
  285. package/dist/tools/tool-registry.d.ts +190 -0
  286. package/dist/tools/tool-registry.d.ts.map +1 -0
  287. package/dist/tools/tool-registry.js +379 -0
  288. package/dist/tools/tool-registry.js.map +1 -0
  289. package/dist/tools/tool-result.d.ts +41 -0
  290. package/dist/tools/tool-result.d.ts.map +1 -0
  291. package/dist/tools/tool-result.js +19 -0
  292. package/dist/tools/tool-result.js.map +1 -0
  293. package/dist/tools/tool-wire.d.ts +24 -0
  294. package/dist/tools/tool-wire.d.ts.map +1 -0
  295. package/dist/tools/tool-wire.js +2 -0
  296. package/dist/tools/tool-wire.js.map +1 -0
  297. package/dist/turn/agent-runtime.d.ts +31 -0
  298. package/dist/turn/agent-runtime.d.ts.map +1 -0
  299. package/dist/turn/agent-runtime.js +30 -0
  300. package/dist/turn/agent-runtime.js.map +1 -0
  301. package/dist/turn/chunk-projection.d.ts +32 -0
  302. package/dist/turn/chunk-projection.d.ts.map +1 -0
  303. package/dist/turn/chunk-projection.js +62 -0
  304. package/dist/turn/chunk-projection.js.map +1 -0
  305. package/dist/turn/compaction.d.ts +48 -0
  306. package/dist/turn/compaction.d.ts.map +1 -0
  307. package/dist/turn/compaction.js +89 -0
  308. package/dist/turn/compaction.js.map +1 -0
  309. package/dist/turn/context-overflow.d.ts +11 -0
  310. package/dist/turn/context-overflow.d.ts.map +1 -0
  311. package/dist/turn/context-overflow.js +53 -0
  312. package/dist/turn/context-overflow.js.map +1 -0
  313. package/dist/turn/context-pressure.d.ts +100 -0
  314. package/dist/turn/context-pressure.d.ts.map +1 -0
  315. package/dist/turn/context-pressure.js +21 -0
  316. package/dist/turn/context-pressure.js.map +1 -0
  317. package/dist/turn/events-to-steps.d.ts +8 -0
  318. package/dist/turn/events-to-steps.d.ts.map +1 -0
  319. package/dist/turn/events-to-steps.js +64 -0
  320. package/dist/turn/events-to-steps.js.map +1 -0
  321. package/dist/turn/index.d.ts +17 -0
  322. package/dist/turn/index.d.ts.map +1 -0
  323. package/dist/turn/index.js +16 -0
  324. package/dist/turn/index.js.map +1 -0
  325. package/dist/turn/json-preview.d.ts +22 -0
  326. package/dist/turn/json-preview.d.ts.map +1 -0
  327. package/dist/turn/json-preview.js +34 -0
  328. package/dist/turn/json-preview.js.map +1 -0
  329. package/dist/turn/json-string-field.d.ts +30 -0
  330. package/dist/turn/json-string-field.d.ts.map +1 -0
  331. package/dist/turn/json-string-field.js +125 -0
  332. package/dist/turn/json-string-field.js.map +1 -0
  333. package/dist/turn/loop-reminder.d.ts +79 -0
  334. package/dist/turn/loop-reminder.d.ts.map +1 -0
  335. package/dist/turn/loop-reminder.js +0 -0
  336. package/dist/turn/loop-reminder.js.map +1 -0
  337. package/dist/turn/nul-safe.d.ts +21 -0
  338. package/dist/turn/nul-safe.d.ts.map +1 -0
  339. package/dist/turn/nul-safe.js +23 -0
  340. package/dist/turn/nul-safe.js.map +1 -0
  341. package/dist/turn/parts-from-events.d.ts +71 -0
  342. package/dist/turn/parts-from-events.d.ts.map +1 -0
  343. package/dist/turn/parts-from-events.js +217 -0
  344. package/dist/turn/parts-from-events.js.map +1 -0
  345. package/dist/turn/parts-to-model-messages.d.ts +158 -0
  346. package/dist/turn/parts-to-model-messages.d.ts.map +1 -0
  347. package/dist/turn/parts-to-model-messages.js +334 -0
  348. package/dist/turn/parts-to-model-messages.js.map +1 -0
  349. package/dist/turn/pending-work.d.ts +10 -0
  350. package/dist/turn/pending-work.d.ts.map +1 -0
  351. package/dist/turn/pending-work.js +14 -0
  352. package/dist/turn/pending-work.js.map +1 -0
  353. package/dist/turn/provider-error.d.ts +45 -0
  354. package/dist/turn/provider-error.d.ts.map +1 -0
  355. package/dist/turn/provider-error.js +154 -0
  356. package/dist/turn/provider-error.js.map +1 -0
  357. package/dist/turn/tool-input-preview.d.ts +94 -0
  358. package/dist/turn/tool-input-preview.d.ts.map +1 -0
  359. package/dist/turn/tool-input-preview.js +143 -0
  360. package/dist/turn/tool-input-preview.js.map +1 -0
  361. package/dist/turn/tool-input-progress.d.ts +47 -0
  362. package/dist/turn/tool-input-progress.d.ts.map +1 -0
  363. package/dist/turn/tool-input-progress.js +50 -0
  364. package/dist/turn/tool-input-progress.js.map +1 -0
  365. package/dist/turn/turn-envelope.d.ts +184 -0
  366. package/dist/turn/turn-envelope.d.ts.map +1 -0
  367. package/dist/turn/turn-envelope.js +2 -0
  368. package/dist/turn/turn-envelope.js.map +1 -0
  369. package/dist/turn/turn-journal.d.ts +49 -0
  370. package/dist/turn/turn-journal.d.ts.map +1 -0
  371. package/dist/turn/turn-journal.js +51 -0
  372. package/dist/turn/turn-journal.js.map +1 -0
  373. package/dist/turn/turn-run.d.ts +487 -0
  374. package/dist/turn/turn-run.d.ts.map +1 -0
  375. package/dist/turn/turn-run.js +1167 -0
  376. package/dist/turn/turn-run.js.map +1 -0
  377. package/dist/turn/usage.d.ts +27 -0
  378. package/dist/turn/usage.d.ts.map +1 -0
  379. package/dist/turn/usage.js +51 -0
  380. package/dist/turn/usage.js.map +1 -0
  381. package/package.json +59 -3
  382. package/src/agent-extensions.ts +33 -0
  383. package/src/builtins/ask-outcome.ts +168 -0
  384. package/src/builtins/ask-schema.ts +186 -0
  385. package/src/builtins/ask.service.ts +482 -0
  386. package/src/builtins/ask.tool.ts +138 -0
  387. package/src/builtins/index.ts +25 -0
  388. package/src/builtins/todo-schema.ts +108 -0
  389. package/src/builtins/todo-settle.hook.ts +221 -0
  390. package/src/builtins/todo.tool.ts +134 -0
  391. package/src/context/context-budget-tracker.ts +519 -0
  392. package/src/context/context-budget.ts +124 -0
  393. package/src/context/index.ts +17 -0
  394. package/src/extensions/repeat-call.hook.ts +77 -0
  395. package/src/hooks/index.ts +19 -0
  396. package/src/hooks/turn-hook.registry.ts +307 -0
  397. package/src/hooks/turn-hook.types.ts +210 -0
  398. package/src/images/byte-cache.ts +61 -0
  399. package/src/images/delivery.ts +508 -0
  400. package/src/images/index.ts +35 -0
  401. package/src/images/prompt.ts +289 -0
  402. package/src/images/vendor-files.ts +235 -0
  403. package/src/in-process/conversation-store.ts +304 -0
  404. package/src/in-process/coordination.ts +177 -0
  405. package/src/in-process/image-source.ts +29 -0
  406. package/src/in-process/index.ts +52 -0
  407. package/src/in-process/question-store.ts +155 -0
  408. package/src/in-process/run-store.ts +115 -0
  409. package/src/in-process/session-store.ts +118 -0
  410. package/src/in-process/stream-bus.ts +244 -0
  411. package/src/in-process/vendor-file-cache.ts +67 -0
  412. package/src/index.ts +28 -0
  413. package/src/loop/active-tick.registry.ts +49 -0
  414. package/src/loop/index.ts +25 -0
  415. package/src/loop/loop-driver.ts +275 -0
  416. package/src/loop/message-hub.ts +532 -0
  417. package/src/loop/orphan-run.sweeper.ts +204 -0
  418. package/src/loop/root-host.ts +119 -0
  419. package/src/ports/context-store.ts +71 -0
  420. package/src/ports/conversation-store.ts +165 -0
  421. package/src/ports/coordination.ts +81 -0
  422. package/src/ports/image-source.ts +26 -0
  423. package/src/ports/index.ts +56 -0
  424. package/src/ports/logger.ts +34 -0
  425. package/src/ports/question-store.ts +117 -0
  426. package/src/ports/run-store.ts +69 -0
  427. package/src/ports/session-store.ts +80 -0
  428. package/src/ports/stream-bus.ts +59 -0
  429. package/src/ports/vendor-file-cache.ts +54 -0
  430. package/src/schema/agent-event.ts +69 -0
  431. package/src/schema/agent-run.ts +44 -0
  432. package/src/schema/index.ts +25 -0
  433. package/src/schema/message-part.ts +100 -0
  434. package/src/subagent/delegate.tool.ts +476 -0
  435. package/src/subagent/index.ts +63 -0
  436. package/src/subagent/milestone-body.ts +144 -0
  437. package/src/subagent/output-scan.ts +56 -0
  438. package/src/subagent/registry-spawn-policy.ts +85 -0
  439. package/src/subagent/roster-block.ts +103 -0
  440. package/src/subagent/situation-block.ts +83 -0
  441. package/src/subagent/spawn-guards.ts +54 -0
  442. package/src/subagent/subagent-registry.ts +283 -0
  443. package/src/subagent/subagent-sessions.ts +496 -0
  444. package/src/testing/contracts.ts +882 -0
  445. package/src/testing/index.ts +14 -0
  446. package/src/testing/stub.ts +28 -0
  447. package/src/tools/agent-tool.base.ts +361 -0
  448. package/src/tools/agent-tool.interface.ts +101 -0
  449. package/src/tools/builtin-names.ts +26 -0
  450. package/src/tools/index.ts +39 -0
  451. package/src/tools/tool-definition.ts +93 -0
  452. package/src/tools/tool-meta.ts +60 -0
  453. package/src/tools/tool-registry.ts +513 -0
  454. package/src/tools/tool-result.ts +45 -0
  455. package/src/tools/tool-wire.ts +24 -0
  456. package/src/turn/agent-runtime.ts +43 -0
  457. package/src/turn/chunk-projection.ts +81 -0
  458. package/src/turn/compaction.ts +103 -0
  459. package/src/turn/context-overflow.ts +54 -0
  460. package/src/turn/context-pressure.ts +114 -0
  461. package/src/turn/events-to-steps.ts +73 -0
  462. package/src/turn/index.ts +71 -0
  463. package/src/turn/json-preview.ts +36 -0
  464. package/src/turn/json-string-field.ts +134 -0
  465. package/src/turn/loop-reminder.ts +0 -0
  466. package/src/turn/nul-safe.ts +22 -0
  467. package/src/turn/parts-from-events.ts +248 -0
  468. package/src/turn/parts-to-model-messages.ts +428 -0
  469. package/src/turn/pending-work.ts +14 -0
  470. package/src/turn/provider-error.ts +160 -0
  471. package/src/turn/tool-input-preview.ts +223 -0
  472. package/src/turn/tool-input-progress.ts +76 -0
  473. package/src/turn/turn-envelope.ts +185 -0
  474. package/src/turn/turn-journal.ts +102 -0
  475. package/src/turn/turn-run.ts +1479 -0
  476. package/src/turn/usage.ts +56 -0
  477. package/README.md +0 -3
@@ -0,0 +1,496 @@
1
+ import type { MessageHub } from '../loop/message-hub.js';
2
+ import type {
3
+ SubagentAwaitLease,
4
+ TreeBudget,
5
+ WakeChannel,
6
+ } from '../ports/coordination.js';
7
+ import {
8
+ type Logger,
9
+ type LoggerFactory,
10
+ silentLogger,
11
+ } from '../ports/logger.js';
12
+ import type { RunStore } from '../ports/run-store.js';
13
+ import type { SessionRecord, SessionStore } from '../ports/session-store.js';
14
+ import type { MessagePart } from '../schema/index.js';
15
+ import type { ToolAgentContext } from '../tools/agent-tool.interface.js';
16
+ import { DELEGATE_TOOL_NAME } from '../tools/builtin-names.js';
17
+ import {
18
+ buildMilestoneBody,
19
+ isFailedTerminal,
20
+ normalizeMilestoneStatus,
21
+ } from './milestone-body.js';
22
+ import { scanSubagentOutput } from './output-scan.js';
23
+ import { MAX_LIVE_SUBS_PER_TREE } from './spawn-guards.js';
24
+
25
+ /** 兜底扫描的缺省「空闲多久才算嫌疑」。 */
26
+ export const SUBAGENT_SWEEP_IDLE_MS = 60_000;
27
+
28
+ /** 派一个新的子 Agent 的请求(`Delegate` 从 `ToolContext` 拼出来)。 */
29
+ export interface SpawnRequest {
30
+ agentName: string;
31
+ /** 一句话任务标题(模型显式给,界面展示)。 */
32
+ title: string;
33
+ prompt: string;
34
+ /** 派它的会话(父)。 */
35
+ parentSessionId: string;
36
+ rootSessionId: string;
37
+ /** 父这一轮的跑次 id——子会话的 `parentRunId`,父会话经它找到。 */
38
+ parentRunId: string;
39
+ /** 父这一轮的深度。 */
40
+ depth: number;
41
+ userId: string | null;
42
+ /** 父这一轮跑的 agent(宿主的扩展字段:跑哪个、哪一版……)与模型能力。 */
43
+ agent: ToolAgentContext;
44
+ /** 父会话的附加信息;缺省照抄给子会话。 */
45
+ sessionMetadata: Readonly<Record<string, unknown>>;
46
+ /** 发起人此刻的权限点。缺省空(fail-closed)。 */
47
+ initiatorPermissions: ReadonlySet<string>;
48
+ }
49
+
50
+ /**
51
+ * 派不派得出(宿主回答)。
52
+ *
53
+ * - `unknown`:没有这个子 Agent(或此刻不可用)。`Delegate` 的报错让模型去核对花名册。
54
+ * - `refused`:有,但这一次不行——`message` 原样给模型,要说清「谁、为什么」不够格,
55
+ * 否则模型会换个名字再试(agent-base:权限点不够、「你自己就能看图,别派识图员」)。
56
+ * - `ok`:可以。`attrs` / `metadata` 写进子会话行(缺省:attrs 空、metadata 照抄父的)。
57
+ */
58
+ export type SpawnCheck =
59
+ | {
60
+ ok: true;
61
+ attrs?: Readonly<Record<string, unknown>>;
62
+ metadata?: Readonly<Record<string, unknown>>;
63
+ }
64
+ | { ok: false; reason: 'unknown' }
65
+ | { ok: false; reason: 'refused'; message: string };
66
+
67
+ /**
68
+ * 宿主的派生策略。花名册与这里**必须是同一个判据**(花名册不列只是不广告,模型凭名字
69
+ * 照样派得动)——用 `SubagentRegistry` 的话,`registrySpawnPolicy` 就是现成的一份。
70
+ */
71
+ export interface SpawnPolicy {
72
+ checkSpawn(req: SpawnRequest): Promise<SpawnCheck>;
73
+ /**
74
+ * 子会话建好、任务投递**之前**:宿主为子会话定下它要用的东西(agent-base 分身:
75
+ * 派活快照)。子会话此刻还没有任务、不会被唤醒,第一轮就能读到。抛错 = 这次派生
76
+ * 失败(名额归还,错误上抛)。
77
+ *
78
+ * `notes` 拼在回执最前面(「技能《×××》已停用,未带」);**为空就别给**,回执逐字不变。
79
+ */
80
+ onSubagentCreated?(
81
+ req: SpawnRequest & { childSessionId: string }
82
+ ): Promise<{ notes?: string[] }>;
83
+ }
84
+
85
+ export type SpawnOutcome =
86
+ | { ok: true; childSessionId: string; notes?: string[] }
87
+ | { ok: false; reason: 'unknown' | 'tree_full' }
88
+ | { ok: false; reason: 'refused'; message: string };
89
+
90
+ /**
91
+ * 追加任务的目标校验结果。`cursorBefore` 是发起追加**之前**的里程碑游标:同步等待据它
92
+ * 判「这一轮跑完了没有」,取产出也只取它之后的。首次 idle 之前追加时为 null,语义退化
93
+ * 成「等首次 settle」。
94
+ */
95
+ export type FollowUpTarget =
96
+ | { ok: true; cursorBefore: number | null }
97
+ | { ok: false; reason: 'not_found' | 'not_own_child' };
98
+
99
+ /** 子会话一轮的回执(同步返回与回投 inbox 同源)。 */
100
+ export interface SubagentResult {
101
+ body: string;
102
+ status: string;
103
+ /** 只有失败才带(正常收尾的 `stop` 写进「原因」是误导)。 */
104
+ stopReason: string | null;
105
+ }
106
+
107
+ /** loop 设置一个 tick 时要的子会话信息。 */
108
+ export interface SubagentTickInfo {
109
+ kind: SessionRecord['kind'];
110
+ /** 子会话 = 父跑次深度 + 1;根会话 0。 */
111
+ depth: number;
112
+ parentRunId: string | null;
113
+ /** 子 Agent 名(钉在会话上的那个,可能是旧名);根会话 null。 */
114
+ agentName: string | null;
115
+ title: string | null;
116
+ }
117
+
118
+ export interface SubagentSessionsDeps {
119
+ sessions: SessionStore;
120
+ /** 消息中心:投递(`post`)与读消息(`store`)。 */
121
+ hub: MessageHub;
122
+ wake: WakeChannel;
123
+ runs: RunStore;
124
+ awaitLease: SubagentAwaitLease;
125
+ treeBudget: TreeBudget;
126
+ policy: SpawnPolicy;
127
+ /** 每棵树同时存活的子 Agent 上限,缺省 `MAX_LIVE_SUBS_PER_TREE`。 */
128
+ maxLivePerTree?: number;
129
+ /** 兜底扫描的空闲门槛,缺省 `SUBAGENT_SWEEP_IDLE_MS`。 */
130
+ sweepIdleMs?: number;
131
+ logger?: LoggerFactory;
132
+ }
133
+
134
+ /**
135
+ * 子会话的生命周期:派生(受理段,**不 await 子跑完**)、追加任务、取回执、收尾回投、
136
+ * 兜底扫描。搬自 agent-base `SubagentSessionService`,会话行走 `SessionStore`、消息走
137
+ * `MessageHub`,派生判据交给宿主的 `SpawnPolicy`。
138
+ *
139
+ * 子会话此后由 loop 独立驱动(inbox + 唤醒),**同步与异步是同一条实现**:子会话都是
140
+ * 独立持久跑的,区别只在父等不等它(`Delegate`)。
141
+ *
142
+ * 宿主要接两处:`LoopHost.afterTick` 里调 `finalizeIfIdle`,启动时调一次 `sweepStale`。
143
+ */
144
+ export class SubagentSessions {
145
+ private readonly logger: Logger;
146
+ readonly maxLivePerTree: number;
147
+
148
+ constructor(private readonly deps: SubagentSessionsDeps) {
149
+ this.logger = (deps.logger ?? silentLogger)('SubagentSessions');
150
+ this.maxLivePerTree = deps.maxLivePerTree ?? MAX_LIVE_SUBS_PER_TREE;
151
+ }
152
+
153
+ /** 新建:问宿主 → 占名额 → 建会话 → 宿主补料 → 投任务 → 唤醒,即返 handle。 */
154
+ async spawn(req: SpawnRequest): Promise<SpawnOutcome> {
155
+ const check = await this.deps.policy.checkSpawn(req);
156
+ if (!check.ok) return check;
157
+
158
+ // 先占名额,占不到不建会话(避免建了又要回滚)。
159
+ const took = await this.deps.treeBudget.tryIncr(
160
+ req.rootSessionId,
161
+ this.maxLivePerTree
162
+ );
163
+ if (!took) return { ok: false, reason: 'tree_full' };
164
+
165
+ try {
166
+ const child = await this.deps.sessions.createSubSession({
167
+ rootSessionId: req.rootSessionId,
168
+ parentRunId: req.parentRunId,
169
+ subagentName: req.agentName,
170
+ userId: req.userId,
171
+ title: req.title,
172
+ metadata: check.metadata ?? req.sessionMetadata,
173
+ ...(check.attrs ? { attrs: check.attrs } : {}),
174
+ });
175
+ const created = await this.deps.policy.onSubagentCreated?.({
176
+ ...req,
177
+ childSessionId: child.id,
178
+ });
179
+ await this.deliver(child.id, req.prompt, req.userId);
180
+ const notes = created?.notes ?? [];
181
+ return notes.length > 0
182
+ ? { ok: true, childSessionId: child.id, notes }
183
+ : { ok: true, childSessionId: child.id };
184
+ } catch (err) {
185
+ // 建会话 / 投递失败:把刚占的名额还回去,不留泄漏。
186
+ await this.deps.treeBudget.decr(req.rootSessionId).catch(() => undefined);
187
+ throw err;
188
+ }
189
+ }
190
+
191
+ /**
192
+ * 追加任务前的目标校验——**必须先于投递**,且与投递分两步:同步等待的租约要夹在
193
+ * 「校验通过」与「投递」之间(见 `Delegate` 的追加任务那段)。
194
+ *
195
+ * 归属判据是「**直接子**」(子的 `parentRunId` 所属会话 == 当前会话),不是「同一棵
196
+ * 树」:孙辈的 handle 本就不会出现在父的上下文里,能续到孙只可能是编了个 id 或从子的
197
+ * 产出正文里抄了一个。
198
+ */
199
+ async resolveFollowUpTarget(input: {
200
+ childSessionId: string;
201
+ parentSessionId: string;
202
+ }): Promise<FollowUpTarget> {
203
+ const child = await this.deps.sessions.getSession(input.childSessionId);
204
+ if (!child || child.kind !== 'subagent') {
205
+ return { ok: false, reason: 'not_found' };
206
+ }
207
+ const owner = child.parentRunId
208
+ ? await this.deps.runs.getSessionId(child.parentRunId)
209
+ : null;
210
+ if (owner !== input.parentSessionId) {
211
+ return { ok: false, reason: 'not_own_child' };
212
+ }
213
+ return { ok: true, cursorBefore: child.lastMilestoneSeq };
214
+ }
215
+
216
+ /**
217
+ * 把追加任务投进子会话并唤醒它。与派生尾段**逐字相同**的通道,子那边零特判——「子
218
+ * 记得自己写过什么」不是这里做的,是会话本身没被丢弃。子此刻仍在跑就是软插话。
219
+ *
220
+ * **不占名额**:名额记的是「同时有几个**新派生**的子」,与「存活 = 游标为 null」同一个口径。
221
+ */
222
+ async deliverFollowUp(input: {
223
+ childSessionId: string;
224
+ prompt: string;
225
+ userId: string | null;
226
+ }): Promise<void> {
227
+ await this.deliver(input.childSessionId, input.prompt, input.userId);
228
+ }
229
+
230
+ /**
231
+ * 子已到达 idle 终态后,取它自 `since` 以来的回执。**与收尾回投 inbox 的那份同源**
232
+ * (同一个取数 + 同一套中和)——换个 `run_in_background` 值就换一份结论,是没法排查
233
+ * 的那类 bug。追加任务传发起前的游标,否则父会连同上一轮全文再收一遍。
234
+ */
235
+ async buildResult(
236
+ childSessionId: string,
237
+ since: number | null = null
238
+ ): Promise<SubagentResult> {
239
+ const out = await this.collectOutput(childSessionId, since);
240
+ return this.resultOf(out);
241
+ }
242
+
243
+ /**
244
+ * 里程碑游标是否已越过 `cursor`(=子在这次等待期间到达过一次 idle 终态)。null 即
245
+ * 「首次 settle 了没有」。**追加任务不能沿用「非 null 即完成」**——那个条件在追加发起的
246
+ * 一瞬间就成立(上一轮推进过),父会立刻拿着上一轮的结果返回。
247
+ */
248
+ async hasAdvancedPast(
249
+ childSessionId: string,
250
+ cursor: number | null
251
+ ): Promise<boolean> {
252
+ const child = await this.deps.sessions.getSession(childSessionId);
253
+ const now = child?.lastMilestoneSeq ?? null;
254
+ if (now === null) return false;
255
+ return cursor === null || now > cursor;
256
+ }
257
+
258
+ /** loop 设置 tick 时要的子会话信息(深度、钉住的子 Agent 名……)。会话不存在返回 null。 */
259
+ async tickInfo(sessionId: string): Promise<SubagentTickInfo | null> {
260
+ const session = await this.deps.sessions.getSession(sessionId);
261
+ if (!session) return null;
262
+ if (session.kind !== 'subagent') {
263
+ return {
264
+ kind: session.kind,
265
+ depth: 0,
266
+ parentRunId: null,
267
+ agentName: null,
268
+ title: session.title,
269
+ };
270
+ }
271
+ const depth = session.parentRunId
272
+ ? (await this.deps.runs.getDepth(session.parentRunId)) + 1
273
+ : 0;
274
+ return {
275
+ kind: 'subagent',
276
+ depth,
277
+ parentRunId: session.parentRunId,
278
+ agentName: session.subagentName,
279
+ title: session.title,
280
+ };
281
+ }
282
+
283
+ /**
284
+ * 子会话空转终态 → 把新产出中和后作为里程碑回投父 inbox 并唤醒父。
285
+ *
286
+ * loop 在每个 tick 收尾(锁已释放、re-wake 之前)对每个会话**无条件**调(`LoopHost.afterTick`),
287
+ * 这里自查:非子会话直接返回。
288
+ *
289
+ * **只还一次名额**:「存活」= 从派生到首次 idle 终态,判据是游标为 null。被追加任务
290
+ * 续跑后再次 idle 只回投新产出、不再还。
291
+ *
292
+ * **并发安全**:两次抢锁成功的唤醒可能并发进来、读到同一个旧游标。所有副作用都收在一次
293
+ * 乐观 CAS(`SessionStore.advanceMilestone`)之后:先按**旧**游标取产出,再把游标推进到
294
+ * 产出的最大 seq(无产出从序列取号);只有 CAS 成功的那一个回投 + 唤醒 + 还名额。
295
+ *
296
+ * 全程不抛:失败只记日志,兜底扫描是后备。
297
+ */
298
+ async finalizeIfIdle(childSessionId: string): Promise<void> {
299
+ try {
300
+ const child = await this.deps.sessions.getSession(childSessionId);
301
+ if (!child || child.kind !== 'subagent') return;
302
+
303
+ // 有待处理的消息 → 软插话进来了,子会被重新唤醒续跑,不回投、不还名额。
304
+ if (await this.deps.hub.hasPending(childSessionId)) return;
305
+
306
+ const parentSessionId = child.parentRunId
307
+ ? await this.deps.runs.getSessionId(child.parentRunId)
308
+ : null;
309
+ if (!parentSessionId) {
310
+ this.logger.warn(
311
+ `finalizeIfIdle(${childSessionId}): cannot locate parent session ` +
312
+ `(parentRunId=${child.parentRunId ?? 'null'}) — skipped`
313
+ );
314
+ return;
315
+ }
316
+
317
+ // 按**旧**游标取产出——CAS 前不得推进游标。
318
+ const oldCursor = child.lastMilestoneSeq;
319
+ const out = await this.collectOutput(childSessionId, oldCursor);
320
+
321
+ // 无新产出且非首次 → 已还过名额、也无可投,直接返回。两种情况要突破:
322
+ // 1. 失败态即便无新文本也必须把「子挂了」上报给父。
323
+ // 2. 有父正同步等着这次续跑:父的判据就是游标,这里一返回游标就停在原地,父只能
324
+ // 空等到超时——而子其实跑完了,只是一个字都没说。
325
+ if (
326
+ !out.produce &&
327
+ !out.failed &&
328
+ oldCursor !== null &&
329
+ !(await this.deps.awaitLease.isAwaited(childSessionId))
330
+ ) {
331
+ return;
332
+ }
333
+
334
+ const watermark =
335
+ out.watermark ?? (await this.deps.hub.store.reserveSeq(childSessionId));
336
+ const claimed = await this.deps.sessions.advanceMilestone(
337
+ childSessionId,
338
+ oldCursor,
339
+ watermark
340
+ );
341
+ if (!claimed) return;
342
+
343
+ // 父正同步等着 → 产物由它自己取,这里**不投 inbox**(否则父既同步拿到、下一轮又收到
344
+ // 一条重复回执)。必须在 CAS **之后**:父的判据正是游标,先 claim 再 CAS 的话父可能
345
+ // 在完成信号落库之前就被判成「已接管」。
346
+ const awaitedByParent = await this.deps.awaitLease.claim(
347
+ childSessionId,
348
+ 'finalizer'
349
+ );
350
+
351
+ if (!awaitedByParent) {
352
+ const result = this.resultOf(out);
353
+ await this.deps.hub.post({
354
+ sessionId: parentSessionId,
355
+ kind: 'tool_result',
356
+ sourceKind: 'tool',
357
+ sourceUserId: null,
358
+ // 围栏由 `MessageHub.take` 取出时包:落库的是数据,围栏是给模型的呈现层。
359
+ source: {
360
+ // 标的是「这是一份子 Agent 回执」这个**类别**,不是触发它的工具——
361
+ // 追加任务的回执也写这个名字,收尾只看会话状态,本就不知道是谁发起的。
362
+ toolName: DELEGATE_TOOL_NAME,
363
+ handle: childSessionId,
364
+ status: result.status,
365
+ stopReason: result.stopReason,
366
+ // 与 stopReason 分开带:那是协议码,这是人话。只有失败才带(已中和)。
367
+ error: out.failed ? out.error : null,
368
+ },
369
+ parts: [{ type: 'text', text: result.body }],
370
+ });
371
+ await this.deps.wake.wake(parentSessionId);
372
+ }
373
+
374
+ if (oldCursor === null) {
375
+ await this.deps.treeBudget.decr(child.rootSessionId);
376
+ }
377
+ } catch (err) {
378
+ this.logger.error(
379
+ `finalizeIfIdle(${childSessionId}) failed: ${String(err)}`
380
+ );
381
+ }
382
+ }
383
+
384
+ /**
385
+ * 兜底:子 loop 可能在回投 / 还名额之前崩掉或丢锁。对每个嫌疑重跑一次收尾(幂等),
386
+ * 再把每棵被碰过的树的名额覆盖为真值。**先收尾后校正**:收尾会把游标从 null 推成非
387
+ * null,校正读到的才是收尾之后的存活数。宿主在启动时调一次(fire-and-forget)。
388
+ */
389
+ async sweepStale(): Promise<void> {
390
+ const stale = await this.deps.sessions.listSubagentSessionsForSweep(
391
+ this.deps.sweepIdleMs ?? SUBAGENT_SWEEP_IDLE_MS
392
+ );
393
+ const touchedRoots = new Set<string>();
394
+ for (const session of stale) {
395
+ touchedRoots.add(session.rootSessionId);
396
+ await this.finalizeIfIdle(session.id);
397
+ }
398
+ const counts = await this.deps.sessions.countAliveSubsByRoot();
399
+ const countByRoot = new Map(counts.map(r => [r.rootSessionId, r.count]));
400
+ for (const rootId of touchedRoots) {
401
+ await this.deps.treeBudget.set(rootId, countByRoot.get(rootId) ?? 0);
402
+ }
403
+ if (stale.length > 0) {
404
+ this.logger.warn(
405
+ `sweepStale: finalized ${stale.length} stale session(s), corrected ${touchedRoots.size} tree(s)`
406
+ );
407
+ }
408
+ }
409
+
410
+ // ---------------------------------------------------------------------------
411
+
412
+ private async deliver(
413
+ sessionId: string,
414
+ prompt: string,
415
+ userId: string | null
416
+ ): Promise<void> {
417
+ await this.deps.hub.post({
418
+ sessionId,
419
+ kind: 'user_message',
420
+ sourceKind: 'user',
421
+ sourceUserId: userId,
422
+ parts: [{ type: 'text', text: prompt }],
423
+ });
424
+ await this.deps.wake.wake(sessionId);
425
+ }
426
+
427
+ /**
428
+ * 子会话自 `since` 以来的 assistant 产出与终态。游标是消息 `seq`(会话内单调)——
429
+ * **不是时间戳**:挂钟会回拨,回拨之后新产出会被判成「旧的」直接跳过,父收到的回执
430
+ * 格式完好、内容缺一段。
431
+ *
432
+ * `watermark` = 取到的行里最大的 seq;没取到行时为 null(调用方从序列取号)。游标取自
433
+ * **取到的那些行**而不是独立取一个「当下」——后者可能跨到尚未取到的消息之后。
434
+ */
435
+ private async collectOutput(
436
+ childSessionId: string,
437
+ since: number | null
438
+ ): Promise<CollectedOutput> {
439
+ const rows = await this.deps.hub.store.listMessages(childSessionId, {
440
+ role: 'assistant',
441
+ afterSeq: since,
442
+ });
443
+ const produce = rows
444
+ .flatMap(r =>
445
+ r.parts
446
+ .filter(
447
+ (p): p is Extract<MessagePart, { type: 'text' }> =>
448
+ p.type === 'text'
449
+ )
450
+ .map(p => p.text)
451
+ )
452
+ .join('\n')
453
+ .trim();
454
+ // 终态取自**最后一条** assistant 行的 metadata(`TurnRecorder.close` 盖的)。
455
+ const lastMeta = (rows[rows.length - 1]?.metadata ?? null) as {
456
+ status?: string;
457
+ stopReason?: string | null;
458
+ error?: string | null;
459
+ } | null;
460
+ const watermark = rows.reduce<number | null>(
461
+ (max, r) => (max === null || r.seq > max ? r.seq : max),
462
+ null
463
+ );
464
+ return {
465
+ produce: produce ? scanSubagentOutput(produce).text : '',
466
+ status: lastMeta?.status,
467
+ stopReason: lastMeta?.stopReason ?? null,
468
+ error: lastMeta?.error ? scanSubagentOutput(lastMeta.error).text : null,
469
+ failed: isFailedTerminal(lastMeta?.status),
470
+ watermark,
471
+ };
472
+ }
473
+
474
+ private resultOf(out: CollectedOutput): SubagentResult {
475
+ return {
476
+ body: buildMilestoneBody(out.produce, {
477
+ status: out.status,
478
+ stopReason: out.stopReason,
479
+ error: out.error,
480
+ }),
481
+ status: normalizeMilestoneStatus(out.status),
482
+ stopReason: out.failed ? out.stopReason : null,
483
+ };
484
+ }
485
+ }
486
+
487
+ interface CollectedOutput {
488
+ /** 已中和的产出正文。 */
489
+ produce: string;
490
+ status: string | undefined;
491
+ stopReason: string | null;
492
+ /** 已中和的错误原文。 */
493
+ error: string | null;
494
+ failed: boolean;
495
+ watermark: number | null;
496
+ }