@animalabs/agent-framework 0.22.1 → 0.22.3

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 (946) hide show
  1. package/README.md +4 -2
  2. package/dist/src/agent.d.ts +266 -28
  3. package/dist/src/agent.d.ts.map +1 -1
  4. package/dist/src/agent.js +539 -104
  5. package/dist/src/agent.js.map +1 -1
  6. package/dist/src/api/mcp-server-core.d.ts +41 -0
  7. package/dist/src/api/mcp-server-core.d.ts.map +1 -0
  8. package/dist/src/api/mcp-server-core.js +593 -0
  9. package/dist/src/api/mcp-server-core.js.map +1 -0
  10. package/dist/src/api/mcp-server.d.ts +2 -36
  11. package/dist/src/api/mcp-server.d.ts.map +1 -1
  12. package/dist/src/api/mcp-server.js +15 -595
  13. package/dist/src/api/mcp-server.js.map +1 -1
  14. package/dist/src/api/server.d.ts +9 -1
  15. package/dist/src/api/server.d.ts.map +1 -1
  16. package/dist/src/api/server.js +55 -27
  17. package/dist/src/api/server.js.map +1 -1
  18. package/dist/src/api/types.d.ts +10 -2
  19. package/dist/src/api/types.d.ts.map +1 -1
  20. package/dist/src/branch-names.d.ts +14 -0
  21. package/dist/src/branch-names.d.ts.map +1 -0
  22. package/dist/src/branch-names.js +22 -0
  23. package/dist/src/branch-names.js.map +1 -0
  24. package/dist/src/closest-names.d.ts +28 -0
  25. package/dist/src/closest-names.d.ts.map +1 -0
  26. package/dist/src/closest-names.js +98 -0
  27. package/dist/src/closest-names.js.map +1 -0
  28. package/dist/src/code-execution/py-runner.d.ts +16 -5
  29. package/dist/src/code-execution/py-runner.d.ts.map +1 -1
  30. package/dist/src/code-execution/py-runner.js +186 -74
  31. package/dist/src/code-execution/py-runner.js.map +1 -1
  32. package/dist/src/code-execution/runtime-py.d.ts.map +1 -1
  33. package/dist/src/code-execution/runtime-py.js +49 -3
  34. package/dist/src/code-execution/runtime-py.js.map +1 -1
  35. package/dist/src/code-execution/tool-definition.d.ts +12 -1
  36. package/dist/src/code-execution/tool-definition.d.ts.map +1 -1
  37. package/dist/src/code-execution/tool-definition.js +21 -3
  38. package/dist/src/code-execution/tool-definition.js.map +1 -1
  39. package/dist/src/config-checks.d.ts +28 -0
  40. package/dist/src/config-checks.d.ts.map +1 -0
  41. package/dist/src/config-checks.js +52 -0
  42. package/dist/src/config-checks.js.map +1 -0
  43. package/dist/src/deadline-timer.d.ts +21 -0
  44. package/dist/src/deadline-timer.d.ts.map +1 -0
  45. package/dist/src/deadline-timer.js +43 -0
  46. package/dist/src/deadline-timer.js.map +1 -0
  47. package/dist/src/error-message.d.ts +30 -0
  48. package/dist/src/error-message.d.ts.map +1 -0
  49. package/dist/src/error-message.js +50 -0
  50. package/dist/src/error-message.js.map +1 -0
  51. package/dist/src/framework.d.ts +1212 -192
  52. package/dist/src/framework.d.ts.map +1 -1
  53. package/dist/src/framework.js +6686 -1835
  54. package/dist/src/framework.js.map +1 -1
  55. package/dist/src/gate/event-gate.d.ts +8 -0
  56. package/dist/src/gate/event-gate.d.ts.map +1 -1
  57. package/dist/src/gate/event-gate.js +27 -3
  58. package/dist/src/gate/event-gate.js.map +1 -1
  59. package/dist/src/gate/gate-script.d.ts.map +1 -1
  60. package/dist/src/gate/gate-script.js.map +1 -1
  61. package/dist/src/index.d.ts +5 -3
  62. package/dist/src/index.d.ts.map +1 -1
  63. package/dist/src/index.js +5 -3
  64. package/dist/src/index.js.map +1 -1
  65. package/dist/src/mcpl/capability-grant.d.ts.map +1 -1
  66. package/dist/src/mcpl/channel-registry.d.ts +170 -13
  67. package/dist/src/mcpl/channel-registry.d.ts.map +1 -1
  68. package/dist/src/mcpl/channel-registry.js +499 -258
  69. package/dist/src/mcpl/channel-registry.js.map +1 -1
  70. package/dist/src/mcpl/checkpoint-manager.d.ts +21 -1
  71. package/dist/src/mcpl/checkpoint-manager.d.ts.map +1 -1
  72. package/dist/src/mcpl/checkpoint-manager.js +91 -30
  73. package/dist/src/mcpl/checkpoint-manager.js.map +1 -1
  74. package/dist/src/mcpl/conversation-router.d.ts +19 -3
  75. package/dist/src/mcpl/conversation-router.d.ts.map +1 -1
  76. package/dist/src/mcpl/conversation-router.js +23 -8
  77. package/dist/src/mcpl/conversation-router.js.map +1 -1
  78. package/dist/src/mcpl/convert-block.d.ts +20 -0
  79. package/dist/src/mcpl/convert-block.d.ts.map +1 -0
  80. package/dist/src/mcpl/convert-block.js +89 -0
  81. package/dist/src/mcpl/convert-block.js.map +1 -0
  82. package/dist/src/mcpl/errors.d.ts +13 -0
  83. package/dist/src/mcpl/errors.d.ts.map +1 -1
  84. package/dist/src/mcpl/errors.js +28 -0
  85. package/dist/src/mcpl/errors.js.map +1 -1
  86. package/dist/src/mcpl/feature-set-manager.d.ts.map +1 -1
  87. package/dist/src/mcpl/feature-set-manager.js +4 -3
  88. package/dist/src/mcpl/feature-set-manager.js.map +1 -1
  89. package/dist/src/mcpl/hook-orchestrator.d.ts +23 -0
  90. package/dist/src/mcpl/hook-orchestrator.d.ts.map +1 -1
  91. package/dist/src/mcpl/hook-orchestrator.js +83 -72
  92. package/dist/src/mcpl/hook-orchestrator.js.map +1 -1
  93. package/dist/src/mcpl/inbound-source.d.ts +114 -0
  94. package/dist/src/mcpl/inbound-source.d.ts.map +1 -0
  95. package/dist/src/mcpl/inbound-source.js +83 -0
  96. package/dist/src/mcpl/inbound-source.js.map +1 -0
  97. package/dist/src/mcpl/index.d.ts +3 -1
  98. package/dist/src/mcpl/index.d.ts.map +1 -1
  99. package/dist/src/mcpl/index.js +3 -1
  100. package/dist/src/mcpl/index.js.map +1 -1
  101. package/dist/src/mcpl/inference-router.d.ts +15 -11
  102. package/dist/src/mcpl/inference-router.d.ts.map +1 -1
  103. package/dist/src/mcpl/inference-router.js +153 -84
  104. package/dist/src/mcpl/inference-router.js.map +1 -1
  105. package/dist/src/mcpl/log-value.d.ts +54 -0
  106. package/dist/src/mcpl/log-value.d.ts.map +1 -0
  107. package/dist/src/mcpl/log-value.js +109 -0
  108. package/dist/src/mcpl/log-value.js.map +1 -0
  109. package/dist/src/mcpl/prose-stream-router.d.ts +6 -6
  110. package/dist/src/mcpl/prose-stream-router.d.ts.map +1 -1
  111. package/dist/src/mcpl/prose-stream-router.js +4 -4
  112. package/dist/src/mcpl/prose-stream-router.js.map +1 -1
  113. package/dist/src/mcpl/push-coalescer.d.ts +64 -7
  114. package/dist/src/mcpl/push-coalescer.d.ts.map +1 -1
  115. package/dist/src/mcpl/push-coalescer.js +121 -24
  116. package/dist/src/mcpl/push-coalescer.js.map +1 -1
  117. package/dist/src/mcpl/push-handler.d.ts +38 -8
  118. package/dist/src/mcpl/push-handler.d.ts.map +1 -1
  119. package/dist/src/mcpl/push-handler.js +77 -78
  120. package/dist/src/mcpl/push-handler.js.map +1 -1
  121. package/dist/src/mcpl/reference-fetcher.d.ts +14 -2
  122. package/dist/src/mcpl/reference-fetcher.d.ts.map +1 -1
  123. package/dist/src/mcpl/reference-fetcher.js +72 -30
  124. package/dist/src/mcpl/reference-fetcher.js.map +1 -1
  125. package/dist/src/mcpl/references.d.ts +49 -14
  126. package/dist/src/mcpl/references.d.ts.map +1 -1
  127. package/dist/src/mcpl/references.js +74 -21
  128. package/dist/src/mcpl/references.js.map +1 -1
  129. package/dist/src/mcpl/refusal-lines.d.ts +37 -0
  130. package/dist/src/mcpl/refusal-lines.d.ts.map +1 -0
  131. package/dist/src/mcpl/refusal-lines.js +61 -0
  132. package/dist/src/mcpl/refusal-lines.js.map +1 -0
  133. package/dist/src/mcpl/scope-manager.d.ts.map +1 -1
  134. package/dist/src/mcpl/server-connection.d.ts +107 -12
  135. package/dist/src/mcpl/server-connection.d.ts.map +1 -1
  136. package/dist/src/mcpl/server-connection.js +470 -139
  137. package/dist/src/mcpl/server-connection.js.map +1 -1
  138. package/dist/src/mcpl/server-registry.d.ts +10 -1
  139. package/dist/src/mcpl/server-registry.d.ts.map +1 -1
  140. package/dist/src/mcpl/server-registry.js +14 -3
  141. package/dist/src/mcpl/server-registry.js.map +1 -1
  142. package/dist/src/mcpl/skip-reply-wake.d.ts +36 -0
  143. package/dist/src/mcpl/skip-reply-wake.d.ts.map +1 -0
  144. package/dist/src/mcpl/skip-reply-wake.js +55 -0
  145. package/dist/src/mcpl/skip-reply-wake.js.map +1 -0
  146. package/dist/src/mcpl/tool-classes.d.ts +1 -1
  147. package/dist/src/mcpl/tool-classes.d.ts.map +1 -1
  148. package/dist/src/mcpl/tool-classes.js +3 -2
  149. package/dist/src/mcpl/tool-classes.js.map +1 -1
  150. package/dist/src/mcpl/tool-lifecycle.d.ts.map +1 -1
  151. package/dist/src/mcpl/tool-lifecycle.js.map +1 -1
  152. package/dist/src/mcpl/transport.d.ts +74 -7
  153. package/dist/src/mcpl/transport.d.ts.map +1 -1
  154. package/dist/src/mcpl/transport.js +209 -22
  155. package/dist/src/mcpl/transport.js.map +1 -1
  156. package/dist/src/mcpl/types.d.ts +43 -28
  157. package/dist/src/mcpl/types.d.ts.map +1 -1
  158. package/dist/src/mcpl/types.js.map +1 -1
  159. package/dist/src/mcpl/visible-content.d.ts +15 -0
  160. package/dist/src/mcpl/visible-content.d.ts.map +1 -1
  161. package/dist/src/mcpl/visible-content.js +25 -0
  162. package/dist/src/mcpl/visible-content.js.map +1 -1
  163. package/dist/src/module-registry.d.ts +19 -1
  164. package/dist/src/module-registry.d.ts.map +1 -1
  165. package/dist/src/module-registry.js +54 -25
  166. package/dist/src/module-registry.js.map +1 -1
  167. package/dist/src/modules/api/index.d.ts.map +1 -1
  168. package/dist/src/modules/api/index.js +1 -1
  169. package/dist/src/modules/api/index.js.map +1 -1
  170. package/dist/src/modules/discord/discord-js-client.d.ts +1 -0
  171. package/dist/src/modules/discord/discord-js-client.d.ts.map +1 -1
  172. package/dist/src/modules/discord/discord-js-client.js +25 -9
  173. package/dist/src/modules/discord/discord-js-client.js.map +1 -1
  174. package/dist/src/modules/discord/index.d.ts +29 -3
  175. package/dist/src/modules/discord/index.d.ts.map +1 -1
  176. package/dist/src/modules/discord/index.js +383 -145
  177. package/dist/src/modules/discord/index.js.map +1 -1
  178. package/dist/src/modules/discord/types.d.ts +14 -1
  179. package/dist/src/modules/discord/types.d.ts.map +1 -1
  180. package/dist/src/modules/health/index.d.ts.map +1 -1
  181. package/dist/src/modules/health/index.js +2 -1
  182. package/dist/src/modules/health/index.js.map +1 -1
  183. package/dist/src/modules/history/index.d.ts +3 -1
  184. package/dist/src/modules/history/index.d.ts.map +1 -1
  185. package/dist/src/modules/history/index.js +359 -127
  186. package/dist/src/modules/history/index.js.map +1 -1
  187. package/dist/src/modules/history/semantic.d.ts +28 -1
  188. package/dist/src/modules/history/semantic.d.ts.map +1 -1
  189. package/dist/src/modules/history/semantic.js +177 -32
  190. package/dist/src/modules/history/semantic.js.map +1 -1
  191. package/dist/src/modules/unknown-tool.d.ts +10 -0
  192. package/dist/src/modules/unknown-tool.d.ts.map +1 -0
  193. package/dist/src/modules/unknown-tool.js +17 -0
  194. package/dist/src/modules/unknown-tool.js.map +1 -0
  195. package/dist/src/modules/workspace/branch-intent.d.ts.map +1 -1
  196. package/dist/src/modules/workspace/branch-intent.js.map +1 -1
  197. package/dist/src/modules/workspace/disk-agreement.d.ts +54 -6
  198. package/dist/src/modules/workspace/disk-agreement.d.ts.map +1 -1
  199. package/dist/src/modules/workspace/disk-agreement.js +93 -27
  200. package/dist/src/modules/workspace/disk-agreement.js.map +1 -1
  201. package/dist/src/modules/workspace/effects.d.ts +64 -6
  202. package/dist/src/modules/workspace/effects.d.ts.map +1 -1
  203. package/dist/src/modules/workspace/effects.js +291 -44
  204. package/dist/src/modules/workspace/effects.js.map +1 -1
  205. package/dist/src/modules/workspace/index.d.ts +127 -27
  206. package/dist/src/modules/workspace/index.d.ts.map +1 -1
  207. package/dist/src/modules/workspace/index.js +821 -248
  208. package/dist/src/modules/workspace/index.js.map +1 -1
  209. package/dist/src/modules/workspace/observe.d.ts +117 -15
  210. package/dist/src/modules/workspace/observe.d.ts.map +1 -1
  211. package/dist/src/modules/workspace/observe.js +436 -51
  212. package/dist/src/modules/workspace/observe.js.map +1 -1
  213. package/dist/src/modules/workspace/reconcile.d.ts +75 -8
  214. package/dist/src/modules/workspace/reconcile.d.ts.map +1 -1
  215. package/dist/src/modules/workspace/reconcile.js +576 -68
  216. package/dist/src/modules/workspace/reconcile.js.map +1 -1
  217. package/dist/src/modules/workspace/types.d.ts +42 -3
  218. package/dist/src/modules/workspace/types.d.ts.map +1 -1
  219. package/dist/src/modules/workspace/types.js.map +1 -1
  220. package/dist/src/modules/workspace/watcher.d.ts +7 -2
  221. package/dist/src/modules/workspace/watcher.d.ts.map +1 -1
  222. package/dist/src/modules/workspace/watcher.js +28 -4
  223. package/dist/src/modules/workspace/watcher.js.map +1 -1
  224. package/dist/src/operator-log.d.ts.map +1 -1
  225. package/dist/src/operator-log.js.map +1 -1
  226. package/dist/src/prose-drafts.d.ts +240 -0
  227. package/dist/src/prose-drafts.d.ts.map +1 -0
  228. package/dist/src/prose-drafts.js +362 -0
  229. package/dist/src/prose-drafts.js.map +1 -0
  230. package/dist/src/prose-segments.d.ts +21 -2
  231. package/dist/src/prose-segments.d.ts.map +1 -1
  232. package/dist/src/prose-segments.js +46 -9
  233. package/dist/src/prose-segments.js.map +1 -1
  234. package/dist/src/provider-waits.d.ts.map +1 -1
  235. package/dist/src/provider-waits.js.map +1 -1
  236. package/dist/src/queue.d.ts.map +1 -1
  237. package/dist/src/record-journal.d.ts.map +1 -1
  238. package/dist/src/record-journal.js.map +1 -1
  239. package/dist/src/recovery/discord-awareness-outbox.d.ts.map +1 -1
  240. package/dist/src/recovery/discord-awareness-outbox.js.map +1 -1
  241. package/dist/src/recovery/offline-branch.d.ts +1 -0
  242. package/dist/src/recovery/offline-branch.d.ts.map +1 -1
  243. package/dist/src/recovery/offline-branch.js +32 -25
  244. package/dist/src/recovery/offline-branch.js.map +1 -1
  245. package/dist/src/recovery/recover-cli.js.map +1 -1
  246. package/dist/src/runtime/liveness-watchdog.d.ts.map +1 -1
  247. package/dist/src/runtime/liveness-watchdog.js.map +1 -1
  248. package/dist/src/safe-slice.d.ts +5 -1
  249. package/dist/src/safe-slice.d.ts.map +1 -1
  250. package/dist/src/safe-slice.js +9 -1
  251. package/dist/src/safe-slice.js.map +1 -1
  252. package/dist/src/shutdown.d.ts.map +1 -1
  253. package/dist/src/shutdown.js.map +1 -1
  254. package/dist/src/stored-removal.d.ts +73 -0
  255. package/dist/src/stored-removal.d.ts.map +1 -0
  256. package/dist/src/stored-removal.js +100 -0
  257. package/dist/src/stored-removal.js.map +1 -0
  258. package/dist/src/thinking-token-stamp.js.map +1 -1
  259. package/dist/src/tool-image-ledger.d.ts +87 -19
  260. package/dist/src/tool-image-ledger.d.ts.map +1 -1
  261. package/dist/src/tool-image-ledger.js +135 -32
  262. package/dist/src/tool-image-ledger.js.map +1 -1
  263. package/dist/src/tool-presentation.d.ts +9 -0
  264. package/dist/src/tool-presentation.d.ts.map +1 -1
  265. package/dist/src/tool-presentation.js +257 -60
  266. package/dist/src/tool-presentation.js.map +1 -1
  267. package/dist/src/tool-result-guard.d.ts.map +1 -1
  268. package/dist/src/tool-result-guard.js +7 -10
  269. package/dist/src/tool-result-guard.js.map +1 -1
  270. package/dist/src/tool-result-history.d.ts +32 -3
  271. package/dist/src/tool-result-history.d.ts.map +1 -1
  272. package/dist/src/tool-result-history.js +106 -19
  273. package/dist/src/tool-result-history.js.map +1 -1
  274. package/dist/src/tune-out/coordinator.d.ts +25 -1
  275. package/dist/src/tune-out/coordinator.d.ts.map +1 -1
  276. package/dist/src/tune-out/coordinator.js +260 -65
  277. package/dist/src/tune-out/coordinator.js.map +1 -1
  278. package/dist/src/tune-out/tools.d.ts +1 -1
  279. package/dist/src/tune-out/tools.d.ts.map +1 -1
  280. package/dist/src/types/agent.d.ts +59 -11
  281. package/dist/src/types/agent.d.ts.map +1 -1
  282. package/dist/src/types/events.d.ts +17 -0
  283. package/dist/src/types/events.d.ts.map +1 -1
  284. package/dist/src/types/framework.d.ts +31 -5
  285. package/dist/src/types/framework.d.ts.map +1 -1
  286. package/dist/src/types/inference-log.d.ts +1 -1
  287. package/dist/src/types/inference-log.d.ts.map +1 -1
  288. package/dist/src/types/module.d.ts +30 -7
  289. package/dist/src/types/module.d.ts.map +1 -1
  290. package/dist/src/types/trace.d.ts +151 -11
  291. package/dist/src/types/trace.d.ts.map +1 -1
  292. package/dist/src/usage/usage-tracker.d.ts +5 -0
  293. package/dist/src/usage/usage-tracker.d.ts.map +1 -1
  294. package/dist/src/usage/usage-tracker.js +35 -8
  295. package/dist/src/usage/usage-tracker.js.map +1 -1
  296. package/package.json +10 -9
  297. package/src/agent.ts +572 -105
  298. package/src/api/mcp-server-core.ts +681 -0
  299. package/src/api/mcp-server.ts +16 -685
  300. package/src/api/server.ts +55 -30
  301. package/src/api/types.ts +10 -2
  302. package/src/branch-names.ts +19 -0
  303. package/src/closest-names.ts +94 -0
  304. package/src/code-execution/py-runner.ts +200 -76
  305. package/src/code-execution/runtime-py.ts +49 -3
  306. package/src/code-execution/tool-definition.ts +28 -4
  307. package/src/config-checks.ts +48 -0
  308. package/src/deadline-timer.ts +44 -0
  309. package/src/error-message.ts +48 -0
  310. package/src/framework.ts +7158 -1936
  311. package/src/gate/event-gate.ts +28 -3
  312. package/src/index.ts +12 -3
  313. package/src/mcpl/channel-registry.ts +615 -289
  314. package/src/mcpl/checkpoint-manager.ts +104 -29
  315. package/src/mcpl/conversation-router.ts +28 -8
  316. package/src/mcpl/convert-block.ts +97 -0
  317. package/src/mcpl/errors.ts +28 -0
  318. package/src/mcpl/feature-set-manager.ts +4 -3
  319. package/src/mcpl/hook-orchestrator.ts +84 -77
  320. package/src/mcpl/inbound-source.ts +156 -0
  321. package/src/mcpl/index.ts +10 -1
  322. package/src/mcpl/inference-router.ts +174 -99
  323. package/src/mcpl/log-value.ts +116 -0
  324. package/src/mcpl/prose-stream-router.ts +6 -6
  325. package/src/mcpl/push-coalescer.ts +124 -24
  326. package/src/mcpl/push-handler.ts +86 -84
  327. package/src/mcpl/reference-fetcher.ts +71 -26
  328. package/src/mcpl/references.ts +81 -22
  329. package/src/mcpl/refusal-lines.ts +59 -0
  330. package/src/mcpl/server-connection.ts +496 -142
  331. package/src/mcpl/server-registry.ts +15 -4
  332. package/src/mcpl/skip-reply-wake.ts +73 -0
  333. package/src/mcpl/tool-classes.ts +3 -2
  334. package/src/mcpl/transport.ts +219 -26
  335. package/src/mcpl/types.ts +18 -3
  336. package/src/mcpl/visible-content.ts +27 -0
  337. package/src/module-registry.ts +58 -23
  338. package/src/modules/api/index.ts +1 -1
  339. package/src/modules/discord/discord-js-client.ts +26 -10
  340. package/src/modules/discord/index.ts +395 -160
  341. package/src/modules/discord/types.ts +15 -2
  342. package/src/modules/health/index.ts +2 -1
  343. package/src/modules/history/index.ts +410 -120
  344. package/src/modules/history/semantic.ts +189 -32
  345. package/src/modules/unknown-tool.ts +16 -0
  346. package/src/modules/workspace/disk-agreement.ts +125 -21
  347. package/src/modules/workspace/effects.ts +279 -35
  348. package/src/modules/workspace/index.ts +841 -261
  349. package/src/modules/workspace/observe.ts +456 -56
  350. package/src/modules/workspace/reconcile.ts +688 -76
  351. package/src/modules/workspace/types.ts +41 -2
  352. package/src/modules/workspace/watcher.ts +27 -4
  353. package/src/prose-drafts.ts +481 -0
  354. package/src/prose-segments.ts +51 -8
  355. package/src/recovery/offline-branch.ts +36 -29
  356. package/src/safe-slice.ts +9 -1
  357. package/src/stored-removal.ts +126 -0
  358. package/src/tool-image-ledger.ts +153 -34
  359. package/src/tool-presentation.ts +224 -40
  360. package/src/tool-result-guard.ts +7 -8
  361. package/src/tool-result-history.ts +124 -20
  362. package/src/tune-out/coordinator.ts +259 -65
  363. package/src/types/agent.ts +59 -13
  364. package/src/types/events.ts +17 -0
  365. package/src/types/framework.ts +31 -5
  366. package/src/types/inference-log.ts +1 -1
  367. package/src/types/module.ts +31 -7
  368. package/src/types/trace.ts +158 -12
  369. package/src/usage/usage-tracker.ts +32 -8
  370. package/dist/test/activation-request-sanitize.test.d.ts +0 -2
  371. package/dist/test/activation-request-sanitize.test.d.ts.map +0 -1
  372. package/dist/test/activation-request-sanitize.test.js +0 -89
  373. package/dist/test/activation-request-sanitize.test.js.map +0 -1
  374. package/dist/test/agent-cache-ttl.test.d.ts +0 -2
  375. package/dist/test/agent-cache-ttl.test.d.ts.map +0 -1
  376. package/dist/test/agent-cache-ttl.test.js +0 -41
  377. package/dist/test/agent-cache-ttl.test.js.map +0 -1
  378. package/dist/test/agent-runtime-settings.test.d.ts +0 -2
  379. package/dist/test/agent-runtime-settings.test.d.ts.map +0 -1
  380. package/dist/test/agent-runtime-settings.test.js +0 -462
  381. package/dist/test/agent-runtime-settings.test.js.map +0 -1
  382. package/dist/test/api-admin-gate.test.d.ts +0 -2
  383. package/dist/test/api-admin-gate.test.d.ts.map +0 -1
  384. package/dist/test/api-admin-gate.test.js +0 -116
  385. package/dist/test/api-admin-gate.test.js.map +0 -1
  386. package/dist/test/assistant-persist-refusal.test.d.ts +0 -2
  387. package/dist/test/assistant-persist-refusal.test.d.ts.map +0 -1
  388. package/dist/test/assistant-persist-refusal.test.js +0 -63
  389. package/dist/test/assistant-persist-refusal.test.js.map +0 -1
  390. package/dist/test/batched-wake-locus.test.d.ts +0 -2
  391. package/dist/test/batched-wake-locus.test.d.ts.map +0 -1
  392. package/dist/test/batched-wake-locus.test.js +0 -166
  393. package/dist/test/batched-wake-locus.test.js.map +0 -1
  394. package/dist/test/busy-agent-scheduler.test.d.ts +0 -2
  395. package/dist/test/busy-agent-scheduler.test.d.ts.map +0 -1
  396. package/dist/test/busy-agent-scheduler.test.js +0 -92
  397. package/dist/test/busy-agent-scheduler.test.js.map +0 -1
  398. package/dist/test/channel-incoming-targeting.test.d.ts +0 -2
  399. package/dist/test/channel-incoming-targeting.test.d.ts.map +0 -1
  400. package/dist/test/channel-incoming-targeting.test.js +0 -81
  401. package/dist/test/channel-incoming-targeting.test.js.map +0 -1
  402. package/dist/test/channel-label-history.test.d.ts +0 -2
  403. package/dist/test/channel-label-history.test.d.ts.map +0 -1
  404. package/dist/test/channel-label-history.test.js +0 -424
  405. package/dist/test/channel-label-history.test.js.map +0 -1
  406. package/dist/test/channel-lifecycle-provenance.test.d.ts +0 -2
  407. package/dist/test/channel-lifecycle-provenance.test.d.ts.map +0 -1
  408. package/dist/test/channel-lifecycle-provenance.test.js +0 -47
  409. package/dist/test/channel-lifecycle-provenance.test.js.map +0 -1
  410. package/dist/test/channel-registry-routing.test.d.ts +0 -2
  411. package/dist/test/channel-registry-routing.test.d.ts.map +0 -1
  412. package/dist/test/channel-registry-routing.test.js +0 -446
  413. package/dist/test/channel-registry-routing.test.js.map +0 -1
  414. package/dist/test/channel-registry-typing.test.d.ts +0 -2
  415. package/dist/test/channel-registry-typing.test.d.ts.map +0 -1
  416. package/dist/test/channel-registry-typing.test.js +0 -91
  417. package/dist/test/channel-registry-typing.test.js.map +0 -1
  418. package/dist/test/channels-changed-respond-first.test.d.ts +0 -2
  419. package/dist/test/channels-changed-respond-first.test.d.ts.map +0 -1
  420. package/dist/test/channels-changed-respond-first.test.js +0 -74
  421. package/dist/test/channels-changed-respond-first.test.js.map +0 -1
  422. package/dist/test/checkpoint-attribution.test.d.ts +0 -2
  423. package/dist/test/checkpoint-attribution.test.d.ts.map +0 -1
  424. package/dist/test/checkpoint-attribution.test.js +0 -200
  425. package/dist/test/checkpoint-attribution.test.js.map +0 -1
  426. package/dist/test/code-execution.test.d.ts +0 -11
  427. package/dist/test/code-execution.test.d.ts.map +0 -1
  428. package/dist/test/code-execution.test.js +0 -1272
  429. package/dist/test/code-execution.test.js.map +0 -1
  430. package/dist/test/component-defaults.test.d.ts +0 -2
  431. package/dist/test/component-defaults.test.d.ts.map +0 -1
  432. package/dist/test/component-defaults.test.js +0 -54
  433. package/dist/test/component-defaults.test.js.map +0 -1
  434. package/dist/test/conversation-fork-injection-scoping.test.d.ts +0 -2
  435. package/dist/test/conversation-fork-injection-scoping.test.d.ts.map +0 -1
  436. package/dist/test/conversation-fork-injection-scoping.test.js +0 -200
  437. package/dist/test/conversation-fork-injection-scoping.test.js.map +0 -1
  438. package/dist/test/conversation-router.test.d.ts +0 -2
  439. package/dist/test/conversation-router.test.d.ts.map +0 -1
  440. package/dist/test/conversation-router.test.js +0 -174
  441. package/dist/test/conversation-router.test.js.map +0 -1
  442. package/dist/test/conversation-routing.test.d.ts +0 -7
  443. package/dist/test/conversation-routing.test.d.ts.map +0 -1
  444. package/dist/test/conversation-routing.test.js +0 -387
  445. package/dist/test/conversation-routing.test.js.map +0 -1
  446. package/dist/test/deferred-wake-integrity.test.d.ts +0 -29
  447. package/dist/test/deferred-wake-integrity.test.d.ts.map +0 -1
  448. package/dist/test/deferred-wake-integrity.test.js +0 -320
  449. package/dist/test/deferred-wake-integrity.test.js.map +0 -1
  450. package/dist/test/discord-awareness-outbox.test.d.ts +0 -2
  451. package/dist/test/discord-awareness-outbox.test.d.ts.map +0 -1
  452. package/dist/test/discord-awareness-outbox.test.js +0 -267
  453. package/dist/test/discord-awareness-outbox.test.js.map +0 -1
  454. package/dist/test/discord-history-delete-window.test.d.ts +0 -2
  455. package/dist/test/discord-history-delete-window.test.d.ts.map +0 -1
  456. package/dist/test/discord-history-delete-window.test.js +0 -81
  457. package/dist/test/discord-history-delete-window.test.js.map +0 -1
  458. package/dist/test/discord-history-sync.test.d.ts +0 -2
  459. package/dist/test/discord-history-sync.test.d.ts.map +0 -1
  460. package/dist/test/discord-history-sync.test.js +0 -56
  461. package/dist/test/discord-history-sync.test.js.map +0 -1
  462. package/dist/test/ephemeral-settle.test.d.ts +0 -2
  463. package/dist/test/ephemeral-settle.test.d.ts.map +0 -1
  464. package/dist/test/ephemeral-settle.test.js +0 -354
  465. package/dist/test/ephemeral-settle.test.js.map +0 -1
  466. package/dist/test/event-gate-passthrough.test.d.ts +0 -15
  467. package/dist/test/event-gate-passthrough.test.d.ts.map +0 -1
  468. package/dist/test/event-gate-passthrough.test.js +0 -289
  469. package/dist/test/event-gate-passthrough.test.js.map +0 -1
  470. package/dist/test/event-gate-policy-mutation.test.d.ts +0 -2
  471. package/dist/test/event-gate-policy-mutation.test.d.ts.map +0 -1
  472. package/dist/test/event-gate-policy-mutation.test.js +0 -137
  473. package/dist/test/event-gate-policy-mutation.test.js.map +0 -1
  474. package/dist/test/event-gate-rate-limit.test.d.ts +0 -2
  475. package/dist/test/event-gate-rate-limit.test.d.ts.map +0 -1
  476. package/dist/test/event-gate-rate-limit.test.js +0 -627
  477. package/dist/test/event-gate-rate-limit.test.js.map +0 -1
  478. package/dist/test/event-gate-script.test.d.ts +0 -2
  479. package/dist/test/event-gate-script.test.d.ts.map +0 -1
  480. package/dist/test/event-gate-script.test.js +0 -95
  481. package/dist/test/event-gate-script.test.js.map +0 -1
  482. package/dist/test/event-gate-selfwake.test.d.ts +0 -15
  483. package/dist/test/event-gate-selfwake.test.d.ts.map +0 -1
  484. package/dist/test/event-gate-selfwake.test.js +0 -125
  485. package/dist/test/event-gate-selfwake.test.js.map +0 -1
  486. package/dist/test/event-gate-tags.test.d.ts +0 -2
  487. package/dist/test/event-gate-tags.test.d.ts.map +0 -1
  488. package/dist/test/event-gate-tags.test.js +0 -76
  489. package/dist/test/event-gate-tags.test.js.map +0 -1
  490. package/dist/test/event-gate.test.d.ts +0 -2
  491. package/dist/test/event-gate.test.d.ts.map +0 -1
  492. package/dist/test/event-gate.test.js +0 -919
  493. package/dist/test/event-gate.test.js.map +0 -1
  494. package/dist/test/explicit-prose-routing.test.d.ts +0 -11
  495. package/dist/test/explicit-prose-routing.test.d.ts.map +0 -1
  496. package/dist/test/explicit-prose-routing.test.js +0 -1394
  497. package/dist/test/explicit-prose-routing.test.js.map +0 -1
  498. package/dist/test/framework.test.d.ts +0 -5
  499. package/dist/test/framework.test.d.ts.map +0 -1
  500. package/dist/test/framework.test.js +0 -1048
  501. package/dist/test/framework.test.js.map +0 -1
  502. package/dist/test/gather-context-timeout.test.d.ts +0 -2
  503. package/dist/test/gather-context-timeout.test.d.ts.map +0 -1
  504. package/dist/test/gather-context-timeout.test.js +0 -120
  505. package/dist/test/gather-context-timeout.test.js.map +0 -1
  506. package/dist/test/health-snapshot.test.d.ts +0 -2
  507. package/dist/test/health-snapshot.test.d.ts.map +0 -1
  508. package/dist/test/health-snapshot.test.js +0 -74
  509. package/dist/test/health-snapshot.test.js.map +0 -1
  510. package/dist/test/helpers/coalescing-fixture.d.ts +0 -72
  511. package/dist/test/helpers/coalescing-fixture.d.ts.map +0 -1
  512. package/dist/test/helpers/coalescing-fixture.js +0 -146
  513. package/dist/test/helpers/coalescing-fixture.js.map +0 -1
  514. package/dist/test/helpers/coalescing-kill-child.d.ts +0 -2
  515. package/dist/test/helpers/coalescing-kill-child.d.ts.map +0 -1
  516. package/dist/test/helpers/coalescing-kill-child.js +0 -24
  517. package/dist/test/helpers/coalescing-kill-child.js.map +0 -1
  518. package/dist/test/helpers/mock-membrane.d.ts +0 -53
  519. package/dist/test/helpers/mock-membrane.d.ts.map +0 -1
  520. package/dist/test/helpers/mock-membrane.js +0 -168
  521. package/dist/test/helpers/mock-membrane.js.map +0 -1
  522. package/dist/test/helpers/pytc-stop-rows.d.ts +0 -11
  523. package/dist/test/helpers/pytc-stop-rows.d.ts.map +0 -1
  524. package/dist/test/helpers/pytc-stop-rows.js +0 -143
  525. package/dist/test/helpers/pytc-stop-rows.js.map +0 -1
  526. package/dist/test/helpers/quiesce-crash-child.d.ts +0 -2
  527. package/dist/test/helpers/quiesce-crash-child.d.ts.map +0 -1
  528. package/dist/test/helpers/quiesce-crash-child.js +0 -156
  529. package/dist/test/helpers/quiesce-crash-child.js.map +0 -1
  530. package/dist/test/history-module-overview.test.d.ts +0 -2
  531. package/dist/test/history-module-overview.test.d.ts.map +0 -1
  532. package/dist/test/history-module-overview.test.js +0 -711
  533. package/dist/test/history-module-overview.test.js.map +0 -1
  534. package/dist/test/history-module-realstore.test.d.ts +0 -2
  535. package/dist/test/history-module-realstore.test.d.ts.map +0 -1
  536. package/dist/test/history-module-realstore.test.js +0 -363
  537. package/dist/test/history-module-realstore.test.js.map +0 -1
  538. package/dist/test/history-module-semantic.test.d.ts +0 -2
  539. package/dist/test/history-module-semantic.test.d.ts.map +0 -1
  540. package/dist/test/history-module-semantic.test.js +0 -213
  541. package/dist/test/history-module-semantic.test.js.map +0 -1
  542. package/dist/test/history-module-ux.test.d.ts +0 -2
  543. package/dist/test/history-module-ux.test.d.ts.map +0 -1
  544. package/dist/test/history-module-ux.test.js +0 -304
  545. package/dist/test/history-module-ux.test.js.map +0 -1
  546. package/dist/test/history-module.test.d.ts +0 -2
  547. package/dist/test/history-module.test.d.ts.map +0 -1
  548. package/dist/test/history-module.test.js +0 -619
  549. package/dist/test/history-module.test.js.map +0 -1
  550. package/dist/test/history-semantic-review-findings.test.d.ts +0 -2
  551. package/dist/test/history-semantic-review-findings.test.d.ts.map +0 -1
  552. package/dist/test/history-semantic-review-findings.test.js +0 -338
  553. package/dist/test/history-semantic-review-findings.test.js.map +0 -1
  554. package/dist/test/history-semantic-sync-converges.test.d.ts +0 -2
  555. package/dist/test/history-semantic-sync-converges.test.d.ts.map +0 -1
  556. package/dist/test/history-semantic-sync-converges.test.js +0 -109
  557. package/dist/test/history-semantic-sync-converges.test.js.map +0 -1
  558. package/dist/test/host-quiesce.test.d.ts +0 -2
  559. package/dist/test/host-quiesce.test.d.ts.map +0 -1
  560. package/dist/test/host-quiesce.test.js +0 -863
  561. package/dist/test/host-quiesce.test.js.map +0 -1
  562. package/dist/test/inference-exhaustion-rewind.test.d.ts +0 -2
  563. package/dist/test/inference-exhaustion-rewind.test.d.ts.map +0 -1
  564. package/dist/test/inference-exhaustion-rewind.test.js +0 -309
  565. package/dist/test/inference-exhaustion-rewind.test.js.map +0 -1
  566. package/dist/test/inference-failure-bounds.test.d.ts +0 -2
  567. package/dist/test/inference-failure-bounds.test.d.ts.map +0 -1
  568. package/dist/test/inference-failure-bounds.test.js +0 -1201
  569. package/dist/test/inference-failure-bounds.test.js.map +0 -1
  570. package/dist/test/inference-failure-observability.test.d.ts +0 -2
  571. package/dist/test/inference-failure-observability.test.d.ts.map +0 -1
  572. package/dist/test/inference-failure-observability.test.js +0 -84
  573. package/dist/test/inference-failure-observability.test.js.map +0 -1
  574. package/dist/test/journal-tool.test.d.ts +0 -2
  575. package/dist/test/journal-tool.test.d.ts.map +0 -1
  576. package/dist/test/journal-tool.test.js +0 -33
  577. package/dist/test/journal-tool.test.js.map +0 -1
  578. package/dist/test/kv-unified-open-flight-retry.test.d.ts +0 -2
  579. package/dist/test/kv-unified-open-flight-retry.test.d.ts.map +0 -1
  580. package/dist/test/kv-unified-open-flight-retry.test.js +0 -189
  581. package/dist/test/kv-unified-open-flight-retry.test.js.map +0 -1
  582. package/dist/test/kv-unified-wiring.test.d.ts +0 -2
  583. package/dist/test/kv-unified-wiring.test.d.ts.map +0 -1
  584. package/dist/test/kv-unified-wiring.test.js +0 -95
  585. package/dist/test/kv-unified-wiring.test.js.map +0 -1
  586. package/dist/test/late-events-after-stop.test.d.ts +0 -2
  587. package/dist/test/late-events-after-stop.test.d.ts.map +0 -1
  588. package/dist/test/late-events-after-stop.test.js +0 -122
  589. package/dist/test/late-events-after-stop.test.js.map +0 -1
  590. package/dist/test/liveness-watchdog.test.d.ts +0 -2
  591. package/dist/test/liveness-watchdog.test.d.ts.map +0 -1
  592. package/dist/test/liveness-watchdog.test.js +0 -94
  593. package/dist/test/liveness-watchdog.test.js.map +0 -1
  594. package/dist/test/machine-close-provenance.test.d.ts +0 -2
  595. package/dist/test/machine-close-provenance.test.d.ts.map +0 -1
  596. package/dist/test/machine-close-provenance.test.js +0 -116
  597. package/dist/test/machine-close-provenance.test.js.map +0 -1
  598. package/dist/test/maintenance-timer.test.d.ts +0 -2
  599. package/dist/test/maintenance-timer.test.d.ts.map +0 -1
  600. package/dist/test/maintenance-timer.test.js +0 -265
  601. package/dist/test/maintenance-timer.test.js.map +0 -1
  602. package/dist/test/mcpl-access-provider.test.d.ts +0 -2
  603. package/dist/test/mcpl-access-provider.test.d.ts.map +0 -1
  604. package/dist/test/mcpl-access-provider.test.js +0 -20
  605. package/dist/test/mcpl-access-provider.test.js.map +0 -1
  606. package/dist/test/mcpl-awareness-barrier.test.d.ts +0 -2
  607. package/dist/test/mcpl-awareness-barrier.test.d.ts.map +0 -1
  608. package/dist/test/mcpl-awareness-barrier.test.js +0 -769
  609. package/dist/test/mcpl-awareness-barrier.test.js.map +0 -1
  610. package/dist/test/mcpl-capability-grant.test.d.ts +0 -10
  611. package/dist/test/mcpl-capability-grant.test.d.ts.map +0 -1
  612. package/dist/test/mcpl-capability-grant.test.js +0 -111
  613. package/dist/test/mcpl-capability-grant.test.js.map +0 -1
  614. package/dist/test/mcpl-capability-scoping.test.d.ts +0 -2
  615. package/dist/test/mcpl-capability-scoping.test.d.ts.map +0 -1
  616. package/dist/test/mcpl-capability-scoping.test.js +0 -266
  617. package/dist/test/mcpl-capability-scoping.test.js.map +0 -1
  618. package/dist/test/mcpl-child-env.test.d.ts +0 -2
  619. package/dist/test/mcpl-child-env.test.d.ts.map +0 -1
  620. package/dist/test/mcpl-child-env.test.js +0 -158
  621. package/dist/test/mcpl-child-env.test.js.map +0 -1
  622. package/dist/test/mcpl-coalescing.test.d.ts +0 -2
  623. package/dist/test/mcpl-coalescing.test.d.ts.map +0 -1
  624. package/dist/test/mcpl-coalescing.test.js +0 -1125
  625. package/dist/test/mcpl-coalescing.test.js.map +0 -1
  626. package/dist/test/mcpl-config-diagnostics.test.d.ts +0 -2
  627. package/dist/test/mcpl-config-diagnostics.test.d.ts.map +0 -1
  628. package/dist/test/mcpl-config-diagnostics.test.js +0 -452
  629. package/dist/test/mcpl-config-diagnostics.test.js.map +0 -1
  630. package/dist/test/mcpl-empty-content.test.d.ts +0 -2
  631. package/dist/test/mcpl-empty-content.test.d.ts.map +0 -1
  632. package/dist/test/mcpl-empty-content.test.js +0 -368
  633. package/dist/test/mcpl-empty-content.test.js.map +0 -1
  634. package/dist/test/mcpl-gate-roundtrip.test.d.ts +0 -2
  635. package/dist/test/mcpl-gate-roundtrip.test.d.ts.map +0 -1
  636. package/dist/test/mcpl-gate-roundtrip.test.js +0 -285
  637. package/dist/test/mcpl-gate-roundtrip.test.js.map +0 -1
  638. package/dist/test/mcpl-list-status.test.d.ts +0 -2
  639. package/dist/test/mcpl-list-status.test.d.ts.map +0 -1
  640. package/dist/test/mcpl-list-status.test.js +0 -82
  641. package/dist/test/mcpl-list-status.test.js.map +0 -1
  642. package/dist/test/mcpl-manifest-changed.test.d.ts +0 -2
  643. package/dist/test/mcpl-manifest-changed.test.d.ts.map +0 -1
  644. package/dist/test/mcpl-manifest-changed.test.js +0 -178
  645. package/dist/test/mcpl-manifest-changed.test.js.map +0 -1
  646. package/dist/test/mcpl-push-convert.test.d.ts +0 -2
  647. package/dist/test/mcpl-push-convert.test.d.ts.map +0 -1
  648. package/dist/test/mcpl-push-convert.test.js +0 -42
  649. package/dist/test/mcpl-push-convert.test.js.map +0 -1
  650. package/dist/test/mcpl-reconnect-events.test.d.ts +0 -2
  651. package/dist/test/mcpl-reconnect-events.test.d.ts.map +0 -1
  652. package/dist/test/mcpl-reconnect-events.test.js +0 -144
  653. package/dist/test/mcpl-reconnect-events.test.js.map +0 -1
  654. package/dist/test/mcpl-reconnect-reregistration.test.d.ts +0 -2
  655. package/dist/test/mcpl-reconnect-reregistration.test.d.ts.map +0 -1
  656. package/dist/test/mcpl-reconnect-reregistration.test.js +0 -236
  657. package/dist/test/mcpl-reconnect-reregistration.test.js.map +0 -1
  658. package/dist/test/mcpl-reference-fetcher.test.d.ts +0 -2
  659. package/dist/test/mcpl-reference-fetcher.test.d.ts.map +0 -1
  660. package/dist/test/mcpl-reference-fetcher.test.js +0 -427
  661. package/dist/test/mcpl-reference-fetcher.test.js.map +0 -1
  662. package/dist/test/mcpl-reference-fields.test.d.ts +0 -2
  663. package/dist/test/mcpl-reference-fields.test.d.ts.map +0 -1
  664. package/dist/test/mcpl-reference-fields.test.js +0 -149
  665. package/dist/test/mcpl-reference-fields.test.js.map +0 -1
  666. package/dist/test/mcpl-request-timeout.test.d.ts +0 -2
  667. package/dist/test/mcpl-request-timeout.test.d.ts.map +0 -1
  668. package/dist/test/mcpl-request-timeout.test.js +0 -138
  669. package/dist/test/mcpl-request-timeout.test.js.map +0 -1
  670. package/dist/test/mcpl-runtime-lifecycle.test.d.ts +0 -7
  671. package/dist/test/mcpl-runtime-lifecycle.test.d.ts.map +0 -1
  672. package/dist/test/mcpl-runtime-lifecycle.test.js +0 -142
  673. package/dist/test/mcpl-runtime-lifecycle.test.js.map +0 -1
  674. package/dist/test/mcpl-tool-class-listing.test.d.ts +0 -2
  675. package/dist/test/mcpl-tool-class-listing.test.d.ts.map +0 -1
  676. package/dist/test/mcpl-tool-class-listing.test.js +0 -147
  677. package/dist/test/mcpl-tool-class-listing.test.js.map +0 -1
  678. package/dist/test/mcpl-tool-classes.test.d.ts +0 -7
  679. package/dist/test/mcpl-tool-classes.test.d.ts.map +0 -1
  680. package/dist/test/mcpl-tool-classes.test.js +0 -80
  681. package/dist/test/mcpl-tool-classes.test.js.map +0 -1
  682. package/dist/test/mcpl-tool-lifecycle-e2e.test.d.ts +0 -2
  683. package/dist/test/mcpl-tool-lifecycle-e2e.test.d.ts.map +0 -1
  684. package/dist/test/mcpl-tool-lifecycle-e2e.test.js +0 -237
  685. package/dist/test/mcpl-tool-lifecycle-e2e.test.js.map +0 -1
  686. package/dist/test/mcpl-tool-lifecycle-emitter.test.d.ts +0 -11
  687. package/dist/test/mcpl-tool-lifecycle-emitter.test.d.ts.map +0 -1
  688. package/dist/test/mcpl-tool-lifecycle-emitter.test.js +0 -412
  689. package/dist/test/mcpl-tool-lifecycle-emitter.test.js.map +0 -1
  690. package/dist/test/mcpl-tool-lifecycle-script.test.d.ts +0 -2
  691. package/dist/test/mcpl-tool-lifecycle-script.test.d.ts.map +0 -1
  692. package/dist/test/mcpl-tool-lifecycle-script.test.js +0 -288
  693. package/dist/test/mcpl-tool-lifecycle-script.test.js.map +0 -1
  694. package/dist/test/mcpl-tool-lifecycle.test.d.ts +0 -11
  695. package/dist/test/mcpl-tool-lifecycle.test.d.ts.map +0 -1
  696. package/dist/test/mcpl-tool-lifecycle.test.js +0 -270
  697. package/dist/test/mcpl-tool-lifecycle.test.js.map +0 -1
  698. package/dist/test/mcpl-ws-transport.test.d.ts +0 -2
  699. package/dist/test/mcpl-ws-transport.test.d.ts.map +0 -1
  700. package/dist/test/mcpl-ws-transport.test.js +0 -258
  701. package/dist/test/mcpl-ws-transport.test.js.map +0 -1
  702. package/dist/test/module-context-integration.test.d.ts +0 -18
  703. package/dist/test/module-context-integration.test.d.ts.map +0 -1
  704. package/dist/test/module-context-integration.test.js +0 -181
  705. package/dist/test/module-context-integration.test.js.map +0 -1
  706. package/dist/test/offline-recovery-branch.test.d.ts +0 -2
  707. package/dist/test/offline-recovery-branch.test.d.ts.map +0 -1
  708. package/dist/test/offline-recovery-branch.test.js +0 -226
  709. package/dist/test/offline-recovery-branch.test.js.map +0 -1
  710. package/dist/test/operator-surgery.test.d.ts +0 -2
  711. package/dist/test/operator-surgery.test.d.ts.map +0 -1
  712. package/dist/test/operator-surgery.test.js +0 -398
  713. package/dist/test/operator-surgery.test.js.map +0 -1
  714. package/dist/test/ops-alert.test.d.ts +0 -2
  715. package/dist/test/ops-alert.test.d.ts.map +0 -1
  716. package/dist/test/ops-alert.test.js +0 -153
  717. package/dist/test/ops-alert.test.js.map +0 -1
  718. package/dist/test/overbudget-drain-breaker.test.d.ts +0 -2
  719. package/dist/test/overbudget-drain-breaker.test.d.ts.map +0 -1
  720. package/dist/test/overbudget-drain-breaker.test.js +0 -197
  721. package/dist/test/overbudget-drain-breaker.test.js.map +0 -1
  722. package/dist/test/per-agent-delivery.test.d.ts +0 -2
  723. package/dist/test/per-agent-delivery.test.d.ts.map +0 -1
  724. package/dist/test/per-agent-delivery.test.js +0 -108
  725. package/dist/test/per-agent-delivery.test.js.map +0 -1
  726. package/dist/test/physical-window-restart.test.d.ts +0 -14
  727. package/dist/test/physical-window-restart.test.d.ts.map +0 -1
  728. package/dist/test/physical-window-restart.test.js +0 -222
  729. package/dist/test/physical-window-restart.test.js.map +0 -1
  730. package/dist/test/placed-reaction-baseline.test.d.ts +0 -2
  731. package/dist/test/placed-reaction-baseline.test.d.ts.map +0 -1
  732. package/dist/test/placed-reaction-baseline.test.js +0 -312
  733. package/dist/test/placed-reaction-baseline.test.js.map +0 -1
  734. package/dist/test/present-while-acting.test.d.ts +0 -19
  735. package/dist/test/present-while-acting.test.d.ts.map +0 -1
  736. package/dist/test/present-while-acting.test.js +0 -706
  737. package/dist/test/present-while-acting.test.js.map +0 -1
  738. package/dist/test/prose-segments.test.d.ts +0 -2
  739. package/dist/test/prose-segments.test.d.ts.map +0 -1
  740. package/dist/test/prose-segments.test.js +0 -52
  741. package/dist/test/prose-segments.test.js.map +0 -1
  742. package/dist/test/prose-stream-router.test.d.ts +0 -2
  743. package/dist/test/prose-stream-router.test.d.ts.map +0 -1
  744. package/dist/test/prose-stream-router.test.js +0 -171
  745. package/dist/test/prose-stream-router.test.js.map +0 -1
  746. package/dist/test/provider-acceleration-cooldown.test.d.ts +0 -2
  747. package/dist/test/provider-acceleration-cooldown.test.d.ts.map +0 -1
  748. package/dist/test/provider-acceleration-cooldown.test.js +0 -435
  749. package/dist/test/provider-acceleration-cooldown.test.js.map +0 -1
  750. package/dist/test/provider-waits.test.d.ts +0 -2
  751. package/dist/test/provider-waits.test.d.ts.map +0 -1
  752. package/dist/test/provider-waits.test.js +0 -2196
  753. package/dist/test/provider-waits.test.js.map +0 -1
  754. package/dist/test/puppet-tool-call.test.d.ts +0 -2
  755. package/dist/test/puppet-tool-call.test.d.ts.map +0 -1
  756. package/dist/test/puppet-tool-call.test.js +0 -224
  757. package/dist/test/puppet-tool-call.test.js.map +0 -1
  758. package/dist/test/puppet-turn-reservation.test.d.ts +0 -2
  759. package/dist/test/puppet-turn-reservation.test.d.ts.map +0 -1
  760. package/dist/test/puppet-turn-reservation.test.js +0 -139
  761. package/dist/test/puppet-turn-reservation.test.js.map +0 -1
  762. package/dist/test/reaction-baseline-platform.test.d.ts +0 -2
  763. package/dist/test/reaction-baseline-platform.test.d.ts.map +0 -1
  764. package/dist/test/reaction-baseline-platform.test.js +0 -124
  765. package/dist/test/reaction-baseline-platform.test.js.map +0 -1
  766. package/dist/test/record-journal.test.d.ts +0 -6
  767. package/dist/test/record-journal.test.d.ts.map +0 -1
  768. package/dist/test/record-journal.test.js +0 -269
  769. package/dist/test/record-journal.test.js.map +0 -1
  770. package/dist/test/refusal-reaction-baseline.test.d.ts +0 -2
  771. package/dist/test/refusal-reaction-baseline.test.d.ts.map +0 -1
  772. package/dist/test/refusal-reaction-baseline.test.js +0 -81
  773. package/dist/test/refusal-reaction-baseline.test.js.map +0 -1
  774. package/dist/test/refusal-rewind.test.d.ts +0 -2
  775. package/dist/test/refusal-rewind.test.d.ts.map +0 -1
  776. package/dist/test/refusal-rewind.test.js +0 -108
  777. package/dist/test/refusal-rewind.test.js.map +0 -1
  778. package/dist/test/refusal-single-call.test.d.ts +0 -2
  779. package/dist/test/refusal-single-call.test.d.ts.map +0 -1
  780. package/dist/test/refusal-single-call.test.js +0 -177
  781. package/dist/test/refusal-single-call.test.js.map +0 -1
  782. package/dist/test/release-changelog.test.d.ts +0 -2
  783. package/dist/test/release-changelog.test.d.ts.map +0 -1
  784. package/dist/test/release-changelog.test.js +0 -159
  785. package/dist/test/release-changelog.test.js.map +0 -1
  786. package/dist/test/same-round-think-policy.test.d.ts +0 -2
  787. package/dist/test/same-round-think-policy.test.d.ts.map +0 -1
  788. package/dist/test/same-round-think-policy.test.js +0 -853
  789. package/dist/test/same-round-think-policy.test.js.map +0 -1
  790. package/dist/test/save-recent-image.test.d.ts +0 -26
  791. package/dist/test/save-recent-image.test.d.ts.map +0 -1
  792. package/dist/test/save-recent-image.test.js +0 -974
  793. package/dist/test/save-recent-image.test.js.map +0 -1
  794. package/dist/test/shutdown-errors.test.d.ts +0 -2
  795. package/dist/test/shutdown-errors.test.d.ts.map +0 -1
  796. package/dist/test/shutdown-errors.test.js +0 -662
  797. package/dist/test/shutdown-errors.test.js.map +0 -1
  798. package/dist/test/silent-heartbeat-rows.test.d.ts +0 -2
  799. package/dist/test/silent-heartbeat-rows.test.d.ts.map +0 -1
  800. package/dist/test/silent-heartbeat-rows.test.js +0 -451
  801. package/dist/test/silent-heartbeat-rows.test.js.map +0 -1
  802. package/dist/test/silent-heartbeat.test.d.ts +0 -2
  803. package/dist/test/silent-heartbeat.test.d.ts.map +0 -1
  804. package/dist/test/silent-heartbeat.test.js +0 -165
  805. package/dist/test/silent-heartbeat.test.js.map +0 -1
  806. package/dist/test/state-scaling-e2e.test.d.ts +0 -22
  807. package/dist/test/state-scaling-e2e.test.d.ts.map +0 -1
  808. package/dist/test/state-scaling-e2e.test.js +0 -206
  809. package/dist/test/state-scaling-e2e.test.js.map +0 -1
  810. package/dist/test/state-scaling.test.d.ts +0 -12
  811. package/dist/test/state-scaling.test.d.ts.map +0 -1
  812. package/dist/test/state-scaling.test.js +0 -251
  813. package/dist/test/state-scaling.test.js.map +0 -1
  814. package/dist/test/stop-with-work-in-flight.test.d.ts +0 -23
  815. package/dist/test/stop-with-work-in-flight.test.d.ts.map +0 -1
  816. package/dist/test/stop-with-work-in-flight.test.js +0 -672
  817. package/dist/test/stop-with-work-in-flight.test.js.map +0 -1
  818. package/dist/test/surgery-marks-receipt.test.d.ts +0 -2
  819. package/dist/test/surgery-marks-receipt.test.d.ts.map +0 -1
  820. package/dist/test/surgery-marks-receipt.test.js +0 -540
  821. package/dist/test/surgery-marks-receipt.test.js.map +0 -1
  822. package/dist/test/thinking-token-stamp.test.d.ts +0 -12
  823. package/dist/test/thinking-token-stamp.test.d.ts.map +0 -1
  824. package/dist/test/thinking-token-stamp.test.js +0 -129
  825. package/dist/test/thinking-token-stamp.test.js.map +0 -1
  826. package/dist/test/timezone.test.d.ts +0 -2
  827. package/dist/test/timezone.test.d.ts.map +0 -1
  828. package/dist/test/timezone.test.js +0 -18
  829. package/dist/test/timezone.test.js.map +0 -1
  830. package/dist/test/tool-batch-hook.test.d.ts +0 -8
  831. package/dist/test/tool-batch-hook.test.d.ts.map +0 -1
  832. package/dist/test/tool-batch-hook.test.js +0 -275
  833. package/dist/test/tool-batch-hook.test.js.map +0 -1
  834. package/dist/test/tool-policy.test.d.ts +0 -2
  835. package/dist/test/tool-policy.test.d.ts.map +0 -1
  836. package/dist/test/tool-policy.test.js +0 -51
  837. package/dist/test/tool-policy.test.js.map +0 -1
  838. package/dist/test/tool-presentation.test.d.ts +0 -2
  839. package/dist/test/tool-presentation.test.d.ts.map +0 -1
  840. package/dist/test/tool-presentation.test.js +0 -268
  841. package/dist/test/tool-presentation.test.js.map +0 -1
  842. package/dist/test/tool-result-content.test.d.ts +0 -2
  843. package/dist/test/tool-result-content.test.d.ts.map +0 -1
  844. package/dist/test/tool-result-content.test.js +0 -37
  845. package/dist/test/tool-result-content.test.js.map +0 -1
  846. package/dist/test/tool-result-guard.test.d.ts +0 -2
  847. package/dist/test/tool-result-guard.test.d.ts.map +0 -1
  848. package/dist/test/tool-result-guard.test.js +0 -3607
  849. package/dist/test/tool-result-guard.test.js.map +0 -1
  850. package/dist/test/tool-result-history.test.d.ts +0 -7
  851. package/dist/test/tool-result-history.test.d.ts.map +0 -1
  852. package/dist/test/tool-result-history.test.js +0 -156
  853. package/dist/test/tool-result-history.test.js.map +0 -1
  854. package/dist/test/tool-result-spill.test.d.ts +0 -13
  855. package/dist/test/tool-result-spill.test.d.ts.map +0 -1
  856. package/dist/test/tool-result-spill.test.js +0 -586
  857. package/dist/test/tool-result-spill.test.js.map +0 -1
  858. package/dist/test/tool-wrapper-prose-guard-integration.test.d.ts +0 -2
  859. package/dist/test/tool-wrapper-prose-guard-integration.test.d.ts.map +0 -1
  860. package/dist/test/tool-wrapper-prose-guard-integration.test.js +0 -485
  861. package/dist/test/tool-wrapper-prose-guard-integration.test.js.map +0 -1
  862. package/dist/test/tool-wrapper-prose-guard.test.d.ts +0 -2
  863. package/dist/test/tool-wrapper-prose-guard.test.d.ts.map +0 -1
  864. package/dist/test/tool-wrapper-prose-guard.test.js +0 -34
  865. package/dist/test/tool-wrapper-prose-guard.test.js.map +0 -1
  866. package/dist/test/tools-observe-parser-conformance.test.d.ts +0 -2
  867. package/dist/test/tools-observe-parser-conformance.test.d.ts.map +0 -1
  868. package/dist/test/tools-observe-parser-conformance.test.js +0 -129
  869. package/dist/test/tools-observe-parser-conformance.test.js.map +0 -1
  870. package/dist/test/trunk-channel-routing.test.d.ts +0 -19
  871. package/dist/test/trunk-channel-routing.test.d.ts.map +0 -1
  872. package/dist/test/trunk-channel-routing.test.js +0 -329
  873. package/dist/test/trunk-channel-routing.test.js.map +0 -1
  874. package/dist/test/tune-out-e2e.test.d.ts +0 -2
  875. package/dist/test/tune-out-e2e.test.d.ts.map +0 -1
  876. package/dist/test/tune-out-e2e.test.js +0 -142
  877. package/dist/test/tune-out-e2e.test.js.map +0 -1
  878. package/dist/test/tune-out-gate-composition.test.d.ts +0 -2
  879. package/dist/test/tune-out-gate-composition.test.d.ts.map +0 -1
  880. package/dist/test/tune-out-gate-composition.test.js +0 -221
  881. package/dist/test/tune-out-gate-composition.test.js.map +0 -1
  882. package/dist/test/tune-out-lifecycle.test.d.ts +0 -2
  883. package/dist/test/tune-out-lifecycle.test.d.ts.map +0 -1
  884. package/dist/test/tune-out-lifecycle.test.js +0 -121
  885. package/dist/test/tune-out-lifecycle.test.js.map +0 -1
  886. package/dist/test/turn-trigger-provenance.test.d.ts +0 -2
  887. package/dist/test/turn-trigger-provenance.test.d.ts.map +0 -1
  888. package/dist/test/turn-trigger-provenance.test.js +0 -137
  889. package/dist/test/turn-trigger-provenance.test.js.map +0 -1
  890. package/dist/test/unconvertible-tool-result.test.d.ts +0 -2
  891. package/dist/test/unconvertible-tool-result.test.d.ts.map +0 -1
  892. package/dist/test/unconvertible-tool-result.test.js +0 -358
  893. package/dist/test/unconvertible-tool-result.test.js.map +0 -1
  894. package/dist/test/usage-accounting.test.d.ts +0 -2
  895. package/dist/test/usage-accounting.test.d.ts.map +0 -1
  896. package/dist/test/usage-accounting.test.js +0 -13
  897. package/dist/test/usage-accounting.test.js.map +0 -1
  898. package/dist/test/usage-tracker.test.d.ts +0 -2
  899. package/dist/test/usage-tracker.test.d.ts.map +0 -1
  900. package/dist/test/usage-tracker.test.js +0 -129
  901. package/dist/test/usage-tracker.test.js.map +0 -1
  902. package/dist/test/utils-surface.test.d.ts +0 -2
  903. package/dist/test/utils-surface.test.d.ts.map +0 -1
  904. package/dist/test/utils-surface.test.js +0 -145
  905. package/dist/test/utils-surface.test.js.map +0 -1
  906. package/dist/test/workspace-branch-continuation.test.d.ts +0 -15
  907. package/dist/test/workspace-branch-continuation.test.d.ts.map +0 -1
  908. package/dist/test/workspace-branch-continuation.test.js +0 -183
  909. package/dist/test/workspace-branch-continuation.test.js.map +0 -1
  910. package/dist/test/workspace-materialize-freshness.test.d.ts +0 -16
  911. package/dist/test/workspace-materialize-freshness.test.d.ts.map +0 -1
  912. package/dist/test/workspace-materialize-freshness.test.js +0 -252
  913. package/dist/test/workspace-materialize-freshness.test.js.map +0 -1
  914. package/dist/test/workspace-path-containment.test.d.ts +0 -19
  915. package/dist/test/workspace-path-containment.test.d.ts.map +0 -1
  916. package/dist/test/workspace-path-containment.test.js +0 -91
  917. package/dist/test/workspace-path-containment.test.js.map +0 -1
  918. package/dist/test/workspace-read-file-from-disk.test.d.ts +0 -17
  919. package/dist/test/workspace-read-file-from-disk.test.d.ts.map +0 -1
  920. package/dist/test/workspace-read-file-from-disk.test.js +0 -174
  921. package/dist/test/workspace-read-file-from-disk.test.js.map +0 -1
  922. package/dist/test/workspace-read-image.test.d.ts +0 -2
  923. package/dist/test/workspace-read-image.test.d.ts.map +0 -1
  924. package/dist/test/workspace-read-image.test.js +0 -597
  925. package/dist/test/workspace-read-image.test.js.map +0 -1
  926. package/dist/test/workspace-read-text.test.d.ts +0 -2
  927. package/dist/test/workspace-read-text.test.d.ts.map +0 -1
  928. package/dist/test/workspace-read-text.test.js +0 -101
  929. package/dist/test/workspace-read-text.test.js.map +0 -1
  930. package/dist/test/workspace-restore-order.test.d.ts +0 -16
  931. package/dist/test/workspace-restore-order.test.d.ts.map +0 -1
  932. package/dist/test/workspace-restore-order.test.js +0 -140
  933. package/dist/test/workspace-restore-order.test.js.map +0 -1
  934. package/dist/test/workspace-three-way.test.d.ts +0 -12
  935. package/dist/test/workspace-three-way.test.d.ts.map +0 -1
  936. package/dist/test/workspace-three-way.test.js +0 -3194
  937. package/dist/test/workspace-three-way.test.js.map +0 -1
  938. package/dist/test/workspace-watcher.test.d.ts +0 -2
  939. package/dist/test/workspace-watcher.test.d.ts.map +0 -1
  940. package/dist/test/workspace-watcher.test.js +0 -281
  941. package/dist/test/workspace-watcher.test.js.map +0 -1
  942. package/dist/test/xml-round-persist.test.d.ts +0 -19
  943. package/dist/test/xml-round-persist.test.d.ts.map +0 -1
  944. package/dist/test/xml-round-persist.test.js +0 -235
  945. package/dist/test/xml-round-persist.test.js.map +0 -1
  946. package/dist/tsconfig.tsbuildinfo +0 -1
@@ -8,6 +8,7 @@
8
8
  */
9
9
 
10
10
  import type { ContentBlock } from '@animalabs/membrane';
11
+ import type { StoredMessage } from '@animalabs/context-manager';
11
12
  import type {
12
13
  Module,
13
14
  ModuleContext,
@@ -24,11 +25,13 @@ import type {
24
25
  DiscordModuleConfig,
25
26
  DiscordModuleState,
26
27
  ConversationContext,
28
+ DiscordAttachment,
27
29
  DiscordClientInterface,
28
30
  DiscordMessageData,
29
31
  DiscordMessageEvent,
30
32
  DiscordEditEvent,
31
33
  DiscordDeleteEvent,
34
+ HistoryMessage,
32
35
  SendInput,
33
36
  SendDMInput,
34
37
  ReplyInput,
@@ -42,6 +45,7 @@ import type {
42
45
  FetchHistoryInput,
43
46
  } from './types.js';
44
47
  import { formatZonedDateTime, resolveTimeZone } from '../../timezone.js';
48
+ import { logValue } from '../../mcpl/log-value.js';
45
49
 
46
50
  // Re-export event types for consumers who want to handle them
47
51
  export type { DiscordMessageEvent, DiscordEditEvent, DiscordDeleteEvent } from './types.js';
@@ -67,9 +71,19 @@ const TYPING_REFRESH_MS = 8_000;
67
71
  // stuck on forever.
68
72
  const TYPING_MAX_MS = 5 * 60_000;
69
73
 
70
- // Trace event types that terminate an agent's turn — any of these stops the
71
- // typing keepalive. They fire once per turn, after all tool-call cycles.
74
+ // The most agents whose latest post the module keeps for their turn's
75
+ // thoughts (lastPosts). Past it, the entry recorded longest ago goes, which
76
+ // bounds the entries of agents that are gone, such as closed conversations'.
77
+ // An entry is wanted only until its turn's speech arrives, so one goes while
78
+ // still wanted only if this many other agents post in that time, and its
79
+ // turn's thoughts then go into no message.
80
+ const MAX_LAST_POSTS = 1_024;
81
+
82
+ // Trace event types that end an agent's turn (onTrace's contract) — any of
83
+ // these stops the typing keepalive. A turn's tool-call cycles stay inside its
84
+ // stream, so they come after them. inference:completed is the normal end.
72
85
  const TURN_TERMINAL_TRACES = new Set([
86
+ 'inference:completed',
73
87
  'inference:turn_ended',
74
88
  'inference:aborted',
75
89
  'inference:failed',
@@ -93,6 +107,128 @@ const TEXT_FILE_EXTENSIONS = [
93
107
 
94
108
  const CONVERSATION_TIMEOUT_MS = 30 * 60 * 1000; // 30 minutes
95
109
 
110
+ /** What the agent reads for a text attachment whose contents couldn't be
111
+ * fetched: by an error, or by an answer that wasn't OK. */
112
+ function attachmentNotFetched(filename: string): { type: 'text'; text: string } {
113
+ return { type: 'text', text: `[Attachment: ${filename} (failed to fetch)]` };
114
+ }
115
+
116
+ /** What a stored message reads when it has no text of its own and nothing the
117
+ * host added, so the agent still sees that a message was there. */
118
+ const EMPTY_MESSAGE = '[Empty message]';
119
+
120
+ /**
121
+ * Metadata on a stored Discord message whose first block is its own text,
122
+ * '' when it has none, and every block after it the host's: images, inlined
123
+ * file text, attachment notes and EMPTY_MESSAGE. An edit replaces content and
124
+ * can't touch metadata, so the mark holds for the row's life, and it tells an
125
+ * edit or a sync which block is Discord's to replace. For the same reason a
126
+ * row stored before the mark never gets it, even once a history sync
127
+ * rebuilds it in this layout. The request builder drops an empty text block,
128
+ * as it does wherever one occurs.
129
+ */
130
+ const TEXT_FIRST = 'discordTextFirst';
131
+
132
+ /** A message's own text as a stored row holds it: '' when it's blank. */
133
+ function ownText(content: string): string {
134
+ return content.trim() ? content : '';
135
+ }
136
+
137
+ const isEmptyMarker = (block: ContentBlock): boolean => block.type === 'text' && block.text === EMPTY_MESSAGE;
138
+ const isBlankText = (block: ContentBlock): boolean => block.type === 'text' && !block.text.trim();
139
+
140
+ /**
141
+ * A text-first row's content: the message's own text, '' when it has none,
142
+ * then `after`, what the host added; EMPTY_MESSAGE when there's neither.
143
+ */
144
+ function textFirst(text: string, after: ContentBlock[] = []): ContentBlock[] {
145
+ return [{ type: 'text', text }, ...(text || after.length > 0 ? after : [{ type: 'text' as const, text: EMPTY_MESSAGE }])];
146
+ }
147
+
148
+ /** A text-first row's content with `text` as the message's own text, in
149
+ * place of its first block, keeping what the host added after it. */
150
+ function withOwnText(content: ContentBlock[], text: string): ContentBlock[] {
151
+ return textFirst(ownText(text), content.slice(1).filter((block) => !isEmptyMarker(block)));
152
+ }
153
+
154
+ /**
155
+ * The content a stored Discord message should hold once Discord's text for it
156
+ * is `discordText`, or null when it holds that already.
157
+ *
158
+ * A text-first row keeps every block the host added and replaces only its own
159
+ * text; EMPTY_MESSAGE goes once there is text, and comes back when nothing is
160
+ * left. A row stored before that layout held its own text first when it had
161
+ * any, but a message without text began with what the host added, which may
162
+ * be text, a file's contents or a note, so its first block can't be told
163
+ * apart. Such a row is left alone unless Discord's text is there and differs
164
+ * from its first block, and then that text takes the first block's place
165
+ * when it's text, and goes before it when it isn't, and EMPTY_MESSAGE goes.
166
+ * So a message without text, stored beginning with a file's contents or a
167
+ * note, loses that block. The history sync, which has the message's
168
+ * attachments, rebuilds such a row instead (needsRebuild).
169
+ */
170
+ function contentForText(stored: StoredMessage, discordText: string): ContentBlock[] | null {
171
+ const text = ownText(discordText);
172
+ const [first, ...rest] = stored.content;
173
+ if (stored.metadata?.[TEXT_FIRST] === true) {
174
+ if (first?.type === 'text' && first.text === text) return null;
175
+ return withOwnText(stored.content, text);
176
+ }
177
+ if (!text || (first?.type === 'text' && first.text === discordText)) return null;
178
+ return [{ type: 'text', text: discordText }, ...(first?.type === 'text' ? rest : stored.content).filter((block) => !isEmptyMarker(block))];
179
+ }
180
+
181
+ /**
182
+ * Whether a stored row lacks or holds more than the live conversion gives
183
+ * Discord's `message` now, its own text aside, so the history sync stores it
184
+ * through that conversion again. The conversion gives each attachment one
185
+ * block: an image, a file's text, or a note when it isn't fetched or isn't
186
+ * read. So a text-first row holds one block per attachment after its text,
187
+ * EMPTY_MESSAGE aside, which the text's rule keeps. A row stored before that
188
+ * layout held its text, when it had any, then those blocks, or EMPTY_MESSAGE
189
+ * alone; one that doesn't was blanked or stripped by an earlier edit or sync,
190
+ * or its message gained or lost text, or lost an attachment. Its first block,
191
+ * when it is the message's own text, counts as that text, even when the text
192
+ * reads as EMPTY_MESSAGE. For a message without text of its own, a first
193
+ * block that's text may be what the host added or a caption the message has
194
+ * since lost, which no count tells apart, so that row is stored again; it
195
+ * then begins with its own '' text. One whose text alone changed is left to
196
+ * the text's rule, which keeps the blocks after it. History without
197
+ * attachments can't be compared, so it rebuilds nothing.
198
+ */
199
+ function needsRebuild(stored: StoredMessage, message: HistoryMessage): boolean {
200
+ if (message.attachments === undefined) return false;
201
+ const attachments = message.attachments.length;
202
+ const held = (blocks: ContentBlock[]) => blocks.filter((block) => !isBlankText(block) && !isEmptyMarker(block)).length;
203
+ if (stored.metadata?.[TEXT_FIRST] === true) return held(stored.content.slice(1)) !== attachments;
204
+ const own = ownText(message.content);
205
+ const [first, ...rest] = stored.content;
206
+ if (!own && first?.type === 'text' && !isBlankText(first) && !isEmptyMarker(first)) return true;
207
+ const expected = (own ? 1 : 0) + attachments;
208
+ const counted = own && first?.type === 'text' && first.text === own ? 1 + held(rest) : held(stored.content);
209
+ return counted !== expected || (expected === 0 && !stored.content.some(isEmptyMarker));
210
+ }
211
+
212
+ /**
213
+ * Whether a row holds non-blank text besides its message's own text now,
214
+ * which may be what a file gave. A marked row whose message's text changed
215
+ * counts its old text here too, which can delay its rebuild until a fetch
216
+ * succeeds but never loses text.
217
+ */
218
+ function holdsOtherText(stored: StoredMessage, message: HistoryMessage): boolean {
219
+ const own = ownText(message.content);
220
+ const [first, ...rest] = stored.content;
221
+ const others = own && first?.type === 'text' && first.text === own ? rest : stored.content;
222
+ return others.some((block) => block.type === 'text' && !isBlankText(block) && !isEmptyMarker(block));
223
+ }
224
+
225
+ /** Whether a message's conversion holds, after the message's own text, the
226
+ * note for an attachment of its whose text wasn't fetched. */
227
+ function holdsNotFetched(content: ContentBlock[], message: HistoryMessage): boolean {
228
+ const notes = new Set((message.attachments ?? []).map((attachment) => attachmentNotFetched(attachment.filename).text));
229
+ return content.slice(1).some((block) => block.type === 'text' && notes.has(block.text));
230
+ }
231
+
96
232
  /**
97
233
  * Discord module for the agent framework.
98
234
  */
@@ -113,8 +249,25 @@ export class DiscordModule implements Module {
113
249
  // Track current reply context per agent
114
250
  private replyContexts: Map<string, ConversationContext> = new Map();
115
251
 
116
- // Last message sent by a tool (for thought-editing)
117
- private lastSentMessage: { channelId: string; messageId: string } | null = null;
252
+ // Where a tool turn's thoughts go (onAgentSpeech edits them in as a
253
+ // spoiler): each agent's latest message posted in a turn, with that turn's
254
+ // id (notePost). A `send` or `reply` records the message its client call
255
+ // returns, and so does the module's own speech. Thoughts go into it only
256
+ // when their speech ends the same turn, and taking them removes it. So
257
+ // neither another agent's message nor one from an earlier turn takes them,
258
+ // and an attempt in the turn that is refused or throws leaves the turn's own
259
+ // post in place. Turn ids increase, so an earlier turn's post that finishes
260
+ // after a later turn's leaves the later one in place. A DM records nothing,
261
+ // since its channel isn't known here, and neither does a post whose call or
262
+ // speech carries no turn. An entry goes when its thoughts are taken, when
263
+ // the agent's next post replaces it, or past MAX_LAST_POSTS agents.
264
+ private lastPosts: Map<string, { turnId: number; channelId: string; messageId: string }> = new Map();
265
+
266
+ // One set per running history sync: the Discord messages the live path
267
+ // stored, edited or was told were deleted since that sync began. What the
268
+ // live path saw is newer than what the sync fetched, so the sync leaves
269
+ // those messages alone.
270
+ private readonly liveDuringSync = new Set<Set<string>>();
118
271
 
119
272
  // Typing keepalive: agentName -> { interval, deadline }. Started on
120
273
  // inference:started, stopped on the turn's terminal trace event. Discord's
@@ -404,7 +557,7 @@ export class DiscordModule implements Module {
404
557
  },
405
558
  {
406
559
  name: 'fetch_history',
407
- description: 'Fetch recent message history from a channel',
560
+ description: 'Fetch recent message history from a channel. A message with attachments lists each one\'s filename, type and size; their contents aren\'t included.',
408
561
  inputSchema: {
409
562
  type: 'object',
410
563
  properties: {
@@ -422,11 +575,11 @@ export class DiscordModule implements Module {
422
575
  try {
423
576
  switch (call.name) {
424
577
  case 'send':
425
- return await this.handleSend(call.input as SendInput);
578
+ return await this.handleSend(call.input as SendInput, call);
426
579
  case 'dm':
427
580
  return await this.handleDM(call.input as SendDMInput);
428
581
  case 'reply':
429
- return await this.handleReply(call.input as ReplyInput);
582
+ return await this.handleReply(call.input as ReplyInput, call);
430
583
  case 'react':
431
584
  return await this.handleReact(call.input as ReactInput);
432
585
  case 'edit':
@@ -507,8 +660,10 @@ export class DiscordModule implements Module {
507
660
  });
508
661
  }
509
662
 
510
- // Build content blocks from message and attachments
511
- const contentBlocks = msg.contentBlocks ?? [{ type: 'text' as const, text: msg.content }];
663
+ // Built from the message and its attachments, or from its text alone
664
+ // when an event carries no blocks; text first, as TEXT_FIRST marks.
665
+ const contentBlocks = msg.contentBlocks ?? textFirst(ownText(msg.content));
666
+ this.noteLive(msg.discordMessageId);
512
667
 
513
668
  // Return declarative response - framework applies all writes atomically
514
669
  return {
@@ -520,6 +675,7 @@ export class DiscordModule implements Module {
520
675
  external: { source: 'discord', id: msg.discordMessageId },
521
676
  channelId: msg.channelId,
522
677
  timestamp: msg.timestamp,
678
+ [TEXT_FIRST]: true,
523
679
  },
524
680
  },
525
681
  ],
@@ -531,29 +687,41 @@ export class DiscordModule implements Module {
531
687
  // Handle Discord message edit
532
688
  if (event.type === 'discord:edit') {
533
689
  const edit = event as DiscordEditEvent;
534
- const internalId = state.findMessageByExternalId('discord', edit.discordMessageId);
535
- if (!internalId) {
690
+ // The stored row, not only its id: an edit changes the message's own
691
+ // text and keeps what the host added beside it.
692
+ // An edit to a message nobody has stored yet is dropped: whatever
693
+ // stores the message, its live add or a history sync running now,
694
+ // stores the text it got, and the next sync's text rule changes it.
695
+ // A row stored in shards can't be edited one shard at a time, so it
696
+ // keeps its text, and the host's log says so. Only an edit that writes
697
+ // marks the message live, so an update that changes nothing leaves a
698
+ // running sync free to rewrite the row.
699
+ const stored = this.storedRow(edit.discordMessageId);
700
+ if (!stored) return {};
701
+ if (stored.bodyGroupId) {
702
+ console.warn(`Discord: An update to message ${edit.discordMessageId} wasn't applied: it's stored in shards, which can't be edited, so if its text changed, the agent still has the earlier text`);
536
703
  return {};
537
704
  }
538
- return {
539
- editMessages: [
540
- {
541
- messageId: internalId,
542
- content: [{ type: 'text', text: edit.newContent }],
543
- },
544
- ],
545
- };
705
+ const content = contentForText(stored, edit.newContent);
706
+ if (!content) return {};
707
+ this.noteLive(edit.discordMessageId);
708
+ return { editMessages: [{ messageId: stored.id, content }] };
546
709
  }
547
710
 
548
711
  // Handle Discord message delete
549
712
  if (event.type === 'discord:delete') {
550
713
  const del = event as DiscordDeleteEvent;
551
- const internalId = state.findMessageByExternalId('discord', del.discordMessageId);
552
- if (!internalId) {
714
+ // A row stored in shards is removed whole: the framework takes out the
715
+ // body a shard belongs to. The message is the live path's even when no
716
+ // row is found, so a running sync doesn't store what its fetch may
717
+ // still hold.
718
+ this.noteLive(del.discordMessageId);
719
+ const stored = this.storedRow(del.discordMessageId);
720
+ if (!stored) {
553
721
  return {};
554
722
  }
555
723
  return {
556
- removeMessages: [internalId],
724
+ removeMessages: [stored.id],
557
725
  };
558
726
  }
559
727
 
@@ -568,13 +736,15 @@ export class DiscordModule implements Module {
568
736
  content: ContentBlock[],
569
737
  context: SpeechContext
570
738
  ): Promise<void> {
571
- // If thoughts are present and we have a recently sent message, edit it
572
- // to prepend the thoughts as spoiler text.
573
- if (context.thoughts && context.thoughts.length > 0 && this.lastSentMessage) {
739
+ // If thoughts are present and this agent posted a message in the turn
740
+ // they end (lastPosts), edit it to prepend the thoughts as spoiler text.
741
+ const post = this.lastPosts.get(agentName);
742
+ if (context.thoughts && context.thoughts.length > 0 && post && post.turnId === context.turnId) {
743
+ this.lastPosts.delete(agentName);
574
744
  const thoughtText = this.extractText(context.thoughts);
575
745
  if (thoughtText) {
576
746
  try {
577
- const { channelId, messageId } = this.lastSentMessage;
747
+ const { channelId, messageId } = post;
578
748
  // Fetch the current message content via the client isn't available,
579
749
  // but we know the tool just sent it — reconstruct by editing with
580
750
  // spoiler-wrapped thoughts prepended.
@@ -586,7 +756,6 @@ export class DiscordModule implements Module {
586
756
  console.warn('Discord: Failed to edit thoughts into message:', err);
587
757
  }
588
758
  }
589
- this.lastSentMessage = null;
590
759
  }
591
760
 
592
761
  // Get reply context for this agent
@@ -615,8 +784,8 @@ export class DiscordModule implements Module {
615
784
  replyTo: replyCtx.replyToMessageId,
616
785
  });
617
786
 
618
- // Track for thought-editing (in case of chained speech)
619
- this.lastSentMessage = { channelId: targetChannel, messageId: result.messageId };
787
+ // Track for thought-editing (in case of chained speech in the same turn)
788
+ this.notePost(agentName, context.turnId, targetChannel, result.messageId);
620
789
 
621
790
  // Clear reply-to after sending (don't keep replying to same message)
622
791
  replyCtx.replyToMessageId = undefined;
@@ -722,131 +891,176 @@ export class DiscordModule implements Module {
722
891
  /**
723
892
  * Sync history for a specific channel - compare with Context Manager and update.
724
893
  * Uses queryMessages() to enumerate stored messages for proper edit/delete detection.
894
+ *
895
+ * The live path can store, edit or remove a row whenever the sync awaits.
896
+ * So the sync fetches history and runs the live conversion it needs first,
897
+ * then reads the store again and writes with no await between that read
898
+ * and its writes. It leaves alone any message the live path stored,
899
+ * changed or was told was deleted while it ran (liveDuringSync), an update
900
+ * that changed nothing aside. A live edit to a message nobody had stored
901
+ * yet is dropped, so a message the sync stores holds the text it fetched
902
+ * until the next sync's text rule changes it. The framework writes an
903
+ * event's response only once every module has processed the event, so an
904
+ * event processed before the sync began can still be written after the
905
+ * sync's own writes, which this doesn't cover.
725
906
  */
726
907
  private async syncChannelHistory(channelId: string): Promise<{
727
908
  newMessages: number;
728
909
  editedMessages: number;
729
910
  deletedMessages: number;
730
911
  }> {
731
- if (!this.ctx) {
732
- return { newMessages: 0, editedMessages: 0, deletedMessages: 0 };
912
+ const unchanged = { newMessages: 0, editedMessages: 0, deletedMessages: 0 };
913
+ const ctx = this.ctx;
914
+ if (!ctx) {
915
+ return unchanged;
733
916
  }
734
-
735
- const scrollback = this.config.historyScrollback ?? 50;
736
-
737
- // Fetch recent history from Discord
738
- const discordMessages = await this.client.fetchHistory(channelId, { limit: scrollback });
739
-
740
- // Build a map of Discord message ID -> content for comparison
741
- const discordMessageMap = new Map<string, { content: string; authorName: string; timestamp: Date }>();
742
- for (const msg of discordMessages) {
743
- discordMessageMap.set(msg.id, {
744
- content: msg.content,
745
- authorName: msg.authorName,
746
- timestamp: msg.timestamp,
747
- });
748
- }
749
-
750
- // Query Context Manager for all Discord messages from this channel
751
- const { messages: storedMessages } = this.ctx.queryMessages({
752
- source: 'discord',
753
- metadata: { channelId },
754
- });
755
-
756
- // Build a map of stored message external IDs -> internal data
757
- const storedMessageMap = new Map<string, { internalId: string; content: string; sourceTimestamp?: number }>();
758
- for (const msg of storedMessages) {
759
- const external = msg.metadata?.external as { id?: string } | undefined;
760
- if (external?.id) {
761
- // Extract text content for comparison
762
- const textContent = msg.content
763
- .filter((block): block is { type: 'text'; text: string } => block.type === 'text')
764
- .map((block) => block.text)
765
- .join('\n');
766
- storedMessageMap.set(external.id, {
767
- internalId: msg.id,
768
- content: textContent,
769
- sourceTimestamp: typeof msg.metadata?.timestamp === 'number'
770
- ? msg.metadata.timestamp
771
- : undefined,
772
- });
917
+ const live = new Set<string>();
918
+ this.liveDuringSync.add(live);
919
+ try {
920
+ const scrollback = this.config.historyScrollback ?? 50;
921
+ // The rows stored as the sync begins. One that is gone by the time it
922
+ // writes was removed meanwhile, and isn't the sync's to bring back.
923
+ const before = this.storedByDiscordId(ctx, channelId);
924
+
925
+ // Fetch recent history from Discord. If the module stopped or restarted
926
+ // meanwhile, this sync's context is gone and it writes nothing.
927
+ const discordMessages = await this.client.fetchHistory(channelId, { limit: scrollback });
928
+ if (this.ctx !== ctx) return unchanged;
929
+
930
+ // Discord's ids, for delete detection inside the fetched window.
931
+ const discordIds = new Set(discordMessages.map((msg) => msg.id));
932
+
933
+ // Discord history is newest-first, while addMessage appends to the stored
934
+ // conversation. Process oldest-first so missed messages retain chronology.
935
+ const chronologicalMessages = [...discordMessages].reverse();
936
+
937
+ // The live conversion, which fetches attachments, for a message the
938
+ // store lacks and for a row that doesn't hold what the conversion gives
939
+ // the message now (needsRebuild). A row stored in shards can't be
940
+ // edited one shard at a time, so it's left as it is.
941
+ const converted = new Map<string, ContentBlock[]>();
942
+ for (const discordMsg of chronologicalMessages) {
943
+ const stored = before.get(discordMsg.id);
944
+ if (stored && (stored.bodyGroupId || !needsRebuild(stored, discordMsg))) continue;
945
+ const content = await this.convertMessageToContent(discordMsg);
946
+ if (this.ctx !== ctx) return unchanged;
947
+ // A failed fetch never costs a row the text it holds: when a file
948
+ // wasn't fetched, a row holding other text, which may be that file's,
949
+ // keeps what it holds, and the next sync tries again.
950
+ if (stored && holdsNotFetched(content, discordMsg) && holdsOtherText(stored, discordMsg)) continue;
951
+ converted.set(discordMsg.id, content);
773
952
  }
774
- }
775
953
 
776
- let newMessages = 0;
777
- let editedMessages = 0;
778
- let deletedMessages = 0;
779
-
780
- // Discord history is newest-first, while addMessage appends to the stored
781
- // conversation. Process oldest-first so missed messages retain chronology.
782
- const chronologicalMessages = [...discordMessages].reverse();
783
- for (const discordMsg of chronologicalMessages) {
784
- const stored = storedMessageMap.get(discordMsg.id);
785
-
786
- if (!stored) {
787
- // New message we haven't seen
788
- // For bot's own messages (from previous sessions), use the agent name
789
- // This ensures continuity of conversation history
790
- const isBotMessage = discordMsg.authorId === this.state.botUserId;
791
- const agentName = this.ctx.getAgents()[0]?.name;
792
- const participantName = isBotMessage
793
- ? (agentName ?? discordMsg.authorName)
794
- : discordMsg.authorName;
795
-
796
- this.ctx.addMessage(
797
- participantName,
798
- [{ type: 'text', text: discordMsg.content }],
799
- {
800
- external: { source: 'discord', id: discordMsg.id },
801
- channelId,
802
- timestamp: discordMsg.timestamp.getTime(),
803
- isOwnMessage: isBotMessage, // Mark as our own for reference
954
+ // From here on nothing awaits, so the rows read now are the rows written.
955
+ const storedMessageMap = this.storedByDiscordId(ctx, channelId);
956
+ let newMessages = 0;
957
+ let editedMessages = 0;
958
+ let deletedMessages = 0;
959
+ for (const discordMsg of chronologicalMessages) {
960
+ if (live.has(discordMsg.id)) continue;
961
+ const stored = storedMessageMap.get(discordMsg.id);
962
+
963
+ if (!stored) {
964
+ // A message we haven't stored. One that was stored when the sync
965
+ // began, and isn't now, was removed meanwhile: not the sync's to
966
+ // bring back.
967
+ const content = converted.get(discordMsg.id);
968
+ if (!content || before.has(discordMsg.id)) continue;
969
+ // For bot's own messages (from previous sessions), use the agent name
970
+ // This ensures continuity of conversation history
971
+ const isBotMessage = discordMsg.authorId === this.state.botUserId;
972
+ const agentName = ctx.getAgents()[0]?.name;
973
+ const participantName = isBotMessage
974
+ ? (agentName ?? discordMsg.authorName)
975
+ : discordMsg.authorName;
976
+ ctx.addMessage(
977
+ participantName,
978
+ content,
979
+ {
980
+ external: { source: 'discord', id: discordMsg.id },
981
+ channelId,
982
+ timestamp: discordMsg.timestamp.getTime(),
983
+ isOwnMessage: isBotMessage, // Mark as our own for reference
984
+ [TEXT_FIRST]: true,
985
+ }
986
+ );
987
+ newMessages++;
988
+ } else if (!stored.bodyGroupId) {
989
+ // We have this message - check whether it changed (offline edit detection)
990
+ const content = needsRebuild(stored, discordMsg)
991
+ ? converted.get(discordMsg.id)
992
+ : contentForText(stored, discordMsg.content);
993
+ if (content) {
994
+ ctx.editMessage(stored.id, content);
995
+ editedMessages++;
804
996
  }
997
+ }
998
+ }
999
+
1000
+ // Check for deletes only inside the history we actually fetched. A short
1001
+ // response covers complete available history; a full page has an older
1002
+ // boundary whose tied millisecond must be preserved.
1003
+ const fetchedCompleteHistory = discordMessages.length < scrollback;
1004
+ const oldestFetchedTimestamp = discordMessages.length > 0
1005
+ ? Math.min(...discordMessages.map((msg) => msg.timestamp.getTime()))
1006
+ : undefined;
1007
+ for (const [externalId, stored] of storedMessageMap) {
1008
+ const sourceTimestamp = typeof stored.metadata?.timestamp === 'number'
1009
+ ? stored.metadata.timestamp
1010
+ : undefined;
1011
+ const isInsideFetchedWindow = fetchedCompleteHistory || (
1012
+ sourceTimestamp !== undefined &&
1013
+ oldestFetchedTimestamp !== undefined &&
1014
+ // Discord timestamps are millisecond-precise, so an older message just
1015
+ // beyond the page can tie the oldest fetched timestamp. Preserve ties
1016
+ // rather than guessing that an unseen boundary message was deleted.
1017
+ sourceTimestamp > oldestFetchedTimestamp
805
1018
  );
806
- newMessages++;
807
- } else {
808
- // We have this message - check if content changed (offline edit detection)
809
- if (stored.content !== discordMsg.content) {
810
- this.ctx.editMessage(stored.internalId, [
811
- { type: 'text', text: discordMsg.content },
812
- ]);
813
- editedMessages++;
1019
+ if (isInsideFetchedWindow && !discordIds.has(externalId) && !live.has(externalId)) {
1020
+ // Message exists in our store but not in Discord - it was deleted
1021
+ // Note: This only catches deletes within the scrollback window.
1022
+ // A message the live path wrote while the sync ran is newer than
1023
+ // the fetch, so it stays. One shard's id takes out a body whole.
1024
+ ctx.removeMessage(stored.id);
1025
+ deletedMessages++;
814
1026
  }
815
1027
  }
816
- }
817
1028
 
818
- // Check for deletes only inside the history we actually fetched. A short
819
- // response covers complete available history; a full page has an older
820
- // boundary whose tied millisecond must be preserved.
821
- const fetchedCompleteHistory = discordMessages.length < scrollback;
822
- const oldestFetchedTimestamp = discordMessages.length > 0
823
- ? Math.min(...discordMessages.map((msg) => msg.timestamp.getTime()))
824
- : undefined;
825
- for (const [externalId, stored] of storedMessageMap) {
826
- const isInsideFetchedWindow = fetchedCompleteHistory || (
827
- stored.sourceTimestamp !== undefined &&
828
- oldestFetchedTimestamp !== undefined &&
829
- // Discord timestamps are millisecond-precise, so an older message just
830
- // beyond the page can tie the oldest fetched timestamp. Preserve ties
831
- // rather than guessing that an unseen boundary message was deleted.
832
- stored.sourceTimestamp > oldestFetchedTimestamp
833
- );
834
- if (isInsideFetchedWindow && !discordMessageMap.has(externalId)) {
835
- // Message exists in our store but not in Discord - it was deleted
836
- // Note: This only catches deletes within the scrollback window
837
- this.ctx.removeMessage(stored.internalId);
838
- deletedMessages++;
1029
+ // Update last read
1030
+ if (discordMessages.length > 0) {
1031
+ // Messages are typically newest first
1032
+ const newestId = discordMessages[0].id;
1033
+ this.state.lastReadMessageId[channelId] = newestId;
839
1034
  }
1035
+
1036
+ return { newMessages, editedMessages, deletedMessages };
1037
+ } finally {
1038
+ this.liveDuringSync.delete(live);
840
1039
  }
1040
+ }
841
1041
 
842
- // Update last read
843
- if (discordMessages.length > 0) {
844
- // Messages are typically newest first
845
- const newestId = discordMessages[0].id;
846
- this.state.lastReadMessageId[channelId] = newestId;
1042
+ /** A channel's stored Discord rows by their Discord message id, whole: an
1043
+ * edit replaces a row's own text and keeps what the host added beside it. */
1044
+ private storedByDiscordId(ctx: ModuleContext, channelId: string): Map<string, StoredMessage> {
1045
+ const rows = new Map<string, StoredMessage>();
1046
+ for (const msg of ctx.queryMessages({ source: 'discord', metadata: { channelId } }).messages) {
1047
+ const external = msg.metadata?.external as { id?: string } | undefined;
1048
+ if (external?.id) rows.set(external.id, msg);
847
1049
  }
1050
+ return rows;
1051
+ }
1052
+
1053
+ /** The stored row of a Discord message, by its id in the row's metadata.
1054
+ * The module context's findMessageByExternalId holds only rows the module
1055
+ * stored through its context, not those a process response added, so it
1056
+ * misses what the live path stored. */
1057
+ private storedRow(discordMessageId: string): StoredMessage | undefined {
1058
+ return this.ctx?.queryMessages({ source: 'discord', externalIds: [discordMessageId] }).messages[0];
1059
+ }
848
1060
 
849
- return { newMessages, editedMessages, deletedMessages };
1061
+ /** Marks a Discord message as the live path's for every history sync running now. */
1062
+ private noteLive(discordMessageId: string): void {
1063
+ for (const live of this.liveDuringSync) live.add(discordMessageId);
850
1064
  }
851
1065
 
852
1066
  private async handleDiscordMessage(message: DiscordMessageData): Promise<void> {
@@ -905,19 +1119,18 @@ export class DiscordModule implements Module {
905
1119
  }
906
1120
 
907
1121
  /**
908
- * Convert Discord message to ContentBlock array.
909
- * Includes text content and any supported attachments (images, text files).
1122
+ * Convert a Discord message, live or from history, to ContentBlock array:
1123
+ * its own text first, '' when it has none, then any supported attachments
1124
+ * (images, text files) and notes for the rest, as TEXT_FIRST marks.
910
1125
  */
911
- private async convertMessageToContent(message: DiscordMessageData): Promise<ContentBlock[]> {
1126
+ private async convertMessageToContent(
1127
+ message: { id: string; content: string; attachments?: readonly DiscordAttachment[] },
1128
+ ): Promise<ContentBlock[]> {
1129
+ // What the host adds after the message's own text: one block per attachment.
912
1130
  const blocks: ContentBlock[] = [];
913
1131
 
914
- // Add text content if present
915
- if (message.content.trim()) {
916
- blocks.push({ type: 'text', text: message.content });
917
- }
918
-
919
1132
  // Process attachments
920
- for (const attachment of message.attachments) {
1133
+ for (const attachment of message.attachments ?? []) {
921
1134
  const contentType = attachment.contentType?.toLowerCase() ?? '';
922
1135
  const filename = attachment.filename.toLowerCase();
923
1136
 
@@ -944,13 +1157,15 @@ export class DiscordModule implements Module {
944
1157
  type: 'text',
945
1158
  text: `\n--- File: ${attachment.filename} ---\n${textContent}\n--- End of ${attachment.filename} ---\n`,
946
1159
  });
1160
+ } else {
1161
+ // An answer whose body is never read holds its connection.
1162
+ await response.body?.cancel().catch(() => {});
1163
+ console.warn(`Discord: Attachment ${logValue(attachment.filename)} in message ${message.id} wasn't fetched: HTTP ${response.status}`);
1164
+ blocks.push(attachmentNotFetched(attachment.filename));
947
1165
  }
948
1166
  } catch (error) {
949
- // If fetch fails, just note the attachment
950
- blocks.push({
951
- type: 'text',
952
- text: `[Attachment: ${attachment.filename} (failed to fetch)]`,
953
- });
1167
+ console.warn(`Discord: Attachment ${logValue(attachment.filename)} in message ${message.id} wasn't fetched:`, error);
1168
+ blocks.push(attachmentNotFetched(attachment.filename));
954
1169
  }
955
1170
  continue;
956
1171
  }
@@ -962,12 +1177,7 @@ export class DiscordModule implements Module {
962
1177
  });
963
1178
  }
964
1179
 
965
- // Ensure we have at least empty text if nothing else
966
- if (blocks.length === 0) {
967
- blocks.push({ type: 'text', text: '[Empty message]' });
968
- }
969
-
970
- return blocks;
1180
+ return textFirst(ownText(message.content), blocks);
971
1181
  }
972
1182
 
973
1183
  /**
@@ -1035,7 +1245,23 @@ export class DiscordModule implements Module {
1035
1245
  // Tool Handlers
1036
1246
  // ==========================================================================
1037
1247
 
1038
- private async handleSend(input: SendInput): Promise<ToolResult> {
1248
+ /** Record a message the agent posted in a turn, for that turn's thoughts (lastPosts). */
1249
+ private notePost(agentName: string | undefined, turnId: number | undefined, channelId: string, messageId: string): void {
1250
+ if (agentName === undefined || turnId === undefined) return;
1251
+ // A later turn's post stays: this one's turn has ended, and its thoughts
1252
+ // have gone or will go nowhere.
1253
+ const current = this.lastPosts.get(agentName);
1254
+ if (current && current.turnId > turnId) return;
1255
+ // Set it last, so the entry recorded longest ago is the first to go.
1256
+ this.lastPosts.delete(agentName);
1257
+ this.lastPosts.set(agentName, { turnId, channelId, messageId });
1258
+ if (this.lastPosts.size > MAX_LAST_POSTS) {
1259
+ const oldest = this.lastPosts.keys().next().value;
1260
+ if (oldest !== undefined) this.lastPosts.delete(oldest);
1261
+ }
1262
+ }
1263
+
1264
+ private async handleSend(input: SendInput, call: ToolCall): Promise<ToolResult> {
1039
1265
  if (!this.checkRateLimit(input.channelId)) {
1040
1266
  return { success: false, error: 'Rate limited', isError: true };
1041
1267
  }
@@ -1045,9 +1271,13 @@ export class DiscordModule implements Module {
1045
1271
  createThread: input.createThread,
1046
1272
  });
1047
1273
 
1048
- // Track for thought-editing
1049
- this.lastSentMessage = { channelId: input.channelId, messageId: result.messageId };
1274
+ // Track for thought-editing: the message is out, whether or not its
1275
+ // thread was started.
1276
+ this.notePost(call.callerAgentName, call.callerTurnId, input.channelId, result.messageId);
1050
1277
 
1278
+ if (result.threadFailure !== undefined) {
1279
+ return { success: false, error: result.threadFailure, isError: true };
1280
+ }
1051
1281
  return { success: true, data: { messageId: result.messageId } };
1052
1282
  }
1053
1283
 
@@ -1056,7 +1286,7 @@ export class DiscordModule implements Module {
1056
1286
  return { success: true, data: { messageId: result.messageId } };
1057
1287
  }
1058
1288
 
1059
- private async handleReply(input: ReplyInput): Promise<ToolResult> {
1289
+ private async handleReply(input: ReplyInput, call: ToolCall): Promise<ToolResult> {
1060
1290
  const replyCtx = this.replyContexts.get('default');
1061
1291
  if (!replyCtx) {
1062
1292
  return { success: false, error: 'No conversation context', isError: true };
@@ -1077,7 +1307,7 @@ export class DiscordModule implements Module {
1077
1307
  });
1078
1308
 
1079
1309
  // Track for thought-editing
1080
- this.lastSentMessage = { channelId: targetChannel, messageId: result.messageId };
1310
+ this.notePost(call.callerAgentName, call.callerTurnId, targetChannel, result.messageId);
1081
1311
 
1082
1312
  // Clear reply-to after sending
1083
1313
  replyCtx.replyToMessageId = undefined;
@@ -1211,6 +1441,11 @@ export class DiscordModule implements Module {
1211
1441
  authorId: m.authorId,
1212
1442
  isBot: m.isBot,
1213
1443
  content: m.content,
1444
+ // Not their URLs: a link Discord signs works for anyone holding it
1445
+ // until it expires, and an agent could repeat it where others read.
1446
+ ...(m.attachments?.length
1447
+ ? { attachments: m.attachments.map(({ filename, contentType, size }) => ({ filename, contentType, size })) }
1448
+ : {}),
1214
1449
  timestamp: formatZonedDateTime(m.timestamp, this.timeZone),
1215
1450
  replyTo: m.replyTo,
1216
1451
  })),