@animalabs/agent-framework 0.22.2 → 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 (935) hide show
  1. package/README.md +3 -1
  2. package/dist/src/agent.d.ts +77 -12
  3. package/dist/src/agent.d.ts.map +1 -1
  4. package/dist/src/agent.js +136 -40
  5. package/dist/src/agent.js.map +1 -1
  6. package/dist/src/api/mcp-server-core.js +1 -1
  7. package/dist/src/api/mcp-server-core.js.map +1 -1
  8. package/dist/src/api/server.d.ts.map +1 -1
  9. package/dist/src/api/server.js +5 -1
  10. package/dist/src/api/server.js.map +1 -1
  11. package/dist/src/api/types.d.ts +1 -1
  12. package/dist/src/api/types.d.ts.map +1 -1
  13. package/dist/src/branch-names.d.ts +14 -0
  14. package/dist/src/branch-names.d.ts.map +1 -0
  15. package/dist/src/branch-names.js +22 -0
  16. package/dist/src/branch-names.js.map +1 -0
  17. package/dist/src/closest-names.d.ts +28 -0
  18. package/dist/src/closest-names.d.ts.map +1 -0
  19. package/dist/src/closest-names.js +98 -0
  20. package/dist/src/closest-names.js.map +1 -0
  21. package/dist/src/code-execution/py-runner.d.ts +16 -5
  22. package/dist/src/code-execution/py-runner.d.ts.map +1 -1
  23. package/dist/src/code-execution/py-runner.js +186 -74
  24. package/dist/src/code-execution/py-runner.js.map +1 -1
  25. package/dist/src/code-execution/runtime-py.d.ts.map +1 -1
  26. package/dist/src/code-execution/runtime-py.js +49 -3
  27. package/dist/src/code-execution/runtime-py.js.map +1 -1
  28. package/dist/src/code-execution/tool-definition.d.ts +12 -1
  29. package/dist/src/code-execution/tool-definition.d.ts.map +1 -1
  30. package/dist/src/code-execution/tool-definition.js +21 -3
  31. package/dist/src/code-execution/tool-definition.js.map +1 -1
  32. package/dist/src/config-checks.d.ts +28 -0
  33. package/dist/src/config-checks.d.ts.map +1 -0
  34. package/dist/src/config-checks.js +52 -0
  35. package/dist/src/config-checks.js.map +1 -0
  36. package/dist/src/deadline-timer.d.ts +21 -0
  37. package/dist/src/deadline-timer.d.ts.map +1 -0
  38. package/dist/src/deadline-timer.js +43 -0
  39. package/dist/src/deadline-timer.js.map +1 -0
  40. package/dist/src/error-message.d.ts +30 -0
  41. package/dist/src/error-message.d.ts.map +1 -0
  42. package/dist/src/error-message.js +50 -0
  43. package/dist/src/error-message.js.map +1 -0
  44. package/dist/src/framework.d.ts +828 -88
  45. package/dist/src/framework.d.ts.map +1 -1
  46. package/dist/src/framework.js +5011 -1326
  47. package/dist/src/framework.js.map +1 -1
  48. package/dist/src/gate/event-gate.d.ts +8 -0
  49. package/dist/src/gate/event-gate.d.ts.map +1 -1
  50. package/dist/src/gate/event-gate.js +27 -3
  51. package/dist/src/gate/event-gate.js.map +1 -1
  52. package/dist/src/index.d.ts +4 -2
  53. package/dist/src/index.d.ts.map +1 -1
  54. package/dist/src/index.js +4 -2
  55. package/dist/src/index.js.map +1 -1
  56. package/dist/src/mcpl/channel-registry.d.ts +144 -6
  57. package/dist/src/mcpl/channel-registry.d.ts.map +1 -1
  58. package/dist/src/mcpl/channel-registry.js +424 -263
  59. package/dist/src/mcpl/channel-registry.js.map +1 -1
  60. package/dist/src/mcpl/checkpoint-manager.d.ts +21 -1
  61. package/dist/src/mcpl/checkpoint-manager.d.ts.map +1 -1
  62. package/dist/src/mcpl/checkpoint-manager.js +91 -30
  63. package/dist/src/mcpl/checkpoint-manager.js.map +1 -1
  64. package/dist/src/mcpl/conversation-router.d.ts +19 -3
  65. package/dist/src/mcpl/conversation-router.d.ts.map +1 -1
  66. package/dist/src/mcpl/conversation-router.js +23 -8
  67. package/dist/src/mcpl/conversation-router.js.map +1 -1
  68. package/dist/src/mcpl/convert-block.d.ts +20 -0
  69. package/dist/src/mcpl/convert-block.d.ts.map +1 -0
  70. package/dist/src/mcpl/convert-block.js +89 -0
  71. package/dist/src/mcpl/convert-block.js.map +1 -0
  72. package/dist/src/mcpl/errors.d.ts +13 -0
  73. package/dist/src/mcpl/errors.d.ts.map +1 -1
  74. package/dist/src/mcpl/errors.js +28 -0
  75. package/dist/src/mcpl/errors.js.map +1 -1
  76. package/dist/src/mcpl/hook-orchestrator.d.ts +23 -0
  77. package/dist/src/mcpl/hook-orchestrator.d.ts.map +1 -1
  78. package/dist/src/mcpl/hook-orchestrator.js +83 -72
  79. package/dist/src/mcpl/hook-orchestrator.js.map +1 -1
  80. package/dist/src/mcpl/inbound-source.d.ts +114 -0
  81. package/dist/src/mcpl/inbound-source.d.ts.map +1 -0
  82. package/dist/src/mcpl/inbound-source.js +83 -0
  83. package/dist/src/mcpl/inbound-source.js.map +1 -0
  84. package/dist/src/mcpl/index.d.ts +3 -1
  85. package/dist/src/mcpl/index.d.ts.map +1 -1
  86. package/dist/src/mcpl/index.js +3 -1
  87. package/dist/src/mcpl/index.js.map +1 -1
  88. package/dist/src/mcpl/inference-router.d.ts +15 -11
  89. package/dist/src/mcpl/inference-router.d.ts.map +1 -1
  90. package/dist/src/mcpl/inference-router.js +153 -84
  91. package/dist/src/mcpl/inference-router.js.map +1 -1
  92. package/dist/src/mcpl/push-coalescer.d.ts +33 -11
  93. package/dist/src/mcpl/push-coalescer.d.ts.map +1 -1
  94. package/dist/src/mcpl/push-coalescer.js +52 -20
  95. package/dist/src/mcpl/push-coalescer.js.map +1 -1
  96. package/dist/src/mcpl/push-handler.d.ts +16 -9
  97. package/dist/src/mcpl/push-handler.d.ts.map +1 -1
  98. package/dist/src/mcpl/push-handler.js +18 -83
  99. package/dist/src/mcpl/push-handler.js.map +1 -1
  100. package/dist/src/mcpl/reference-fetcher.d.ts +14 -2
  101. package/dist/src/mcpl/reference-fetcher.d.ts.map +1 -1
  102. package/dist/src/mcpl/reference-fetcher.js +72 -30
  103. package/dist/src/mcpl/reference-fetcher.js.map +1 -1
  104. package/dist/src/mcpl/references.d.ts +47 -12
  105. package/dist/src/mcpl/references.d.ts.map +1 -1
  106. package/dist/src/mcpl/references.js +74 -21
  107. package/dist/src/mcpl/references.js.map +1 -1
  108. package/dist/src/mcpl/server-connection.d.ts +89 -10
  109. package/dist/src/mcpl/server-connection.d.ts.map +1 -1
  110. package/dist/src/mcpl/server-connection.js +405 -129
  111. package/dist/src/mcpl/server-connection.js.map +1 -1
  112. package/dist/src/mcpl/server-registry.d.ts +10 -1
  113. package/dist/src/mcpl/server-registry.d.ts.map +1 -1
  114. package/dist/src/mcpl/server-registry.js +14 -3
  115. package/dist/src/mcpl/server-registry.js.map +1 -1
  116. package/dist/src/mcpl/skip-reply-wake.d.ts +36 -0
  117. package/dist/src/mcpl/skip-reply-wake.d.ts.map +1 -0
  118. package/dist/src/mcpl/skip-reply-wake.js +55 -0
  119. package/dist/src/mcpl/skip-reply-wake.js.map +1 -0
  120. package/dist/src/mcpl/transport.d.ts +51 -2
  121. package/dist/src/mcpl/transport.d.ts.map +1 -1
  122. package/dist/src/mcpl/transport.js +114 -20
  123. package/dist/src/mcpl/transport.js.map +1 -1
  124. package/dist/src/mcpl/types.d.ts +14 -3
  125. package/dist/src/mcpl/types.d.ts.map +1 -1
  126. package/dist/src/mcpl/types.js.map +1 -1
  127. package/dist/src/mcpl/visible-content.d.ts +15 -0
  128. package/dist/src/mcpl/visible-content.d.ts.map +1 -1
  129. package/dist/src/mcpl/visible-content.js +25 -0
  130. package/dist/src/mcpl/visible-content.js.map +1 -1
  131. package/dist/src/module-registry.d.ts +19 -1
  132. package/dist/src/module-registry.d.ts.map +1 -1
  133. package/dist/src/module-registry.js +54 -25
  134. package/dist/src/module-registry.js.map +1 -1
  135. package/dist/src/modules/api/index.js +1 -1
  136. package/dist/src/modules/api/index.js.map +1 -1
  137. package/dist/src/modules/discord/discord-js-client.d.ts +1 -0
  138. package/dist/src/modules/discord/discord-js-client.d.ts.map +1 -1
  139. package/dist/src/modules/discord/discord-js-client.js +25 -9
  140. package/dist/src/modules/discord/discord-js-client.js.map +1 -1
  141. package/dist/src/modules/discord/index.d.ts +29 -3
  142. package/dist/src/modules/discord/index.d.ts.map +1 -1
  143. package/dist/src/modules/discord/index.js +379 -143
  144. package/dist/src/modules/discord/index.js.map +1 -1
  145. package/dist/src/modules/discord/types.d.ts +14 -1
  146. package/dist/src/modules/discord/types.d.ts.map +1 -1
  147. package/dist/src/modules/health/index.d.ts.map +1 -1
  148. package/dist/src/modules/health/index.js +2 -1
  149. package/dist/src/modules/health/index.js.map +1 -1
  150. package/dist/src/modules/history/index.d.ts +3 -1
  151. package/dist/src/modules/history/index.d.ts.map +1 -1
  152. package/dist/src/modules/history/index.js +359 -127
  153. package/dist/src/modules/history/index.js.map +1 -1
  154. package/dist/src/modules/history/semantic.d.ts +28 -1
  155. package/dist/src/modules/history/semantic.d.ts.map +1 -1
  156. package/dist/src/modules/history/semantic.js +177 -32
  157. package/dist/src/modules/history/semantic.js.map +1 -1
  158. package/dist/src/modules/unknown-tool.d.ts +10 -0
  159. package/dist/src/modules/unknown-tool.d.ts.map +1 -0
  160. package/dist/src/modules/unknown-tool.js +17 -0
  161. package/dist/src/modules/unknown-tool.js.map +1 -0
  162. package/dist/src/modules/workspace/disk-agreement.d.ts +32 -2
  163. package/dist/src/modules/workspace/disk-agreement.d.ts.map +1 -1
  164. package/dist/src/modules/workspace/disk-agreement.js +30 -2
  165. package/dist/src/modules/workspace/disk-agreement.js.map +1 -1
  166. package/dist/src/modules/workspace/effects.d.ts +64 -6
  167. package/dist/src/modules/workspace/effects.d.ts.map +1 -1
  168. package/dist/src/modules/workspace/effects.js +291 -44
  169. package/dist/src/modules/workspace/effects.js.map +1 -1
  170. package/dist/src/modules/workspace/index.d.ts +119 -23
  171. package/dist/src/modules/workspace/index.d.ts.map +1 -1
  172. package/dist/src/modules/workspace/index.js +793 -247
  173. package/dist/src/modules/workspace/index.js.map +1 -1
  174. package/dist/src/modules/workspace/observe.d.ts +75 -8
  175. package/dist/src/modules/workspace/observe.d.ts.map +1 -1
  176. package/dist/src/modules/workspace/observe.js +174 -14
  177. package/dist/src/modules/workspace/observe.js.map +1 -1
  178. package/dist/src/modules/workspace/reconcile.d.ts +58 -7
  179. package/dist/src/modules/workspace/reconcile.d.ts.map +1 -1
  180. package/dist/src/modules/workspace/reconcile.js +521 -56
  181. package/dist/src/modules/workspace/reconcile.js.map +1 -1
  182. package/dist/src/modules/workspace/types.d.ts +18 -4
  183. package/dist/src/modules/workspace/types.d.ts.map +1 -1
  184. package/dist/src/modules/workspace/types.js.map +1 -1
  185. package/dist/src/modules/workspace/watcher.d.ts +7 -2
  186. package/dist/src/modules/workspace/watcher.d.ts.map +1 -1
  187. package/dist/src/modules/workspace/watcher.js +28 -4
  188. package/dist/src/modules/workspace/watcher.js.map +1 -1
  189. package/dist/src/prose-drafts.d.ts +240 -0
  190. package/dist/src/prose-drafts.d.ts.map +1 -0
  191. package/dist/src/prose-drafts.js +362 -0
  192. package/dist/src/prose-drafts.js.map +1 -0
  193. package/dist/src/prose-segments.d.ts +21 -2
  194. package/dist/src/prose-segments.d.ts.map +1 -1
  195. package/dist/src/prose-segments.js +46 -9
  196. package/dist/src/prose-segments.js.map +1 -1
  197. package/dist/src/recovery/offline-branch.d.ts +1 -0
  198. package/dist/src/recovery/offline-branch.d.ts.map +1 -1
  199. package/dist/src/recovery/offline-branch.js +3 -1
  200. package/dist/src/recovery/offline-branch.js.map +1 -1
  201. package/dist/src/safe-slice.d.ts +5 -1
  202. package/dist/src/safe-slice.d.ts.map +1 -1
  203. package/dist/src/safe-slice.js +9 -1
  204. package/dist/src/safe-slice.js.map +1 -1
  205. package/dist/src/tool-image-ledger.d.ts +87 -19
  206. package/dist/src/tool-image-ledger.d.ts.map +1 -1
  207. package/dist/src/tool-image-ledger.js +135 -32
  208. package/dist/src/tool-image-ledger.js.map +1 -1
  209. package/dist/src/tool-presentation.d.ts +9 -0
  210. package/dist/src/tool-presentation.d.ts.map +1 -1
  211. package/dist/src/tool-presentation.js +257 -60
  212. package/dist/src/tool-presentation.js.map +1 -1
  213. package/dist/src/tool-result-guard.d.ts.map +1 -1
  214. package/dist/src/tool-result-guard.js +7 -10
  215. package/dist/src/tool-result-guard.js.map +1 -1
  216. package/dist/src/tool-result-history.d.ts +32 -3
  217. package/dist/src/tool-result-history.d.ts.map +1 -1
  218. package/dist/src/tool-result-history.js +106 -19
  219. package/dist/src/tool-result-history.js.map +1 -1
  220. package/dist/src/tune-out/coordinator.d.ts +25 -1
  221. package/dist/src/tune-out/coordinator.d.ts.map +1 -1
  222. package/dist/src/tune-out/coordinator.js +260 -65
  223. package/dist/src/tune-out/coordinator.js.map +1 -1
  224. package/dist/src/types/agent.d.ts +17 -5
  225. package/dist/src/types/agent.d.ts.map +1 -1
  226. package/dist/src/types/events.d.ts +17 -0
  227. package/dist/src/types/events.d.ts.map +1 -1
  228. package/dist/src/types/framework.d.ts +21 -5
  229. package/dist/src/types/framework.d.ts.map +1 -1
  230. package/dist/src/types/inference-log.d.ts +1 -1
  231. package/dist/src/types/inference-log.d.ts.map +1 -1
  232. package/dist/src/types/module.d.ts +23 -4
  233. package/dist/src/types/module.d.ts.map +1 -1
  234. package/dist/src/types/trace.d.ts +95 -6
  235. package/dist/src/types/trace.d.ts.map +1 -1
  236. package/dist/src/usage/usage-tracker.d.ts +5 -0
  237. package/dist/src/usage/usage-tracker.d.ts.map +1 -1
  238. package/dist/src/usage/usage-tracker.js +35 -8
  239. package/dist/src/usage/usage-tracker.js.map +1 -1
  240. package/package.json +3 -4
  241. package/src/agent.ts +162 -40
  242. package/src/api/mcp-server-core.ts +1 -1
  243. package/src/api/server.ts +4 -1
  244. package/src/api/types.ts +1 -1
  245. package/src/branch-names.ts +19 -0
  246. package/src/closest-names.ts +94 -0
  247. package/src/code-execution/py-runner.ts +200 -76
  248. package/src/code-execution/runtime-py.ts +49 -3
  249. package/src/code-execution/tool-definition.ts +28 -4
  250. package/src/config-checks.ts +48 -0
  251. package/src/deadline-timer.ts +44 -0
  252. package/src/error-message.ts +48 -0
  253. package/src/framework.ts +5352 -1388
  254. package/src/gate/event-gate.ts +28 -3
  255. package/src/index.ts +11 -2
  256. package/src/mcpl/channel-registry.ts +517 -286
  257. package/src/mcpl/checkpoint-manager.ts +104 -29
  258. package/src/mcpl/conversation-router.ts +28 -8
  259. package/src/mcpl/convert-block.ts +97 -0
  260. package/src/mcpl/errors.ts +28 -0
  261. package/src/mcpl/hook-orchestrator.ts +84 -77
  262. package/src/mcpl/inbound-source.ts +156 -0
  263. package/src/mcpl/index.ts +10 -1
  264. package/src/mcpl/inference-router.ts +174 -99
  265. package/src/mcpl/push-coalescer.ts +60 -24
  266. package/src/mcpl/push-handler.ts +20 -90
  267. package/src/mcpl/reference-fetcher.ts +71 -26
  268. package/src/mcpl/references.ts +81 -22
  269. package/src/mcpl/server-connection.ts +427 -132
  270. package/src/mcpl/server-registry.ts +15 -4
  271. package/src/mcpl/skip-reply-wake.ts +73 -0
  272. package/src/mcpl/transport.ts +120 -18
  273. package/src/mcpl/types.ts +14 -3
  274. package/src/mcpl/visible-content.ts +27 -0
  275. package/src/module-registry.ts +58 -23
  276. package/src/modules/api/index.ts +1 -1
  277. package/src/modules/discord/discord-js-client.ts +26 -10
  278. package/src/modules/discord/index.ts +391 -158
  279. package/src/modules/discord/types.ts +15 -2
  280. package/src/modules/health/index.ts +2 -1
  281. package/src/modules/history/index.ts +410 -120
  282. package/src/modules/history/semantic.ts +189 -32
  283. package/src/modules/unknown-tool.ts +16 -0
  284. package/src/modules/workspace/disk-agreement.ts +51 -3
  285. package/src/modules/workspace/effects.ts +279 -35
  286. package/src/modules/workspace/index.ts +810 -260
  287. package/src/modules/workspace/observe.ts +194 -20
  288. package/src/modules/workspace/reconcile.ts +619 -64
  289. package/src/modules/workspace/types.ts +18 -4
  290. package/src/modules/workspace/watcher.ts +27 -4
  291. package/src/prose-drafts.ts +481 -0
  292. package/src/prose-segments.ts +51 -8
  293. package/src/recovery/offline-branch.ts +4 -1
  294. package/src/safe-slice.ts +9 -1
  295. package/src/tool-image-ledger.ts +153 -34
  296. package/src/tool-presentation.ts +224 -40
  297. package/src/tool-result-guard.ts +7 -8
  298. package/src/tool-result-history.ts +124 -20
  299. package/src/tune-out/coordinator.ts +259 -65
  300. package/src/types/agent.ts +17 -7
  301. package/src/types/events.ts +17 -0
  302. package/src/types/framework.ts +21 -5
  303. package/src/types/inference-log.ts +1 -1
  304. package/src/types/module.ts +24 -4
  305. package/src/types/trace.ts +101 -6
  306. package/src/usage/usage-tracker.ts +32 -8
  307. package/dist/test/activation-request-sanitize.test.d.ts +0 -2
  308. package/dist/test/activation-request-sanitize.test.d.ts.map +0 -1
  309. package/dist/test/activation-request-sanitize.test.js +0 -89
  310. package/dist/test/activation-request-sanitize.test.js.map +0 -1
  311. package/dist/test/agent-cache-ttl.test.d.ts +0 -2
  312. package/dist/test/agent-cache-ttl.test.d.ts.map +0 -1
  313. package/dist/test/agent-cache-ttl.test.js +0 -41
  314. package/dist/test/agent-cache-ttl.test.js.map +0 -1
  315. package/dist/test/agent-runtime-settings.test.d.ts +0 -2
  316. package/dist/test/agent-runtime-settings.test.d.ts.map +0 -1
  317. package/dist/test/agent-runtime-settings.test.js +0 -1598
  318. package/dist/test/agent-runtime-settings.test.js.map +0 -1
  319. package/dist/test/api-admin-gate.test.d.ts +0 -2
  320. package/dist/test/api-admin-gate.test.d.ts.map +0 -1
  321. package/dist/test/api-admin-gate.test.js +0 -116
  322. package/dist/test/api-admin-gate.test.js.map +0 -1
  323. package/dist/test/assistant-persist-refusal.test.d.ts +0 -2
  324. package/dist/test/assistant-persist-refusal.test.d.ts.map +0 -1
  325. package/dist/test/assistant-persist-refusal.test.js +0 -63
  326. package/dist/test/assistant-persist-refusal.test.js.map +0 -1
  327. package/dist/test/batched-wake-locus.test.d.ts +0 -2
  328. package/dist/test/batched-wake-locus.test.d.ts.map +0 -1
  329. package/dist/test/batched-wake-locus.test.js +0 -166
  330. package/dist/test/batched-wake-locus.test.js.map +0 -1
  331. package/dist/test/busy-agent-scheduler.test.d.ts +0 -2
  332. package/dist/test/busy-agent-scheduler.test.d.ts.map +0 -1
  333. package/dist/test/busy-agent-scheduler.test.js +0 -92
  334. package/dist/test/busy-agent-scheduler.test.js.map +0 -1
  335. package/dist/test/channel-incoming-targeting.test.d.ts +0 -2
  336. package/dist/test/channel-incoming-targeting.test.d.ts.map +0 -1
  337. package/dist/test/channel-incoming-targeting.test.js +0 -81
  338. package/dist/test/channel-incoming-targeting.test.js.map +0 -1
  339. package/dist/test/channel-label-history.test.d.ts +0 -2
  340. package/dist/test/channel-label-history.test.d.ts.map +0 -1
  341. package/dist/test/channel-label-history.test.js +0 -424
  342. package/dist/test/channel-label-history.test.js.map +0 -1
  343. package/dist/test/channel-lifecycle-provenance.test.d.ts +0 -2
  344. package/dist/test/channel-lifecycle-provenance.test.d.ts.map +0 -1
  345. package/dist/test/channel-lifecycle-provenance.test.js +0 -47
  346. package/dist/test/channel-lifecycle-provenance.test.js.map +0 -1
  347. package/dist/test/channel-registry-routing.test.d.ts +0 -2
  348. package/dist/test/channel-registry-routing.test.d.ts.map +0 -1
  349. package/dist/test/channel-registry-routing.test.js +0 -446
  350. package/dist/test/channel-registry-routing.test.js.map +0 -1
  351. package/dist/test/channel-registry-typing.test.d.ts +0 -2
  352. package/dist/test/channel-registry-typing.test.d.ts.map +0 -1
  353. package/dist/test/channel-registry-typing.test.js +0 -91
  354. package/dist/test/channel-registry-typing.test.js.map +0 -1
  355. package/dist/test/channels-changed-respond-first.test.d.ts +0 -2
  356. package/dist/test/channels-changed-respond-first.test.d.ts.map +0 -1
  357. package/dist/test/channels-changed-respond-first.test.js +0 -74
  358. package/dist/test/channels-changed-respond-first.test.js.map +0 -1
  359. package/dist/test/checkpoint-attribution.test.d.ts +0 -2
  360. package/dist/test/checkpoint-attribution.test.d.ts.map +0 -1
  361. package/dist/test/checkpoint-attribution.test.js +0 -200
  362. package/dist/test/checkpoint-attribution.test.js.map +0 -1
  363. package/dist/test/code-execution.test.d.ts +0 -11
  364. package/dist/test/code-execution.test.d.ts.map +0 -1
  365. package/dist/test/code-execution.test.js +0 -1272
  366. package/dist/test/code-execution.test.js.map +0 -1
  367. package/dist/test/component-defaults.test.d.ts +0 -2
  368. package/dist/test/component-defaults.test.d.ts.map +0 -1
  369. package/dist/test/component-defaults.test.js +0 -54
  370. package/dist/test/component-defaults.test.js.map +0 -1
  371. package/dist/test/conversation-fork-injection-scoping.test.d.ts +0 -2
  372. package/dist/test/conversation-fork-injection-scoping.test.d.ts.map +0 -1
  373. package/dist/test/conversation-fork-injection-scoping.test.js +0 -200
  374. package/dist/test/conversation-fork-injection-scoping.test.js.map +0 -1
  375. package/dist/test/conversation-router.test.d.ts +0 -2
  376. package/dist/test/conversation-router.test.d.ts.map +0 -1
  377. package/dist/test/conversation-router.test.js +0 -174
  378. package/dist/test/conversation-router.test.js.map +0 -1
  379. package/dist/test/conversation-routing.test.d.ts +0 -7
  380. package/dist/test/conversation-routing.test.d.ts.map +0 -1
  381. package/dist/test/conversation-routing.test.js +0 -621
  382. package/dist/test/conversation-routing.test.js.map +0 -1
  383. package/dist/test/deferred-wake-integrity.test.d.ts +0 -29
  384. package/dist/test/deferred-wake-integrity.test.d.ts.map +0 -1
  385. package/dist/test/deferred-wake-integrity.test.js +0 -320
  386. package/dist/test/deferred-wake-integrity.test.js.map +0 -1
  387. package/dist/test/discord-awareness-outbox.test.d.ts +0 -2
  388. package/dist/test/discord-awareness-outbox.test.d.ts.map +0 -1
  389. package/dist/test/discord-awareness-outbox.test.js +0 -371
  390. package/dist/test/discord-awareness-outbox.test.js.map +0 -1
  391. package/dist/test/discord-history-delete-window.test.d.ts +0 -2
  392. package/dist/test/discord-history-delete-window.test.d.ts.map +0 -1
  393. package/dist/test/discord-history-delete-window.test.js +0 -81
  394. package/dist/test/discord-history-delete-window.test.js.map +0 -1
  395. package/dist/test/discord-history-sync.test.d.ts +0 -2
  396. package/dist/test/discord-history-sync.test.d.ts.map +0 -1
  397. package/dist/test/discord-history-sync.test.js +0 -56
  398. package/dist/test/discord-history-sync.test.js.map +0 -1
  399. package/dist/test/discord-typing-keepalive.test.d.ts +0 -2
  400. package/dist/test/discord-typing-keepalive.test.d.ts.map +0 -1
  401. package/dist/test/discord-typing-keepalive.test.js +0 -77
  402. package/dist/test/discord-typing-keepalive.test.js.map +0 -1
  403. package/dist/test/ephemeral-settle.test.d.ts +0 -2
  404. package/dist/test/ephemeral-settle.test.d.ts.map +0 -1
  405. package/dist/test/ephemeral-settle.test.js +0 -354
  406. package/dist/test/ephemeral-settle.test.js.map +0 -1
  407. package/dist/test/event-gate-passthrough.test.d.ts +0 -15
  408. package/dist/test/event-gate-passthrough.test.d.ts.map +0 -1
  409. package/dist/test/event-gate-passthrough.test.js +0 -289
  410. package/dist/test/event-gate-passthrough.test.js.map +0 -1
  411. package/dist/test/event-gate-policy-mutation.test.d.ts +0 -2
  412. package/dist/test/event-gate-policy-mutation.test.d.ts.map +0 -1
  413. package/dist/test/event-gate-policy-mutation.test.js +0 -137
  414. package/dist/test/event-gate-policy-mutation.test.js.map +0 -1
  415. package/dist/test/event-gate-rate-limit.test.d.ts +0 -2
  416. package/dist/test/event-gate-rate-limit.test.d.ts.map +0 -1
  417. package/dist/test/event-gate-rate-limit.test.js +0 -627
  418. package/dist/test/event-gate-rate-limit.test.js.map +0 -1
  419. package/dist/test/event-gate-script.test.d.ts +0 -2
  420. package/dist/test/event-gate-script.test.d.ts.map +0 -1
  421. package/dist/test/event-gate-script.test.js +0 -95
  422. package/dist/test/event-gate-script.test.js.map +0 -1
  423. package/dist/test/event-gate-selfwake.test.d.ts +0 -15
  424. package/dist/test/event-gate-selfwake.test.d.ts.map +0 -1
  425. package/dist/test/event-gate-selfwake.test.js +0 -125
  426. package/dist/test/event-gate-selfwake.test.js.map +0 -1
  427. package/dist/test/event-gate-tags.test.d.ts +0 -2
  428. package/dist/test/event-gate-tags.test.d.ts.map +0 -1
  429. package/dist/test/event-gate-tags.test.js +0 -76
  430. package/dist/test/event-gate-tags.test.js.map +0 -1
  431. package/dist/test/event-gate.test.d.ts +0 -2
  432. package/dist/test/event-gate.test.d.ts.map +0 -1
  433. package/dist/test/event-gate.test.js +0 -919
  434. package/dist/test/event-gate.test.js.map +0 -1
  435. package/dist/test/explicit-prose-routing.test.d.ts +0 -11
  436. package/dist/test/explicit-prose-routing.test.d.ts.map +0 -1
  437. package/dist/test/explicit-prose-routing.test.js +0 -1715
  438. package/dist/test/explicit-prose-routing.test.js.map +0 -1
  439. package/dist/test/framework.test.d.ts +0 -5
  440. package/dist/test/framework.test.d.ts.map +0 -1
  441. package/dist/test/framework.test.js +0 -1048
  442. package/dist/test/framework.test.js.map +0 -1
  443. package/dist/test/gather-context-timeout.test.d.ts +0 -2
  444. package/dist/test/gather-context-timeout.test.d.ts.map +0 -1
  445. package/dist/test/gather-context-timeout.test.js +0 -120
  446. package/dist/test/gather-context-timeout.test.js.map +0 -1
  447. package/dist/test/health-snapshot.test.d.ts +0 -2
  448. package/dist/test/health-snapshot.test.d.ts.map +0 -1
  449. package/dist/test/health-snapshot.test.js +0 -74
  450. package/dist/test/health-snapshot.test.js.map +0 -1
  451. package/dist/test/helpers/coalescing-fixture.d.ts +0 -74
  452. package/dist/test/helpers/coalescing-fixture.d.ts.map +0 -1
  453. package/dist/test/helpers/coalescing-fixture.js +0 -152
  454. package/dist/test/helpers/coalescing-fixture.js.map +0 -1
  455. package/dist/test/helpers/coalescing-kill-child.d.ts +0 -2
  456. package/dist/test/helpers/coalescing-kill-child.d.ts.map +0 -1
  457. package/dist/test/helpers/coalescing-kill-child.js +0 -24
  458. package/dist/test/helpers/coalescing-kill-child.js.map +0 -1
  459. package/dist/test/helpers/mock-membrane.d.ts +0 -53
  460. package/dist/test/helpers/mock-membrane.d.ts.map +0 -1
  461. package/dist/test/helpers/mock-membrane.js +0 -168
  462. package/dist/test/helpers/mock-membrane.js.map +0 -1
  463. package/dist/test/helpers/pytc-stop-rows.d.ts +0 -11
  464. package/dist/test/helpers/pytc-stop-rows.d.ts.map +0 -1
  465. package/dist/test/helpers/pytc-stop-rows.js +0 -143
  466. package/dist/test/helpers/pytc-stop-rows.js.map +0 -1
  467. package/dist/test/helpers/quiesce-crash-child.d.ts +0 -2
  468. package/dist/test/helpers/quiesce-crash-child.d.ts.map +0 -1
  469. package/dist/test/helpers/quiesce-crash-child.js +0 -156
  470. package/dist/test/helpers/quiesce-crash-child.js.map +0 -1
  471. package/dist/test/hide-then-turn.test.d.ts +0 -2
  472. package/dist/test/hide-then-turn.test.d.ts.map +0 -1
  473. package/dist/test/hide-then-turn.test.js +0 -101
  474. package/dist/test/hide-then-turn.test.js.map +0 -1
  475. package/dist/test/history-module-overview.test.d.ts +0 -2
  476. package/dist/test/history-module-overview.test.d.ts.map +0 -1
  477. package/dist/test/history-module-overview.test.js +0 -711
  478. package/dist/test/history-module-overview.test.js.map +0 -1
  479. package/dist/test/history-module-realstore.test.d.ts +0 -2
  480. package/dist/test/history-module-realstore.test.d.ts.map +0 -1
  481. package/dist/test/history-module-realstore.test.js +0 -363
  482. package/dist/test/history-module-realstore.test.js.map +0 -1
  483. package/dist/test/history-module-semantic.test.d.ts +0 -2
  484. package/dist/test/history-module-semantic.test.d.ts.map +0 -1
  485. package/dist/test/history-module-semantic.test.js +0 -213
  486. package/dist/test/history-module-semantic.test.js.map +0 -1
  487. package/dist/test/history-module-ux.test.d.ts +0 -2
  488. package/dist/test/history-module-ux.test.d.ts.map +0 -1
  489. package/dist/test/history-module-ux.test.js +0 -304
  490. package/dist/test/history-module-ux.test.js.map +0 -1
  491. package/dist/test/history-module.test.d.ts +0 -2
  492. package/dist/test/history-module.test.d.ts.map +0 -1
  493. package/dist/test/history-module.test.js +0 -619
  494. package/dist/test/history-module.test.js.map +0 -1
  495. package/dist/test/history-semantic-review-findings.test.d.ts +0 -2
  496. package/dist/test/history-semantic-review-findings.test.d.ts.map +0 -1
  497. package/dist/test/history-semantic-review-findings.test.js +0 -338
  498. package/dist/test/history-semantic-review-findings.test.js.map +0 -1
  499. package/dist/test/history-semantic-sync-converges.test.d.ts +0 -2
  500. package/dist/test/history-semantic-sync-converges.test.d.ts.map +0 -1
  501. package/dist/test/history-semantic-sync-converges.test.js +0 -109
  502. package/dist/test/history-semantic-sync-converges.test.js.map +0 -1
  503. package/dist/test/host-quiesce.test.d.ts +0 -2
  504. package/dist/test/host-quiesce.test.d.ts.map +0 -1
  505. package/dist/test/host-quiesce.test.js +0 -988
  506. package/dist/test/host-quiesce.test.js.map +0 -1
  507. package/dist/test/inference-exhaustion-rewind.test.d.ts +0 -2
  508. package/dist/test/inference-exhaustion-rewind.test.d.ts.map +0 -1
  509. package/dist/test/inference-exhaustion-rewind.test.js +0 -387
  510. package/dist/test/inference-exhaustion-rewind.test.js.map +0 -1
  511. package/dist/test/inference-failure-bounds.test.d.ts +0 -2
  512. package/dist/test/inference-failure-bounds.test.d.ts.map +0 -1
  513. package/dist/test/inference-failure-bounds.test.js +0 -1202
  514. package/dist/test/inference-failure-bounds.test.js.map +0 -1
  515. package/dist/test/inference-failure-observability.test.d.ts +0 -2
  516. package/dist/test/inference-failure-observability.test.d.ts.map +0 -1
  517. package/dist/test/inference-failure-observability.test.js +0 -84
  518. package/dist/test/inference-failure-observability.test.js.map +0 -1
  519. package/dist/test/journal-tool.test.d.ts +0 -2
  520. package/dist/test/journal-tool.test.d.ts.map +0 -1
  521. package/dist/test/journal-tool.test.js +0 -33
  522. package/dist/test/journal-tool.test.js.map +0 -1
  523. package/dist/test/kv-unified-open-flight-retry.test.d.ts +0 -2
  524. package/dist/test/kv-unified-open-flight-retry.test.d.ts.map +0 -1
  525. package/dist/test/kv-unified-open-flight-retry.test.js +0 -189
  526. package/dist/test/kv-unified-open-flight-retry.test.js.map +0 -1
  527. package/dist/test/kv-unified-wiring.test.d.ts +0 -2
  528. package/dist/test/kv-unified-wiring.test.d.ts.map +0 -1
  529. package/dist/test/kv-unified-wiring.test.js +0 -95
  530. package/dist/test/kv-unified-wiring.test.js.map +0 -1
  531. package/dist/test/late-events-after-stop.test.d.ts +0 -2
  532. package/dist/test/late-events-after-stop.test.d.ts.map +0 -1
  533. package/dist/test/late-events-after-stop.test.js +0 -122
  534. package/dist/test/late-events-after-stop.test.js.map +0 -1
  535. package/dist/test/liveness-watchdog.test.d.ts +0 -2
  536. package/dist/test/liveness-watchdog.test.d.ts.map +0 -1
  537. package/dist/test/liveness-watchdog.test.js +0 -94
  538. package/dist/test/liveness-watchdog.test.js.map +0 -1
  539. package/dist/test/machine-close-provenance.test.d.ts +0 -2
  540. package/dist/test/machine-close-provenance.test.d.ts.map +0 -1
  541. package/dist/test/machine-close-provenance.test.js +0 -116
  542. package/dist/test/machine-close-provenance.test.js.map +0 -1
  543. package/dist/test/maintenance-timer.test.d.ts +0 -2
  544. package/dist/test/maintenance-timer.test.d.ts.map +0 -1
  545. package/dist/test/maintenance-timer.test.js +0 -1827
  546. package/dist/test/maintenance-timer.test.js.map +0 -1
  547. package/dist/test/mcp-server-bin.test.d.ts +0 -2
  548. package/dist/test/mcp-server-bin.test.d.ts.map +0 -1
  549. package/dist/test/mcp-server-bin.test.js +0 -142
  550. package/dist/test/mcp-server-bin.test.js.map +0 -1
  551. package/dist/test/mcpl-access-provider.test.d.ts +0 -2
  552. package/dist/test/mcpl-access-provider.test.d.ts.map +0 -1
  553. package/dist/test/mcpl-access-provider.test.js +0 -20
  554. package/dist/test/mcpl-access-provider.test.js.map +0 -1
  555. package/dist/test/mcpl-awareness-barrier.test.d.ts +0 -2
  556. package/dist/test/mcpl-awareness-barrier.test.d.ts.map +0 -1
  557. package/dist/test/mcpl-awareness-barrier.test.js +0 -769
  558. package/dist/test/mcpl-awareness-barrier.test.js.map +0 -1
  559. package/dist/test/mcpl-capability-grant.test.d.ts +0 -10
  560. package/dist/test/mcpl-capability-grant.test.d.ts.map +0 -1
  561. package/dist/test/mcpl-capability-grant.test.js +0 -111
  562. package/dist/test/mcpl-capability-grant.test.js.map +0 -1
  563. package/dist/test/mcpl-capability-scoping.test.d.ts +0 -2
  564. package/dist/test/mcpl-capability-scoping.test.d.ts.map +0 -1
  565. package/dist/test/mcpl-capability-scoping.test.js +0 -266
  566. package/dist/test/mcpl-capability-scoping.test.js.map +0 -1
  567. package/dist/test/mcpl-child-env.test.d.ts +0 -2
  568. package/dist/test/mcpl-child-env.test.d.ts.map +0 -1
  569. package/dist/test/mcpl-child-env.test.js +0 -158
  570. package/dist/test/mcpl-child-env.test.js.map +0 -1
  571. package/dist/test/mcpl-coalesced-content-parity.test.d.ts +0 -2
  572. package/dist/test/mcpl-coalesced-content-parity.test.d.ts.map +0 -1
  573. package/dist/test/mcpl-coalesced-content-parity.test.js +0 -532
  574. package/dist/test/mcpl-coalesced-content-parity.test.js.map +0 -1
  575. package/dist/test/mcpl-coalescing.test.d.ts +0 -2
  576. package/dist/test/mcpl-coalescing.test.d.ts.map +0 -1
  577. package/dist/test/mcpl-coalescing.test.js +0 -1125
  578. package/dist/test/mcpl-coalescing.test.js.map +0 -1
  579. package/dist/test/mcpl-config-diagnostics.test.d.ts +0 -2
  580. package/dist/test/mcpl-config-diagnostics.test.d.ts.map +0 -1
  581. package/dist/test/mcpl-config-diagnostics.test.js +0 -452
  582. package/dist/test/mcpl-config-diagnostics.test.js.map +0 -1
  583. package/dist/test/mcpl-empty-content.test.d.ts +0 -2
  584. package/dist/test/mcpl-empty-content.test.d.ts.map +0 -1
  585. package/dist/test/mcpl-empty-content.test.js +0 -368
  586. package/dist/test/mcpl-empty-content.test.js.map +0 -1
  587. package/dist/test/mcpl-gate-roundtrip.test.d.ts +0 -2
  588. package/dist/test/mcpl-gate-roundtrip.test.d.ts.map +0 -1
  589. package/dist/test/mcpl-gate-roundtrip.test.js +0 -285
  590. package/dist/test/mcpl-gate-roundtrip.test.js.map +0 -1
  591. package/dist/test/mcpl-list-status.test.d.ts +0 -2
  592. package/dist/test/mcpl-list-status.test.d.ts.map +0 -1
  593. package/dist/test/mcpl-list-status.test.js +0 -82
  594. package/dist/test/mcpl-list-status.test.js.map +0 -1
  595. package/dist/test/mcpl-manifest-changed.test.d.ts +0 -2
  596. package/dist/test/mcpl-manifest-changed.test.d.ts.map +0 -1
  597. package/dist/test/mcpl-manifest-changed.test.js +0 -178
  598. package/dist/test/mcpl-manifest-changed.test.js.map +0 -1
  599. package/dist/test/mcpl-push-convert.test.d.ts +0 -2
  600. package/dist/test/mcpl-push-convert.test.d.ts.map +0 -1
  601. package/dist/test/mcpl-push-convert.test.js +0 -42
  602. package/dist/test/mcpl-push-convert.test.js.map +0 -1
  603. package/dist/test/mcpl-reconnect-events.test.d.ts +0 -2
  604. package/dist/test/mcpl-reconnect-events.test.d.ts.map +0 -1
  605. package/dist/test/mcpl-reconnect-events.test.js +0 -144
  606. package/dist/test/mcpl-reconnect-events.test.js.map +0 -1
  607. package/dist/test/mcpl-reconnect-reregistration.test.d.ts +0 -2
  608. package/dist/test/mcpl-reconnect-reregistration.test.d.ts.map +0 -1
  609. package/dist/test/mcpl-reconnect-reregistration.test.js +0 -238
  610. package/dist/test/mcpl-reconnect-reregistration.test.js.map +0 -1
  611. package/dist/test/mcpl-reference-fetcher.test.d.ts +0 -2
  612. package/dist/test/mcpl-reference-fetcher.test.d.ts.map +0 -1
  613. package/dist/test/mcpl-reference-fetcher.test.js +0 -427
  614. package/dist/test/mcpl-reference-fetcher.test.js.map +0 -1
  615. package/dist/test/mcpl-reference-fields.test.d.ts +0 -2
  616. package/dist/test/mcpl-reference-fields.test.d.ts.map +0 -1
  617. package/dist/test/mcpl-reference-fields.test.js +0 -149
  618. package/dist/test/mcpl-reference-fields.test.js.map +0 -1
  619. package/dist/test/mcpl-rejection-log-lines.test.d.ts +0 -2
  620. package/dist/test/mcpl-rejection-log-lines.test.d.ts.map +0 -1
  621. package/dist/test/mcpl-rejection-log-lines.test.js +0 -349
  622. package/dist/test/mcpl-rejection-log-lines.test.js.map +0 -1
  623. package/dist/test/mcpl-request-timeout.test.d.ts +0 -2
  624. package/dist/test/mcpl-request-timeout.test.d.ts.map +0 -1
  625. package/dist/test/mcpl-request-timeout.test.js +0 -138
  626. package/dist/test/mcpl-request-timeout.test.js.map +0 -1
  627. package/dist/test/mcpl-runtime-lifecycle.test.d.ts +0 -7
  628. package/dist/test/mcpl-runtime-lifecycle.test.d.ts.map +0 -1
  629. package/dist/test/mcpl-runtime-lifecycle.test.js +0 -142
  630. package/dist/test/mcpl-runtime-lifecycle.test.js.map +0 -1
  631. package/dist/test/mcpl-stderr-tail.test.d.ts +0 -2
  632. package/dist/test/mcpl-stderr-tail.test.d.ts.map +0 -1
  633. package/dist/test/mcpl-stderr-tail.test.js +0 -210
  634. package/dist/test/mcpl-stderr-tail.test.js.map +0 -1
  635. package/dist/test/mcpl-tool-class-listing.test.d.ts +0 -2
  636. package/dist/test/mcpl-tool-class-listing.test.d.ts.map +0 -1
  637. package/dist/test/mcpl-tool-class-listing.test.js +0 -147
  638. package/dist/test/mcpl-tool-class-listing.test.js.map +0 -1
  639. package/dist/test/mcpl-tool-classes.test.d.ts +0 -7
  640. package/dist/test/mcpl-tool-classes.test.d.ts.map +0 -1
  641. package/dist/test/mcpl-tool-classes.test.js +0 -80
  642. package/dist/test/mcpl-tool-classes.test.js.map +0 -1
  643. package/dist/test/mcpl-tool-lifecycle-e2e.test.d.ts +0 -2
  644. package/dist/test/mcpl-tool-lifecycle-e2e.test.d.ts.map +0 -1
  645. package/dist/test/mcpl-tool-lifecycle-e2e.test.js +0 -237
  646. package/dist/test/mcpl-tool-lifecycle-e2e.test.js.map +0 -1
  647. package/dist/test/mcpl-tool-lifecycle-emitter.test.d.ts +0 -11
  648. package/dist/test/mcpl-tool-lifecycle-emitter.test.d.ts.map +0 -1
  649. package/dist/test/mcpl-tool-lifecycle-emitter.test.js +0 -412
  650. package/dist/test/mcpl-tool-lifecycle-emitter.test.js.map +0 -1
  651. package/dist/test/mcpl-tool-lifecycle-script.test.d.ts +0 -2
  652. package/dist/test/mcpl-tool-lifecycle-script.test.d.ts.map +0 -1
  653. package/dist/test/mcpl-tool-lifecycle-script.test.js +0 -288
  654. package/dist/test/mcpl-tool-lifecycle-script.test.js.map +0 -1
  655. package/dist/test/mcpl-tool-lifecycle.test.d.ts +0 -11
  656. package/dist/test/mcpl-tool-lifecycle.test.d.ts.map +0 -1
  657. package/dist/test/mcpl-tool-lifecycle.test.js +0 -270
  658. package/dist/test/mcpl-tool-lifecycle.test.js.map +0 -1
  659. package/dist/test/mcpl-transport-close.test.d.ts +0 -2
  660. package/dist/test/mcpl-transport-close.test.d.ts.map +0 -1
  661. package/dist/test/mcpl-transport-close.test.js +0 -373
  662. package/dist/test/mcpl-transport-close.test.js.map +0 -1
  663. package/dist/test/mcpl-transport-spawn.test.d.ts +0 -2
  664. package/dist/test/mcpl-transport-spawn.test.d.ts.map +0 -1
  665. package/dist/test/mcpl-transport-spawn.test.js +0 -58
  666. package/dist/test/mcpl-transport-spawn.test.js.map +0 -1
  667. package/dist/test/mcpl-ws-transport.test.d.ts +0 -2
  668. package/dist/test/mcpl-ws-transport.test.d.ts.map +0 -1
  669. package/dist/test/mcpl-ws-transport.test.js +0 -259
  670. package/dist/test/mcpl-ws-transport.test.js.map +0 -1
  671. package/dist/test/module-context-integration.test.d.ts +0 -18
  672. package/dist/test/module-context-integration.test.d.ts.map +0 -1
  673. package/dist/test/module-context-integration.test.js +0 -181
  674. package/dist/test/module-context-integration.test.js.map +0 -1
  675. package/dist/test/offline-recovery-branch.test.d.ts +0 -2
  676. package/dist/test/offline-recovery-branch.test.d.ts.map +0 -1
  677. package/dist/test/offline-recovery-branch.test.js +0 -570
  678. package/dist/test/offline-recovery-branch.test.js.map +0 -1
  679. package/dist/test/operator-surgery.test.d.ts +0 -2
  680. package/dist/test/operator-surgery.test.d.ts.map +0 -1
  681. package/dist/test/operator-surgery.test.js +0 -595
  682. package/dist/test/operator-surgery.test.js.map +0 -1
  683. package/dist/test/ops-alert.test.d.ts +0 -2
  684. package/dist/test/ops-alert.test.d.ts.map +0 -1
  685. package/dist/test/ops-alert.test.js +0 -153
  686. package/dist/test/ops-alert.test.js.map +0 -1
  687. package/dist/test/overbudget-drain-breaker.test.d.ts +0 -2
  688. package/dist/test/overbudget-drain-breaker.test.d.ts.map +0 -1
  689. package/dist/test/overbudget-drain-breaker.test.js +0 -198
  690. package/dist/test/overbudget-drain-breaker.test.js.map +0 -1
  691. package/dist/test/pack-installs-alone.test.d.ts +0 -2
  692. package/dist/test/pack-installs-alone.test.d.ts.map +0 -1
  693. package/dist/test/pack-installs-alone.test.js +0 -284
  694. package/dist/test/pack-installs-alone.test.js.map +0 -1
  695. package/dist/test/per-agent-delivery.test.d.ts +0 -2
  696. package/dist/test/per-agent-delivery.test.d.ts.map +0 -1
  697. package/dist/test/per-agent-delivery.test.js +0 -108
  698. package/dist/test/per-agent-delivery.test.js.map +0 -1
  699. package/dist/test/physical-window-restart.test.d.ts +0 -16
  700. package/dist/test/physical-window-restart.test.d.ts.map +0 -1
  701. package/dist/test/physical-window-restart.test.js +0 -487
  702. package/dist/test/physical-window-restart.test.js.map +0 -1
  703. package/dist/test/placed-reaction-baseline.test.d.ts +0 -2
  704. package/dist/test/placed-reaction-baseline.test.d.ts.map +0 -1
  705. package/dist/test/placed-reaction-baseline.test.js +0 -312
  706. package/dist/test/placed-reaction-baseline.test.js.map +0 -1
  707. package/dist/test/present-while-acting.test.d.ts +0 -19
  708. package/dist/test/present-while-acting.test.d.ts.map +0 -1
  709. package/dist/test/present-while-acting.test.js +0 -1649
  710. package/dist/test/present-while-acting.test.js.map +0 -1
  711. package/dist/test/prose-segments.test.d.ts +0 -2
  712. package/dist/test/prose-segments.test.d.ts.map +0 -1
  713. package/dist/test/prose-segments.test.js +0 -52
  714. package/dist/test/prose-segments.test.js.map +0 -1
  715. package/dist/test/prose-stream-router.test.d.ts +0 -2
  716. package/dist/test/prose-stream-router.test.d.ts.map +0 -1
  717. package/dist/test/prose-stream-router.test.js +0 -171
  718. package/dist/test/prose-stream-router.test.js.map +0 -1
  719. package/dist/test/provider-acceleration-cooldown.test.d.ts +0 -2
  720. package/dist/test/provider-acceleration-cooldown.test.d.ts.map +0 -1
  721. package/dist/test/provider-acceleration-cooldown.test.js +0 -435
  722. package/dist/test/provider-acceleration-cooldown.test.js.map +0 -1
  723. package/dist/test/provider-waits.test.d.ts +0 -2
  724. package/dist/test/provider-waits.test.d.ts.map +0 -1
  725. package/dist/test/provider-waits.test.js +0 -2259
  726. package/dist/test/provider-waits.test.js.map +0 -1
  727. package/dist/test/puppet-tool-call.test.d.ts +0 -2
  728. package/dist/test/puppet-tool-call.test.d.ts.map +0 -1
  729. package/dist/test/puppet-tool-call.test.js +0 -226
  730. package/dist/test/puppet-tool-call.test.js.map +0 -1
  731. package/dist/test/puppet-turn-reservation.test.d.ts +0 -2
  732. package/dist/test/puppet-turn-reservation.test.d.ts.map +0 -1
  733. package/dist/test/puppet-turn-reservation.test.js +0 -139
  734. package/dist/test/puppet-turn-reservation.test.js.map +0 -1
  735. package/dist/test/reaction-baseline-platform.test.d.ts +0 -2
  736. package/dist/test/reaction-baseline-platform.test.d.ts.map +0 -1
  737. package/dist/test/reaction-baseline-platform.test.js +0 -124
  738. package/dist/test/reaction-baseline-platform.test.js.map +0 -1
  739. package/dist/test/record-journal.test.d.ts +0 -6
  740. package/dist/test/record-journal.test.d.ts.map +0 -1
  741. package/dist/test/record-journal.test.js +0 -269
  742. package/dist/test/record-journal.test.js.map +0 -1
  743. package/dist/test/refusal-reaction-baseline.test.d.ts +0 -2
  744. package/dist/test/refusal-reaction-baseline.test.d.ts.map +0 -1
  745. package/dist/test/refusal-reaction-baseline.test.js +0 -81
  746. package/dist/test/refusal-reaction-baseline.test.js.map +0 -1
  747. package/dist/test/refusal-rewind.test.d.ts +0 -2
  748. package/dist/test/refusal-rewind.test.d.ts.map +0 -1
  749. package/dist/test/refusal-rewind.test.js +0 -117
  750. package/dist/test/refusal-rewind.test.js.map +0 -1
  751. package/dist/test/refusal-single-call.test.d.ts +0 -2
  752. package/dist/test/refusal-single-call.test.d.ts.map +0 -1
  753. package/dist/test/refusal-single-call.test.js +0 -177
  754. package/dist/test/refusal-single-call.test.js.map +0 -1
  755. package/dist/test/release-bump.test.d.ts +0 -2
  756. package/dist/test/release-bump.test.d.ts.map +0 -1
  757. package/dist/test/release-bump.test.js +0 -248
  758. package/dist/test/release-bump.test.js.map +0 -1
  759. package/dist/test/release-changelog.test.d.ts +0 -2
  760. package/dist/test/release-changelog.test.d.ts.map +0 -1
  761. package/dist/test/release-changelog.test.js +0 -159
  762. package/dist/test/release-changelog.test.js.map +0 -1
  763. package/dist/test/release-holds.test.d.ts +0 -2
  764. package/dist/test/release-holds.test.d.ts.map +0 -1
  765. package/dist/test/release-holds.test.js +0 -456
  766. package/dist/test/release-holds.test.js.map +0 -1
  767. package/dist/test/same-round-think-policy.test.d.ts +0 -2
  768. package/dist/test/same-round-think-policy.test.d.ts.map +0 -1
  769. package/dist/test/same-round-think-policy.test.js +0 -853
  770. package/dist/test/same-round-think-policy.test.js.map +0 -1
  771. package/dist/test/save-recent-image.test.d.ts +0 -26
  772. package/dist/test/save-recent-image.test.d.ts.map +0 -1
  773. package/dist/test/save-recent-image.test.js +0 -974
  774. package/dist/test/save-recent-image.test.js.map +0 -1
  775. package/dist/test/shutdown-errors.test.d.ts +0 -2
  776. package/dist/test/shutdown-errors.test.d.ts.map +0 -1
  777. package/dist/test/shutdown-errors.test.js +0 -662
  778. package/dist/test/shutdown-errors.test.js.map +0 -1
  779. package/dist/test/silent-heartbeat-rows.test.d.ts +0 -2
  780. package/dist/test/silent-heartbeat-rows.test.d.ts.map +0 -1
  781. package/dist/test/silent-heartbeat-rows.test.js +0 -451
  782. package/dist/test/silent-heartbeat-rows.test.js.map +0 -1
  783. package/dist/test/silent-heartbeat.test.d.ts +0 -2
  784. package/dist/test/silent-heartbeat.test.d.ts.map +0 -1
  785. package/dist/test/silent-heartbeat.test.js +0 -165
  786. package/dist/test/silent-heartbeat.test.js.map +0 -1
  787. package/dist/test/state-scaling-e2e.test.d.ts +0 -22
  788. package/dist/test/state-scaling-e2e.test.d.ts.map +0 -1
  789. package/dist/test/state-scaling-e2e.test.js +0 -206
  790. package/dist/test/state-scaling-e2e.test.js.map +0 -1
  791. package/dist/test/state-scaling.test.d.ts +0 -12
  792. package/dist/test/state-scaling.test.d.ts.map +0 -1
  793. package/dist/test/state-scaling.test.js +0 -251
  794. package/dist/test/state-scaling.test.js.map +0 -1
  795. package/dist/test/stop-with-host-operations.test.d.ts +0 -20
  796. package/dist/test/stop-with-host-operations.test.d.ts.map +0 -1
  797. package/dist/test/stop-with-host-operations.test.js +0 -1174
  798. package/dist/test/stop-with-host-operations.test.js.map +0 -1
  799. package/dist/test/stop-with-work-in-flight.test.d.ts +0 -23
  800. package/dist/test/stop-with-work-in-flight.test.d.ts.map +0 -1
  801. package/dist/test/stop-with-work-in-flight.test.js +0 -784
  802. package/dist/test/stop-with-work-in-flight.test.js.map +0 -1
  803. package/dist/test/surgery-marks-receipt.test.d.ts +0 -2
  804. package/dist/test/surgery-marks-receipt.test.d.ts.map +0 -1
  805. package/dist/test/surgery-marks-receipt.test.js +0 -540
  806. package/dist/test/surgery-marks-receipt.test.js.map +0 -1
  807. package/dist/test/thinking-token-stamp.test.d.ts +0 -12
  808. package/dist/test/thinking-token-stamp.test.d.ts.map +0 -1
  809. package/dist/test/thinking-token-stamp.test.js +0 -129
  810. package/dist/test/thinking-token-stamp.test.js.map +0 -1
  811. package/dist/test/timezone.test.d.ts +0 -2
  812. package/dist/test/timezone.test.d.ts.map +0 -1
  813. package/dist/test/timezone.test.js +0 -18
  814. package/dist/test/timezone.test.js.map +0 -1
  815. package/dist/test/tool-batch-hook.test.d.ts +0 -8
  816. package/dist/test/tool-batch-hook.test.d.ts.map +0 -1
  817. package/dist/test/tool-batch-hook.test.js +0 -275
  818. package/dist/test/tool-batch-hook.test.js.map +0 -1
  819. package/dist/test/tool-policy.test.d.ts +0 -2
  820. package/dist/test/tool-policy.test.d.ts.map +0 -1
  821. package/dist/test/tool-policy.test.js +0 -51
  822. package/dist/test/tool-policy.test.js.map +0 -1
  823. package/dist/test/tool-presentation.test.d.ts +0 -2
  824. package/dist/test/tool-presentation.test.d.ts.map +0 -1
  825. package/dist/test/tool-presentation.test.js +0 -268
  826. package/dist/test/tool-presentation.test.js.map +0 -1
  827. package/dist/test/tool-result-content.test.d.ts +0 -2
  828. package/dist/test/tool-result-content.test.d.ts.map +0 -1
  829. package/dist/test/tool-result-content.test.js +0 -37
  830. package/dist/test/tool-result-content.test.js.map +0 -1
  831. package/dist/test/tool-result-guard.test.d.ts +0 -2
  832. package/dist/test/tool-result-guard.test.d.ts.map +0 -1
  833. package/dist/test/tool-result-guard.test.js +0 -3729
  834. package/dist/test/tool-result-guard.test.js.map +0 -1
  835. package/dist/test/tool-result-history.test.d.ts +0 -7
  836. package/dist/test/tool-result-history.test.d.ts.map +0 -1
  837. package/dist/test/tool-result-history.test.js +0 -156
  838. package/dist/test/tool-result-history.test.js.map +0 -1
  839. package/dist/test/tool-result-spill.test.d.ts +0 -13
  840. package/dist/test/tool-result-spill.test.d.ts.map +0 -1
  841. package/dist/test/tool-result-spill.test.js +0 -586
  842. package/dist/test/tool-result-spill.test.js.map +0 -1
  843. package/dist/test/tool-wrapper-prose-guard-integration.test.d.ts +0 -2
  844. package/dist/test/tool-wrapper-prose-guard-integration.test.d.ts.map +0 -1
  845. package/dist/test/tool-wrapper-prose-guard-integration.test.js +0 -485
  846. package/dist/test/tool-wrapper-prose-guard-integration.test.js.map +0 -1
  847. package/dist/test/tool-wrapper-prose-guard.test.d.ts +0 -2
  848. package/dist/test/tool-wrapper-prose-guard.test.d.ts.map +0 -1
  849. package/dist/test/tool-wrapper-prose-guard.test.js +0 -34
  850. package/dist/test/tool-wrapper-prose-guard.test.js.map +0 -1
  851. package/dist/test/tools-observe-parser-conformance.test.d.ts +0 -2
  852. package/dist/test/tools-observe-parser-conformance.test.d.ts.map +0 -1
  853. package/dist/test/tools-observe-parser-conformance.test.js +0 -129
  854. package/dist/test/tools-observe-parser-conformance.test.js.map +0 -1
  855. package/dist/test/trunk-channel-routing.test.d.ts +0 -19
  856. package/dist/test/trunk-channel-routing.test.d.ts.map +0 -1
  857. package/dist/test/trunk-channel-routing.test.js +0 -652
  858. package/dist/test/trunk-channel-routing.test.js.map +0 -1
  859. package/dist/test/tune-out-e2e.test.d.ts +0 -2
  860. package/dist/test/tune-out-e2e.test.d.ts.map +0 -1
  861. package/dist/test/tune-out-e2e.test.js +0 -142
  862. package/dist/test/tune-out-e2e.test.js.map +0 -1
  863. package/dist/test/tune-out-gate-composition.test.d.ts +0 -2
  864. package/dist/test/tune-out-gate-composition.test.d.ts.map +0 -1
  865. package/dist/test/tune-out-gate-composition.test.js +0 -221
  866. package/dist/test/tune-out-gate-composition.test.js.map +0 -1
  867. package/dist/test/tune-out-lifecycle.test.d.ts +0 -2
  868. package/dist/test/tune-out-lifecycle.test.d.ts.map +0 -1
  869. package/dist/test/tune-out-lifecycle.test.js +0 -121
  870. package/dist/test/tune-out-lifecycle.test.js.map +0 -1
  871. package/dist/test/turn-trigger-provenance.test.d.ts +0 -2
  872. package/dist/test/turn-trigger-provenance.test.d.ts.map +0 -1
  873. package/dist/test/turn-trigger-provenance.test.js +0 -137
  874. package/dist/test/turn-trigger-provenance.test.js.map +0 -1
  875. package/dist/test/unconvertible-tool-result.test.d.ts +0 -2
  876. package/dist/test/unconvertible-tool-result.test.d.ts.map +0 -1
  877. package/dist/test/unconvertible-tool-result.test.js +0 -358
  878. package/dist/test/unconvertible-tool-result.test.js.map +0 -1
  879. package/dist/test/unsent-compiles.test.d.ts +0 -2
  880. package/dist/test/unsent-compiles.test.d.ts.map +0 -1
  881. package/dist/test/unsent-compiles.test.js +0 -139
  882. package/dist/test/unsent-compiles.test.js.map +0 -1
  883. package/dist/test/usage-accounting.test.d.ts +0 -2
  884. package/dist/test/usage-accounting.test.d.ts.map +0 -1
  885. package/dist/test/usage-accounting.test.js +0 -13
  886. package/dist/test/usage-accounting.test.js.map +0 -1
  887. package/dist/test/usage-tracker.test.d.ts +0 -2
  888. package/dist/test/usage-tracker.test.d.ts.map +0 -1
  889. package/dist/test/usage-tracker.test.js +0 -129
  890. package/dist/test/usage-tracker.test.js.map +0 -1
  891. package/dist/test/utils-surface.test.d.ts +0 -2
  892. package/dist/test/utils-surface.test.d.ts.map +0 -1
  893. package/dist/test/utils-surface.test.js +0 -145
  894. package/dist/test/utils-surface.test.js.map +0 -1
  895. package/dist/test/workspace-branch-continuation.test.d.ts +0 -15
  896. package/dist/test/workspace-branch-continuation.test.d.ts.map +0 -1
  897. package/dist/test/workspace-branch-continuation.test.js +0 -183
  898. package/dist/test/workspace-branch-continuation.test.js.map +0 -1
  899. package/dist/test/workspace-materialize-freshness.test.d.ts +0 -16
  900. package/dist/test/workspace-materialize-freshness.test.d.ts.map +0 -1
  901. package/dist/test/workspace-materialize-freshness.test.js +0 -252
  902. package/dist/test/workspace-materialize-freshness.test.js.map +0 -1
  903. package/dist/test/workspace-path-containment.test.d.ts +0 -19
  904. package/dist/test/workspace-path-containment.test.d.ts.map +0 -1
  905. package/dist/test/workspace-path-containment.test.js +0 -91
  906. package/dist/test/workspace-path-containment.test.js.map +0 -1
  907. package/dist/test/workspace-read-file-from-disk.test.d.ts +0 -17
  908. package/dist/test/workspace-read-file-from-disk.test.d.ts.map +0 -1
  909. package/dist/test/workspace-read-file-from-disk.test.js +0 -174
  910. package/dist/test/workspace-read-file-from-disk.test.js.map +0 -1
  911. package/dist/test/workspace-read-image.test.d.ts +0 -2
  912. package/dist/test/workspace-read-image.test.d.ts.map +0 -1
  913. package/dist/test/workspace-read-image.test.js +0 -597
  914. package/dist/test/workspace-read-image.test.js.map +0 -1
  915. package/dist/test/workspace-read-text.test.d.ts +0 -2
  916. package/dist/test/workspace-read-text.test.d.ts.map +0 -1
  917. package/dist/test/workspace-read-text.test.js +0 -101
  918. package/dist/test/workspace-read-text.test.js.map +0 -1
  919. package/dist/test/workspace-restore-order.test.d.ts +0 -16
  920. package/dist/test/workspace-restore-order.test.d.ts.map +0 -1
  921. package/dist/test/workspace-restore-order.test.js +0 -140
  922. package/dist/test/workspace-restore-order.test.js.map +0 -1
  923. package/dist/test/workspace-three-way.test.d.ts +0 -12
  924. package/dist/test/workspace-three-way.test.d.ts.map +0 -1
  925. package/dist/test/workspace-three-way.test.js +0 -4094
  926. package/dist/test/workspace-three-way.test.js.map +0 -1
  927. package/dist/test/workspace-watcher.test.d.ts +0 -2
  928. package/dist/test/workspace-watcher.test.d.ts.map +0 -1
  929. package/dist/test/workspace-watcher.test.js +0 -281
  930. package/dist/test/workspace-watcher.test.js.map +0 -1
  931. package/dist/test/xml-round-persist.test.d.ts +0 -19
  932. package/dist/test/xml-round-persist.test.d.ts.map +0 -1
  933. package/dist/test/xml-round-persist.test.js +0 -235
  934. package/dist/test/xml-round-persist.test.js.map +0 -1
  935. 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,6 +71,14 @@ const TYPING_REFRESH_MS = 8_000;
67
71
  // stuck on forever.
68
72
  const TYPING_MAX_MS = 5 * 60_000;
69
73
 
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
+
70
82
  // Trace event types that end an agent's turn (onTrace's contract) — any of
71
83
  // these stops the typing keepalive. A turn's tool-call cycles stay inside its
72
84
  // stream, so they come after them. inference:completed is the normal end.
@@ -95,6 +107,128 @@ const TEXT_FILE_EXTENSIONS = [
95
107
 
96
108
  const CONVERSATION_TIMEOUT_MS = 30 * 60 * 1000; // 30 minutes
97
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
+
98
232
  /**
99
233
  * Discord module for the agent framework.
100
234
  */
@@ -115,8 +249,25 @@ export class DiscordModule implements Module {
115
249
  // Track current reply context per agent
116
250
  private replyContexts: Map<string, ConversationContext> = new Map();
117
251
 
118
- // Last message sent by a tool (for thought-editing)
119
- 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>>();
120
271
 
121
272
  // Typing keepalive: agentName -> { interval, deadline }. Started on
122
273
  // inference:started, stopped on the turn's terminal trace event. Discord's
@@ -406,7 +557,7 @@ export class DiscordModule implements Module {
406
557
  },
407
558
  {
408
559
  name: 'fetch_history',
409
- 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.',
410
561
  inputSchema: {
411
562
  type: 'object',
412
563
  properties: {
@@ -424,11 +575,11 @@ export class DiscordModule implements Module {
424
575
  try {
425
576
  switch (call.name) {
426
577
  case 'send':
427
- return await this.handleSend(call.input as SendInput);
578
+ return await this.handleSend(call.input as SendInput, call);
428
579
  case 'dm':
429
580
  return await this.handleDM(call.input as SendDMInput);
430
581
  case 'reply':
431
- return await this.handleReply(call.input as ReplyInput);
582
+ return await this.handleReply(call.input as ReplyInput, call);
432
583
  case 'react':
433
584
  return await this.handleReact(call.input as ReactInput);
434
585
  case 'edit':
@@ -509,8 +660,10 @@ export class DiscordModule implements Module {
509
660
  });
510
661
  }
511
662
 
512
- // Build content blocks from message and attachments
513
- 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);
514
667
 
515
668
  // Return declarative response - framework applies all writes atomically
516
669
  return {
@@ -522,6 +675,7 @@ export class DiscordModule implements Module {
522
675
  external: { source: 'discord', id: msg.discordMessageId },
523
676
  channelId: msg.channelId,
524
677
  timestamp: msg.timestamp,
678
+ [TEXT_FIRST]: true,
525
679
  },
526
680
  },
527
681
  ],
@@ -533,29 +687,41 @@ export class DiscordModule implements Module {
533
687
  // Handle Discord message edit
534
688
  if (event.type === 'discord:edit') {
535
689
  const edit = event as DiscordEditEvent;
536
- const internalId = state.findMessageByExternalId('discord', edit.discordMessageId);
537
- 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`);
538
703
  return {};
539
704
  }
540
- return {
541
- editMessages: [
542
- {
543
- messageId: internalId,
544
- content: [{ type: 'text', text: edit.newContent }],
545
- },
546
- ],
547
- };
705
+ const content = contentForText(stored, edit.newContent);
706
+ if (!content) return {};
707
+ this.noteLive(edit.discordMessageId);
708
+ return { editMessages: [{ messageId: stored.id, content }] };
548
709
  }
549
710
 
550
711
  // Handle Discord message delete
551
712
  if (event.type === 'discord:delete') {
552
713
  const del = event as DiscordDeleteEvent;
553
- const internalId = state.findMessageByExternalId('discord', del.discordMessageId);
554
- 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) {
555
721
  return {};
556
722
  }
557
723
  return {
558
- removeMessages: [internalId],
724
+ removeMessages: [stored.id],
559
725
  };
560
726
  }
561
727
 
@@ -570,13 +736,15 @@ export class DiscordModule implements Module {
570
736
  content: ContentBlock[],
571
737
  context: SpeechContext
572
738
  ): Promise<void> {
573
- // If thoughts are present and we have a recently sent message, edit it
574
- // to prepend the thoughts as spoiler text.
575
- 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);
576
744
  const thoughtText = this.extractText(context.thoughts);
577
745
  if (thoughtText) {
578
746
  try {
579
- const { channelId, messageId } = this.lastSentMessage;
747
+ const { channelId, messageId } = post;
580
748
  // Fetch the current message content via the client isn't available,
581
749
  // but we know the tool just sent it — reconstruct by editing with
582
750
  // spoiler-wrapped thoughts prepended.
@@ -588,7 +756,6 @@ export class DiscordModule implements Module {
588
756
  console.warn('Discord: Failed to edit thoughts into message:', err);
589
757
  }
590
758
  }
591
- this.lastSentMessage = null;
592
759
  }
593
760
 
594
761
  // Get reply context for this agent
@@ -617,8 +784,8 @@ export class DiscordModule implements Module {
617
784
  replyTo: replyCtx.replyToMessageId,
618
785
  });
619
786
 
620
- // Track for thought-editing (in case of chained speech)
621
- 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);
622
789
 
623
790
  // Clear reply-to after sending (don't keep replying to same message)
624
791
  replyCtx.replyToMessageId = undefined;
@@ -724,131 +891,176 @@ export class DiscordModule implements Module {
724
891
  /**
725
892
  * Sync history for a specific channel - compare with Context Manager and update.
726
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.
727
906
  */
728
907
  private async syncChannelHistory(channelId: string): Promise<{
729
908
  newMessages: number;
730
909
  editedMessages: number;
731
910
  deletedMessages: number;
732
911
  }> {
733
- if (!this.ctx) {
734
- 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;
735
916
  }
736
-
737
- const scrollback = this.config.historyScrollback ?? 50;
738
-
739
- // Fetch recent history from Discord
740
- const discordMessages = await this.client.fetchHistory(channelId, { limit: scrollback });
741
-
742
- // Build a map of Discord message ID -> content for comparison
743
- const discordMessageMap = new Map<string, { content: string; authorName: string; timestamp: Date }>();
744
- for (const msg of discordMessages) {
745
- discordMessageMap.set(msg.id, {
746
- content: msg.content,
747
- authorName: msg.authorName,
748
- timestamp: msg.timestamp,
749
- });
750
- }
751
-
752
- // Query Context Manager for all Discord messages from this channel
753
- const { messages: storedMessages } = this.ctx.queryMessages({
754
- source: 'discord',
755
- metadata: { channelId },
756
- });
757
-
758
- // Build a map of stored message external IDs -> internal data
759
- const storedMessageMap = new Map<string, { internalId: string; content: string; sourceTimestamp?: number }>();
760
- for (const msg of storedMessages) {
761
- const external = msg.metadata?.external as { id?: string } | undefined;
762
- if (external?.id) {
763
- // Extract text content for comparison
764
- const textContent = msg.content
765
- .filter((block): block is { type: 'text'; text: string } => block.type === 'text')
766
- .map((block) => block.text)
767
- .join('\n');
768
- storedMessageMap.set(external.id, {
769
- internalId: msg.id,
770
- content: textContent,
771
- sourceTimestamp: typeof msg.metadata?.timestamp === 'number'
772
- ? msg.metadata.timestamp
773
- : undefined,
774
- });
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);
775
952
  }
776
- }
777
953
 
778
- let newMessages = 0;
779
- let editedMessages = 0;
780
- let deletedMessages = 0;
781
-
782
- // Discord history is newest-first, while addMessage appends to the stored
783
- // conversation. Process oldest-first so missed messages retain chronology.
784
- const chronologicalMessages = [...discordMessages].reverse();
785
- for (const discordMsg of chronologicalMessages) {
786
- const stored = storedMessageMap.get(discordMsg.id);
787
-
788
- if (!stored) {
789
- // New message we haven't seen
790
- // For bot's own messages (from previous sessions), use the agent name
791
- // This ensures continuity of conversation history
792
- const isBotMessage = discordMsg.authorId === this.state.botUserId;
793
- const agentName = this.ctx.getAgents()[0]?.name;
794
- const participantName = isBotMessage
795
- ? (agentName ?? discordMsg.authorName)
796
- : discordMsg.authorName;
797
-
798
- this.ctx.addMessage(
799
- participantName,
800
- [{ type: 'text', text: discordMsg.content }],
801
- {
802
- external: { source: 'discord', id: discordMsg.id },
803
- channelId,
804
- timestamp: discordMsg.timestamp.getTime(),
805
- 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++;
806
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
807
1018
  );
808
- newMessages++;
809
- } else {
810
- // We have this message - check if content changed (offline edit detection)
811
- if (stored.content !== discordMsg.content) {
812
- this.ctx.editMessage(stored.internalId, [
813
- { type: 'text', text: discordMsg.content },
814
- ]);
815
- 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++;
816
1026
  }
817
1027
  }
818
- }
819
1028
 
820
- // Check for deletes only inside the history we actually fetched. A short
821
- // response covers complete available history; a full page has an older
822
- // boundary whose tied millisecond must be preserved.
823
- const fetchedCompleteHistory = discordMessages.length < scrollback;
824
- const oldestFetchedTimestamp = discordMessages.length > 0
825
- ? Math.min(...discordMessages.map((msg) => msg.timestamp.getTime()))
826
- : undefined;
827
- for (const [externalId, stored] of storedMessageMap) {
828
- const isInsideFetchedWindow = fetchedCompleteHistory || (
829
- stored.sourceTimestamp !== undefined &&
830
- oldestFetchedTimestamp !== undefined &&
831
- // Discord timestamps are millisecond-precise, so an older message just
832
- // beyond the page can tie the oldest fetched timestamp. Preserve ties
833
- // rather than guessing that an unseen boundary message was deleted.
834
- stored.sourceTimestamp > oldestFetchedTimestamp
835
- );
836
- if (isInsideFetchedWindow && !discordMessageMap.has(externalId)) {
837
- // Message exists in our store but not in Discord - it was deleted
838
- // Note: This only catches deletes within the scrollback window
839
- this.ctx.removeMessage(stored.internalId);
840
- 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;
841
1034
  }
1035
+
1036
+ return { newMessages, editedMessages, deletedMessages };
1037
+ } finally {
1038
+ this.liveDuringSync.delete(live);
842
1039
  }
1040
+ }
843
1041
 
844
- // Update last read
845
- if (discordMessages.length > 0) {
846
- // Messages are typically newest first
847
- const newestId = discordMessages[0].id;
848
- 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);
849
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
+ }
850
1060
 
851
- 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);
852
1064
  }
853
1065
 
854
1066
  private async handleDiscordMessage(message: DiscordMessageData): Promise<void> {
@@ -907,19 +1119,18 @@ export class DiscordModule implements Module {
907
1119
  }
908
1120
 
909
1121
  /**
910
- * Convert Discord message to ContentBlock array.
911
- * 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.
912
1125
  */
913
- 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.
914
1130
  const blocks: ContentBlock[] = [];
915
1131
 
916
- // Add text content if present
917
- if (message.content.trim()) {
918
- blocks.push({ type: 'text', text: message.content });
919
- }
920
-
921
1132
  // Process attachments
922
- for (const attachment of message.attachments) {
1133
+ for (const attachment of message.attachments ?? []) {
923
1134
  const contentType = attachment.contentType?.toLowerCase() ?? '';
924
1135
  const filename = attachment.filename.toLowerCase();
925
1136
 
@@ -946,13 +1157,15 @@ export class DiscordModule implements Module {
946
1157
  type: 'text',
947
1158
  text: `\n--- File: ${attachment.filename} ---\n${textContent}\n--- End of ${attachment.filename} ---\n`,
948
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));
949
1165
  }
950
1166
  } catch (error) {
951
- // If fetch fails, just note the attachment
952
- blocks.push({
953
- type: 'text',
954
- text: `[Attachment: ${attachment.filename} (failed to fetch)]`,
955
- });
1167
+ console.warn(`Discord: Attachment ${logValue(attachment.filename)} in message ${message.id} wasn't fetched:`, error);
1168
+ blocks.push(attachmentNotFetched(attachment.filename));
956
1169
  }
957
1170
  continue;
958
1171
  }
@@ -964,12 +1177,7 @@ export class DiscordModule implements Module {
964
1177
  });
965
1178
  }
966
1179
 
967
- // Ensure we have at least empty text if nothing else
968
- if (blocks.length === 0) {
969
- blocks.push({ type: 'text', text: '[Empty message]' });
970
- }
971
-
972
- return blocks;
1180
+ return textFirst(ownText(message.content), blocks);
973
1181
  }
974
1182
 
975
1183
  /**
@@ -1037,7 +1245,23 @@ export class DiscordModule implements Module {
1037
1245
  // Tool Handlers
1038
1246
  // ==========================================================================
1039
1247
 
1040
- 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> {
1041
1265
  if (!this.checkRateLimit(input.channelId)) {
1042
1266
  return { success: false, error: 'Rate limited', isError: true };
1043
1267
  }
@@ -1047,9 +1271,13 @@ export class DiscordModule implements Module {
1047
1271
  createThread: input.createThread,
1048
1272
  });
1049
1273
 
1050
- // Track for thought-editing
1051
- 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);
1052
1277
 
1278
+ if (result.threadFailure !== undefined) {
1279
+ return { success: false, error: result.threadFailure, isError: true };
1280
+ }
1053
1281
  return { success: true, data: { messageId: result.messageId } };
1054
1282
  }
1055
1283
 
@@ -1058,7 +1286,7 @@ export class DiscordModule implements Module {
1058
1286
  return { success: true, data: { messageId: result.messageId } };
1059
1287
  }
1060
1288
 
1061
- private async handleReply(input: ReplyInput): Promise<ToolResult> {
1289
+ private async handleReply(input: ReplyInput, call: ToolCall): Promise<ToolResult> {
1062
1290
  const replyCtx = this.replyContexts.get('default');
1063
1291
  if (!replyCtx) {
1064
1292
  return { success: false, error: 'No conversation context', isError: true };
@@ -1079,7 +1307,7 @@ export class DiscordModule implements Module {
1079
1307
  });
1080
1308
 
1081
1309
  // Track for thought-editing
1082
- this.lastSentMessage = { channelId: targetChannel, messageId: result.messageId };
1310
+ this.notePost(call.callerAgentName, call.callerTurnId, targetChannel, result.messageId);
1083
1311
 
1084
1312
  // Clear reply-to after sending
1085
1313
  replyCtx.replyToMessageId = undefined;
@@ -1213,6 +1441,11 @@ export class DiscordModule implements Module {
1213
1441
  authorId: m.authorId,
1214
1442
  isBot: m.isBot,
1215
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
+ : {}),
1216
1449
  timestamp: formatZonedDateTime(m.timestamp, this.timeZone),
1217
1450
  replyTo: m.replyTo,
1218
1451
  })),