@animalabs/agent-framework 0.23.3 → 0.24.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (355) hide show
  1. package/README.md +212 -42
  2. package/dist/src/agent.d.ts +65 -9
  3. package/dist/src/agent.d.ts.map +1 -1
  4. package/dist/src/agent.js +98 -12
  5. package/dist/src/agent.js.map +1 -1
  6. package/dist/src/api/server.d.ts.map +1 -1
  7. package/dist/src/api/server.js +14 -12
  8. package/dist/src/api/server.js.map +1 -1
  9. package/dist/src/clock-rows.d.ts +115 -0
  10. package/dist/src/clock-rows.d.ts.map +1 -0
  11. package/dist/src/clock-rows.js +222 -0
  12. package/dist/src/clock-rows.js.map +1 -0
  13. package/dist/src/code-execution/engine.d.ts +177 -0
  14. package/dist/src/code-execution/engine.d.ts.map +1 -0
  15. package/dist/src/code-execution/engine.js +494 -0
  16. package/dist/src/code-execution/engine.js.map +1 -0
  17. package/dist/src/code-execution/index.d.ts +5 -10
  18. package/dist/src/code-execution/index.d.ts.map +1 -1
  19. package/dist/src/code-execution/index.js +5 -9
  20. package/dist/src/code-execution/index.js.map +1 -1
  21. package/dist/src/code-execution/isolate/calls.d.ts +114 -0
  22. package/dist/src/code-execution/isolate/calls.d.ts.map +1 -0
  23. package/dist/src/code-execution/isolate/calls.js +145 -0
  24. package/dist/src/code-execution/isolate/calls.js.map +1 -0
  25. package/dist/src/code-execution/isolate/child-entry.d.ts +2 -0
  26. package/dist/src/code-execution/isolate/child-entry.d.ts.map +1 -0
  27. package/dist/src/code-execution/isolate/child-entry.js +5 -0
  28. package/dist/src/code-execution/isolate/child-entry.js.map +1 -0
  29. package/dist/src/code-execution/isolate/child-main.d.ts +26 -0
  30. package/dist/src/code-execution/isolate/child-main.d.ts.map +1 -0
  31. package/dist/src/code-execution/isolate/child-main.js +132 -0
  32. package/dist/src/code-execution/isolate/child-main.js.map +1 -0
  33. package/dist/src/code-execution/isolate/child.d.ts +44 -0
  34. package/dist/src/code-execution/isolate/child.d.ts.map +1 -0
  35. package/dist/src/code-execution/isolate/child.js +315 -0
  36. package/dist/src/code-execution/isolate/child.js.map +1 -0
  37. package/dist/src/code-execution/isolate/frames.d.ts +80 -0
  38. package/dist/src/code-execution/isolate/frames.d.ts.map +1 -0
  39. package/dist/src/code-execution/isolate/frames.js +210 -0
  40. package/dist/src/code-execution/isolate/frames.js.map +1 -0
  41. package/dist/src/code-execution/isolate/output.d.ts +68 -0
  42. package/dist/src/code-execution/isolate/output.d.ts.map +1 -0
  43. package/dist/src/code-execution/isolate/output.js +143 -0
  44. package/dist/src/code-execution/isolate/output.js.map +1 -0
  45. package/dist/src/code-execution/isolate/prelude.d.ts +109 -0
  46. package/dist/src/code-execution/isolate/prelude.d.ts.map +1 -0
  47. package/dist/src/code-execution/isolate/prelude.js +401 -0
  48. package/dist/src/code-execution/isolate/prelude.js.map +1 -0
  49. package/dist/src/code-execution/isolate/protocol.d.ts +151 -0
  50. package/dist/src/code-execution/isolate/protocol.d.ts.map +1 -0
  51. package/dist/src/code-execution/isolate/protocol.js +150 -0
  52. package/dist/src/code-execution/isolate/protocol.js.map +1 -0
  53. package/dist/src/code-execution/isolate/render.d.ts +57 -0
  54. package/dist/src/code-execution/isolate/render.d.ts.map +1 -0
  55. package/dist/src/code-execution/isolate/render.js +214 -0
  56. package/dist/src/code-execution/isolate/render.js.map +1 -0
  57. package/dist/src/code-execution/isolate/runner.d.ts +250 -0
  58. package/dist/src/code-execution/isolate/runner.d.ts.map +1 -0
  59. package/dist/src/code-execution/isolate/runner.js +854 -0
  60. package/dist/src/code-execution/isolate/runner.js.map +1 -0
  61. package/dist/src/code-execution/isolate/scripts.d.ts +175 -0
  62. package/dist/src/code-execution/isolate/scripts.d.ts.map +1 -0
  63. package/dist/src/code-execution/isolate/scripts.js +357 -0
  64. package/dist/src/code-execution/isolate/scripts.js.map +1 -0
  65. package/dist/src/code-execution/quickjs.wasm +0 -0
  66. package/dist/src/code-execution/tool-definition.d.ts +93 -43
  67. package/dist/src/code-execution/tool-definition.d.ts.map +1 -1
  68. package/dist/src/code-execution/tool-definition.js +176 -142
  69. package/dist/src/code-execution/tool-definition.js.map +1 -1
  70. package/dist/src/deadline-timer.d.ts +3 -0
  71. package/dist/src/deadline-timer.d.ts.map +1 -1
  72. package/dist/src/deadline-timer.js +1 -1
  73. package/dist/src/deadline-timer.js.map +1 -1
  74. package/dist/src/framework.d.ts +1120 -457
  75. package/dist/src/framework.d.ts.map +1 -1
  76. package/dist/src/framework.js +4635 -2505
  77. package/dist/src/framework.js.map +1 -1
  78. package/dist/src/gate/event-gate.d.ts +28 -4
  79. package/dist/src/gate/event-gate.d.ts.map +1 -1
  80. package/dist/src/gate/event-gate.js +89 -13
  81. package/dist/src/gate/event-gate.js.map +1 -1
  82. package/dist/src/held-writes.d.ts +16 -3
  83. package/dist/src/held-writes.d.ts.map +1 -1
  84. package/dist/src/held-writes.js +16 -3
  85. package/dist/src/held-writes.js.map +1 -1
  86. package/dist/src/index.d.ts +8 -6
  87. package/dist/src/index.d.ts.map +1 -1
  88. package/dist/src/index.js +10 -8
  89. package/dist/src/index.js.map +1 -1
  90. package/dist/src/mcpl/channel-registry.d.ts +483 -115
  91. package/dist/src/mcpl/channel-registry.d.ts.map +1 -1
  92. package/dist/src/mcpl/channel-registry.js +1735 -425
  93. package/dist/src/mcpl/channel-registry.js.map +1 -1
  94. package/dist/src/mcpl/conversation-router.d.ts +19 -39
  95. package/dist/src/mcpl/conversation-router.d.ts.map +1 -1
  96. package/dist/src/mcpl/conversation-router.js +27 -59
  97. package/dist/src/mcpl/conversation-router.js.map +1 -1
  98. package/dist/src/mcpl/convert-block.d.ts.map +1 -1
  99. package/dist/src/mcpl/convert-block.js +9 -5
  100. package/dist/src/mcpl/convert-block.js.map +1 -1
  101. package/dist/src/mcpl/inbound-source.d.ts +50 -0
  102. package/dist/src/mcpl/inbound-source.d.ts.map +1 -1
  103. package/dist/src/mcpl/inbound-source.js +130 -0
  104. package/dist/src/mcpl/inbound-source.js.map +1 -1
  105. package/dist/src/mcpl/index.d.ts +2 -1
  106. package/dist/src/mcpl/index.d.ts.map +1 -1
  107. package/dist/src/mcpl/index.js +3 -2
  108. package/dist/src/mcpl/index.js.map +1 -1
  109. package/dist/src/mcpl/log-value.d.ts +6 -0
  110. package/dist/src/mcpl/log-value.d.ts.map +1 -1
  111. package/dist/src/mcpl/log-value.js +8 -0
  112. package/dist/src/mcpl/log-value.js.map +1 -1
  113. package/dist/src/mcpl/modern-connection.d.ts +15 -6
  114. package/dist/src/mcpl/modern-connection.d.ts.map +1 -1
  115. package/dist/src/mcpl/modern-connection.js +168 -53
  116. package/dist/src/mcpl/modern-connection.js.map +1 -1
  117. package/dist/src/mcpl/prose-grammar.d.ts +4 -5
  118. package/dist/src/mcpl/prose-grammar.d.ts.map +1 -1
  119. package/dist/src/mcpl/prose-grammar.js +4 -5
  120. package/dist/src/mcpl/prose-grammar.js.map +1 -1
  121. package/dist/src/mcpl/protocol-family.d.ts +97 -10
  122. package/dist/src/mcpl/protocol-family.d.ts.map +1 -1
  123. package/dist/src/mcpl/protocol-family.js +174 -17
  124. package/dist/src/mcpl/protocol-family.js.map +1 -1
  125. package/dist/src/mcpl/push-coalescer.d.ts +132 -14
  126. package/dist/src/mcpl/push-coalescer.d.ts.map +1 -1
  127. package/dist/src/mcpl/push-coalescer.js +227 -50
  128. package/dist/src/mcpl/push-coalescer.js.map +1 -1
  129. package/dist/src/mcpl/push-handler.d.ts +9 -20
  130. package/dist/src/mcpl/push-handler.d.ts.map +1 -1
  131. package/dist/src/mcpl/push-handler.js +7 -49
  132. package/dist/src/mcpl/push-handler.js.map +1 -1
  133. package/dist/src/mcpl/reference-fetcher.d.ts +2 -2
  134. package/dist/src/mcpl/reference-fetcher.d.ts.map +1 -1
  135. package/dist/src/mcpl/reference-fetcher.js +4 -4
  136. package/dist/src/mcpl/reference-fetcher.js.map +1 -1
  137. package/dist/src/mcpl/server-connection.d.ts +50 -21
  138. package/dist/src/mcpl/server-connection.d.ts.map +1 -1
  139. package/dist/src/mcpl/server-connection.js +158 -74
  140. package/dist/src/mcpl/server-connection.js.map +1 -1
  141. package/dist/src/mcpl/tags.d.ts +24 -0
  142. package/dist/src/mcpl/tags.d.ts.map +1 -1
  143. package/dist/src/mcpl/tags.js +33 -0
  144. package/dist/src/mcpl/tags.js.map +1 -1
  145. package/dist/src/mcpl/tool-result-normalize.d.ts +2 -1
  146. package/dist/src/mcpl/tool-result-normalize.d.ts.map +1 -1
  147. package/dist/src/mcpl/tool-result-normalize.js.map +1 -1
  148. package/dist/src/mcpl/transport.d.ts +55 -7
  149. package/dist/src/mcpl/transport.d.ts.map +1 -1
  150. package/dist/src/mcpl/transport.js +163 -34
  151. package/dist/src/mcpl/transport.js.map +1 -1
  152. package/dist/src/mcpl/types.d.ts +22 -6
  153. package/dist/src/mcpl/types.d.ts.map +1 -1
  154. package/dist/src/mcpl/types.js.map +1 -1
  155. package/dist/src/module-registry.d.ts +4 -2
  156. package/dist/src/module-registry.d.ts.map +1 -1
  157. package/dist/src/module-registry.js +100 -13
  158. package/dist/src/module-registry.js.map +1 -1
  159. package/dist/src/modules/discord/index.d.ts.map +1 -1
  160. package/dist/src/modules/discord/index.js +8 -13
  161. package/dist/src/modules/discord/index.js.map +1 -1
  162. package/dist/src/modules/history/index.d.ts.map +1 -1
  163. package/dist/src/modules/history/index.js +27 -4
  164. package/dist/src/modules/history/index.js.map +1 -1
  165. package/dist/src/modules/history/semantic.d.ts +15 -3
  166. package/dist/src/modules/history/semantic.d.ts.map +1 -1
  167. package/dist/src/modules/history/semantic.js +27 -5
  168. package/dist/src/modules/history/semantic.js.map +1 -1
  169. package/dist/src/modules/index.d.ts +1 -1
  170. package/dist/src/modules/index.d.ts.map +1 -1
  171. package/dist/src/modules/index.js.map +1 -1
  172. package/dist/src/modules/unknown-tool.d.ts +4 -1
  173. package/dist/src/modules/unknown-tool.d.ts.map +1 -1
  174. package/dist/src/modules/unknown-tool.js +4 -1
  175. package/dist/src/modules/unknown-tool.js.map +1 -1
  176. package/dist/src/modules/workspace/branch-intent.d.ts +3 -1
  177. package/dist/src/modules/workspace/branch-intent.d.ts.map +1 -1
  178. package/dist/src/modules/workspace/branch-intent.js +3 -1
  179. package/dist/src/modules/workspace/branch-intent.js.map +1 -1
  180. package/dist/src/modules/workspace/edit-plan.d.ts +265 -0
  181. package/dist/src/modules/workspace/edit-plan.d.ts.map +1 -0
  182. package/dist/src/modules/workspace/edit-plan.js +794 -0
  183. package/dist/src/modules/workspace/edit-plan.js.map +1 -0
  184. package/dist/src/modules/workspace/edit-text.d.ts +117 -0
  185. package/dist/src/modules/workspace/edit-text.d.ts.map +1 -0
  186. package/dist/src/modules/workspace/edit-text.js +584 -0
  187. package/dist/src/modules/workspace/edit-text.js.map +1 -0
  188. package/dist/src/modules/workspace/effects.d.ts +5 -4
  189. package/dist/src/modules/workspace/effects.d.ts.map +1 -1
  190. package/dist/src/modules/workspace/effects.js +78 -25
  191. package/dist/src/modules/workspace/effects.js.map +1 -1
  192. package/dist/src/modules/workspace/index.d.ts +493 -62
  193. package/dist/src/modules/workspace/index.d.ts.map +1 -1
  194. package/dist/src/modules/workspace/index.js +2216 -652
  195. package/dist/src/modules/workspace/index.js.map +1 -1
  196. package/dist/src/modules/workspace/observe.d.ts +213 -38
  197. package/dist/src/modules/workspace/observe.d.ts.map +1 -1
  198. package/dist/src/modules/workspace/observe.js +416 -36
  199. package/dist/src/modules/workspace/observe.js.map +1 -1
  200. package/dist/src/modules/workspace/reconcile.d.ts.map +1 -1
  201. package/dist/src/modules/workspace/reconcile.js +15 -8
  202. package/dist/src/modules/workspace/reconcile.js.map +1 -1
  203. package/dist/src/modules/workspace/text.d.ts +32 -0
  204. package/dist/src/modules/workspace/text.d.ts.map +1 -0
  205. package/dist/src/modules/workspace/text.js +67 -0
  206. package/dist/src/modules/workspace/text.js.map +1 -0
  207. package/dist/src/modules/workspace/types.d.ts +210 -6
  208. package/dist/src/modules/workspace/types.d.ts.map +1 -1
  209. package/dist/src/modules/workspace/types.js.map +1 -1
  210. package/dist/src/modules/workspace/watcher.d.ts +3 -2
  211. package/dist/src/modules/workspace/watcher.d.ts.map +1 -1
  212. package/dist/src/modules/workspace/watcher.js.map +1 -1
  213. package/dist/src/operator-log.d.ts +52 -24
  214. package/dist/src/operator-log.d.ts.map +1 -1
  215. package/dist/src/operator-log.js.map +1 -1
  216. package/dist/src/recovery/discord-awareness-outbox.d.ts +496 -72
  217. package/dist/src/recovery/discord-awareness-outbox.d.ts.map +1 -1
  218. package/dist/src/recovery/discord-awareness-outbox.js +1196 -289
  219. package/dist/src/recovery/discord-awareness-outbox.js.map +1 -1
  220. package/dist/src/recovery/offline-branch.d.ts +26 -1
  221. package/dist/src/recovery/offline-branch.d.ts.map +1 -1
  222. package/dist/src/recovery/offline-branch.js +164 -39
  223. package/dist/src/recovery/offline-branch.js.map +1 -1
  224. package/dist/src/recovery/recover-cli.js +23 -4
  225. package/dist/src/recovery/recover-cli.js.map +1 -1
  226. package/dist/src/send-tools.d.ts +11 -0
  227. package/dist/src/send-tools.d.ts.map +1 -0
  228. package/dist/src/send-tools.js +11 -0
  229. package/dist/src/send-tools.js.map +1 -0
  230. package/dist/src/timezone.d.ts +4 -2
  231. package/dist/src/timezone.d.ts.map +1 -1
  232. package/dist/src/timezone.js +4 -2
  233. package/dist/src/timezone.js.map +1 -1
  234. package/dist/src/tool-image-ledger.d.ts +46 -7
  235. package/dist/src/tool-image-ledger.d.ts.map +1 -1
  236. package/dist/src/tool-image-ledger.js +60 -7
  237. package/dist/src/tool-image-ledger.js.map +1 -1
  238. package/dist/src/tool-result-guard.d.ts +14 -11
  239. package/dist/src/tool-result-guard.d.ts.map +1 -1
  240. package/dist/src/tool-result-guard.js +17 -14
  241. package/dist/src/tool-result-guard.js.map +1 -1
  242. package/dist/src/tool-result-history.d.ts +3 -2
  243. package/dist/src/tool-result-history.d.ts.map +1 -1
  244. package/dist/src/tool-result-history.js +3 -2
  245. package/dist/src/tool-result-history.js.map +1 -1
  246. package/dist/src/tune-out/coordinator.d.ts +21 -0
  247. package/dist/src/tune-out/coordinator.d.ts.map +1 -1
  248. package/dist/src/tune-out/coordinator.js +142 -40
  249. package/dist/src/tune-out/coordinator.js.map +1 -1
  250. package/dist/src/types/agent.d.ts +31 -6
  251. package/dist/src/types/agent.d.ts.map +1 -1
  252. package/dist/src/types/events.d.ts +66 -9
  253. package/dist/src/types/events.d.ts.map +1 -1
  254. package/dist/src/types/framework.d.ts +69 -62
  255. package/dist/src/types/framework.d.ts.map +1 -1
  256. package/dist/src/types/module.d.ts +40 -8
  257. package/dist/src/types/module.d.ts.map +1 -1
  258. package/dist/src/types/trace.d.ts +111 -10
  259. package/dist/src/types/trace.d.ts.map +1 -1
  260. package/dist/src/usage/types.d.ts +16 -0
  261. package/dist/src/usage/types.d.ts.map +1 -1
  262. package/dist/src/usage/usage-tracker.d.ts +14 -1
  263. package/dist/src/usage/usage-tracker.d.ts.map +1 -1
  264. package/dist/src/usage/usage-tracker.js +81 -41
  265. package/dist/src/usage/usage-tracker.js.map +1 -1
  266. package/package.json +6 -8
  267. package/src/agent.ts +99 -12
  268. package/src/api/server.ts +14 -12
  269. package/src/clock-rows.ts +302 -0
  270. package/src/code-execution/engine.ts +595 -0
  271. package/src/code-execution/index.ts +5 -17
  272. package/src/code-execution/isolate/calls.ts +199 -0
  273. package/src/code-execution/isolate/child-entry.ts +5 -0
  274. package/src/code-execution/isolate/child-main.ts +132 -0
  275. package/src/code-execution/isolate/child.ts +327 -0
  276. package/src/code-execution/isolate/frames.ts +209 -0
  277. package/src/code-execution/isolate/output.ts +161 -0
  278. package/src/code-execution/isolate/prelude.ts +409 -0
  279. package/src/code-execution/isolate/protocol.ts +240 -0
  280. package/src/code-execution/isolate/render.ts +230 -0
  281. package/src/code-execution/isolate/runner.ts +911 -0
  282. package/src/code-execution/isolate/scripts.ts +479 -0
  283. package/src/code-execution/quickjs.wasm +0 -0
  284. package/src/code-execution/quickjs.wasm.LICENSES +149 -0
  285. package/src/code-execution/tool-definition.ts +236 -167
  286. package/src/deadline-timer.ts +1 -1
  287. package/src/framework.ts +4978 -2671
  288. package/src/gate/event-gate.ts +79 -17
  289. package/src/held-writes.ts +17 -3
  290. package/src/index.ts +32 -22
  291. package/src/mcpl/channel-registry.ts +1892 -471
  292. package/src/mcpl/conversation-router.ts +26 -72
  293. package/src/mcpl/convert-block.ts +9 -5
  294. package/src/mcpl/inbound-source.ts +131 -0
  295. package/src/mcpl/index.ts +4 -2
  296. package/src/mcpl/log-value.ts +9 -0
  297. package/src/mcpl/modern-connection.ts +162 -53
  298. package/src/mcpl/prose-grammar.ts +4 -5
  299. package/src/mcpl/protocol-family.ts +200 -22
  300. package/src/mcpl/push-coalescer.ts +306 -62
  301. package/src/mcpl/push-handler.ts +12 -54
  302. package/src/mcpl/reference-fetcher.ts +4 -4
  303. package/src/mcpl/server-connection.ts +180 -79
  304. package/src/mcpl/tags.ts +36 -0
  305. package/src/mcpl/tool-result-normalize.ts +2 -1
  306. package/src/mcpl/transport.ts +162 -33
  307. package/src/mcpl/types.ts +23 -6
  308. package/src/module-registry.ts +92 -13
  309. package/src/modules/discord/index.ts +8 -13
  310. package/src/modules/history/index.ts +25 -3
  311. package/src/modules/history/semantic.ts +29 -6
  312. package/src/modules/index.ts +1 -0
  313. package/src/modules/unknown-tool.ts +4 -1
  314. package/src/modules/workspace/branch-intent.ts +3 -1
  315. package/src/modules/workspace/edit-plan.ts +954 -0
  316. package/src/modules/workspace/edit-text.ts +618 -0
  317. package/src/modules/workspace/effects.ts +70 -19
  318. package/src/modules/workspace/index.ts +2293 -650
  319. package/src/modules/workspace/observe.ts +465 -56
  320. package/src/modules/workspace/reconcile.ts +14 -7
  321. package/src/modules/workspace/text.ts +68 -0
  322. package/src/modules/workspace/types.ts +211 -6
  323. package/src/modules/workspace/watcher.ts +3 -2
  324. package/src/operator-log.ts +47 -19
  325. package/src/recovery/discord-awareness-outbox.ts +1500 -356
  326. package/src/recovery/offline-branch.ts +189 -55
  327. package/src/recovery/recover-cli.ts +25 -4
  328. package/src/send-tools.ts +11 -0
  329. package/src/timezone.ts +4 -2
  330. package/src/tool-image-ledger.ts +62 -8
  331. package/src/tool-result-guard.ts +18 -15
  332. package/src/tool-result-history.ts +3 -2
  333. package/src/tune-out/coordinator.ts +166 -45
  334. package/src/types/agent.ts +32 -6
  335. package/src/types/events.ts +66 -9
  336. package/src/types/framework.ts +69 -62
  337. package/src/types/module.ts +40 -8
  338. package/src/types/trace.ts +121 -15
  339. package/src/usage/types.ts +16 -0
  340. package/src/usage/usage-tracker.ts +86 -43
  341. package/dist/src/code-execution/py-runner.d.ts +0 -191
  342. package/dist/src/code-execution/py-runner.d.ts.map +0 -1
  343. package/dist/src/code-execution/py-runner.js +0 -655
  344. package/dist/src/code-execution/py-runner.js.map +0 -1
  345. package/dist/src/code-execution/runtime-py.d.ts +0 -50
  346. package/dist/src/code-execution/runtime-py.d.ts.map +0 -1
  347. package/dist/src/code-execution/runtime-py.js +0 -677
  348. package/dist/src/code-execution/runtime-py.js.map +0 -1
  349. package/dist/src/mcpl/prose-stream-router.d.ts +0 -88
  350. package/dist/src/mcpl/prose-stream-router.d.ts.map +0 -1
  351. package/dist/src/mcpl/prose-stream-router.js +0 -291
  352. package/dist/src/mcpl/prose-stream-router.js.map +0 -1
  353. package/src/code-execution/py-runner.ts +0 -791
  354. package/src/code-execution/runtime-py.ts +0 -677
  355. package/src/mcpl/prose-stream-router.ts +0 -268
@@ -19,6 +19,10 @@ import type { McplServerRegistry } from './server-registry.js';
19
19
  import type { FeatureSetManager } from './feature-set-manager.js';
20
20
  import type { ToolDefinition, ToolResult, ProcessEvent } from '../types/index.js';
21
21
  import type { InboundSource } from './inbound-source.js';
22
+ /** Why a channel is selected for opening after a failed open by speech or a
23
+ * reply: its put-back couldn't be recorded, or the server's latest
24
+ * announcement or the subscription policy lifted the default it restored. */
25
+ export type SelectedForOpening = 'unrecorded' | 'server-bootstrap' | 'subscription-policy';
22
26
  type DesiredChannelState = 'open' | 'closed' | 'tuned-out';
23
27
  /**
24
28
  * Parameters of an active tune-out (issue #77), carried on the
@@ -34,8 +38,11 @@ export interface TuneOutParams {
34
38
  epochId: string;
35
39
  /** Subconscious summary cadence, in seconds. */
36
40
  cadenceSeconds: number;
37
- /** Maximum messages dumped raw at cancel; above the cap the subconscious
38
- * curates a digest and `fetch_history` covers the rest. */
41
+ /** Maximum messages dumped raw at cancel, the newest. Where the residents'
42
+ * strategies cap a message's size, the dump holds as many as fit whole in
43
+ * one message, or, when even the newest doesn't, as much of the newest as
44
+ * fits beside the cut's mark, if any does. For those left out the
45
+ * subconscious curates a digest, and `fetch_history` covers them. */
39
46
  backlogCap: number;
40
47
  /** Wake invocations before the tune-out auto-cancels. */
41
48
  maxWakes: number;
@@ -47,6 +54,14 @@ export interface TuneOutParams {
47
54
  * period chosen by the agent"). Unset = until cancelled. */
48
55
  expiresAtMs?: number;
49
56
  }
57
+ /**
58
+ * The desired state `store`'s lifecycle log records for `channelId` on
59
+ * `serverId`, for a reader with no registry yet, as a serving boot's
60
+ * deferred-write flush is, before initializeMcpl: the last decision wins, as
61
+ * the registry's replay reads it (getDesiredState answers once there is a
62
+ * registry). undefined when no decision names it.
63
+ */
64
+ export declare function desiredStateInLog(store: JsStore, serverId: string, channelId: string): DesiredChannelState | undefined;
50
65
  /** A registered channel entry, keyed by `{serverId}:{channelId}`. */
51
66
  interface ChannelEntry {
52
67
  serverId: string;
@@ -94,8 +109,27 @@ interface McplChannelIncomingEvent {
94
109
  * turn going on.
95
110
  */
96
111
  export declare function journalToolDescription(canSkipReply: boolean): string;
112
+ /**
113
+ * channel_open's and channel_close's descriptions for an agent whose window doesn't hold a channel's traffic: an
114
+ * ephemeral run, whose store is its own unless it's where channel messages are stored (on a host with no residents,
115
+ * the first registered agent), and on a host that routes conversations every agent but a fork, since a channel's
116
+ * messages go to its fork or, unrouted, nowhere. The descriptions in CHANNEL_TOOL_DEFINITIONS, written for the agents
117
+ * that read a channel, promised such an agent what it never gets: "Messages that address you still reach you", and
118
+ * history "preceding the message that invited you" when nothing invites it. Given per agent (AgentFramework's
119
+ * getToolsForAgent), so a holder's cached tool list doesn't change.
120
+ *
121
+ * Both say the call is for every agent: the decision is recorded per server and channel (setDesiredState), so a run's
122
+ * close closes the channel for the agents whose windows hold it, which "its messages don't come to you" alone could
123
+ * read as costing nothing. They claim only what holds on both lanes: a push that names a channel is stored in the
124
+ * residents' shared slot whether or not the channel is open (handleMcplPushEvent), so on a routed host the residents
125
+ * get the channel's pushes, and a server may push while a channel is closed and send channels/incoming once it's
126
+ * open. So opening brings the caller none of the channel's messages, and closing stops none reaching it. The history
127
+ * channel_open asks for comes back in its result (handleToolOpen), so that clause is true for anyone.
128
+ */
129
+ export declare const NON_HOLDER_CHANNEL_DESCRIPTIONS: Readonly<Record<'channel_open' | 'channel_close', string>>;
97
130
  /** Bound connector values for notices, logs and an outcome's reason. A
98
- * PublishOutcome keeps the connector's structured data (`detail`) whole. */
131
+ * PublishOutcome keeps the connector's structured data (`detail`) as the
132
+ * connection gives it, its strings redacted (redactedData). */
99
133
  export declare function connectorText(value: unknown): string;
100
134
  /** Where a publish was resolved to go — named by the registry, never by
101
135
  * the caller's spelling. */
@@ -105,6 +139,9 @@ export interface PublishDestination {
105
139
  /** The channel's registered label when the attempt was made. */
106
140
  label?: string;
107
141
  }
142
+ /** One key per destination, its server and channel: unlike joining the two
143
+ * with a separator, no two destinations share one, whatever their ids hold. */
144
+ export declare function destinationKey(to: PublishDestination): string;
108
145
  /**
109
146
  * What one channels/publish attempt established (ChannelRegistry.publish).
110
147
  * - `delivered`: the connector returned `delivered: true`. A historical
@@ -127,11 +164,29 @@ export interface PublishOutcome {
127
164
  /** Why it failed, or why its outcome is unknown — for a connector error,
128
165
  * its message, bounded (which may say what was already posted). */
129
166
  reason?: string;
130
- /** The connector error's structured `data`, verbatim, when it sent one. */
167
+ /** The connector error's structured `data`, with the strings in it
168
+ * redacted (redactedData), when it sent one. */
131
169
  detail?: unknown;
132
170
  /** When the outcome was established (epoch ms). */
133
171
  at: number;
134
172
  }
173
+ /**
174
+ * Why the destination refused a publishForAgent before anything went out.
175
+ * Its words say the same, since both come from one check: the channel isn't
176
+ * registered here, it takes no posts, or its server is gone, this host is
177
+ * connecting to it, it's reconnecting, or it's up without channels.publish
178
+ * (serverReach); or the request wasn't sent, as its connection refused it
179
+ * before anything was written (McplRequestError's `not-sent`). A refusal of
180
+ * the caller's own input, such as no text or no channel id, carries none,
181
+ * and so does a publish that went out, whatever became of it: its words say
182
+ * whether it may have been posted.
183
+ */
184
+ export type PublishRefusalReason = 'channel-not-registered' | 'inbound-only' | 'server-gone' | 'server-connecting' | 'server-down' | 'not-permitted' | 'not-sent';
185
+ /** A tune-out's open answered for a tune-out that ended, or that a later
186
+ * decision or a later tune-out replaced, while the open was out: by
187
+ * openForTuneOut, and by a repeated tune_out whose tune-out isn't the one it
188
+ * read before it waited. */
189
+ export declare const TUNE_OUT_REPLACED: string;
135
190
  interface ChannelRegistryOptions {
136
191
  /**
137
192
  * An ordinary (uncoalesced) `channels/incoming` message has just been
@@ -144,22 +199,32 @@ interface ChannelRegistryOptions {
144
199
  * RFC-006: an admitted `channels/incoming` message carrying `coalesce`, with
145
200
  * the event the ordinary path would have queued. The handler decides
146
201
  * replace / append / withdraw and returns the per-message result. Throws a
147
- * `CoalesceError` for a malformed or unauthorized occurrence.
202
+ * `CoalesceError` for a malformed or unauthorized occurrence. `firstView`
203
+ * says the coalescer delivered the message as the agent's first view of it,
204
+ * with the delivery's own `firstView` mark; it is the host's own, and isn't
205
+ * in the answer to the server.
148
206
  */
149
- handleCoalescedIncoming?: (serverId: string, message: ChannelIncomingMessage, event: McplChannelIncomingEvent) => Promise<ChannelIncomingMessageResult>;
207
+ handleCoalescedIncoming?: (serverId: string, message: ChannelIncomingMessage, event: McplChannelIncomingEvent) => Promise<ChannelIncomingMessageResult & {
208
+ firstView?: true;
209
+ }>;
150
210
  /** Chronicle store used for durable desired channel lifecycle state. */
151
211
  store?: JsStore;
152
212
  /** Callback to determine whether an incoming message should trigger inference. */
153
213
  shouldTriggerInference?: (content: string, metadata: Record<string, unknown>) => boolean;
154
214
  /**
155
- * Called when a text-only turn's speech could NOT be delivered to its
156
- * conversational locus — no locus, an unregistered channel, a missing
157
- * server, or the server reporting `delivered: false`. Not called for an
158
- * ephemeral run's speech with no locus, which is its caller's result
159
- * (`takesGlobalFallback`). The host wires this to drop a
160
- * `[discord-send-failed]` marker into chronicle so the failure is
161
- * visible to the agent (and operator) rather than silently lost. Must not
162
- * itself trigger inference (avoid wake loops).
215
+ * Called when a text-only turn's speech was not delivered to its
216
+ * conversational locus (`failed`), or may not have been (`unknown`), for
217
+ * whatever reason deliverSpeech gives, such as no locus, a channel that
218
+ * isn't registered or refuses speech, a missing server or grant, a failed
219
+ * open, the server reporting `delivered: false`, or a publish answered
220
+ * with an error, a timeout or a lost connection, after which whether it
221
+ * was posted is unknown. It isn't called for an ephemeral run's speech
222
+ * whose turn has no locus (a null locus), which is its caller's result
223
+ * (`takesGlobalFallback`), nor for a `failed` delivery whose caller holds
224
+ * its words with a notice of its own (deliverSpeech's `heldOnFailure`).
225
+ * The host wires this to drop a `[discord-send-failed]` marker into
226
+ * chronicle so the failure is visible to the agent (and operator) rather
227
+ * than silently lost. Must not itself trigger inference (avoid wake loops).
163
228
  */
164
229
  onRouteFailure?: (info: {
165
230
  conversationId: string;
@@ -198,9 +263,11 @@ interface ChannelRegistryOptions {
198
263
  * forks are spawned bound to a single channel (the framework tracks this in
199
264
  * `conversationAgentHomes` / `ConversationRouter.channelForAgent`); their
200
265
  * plain-text speech must route THERE. The process-global `defaultPublishChannel`
201
- * tracks only the most-recent inbound across ALL channels, so with one fork per
202
- * channel running concurrently it misroutes a fork's reply to whichever channel
203
- * last spoke (item 3). Returns undefined for the trunk/primary agent, which has
266
+ * tracks only the most recent inbound message across ALL channels (reaction,
267
+ * reaction-removal, edit and deletion markers aside, apart from an edit the
268
+ * coalescer delivers on acceptance as the agent's first view), so with one
269
+ * fork per channel running concurrently it misroutes a fork's reply to
270
+ * whichever channel last spoke (item 3). Returns undefined for the trunk/primary agent, which has
204
271
  * no home and correctly falls back to the global locus (heartbeats, etc.).
205
272
  */
206
273
  homeChannelResolver?: (agentName: string) => string | undefined;
@@ -210,11 +277,12 @@ interface ChannelRegistryOptions {
210
277
  * turn. This is the fix for single-TRUNK agents (the only mode
211
278
  * connectome-host runs — it never exposes conversation forks). A trunk agent
212
279
  * has no fork home, so without this its plain-text speech falls back to the
213
- * process-global `defaultPublishChannel`, which tracks the most-recent inbound
214
- * across ALL channels and misroutes a reply to whichever channel last spoke
215
- * under concurrency (item-3 redux). The framework keeps both on the live
216
- * turn's routing state and exposes them here. For a heartbeat / no-trigger
217
- * turn it resolves to undefined until the turn's locus is resolved, so that
280
+ * process-global `defaultPublishChannel`, which tracks the most recent inbound
281
+ * message across ALL channels (markers aside) and misroutes a reply to
282
+ * whichever channel last spoke under concurrency (item-3 redux). The
283
+ * framework keeps both on the live turn's routing state and exposes them
284
+ * here. For a heartbeat / no-trigger turn it resolves to undefined until the
285
+ * turn's locus is resolved, so that
218
286
  * resolution takes the global fallback, which the turn then keeps.
219
287
  * Consulted AFTER `homeChannelResolver` (a fork's home always wins), BEFORE
220
288
  * `defaultPublishChannel`.
@@ -234,6 +302,14 @@ interface ChannelRegistryOptions {
234
302
  takesGlobalFallback?: (conversationId: string) => boolean;
235
303
  /** Whether this framework has EventGate and can honor skip_reply self-wakes. */
236
304
  eventGatePresent?: boolean;
305
+ /**
306
+ * Whether this host is connecting to the server of this id: a connect or a
307
+ * restart of the id is in flight, or the policy exchange of the transport
308
+ * its registered connection is on is. Its channel tools and speech then say
309
+ * so, as its tool calls do, rather than read the empty grant meanwhile as a
310
+ * refusal (serverReach). It words a refusal only: the grant decides.
311
+ */
312
+ serverConnecting?: (serverId: string) => boolean;
237
313
  }
238
314
  /**
239
315
  * Who is actually making a channel tool call, as established by the
@@ -247,19 +323,6 @@ export type ChannelToolOrigin = {
247
323
  } | {
248
324
  kind: 'agent';
249
325
  agentName: string;
250
- /** The calling turn's trigger channel with the server whose message it
251
- * was: a channel_publish into that channel goes out through that server
252
- * only. */
253
- trigger?: {
254
- channelId: string;
255
- serverId: string;
256
- };
257
- /** The calling turn's locus with the server of the message that put it
258
- * there, where that isn't the trigger: the same holds for it. */
259
- locus?: {
260
- channelId: string;
261
- serverId: string;
262
- };
263
326
  };
264
327
  /** The machine decision sources a module-origin channel_close may record.
265
328
  * Closed on purpose: honest provenance means a small, auditable vocabulary,
@@ -277,9 +340,17 @@ export declare class ChannelRegistry {
277
340
  private homeChannelResolver?;
278
341
  private activeChannelResolver?;
279
342
  private takesGlobalFallback?;
343
+ private serverConnecting?;
280
344
  private store?;
281
345
  /** Registered channels, keyed by `{serverId}:{channelId}`. */
282
346
  private channels;
347
+ /**
348
+ * Each outgoing stream, by `inferenceId`, with the destinations it has
349
+ * started at (destinationKey): the rest of the stream there goes on there,
350
+ * and its `complete` goes only there (sendOutgoingChunk). An entry goes
351
+ * with the stream's `complete` for its destination.
352
+ */
353
+ private takenStreams;
283
354
  /** Holds back repeats of the line for a message refused because its
284
355
  * channel isn't registered (RefusalLines). */
285
356
  private unknownChannelLines;
@@ -328,11 +399,12 @@ export declare class ChannelRegistry {
328
399
  * sent at all.
329
400
  */
330
401
  private dmClassified;
331
- /** Most recent incoming channel ID — used for speech routing / default publish. */
402
+ /** The channel of the most recent incoming message that isn't a reaction,
403
+ * reaction removal, edit or deletion marker, apart from an edit the
404
+ * coalescer delivers on acceptance as the agent's first view: used for
405
+ * speech routing and the default publish. */
332
406
  private defaultPublishChannel;
333
- /** The server whose accepted message set defaultPublishChannel. */
334
- private defaultPublishServer;
335
- /** Most recent incoming message metadata, used for buildChannelContext. */
407
+ /** The same message's id and thread, used for buildChannelContext. */
336
408
  private defaultPublishMessageId;
337
409
  private defaultPublishThreadId;
338
410
  /** Per-channel typing indicator timers. */
@@ -350,14 +422,71 @@ export declare class ChannelRegistry {
350
422
  private channelLifecycleTails;
351
423
  private serverRemovals;
352
424
  private lifecycleOutstanding;
425
+ private lifecycleQueuedRemovals;
353
426
  private unconfirmedChannelTargets;
427
+ private failedCloseTargets;
428
+ private tuneOutOpens;
429
+ private untargetedPushEntries;
430
+ private transportCloses;
354
431
  private invalidateTransportConfirmation;
355
432
  /** Whether the host directs this server's channel lifecycle (§14.1: its
356
433
  * `channels.lifecycle` grant). Where it doesn't, the server opens and
357
434
  * closes its own channels, and sends no receipt the host could wait for. */
358
- private directsLifecycle;
359
- /** A registration's entry: nothing about its transport is known until a
360
- * receipt for its target confirms it open or closed. */
435
+ directsLifecycle(serverId: string): boolean;
436
+ /** Whether a decided close holds words back from a channel: only where
437
+ * the host directs the server's lifecycle. Without that grant the host
438
+ * can't close the channel, and words go into a transport that is open,
439
+ * as the open step's engagesDecidedClosed reads it too. */
440
+ private closeStands;
441
+ /** Where this server stands for a request this host would make of it
442
+ * (ServerReach). One without a connection's state reads as connected.
443
+ * A closed connection the host is restarting reads as connecting, as
444
+ * one being connected does. */
445
+ private serverReach;
446
+ /**
447
+ * Why this host won't open or close this server's channels, for a caller
448
+ * that found its grant without channels.lifecycle (§14.1), which decides:
449
+ * the server's state says why. It isn't up, or it's up without that grant.
450
+ * Neither the grant's name, which is the operator's, nor an empty grant's
451
+ * refusal, which needn't be the server's, reaches the agent.
452
+ */
453
+ private lifecycleRefusal;
454
+ /**
455
+ * Why a send to this server's channels is refused before anything goes
456
+ * out, as one clause with what works from there, for a caller that found
457
+ * no server or a grant without channels.publish (§14.1), which decides:
458
+ * the server's state says why. Plain speech gives it as its reason, and
459
+ * channel_publish and speak_in_channel as theirs, so one refusal has one
460
+ * wording. `checked` is the connection whose grant refused, where that
461
+ * was read before the words waited: one the registry has replaced since
462
+ * says nothing about the server that stands now.
463
+ */
464
+ private sendRefusal;
465
+ /**
466
+ * What a failed channel_open or channel_close tells the agent. Its
467
+ * decision was recorded before the server was asked, and reconciling
468
+ * applies it when the server next registers the channel (for a push's
469
+ * placeholder, if it ever does), if this host directs their lifecycle then
470
+ * (laterClause). A decision the log refused changed nothing, so that comes
471
+ * first. A channel no longer registered
472
+ * can't be reached by any channel tool, so its text names none. A later
473
+ * decision that came first is what stands, so that comes next. Then the
474
+ * server's state: one that isn't up gets the change when it's back, though
475
+ * not a backscroll's history. For the request's own failure, its state is
476
+ * read now, since a request out when the server dropped may have taken
477
+ * effect, and reconciling settles it either way. A decision already in
478
+ * effect, with no other work for the channel under way, says so, as one
479
+ * whose backscroll alone failed is. Then the failure's kind, since each
480
+ * has its own next step (ChannelLifecycleError). A request's own failure
481
+ * is in the connection's words.
482
+ */
483
+ private lifecycleFailureText;
484
+ /** A registration's entry, or a push's (ensureChannelRegistered): nothing
485
+ * about its transport is known until a receipt for its target confirms it
486
+ * open or closed, or the channel's traffic shows it open, which it does
487
+ * where the host doesn't direct the lifecycle, and for a push's entry
488
+ * decided open or tuned out that no update has given a target
489
+ * (handleIncoming). */
361
490
  private registerEntry;
362
491
  private hasPendingLifecycle;
363
492
  private handleCoalescedIncoming?;
@@ -412,15 +541,17 @@ export declare class ChannelRegistry {
412
541
  * locus. A push event from a closed channel must never mutate lifecycle
413
542
  * state: direct-address events are intentionally usable without subscribing.
414
543
  *
415
- * Mirrors the lazy-registration inside handleIncoming(), but for channels
416
- * that only ever arrive as push/events rather than channels/incoming — the
417
- * motivating case is Discord DMs, which discord-mcpl forwards via push/event
418
- * with the channel closed (`channelIsOpen:false`). Such a channel is never
419
- * registered, so routeSpeech() can't resolve it and the agent's reply is
420
- * silently dropped even though the inbound message proves the channel is
421
- * reachable (item-3 redux, DM sub-case). Idempotent: a later authoritative
422
- * channels/register or channels/changed overwrites this descriptor with the
423
- * richer one.
544
+ * For channels that only ever arrive as push/events rather than
545
+ * channels/incoming — the motivating case is Discord DMs, which
546
+ * discord-mcpl forwards via push/event with the channel closed
547
+ * (`channelIsOpen:false`). Such a channel is never registered, so
548
+ * routeSpeech() can't resolve it and the agent's reply is silently dropped
549
+ * even though the inbound message proves the channel is reachable (item-3
550
+ * redux, DM sub-case). Its entry starts with its transport unknown, as a
551
+ * registration's does. Its traffic shows it open, for a channel decided
552
+ * open or tuned out, until an update gives it a target (handleIncoming).
553
+ * Idempotent: a later authoritative channels/register or channels/changed
554
+ * overwrites this descriptor with the richer one.
424
555
  */
425
556
  ensureChannelRegistered(serverId: string, channelId: string, label?: string, extraMetadata?: Record<string, unknown>): void;
426
557
  /**
@@ -440,7 +571,10 @@ export declare class ChannelRegistry {
440
571
  */
441
572
  stopTyping(channelId?: string): void;
442
573
  /**
443
- * Get the default publish channel ID (most recent incoming channel).
574
+ * Get the default publish channel ID: the channel of the most recent
575
+ * incoming message that isn't a reaction, reaction removal, edit or
576
+ * deletion marker, apart from an edit the coalescer delivers on acceptance
577
+ * as the agent's first view.
444
578
  */
445
579
  getDefaultPublishChannel(): string | null;
446
580
  /**
@@ -459,7 +593,12 @@ export declare class ChannelRegistry {
459
593
  /** The registered label of `channelId` on exactly `serverId` (no
460
594
  * cross-server first match), or undefined when it has none. */
461
595
  getChannelLabel(serverId: string, channelId: string): string | undefined;
462
- isChannelOpen(channelId: string): boolean;
596
+ /** Whether `channelId`'s transport is open: on `serverId` where the caller
597
+ * knows the channel's server, and otherwise on the first server found to
598
+ * register that id (findChannelEntry). The map's key joins the two ids
599
+ * with a colon, so another server's entry can sit under a key: it has to
600
+ * be this server's (as in streamingServerAt). */
601
+ isChannelOpen(channelId: string, serverId?: string): boolean;
463
602
  getDesiredState(serverId: string, channelId: string): DesiredChannelState | undefined;
464
603
  /**
465
604
  * Get all open channels.
@@ -494,6 +633,36 @@ export declare class ChannelRegistry {
494
633
  * server's channels don't linger and route speech into the void.
495
634
  */
496
635
  removeServer(serverId: string): void;
636
+ /**
637
+ * The server's transport closed. Whatever it confirmed about a channel,
638
+ * open or closed, held for that transport only, so each of the server's
639
+ * channels reads as a registration's does: not open, and not confirmed
640
+ * closed. Where the host directs the server's lifecycle, a receipt
641
+ * confirms it again: a `channel_open` asks the server, and delivery opens
642
+ * before it publishes (an untargeted push entry's traffic confirms it, as
643
+ * before). Where the host doesn't, its traffic does, as after a
644
+ * registration. The entries, their desired state, labels and tune-out
645
+ * state stay, since the server is expected back (`removeServer` is for one
646
+ * that isn't).
647
+ *
648
+ * What was under way here at the close confirms nothing afterwards
649
+ * (transportCloses). Traffic that arrived before the close and is admitted
650
+ * after it, behind the coalescer's await, marks nothing open
651
+ * (handleIncoming). A lifecycle request sent before the close is answered
652
+ * for an older transport: its failure withdraws the open flag, and its
653
+ * receipt confirms nothing, and the operation tries again, which on the
654
+ * closed connection is refused as unreachable, so the decision waits for
655
+ * the next registration (runLifecycleOperation's sameTarget). What the
656
+ * connection holds across the boundary is another matter: it reaches
657
+ * handleIncoming after the next transport's grant, as that transport's
658
+ * traffic (resetPolicyForTransportBoundary), as it does after a
659
+ * registration.
660
+ *
661
+ * The framework calls this first in its handler for the connection's
662
+ * `close`, so a registration on the next transport, whose entries are new,
663
+ * can't come first and lose its confirmations to it.
664
+ */
665
+ transportClosed(serverId: string): void;
497
666
  /**
498
667
  * Stop all typing intervals and clear all channel registrations.
499
668
  */
@@ -503,7 +672,9 @@ export declare class ChannelRegistry {
503
672
  /**
504
673
  * Each writer appends its record here before it changes memory for it, so
505
674
  * an append that throws, as on a full disk, fails the operation with that
506
- * change unmade, and memory and the log still agree. A retry then records
675
+ * change unmade, and memory and the log still agree. A record that changes
676
+ * no memory, as a decline's of the invitation it declined, is its
677
+ * caller's to handle (handleToolDecline). A retry then records
507
678
  * the change rather than finding it in memory already, where
508
679
  * setDesiredState's same-state return would record nothing, and a restart
509
680
  * replays what memory held. appendLabelSighting keeps the same order for
@@ -642,9 +813,59 @@ export declare class ChannelRegistry {
642
813
  * Enter (or re-enter with fresh params) the tuned-out state for a channel.
643
814
  * Re-entering under a new epochId replaces the active epoch; the previous
644
815
  * epoch's stamped messages stay excluded (stamps are permanent) and its
645
- * wake count is superseded. Transport stays open (see reconcile).
816
+ * wake count is superseded. Its transport is kept open: tune_out opens a
817
+ * closed one (openForTuneOut), and reconcile opens it at the channel's
818
+ * registration.
646
819
  */
647
820
  enterTuneOut(serverId: string, channelId: string, params: TuneOutParams, source: string): void;
821
+ /**
822
+ * Make a tuned-out channel's transport match its tune-out, which keeps it
823
+ * open so its traffic reaches the subconscious (TuneOutParams). The
824
+ * tune-out is recorded first (enterTuneOut), and this writes no decision,
825
+ * so the tune-out stands whatever becomes of the open. Lifecycle work
826
+ * queued for the channel goes first, until none is left, since each
827
+ * operation reads the decision when it runs and so opens a channel tuned
828
+ * out meanwhile; its own failure, such as a close the server refused,
829
+ * isn't this open's. Then the state is read. Where this host directs the
830
+ * lifecycle and the transport isn't confirmed open, the channel's
831
+ * lifecycle queue opens it once (applyDesiredChannelState reads a
832
+ * tune-out as open), and the answer waits for the work queued after it
833
+ * too, such as a registration that came back, and comes from the state
834
+ * that work leaves. Returns nothing where the transport is open, or, for
835
+ * tune_out's answer, why the channel's messages don't or may not reach the
836
+ * subconscious yet and when they will, or that the tune-out isn't in
837
+ * effect any more. A call while this tune-out's open is in flight, as a
838
+ * repeated tune_out makes, gets that open's answer rather than send
839
+ * another.
840
+ */
841
+ openForTuneOut(serverId: string, channelId: string): Promise<string | undefined>;
842
+ /**
843
+ * Whether a tune_out repeated now has nothing to wait for and finds its
844
+ * channel's transport open, as the tune-out reads it: no lifecycle work
845
+ * queued for the channel, since the tune-out's own call may still be
846
+ * waiting for the work queued after its open; its server up; and an open
847
+ * flag the tune-out takes as open (tuneOutReadsOpen). Where it doesn't,
848
+ * the repeat goes through openForTuneOut, which joins this tune-out's open
849
+ * in flight, or waits for the queued work and, where this host can open
850
+ * the channel, tries the open again.
851
+ */
852
+ tuneOutTransportOpen(serverId: string, channelId: string): boolean;
853
+ /**
854
+ * Whether a tune-out takes an entry's transport as open: its open flag,
855
+ * unless a close for it failed since it was confirmed (failedCloseTargets),
856
+ * since that close may have taken effect. The other readers take any flag
857
+ * a failed request left as it was (runLifecycleOperation), since a send
858
+ * through it fails where it can be seen, and channel_open sends an open
859
+ * after a failed close anyway, its decision having been closed. A
860
+ * tune-out's success says traffic will arrive, nothing would show it
861
+ * doesn't, and the decision it replaced isn't known here. An open that
862
+ * failed, as a redundant one queued behind a confirming one may, can't
863
+ * have closed the channel: one for the current target leaves the flag as
864
+ * it was, so an open flag stays open (one for a target no longer current
865
+ * withdraws it).
866
+ */
867
+ private tuneOutReadsOpen;
868
+ private openTuneOutTransport;
648
869
  /**
649
870
  * End the active tune-out, returning the channel to `nextState`.
650
871
  * The caller (tune-out coordinator) owns the dump/notice flow; this is
@@ -671,6 +892,15 @@ export declare class ChannelRegistry {
671
892
  params: TuneOutParams;
672
893
  wakeCount: number;
673
894
  } | null;
895
+ /** Every tune-out on record, whether or not its channel is registered
896
+ * here yet: the decisions the lifecycle log's replay restored, and any
897
+ * made since. */
898
+ tuneOutsOnRecord(): Array<{
899
+ serverId: string;
900
+ channelId: string;
901
+ params: TuneOutParams;
902
+ source: string;
903
+ }>;
674
904
  /** Registered channel entries (read-only iteration for the coordinator). */
675
905
  listChannelsRaw(): Array<{
676
906
  serverId: string;
@@ -685,14 +915,24 @@ export declare class ChannelRegistry {
685
915
  writeCoordinatorState(stateId: string, value: unknown): void;
686
916
  /**
687
917
  * Publish into a channel on behalf of a named non-resident agent (the
688
- * subconscious's speak_in_channel). Same delivery path as the
689
- * channel_publish tool; the agent name rides the speech-routed trace.
918
+ * subconscious's speak_in_channel). Same delivery path, and the same result
919
+ * as the channel_publish tool apart from `reason` below. Its traces carry the agent's name and follow
920
+ * the publish's outcome as deliverSpeech's do: speech-routed after a
921
+ * confirmed delivery, and speech-route-failed otherwise, `unknown` when the
922
+ * words may have been posted and `failed` when nothing was, a refusal before
923
+ * the publish included. The routed trace carries no message id, as before:
924
+ * nothing here reads one, and a consumer that edits the newest traced
925
+ * message in a channel would have this post to edit when an interruption of
926
+ * the resident matches none. A refusal of the destination before anything
927
+ * went out carries its `reason` (PublishRefusalReason), so a caller can act
928
+ * on why nothing was posted without reading the words.
690
929
  */
691
930
  publishForAgent(channelId: string, text: string, agentName: string): Promise<{
692
931
  success: boolean;
693
932
  data?: unknown;
694
933
  error?: string;
695
934
  isError?: boolean;
935
+ reason?: PublishRefusalReason;
696
936
  }>;
697
937
  /**
698
938
  * Consume the old recipe policy exactly once. It seeds Chronicle for
@@ -722,6 +962,25 @@ export declare class ChannelRegistry {
722
962
  private applyDesiredChannelState;
723
963
  /** One queued lifecycle operation, run when its turn in the queue comes. */
724
964
  private runLifecycleOperation;
965
+ /** Whether lifecycle work already outstanding for the channel will carry out
966
+ * its current decision: some is, and the newest was queued since its
967
+ * server's registrations were last removed, so it won't cancel when it
968
+ * would run. Each operation reads the decision when it runs. It answers for
969
+ * now: a removal after it cancels that work too, and takes the channel's
970
+ * entry with it, so the channel's next registration by channels/register,
971
+ * or as added by channels/changed, carries the decision out, where this
972
+ * host directs the lifecycle then. A push's registration
973
+ * (ensureChannelRegistered) queues no lifecycle work. So where a push
974
+ * re-makes an entry that a channels/changed removal took while an RPC for
975
+ * the old entry was out, the operation running that RPC carries the
976
+ * decision out for the push's entry only if the RPC is answered: a failed
977
+ * one rethrows, since its retry covers only a retarget of its own entry.
978
+ * This answers true meanwhile, so a channels/changed update that retargets
979
+ * the push's entry is left to that operation, and stays undone after a
980
+ * failed RPC until lifecycle work is queued for the channel again
981
+ * (applyDesiredChannelState). No server we know of sends `updated` for a
982
+ * channel it has removed. */
983
+ private outstandingWorkCarriesOut;
725
984
  /**
726
985
  * A server that answered an open with another channel really opened that
727
986
  * one. When it's registered here and the host wants it closed, close it
@@ -732,11 +991,22 @@ export declare class ChannelRegistry {
732
991
  * doesn't know needs nothing: §14.5 refuses its traffic.
733
992
  */
734
993
  private closeSubstitutedChannel;
994
+ /**
995
+ * Carry out a channel's decision through its lifecycle queue, for a
996
+ * transport the server may have opened without the host's knowing: one it
997
+ * opened for another channel's request (closeSubstitutedChannel), or one a
998
+ * failed open's request may have reached (openChannelNow). The decision is
999
+ * a closed one, except after a failed open whose put-back the server's
1000
+ * latest announcement or the policy lifted. A failure is reported as a
1001
+ * trace; the decision stands.
1002
+ */
1003
+ private applyThroughQueue;
735
1004
  /**
736
1005
  * Join outstanding lifecycle work without recording new intent. Retargeting
737
1006
  * may have invalidated open confirmation while the decision remains pending.
738
- * A close that settles during the wait remains authoritative; waiting for
739
- * it is not an instruction to open the channel again.
1007
+ * A close that settles during the wait remains authoritative where the host
1008
+ * directs the server's lifecycle (closeStands); waiting for it is not an
1009
+ * instruction to open the channel again.
740
1010
  */
741
1011
  private waitForOpenChannel;
742
1012
  private reconcileChannels;
@@ -749,16 +1019,15 @@ export declare class ChannelRegistry {
749
1019
  private sendTypingNotification;
750
1020
  /** Descriptors registered by one server — the §14.3 channels/list answer. */
751
1021
  descriptorsForServer(serverId: string): ChannelDescriptor[];
752
- /**
753
- * The server whose accepted message set the global fallback, where
754
- * `channelId` is the fallback's channel: a turn whose locus is the
755
- * fallback resolves it with this server, taken with the locus.
756
- */
757
- fallbackServerFor(channelId: string): string | undefined;
758
1022
  /** Server id owning a registered channel (by descriptor id), or null. */
759
1023
  getChannelServerId(channelId: string): string | null;
760
- /** Whether a server other than `serverId` registers `channelId`. */
761
- private registeredByAnotherServer;
1024
+ /**
1025
+ * The server that declared this channel inbound-only (isInboundOnly), or
1026
+ * undefined when it isn't one. The notices name that server. A caller that
1027
+ * knows the channel's server passes it; otherwise the channel is found by
1028
+ * its id alone (findChannelEntry).
1029
+ */
1030
+ inboundOnlyServer(channelId: string, serverId?: string): string | undefined;
762
1031
  /**
763
1032
  * Find a channel entry by channelId (searches across all servers).
764
1033
  * Returns the first match.
@@ -773,21 +1042,56 @@ export declare class ChannelRegistry {
773
1042
  /**
774
1043
  * Record durable desired-open intent, then queue the channel's lifecycle
775
1044
  * work (applyDesiredChannelState), which tells the server to subscribe and
776
- * marks the live entry open on a receipt for its current target. Every
777
- * open the agent or its speech asks for — the channel_open tool, delivery
1045
+ * marks the live entry open on a receipt for its current target, applying
1046
+ * an inbound-only declaration the answer carries (applyOpenDeclaration).
1047
+ * Every open the agent or its speech asks for — the channel_open tool, delivery
778
1048
  * into a closed locus, an explicit send into a closed channel — comes
779
1049
  * here. Reconciliation queues that work directly, as the closes do
780
1050
  * (channel_close, a decline, and the close of a substituted channel).
781
- * Desired state is recorded BEFORE the server round-trip: intent sticks
782
- * even if the subscribe fails, and reconciliation retries later.
783
- * Automatic delivery needs open transport, not a change of attention:
784
- * preserve tune-out epochs both before and during the round-trip.
1051
+ * Desired state is recorded BEFORE the server round-trip. The agent's own
1052
+ * open is a decision about the channel: it sticks even if the subscribe
1053
+ * fails, and reconciliation retries later. An open by speech or a reply is
1054
+ * incidental to its words: when its round-trip fails, the decision it
1055
+ * wrote goes back to the one it replaced, so the agent, told the channel
1056
+ * is closed and the open failed, isn't later put into it by that decision.
1057
+ * That holds only while the record is still the one it wrote: a decision
1058
+ * made meanwhile stands, and the failure then comes as `overtaken`
1059
+ * (ChannelLifecycleError). Where the decision put back is a pure default,
1060
+ * nobody had decided, so the channel then follows its server's latest
1061
+ * announcement and the policy: a re-announcement during the round-trip
1062
+ * found the open's own record and lifted nothing. If they select it for
1063
+ * opening, the failure says so (`selected-again`). And since
1064
+ * a failed request may have reached the server, the decision that stands
1065
+ * is carried out on the wire too. An open by speech or a reply that can't
1066
+ * send its request, on a server without channels.lifecycle, writes
1067
+ * nothing. Automatic delivery needs open transport, not a change of
1068
+ * attention: preserve tune-out epochs both before and during the
1069
+ * round-trip.
785
1070
  *
786
1071
  * `opened` says whether this call turned a closed channel open, which is
787
1072
  * what the delivery and reply notices tell the resident. Reconfirming the
788
1073
  * transport of a channel already decided open or tuned out isn't one.
789
1074
  */
790
1075
  private openChannelNow;
1076
+ /**
1077
+ * An open's answer carries the server's descriptor for the channel
1078
+ * (§14.3), the first place a lazily registered channel's own declaration
1079
+ * can arrive. runLifecycleOperation hands it here, wherever the host opens
1080
+ * a channel, once the answer is known to be for the channel's current
1081
+ * entry and target. An answer that names another channel never arrives
1082
+ * here: it's a substitution, which fails the open. One whose channel names
1083
+ * no id is this channel's, as runLifecycleOperation takes it, so its
1084
+ * declaration applies too.
1085
+ *
1086
+ * Only an inbound-only declaration is applied. The answer isn't always the
1087
+ * server's latest word: a `channels/changed` that arrives in the same read
1088
+ * as the answer is handled before the open's operation resumes, so the
1089
+ * answer is applied over it. Applying only a refusal keeps that race
1090
+ * fail-closed: a stale answer can keep a channel refused until the
1091
+ * server's next update, but never lift a newer refusal. A server lifts its
1092
+ * declaration by changing or registering the channel again.
1093
+ */
1094
+ private applyOpenDeclaration;
791
1095
  /**
792
1096
  * Resolve a `>>` prose-routing target (explicit prose routing —
793
1097
  * docs/explicit-prose-routing.md) to a registered channel.
@@ -801,14 +1105,25 @@ export declare class ChannelRegistry {
801
1105
  *
802
1106
  * Ambiguity is an error carrying candidates — never a guess: this is the
803
1107
  * mechanism that makes prose misdelivery structurally impossible.
1108
+ *
1109
+ * `forSpeech` is for a target the agent's speech will be posted to: a
1110
+ * channel its server declared inbound-only (isInboundOnly) then resolves
1111
+ * to an error that says so, since nothing is published there, and that
1112
+ * names the channel as `refusedChannelId`, so a caller can tell a refused
1113
+ * channel from a name that resolved to nothing. Without it, as for reading
1114
+ * a channel's history, any registered channel resolves.
804
1115
  */
805
- resolveProseTarget(spec: string): {
1116
+ resolveProseTarget(spec: string, opts?: {
1117
+ forSpeech?: boolean;
1118
+ }): {
806
1119
  channelId: string;
807
1120
  label?: string;
808
1121
  } | {
809
1122
  error: string;
810
1123
  candidates?: string[];
1124
+ refusedChannelId?: string;
811
1125
  };
1126
+ private resolveTargetByName;
812
1127
  /**
813
1128
  * The `>>` target to show an agent for a channel: one whitespace-free token
814
1129
  * that `resolveProseTarget()` maps back to this same channel. The prefix
@@ -831,12 +1146,24 @@ export declare class ChannelRegistry {
831
1146
  * engaging a channel opens it, so typing indicators, reaction machinery,
832
1147
  * and inbound forwarding all come alive with the first outbound message.
833
1148
  * Accepts composite MCPL ids or raw server-internal ids (explicit send
834
- * tools receive whatever the agent typed).
1149
+ * tools receive whatever the agent typed). An `open-failed` answer says
1150
+ * whether the open that failed was one that would have opened a channel
1151
+ * not selected open (`opening`), as opposed to one reconfirming the
1152
+ * transport of a channel already selected open or tuned out. It isn't one
1153
+ * either where a decision made during its round-trip replaced it
1154
+ * (`overtaken`), or where queued lifecycle work left the
1155
+ * channel closed before any open was sent. `selectedForOpening` says the
1156
+ * channel is selected for opening after the failure, and why: the put-back
1157
+ * couldn't be recorded (`put-back-unrecorded`), or the server's latest
1158
+ * announcement or the policy lifted the default it restored
1159
+ * (`selected-again`).
835
1160
  */
836
1161
  openIfClosedForSend(rawChannelId: string, serverId?: string): Promise<{
837
1162
  status: 'opened' | 'already-open' | 'unknown-channel' | 'ambiguous' | 'open-failed';
838
1163
  channelId?: string;
839
1164
  label?: string;
1165
+ opening?: boolean;
1166
+ selectedForOpening?: SelectedForOpening;
840
1167
  }>;
841
1168
  private handleToolOpen;
842
1169
  private handleToolClose;
@@ -873,34 +1200,47 @@ export declare class ChannelRegistry {
873
1200
  */
874
1201
  private handleToolSkipReply;
875
1202
  /**
876
- * Host-owned output routing (see forking-knowledge-miner LOCUS-ROUTING-DESIGN).
877
- * Publish the agent's plain-text speech to the current conversational locus
878
- * (the most recent incoming channel, tracked cross-surface here in the host).
879
- * Called by the framework on a text-only turn — replaces the per-surface
880
- * sticky auto-post that used to live in discord-mcpl. Returns null when there
881
- * is no locus / the channel or its server can't be resolved (in which case
882
- * the speech simply stays in chronicle + module surfaces).
1203
+ * MCPL Spec 14.3 outgoing streaming: forward a text delta to the server
1204
+ * owning the channel. The framework sends each piece of prose once its
1205
+ * publish succeeds, so a stream carries only what was published.
1206
+ * Emitted only when that server's grant has `channels.streaming` —
1207
+ * servers that never opted in receive nothing. Fire-and-forget and never
1208
+ * throws: streaming is an observer surface; the authoritative delivery is
1209
+ * channels/publish.
1210
+ *
1211
+ * `to` is the destination the publish went to, its server and channel.
1212
+ * The chunk goes there while that server registers that channel (Spec
1213
+ * 14.3: the recipient is "the server that registered the target
1214
+ * channel"). A stream doesn't start in a channel its server has declared
1215
+ * inbound-only (#350's rule), not even for a publish delivered there just
1216
+ * before the declaration. One that started there before it goes on, since
1217
+ * the declaration doesn't unregister the channel: a later chunk is for a
1218
+ * publish delivered before it. A bare channel id is resolved as before, to
1219
+ * the one server that registers it, at each call (streamingServerFor), and
1220
+ * keeps no record: a stream sent by destination ends by destination, since
1221
+ * only a destination's `complete` removes its record.
1222
+ */
1223
+ sendOutgoingChunk(to: string | PublishDestination, conversationId: string, inferenceId: string, index: number, delta: string): void;
1224
+ /**
1225
+ * Spec 14.3 companion: final moderated content per channel at stream end.
1226
+ * Given a destination, it goes only where the stream started
1227
+ * (sendOutgoingChunk), while that server still registers that channel,
1228
+ * inbound-only or not, and its grant has `channels.streaming`: once per
1229
+ * destination, whose consumer, such as a TTS utterance, finalizes on it
1230
+ * and reconciles any chunk it missed. A bare channel id is resolved as
1231
+ * before (streamingServerFor).
883
1232
  */
1233
+ sendOutgoingComplete(to: string | PublishDestination, conversationId: string, inferenceId: string, text: string): void;
1234
+ private streamingServerFor;
1235
+ /**
1236
+ * A destination's server, for a stream message: while that server
1237
+ * registers that channel, and its grant has `channels.streaming` (as in
1238
+ * streamingServerFor). A stream doesn't start in an inbound-only channel.
1239
+ */
1240
+ private streamingServerAt;
884
1241
  /** Resolve the outbound locus (fork HOME → this-turn's TRIGGERING channel →
885
1242
  * process-global default). Public so a multi-segment caller can snapshot it
886
1243
  * ONCE and pin every segment to it via routeSpeech's `overrideChannelId`. */
887
- /**
888
- * MCPL Spec 14.3 outgoing streaming: forward a moderated text delta to the
889
- * server owning the channel, AS THE MODEL GENERATES. Emitted only when that
890
- * server declared `channels.streaming` in its initialize capabilities —
891
- * servers that never opted in (the whole existing fleet) receive nothing.
892
- * Fire-and-forget and never throws: streaming is an observer surface; the
893
- * authoritative delivery is the eventual channels/publish.
894
- */
895
- sendOutgoingChunk(channelId: string, conversationId: string, inferenceId: string, index: number, delta: string,
896
- /** The server the channel resolves with, as the speech's locus does
897
- * (deliverSpeech's locusServerId). */
898
- serverId?: string): void;
899
- /** Spec 14.3 companion: final moderated content per channel at stream end. */
900
- sendOutgoingComplete(channelId: string, conversationId: string, inferenceId: string, text: string,
901
- /** As sendOutgoingChunk's. */
902
- serverId?: string): void;
903
- private streamingServerFor;
904
1244
  resolveLocus(conversationId: string): string | null;
905
1245
  /** The process-global fallback channel for this conversation, or null when it takes none (takesGlobalFallback). */
906
1246
  private globalFallbackFor;
@@ -936,7 +1276,33 @@ export declare class ChannelRegistry {
936
1276
  * possible to send into a closed channel: a closed but registered
937
1277
  * destination is opened first (`openSource` names why), once its server
938
1278
  * and that server's channels.publish grant are known to take the send, so
939
- * a refused send opens nothing; and a failed open sends nothing.
1279
+ * a send refused before the open opens nothing; and a failed open sends
1280
+ * nothing.
1281
+ *
1282
+ * A channel its server declared inbound-only (isInboundOnly) takes nothing
1283
+ * the host would post, whichever path the words took, a drafts resend
1284
+ * included: it's refused before anything opens. The channel's queued
1285
+ * lifecycle work and the open await the server, and a channels/changed
1286
+ * update, a re-register or the open's own answer (applyOpenDeclaration)
1287
+ * may declare the channel inbound-only meanwhile, or a removal take it
1288
+ * away. So the check just before the publish, after every await, reads
1289
+ * the channel's registration as it is then, and refuses one that is gone
1290
+ * or inbound-only, or whose server's grant no longer has channels.publish.
1291
+ * A removal during a wait already fails it there (waitForOpenChannel); the
1292
+ * check also catches one made after the last wait, as the opening's notice
1293
+ * can. A registration nothing has confirmed open, such as one that
1294
+ * replaced the one waited for or a retarget of it, or one whose close now
1295
+ * stands (where the host directs the server's lifecycle), is treated as at
1296
+ * the first wait: the words wait for its queued lifecycle work, and the
1297
+ * check runs again on the registration that work leaves. Words refused
1298
+ * after an open for a declaration leave the channel open, and the agent
1299
+ * gets the failure for the words. An open by delivery (`openSource`
1300
+ * 'opened-by-delivery', the default) that turned a closed channel open
1301
+ * also gives the notice that it's open, which says how to close it to a
1302
+ * reader that can.
1303
+ * One that only reconfirmed the transport of a channel already decided
1304
+ * open or tuned out changes no decision, and gives none. When the
1305
+ * registration is gone, the failure says the channel was removed.
940
1306
  *
941
1307
  * Only the connector's `delivered: true` confirms a post. `failed` means
942
1308
  * nothing was posted: the attempt stopped before the request was written,
@@ -960,9 +1326,13 @@ export declare class ChannelRegistry {
960
1326
  * Plain speech for one turn segment: publish `text` to the turn's frozen
961
1327
  * locus and report the PublishOutcome. A failure (or an uncertain outcome)
962
1328
  * is surfaced as a trace and through onRouteFailure, so the agent learns
963
- * its words did not (or may not have) reached anyone. An ephemeral run's
964
- * speech with no locus is the exception: it is its caller's result, so it
965
- * returns as not delivered and surfaces nothing.
1329
+ * its words did not (or may not have) reached anyone. A `failed` one whose
1330
+ * caller holds its words with a notice of its own (`heldOnFailure`) gets
1331
+ * the trace but not onRouteFailure. An ephemeral run's speech with no locus
1332
+ * (null) is its caller's result: it returns as not delivered and surfaces
1333
+ * nothing. This is host-owned output routing (see forking-knowledge-miner
1334
+ * LOCUS-ROUTING-DESIGN), which replaced the per-surface sticky auto-post
1335
+ * that used to live in discord-mcpl.
966
1336
  */
967
1337
  deliverSpeech(conversationId: string, text: string,
968
1338
  /** The turn's FROZEN locus, snapshotted once by the caller (resolveLocus
@@ -977,25 +1347,23 @@ export declare class ChannelRegistry {
977
1347
  locusChannelId: string | null,
978
1348
  /** `heldOnFailure`: the caller holds a `failed` delivery's words as a
979
1349
  * draft with its own notice, so no failure marker is written for it.
980
- * An `unknown` outcome still gets its marker. `locusServerId`: the
981
- * server the locus resolves with, snapshotted by the caller with the
982
- * locus: the server whose message triggered the turn, where the locus is
983
- * that message's channel. The speech goes out through that server only,
984
- * and fails where it no longer registers the channel. Without it, the
985
- * locus is taken only where exactly one server registers it. */
1350
+ * An `unknown` outcome still gets its marker. */
986
1351
  opts?: {
987
1352
  heldOnFailure?: boolean;
988
- locusServerId?: string;
989
1353
  }): Promise<PublishOutcome>;
990
- /** deliverSpeech, reduced to the confirmed delivery (null when there was
991
- * none). `opts.locusServerId` is deliverSpeech's. */
992
- routeSpeech(conversationId: string, text: string, locusChannelId: string | null, opts?: {
993
- locusServerId?: string;
994
- }): Promise<{
1354
+ /** deliverSpeech, reduced to the confirmed delivery (null when there was none). */
1355
+ routeSpeech(conversationId: string, text: string, locusChannelId: string | null): Promise<{
995
1356
  delivered: boolean;
1357
+ serverId: string;
996
1358
  channelId: string;
997
1359
  messageId?: string;
998
1360
  } | null>;
1361
+ /**
1362
+ * channel_publish, and the subconscious's speak_in_channel
1363
+ * (publishForAgent), which shares its delivery. Where an agent finds a
1364
+ * channel id differs: the subconscious isn't offered channel_list, and is
1365
+ * given speak_in_channel for the tuned-out channels whose messages it reads.
1366
+ */
999
1367
  private handleToolPublish;
1000
1368
  }
1001
1369
  export {};