@animalabs/agent-framework 0.32.0 → 0.34.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 (368) hide show
  1. package/README.md +340 -22
  2. package/dist/src/admission/admit.d.ts +18 -0
  3. package/dist/src/admission/admit.d.ts.map +1 -1
  4. package/dist/src/admission/admit.js +16 -3
  5. package/dist/src/admission/admit.js.map +1 -1
  6. package/dist/src/agent.d.ts +208 -80
  7. package/dist/src/agent.d.ts.map +1 -1
  8. package/dist/src/agent.js +345 -113
  9. package/dist/src/agent.js.map +1 -1
  10. package/dist/src/api/mcp-server-core.d.ts.map +1 -1
  11. package/dist/src/api/mcp-server-core.js +50 -12
  12. package/dist/src/api/mcp-server-core.js.map +1 -1
  13. package/dist/src/api/server.d.ts.map +1 -1
  14. package/dist/src/api/server.js +4 -20
  15. package/dist/src/api/server.js.map +1 -1
  16. package/dist/src/append-all.d.ts +5 -0
  17. package/dist/src/append-all.d.ts.map +1 -0
  18. package/dist/src/append-all.js +8 -0
  19. package/dist/src/append-all.js.map +1 -0
  20. package/dist/src/code-execution/isolate/scripts.d.ts +12 -8
  21. package/dist/src/code-execution/isolate/scripts.d.ts.map +1 -1
  22. package/dist/src/code-execution/isolate/scripts.js +24 -0
  23. package/dist/src/code-execution/isolate/scripts.js.map +1 -1
  24. package/dist/src/config-checks.d.ts +7 -0
  25. package/dist/src/config-checks.d.ts.map +1 -1
  26. package/dist/src/config-checks.js +14 -0
  27. package/dist/src/config-checks.js.map +1 -1
  28. package/dist/src/context-manager-errors.d.ts +25 -0
  29. package/dist/src/context-manager-errors.d.ts.map +1 -0
  30. package/dist/src/context-manager-errors.js +31 -0
  31. package/dist/src/context-manager-errors.js.map +1 -0
  32. package/dist/src/context-options.d.ts +70 -0
  33. package/dist/src/context-options.d.ts.map +1 -0
  34. package/dist/src/context-options.js +90 -0
  35. package/dist/src/context-options.js.map +1 -0
  36. package/dist/src/cut-off-round.js +4 -4
  37. package/dist/src/deferred-import.d.ts +93 -0
  38. package/dist/src/deferred-import.d.ts.map +1 -0
  39. package/dist/src/deferred-import.js +177 -0
  40. package/dist/src/deferred-import.js.map +1 -0
  41. package/dist/src/dendrite/audience.d.ts +223 -0
  42. package/dist/src/dendrite/audience.d.ts.map +1 -0
  43. package/dist/src/dendrite/audience.js +202 -0
  44. package/dist/src/dendrite/audience.js.map +1 -0
  45. package/dist/src/dendrite/index.d.ts +5 -3
  46. package/dist/src/dendrite/index.d.ts.map +1 -1
  47. package/dist/src/dendrite/index.js +2 -1
  48. package/dist/src/dendrite/index.js.map +1 -1
  49. package/dist/src/dendrite/presets.d.ts +10 -5
  50. package/dist/src/dendrite/presets.d.ts.map +1 -1
  51. package/dist/src/dendrite/presets.js +17 -5
  52. package/dist/src/dendrite/presets.js.map +1 -1
  53. package/dist/src/dendrite/registry.d.ts +62 -7
  54. package/dist/src/dendrite/registry.d.ts.map +1 -1
  55. package/dist/src/dendrite/registry.js +183 -12
  56. package/dist/src/dendrite/registry.js.map +1 -1
  57. package/dist/src/dendrite/types.d.ts +91 -8
  58. package/dist/src/dendrite/types.d.ts.map +1 -1
  59. package/dist/src/failure-text.d.ts +36 -0
  60. package/dist/src/failure-text.d.ts.map +1 -0
  61. package/dist/src/failure-text.js +89 -0
  62. package/dist/src/failure-text.js.map +1 -0
  63. package/dist/src/foreign-rounds.d.ts +69 -0
  64. package/dist/src/foreign-rounds.d.ts.map +1 -0
  65. package/dist/src/foreign-rounds.js +152 -0
  66. package/dist/src/foreign-rounds.js.map +1 -0
  67. package/dist/src/framework.d.ts +2064 -842
  68. package/dist/src/framework.d.ts.map +1 -1
  69. package/dist/src/framework.js +8586 -3739
  70. package/dist/src/framework.js.map +1 -1
  71. package/dist/src/gate/event-gate.d.ts +125 -21
  72. package/dist/src/gate/event-gate.d.ts.map +1 -1
  73. package/dist/src/gate/event-gate.js +487 -72
  74. package/dist/src/gate/event-gate.js.map +1 -1
  75. package/dist/src/gate/index.d.ts +1 -1
  76. package/dist/src/gate/index.d.ts.map +1 -1
  77. package/dist/src/gate/index.js.map +1 -1
  78. package/dist/src/gate/reply-judge.d.ts +4 -0
  79. package/dist/src/gate/reply-judge.d.ts.map +1 -1
  80. package/dist/src/gate/reply-judge.js +12 -3
  81. package/dist/src/gate/reply-judge.js.map +1 -1
  82. package/dist/src/gate/rule-scope.d.ts +30 -0
  83. package/dist/src/gate/rule-scope.d.ts.map +1 -0
  84. package/dist/src/gate/rule-scope.js +41 -0
  85. package/dist/src/gate/rule-scope.js.map +1 -0
  86. package/dist/src/gate/suppress-script-worker.d.ts +2 -0
  87. package/dist/src/gate/suppress-script-worker.d.ts.map +1 -0
  88. package/dist/src/gate/suppress-script-worker.js +103 -0
  89. package/dist/src/gate/suppress-script-worker.js.map +1 -0
  90. package/dist/src/gate/suppress-scripts.d.ts +105 -0
  91. package/dist/src/gate/suppress-scripts.d.ts.map +1 -0
  92. package/dist/src/gate/suppress-scripts.js +403 -0
  93. package/dist/src/gate/suppress-scripts.js.map +1 -0
  94. package/dist/src/gate/suppression-review.d.ts +143 -0
  95. package/dist/src/gate/suppression-review.d.ts.map +1 -0
  96. package/dist/src/gate/suppression-review.js +463 -0
  97. package/dist/src/gate/suppression-review.js.map +1 -0
  98. package/dist/src/gate/suppression-stats.d.ts +125 -0
  99. package/dist/src/gate/suppression-stats.d.ts.map +1 -0
  100. package/dist/src/gate/suppression-stats.js +214 -0
  101. package/dist/src/gate/suppression-stats.js.map +1 -0
  102. package/dist/src/gate/types.d.ts +142 -7
  103. package/dist/src/gate/types.d.ts.map +1 -1
  104. package/dist/src/gate/wake-onboarding.d.ts +119 -0
  105. package/dist/src/gate/wake-onboarding.d.ts.map +1 -0
  106. package/dist/src/gate/wake-onboarding.js +277 -0
  107. package/dist/src/gate/wake-onboarding.js.map +1 -0
  108. package/dist/src/heartbeat/heartbeat.js +1 -1
  109. package/dist/src/heartbeat/heartbeat.js.map +1 -1
  110. package/dist/src/held-writes.d.ts +31 -23
  111. package/dist/src/held-writes.d.ts.map +1 -1
  112. package/dist/src/held-writes.js +44 -59
  113. package/dist/src/held-writes.js.map +1 -1
  114. package/dist/src/index.d.ts +6 -2
  115. package/dist/src/index.d.ts.map +1 -1
  116. package/dist/src/index.js +4 -0
  117. package/dist/src/index.js.map +1 -1
  118. package/dist/src/inference-bounds.d.ts +2 -1
  119. package/dist/src/inference-bounds.d.ts.map +1 -1
  120. package/dist/src/inference-bounds.js +9 -6
  121. package/dist/src/inference-bounds.js.map +1 -1
  122. package/dist/src/jsonrpc-envelope.d.ts +69 -0
  123. package/dist/src/jsonrpc-envelope.d.ts.map +1 -0
  124. package/dist/src/jsonrpc-envelope.js +66 -0
  125. package/dist/src/jsonrpc-envelope.js.map +1 -0
  126. package/dist/src/mcpl/channel-registry.d.ts +188 -28
  127. package/dist/src/mcpl/channel-registry.d.ts.map +1 -1
  128. package/dist/src/mcpl/channel-registry.js +426 -70
  129. package/dist/src/mcpl/channel-registry.js.map +1 -1
  130. package/dist/src/mcpl/checkpoint-manager.d.ts +2 -4
  131. package/dist/src/mcpl/checkpoint-manager.d.ts.map +1 -1
  132. package/dist/src/mcpl/checkpoint-manager.js.map +1 -1
  133. package/dist/src/mcpl/feature-set-manager.d.ts +2 -4
  134. package/dist/src/mcpl/feature-set-manager.d.ts.map +1 -1
  135. package/dist/src/mcpl/feature-set-manager.js.map +1 -1
  136. package/dist/src/mcpl/inbound-source.d.ts +2 -1
  137. package/dist/src/mcpl/inbound-source.d.ts.map +1 -1
  138. package/dist/src/mcpl/inbound-source.js +2 -1
  139. package/dist/src/mcpl/inbound-source.js.map +1 -1
  140. package/dist/src/mcpl/inference-router.d.ts +6 -6
  141. package/dist/src/mcpl/inference-router.d.ts.map +1 -1
  142. package/dist/src/mcpl/inference-router.js.map +1 -1
  143. package/dist/src/mcpl/modern-connection.d.ts +109 -15
  144. package/dist/src/mcpl/modern-connection.d.ts.map +1 -1
  145. package/dist/src/mcpl/modern-connection.js +593 -86
  146. package/dist/src/mcpl/modern-connection.js.map +1 -1
  147. package/dist/src/mcpl/protocol-family.d.ts +3 -1
  148. package/dist/src/mcpl/protocol-family.d.ts.map +1 -1
  149. package/dist/src/mcpl/protocol-family.js +15 -9
  150. package/dist/src/mcpl/protocol-family.js.map +1 -1
  151. package/dist/src/mcpl/push-coalescer.d.ts +132 -22
  152. package/dist/src/mcpl/push-coalescer.d.ts.map +1 -1
  153. package/dist/src/mcpl/push-coalescer.js +105 -15
  154. package/dist/src/mcpl/push-coalescer.js.map +1 -1
  155. package/dist/src/mcpl/push-handler.d.ts +9 -7
  156. package/dist/src/mcpl/push-handler.d.ts.map +1 -1
  157. package/dist/src/mcpl/push-handler.js.map +1 -1
  158. package/dist/src/mcpl/server-connection.d.ts +50 -28
  159. package/dist/src/mcpl/server-connection.d.ts.map +1 -1
  160. package/dist/src/mcpl/server-connection.js +165 -72
  161. package/dist/src/mcpl/server-connection.js.map +1 -1
  162. package/dist/src/mcpl/tool-classes.d.ts.map +1 -1
  163. package/dist/src/mcpl/tool-classes.js +3 -0
  164. package/dist/src/mcpl/tool-classes.js.map +1 -1
  165. package/dist/src/mcpl/tool-presence.d.ts.map +1 -1
  166. package/dist/src/mcpl/tool-presence.js +10 -6
  167. package/dist/src/mcpl/tool-presence.js.map +1 -1
  168. package/dist/src/mcpl/toolset-host.d.ts.map +1 -1
  169. package/dist/src/mcpl/toolset-host.js +7 -6
  170. package/dist/src/mcpl/toolset-host.js.map +1 -1
  171. package/dist/src/mcpl/toolsets-module.d.ts.map +1 -1
  172. package/dist/src/mcpl/toolsets-module.js +2 -1
  173. package/dist/src/mcpl/toolsets-module.js.map +1 -1
  174. package/dist/src/mcpl/types.d.ts +33 -6
  175. package/dist/src/mcpl/types.d.ts.map +1 -1
  176. package/dist/src/mcpl/types.js.map +1 -1
  177. package/dist/src/module-registry.d.ts +24 -1
  178. package/dist/src/module-registry.d.ts.map +1 -1
  179. package/dist/src/module-registry.js +68 -18
  180. package/dist/src/module-registry.js.map +1 -1
  181. package/dist/src/modules/discord/index.d.ts +45 -8
  182. package/dist/src/modules/discord/index.d.ts.map +1 -1
  183. package/dist/src/modules/discord/index.js +238 -87
  184. package/dist/src/modules/discord/index.js.map +1 -1
  185. package/dist/src/modules/health/index.js +2 -2
  186. package/dist/src/modules/health/index.js.map +1 -1
  187. package/dist/src/modules/history/index.d.ts +59 -0
  188. package/dist/src/modules/history/index.d.ts.map +1 -1
  189. package/dist/src/modules/history/index.js +432 -67
  190. package/dist/src/modules/history/index.js.map +1 -1
  191. package/dist/src/modules/history/semantic.d.ts +6 -5
  192. package/dist/src/modules/history/semantic.d.ts.map +1 -1
  193. package/dist/src/modules/history/semantic.js +18 -25
  194. package/dist/src/modules/history/semantic.js.map +1 -1
  195. package/dist/src/modules/workspace/disk-agreement.d.ts +1 -1
  196. package/dist/src/modules/workspace/disk-agreement.js +1 -1
  197. package/dist/src/modules/workspace/index.d.ts +28 -7
  198. package/dist/src/modules/workspace/index.d.ts.map +1 -1
  199. package/dist/src/modules/workspace/index.js +80 -25
  200. package/dist/src/modules/workspace/index.js.map +1 -1
  201. package/dist/src/modules/workspace/observe.d.ts.map +1 -1
  202. package/dist/src/modules/workspace/observe.js +2 -1
  203. package/dist/src/modules/workspace/observe.js.map +1 -1
  204. package/dist/src/modules/workspace/reconcile.d.ts.map +1 -1
  205. package/dist/src/modules/workspace/reconcile.js +3 -2
  206. package/dist/src/modules/workspace/reconcile.js.map +1 -1
  207. package/dist/src/notice-tags.d.ts +20 -9
  208. package/dist/src/notice-tags.d.ts.map +1 -1
  209. package/dist/src/notice-tags.js +20 -9
  210. package/dist/src/notice-tags.js.map +1 -1
  211. package/dist/src/operator-log.d.ts +36 -3
  212. package/dist/src/operator-log.d.ts.map +1 -1
  213. package/dist/src/operator-log.js +2 -2
  214. package/dist/src/operator-log.js.map +1 -1
  215. package/dist/src/presentation.d.ts +747 -0
  216. package/dist/src/presentation.d.ts.map +1 -0
  217. package/dist/src/presentation.js +1437 -0
  218. package/dist/src/presentation.js.map +1 -0
  219. package/dist/src/prose-drafts.d.ts +15 -11
  220. package/dist/src/prose-drafts.d.ts.map +1 -1
  221. package/dist/src/prose-drafts.js +16 -12
  222. package/dist/src/prose-drafts.js.map +1 -1
  223. package/dist/src/read-marks.d.ts +192 -0
  224. package/dist/src/read-marks.d.ts.map +1 -0
  225. package/dist/src/read-marks.js +242 -0
  226. package/dist/src/read-marks.js.map +1 -0
  227. package/dist/src/reasoning-loss.d.ts +5 -0
  228. package/dist/src/reasoning-loss.d.ts.map +1 -0
  229. package/dist/src/reasoning-loss.js +8 -0
  230. package/dist/src/reasoning-loss.js.map +1 -0
  231. package/dist/src/recovery/offline-branch.d.ts +91 -6
  232. package/dist/src/recovery/offline-branch.d.ts.map +1 -1
  233. package/dist/src/recovery/offline-branch.js +277 -32
  234. package/dist/src/recovery/offline-branch.js.map +1 -1
  235. package/dist/src/recovery/recover-cli.js +24 -4
  236. package/dist/src/recovery/recover-cli.js.map +1 -1
  237. package/dist/src/send-tools.d.ts +5 -9
  238. package/dist/src/send-tools.d.ts.map +1 -1
  239. package/dist/src/send-tools.js +40 -7
  240. package/dist/src/send-tools.js.map +1 -1
  241. package/dist/src/sent-rows.js +1 -1
  242. package/dist/src/stored-injections.d.ts +2 -2
  243. package/dist/src/stored-injections.js +2 -2
  244. package/dist/src/stored-removal.d.ts +17 -4
  245. package/dist/src/stored-removal.d.ts.map +1 -1
  246. package/dist/src/stored-removal.js +29 -5
  247. package/dist/src/stored-removal.js.map +1 -1
  248. package/dist/src/supplied-text.d.ts +1 -1
  249. package/dist/src/supplied-text.js +3 -3
  250. package/dist/src/supplied-text.js.map +1 -1
  251. package/dist/src/thinking-drops.d.ts +2 -0
  252. package/dist/src/thinking-drops.d.ts.map +1 -1
  253. package/dist/src/thinking-drops.js.map +1 -1
  254. package/dist/src/tool-presentation.d.ts.map +1 -1
  255. package/dist/src/tool-presentation.js +38 -9
  256. package/dist/src/tool-presentation.js.map +1 -1
  257. package/dist/src/tool-result-guard.d.ts +12 -1
  258. package/dist/src/tool-result-guard.d.ts.map +1 -1
  259. package/dist/src/tool-result-guard.js +42 -8
  260. package/dist/src/tool-result-guard.js.map +1 -1
  261. package/dist/src/tune-out/coordinator.d.ts +1170 -81
  262. package/dist/src/tune-out/coordinator.d.ts.map +1 -1
  263. package/dist/src/tune-out/coordinator.js +3732 -369
  264. package/dist/src/tune-out/coordinator.js.map +1 -1
  265. package/dist/src/tune-out/tools.d.ts +114 -17
  266. package/dist/src/tune-out/tools.d.ts.map +1 -1
  267. package/dist/src/tune-out/tools.js +89 -28
  268. package/dist/src/tune-out/tools.js.map +1 -1
  269. package/dist/src/tune-out/window-anchor.d.ts +143 -0
  270. package/dist/src/tune-out/window-anchor.d.ts.map +1 -0
  271. package/dist/src/tune-out/window-anchor.js +202 -0
  272. package/dist/src/tune-out/window-anchor.js.map +1 -0
  273. package/dist/src/types/agent.d.ts +121 -25
  274. package/dist/src/types/agent.d.ts.map +1 -1
  275. package/dist/src/types/events.d.ts +2 -0
  276. package/dist/src/types/events.d.ts.map +1 -1
  277. package/dist/src/types/framework.d.ts +72 -17
  278. package/dist/src/types/framework.d.ts.map +1 -1
  279. package/dist/src/types/inference-log.d.ts +1 -0
  280. package/dist/src/types/inference-log.d.ts.map +1 -1
  281. package/dist/src/types/module.d.ts +180 -69
  282. package/dist/src/types/module.d.ts.map +1 -1
  283. package/dist/src/types/trace.d.ts +573 -39
  284. package/dist/src/types/trace.d.ts.map +1 -1
  285. package/package.json +4 -4
  286. package/src/admission/admit.ts +32 -3
  287. package/src/agent.ts +392 -132
  288. package/src/api/mcp-server-core.ts +54 -17
  289. package/src/api/server.ts +4 -23
  290. package/src/append-all.ts +6 -0
  291. package/src/code-execution/isolate/scripts.ts +28 -3
  292. package/src/config-checks.ts +14 -0
  293. package/src/context-manager-errors.ts +37 -0
  294. package/src/context-options.ts +106 -0
  295. package/src/cut-off-round.ts +4 -4
  296. package/src/deferred-import.ts +239 -0
  297. package/src/dendrite/audience.ts +315 -0
  298. package/src/dendrite/index.ts +14 -2
  299. package/src/dendrite/presets.ts +18 -6
  300. package/src/dendrite/registry.ts +213 -14
  301. package/src/dendrite/types.ts +92 -8
  302. package/src/failure-text.ts +88 -0
  303. package/src/foreign-rounds.ts +199 -0
  304. package/src/framework.ts +8796 -3813
  305. package/src/gate/event-gate.ts +518 -91
  306. package/src/gate/index.ts +3 -0
  307. package/src/gate/reply-judge.ts +12 -3
  308. package/src/gate/rule-scope.ts +45 -0
  309. package/src/gate/suppress-script-worker.ts +89 -0
  310. package/src/gate/suppress-scripts.ts +414 -0
  311. package/src/gate/suppression-review.ts +517 -0
  312. package/src/gate/suppression-stats.ts +314 -0
  313. package/src/gate/types.ts +148 -7
  314. package/src/gate/wake-onboarding.ts +309 -0
  315. package/src/heartbeat/heartbeat.ts +1 -1
  316. package/src/held-writes.ts +49 -60
  317. package/src/index.ts +10 -2
  318. package/src/inference-bounds.ts +11 -6
  319. package/src/jsonrpc-envelope.ts +81 -0
  320. package/src/mcpl/channel-registry.ts +513 -116
  321. package/src/mcpl/checkpoint-manager.ts +3 -2
  322. package/src/mcpl/feature-set-manager.ts +2 -1
  323. package/src/mcpl/inbound-source.ts +2 -1
  324. package/src/mcpl/inference-router.ts +7 -4
  325. package/src/mcpl/modern-connection.ts +629 -91
  326. package/src/mcpl/protocol-family.ts +15 -9
  327. package/src/mcpl/push-coalescer.ts +193 -34
  328. package/src/mcpl/push-handler.ts +10 -5
  329. package/src/mcpl/server-connection.ts +169 -75
  330. package/src/mcpl/tool-classes.ts +3 -0
  331. package/src/mcpl/tool-presence.ts +10 -5
  332. package/src/mcpl/toolset-host.ts +7 -6
  333. package/src/mcpl/toolsets-module.ts +2 -1
  334. package/src/mcpl/types.ts +33 -6
  335. package/src/module-registry.ts +73 -17
  336. package/src/modules/discord/index.ts +230 -82
  337. package/src/modules/health/index.ts +2 -2
  338. package/src/modules/history/index.ts +439 -70
  339. package/src/modules/history/semantic.ts +18 -24
  340. package/src/modules/workspace/disk-agreement.ts +1 -1
  341. package/src/modules/workspace/index.ts +89 -26
  342. package/src/modules/workspace/observe.ts +2 -1
  343. package/src/modules/workspace/reconcile.ts +3 -2
  344. package/src/notice-tags.ts +21 -9
  345. package/src/operator-log.ts +36 -3
  346. package/src/presentation.ts +1678 -0
  347. package/src/prose-drafts.ts +16 -12
  348. package/src/read-marks.ts +328 -0
  349. package/src/reasoning-loss.ts +7 -0
  350. package/src/recovery/offline-branch.ts +350 -35
  351. package/src/recovery/recover-cli.ts +23 -4
  352. package/src/send-tools.ts +40 -7
  353. package/src/sent-rows.ts +1 -1
  354. package/src/stored-injections.ts +2 -2
  355. package/src/stored-removal.ts +31 -7
  356. package/src/supplied-text.ts +3 -3
  357. package/src/thinking-drops.ts +2 -0
  358. package/src/tool-presentation.ts +34 -9
  359. package/src/tool-result-guard.ts +41 -7
  360. package/src/tune-out/coordinator.ts +4121 -472
  361. package/src/tune-out/tools.ts +162 -44
  362. package/src/tune-out/window-anchor.ts +277 -0
  363. package/src/types/agent.ts +122 -25
  364. package/src/types/events.ts +2 -0
  365. package/src/types/framework.ts +73 -17
  366. package/src/types/inference-log.ts +1 -0
  367. package/src/types/module.ts +181 -68
  368. package/src/types/trace.ts +607 -43
package/src/send-tools.ts CHANGED
@@ -1,12 +1,45 @@
1
1
  /**
2
- * Tools whose call delivers the resident's message to a channel or person,
3
- * by bare name (an MCPL server's `<prefix>--` stripped). The framework reads
4
- * a call of one as an explicit send that silences the round's auto-routed
5
- * prose where it may have posted; the history module's semantic index reads
6
- * its message argument as what the resident wrote to someone, whether or not
7
- * it was delivered.
2
+ * Tools whose call carries the resident's words, by bare name (an MCPL
3
+ * server's `<prefix>--` stripped); edit_message's words are the new text of a
4
+ * message it sent. The framework reads a call of a `silences` one as an
5
+ * explicit send that silences the round's auto-routed prose where it may have
6
+ * posted; the history module reads the words of any of them as what the
7
+ * resident wrote to someone, whether or not it was delivered. With prose
8
+ * routing disabled the resident speaks through these.
8
9
  */
9
- export const SEND_TOOLS = new Set(['channel_publish', 'send_message', 'reply_message', 'send_dm']);
10
+ const SPEECH_TOOLS: ReadonlyMap<string, { words: readonly string[]; silences: boolean }> = new Map([
11
+ // channel_publish still takes `text` from older callers.
12
+ ['channel_publish', { words: ['content', 'text'], silences: true }],
13
+ // telegram-mcpl's send_message takes `message`.
14
+ ['send_message', { words: ['content', 'message', 'text'], silences: true }],
15
+ ['reply_message', { words: ['content', 'text'], silences: true }],
16
+ ['send_dm', { words: ['content', 'text'], silences: true }],
17
+ // telegram-mcpl's reply, file send, scheduled send and poll.
18
+ ['reply_to_message', { words: ['text'], silences: true }],
19
+ ['send_file', { words: ['caption'], silences: false }],
20
+ ['send_scheduled_message', { words: ['message'], silences: false }],
21
+ ['create_poll', { words: ['question'], silences: false }],
22
+ // telegram-mcpl's edit_message takes `new_text`.
23
+ ['edit_message', { words: ['content', 'new_text', 'text'], silences: false }],
24
+ // slack-mcpl's upload_file posts `comment` with the file; its `content` is
25
+ // the file.
26
+ ['upload_file', { words: ['comment'], silences: false }],
27
+ // Eidoverse's say and whisper take `text`.
28
+ ['say', { words: ['text'], silences: true }],
29
+ ['whisper', { words: ['text'], silences: true }],
30
+ ]);
31
+
32
+ export const SILENCING_SENDS = new Set([...SPEECH_TOOLS].filter(([, tool]) => tool.silences).map(([name]) => name));
10
33
 
11
34
  /** Strip the `server--` MCPL prefix from a tool name. */
12
35
  export const bareToolName = (n: string): string => n.split('--').pop()!;
36
+
37
+ export function speechOf(name: unknown, input: unknown): { tool: string; words: string } | undefined {
38
+ if (typeof name !== 'string' || typeof input !== 'object' || input === null) return undefined;
39
+ const tool = bareToolName(name);
40
+ const row = SPEECH_TOOLS.get(tool);
41
+ if (!row) return undefined;
42
+ const args = input as Record<string, unknown>;
43
+ const words = row.words.map((arg) => args[arg]).find((value) => value !== undefined && value !== null);
44
+ return typeof words === 'string' && words.trim().length > 0 ? { tool, words } : undefined;
45
+ }
package/src/sent-rows.ts CHANGED
@@ -152,7 +152,7 @@ export function roundRows(
152
152
  * the two alike (read from the provider on 2026-10-23: Haiku 5.5 with the drop control, on an enforcing API-key
153
153
  * organization and on a subscription account, reported no drop for either, and dropped both replies' blocks when an
154
154
  * earlier user message changed). The store's own fields beside them, such as
155
- * `toolName`, don't reach the provider on membrane's native path, the only one noted (membrane 0.8.0's XML
155
+ * `toolName`, don't reach the provider on membrane's native path, the only one noted (membrane 0.8.0's and 0.9.0's XML
156
156
  * formatter reads `toolName`, and an XML stream is never noted).
157
157
  */
158
158
  function normalizedResult(block: ContentBlock): unknown {
@@ -14,8 +14,8 @@
14
14
  * a start stored whose compile then didn't record) has the same content,
15
15
  * every part of it, and the compile
16
16
  * then renders
17
- * it from the store like any message, where it stays. While the window is
18
- * held (AgentFramework's slotHeldFrom), `compile()` places it instead. Being a
17
+ * it from the store like any message, where it stays. While the host is
18
+ * quiesced, `compile()` places it instead. Being a
19
19
  * message, it's history to the strategy: capped by its per-message bound,
20
20
  * sharded, selected by the budget and folded like any other.
21
21
  *
@@ -50,13 +50,14 @@ export function locateMessageIndices(
50
50
 
51
51
  /**
52
52
  * Inclusive slot range of the body-group run containing `index` (the slot
53
- * itself when it is not sharded). Delegates to the store's own
54
- * `alignToBodyGroups` edge walk — one contiguity assumption, not two.
53
+ * itself when it is not sharded), and the ids of its rows in store order.
54
+ * Delegates to the store's own `alignToBodyGroups` edge walk — one
55
+ * contiguity assumption, not two.
55
56
  */
56
57
  export function bodyGroupRun(
57
58
  cm: SurgeryReadableCm,
58
59
  index: number,
59
- ): { from: number; to: number; fromId: string; toId: string; group: boolean } {
60
+ ): { from: number; to: number; fromId: string; toId: string; group: boolean; ids: MessageId[] } {
60
61
  const win = cm.getMessageWindow(index, 1, { alignToBodyGroups: true, resolveBlobs: false });
61
62
  const from = win.startIndex;
62
63
  const to = win.startIndex + win.messages.length - 1;
@@ -66,6 +67,7 @@ export function bodyGroupRun(
66
67
  fromId: String(win.messages[0].id),
67
68
  toId: String(win.messages[win.messages.length - 1].id),
68
69
  group: win.messages[0].bodyGroupId !== undefined,
70
+ ids: win.messages.map((m) => String(m.id) as MessageId),
69
71
  };
70
72
  }
71
73
 
@@ -90,23 +92,45 @@ export function removeStoredMessages(cm: Removals, first: StoredLike, last: Stor
90
92
  * Remove one stored message by its id, with the rest of its body when it's
91
93
  * in one: a module or a coalescer removes a message it added by the id
92
94
  * `addMessage` returned, which for a long message stored in shards is its
93
- * first shard's.
95
+ * first shard's. Returns the ids of every row it removed, in store order:
96
+ * the id given for a message outside any body, each shard's for a body, so
97
+ * a caller can take them out of the windows of the other agents that held
98
+ * them (#291).
94
99
  */
95
- export function removeStoredMessage(cm: ContextManager, id: MessageId): void {
100
+ export function removeStoredMessage(cm: ContextManager, id: MessageId): MessageId[] {
96
101
  const message = cm.getMessage(id) as StoredLike | null;
97
102
  if (!message?.bodyGroupId) {
98
103
  cm.removeMessage(id);
99
- return;
104
+ return [id];
100
105
  }
101
106
  // Found in blob-free windows: a full read of the branch would inflate every
102
107
  // attachment on it, once for each message a sweep removes.
103
108
  const index = locateMessageIndex(cm, String(id));
104
109
  if (index < 0) {
105
110
  cm.removeMessage(id);
106
- return;
111
+ return [id];
107
112
  }
108
113
  const run = bodyGroupRun(cm, index);
109
114
  cm.removeMessages(run.fromId as MessageId, run.toId as MessageId);
115
+ return run.ids;
116
+ }
117
+
118
+ /**
119
+ * The ids of the stored messages `firstId`..`lastId` (inclusive, in store
120
+ * order, every shard of a body), read before a removal of that interval so
121
+ * the caller knows what it took. Both ends are found tail-first and the
122
+ * rows between them read in one blob-free window. Empty when either end is
123
+ * not on the active branch; the ends may be given in either order.
124
+ */
125
+ export function storedIdsBetween(cm: SurgeryReadableCm, firstId: string, lastId: string): MessageId[] {
126
+ const found = locateMessageIndices(cm, new Set([firstId, lastId]));
127
+ const first = found.get(firstId);
128
+ const last = found.get(lastId);
129
+ if (!first || !last) return [];
130
+ const from = Math.min(first.index, last.index);
131
+ const to = Math.max(first.index, last.index);
132
+ const { messages } = cm.getMessageWindow(from, to - from + 1, { resolveBlobs: false });
133
+ return messages.map((m) => String(m.id) as MessageId);
110
134
  }
111
135
 
112
136
  /** removeStoredMessages for an interval known by its ids. */
@@ -5,7 +5,7 @@
5
5
  * a line that reads as the framework's own.
6
6
  */
7
7
 
8
- import { CONTEXT_MANAGER_TAGS, MEMBRANE_TAGS, NOTICE_TAG } from './notice-tags.js';
8
+ import { CONTEXT_MANAGER_TAGS, FORMER_NOTICE_TAGS, MEMBRANE_TAGS, NOTICE_TAG } from './notice-tags.js';
9
9
 
10
10
  /** Every form of line break a reader might take for one: CR LF, CR, LF,
11
11
  * vertical tab, form feed, NEL, and the Unicode line and paragraph separators. */
@@ -27,14 +27,14 @@ const SKIPPED = `[\\s\\p{Cc}${INVISIBLE}]`;
27
27
  const tagWord = (word: string): string =>
28
28
  [...word].map((c) => (/[\\^$.*+?()[\]{}|/]/.test(c) ? `\\${c}` : c)).join(`${SKIPPED}*`);
29
29
  const NOTICE_OPENING = new RegExp(
30
- `\\[(?=${SKIPPED}*(?:${[...Object.values(NOTICE_TAG), ...CONTEXT_MANAGER_TAGS, ...MEMBRANE_TAGS].map((tag) => tag.split(' ').map(tagWord).join(`${SKIPPED}+`)).join('|')})(?![\\p{L}\\p{N}]))`,
30
+ `\\[(?=${SKIPPED}*(?:${[...Object.values(NOTICE_TAG), ...FORMER_NOTICE_TAGS, ...CONTEXT_MANAGER_TAGS, ...MEMBRANE_TAGS].map((tag) => tag.split(' ').map(tagWord).join(`${SKIPPED}+`)).join('|')})(?![\\p{L}\\p{N}]))`,
31
31
  'giu',
32
32
  );
33
33
 
34
34
  /**
35
35
  * Texts read as one string, joined by line breaks, with a backslash put
36
36
  * before the bracket of each opening of a listed tag (NOTICE_TAG,
37
- * CONTEXT_MANAGER_TAGS, MEMBRANE_TAGS) that hasn't one before it in its own
37
+ * FORMER_NOTICE_TAGS, CONTEXT_MANAGER_TAGS, MEMBRANE_TAGS) that hasn't one before it in its own
38
38
  * text. A text `marks` says false of is read and never changed.
39
39
  *
40
40
  * Every opening, not only one that starts a line: membrane's XML formatter
@@ -34,6 +34,8 @@ export interface StreamThinkingDrops {
34
34
  place: (entries: readonly ThinkingBindingEntry[]) => PlacedDrop[];
35
35
  recordedAfter?: number;
36
36
  branch?: string;
37
+ /** `StartStreamResult`'s `noteThinkingDropped`. */
38
+ noteDropped?: (messageIds: readonly MessageId[]) => boolean;
37
39
  }
38
40
 
39
41
  /** A signed block's identity on the wire: a thinking block's signature, a redacted block's data. */
@@ -3,6 +3,7 @@ import { constants, fchmodSync, closeSync, fstatSync, lstatSync, openSync, readS
3
3
  import { closestNames } from './closest-names.js';
4
4
  import { boundedErrorMessage, errorMessage } from './error-message.js';
5
5
  import type { ToolDefinition, ToolResult } from './types/events.js';
6
+ import { appendAll } from './append-all.js';
6
7
 
7
8
  export interface ToolPresentationConfig {
8
9
  /** Absolute path to shared editable JSON. Missing file means no overrides. */
@@ -36,6 +37,8 @@ const MAX_DESCRIPTION_CHARS = 32768;
36
37
  const protectedNames = new Set(['set_tool_visibility', 'set_tool_description', 'workspace--read', 'toolsets--open', 'toolsets--act', 'toolsets--look', 'toolsets--close']);
37
38
  export const isPresentationTool = (name: string): boolean => name === 'set_tool_visibility' || name === 'set_tool_description';
38
39
  const hash = (value: string): string => createHash('sha256').update(value).digest('hex');
40
+ /** The catalogue's line layout, folded into its revision so a line reference saved under an earlier layout reads as stale. Raise it with any change to where the catalogue's lines fall. */
41
+ const CATALOGUE_LAYOUT = 2;
39
42
 
40
43
  /**
41
44
  * A presentation or defaults file this host can't use. Each problem is a
@@ -61,9 +64,9 @@ const characters = (text: string): number => [...text].length;
61
64
  /** A text's first `n` characters, never splitting a code point. */
62
65
  const firstCharacters = (text: string, n: number): string => [...text].slice(0, n).join('');
63
66
 
64
- /** A name as a message quotes it: whole up to 60 characters, and past that cut, with its length, since a file can hold a key of any size. */
65
- function quoted(name: string): string {
66
- return characters(name) <= 60 ? JSON.stringify(name) : `${JSON.stringify(firstCharacters(name, 57))}... (${count(characters(name))} characters)`;
67
+ /** A text as a message quotes it: whole up to `limit` characters, and past that cut, with its length, since a file can hold a key, and a tool a description, of any size. */
68
+ function quoted(name: string, limit = 60): string {
69
+ return characters(name) <= limit ? JSON.stringify(name) : `${JSON.stringify(firstCharacters(name, limit - 3))}... (${count(characters(name))} characters)`;
67
70
  }
68
71
 
69
72
  /** A file's problem as a message quotes it: its own clauses whole, and anything else bounded, since nobody wrote that text for its reader. */
@@ -246,7 +249,7 @@ export class ToolPresentation {
246
249
  return {name:tool.name,source:sources.get(tool.name) ?? 'Unattributed',visible:override?.visible ?? true,originalDescription:tool.description,description,descriptionSource,inputSchema:structuredClone(tool.inputSchema)};
247
250
  });
248
251
  const available = tools.map((tool,i) => ({...structuredClone(tool),description:entries[i].description}));
249
- return {revision:hash(JSON.stringify({raw,entries,diagnostics})),source:this.config.path,cataloguePath:this.config.cataloguePath,diagnostics,available,
252
+ return {revision:hash(JSON.stringify({layout:CATALOGUE_LAYOUT,raw,entries,diagnostics})),source:this.config.path,cataloguePath:this.config.cataloguePath,diagnostics,available,
250
253
  advertised:available.filter((_,i)=>entries[i].visible),entries};
251
254
  }
252
255
  edit(tool: string, input: unknown, available: ToolDefinition[]): ToolResult {
@@ -336,7 +339,7 @@ export class ToolPresentation {
336
339
  const name = args.name as string;
337
340
  if (!available.some((t) => t.name === name)) {
338
341
  const near = closestNames(name, available.map((t) => t.name));
339
- throw new PresentationRefusal(`Nothing was changed: no tool named ${quoted(name)} is available to you.${near.length ? ` Did you mean ${quotedList(near, 'or', JSON.stringify)}?` : ''}`
342
+ throw new PresentationRefusal(`Nothing was changed: you have no tool named ${quoted(name)} right now, shown or hidden.${near.length ? ` Did you mean ${quotedList(near, 'or', JSON.stringify)}?` : ''}`
340
343
  + ` Copy the exact name from your tool catalogue's index, workspace--read {"path":${JSON.stringify(this.config.cataloguePath)},"limit":140}, reading on with "offset" if the index runs past that.`);
341
344
  }
342
345
  if (field === 'description' && typeof args.description === 'string' && characters(args.description) > MAX_DESCRIPTION_CHARS)
@@ -346,6 +349,11 @@ export class ToolPresentation {
346
349
  return name;
347
350
  }
348
351
  }
352
+ const SUMMARY_CHARACTERS = 200;
353
+ function summaryOf(description: string): string {
354
+ const first = description.split(/\r\n|[\n\v\f\r\x85\u2028\u2029]/).find(line => line.trim() !== '');
355
+ return first === undefined ? '' : `: ${quoted(first, SUMMARY_CHARACTERS)}`;
356
+ }
349
357
  export function renderCatalogue(snapshot: PresentationSnapshot): string {
350
358
  const groups = new Map<string, PresentationSnapshot['entries']>();
351
359
  for (const entry of snapshot.entries) {
@@ -360,12 +368,22 @@ export function renderCatalogue(snapshot: PresentationSnapshot): string {
360
368
  'Visible = not hidden by you: in your tool list, unless the host keeps it in its "settings" toolset or a server\'s tab (toolsets--look shows those). Hidden = moved into the "settings" toolset, or its MCPL server\'s tab: toolsets--look shows it, toolsets--act calls it once that toolset is open.',
361
369
  'These are your visibility choices, not fixed primary/secondary rankings.',
362
370
  'Copy exact names from the index; similar-sounding names may not exist.',
371
+ 'Index by source: line N.',
363
372
  'Show a hidden tool: set_tool_visibility {"name":"EXACT_NAME","visible":true}.',
364
373
  `Read details: workspace--read {"path":${JSON.stringify(snapshot.cataloguePath)},"offset":LINE,"limit":LINES}.`,
365
374
  'Line references below belong to this revision; reread the index after changes.', '',
366
375
  ];
376
+ const indexLineAt = lines.indexOf('Index by source: line N.');
367
377
  // One line each: a quoted parse error can hold the file's own line breaks.
368
378
  for (const diagnostic of snapshot.diagnostics) lines.push('Diagnostic: '+diagnostic.replace(/\r\n|\r|\n/g, '\\n'));
379
+ const hidden = snapshot.entries.filter(e => !e.visible);
380
+ const hiddenAt = new Map<string, number>();
381
+ if (hidden.length) {
382
+ lines.push(`## Hidden (${hidden.length})`, '');
383
+ for (const entry of hidden) {hiddenAt.set(entry.name, lines.length); lines.push('');}
384
+ lines.push('');
385
+ }
386
+ lines[indexLineAt] = `Index by source: line ${lines.length + 1}.`;
369
387
  lines.push('## Index by source', '');
370
388
  const index = new Map<string, number>();
371
389
  for (const [source, entries] of groups) {
@@ -378,11 +396,18 @@ export function renderCatalogue(snapshot: PresentationSnapshot): string {
378
396
  lines.push(`### ${source}`, '');
379
397
  for (const entry of entries) {
380
398
  const start = lines.length + 1;
381
- lines.push(`#### ${entry.name} (${entry.visible?'visible':'hidden'})`, '',
382
- ...entry.description.split('\n'), '', `Description from: ${entry.descriptionSource ?? 'installed component'}`, '', `Schema: ${JSON.stringify(entry.inputSchema)}`);
383
- if(entry.description!==entry.originalDescription) lines.push('', 'Original description:', ...entry.originalDescription.split('\n'));
399
+ lines.push(`#### ${entry.name} (${entry.visible?'visible':'hidden'})`, '');
400
+ appendAll(lines, entry.description.split('\n'));
401
+ lines.push('', `Description from: ${entry.descriptionSource ?? 'installed component'}`, '', `Schema: ${JSON.stringify(entry.inputSchema)}`);
402
+ if(entry.description!==entry.originalDescription) {
403
+ lines.push('', 'Original description:');
404
+ appendAll(lines, entry.originalDescription.split('\n'));
405
+ }
384
406
  lines.push('');
385
- lines[index.get(entry.name)!] = `- [${entry.visible?'visible':'hidden'}] ${entry.name} — details: offset ${start}, limit ${lines.length-start+1}`;
407
+ const details = `details: offset ${start}, limit ${lines.length-start+1}`;
408
+ lines[index.get(entry.name)!] = `- [${entry.visible?'visible':'hidden'}] ${entry.name} — ${details}`;
409
+ const at = hiddenAt.get(entry.name);
410
+ if (at !== undefined) lines[at] = `- ${entry.name} (${entry.source})${summaryOf(entry.description)} — ${details}`;
386
411
  }
387
412
  }
388
413
  return lines.join('\n');
@@ -7,6 +7,7 @@ import { ensureStateRegistered } from './module-registry.js';
7
7
  import { classifyBlock } from './mcpl/references.js';
8
8
  import { resultClaimsOf, rfc005TextOf, toolResultDataToHistoryString } from './tool-result-history.js';
9
9
  import { safeSlice } from './safe-slice.js';
10
+ import { asOwnRow, presentLandedThenRethrow } from './dendrite/audience.js';
10
11
 
11
12
  export const TOOL_RESULT_GUARD_NOTICE = 'Tool result withheld by the guard. The tool has already executed.';
12
13
  export type WithheldNoticeKind = 'ran' | 'refused' | 'error';
@@ -195,6 +196,16 @@ export class ToolResultGuard {
195
196
 
196
197
  get enabled(): boolean { return this.override ?? this.configured; }
197
198
  setHost(host: WithheldHost | undefined): void { this.host = host; }
199
+
200
+ /** Where the results message is told of once stored (the agent's own-row sink, Agent.setOwnRowSink). */
201
+ private ownRowSink?: (ids: readonly MessageId[]) => void;
202
+ /**
203
+ * Install where storeResults tells of the results message it stores, once
204
+ * the add has returned (the presentation index presents it in the agent's
205
+ * window then, #291), or take it off with undefined. An idempotent retry
206
+ * of a batch already staged stores nothing and tells nothing.
207
+ */
208
+ setOwnRowSink(sink: ((ids: readonly MessageId[]) => void) | undefined): void { this.ownRowSink = sink; }
198
209
  /** Settles once every annotation started so far has finished: each of
199
210
  * those stubs has been edited to say where its original is, or its edit
200
211
  * failed and waits in the storage queue, retried in order until it lands
@@ -343,7 +354,9 @@ export class ToolResultGuard {
343
354
 
344
355
  /** `keptCap` is where what a stub keeps of a withheld result is cut: the
345
356
  * cap the caller stored `content` under, less the stub's notice room where
346
- * its message's bound sets it (toolResultShare, tool-image-ledger.ts). */
357
+ * its message's bound sets it (toolResultShare, tool-image-ledger.ts).
358
+ * The results are the agent's own row, stamped so (asOwnRow) on top of
359
+ * the caller's `metadata`, guarded or not. */
347
360
  storeResults(
348
361
  content: ContentBlock[],
349
362
  wireResults: ToolResult[],
@@ -352,7 +365,17 @@ export class ToolResultGuard {
352
365
  /** Where what a stub keeps is cut. */
353
366
  keptCap: number | undefined,
354
367
  ): MessageId {
355
- if (!this.enabled) return this.cm.addMessage('user', content, metadata);
368
+ metadata = asOwnRow(metadata, this.agentName);
369
+ if (!this.enabled) {
370
+ let id: MessageId;
371
+ try {
372
+ id = this.cm.addMessage('user', content, metadata);
373
+ } catch (error) {
374
+ presentLandedThenRethrow(error, this.agentName, this.ownRowSink, (row) => this.cm.getMessage(row) !== null);
375
+ }
376
+ this.ownRowSink?.([id]);
377
+ return id;
378
+ }
356
379
  if (this.pending) {
357
380
  // Idempotent for the same not-yet-submitted batch: a caller that
358
381
  // retries after a failure between staging and submission (e.g. a
@@ -392,9 +415,19 @@ export class ToolResultGuard {
392
415
  // chunk is ever summarized from the placeholder; released after the
393
416
  // settlement edit. Holds are in-memory only — a reopened manager has none,
394
417
  // which is correct since a reopened guard has no pending batch.
395
- const messageId = this.cm.addMessage('user', withheld, metadata, undefined, { holdCompression: true });
418
+ // A write that throws with rows of it stored presents them, as one that
419
+ // returned would be, and throws on with no batch pending, as before.
420
+ let messageId: MessageId;
421
+ try {
422
+ messageId = this.cm.addMessage('user', withheld, metadata, undefined, { holdCompression: true });
423
+ } catch (error) {
424
+ presentLandedThenRethrow(error, this.agentName, this.ownRowSink, (row) => this.cm.getMessage(row) !== null);
425
+ }
396
426
  this.pending = { id, messageId, content, withheld, wireResults,
397
427
  branch: this.cm.currentBranch().name, submitted: false, durable: false, kept, notices };
428
+ // Told before the durability barrier below, so the sync that makes the
429
+ // audit durable carries the row's presentation too.
430
+ this.ownRowSink?.([messageId]);
398
431
  // Durability barrier: the audit must reach Chronicle's chain heads before
399
432
  // the originals can go to a provider. On a failed sync the batch fails
400
433
  // CLOSED: the placeholders go on the wire instead (the turn continues,
@@ -575,8 +608,9 @@ export class ToolResultGuard {
575
608
  let deadlineSpent = false;
576
609
  for (const [index, block] of pending.content.entries()) {
577
610
  if (block.type !== 'tool_result') continue;
578
- // Once the store has left the batch's branch (a rollback, an undo, a
579
- // host's switch), write no more. This result and every later one is
611
+ // Once the store has left the batch's branch (a rollback, a
612
+ // suppression, a host's switch; an undo moves no branch), write no
613
+ // more. This result and every later one is
580
614
  // skipped, and its original stays in the audit record. Nothing
581
615
  // yields from here to the edit's own branch check, so while the
582
616
  // store is away the stub stays as it is. A write already under way
@@ -606,8 +640,8 @@ export class ToolResultGuard {
606
640
  // Declined where it would have committed, since the workspace had
607
641
  // left the batch's branch. Nothing was written, and no more are, as
608
642
  // for the results the branch check above stops. If the branch is
609
- // back by the edit, as after an undo and a redo, the stubs of this
610
- // result and the later ones name the audit record.
643
+ // back by the edit, as after a host's switch away and back, the stubs
644
+ // of this result and the later ones name the audit record.
611
645
  if (spill && 'skipped' in spill && spill.skipped === 'branch_changed') branchLeft = true;
612
646
  // A batch that used its deadline is said once, here, where the
613
647
  // batch is known; the host returns the skip without a line.