@openclaw/discord 2026.9.5 → 2026.9.7

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 (517) hide show
  1. package/assets/icon.png +0 -0
  2. package/dist/.setup/{account-inspect-BwQj24ht.mjs → account-inspect-De8hOUxG.mjs} +1 -1
  3. package/dist/.setup/{accounts-CwJQoLjM.mjs → accounts-ChaMcixG.mjs} +1 -4
  4. package/dist/.setup/{activities-api-DBwRt5ES.mjs → activities-api-tvbsU2e3.mjs} +38 -66
  5. package/dist/.setup/{api-CBK9zcq5.mjs → api-DVbJwZVt.mjs} +10 -2
  6. package/dist/.setup/{approval-handler.runtime-Du3n5ypX.mjs → approval-handler.runtime-DxCK2Rux.mjs} +49 -125
  7. package/dist/.setup/{approval-message-updates-BN7JtScm.mjs → approval-message-updates-BKFqavHZ.mjs} +2 -2
  8. package/dist/.setup/{audit-C8uaKoa9.mjs → audit-CLg9I71N.mjs} +5 -5
  9. package/dist/.setup/{channel-ChKdlBgH.mjs → channel-DxlUVU9t.mjs} +125 -228
  10. package/dist/.setup/{channel-type-DKnjV1XW.mjs → channel-type-DRCrEMss.mjs} +22 -22
  11. package/dist/.setup/{channel.setup-BlC3-Kzz.mjs → channel.setup-CRo1GjV7.mjs} +6 -9
  12. package/dist/.setup/{components-MqMWUWnE.mjs → components-Cq1PvIpN.mjs} +42 -71
  13. package/dist/.setup/{config-schema-CiZz-mtA.mjs → config-schema-oxELUSDx.mjs} +19 -44
  14. package/dist/.setup/{conversation-binding-route-_rz33QHO.mjs → conversation-binding-route-Caz_XuFH.mjs} +14 -6
  15. package/dist/.setup/{directory-config-BytTftz-.mjs → directory-config-esqNn0Eo.mjs} +6 -9
  16. package/dist/.setup/{directory-live--EGTH0DC.mjs → directory-live-DtKRHuGV.mjs} +6 -12
  17. package/dist/.setup/{discord-BXpHW-cu.mjs → discord-0xJYfdDD.mjs} +82 -386
  18. package/dist/.setup/{doctor-DxcdkXzz.mjs → doctor-BCl1H5tl.mjs} +21 -36
  19. package/dist/.setup/{doctor-contract-Co5vRCZ6.mjs → doctor-contract-CvvgwrrG.mjs} +41 -50
  20. package/dist/.setup/{channel-actions.runtime-CJmiFfps.mjs → handle-action-CUvQWnE7.mjs} +74 -105
  21. package/dist/.setup/{handle-action.guild-admin-DAFyh_yV.mjs → handle-action.guild-admin-Df-8gVle.mjs} +63 -121
  22. package/dist/.setup/{live-policy-config-eKQ-PLdy.mjs → live-policy-config-8Pv20CHc.mjs} +2 -3
  23. package/dist/.setup/{message-handler-DnUrDpaU.mjs → message-handler-B-Jk4oDk.mjs} +18 -93
  24. package/dist/.setup/message-handler.preflight-pluralkit-CWLUBVcx.mjs +141 -0
  25. package/dist/.setup/{message-handler.preflight-CtqaF_fb.mjs → message-handler.preflight-v-__NSDq.mjs} +73 -287
  26. package/dist/.setup/{message-handler.process-Dz1xvuQU.mjs → message-handler.process-BNFFuChn.mjs} +423 -374
  27. package/dist/.setup/{outbound-adapter-C8v79z9Z.mjs → outbound-adapter-BobT-kse.mjs} +105 -19
  28. package/dist/.setup/{outbound-session-route-CqWbuMOm.mjs → outbound-session-route-zVGxxceg.mjs} +142 -109
  29. package/dist/.setup/{pluralkit-CdAt1G0P.mjs → pluralkit-a6_NLfH9.mjs} +1 -1
  30. package/dist/.setup/{preflight-audio-DrnqFA8U.mjs → preflight-audio-DHGIHEpv.mjs} +2 -1
  31. package/dist/.setup/{presence-cache-dYSHPWMx.mjs → presence-cache-Di3H3DIU.mjs} +0 -4
  32. package/dist/.setup/{probe-CupW4we4.mjs → probe-LYrIHlBF.mjs} +13 -4
  33. package/dist/.setup/{provider-72zIvN-i.mjs → provider-B_G5hASF.mjs} +1112 -1668
  34. package/dist/.setup/provider-session.runtime-BYlTBFD2.mjs +6 -0
  35. package/dist/.setup/provider.runtime-CUE3UxER.mjs +2 -0
  36. package/dist/.setup/{realtime-session.runtime-DTccTgTM.mjs → realtime-session.runtime-oUd9DOcz.mjs} +372 -345
  37. package/dist/.setup/receive-recovery-CHPOsnLc.mjs +514 -0
  38. package/dist/.setup/{resolve-allowlist-common-CwMBzbx9.mjs → resolve-allowlist-common-DPdRggu5.mjs} +4 -7
  39. package/dist/.setup/{resolve-channels-BbvsLQOZ.mjs → resolve-channels-BFPNRmVv.mjs} +21 -40
  40. package/dist/.setup/{resolve-users-ByFlR7LQ.mjs → resolve-users-0-aBuCy3.mjs} +4 -4
  41. package/dist/.setup/{retry-DBfcEgmO.mjs → retry-pz_cSha2.mjs} +81 -16
  42. package/dist/.setup/rolldown-runtime-B4FMCO8f.mjs +28 -0
  43. package/dist/.setup/{runtime-SchNfUsQ.mjs → runtime-FN000lxA.mjs} +83 -166
  44. package/dist/.setup/runtime-doctor-migrations-CshUGl36.mjs +159 -0
  45. package/dist/.setup/{runtime-BVoa7hhx.mjs → runtime-sUksZ--Q.mjs} +2 -5
  46. package/dist/.setup/{secret-config-contract-DFu9hfU8.mjs → secret-config-contract-uOE2J7yM.mjs} +15 -85
  47. package/dist/.setup/{security-audit-s5w50-Ly.mjs → security-audit-Cdaegq7C.mjs} +3 -1
  48. package/dist/.setup/{send-CKDczUNL.mjs → send-CrfEI6Bs.mjs} +73 -114
  49. package/dist/.setup/{send.components-DWQjXhPV.mjs → send.components-DxQAMfES.mjs} +62 -107
  50. package/dist/.setup/{send.outbound-D0hQ7s50.mjs → send.outbound-BISKnb-a.mjs} +79 -154
  51. package/dist/.setup/{send.shared-Zwx6BxQ5.mjs → send.shared-DGFkbkQR.mjs} +10 -25
  52. package/dist/.setup/{sender-identity-0Ymgvmaj.mjs → sender-identity-B9X5Vb9R.mjs} +2 -3
  53. package/dist/.setup/setup-plugin-api-BQUBxbhe.mjs +3 -0
  54. package/dist/.setup/{shared-CaA3Vv4n.mjs → shared-B3wZ4hN-.mjs} +25 -32
  55. package/dist/.setup/{subagent-hooks-Bired9q6.mjs → subagent-hooks-nlUE9ow7.mjs} +5 -6
  56. package/dist/.setup/system-events-CdeZnvPV.mjs +33 -0
  57. package/dist/.setup/{target-resolver-B6MrxbYv.mjs → target-resolver-BuLapkhy.mjs} +9 -12
  58. package/dist/.setup/targets-0KUcEIYx.mjs +3 -0
  59. package/dist/.setup/{thread-bindings-CK5272V3.mjs → thread-bindings-D7TfgjR_.mjs} +33 -35
  60. package/dist/.setup/thread-bindings.manager-DN-NissX.mjs +819 -0
  61. package/dist/.setup/thread-bindings.session-updates-CshfKghV.mjs +359 -0
  62. package/dist/.setup/{thread-bindings.state-BThFQEga.mjs → thread-bindings.state-g6v9zAym.mjs} +21 -62
  63. package/dist/.setup/{transcripts-source-CuWYgayu.mjs → transcripts-source-p8EV179h.mjs} +133 -238
  64. package/dist/.setup/{typing-BKZL5fGj.mjs → typing-BiHCzBRu.mjs} +2 -1
  65. package/dist/.setup/{voice-runtime-DHVQ2mFz.mjs → voice-runtime-B46rcwrG.mjs} +633 -1085
  66. package/dist/account-inspect-api.js +1 -1
  67. package/dist/action-runtime-api.js +1 -1
  68. package/dist/activities-api.js +1 -1
  69. package/dist/api.js +18 -18
  70. package/dist/channel-config-api.js +1 -1
  71. package/dist/channel-plugin-api.js +1 -1
  72. package/dist/directory-contract-api.js +1 -1
  73. package/dist/doctor-contract-api.js +4 -4
  74. package/dist/index.js +1 -1
  75. package/dist/runtime-api.js +20 -20
  76. package/dist/secret-contract-api.js +1 -1
  77. package/dist/security-audit-contract-api.js +1 -1
  78. package/dist/setup-entry.js +1 -1
  79. package/dist/setup-plugin-api.js +1 -1
  80. package/dist/src/voice/audio-worker.runtime.js +1056 -0
  81. package/dist/subagent-hooks-api.js +3 -4
  82. package/dist/transcripts-source-api.js +1 -1
  83. package/node_modules/@napi-rs/wasm-runtime/dist/emnapi-plugins.cjs +8 -4
  84. package/node_modules/@napi-rs/wasm-runtime/dist/emnapi-plugins.js +8 -4
  85. package/node_modules/@napi-rs/wasm-runtime/dist/fs-proxy.cjs +1 -1
  86. package/node_modules/@napi-rs/wasm-runtime/dist/fs.js +770 -695
  87. package/node_modules/@napi-rs/wasm-runtime/fs-proxy.js +3 -2
  88. package/node_modules/@napi-rs/wasm-runtime/package.json +1 -1
  89. package/node_modules/@tybys/wasm-util/LICENSE +21 -0
  90. package/node_modules/@tybys/wasm-util/package.json +1 -1
  91. package/node_modules/@types/node/README.md +2 -2
  92. package/node_modules/@types/node/child_process.d.ts +1 -1
  93. package/node_modules/@types/node/crypto.d.ts +20 -8
  94. package/node_modules/@types/node/ffi.d.ts +14 -0
  95. package/node_modules/@types/node/http2.d.ts +3 -2
  96. package/node_modules/@types/node/net.d.ts +16 -4
  97. package/node_modules/@types/node/package.json +2 -17
  98. package/node_modules/@types/node/process.d.ts +1 -0
  99. package/node_modules/@types/node/quic.d.ts +39 -1
  100. package/node_modules/@types/node/stream/iter.d.ts +9 -12
  101. package/node_modules/@types/node/test/reporters.d.ts +1 -0
  102. package/node_modules/@types/node/test.d.ts +72 -0
  103. package/node_modules/@types/node/tls.d.ts +14 -10
  104. package/node_modules/@types/node/vm.d.ts +2 -1
  105. package/node_modules/@types/node/web-globals/streams.d.ts +4 -0
  106. package/node_modules/@types/node/worker_threads.d.ts +4 -1
  107. package/node_modules/typebox/build/compile/code.mjs +1 -2
  108. package/node_modules/typebox/build/compile/validator.mjs +5 -1
  109. package/node_modules/typebox/build/format/iri.mjs +16 -9
  110. package/node_modules/typebox/build/guard/emit.mjs +2 -2
  111. package/node_modules/typebox/build/guard/guard.d.mts +7 -5
  112. package/node_modules/typebox/build/guard/guard.mjs +14 -9
  113. package/node_modules/typebox/build/guard/index.mjs +6 -0
  114. package/node_modules/typebox/build/guard/unicode/unicode.d.mts +6 -0
  115. package/node_modules/typebox/build/guard/unicode/unicode.mjs +35 -0
  116. package/node_modules/typebox/build/guard/{string.mjs → unicode/unicode_segment.mjs} +16 -19
  117. package/node_modules/typebox/build/schema/build.mjs +2 -3
  118. package/node_modules/typebox/build/schema/engine/_pathing.d.mts +1 -0
  119. package/node_modules/typebox/build/schema/engine/_pathing.mjs +11 -0
  120. package/node_modules/typebox/build/schema/engine/_refine.mjs +13 -5
  121. package/node_modules/typebox/build/schema/engine/additionalProperties.mjs +2 -1
  122. package/node_modules/typebox/build/schema/engine/dependencies.mjs +2 -1
  123. package/node_modules/typebox/build/schema/engine/dependentSchemas.mjs +2 -1
  124. package/node_modules/typebox/build/schema/engine/dynamicRef.d.mts +1 -1
  125. package/node_modules/typebox/build/schema/engine/dynamicRef.mjs +2 -2
  126. package/node_modules/typebox/build/schema/engine/format.mjs +9 -2
  127. package/node_modules/typebox/build/schema/engine/patternProperties.mjs +3 -2
  128. package/node_modules/typebox/build/schema/engine/properties.mjs +3 -2
  129. package/node_modules/typebox/build/schema/engine/propertyNames.mjs +2 -1
  130. package/node_modules/typebox/build/schema/engine/recursiveRef.d.mts +1 -1
  131. package/node_modules/typebox/build/schema/engine/recursiveRef.mjs +2 -2
  132. package/node_modules/typebox/build/schema/engine/ref.d.mts +1 -1
  133. package/node_modules/typebox/build/schema/engine/ref.mjs +2 -2
  134. package/node_modules/typebox/build/schema/engine/schema.mjs +24 -24
  135. package/node_modules/typebox/build/schema/parse.mjs +3 -0
  136. package/node_modules/typebox/build/schema/pointer/pointer.d.mts +1 -6
  137. package/node_modules/typebox/build/schema/pointer/pointer.mjs +47 -64
  138. package/node_modules/typebox/build/system/settings/internal.d.mts +2 -0
  139. package/node_modules/typebox/build/system/settings/internal.mjs +20 -0
  140. package/node_modules/typebox/build/system/settings/settings.d.mts +11 -0
  141. package/node_modules/typebox/build/system/settings/settings.mjs +14 -0
  142. package/node_modules/typebox/build/type/extends/inference.d.mts +1 -1
  143. package/node_modules/typebox/build/type/extends/inference.mjs +15 -2
  144. package/node_modules/typebox/build/type/extends/tuple.d.mts +2 -1
  145. package/node_modules/typebox/build/type/extends/tuple.mjs +21 -1
  146. package/node_modules/typebox/build/value/parse/parse.mjs +10 -4
  147. package/node_modules/typebox/package.json +1 -1
  148. package/node_modules/typebox/readme.md +3 -1
  149. package/node_modules/zod/README.md +2 -2
  150. package/node_modules/zod/compile.cjs +19 -0
  151. package/node_modules/zod/index.cjs +19 -0
  152. package/node_modules/zod/locales/index.cjs +19 -0
  153. package/node_modules/zod/mini/index.cjs +19 -0
  154. package/node_modules/zod/package.json +8 -7
  155. package/node_modules/zod/src/v3/helpers/errorUtil.ts +1 -1
  156. package/node_modules/zod/src/v4/classic/external.ts +2 -0
  157. package/node_modules/zod/src/v4/classic/from-json-schema.ts +248 -25
  158. package/node_modules/zod/src/v4/classic/schemas.ts +243 -168
  159. package/node_modules/zod/src/v4/classic/tests/assignability.test.ts +60 -9
  160. package/node_modules/zod/src/v4/classic/tests/bigint.test.ts +6 -0
  161. package/node_modules/zod/src/v4/classic/tests/continuability.test.ts +2 -2
  162. package/node_modules/zod/src/v4/classic/tests/cyclic-data.test.ts +265 -0
  163. package/node_modules/zod/src/v4/classic/tests/discriminated-unions.test.ts +112 -6
  164. package/node_modules/zod/src/v4/classic/tests/enum.test.ts +9 -0
  165. package/node_modules/zod/src/v4/classic/tests/error.test.ts +130 -1
  166. package/node_modules/zod/src/v4/classic/tests/from-json-schema.test.ts +157 -0
  167. package/node_modules/zod/src/v4/classic/tests/iban.test.ts +81 -0
  168. package/node_modules/zod/src/v4/classic/tests/instance-footprint.test.ts +40 -2
  169. package/node_modules/zod/src/v4/classic/tests/instanceof.test.ts +27 -7
  170. package/node_modules/zod/src/v4/classic/tests/issue-schema.test.ts +88 -56
  171. package/node_modules/zod/src/v4/classic/tests/number.test.ts +39 -0
  172. package/node_modules/zod/src/v4/classic/tests/object.test.ts +56 -0
  173. package/node_modules/zod/src/v4/classic/tests/optin-ladder.test.ts +3 -2
  174. package/node_modules/zod/src/v4/classic/tests/prefault.test.ts +70 -0
  175. package/node_modules/zod/src/v4/classic/tests/properties.test.ts +141 -0
  176. package/node_modules/zod/src/v4/classic/tests/recursive-types.test.ts +46 -1
  177. package/node_modules/zod/src/v4/classic/tests/standard-schema.test.ts +19 -0
  178. package/node_modules/zod/src/v4/classic/tests/string.test.ts +95 -1
  179. package/node_modules/zod/src/v4/classic/tests/template-literal.test.ts +33 -1
  180. package/node_modules/zod/src/v4/classic/tests/to-json-schema.test.ts +234 -38
  181. package/node_modules/zod/src/v4/classic/tests/validate.test.ts +569 -0
  182. package/node_modules/zod/src/v4/core/api.ts +44 -28
  183. package/node_modules/zod/src/v4/core/checks.ts +62 -102
  184. package/node_modules/zod/src/v4/core/compile.ts +218 -93
  185. package/node_modules/zod/src/v4/core/core.ts +1 -3
  186. package/node_modules/zod/src/v4/core/doc.ts +6 -2
  187. package/node_modules/zod/src/v4/core/errors.ts +3 -6
  188. package/node_modules/zod/src/v4/core/json-schema-generator.ts +2 -2
  189. package/node_modules/zod/src/v4/core/json-schema-processors.ts +185 -81
  190. package/node_modules/zod/src/v4/core/memoizer.ts +75 -28
  191. package/node_modules/zod/src/v4/core/parse.ts +37 -16
  192. package/node_modules/zod/src/v4/core/regexes.ts +14 -4
  193. package/node_modules/zod/src/v4/core/schemas.ts +296 -132
  194. package/node_modules/zod/src/v4/core/tests/cached.test.ts +54 -0
  195. package/node_modules/zod/src/v4/core/tests/compile-differential.test.ts +35 -0
  196. package/node_modules/zod/src/v4/core/tests/compile-generative.test.ts +445 -0
  197. package/node_modules/zod/src/v4/core/tests/compile.test.ts +399 -2
  198. package/node_modules/zod/src/v4/core/tests/email-regex.test.ts +140 -0
  199. package/node_modules/zod/src/v4/core/tests/locales/tg.test.ts +85 -0
  200. package/node_modules/zod/src/v4/core/tests/polyfill-collision.test.ts +46 -0
  201. package/node_modules/zod/src/v4/core/tests/url-no-canparse.test.ts +118 -16
  202. package/node_modules/zod/src/v4/core/to-json-schema.ts +9 -7
  203. package/node_modules/zod/src/v4/core/util.ts +218 -147
  204. package/node_modules/zod/src/v4/core/versions.ts +2 -2
  205. package/node_modules/zod/src/v4/locales/ar.ts +2 -0
  206. package/node_modules/zod/src/v4/locales/az.ts +2 -0
  207. package/node_modules/zod/src/v4/locales/be.ts +2 -0
  208. package/node_modules/zod/src/v4/locales/bg.ts +2 -0
  209. package/node_modules/zod/src/v4/locales/bn.ts +2 -0
  210. package/node_modules/zod/src/v4/locales/ca.ts +2 -0
  211. package/node_modules/zod/src/v4/locales/ckb.ts +2 -0
  212. package/node_modules/zod/src/v4/locales/cs.ts +2 -0
  213. package/node_modules/zod/src/v4/locales/da.ts +2 -0
  214. package/node_modules/zod/src/v4/locales/de.ts +2 -0
  215. package/node_modules/zod/src/v4/locales/el.ts +2 -0
  216. package/node_modules/zod/src/v4/locales/en.ts +2 -0
  217. package/node_modules/zod/src/v4/locales/eo.ts +2 -0
  218. package/node_modules/zod/src/v4/locales/es.ts +2 -0
  219. package/node_modules/zod/src/v4/locales/fa.ts +2 -0
  220. package/node_modules/zod/src/v4/locales/fi.ts +2 -0
  221. package/node_modules/zod/src/v4/locales/fr-CA.ts +2 -0
  222. package/node_modules/zod/src/v4/locales/fr.ts +2 -0
  223. package/node_modules/zod/src/v4/locales/gu.ts +2 -0
  224. package/node_modules/zod/src/v4/locales/he.ts +2 -0
  225. package/node_modules/zod/src/v4/locales/hi.ts +2 -0
  226. package/node_modules/zod/src/v4/locales/hr.ts +2 -0
  227. package/node_modules/zod/src/v4/locales/hu.ts +2 -0
  228. package/node_modules/zod/src/v4/locales/hy.ts +2 -0
  229. package/node_modules/zod/src/v4/locales/id.ts +2 -0
  230. package/node_modules/zod/src/v4/locales/index.ts +1 -0
  231. package/node_modules/zod/src/v4/locales/is.ts +2 -0
  232. package/node_modules/zod/src/v4/locales/it.ts +2 -0
  233. package/node_modules/zod/src/v4/locales/ja.ts +2 -0
  234. package/node_modules/zod/src/v4/locales/ka.ts +2 -0
  235. package/node_modules/zod/src/v4/locales/km.ts +2 -0
  236. package/node_modules/zod/src/v4/locales/kn.ts +2 -0
  237. package/node_modules/zod/src/v4/locales/ko.ts +2 -0
  238. package/node_modules/zod/src/v4/locales/lt.ts +2 -0
  239. package/node_modules/zod/src/v4/locales/mk.ts +2 -0
  240. package/node_modules/zod/src/v4/locales/ms.ts +2 -0
  241. package/node_modules/zod/src/v4/locales/ne.ts +2 -0
  242. package/node_modules/zod/src/v4/locales/nl.ts +2 -0
  243. package/node_modules/zod/src/v4/locales/nn.ts +2 -0
  244. package/node_modules/zod/src/v4/locales/no.ts +2 -0
  245. package/node_modules/zod/src/v4/locales/ota.ts +2 -0
  246. package/node_modules/zod/src/v4/locales/pl.ts +2 -0
  247. package/node_modules/zod/src/v4/locales/ps.ts +2 -0
  248. package/node_modules/zod/src/v4/locales/pt-BR.ts +2 -0
  249. package/node_modules/zod/src/v4/locales/pt.ts +2 -0
  250. package/node_modules/zod/src/v4/locales/ro.ts +2 -0
  251. package/node_modules/zod/src/v4/locales/ru.ts +2 -0
  252. package/node_modules/zod/src/v4/locales/sk.ts +2 -0
  253. package/node_modules/zod/src/v4/locales/sl.ts +2 -0
  254. package/node_modules/zod/src/v4/locales/sv.ts +2 -0
  255. package/node_modules/zod/src/v4/locales/ta.ts +2 -0
  256. package/node_modules/zod/src/v4/locales/tg.ts +135 -0
  257. package/node_modules/zod/src/v4/locales/th.ts +2 -0
  258. package/node_modules/zod/src/v4/locales/tk.ts +2 -0
  259. package/node_modules/zod/src/v4/locales/tr.ts +2 -0
  260. package/node_modules/zod/src/v4/locales/uk.ts +2 -0
  261. package/node_modules/zod/src/v4/locales/ur.ts +2 -0
  262. package/node_modules/zod/src/v4/locales/uz.ts +2 -0
  263. package/node_modules/zod/src/v4/locales/vi.ts +2 -0
  264. package/node_modules/zod/src/v4/locales/yo.ts +2 -0
  265. package/node_modules/zod/src/v4/locales/zh-CN.ts +2 -0
  266. package/node_modules/zod/src/v4/locales/zh-TW.ts +2 -0
  267. package/node_modules/zod/src/v4/mini/external.ts +2 -0
  268. package/node_modules/zod/src/v4/mini/schemas.ts +32 -7
  269. package/node_modules/zod/src/v4/mini/tests/checks.test.ts +1 -1
  270. package/node_modules/zod/src/v4/mini/tests/computed.test.ts +11 -17
  271. package/node_modules/zod/src/v4/mini/tests/index.test.ts +86 -0
  272. package/node_modules/zod/src/v4/mini/tests/recursive-types.test.ts +16 -0
  273. package/node_modules/zod/src/v4/mini/tests/string.test.ts +23 -0
  274. package/node_modules/zod/v3/ZodError.cjs +19 -0
  275. package/node_modules/zod/v3/errors.cjs +19 -0
  276. package/node_modules/zod/v3/external.cjs +19 -0
  277. package/node_modules/zod/v3/helpers/enumUtil.cjs +19 -0
  278. package/node_modules/zod/v3/helpers/errorUtil.cjs +20 -1
  279. package/node_modules/zod/v3/helpers/errorUtil.js +1 -1
  280. package/node_modules/zod/v3/helpers/parseUtil.cjs +19 -0
  281. package/node_modules/zod/v3/helpers/partialUtil.cjs +19 -0
  282. package/node_modules/zod/v3/helpers/typeAliases.cjs +19 -0
  283. package/node_modules/zod/v3/helpers/util.cjs +19 -0
  284. package/node_modules/zod/v3/index.cjs +19 -0
  285. package/node_modules/zod/v3/standard-schema.cjs +19 -0
  286. package/node_modules/zod/v3/types.cjs +19 -0
  287. package/node_modules/zod/v4/classic/checks.cjs +19 -0
  288. package/node_modules/zod/v4/classic/coerce.cjs +19 -0
  289. package/node_modules/zod/v4/classic/compat.cjs +19 -0
  290. package/node_modules/zod/v4/classic/deep-partial.cjs +19 -0
  291. package/node_modules/zod/v4/classic/errors.cjs +19 -0
  292. package/node_modules/zod/v4/classic/external.cjs +22 -1
  293. package/node_modules/zod/v4/classic/external.d.cts +1 -1
  294. package/node_modules/zod/v4/classic/external.d.ts +1 -1
  295. package/node_modules/zod/v4/classic/external.js +1 -1
  296. package/node_modules/zod/v4/classic/from-json-schema.cjs +264 -24
  297. package/node_modules/zod/v4/classic/from-json-schema.js +245 -24
  298. package/node_modules/zod/v4/classic/in-out.cjs +19 -0
  299. package/node_modules/zod/v4/classic/index.cjs +19 -0
  300. package/node_modules/zod/v4/classic/iso.cjs +19 -0
  301. package/node_modules/zod/v4/classic/parse.cjs +19 -0
  302. package/node_modules/zod/v4/classic/schemas.cjs +100 -35
  303. package/node_modules/zod/v4/classic/schemas.d.cts +15 -1
  304. package/node_modules/zod/v4/classic/schemas.d.ts +15 -1
  305. package/node_modules/zod/v4/classic/schemas.js +77 -33
  306. package/node_modules/zod/v4/core/api.cjs +45 -22
  307. package/node_modules/zod/v4/core/api.d.cts +12 -6
  308. package/node_modules/zod/v4/core/api.d.ts +12 -6
  309. package/node_modules/zod/v4/core/api.js +25 -22
  310. package/node_modules/zod/v4/core/checks.cjs +51 -97
  311. package/node_modules/zod/v4/core/checks.d.cts +17 -1
  312. package/node_modules/zod/v4/core/checks.d.ts +17 -1
  313. package/node_modules/zod/v4/core/checks.js +31 -96
  314. package/node_modules/zod/v4/core/compile.cjs +173 -78
  315. package/node_modules/zod/v4/core/compile.d.cts +18 -4
  316. package/node_modules/zod/v4/core/compile.d.ts +18 -4
  317. package/node_modules/zod/v4/core/compile.js +154 -79
  318. package/node_modules/zod/v4/core/core.cjs +20 -1
  319. package/node_modules/zod/v4/core/core.js +1 -1
  320. package/node_modules/zod/v4/core/doc.cjs +26 -2
  321. package/node_modules/zod/v4/core/doc.js +7 -2
  322. package/node_modules/zod/v4/core/errors.cjs +21 -5
  323. package/node_modules/zod/v4/core/errors.js +2 -5
  324. package/node_modules/zod/v4/core/index.cjs +19 -0
  325. package/node_modules/zod/v4/core/json-schema-generator.cjs +20 -1
  326. package/node_modules/zod/v4/core/json-schema-generator.js +2 -2
  327. package/node_modules/zod/v4/core/json-schema-processors.cjs +188 -72
  328. package/node_modules/zod/v4/core/json-schema-processors.d.cts +16 -0
  329. package/node_modules/zod/v4/core/json-schema-processors.d.ts +16 -0
  330. package/node_modules/zod/v4/core/json-schema-processors.js +170 -74
  331. package/node_modules/zod/v4/core/json-schema.cjs +19 -0
  332. package/node_modules/zod/v4/core/memoizer.cjs +111 -23
  333. package/node_modules/zod/v4/core/memoizer.js +69 -23
  334. package/node_modules/zod/v4/core/parse.cjs +56 -16
  335. package/node_modules/zod/v4/core/parse.js +37 -16
  336. package/node_modules/zod/v4/core/regexes.cjs +31 -6
  337. package/node_modules/zod/v4/core/regexes.d.cts +3 -0
  338. package/node_modules/zod/v4/core/regexes.d.ts +3 -0
  339. package/node_modules/zod/v4/core/regexes.js +10 -4
  340. package/node_modules/zod/v4/core/registries.cjs +19 -0
  341. package/node_modules/zod/v4/core/schemas.cjs +302 -114
  342. package/node_modules/zod/v4/core/schemas.d.cts +28 -8
  343. package/node_modules/zod/v4/core/schemas.d.ts +28 -8
  344. package/node_modules/zod/v4/core/schemas.js +279 -113
  345. package/node_modules/zod/v4/core/standard-schema.cjs +19 -0
  346. package/node_modules/zod/v4/core/to-json-schema.cjs +28 -7
  347. package/node_modules/zod/v4/core/to-json-schema.d.cts +4 -3
  348. package/node_modules/zod/v4/core/to-json-schema.d.ts +4 -3
  349. package/node_modules/zod/v4/core/to-json-schema.js +7 -6
  350. package/node_modules/zod/v4/core/util.cjs +177 -143
  351. package/node_modules/zod/v4/core/util.d.cts +25 -4
  352. package/node_modules/zod/v4/core/util.d.ts +25 -4
  353. package/node_modules/zod/v4/core/util.js +156 -143
  354. package/node_modules/zod/v4/core/versions.cjs +21 -2
  355. package/node_modules/zod/v4/core/versions.d.cts +1 -1
  356. package/node_modules/zod/v4/core/versions.d.ts +1 -1
  357. package/node_modules/zod/v4/core/versions.js +2 -2
  358. package/node_modules/zod/v4/core/visit.cjs +19 -0
  359. package/node_modules/zod/v4/index.cjs +19 -0
  360. package/node_modules/zod/v4/locales/ar.cjs +2 -0
  361. package/node_modules/zod/v4/locales/ar.js +2 -0
  362. package/node_modules/zod/v4/locales/az.cjs +2 -0
  363. package/node_modules/zod/v4/locales/az.js +2 -0
  364. package/node_modules/zod/v4/locales/be.cjs +2 -0
  365. package/node_modules/zod/v4/locales/be.js +2 -0
  366. package/node_modules/zod/v4/locales/bg.cjs +2 -0
  367. package/node_modules/zod/v4/locales/bg.js +2 -0
  368. package/node_modules/zod/v4/locales/bn.cjs +2 -0
  369. package/node_modules/zod/v4/locales/bn.js +2 -0
  370. package/node_modules/zod/v4/locales/ca.cjs +2 -0
  371. package/node_modules/zod/v4/locales/ca.js +2 -0
  372. package/node_modules/zod/v4/locales/ckb.cjs +2 -0
  373. package/node_modules/zod/v4/locales/ckb.js +2 -0
  374. package/node_modules/zod/v4/locales/cs.cjs +2 -0
  375. package/node_modules/zod/v4/locales/cs.js +2 -0
  376. package/node_modules/zod/v4/locales/da.cjs +2 -0
  377. package/node_modules/zod/v4/locales/da.js +2 -0
  378. package/node_modules/zod/v4/locales/de.cjs +2 -0
  379. package/node_modules/zod/v4/locales/de.js +2 -0
  380. package/node_modules/zod/v4/locales/el.cjs +2 -0
  381. package/node_modules/zod/v4/locales/el.js +2 -0
  382. package/node_modules/zod/v4/locales/en.cjs +2 -0
  383. package/node_modules/zod/v4/locales/en.js +2 -0
  384. package/node_modules/zod/v4/locales/eo.cjs +2 -0
  385. package/node_modules/zod/v4/locales/eo.js +2 -0
  386. package/node_modules/zod/v4/locales/es.cjs +2 -0
  387. package/node_modules/zod/v4/locales/es.js +2 -0
  388. package/node_modules/zod/v4/locales/fa.cjs +2 -0
  389. package/node_modules/zod/v4/locales/fa.js +2 -0
  390. package/node_modules/zod/v4/locales/fi.cjs +2 -0
  391. package/node_modules/zod/v4/locales/fi.js +2 -0
  392. package/node_modules/zod/v4/locales/fr-CA.cjs +2 -0
  393. package/node_modules/zod/v4/locales/fr-CA.js +2 -0
  394. package/node_modules/zod/v4/locales/fr.cjs +2 -0
  395. package/node_modules/zod/v4/locales/fr.js +2 -0
  396. package/node_modules/zod/v4/locales/gu.cjs +2 -0
  397. package/node_modules/zod/v4/locales/gu.js +2 -0
  398. package/node_modules/zod/v4/locales/he.cjs +2 -0
  399. package/node_modules/zod/v4/locales/he.js +2 -0
  400. package/node_modules/zod/v4/locales/hi.cjs +2 -0
  401. package/node_modules/zod/v4/locales/hi.js +2 -0
  402. package/node_modules/zod/v4/locales/hr.cjs +2 -0
  403. package/node_modules/zod/v4/locales/hr.js +2 -0
  404. package/node_modules/zod/v4/locales/hu.cjs +2 -0
  405. package/node_modules/zod/v4/locales/hu.js +2 -0
  406. package/node_modules/zod/v4/locales/hy.cjs +2 -0
  407. package/node_modules/zod/v4/locales/hy.js +2 -0
  408. package/node_modules/zod/v4/locales/id.cjs +2 -0
  409. package/node_modules/zod/v4/locales/id.js +2 -0
  410. package/node_modules/zod/v4/locales/index.cjs +22 -1
  411. package/node_modules/zod/v4/locales/index.d.cts +1 -0
  412. package/node_modules/zod/v4/locales/index.d.ts +1 -0
  413. package/node_modules/zod/v4/locales/index.js +1 -0
  414. package/node_modules/zod/v4/locales/is.cjs +2 -0
  415. package/node_modules/zod/v4/locales/is.js +2 -0
  416. package/node_modules/zod/v4/locales/it.cjs +2 -0
  417. package/node_modules/zod/v4/locales/it.js +2 -0
  418. package/node_modules/zod/v4/locales/ja.cjs +2 -0
  419. package/node_modules/zod/v4/locales/ja.js +2 -0
  420. package/node_modules/zod/v4/locales/ka.cjs +2 -0
  421. package/node_modules/zod/v4/locales/ka.js +2 -0
  422. package/node_modules/zod/v4/locales/km.cjs +2 -0
  423. package/node_modules/zod/v4/locales/km.js +2 -0
  424. package/node_modules/zod/v4/locales/kn.cjs +2 -0
  425. package/node_modules/zod/v4/locales/kn.js +2 -0
  426. package/node_modules/zod/v4/locales/ko.cjs +2 -0
  427. package/node_modules/zod/v4/locales/ko.js +2 -0
  428. package/node_modules/zod/v4/locales/lt.cjs +2 -0
  429. package/node_modules/zod/v4/locales/lt.js +2 -0
  430. package/node_modules/zod/v4/locales/mk.cjs +2 -0
  431. package/node_modules/zod/v4/locales/mk.js +2 -0
  432. package/node_modules/zod/v4/locales/ms.cjs +2 -0
  433. package/node_modules/zod/v4/locales/ms.js +2 -0
  434. package/node_modules/zod/v4/locales/ne.cjs +2 -0
  435. package/node_modules/zod/v4/locales/ne.js +2 -0
  436. package/node_modules/zod/v4/locales/nl.cjs +2 -0
  437. package/node_modules/zod/v4/locales/nl.js +2 -0
  438. package/node_modules/zod/v4/locales/nn.cjs +2 -0
  439. package/node_modules/zod/v4/locales/nn.js +2 -0
  440. package/node_modules/zod/v4/locales/no.cjs +2 -0
  441. package/node_modules/zod/v4/locales/no.js +2 -0
  442. package/node_modules/zod/v4/locales/ota.cjs +2 -0
  443. package/node_modules/zod/v4/locales/ota.js +2 -0
  444. package/node_modules/zod/v4/locales/pl.cjs +2 -0
  445. package/node_modules/zod/v4/locales/pl.js +2 -0
  446. package/node_modules/zod/v4/locales/ps.cjs +2 -0
  447. package/node_modules/zod/v4/locales/ps.js +2 -0
  448. package/node_modules/zod/v4/locales/pt-BR.cjs +2 -0
  449. package/node_modules/zod/v4/locales/pt-BR.js +2 -0
  450. package/node_modules/zod/v4/locales/pt.cjs +2 -0
  451. package/node_modules/zod/v4/locales/pt.js +2 -0
  452. package/node_modules/zod/v4/locales/ro.cjs +2 -0
  453. package/node_modules/zod/v4/locales/ro.js +2 -0
  454. package/node_modules/zod/v4/locales/ru.cjs +2 -0
  455. package/node_modules/zod/v4/locales/ru.js +2 -0
  456. package/node_modules/zod/v4/locales/sk.cjs +2 -0
  457. package/node_modules/zod/v4/locales/sk.js +2 -0
  458. package/node_modules/zod/v4/locales/sl.cjs +2 -0
  459. package/node_modules/zod/v4/locales/sl.js +2 -0
  460. package/node_modules/zod/v4/locales/sv.cjs +2 -0
  461. package/node_modules/zod/v4/locales/sv.js +2 -0
  462. package/node_modules/zod/v4/locales/ta.cjs +2 -0
  463. package/node_modules/zod/v4/locales/ta.js +2 -0
  464. package/node_modules/zod/v4/locales/tg.cjs +144 -0
  465. package/node_modules/zod/v4/locales/tg.d.cts +5 -0
  466. package/node_modules/zod/v4/locales/tg.d.ts +4 -0
  467. package/node_modules/zod/v4/locales/tg.js +117 -0
  468. package/node_modules/zod/v4/locales/th.cjs +2 -0
  469. package/node_modules/zod/v4/locales/th.js +2 -0
  470. package/node_modules/zod/v4/locales/tk.cjs +2 -0
  471. package/node_modules/zod/v4/locales/tk.js +2 -0
  472. package/node_modules/zod/v4/locales/tr.cjs +2 -0
  473. package/node_modules/zod/v4/locales/tr.js +2 -0
  474. package/node_modules/zod/v4/locales/uk.cjs +2 -0
  475. package/node_modules/zod/v4/locales/uk.js +2 -0
  476. package/node_modules/zod/v4/locales/ur.cjs +2 -0
  477. package/node_modules/zod/v4/locales/ur.js +2 -0
  478. package/node_modules/zod/v4/locales/uz.cjs +2 -0
  479. package/node_modules/zod/v4/locales/uz.js +2 -0
  480. package/node_modules/zod/v4/locales/vi.cjs +2 -0
  481. package/node_modules/zod/v4/locales/vi.js +2 -0
  482. package/node_modules/zod/v4/locales/yo.cjs +2 -0
  483. package/node_modules/zod/v4/locales/yo.js +2 -0
  484. package/node_modules/zod/v4/locales/zh-CN.cjs +2 -0
  485. package/node_modules/zod/v4/locales/zh-CN.js +2 -0
  486. package/node_modules/zod/v4/locales/zh-TW.cjs +2 -0
  487. package/node_modules/zod/v4/locales/zh-TW.js +2 -0
  488. package/node_modules/zod/v4/mini/checks.cjs +19 -0
  489. package/node_modules/zod/v4/mini/coerce.cjs +19 -0
  490. package/node_modules/zod/v4/mini/deep-partial.cjs +19 -0
  491. package/node_modules/zod/v4/mini/external.cjs +22 -1
  492. package/node_modules/zod/v4/mini/external.d.cts +1 -1
  493. package/node_modules/zod/v4/mini/external.d.ts +1 -1
  494. package/node_modules/zod/v4/mini/external.js +1 -1
  495. package/node_modules/zod/v4/mini/in-out.cjs +19 -0
  496. package/node_modules/zod/v4/mini/index.cjs +19 -0
  497. package/node_modules/zod/v4/mini/iso.cjs +19 -0
  498. package/node_modules/zod/v4/mini/parse.cjs +19 -0
  499. package/node_modules/zod/v4/mini/schemas.cjs +44 -8
  500. package/node_modules/zod/v4/mini/schemas.d.cts +6 -1
  501. package/node_modules/zod/v4/mini/schemas.d.ts +6 -1
  502. package/node_modules/zod/v4/mini/schemas.js +21 -6
  503. package/node_modules/zod/v4-mini/index.cjs +19 -0
  504. package/openclaw.plugin.json +21 -1
  505. package/package.json +9 -6
  506. package/dist/.setup/agent-components.runtime-CEPrf2SY.mjs +0 -4
  507. package/dist/.setup/message-handler.history-CJOsN9w5.mjs +0 -28
  508. package/dist/.setup/probe.runtime-DBQ_AGPe.mjs +0 -2
  509. package/dist/.setup/provider-session.runtime-BW7QrF5C.mjs +0 -6
  510. package/dist/.setup/provider.runtime-DuhmKdDU.mjs +0 -2
  511. package/dist/.setup/security-audit.runtime-DHtYenx9.mjs +0 -2
  512. package/dist/.setup/setup-plugin-api-CINIEBLa.mjs +0 -3
  513. package/dist/.setup/system-events-B2YEEMbS.mjs +0 -34
  514. package/dist/.setup/targets-D1mAB5yO.mjs +0 -3
  515. package/dist/.setup/thread-bindings.manager-eexkKyrG.mjs +0 -678
  516. package/dist/.setup/thread-bindings.session-updates-DCQq1WZ5.mjs +0 -55
  517. /package/node_modules/typebox/build/guard/{string.d.mts → unicode/unicode_segment.d.mts} +0 -0
@@ -1,37 +1,38 @@
1
- import { ft as editChannelMessage, st as createChannelMessage, t as discord_exports, ut as deleteChannelMessage } from "./discord-BXpHW-cu.mjs";
2
- import { C as resolveTimestampMs, i as normalizeDiscordAllowList, o as normalizeDiscordSlug } from "./channel-type-DKnjV1XW.mjs";
3
- import { p as resolveDiscordMaxLinesPerMessage } from "./accounts-CwJQoLjM.mjs";
4
- import { b as resolveDiscordChannelId, o as chunkDiscordTextWithMode } from "./retry-DBfcEgmO.mjs";
5
- import { F as createDiscordRuntimeAccountContext, P as createDiscordRestClient, d as resolveDiscordTargetChannelId, k as resolveDiscordMessageFlags } from "./send.shared-Zwx6BxQ5.mjs";
6
- import { a as discordTextHasBroadcastMention } from "./send.outbound-D0hQ7s50.mjs";
7
- import { D as resolveDiscordMessageStickers, b as resolveDiscordMessageText, h as resolveDiscordThreadStarter, p as resolveDiscordAutoThreadReplyPlan, w as resolveReferencedReplyMediaList, x as formatDiscordMediaText } from "./transcripts-source-CuWYgayu.mjs";
8
- import { a as removeReactionDiscord, f as editMessageDiscord, r as reactMessageDiscord } from "./send-CKDczUNL.mjs";
1
+ import { C as withDiscordRequestAuthority, D as Message, Mt as getGuildMember, ct as createChannelMessage, dt as deleteChannelMessage, pt as editChannelMessage, t as discord_exports, vt as listChannelMessages } from "./discord-0xJYfdDD.mjs";
2
+ import { i as normalizeDiscordAllowList, o as normalizeDiscordSlug, w as resolveTimestampMs } from "./channel-type-DRCrEMss.mjs";
3
+ import { p as resolveDiscordMaxLinesPerMessage } from "./accounts-ChaMcixG.mjs";
4
+ import { o as chunkDiscordTextWithMode, x as resolveDiscordChannelId } from "./retry-pz_cSha2.mjs";
5
+ import { N as createDiscordRestClient, O as resolveDiscordMessageFlags, P as createDiscordRuntimeAccountContext, u as resolveDiscordTargetChannelId } from "./send.shared-DGFkbkQR.mjs";
6
+ import { a as discordTextHasBroadcastMention } from "./send.outbound-BISKnb-a.mjs";
7
+ import { C as resolveReferencedReplyMediaList, E as resolveDiscordMessageStickers, O as resolveDiscordReferencedReplyMessageId, _ as resolveDiscordMessageHistoryText, b as formatDiscordMediaText, f as resolveDiscordAutoThreadReplyPlan, m as resolveDiscordThreadStarter, y as resolveDiscordMessageText } from "./transcripts-source-p8EV179h.mjs";
8
+ import { a as removeReactionDiscord, r as reactMessageDiscord } from "./send-CrfEI6Bs.mjs";
9
9
  import { n as DISCORD_ATTACHMENT_TOTAL_TIMEOUT_MS, t as DISCORD_ATTACHMENT_IDLE_TIMEOUT_MS } from "./timeouts-D86uWLt_.mjs";
10
- import "./targets-D1mAB5yO.mjs";
11
- import { b as discordInboundEventDelivery, h as resolveDiscordConversationIdentity, u as buildDiscordRoutePeer } from "./outbound-session-route-CqWbuMOm.mjs";
12
- import { t as DISCORD_TEXT_CHUNK_LIMIT } from "./outbound-adapter-C8v79z9Z.mjs";
13
- import { a as formatDiscordReplySkip, c as buildGuildLabel, g as createDiscordSupplementalContextAccessChecker, h as buildDiscordInboundAccessContext, i as formatDiscordReplyDeliveryFailure, l as resolveReplyContext, o as sanitizeDiscordFrontChannelReplyPayloads, r as deliverDiscordReply, s as buildDirectLabel } from "./provider-72zIvN-i.mjs";
14
- import { n as resolveDiscordWebhookId } from "./sender-identity-0Ymgvmaj.mjs";
10
+ import "./targets-0KUcEIYx.mjs";
11
+ import { b as discordInboundEventDelivery, h as resolveDiscordConversationIdentity, u as buildDiscordRoutePeer } from "./outbound-session-route-zVGxxceg.mjs";
12
+ import { t as DISCORD_TEXT_CHUNK_LIMIT } from "./outbound-adapter-BobT-kse.mjs";
13
+ import { T as createDiscordSupplementalContextAccessChecker, a as formatDiscordReplySkip, c as buildGuildLabel, i as formatDiscordReplyDeliveryFailure, l as resolveReplyContext, o as sanitizeDiscordFrontChannelReplyPayloads, r as deliverDiscordReply, s as buildDirectLabel, w as buildDiscordInboundAccessContext } from "./provider-B_G5hASF.mjs";
14
+ import { n as resolveDiscordWebhookId, t as resolveDiscordSenderIdentity } from "./sender-identity-B9X5Vb9R.mjs";
15
15
  import { t as beginDiscordActiveTurnThreadRoute } from "./active-turn-thread-route-fmHl1HNd.mjs";
16
- import { n as filterDiscordHistoryEntriesForContext, t as createDiscordHistorySenderProvenance } from "./message-handler.history-CJOsN9w5.mjs";
17
- import { t as sendTyping } from "./typing-BKZL5fGj.mjs";
18
- import { expectDefined } from "openclaw/plugin-sdk/expect-runtime";
16
+ import { a as createDiscordHistorySenderProvenance, h as shouldIgnoreBoundThreadWebhookMessage, l as isBoundThreadBotSystemMessage, o as filterDiscordHistoryEntriesForContext, s as resolveDiscordHistoryMediaIds, t as resolveDiscordPreflightPluralKitInfo } from "./message-handler.preflight-pluralkit-CWLUBVcx.mjs";
17
+ import { t as sendTyping } from "./typing-BiHCzBRu.mjs";
19
18
  import { formatErrorMessage } from "openclaw/plugin-sdk/error-runtime";
20
19
  import { buildAgentSessionKey, resolveThreadSessionKeys } from "openclaw/plugin-sdk/routing";
20
+ import { normalizeOptionalString } from "openclaw/plugin-sdk/string-coerce-runtime";
21
21
  import { getReplyPayloadTtsSupplement, isReplyPayloadNonTerminalToolErrorWarning, resolveSendableOutboundReplyParts } from "openclaw/plugin-sdk/reply-payload";
22
22
  import { danger, logVerbose, shouldLogVerbose, sleepWithAbort } from "openclaw/plugin-sdk/runtime-env";
23
23
  import { truncateUtf16Safe } from "openclaw/plugin-sdk/text-utility-runtime";
24
24
  import { resolveChunkMode } from "openclaw/plugin-sdk/reply-chunking";
25
25
  import { resolveMarkdownTableMode } from "openclaw/plugin-sdk/markdown-table-runtime";
26
- import { convertMarkdownTables, stripInlineDirectiveTagsForDelivery, stripReasoningTagsFromText } from "openclaw/plugin-sdk/text-chunking";
27
- import { bindIngressLifecycleToReplyOptions, createChannelMessageReplyPipeline, createChannelProgressDraftCompositor, createFinalizableDraftStreamControlsForState, createTypingCallbacks, defineFinalizableLivePreviewAdapter, deliverWithFinalizableLivePreviewAdapter, resolveChannelDraftStreamingChunking, resolveChannelMessageSourceReplyDeliveryMode, resolveChannelPreviewStreamMode, resolveChannelStreamingBlockEnabled, resolveChannelStreamingPreviewCommandText, resolveChannelStreamingProgressNarration, resolveTranscriptBackedChannelFinalText } from "openclaw/plugin-sdk/channel-outbound";
26
+ import { stripInlineDirectiveTagsForDelivery, stripReasoningTagsFromText } from "openclaw/plugin-sdk/text-chunking";
27
+ import { resolveBatchedReplyThreadingPolicy } from "openclaw/plugin-sdk/reply-reference";
28
+ import { bindIngressLifecycleToReplyOptions, createChannelMessageReplyPipeline, createChannelProgressDraftCompositor, createFinalizableDraftLifecycle, createLivePreviewLifecycle, createTypingCallbacks, isRecentOutboundMessageIdentity, resolveChannelDraftStreamingChunking, resolveChannelMessageSourceReplyDeliveryMode, resolveChannelPreviewStreamMode, resolveChannelStreamingBlockEnabled, resolveChannelStreamingPreviewCommandText, resolveChannelStreamingProgressNarration, resolveTranscriptBackedChannelFinalText } from "openclaw/plugin-sdk/channel-outbound";
28
29
  import { getAgentScopedMediaLocalRoots } from "openclaw/plugin-sdk/media-runtime";
29
30
  import { buildChannelInboundEventContext, createCommandTurnContext, dispatchChannelInboundTurn, formatInboundEnvelope, formatInboundMediaUnavailableText, getGroupThreadDeliverySession, hasFinalInboundReplyDispatch, readAgentRunTerminalOutcome, resolveEnvelopeFormatOptions, toHistoryMediaEntries, toInboundMediaFactsWithMetadata } from "openclaw/plugin-sdk/channel-inbound";
30
31
  import { evaluateSupplementalContextVisibility } from "openclaw/plugin-sdk/security-runtime";
31
- import { resolvePinnedMainDmOwnerFromAllowlist } from "openclaw/plugin-sdk/conversation-runtime";
32
+ import { resolvePinnedMainDmOwnerFromAllowlist as resolvePinnedMainDmOwnerFromAllowlist$1 } from "openclaw/plugin-sdk/conversation-runtime";
32
33
  import { resolveAgentConfig } from "openclaw/plugin-sdk/agent-scope-runtime";
33
- import { EmbeddedBlockChunker, resolveAckReaction, resolveAgentConfig as resolveAgentConfig$1, resolveHumanDelayConfig } from "openclaw/plugin-sdk/agent-runtime";
34
34
  import { isDangerousNameMatchingEnabled } from "openclaw/plugin-sdk/dangerous-name-runtime";
35
+ import { EmbeddedBlockChunker, resolveAckReaction, resolveAgentConfig as resolveAgentConfig$1, resolveHumanDelayConfig } from "openclaw/plugin-sdk/agent-runtime";
35
36
  import { getSessionEntry, readSessionUpdatedAt, resolveStorePath } from "openclaw/plugin-sdk/session-store-runtime";
36
37
  import { getGlobalHookRunner } from "openclaw/plugin-sdk/plugin-runtime";
37
38
  import { buildHistoryContextFromEntries, buildInboundHistoryFromEntries, createChannelHistoryWindow } from "openclaw/plugin-sdk/reply-history";
@@ -39,6 +40,114 @@ import { resolveChannelContextVisibilityMode } from "openclaw/plugin-sdk/context
39
40
  import { formatAudioTranscriptForAgent } from "openclaw/plugin-sdk/media-understanding-runtime";
40
41
  import { createStatusReactionController, logAckFailure, logTypingFailure, shouldAckReaction } from "openclaw/plugin-sdk/channel-feedback";
41
42
  import { readLatestAssistantTextByIdentity } from "openclaw/plugin-sdk/session-transcript-runtime";
43
+ //#region extensions/discord/src/monitor/message-handler.recent-history.ts
44
+ /** Fetch a physical recent window, never walking older pages to refill filtered rows. */
45
+ async function recoverDiscordChannelHistory(params) {
46
+ const { ctx, isCurrent } = params;
47
+ if (ctx.historyLimit <= 0 || !isCurrent()) return [];
48
+ const excludedIds = /* @__PURE__ */ new Set([ctx.message.id, ...ctx.sourceMessageIds ?? []]);
49
+ if (ctx.canonicalMessageId) excludedIds.add(ctx.canonicalMessageId);
50
+ let remaining = ctx.historyLimit + excludedIds.size - 1;
51
+ let before = ctx.message.id;
52
+ const triggerTimestamp = resolveTimestampMs(ctx.message.timestamp);
53
+ const guildId = ctx.data.guild?.id ?? ctx.data.guild_id;
54
+ const cachedMedia = new Map((ctx.guildHistories.get(ctx.messageChannelId) ?? []).map((entry) => [entry.messageId, entry]));
55
+ const members = /* @__PURE__ */ new Map();
56
+ const roleAllowList = ctx.channelConfig?.roles ?? ctx.guildInfo?.roles ?? [];
57
+ const entries = [];
58
+ try {
59
+ while (remaining > 0 && isCurrent()) {
60
+ const limit = Math.min(100, remaining);
61
+ const page = await listChannelMessages(ctx.client.rest, ctx.messageChannelId, {
62
+ before,
63
+ limit
64
+ });
65
+ if (!isCurrent()) return [];
66
+ const window = page.slice(0, limit);
67
+ remaining -= window.length;
68
+ for (const raw of window) {
69
+ const row = raw;
70
+ const timestamp = resolveTimestampMs(row.timestamp);
71
+ if (row.channel_id !== ctx.messageChannelId || row.guild_id && row.guild_id !== guildId || excludedIds.has(row.id) || /^\d+$/u.test(row.id) && /^\d+$/u.test(ctx.message.id) && BigInt(row.id) >= BigInt(ctx.message.id) || timestamp === void 0 || triggerTimestamp !== void 0 && timestamp > triggerTimestamp || params.sessionStartedAt !== void 0 && timestamp < params.sessionStartedAt || row.type === discord_exports.MessageType.ChatInputCommand || row.type === discord_exports.MessageType.ContextMenuCommand || row.author.id === ctx.botUserId) continue;
72
+ excludedIds.add(row.id);
73
+ const message = new Message(ctx.client, row);
74
+ let body = resolveDiscordMessageHistoryText(message, { includeForwarded: true });
75
+ if (!body || isRecentOutboundMessageIdentity({
76
+ channel: "discord",
77
+ accountId: ctx.accountId,
78
+ conversationId: ctx.messageChannelId,
79
+ messageId: row.id,
80
+ ...row.webhook_id ? { sourceId: row.webhook_id } : {}
81
+ }) || shouldIgnoreBoundThreadWebhookMessage({
82
+ threadId: ctx.messageChannelId,
83
+ webhookId: message.webhookId,
84
+ threadBinding: ctx.threadBinding
85
+ }) || isBoundThreadBotSystemMessage({
86
+ isBoundThreadSession: Boolean(ctx.threadBinding && ctx.threadChannel),
87
+ isBotAuthor: Boolean(row.author.bot),
88
+ text: body
89
+ })) continue;
90
+ const needsPluralKitLookup = Boolean(ctx.discordConfig?.pluralkit?.enabled && message.webhookId);
91
+ const pluralkitInfo = needsPluralKitLookup ? await resolveDiscordPreflightPluralKitInfo({
92
+ message,
93
+ webhookId: message.webhookId,
94
+ config: ctx.discordConfig?.pluralkit,
95
+ abortSignal: ctx.abortSignal
96
+ }) : null;
97
+ if (needsPluralKitLookup && !isCurrent()) return [];
98
+ const sender = resolveDiscordSenderIdentity({
99
+ author: message.author,
100
+ member: row.member,
101
+ pluralkitInfo
102
+ });
103
+ let member = row.member;
104
+ if (params.mode !== "all" && roleAllowList.length > 0 && !member && guildId && !params.isSenderAllowed({
105
+ ...sender,
106
+ memberRoleIds: []
107
+ })) {
108
+ member = members.get(row.author.id);
109
+ if (!member) {
110
+ member = await getGuildMember(ctx.client.rest, guildId, row.author.id);
111
+ if (!isCurrent()) return [];
112
+ members.set(row.author.id, member);
113
+ }
114
+ }
115
+ const senderProvenance = createDiscordHistorySenderProvenance({
116
+ sender,
117
+ memberRoleIds: member?.roles ?? []
118
+ });
119
+ const mediaIds = resolveDiscordHistoryMediaIds(message);
120
+ const cached = cachedMedia.get(row.id);
121
+ const media = mediaIds.length > 0 && cached?.mediaIds?.length === mediaIds.length && cached.mediaIds.every((id, index) => id === mediaIds[index]) ? cached.media : void 0;
122
+ if (mediaIds.length > (media?.length ?? 0)) body = formatInboundMediaUnavailableText({
123
+ body,
124
+ notice: "[discord historical attachment unavailable]"
125
+ });
126
+ entries.push({
127
+ sender: sender.label,
128
+ body,
129
+ timestamp,
130
+ messageId: row.id,
131
+ senderProvenance,
132
+ ...media?.length ? { media } : {}
133
+ });
134
+ }
135
+ const nextBefore = window.at(-1)?.id;
136
+ if (window.length < limit || !nextBefore || nextBefore === before || /^\d+$/u.test(nextBefore) && /^\d+$/u.test(before) && BigInt(nextBefore) >= BigInt(before)) break;
137
+ before = nextBefore;
138
+ }
139
+ if (!isCurrent()) return [];
140
+ return filterDiscordHistoryEntriesForContext({
141
+ entries: entries.toReversed(),
142
+ mode: params.mode,
143
+ isSenderAllowed: params.isSenderAllowed
144
+ }).entries.slice(-ctx.historyLimit);
145
+ } catch (error) {
146
+ ctx.runtime.error(danger(`discord: recent history omitted for ${ctx.messageChannelId}: ${String(error)}`));
147
+ return [];
148
+ }
149
+ }
150
+ //#endregion
42
151
  //#region extensions/discord/src/monitor/message-handler.retry.ts
43
152
  const REPLY_SESSION_INIT_CONFLICT_MESSAGE_RE = /^reply session initialization conflicted for \S+$/u;
44
153
  const DISCORD_SESSION_CONFLICT_FAILURE_TEXT = "⚠️ Couldn't process this message because the session stayed busy. Please try again in a moment.";
@@ -74,6 +183,7 @@ function normalizeDiscordDmOwnerEntry(entry) {
74
183
  async function buildDiscordMessageProcessContext(params) {
75
184
  const { ctx, text, mediaList } = params;
76
185
  const { cfg, discordConfig, accountId, runtime, botUserId, mediaMaxBytes, discordRestFetch, abortSignal, guildHistories, historyLimit, replyToMode, message, author, sender, canonicalMessageId, data, client, channelInfo, channelName, messageChannelId, isGuildMessage, isDirectMessage, isGroupDm, baseText, preflightAudioTranscript, threadChannel, threadParentId, threadParentName, threadParentType, threadName, displayChannelSlug, guildInfo, guildSlug, memberRoleIds, channelConfig, baseSessionKey, boundSessionKey, route, commandAuthorized, hasControlCommand, resolveChannelIngress } = ctx;
186
+ if (abortSignal?.aborted || ctx.isPolicyCurrent?.() === false) return null;
77
187
  const fromLabel = isDirectMessage ? buildDirectLabel(author) : buildGuildLabel({
78
188
  guild: data.guild ?? void 0,
79
189
  channelName: channelName ?? messageChannelId,
@@ -100,7 +210,7 @@ async function buildDiscordMessageProcessContext(params) {
100
210
  isGuild: isGuildMessage,
101
211
  channelTopic: channelInfo?.topic
102
212
  });
103
- const pinnedMainDmOwner = isDirectMessage ? resolvePinnedMainDmOwnerFromAllowlist({
213
+ const pinnedMainDmOwner = isDirectMessage ? resolvePinnedMainDmOwnerFromAllowlist$1({
104
214
  dmScope: cfg.session?.dmScope,
105
215
  allowFrom: channelConfig?.users ?? guildInfo?.users,
106
216
  normalizeEntry: normalizeDiscordDmOwnerEntry
@@ -119,10 +229,28 @@ async function buildDiscordMessageProcessContext(params) {
119
229
  });
120
230
  const storePath = resolveStorePath(cfg.session?.store, { agentId: route.agentId });
121
231
  const envelopeOptions = resolveEnvelopeFormatOptions(cfg);
122
- const previousTimestamp = readSessionUpdatedAt({
232
+ const routeSession = getSessionEntry({
233
+ agentId: route.agentId,
123
234
  storePath,
124
- sessionKey: route.sessionKey
235
+ sessionKey: route.sessionKey,
236
+ readConsistency: "latest"
125
237
  });
238
+ const previousTimestamp = routeSession?.updatedAt;
239
+ const shouldIncludeChannelHistory = !isDirectMessage && (ctx.inboundEventKind === "room_event" || !(isGuildMessage && channelConfig?.autoThread && !threadChannel));
240
+ const recoversHistory = shouldIncludeChannelHistory && isGuildMessage && historyLimit > 0;
241
+ const historySessionScope = {
242
+ agentId: route.agentId,
243
+ storePath,
244
+ sessionKey: boundSessionKey ?? route.sessionKey,
245
+ readConsistency: "latest"
246
+ };
247
+ const historySession = recoversHistory ? historySessionScope.sessionKey === route.sessionKey ? routeSession : getSessionEntry(historySessionScope) : void 0;
248
+ const isHistoryCurrent = () => {
249
+ if (abortSignal?.aborted || ctx.isPolicyCurrent?.() === false) return false;
250
+ if (!recoversHistory) return true;
251
+ const current = getSessionEntry(historySessionScope);
252
+ return current?.sessionId === historySession?.sessionId && current?.lifecycleRevision === historySession?.lifecycleRevision && current?.sessionStartedAt === historySession?.sessionStartedAt && current?.updatedAt === 0 === (historySession?.updatedAt === 0);
253
+ };
126
254
  const channelHistory = createChannelHistoryWindow({ historyMap: guildHistories });
127
255
  let visibleChannelHistory;
128
256
  const unavailableMediaCount = mediaList.filter((media) => !media.path).length;
@@ -142,20 +270,26 @@ async function buildDiscordMessageProcessContext(params) {
142
270
  previousTimestamp,
143
271
  envelope: envelopeOptions
144
272
  });
145
- const shouldIncludeChannelHistory = !isDirectMessage && (ctx.inboundEventKind === "room_event" || !(isGuildMessage && channelConfig?.autoThread && !threadChannel));
146
273
  if (shouldIncludeChannelHistory) {
147
274
  removeDiscordReplayHistoryEntry(guildHistories, messageChannelId, message.id);
148
275
  if (historyLimit > 0) {
149
- const filteredHistory = filterDiscordHistoryEntriesForContext({
150
- entries: guildHistories.get(messageChannelId) ?? [],
276
+ if (isGuildMessage) visibleChannelHistory = historySession?.updatedAt === 0 ? [] : await recoverDiscordChannelHistory({
277
+ ctx,
278
+ sessionStartedAt: historySession?.sessionStartedAt,
279
+ isCurrent: isHistoryCurrent,
151
280
  mode: contextVisibilityMode,
152
281
  isSenderAllowed: isSupplementalContextSenderAllowed
153
282
  });
154
- visibleChannelHistory = filteredHistory.entries;
155
- if (filteredHistory.omitted > 0) logVerbose(`discord: omit ${filteredHistory.omitted} pending history entries (mode=${contextVisibilityMode})`);
283
+ else visibleChannelHistory = filterDiscordHistoryEntriesForContext({
284
+ entries: guildHistories.get(messageChannelId) ?? [],
285
+ mode: contextVisibilityMode,
286
+ isSenderAllowed: isSupplementalContextSenderAllowed
287
+ }).entries.slice(-historyLimit);
288
+ if (!isHistoryCurrent()) return null;
156
289
  combinedBody = buildHistoryContextFromEntries({
157
290
  entries: visibleChannelHistory,
158
291
  currentMessage: combinedBody,
292
+ historyKind: isGuildMessage ? "recent" : "pending",
159
293
  formatEntry: (entry) => formatInboundEnvelope({
160
294
  channel: "Discord",
161
295
  from: fromLabel,
@@ -176,12 +310,6 @@ async function buildDiscordMessageProcessContext(params) {
176
310
  tag: replyContext.senderTag,
177
311
  memberRoleIds: replyContext.memberRoleIds
178
312
  }) : true;
179
- const replyVisible = evaluateSupplementalContextVisibility({
180
- mode: contextVisibilityMode,
181
- kind: "quote",
182
- senderAllowed: replySenderAllowed
183
- }).include;
184
- if (replyContext && !replyVisible && isGuildMessage) logVerbose(`discord: drop reply context (mode=${contextVisibilityMode})`);
185
313
  if (forumContextLine) combinedBody = `${combinedBody}\n${forumContextLine}`;
186
314
  let threadStarterBody;
187
315
  let threadLabel;
@@ -197,6 +325,7 @@ async function buildDiscordMessageProcessContext(params) {
197
325
  parentType: threadParentType,
198
326
  resolveTimestampMs
199
327
  });
328
+ if (!isHistoryCurrent()) return null;
200
329
  if (starter?.text) {
201
330
  if (evaluateSupplementalContextVisibility({
202
331
  mode: contextVisibilityMode,
@@ -235,6 +364,7 @@ async function buildDiscordMessageProcessContext(params) {
235
364
  parentSessionKey,
236
365
  useSuffix: false
237
366
  });
367
+ if (!isHistoryCurrent()) return null;
238
368
  const replyPlan = await resolveDiscordAutoThreadReplyPlan({
239
369
  client,
240
370
  message,
@@ -255,6 +385,7 @@ async function buildDiscordMessageProcessContext(params) {
255
385
  groupScope: route.groupScope,
256
386
  threadParentInheritanceEnabled
257
387
  });
388
+ if (!isHistoryCurrent()) return null;
258
389
  const deliverTarget = replyPlan.deliverTarget;
259
390
  const replyTarget = replyPlan.replyTarget;
260
391
  const replyReference = replyPlan.replyReference;
@@ -284,12 +415,15 @@ async function buildDiscordMessageProcessContext(params) {
284
415
  const channelIngress = await resolveChannelIngress({
285
416
  agentId: route.agentId,
286
417
  sessionKey: effectiveSessionKey,
418
+ nativeChannelId: messageChannelId,
287
419
  messageId: canonicalMessageId ?? message.id,
288
420
  inboundEventKind: ctx.inboundEventKind
289
421
  }, {
290
422
  parentId: conversationParentId,
291
423
  threadId: threadChannel?.id ?? autoThreadContext?.createdThreadId ?? void 0
292
424
  });
425
+ if (!isHistoryCurrent()) return null;
426
+ const batchMessageIds = ctx.sourceMessageIds && ctx.sourceMessageIds.length > 1 ? [...ctx.sourceMessageIds] : void 0;
293
427
  const ctxPayload = await (ctx.buildContext ?? buildChannelInboundEventContext)({
294
428
  channelIngress,
295
429
  channel: "discord",
@@ -326,9 +460,7 @@ async function buildDiscordMessageProcessContext(params) {
326
460
  threadId: threadChannel?.id ?? autoThreadContext?.createdThreadId ?? void 0
327
461
  },
328
462
  route: {
329
- agentId: route.agentId,
330
- dmScope: route.dmScope,
331
- accountId: route.accountId,
463
+ ...route,
332
464
  routeSessionKey: route.sessionKey,
333
465
  dispatchSessionKey: effectiveSessionKey,
334
466
  parentSessionKey: autoThreadContext?.ParentSessionKey ?? threadKeys.parentSessionKey,
@@ -336,6 +468,7 @@ async function buildDiscordMessageProcessContext(params) {
336
468
  },
337
469
  reply: {
338
470
  to: effectiveTo,
471
+ replyToId: resolveDiscordReferencedReplyMessageId(message) ?? void 0,
339
472
  ...originatingTo !== effectiveTo ? { originatingTo } : {}
340
473
  },
341
474
  message: {
@@ -346,7 +479,10 @@ async function buildDiscordMessageProcessContext(params) {
346
479
  commandBody: baseText,
347
480
  inboundHistory
348
481
  },
349
- sessionTranscript: { historyLimit: shouldIncludeChannelHistory ? historyLimit : 0 },
482
+ sessionTranscript: {
483
+ historyLimit: shouldIncludeChannelHistory ? historyLimit : 0,
484
+ historyKind: isGuildMessage ? "recent" : "pending"
485
+ },
350
486
  access: {
351
487
  mentions: {
352
488
  canDetectMention: ctx.canDetectMention,
@@ -363,7 +499,7 @@ async function buildDiscordMessageProcessContext(params) {
363
499
  }),
364
500
  media: await toInboundMediaFactsWithMetadata(mediaList, { transcribed: (_media, index) => index === preflightAudioIndex }),
365
501
  supplemental: {
366
- quote: replyContext && replyVisible ? {
502
+ quote: replyContext ? {
367
503
  id: replyContext.id,
368
504
  body: replyContext.body,
369
505
  sender: replyContext.sender,
@@ -388,6 +524,10 @@ async function buildDiscordMessageProcessContext(params) {
388
524
  groupSystemPrompt: isGuildMessage ? groupSystemPrompt : void 0
389
525
  },
390
526
  extra: {
527
+ MessageSids: batchMessageIds,
528
+ MessageSidFirst: batchMessageIds?.[0],
529
+ MessageSidLast: batchMessageIds?.at(-1),
530
+ ReplyThreading: resolveBatchedReplyThreadingPolicy(replyToMode, batchMessageIds !== void 0),
391
531
  GroupThread: ctx.groupThread,
392
532
  ...preflightAudioTranscript !== void 0 ? { Transcript: preflightAudioTranscript } : {},
393
533
  GroupSubject: isDirectMessage ? void 0 : groupChannel,
@@ -397,6 +537,7 @@ async function buildDiscordMessageProcessContext(params) {
397
537
  OwnerAllowFrom: ownerAllowFrom
398
538
  }
399
539
  });
540
+ if (!isHistoryCurrent()) return null;
400
541
  const persistedSessionKey = ctxPayload.SessionKey ?? route.sessionKey;
401
542
  if (ctx.inboundEventKind === "room_event" && shouldIncludeChannelHistory) {
402
543
  const historyText = [text, formatDiscordMediaText({
@@ -411,6 +552,7 @@ async function buildDiscordMessageProcessContext(params) {
411
552
  body: historyText,
412
553
  timestamp: resolveTimestampMs(message.timestamp),
413
554
  messageId: message.id,
555
+ mediaIds: resolveDiscordHistoryMediaIds(message),
414
556
  senderProvenance: createDiscordHistorySenderProvenance({
415
557
  sender,
416
558
  memberRoleIds
@@ -494,6 +636,7 @@ function createDiscordMessageProgressRuntime(params) {
494
636
  onQueuedFollowupAdmitted: draftPreview.draftStream ? () => {
495
637
  if (draftPreview.handleQueuedFollowupAdmitted()) params.onTurnReset();
496
638
  } : void 0,
639
+ onQueuedFollowupSettled: draftPreview.draftStream ? () => draftPreview.cleanup() : void 0,
497
640
  suppressDefaultToolProgressMessages: params.sourceRepliesAreToolOnly && params.reactions.statusReactionsExplicitlyEnabled || draftPreview.suppressDefaultToolProgressMessages ? true : void 0,
498
641
  allowToolLifecycleWhenProgressHidden: params.reactions.statusReactionsEnabled ? true : void 0,
499
642
  commentaryProgressEnabled: draftPreview.isProgressMode ? draftPreview.commentaryProgressEnabled : void 0,
@@ -524,10 +667,7 @@ function createDiscordMessageProgressRuntime(params) {
524
667
  return await draftPreview.pushToolEvent(payload);
525
668
  },
526
669
  onItemEvent: async (payload) => {
527
- if (payload.kind === "preamble") {
528
- if (shouldYieldDraftCommentary()) return;
529
- return await draftPreview.pushPreambleItemEvent(payload);
530
- }
670
+ if (payload.kind === "preamble" && shouldYieldDraftCommentary()) return;
531
671
  return await draftPreview.pushItemEvent(payload);
532
672
  },
533
673
  onPlanUpdate: async (payload) => {
@@ -540,12 +680,6 @@ function createDiscordMessageProgressRuntime(params) {
540
680
  onApprovalEvent: async (payload) => {
541
681
  return await draftPreview.pushApprovalEvent(payload);
542
682
  },
543
- onCommandOutput: async (payload) => {
544
- return await draftPreview.pushCommandOutputEvent(payload);
545
- },
546
- onPatchSummary: async (payload) => {
547
- return await draftPreview.pushPatchEvent(payload);
548
- },
549
683
  onCompactionStart: async () => {
550
684
  if (!abortSignal?.aborted) await params.reactions.controller.setCompacting();
551
685
  return false;
@@ -597,13 +731,6 @@ function queueInitialDiscordAckReaction(params) {
597
731
  }
598
732
  //#endregion
599
733
  //#region extensions/discord/src/monitor/message-handler.process-reactions.ts
600
- function readToolStringArg(args, key) {
601
- const value = args[key];
602
- return typeof value === "string" && value.trim() ? value.trim() : void 0;
603
- }
604
- function readToolBooleanArg(args, key) {
605
- return args[key] === true;
606
- }
607
734
  function createDiscordMessageReactionRuntime(params) {
608
735
  const { ctx } = params;
609
736
  const { cfg, accountId, token, ackReactionScope, message, messageChannelId, isGuildMessage, isDirectMessage, isGroupDm, canDetectMention, effectiveWasMentioned, shouldBypassMention, route } = ctx;
@@ -645,10 +772,10 @@ function createDiscordMessageReactionRuntime(params) {
645
772
  });
646
773
  let statusReactionTarget = `${messageChannelId}/${message.id}`;
647
774
  let statusReactionsActive = statusReactionsEnabled;
648
- let statusReactions = createStatusReactionController({
649
- enabled: statusReactionsEnabled,
650
- adapter: discordAdapter,
651
- initialEmoji: ackReaction,
775
+ const createController = (enabled, adapter, initialEmoji) => createStatusReactionController({
776
+ enabled,
777
+ adapter,
778
+ initialEmoji,
652
779
  presentation: "acknowledgement",
653
780
  onError: (err) => {
654
781
  logAckFailure({
@@ -659,8 +786,9 @@ function createDiscordMessageReactionRuntime(params) {
659
786
  });
660
787
  }
661
788
  });
789
+ let statusReactions = createController(statusReactionsEnabled, discordAdapter, ackReaction);
662
790
  const resolveTrackedReactionChannelId = async (args) => {
663
- const target = readToolStringArg(args, "channelId") ?? readToolStringArg(args, "channel_id") ?? readToolStringArg(args, "to");
791
+ const target = normalizeOptionalString(args.channelId) ?? normalizeOptionalString(args.channel_id) ?? normalizeOptionalString(args.to);
664
792
  if (!target) return messageChannelId;
665
793
  try {
666
794
  return resolveDiscordChannelId(target);
@@ -675,11 +803,11 @@ function createDiscordMessageReactionRuntime(params) {
675
803
  const maybeBindToToolReaction = async (payload) => {
676
804
  if (params.sourceRepliesAreToolOnly || cfg.messages?.statusReactions?.enabled === false || payload.phase !== "start" || payload.name !== "message" || !payload.args) return;
677
805
  const args = payload.args;
678
- if (readToolStringArg(args, "action")?.toLowerCase() !== "react") return;
679
- if (!(readToolBooleanArg(args, "trackToolCalls") || readToolBooleanArg(args, "track_tool_calls"))) return;
680
- const emoji = readToolStringArg(args, "emoji");
681
- if (!emoji || readToolBooleanArg(args, "remove")) return;
682
- const trackedMessageId = readToolStringArg(args, "messageId") ?? readToolStringArg(args, "message_id") ?? message.id;
806
+ if (normalizeOptionalString(args.action)?.toLowerCase() !== "react") return;
807
+ if (!(args.trackToolCalls === true || args.track_tool_calls === true)) return;
808
+ const emoji = normalizeOptionalString(args.emoji);
809
+ if (!emoji || args.remove === true) return;
810
+ const trackedMessageId = normalizeOptionalString(args.messageId) ?? normalizeOptionalString(args.message_id) ?? message.id;
683
811
  let trackedChannelId;
684
812
  try {
685
813
  trackedChannelId = await resolveTrackedReactionChannelId(args);
@@ -687,31 +815,18 @@ function createDiscordMessageReactionRuntime(params) {
687
815
  logAckFailure({
688
816
  log: logVerbose,
689
817
  channel: "discord",
690
- target: `${readToolStringArg(args, "to") ?? readToolStringArg(args, "channelId") ?? messageChannelId}/${trackedMessageId}`,
818
+ target: `${normalizeOptionalString(args.to) ?? normalizeOptionalString(args.channelId) ?? messageChannelId}/${trackedMessageId}`,
691
819
  error: err
692
820
  });
693
821
  return;
694
822
  }
695
823
  statusReactionTarget = `${trackedChannelId}/${trackedMessageId}`;
696
824
  if (statusReactionsActive) statusReactions.clear();
697
- statusReactions = createStatusReactionController({
698
- enabled: true,
699
- adapter: createDiscordAckReactionAdapter({
700
- channelId: trackedChannelId,
701
- messageId: trackedMessageId,
702
- reactionContext: ackReactionContext
703
- }),
704
- initialEmoji: emoji,
705
- presentation: "acknowledgement",
706
- onError: (err) => {
707
- logAckFailure({
708
- log: logVerbose,
709
- channel: "discord",
710
- target: statusReactionTarget,
711
- error: err
712
- });
713
- }
714
- });
825
+ statusReactions = createController(true, createDiscordAckReactionAdapter({
826
+ channelId: trackedChannelId,
827
+ messageId: trackedMessageId,
828
+ reactionContext: ackReactionContext
829
+ }), emoji);
715
830
  statusReactionsActive = true;
716
831
  statusReactions.setQueued();
717
832
  };
@@ -719,7 +834,6 @@ function createDiscordMessageReactionRuntime(params) {
719
834
  const queueInitialAckReactionAfterRecord = () => {
720
835
  if (initialAckReactionQueued) return;
721
836
  initialAckReactionQueued = true;
722
- if (statusReactionsEnabled) statusReactionsActive = true;
723
837
  queueInitialDiscordAckReaction({
724
838
  enabled: statusReactionsEnabled,
725
839
  shouldSendAckReaction,
@@ -776,14 +890,14 @@ function createDiscordDraftStream(params) {
776
890
  stopped: false,
777
891
  final: false
778
892
  };
779
- let streamMessageId;
893
+ let streamMessage;
780
894
  let lastSentText = "";
781
895
  let streamGeneration = 0;
782
896
  let activeCreateGeneration;
783
897
  let discardActiveCreate = false;
784
- let pendingCleanupMessages = [];
785
898
  const sendOrEditStreamMessage = async ({ text, complete }) => {
786
899
  const generation = streamGeneration;
900
+ const targetChannelId = channelId;
787
901
  if (streamState.stopped && !streamState.final) return false;
788
902
  const trimmed = text.trimEnd();
789
903
  if (!trimmed) return false;
@@ -793,17 +907,18 @@ function createDiscordDraftStream(params) {
793
907
  return false;
794
908
  }
795
909
  if (trimmed === lastSentText) return true;
796
- if (streamMessageId === void 0 && minInitialChars != null && !streamState.final && !complete) {
910
+ if (streamMessage === void 0 && minInitialChars != null && !streamState.final && !complete) {
797
911
  if (trimmed.length < minInitialChars) return false;
798
912
  }
799
- lastSentText = trimmed;
800
913
  try {
801
- if (streamMessageId !== void 0) {
802
- await editChannelMessage(rest, channelId, streamMessageId, { body: {
803
- content: trimmed,
804
- allowed_mentions: DISCORD_PREVIEW_ALLOWED_MENTIONS,
805
- ...flags ? { flags } : {}
806
- } });
914
+ const body = {
915
+ content: trimmed,
916
+ allowed_mentions: DISCORD_PREVIEW_ALLOWED_MENTIONS,
917
+ ...flags ? { flags } : {}
918
+ };
919
+ if (streamMessage !== void 0) {
920
+ await editChannelMessage(rest, streamMessage.channelId, streamMessage.messageId, { body });
921
+ if (generation === streamGeneration) lastSentText = trimmed;
807
922
  return true;
808
923
  }
809
924
  const replyToMessageId = resolveReplyToMessageId()?.trim();
@@ -812,20 +927,17 @@ function createDiscordDraftStream(params) {
812
927
  fail_if_not_exists: false
813
928
  } : void 0;
814
929
  activeCreateGeneration = generation;
815
- const sentMessageId = (await createChannelMessage(rest, channelId, { body: {
816
- content: trimmed,
817
- allowed_mentions: DISCORD_PREVIEW_ALLOWED_MENTIONS,
818
- ...flags ? { flags } : {},
930
+ const sentMessageId = (await createChannelMessage(rest, targetChannelId, { body: {
931
+ ...body,
819
932
  ...messageReference ? { message_reference: messageReference } : {}
820
933
  } }))?.id;
821
934
  const shouldDiscardStaleCreate = activeCreateGeneration === generation && discardActiveCreate;
822
935
  activeCreateGeneration = void 0;
823
936
  discardActiveCreate = false;
824
937
  if (generation !== streamGeneration) {
825
- if (shouldDiscardStaleCreate && typeof sentMessageId === "string" && sentMessageId) await deleteCleanupMessage({
826
- channelId,
827
- messageId: sentMessageId,
828
- warnPrefix: "discord stale stream preview cleanup failed"
938
+ if (shouldDiscardStaleCreate && typeof sentMessageId === "string" && sentMessageId) await lifecycle.retire({
939
+ channelId: targetChannelId,
940
+ messageId: sentMessageId
829
941
  });
830
942
  return true;
831
943
  }
@@ -834,7 +946,11 @@ function createDiscordDraftStream(params) {
834
946
  params.warn?.("discord stream preview stopped (missing message id from send)");
835
947
  return false;
836
948
  }
837
- streamMessageId = sentMessageId;
949
+ streamMessage = {
950
+ channelId: targetChannelId,
951
+ messageId: sentMessageId
952
+ };
953
+ lastSentText = trimmed;
838
954
  return true;
839
955
  } catch (err) {
840
956
  if (activeCreateGeneration === generation) {
@@ -847,7 +963,12 @@ function createDiscordDraftStream(params) {
847
963
  return false;
848
964
  }
849
965
  };
850
- const { loop, update: updateDraft, stop, discardPending, seal } = createFinalizableDraftStreamControlsForState({
966
+ const clearMessageId = () => {
967
+ streamMessage = void 0;
968
+ lastSentText = "";
969
+ loop.resetThrottleWindow();
970
+ };
971
+ const lifecycle = createFinalizableDraftLifecycle({
851
972
  throttleMs,
852
973
  coalesceInFlight: true,
853
974
  state: streamState,
@@ -856,8 +977,15 @@ function createDiscordDraftStream(params) {
856
977
  text: "",
857
978
  complete: false
858
979
  },
859
- isEmpty: (value) => !value.text
980
+ isEmpty: (value) => !value.text,
981
+ readMessageId: () => streamMessage,
982
+ clearMessageId,
983
+ isValidMessageId: (value) => value !== void 0,
984
+ deleteMessage: (message) => deleteChannelMessage(rest, message.channelId, message.messageId),
985
+ warn: params.warn,
986
+ warnPrefix: "discord stream preview cleanup failed"
860
987
  });
988
+ const { loop, update: updateDraft, stop, discardPending, seal } = lifecycle;
861
989
  const update = (text, options) => updateDraft({
862
990
  text,
863
991
  complete: options?.complete === true
@@ -867,35 +995,21 @@ function createDiscordDraftStream(params) {
867
995
  streamGeneration += 1;
868
996
  streamState.stopped = false;
869
997
  streamState.final = false;
870
- streamMessageId = void 0;
998
+ streamMessage = void 0;
871
999
  lastSentText = "";
872
1000
  loop.resetPending();
873
1001
  loop.resetThrottleWindow();
874
1002
  };
875
- const deleteCleanupMessage = async (message) => {
876
- try {
877
- await deleteChannelMessage(rest, message.channelId, message.messageId);
878
- } catch (err) {
879
- pendingCleanupMessages.push(message);
880
- params.warn?.(`${message.warnPrefix}: ${formatErrorMessage(err)}`);
881
- }
882
- };
883
- const cleanupPendingMessages = async () => {
884
- const pending = pendingCleanupMessages;
885
- pendingCleanupMessages = [];
886
- for (const message of pending) await deleteCleanupMessage(message);
887
- };
888
1003
  const retarget = async (nextChannelId) => {
889
1004
  const normalized = nextChannelId.trim();
890
1005
  if (!normalized || normalized === channelId) return;
891
1006
  await loop.waitForInFlight();
892
1007
  const pending = loop.takePending();
893
- const previousChannelId = channelId;
894
- const previousMessageId = streamMessageId;
1008
+ const previousMessage = streamMessage;
895
1009
  const previousText = pending.text || lastSentText;
896
1010
  streamGeneration += 1;
897
1011
  channelId = normalized;
898
- streamMessageId = void 0;
1012
+ streamMessage = void 0;
899
1013
  lastSentText = "";
900
1014
  streamState.stopped = false;
901
1015
  streamState.final = false;
@@ -904,49 +1018,40 @@ function createDiscordDraftStream(params) {
904
1018
  update(previousText, { complete: pending.text ? pending.complete : true });
905
1019
  await loop.flush();
906
1020
  }
907
- if (previousMessageId) {
908
- const stale = {
909
- channelId: previousChannelId,
910
- messageId: previousMessageId,
911
- warnPrefix: "discord stream preview retarget cleanup failed"
912
- };
913
- if (!streamMessageId) {
914
- pendingCleanupMessages.push(stale);
1021
+ if (previousMessage) {
1022
+ if (!streamMessage) {
1023
+ await lifecycle.retire(previousMessage, { defer: true });
915
1024
  throw new Error("discord stream preview retarget replacement failed");
916
1025
  }
917
- await deleteCleanupMessage(stale);
1026
+ await lifecycle.retire(previousMessage);
918
1027
  }
919
1028
  };
920
- const deleteCurrentMessage = async () => {
921
- loop.resetPending();
922
- await loop.waitForInFlight();
923
- const currentMessage = streamMessageId ? {
924
- channelId,
925
- messageId: streamMessageId,
926
- warnPrefix: "discord stream preview cleanup failed"
927
- } : void 0;
928
- streamMessageId = void 0;
929
- lastSentText = "";
930
- loop.resetThrottleWindow();
931
- if (!currentMessage) return;
932
- await deleteCleanupMessage(currentMessage);
933
- };
934
- const clear = async () => {
935
- await discardPending();
936
- await deleteCurrentMessage();
1029
+ const retireCurrentMessage = async (stopForClear) => {
1030
+ const generation = streamGeneration;
1031
+ await stopForClear();
1032
+ if (generation !== streamGeneration) return;
1033
+ const message = streamMessage;
1034
+ clearMessageId();
1035
+ if (message) await lifecycle.retire(message);
937
1036
  };
938
1037
  params.log?.(`discord stream preview ready (maxChars=${maxChars}, throttleMs=${throttleMs})`);
939
1038
  return {
940
1039
  update,
941
1040
  flush: loop.flush,
942
- messageId: () => streamMessageId,
943
- clear,
944
- deleteCurrentMessage,
1041
+ messageId: () => streamMessage?.messageId,
1042
+ lastDeliveredText: () => lastSentText,
1043
+ clear: () => retireCurrentMessage(discardPending),
1044
+ deleteCurrentMessage: () => retireCurrentMessage(async () => {
1045
+ loop.resetPending();
1046
+ await loop.waitForInFlight();
1047
+ }),
945
1048
  discardPending,
946
1049
  seal,
947
1050
  stop,
948
1051
  retarget,
949
- cleanupPendingMessages,
1052
+ cleanupPendingMessages: async () => {
1053
+ await lifecycle.cleanupPending();
1054
+ },
950
1055
  forceNewMessage
951
1056
  };
952
1057
  }
@@ -985,15 +1090,12 @@ function createDiscordDraftPreviewController(params) {
985
1090
  let lastPartialText = "";
986
1091
  let draftText = "";
987
1092
  let hasStreamedAssistantText = false;
988
- let finalizedViaPreviewMessage = false;
989
- let finalReplyError;
990
- let progressDraftStartedBeforeFinal = false;
991
- let progressDraftCollapsed = false;
992
1093
  let progressNarratorLifecycle;
993
1094
  const narrationProgressEnabled = Boolean(draftStream) && discordStreamMode === "progress" && resolveChannelStreamingProgressNarration(params.discordConfig);
994
1095
  const narrationHideCommandText = narrationProgressEnabled && resolveChannelStreamingPreviewCommandText(params.discordConfig) === "status";
995
1096
  const progressSeed = `${params.accountId}:${params.deliverChannelId}`;
996
1097
  const progressDraft = createChannelProgressDraftCompositor({
1098
+ preparedItems: true,
997
1099
  entry: params.discordConfig,
998
1100
  mode: discordStreamMode,
999
1101
  active: Boolean(draftStream),
@@ -1019,6 +1121,44 @@ function createDiscordDraftPreviewController(params) {
1019
1121
  isEmptyLine: isEmptyDiscordProgressLine,
1020
1122
  shouldStartNow: shouldStartDiscordProgressDraftNow
1021
1123
  });
1124
+ const freezeProgress = () => {
1125
+ progressDraft.markFinalReplyStarted();
1126
+ progressNarratorLifecycle?.stopTurn();
1127
+ };
1128
+ const flush = async () => {
1129
+ if (!draftStream) return;
1130
+ if (draftChunker?.hasBuffered()) {
1131
+ draftChunker.drain({
1132
+ force: true,
1133
+ emit: (chunk) => {
1134
+ draftText += chunk;
1135
+ }
1136
+ });
1137
+ draftChunker.reset();
1138
+ if (draftText) draftStream.update(draftText);
1139
+ }
1140
+ await draftStream.flush();
1141
+ };
1142
+ const lifecycle = createLivePreviewLifecycle({
1143
+ draft: draftStream ? {
1144
+ flush,
1145
+ id: draftStream.messageId,
1146
+ seal: draftStream.seal,
1147
+ discardPending: draftStream.discardPending,
1148
+ clear: draftStream.clear
1149
+ } : void 0,
1150
+ retainOnError: true,
1151
+ cleanupUndelivered: true,
1152
+ onFinalStarted: () => {
1153
+ freezeProgress();
1154
+ params.onFinalReplyStart?.();
1155
+ },
1156
+ onFinalDelivered: () => {
1157
+ progressDraft.markFinalReplyDelivered();
1158
+ params.onFinalReplyDelivered?.();
1159
+ },
1160
+ onCleanupFailure: (err) => params.log(`discord: draft cleanup failed: ${String(err)}`)
1161
+ });
1022
1162
  const resetProgressState = () => {
1023
1163
  lastPartialText = "";
1024
1164
  draftText = "";
@@ -1036,10 +1176,7 @@ function createDiscordDraftPreviewController(params) {
1036
1176
  const beganNewTurn = progressDraft.beginNewTurn(options);
1037
1177
  if (!beganNewTurn) progressDraft.beginAssistantMessage();
1038
1178
  if (beganNewTurn) {
1039
- progressDraftCollapsed = false;
1040
- progressDraftStartedBeforeFinal = false;
1041
- finalReplyError = void 0;
1042
- finalizedViaPreviewMessage = false;
1179
+ lifecycle.reset();
1043
1180
  progressNarratorLifecycle?.beginTurn();
1044
1181
  }
1045
1182
  if (discordStreamMode === "progress") {
@@ -1049,6 +1186,7 @@ function createDiscordDraftPreviewController(params) {
1049
1186
  };
1050
1187
  return {
1051
1188
  draftStream,
1189
+ lifecycle,
1052
1190
  narrationProgressEnabled,
1053
1191
  narrationHideCommandText,
1054
1192
  commentaryProgressEnabled: progressDraft.commentaryProgressEnabled,
@@ -1056,36 +1194,48 @@ function createDiscordDraftPreviewController(params) {
1056
1194
  get isProgressMode() {
1057
1195
  return discordStreamMode === "progress";
1058
1196
  },
1059
- get hasProgressDraftStarted() {
1060
- return progressDraft.hasStarted;
1061
- },
1062
1197
  get isProgressDraftVisible() {
1063
1198
  return progressDraft.isVisible;
1064
1199
  },
1065
- get hasProgressDraftToCollapse() {
1066
- return !progressDraftCollapsed && (progressDraft.hasStarted || progressDraftStartedBeforeFinal);
1067
- },
1068
- markProgressDraftCollapsed() {
1069
- progressDraftCollapsed = true;
1070
- progressDraftStartedBeforeFinal = false;
1071
- },
1072
- get finalizedViaPreviewMessage() {
1073
- return finalizedViaPreviewMessage;
1074
- },
1075
- setProgressNarratorLifecycle(lifecycle) {
1076
- progressNarratorLifecycle = lifecycle;
1077
- },
1078
- markFinalReplyStarted() {
1079
- progressDraftStartedBeforeFinal ||= progressDraft.hasStarted;
1080
- progressDraft.markFinalReplyStarted();
1081
- progressNarratorLifecycle?.stopTurn();
1082
- },
1083
- markFinalReplyDelivered(isError = false) {
1084
- finalReplyError = isError;
1085
- progressDraft.markFinalReplyDelivered();
1200
+ setProgressNarratorLifecycle(narratorLifecycle) {
1201
+ progressNarratorLifecycle = narratorLifecycle;
1086
1202
  },
1087
- markPreviewFinalized() {
1088
- finalizedViaPreviewMessage = true;
1203
+ freezeProgress,
1204
+ async adoptProgressContinuation(payload, info, target) {
1205
+ const adopt = info.adoptProgressContinuation;
1206
+ if (!draftStream || discordStreamMode !== "progress" || !adopt || info.kind !== "final" || payload.isError || payload.isCommentary || resolveSendableOutboundReplyParts(payload).hasMedia || payload.interactive !== void 0 || payload.presentation !== void 0 || payload.channelData !== void 0) return false;
1207
+ const snapshot = progressDraft.getSnapshot();
1208
+ if (!snapshot.statusHeadline && !snapshot.plan?.length && !snapshot.lines.length) return false;
1209
+ const assertCurrent = () => {
1210
+ params.abortSignal?.throwIfAborted();
1211
+ info.assertPlatformSendAuthorized?.();
1212
+ };
1213
+ return await withDiscordRequestAuthority(assertCurrent, async () => {
1214
+ assertCurrent();
1215
+ freezeProgress();
1216
+ const text = progressDraft.getText().trimEnd();
1217
+ draftStream.update(text, { complete: true });
1218
+ await draftStream.flush();
1219
+ assertCurrent();
1220
+ const messageId = draftStream.messageId();
1221
+ if (!messageId || !text || draftStream.lastDeliveredText() !== text) return false;
1222
+ if (!await adopt({
1223
+ channel: "discord",
1224
+ accountId: params.accountId,
1225
+ ...target,
1226
+ messageId,
1227
+ text,
1228
+ snapshot
1229
+ })) return false;
1230
+ if (draftStream.messageId() === messageId) {
1231
+ lifecycle.retainPreview();
1232
+ draftStream.forceNewMessage();
1233
+ progressDraft.markFinalReplyDelivered();
1234
+ resetProgressState();
1235
+ await draftStream.discardPending();
1236
+ }
1237
+ return true;
1238
+ });
1089
1239
  },
1090
1240
  async retarget(channelId) {
1091
1241
  await draftStream?.retarget(channelId);
@@ -1094,43 +1244,18 @@ function createDiscordDraftPreviewController(params) {
1094
1244
  if (!draftStream || discordStreamMode !== "progress") return false;
1095
1245
  const progressText = lastPartialText.trimEnd();
1096
1246
  if (!progressText) return false;
1247
+ lifecycle.retainPreview();
1097
1248
  draftStream.update(progressText);
1098
1249
  await draftStream.stop();
1099
- if (!draftStream.messageId()) return false;
1100
- finalizedViaPreviewMessage = true;
1101
- return true;
1250
+ return Boolean(draftStream.messageId());
1102
1251
  },
1103
1252
  disableBlockStreamingForDraft: draftStream ? true : void 0,
1104
1253
  pushToolEvent: progressDraft.pushToolEvent,
1105
- pushItemEvent: progressDraft.pushItemEvent,
1254
+ pushItemEvent: progressDraft.pushItemEvent.bind(progressDraft),
1106
1255
  pushApprovalEvent: progressDraft.pushApprovalEvent.bind(progressDraft),
1107
- pushCommandOutputEvent: progressDraft.pushCommandOutputEvent,
1108
- pushPatchEvent: progressDraft.pushPatchEvent,
1109
1256
  pushPlanProgress: progressDraft.pushPlanProgress.bind(progressDraft),
1110
1257
  pushReasoningProgress: progressDraft.pushReasoningProgress.bind(progressDraft),
1111
1258
  pushNarrationProgress: progressDraft.pushNarrationProgress.bind(progressDraft),
1112
- async pushPreambleItemEvent(payload) {
1113
- const headlineAccepted = await progressDraft.pushPreambleHeadline(payload.progressText, { itemId: payload.itemId });
1114
- if (!progressDraft.commentaryProgressEnabled) return headlineAccepted;
1115
- const commentaryAccepted = await progressDraft.pushCommentaryProgress(payload.progressText, { itemId: payload.itemId });
1116
- return headlineAccepted || commentaryAccepted;
1117
- },
1118
- resolvePreviewFinalText(text) {
1119
- if (typeof text !== "string") return;
1120
- const formatted = convertMarkdownTables(stripInlineDirectiveTagsForDelivery(text).text, params.tableMode);
1121
- const chunks = chunkDiscordTextWithMode(formatted, {
1122
- maxChars: draftMaxChars,
1123
- maxLines: params.maxLinesPerMessage,
1124
- chunkMode: params.chunkMode
1125
- });
1126
- if (!chunks.length && formatted) chunks.push(formatted);
1127
- if (chunks.length !== 1) return;
1128
- const trimmed = expectDefined(chunks.at(0), "single Discord preview chunk").trim();
1129
- if (!trimmed) return;
1130
- const currentPreviewText = discordStreamMode === "block" ? draftText : lastPartialText;
1131
- if (currentPreviewText && currentPreviewText.startsWith(trimmed) && trimmed.length < currentPreviewText.length) return;
1132
- return trimmed;
1133
- },
1134
1259
  updateFromPartial(text) {
1135
1260
  if (!draftStream || !text) return;
1136
1261
  const cleaned = stripInlineDirectiveTagsForDelivery(stripReasoningTagsFromText(text, {
@@ -1177,25 +1302,11 @@ function createDiscordDraftPreviewController(params) {
1177
1302
  handleQueuedFollowupAdmitted() {
1178
1303
  return beginNewProgressTurn({ force: true });
1179
1304
  },
1180
- async flush() {
1181
- if (!draftStream) return;
1182
- if (draftChunker?.hasBuffered()) {
1183
- draftChunker.drain({
1184
- force: true,
1185
- emit: (chunk) => {
1186
- draftText += chunk;
1187
- }
1188
- });
1189
- draftChunker.reset();
1190
- if (draftText) draftStream.update(draftText);
1191
- }
1192
- await draftStream.flush();
1193
- },
1194
- async cleanup({ finalDeliveryFailed = false } = {}) {
1305
+ flush,
1306
+ async cleanup({ failed = false } = {}) {
1195
1307
  try {
1196
1308
  progressDraft.cancel();
1197
- if (finalReplyError !== false) await draftStream?.discardPending();
1198
- if (!(discordStreamMode === "progress" && finalDeliveryFailed) && finalReplyError !== true && !finalizedViaPreviewMessage && draftStream?.messageId()) await draftStream.clear();
1309
+ await lifecycle.cleanup({ failed });
1199
1310
  await draftStream?.cleanupPendingMessages();
1200
1311
  } catch (err) {
1201
1312
  params.log(`discord: draft cleanup failed: ${String(err)}`);
@@ -1260,7 +1371,7 @@ function createDiscordBeforePayloadDelivery(params) {
1260
1371
  }
1261
1372
  if (payload.isReasoning || payload.isCommentary) return payload;
1262
1373
  if (params.draftPreview.draftStream && params.draftPreview.isProgressMode && info.kind === "block" && !resolveSendableOutboundReplyParts(payload).hasMedia && !payload.isError) return null;
1263
- if (info.kind === "final" && !params.isFallbackOnlyToolWarningFinal(payload)) params.draftPreview.markFinalReplyStarted();
1374
+ if (info.kind === "final" && !params.isFallbackOnlyToolWarningFinal(payload)) params.draftPreview.freezeProgress();
1264
1375
  return payload;
1265
1376
  };
1266
1377
  }
@@ -1268,13 +1379,13 @@ function createDiscordMessageReplyRuntime(params) {
1268
1379
  const { ctx, processContext } = params;
1269
1380
  const { cfg, discordConfig, accountId, token, guildHistories, historyLimit, textLimit, messageChannelId, isDirectMessage, route } = ctx;
1270
1381
  const { ctxPayload, deliverTarget, replyReference } = processContext;
1271
- const typingChannelId = deliverTarget.startsWith("channel:") ? deliverTarget.slice(8) : messageChannelId;
1382
+ const deliverChannelId = deliverTarget.startsWith("channel:") ? deliverTarget.slice(8) : messageChannelId;
1272
1383
  let typingFeedback;
1273
1384
  const getTypingFeedback = () => typingFeedback ??= createDiscordReplyTypingFeedback({
1274
1385
  cfg,
1275
1386
  token,
1276
1387
  accountId,
1277
- channelId: typingChannelId,
1388
+ channelId: deliverChannelId,
1278
1389
  rest: params.feedbackRest,
1279
1390
  log: logVerbose,
1280
1391
  keepaliveIntervalMs: params.shouldDisableCoreTypingKeepalive ? void 0 : 0
@@ -1338,7 +1449,6 @@ function createDiscordMessageReplyRuntime(params) {
1338
1449
  return;
1339
1450
  }
1340
1451
  };
1341
- const deliverChannelId = deliverTarget.startsWith("channel:") ? deliverTarget.slice(8) : messageChannelId;
1342
1452
  return {
1343
1453
  replyPipeline,
1344
1454
  onModelSelected,
@@ -1348,20 +1458,19 @@ function createDiscordMessageReplyRuntime(params) {
1348
1458
  beginQueuedDeliveryCorrelation: beginDeliveryCorrelation,
1349
1459
  endDeliveryCorrelation,
1350
1460
  resolveCurrentTurnTranscriptFinalText,
1351
- deliverChannelId,
1352
1461
  draftPreview: createDiscordDraftPreviewController({
1353
1462
  groupThread: Boolean(ctxPayload.GroupThread),
1354
1463
  cfg,
1355
1464
  discordConfig,
1356
1465
  accountId,
1466
+ abortSignal: ctx.abortSignal,
1357
1467
  sourceRepliesAreToolOnly: params.sourceRepliesAreToolOnly,
1358
1468
  textLimit,
1359
1469
  deliveryRest: params.deliveryRest,
1360
1470
  deliverChannelId,
1361
1471
  replyReference,
1362
- tableMode,
1363
- maxLinesPerMessage,
1364
- chunkMode,
1472
+ onFinalReplyStart: params.onFinalReplyStart,
1473
+ onFinalReplyDelivered: params.onFinalReplyDelivered,
1365
1474
  log: logVerbose
1366
1475
  }),
1367
1476
  resolvedBlockStreamingEnabled: resolveChannelStreamingBlockEnabled(discordConfig)
@@ -1412,15 +1521,22 @@ function isFallbackOnlyToolWarningFinal(payload) {
1412
1521
  }
1413
1522
  async function processDiscordMessage(ctx, observer) {
1414
1523
  const dispatchStartedAt = Date.now();
1415
- const { cfg, accountId, token, runtime, textLimit, replyToMode, message, messageChannelId, isGuildMessage, isDirectMessage, isGroupDm, messageText, threadBindings, route, abortSignal, turnAdoptionLifecycle, preparedMedia: mediaList } = ctx;
1416
- if (abortSignal?.aborted) return;
1524
+ const { cfg, accountId, token, runtime, textLimit, replyToMode, message, messageChannelId, isGuildMessage, isDirectMessage, isGroupDm, messageText, threadBindings, route, abortSignal, isPolicyCurrent, turnAdoptionLifecycle, preparedMedia: mediaList } = ctx;
1525
+ if (abortSignal?.aborted || isPolicyCurrent?.() === false) return;
1417
1526
  const text = messageText;
1418
1527
  if (!text && mediaList.length === 0) {
1419
1528
  logVerbose("discord: drop message " + message.id + " (empty content)");
1420
1529
  return;
1421
1530
  }
1422
1531
  const boundThreadId = ctx.threadBinding?.conversation?.conversationId?.trim();
1423
- if (boundThreadId && typeof threadBindings.touchThread === "function") threadBindings.touchThread({ threadId: boundThreadId });
1532
+ if (boundThreadId && typeof threadBindings.touchThread === "function") {
1533
+ try {
1534
+ await threadBindings.touchThread({ threadId: boundThreadId });
1535
+ } catch (error) {
1536
+ runtime.error(danger(`discord: failed to refresh thread binding activity (${boundThreadId}): ${String(error)}`));
1537
+ }
1538
+ if (abortSignal?.aborted || isPolicyCurrent?.() === false) return;
1539
+ }
1424
1540
  const sourceReplyDeliveryMode = resolveChannelMessageSourceReplyDeliveryMode({
1425
1541
  cfg,
1426
1542
  ctx: {
@@ -1460,7 +1576,7 @@ async function processDiscordMessage(ctx, observer) {
1460
1576
  createdThreadId: replyPlan.createdThreadId,
1461
1577
  sessionKey: persistedSessionKey
1462
1578
  });
1463
- const { replyPipeline, onModelSelected, tableMode, maxLinesPerMessage, chunkMode, beginQueuedDeliveryCorrelation, endDeliveryCorrelation, resolveCurrentTurnTranscriptFinalText, deliverChannelId: initialDeliverChannelId, draftPreview, resolvedBlockStreamingEnabled } = createDiscordMessageReplyRuntime({
1579
+ const { replyPipeline, onModelSelected, tableMode, maxLinesPerMessage, chunkMode, beginQueuedDeliveryCorrelation, endDeliveryCorrelation, resolveCurrentTurnTranscriptFinalText, draftPreview, resolvedBlockStreamingEnabled } = createDiscordMessageReplyRuntime({
1464
1580
  ctx,
1465
1581
  processContext: {
1466
1582
  ...processContext,
@@ -1471,40 +1587,29 @@ async function processDiscordMessage(ctx, observer) {
1471
1587
  isRoomEvent,
1472
1588
  dispatchStartedAt,
1473
1589
  feedbackRest: reactions.feedbackRest,
1474
- deliveryRest: reactions.deliveryRest
1590
+ deliveryRest: reactions.deliveryRest,
1591
+ onFinalReplyStart: observer?.onFinalReplyStart,
1592
+ onFinalReplyDelivered: observer?.onFinalReplyDelivered
1475
1593
  });
1476
- let deliverChannelId = initialDeliverChannelId;
1594
+ let deliverThreadId = ctxPayload.MessageThreadId;
1477
1595
  activeThreadRoute.bindThreadAdoption(async (threadId) => {
1478
1596
  deliverTarget = `channel:${threadId}`;
1479
- deliverChannelId = threadId;
1597
+ deliverThreadId = threadId;
1480
1598
  await draftPreview.retarget(threadId);
1481
1599
  });
1482
- let finalReplyStartNotified = false;
1483
- const notifyFinalReplyStart = () => {
1484
- if (finalReplyStartNotified) return;
1485
- finalReplyStartNotified = true;
1486
- draftPreview.markFinalReplyStarted();
1487
- observer?.onFinalReplyStart?.();
1600
+ const { lifecycle } = draftPreview;
1601
+ const observeFinalDelivery = async () => {
1602
+ if (lifecycle.finalSucceeded) return;
1603
+ draftPreview.freezeProgress();
1604
+ const retainedProgress = activeThreadRoute.threadReplyDelivered && !lifecycle.previewFinalized ? draftPreview.finalizeProgressDraft().catch((error) => {
1605
+ logVerbose(`discord: failed to finalize adopted thread progress (${String(error)})`);
1606
+ }) : void 0;
1607
+ await lifecycle.observeDelivery({ visibleReplySent: true });
1608
+ await retainedProgress;
1488
1609
  };
1489
- let userFacingFinalDelivered = false;
1490
- let userFacingFinalDeliveryFailed = false;
1491
1610
  let pendingToolWarningFinal;
1492
- const markFinalReplyDelivered = (isError = false) => {
1493
- draftPreview.markFinalReplyDelivered(isError);
1494
- if (!isError) {
1495
- userFacingFinalDelivered = true;
1496
- userFacingFinalDeliveryFailed = false;
1497
- pendingToolWarningFinal = void 0;
1498
- observer?.onFinalReplyDelivered?.();
1499
- }
1500
- };
1501
- let clearProgressDraftAfterFinalDelivery = false;
1502
1611
  const resetDeliveryState = () => {
1503
- finalReplyStartNotified = false;
1504
- userFacingFinalDelivered = false;
1505
- userFacingFinalDeliveryFailed = false;
1506
1612
  pendingToolWarningFinal = void 0;
1507
- clearProgressDraftAfterFinalDelivery = false;
1508
1613
  };
1509
1614
  const progress = createDiscordMessageProgressRuntime({
1510
1615
  ctx,
@@ -1544,7 +1649,6 @@ async function processDiscordMessage(ctx, observer) {
1544
1649
  token,
1545
1650
  accountId,
1546
1651
  rest: reactions.deliveryRest,
1547
- runtime,
1548
1652
  replyToMode,
1549
1653
  textLimit,
1550
1654
  maxLinesPerMessage,
@@ -1589,14 +1693,14 @@ async function processDiscordMessage(ctx, observer) {
1589
1693
  return result;
1590
1694
  }
1591
1695
  if (isFinal && !options?.allowFallbackOnlyToolWarning && isFallbackOnlyToolWarningFinal(payload)) {
1592
- if (!userFacingFinalDelivered && (!finalReplyStartNotified || userFacingFinalDeliveryFailed)) pendingToolWarningFinal = {
1696
+ if (!lifecycle.finalSucceeded && !lifecycle.previewFinalized && (!lifecycle.finalStarted || lifecycle.finalFailed)) pendingToolWarningFinal = {
1593
1697
  payload,
1594
1698
  info,
1595
1699
  deliverySession
1596
1700
  };
1597
1701
  return { visibleReplySent: false };
1598
1702
  }
1599
- if (isFinal) draftPreview.markFinalReplyStarted();
1703
+ if (isFinal) draftPreview.freezeProgress();
1600
1704
  const finalText = isFinal && !ctxPayload.GroupThread && typeof payload.text === "string" ? await resolveTranscriptBackedChannelFinalText({
1601
1705
  payload,
1602
1706
  finalText: payload.text,
@@ -1616,104 +1720,56 @@ async function processDiscordMessage(ctx, observer) {
1616
1720
  }));
1617
1721
  return { visibleReplySent: false };
1618
1722
  }
1723
+ if (await draftPreview.adoptProgressContinuation(deliverablePayload, info, {
1724
+ to: isDirectMessage ? ctxPayload.OriginatingTo ?? ctxPayload.To ?? deliverTarget : deliverTarget,
1725
+ threadId: deliverThreadId
1726
+ })) {
1727
+ replyReference.markSent();
1728
+ return { visibleReplySent: true };
1729
+ }
1619
1730
  if (isFinal && !replyLifecycleStarted && !isRoomEvent && configuredTypingMode !== "never") await onDiscordReplyStart();
1620
1731
  const draftStream = draftPreview.draftStream;
1621
1732
  if (draftStream && draftPreview.isProgressMode && info.kind === "block" && !deliverablePayload.isCommentary && !options?.allowProgressBlock) {
1622
1733
  if (!resolveSendableOutboundReplyParts(deliverablePayload).hasMedia && !deliverablePayload.isError) return { visibleReplySent: false };
1623
1734
  }
1624
- if (draftStream && isFinal && draftPreview.isProgressMode && !deliverablePayload.isError && draftPreview.hasProgressDraftToCollapse && draftStream) {
1625
- await draftPreview.flush();
1626
- clearProgressDraftAfterFinalDelivery = true;
1627
- }
1628
- if (draftStream && isFinal && !draftPreview.isProgressMode && !deliverablePayload.isError) {
1629
- const ttsSupplement = getReplyPayloadTtsSupplement(deliverablePayload);
1630
- if ((await deliverWithFinalizableLivePreviewAdapter({
1631
- kind: info.kind,
1632
- payload: deliverablePayload,
1633
- adapter: defineFinalizableLivePreviewAdapter({
1634
- draft: {
1635
- flush: () => draftPreview.flush(),
1636
- clear: () => draftStream.clear(),
1637
- discardPending: () => draftStream.discardPending(),
1638
- seal: () => draftStream.seal(),
1639
- id: draftStream.messageId
1640
- },
1641
- buildFinalEdit: () => {},
1642
- editFinal: async (previewMessageId, edit) => {
1643
- if (abortSignal?.aborted) throw new Error("process aborted");
1644
- notifyFinalReplyStart();
1645
- await editMessageDiscord(deliverChannelId, previewMessageId, edit, {
1646
- cfg,
1647
- accountId,
1648
- rest: reactions.deliveryRest
1649
- });
1650
- },
1651
- onPreviewFinalized: () => {
1652
- markFinalReplyDelivered();
1653
- draftPreview.markPreviewFinalized();
1654
- replyReference.markSent();
1655
- },
1656
- logPreviewEditFailure: (err) => {
1657
- logVerbose(`discord: preview final edit failed; falling back to standard send (${String(err)})`);
1658
- }
1659
- }),
1660
- deliverNormally: async () => {
1661
- if (abortSignal?.aborted) return false;
1662
- const fallbackPayload = ttsSupplement && ttsSupplement.visibleTextAlreadyDelivered !== true && !deliverablePayload.text?.trim() ? {
1663
- ...deliverablePayload,
1664
- text: ttsSupplement.spokenText
1665
- } : deliverablePayload;
1666
- const allowedMentions = discordTextHasBroadcastMention(fallbackPayload.text ?? "") ? TARGETED_ONLY_ALLOWED_MENTIONS : void 0;
1667
- const replyToId = replyReference.use();
1668
- notifyFinalReplyStart();
1669
- return (await deliverDiscordReply({
1670
- ...deliveryOptions,
1671
- replies: [fallbackPayload],
1735
+ let deliveryResult = { visibleReplySent: false };
1736
+ await lifecycle.deliver({
1737
+ kind: info.kind,
1738
+ payload: deliverablePayload,
1739
+ isError: deliverablePayload.isError === true,
1740
+ deliverNormally: async () => {
1741
+ if (abortSignal?.aborted) {
1742
+ logVerbose(formatDiscordReplySkip({
1743
+ kind: info.kind,
1744
+ reason: "aborted before delivery",
1672
1745
  target: deliverTarget,
1673
- replyToId,
1674
- allowedMentions,
1675
- kind: info.kind
1676
- })).visibleReplySent;
1677
- },
1678
- onNormalDelivered: () => {
1679
- markFinalReplyDelivered();
1680
- replyReference.markSent();
1746
+ sessionKey: ctxPayload.SessionKey
1747
+ }));
1748
+ return deliveryResult;
1681
1749
  }
1682
- })).kind !== "normal-skipped") return { visibleReplySent: true };
1683
- }
1684
- if (abortSignal?.aborted) {
1685
- logVerbose(formatDiscordReplySkip({
1686
- kind: info.kind,
1687
- reason: "aborted before delivery",
1688
- target: deliverTarget,
1689
- sessionKey: ctxPayload.SessionKey
1690
- }));
1691
- return { visibleReplySent: false };
1692
- }
1693
- const replyToId = replyReference.use();
1694
- if (isFinal) notifyFinalReplyStart();
1695
- const result = await deliverDiscordReply({
1696
- ...deliveryOptions,
1697
- replies: [deliverablePayload],
1698
- target: deliverTarget,
1699
- replyToId,
1700
- kind: info.kind
1750
+ const freshPreviewFinal = draftStream && isFinal && !draftPreview.isProgressMode && !deliverablePayload.isError;
1751
+ const ttsSupplement = freshPreviewFinal ? getReplyPayloadTtsSupplement(deliverablePayload) : void 0;
1752
+ const finalPayload = ttsSupplement && ttsSupplement.visibleTextAlreadyDelivered !== true && !deliverablePayload.text?.trim() ? {
1753
+ ...deliverablePayload,
1754
+ text: ttsSupplement.spokenText
1755
+ } : deliverablePayload;
1756
+ const allowedMentions = freshPreviewFinal && discordTextHasBroadcastMention(finalPayload.text ?? "") ? TARGETED_ONLY_ALLOWED_MENTIONS : void 0;
1757
+ deliveryResult = await deliverDiscordReply({
1758
+ ...deliveryOptions,
1759
+ replies: [finalPayload],
1760
+ target: deliverTarget,
1761
+ replyToId: replyReference.use(),
1762
+ allowedMentions,
1763
+ kind: info.kind
1764
+ });
1765
+ return deliveryResult;
1766
+ },
1767
+ onNormalDelivered: () => replyReference.markSent()
1701
1768
  });
1702
- if (!result.visibleReplySent) return result;
1703
- replyReference.markSent();
1704
- if (isFinal) {
1705
- markFinalReplyDelivered(deliverablePayload.isError === true);
1706
- if (deliverablePayload.isError !== true && clearProgressDraftAfterFinalDelivery) {
1707
- clearProgressDraftAfterFinalDelivery = false;
1708
- draftPreview.markProgressDraftCollapsed();
1709
- await draftStream?.discardPending();
1710
- await draftStream?.clear();
1711
- }
1712
- }
1713
- return result;
1769
+ return deliveryResult;
1714
1770
  };
1715
1771
  const onDiscordDeliveryError = (err, info) => {
1716
- if (info.kind === "final" && finalReplyStartNotified && !userFacingFinalDelivered) userFacingFinalDeliveryFailed = true;
1772
+ if (info.kind === "final") lifecycle.observeFailure();
1717
1773
  runtime.error(danger(formatDiscordReplyDeliveryFailure({
1718
1774
  kind: info.kind,
1719
1775
  err,
@@ -1725,7 +1781,7 @@ async function processDiscordMessage(ctx, observer) {
1725
1781
  let dispatchError = false;
1726
1782
  let dispatchAborted = false;
1727
1783
  const deliverPendingToolWarningFinalIfNeeded = async () => {
1728
- if (!pendingToolWarningFinal || userFacingFinalDelivered || abortSignal?.aborted) return;
1784
+ if (!pendingToolWarningFinal || lifecycle.finalSucceeded || lifecycle.previewFinalized || abortSignal?.aborted) return;
1729
1785
  const pending = pendingToolWarningFinal;
1730
1786
  pendingToolWarningFinal = void 0;
1731
1787
  try {
@@ -1740,7 +1796,7 @@ async function processDiscordMessage(ctx, observer) {
1740
1796
  }
1741
1797
  };
1742
1798
  try {
1743
- if (abortSignal?.aborted) {
1799
+ if (abortSignal?.aborted || isPolicyCurrent?.() === false) {
1744
1800
  dispatchAborted = true;
1745
1801
  return;
1746
1802
  }
@@ -1795,6 +1851,7 @@ async function processDiscordMessage(ctx, observer) {
1795
1851
  disableBlockStreaming: sourceRepliesAreToolOnly ? true : draftPreview.disableBlockStreamingForDraft ?? (typeof resolvedBlockStreamingEnabled === "boolean" ? !resolvedBlockStreamingEnabled : void 0),
1796
1852
  onPartialReply: draftPreview.draftStream && !draftPreview.isProgressMode ? (payload) => draftPreview.updateFromPartial(payload.text) : void 0,
1797
1853
  ...progress.replyOptions,
1854
+ onObservedReplyDelivery: observeFinalDelivery,
1798
1855
  onModelSelected
1799
1856
  }
1800
1857
  });
@@ -1804,15 +1861,7 @@ async function processDiscordMessage(ctx, observer) {
1804
1861
  dispatchAborted = true;
1805
1862
  return;
1806
1863
  }
1807
- if (activeThreadRoute.threadReplyDelivered && !userFacingFinalDelivered) {
1808
- draftPreview.markFinalReplyStarted();
1809
- if (draftPreview.hasProgressDraftToCollapse) try {
1810
- await draftPreview.finalizeProgressDraft();
1811
- } catch (error) {
1812
- logVerbose(`discord: failed to finalize adopted thread progress (${String(error)})`);
1813
- }
1814
- markFinalReplyDelivered();
1815
- }
1864
+ if (activeThreadRoute.threadReplyDelivered) await observeFinalDelivery();
1816
1865
  } catch (err) {
1817
1866
  if (abortSignal?.aborted) {
1818
1867
  dispatchAborted = true;
@@ -1832,10 +1881,10 @@ async function processDiscordMessage(ctx, observer) {
1832
1881
  } finally {
1833
1882
  activeThreadRoute.end();
1834
1883
  endDeliveryCorrelation();
1835
- await draftPreview.cleanup({ finalDeliveryFailed: userFacingFinalDeliveryFailed });
1836
1884
  dispatchError ||= readAgentRunTerminalOutcome(dispatchResult) === "failed";
1837
1885
  const finalReceipt = dispatchResult?.settledReceipt?.counts.final;
1838
1886
  const finalDeliveryFailed = (finalReceipt?.failedBeforeSend ?? 0) + (finalReceipt?.failedAfterSend ?? 0) > 0;
1887
+ await draftPreview.cleanup({ failed: finalDeliveryFailed || dispatchError });
1839
1888
  await reactions.finish({
1840
1889
  dispatchAborted,
1841
1890
  dispatchError,
@@ -1851,4 +1900,4 @@ async function processDiscordMessage(ctx, observer) {
1851
1900
  }
1852
1901
  }
1853
1902
  //#endregion
1854
- export { formatDiscordReplySkip, processDiscordMessage };
1903
+ export { processDiscordMessage };