@openclaw/slack 2026.8.1-beta.2 → 2026.8.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (246) hide show
  1. package/dist/account-configured-sUohAxZr.js +33 -0
  2. package/dist/account-inspect-CN2hBsim.js +87 -0
  3. package/dist/account-inspect-api.js +1 -1
  4. package/dist/{accounts-CK4AVI2_.js → accounts-Dm_H77gH.js} +12 -11
  5. package/dist/{accounts.runtime-Cb7QwWBz.js → accounts.runtime-DRuEK6mL.js} +1 -1
  6. package/dist/{action-runtime-BkGe7ny_.js → action-runtime-044ldvNL.js} +80 -79
  7. package/dist/action-runtime.runtime-BL3KzX13.js +2 -0
  8. package/dist/{actions-BTDXwwE3.js → actions-BI7JkfVm.js} +273 -263
  9. package/dist/api.js +14 -14
  10. package/dist/{approval-handler.runtime-CJaNzAq2.js → approval-handler.runtime-DYv0UIZS.js} +53 -174
  11. package/dist/{channel-D_tovcUL.js → channel-1vIJOzPx.js} +134 -160
  12. package/dist/channel-config-api.js +1 -1
  13. package/dist/channel-plugin-api.js +1 -1
  14. package/dist/{channel-type-B9MSdoGN.js → channel-type-DlFSKeIZ.js} +3 -7
  15. package/dist/{channel.setup-Bch9dYmA.js → channel.setup-ofDi3_Pu.js} +34 -49
  16. package/dist/{config-schema-xto5jFIx.js → config-schema-BVIMyiDN.js} +42 -19
  17. package/dist/configured-state.js +34 -0
  18. package/dist/conversation-binding-route-DFVLUdYF.js +115 -0
  19. package/dist/{directory-config-CNBz8lJa.js → directory-config-DqfQ42OV.js} +1 -1
  20. package/dist/directory-contract-api.js +1 -1
  21. package/dist/{directory-live-CFKUtW9E.js → directory-live-BPaNHjmP.js} +2 -2
  22. package/dist/{group-policy-c4RP9bjc.js → group-policy-BdwszjYn.js} +625 -773
  23. package/dist/{message-tool-api-BykQB4AU.js → message-tool-api-CJ0kjcg5.js} +23 -5
  24. package/dist/message-tool-api.js +1 -1
  25. package/dist/{monitor-1nF1NtqT.js → monitor-Dq5Cmrvp.js} +3 -3
  26. package/dist/{outbound-adapter-S81tsswN.js → outbound-adapter-DYaI8ThX.js} +101 -66
  27. package/dist/{pipeline.runtime-BvYsM5JO.js → pipeline.runtime-Bd22U0ga.js} +494 -474
  28. package/dist/{policy-TapwbeaT.js → policy-CtQVbde1.js} +2 -1
  29. package/dist/{probe-HoEg_WxB.js → probe-0usmAb0i.js} +209 -22
  30. package/dist/{provider-CDNvBXUi.js → provider-CN_8hFv2.js} +296 -178
  31. package/dist/{relay-source-C9leF11u.js → relay-source-BNGpsdwV.js} +1 -1
  32. package/dist/{replies-CeOfv82I.js → replies-BSiRQOJ1.js} +48 -27
  33. package/dist/{resolve-channels-CNPrxaXY.js → resolve-channels-Czheznc8.js} +1 -1
  34. package/dist/{resolve-users-Dzomuwnr.js → resolve-users-BAOlNimr.js} +1 -1
  35. package/dist/runtime-api.js +11 -11
  36. package/dist/{scopes-cYXKkrRD.js → scopes-COSlmhnH.js} +1 -1
  37. package/dist/security-contract-api.js +1 -1
  38. package/dist/{send-Nor0iBwY.js → send-DS9ICrBI.js} +88 -100
  39. package/dist/send-results-eeOu_HYm.js +23 -0
  40. package/dist/{send.runtime-BmgNe6S9.js → send.runtime-D_Bb6IuH.js} +1 -1
  41. package/dist/setup-plugin-api.js +1 -1
  42. package/dist/{setup-surface-CbX1-Knh.js → setup-surface-BGnd2pSe.js} +6 -6
  43. package/dist/{shared-zdT5AMp-.js → shared-D5B-5hBg.js} +35 -9
  44. package/dist/{slash-dispatch.runtime-Bnr9GR1S.js → slash-dispatch.runtime-CilDmI0c.js} +2 -2
  45. package/node_modules/@slack/bolt/node_modules/@types/node/README.md +1 -1
  46. package/node_modules/@slack/bolt/node_modules/@types/node/child_process.d.ts +0 -1
  47. package/node_modules/@slack/bolt/node_modules/@types/node/crypto.d.ts +6 -6
  48. package/node_modules/@slack/bolt/node_modules/@types/node/dns/promises.d.ts +5 -5
  49. package/node_modules/@slack/bolt/node_modules/@types/node/dns.d.ts +5 -5
  50. package/node_modules/@slack/bolt/node_modules/@types/node/fs.d.ts +7 -0
  51. package/node_modules/@slack/bolt/node_modules/@types/node/http.d.ts +30 -0
  52. package/node_modules/@slack/bolt/node_modules/@types/node/http2.d.ts +4 -4
  53. package/node_modules/@slack/bolt/node_modules/@types/node/os.d.ts +30 -30
  54. package/node_modules/@slack/bolt/node_modules/@types/node/package.json +2 -2
  55. package/node_modules/@slack/bolt/node_modules/@types/node/perf_hooks.d.ts +2 -1
  56. package/node_modules/@slack/bolt/node_modules/@types/node/process.d.ts +42 -43
  57. package/node_modules/@slack/bolt/node_modules/@types/node/quic.d.ts +1049 -84
  58. package/node_modules/@slack/bolt/node_modules/@types/node/sqlite.d.ts +14 -1
  59. package/node_modules/@slack/bolt/node_modules/@types/node/stream/iter.d.ts +3 -2
  60. package/node_modules/@slack/bolt/node_modules/@types/node/test.d.ts +61 -0
  61. package/node_modules/@slack/bolt/node_modules/@types/node/v8.d.ts +20 -23
  62. package/node_modules/@slack/bolt/node_modules/body-parser/node_modules/content-type/README.md +2 -0
  63. package/node_modules/@slack/bolt/node_modules/body-parser/node_modules/content-type/dist/index.d.ts +20 -0
  64. package/node_modules/@slack/bolt/node_modules/body-parser/node_modules/content-type/dist/index.js +20 -14
  65. package/node_modules/@slack/bolt/node_modules/body-parser/node_modules/content-type/dist/index.js.map +1 -1
  66. package/node_modules/@slack/bolt/node_modules/body-parser/node_modules/content-type/package.json +1 -1
  67. package/node_modules/@slack/bolt/node_modules/type-is/node_modules/content-type/README.md +2 -0
  68. package/node_modules/@slack/bolt/node_modules/type-is/node_modules/content-type/dist/index.d.ts +20 -0
  69. package/node_modules/@slack/bolt/node_modules/type-is/node_modules/content-type/dist/index.js +20 -14
  70. package/node_modules/@slack/bolt/node_modules/type-is/node_modules/content-type/dist/index.js.map +1 -1
  71. package/node_modules/@slack/bolt/node_modules/type-is/node_modules/content-type/package.json +1 -1
  72. package/node_modules/@slack/socket-mode/node_modules/@types/node/README.md +1 -1
  73. package/node_modules/@slack/socket-mode/node_modules/@types/node/child_process.d.ts +0 -1
  74. package/node_modules/@slack/socket-mode/node_modules/@types/node/crypto.d.ts +6 -6
  75. package/node_modules/@slack/socket-mode/node_modules/@types/node/dns/promises.d.ts +5 -5
  76. package/node_modules/@slack/socket-mode/node_modules/@types/node/dns.d.ts +5 -5
  77. package/node_modules/@slack/socket-mode/node_modules/@types/node/fs.d.ts +7 -0
  78. package/node_modules/@slack/socket-mode/node_modules/@types/node/http.d.ts +30 -0
  79. package/node_modules/@slack/socket-mode/node_modules/@types/node/http2.d.ts +4 -4
  80. package/node_modules/@slack/socket-mode/node_modules/@types/node/os.d.ts +30 -30
  81. package/node_modules/@slack/socket-mode/node_modules/@types/node/package.json +2 -2
  82. package/node_modules/@slack/socket-mode/node_modules/@types/node/perf_hooks.d.ts +2 -1
  83. package/node_modules/@slack/socket-mode/node_modules/@types/node/process.d.ts +42 -43
  84. package/node_modules/@slack/socket-mode/node_modules/@types/node/quic.d.ts +1049 -84
  85. package/node_modules/@slack/socket-mode/node_modules/@types/node/sqlite.d.ts +14 -1
  86. package/node_modules/@slack/socket-mode/node_modules/@types/node/stream/iter.d.ts +3 -2
  87. package/node_modules/@slack/socket-mode/node_modules/@types/node/test.d.ts +61 -0
  88. package/node_modules/@slack/socket-mode/node_modules/@types/node/v8.d.ts +20 -23
  89. package/node_modules/@slack/web-api/node_modules/@types/node/README.md +1 -1
  90. package/node_modules/@slack/web-api/node_modules/@types/node/child_process.d.ts +0 -1
  91. package/node_modules/@slack/web-api/node_modules/@types/node/crypto.d.ts +6 -6
  92. package/node_modules/@slack/web-api/node_modules/@types/node/dns/promises.d.ts +5 -5
  93. package/node_modules/@slack/web-api/node_modules/@types/node/dns.d.ts +5 -5
  94. package/node_modules/@slack/web-api/node_modules/@types/node/fs.d.ts +7 -0
  95. package/node_modules/@slack/web-api/node_modules/@types/node/http.d.ts +30 -0
  96. package/node_modules/@slack/web-api/node_modules/@types/node/http2.d.ts +4 -4
  97. package/node_modules/@slack/web-api/node_modules/@types/node/os.d.ts +30 -30
  98. package/node_modules/@slack/web-api/node_modules/@types/node/package.json +2 -2
  99. package/node_modules/@slack/web-api/node_modules/@types/node/perf_hooks.d.ts +2 -1
  100. package/node_modules/@slack/web-api/node_modules/@types/node/process.d.ts +42 -43
  101. package/node_modules/@slack/web-api/node_modules/@types/node/quic.d.ts +1049 -84
  102. package/node_modules/@slack/web-api/node_modules/@types/node/sqlite.d.ts +14 -1
  103. package/node_modules/@slack/web-api/node_modules/@types/node/stream/iter.d.ts +3 -2
  104. package/node_modules/@slack/web-api/node_modules/@types/node/test.d.ts +61 -0
  105. package/node_modules/@slack/web-api/node_modules/@types/node/v8.d.ts +20 -23
  106. package/node_modules/typebox/build/format/date.d.mts +1 -1
  107. package/node_modules/typebox/build/format/date.mjs +1 -1
  108. package/node_modules/typebox/build/format/date_time.d.mts +2 -2
  109. package/node_modules/typebox/build/format/date_time.mjs +3 -3
  110. package/node_modules/typebox/build/format/email.d.mts +1 -1
  111. package/node_modules/typebox/build/format/email.mjs +2 -2
  112. package/node_modules/typebox/build/format/hostname.mjs +2 -10
  113. package/node_modules/typebox/build/format/idn_email.d.mts +1 -1
  114. package/node_modules/typebox/build/format/idn_email.mjs +3 -3
  115. package/node_modules/typebox/build/format/idn_hostname.d.mts +1 -0
  116. package/node_modules/typebox/build/format/idn_hostname.mjs +3 -11
  117. package/node_modules/typebox/build/format/idna/format/bidi.d.mts +3 -0
  118. package/node_modules/typebox/build/format/idna/format/bidi.mjs +98 -0
  119. package/node_modules/typebox/build/format/idna/format/puny.d.mts +3 -0
  120. package/node_modules/typebox/build/format/idna/format/puny.mjs +144 -0
  121. package/node_modules/typebox/build/format/idna/hostname.d.mts +1 -0
  122. package/node_modules/typebox/build/format/idna/hostname.mjs +16 -0
  123. package/node_modules/typebox/build/format/idna/idn-hostname.d.mts +1 -0
  124. package/node_modules/typebox/build/format/idna/idn-hostname.mjs +23 -0
  125. package/node_modules/typebox/build/format/idna/index.d.mts +2 -0
  126. package/node_modules/typebox/build/format/idna/index.mjs +2 -0
  127. package/node_modules/typebox/build/format/idna/label/ascii.d.mts +1 -0
  128. package/node_modules/typebox/build/format/idna/label/ascii.mjs +9 -0
  129. package/node_modules/typebox/build/format/idna/label/puny.d.mts +1 -0
  130. package/node_modules/typebox/build/format/idna/label/puny.mjs +28 -0
  131. package/node_modules/typebox/build/format/idna/label/unicode.d.mts +1 -0
  132. package/node_modules/typebox/build/format/idna/label/unicode.mjs +106 -0
  133. package/node_modules/typebox/build/format/idna/pattern/pattern.d.mts +30 -0
  134. package/node_modules/typebox/build/format/idna/pattern/pattern.mjs +70 -0
  135. package/node_modules/typebox/build/format/ipv4.d.mts +0 -1
  136. package/node_modules/typebox/build/format/ipv4.mjs +2 -32
  137. package/node_modules/typebox/build/format/ipv6.mjs +2 -61
  138. package/node_modules/typebox/build/format/iri.d.mts +2 -2
  139. package/node_modules/typebox/build/format/iri.mjs +26 -8
  140. package/node_modules/typebox/build/format/iri_reference.d.mts +2 -2
  141. package/node_modules/typebox/build/format/iri_reference.mjs +9 -55
  142. package/node_modules/typebox/build/format/regex.d.mts +1 -2
  143. package/node_modules/typebox/build/format/regex.mjs +2 -6
  144. package/node_modules/typebox/build/format/time.d.mts +2 -2
  145. package/node_modules/typebox/build/format/time.mjs +19 -14
  146. package/node_modules/typebox/build/format/uri.d.mts +1 -1
  147. package/node_modules/typebox/build/format/uri.mjs +3 -130
  148. package/node_modules/typebox/build/format/uri_reference.d.mts +1 -1
  149. package/node_modules/typebox/build/format/uri_reference.mjs +2 -3
  150. package/node_modules/typebox/build/format/uri_template.d.mts +2 -3
  151. package/node_modules/typebox/build/format/uri_template.mjs +4 -5
  152. package/node_modules/typebox/build/format/url.d.mts +3 -3
  153. package/node_modules/typebox/build/format/url.mjs +4 -5
  154. package/node_modules/typebox/build/guard/emit.d.mts +3 -1
  155. package/node_modules/typebox/build/guard/emit.mjs +12 -5
  156. package/node_modules/typebox/build/guard/guard.d.mts +8 -2
  157. package/node_modules/typebox/build/guard/guard.mjs +25 -4
  158. package/node_modules/typebox/build/guard/string.d.mts +2 -2
  159. package/node_modules/typebox/build/guard/string.mjs +7 -7
  160. package/node_modules/typebox/build/schema/engine/_context.mjs +3 -3
  161. package/node_modules/typebox/build/schema/engine/_functions.mjs +1 -2
  162. package/node_modules/typebox/build/schema/engine/_regexp.d.mts +2 -0
  163. package/node_modules/typebox/build/schema/engine/_regexp.mjs +4 -0
  164. package/node_modules/typebox/build/schema/engine/_stack.mjs +12 -13
  165. package/node_modules/typebox/build/schema/engine/additionalItems.mjs +17 -7
  166. package/node_modules/typebox/build/schema/engine/additionalProperties.mjs +4 -3
  167. package/node_modules/typebox/build/schema/engine/contains.mjs +18 -6
  168. package/node_modules/typebox/build/schema/engine/enum.mjs +1 -1
  169. package/node_modules/typebox/build/schema/engine/items.mjs +26 -6
  170. package/node_modules/typebox/build/schema/engine/maxContains.mjs +3 -3
  171. package/node_modules/typebox/build/schema/engine/minContains.mjs +14 -4
  172. package/node_modules/typebox/build/schema/engine/not.mjs +4 -2
  173. package/node_modules/typebox/build/schema/engine/oneOf.mjs +7 -6
  174. package/node_modules/typebox/build/schema/engine/pattern.mjs +3 -2
  175. package/node_modules/typebox/build/schema/engine/patternProperties.mjs +4 -3
  176. package/node_modules/typebox/build/schema/engine/ref.mjs +1 -7
  177. package/node_modules/typebox/build/schema/engine/schema.mjs +13 -4
  178. package/node_modules/typebox/build/schema/engine/type.mjs +1 -1
  179. package/node_modules/typebox/build/schema/resolve/resolve.d.mts +4 -1
  180. package/node_modules/typebox/build/schema/resolve/resolve.mjs +202 -1
  181. package/node_modules/typebox/build/schema/static/propertyNames.d.mts +5 -0
  182. package/node_modules/typebox/build/schema/static/propertyNames.mjs +3 -0
  183. package/node_modules/typebox/build/schema/static/schema.d.mts +3 -0
  184. package/node_modules/typebox/build/schema/types/index.d.mts +0 -2
  185. package/node_modules/typebox/build/schema/types/index.mjs +0 -2
  186. package/node_modules/typebox/build/system/memory/clone.mjs +14 -11
  187. package/node_modules/typebox/build/system/memory/discard.mjs +6 -5
  188. package/node_modules/typebox/build/system/settings/settings.d.mts +9 -0
  189. package/node_modules/typebox/build/system/settings/settings.mjs +2 -0
  190. package/node_modules/typebox/build/type/engine/call/distribute_arguments.d.mts +6 -1
  191. package/node_modules/typebox/build/type/engine/call/distribute_arguments.mjs +16 -3
  192. package/node_modules/typebox/build/type/engine/call/instantiate.mjs +34 -4
  193. package/node_modules/typebox/build/type/engine/evaluate/broaden.d.mts +5 -5
  194. package/node_modules/typebox/build/type/engine/evaluate/broaden.mjs +20 -26
  195. package/node_modules/typebox/build/type/engine/evaluate/compare.d.mts +6 -10
  196. package/node_modules/typebox/build/type/engine/evaluate/compare.mjs +9 -13
  197. package/node_modules/typebox/build/type/engine/evaluate/composite.d.mts +7 -4
  198. package/node_modules/typebox/build/type/engine/evaluate/composite.mjs +12 -19
  199. package/node_modules/typebox/build/type/engine/evaluate/distribute.d.mts +4 -20
  200. package/node_modules/typebox/build/type/engine/evaluate/distribute.mjs +8 -20
  201. package/node_modules/typebox/build/type/engine/evaluate/evaluate.d.mts +4 -4
  202. package/node_modules/typebox/build/type/engine/evaluate/evaluate.mjs +11 -8
  203. package/node_modules/typebox/build/type/engine/evaluate/flatten.d.mts +1 -1
  204. package/node_modules/typebox/build/type/engine/evaluate/flatten.mjs +3 -4
  205. package/node_modules/typebox/build/type/engine/evaluate/narrow.d.mts +17 -2
  206. package/node_modules/typebox/build/type/engine/evaluate/narrow.mjs +26 -6
  207. package/node_modules/typebox/build/type/engine/exclude/operation.mjs +3 -4
  208. package/node_modules/typebox/build/type/engine/extract/operation.d.mts +1 -1
  209. package/node_modules/typebox/build/type/engine/extract/operation.mjs +3 -4
  210. package/node_modules/typebox/build/type/engine/priority/priority.d.mts +2 -2
  211. package/node_modules/typebox/build/type/engine/priority/priority.mjs +3 -4
  212. package/node_modules/typebox/build/type/script/mapping.d.mts +32 -29
  213. package/node_modules/typebox/build/type/script/mapping.mjs +18 -25
  214. package/node_modules/typebox/build/type/script/parser.d.mts +19 -25
  215. package/node_modules/typebox/build/type/script/parser.mjs +27 -23
  216. package/node_modules/typebox/build/value/errors/errors.d.mts +2 -2
  217. package/node_modules/typebox/build/value/errors/errors.mjs +1 -1
  218. package/node_modules/typebox/package.json +27 -27
  219. package/node_modules/typebox/readme.md +79 -82
  220. package/node_modules/ws/lib/permessage-deflate.js +3 -1
  221. package/node_modules/ws/package.json +1 -1
  222. package/openclaw.plugin.json +57 -7
  223. package/package.json +9 -9
  224. package/dist/account-configured-BwfXBo_F.js +0 -14
  225. package/dist/account-inspect-Drw2gAiN.js +0 -89
  226. package/dist/account-reply-mode-DrUXogvO.js +0 -14
  227. package/dist/action-runtime.runtime-D9I6uc0Q.js +0 -2
  228. package/dist/actions.runtime-DLFyUkvg.js +0 -2
  229. package/dist/block-text-YtiNkqmx.js +0 -79
  230. package/dist/runtime-api-Cj9nxBNv.js +0 -10
  231. package/node_modules/p-map/index.d.ts +0 -155
  232. package/node_modules/p-map/index.js +0 -285
  233. package/node_modules/p-map/license +0 -9
  234. package/node_modules/p-map/package.json +0 -57
  235. package/node_modules/p-map/readme.md +0 -190
  236. package/node_modules/typebox/build/format/_idna.d.mts +0 -2
  237. package/node_modules/typebox/build/format/_idna.mjs +0 -246
  238. package/node_modules/typebox/build/format/_puny.d.mts +0 -1
  239. package/node_modules/typebox/build/format/_puny.mjs +0 -77
  240. package/node_modules/typebox/build/schema/resolve/ref.d.mts +0 -3
  241. package/node_modules/typebox/build/schema/resolve/ref.mjs +0 -146
  242. package/node_modules/typebox/build/schema/types/contentEncoding.d.mts +0 -9
  243. package/node_modules/typebox/build/schema/types/contentEncoding.mjs +0 -13
  244. package/node_modules/typebox/build/schema/types/contentMediaType.d.mts +0 -9
  245. package/node_modules/typebox/build/schema/types/contentMediaType.mjs +0 -13
  246. package/dist/{security-audit-DR097212.js → security-audit-B_yKr7MW.js} +1 -1
@@ -1,35 +1,37 @@
1
- import { t as resolveSlackReplyToMode } from "./account-reply-mode-DrUXogvO.js";
2
- import { a as parseSlackTarget, n as formatSlackTarget } from "./target-parsing-BnMD2ZqZ.js";
3
- import "./targets-Cx5W_n3W.js";
4
- import { B as SLACK_TEXT_LIMIT, G as truncateSlackText, K as truncateSlackTextByUtf8Bytes, L as SLACK_EDIT_TEXT_MAX_BYTES, M as normalizeSlackOutboundText, N as buildSlackBlocksFallbackText, T as hasSlackNativeDataBlock, W as countSlackTextUtf8Bytes, Z as SLACK_SESSION_LINK_ACTION_ID, at as escapeSlackMrkdwn, c as normalizeSlackAllowOwnerEntry, s as normalizeAllowListLower, u as resolveSlackAllowListMatch, y as resolveSlackReplyRenderPlan } from "./group-policy-c4RP9bjc.js";
5
- import { r as formatSlackError } from "./probe-HoEg_WxB.js";
1
+ import { n as resolveSlackConversationBindingRoute, r as resolveSlackReplyToMode, t as normalizeSlackRouteBindingConfig } from "./conversation-binding-route-DFVLUdYF.js";
2
+ import { n as formatSlackTarget } from "./target-parsing-BnMD2ZqZ.js";
3
+ import { I as countSlackTextUtf8Bytes, L as truncateSlackText, M as SLACK_TEXT_LIMIT, Q as normalizeSlackOutboundText, R as truncateSlackTextByUtf8Bytes, T as buildSlackBlocksFallbackText, U as SLACK_SESSION_LINK_ACTION_ID, a as qualifySlackConversationId, b as hasSlackNativeDataBlock, et as escapeSlackMrkdwn, k as SLACK_EDIT_TEXT_MAX_BYTES, m as resolveSlackReplyRenderPlan, o as qualifySlackRoutePeerId, s as resolveSlackEnterpriseMainDmSessionKey } from "./group-policy-BdwszjYn.js";
4
+ import { f as resolveSlackAllowListMatch, l as normalizeAllowListLower, o as formatSlackError, u as normalizeSlackAllowOwnerEntry } from "./probe-0usmAb0i.js";
6
5
  import { n as resolveSlackStreamingMode, t as resolveSlackNativeStreaming } from "./streaming-compat-B-e0mqM0.js";
7
- import { b as formatSlackFileReference, i as editSlackRenderedMessage, p as removeSlackReaction, r as editSlackMessage, t as deleteSlackMessage, u as reactSlackMessage, v as resolveSlackThreadHistory, x as buildSlackEditTextPayload, y as resolveSlackThreadStarter } from "./actions-BTDXwwE3.js";
8
- import { a as resolveSlackMessageText } from "./block-text-YtiNkqmx.js";
9
- import { c as hasSlackThreadFailureNotice, d as recordSlackThreadFailureNotice, f as recordSlackThreadParticipation, l as hasSlackThreadParticipation, o as clearSlackThreadFailureNotice, p as buildSlackNativeDataDeliveryPlan, r as sendMessageSlack, u as hasSlackThreadParticipationWithPersistence } from "./send-Nor0iBwY.js";
10
- import { C as resolveChannelResetConfig, D as stripSlackMentionsForCommandDetection, S as resolveChannelContextVisibilityMode, T as updateLastRoute, _ as normalizeSlackChannelType, b as parseSlackAssistantThreadMetadata, c as resolveConversationLabel$1, d as resolveSlackEffectiveAllowFrom, g as resolveSlackEnterpriseMainDmSessionKey, h as qualifySlackRoutePeerId, l as authorizeSlackBotRoomMessage, m as qualifySlackConversationId, o as authorizeSlackDirectMessage, r as resolveSlackRoomContextHints, s as trackSlackDraftMessage, u as resolveSlackCommandIngress, v as resolveSlackChatType, w as resolveStorePath, x as readSessionUpdatedAt, y as buildSlackAssistantThreadMetadata } from "./provider-CDNvBXUi.js";
11
- import { n as resolveSlackChannelConfig } from "./policy-TapwbeaT.js";
12
- import { a as resolveDeliveredSlackReplyThreadTs, i as readSlackReplyBlocks, n as deliverReplies, o as resolveSlackThreadTs, s as emitSlackMessageSentHooks, t as createSlackReplyDeliveryPlan } from "./replies-CeOfv82I.js";
6
+ import { D as resolveSlackMessageText$1, E as resolveSlackBlocksText, O as buildSlackEditTextPayload, S as formatSlackFileReferenceList, T as isSlackUnfurlAttachment, a as editSlackRenderedMessage, d as reactSlackMessage, i as editSlackMessage, m as removeSlackReaction, n as deleteSlackMessage, v as logVerbose$1, w as hasSlackTableBlock, x as formatSlackFileReference } from "./actions-BI7JkfVm.js";
7
+ import { c as hasSlackThreadFailureNotice, d as recordSlackThreadFailureNotice, f as recordSlackThreadParticipation, l as hasSlackThreadParticipation, m as buildSlackNativeDataDeliveryPlan, o as clearSlackThreadFailureNotice, r as sendMessageSlack, u as hasSlackThreadParticipationWithPersistence } from "./send-DS9ICrBI.js";
8
+ import { C as resolveStorePath, E as stripSlackMentionsForCommandDetection, S as resolveChannelResetConfig, _ as resolveSlackChatType, b as readSessionUpdatedAt, c as resolveSlackThreadTargets, d as authorizeSlackBotRoomMessage, f as resolveSlackCommandIngress, g as normalizeSlackChannelType, l as trackSlackDraftMessage, o as authorizeSlackDirectMessage, p as resolveSlackEffectiveAllowFrom, r as resolveSlackRoomContextHints, s as resolveSlackThreadContext, u as resolveConversationLabel$1, v as buildSlackAssistantThreadMetadata, w as updateLastRoute, x as resolveChannelContextVisibilityMode, y as parseSlackAssistantThreadMetadata } from "./provider-CN_8hFv2.js";
9
+ import { n as resolveSlackChannelConfig } from "./policy-CtQVbde1.js";
10
+ import { a as resolveDeliveredSlackReplyThreadTs, c as emitSlackMessageSentHooks, i as readSlackReplyBlocks, n as deliverReplies, o as resolveSlackThreadTs, s as sanitizeSlackMonitorReplyPayload, t as createSlackReplyDeliveryPlan } from "./replies-BSiRQOJ1.js";
13
11
  import { asOptionalRecord, normalizeLowercaseStringOrEmpty, normalizeOptionalLowercaseString, normalizeOptionalString } from "openclaw/plugin-sdk/string-coerce-runtime";
14
12
  import { resolveAgentRoute, resolveInboundLastRouteSessionKey, resolveThreadSessionKeys } from "openclaw/plugin-sdk/routing";
15
- import { buildChannelProgressDraftLine, buildChannelProgressDraftLineForEntry, createChannelMessageReplyPipeline, createChannelProgressDraftCompositor, createChannelProgressReceiptTracker, createFinalizableDraftStreamControlsForState, defineFinalizableLivePreviewAdapter, deliverWithFinalizableLivePreviewAdapter, formatChannelProgressDraftText, formatPlanChecklistLines, isChannelProgressDraftWorkToolName, resolveAgentOutboundIdentity, resolveChannelMessageSourceReplyDeliveryMode, resolveChannelProgressDraftConfig, resolveChannelProgressDraftMaxLineChars, resolveChannelStreamingBlockEnabled, resolveChannelStreamingPreviewToolProgress, resolveChannelStreamingSuppressDefaultToolProgressMessages } from "openclaw/plugin-sdk/channel-outbound";
13
+ import { buildChannelProgressDraftLine, buildChannelProgressDraftLineForEntry, createChannelMessageReplyPipeline, createChannelProgressDraftCompositor, createChannelProgressWorkCounter, createFinalizableDraftStreamControlsForState, defineFinalizableLivePreviewAdapter, deliverWithFinalizableLivePreviewAdapter, formatChannelProgressDraftText, formatPlanChecklistLines, isChannelProgressDraftWorkToolName, resolveAgentOutboundIdentity, resolveChannelMessageSourceReplyDeliveryMode, resolveChannelProgressDraftConfig, resolveChannelProgressDraftMaxLineChars, resolveChannelStreamingBlockEnabled, resolveChannelStreamingPreviewToolProgress, resolveChannelStreamingSuppressDefaultToolProgressMessages } from "openclaw/plugin-sdk/channel-outbound";
16
14
  import { createLazyRuntimeModule } from "openclaw/plugin-sdk/lazy-runtime";
17
15
  import { danger, logVerbose, shouldLogVerbose } from "openclaw/plugin-sdk/runtime-env";
16
+ import { sanitizeAssistantVisibleText } from "openclaw/plugin-sdk/text-chunking";
17
+ import { resolveMarkdownTableMode } from "openclaw/plugin-sdk/markdown-table-runtime";
18
+ import { buildTtsSupplementMediaPayload, getReplyPayloadTtsSupplement, isReplyPayloadNonTerminalToolErrorWarning, resolveSendableOutboundReplyParts } from "openclaw/plugin-sdk/reply-payload";
18
19
  import { truncateUtf16Safe } from "openclaw/plugin-sdk/text-utility-runtime";
19
20
  import { createHash } from "node:crypto";
21
+ import { pruneMapToMaxSize } from "openclaw/plugin-sdk/collection-runtime";
22
+ import { ensureConfiguredBindingRouteReady } from "openclaw/plugin-sdk/conversation-runtime";
23
+ import { resolveChannelImplicitMentions } from "openclaw/plugin-sdk/channel-ingress-runtime";
20
24
  import fs from "node:fs/promises";
25
+ import { runTasksWithConcurrency } from "openclaw/plugin-sdk/concurrency-runtime";
21
26
  import { formatErrorMessage, toErrorObject } from "openclaw/plugin-sdk/error-runtime";
22
- import { asDateTimestampMs, asFiniteNumberInRange, parseStrictFiniteNumber, resolveExpiresAtMsFromDurationMs } from "openclaw/plugin-sdk/number-runtime";
23
- import { buildTtsSupplementMediaPayload, getReplyPayloadTtsSupplement, isReplyPayloadNonTerminalToolErrorWarning, resolveSendableOutboundReplyParts } from "openclaw/plugin-sdk/reply-payload";
24
27
  import { filterSupplementalContextItems, resolvePinnedMainDmOwnerFromAllowlist, shouldIncludeSupplementalContext } from "openclaw/plugin-sdk/security-runtime";
25
28
  import { mimeTypeFromFilePath } from "openclaw/plugin-sdk/media-mime";
26
- import { ensureConfiguredBindingRouteReady, resolveConfiguredBindingRoute, resolveRuntimeConversationBindingRoute } from "openclaw/plugin-sdk/conversation-runtime";
27
29
  import { createChannelHistoryWindow } from "openclaw/plugin-sdk/reply-history";
28
30
  import { mergePairLoopGuardConfig } from "openclaw/plugin-sdk/pair-loop-guard-runtime";
29
31
  import { enqueueRoutedSystemEvent } from "openclaw/plugin-sdk/system-event-runtime";
30
- import { resolveChannelImplicitMentions } from "openclaw/plugin-sdk/channel-ingress-runtime";
32
+ import { asDateTimestampMs, asFiniteNumberInRange, parseStrictFiniteNumber, resolveExpiresAtMsFromDurationMs } from "openclaw/plugin-sdk/number-runtime";
31
33
  import { getGlobalHookRunner } from "openclaw/plugin-sdk/plugin-runtime";
32
- import { buildChannelInboundEventContext, buildMentionRegexes, classifyChannelInboundEvent, dispatchChannelInboundTurn, formatInboundEnvelope, formatInboundMediaUnavailableText, hasVisibleInboundReplyDispatch, implicitMentionKindWhen, logInboundDrop, matchesMentionWithExplicit, readAgentRunTerminalOutcome, recordDroppedChannelInboundHistory, resolveEnvelopeFormatOptions, resolveInboundMentionDecision, resolveInboundSupplementalSenderAllowed, resolveUnmentionedGroupInboundPolicy, toInboundMediaFactsWithMetadata } from "openclaw/plugin-sdk/channel-inbound";
34
+ import { buildChannelInboundEventContext, buildMentionRegexes, classifyChannelInboundEvent, dispatchChannelInboundTurn, formatInboundEnvelope, formatInboundMediaUnavailableText, hasVisibleInboundReplyDispatch, implicitMentionKindWhen, logInboundDrop, matchesMentionWithExplicit, readAgentRunTerminalOutcome, recordDroppedChannelInboundHistory, resolveEnvelopeFormatOptions, resolveInboundMentionDecision, resolveInboundReplyDispatchCounts, resolveInboundSupplementalSenderAllowed, resolveUnmentionedGroupInboundPolicy, toInboundMediaFactsWithMetadata } from "openclaw/plugin-sdk/channel-inbound";
33
35
  import { resolveHumanDelayConfig } from "openclaw/plugin-sdk/agent-runtime";
34
36
  import { resolveGatewayPublicOrigin } from "openclaw/plugin-sdk/config-contracts";
35
37
  import { buildControlUiSessionPath } from "openclaw/plugin-sdk/session-discussion";
@@ -37,8 +39,7 @@ import { DEFAULT_TIMING, createStatusReactionController, logAckFailure, logTypin
37
39
  import { hasControlCommand } from "openclaw/plugin-sdk/command-detection";
38
40
  import { isAbortRequestText } from "openclaw/plugin-sdk/command-primitives-runtime";
39
41
  import { shouldHandleTextCommands } from "openclaw/plugin-sdk/command-surface";
40
- import { createChannelPreflightAudio } from "openclaw/plugin-sdk/media-understanding-runtime";
41
- import { runTasksWithConcurrency } from "openclaw/plugin-sdk/concurrency-runtime";
42
+ import { createChannelPreflightAudio, formatAudioTranscriptForAgent } from "openclaw/plugin-sdk/media-understanding-runtime";
42
43
  //#region extensions/slack/src/streaming.ts
43
44
  /**
44
45
  * Thrown when Slack definitively rejects a stream flush/finalize while text
@@ -267,7 +268,11 @@ function resolveExplicitSlackProgressTitle(entry) {
267
268
  const trimmed = label.trim();
268
269
  return trimmed && trimmed.toLowerCase() !== "auto" ? trimmed : void 0;
269
270
  }
271
+ function resolveSlackProgressStyle(entry) {
272
+ return entry?.streaming?.progress?.style === "compact" ? "compact" : "card";
273
+ }
270
274
  function resolveSlackNativeProgressTaskCards(entry) {
275
+ if (resolveSlackProgressStyle(entry) === "compact") return false;
271
276
  const streaming = entry?.streaming;
272
277
  if (!streaming || typeof streaming !== "object" || Array.isArray(streaming)) return true;
273
278
  const progressConfig = streaming.progress;
@@ -380,12 +385,12 @@ function createSlackDraftStream(params) {
380
385
  const send = params.send ?? sendMessageSlack;
381
386
  const edit = params.edit ?? editSlackMessage;
382
387
  const remove = params.remove ?? deleteSlackMessage;
383
- let streamMessageId;
384
- let streamChannelId;
388
+ let streamMessage;
385
389
  let untrackConversationBoundary;
386
390
  let lastVisibleUpdate;
387
391
  let lastSentKey = "";
388
- const detachedMessages = [];
392
+ const pendingCleanupMessages = [];
393
+ let cleanupTail = Promise.resolve();
389
394
  const finalizedMessageIds = /* @__PURE__ */ new Set();
390
395
  const streamState = {
391
396
  stopped: false,
@@ -407,8 +412,8 @@ function createSlackDraftStream(params) {
407
412
  if (sentKey === lastSentKey) return;
408
413
  lastSentKey = sentKey;
409
414
  try {
410
- if (streamChannelId && streamMessageId) {
411
- await edit(streamChannelId, streamMessageId, trimmed, {
415
+ if (streamMessage) {
416
+ await edit(streamMessage.channelId, streamMessage.messageId, trimmed, {
412
417
  cfg: params.cfg,
413
418
  token: params.token,
414
419
  accountId: params.accountId,
@@ -440,27 +445,29 @@ function createSlackDraftStream(params) {
440
445
  ...params.metadata ? { metadata: params.metadata } : {},
441
446
  ...blocks ? { blocks } : {}
442
447
  });
443
- streamChannelId = sent.channelId || streamChannelId;
444
- streamMessageId = sent.messageId || streamMessageId;
445
- if (!streamChannelId || !streamMessageId) {
448
+ if (!sent.channelId || !sent.messageId) {
446
449
  stopTrackingConversationBoundary();
447
450
  streamState.stopped = true;
448
451
  params.warn?.("slack stream preview stopped (missing identifiers from sendMessage)");
449
452
  return;
450
453
  }
454
+ streamMessage = {
455
+ channelId: sent.channelId,
456
+ messageId: sent.messageId
457
+ };
451
458
  lastVisibleUpdate = {
452
459
  text: trimmed,
453
460
  ...blocks ? { blocks } : {}
454
461
  };
455
- if (pendingBoundary && params.conversationChannelId === streamChannelId) pendingBoundary.setMessageTs(streamMessageId);
462
+ if (pendingBoundary && params.conversationChannelId === streamMessage.channelId) pendingBoundary.setMessageTs(streamMessage.messageId);
456
463
  else {
457
464
  stopTrackingConversationBoundary();
458
465
  untrackConversationBoundary = trackSlackDraftMessage({
459
466
  accountId: params.accountId,
460
467
  teamId: params.eventScope?.teamId,
461
- channelId: streamChannelId,
468
+ channelId: streamMessage.channelId,
462
469
  threadTs,
463
- messageTs: streamMessageId,
470
+ messageTs: streamMessage.messageId,
464
471
  onInterveningMessage: forceNewMessage
465
472
  }).stop;
466
473
  }
@@ -481,60 +488,58 @@ function createSlackDraftStream(params) {
481
488
  untrackConversationBoundary?.();
482
489
  untrackConversationBoundary = void 0;
483
490
  };
484
- const removeMessage = async (channelId, messageId) => {
485
- try {
486
- await remove(channelId, messageId, {
487
- token: params.token,
488
- accountId: params.accountId,
489
- ...params.eventScope ? { client: params.eventScope.client } : {}
490
- });
491
- } catch (err) {
492
- params.warn?.(`slack stream preview cleanup failed: ${formatSlackError(err)}`);
493
- }
491
+ const dropDetachedMessages = () => {
492
+ cleanupTail = cleanupTail.then(async () => {
493
+ for (let index = 0; index < pendingCleanupMessages.length;) {
494
+ const message = pendingCleanupMessages[index];
495
+ if (!message) return;
496
+ try {
497
+ await remove(message.channelId, message.messageId, {
498
+ token: params.token,
499
+ accountId: params.accountId,
500
+ ...params.eventScope ? { client: params.eventScope.client } : {}
501
+ });
502
+ pendingCleanupMessages.splice(index, 1);
503
+ } catch (err) {
504
+ params.warn?.(`slack stream preview cleanup failed: ${formatSlackError(err)}`);
505
+ index += 1;
506
+ }
507
+ }
508
+ });
509
+ return cleanupTail;
494
510
  };
495
511
  const clear = async () => {
496
512
  stopTrackingConversationBoundary();
497
513
  await discardPending();
498
- const channelId = streamChannelId;
499
- const messageId = streamMessageId;
500
- streamChannelId = void 0;
501
- streamMessageId = void 0;
514
+ if (streamMessage) {
515
+ pendingCleanupMessages.push(streamMessage);
516
+ streamMessage = void 0;
517
+ }
502
518
  lastVisibleUpdate = void 0;
503
519
  lastSentKey = "";
504
- if (!channelId || !messageId) return;
505
- await removeMessage(channelId, messageId);
520
+ await dropDetachedMessages();
506
521
  };
507
522
  const forceNewMessage = () => {
508
523
  stopTrackingConversationBoundary();
509
524
  streamState.stopped = false;
510
525
  streamState.final = false;
511
- if (streamChannelId && streamMessageId && !finalizedMessageIds.has(streamMessageId)) detachedMessages.push({
512
- channelId: streamChannelId,
513
- messageId: streamMessageId
514
- });
515
- streamMessageId = void 0;
516
- streamChannelId = void 0;
526
+ if (streamMessage && !finalizedMessageIds.has(streamMessage.messageId)) pendingCleanupMessages.push(streamMessage);
527
+ streamMessage = void 0;
517
528
  lastVisibleUpdate = void 0;
518
529
  lastSentKey = "";
519
530
  loop.resetPending();
520
531
  };
521
- const dropDetachedMessages = async () => {
522
- let message;
523
- while ((message = detachedMessages.shift()) !== void 0) {
524
- const { channelId, messageId } = message;
525
- await removeMessage(channelId, messageId);
526
- }
527
- };
528
532
  const discardPendingAndStopTracking = async () => {
529
533
  stopTrackingConversationBoundary();
530
534
  await discardPending();
531
535
  };
532
536
  const finalizeMessage = async (messageId, editFinal) => {
533
- const channelId = streamChannelId;
537
+ const currentMessage = streamMessage;
534
538
  const previousUpdate = lastVisibleUpdate;
535
- if (!channelId || streamMessageId !== messageId || !previousUpdate) return false;
539
+ if (!currentMessage || currentMessage.messageId !== messageId || !previousUpdate) return false;
540
+ const { channelId } = currentMessage;
536
541
  await editFinal();
537
- if (streamChannelId === channelId && streamMessageId === messageId) {
542
+ if (streamMessage?.channelId === channelId && streamMessage.messageId === messageId) {
538
543
  finalizedMessageIds.add(messageId);
539
544
  stopTrackingConversationBoundary();
540
545
  return true;
@@ -562,8 +567,58 @@ function createSlackDraftStream(params) {
562
567
  forceNewMessage,
563
568
  dropDetachedMessages,
564
569
  finalizeMessage,
565
- messageId: () => streamMessageId,
566
- channelId: () => streamChannelId
570
+ messageId: () => streamMessage?.messageId,
571
+ channelId: () => streamMessage?.channelId
572
+ };
573
+ }
574
+ //#endregion
575
+ //#region extensions/slack/src/stream-mode.ts
576
+ function resolveSlackStreamingConfig(params) {
577
+ return {
578
+ mode: resolveSlackStreamingMode(params),
579
+ nativeStreaming: resolveSlackNativeStreaming(params)
580
+ };
581
+ }
582
+ function applyAppendOnlyStreamUpdate(params) {
583
+ const incoming = params.incoming.trimEnd();
584
+ if (!incoming) return {
585
+ rendered: params.rendered,
586
+ source: params.source,
587
+ changed: false
588
+ };
589
+ if (!params.rendered) return {
590
+ rendered: incoming,
591
+ source: incoming,
592
+ changed: true
593
+ };
594
+ if (incoming === params.source) return {
595
+ rendered: params.rendered,
596
+ source: params.source,
597
+ changed: false
598
+ };
599
+ if (incoming.startsWith(params.rendered)) return {
600
+ rendered: incoming,
601
+ source: incoming,
602
+ changed: incoming !== params.rendered
603
+ };
604
+ if (incoming.startsWith(params.source)) {
605
+ const delta = incoming.slice(params.source.length);
606
+ return {
607
+ rendered: `${params.rendered}${delta}`,
608
+ source: incoming,
609
+ changed: delta.length > 0
610
+ };
611
+ }
612
+ if (params.source.startsWith(incoming)) return {
613
+ rendered: params.rendered,
614
+ source: params.source,
615
+ changed: false
616
+ };
617
+ const separator = params.separator ?? (params.rendered.endsWith("\n") ? "" : "\n");
618
+ return {
619
+ rendered: `${params.rendered}${separator}${incoming}`,
620
+ source: incoming,
621
+ changed: true
567
622
  };
568
623
  }
569
624
  //#endregion
@@ -628,12 +683,14 @@ function lineTaskTitle(line) {
628
683
  return compactTitle(label);
629
684
  }
630
685
  function lineTaskDetails(line, maxLineChars) {
631
- const detail = (lineDetailParts(line).join(" · ") || line.status?.trim())?.replace(SLACK_PROGRESS_LINE_DELTA_RE, "").replace(/\s+·\s*$/u, "").trim();
632
- return detail ? compactDetail(detail, maxLineChars) : void 0;
686
+ const detail = line.detail?.replace(SLACK_PROGRESS_LINE_DELTA_RE, "").replace(/\s+·\s*$/u, "").trim();
687
+ return detail && detail !== line.status?.trim() ? compactDetail(detail, maxLineChars) : void 0;
633
688
  }
634
689
  function lineTaskOutput(line) {
635
- const match = SLACK_PROGRESS_LINE_DELTA_RE.exec(lineDetailParts(line).join(" · "));
636
- return match ? `+${match[1]} −${match[2]}` : void 0;
690
+ const match = line.detail ? SLACK_PROGRESS_LINE_DELTA_RE.exec(line.detail) : null;
691
+ if (match) return `+${match[1]} −${match[2]}`;
692
+ const status = line.status?.replace(/\s+/g, " ").trim();
693
+ return status && lineTaskStatus(line) === "error" ? status : void 0;
637
694
  }
638
695
  function lineTaskStatus(line) {
639
696
  const normalized = line.status?.replace(/\s+/g, " ").trim().toLowerCase();
@@ -738,7 +795,7 @@ function buildSlackProgressStreamChunks(params) {
738
795
  };
739
796
  if (task.details) chunk.details = task.details;
740
797
  if (task.output) chunk.output = task.output;
741
- if (index === finalTaskIndex && diffOutput) chunk.output = diffOutput;
798
+ if (index === finalTaskIndex && diffOutput) chunk.output = [task.output, diffOutput].filter(Boolean).join(" · ");
742
799
  if (index === finalTaskIndex && params.sessionUrl) chunk.sources = buildSessionSources(params.sessionUrl);
743
800
  return chunk;
744
801
  });
@@ -784,8 +841,7 @@ function buildSlackProgressCardBlocks(params) {
784
841
  ...diffStat ? [diffStat] : [],
785
842
  ...params.elapsedSeconds && params.elapsedSeconds > 0 ? [`⏱ ${params.elapsedSeconds}s`] : []
786
843
  ].join(" · ");
787
- const terminalFooter = [params.receiptSummary?.trim(), diffStat].filter(Boolean).join(" · ");
788
- const footer = params.state === "working" ? workingFooter : terminalFooter;
844
+ const footer = params.state === "working" ? workingFooter : diffStat;
789
845
  return [
790
846
  {
791
847
  type: "section",
@@ -821,35 +877,106 @@ function buildSlackProgressCardBlocks(params) {
821
877
  }] : []
822
878
  ].slice(0, 50);
823
879
  }
880
+ const EMPTY_SLACK_NATIVE_STREAM_SNAPSHOT = { tasks: /* @__PURE__ */ new Map() };
881
+ const SLACK_TASK_FIELD_SEPARATOR = " · ";
882
+ function resolveTaskFieldDelta(previous, incoming) {
883
+ if (!incoming) return {
884
+ field: previous,
885
+ delta: void 0
886
+ };
887
+ if (previous?.rendered.includes(incoming)) return {
888
+ field: {
889
+ rendered: previous.rendered,
890
+ source: incoming
891
+ },
892
+ delta: void 0
893
+ };
894
+ const next = applyAppendOnlyStreamUpdate({
895
+ incoming,
896
+ rendered: previous?.rendered ?? "",
897
+ source: previous?.source ?? "",
898
+ separator: SLACK_TASK_FIELD_SEPARATOR
899
+ });
900
+ const delta = next.changed ? next.rendered.slice(previous?.rendered.length ?? 0) : void 0;
901
+ return {
902
+ field: {
903
+ rendered: next.rendered,
904
+ source: next.source
905
+ },
906
+ delta
907
+ };
908
+ }
824
909
  /**
825
- * Slack native streams key task rows by persistent id with no removal chunk.
826
- * When the task source switches representation (tool lines <-> typed plan) or
827
- * a snapshot drops ids, previously emitted non-terminal rows must receive a
828
- * final update or they linger in_progress forever.
910
+ * Turns a full task snapshot into the delta Slack must receive. Native streams
911
+ * key rows by persistent id with no removal chunk: unchanged rows are omitted,
912
+ * changed rows carry only their unsent field text, and rows that dropped out
913
+ * (plan shrinks, tool-line <-> plan source switches) get a final complete
914
+ * update or they linger in_progress forever.
829
915
  */
830
916
  function reconcileSlackNativeTaskChunks(params) {
831
917
  const nextTasks = /* @__PURE__ */ new Map();
832
- for (const chunk of params.chunks ?? []) if (chunk.type === "task_update") nextTasks.set(chunk.id, {
833
- title: chunk.title,
834
- status: chunk.status
835
- });
836
- const terminalized = [...params.previousTasks].filter(([id, task]) => !nextTasks.has(id) && task.status !== "complete" && task.status !== "error").map(([id, task]) => {
837
- const entry = {
838
- title: task.title,
839
- status: "complete"
918
+ let planTitle = params.previous.planTitle;
919
+ const emitted = [];
920
+ for (const chunk of params.chunks ?? []) {
921
+ if (chunk.type === "plan_update") {
922
+ if (chunk.title !== planTitle) {
923
+ planTitle = chunk.title;
924
+ emitted.push(chunk);
925
+ }
926
+ continue;
927
+ }
928
+ if (chunk.type !== "task_update") {
929
+ emitted.push(chunk);
930
+ continue;
931
+ }
932
+ const previousRow = params.previous.tasks.get(chunk.id);
933
+ const status = chunk.status;
934
+ const details = resolveTaskFieldDelta(previousRow?.details, chunk.details);
935
+ const output = resolveTaskFieldDelta(previousRow?.output, chunk.output);
936
+ const sourcesChanged = Boolean(chunk.sources) && !previousRow?.sourcesSent;
937
+ const row = {
938
+ title: chunk.title,
939
+ status
840
940
  };
841
- nextTasks.set(id, entry);
842
- return {
941
+ if (details.field) row.details = details.field;
942
+ if (output.field) row.output = output.field;
943
+ if (sourcesChanged || previousRow?.sourcesSent) row.sourcesSent = true;
944
+ nextTasks.set(chunk.id, row);
945
+ if (!(!previousRow || previousRow.title !== chunk.title || previousRow.status !== status || Boolean(details.delta) || Boolean(output.delta) || sourcesChanged)) continue;
946
+ const update = {
947
+ type: "task_update",
948
+ id: chunk.id,
949
+ title: chunk.title,
950
+ status
951
+ };
952
+ if (details.delta) update.details = details.delta;
953
+ if (output.delta) update.output = output.delta;
954
+ if (sourcesChanged) update.sources = chunk.sources;
955
+ emitted.push(update);
956
+ }
957
+ for (const [id, row] of params.previous.tasks) {
958
+ if (nextTasks.has(id)) continue;
959
+ if (row.status === "complete" || row.status === "error") {
960
+ nextTasks.set(id, row);
961
+ continue;
962
+ }
963
+ nextTasks.set(id, {
964
+ ...row,
965
+ status: "complete"
966
+ });
967
+ emitted.push({
843
968
  type: "task_update",
844
969
  id,
845
- title: task.title,
970
+ title: row.title,
846
971
  status: "complete"
847
- };
848
- });
849
- for (const [id, task] of params.previousTasks) if (!nextTasks.has(id)) nextTasks.set(id, task);
972
+ });
973
+ }
850
974
  return {
851
- chunks: params.chunks?.length ? [...params.chunks, ...terminalized] : terminalized.length ? terminalized : params.chunks,
852
- tasks: nextTasks
975
+ chunks: emitted.length > 0 ? emitted : void 0,
976
+ snapshot: {
977
+ ...planTitle ? { planTitle } : {},
978
+ tasks: nextTasks
979
+ }
853
980
  };
854
981
  }
855
982
  function buildSlackProgressStreamCompletionChunks(params) {
@@ -859,56 +986,6 @@ function buildSlackProgressStreamCompletionChunks(params) {
859
986
  });
860
987
  }
861
988
  //#endregion
862
- //#region extensions/slack/src/stream-mode.ts
863
- function resolveSlackStreamingConfig(params) {
864
- return {
865
- mode: resolveSlackStreamingMode(params),
866
- nativeStreaming: resolveSlackNativeStreaming(params)
867
- };
868
- }
869
- function applyAppendOnlyStreamUpdate(params) {
870
- const incoming = params.incoming.trimEnd();
871
- if (!incoming) return {
872
- rendered: params.rendered,
873
- source: params.source,
874
- changed: false
875
- };
876
- if (!params.rendered) return {
877
- rendered: incoming,
878
- source: incoming,
879
- changed: true
880
- };
881
- if (incoming === params.source) return {
882
- rendered: params.rendered,
883
- source: params.source,
884
- changed: false
885
- };
886
- if (incoming.startsWith(params.rendered)) return {
887
- rendered: incoming,
888
- source: incoming,
889
- changed: incoming !== params.rendered
890
- };
891
- if (incoming.startsWith(params.source)) {
892
- const delta = incoming.slice(params.source.length);
893
- return {
894
- rendered: `${params.rendered}${delta}`,
895
- source: incoming,
896
- changed: delta.length > 0
897
- };
898
- }
899
- if (params.source.startsWith(incoming)) return {
900
- rendered: params.rendered,
901
- source: params.source,
902
- changed: false
903
- };
904
- const separator = params.rendered.endsWith("\n") ? "" : "\n";
905
- return {
906
- rendered: `${params.rendered}${separator}${incoming}`,
907
- source: incoming,
908
- changed: true
909
- };
910
- }
911
- //#endregion
912
989
  //#region extensions/slack/src/monitor/message-handler/dispatch-progress-render.ts
913
990
  function resolveStructuredProgressLines(lines) {
914
991
  return lines.map((line) => {
@@ -1098,12 +1175,9 @@ function createSlackDraftProgressCardRuntime(params) {
1098
1175
  maxLineChars: params.maxLineChars,
1099
1176
  diffStat: snapshot.diffStat,
1100
1177
  ...state === "working" ? {
1101
- toolCalls: params.progressReceipt.toolCalls,
1102
- elapsedSeconds: params.progressReceipt.elapsedSeconds
1103
- } : {
1104
- receiptSummary: params.progressReceipt.buildSummaryLine(),
1105
- sessionUrl: resolveSessionUrl()
1106
- }
1178
+ toolCalls: params.progressWorkCounter.toolCalls,
1179
+ elapsedSeconds: params.progressWorkCounter.elapsedSeconds
1180
+ } : { sessionUrl: resolveSessionUrl() }
1107
1181
  });
1108
1182
  };
1109
1183
  const finalize = async (status, snapshot = params.getSnapshot(), fallbackText = resolveText(snapshot)) => {
@@ -1263,7 +1337,7 @@ function createSlackProgressRuntime(runtimeParams) {
1263
1337
  log: logVerbose,
1264
1338
  warn: logVerbose
1265
1339
  }) : void 0;
1266
- let hasStreamedMessage = false;
1340
+ let hasStreamedAnswer = false;
1267
1341
  const isProgressMode = slackStreaming.mode === "progress";
1268
1342
  const useNativeProgressStreaming = useStreaming && slackStreaming.mode === "progress";
1269
1343
  const progressDraftActive = Boolean(draftStream) || useNativeProgressStreaming;
@@ -1276,12 +1350,11 @@ function createSlackProgressRuntime(runtimeParams) {
1276
1350
  previewStreamingEnabled
1277
1351
  });
1278
1352
  let previewToolProgressSuppressed = false;
1279
- let nativeTaskState = /* @__PURE__ */ new Map();
1353
+ let nativeStreamSnapshot = EMPTY_SLACK_NATIVE_STREAM_SNAPSHOT;
1280
1354
  let appendRenderedText = "";
1281
1355
  let appendSourceText = "";
1282
1356
  let nativeProgressCompletionSent = false;
1283
1357
  let nativeProgressTerminalStatus = "complete";
1284
- let nativeProgressChunkKey;
1285
1358
  let nativeNarrationRenderedText = "";
1286
1359
  let nativeNarrationSourceText = "";
1287
1360
  let nativeStreamOrder = Promise.resolve();
@@ -1290,9 +1363,10 @@ function createSlackProgressRuntime(runtimeParams) {
1290
1363
  nativeStreamOrder = run.catch(() => void 0);
1291
1364
  return run;
1292
1365
  };
1293
- const progressReceipt = createChannelProgressReceiptTracker();
1366
+ const progressWorkCounter = createChannelProgressWorkCounter();
1294
1367
  const progressSeed = `${account.accountId}:${message.channel}`;
1295
- const useDraftProgressCard = Boolean(draftStream) && isProgressMode;
1368
+ const slackProgressStyle = resolveSlackProgressStyle(account.config);
1369
+ const useDraftProgressCard = Boolean(draftStream) && isProgressMode && slackProgressStyle === "card";
1296
1370
  const explicitProgressTitle = resolveExplicitSlackProgressTitle(account.config);
1297
1371
  const progressDraftMaxLineChars = resolveChannelProgressDraftMaxLineChars(account.config);
1298
1372
  const progressCard = createSlackDraftProgressCardRuntime({
@@ -1305,7 +1379,7 @@ function createSlackProgressRuntime(runtimeParams) {
1305
1379
  },
1306
1380
  draftStream,
1307
1381
  enabled: useDraftProgressCard,
1308
- progressReceipt,
1382
+ progressWorkCounter,
1309
1383
  progressSeed,
1310
1384
  explicitTitle: explicitProgressTitle,
1311
1385
  maxLineChars: progressDraftMaxLineChars,
@@ -1367,16 +1441,14 @@ function createSlackProgressRuntime(runtimeParams) {
1367
1441
  const snapshot = progressDraft.getSnapshot();
1368
1442
  const progressLines = resolveNativeProgressLines(snapshot);
1369
1443
  const narrationUpdate = resolveNarrationUpdate(resolveNativeProgressNarration(snapshot));
1370
- const hasRetirableNativeTasks = [...nativeTaskState.values()].some((task) => task.status !== "complete" && task.status !== "error");
1444
+ const hasRetirableNativeTasks = [...nativeStreamSnapshot.tasks.values()].some((task) => task.status !== "complete" && task.status !== "error");
1371
1445
  if (!useNativeProgressStreaming || delivery.streamFailed || progressLines.length === 0 && !snapshot.plan?.length && !snapshot.statusHeadline && !explicitProgressTitle && !hasRetirableNativeTasks && !narrationUpdate.delta) return false;
1372
1446
  if (!await nativeTransport.waitForStart()) return false;
1373
1447
  const reconciled = reconcileSlackNativeTaskChunks({
1374
- previousTasks: nativeTaskState,
1448
+ previous: nativeStreamSnapshot,
1375
1449
  chunks: buildNativeProgressChunks$1(snapshot)
1376
1450
  });
1377
- const chunkKey = JSON.stringify(reconciled.chunks ?? []);
1378
- const taskChunksChanged = chunkKey !== nativeProgressChunkKey;
1379
- const chunks = taskChunksChanged ? reconciled.chunks : void 0;
1451
+ const chunks = reconciled.chunks;
1380
1452
  if (!chunks?.length && !narrationUpdate.delta) return false;
1381
1453
  try {
1382
1454
  const hadSession = Boolean(delivery.streamSession);
@@ -1390,10 +1462,7 @@ function createSlackProgressRuntime(runtimeParams) {
1390
1462
  nativeNarrationRenderedText = narrationUpdate.next.rendered;
1391
1463
  nativeNarrationSourceText = narrationUpdate.next.source;
1392
1464
  }
1393
- if (taskChunksChanged) {
1394
- nativeProgressChunkKey = chunkKey;
1395
- nativeTaskState = reconciled.tasks;
1396
- }
1465
+ if (chunks?.length) nativeStreamSnapshot = reconciled.snapshot;
1397
1466
  return true;
1398
1467
  } catch (err) {
1399
1468
  runtime.error?.(danger(`slack-stream: native progress stream failed: ${formatSlackError(err)}, falling back`));
@@ -1420,7 +1489,7 @@ function createSlackProgressRuntime(runtimeParams) {
1420
1489
  return true;
1421
1490
  };
1422
1491
  const resetProgressTurnState = () => {
1423
- progressReceipt.reset();
1492
+ progressWorkCounter.reset();
1424
1493
  nativeNarrationRenderedText = "";
1425
1494
  nativeNarrationSourceText = "";
1426
1495
  };
@@ -1445,7 +1514,6 @@ function createSlackProgressRuntime(runtimeParams) {
1445
1514
  text: previewText,
1446
1515
  blocks: progressCard.resolvePresentation(snapshot, "working")
1447
1516
  } : previewText);
1448
- hasStreamedMessage = true;
1449
1517
  if (options?.flush) await draftStream.flush();
1450
1518
  return Boolean(draftStream.messageId() && draftStream.channelId());
1451
1519
  }
@@ -1476,10 +1544,10 @@ function createSlackProgressRuntime(runtimeParams) {
1476
1544
  const snapshot = progressDraft.getSnapshot();
1477
1545
  const lines = resolveNativeProgressLines(snapshot);
1478
1546
  const sessionUrl = progressCard.resolveSessionUrl();
1479
- const hasRetirableNativeTasks = [...nativeTaskState.values()].some((task) => task.status !== "complete" && task.status !== "error");
1547
+ const hasRetirableNativeTasks = [...nativeStreamSnapshot.tasks.values()].some((task) => task.status !== "complete" && task.status !== "error");
1480
1548
  if (lines.length === 0 && !snapshot.plan?.length && !hasRetirableNativeTasks && !snapshot.diffStat && !sessionUrl) return;
1481
1549
  return reconcileSlackNativeTaskChunks({
1482
- previousTasks: nativeTaskState,
1550
+ previous: nativeStreamSnapshot,
1483
1551
  chunks: buildSlackProgressStreamCompletionChunks({
1484
1552
  title: resolveNativeProgressTitle(snapshot) ?? (lines.length === 0 && !snapshot.plan?.length ? "Working" : void 0),
1485
1553
  lines,
@@ -1514,7 +1582,10 @@ function createSlackProgressRuntime(runtimeParams) {
1514
1582
  delivery.streamFailed = false;
1515
1583
  };
1516
1584
  const pushPlanProgress = async (steps, explanation) => {
1517
- if (isProgressMode) return await progressDraft.pushPlanProgress(steps, { explanation });
1585
+ if (isProgressMode) {
1586
+ if (slackProgressStyle === "compact") return false;
1587
+ return await progressDraft.pushPlanProgress(steps, { explanation });
1588
+ }
1518
1589
  if (previewToolProgressSuppressed || !draftStream) return false;
1519
1590
  const text = formatChannelProgressDraftText({
1520
1591
  entry: account.config,
@@ -1524,10 +1595,7 @@ function createSlackProgressRuntime(runtimeParams) {
1524
1595
  narration: explanation,
1525
1596
  plan: steps
1526
1597
  });
1527
- if (text) {
1528
- draftStream.update(text);
1529
- hasStreamedMessage = true;
1530
- }
1598
+ if (text) draftStream.update(text);
1531
1599
  return false;
1532
1600
  };
1533
1601
  const pushPreviewProgress = async (line, options) => {
@@ -1542,7 +1610,7 @@ function createSlackProgressRuntime(runtimeParams) {
1542
1610
  return await progressDraft.pushToolProgress(line, options);
1543
1611
  };
1544
1612
  const updateDraftFromPartial = (text) => {
1545
- const trimmed = text?.trimEnd();
1613
+ const trimmed = text && sanitizeAssistantVisibleText(text).trimEnd();
1546
1614
  if (!trimmed) return false;
1547
1615
  if (slackStreaming.mode === "block") {
1548
1616
  previewToolProgressSuppressed = true;
@@ -1556,14 +1624,14 @@ function createSlackProgressRuntime(runtimeParams) {
1556
1624
  appendSourceText = next.source;
1557
1625
  if (!next.changed) return false;
1558
1626
  draftStream?.update(next.rendered);
1559
- hasStreamedMessage = true;
1627
+ hasStreamedAnswer = true;
1560
1628
  return false;
1561
1629
  }
1562
1630
  if (isProgressMode) return false;
1563
1631
  previewToolProgressSuppressed = true;
1564
1632
  progressDraft.suppress();
1565
1633
  draftStream?.update(trimmed);
1566
- hasStreamedMessage = true;
1634
+ hasStreamedAnswer = true;
1567
1635
  return false;
1568
1636
  };
1569
1637
  const pushReasoningProgress = async (payload) => {
@@ -1580,11 +1648,10 @@ function createSlackProgressRuntime(runtimeParams) {
1580
1648
  progressDraft.mergeReasoningProgress(normalized, { snapshot: true });
1581
1649
  return visible;
1582
1650
  }
1583
- progressReceipt.noteReasoning();
1584
1651
  return await progressDraft.pushReasoningProgress(payload.text, { snapshot: payload.isReasoningSnapshot === true });
1585
1652
  };
1586
1653
  const resetDraftDeliveryState = () => {
1587
- hasStreamedMessage = false;
1654
+ hasStreamedAnswer = false;
1588
1655
  appendRenderedText = "";
1589
1656
  appendSourceText = "";
1590
1657
  };
@@ -1604,10 +1671,9 @@ function createSlackProgressRuntime(runtimeParams) {
1604
1671
  await dropDetachedProgressCards();
1605
1672
  }
1606
1673
  resetProgressTurnState();
1607
- nativeTaskState = /* @__PURE__ */ new Map();
1674
+ nativeStreamSnapshot = EMPTY_SLACK_NATIVE_STREAM_SNAPSHOT;
1608
1675
  nativeProgressCompletionSent = false;
1609
1676
  nativeProgressTerminalStatus = "complete";
1610
- nativeProgressChunkKey = void 0;
1611
1677
  progressCard.reset();
1612
1678
  resetPreviewDeliveryState();
1613
1679
  delivery.resetDeliveryTracker();
@@ -1618,7 +1684,7 @@ function createSlackProgressRuntime(runtimeParams) {
1618
1684
  await beginNewProgressTurn();
1619
1685
  return;
1620
1686
  }
1621
- if (hasStreamedMessage) draftStream?.forceNewMessage();
1687
+ if (hasStreamedAnswer) draftStream?.forceNewMessage();
1622
1688
  resetDraftDeliveryState();
1623
1689
  resetDraftProgressState();
1624
1690
  };
@@ -1645,7 +1711,7 @@ function createSlackProgressRuntime(runtimeParams) {
1645
1711
  suppressDefaultToolProgressMessages,
1646
1712
  progressDraft,
1647
1713
  commentaryProgressEnabled,
1648
- progressReceipt,
1714
+ progressWorkCounter,
1649
1715
  get nativeProgressCompletionSent() {
1650
1716
  return nativeProgressCompletionSent;
1651
1717
  },
@@ -1673,41 +1739,6 @@ function createSlackProgressRuntime(runtimeParams) {
1673
1739
  };
1674
1740
  }
1675
1741
  //#endregion
1676
- //#region extensions/slack/src/threading.ts
1677
- function resolveSlackThreadContext(params) {
1678
- const incomingThreadTs = params.message.thread_ts;
1679
- const eventTs = params.message.event_ts;
1680
- const messageTs = params.message.ts ?? eventTs;
1681
- const hasThreadTs = typeof incomingThreadTs === "string" && incomingThreadTs.length > 0;
1682
- const isThreadReply = hasThreadTs && (incomingThreadTs !== messageTs || Boolean(params.message.parent_user_id));
1683
- const replyToId = isThreadReply ? incomingThreadTs : void 0;
1684
- const isAssistantDmThreadRoot = hasThreadTs && !isThreadReply && params.isDirectMessage === true;
1685
- return {
1686
- incomingThreadTs,
1687
- messageTs,
1688
- isThreadReply,
1689
- replyToId,
1690
- messageThreadId: isThreadReply || isAssistantDmThreadRoot ? incomingThreadTs : params.replyToMode === "all" ? messageTs : void 0
1691
- };
1692
- }
1693
- /**
1694
- * Resolves Slack thread targeting for replies and status indicators.
1695
- *
1696
- * @returns replyThreadTs - Thread timestamp for reply messages
1697
- * @returns statusThreadTs - Thread timestamp for status indicators (typing, etc.)
1698
- * @returns isThreadReply - true if this is a genuine user reply in a thread,
1699
- * false if thread_ts comes from a bot status message (e.g. typing indicator)
1700
- */
1701
- function resolveSlackThreadTargets(params) {
1702
- const { incomingThreadTs, messageTs, isThreadReply } = resolveSlackThreadContext(params);
1703
- const replyThreadTs = isThreadReply ? incomingThreadTs : params.replyToMode === "all" ? messageTs : void 0;
1704
- return {
1705
- replyThreadTs,
1706
- statusThreadTs: replyThreadTs,
1707
- isThreadReply
1708
- };
1709
- }
1710
- //#endregion
1711
1742
  //#region extensions/slack/src/monitor/message-handler/dispatch-setup.ts
1712
1743
  async function createSlackDispatchSetup(prepared) {
1713
1744
  const { ctx, account, message, route } = prepared;
@@ -1829,10 +1860,7 @@ async function createSlackDispatchSetup(prepared) {
1829
1860
  agentId: route.agentId,
1830
1861
  channel: "slack",
1831
1862
  accountId: route.accountId,
1832
- transformReplyPayload: (payload) => {
1833
- if (payload.isReasoning === true) return null;
1834
- return payload;
1835
- },
1863
+ transformReplyPayload: sanitizeSlackMonitorReplyPayload,
1836
1864
  typing: {
1837
1865
  start: async () => {
1838
1866
  if (!threadStatusGate.hasVisibleOutput()) {
@@ -1980,11 +2008,6 @@ function createSlackStreamingDeliveryRuntime(setup) {
1980
2008
  observedFinalReplyDelivery: false
1981
2009
  };
1982
2010
  const streamedDeliveries = [];
1983
- const streamedFailuresOwnedByDispatcher = {
1984
- tool: 0,
1985
- block: 0,
1986
- final: 0
1987
- };
1988
2011
  const refreshStreamedAcknowledgements = (session) => {
1989
2012
  if (session.pendingText.length === 0) for (const delivery of streamedDeliveries) delivery.acknowledged = true;
1990
2013
  };
@@ -2123,7 +2146,6 @@ function createSlackStreamingDeliveryRuntime(setup) {
2123
2146
  }
2124
2147
  };
2125
2148
  const deliverNormally = async (params) => {
2126
- if (params.payload.isReasoning === true) return;
2127
2149
  const replyThreadTs = resolveDeliveryThreadTs(params);
2128
2150
  const deliveryReplyThreadTs = replyDeliveryMode === "off" && !forcedReplyThreadTs && !isThreadReply ? void 0 : replyThreadTs;
2129
2151
  if (deliveryTracker.hasDelivered({
@@ -2167,10 +2189,7 @@ function createSlackStreamingDeliveryRuntime(setup) {
2167
2189
  return deliveryReplyThreadTs;
2168
2190
  };
2169
2191
  const deliverBufferedStreamFallback = async (params) => {
2170
- if (!await deliverPendingStreamFallback(params.session, params.err)) {
2171
- streamedFailuresOwnedByDispatcher[params.kind] += 1;
2172
- return false;
2173
- }
2192
+ if (!await deliverPendingStreamFallback(params.session, params.err)) return false;
2174
2193
  replyPlan.markSent();
2175
2194
  if (params.kind === "final") state.observedFinalReplyDelivery = true;
2176
2195
  deliveryTracker.markDelivered({
@@ -2189,7 +2208,6 @@ function createSlackStreamingDeliveryRuntime(setup) {
2189
2208
  return !state.streamFailed && !reply.hasMedia && renderPlan.mode !== "split" && !plannedBlocks?.length && !readSlackReplyBlocks(payload)?.length && reply.hasText && (!options?.maxTextBytes || countSlackTextUtf8Bytes(reply.trimmedText) <= options.maxTextBytes);
2190
2209
  };
2191
2210
  const deliverWithStreaming = async (params) => {
2192
- if (params.payload.isReasoning === true) return;
2193
2211
  const reply = resolveSendableOutboundReplyParts(params.payload);
2194
2212
  if (!isStreamingEligible(params.payload)) {
2195
2213
  await deliverNormally({
@@ -2329,23 +2347,6 @@ function createSlackStreamingDeliveryRuntime(setup) {
2329
2347
  });
2330
2348
  }
2331
2349
  };
2332
- const reconcileCounts = (counts) => {
2333
- const next = { ...counts };
2334
- let changed = false;
2335
- for (const kind of [
2336
- "tool",
2337
- "block",
2338
- "final"
2339
- ]) {
2340
- const failedStreamedCount = streamedDeliveries.filter((delivery) => delivery.kind === kind && delivery.outcome === "failure").length;
2341
- const additionalFailedStreamed = Math.max(0, failedStreamedCount - streamedFailuresOwnedByDispatcher[kind]);
2342
- if (additionalFailedStreamed > 0) {
2343
- next[kind] = Math.max(0, (next[kind] ?? 0) - additionalFailedStreamed);
2344
- changed = true;
2345
- }
2346
- }
2347
- return changed ? next : counts;
2348
- };
2349
2350
  return Object.assign(state, {
2350
2351
  acknowledgeStoppedStreamedDeliveries,
2351
2352
  deliverNormally,
@@ -2357,7 +2358,6 @@ function createSlackStreamingDeliveryRuntime(setup) {
2357
2358
  isStreamingEligible,
2358
2359
  markPreviewPayloadDelivered,
2359
2360
  rememberDeliveredThreadTs,
2360
- reconcileCounts,
2361
2361
  resetDeliveryTracker: () => {
2362
2362
  deliveryTracker = createSlackEventDeliveryTracker();
2363
2363
  }
@@ -2409,7 +2409,6 @@ async function dispatchPreparedSlackMessage(prepared) {
2409
2409
  return payload;
2410
2410
  };
2411
2411
  const deliverSlackPayload = async (payload, info) => {
2412
- if (payload.isReasoning === true) return { visibleReplySent: false };
2413
2412
  if (info.kind === "final" && slackStreaming.mode === "progress" && progress.isProgressMode) {
2414
2413
  if (progress.useNativeProgressStreaming) {
2415
2414
  await progress.deliverNativeFinal(payload, info.kind);
@@ -2460,66 +2459,14 @@ async function dispatchPreparedSlackMessage(prepared) {
2460
2459
  const slackBlocks = replyRenderPlan.mode === "single" ? replyRenderPlan.blocks : replyRenderPlan.blockPart?.blocks;
2461
2460
  const requiresSeparateFallbackDelivery = replyRenderPlan.mode === "split";
2462
2461
  const trimmedFinalText = replyRenderPlan.mode === "single" ? replyRenderPlan.text.trim() : replyRenderPlan.fallbackText.trim();
2463
- const previewFinalText = replyRenderPlan.mode === "single" && replyRenderPlan.textIsSlackMrkdwn ? trimmedFinalText : normalizeSlackOutboundText((replySourceText ?? "").trim());
2462
+ const previewFinalText = replyRenderPlan.mode === "single" && replyRenderPlan.textIsSlackMrkdwn ? trimmedFinalText : normalizeSlackOutboundText((replySourceText ?? "").trim(), { tableMode: resolveMarkdownTableMode({
2463
+ cfg,
2464
+ channel: "slack",
2465
+ accountId: account.accountId
2466
+ }) });
2464
2467
  const previewFinalTextFitsEdit = countSlackTextUtf8Bytes(previewFinalText) <= SLACK_EDIT_TEXT_MAX_BYTES;
2465
2468
  const shouldRestoreTtsSupplementTextForPreviewFallback = Boolean(ttsSupplement) && ttsSupplement?.visibleTextAlreadyDelivered !== true && Boolean(draftStream) && !draftPreviewCommitted.value && !delivery.observedFinalReplyDelivery && previewStreamingEnabled && !payload.text?.trim();
2466
- if (info.kind === "final" && ttsSupplement && draftStream && !hasSlackCustomIdentity && !draftPreviewCommitted.value && !delivery.observedFinalReplyDelivery && previewStreamingEnabled && !payload.isError && !requiresSeparateFallbackDelivery && previewFinalTextFitsEdit && trimmedFinalText.length > 0) {
2467
- await draftStream.flush();
2468
- const channelId = draftStream.channelId();
2469
- const messageId = draftStream.messageId();
2470
- if (channelId && messageId) {
2471
- const finalThreadTs = delivery.usedReplyThreadTs ?? statusThreadTs;
2472
- await draftStream.seal();
2473
- try {
2474
- if (!await draftStream.finalizeMessage(messageId, async () => {
2475
- await finalizeSlackPreviewEdit({
2476
- client: slackClient,
2477
- token: ctx.botToken,
2478
- accountId: account.accountId,
2479
- channelId,
2480
- messageId,
2481
- text: previewFinalText,
2482
- ...slackBlocks?.length ? { blocks: slackBlocks } : {},
2483
- threadTs: finalThreadTs
2484
- });
2485
- })) throw new Error("Slack preview moved below a newer conversation message");
2486
- } catch (err) {
2487
- logVerbose(`slack: preview final edit failed; falling back to standard send (${formatSlackError(err)})`);
2488
- await draftStream.discardPending();
2489
- let delivered = false;
2490
- try {
2491
- await delivery.deliverNormally({
2492
- payload: payload.text?.trim() ? payload : {
2493
- ...payload,
2494
- text: ttsSupplement.spokenText
2495
- },
2496
- kind: info.kind,
2497
- forcedThreadTs: finalThreadTs
2498
- });
2499
- delivered = true;
2500
- } finally {
2501
- if (delivered) await draftStream.clear();
2502
- }
2503
- return;
2504
- }
2505
- draftPreviewCommitted.value = true;
2506
- delivery.observedFinalReplyDelivery = true;
2507
- delivery.observedReplyDelivery = true;
2508
- replyPlan.markSent();
2509
- await delivery.deliverNormally({
2510
- payload: buildTtsSupplementMediaPayload(payload),
2511
- kind: info.kind,
2512
- forcedThreadTs: finalThreadTs
2513
- });
2514
- delivery.markPreviewPayloadDelivered({
2515
- kind: info.kind,
2516
- payload,
2517
- threadTs: finalThreadTs
2518
- });
2519
- progress.progressDraft.markFinalReplyDelivered();
2520
- return;
2521
- }
2522
- }
2469
+ let ttsPreviewFinalization;
2523
2470
  await deliverWithFinalizableLivePreviewAdapter({
2524
2471
  kind: info.kind,
2525
2472
  payload,
@@ -2552,6 +2499,7 @@ async function dispatchPreparedSlackMessage(prepared) {
2552
2499
  payload,
2553
2500
  threadTs: edit.threadTs
2554
2501
  })) return;
2502
+ if (ttsSupplement) ttsPreviewFinalization = { threadTs: edit.threadTs };
2555
2503
  if (!await draftStream?.finalizeMessage(preview.messageId, async () => {
2556
2504
  await finalizeSlackPreviewEdit({
2557
2505
  client: slackClient,
@@ -2607,11 +2555,12 @@ async function dispatchPreparedSlackMessage(prepared) {
2607
2555
  }),
2608
2556
  deliverNormally: async () => {
2609
2557
  await delivery.deliverNormally({
2610
- payload: shouldRestoreTtsSupplementTextForPreviewFallback ? {
2558
+ payload: shouldRestoreTtsSupplementTextForPreviewFallback || ttsPreviewFinalization && !payload.text?.trim() ? {
2611
2559
  ...payload,
2612
2560
  text: ttsSupplement?.spokenText
2613
2561
  } : payload,
2614
- kind: info.kind
2562
+ kind: info.kind,
2563
+ ...ttsPreviewFinalization?.threadTs ? { forcedThreadTs: ttsPreviewFinalization.threadTs } : {}
2615
2564
  });
2616
2565
  }
2617
2566
  });
@@ -2619,8 +2568,7 @@ async function dispatchPreparedSlackMessage(prepared) {
2619
2568
  };
2620
2569
  let dispatchError;
2621
2570
  let agentRunFailed = false;
2622
- let queuedFinal = false;
2623
- let counts = {};
2571
+ let settledDispatchResult;
2624
2572
  try {
2625
2573
  const turnResult = await dispatchChannelInboundTurn({
2626
2574
  cfg,
@@ -2631,6 +2579,7 @@ async function dispatchPreparedSlackMessage(prepared) {
2631
2579
  sessionKey: route.sessionKey
2632
2580
  },
2633
2581
  ctxPayload: prepared.ctxPayload,
2582
+ dispatchReplyFromConfig: ctx.dispatchReplyFromConfig,
2634
2583
  dispatcherOptions: {
2635
2584
  ...replyPipeline,
2636
2585
  transformReplyPayload: (payload) => {
@@ -2672,7 +2621,6 @@ async function dispatchPreparedSlackMessage(prepared) {
2672
2621
  return false;
2673
2622
  } : void 0,
2674
2623
  onReasoningEnd: async () => {
2675
- progress.progressReceipt.closeReasoning();
2676
2624
  await progress.onDraftBoundary?.();
2677
2625
  return false;
2678
2626
  },
@@ -2686,18 +2634,14 @@ async function dispatchPreparedSlackMessage(prepared) {
2686
2634
  } : void 0,
2687
2635
  onToolStart: async (payload) => {
2688
2636
  if (statusReactionsEnabled) await statusReactions.setTool(payload.name);
2689
- if (payload.phase === "start") progress.progressReceipt.noteToolCall(payload.name);
2637
+ if (payload.phase === "start") progress.progressWorkCounter.noteToolCall(payload.name);
2690
2638
  return await progress.progressDraft.pushToolEvent(payload);
2691
2639
  },
2692
2640
  onItemEvent: async (payload) => {
2693
2641
  if (progress.isProgressMode && payload.kind === "preamble") {
2694
2642
  if (progress.shouldYieldDraftProgress()) return false;
2695
2643
  const headlineVisible = await progress.progressDraft.pushPreambleHeadline(payload.progressText, { itemId: payload.itemId });
2696
- if (progress.commentaryProgressEnabled) {
2697
- const accepted = await progress.progressDraft.pushCommentaryProgress(payload.progressText, { itemId: payload.itemId });
2698
- if (accepted) progress.progressReceipt.noteCommentary(payload.itemId, payload.progressText);
2699
- return accepted || headlineVisible;
2700
- }
2644
+ if (progress.commentaryProgressEnabled) return await progress.progressDraft.pushCommentaryProgress(payload.progressText, { itemId: payload.itemId }) || headlineVisible;
2701
2645
  return headlineVisible;
2702
2646
  }
2703
2647
  return await progress.progressDraft.pushItemEvent(payload);
@@ -2719,8 +2663,7 @@ async function dispatchPreparedSlackMessage(prepared) {
2719
2663
  });
2720
2664
  if (turnResult.dispatched) {
2721
2665
  const result = turnResult.dispatchResult;
2722
- queuedFinal = result.queuedFinal;
2723
- counts = result.counts;
2666
+ settledDispatchResult = result;
2724
2667
  const agentRunOutcome = readAgentRunTerminalOutcome(result);
2725
2668
  agentRunFailed = agentRunOutcome === "failed";
2726
2669
  if (agentRunOutcome === "completed" && !sawTerminalFailurePayload && prepared.ctxPayload.ChatType === "channel") clearSlackThreadFailureNotice({
@@ -2759,12 +2702,7 @@ async function dispatchPreparedSlackMessage(prepared) {
2759
2702
  if (!finalStream.delivered) dispatchError ??= err;
2760
2703
  }
2761
2704
  }
2762
- counts = delivery.reconcileCounts(counts);
2763
- queuedFinal = queuedFinal && (counts.final ?? 0) > 0;
2764
- const anyReplyDelivered = hasVisibleInboundReplyDispatch({
2765
- queuedFinal,
2766
- counts
2767
- }, {
2705
+ const anyReplyDelivered = hasVisibleInboundReplyDispatch(settledDispatchResult, {
2768
2706
  observedReplyDelivery: delivery.observedReplyDelivery,
2769
2707
  fallbackDelivered: streamFallbackDelivered
2770
2708
  });
@@ -2786,11 +2724,11 @@ async function dispatchPreparedSlackMessage(prepared) {
2786
2724
  if (dispatchError) throw toErrorObject(dispatchError, "Slack dispatch failed");
2787
2725
  if (!anyReplyDelivered && !draftPreviewCommitted.value && !(agentRunFailed && progress.useDraftProgressCard)) {
2788
2726
  await draftStream?.clear();
2789
- await progress.dropDetachedProgressCards();
2727
+ await draftStream?.dropDetachedMessages();
2790
2728
  return;
2791
2729
  }
2792
2730
  if (shouldLogVerbose()) {
2793
- const finalCount = counts.final;
2731
+ const finalCount = resolveInboundReplyDispatchCounts(settledDispatchResult).final;
2794
2732
  logVerbose(`slack: delivered ${finalCount} reply${finalCount === 1 ? "" : "ies"} to ${prepared.replyTarget}`);
2795
2733
  }
2796
2734
  }
@@ -2834,6 +2772,153 @@ function normalizeSlackAppContextEntities(value) {
2834
2772
  });
2835
2773
  }
2836
2774
  //#endregion
2775
+ //#region extensions/slack/src/monitor/thread.ts
2776
+ const THREAD_STARTER_CACHE = /* @__PURE__ */ new Map();
2777
+ const THREAD_STARTER_CACHE_TTL_MS = 360 * 6e4;
2778
+ const THREAD_STARTER_CACHE_MAX = 2e3;
2779
+ function evictThreadStarterCache() {
2780
+ const now = asDateTimestampMs(Date.now());
2781
+ if (now === void 0) {
2782
+ THREAD_STARTER_CACHE.clear();
2783
+ return;
2784
+ }
2785
+ for (const [cacheKey, entry] of THREAD_STARTER_CACHE.entries()) if (asDateTimestampMs(entry.expiresAt) === void 0 || entry.expiresAt <= now) THREAD_STARTER_CACHE.delete(cacheKey);
2786
+ pruneMapToMaxSize(THREAD_STARTER_CACHE, THREAD_STARTER_CACHE_MAX);
2787
+ }
2788
+ function formatSlackFilePlaceholder(files) {
2789
+ return `[attached: ${formatSlackFileReferenceList(files)}]`;
2790
+ }
2791
+ function pushUniqueText(parts, value, options = {}) {
2792
+ const text = options.preserveWhitespace ? typeof value === "string" && value.trim().length > 0 ? value : void 0 : normalizeOptionalString(value);
2793
+ if (text && !parts.includes(text)) parts.push(text);
2794
+ }
2795
+ function resolveSlackBlocksFallbackText(blocks) {
2796
+ return resolveSlackBlocksText(blocks)?.text;
2797
+ }
2798
+ function resolveSlackAttachmentFallbackText(attachments) {
2799
+ if (!Array.isArray(attachments) || attachments.length === 0) return;
2800
+ const parts = [];
2801
+ for (const attachment of attachments) {
2802
+ const excludeTableBlocks = isSlackUnfurlAttachment(attachment);
2803
+ const fallbackBlocks = (blocks) => excludeTableBlocks ? blocks?.filter((block) => !hasSlackTableBlock([block])) : blocks;
2804
+ pushUniqueText(parts, attachment.pretext);
2805
+ pushUniqueText(parts, attachment.title);
2806
+ pushUniqueText(parts, attachment.text);
2807
+ if (!(hasSlackTableBlock(attachment.blocks) && normalizeOptionalString(attachment.fallback) === "[no preview available]")) pushUniqueText(parts, attachment.fallback);
2808
+ for (const field of attachment.fields ?? []) {
2809
+ pushUniqueText(parts, field.title);
2810
+ pushUniqueText(parts, field.value);
2811
+ }
2812
+ pushUniqueText(parts, resolveSlackBlocksFallbackText(fallbackBlocks(attachment.blocks)), { preserveWhitespace: true });
2813
+ pushUniqueText(parts, resolveSlackBlocksFallbackText(fallbackBlocks(attachment.message_blocks)), { preserveWhitespace: true });
2814
+ }
2815
+ return parts.length > 0 ? parts.join("\n") : void 0;
2816
+ }
2817
+ function resolveSlackMessageText(message) {
2818
+ const messageText = normalizeOptionalString(message.text) ?? resolveSlackAttachmentFallbackText(message.attachments);
2819
+ return resolveSlackMessageText$1({
2820
+ ...message,
2821
+ text: messageText
2822
+ }, { preserveMessageTextWhitespace: true });
2823
+ }
2824
+ async function resolveSlackThreadStarter(params) {
2825
+ evictThreadStarterCache();
2826
+ const cacheKey = JSON.stringify([
2827
+ params.workspaceScope.accountId,
2828
+ params.workspaceScope.teamId,
2829
+ params.channelId,
2830
+ params.threadTs
2831
+ ]);
2832
+ const cached = THREAD_STARTER_CACHE.get(cacheKey);
2833
+ if (cached) {
2834
+ const now = asDateTimestampMs(Date.now());
2835
+ if (now !== void 0 && cached.expiresAt > now) return cached.value;
2836
+ THREAD_STARTER_CACHE.delete(cacheKey);
2837
+ }
2838
+ try {
2839
+ const message = (await params.client.conversations.replies({
2840
+ channel: params.channelId,
2841
+ ts: params.threadTs,
2842
+ limit: 1,
2843
+ inclusive: true
2844
+ }))?.messages?.[0];
2845
+ const text = message ? resolveSlackMessageText(message) : void 0;
2846
+ const files = message?.files?.length ? message.files : void 0;
2847
+ if (!message || !text && !files) return null;
2848
+ const starter = {
2849
+ text: text || formatSlackFilePlaceholder(files),
2850
+ userId: message.user,
2851
+ botId: message.bot_id,
2852
+ ts: message.ts,
2853
+ files
2854
+ };
2855
+ const expiresAt = resolveExpiresAtMsFromDurationMs(THREAD_STARTER_CACHE_TTL_MS);
2856
+ if (expiresAt !== void 0) {
2857
+ if (THREAD_STARTER_CACHE.has(cacheKey)) THREAD_STARTER_CACHE.delete(cacheKey);
2858
+ THREAD_STARTER_CACHE.set(cacheKey, {
2859
+ value: starter,
2860
+ expiresAt
2861
+ });
2862
+ evictThreadStarterCache();
2863
+ }
2864
+ return starter;
2865
+ } catch (err) {
2866
+ logVerbose$1(`slack thread starter fetch failed channel=${params.channelId} ts=${params.threadTs}: ${formatErrorMessage(err)}`);
2867
+ return null;
2868
+ }
2869
+ }
2870
+ const SLACK_THREAD_HISTORY_MAX_PAGES = 3;
2871
+ /**
2872
+ * Fetches the most recent messages in a Slack thread (excluding the current message).
2873
+ * Used to populate thread context when a new thread session starts.
2874
+ *
2875
+ * Uses cursor pagination and keeps only the latest N retained messages when the full
2876
+ * thread fits in the bounded fetch window.
2877
+ */
2878
+ async function resolveSlackThreadHistory(params) {
2879
+ const maxMessages = params.limit ?? 20;
2880
+ if (!Number.isFinite(maxMessages) || maxMessages <= 0) return [];
2881
+ const fetchLimit = 200;
2882
+ const retained = [];
2883
+ let cursor;
2884
+ let pagesFetched = 0;
2885
+ try {
2886
+ do {
2887
+ pagesFetched += 1;
2888
+ const response = await params.client.conversations.replies({
2889
+ channel: params.channelId,
2890
+ ts: params.threadTs,
2891
+ limit: fetchLimit,
2892
+ inclusive: true,
2893
+ ...cursor ? { cursor } : {}
2894
+ });
2895
+ for (const msg of response.messages ?? []) {
2896
+ const text = resolveSlackMessageText(msg);
2897
+ if (!text && !msg.files?.length) continue;
2898
+ if (params.currentMessageTs && msg.ts === params.currentMessageTs) continue;
2899
+ retained.push([msg, text]);
2900
+ }
2901
+ if (retained.length > maxMessages) retained.splice(0, retained.length - maxMessages);
2902
+ const next = response.response_metadata?.next_cursor;
2903
+ cursor = typeof next === "string" && next.trim().length > 0 ? next.trim() : void 0;
2904
+ } while (cursor && pagesFetched < SLACK_THREAD_HISTORY_MAX_PAGES);
2905
+ if (cursor) {
2906
+ logVerbose$1(`slack thread history capped channel=${params.channelId} ts=${params.threadTs} pages=${SLACK_THREAD_HISTORY_MAX_PAGES}`);
2907
+ return [];
2908
+ }
2909
+ return retained.map(([message, text]) => ({
2910
+ text: text ?? formatSlackFilePlaceholder(message.files),
2911
+ userId: message.user,
2912
+ botId: message.bot_id,
2913
+ ts: message.ts,
2914
+ files: message.files
2915
+ }));
2916
+ } catch (err) {
2917
+ logVerbose$1(`slack thread history fetch failed channel=${params.channelId} ts=${params.threadTs}: ${formatErrorMessage(err)}`);
2918
+ return [];
2919
+ }
2920
+ }
2921
+ //#endregion
2837
2922
  //#region extensions/slack/src/monitor/message-handler/preflight-audio.ts
2838
2923
  function isSlackAudioFile(file) {
2839
2924
  if (file.subtype === "slack_audio") return true;
@@ -2849,7 +2934,7 @@ function findCaptionlessSlackAudioFile(message) {
2849
2934
  return message.files?.slice(0, 8).find(isSlackAudioFile);
2850
2935
  }
2851
2936
  function formatSlackAudioTranscriptForAgent(params) {
2852
- return [`[Audio transcript (machine-generated, untrusted)]: ${JSON.stringify(params.transcript)}`, params.rawBody].filter(Boolean).join("\n");
2937
+ return [formatAudioTranscriptForAgent(params.transcript), params.rawBody].filter(Boolean).join("\n");
2853
2938
  }
2854
2939
  async function resolveSlackPreflightAudioTranscript(params) {
2855
2940
  const mediaIndex = params.media.findIndex((entry) => entry.contentType?.toLowerCase().startsWith("audio/"));
@@ -2884,7 +2969,24 @@ async function discardSlackPreflightMedia(media) {
2884
2969
  const SLACK_MENTION_RESOLUTION_CONCURRENCY = 4;
2885
2970
  const SLACK_MENTION_RESOLUTION_MAX_LOOKUPS_PER_MESSAGE = 20;
2886
2971
  const SLACK_USER_MENTION_RE$1 = /<@([A-Z0-9]+)(?:\|[^>]+)?>/gi;
2887
- const loadSlackMediaModule$1 = createLazyRuntimeModule(() => import("./actions-BTDXwwE3.js").then((n) => n._));
2972
+ const MAX_SLACK_UNAVAILABLE_FILE_TEXT_CHARS = 2e3;
2973
+ const loadSlackMediaModule$1 = createLazyRuntimeModule(() => import("./actions-BI7JkfVm.js").then((n) => n._));
2974
+ function formatSlackUnavailableMedia(params) {
2975
+ let fileReferences = params.files?.map((file) => `${formatSlackFileReference(file)} unavailable (${file.reason})`).join(", ");
2976
+ if (fileReferences && fileReferences.length > MAX_SLACK_UNAVAILABLE_FILE_TEXT_CHARS) fileReferences = `${truncateUtf16Safe(fileReferences, MAX_SLACK_UNAVAILABLE_FILE_TEXT_CHARS)}; … (file references truncated)`;
2977
+ const fileBlock = fileReferences ? `[Slack file: ${fileReferences}]` : void 0;
2978
+ const body = [params.body, fileBlock].filter(Boolean).join("\n");
2979
+ if (params.unavailableMediaCount === 0) return body;
2980
+ const notice = `[slack ${params.unavailableMediaCount > 1 ? `${params.unavailableMediaCount} attachments` : "attachment"} unavailable]`;
2981
+ return params.prependUnavailable ? [
2982
+ notice,
2983
+ fileBlock,
2984
+ params.body
2985
+ ].filter(Boolean).join("\n") : formatInboundMediaUnavailableText({
2986
+ body,
2987
+ notice
2988
+ });
2989
+ }
2888
2990
  function collectUniqueSlackMentionIds$1(texts) {
2889
2991
  const seen = /* @__PURE__ */ new Set();
2890
2992
  const mentionIds = [];
@@ -2922,8 +3024,9 @@ async function resolveSlackMessageContent(params) {
2922
3024
  isThreadReply: params.isThreadReply,
2923
3025
  threadStarter: params.threadStarter
2924
3026
  });
2925
- const mediaPromise = ownFiles && ownFiles.length > 0 ? loadSlackMediaModule$1().then(({ resolveSlackMedia }) => resolveSlackMedia({
3027
+ const attachmentContent = ownFiles?.length || params.message.attachments?.length ? await loadSlackMediaModule$1().then(({ resolveSlackAttachmentContent }) => resolveSlackAttachmentContent({
2926
3028
  files: ownFiles,
3029
+ attachments: params.message.attachments,
2927
3030
  client: params.client,
2928
3031
  token: params.botToken,
2929
3032
  maxBytes: params.mediaMaxBytes,
@@ -2931,30 +3034,9 @@ async function resolveSlackMessageContent(params) {
2931
3034
  totalTimeoutMs: params.mediaTotalTimeoutMs,
2932
3035
  abortSignal: params.abortSignal,
2933
3036
  preloadedMedia: params.preloadedMedia
2934
- })) : Promise.resolve(null);
2935
- const attachmentContentPromise = params.message.attachments && params.message.attachments.length > 0 ? loadSlackMediaModule$1().then(({ resolveSlackAttachmentContent }) => resolveSlackAttachmentContent({
2936
- attachments: params.message.attachments,
2937
- client: params.client,
2938
- token: params.botToken,
2939
- maxBytes: params.mediaMaxBytes,
2940
- readIdleTimeoutMs: params.mediaReadIdleTimeoutMs,
2941
- totalTimeoutMs: params.mediaTotalTimeoutMs,
2942
- abortSignal: params.abortSignal
2943
- })) : Promise.resolve(null);
2944
- const [media, attachmentContent] = await Promise.all([mediaPromise, attachmentContentPromise]);
2945
- const mergedMedia = [...media ?? [], ...attachmentContent?.media ?? []];
2946
- const effectiveDirectMedia = mergedMedia.length > 0 ? mergedMedia : null;
2947
- const mediaPlaceholder = effectiveDirectMedia ? effectiveDirectMedia.map((item) => item.placeholder).join(" ") : void 0;
2948
- const fallbackFileIds = /* @__PURE__ */ new Set();
2949
- const fallbackFiles = [...ownFiles ?? [], ...attachmentContent?.files ?? []].filter((file) => {
2950
- const fileId = normalizeOptionalString(file.id);
2951
- if (!fileId) return true;
2952
- if (fallbackFileIds.has(fileId)) return false;
2953
- fallbackFileIds.add(fileId);
2954
- return true;
2955
- });
2956
- const fileOnlyFallback = !mediaPlaceholder && fallbackFiles.length > 0 ? fallbackFiles.slice(0, 8).map((file) => formatSlackFileReference(file)).join(", ") : void 0;
2957
- const fileOnlyPlaceholder = fileOnlyFallback ? `[Slack file: ${fileOnlyFallback}]` : void 0;
3037
+ })) : null;
3038
+ const effectiveDirectMedia = attachmentContent?.media.length ? attachmentContent.media : null;
3039
+ const mediaPlaceholder = effectiveDirectMedia?.map((item) => item.placeholder).join(" ");
2958
3040
  let botAttachmentText;
2959
3041
  if (params.isBotMessage && !attachmentContent?.text) {
2960
3042
  const botAttachmentTextParts = [];
@@ -2965,7 +3047,7 @@ async function resolveSlackMessageContent(params) {
2965
3047
  botAttachmentText = botAttachmentTextParts.length > 0 ? botAttachmentTextParts.join("\n") : void 0;
2966
3048
  }
2967
3049
  const textParts = [
2968
- resolveSlackMessageText(params.message),
3050
+ resolveSlackMessageText$1(params.message),
2969
3051
  attachmentContent?.text,
2970
3052
  botAttachmentText
2971
3053
  ];
@@ -2991,23 +3073,20 @@ async function resolveSlackMessageContent(params) {
2991
3073
  renderedMentions.set(result.userId, result.rendered);
2992
3074
  }
2993
3075
  }
2994
- let rawBody = [
2995
- renderSlackUserMentions(textParts[0], renderedMentions),
2996
- renderSlackUserMentions(textParts[1], renderedMentions),
2997
- renderSlackUserMentions(textParts[2], renderedMentions),
2998
- mediaPlaceholder,
2999
- fileOnlyPlaceholder
3000
- ].filter(Boolean).join("\n") || "";
3001
- const unavailableImageCount = attachmentContent?.unavailableImageCount ?? 0;
3002
- if (unavailableImageCount > 0) rawBody = formatInboundMediaUnavailableText({
3003
- body: rawBody,
3004
- notice: `[slack ${unavailableImageCount > 1 ? `${unavailableImageCount} forwarded images` : "forwarded image"} unavailable]`
3076
+ const rawBody = formatSlackUnavailableMedia({
3077
+ body: [
3078
+ renderSlackUserMentions(textParts[0], renderedMentions),
3079
+ renderSlackUserMentions(textParts[1], renderedMentions),
3080
+ renderSlackUserMentions(textParts[2], renderedMentions),
3081
+ mediaPlaceholder
3082
+ ].filter(Boolean).join("\n") || "",
3083
+ files: attachmentContent?.files,
3084
+ unavailableMediaCount: attachmentContent?.unavailableMediaCount ?? 0
3005
3085
  });
3006
- if (!rawBody) return null;
3007
- return {
3086
+ return rawBody ? {
3008
3087
  rawBody,
3009
3088
  effectiveDirectMedia
3010
- };
3089
+ } : null;
3011
3090
  }
3012
3091
  //#endregion
3013
3092
  //#region extensions/slack/src/monitor/message-handler/prepare-dm-history.ts
@@ -3083,62 +3162,6 @@ async function resolveSlackDmHistoryContext(params) {
3083
3162
  }
3084
3163
  //#endregion
3085
3164
  //#region extensions/slack/src/monitor/message-handler/prepare-routing.ts
3086
- const slackRouteBindingConfigCache = /* @__PURE__ */ new WeakMap();
3087
- function slackTargetDefaultKindForPeer(kind) {
3088
- return kind === "direct" ? "user" : "channel";
3089
- }
3090
- function slackTargetKindMatchesPeer(peerKind, targetKind) {
3091
- if (targetKind === "user") return peerKind === "direct";
3092
- return peerKind === "channel" || peerKind === "group";
3093
- }
3094
- function normalizeSlackRouteBindingPeer(peer) {
3095
- const rawId = peer.id.trim();
3096
- if (!rawId || rawId === "*") return peer;
3097
- const target = (() => {
3098
- try {
3099
- return parseSlackTarget(rawId, { defaultKind: slackTargetDefaultKindForPeer(peer.kind) });
3100
- } catch {
3101
- return;
3102
- }
3103
- })();
3104
- if (!target || !slackTargetKindMatchesPeer(peer.kind, target.kind)) return peer;
3105
- const normalizedId = target.teamId ? `team:${target.teamId}:${target.kind}:${target.id}` : target.id;
3106
- return normalizedId === peer.id ? peer : {
3107
- ...peer,
3108
- id: normalizedId
3109
- };
3110
- }
3111
- function normalizeSlackRouteBindingConfig(cfg) {
3112
- const bindings = cfg.bindings;
3113
- const cached = slackRouteBindingConfigCache.get(cfg);
3114
- if (cached && cached.bindingsRef === bindings) return cached.normalizedCfg;
3115
- if (!Array.isArray(bindings)) return cfg;
3116
- let changed = false;
3117
- const normalizedBindings = bindings.map((binding) => {
3118
- if (binding.type === "acp" || binding.match.channel.trim().toLowerCase() !== "slack") return binding;
3119
- const peer = binding.match.peer;
3120
- if (!peer) return binding;
3121
- const normalizedPeer = normalizeSlackRouteBindingPeer(peer);
3122
- if (normalizedPeer === peer) return binding;
3123
- changed = true;
3124
- return {
3125
- ...binding,
3126
- match: {
3127
- ...binding.match,
3128
- peer: normalizedPeer
3129
- }
3130
- };
3131
- });
3132
- const normalizedCfg = changed ? {
3133
- ...cfg,
3134
- bindings: normalizedBindings
3135
- } : cfg;
3136
- slackRouteBindingConfigCache.set(cfg, {
3137
- bindingsRef: bindings,
3138
- normalizedCfg
3139
- });
3140
- return normalizedCfg;
3141
- }
3142
3165
  function resolveSlackBaseConversationId(params) {
3143
3166
  return qualifySlackConversationId(params.isDirectMessage ? `user:${params.message.user ?? "unknown"}` : params.message.channel, params.eventScope);
3144
3167
  }
@@ -3197,44 +3220,18 @@ function resolveSlackRoutingContext(params) {
3197
3220
  eventScope
3198
3221
  });
3199
3222
  const runtimeBindingThreadId = routedThreadId ?? (isDirectMessage && isThreadReply ? threadTs : void 0);
3200
- const boundThreadRoute = !eventScope && runtimeBindingThreadId ? resolveRuntimeConversationBindingRoute({
3201
- route,
3202
- conversation: {
3203
- channel: "slack",
3204
- accountId: account.accountId,
3205
- conversationId: runtimeBindingThreadId,
3206
- parentConversationId: baseConversationId
3207
- }
3208
- }) : null;
3209
- const runtimeRoute = eventScope ? {
3210
- route,
3211
- bindingRecord: null,
3212
- boundSessionKey: void 0
3213
- } : boundThreadRoute?.boundSessionKey || boundThreadRoute?.bindingRecord ? boundThreadRoute : resolveRuntimeConversationBindingRoute({
3223
+ const bindingRoute = resolveSlackConversationBindingRoute({
3224
+ cfg: ctx.cfg,
3214
3225
  route,
3215
- conversation: {
3216
- channel: "slack",
3217
- accountId: account.accountId,
3218
- conversationId: baseConversationId
3219
- }
3226
+ accountId: account.accountId,
3227
+ baseConversationId,
3228
+ runtimeBindingThreadId,
3229
+ bindingsEnabled: !eventScope
3220
3230
  });
3221
- let configuredBinding = null;
3222
- let configuredBindingSessionKey = "";
3223
- if (runtimeRoute.boundSessionKey || runtimeRoute.bindingRecord) route = runtimeRoute.route;
3224
- else if (!eventScope) {
3225
- const configuredRoute = resolveConfiguredBindingRoute({
3226
- cfg: ctx.cfg,
3227
- route,
3228
- conversation: {
3229
- channel: "slack",
3230
- accountId: account.accountId,
3231
- conversationId: baseConversationId
3232
- }
3233
- });
3234
- configuredBinding = configuredRoute.bindingResolution;
3235
- configuredBindingSessionKey = configuredRoute.boundSessionKey ?? "";
3236
- route = configuredRoute.route;
3237
- }
3231
+ const runtimeRoute = bindingRoute.runtimeRoute;
3232
+ const configuredBinding = bindingRoute.configuredRoute?.bindingResolution ?? null;
3233
+ const configuredBindingSessionKey = bindingRoute.configuredRoute?.boundSessionKey ?? "";
3234
+ route = bindingRoute.route;
3238
3235
  const threadKeys = runtimeRoute.boundSessionKey || configuredBindingSessionKey ? {
3239
3236
  sessionKey: route.sessionKey,
3240
3237
  parentSessionKey: void 0
@@ -3317,7 +3314,7 @@ function formatSlackThreadLabelSnippet(text) {
3317
3314
  }
3318
3315
  //#endregion
3319
3316
  //#region extensions/slack/src/monitor/message-handler/prepare-thread-context.ts
3320
- const loadSlackMediaModule = createLazyRuntimeModule(() => import("./actions-BTDXwwE3.js").then((n) => n._));
3317
+ const loadSlackMediaModule = createLazyRuntimeModule(() => import("./actions-BI7JkfVm.js").then((n) => n._));
3321
3318
  const SLACK_THREAD_CONTEXT_USER_LOOKUP_CONCURRENCY = 4;
3322
3319
  function resolveSlackThreadSessionFreshness(params) {
3323
3320
  return params.ctx.channelRuntime?.session?.resolveEntryResetFreshness?.({
@@ -3429,13 +3426,20 @@ async function resolveSlackThreadContextData(params) {
3429
3426
  const snippet = formatSlackThreadLabelSnippet(starter.text);
3430
3427
  threadLabel = `Slack thread ${params.roomLabel}${snippet ? `: ${snippet}` : ""}`;
3431
3428
  if (shouldSeedInitialThreadContext && !params.effectiveDirectMedia && starter.files && starter.files.length > 0) {
3432
- const { resolveSlackMedia } = await loadSlackMediaModule();
3433
- threadStarterMedia = await resolveSlackMedia({
3429
+ const { resolveSlackAttachmentContent } = await loadSlackMediaModule();
3430
+ const attachmentContent = await resolveSlackAttachmentContent({
3434
3431
  files: starter.files,
3435
3432
  client: params.eventScope?.client ?? params.ctx.app.client,
3436
3433
  token: params.ctx.botToken,
3437
3434
  maxBytes: params.ctx.mediaMaxBytes
3438
3435
  });
3436
+ threadStarterMedia = attachmentContent?.media.length ? attachmentContent.media : null;
3437
+ if (attachmentContent) threadStarterBody = formatSlackUnavailableMedia({
3438
+ body: threadStarterBody,
3439
+ files: attachmentContent.files,
3440
+ unavailableMediaCount: attachmentContent.unavailableMediaCount,
3441
+ prependUnavailable: true
3442
+ });
3439
3443
  if (threadStarterMedia) logVerbose(`slack: hydrated thread starter file ${threadStarterMedia.map((item) => item.placeholder).join(", ")} from root message`);
3440
3444
  }
3441
3445
  } else threadLabel = `Slack thread ${params.roomLabel}`;
@@ -3456,14 +3460,20 @@ async function resolveSlackThreadContextData(params) {
3456
3460
  const threadInitialHistoryLimit = params.account.config?.thread?.initialHistoryLimit ?? 20;
3457
3461
  if (threadInitialHistoryLimit > 0 && shouldLoadInitialThreadHistory) {
3458
3462
  const currentBotRootTs = starter?.ts ?? params.threadTs;
3463
+ const threadHistory = await resolveSlackThreadHistory({
3464
+ channelId: params.message.channel,
3465
+ threadTs: params.threadTs,
3466
+ client: params.eventScope?.client ?? params.ctx.app.client,
3467
+ currentMessageTs: params.message.ts,
3468
+ limit: threadInitialHistoryLimit
3469
+ });
3470
+ const enrichedStarter = starter && threadStarterBody && threadStarterBody !== starter.text ? {
3471
+ ...starter,
3472
+ text: threadStarterBody,
3473
+ ts: currentBotRootTs
3474
+ } : null;
3459
3475
  const threadHistoryWithBotRoot = ensureSlackThreadHistoryHasBotRoot({
3460
- history: await resolveSlackThreadHistory({
3461
- channelId: params.message.channel,
3462
- threadTs: params.threadTs,
3463
- client: params.eventScope?.client ?? params.ctx.app.client,
3464
- currentMessageTs: params.message.ts,
3465
- limit: threadInitialHistoryLimit
3466
- }),
3476
+ history: enrichedStarter && !threadHistory.some((entry) => entry.ts === currentBotRootTs) ? [enrichedStarter, ...threadHistory.length >= threadInitialHistoryLimit ? threadHistory.slice(1) : threadHistory] : threadHistory,
3467
3477
  includeBotStarterAsRootContext,
3468
3478
  threadStarter: starter ? {
3469
3479
  ...starter,
@@ -3522,7 +3532,7 @@ async function resolveSlackThreadContextData(params) {
3522
3532
  });
3523
3533
  const role = isCurrentBot || isOtherBot || Boolean(historyMsg.botId) ? "assistant" : "user";
3524
3534
  const msgSenderName = isCurrentBot ? "Bot (this assistant)" : msgUser?.name ?? (historyMsg.botId ? `Bot (${historyMsg.botId})` : "Unknown");
3525
- const msgWithId = `${historyMsg.text}\n[slack message id: ${historyMsg.ts ?? "unknown"} channel: ${params.message.channel}]`;
3535
+ const msgWithId = `${historyMsg.ts === currentBotRootTs && threadStarterBody ? threadStarterBody : historyMsg.text}\n[slack message id: ${historyMsg.ts ?? "unknown"} channel: ${params.message.channel}]`;
3526
3536
  historyParts.push(formatInboundEnvelope({
3527
3537
  channel: "Slack",
3528
3538
  from: `${msgSenderName} (${role})`,
@@ -4468,6 +4478,7 @@ async function prepareSlackMessage(params) {
4468
4478
  workspaceName
4469
4479
  }) : void 0;
4470
4480
  const senderName = await resolveSenderName();
4481
+ const conversationAvatar = isDirectMessage && message.user ? ctx.resolveUserAvatar(message.user, opts.eventScope) : void 0;
4471
4482
  const preview = truncateUtf16Safe(bodyForAgent.replace(/\s+/g, " "), 160);
4472
4483
  const inboundLabel = isDirectMessage ? `Slack DM from ${senderName}` : `Slack message in ${roomLabel} from ${senderName}`;
4473
4484
  const slackFrom = isDirectMessage ? `slack:${message.user}` : isRoom ? `slack:channel:${message.channel}` : `slack:group:${message.channel}`;
@@ -4600,10 +4611,19 @@ async function prepareSlackMessage(params) {
4600
4611
  conversation: {
4601
4612
  kind: chatType,
4602
4613
  id: message.channel,
4614
+ routePeer: {
4615
+ kind: chatType,
4616
+ id: qualifySlackRoutePeerId({
4617
+ id: isDirectMessage ? message.user ?? "unknown" : message.channel,
4618
+ kind: isDirectMessage ? "user" : "channel",
4619
+ eventScope: opts.eventScope
4620
+ })
4621
+ },
4603
4622
  label: envelopeFrom,
4604
4623
  spaceId: opts.eventScope?.teamId || ctx.teamId || void 0,
4605
4624
  threadId: boundMessageThreadId,
4606
- nativeChannelId: message.channel
4625
+ nativeChannelId: message.channel,
4626
+ avatar: conversationAvatar
4607
4627
  },
4608
4628
  route: {
4609
4629
  agentId: route.agentId,