@animalabs/agent-framework 0.22.2 → 0.23.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 (997) hide show
  1. package/README.md +108 -4
  2. package/dist/src/agent.d.ts +108 -17
  3. package/dist/src/agent.d.ts.map +1 -1
  4. package/dist/src/agent.js +207 -67
  5. package/dist/src/agent.js.map +1 -1
  6. package/dist/src/api/mcp-server-core.js +1 -1
  7. package/dist/src/api/mcp-server-core.js.map +1 -1
  8. package/dist/src/api/server.d.ts.map +1 -1
  9. package/dist/src/api/server.js +5 -1
  10. package/dist/src/api/server.js.map +1 -1
  11. package/dist/src/api/types.d.ts +1 -1
  12. package/dist/src/api/types.d.ts.map +1 -1
  13. package/dist/src/branch-names.d.ts +14 -0
  14. package/dist/src/branch-names.d.ts.map +1 -0
  15. package/dist/src/branch-names.js +22 -0
  16. package/dist/src/branch-names.js.map +1 -0
  17. package/dist/src/closest-names.d.ts +28 -0
  18. package/dist/src/closest-names.d.ts.map +1 -0
  19. package/dist/src/closest-names.js +98 -0
  20. package/dist/src/closest-names.js.map +1 -0
  21. package/dist/src/code-execution/index.d.ts +1 -1
  22. package/dist/src/code-execution/index.d.ts.map +1 -1
  23. package/dist/src/code-execution/index.js.map +1 -1
  24. package/dist/src/code-execution/py-runner.d.ts +50 -7
  25. package/dist/src/code-execution/py-runner.d.ts.map +1 -1
  26. package/dist/src/code-execution/py-runner.js +258 -90
  27. package/dist/src/code-execution/py-runner.js.map +1 -1
  28. package/dist/src/code-execution/runtime-py.d.ts +3 -2
  29. package/dist/src/code-execution/runtime-py.d.ts.map +1 -1
  30. package/dist/src/code-execution/runtime-py.js +94 -8
  31. package/dist/src/code-execution/runtime-py.js.map +1 -1
  32. package/dist/src/code-execution/tool-definition.d.ts +17 -1
  33. package/dist/src/code-execution/tool-definition.d.ts.map +1 -1
  34. package/dist/src/code-execution/tool-definition.js +72 -6
  35. package/dist/src/code-execution/tool-definition.js.map +1 -1
  36. package/dist/src/config-checks.d.ts +28 -0
  37. package/dist/src/config-checks.d.ts.map +1 -0
  38. package/dist/src/config-checks.js +56 -0
  39. package/dist/src/config-checks.js.map +1 -0
  40. package/dist/src/deadline-timer.d.ts +21 -0
  41. package/dist/src/deadline-timer.d.ts.map +1 -0
  42. package/dist/src/deadline-timer.js +43 -0
  43. package/dist/src/deadline-timer.js.map +1 -0
  44. package/dist/src/error-message.d.ts +30 -0
  45. package/dist/src/error-message.d.ts.map +1 -0
  46. package/dist/src/error-message.js +50 -0
  47. package/dist/src/error-message.js.map +1 -0
  48. package/dist/src/framework.d.ts +1529 -165
  49. package/dist/src/framework.d.ts.map +1 -1
  50. package/dist/src/framework.js +8264 -1939
  51. package/dist/src/framework.js.map +1 -1
  52. package/dist/src/gate/event-gate.d.ts +8 -0
  53. package/dist/src/gate/event-gate.d.ts.map +1 -1
  54. package/dist/src/gate/event-gate.js +36 -5
  55. package/dist/src/gate/event-gate.js.map +1 -1
  56. package/dist/src/held-writes.d.ts +16 -0
  57. package/dist/src/held-writes.d.ts.map +1 -0
  58. package/dist/src/held-writes.js +56 -0
  59. package/dist/src/held-writes.js.map +1 -0
  60. package/dist/src/index.d.ts +10 -4
  61. package/dist/src/index.d.ts.map +1 -1
  62. package/dist/src/index.js +11 -5
  63. package/dist/src/index.js.map +1 -1
  64. package/dist/src/mcpl/capability-grant.d.ts +4 -0
  65. package/dist/src/mcpl/capability-grant.d.ts.map +1 -1
  66. package/dist/src/mcpl/capability-grant.js +1 -1
  67. package/dist/src/mcpl/capability-grant.js.map +1 -1
  68. package/dist/src/mcpl/channel-registry.d.ts +233 -18
  69. package/dist/src/mcpl/channel-registry.d.ts.map +1 -1
  70. package/dist/src/mcpl/channel-registry.js +975 -386
  71. package/dist/src/mcpl/channel-registry.js.map +1 -1
  72. package/dist/src/mcpl/checkpoint-manager.d.ts +21 -1
  73. package/dist/src/mcpl/checkpoint-manager.d.ts.map +1 -1
  74. package/dist/src/mcpl/checkpoint-manager.js +91 -30
  75. package/dist/src/mcpl/checkpoint-manager.js.map +1 -1
  76. package/dist/src/mcpl/conversation-router.d.ts +19 -3
  77. package/dist/src/mcpl/conversation-router.d.ts.map +1 -1
  78. package/dist/src/mcpl/conversation-router.js +23 -8
  79. package/dist/src/mcpl/conversation-router.js.map +1 -1
  80. package/dist/src/mcpl/convert-block.d.ts +20 -0
  81. package/dist/src/mcpl/convert-block.d.ts.map +1 -0
  82. package/dist/src/mcpl/convert-block.js +88 -0
  83. package/dist/src/mcpl/convert-block.js.map +1 -0
  84. package/dist/src/mcpl/errors.d.ts +13 -0
  85. package/dist/src/mcpl/errors.d.ts.map +1 -1
  86. package/dist/src/mcpl/errors.js +28 -0
  87. package/dist/src/mcpl/errors.js.map +1 -1
  88. package/dist/src/mcpl/hook-orchestrator.d.ts +23 -0
  89. package/dist/src/mcpl/hook-orchestrator.d.ts.map +1 -1
  90. package/dist/src/mcpl/hook-orchestrator.js +83 -72
  91. package/dist/src/mcpl/hook-orchestrator.js.map +1 -1
  92. package/dist/src/mcpl/inbound-source.d.ts +114 -0
  93. package/dist/src/mcpl/inbound-source.d.ts.map +1 -0
  94. package/dist/src/mcpl/inbound-source.js +83 -0
  95. package/dist/src/mcpl/inbound-source.js.map +1 -0
  96. package/dist/src/mcpl/index.d.ts +7 -1
  97. package/dist/src/mcpl/index.d.ts.map +1 -1
  98. package/dist/src/mcpl/index.js +5 -1
  99. package/dist/src/mcpl/index.js.map +1 -1
  100. package/dist/src/mcpl/inference-router.d.ts +19 -13
  101. package/dist/src/mcpl/inference-router.d.ts.map +1 -1
  102. package/dist/src/mcpl/inference-router.js +155 -87
  103. package/dist/src/mcpl/inference-router.js.map +1 -1
  104. package/dist/src/mcpl/log-value.d.ts +7 -0
  105. package/dist/src/mcpl/log-value.d.ts.map +1 -1
  106. package/dist/src/mcpl/log-value.js +9 -0
  107. package/dist/src/mcpl/log-value.js.map +1 -1
  108. package/dist/src/mcpl/modern-connection.d.ts +227 -0
  109. package/dist/src/mcpl/modern-connection.d.ts.map +1 -0
  110. package/dist/src/mcpl/modern-connection.js +1088 -0
  111. package/dist/src/mcpl/modern-connection.js.map +1 -0
  112. package/dist/src/mcpl/prefix-rule.d.ts +18 -0
  113. package/dist/src/mcpl/prefix-rule.d.ts.map +1 -0
  114. package/dist/src/mcpl/prefix-rule.js +25 -0
  115. package/dist/src/mcpl/prefix-rule.js.map +1 -0
  116. package/dist/src/mcpl/protocol-family.d.ts +179 -0
  117. package/dist/src/mcpl/protocol-family.d.ts.map +1 -0
  118. package/dist/src/mcpl/protocol-family.js +697 -0
  119. package/dist/src/mcpl/protocol-family.js.map +1 -0
  120. package/dist/src/mcpl/push-coalescer.d.ts +58 -17
  121. package/dist/src/mcpl/push-coalescer.d.ts.map +1 -1
  122. package/dist/src/mcpl/push-coalescer.js +93 -32
  123. package/dist/src/mcpl/push-coalescer.js.map +1 -1
  124. package/dist/src/mcpl/push-handler.d.ts +16 -9
  125. package/dist/src/mcpl/push-handler.d.ts.map +1 -1
  126. package/dist/src/mcpl/push-handler.js +18 -83
  127. package/dist/src/mcpl/push-handler.js.map +1 -1
  128. package/dist/src/mcpl/reference-fetcher.d.ts +76 -13
  129. package/dist/src/mcpl/reference-fetcher.d.ts.map +1 -1
  130. package/dist/src/mcpl/reference-fetcher.js +275 -66
  131. package/dist/src/mcpl/reference-fetcher.js.map +1 -1
  132. package/dist/src/mcpl/references.d.ts +98 -18
  133. package/dist/src/mcpl/references.d.ts.map +1 -1
  134. package/dist/src/mcpl/references.js +170 -32
  135. package/dist/src/mcpl/references.js.map +1 -1
  136. package/dist/src/mcpl/server-connection.d.ts +406 -31
  137. package/dist/src/mcpl/server-connection.d.ts.map +1 -1
  138. package/dist/src/mcpl/server-connection.js +1331 -272
  139. package/dist/src/mcpl/server-connection.js.map +1 -1
  140. package/dist/src/mcpl/server-registry.d.ts +35 -6
  141. package/dist/src/mcpl/server-registry.d.ts.map +1 -1
  142. package/dist/src/mcpl/server-registry.js +63 -13
  143. package/dist/src/mcpl/server-registry.js.map +1 -1
  144. package/dist/src/mcpl/skip-reply-wake.d.ts +36 -0
  145. package/dist/src/mcpl/skip-reply-wake.d.ts.map +1 -0
  146. package/dist/src/mcpl/skip-reply-wake.js +55 -0
  147. package/dist/src/mcpl/skip-reply-wake.js.map +1 -0
  148. package/dist/src/mcpl/tool-result-normalize.d.ts +54 -0
  149. package/dist/src/mcpl/tool-result-normalize.d.ts.map +1 -0
  150. package/dist/src/mcpl/tool-result-normalize.js +232 -0
  151. package/dist/src/mcpl/tool-result-normalize.js.map +1 -0
  152. package/dist/src/mcpl/transport.d.ts +104 -12
  153. package/dist/src/mcpl/transport.d.ts.map +1 -1
  154. package/dist/src/mcpl/transport.js +315 -85
  155. package/dist/src/mcpl/transport.js.map +1 -1
  156. package/dist/src/mcpl/types.d.ts +76 -19
  157. package/dist/src/mcpl/types.d.ts.map +1 -1
  158. package/dist/src/mcpl/types.js.map +1 -1
  159. package/dist/src/mcpl/visible-content.d.ts +16 -0
  160. package/dist/src/mcpl/visible-content.d.ts.map +1 -1
  161. package/dist/src/mcpl/visible-content.js +26 -0
  162. package/dist/src/mcpl/visible-content.js.map +1 -1
  163. package/dist/src/module-registry.d.ts +34 -6
  164. package/dist/src/module-registry.d.ts.map +1 -1
  165. package/dist/src/module-registry.js +119 -31
  166. package/dist/src/module-registry.js.map +1 -1
  167. package/dist/src/modules/api/index.d.ts +1 -1
  168. package/dist/src/modules/api/index.d.ts.map +1 -1
  169. package/dist/src/modules/api/index.js +3 -2
  170. package/dist/src/modules/api/index.js.map +1 -1
  171. package/dist/src/modules/discord/discord-js-client.d.ts +43 -2
  172. package/dist/src/modules/discord/discord-js-client.d.ts.map +1 -1
  173. package/dist/src/modules/discord/discord-js-client.js +286 -67
  174. package/dist/src/modules/discord/discord-js-client.js.map +1 -1
  175. package/dist/src/modules/discord/index.d.ts +53 -5
  176. package/dist/src/modules/discord/index.d.ts.map +1 -1
  177. package/dist/src/modules/discord/index.js +712 -186
  178. package/dist/src/modules/discord/index.js.map +1 -1
  179. package/dist/src/modules/discord/refusal.d.ts +14 -0
  180. package/dist/src/modules/discord/refusal.d.ts.map +1 -0
  181. package/dist/src/modules/discord/refusal.js +14 -0
  182. package/dist/src/modules/discord/refusal.js.map +1 -0
  183. package/dist/src/modules/discord/types.d.ts +27 -4
  184. package/dist/src/modules/discord/types.d.ts.map +1 -1
  185. package/dist/src/modules/health/index.d.ts.map +1 -1
  186. package/dist/src/modules/health/index.js +8 -3
  187. package/dist/src/modules/health/index.js.map +1 -1
  188. package/dist/src/modules/history/index.d.ts +3 -1
  189. package/dist/src/modules/history/index.d.ts.map +1 -1
  190. package/dist/src/modules/history/index.js +359 -127
  191. package/dist/src/modules/history/index.js.map +1 -1
  192. package/dist/src/modules/history/semantic.d.ts +28 -1
  193. package/dist/src/modules/history/semantic.d.ts.map +1 -1
  194. package/dist/src/modules/history/semantic.js +177 -32
  195. package/dist/src/modules/history/semantic.js.map +1 -1
  196. package/dist/src/modules/index.d.ts +1 -1
  197. package/dist/src/modules/index.d.ts.map +1 -1
  198. package/dist/src/modules/index.js +1 -1
  199. package/dist/src/modules/index.js.map +1 -1
  200. package/dist/src/modules/unknown-tool.d.ts +10 -0
  201. package/dist/src/modules/unknown-tool.d.ts.map +1 -0
  202. package/dist/src/modules/unknown-tool.js +17 -0
  203. package/dist/src/modules/unknown-tool.js.map +1 -0
  204. package/dist/src/modules/workspace/disk-agreement.d.ts +57 -4
  205. package/dist/src/modules/workspace/disk-agreement.d.ts.map +1 -1
  206. package/dist/src/modules/workspace/disk-agreement.js +75 -7
  207. package/dist/src/modules/workspace/disk-agreement.js.map +1 -1
  208. package/dist/src/modules/workspace/effects.d.ts +66 -7
  209. package/dist/src/modules/workspace/effects.d.ts.map +1 -1
  210. package/dist/src/modules/workspace/effects.js +303 -46
  211. package/dist/src/modules/workspace/effects.js.map +1 -1
  212. package/dist/src/modules/workspace/index.d.ts +313 -45
  213. package/dist/src/modules/workspace/index.d.ts.map +1 -1
  214. package/dist/src/modules/workspace/index.js +1404 -304
  215. package/dist/src/modules/workspace/index.js.map +1 -1
  216. package/dist/src/modules/workspace/observe.d.ts +315 -16
  217. package/dist/src/modules/workspace/observe.d.ts.map +1 -1
  218. package/dist/src/modules/workspace/observe.js +727 -37
  219. package/dist/src/modules/workspace/observe.js.map +1 -1
  220. package/dist/src/modules/workspace/reconcile.d.ts +58 -7
  221. package/dist/src/modules/workspace/reconcile.d.ts.map +1 -1
  222. package/dist/src/modules/workspace/reconcile.js +521 -56
  223. package/dist/src/modules/workspace/reconcile.js.map +1 -1
  224. package/dist/src/modules/workspace/types.d.ts +28 -5
  225. package/dist/src/modules/workspace/types.d.ts.map +1 -1
  226. package/dist/src/modules/workspace/types.js.map +1 -1
  227. package/dist/src/modules/workspace/watcher.d.ts +49 -2
  228. package/dist/src/modules/workspace/watcher.d.ts.map +1 -1
  229. package/dist/src/modules/workspace/watcher.js +158 -29
  230. package/dist/src/modules/workspace/watcher.js.map +1 -1
  231. package/dist/src/prose-drafts.d.ts +240 -0
  232. package/dist/src/prose-drafts.d.ts.map +1 -0
  233. package/dist/src/prose-drafts.js +362 -0
  234. package/dist/src/prose-drafts.js.map +1 -0
  235. package/dist/src/prose-segments.d.ts +21 -2
  236. package/dist/src/prose-segments.d.ts.map +1 -1
  237. package/dist/src/prose-segments.js +46 -9
  238. package/dist/src/prose-segments.js.map +1 -1
  239. package/dist/src/recovery/offline-branch.d.ts +1 -0
  240. package/dist/src/recovery/offline-branch.d.ts.map +1 -1
  241. package/dist/src/recovery/offline-branch.js +3 -1
  242. package/dist/src/recovery/offline-branch.js.map +1 -1
  243. package/dist/src/safe-slice.d.ts +5 -1
  244. package/dist/src/safe-slice.d.ts.map +1 -1
  245. package/dist/src/safe-slice.js +9 -1
  246. package/dist/src/safe-slice.js.map +1 -1
  247. package/dist/src/silent-heartbeat.d.ts +112 -39
  248. package/dist/src/silent-heartbeat.d.ts.map +1 -1
  249. package/dist/src/silent-heartbeat.js +100 -29
  250. package/dist/src/silent-heartbeat.js.map +1 -1
  251. package/dist/src/tool-args.d.ts +40 -0
  252. package/dist/src/tool-args.d.ts.map +1 -0
  253. package/dist/src/tool-args.js +207 -0
  254. package/dist/src/tool-args.js.map +1 -0
  255. package/dist/src/tool-image-ledger.d.ts +87 -19
  256. package/dist/src/tool-image-ledger.d.ts.map +1 -1
  257. package/dist/src/tool-image-ledger.js +135 -32
  258. package/dist/src/tool-image-ledger.js.map +1 -1
  259. package/dist/src/tool-presentation.d.ts +9 -0
  260. package/dist/src/tool-presentation.d.ts.map +1 -1
  261. package/dist/src/tool-presentation.js +266 -62
  262. package/dist/src/tool-presentation.js.map +1 -1
  263. package/dist/src/tool-result-guard.d.ts.map +1 -1
  264. package/dist/src/tool-result-guard.js +7 -10
  265. package/dist/src/tool-result-guard.js.map +1 -1
  266. package/dist/src/tool-result-history.d.ts +32 -3
  267. package/dist/src/tool-result-history.d.ts.map +1 -1
  268. package/dist/src/tool-result-history.js +106 -19
  269. package/dist/src/tool-result-history.js.map +1 -1
  270. package/dist/src/tune-out/coordinator.d.ts +25 -1
  271. package/dist/src/tune-out/coordinator.d.ts.map +1 -1
  272. package/dist/src/tune-out/coordinator.js +260 -65
  273. package/dist/src/tune-out/coordinator.js.map +1 -1
  274. package/dist/src/types/agent.d.ts +44 -22
  275. package/dist/src/types/agent.d.ts.map +1 -1
  276. package/dist/src/types/events.d.ts +25 -0
  277. package/dist/src/types/events.d.ts.map +1 -1
  278. package/dist/src/types/framework.d.ts +38 -7
  279. package/dist/src/types/framework.d.ts.map +1 -1
  280. package/dist/src/types/inference-log.d.ts +1 -1
  281. package/dist/src/types/inference-log.d.ts.map +1 -1
  282. package/dist/src/types/module.d.ts +77 -14
  283. package/dist/src/types/module.d.ts.map +1 -1
  284. package/dist/src/types/trace.d.ts +97 -8
  285. package/dist/src/types/trace.d.ts.map +1 -1
  286. package/dist/src/usage/usage-tracker.d.ts +5 -0
  287. package/dist/src/usage/usage-tracker.d.ts.map +1 -1
  288. package/dist/src/usage/usage-tracker.js +35 -8
  289. package/dist/src/usage/usage-tracker.js.map +1 -1
  290. package/package.json +5 -4
  291. package/src/agent.ts +257 -72
  292. package/src/api/mcp-server-core.ts +1 -1
  293. package/src/api/server.ts +4 -1
  294. package/src/api/types.ts +1 -1
  295. package/src/branch-names.ts +19 -0
  296. package/src/closest-names.ts +94 -0
  297. package/src/code-execution/index.ts +1 -0
  298. package/src/code-execution/py-runner.ts +304 -93
  299. package/src/code-execution/runtime-py.ts +94 -8
  300. package/src/code-execution/tool-definition.ts +85 -7
  301. package/src/config-checks.ts +50 -0
  302. package/src/deadline-timer.ts +44 -0
  303. package/src/error-message.ts +48 -0
  304. package/src/framework.ts +8625 -1984
  305. package/src/gate/event-gate.ts +38 -5
  306. package/src/held-writes.ts +59 -0
  307. package/src/index.ts +29 -5
  308. package/src/mcpl/capability-grant.ts +1 -1
  309. package/src/mcpl/channel-registry.ts +1095 -411
  310. package/src/mcpl/checkpoint-manager.ts +104 -29
  311. package/src/mcpl/conversation-router.ts +28 -8
  312. package/src/mcpl/convert-block.ts +105 -0
  313. package/src/mcpl/errors.ts +28 -0
  314. package/src/mcpl/hook-orchestrator.ts +84 -77
  315. package/src/mcpl/inbound-source.ts +156 -0
  316. package/src/mcpl/index.ts +23 -1
  317. package/src/mcpl/inference-router.ts +179 -103
  318. package/src/mcpl/log-value.ts +10 -0
  319. package/src/mcpl/modern-connection.ts +1182 -0
  320. package/src/mcpl/prefix-rule.ts +32 -0
  321. package/src/mcpl/protocol-family.ts +691 -0
  322. package/src/mcpl/push-coalescer.ts +110 -36
  323. package/src/mcpl/push-handler.ts +20 -90
  324. package/src/mcpl/reference-fetcher.ts +318 -67
  325. package/src/mcpl/references.ts +183 -34
  326. package/src/mcpl/server-connection.ts +1404 -280
  327. package/src/mcpl/server-registry.ts +63 -14
  328. package/src/mcpl/skip-reply-wake.ts +73 -0
  329. package/src/mcpl/tool-result-normalize.ts +294 -0
  330. package/src/mcpl/transport.ts +320 -76
  331. package/src/mcpl/types.ts +77 -19
  332. package/src/mcpl/visible-content.ts +28 -0
  333. package/src/module-registry.ts +126 -36
  334. package/src/modules/api/index.ts +3 -2
  335. package/src/modules/discord/discord-js-client.ts +306 -74
  336. package/src/modules/discord/index.ts +737 -201
  337. package/src/modules/discord/refusal.ts +13 -0
  338. package/src/modules/discord/types.ts +27 -6
  339. package/src/modules/health/index.ts +8 -3
  340. package/src/modules/history/index.ts +410 -120
  341. package/src/modules/history/semantic.ts +189 -32
  342. package/src/modules/index.ts +1 -1
  343. package/src/modules/unknown-tool.ts +16 -0
  344. package/src/modules/workspace/disk-agreement.ts +97 -8
  345. package/src/modules/workspace/effects.ts +291 -36
  346. package/src/modules/workspace/index.ts +1469 -321
  347. package/src/modules/workspace/observe.ts +784 -41
  348. package/src/modules/workspace/reconcile.ts +619 -64
  349. package/src/modules/workspace/types.ts +28 -5
  350. package/src/modules/workspace/watcher.ts +154 -30
  351. package/src/prose-drafts.ts +481 -0
  352. package/src/prose-segments.ts +51 -8
  353. package/src/recovery/offline-branch.ts +4 -1
  354. package/src/safe-slice.ts +9 -1
  355. package/src/silent-heartbeat.ts +184 -59
  356. package/src/tool-args.ts +213 -0
  357. package/src/tool-image-ledger.ts +153 -34
  358. package/src/tool-presentation.ts +233 -42
  359. package/src/tool-result-guard.ts +7 -8
  360. package/src/tool-result-history.ts +124 -20
  361. package/src/tune-out/coordinator.ts +259 -65
  362. package/src/types/agent.ts +44 -24
  363. package/src/types/events.ts +25 -0
  364. package/src/types/framework.ts +38 -7
  365. package/src/types/inference-log.ts +1 -1
  366. package/src/types/module.ts +79 -14
  367. package/src/types/trace.ts +103 -8
  368. package/src/usage/usage-tracker.ts +32 -8
  369. package/dist/test/activation-request-sanitize.test.d.ts +0 -2
  370. package/dist/test/activation-request-sanitize.test.d.ts.map +0 -1
  371. package/dist/test/activation-request-sanitize.test.js +0 -89
  372. package/dist/test/activation-request-sanitize.test.js.map +0 -1
  373. package/dist/test/agent-cache-ttl.test.d.ts +0 -2
  374. package/dist/test/agent-cache-ttl.test.d.ts.map +0 -1
  375. package/dist/test/agent-cache-ttl.test.js +0 -41
  376. package/dist/test/agent-cache-ttl.test.js.map +0 -1
  377. package/dist/test/agent-runtime-settings.test.d.ts +0 -2
  378. package/dist/test/agent-runtime-settings.test.d.ts.map +0 -1
  379. package/dist/test/agent-runtime-settings.test.js +0 -1598
  380. package/dist/test/agent-runtime-settings.test.js.map +0 -1
  381. package/dist/test/api-admin-gate.test.d.ts +0 -2
  382. package/dist/test/api-admin-gate.test.d.ts.map +0 -1
  383. package/dist/test/api-admin-gate.test.js +0 -116
  384. package/dist/test/api-admin-gate.test.js.map +0 -1
  385. package/dist/test/assistant-persist-refusal.test.d.ts +0 -2
  386. package/dist/test/assistant-persist-refusal.test.d.ts.map +0 -1
  387. package/dist/test/assistant-persist-refusal.test.js +0 -63
  388. package/dist/test/assistant-persist-refusal.test.js.map +0 -1
  389. package/dist/test/batched-wake-locus.test.d.ts +0 -2
  390. package/dist/test/batched-wake-locus.test.d.ts.map +0 -1
  391. package/dist/test/batched-wake-locus.test.js +0 -166
  392. package/dist/test/batched-wake-locus.test.js.map +0 -1
  393. package/dist/test/busy-agent-scheduler.test.d.ts +0 -2
  394. package/dist/test/busy-agent-scheduler.test.d.ts.map +0 -1
  395. package/dist/test/busy-agent-scheduler.test.js +0 -92
  396. package/dist/test/busy-agent-scheduler.test.js.map +0 -1
  397. package/dist/test/channel-incoming-targeting.test.d.ts +0 -2
  398. package/dist/test/channel-incoming-targeting.test.d.ts.map +0 -1
  399. package/dist/test/channel-incoming-targeting.test.js +0 -81
  400. package/dist/test/channel-incoming-targeting.test.js.map +0 -1
  401. package/dist/test/channel-label-history.test.d.ts +0 -2
  402. package/dist/test/channel-label-history.test.d.ts.map +0 -1
  403. package/dist/test/channel-label-history.test.js +0 -424
  404. package/dist/test/channel-label-history.test.js.map +0 -1
  405. package/dist/test/channel-lifecycle-provenance.test.d.ts +0 -2
  406. package/dist/test/channel-lifecycle-provenance.test.d.ts.map +0 -1
  407. package/dist/test/channel-lifecycle-provenance.test.js +0 -47
  408. package/dist/test/channel-lifecycle-provenance.test.js.map +0 -1
  409. package/dist/test/channel-registry-routing.test.d.ts +0 -2
  410. package/dist/test/channel-registry-routing.test.d.ts.map +0 -1
  411. package/dist/test/channel-registry-routing.test.js +0 -446
  412. package/dist/test/channel-registry-routing.test.js.map +0 -1
  413. package/dist/test/channel-registry-typing.test.d.ts +0 -2
  414. package/dist/test/channel-registry-typing.test.d.ts.map +0 -1
  415. package/dist/test/channel-registry-typing.test.js +0 -91
  416. package/dist/test/channel-registry-typing.test.js.map +0 -1
  417. package/dist/test/channels-changed-respond-first.test.d.ts +0 -2
  418. package/dist/test/channels-changed-respond-first.test.d.ts.map +0 -1
  419. package/dist/test/channels-changed-respond-first.test.js +0 -74
  420. package/dist/test/channels-changed-respond-first.test.js.map +0 -1
  421. package/dist/test/checkpoint-attribution.test.d.ts +0 -2
  422. package/dist/test/checkpoint-attribution.test.d.ts.map +0 -1
  423. package/dist/test/checkpoint-attribution.test.js +0 -200
  424. package/dist/test/checkpoint-attribution.test.js.map +0 -1
  425. package/dist/test/code-execution.test.d.ts +0 -11
  426. package/dist/test/code-execution.test.d.ts.map +0 -1
  427. package/dist/test/code-execution.test.js +0 -1272
  428. package/dist/test/code-execution.test.js.map +0 -1
  429. package/dist/test/component-defaults.test.d.ts +0 -2
  430. package/dist/test/component-defaults.test.d.ts.map +0 -1
  431. package/dist/test/component-defaults.test.js +0 -54
  432. package/dist/test/component-defaults.test.js.map +0 -1
  433. package/dist/test/conversation-fork-injection-scoping.test.d.ts +0 -2
  434. package/dist/test/conversation-fork-injection-scoping.test.d.ts.map +0 -1
  435. package/dist/test/conversation-fork-injection-scoping.test.js +0 -200
  436. package/dist/test/conversation-fork-injection-scoping.test.js.map +0 -1
  437. package/dist/test/conversation-router.test.d.ts +0 -2
  438. package/dist/test/conversation-router.test.d.ts.map +0 -1
  439. package/dist/test/conversation-router.test.js +0 -174
  440. package/dist/test/conversation-router.test.js.map +0 -1
  441. package/dist/test/conversation-routing.test.d.ts +0 -7
  442. package/dist/test/conversation-routing.test.d.ts.map +0 -1
  443. package/dist/test/conversation-routing.test.js +0 -621
  444. package/dist/test/conversation-routing.test.js.map +0 -1
  445. package/dist/test/deferred-wake-integrity.test.d.ts +0 -29
  446. package/dist/test/deferred-wake-integrity.test.d.ts.map +0 -1
  447. package/dist/test/deferred-wake-integrity.test.js +0 -320
  448. package/dist/test/deferred-wake-integrity.test.js.map +0 -1
  449. package/dist/test/discord-awareness-outbox.test.d.ts +0 -2
  450. package/dist/test/discord-awareness-outbox.test.d.ts.map +0 -1
  451. package/dist/test/discord-awareness-outbox.test.js +0 -371
  452. package/dist/test/discord-awareness-outbox.test.js.map +0 -1
  453. package/dist/test/discord-history-delete-window.test.d.ts +0 -2
  454. package/dist/test/discord-history-delete-window.test.d.ts.map +0 -1
  455. package/dist/test/discord-history-delete-window.test.js +0 -81
  456. package/dist/test/discord-history-delete-window.test.js.map +0 -1
  457. package/dist/test/discord-history-sync.test.d.ts +0 -2
  458. package/dist/test/discord-history-sync.test.d.ts.map +0 -1
  459. package/dist/test/discord-history-sync.test.js +0 -56
  460. package/dist/test/discord-history-sync.test.js.map +0 -1
  461. package/dist/test/discord-typing-keepalive.test.d.ts +0 -2
  462. package/dist/test/discord-typing-keepalive.test.d.ts.map +0 -1
  463. package/dist/test/discord-typing-keepalive.test.js +0 -77
  464. package/dist/test/discord-typing-keepalive.test.js.map +0 -1
  465. package/dist/test/ephemeral-settle.test.d.ts +0 -2
  466. package/dist/test/ephemeral-settle.test.d.ts.map +0 -1
  467. package/dist/test/ephemeral-settle.test.js +0 -354
  468. package/dist/test/ephemeral-settle.test.js.map +0 -1
  469. package/dist/test/event-gate-passthrough.test.d.ts +0 -15
  470. package/dist/test/event-gate-passthrough.test.d.ts.map +0 -1
  471. package/dist/test/event-gate-passthrough.test.js +0 -289
  472. package/dist/test/event-gate-passthrough.test.js.map +0 -1
  473. package/dist/test/event-gate-policy-mutation.test.d.ts +0 -2
  474. package/dist/test/event-gate-policy-mutation.test.d.ts.map +0 -1
  475. package/dist/test/event-gate-policy-mutation.test.js +0 -137
  476. package/dist/test/event-gate-policy-mutation.test.js.map +0 -1
  477. package/dist/test/event-gate-rate-limit.test.d.ts +0 -2
  478. package/dist/test/event-gate-rate-limit.test.d.ts.map +0 -1
  479. package/dist/test/event-gate-rate-limit.test.js +0 -627
  480. package/dist/test/event-gate-rate-limit.test.js.map +0 -1
  481. package/dist/test/event-gate-script.test.d.ts +0 -2
  482. package/dist/test/event-gate-script.test.d.ts.map +0 -1
  483. package/dist/test/event-gate-script.test.js +0 -95
  484. package/dist/test/event-gate-script.test.js.map +0 -1
  485. package/dist/test/event-gate-selfwake.test.d.ts +0 -15
  486. package/dist/test/event-gate-selfwake.test.d.ts.map +0 -1
  487. package/dist/test/event-gate-selfwake.test.js +0 -125
  488. package/dist/test/event-gate-selfwake.test.js.map +0 -1
  489. package/dist/test/event-gate-tags.test.d.ts +0 -2
  490. package/dist/test/event-gate-tags.test.d.ts.map +0 -1
  491. package/dist/test/event-gate-tags.test.js +0 -76
  492. package/dist/test/event-gate-tags.test.js.map +0 -1
  493. package/dist/test/event-gate.test.d.ts +0 -2
  494. package/dist/test/event-gate.test.d.ts.map +0 -1
  495. package/dist/test/event-gate.test.js +0 -919
  496. package/dist/test/event-gate.test.js.map +0 -1
  497. package/dist/test/explicit-prose-routing.test.d.ts +0 -11
  498. package/dist/test/explicit-prose-routing.test.d.ts.map +0 -1
  499. package/dist/test/explicit-prose-routing.test.js +0 -1715
  500. package/dist/test/explicit-prose-routing.test.js.map +0 -1
  501. package/dist/test/framework.test.d.ts +0 -5
  502. package/dist/test/framework.test.d.ts.map +0 -1
  503. package/dist/test/framework.test.js +0 -1048
  504. package/dist/test/framework.test.js.map +0 -1
  505. package/dist/test/gather-context-timeout.test.d.ts +0 -2
  506. package/dist/test/gather-context-timeout.test.d.ts.map +0 -1
  507. package/dist/test/gather-context-timeout.test.js +0 -120
  508. package/dist/test/gather-context-timeout.test.js.map +0 -1
  509. package/dist/test/health-snapshot.test.d.ts +0 -2
  510. package/dist/test/health-snapshot.test.d.ts.map +0 -1
  511. package/dist/test/health-snapshot.test.js +0 -74
  512. package/dist/test/health-snapshot.test.js.map +0 -1
  513. package/dist/test/helpers/coalescing-fixture.d.ts +0 -74
  514. package/dist/test/helpers/coalescing-fixture.d.ts.map +0 -1
  515. package/dist/test/helpers/coalescing-fixture.js +0 -152
  516. package/dist/test/helpers/coalescing-fixture.js.map +0 -1
  517. package/dist/test/helpers/coalescing-kill-child.d.ts +0 -2
  518. package/dist/test/helpers/coalescing-kill-child.d.ts.map +0 -1
  519. package/dist/test/helpers/coalescing-kill-child.js +0 -24
  520. package/dist/test/helpers/coalescing-kill-child.js.map +0 -1
  521. package/dist/test/helpers/mock-membrane.d.ts +0 -53
  522. package/dist/test/helpers/mock-membrane.d.ts.map +0 -1
  523. package/dist/test/helpers/mock-membrane.js +0 -168
  524. package/dist/test/helpers/mock-membrane.js.map +0 -1
  525. package/dist/test/helpers/pytc-stop-rows.d.ts +0 -11
  526. package/dist/test/helpers/pytc-stop-rows.d.ts.map +0 -1
  527. package/dist/test/helpers/pytc-stop-rows.js +0 -143
  528. package/dist/test/helpers/pytc-stop-rows.js.map +0 -1
  529. package/dist/test/helpers/quiesce-crash-child.d.ts +0 -2
  530. package/dist/test/helpers/quiesce-crash-child.d.ts.map +0 -1
  531. package/dist/test/helpers/quiesce-crash-child.js +0 -156
  532. package/dist/test/helpers/quiesce-crash-child.js.map +0 -1
  533. package/dist/test/hide-then-turn.test.d.ts +0 -2
  534. package/dist/test/hide-then-turn.test.d.ts.map +0 -1
  535. package/dist/test/hide-then-turn.test.js +0 -101
  536. package/dist/test/hide-then-turn.test.js.map +0 -1
  537. package/dist/test/history-module-overview.test.d.ts +0 -2
  538. package/dist/test/history-module-overview.test.d.ts.map +0 -1
  539. package/dist/test/history-module-overview.test.js +0 -711
  540. package/dist/test/history-module-overview.test.js.map +0 -1
  541. package/dist/test/history-module-realstore.test.d.ts +0 -2
  542. package/dist/test/history-module-realstore.test.d.ts.map +0 -1
  543. package/dist/test/history-module-realstore.test.js +0 -363
  544. package/dist/test/history-module-realstore.test.js.map +0 -1
  545. package/dist/test/history-module-semantic.test.d.ts +0 -2
  546. package/dist/test/history-module-semantic.test.d.ts.map +0 -1
  547. package/dist/test/history-module-semantic.test.js +0 -213
  548. package/dist/test/history-module-semantic.test.js.map +0 -1
  549. package/dist/test/history-module-ux.test.d.ts +0 -2
  550. package/dist/test/history-module-ux.test.d.ts.map +0 -1
  551. package/dist/test/history-module-ux.test.js +0 -304
  552. package/dist/test/history-module-ux.test.js.map +0 -1
  553. package/dist/test/history-module.test.d.ts +0 -2
  554. package/dist/test/history-module.test.d.ts.map +0 -1
  555. package/dist/test/history-module.test.js +0 -619
  556. package/dist/test/history-module.test.js.map +0 -1
  557. package/dist/test/history-semantic-review-findings.test.d.ts +0 -2
  558. package/dist/test/history-semantic-review-findings.test.d.ts.map +0 -1
  559. package/dist/test/history-semantic-review-findings.test.js +0 -338
  560. package/dist/test/history-semantic-review-findings.test.js.map +0 -1
  561. package/dist/test/history-semantic-sync-converges.test.d.ts +0 -2
  562. package/dist/test/history-semantic-sync-converges.test.d.ts.map +0 -1
  563. package/dist/test/history-semantic-sync-converges.test.js +0 -109
  564. package/dist/test/history-semantic-sync-converges.test.js.map +0 -1
  565. package/dist/test/host-quiesce.test.d.ts +0 -2
  566. package/dist/test/host-quiesce.test.d.ts.map +0 -1
  567. package/dist/test/host-quiesce.test.js +0 -988
  568. package/dist/test/host-quiesce.test.js.map +0 -1
  569. package/dist/test/inference-exhaustion-rewind.test.d.ts +0 -2
  570. package/dist/test/inference-exhaustion-rewind.test.d.ts.map +0 -1
  571. package/dist/test/inference-exhaustion-rewind.test.js +0 -387
  572. package/dist/test/inference-exhaustion-rewind.test.js.map +0 -1
  573. package/dist/test/inference-failure-bounds.test.d.ts +0 -2
  574. package/dist/test/inference-failure-bounds.test.d.ts.map +0 -1
  575. package/dist/test/inference-failure-bounds.test.js +0 -1202
  576. package/dist/test/inference-failure-bounds.test.js.map +0 -1
  577. package/dist/test/inference-failure-observability.test.d.ts +0 -2
  578. package/dist/test/inference-failure-observability.test.d.ts.map +0 -1
  579. package/dist/test/inference-failure-observability.test.js +0 -84
  580. package/dist/test/inference-failure-observability.test.js.map +0 -1
  581. package/dist/test/journal-tool.test.d.ts +0 -2
  582. package/dist/test/journal-tool.test.d.ts.map +0 -1
  583. package/dist/test/journal-tool.test.js +0 -33
  584. package/dist/test/journal-tool.test.js.map +0 -1
  585. package/dist/test/kv-unified-open-flight-retry.test.d.ts +0 -2
  586. package/dist/test/kv-unified-open-flight-retry.test.d.ts.map +0 -1
  587. package/dist/test/kv-unified-open-flight-retry.test.js +0 -189
  588. package/dist/test/kv-unified-open-flight-retry.test.js.map +0 -1
  589. package/dist/test/kv-unified-wiring.test.d.ts +0 -2
  590. package/dist/test/kv-unified-wiring.test.d.ts.map +0 -1
  591. package/dist/test/kv-unified-wiring.test.js +0 -95
  592. package/dist/test/kv-unified-wiring.test.js.map +0 -1
  593. package/dist/test/late-events-after-stop.test.d.ts +0 -2
  594. package/dist/test/late-events-after-stop.test.d.ts.map +0 -1
  595. package/dist/test/late-events-after-stop.test.js +0 -122
  596. package/dist/test/late-events-after-stop.test.js.map +0 -1
  597. package/dist/test/liveness-watchdog.test.d.ts +0 -2
  598. package/dist/test/liveness-watchdog.test.d.ts.map +0 -1
  599. package/dist/test/liveness-watchdog.test.js +0 -94
  600. package/dist/test/liveness-watchdog.test.js.map +0 -1
  601. package/dist/test/machine-close-provenance.test.d.ts +0 -2
  602. package/dist/test/machine-close-provenance.test.d.ts.map +0 -1
  603. package/dist/test/machine-close-provenance.test.js +0 -116
  604. package/dist/test/machine-close-provenance.test.js.map +0 -1
  605. package/dist/test/maintenance-timer.test.d.ts +0 -2
  606. package/dist/test/maintenance-timer.test.d.ts.map +0 -1
  607. package/dist/test/maintenance-timer.test.js +0 -1827
  608. package/dist/test/maintenance-timer.test.js.map +0 -1
  609. package/dist/test/mcp-server-bin.test.d.ts +0 -2
  610. package/dist/test/mcp-server-bin.test.d.ts.map +0 -1
  611. package/dist/test/mcp-server-bin.test.js +0 -142
  612. package/dist/test/mcp-server-bin.test.js.map +0 -1
  613. package/dist/test/mcpl-access-provider.test.d.ts +0 -2
  614. package/dist/test/mcpl-access-provider.test.d.ts.map +0 -1
  615. package/dist/test/mcpl-access-provider.test.js +0 -20
  616. package/dist/test/mcpl-access-provider.test.js.map +0 -1
  617. package/dist/test/mcpl-awareness-barrier.test.d.ts +0 -2
  618. package/dist/test/mcpl-awareness-barrier.test.d.ts.map +0 -1
  619. package/dist/test/mcpl-awareness-barrier.test.js +0 -769
  620. package/dist/test/mcpl-awareness-barrier.test.js.map +0 -1
  621. package/dist/test/mcpl-capability-grant.test.d.ts +0 -10
  622. package/dist/test/mcpl-capability-grant.test.d.ts.map +0 -1
  623. package/dist/test/mcpl-capability-grant.test.js +0 -111
  624. package/dist/test/mcpl-capability-grant.test.js.map +0 -1
  625. package/dist/test/mcpl-capability-scoping.test.d.ts +0 -2
  626. package/dist/test/mcpl-capability-scoping.test.d.ts.map +0 -1
  627. package/dist/test/mcpl-capability-scoping.test.js +0 -266
  628. package/dist/test/mcpl-capability-scoping.test.js.map +0 -1
  629. package/dist/test/mcpl-child-env.test.d.ts +0 -2
  630. package/dist/test/mcpl-child-env.test.d.ts.map +0 -1
  631. package/dist/test/mcpl-child-env.test.js +0 -158
  632. package/dist/test/mcpl-child-env.test.js.map +0 -1
  633. package/dist/test/mcpl-coalesced-content-parity.test.d.ts +0 -2
  634. package/dist/test/mcpl-coalesced-content-parity.test.d.ts.map +0 -1
  635. package/dist/test/mcpl-coalesced-content-parity.test.js +0 -532
  636. package/dist/test/mcpl-coalesced-content-parity.test.js.map +0 -1
  637. package/dist/test/mcpl-coalescing.test.d.ts +0 -2
  638. package/dist/test/mcpl-coalescing.test.d.ts.map +0 -1
  639. package/dist/test/mcpl-coalescing.test.js +0 -1125
  640. package/dist/test/mcpl-coalescing.test.js.map +0 -1
  641. package/dist/test/mcpl-config-diagnostics.test.d.ts +0 -2
  642. package/dist/test/mcpl-config-diagnostics.test.d.ts.map +0 -1
  643. package/dist/test/mcpl-config-diagnostics.test.js +0 -452
  644. package/dist/test/mcpl-config-diagnostics.test.js.map +0 -1
  645. package/dist/test/mcpl-empty-content.test.d.ts +0 -2
  646. package/dist/test/mcpl-empty-content.test.d.ts.map +0 -1
  647. package/dist/test/mcpl-empty-content.test.js +0 -368
  648. package/dist/test/mcpl-empty-content.test.js.map +0 -1
  649. package/dist/test/mcpl-gate-roundtrip.test.d.ts +0 -2
  650. package/dist/test/mcpl-gate-roundtrip.test.d.ts.map +0 -1
  651. package/dist/test/mcpl-gate-roundtrip.test.js +0 -285
  652. package/dist/test/mcpl-gate-roundtrip.test.js.map +0 -1
  653. package/dist/test/mcpl-list-status.test.d.ts +0 -2
  654. package/dist/test/mcpl-list-status.test.d.ts.map +0 -1
  655. package/dist/test/mcpl-list-status.test.js +0 -82
  656. package/dist/test/mcpl-list-status.test.js.map +0 -1
  657. package/dist/test/mcpl-manifest-changed.test.d.ts +0 -2
  658. package/dist/test/mcpl-manifest-changed.test.d.ts.map +0 -1
  659. package/dist/test/mcpl-manifest-changed.test.js +0 -178
  660. package/dist/test/mcpl-manifest-changed.test.js.map +0 -1
  661. package/dist/test/mcpl-push-convert.test.d.ts +0 -2
  662. package/dist/test/mcpl-push-convert.test.d.ts.map +0 -1
  663. package/dist/test/mcpl-push-convert.test.js +0 -42
  664. package/dist/test/mcpl-push-convert.test.js.map +0 -1
  665. package/dist/test/mcpl-reconnect-events.test.d.ts +0 -2
  666. package/dist/test/mcpl-reconnect-events.test.d.ts.map +0 -1
  667. package/dist/test/mcpl-reconnect-events.test.js +0 -144
  668. package/dist/test/mcpl-reconnect-events.test.js.map +0 -1
  669. package/dist/test/mcpl-reconnect-reregistration.test.d.ts +0 -2
  670. package/dist/test/mcpl-reconnect-reregistration.test.d.ts.map +0 -1
  671. package/dist/test/mcpl-reconnect-reregistration.test.js +0 -238
  672. package/dist/test/mcpl-reconnect-reregistration.test.js.map +0 -1
  673. package/dist/test/mcpl-reference-fetcher.test.d.ts +0 -2
  674. package/dist/test/mcpl-reference-fetcher.test.d.ts.map +0 -1
  675. package/dist/test/mcpl-reference-fetcher.test.js +0 -427
  676. package/dist/test/mcpl-reference-fetcher.test.js.map +0 -1
  677. package/dist/test/mcpl-reference-fields.test.d.ts +0 -2
  678. package/dist/test/mcpl-reference-fields.test.d.ts.map +0 -1
  679. package/dist/test/mcpl-reference-fields.test.js +0 -149
  680. package/dist/test/mcpl-reference-fields.test.js.map +0 -1
  681. package/dist/test/mcpl-rejection-log-lines.test.d.ts +0 -2
  682. package/dist/test/mcpl-rejection-log-lines.test.d.ts.map +0 -1
  683. package/dist/test/mcpl-rejection-log-lines.test.js +0 -349
  684. package/dist/test/mcpl-rejection-log-lines.test.js.map +0 -1
  685. package/dist/test/mcpl-request-timeout.test.d.ts +0 -2
  686. package/dist/test/mcpl-request-timeout.test.d.ts.map +0 -1
  687. package/dist/test/mcpl-request-timeout.test.js +0 -138
  688. package/dist/test/mcpl-request-timeout.test.js.map +0 -1
  689. package/dist/test/mcpl-runtime-lifecycle.test.d.ts +0 -7
  690. package/dist/test/mcpl-runtime-lifecycle.test.d.ts.map +0 -1
  691. package/dist/test/mcpl-runtime-lifecycle.test.js +0 -142
  692. package/dist/test/mcpl-runtime-lifecycle.test.js.map +0 -1
  693. package/dist/test/mcpl-stderr-tail.test.d.ts +0 -2
  694. package/dist/test/mcpl-stderr-tail.test.d.ts.map +0 -1
  695. package/dist/test/mcpl-stderr-tail.test.js +0 -210
  696. package/dist/test/mcpl-stderr-tail.test.js.map +0 -1
  697. package/dist/test/mcpl-tool-class-listing.test.d.ts +0 -2
  698. package/dist/test/mcpl-tool-class-listing.test.d.ts.map +0 -1
  699. package/dist/test/mcpl-tool-class-listing.test.js +0 -147
  700. package/dist/test/mcpl-tool-class-listing.test.js.map +0 -1
  701. package/dist/test/mcpl-tool-classes.test.d.ts +0 -7
  702. package/dist/test/mcpl-tool-classes.test.d.ts.map +0 -1
  703. package/dist/test/mcpl-tool-classes.test.js +0 -80
  704. package/dist/test/mcpl-tool-classes.test.js.map +0 -1
  705. package/dist/test/mcpl-tool-lifecycle-e2e.test.d.ts +0 -2
  706. package/dist/test/mcpl-tool-lifecycle-e2e.test.d.ts.map +0 -1
  707. package/dist/test/mcpl-tool-lifecycle-e2e.test.js +0 -237
  708. package/dist/test/mcpl-tool-lifecycle-e2e.test.js.map +0 -1
  709. package/dist/test/mcpl-tool-lifecycle-emitter.test.d.ts +0 -11
  710. package/dist/test/mcpl-tool-lifecycle-emitter.test.d.ts.map +0 -1
  711. package/dist/test/mcpl-tool-lifecycle-emitter.test.js +0 -412
  712. package/dist/test/mcpl-tool-lifecycle-emitter.test.js.map +0 -1
  713. package/dist/test/mcpl-tool-lifecycle-script.test.d.ts +0 -2
  714. package/dist/test/mcpl-tool-lifecycle-script.test.d.ts.map +0 -1
  715. package/dist/test/mcpl-tool-lifecycle-script.test.js +0 -288
  716. package/dist/test/mcpl-tool-lifecycle-script.test.js.map +0 -1
  717. package/dist/test/mcpl-tool-lifecycle.test.d.ts +0 -11
  718. package/dist/test/mcpl-tool-lifecycle.test.d.ts.map +0 -1
  719. package/dist/test/mcpl-tool-lifecycle.test.js +0 -270
  720. package/dist/test/mcpl-tool-lifecycle.test.js.map +0 -1
  721. package/dist/test/mcpl-transport-close.test.d.ts +0 -2
  722. package/dist/test/mcpl-transport-close.test.d.ts.map +0 -1
  723. package/dist/test/mcpl-transport-close.test.js +0 -373
  724. package/dist/test/mcpl-transport-close.test.js.map +0 -1
  725. package/dist/test/mcpl-transport-spawn.test.d.ts +0 -2
  726. package/dist/test/mcpl-transport-spawn.test.d.ts.map +0 -1
  727. package/dist/test/mcpl-transport-spawn.test.js +0 -58
  728. package/dist/test/mcpl-transport-spawn.test.js.map +0 -1
  729. package/dist/test/mcpl-ws-transport.test.d.ts +0 -2
  730. package/dist/test/mcpl-ws-transport.test.d.ts.map +0 -1
  731. package/dist/test/mcpl-ws-transport.test.js +0 -259
  732. package/dist/test/mcpl-ws-transport.test.js.map +0 -1
  733. package/dist/test/module-context-integration.test.d.ts +0 -18
  734. package/dist/test/module-context-integration.test.d.ts.map +0 -1
  735. package/dist/test/module-context-integration.test.js +0 -181
  736. package/dist/test/module-context-integration.test.js.map +0 -1
  737. package/dist/test/offline-recovery-branch.test.d.ts +0 -2
  738. package/dist/test/offline-recovery-branch.test.d.ts.map +0 -1
  739. package/dist/test/offline-recovery-branch.test.js +0 -570
  740. package/dist/test/offline-recovery-branch.test.js.map +0 -1
  741. package/dist/test/operator-surgery.test.d.ts +0 -2
  742. package/dist/test/operator-surgery.test.d.ts.map +0 -1
  743. package/dist/test/operator-surgery.test.js +0 -595
  744. package/dist/test/operator-surgery.test.js.map +0 -1
  745. package/dist/test/ops-alert.test.d.ts +0 -2
  746. package/dist/test/ops-alert.test.d.ts.map +0 -1
  747. package/dist/test/ops-alert.test.js +0 -153
  748. package/dist/test/ops-alert.test.js.map +0 -1
  749. package/dist/test/overbudget-drain-breaker.test.d.ts +0 -2
  750. package/dist/test/overbudget-drain-breaker.test.d.ts.map +0 -1
  751. package/dist/test/overbudget-drain-breaker.test.js +0 -198
  752. package/dist/test/overbudget-drain-breaker.test.js.map +0 -1
  753. package/dist/test/pack-installs-alone.test.d.ts +0 -2
  754. package/dist/test/pack-installs-alone.test.d.ts.map +0 -1
  755. package/dist/test/pack-installs-alone.test.js +0 -284
  756. package/dist/test/pack-installs-alone.test.js.map +0 -1
  757. package/dist/test/per-agent-delivery.test.d.ts +0 -2
  758. package/dist/test/per-agent-delivery.test.d.ts.map +0 -1
  759. package/dist/test/per-agent-delivery.test.js +0 -108
  760. package/dist/test/per-agent-delivery.test.js.map +0 -1
  761. package/dist/test/physical-window-restart.test.d.ts +0 -16
  762. package/dist/test/physical-window-restart.test.d.ts.map +0 -1
  763. package/dist/test/physical-window-restart.test.js +0 -487
  764. package/dist/test/physical-window-restart.test.js.map +0 -1
  765. package/dist/test/placed-reaction-baseline.test.d.ts +0 -2
  766. package/dist/test/placed-reaction-baseline.test.d.ts.map +0 -1
  767. package/dist/test/placed-reaction-baseline.test.js +0 -312
  768. package/dist/test/placed-reaction-baseline.test.js.map +0 -1
  769. package/dist/test/present-while-acting.test.d.ts +0 -19
  770. package/dist/test/present-while-acting.test.d.ts.map +0 -1
  771. package/dist/test/present-while-acting.test.js +0 -1649
  772. package/dist/test/present-while-acting.test.js.map +0 -1
  773. package/dist/test/prose-segments.test.d.ts +0 -2
  774. package/dist/test/prose-segments.test.d.ts.map +0 -1
  775. package/dist/test/prose-segments.test.js +0 -52
  776. package/dist/test/prose-segments.test.js.map +0 -1
  777. package/dist/test/prose-stream-router.test.d.ts +0 -2
  778. package/dist/test/prose-stream-router.test.d.ts.map +0 -1
  779. package/dist/test/prose-stream-router.test.js +0 -171
  780. package/dist/test/prose-stream-router.test.js.map +0 -1
  781. package/dist/test/provider-acceleration-cooldown.test.d.ts +0 -2
  782. package/dist/test/provider-acceleration-cooldown.test.d.ts.map +0 -1
  783. package/dist/test/provider-acceleration-cooldown.test.js +0 -435
  784. package/dist/test/provider-acceleration-cooldown.test.js.map +0 -1
  785. package/dist/test/provider-waits.test.d.ts +0 -2
  786. package/dist/test/provider-waits.test.d.ts.map +0 -1
  787. package/dist/test/provider-waits.test.js +0 -2259
  788. package/dist/test/provider-waits.test.js.map +0 -1
  789. package/dist/test/puppet-tool-call.test.d.ts +0 -2
  790. package/dist/test/puppet-tool-call.test.d.ts.map +0 -1
  791. package/dist/test/puppet-tool-call.test.js +0 -226
  792. package/dist/test/puppet-tool-call.test.js.map +0 -1
  793. package/dist/test/puppet-turn-reservation.test.d.ts +0 -2
  794. package/dist/test/puppet-turn-reservation.test.d.ts.map +0 -1
  795. package/dist/test/puppet-turn-reservation.test.js +0 -139
  796. package/dist/test/puppet-turn-reservation.test.js.map +0 -1
  797. package/dist/test/reaction-baseline-platform.test.d.ts +0 -2
  798. package/dist/test/reaction-baseline-platform.test.d.ts.map +0 -1
  799. package/dist/test/reaction-baseline-platform.test.js +0 -124
  800. package/dist/test/reaction-baseline-platform.test.js.map +0 -1
  801. package/dist/test/record-journal.test.d.ts +0 -6
  802. package/dist/test/record-journal.test.d.ts.map +0 -1
  803. package/dist/test/record-journal.test.js +0 -269
  804. package/dist/test/record-journal.test.js.map +0 -1
  805. package/dist/test/refusal-reaction-baseline.test.d.ts +0 -2
  806. package/dist/test/refusal-reaction-baseline.test.d.ts.map +0 -1
  807. package/dist/test/refusal-reaction-baseline.test.js +0 -81
  808. package/dist/test/refusal-reaction-baseline.test.js.map +0 -1
  809. package/dist/test/refusal-rewind.test.d.ts +0 -2
  810. package/dist/test/refusal-rewind.test.d.ts.map +0 -1
  811. package/dist/test/refusal-rewind.test.js +0 -117
  812. package/dist/test/refusal-rewind.test.js.map +0 -1
  813. package/dist/test/refusal-single-call.test.d.ts +0 -2
  814. package/dist/test/refusal-single-call.test.d.ts.map +0 -1
  815. package/dist/test/refusal-single-call.test.js +0 -177
  816. package/dist/test/refusal-single-call.test.js.map +0 -1
  817. package/dist/test/release-bump.test.d.ts +0 -2
  818. package/dist/test/release-bump.test.d.ts.map +0 -1
  819. package/dist/test/release-bump.test.js +0 -248
  820. package/dist/test/release-bump.test.js.map +0 -1
  821. package/dist/test/release-changelog.test.d.ts +0 -2
  822. package/dist/test/release-changelog.test.d.ts.map +0 -1
  823. package/dist/test/release-changelog.test.js +0 -159
  824. package/dist/test/release-changelog.test.js.map +0 -1
  825. package/dist/test/release-holds.test.d.ts +0 -2
  826. package/dist/test/release-holds.test.d.ts.map +0 -1
  827. package/dist/test/release-holds.test.js +0 -456
  828. package/dist/test/release-holds.test.js.map +0 -1
  829. package/dist/test/same-round-think-policy.test.d.ts +0 -2
  830. package/dist/test/same-round-think-policy.test.d.ts.map +0 -1
  831. package/dist/test/same-round-think-policy.test.js +0 -853
  832. package/dist/test/same-round-think-policy.test.js.map +0 -1
  833. package/dist/test/save-recent-image.test.d.ts +0 -26
  834. package/dist/test/save-recent-image.test.d.ts.map +0 -1
  835. package/dist/test/save-recent-image.test.js +0 -974
  836. package/dist/test/save-recent-image.test.js.map +0 -1
  837. package/dist/test/shutdown-errors.test.d.ts +0 -2
  838. package/dist/test/shutdown-errors.test.d.ts.map +0 -1
  839. package/dist/test/shutdown-errors.test.js +0 -662
  840. package/dist/test/shutdown-errors.test.js.map +0 -1
  841. package/dist/test/silent-heartbeat-rows.test.d.ts +0 -2
  842. package/dist/test/silent-heartbeat-rows.test.d.ts.map +0 -1
  843. package/dist/test/silent-heartbeat-rows.test.js +0 -451
  844. package/dist/test/silent-heartbeat-rows.test.js.map +0 -1
  845. package/dist/test/silent-heartbeat.test.d.ts +0 -2
  846. package/dist/test/silent-heartbeat.test.d.ts.map +0 -1
  847. package/dist/test/silent-heartbeat.test.js +0 -165
  848. package/dist/test/silent-heartbeat.test.js.map +0 -1
  849. package/dist/test/state-scaling-e2e.test.d.ts +0 -22
  850. package/dist/test/state-scaling-e2e.test.d.ts.map +0 -1
  851. package/dist/test/state-scaling-e2e.test.js +0 -206
  852. package/dist/test/state-scaling-e2e.test.js.map +0 -1
  853. package/dist/test/state-scaling.test.d.ts +0 -12
  854. package/dist/test/state-scaling.test.d.ts.map +0 -1
  855. package/dist/test/state-scaling.test.js +0 -251
  856. package/dist/test/state-scaling.test.js.map +0 -1
  857. package/dist/test/stop-with-host-operations.test.d.ts +0 -20
  858. package/dist/test/stop-with-host-operations.test.d.ts.map +0 -1
  859. package/dist/test/stop-with-host-operations.test.js +0 -1174
  860. package/dist/test/stop-with-host-operations.test.js.map +0 -1
  861. package/dist/test/stop-with-work-in-flight.test.d.ts +0 -23
  862. package/dist/test/stop-with-work-in-flight.test.d.ts.map +0 -1
  863. package/dist/test/stop-with-work-in-flight.test.js +0 -784
  864. package/dist/test/stop-with-work-in-flight.test.js.map +0 -1
  865. package/dist/test/surgery-marks-receipt.test.d.ts +0 -2
  866. package/dist/test/surgery-marks-receipt.test.d.ts.map +0 -1
  867. package/dist/test/surgery-marks-receipt.test.js +0 -540
  868. package/dist/test/surgery-marks-receipt.test.js.map +0 -1
  869. package/dist/test/thinking-token-stamp.test.d.ts +0 -12
  870. package/dist/test/thinking-token-stamp.test.d.ts.map +0 -1
  871. package/dist/test/thinking-token-stamp.test.js +0 -129
  872. package/dist/test/thinking-token-stamp.test.js.map +0 -1
  873. package/dist/test/timezone.test.d.ts +0 -2
  874. package/dist/test/timezone.test.d.ts.map +0 -1
  875. package/dist/test/timezone.test.js +0 -18
  876. package/dist/test/timezone.test.js.map +0 -1
  877. package/dist/test/tool-batch-hook.test.d.ts +0 -8
  878. package/dist/test/tool-batch-hook.test.d.ts.map +0 -1
  879. package/dist/test/tool-batch-hook.test.js +0 -275
  880. package/dist/test/tool-batch-hook.test.js.map +0 -1
  881. package/dist/test/tool-policy.test.d.ts +0 -2
  882. package/dist/test/tool-policy.test.d.ts.map +0 -1
  883. package/dist/test/tool-policy.test.js +0 -51
  884. package/dist/test/tool-policy.test.js.map +0 -1
  885. package/dist/test/tool-presentation.test.d.ts +0 -2
  886. package/dist/test/tool-presentation.test.d.ts.map +0 -1
  887. package/dist/test/tool-presentation.test.js +0 -268
  888. package/dist/test/tool-presentation.test.js.map +0 -1
  889. package/dist/test/tool-result-content.test.d.ts +0 -2
  890. package/dist/test/tool-result-content.test.d.ts.map +0 -1
  891. package/dist/test/tool-result-content.test.js +0 -37
  892. package/dist/test/tool-result-content.test.js.map +0 -1
  893. package/dist/test/tool-result-guard.test.d.ts +0 -2
  894. package/dist/test/tool-result-guard.test.d.ts.map +0 -1
  895. package/dist/test/tool-result-guard.test.js +0 -3729
  896. package/dist/test/tool-result-guard.test.js.map +0 -1
  897. package/dist/test/tool-result-history.test.d.ts +0 -7
  898. package/dist/test/tool-result-history.test.d.ts.map +0 -1
  899. package/dist/test/tool-result-history.test.js +0 -156
  900. package/dist/test/tool-result-history.test.js.map +0 -1
  901. package/dist/test/tool-result-spill.test.d.ts +0 -13
  902. package/dist/test/tool-result-spill.test.d.ts.map +0 -1
  903. package/dist/test/tool-result-spill.test.js +0 -586
  904. package/dist/test/tool-result-spill.test.js.map +0 -1
  905. package/dist/test/tool-wrapper-prose-guard-integration.test.d.ts +0 -2
  906. package/dist/test/tool-wrapper-prose-guard-integration.test.d.ts.map +0 -1
  907. package/dist/test/tool-wrapper-prose-guard-integration.test.js +0 -485
  908. package/dist/test/tool-wrapper-prose-guard-integration.test.js.map +0 -1
  909. package/dist/test/tool-wrapper-prose-guard.test.d.ts +0 -2
  910. package/dist/test/tool-wrapper-prose-guard.test.d.ts.map +0 -1
  911. package/dist/test/tool-wrapper-prose-guard.test.js +0 -34
  912. package/dist/test/tool-wrapper-prose-guard.test.js.map +0 -1
  913. package/dist/test/tools-observe-parser-conformance.test.d.ts +0 -2
  914. package/dist/test/tools-observe-parser-conformance.test.d.ts.map +0 -1
  915. package/dist/test/tools-observe-parser-conformance.test.js +0 -129
  916. package/dist/test/tools-observe-parser-conformance.test.js.map +0 -1
  917. package/dist/test/trunk-channel-routing.test.d.ts +0 -19
  918. package/dist/test/trunk-channel-routing.test.d.ts.map +0 -1
  919. package/dist/test/trunk-channel-routing.test.js +0 -652
  920. package/dist/test/trunk-channel-routing.test.js.map +0 -1
  921. package/dist/test/tune-out-e2e.test.d.ts +0 -2
  922. package/dist/test/tune-out-e2e.test.d.ts.map +0 -1
  923. package/dist/test/tune-out-e2e.test.js +0 -142
  924. package/dist/test/tune-out-e2e.test.js.map +0 -1
  925. package/dist/test/tune-out-gate-composition.test.d.ts +0 -2
  926. package/dist/test/tune-out-gate-composition.test.d.ts.map +0 -1
  927. package/dist/test/tune-out-gate-composition.test.js +0 -221
  928. package/dist/test/tune-out-gate-composition.test.js.map +0 -1
  929. package/dist/test/tune-out-lifecycle.test.d.ts +0 -2
  930. package/dist/test/tune-out-lifecycle.test.d.ts.map +0 -1
  931. package/dist/test/tune-out-lifecycle.test.js +0 -121
  932. package/dist/test/tune-out-lifecycle.test.js.map +0 -1
  933. package/dist/test/turn-trigger-provenance.test.d.ts +0 -2
  934. package/dist/test/turn-trigger-provenance.test.d.ts.map +0 -1
  935. package/dist/test/turn-trigger-provenance.test.js +0 -137
  936. package/dist/test/turn-trigger-provenance.test.js.map +0 -1
  937. package/dist/test/unconvertible-tool-result.test.d.ts +0 -2
  938. package/dist/test/unconvertible-tool-result.test.d.ts.map +0 -1
  939. package/dist/test/unconvertible-tool-result.test.js +0 -358
  940. package/dist/test/unconvertible-tool-result.test.js.map +0 -1
  941. package/dist/test/unsent-compiles.test.d.ts +0 -2
  942. package/dist/test/unsent-compiles.test.d.ts.map +0 -1
  943. package/dist/test/unsent-compiles.test.js +0 -139
  944. package/dist/test/unsent-compiles.test.js.map +0 -1
  945. package/dist/test/usage-accounting.test.d.ts +0 -2
  946. package/dist/test/usage-accounting.test.d.ts.map +0 -1
  947. package/dist/test/usage-accounting.test.js +0 -13
  948. package/dist/test/usage-accounting.test.js.map +0 -1
  949. package/dist/test/usage-tracker.test.d.ts +0 -2
  950. package/dist/test/usage-tracker.test.d.ts.map +0 -1
  951. package/dist/test/usage-tracker.test.js +0 -129
  952. package/dist/test/usage-tracker.test.js.map +0 -1
  953. package/dist/test/utils-surface.test.d.ts +0 -2
  954. package/dist/test/utils-surface.test.d.ts.map +0 -1
  955. package/dist/test/utils-surface.test.js +0 -145
  956. package/dist/test/utils-surface.test.js.map +0 -1
  957. package/dist/test/workspace-branch-continuation.test.d.ts +0 -15
  958. package/dist/test/workspace-branch-continuation.test.d.ts.map +0 -1
  959. package/dist/test/workspace-branch-continuation.test.js +0 -183
  960. package/dist/test/workspace-branch-continuation.test.js.map +0 -1
  961. package/dist/test/workspace-materialize-freshness.test.d.ts +0 -16
  962. package/dist/test/workspace-materialize-freshness.test.d.ts.map +0 -1
  963. package/dist/test/workspace-materialize-freshness.test.js +0 -252
  964. package/dist/test/workspace-materialize-freshness.test.js.map +0 -1
  965. package/dist/test/workspace-path-containment.test.d.ts +0 -19
  966. package/dist/test/workspace-path-containment.test.d.ts.map +0 -1
  967. package/dist/test/workspace-path-containment.test.js +0 -91
  968. package/dist/test/workspace-path-containment.test.js.map +0 -1
  969. package/dist/test/workspace-read-file-from-disk.test.d.ts +0 -17
  970. package/dist/test/workspace-read-file-from-disk.test.d.ts.map +0 -1
  971. package/dist/test/workspace-read-file-from-disk.test.js +0 -174
  972. package/dist/test/workspace-read-file-from-disk.test.js.map +0 -1
  973. package/dist/test/workspace-read-image.test.d.ts +0 -2
  974. package/dist/test/workspace-read-image.test.d.ts.map +0 -1
  975. package/dist/test/workspace-read-image.test.js +0 -597
  976. package/dist/test/workspace-read-image.test.js.map +0 -1
  977. package/dist/test/workspace-read-text.test.d.ts +0 -2
  978. package/dist/test/workspace-read-text.test.d.ts.map +0 -1
  979. package/dist/test/workspace-read-text.test.js +0 -101
  980. package/dist/test/workspace-read-text.test.js.map +0 -1
  981. package/dist/test/workspace-restore-order.test.d.ts +0 -16
  982. package/dist/test/workspace-restore-order.test.d.ts.map +0 -1
  983. package/dist/test/workspace-restore-order.test.js +0 -140
  984. package/dist/test/workspace-restore-order.test.js.map +0 -1
  985. package/dist/test/workspace-three-way.test.d.ts +0 -12
  986. package/dist/test/workspace-three-way.test.d.ts.map +0 -1
  987. package/dist/test/workspace-three-way.test.js +0 -4094
  988. package/dist/test/workspace-three-way.test.js.map +0 -1
  989. package/dist/test/workspace-watcher.test.d.ts +0 -2
  990. package/dist/test/workspace-watcher.test.d.ts.map +0 -1
  991. package/dist/test/workspace-watcher.test.js +0 -281
  992. package/dist/test/workspace-watcher.test.js.map +0 -1
  993. package/dist/test/xml-round-persist.test.d.ts +0 -19
  994. package/dist/test/xml-round-persist.test.d.ts.map +0 -1
  995. package/dist/test/xml-round-persist.test.js +0 -235
  996. package/dist/test/xml-round-persist.test.js.map +0 -1
  997. package/dist/tsconfig.tsbuildinfo +0 -1
@@ -1,1174 +0,0 @@
1
- /**
2
- * stop() and an operator's operations.
3
- *
4
- * Once stop() has begun, an operator's entry points refuse: quiesce, resume,
5
- * the store surgeries, a branch switch, undo, redo, maintain, puppet, the
6
- * awareness sync and the MCPL lifecycle calls (a host/command is refused by
7
- * its listener). The marks' delivery a branch move starts isn't one of these
8
- * operations: stop() doesn't wait for it, and starts none once it has begun.
9
- * These tests cover those refusals and the operations admitted before them, over
10
- * MCPL or from a direct call: stop() waits for each, and for what each starts
11
- * while it waits, before the event gate, the modules, the MCPL connections
12
- * and the store go. A budget can cut that wait short, leaving the store open.
13
- *
14
- * Where a test holds an operation open, it lets it go once stop() reads a
15
- * nonempty set of operations to wait on, or reaches its modules' teardown.
16
- * main reaches teardown without reading any such set, so the order of the
17
- * two events is the verdict, and it doesn't depend on timing.
18
- */
19
- import { describe, it, beforeEach, afterEach } from 'node:test';
20
- import assert from 'node:assert/strict';
21
- import { EventEmitter } from 'node:events';
22
- import { existsSync, mkdtempSync, readFileSync, rmSync } from 'node:fs';
23
- import { tmpdir } from 'node:os';
24
- import { join } from 'node:path';
25
- import { AgentFramework, OperatorActionError, ShutdownTimeoutError } from '../src/index.js';
26
- import { ApiServer } from '../src/api/server.js';
27
- import { MockMembrane } from './helpers/mock-membrane.js';
28
- /** Resolve once `cond` holds; fail, naming `what`, after `ms`. */
29
- async function until(cond, what, ms = 5000) {
30
- const deadline = Date.now() + ms;
31
- while (!cond()) {
32
- if (Date.now() > deadline)
33
- throw new Error(`timed out waiting for ${what}`);
34
- await new Promise((r) => setTimeout(r, 5));
35
- }
36
- }
37
- /** Records when stop() reaches its modules' teardown, which comes after its wait for operations. */
38
- class TeardownProbe {
39
- order;
40
- name = 'teardown-probe';
41
- constructor(order) {
42
- this.order = order;
43
- }
44
- async start(_ctx) { }
45
- async stop() { this.order.push('modules stopped'); }
46
- getTools() { return []; }
47
- async handleToolCall() { return { success: false, error: 'no tools' }; }
48
- async onProcess() { return {}; }
49
- }
50
- const internals = (framework) => framework;
51
- describe('stop() with an operator operation in flight', () => {
52
- let tempDir;
53
- let storePath;
54
- let logged;
55
- let rejections;
56
- let order;
57
- let waitReads;
58
- const onRejection = (reason) => { rejections.push(reason); };
59
- const consoleError = console.error;
60
- const consoleWarn = console.warn;
61
- beforeEach(() => {
62
- tempDir = mkdtempSync(join(tmpdir(), 'af-stop-host-ops-'));
63
- storePath = join(tempDir, 'store');
64
- logged = [];
65
- rejections = [];
66
- order = [];
67
- waitReads = 0;
68
- process.on('unhandledRejection', onRejection);
69
- console.error = (...args) => { logged.push(args.map(String).join(' ')); };
70
- console.warn = (...args) => { logged.push(args.map(String).join(' ')); };
71
- });
72
- afterEach(() => {
73
- console.error = consoleError;
74
- console.warn = consoleWarn;
75
- process.off('unhandledRejection', onRejection);
76
- rmSync(tempDir, { recursive: true, force: true });
77
- });
78
- async function create() {
79
- const framework = await AgentFramework.create({
80
- storePath,
81
- membrane: new MockMembrane().asMembrane(),
82
- agents: [{ name: 'agent', model: 'test-model', systemPrompt: 'test' }],
83
- modules: [new TeardownProbe(order)],
84
- });
85
- internals(framework).operatorOperations = new class extends Set {
86
- [Symbol.iterator]() {
87
- if (this.size > 0)
88
- waitReads++;
89
- return super[Symbol.iterator]();
90
- }
91
- }();
92
- return framework;
93
- }
94
- /** A positive observation releases the hold. Main reaches module teardown
95
- * without reading the set, making the wrong order observable too. */
96
- async function releaseWhenStopWaits(release) {
97
- try {
98
- await until(() => waitReads > 0 || order.includes('modules stopped'), 'stop to read pending operations or stop its modules', 30_000);
99
- }
100
- finally {
101
- release();
102
- }
103
- }
104
- async function bootsQuiesced() {
105
- const restarted = await create();
106
- try {
107
- return restarted.getHostModeStatus().quiesced;
108
- }
109
- finally {
110
- await restarted.stop();
111
- }
112
- }
113
- it('a quiesce waiting for its drain stops waiting when stop() begins, and stop() waits for it', { timeout: 20_000 }, async () => {
114
- const framework = await create();
115
- framework.start();
116
- // A turn between dequeue and stream registration holds its token with no
117
- // stream to cancel. Stop cuts the drain short; the token remains alive.
118
- const tokens = internals(framework).activeTurnTokens;
119
- tokens.set('agent', -1);
120
- let settled = false;
121
- const traces = [];
122
- framework.onTrace((event) => { traces.push(event.type); });
123
- const quiescing = framework.quiesce({ reason: 'surgery', timeoutMs: 600_000 });
124
- void quiescing.then(() => { settled = true; }, () => { settled = true; });
125
- const stopping = framework.stop();
126
- try {
127
- await until(() => settled || order.includes('modules stopped'), 'stop to interrupt the quiesce or reach teardown', 10_000);
128
- await stopping;
129
- assert.equal(settled, true, 'stop() returned while the quiesce was still waiting');
130
- const status = await quiescing;
131
- assert.equal(status.quiesced, true);
132
- assert.equal(status.drained, false);
133
- assert.ok(!traces.includes('host:quiesce'), 'an interrupted drain reports no completed quiesce');
134
- assert.ok(logged.some((line) => line.includes('quiesce stopped waiting for its drain: the framework is stopping')), logged.join('\n'));
135
- }
136
- finally {
137
- tokens.delete('agent');
138
- await quiescing.catch(() => { });
139
- await stopping;
140
- }
141
- assert.equal(await bootsQuiesced(), true, 'the host boots quiesced');
142
- assert.deepEqual(rejections, []);
143
- });
144
- it("an abandon waiting on a turn it can't cancel stops waiting when stop() begins, and stop() waits for it", { timeout: 20_000 }, async () => {
145
- const framework = await create();
146
- framework.start();
147
- const tokens = internals(framework).activeTurnTokens;
148
- tokens.set('agent', -1);
149
- let settled = false;
150
- const quiescing = framework.quiesce({ timeoutMs: 1_000, abandon: true });
151
- void quiescing.then(() => { settled = true; }, () => { settled = true; });
152
- try {
153
- // After its one-second window, abandon finds no stream to cancel and
154
- // gives the turn ten seconds to settle on its own.
155
- await until(() => logged.some((line) => line.includes('cannot abandon turn for agent')), 'abandon to find the held token');
156
- const began = Date.now();
157
- await framework.stop();
158
- const took = Date.now() - began;
159
- assert.equal(settled, true, 'stop() returned while the abandon was still waiting');
160
- // Only waiting out the ten-second grace should consume this bound.
161
- assert.ok(took < 8_000, `stop() took ${took} ms, waiting out the abandon's ten seconds`);
162
- assert.deepEqual((await quiescing).unabandonable, ['agent']);
163
- }
164
- finally {
165
- tokens.delete('agent');
166
- await quiescing.catch(() => { });
167
- }
168
- assert.deepEqual(rejections, []);
169
- });
170
- it('a resume waiting when stop() begins refuses, and the host stays quiesced', async () => {
171
- const framework = await create();
172
- framework.start();
173
- await framework.quiesce({ reason: 'surgery' });
174
- // resume() waits for a running maintenance pass before its feasibility
175
- // gate, and so does stop(): both go on when the pass ends.
176
- let endPass;
177
- internals(framework).maintenancePass = new Promise((resolve) => { endPass = resolve; });
178
- const resuming = framework.resume();
179
- const stopping = framework.stop();
180
- endPass();
181
- await assert.rejects(resuming, /^Error: resume refused: the framework is stopping, so the host stays quiesced$/);
182
- await stopping;
183
- assert.equal(await bootsQuiesced(), true, 'the host boots quiesced');
184
- assert.deepEqual(rejections, []);
185
- });
186
- it('a quiesce called after stop() is refused, and persists nothing', async () => {
187
- const framework = await create();
188
- await framework.stop();
189
- await assert.rejects(framework.quiesce({ reason: 'too late' }), /^Error: quiesce refused: the framework is stopping$/);
190
- assert.equal(await bootsQuiesced(), false, 'the host boots serving');
191
- });
192
- it('a resume called after stop() is refused, and the host stays quiesced', async () => {
193
- const framework = await create();
194
- await framework.quiesce();
195
- await framework.stop();
196
- await assert.rejects(framework.resume(), /^Error: resume refused: the framework is stopping$/);
197
- assert.equal(await bootsQuiesced(), true, 'the host boots quiesced');
198
- });
199
- it('stop() waits for a resume past its commit point, and a reopen that fails is released, not recycled', async () => {
200
- const framework = await create();
201
- const connection = {
202
- id: 'srv',
203
- recycled: 0,
204
- readied: 0,
205
- pauseDataPlane() { },
206
- readyControlPlane() { },
207
- ready() { this.readied++; },
208
- async reconnectAfterFailure() { this.recycled++; },
209
- };
210
- const fw = internals(framework);
211
- fw.mcplServerRegistry = { getAllServers: () => [connection], closeAll: async () => { } };
212
- const failures = [];
213
- framework.onTrace((event) => {
214
- if (event.type === 'mcpl:server-error')
215
- failures.push(String(event.serverId));
216
- });
217
- framework.start();
218
- await framework.quiesce();
219
- // The reopen waits on the awareness barrier, which fails while stop() waits.
220
- let failBarrier;
221
- fw.beginDiscordAwarenessBarrier = () => ({
222
- requiresBarrier: true,
223
- promise: new Promise((_, reject) => { failBarrier = reject; }),
224
- });
225
- const resuming = framework.resume().then((status) => { order.push('resume settled'); return status; });
226
- await until(() => failBarrier !== undefined, 'the resume to reach its reopen');
227
- const stopping = framework.stop();
228
- await releaseWhenStopWaits(() => failBarrier(new Error('the awareness drain failed')));
229
- await stopping;
230
- assert.deepEqual(order, ['resume settled', 'modules stopped']);
231
- assert.equal((await resuming).quiesced, false, 'past its commit point the resume completes');
232
- assert.deepEqual(failures, ['srv'], 'the failure is still reported');
233
- assert.equal(connection.recycled, 0, 'a stopping host recycles no connection');
234
- assert.equal(fw.discordAwarenessBarrier, null, 'the failed barrier is released');
235
- assert.equal(connection.readied, 1, 'its data plane opens, so the listeners answer what it held back');
236
- assert.equal(await bootsQuiesced(), false, 'its durable clear landed');
237
- assert.deepEqual(rejections, []);
238
- });
239
- it("stop() waits for a host/command, so its answer goes out before the connections close", async () => {
240
- const framework = await create();
241
- const connection = Object.assign(new EventEmitter(), { id: 'srv' });
242
- internals(framework).wireMcplEvents(connection);
243
- const cm = framework.getAgent('agent').getContextManager();
244
- for (const n of [1, 2]) {
245
- cm.addMessage('user', [{ type: 'text', text: `m${n}` }], { serverId: 'srv', channelId: 'discord:g1:c1', messageId: `d${n}` });
246
- }
247
- // hide's answer carries a preview of what the agent sees now; hold it.
248
- let release;
249
- const held = new Promise((resolve) => { release = resolve; });
250
- const preview = framework.previewActivation.bind(framework);
251
- let previewing = false;
252
- framework.previewActivation = (async (...args) => {
253
- previewing = true;
254
- await held;
255
- return preview(...args);
256
- });
257
- const answers = [];
258
- connection.emit('host-command', { command: 'hide', agentName: 'agent', fromMessageId: 'd1' }, {
259
- id: 7,
260
- respond: (result) => { answers.push(result); order.push('host/command answered'); },
261
- respondError: (code, message) => { answers.push({ code, message }); order.push('host/command answered'); },
262
- });
263
- await until(() => previewing, 'hide to reach its preview');
264
- const stopping = framework.stop();
265
- await releaseWhenStopWaits(release);
266
- await stopping;
267
- assert.deepEqual(order, ['host/command answered', 'modules stopped']);
268
- assert.equal(answers[0].ok, true, JSON.stringify(answers));
269
- assert.equal(answers[0].hidden, 1);
270
- assert.deepEqual(rejections, []);
271
- });
272
- it('stop() waits for a store surgery to release the store', async () => {
273
- const framework = await create();
274
- const cm = framework.getAgent('agent').getContextManager();
275
- const ids = [1, 2, 3].map((n) => cm.addMessage('user', [{ type: 'text', text: `m${n}` }]));
276
- // The rollback moves the branch while it holds the store; hold that.
277
- let release;
278
- const held = new Promise((resolve) => { release = resolve; });
279
- let switching = false;
280
- const switchBranch = cm.switchBranch.bind(cm);
281
- cm.switchBranch = async (...args) => {
282
- switching = true;
283
- await held;
284
- const switched = await switchBranch(...args);
285
- order.push('branch moved');
286
- return switched;
287
- };
288
- const rolling = framework.rollbackToMessage('agent', { messageId: ids[0] });
289
- await until(() => switching, 'the rollback to reach its branch move');
290
- const stopping = framework.stop();
291
- await releaseWhenStopWaits(release);
292
- await stopping;
293
- assert.deepEqual(order, ['branch moved', 'modules stopped']);
294
- assert.equal((await rolling).messagesRemoved, 2);
295
- // Its marks' delivery would race the teardown, so it's left to the next start.
296
- assert.ok(logged.some((line) => line.includes('delivery after rollback agent=agent not started')), logged.join('\n'));
297
- assert.deepEqual(rejections, []);
298
- });
299
- it('stop() waits for an awareness sync already running', async () => {
300
- const framework = await create();
301
- let deliver;
302
- internals(framework).beginDiscordAwarenessBarrier = () => ({
303
- requiresBarrier: true,
304
- promise: new Promise((resolve) => {
305
- deliver = () => resolve({ status: 'delivered', delivered: 1, failed: 0 });
306
- }),
307
- });
308
- const syncing = framework.syncDiscordAwarenessMarkers().then(() => { order.push('awareness synced'); });
309
- await until(() => deliver !== undefined, 'the sync to wait on its barrier');
310
- const stopping = framework.stop();
311
- await releaseWhenStopWaits(() => deliver());
312
- await stopping;
313
- await syncing;
314
- assert.deepEqual(order, ['awareness synced', 'modules stopped']);
315
- assert.deepEqual(rejections, []);
316
- });
317
- it("a stop() called from a trace inside stop()'s own start gets the same attempt, and one teardown runs", async () => {
318
- const framework = await create();
319
- const fw = framework;
320
- // A coalescer with a render in flight reports it from suspend(), the first
321
- // thing stop() does, as a trace.
322
- let suspended = false;
323
- fw.pushCoalescer = {
324
- suspend: () => {
325
- if (suspended)
326
- return;
327
- suspended = true;
328
- fw.emitTrace({ type: 'mcpl:coalescing', phase: 'suspended' });
329
- },
330
- };
331
- // A turn to undo, so an admitted undo would move the branch.
332
- const record = framework.recordTurnCheckpoint.bind(framework);
333
- record('agent');
334
- framework.getAgent('agent').getContextManager().addMessage('user', [{ type: 'text', text: 'a turn' }]);
335
- const connection = Object.assign(new EventEmitter(), { id: 'srv' });
336
- internals(framework).wireMcplEvents(connection);
337
- let barriers = 0;
338
- internals(framework).beginDiscordAwarenessBarrier = () => {
339
- barriers++;
340
- return { requiresBarrier: false, promise: Promise.resolve({ status: 'delivered', delivered: 0, failed: 0 }) };
341
- };
342
- let inner;
343
- let undoInside;
344
- let syncInside;
345
- let hostUndo;
346
- framework.onTrace((event) => {
347
- if (event.type !== 'mcpl:coalescing' || inner)
348
- return;
349
- inner = framework.stop();
350
- // stop() has begun, though its queue isn't closed yet.
351
- try {
352
- framework.undoLastTurn('agent');
353
- }
354
- catch (error) {
355
- undoInside = error;
356
- }
357
- syncInside = framework.syncDiscordAwarenessMarkers();
358
- void syncInside.catch(() => { });
359
- framework.startDiscordAwarenessDelivery('probe');
360
- connection.emit('host-command', { command: 'undo', agentName: 'agent', turns: 1 }, {
361
- respond: (result) => { hostUndo = { respond: result }; },
362
- respondError: (code, message) => { hostUndo = { code, message }; },
363
- });
364
- });
365
- const outer = framework.stop();
366
- assert.equal(inner, outer, 'the reentrant stop() gets the attempt already running');
367
- assert.match(String(undoInside), /^Error: undo refused: the framework is stopping$/);
368
- await assert.rejects(syncInside, /^Error: awareness sync refused: the framework is stopping$/);
369
- assert.ok(logged.some((line) => line.includes('delivery after probe agent=framework not started')), logged.join('\n'));
370
- assert.equal(barriers, 0, 'neither the sync nor the delivery reached a barrier');
371
- assert.deepEqual(hostUndo, { code: -32000, message: 'the host is stopping' });
372
- assert.equal(framework.getStore().currentBranch().name, 'main', 'nothing moved the branch');
373
- await outer;
374
- assert.deepEqual(order, ['modules stopped'], 'one teardown');
375
- assert.equal(framework.getStore().isClosed(), true);
376
- await framework.stop();
377
- assert.deepEqual(rejections, []);
378
- });
379
- it('an awareness sync after a stop() that failed is refused', async () => {
380
- const framework = await create();
381
- const fw = framework;
382
- // A runner whose dispose throws fails stop() after the queue has closed,
383
- // before stop() reaches its wait on the operator set.
384
- fw.codeExecutionRunners.set('agent', { dispose() { throw new Error('dispose failed'); } });
385
- await assert.rejects(framework.stop(), /dispose failed/);
386
- await assert.rejects(framework.syncDiscordAwarenessMarkers(), /^Error: awareness sync refused: the framework is stopping$/);
387
- fw.codeExecutionRunners.clear();
388
- await framework.stop();
389
- assert.equal(framework.getStore().isClosed(), true);
390
- });
391
- it('an awareness sync called once stop() has begun is refused, and installs no barrier', async () => {
392
- const framework = await create();
393
- let barriers = 0;
394
- internals(framework).beginDiscordAwarenessBarrier = () => {
395
- barriers++;
396
- return { requiresBarrier: false, promise: Promise.resolve({ status: 'delivered', delivered: 0, failed: 0 }) };
397
- };
398
- let finishModules;
399
- const hold = new Promise((resolve) => { finishModules = resolve; });
400
- framework.getModule('teardown-probe').stop = async () => {
401
- order.push('modules stopped');
402
- await hold;
403
- };
404
- const stopping = framework.stop();
405
- try {
406
- await until(() => order.includes('modules stopped'), 'module teardown');
407
- await assert.rejects(framework.syncDiscordAwarenessMarkers(), /^Error: awareness sync refused: the framework is stopping$/);
408
- assert.equal(barriers, 0);
409
- }
410
- finally {
411
- finishModules();
412
- await stopping;
413
- }
414
- await assert.rejects(framework.syncDiscordAwarenessMarkers(), /^Error: awareness sync refused: the framework is stopping$/);
415
- assert.equal(barriers, 0);
416
- });
417
- for (const action of ['rollback', 'suppress'])
418
- it('a ' + action + " whose branch move outlasts stop()'s budget still finishes, and leaves its marks' delivery to the next start", { timeout: 20_000 }, async () => {
419
- // The surgery was admitted before stop() began, so nothing refuses it
420
- // partway. Its marks' delivery isn't started while the framework stops:
421
- // the durable outbox keeps them for the next start.
422
- const framework = await create();
423
- const cm = framework.getAgent('agent').getContextManager();
424
- const ids = [1, 2, 3].map((n) => cm.addMessage('user', [{ type: 'text', text: 'm' + n }]));
425
- let finishMove;
426
- const moveHold = new Promise((resolve) => { finishMove = resolve; });
427
- if (action === 'rollback') {
428
- const switchBranch = cm.switchBranch.bind(cm);
429
- cm.switchBranch = async (...args) => { await moveHold; return switchBranch(...args); };
430
- }
431
- else {
432
- const fork = cm.fork.bind(cm);
433
- cm.fork = async (...args) => { await moveHold; return fork(...args); };
434
- }
435
- let barriers = 0;
436
- internals(framework).beginDiscordAwarenessBarrier = () => {
437
- barriers++;
438
- return { requiresBarrier: false, promise: Promise.resolve({ status: 'delivered', delivered: 0, failed: 0 }) };
439
- };
440
- const surgery = action === 'rollback'
441
- ? framework.rollbackToMessage('agent', { messageId: ids[0] })
442
- : framework.suppressMessages('agent', { messageIds: [ids[1]] });
443
- void surgery.catch(() => { });
444
- try {
445
- await assert.rejects(framework.stop(100), (error) => error instanceof ShutdownTimeoutError && error.pending.includes('surgery:' + (action === 'rollback' ? 'roll back' : 'suppress')));
446
- }
447
- finally {
448
- finishMove();
449
- }
450
- const result = await surgery;
451
- assert.ok(result.messagesRemoved > 0, JSON.stringify(result));
452
- assert.equal(barriers, 0, 'no delivery started while the framework stops');
453
- assert.ok(logged.some((line) => line.includes('delivery after ' + action + ' agent=agent not started')), logged.join('\n'));
454
- await framework.stop();
455
- assert.equal(framework.getStore().isClosed(), true);
456
- assert.deepEqual(rejections, []);
457
- });
458
- it("an operation that outlasts stop()'s budget fails the stop and keeps the store open for a retry", async () => {
459
- const framework = await create();
460
- let deliver;
461
- internals(framework).beginDiscordAwarenessBarrier = () => ({
462
- requiresBarrier: true,
463
- promise: new Promise((resolve) => {
464
- deliver = () => resolve({ status: 'delivered', delivered: 1, failed: 0 });
465
- }),
466
- });
467
- const syncing = framework.syncDiscordAwarenessMarkers();
468
- await until(() => deliver !== undefined, 'the sync to wait on its barrier');
469
- await assert.rejects(framework.stop(100), (error) => error instanceof ShutdownTimeoutError
470
- && error.pending.includes('awareness:sync')
471
- && /^Shutdown timed out after 100 ms; pending: awareness:sync$/.test(error.message));
472
- assert.equal(framework.getStore().isClosed(), false, 'the operation may still write');
473
- assert.ok(order.includes('modules stopped'), 'timeout still proceeds with teardown');
474
- // Bounded: a sync admitted here would wait on a barrier of its own, so it
475
- // fails the test rather than hanging it.
476
- const late = framework.syncDiscordAwarenessMarkers().then(() => 'admitted', (error) => String(error));
477
- const stillRunning = new Promise((resolve) => { setTimeout(() => resolve('still running'), 1_000).unref(); });
478
- assert.equal(await Promise.race([late, stillRunning]), 'Error: awareness sync refused: the framework is stopping', 'no stop() is waiting now, so a new sync is refused');
479
- await assert.rejects(framework.stop(100), (error) => error instanceof ShutdownTimeoutError && error.pending.includes('awareness:sync'));
480
- assert.equal(framework.getStore().isClosed(), false, 'a still-running retry keeps the store open too');
481
- deliver();
482
- await syncing;
483
- await framework.stop();
484
- assert.equal(framework.getStore().isClosed(), true);
485
- assert.deepEqual(rejections, []);
486
- });
487
- const lateCalls = [
488
- ['quiesce', (f) => f.quiesce()],
489
- ['resume', (f) => f.resume()],
490
- ['roll back', (f) => f.rollbackToMessage('agent', { messageId: 'invalid' })],
491
- ['suppress', (f) => f.suppressMessages('agent', { messageIds: ['invalid'] })],
492
- ['undo', (f) => f.undoLastTurn('agent')],
493
- ['redo', (f) => f.redo('agent')],
494
- ['maintain', (f) => f.maintenanceTick()],
495
- ['puppet', (f) => f.puppetToolCall('agent', 'unused', {})],
496
- ['switch branch', (f) => f.switchBranch('main')],
497
- ['connect MCPL server', (f) => f.connectMcplServer({ id: 'late', command: 'unused' })],
498
- ['disconnect MCPL server', (f) => f.disconnectMcplServer('late')],
499
- ['restart MCPL server', (f) => f.restartMcplServer('late')],
500
- ['awareness sync', (f) => f.syncDiscordAwarenessMarkers()],
501
- ];
502
- for (const [verb, call] of lateCalls) {
503
- it(verb + ' is refused during teardown and after stop(), with no writes and no operator log', async () => {
504
- const framework = await create();
505
- let backendCalls = 0;
506
- Object.assign(internals(framework), {
507
- mcplHostCapabilities: {},
508
- mcplServerRegistry: {
509
- getAllServers: () => [], closeAll: async () => { },
510
- removeServer: async () => { backendCalls++; },
511
- },
512
- connectMcplServerInternal: async () => { backendCalls++; },
513
- refreshMcplTools: async () => { backendCalls++; },
514
- emitMcplToolDiff: () => { backendCalls++; },
515
- });
516
- let finishModules;
517
- const hold = new Promise((resolve) => { finishModules = resolve; });
518
- framework.getModule('teardown-probe').stop = async () => {
519
- order.push('modules stopped');
520
- await hold;
521
- };
522
- const stopping = framework.stop();
523
- await until(() => order.includes('modules stopped'), 'module teardown');
524
- const sequence = framework.getStore().currentSequence();
525
- const branch = framework.getStore().currentBranch().name;
526
- const logPath = framework.getOperatorLogPath();
527
- const log = () => existsSync(logPath) ? readFileSync(logPath, 'utf8') : '';
528
- const beforeLog = log();
529
- const refused = async () => assert.rejects(Promise.resolve().then(() => call(framework)), (error) => error instanceof Error && error.message === verb + ' refused: the framework is stopping');
530
- try {
531
- await refused();
532
- assert.equal(framework.getStore().currentSequence(), sequence);
533
- assert.equal(framework.getStore().currentBranch().name, branch);
534
- assert.equal(log(), beforeLog);
535
- assert.equal(backendCalls, 0);
536
- }
537
- finally {
538
- finishModules();
539
- await stopping;
540
- }
541
- await refused();
542
- assert.equal(log(), beforeLog);
543
- });
544
- }
545
- it('a resume called once stop() has begun refuses before a held maintenance pass ends', async () => {
546
- const framework = await create();
547
- await framework.quiesce();
548
- let endPass;
549
- internals(framework).maintenancePass = new Promise((resolve) => { endPass = resolve; });
550
- const stopping = framework.stop();
551
- let settled = false;
552
- const resuming = framework.resume().finally(() => { settled = true; });
553
- void resuming.catch(() => { });
554
- try {
555
- // Admission is synchronous; promise settlement needs only its microtasks.
556
- await Promise.resolve();
557
- await Promise.resolve();
558
- assert.equal(settled, true, 'refusal must not wait for maintenance');
559
- await assert.rejects(resuming, /resume refused: the framework is stopping/);
560
- }
561
- finally {
562
- endPass();
563
- await stopping;
564
- await resuming.catch(() => { });
565
- }
566
- });
567
- it('a resume checks again after its preview retries, and refuses when stop() began during them', async () => {
568
- const framework = await create();
569
- await framework.quiesce();
570
- let previewed = false;
571
- framework.previewAgentRuntimeSettings = (() => {
572
- previewed = true;
573
- return { available: false, reason: 'preview_in_flight', path: 'none', liveBudgetTokens: 0, transition: 'stable' };
574
- });
575
- const resuming = framework.resume();
576
- void resuming.catch(() => { });
577
- assert.equal(previewed, true);
578
- const stopping = framework.stop();
579
- await assert.rejects(resuming, /resume refused: the framework is stopping/);
580
- await stopping;
581
- assert.equal(await bootsQuiesced(), true);
582
- });
583
- it('a resume whose reopen succeeds while stop() waits releases the barrier and opens the data plane', async () => {
584
- // The listeners answer whatever the pause held back with their stopping
585
- // refusal, so the stopping host opens its planes as a serving one does.
586
- const framework = await create();
587
- let ready = 0;
588
- const connection = {
589
- id: 'srv', pauseDataPlane() { }, readyControlPlane() { },
590
- ready() { ready++; },
591
- };
592
- const fw = internals(framework);
593
- fw.mcplServerRegistry = { getAllServers: () => [connection], closeAll: async () => { } };
594
- await framework.quiesce();
595
- let deliver;
596
- fw.beginDiscordAwarenessBarrier = () => ({
597
- requiresBarrier: true,
598
- promise: new Promise((resolve) => { deliver = () => resolve({ status: 'delivered', delivered: 0, failed: 0 }); }),
599
- });
600
- const resuming = framework.resume();
601
- await until(() => deliver !== undefined, 'resume barrier');
602
- const stopping = framework.stop();
603
- await releaseWhenStopWaits(deliver);
604
- await resuming;
605
- await stopping;
606
- assert.equal(ready, 1);
607
- assert.equal(fw.discordAwarenessBarrier, null);
608
- assert.ok(logged.some((line) => line.includes("parked wake(s) won't run") && line.includes('stopping')));
609
- assert.equal(await bootsQuiesced(), false);
610
- });
611
- it('stop() waits for a puppet tool call, so it finishes before the modules stop', { timeout: 20_000 }, async () => {
612
- const framework = await create();
613
- const fw = framework;
614
- let release;
615
- const held = new Promise((resolve) => { release = resolve; });
616
- let called = false;
617
- fw.getToolsForAgent = () => [{ name: 'probe' }];
618
- fw.executeToolCall = async () => {
619
- called = true;
620
- await held;
621
- order.push('tool returned');
622
- return { success: true, data: 'done' };
623
- };
624
- // The pair's two writes are what the wait protects.
625
- const cm = framework.getAgent('agent').getContextManager();
626
- const addMessage = cm.addMessage.bind(cm);
627
- cm.addMessage = ((...args) => {
628
- const id = addMessage(...args);
629
- order.push('message stored');
630
- return id;
631
- });
632
- const puppeting = framework.puppetToolCall('agent', 'probe', {});
633
- void puppeting.catch(() => { });
634
- await until(() => called, 'the puppet call to reach its tool');
635
- const stopping = framework.stop();
636
- await releaseWhenStopWaits(release);
637
- const { toolUseId } = await puppeting;
638
- await stopping;
639
- assert.match(toolUseId, /^toolu_01/);
640
- assert.deepEqual(order, ['tool returned', 'message stored', 'message stored', 'modules stopped']);
641
- assert.deepEqual(rejections, []);
642
- });
643
- it("stop() waits for a branch switch from the API server, its config mount included", { timeout: 20_000 }, async () => {
644
- const framework = await create();
645
- const api = new ApiServer(framework);
646
- await api.cmdBranchCreate({ name: 'side' });
647
- const fw = internals(framework);
648
- let release;
649
- const held = new Promise((resolve) => { release = resolve; });
650
- let mounting = false;
651
- const getModule = fw.moduleRegistry.getModule.bind(fw.moduleRegistry);
652
- fw.moduleRegistry.getModule = (name) => name === 'workspace' ? {
653
- materializeMount: async () => { mounting = true; await held; order.push('config materialized'); },
654
- } : getModule(name);
655
- const switching = api.cmdBranchSwitch({ name: 'side' });
656
- void switching.catch(() => { });
657
- await until(() => mounting, 'the switch to reach its config mount');
658
- const stopping = framework.stop();
659
- await releaseWhenStopWaits(release);
660
- await switching;
661
- await stopping;
662
- assert.deepEqual(order, ['config materialized', 'modules stopped']);
663
- assert.deepEqual(rejections, []);
664
- });
665
- it("the API server's current branch follows the store when a switch fails after moving it, and clients hear of the move", async () => {
666
- const framework = await create();
667
- try {
668
- const api = new ApiServer(framework);
669
- await api.cmdBranchCreate({ name: 'side' });
670
- const broadcasts = [];
671
- api.broadcast = (event, data) => { broadcasts.push([event, data]); };
672
- const fw = internals(framework);
673
- const getModule = fw.moduleRegistry.getModule.bind(fw.moduleRegistry);
674
- fw.moduleRegistry.getModule = (name) => name === 'workspace' ? {
675
- materializeMount: async () => { throw new Error('disk full'); },
676
- } : getModule(name);
677
- await assert.rejects(api.cmdBranchSwitch({ name: 'side' }), /disk full/);
678
- assert.equal(framework.getStore().currentBranch().name, 'side');
679
- assert.equal((await api.cmdBranchCurrent()).name, 'side');
680
- assert.deepEqual(broadcasts, [['branch:switched', { from: 'main', to: 'side' }]]);
681
- }
682
- finally {
683
- await framework.stop();
684
- }
685
- });
686
- it("a successful switch from the API server names the store's branch as where it moved from, even with a stale cache", async () => {
687
- const framework = await create();
688
- try {
689
- const api = new ApiServer(framework);
690
- await api.cmdBranchCreate({ name: 'side' });
691
- const broadcasts = [];
692
- api.broadcast = (event, data) => { broadcasts.push([event, data]); };
693
- // As after a rollback made outside the API server.
694
- api.lastKnownBranch = 'stale';
695
- await api.cmdBranchSwitch({ name: 'side' });
696
- assert.deepEqual(broadcasts, [['branch:switched', { from: 'main', to: 'side' }]]);
697
- }
698
- finally {
699
- await framework.stop();
700
- }
701
- });
702
- it('a switch from the API server that waits for running maintenance names the branch it moved to, and the current branch is the store\'s throughout', async () => {
703
- const framework = await create();
704
- try {
705
- const api = new ApiServer(framework);
706
- await api.cmdBranchCreate({ name: 'side' });
707
- const broadcasts = [];
708
- api.broadcast = (event, data) => { broadcasts.push([event, data]); };
709
- // A maintenance pass still running: the switch moves the store once it ends.
710
- let finish;
711
- internals(framework).maintenancePass = new Promise((resolve) => { finish = resolve; });
712
- const switching = api.cmdBranchSwitch({ name: 'side' });
713
- await new Promise((resolve) => setTimeout(resolve, 20));
714
- assert.equal(framework.getStore().currentBranch().name, 'main', 'the switch waits for the pass');
715
- assert.equal((await api.cmdBranchCurrent()).name, 'main');
716
- assert.deepEqual(broadcasts, []);
717
- finish();
718
- internals(framework).maintenancePass = null;
719
- await switching;
720
- assert.equal(framework.getStore().currentBranch().name, 'side');
721
- assert.equal((await api.cmdBranchCurrent()).name, 'side');
722
- assert.deepEqual(broadcasts, [['branch:switched', { from: 'main', to: 'side' }]]);
723
- }
724
- finally {
725
- await framework.stop();
726
- }
727
- });
728
- it('two API switches handled together each announce their own move', async () => {
729
- // With no workspace module, a switch holds the store for no await, so a
730
- // second one can move the store before the first's continuation runs.
731
- const framework = await create();
732
- try {
733
- const api = new ApiServer(framework);
734
- await api.cmdBranchCreate({ name: 'a' });
735
- await api.cmdBranchCreate({ name: 'b' });
736
- const broadcasts = [];
737
- api.broadcast = (event, data) => { broadcasts.push([event, data]); };
738
- await Promise.all([api.cmdBranchSwitch({ name: 'a' }), api.cmdBranchSwitch({ name: 'b' })]);
739
- assert.deepEqual(broadcasts, [
740
- ['branch:switched', { from: 'main', to: 'a' }],
741
- ['branch:switched', { from: 'a', to: 'b' }],
742
- ]);
743
- assert.equal(framework.getStore().currentBranch().name, 'b');
744
- assert.equal((await api.cmdBranchCurrent()).name, 'b');
745
- }
746
- finally {
747
- await framework.stop();
748
- }
749
- });
750
- it("the API server's current branch is the store's while a switch is still running", { timeout: 20_000 }, async () => {
751
- const framework = await create();
752
- try {
753
- const api = new ApiServer(framework);
754
- await api.cmdBranchCreate({ name: 'side' });
755
- const fw = internals(framework);
756
- let release;
757
- const held = new Promise((resolve) => { release = resolve; });
758
- let mounting = false;
759
- const getModule = fw.moduleRegistry.getModule.bind(fw.moduleRegistry);
760
- fw.moduleRegistry.getModule = (name) => name === 'workspace' ? {
761
- materializeMount: async () => { mounting = true; await held; },
762
- } : getModule(name);
763
- const switching = api.cmdBranchSwitch({ name: 'side' });
764
- try {
765
- await until(() => mounting, 'the switch to reach its config mount');
766
- assert.equal((await api.cmdBranchCurrent()).name, 'side');
767
- await assert.rejects(api.cmdBranchDelete({ name: 'side' }), /Cannot delete current branch/);
768
- // The switch holds the store through its mount.
769
- assert.throws(() => framework.undoLastTurn('agent'), (error) => error instanceof OperatorActionError
770
- && error.code === 'agent-busy' && error.message === 'Cannot undo: the store is under live switch branch for every agent');
771
- assert.throws(() => framework.redo('agent'), (error) => error instanceof OperatorActionError
772
- && error.code === 'agent-busy' && error.message === 'Cannot redo: the store is under live switch branch for every agent');
773
- // A host/command undo in turns mode answers the refusal with its code.
774
- const connection = Object.assign(new EventEmitter(), { id: 'srv' });
775
- fw.wireMcplEvents(connection);
776
- let answer;
777
- connection.emit('host-command', { command: 'undo', agentName: 'agent', turns: 1 }, {
778
- id: 11,
779
- respond: (result) => { answer = result; },
780
- respondError: (error) => { answer = { respondError: String(error) }; },
781
- });
782
- await until(() => answer !== undefined, 'the host/command undo to answer');
783
- assert.deepEqual(answer, {
784
- ok: false,
785
- error: 'Cannot undo: the store is under live switch branch for every agent',
786
- code: 'agent-busy',
787
- });
788
- }
789
- finally {
790
- release();
791
- }
792
- await switching;
793
- }
794
- finally {
795
- await framework.stop();
796
- }
797
- });
798
- it("switchBranch() starts the marks' delivery on the branch it moved to", async () => {
799
- const framework = await create();
800
- try {
801
- const api = new ApiServer(framework);
802
- await api.cmdBranchCreate({ name: 'side' });
803
- const reconciledOn = [];
804
- internals(framework).beginDiscordAwarenessBarrier = () => {
805
- reconciledOn.push(framework.getStore().currentBranch().name);
806
- return { requiresBarrier: false, promise: Promise.resolve({ status: 'delivered', delivered: 0, failed: 0 }) };
807
- };
808
- await framework.switchBranch('side');
809
- assert.deepEqual(reconciledOn, ['side']);
810
- }
811
- finally {
812
- await framework.stop();
813
- }
814
- });
815
- it("stop() doesn't wait for the marks' delivery a branch switch started", { timeout: 20_000 }, async () => {
816
- const framework = await create();
817
- const api = new ApiServer(framework);
818
- await api.cmdBranchCreate({ name: 'side' });
819
- let delivering = false;
820
- internals(framework).beginDiscordAwarenessBarrier = () => {
821
- delivering = true;
822
- // A delivery that never ends, as a drain to an unreachable server might.
823
- return { requiresBarrier: true, promise: new Promise(() => { }) };
824
- };
825
- await framework.switchBranch('side');
826
- assert.equal(delivering, true, 'the switch started the delivery and answered without it');
827
- // A budget, so a stop() that waited for the delivery would fail rather than
828
- // hang, with room for an ordinary teardown on a loaded runner.
829
- await framework.stop(5_000);
830
- assert.ok(order.includes('modules stopped'));
831
- assert.equal(framework.getStore().isClosed(), true);
832
- assert.deepEqual(rejections, []);
833
- });
834
- it('a branch switch during a live turn is refused, and the branch stays', async () => {
835
- const framework = await create();
836
- const api = new ApiServer(framework);
837
- await api.cmdBranchCreate({ name: 'side' });
838
- const broadcasts = [];
839
- api.broadcast = (event, data) => { broadcasts.push([event, data]); };
840
- // A stale cache, as after a rollback made outside the API server.
841
- api.lastKnownBranch = 'stale';
842
- // A turn holds its token from dequeue, before its stream registers.
843
- const tokens = internals(framework).activeTurnTokens;
844
- tokens.set('agent', -1);
845
- try {
846
- await assert.rejects(framework.switchBranch('side'), /^OperatorActionError: Cannot switch branch while agent is idle\+turn-alive/);
847
- await assert.rejects(api.cmdBranchSwitch({ name: 'side' }), /Cannot switch branch while agent is idle\+turn-alive/);
848
- assert.equal(framework.getStore().currentBranch().name, 'main');
849
- assert.equal((await api.cmdBranchCurrent()).name, 'main');
850
- assert.deepEqual(broadcasts, [], 'a refused switch moved nothing, so it announces nothing');
851
- }
852
- finally {
853
- tokens.delete('agent');
854
- }
855
- await framework.stop();
856
- });
857
- it('a branch switch from the API server once stop() has begun is refused, and the branch stays', async () => {
858
- const framework = await create();
859
- const api = new ApiServer(framework);
860
- await api.cmdBranchCreate({ name: 'side' });
861
- let finishModules;
862
- const hold = new Promise((resolve) => { finishModules = resolve; });
863
- framework.getModule('teardown-probe').stop = async () => {
864
- order.push('modules stopped');
865
- await hold;
866
- };
867
- const stopping = framework.stop();
868
- try {
869
- await until(() => order.includes('modules stopped'), 'module teardown');
870
- await assert.rejects(api.cmdBranchSwitch({ name: 'side' }), /^Error: switch branch refused: the framework is stopping$/);
871
- assert.equal(framework.getStore().currentBranch().name, 'main');
872
- assert.equal((await api.cmdBranchCurrent()).name, 'main');
873
- }
874
- finally {
875
- finishModules();
876
- await stopping;
877
- }
878
- // With the store closed too, the refusal is what the caller sees.
879
- await assert.rejects(api.cmdBranchSwitch({ name: 'side' }), /^Error: switch branch refused: the framework is stopping$/);
880
- assert.equal((await api.cmdBranchCurrent()).name, 'main');
881
- });
882
- for (const action of ['connect', 'disconnect', 'restart']) {
883
- it('stop() waits for an MCPL ' + action + ' already running before it closes the connections', async () => {
884
- const framework = await create();
885
- const fw = framework;
886
- let release;
887
- const held = new Promise((resolve) => { release = resolve; });
888
- let entered = false;
889
- let connected = action !== 'connect';
890
- fw.mcplHostCapabilities = {};
891
- fw.mcplServerConfigs.set('srv', { id: 'srv', command: 'unused' });
892
- fw.connectMcplServerInternal = async () => {
893
- entered = true;
894
- await held;
895
- connected = true;
896
- order.push('connection opened');
897
- };
898
- fw.refreshMcplTools = async () => { };
899
- fw.emitMcplToolDiff = () => { };
900
- fw.mcplServerRegistry = {
901
- getAllServers: () => [],
902
- removeServer: async () => {
903
- entered = true;
904
- await held;
905
- connected = false;
906
- order.push('connection removed');
907
- },
908
- closeAll: async () => { connected = false; order.push('connections closed'); },
909
- };
910
- const running = action === 'connect' ? framework.connectMcplServer({ id: 'srv', command: 'unused' })
911
- : action === 'disconnect' ? framework.disconnectMcplServer('srv') : framework.restartMcplServer('srv');
912
- void running.catch(() => { });
913
- await until(() => entered, 'MCPL operation');
914
- const stopping = framework.stop();
915
- await releaseWhenStopWaits(release);
916
- await running;
917
- await stopping;
918
- assert.equal(connected, false);
919
- const settled = action === 'disconnect' ? 'connection removed' : 'connection opened';
920
- assert.ok(order.includes(settled) && order.indexOf(settled) < order.indexOf('modules stopped'), order.join(', '));
921
- });
922
- }
923
- for (const action of ['undo', 'redo', 'rollback', 'suppress']) {
924
- it(action + "'s config materialization doesn't hold its caller, and stop() waits for it", { timeout: 20_000 }, async () => {
925
- const framework = await create();
926
- const fw = internals(framework);
927
- const cm = framework.getAgent('agent').getContextManager();
928
- const sequenceBefore = framework.getStore().currentSequence();
929
- const ids = [1, 2, 3].map((n) => cm.addMessage('user', [{ type: 'text', text: 'm' + n }]));
930
- fw.saveTurnCheckpoints('agent', [{ agentName: 'agent', turnIndex: 1, sequenceBefore, branchName: 'main', timestamp: Date.now() }]);
931
- if (action === 'redo')
932
- framework.undoLastTurn('agent');
933
- let release;
934
- const held = new Promise((resolve) => { release = resolve; });
935
- let materializing = false;
936
- const getModule = fw.moduleRegistry.getModule.bind(fw.moduleRegistry);
937
- fw.moduleRegistry.getModule = (name) => name === 'workspace' ? {
938
- materializeMount: async () => { materializing = true; await held; order.push('config materialized'); },
939
- } : getModule(name);
940
- if (action === 'undo')
941
- framework.undoLastTurn('agent');
942
- else if (action === 'redo')
943
- framework.redo('agent');
944
- else if (action === 'rollback')
945
- await framework.rollbackToMessage('agent', { messageId: ids[0] });
946
- else
947
- await framework.suppressMessages('agent', { messageIds: [ids[1]] });
948
- assert.equal(materializing, true, 'the caller returned before file IO settled');
949
- const stopping = framework.stop();
950
- await releaseWhenStopWaits(release);
951
- await stopping;
952
- assert.deepEqual(order, ['config materialized', 'modules stopped']);
953
- });
954
- }
955
- it('a config materialization that fails is logged, and its undo still succeeds', async () => {
956
- const framework = await create();
957
- const fw = internals(framework);
958
- const cm = framework.getAgent('agent').getContextManager();
959
- const sequenceBefore = framework.getStore().currentSequence();
960
- cm.addMessage('user', [{ type: 'text', text: 'a turn' }]);
961
- fw.saveTurnCheckpoints('agent', [{ agentName: 'agent', turnIndex: 1, sequenceBefore, branchName: 'main', timestamp: Date.now() }]);
962
- const getModule = fw.moduleRegistry.getModule.bind(fw.moduleRegistry);
963
- fw.moduleRegistry.getModule = (name) => name === 'workspace' ? {
964
- materializeMount: async () => { throw new Error('disk full'); },
965
- } : getModule(name);
966
- assert.equal(framework.undoLastTurn('agent').undone, true);
967
- await framework.stop();
968
- assert.ok(logged.some((line) => line.includes('re-materializing the config mount after a branch switch failed') && line.includes('disk full')), logged.join('\n'));
969
- assert.deepEqual(rejections, []);
970
- });
971
- for (const action of ['rollback', 'suppress'])
972
- it('stop() also waits for the materialization a ' + action + ' in flight starts after stop() first reads the set', { timeout: 20_000 }, async () => {
973
- const framework = await create();
974
- const fw = internals(framework);
975
- const cm = framework.getAgent('agent').getContextManager();
976
- const ids = [1, 2, 3].map((n) => cm.addMessage('user', [{ type: 'text', text: 'm' + n }]));
977
- let finishSwitch;
978
- const switchHold = new Promise((resolve) => { finishSwitch = resolve; });
979
- if (action === 'rollback') {
980
- const switchBranch = cm.switchBranch.bind(cm);
981
- cm.switchBranch = async (...args) => { await switchHold; return switchBranch(...args); };
982
- }
983
- else {
984
- const fork = cm.fork.bind(cm);
985
- cm.fork = async (...args) => { await switchHold; return fork(...args); };
986
- }
987
- let finishMaterialize;
988
- const materializeHold = new Promise((resolve) => { finishMaterialize = resolve; });
989
- let materializing = false;
990
- const getModule = fw.moduleRegistry.getModule.bind(fw.moduleRegistry);
991
- fw.moduleRegistry.getModule = (name) => name === 'workspace' ? {
992
- materializeMount: async () => { materializing = true; await materializeHold; order.push('config materialized'); },
993
- } : getModule(name);
994
- const rolling = action === 'rollback'
995
- ? framework.rollbackToMessage('agent', { messageId: ids[0] })
996
- : framework.suppressMessages('agent', { messageIds: [ids[1]] });
997
- void rolling.catch(() => { });
998
- const stopping = framework.stop();
999
- await releaseWhenStopWaits(finishSwitch);
1000
- try {
1001
- await rolling;
1002
- assert.equal(materializing, true);
1003
- await until(() => waitReads >= 2 || order.includes('modules stopped'), 'stop to discover child work', 30_000);
1004
- assert.equal(order.includes('modules stopped'), false, 'the original snapshot is not the whole wait');
1005
- }
1006
- finally {
1007
- finishMaterialize();
1008
- await stopping;
1009
- }
1010
- assert.deepEqual(order, ['config materialized', 'modules stopped']);
1011
- });
1012
- it("a trace listener that calls stop() doesn't lose the operation whose trace it heard", async () => {
1013
- const framework = await create();
1014
- const fw = internals(framework);
1015
- const cm = framework.getAgent('agent').getContextManager();
1016
- const sequenceBefore = framework.getStore().currentSequence();
1017
- cm.addMessage('user', [{ type: 'text', text: 'a turn' }]);
1018
- fw.saveTurnCheckpoints('agent', [{ agentName: 'agent', turnIndex: 1, sequenceBefore, branchName: 'main', timestamp: Date.now() }]);
1019
- // Hold the undo's preview, the last thing it does before it answers.
1020
- let release;
1021
- const held = new Promise((resolve) => { release = resolve; });
1022
- let previewing = false;
1023
- fw.lastVisiblePreview = async () => {
1024
- previewing = true;
1025
- await held;
1026
- return null;
1027
- };
1028
- let stopping;
1029
- framework.onTrace((event) => {
1030
- if (event.type === 'undo:completed')
1031
- stopping = framework.stop();
1032
- });
1033
- const connection = Object.assign(new EventEmitter(), { id: 'srv' });
1034
- fw.wireMcplEvents(connection);
1035
- connection.emit('host-command', { command: 'undo', agentName: 'agent', turns: 1 }, {
1036
- id: 9,
1037
- respond: () => { order.push('undo answered'); },
1038
- respondError: () => { order.push('undo failed'); },
1039
- });
1040
- await until(() => stopping !== undefined && (previewing || order.includes('undo failed')), 'reentrant stop and the undo\'s preview');
1041
- await releaseWhenStopWaits(release);
1042
- await stopping;
1043
- await until(() => order.includes('undo answered') || order.includes('undo failed'), 'undo answer');
1044
- assert.ok(order.indexOf('undo answered') >= 0 && order.indexOf('undo answered') < order.indexOf('modules stopped'), order.join(', '));
1045
- assert.deepEqual(rejections, []);
1046
- });
1047
- it("the API server's undo whose trace starts stop() answers, and leaves its marks' delivery to the next start", async () => {
1048
- const framework = await create();
1049
- const fw = internals(framework);
1050
- const cm = framework.getAgent('agent').getContextManager();
1051
- const record = fw.recordTurnCheckpoint.bind(fw);
1052
- record('agent');
1053
- cm.addMessage('user', [{ type: 'text', text: 'a turn' }]);
1054
- let barriers = 0;
1055
- fw.beginDiscordAwarenessBarrier = () => {
1056
- barriers++;
1057
- return { requiresBarrier: false, promise: Promise.resolve({ status: 'delivered', delivered: 0, failed: 0 }) };
1058
- };
1059
- let stopping;
1060
- framework.onTrace((event) => {
1061
- if (event.type === 'undo:completed' && !stopping)
1062
- stopping = framework.stop();
1063
- });
1064
- const api = new ApiServer(framework);
1065
- api.broadcast = () => { };
1066
- assert.equal((await api.cmdUndo({ agentName: 'agent' })).undone, true);
1067
- assert.ok(stopping, "the undo's trace started stop()");
1068
- await stopping;
1069
- assert.equal(barriers, 0, 'no delivery started while the framework stops');
1070
- assert.ok(logged.some((line) => line.includes('delivery after undo agent=agent not started')), logged.join('\n'));
1071
- assert.deepEqual(rejections, []);
1072
- });
1073
- it('a multi-turn host/command undo whose first turn starts stop() still undoes every turn it was asked for', async () => {
1074
- const framework = await create();
1075
- const fw = internals(framework);
1076
- const cm = framework.getAgent('agent').getContextManager();
1077
- // Two turns, each checkpointed as a real turn's start records it.
1078
- const record = fw.recordTurnCheckpoint.bind(fw);
1079
- record('agent');
1080
- cm.addMessage('user', [{ type: 'text', text: 'turn one' }]);
1081
- record('agent');
1082
- cm.addMessage('user', [{ type: 'text', text: 'turn two' }]);
1083
- let stopping;
1084
- framework.onTrace((event) => {
1085
- if (event.type === 'undo:completed' && !stopping)
1086
- stopping = framework.stop();
1087
- });
1088
- const connection = Object.assign(new EventEmitter(), { id: 'srv' });
1089
- fw.wireMcplEvents(connection);
1090
- let answer;
1091
- // Read as the answer goes out: stop() closes the store once the undo is done.
1092
- let checkpoints;
1093
- let texts = [];
1094
- connection.emit('host-command', { command: 'undo', agentName: 'agent', turns: 2 }, {
1095
- id: 10,
1096
- respond: (result) => {
1097
- answer = result;
1098
- checkpoints = fw.getTurnCheckpoints('agent');
1099
- texts = cm.getAllMessages().map((m) => JSON.stringify(m.content));
1100
- },
1101
- respondError: () => { order.push('undo failed'); },
1102
- });
1103
- await until(() => answer !== undefined || order.includes('undo failed'), 'the undo to answer');
1104
- assert.equal(answer?.ok, true, JSON.stringify(answer));
1105
- assert.equal(answer?.undone, 2, JSON.stringify(answer));
1106
- assert.deepEqual(checkpoints, [], 'both turns were rolled back');
1107
- assert.ok(!texts.some((t) => t.includes('turn one') || t.includes('turn two')), texts.join(' | '));
1108
- assert.ok(stopping, 'the first turn started stop()');
1109
- await stopping;
1110
- assert.deepEqual(rejections, []);
1111
- });
1112
- for (const elapsed of [6_000, 9_999, 11_000])
1113
- it("work an operation starts shares stop()'s deadline, " + elapsed + ' ms in', async () => {
1114
- const framework = await create();
1115
- const fw = internals(framework);
1116
- const cm = framework.getAgent('agent').getContextManager();
1117
- const ids = [1, 2, 3].map((n) => cm.addMessage('user', [{ type: 'text', text: 'm' + n }]));
1118
- let finishSwitch;
1119
- const switchHold = new Promise((resolve) => { finishSwitch = resolve; });
1120
- const switchBranch = cm.switchBranch.bind(cm);
1121
- cm.switchBranch = async (...args) => { await switchHold; return switchBranch(...args); };
1122
- let finishMaterialize;
1123
- const materializeHold = new Promise((resolve) => { finishMaterialize = resolve; });
1124
- const getModule = fw.moduleRegistry.getModule.bind(fw.moduleRegistry);
1125
- fw.moduleRegistry.getModule = (name) => name === 'workspace' ? {
1126
- materializeMount: async () => { await materializeHold; order.push('config materialized'); },
1127
- } : getModule(name);
1128
- const rolling = framework.rollbackToMessage('agent', { messageId: ids[0] });
1129
- void rolling.catch(() => { });
1130
- const nowProperty = Object.getOwnPropertyDescriptor(performance, 'now');
1131
- const timer = globalThis.setTimeout;
1132
- const budgets = [];
1133
- let now = 0;
1134
- let stopping;
1135
- try {
1136
- Object.defineProperty(performance, 'now', { configurable: true, value: () => now });
1137
- globalThis.setTimeout = ((...args) => {
1138
- if (args[1] !== undefined && args[1] > 100)
1139
- budgets.push(args[1]);
1140
- return timer(...args);
1141
- });
1142
- stopping = framework.stop(10_000);
1143
- void stopping.catch(() => { });
1144
- await releaseWhenStopWaits(() => { now = elapsed; finishSwitch(); });
1145
- await rolling;
1146
- await until(() => waitReads >= 2 || order.includes('modules stopped'), 'the second operator wait');
1147
- // Clock input controls the remaining budget. In the timeout cases,
1148
- // work stays held until the assertion, so elapsed wall time is no verdict.
1149
- if (elapsed === 6_000) {
1150
- assert.deepEqual(budgets.slice(0, 2), [10_000, 4_000]);
1151
- finishMaterialize();
1152
- await stopping;
1153
- }
1154
- else {
1155
- await assert.rejects(stopping, (error) => error instanceof ShutdownTimeoutError && error.pending.includes('config:materialize')
1156
- && error.message.startsWith('Shutdown timed out after 10000 ms;'));
1157
- assert.equal(framework.getStore().isClosed(), false);
1158
- }
1159
- }
1160
- finally {
1161
- finishSwitch();
1162
- finishMaterialize();
1163
- globalThis.setTimeout = timer;
1164
- if (nowProperty)
1165
- Object.defineProperty(performance, 'now', nowProperty);
1166
- else
1167
- Reflect.deleteProperty(performance, 'now');
1168
- await rolling.catch(() => { });
1169
- await stopping?.catch(() => { });
1170
- await framework.stop();
1171
- }
1172
- });
1173
- });
1174
- //# sourceMappingURL=stop-with-host-operations.test.js.map