@animalabs/agent-framework 0.23.1 → 0.24.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 (338) hide show
  1. package/README.md +212 -42
  2. package/dist/src/agent.d.ts +60 -9
  3. package/dist/src/agent.d.ts.map +1 -1
  4. package/dist/src/agent.js +92 -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/code-execution/engine.d.ts +177 -0
  10. package/dist/src/code-execution/engine.d.ts.map +1 -0
  11. package/dist/src/code-execution/engine.js +494 -0
  12. package/dist/src/code-execution/engine.js.map +1 -0
  13. package/dist/src/code-execution/index.d.ts +5 -10
  14. package/dist/src/code-execution/index.d.ts.map +1 -1
  15. package/dist/src/code-execution/index.js +5 -9
  16. package/dist/src/code-execution/index.js.map +1 -1
  17. package/dist/src/code-execution/isolate/calls.d.ts +114 -0
  18. package/dist/src/code-execution/isolate/calls.d.ts.map +1 -0
  19. package/dist/src/code-execution/isolate/calls.js +145 -0
  20. package/dist/src/code-execution/isolate/calls.js.map +1 -0
  21. package/dist/src/code-execution/isolate/child-entry.d.ts +2 -0
  22. package/dist/src/code-execution/isolate/child-entry.d.ts.map +1 -0
  23. package/dist/src/code-execution/isolate/child-entry.js +5 -0
  24. package/dist/src/code-execution/isolate/child-entry.js.map +1 -0
  25. package/dist/src/code-execution/isolate/child-main.d.ts +26 -0
  26. package/dist/src/code-execution/isolate/child-main.d.ts.map +1 -0
  27. package/dist/src/code-execution/isolate/child-main.js +132 -0
  28. package/dist/src/code-execution/isolate/child-main.js.map +1 -0
  29. package/dist/src/code-execution/isolate/child.d.ts +44 -0
  30. package/dist/src/code-execution/isolate/child.d.ts.map +1 -0
  31. package/dist/src/code-execution/isolate/child.js +315 -0
  32. package/dist/src/code-execution/isolate/child.js.map +1 -0
  33. package/dist/src/code-execution/isolate/frames.d.ts +80 -0
  34. package/dist/src/code-execution/isolate/frames.d.ts.map +1 -0
  35. package/dist/src/code-execution/isolate/frames.js +210 -0
  36. package/dist/src/code-execution/isolate/frames.js.map +1 -0
  37. package/dist/src/code-execution/isolate/output.d.ts +68 -0
  38. package/dist/src/code-execution/isolate/output.d.ts.map +1 -0
  39. package/dist/src/code-execution/isolate/output.js +143 -0
  40. package/dist/src/code-execution/isolate/output.js.map +1 -0
  41. package/dist/src/code-execution/isolate/prelude.d.ts +109 -0
  42. package/dist/src/code-execution/isolate/prelude.d.ts.map +1 -0
  43. package/dist/src/code-execution/isolate/prelude.js +401 -0
  44. package/dist/src/code-execution/isolate/prelude.js.map +1 -0
  45. package/dist/src/code-execution/isolate/protocol.d.ts +151 -0
  46. package/dist/src/code-execution/isolate/protocol.d.ts.map +1 -0
  47. package/dist/src/code-execution/isolate/protocol.js +150 -0
  48. package/dist/src/code-execution/isolate/protocol.js.map +1 -0
  49. package/dist/src/code-execution/isolate/render.d.ts +57 -0
  50. package/dist/src/code-execution/isolate/render.d.ts.map +1 -0
  51. package/dist/src/code-execution/isolate/render.js +214 -0
  52. package/dist/src/code-execution/isolate/render.js.map +1 -0
  53. package/dist/src/code-execution/isolate/runner.d.ts +250 -0
  54. package/dist/src/code-execution/isolate/runner.d.ts.map +1 -0
  55. package/dist/src/code-execution/isolate/runner.js +854 -0
  56. package/dist/src/code-execution/isolate/runner.js.map +1 -0
  57. package/dist/src/code-execution/isolate/scripts.d.ts +175 -0
  58. package/dist/src/code-execution/isolate/scripts.d.ts.map +1 -0
  59. package/dist/src/code-execution/isolate/scripts.js +357 -0
  60. package/dist/src/code-execution/isolate/scripts.js.map +1 -0
  61. package/dist/src/code-execution/quickjs.wasm +0 -0
  62. package/dist/src/code-execution/tool-definition.d.ts +93 -43
  63. package/dist/src/code-execution/tool-definition.d.ts.map +1 -1
  64. package/dist/src/code-execution/tool-definition.js +176 -142
  65. package/dist/src/code-execution/tool-definition.js.map +1 -1
  66. package/dist/src/deadline-timer.d.ts +3 -0
  67. package/dist/src/deadline-timer.d.ts.map +1 -1
  68. package/dist/src/deadline-timer.js +1 -1
  69. package/dist/src/deadline-timer.js.map +1 -1
  70. package/dist/src/framework.d.ts +1036 -440
  71. package/dist/src/framework.d.ts.map +1 -1
  72. package/dist/src/framework.js +4131 -2228
  73. package/dist/src/framework.js.map +1 -1
  74. package/dist/src/gate/event-gate.d.ts +28 -1
  75. package/dist/src/gate/event-gate.d.ts.map +1 -1
  76. package/dist/src/gate/event-gate.js +88 -10
  77. package/dist/src/gate/event-gate.js.map +1 -1
  78. package/dist/src/held-writes.d.ts +16 -3
  79. package/dist/src/held-writes.d.ts.map +1 -1
  80. package/dist/src/held-writes.js +16 -3
  81. package/dist/src/held-writes.js.map +1 -1
  82. package/dist/src/index.d.ts +6 -6
  83. package/dist/src/index.d.ts.map +1 -1
  84. package/dist/src/index.js +9 -8
  85. package/dist/src/index.js.map +1 -1
  86. package/dist/src/mcpl/channel-registry.d.ts +471 -75
  87. package/dist/src/mcpl/channel-registry.d.ts.map +1 -1
  88. package/dist/src/mcpl/channel-registry.js +1673 -337
  89. package/dist/src/mcpl/channel-registry.js.map +1 -1
  90. package/dist/src/mcpl/conversation-router.d.ts +12 -7
  91. package/dist/src/mcpl/conversation-router.d.ts.map +1 -1
  92. package/dist/src/mcpl/conversation-router.js +12 -7
  93. package/dist/src/mcpl/conversation-router.js.map +1 -1
  94. package/dist/src/mcpl/convert-block.d.ts.map +1 -1
  95. package/dist/src/mcpl/convert-block.js +9 -5
  96. package/dist/src/mcpl/convert-block.js.map +1 -1
  97. package/dist/src/mcpl/inbound-source.d.ts +50 -0
  98. package/dist/src/mcpl/inbound-source.d.ts.map +1 -1
  99. package/dist/src/mcpl/inbound-source.js +130 -0
  100. package/dist/src/mcpl/inbound-source.js.map +1 -1
  101. package/dist/src/mcpl/index.d.ts +2 -1
  102. package/dist/src/mcpl/index.d.ts.map +1 -1
  103. package/dist/src/mcpl/index.js +3 -2
  104. package/dist/src/mcpl/index.js.map +1 -1
  105. package/dist/src/mcpl/log-value.d.ts +6 -0
  106. package/dist/src/mcpl/log-value.d.ts.map +1 -1
  107. package/dist/src/mcpl/log-value.js +8 -0
  108. package/dist/src/mcpl/log-value.js.map +1 -1
  109. package/dist/src/mcpl/modern-connection.d.ts +15 -6
  110. package/dist/src/mcpl/modern-connection.d.ts.map +1 -1
  111. package/dist/src/mcpl/modern-connection.js +168 -53
  112. package/dist/src/mcpl/modern-connection.js.map +1 -1
  113. package/dist/src/mcpl/prose-grammar.d.ts +4 -5
  114. package/dist/src/mcpl/prose-grammar.d.ts.map +1 -1
  115. package/dist/src/mcpl/prose-grammar.js +4 -5
  116. package/dist/src/mcpl/prose-grammar.js.map +1 -1
  117. package/dist/src/mcpl/protocol-family.d.ts +97 -10
  118. package/dist/src/mcpl/protocol-family.d.ts.map +1 -1
  119. package/dist/src/mcpl/protocol-family.js +173 -16
  120. package/dist/src/mcpl/protocol-family.js.map +1 -1
  121. package/dist/src/mcpl/push-coalescer.d.ts +132 -14
  122. package/dist/src/mcpl/push-coalescer.d.ts.map +1 -1
  123. package/dist/src/mcpl/push-coalescer.js +227 -50
  124. package/dist/src/mcpl/push-coalescer.js.map +1 -1
  125. package/dist/src/mcpl/push-handler.d.ts +6 -1
  126. package/dist/src/mcpl/push-handler.d.ts.map +1 -1
  127. package/dist/src/mcpl/push-handler.js +4 -1
  128. package/dist/src/mcpl/push-handler.js.map +1 -1
  129. package/dist/src/mcpl/reference-fetcher.d.ts +2 -2
  130. package/dist/src/mcpl/reference-fetcher.d.ts.map +1 -1
  131. package/dist/src/mcpl/reference-fetcher.js +4 -4
  132. package/dist/src/mcpl/reference-fetcher.js.map +1 -1
  133. package/dist/src/mcpl/server-connection.d.ts +50 -21
  134. package/dist/src/mcpl/server-connection.d.ts.map +1 -1
  135. package/dist/src/mcpl/server-connection.js +158 -74
  136. package/dist/src/mcpl/server-connection.js.map +1 -1
  137. package/dist/src/mcpl/tags.d.ts +24 -0
  138. package/dist/src/mcpl/tags.d.ts.map +1 -1
  139. package/dist/src/mcpl/tags.js +33 -0
  140. package/dist/src/mcpl/tags.js.map +1 -1
  141. package/dist/src/mcpl/tool-result-normalize.d.ts +2 -1
  142. package/dist/src/mcpl/tool-result-normalize.d.ts.map +1 -1
  143. package/dist/src/mcpl/tool-result-normalize.js.map +1 -1
  144. package/dist/src/mcpl/transport.d.ts +55 -7
  145. package/dist/src/mcpl/transport.d.ts.map +1 -1
  146. package/dist/src/mcpl/transport.js +163 -34
  147. package/dist/src/mcpl/transport.js.map +1 -1
  148. package/dist/src/mcpl/types.d.ts +22 -6
  149. package/dist/src/mcpl/types.d.ts.map +1 -1
  150. package/dist/src/mcpl/types.js.map +1 -1
  151. package/dist/src/module-registry.d.ts +4 -2
  152. package/dist/src/module-registry.d.ts.map +1 -1
  153. package/dist/src/module-registry.js +100 -13
  154. package/dist/src/module-registry.js.map +1 -1
  155. package/dist/src/modules/discord/index.d.ts.map +1 -1
  156. package/dist/src/modules/discord/index.js +8 -13
  157. package/dist/src/modules/discord/index.js.map +1 -1
  158. package/dist/src/modules/history/index.d.ts.map +1 -1
  159. package/dist/src/modules/history/index.js +27 -4
  160. package/dist/src/modules/history/index.js.map +1 -1
  161. package/dist/src/modules/history/semantic.d.ts +15 -3
  162. package/dist/src/modules/history/semantic.d.ts.map +1 -1
  163. package/dist/src/modules/history/semantic.js +27 -5
  164. package/dist/src/modules/history/semantic.js.map +1 -1
  165. package/dist/src/modules/index.d.ts +1 -1
  166. package/dist/src/modules/index.d.ts.map +1 -1
  167. package/dist/src/modules/index.js.map +1 -1
  168. package/dist/src/modules/unknown-tool.d.ts +4 -1
  169. package/dist/src/modules/unknown-tool.d.ts.map +1 -1
  170. package/dist/src/modules/unknown-tool.js +4 -1
  171. package/dist/src/modules/unknown-tool.js.map +1 -1
  172. package/dist/src/modules/workspace/branch-intent.d.ts +3 -1
  173. package/dist/src/modules/workspace/branch-intent.d.ts.map +1 -1
  174. package/dist/src/modules/workspace/branch-intent.js +3 -1
  175. package/dist/src/modules/workspace/branch-intent.js.map +1 -1
  176. package/dist/src/modules/workspace/edit-plan.d.ts +265 -0
  177. package/dist/src/modules/workspace/edit-plan.d.ts.map +1 -0
  178. package/dist/src/modules/workspace/edit-plan.js +794 -0
  179. package/dist/src/modules/workspace/edit-plan.js.map +1 -0
  180. package/dist/src/modules/workspace/edit-text.d.ts +117 -0
  181. package/dist/src/modules/workspace/edit-text.d.ts.map +1 -0
  182. package/dist/src/modules/workspace/edit-text.js +584 -0
  183. package/dist/src/modules/workspace/edit-text.js.map +1 -0
  184. package/dist/src/modules/workspace/effects.d.ts +5 -4
  185. package/dist/src/modules/workspace/effects.d.ts.map +1 -1
  186. package/dist/src/modules/workspace/effects.js +78 -25
  187. package/dist/src/modules/workspace/effects.js.map +1 -1
  188. package/dist/src/modules/workspace/index.d.ts +484 -61
  189. package/dist/src/modules/workspace/index.d.ts.map +1 -1
  190. package/dist/src/modules/workspace/index.js +2173 -645
  191. package/dist/src/modules/workspace/index.js.map +1 -1
  192. package/dist/src/modules/workspace/observe.d.ts +213 -38
  193. package/dist/src/modules/workspace/observe.d.ts.map +1 -1
  194. package/dist/src/modules/workspace/observe.js +416 -36
  195. package/dist/src/modules/workspace/observe.js.map +1 -1
  196. package/dist/src/modules/workspace/reconcile.d.ts.map +1 -1
  197. package/dist/src/modules/workspace/reconcile.js +15 -8
  198. package/dist/src/modules/workspace/reconcile.js.map +1 -1
  199. package/dist/src/modules/workspace/text.d.ts +32 -0
  200. package/dist/src/modules/workspace/text.d.ts.map +1 -0
  201. package/dist/src/modules/workspace/text.js +67 -0
  202. package/dist/src/modules/workspace/text.js.map +1 -0
  203. package/dist/src/modules/workspace/types.d.ts +210 -6
  204. package/dist/src/modules/workspace/types.d.ts.map +1 -1
  205. package/dist/src/modules/workspace/types.js.map +1 -1
  206. package/dist/src/modules/workspace/watcher.d.ts +3 -2
  207. package/dist/src/modules/workspace/watcher.d.ts.map +1 -1
  208. package/dist/src/modules/workspace/watcher.js.map +1 -1
  209. package/dist/src/operator-log.d.ts +52 -24
  210. package/dist/src/operator-log.d.ts.map +1 -1
  211. package/dist/src/operator-log.js.map +1 -1
  212. package/dist/src/recovery/discord-awareness-outbox.d.ts +496 -72
  213. package/dist/src/recovery/discord-awareness-outbox.d.ts.map +1 -1
  214. package/dist/src/recovery/discord-awareness-outbox.js +1196 -289
  215. package/dist/src/recovery/discord-awareness-outbox.js.map +1 -1
  216. package/dist/src/recovery/offline-branch.d.ts +26 -1
  217. package/dist/src/recovery/offline-branch.d.ts.map +1 -1
  218. package/dist/src/recovery/offline-branch.js +164 -39
  219. package/dist/src/recovery/offline-branch.js.map +1 -1
  220. package/dist/src/recovery/recover-cli.js +23 -4
  221. package/dist/src/recovery/recover-cli.js.map +1 -1
  222. package/dist/src/send-tools.d.ts +11 -0
  223. package/dist/src/send-tools.d.ts.map +1 -0
  224. package/dist/src/send-tools.js +11 -0
  225. package/dist/src/send-tools.js.map +1 -0
  226. package/dist/src/tool-result-guard.d.ts +4 -3
  227. package/dist/src/tool-result-guard.d.ts.map +1 -1
  228. package/dist/src/tool-result-guard.js +5 -4
  229. package/dist/src/tool-result-guard.js.map +1 -1
  230. package/dist/src/tool-result-history.d.ts +1 -1
  231. package/dist/src/tool-result-history.js +1 -1
  232. package/dist/src/tune-out/coordinator.d.ts +21 -0
  233. package/dist/src/tune-out/coordinator.d.ts.map +1 -1
  234. package/dist/src/tune-out/coordinator.js +139 -37
  235. package/dist/src/tune-out/coordinator.js.map +1 -1
  236. package/dist/src/types/agent.d.ts +4 -0
  237. package/dist/src/types/agent.d.ts.map +1 -1
  238. package/dist/src/types/events.d.ts +62 -9
  239. package/dist/src/types/events.d.ts.map +1 -1
  240. package/dist/src/types/framework.d.ts +62 -58
  241. package/dist/src/types/framework.d.ts.map +1 -1
  242. package/dist/src/types/module.d.ts +40 -8
  243. package/dist/src/types/module.d.ts.map +1 -1
  244. package/dist/src/types/trace.d.ts +111 -10
  245. package/dist/src/types/trace.d.ts.map +1 -1
  246. package/dist/src/usage/types.d.ts +16 -0
  247. package/dist/src/usage/types.d.ts.map +1 -1
  248. package/dist/src/usage/usage-tracker.d.ts +14 -1
  249. package/dist/src/usage/usage-tracker.d.ts.map +1 -1
  250. package/dist/src/usage/usage-tracker.js +81 -41
  251. package/dist/src/usage/usage-tracker.js.map +1 -1
  252. package/package.json +6 -5
  253. package/src/agent.ts +93 -12
  254. package/src/api/server.ts +14 -12
  255. package/src/code-execution/engine.ts +595 -0
  256. package/src/code-execution/index.ts +5 -17
  257. package/src/code-execution/isolate/calls.ts +199 -0
  258. package/src/code-execution/isolate/child-entry.ts +5 -0
  259. package/src/code-execution/isolate/child-main.ts +132 -0
  260. package/src/code-execution/isolate/child.ts +327 -0
  261. package/src/code-execution/isolate/frames.ts +209 -0
  262. package/src/code-execution/isolate/output.ts +161 -0
  263. package/src/code-execution/isolate/prelude.ts +409 -0
  264. package/src/code-execution/isolate/protocol.ts +240 -0
  265. package/src/code-execution/isolate/render.ts +230 -0
  266. package/src/code-execution/isolate/runner.ts +911 -0
  267. package/src/code-execution/isolate/scripts.ts +479 -0
  268. package/src/code-execution/quickjs.wasm +0 -0
  269. package/src/code-execution/quickjs.wasm.LICENSES +149 -0
  270. package/src/code-execution/tool-definition.ts +236 -167
  271. package/src/deadline-timer.ts +1 -1
  272. package/src/framework.ts +4507 -2406
  273. package/src/gate/event-gate.ts +78 -11
  274. package/src/held-writes.ts +17 -3
  275. package/src/index.ts +30 -22
  276. package/src/mcpl/channel-registry.ts +1825 -368
  277. package/src/mcpl/conversation-router.ts +12 -7
  278. package/src/mcpl/convert-block.ts +9 -5
  279. package/src/mcpl/inbound-source.ts +131 -0
  280. package/src/mcpl/index.ts +4 -2
  281. package/src/mcpl/log-value.ts +9 -0
  282. package/src/mcpl/modern-connection.ts +162 -53
  283. package/src/mcpl/prose-grammar.ts +4 -5
  284. package/src/mcpl/protocol-family.ts +199 -21
  285. package/src/mcpl/push-coalescer.ts +306 -62
  286. package/src/mcpl/push-handler.ts +10 -2
  287. package/src/mcpl/reference-fetcher.ts +4 -4
  288. package/src/mcpl/server-connection.ts +180 -79
  289. package/src/mcpl/tags.ts +36 -0
  290. package/src/mcpl/tool-result-normalize.ts +2 -1
  291. package/src/mcpl/transport.ts +162 -33
  292. package/src/mcpl/types.ts +23 -6
  293. package/src/module-registry.ts +92 -13
  294. package/src/modules/discord/index.ts +8 -13
  295. package/src/modules/history/index.ts +25 -3
  296. package/src/modules/history/semantic.ts +29 -6
  297. package/src/modules/index.ts +1 -0
  298. package/src/modules/unknown-tool.ts +4 -1
  299. package/src/modules/workspace/branch-intent.ts +3 -1
  300. package/src/modules/workspace/edit-plan.ts +954 -0
  301. package/src/modules/workspace/edit-text.ts +618 -0
  302. package/src/modules/workspace/effects.ts +70 -19
  303. package/src/modules/workspace/index.ts +2247 -642
  304. package/src/modules/workspace/observe.ts +465 -56
  305. package/src/modules/workspace/reconcile.ts +14 -7
  306. package/src/modules/workspace/text.ts +68 -0
  307. package/src/modules/workspace/types.ts +211 -6
  308. package/src/modules/workspace/watcher.ts +3 -2
  309. package/src/operator-log.ts +47 -19
  310. package/src/recovery/discord-awareness-outbox.ts +1500 -356
  311. package/src/recovery/offline-branch.ts +189 -55
  312. package/src/recovery/recover-cli.ts +25 -4
  313. package/src/send-tools.ts +11 -0
  314. package/src/tool-result-guard.ts +6 -5
  315. package/src/tool-result-history.ts +1 -1
  316. package/src/tune-out/coordinator.ts +163 -42
  317. package/src/types/agent.ts +4 -0
  318. package/src/types/events.ts +62 -9
  319. package/src/types/framework.ts +62 -58
  320. package/src/types/module.ts +40 -8
  321. package/src/types/trace.ts +121 -15
  322. package/src/usage/types.ts +16 -0
  323. package/src/usage/usage-tracker.ts +86 -43
  324. package/dist/src/code-execution/py-runner.d.ts +0 -191
  325. package/dist/src/code-execution/py-runner.d.ts.map +0 -1
  326. package/dist/src/code-execution/py-runner.js +0 -655
  327. package/dist/src/code-execution/py-runner.js.map +0 -1
  328. package/dist/src/code-execution/runtime-py.d.ts +0 -50
  329. package/dist/src/code-execution/runtime-py.d.ts.map +0 -1
  330. package/dist/src/code-execution/runtime-py.js +0 -677
  331. package/dist/src/code-execution/runtime-py.js.map +0 -1
  332. package/dist/src/mcpl/prose-stream-router.d.ts +0 -88
  333. package/dist/src/mcpl/prose-stream-router.d.ts.map +0 -1
  334. package/dist/src/mcpl/prose-stream-router.js +0 -291
  335. package/dist/src/mcpl/prose-stream-router.js.map +0 -1
  336. package/src/code-execution/py-runner.ts +0 -791
  337. package/src/code-execution/runtime-py.ts +0 -677
  338. package/src/mcpl/prose-stream-router.ts +0 -268
@@ -1,268 +0,0 @@
1
- /**
2
- * Incremental prose router: turns a stream of text deltas into a stream of
3
- * (channelId, delta) pairs AS THE MODEL GENERATES, so downstream surfaces
4
- * (voice synthesis, streamed message rendering, future platforms) can act on
5
- * speech before the turn completes. This is the emission half of MCPL Spec
6
- * 14.3 (`channels/outgoing/chunk`) — the notification has existed in the
7
- * wire types since the spec landed; this class is what finally produces it.
8
- *
9
- * Correctness contract: routing decisions here MUST agree with the delivery
10
- * path (deliverProse/parseProsePrefix). Both use prose-grammar.ts; this
11
- * router additionally holds back exactly as much text as needed to make each
12
- * line's decision — the start of a line is buffered only until it either
13
- * cannot be a `>>` prefix (flush as body) or its prefix token (+ optional
14
- * ` !` modifier) completes (switch target, swallow the prefix). Body text
15
- * after the decision point streams through with zero added latency.
16
- *
17
- * Suppression is fail-closed: text whose destination is unknown (explicit
18
- * mode before the first `>>`, unresolvable/ambiguous targets, `>>skip_reply`)
19
- * emits NOTHING — the delivery path will bounce/retain it; a stream consumer
20
- * must never see text that delivery would refuse to send.
21
- *
22
- * Three modes, mirroring proseRouting:
23
- * - explicit: parse `>>` prefixes. A fresh turn's stream starts suppressed;
24
- * a later stream of the turn starts at the turn's destination,
25
- * and each round's end returns the stream to it (retarget).
26
- * - hybrid: parse `>>>` envelopes, with the turn's locus as the
27
- * fallback. An envelope with no target, or `>>>skip_reply`,
28
- * holds back what follows until a later `>>>` names a target.
29
- * - locus: NO prefix parsing (locus mode's `>>` lines are plain text);
30
- * everything streams to the turn's locus.
31
- */
32
-
33
- export interface RoutedDelta {
34
- channelId: string;
35
- delta: string;
36
- }
37
-
38
- type State = 'line-start' | 'indent' | 'maybe-prefix' | 'prefix-gap' | 'prefix-token' | 'after-token' | 'body';
39
-
40
- /** Whitespace as the delivery path reads it (`trimStart()`, `\s`, `\S`). */
41
- const isSpace = (ch: string): boolean => /\s/.test(ch);
42
-
43
- export class ProseStreamRouter {
44
- private target: string | null;
45
- private state: State = 'line-start';
46
- private held = ''; // text held while a line's decision is pending
47
- private token = ''; // the >>spec token being accumulated
48
- private sawBang = false;
49
- private accumulated = new Map<string, string>();
50
-
51
- constructor(
52
- private opts: {
53
- /** explicit parses `>>`; hybrid parses `>>>` while retaining locus fallback. */
54
- mode: 'explicit' | 'hybrid' | 'locus';
55
- /** Initial destination: the turn's locus (locus and hybrid mode); in
56
- * explicit mode, null on a fresh turn, or the turn's destination on a
57
- * later stream of the turn. */
58
- initialTarget: string | null;
59
- /** Resolve a `>>spec` to a channelId, or null (unresolved/ambiguous). */
60
- resolve: (spec: string) => string | null;
61
- },
62
- ) {
63
- this.target = opts.initialTarget;
64
- if (opts.mode === 'locus') this.state = 'body';
65
- }
66
-
67
- /** Per-channel full text emitted so far (for outgoing/complete). */
68
- byChannel(): ReadonlyMap<string, string> {
69
- return this.accumulated;
70
- }
71
-
72
- /**
73
- * Point the stream at a destination decided outside it. Explicit mode does
74
- * this at each round's end, with the turn's destination: a private round's
75
- * prefixes, a `>>skip_reply` envelope and a target that didn't resolve all
76
- * leave that destination as it was, though the stream followed them while
77
- * the round was written.
78
- */
79
- retarget(target: string | null): void {
80
- this.target = target;
81
- }
82
-
83
- /**
84
- * Drop everything routed so far and return to the constructed state.
85
- *
86
- * For a membrane refusal retry (RetryingEvent): the abandoned attempt's
87
- * prose must not survive into the new one, and `accumulated` feeds
88
- * outgoing/complete — leaving it would finalize text the model never
89
- * actually said in the attempt that stands.
90
- */
91
- reset(): void {
92
- this.target = this.opts.initialTarget;
93
- this.state = this.opts.mode === 'locus' ? 'body' : 'line-start';
94
- this.held = '';
95
- this.token = '';
96
- this.sawBang = false;
97
- this.accumulated = new Map();
98
- }
99
-
100
- feed(delta: string): RoutedDelta[] {
101
- const out: RoutedDelta[] = [];
102
- for (const ch of delta) this.step(ch, out);
103
- return coalesce(out);
104
- }
105
-
106
- /**
107
- * The end of a segment: one round's text, which delivery parses on its
108
- * own. The pending line's decision is made now. Held line-start text can
109
- * no longer become a prefix, so it is body. A prefix whose target is
110
- * written but has no body takes effect, as delivery reads `>>#chan` with
111
- * nothing after it. The next segment starts a new line.
112
- */
113
- endSegment(): RoutedDelta[] {
114
- const out: RoutedDelta[] = [];
115
- if (this.state === 'indent') this.emit(this.held, out);
116
- if (this.state === 'maybe-prefix') {
117
- // Hybrid's `>>>` with nothing after it is an envelope with no target:
118
- // delivery bounces it and holds back what follows. Anything else held
119
- // is text to delivery, explicit's bare `>>` included.
120
- const arrows = this.held.trimStart();
121
- if (this.opts.mode === 'hybrid' && arrows === '>>>') this.target = null;
122
- else this.emit(this.held, out);
123
- }
124
- // Hybrid's `>>>` and a gap with nothing after it: no target either.
125
- if (this.state === 'prefix-gap') this.target = null;
126
- if (this.state === 'prefix-token') this.applyTarget();
127
- this.held = '';
128
- this.token = '';
129
- if (this.opts.mode !== 'locus') this.state = 'line-start';
130
- return coalesce(out);
131
- }
132
-
133
- /** End of stream: the last segment ends. */
134
- finish(): RoutedDelta[] {
135
- return this.endSegment();
136
- }
137
-
138
- private step(ch: string, out: RoutedDelta[]): void {
139
- switch (this.state) {
140
- case 'body':
141
- if (ch === '\n' && this.opts.mode !== 'locus') {
142
- this.emit('\n', out);
143
- this.state = 'line-start';
144
- } else {
145
- this.emit(ch, out);
146
- }
147
- return;
148
-
149
- case 'line-start':
150
- // Indentation before a prefix is held until the line's decision: the
151
- // delivery path reads an indented `>>` (explicit) or `>>>` (hybrid)
152
- // line as a prefix too, after any leading whitespace.
153
- if (ch !== '\n' && isSpace(ch)) {
154
- this.state = 'indent';
155
- this.held = ch;
156
- return;
157
- }
158
- if (ch === '>') { this.state = 'maybe-prefix'; this.held = '>'; return; }
159
- this.state = 'body';
160
- this.step(ch, out);
161
- return;
162
-
163
- case 'indent':
164
- if (ch !== '\n' && isSpace(ch)) { this.held += ch; return; }
165
- if (ch === '>') { this.held += ch; this.state = 'maybe-prefix'; return; }
166
- this.emit(this.held, out);
167
- this.held = '';
168
- this.state = 'body';
169
- this.step(ch, out);
170
- return;
171
-
172
- case 'maybe-prefix': {
173
- const prefix = this.opts.mode === 'hybrid' ? '>>>' : '>>';
174
- const arrows = this.held.trimStart();
175
- if (ch === '>' && arrows.length < prefix.length) {
176
- this.held += '>';
177
- return;
178
- }
179
- if (arrows === prefix) {
180
- if (this.opts.mode === 'hybrid' && (ch === ' ' || ch === '\t')) {
181
- this.held = '';
182
- this.state = 'prefix-gap';
183
- return;
184
- }
185
- if (isSpace(ch)) {
186
- if (this.opts.mode === 'explicit') {
187
- // `>>` and then whitespace is a quoted arrow: body text, since
188
- // delivery's prefix needs a target right after the arrows.
189
- this.emit(this.held, out);
190
- } else {
191
- // `>>>` and then whitespace other than a space or tab (a
192
- // newline included) is an envelope with no target. Delivery
193
- // bounces it and holds back what follows until a later `>>>`
194
- // names a target.
195
- this.target = null;
196
- }
197
- // The whitespace itself is body, a newline included.
198
- this.held = '';
199
- this.state = 'body';
200
- this.step(ch, out);
201
- return;
202
- }
203
- this.state = 'prefix-token';
204
- this.token = ch;
205
- this.held = '';
206
- return;
207
- }
208
- this.emit(this.held, out);
209
- this.held = '';
210
- this.state = 'body';
211
- this.step(ch, out);
212
- return;
213
- }
214
-
215
- case 'prefix-gap':
216
- if (ch === ' ' || ch === '\t') return;
217
- if (ch === '\n') { this.target = null; this.state = 'line-start'; return; }
218
- // Other whitespace can't start hybrid's target (`[ \t]*\S+`): an
219
- // envelope with no target, as above.
220
- if (isSpace(ch)) { this.target = null; this.state = 'body'; return; }
221
- this.state = 'prefix-token';
222
- this.token = ch;
223
- return;
224
-
225
- case 'prefix-token':
226
- if (ch === ' ' || ch === '\t') { this.applyTarget(); this.state = 'after-token'; this.sawBang = false; return; }
227
- if (ch === '\n') { this.applyTarget(); this.state = 'line-start'; return; }
228
- // Any other whitespace ends the token too (`\S+`), and starts the
229
- // body: the grammar's gap after a token is spaces and tabs only.
230
- if (isSpace(ch)) { this.applyTarget(); this.state = 'body'; this.step(ch, out); return; }
231
- this.token += ch;
232
- return;
233
-
234
- case 'after-token':
235
- // Grammar: `([ \t]+!)?[ \t]*` — one optional `!` immediately after the
236
- // first whitespace run is the continue-turn modifier, not body.
237
- if (ch === ' ' || ch === '\t') return;
238
- if (ch === '\n') { this.state = 'line-start'; return; }
239
- if (ch === '!' && !this.sawBang) { this.sawBang = true; return; }
240
- this.state = 'body';
241
- this.step(ch, out);
242
- return;
243
- }
244
- }
245
-
246
- private applyTarget(): void {
247
- const spec = this.token;
248
- this.token = '';
249
- if (spec === 'skip_reply') { this.target = null; return; }
250
- this.target = this.opts.resolve(spec);
251
- }
252
-
253
- private emit(text: string, out: RoutedDelta[]): void {
254
- if (this.target === null || !text) return;
255
- out.push({ channelId: this.target, delta: text });
256
- this.accumulated.set(this.target, (this.accumulated.get(this.target) ?? '') + text);
257
- }
258
- }
259
-
260
- function coalesce(deltas: RoutedDelta[]): RoutedDelta[] {
261
- const out: RoutedDelta[] = [];
262
- for (const d of deltas) {
263
- const last = out[out.length - 1];
264
- if (last && last.channelId === d.channelId) last.delta += d.delta;
265
- else out.push({ ...d });
266
- }
267
- return out;
268
- }