@openclaw/discord 2026.8.1-beta.2 → 2026.8.1-beta.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (100) hide show
  1. package/dist/{account-inspect-CqzrH14k.js → account-inspect-D5xmUpnj.js} +1 -1
  2. package/dist/account-inspect-api.js +1 -1
  3. package/dist/accounts-DNl-oCEw.js +371 -0
  4. package/dist/action-runtime-api.js +1 -1
  5. package/dist/{activities-api-DS7vpdtp.js → activities-api-KCBAmWxD.js} +133 -175
  6. package/dist/activities-api.js +1 -1
  7. package/dist/api.js +17 -17
  8. package/dist/{approval-handler.runtime-B6yEV79q.js → approval-handler.runtime-B12RCYr8.js} +6 -6
  9. package/dist/{approval-message-safety-AcIxvrf3.js → approval-message-safety-XGFPbDoI.js} +89 -3
  10. package/dist/{audit-Db-rlntl.js → audit-Yc7eZDd6.js} +5 -5
  11. package/dist/{channel-actions-5s_hjYKd.js → channel-actions-Dr2QI8Bf.js} +10 -6
  12. package/dist/{channel-actions.runtime-CLKrx6tr.js → channel-actions.runtime-CODTvo7c.js} +53 -68
  13. package/dist/{channel-CnnbJSt5.js → channel-cXYzGc4L.js} +74 -50
  14. package/dist/channel-config-api.js +1 -1
  15. package/dist/channel-plugin-api.js +1 -1
  16. package/dist/{channel.setup-BFAO-V1P.js → channel.setup-CSiwnMgs.js} +5 -5
  17. package/dist/{outbound-session-route-DxLkrgKQ.js → components-ezGKo_Yh.js} +3 -49
  18. package/dist/{config-schema-BgEskFAs.js → config-schema-DC5kDtQ5.js} +33 -7
  19. package/dist/conversation-binding-route-D6rCQ5S0.js +43 -0
  20. package/dist/{directory-config-BVX7Cflc.js → directory-config-XyCfoqLg.js} +2 -2
  21. package/dist/directory-contract-api.js +1 -1
  22. package/dist/{directory-live-DGIGxpIo.js → directory-live-Df0NbFJB.js} +3 -3
  23. package/dist/{doctor-BzC-TLnB.js → doctor-DYY31GrO.js} +33 -12
  24. package/dist/doctor-contract-api.js +3 -3
  25. package/dist/{handle-action.guild-admin-BNVTUISF.js → handle-action.guild-admin-6Tvvinsa.js} +2 -2
  26. package/dist/index.js +3 -4
  27. package/dist/{message-handler-Unk_f10F.js → message-handler-B61q5MOF.js} +82 -6
  28. package/dist/{message-handler.preflight-C9zecxR9.js → message-handler.preflight-Bzg_Hawz.js} +36 -46
  29. package/dist/{message-handler.process-DWQ6UHHu.js → message-handler.process--4_712Ec.js} +159 -183
  30. package/dist/{message-utils-BSCPVgy0.js → message-utils-BXLLnFl6.js} +31 -32
  31. package/dist/{outbound-adapter-D9nRivT1.js → outbound-adapter-DxHTOqiN.js} +83 -53
  32. package/dist/{outbound-components-cTzwBJ60.js → outbound-components-B2PL0ooH.js} +3 -3
  33. package/dist/owner-access-Bg41VzAf.js +107 -0
  34. package/dist/{pluralkit-DdiJ9KMK.js → pluralkit-dUl4v1X3.js} +1 -1
  35. package/dist/{probe-Bl-k5_Ku.js → probe-BTdtVRwU.js} +1 -1
  36. package/dist/{probe.runtime-M9fREKvp.js → probe.runtime-Dq5-PRKT.js} +1 -1
  37. package/dist/{provider-DvSNb-2v.js → provider-DlK_ynqt.js} +356 -967
  38. package/dist/{provider-session.runtime-BUEqD0rA.js → provider-session.runtime-CvvphHvs.js} +3 -3
  39. package/dist/provider.runtime-CzKGRiAF.js +2 -0
  40. package/dist/{realtime-session.runtime-C7wen-aF.js → realtime-session.runtime-ysbMG8v7.js} +24 -13
  41. package/dist/{resolve-allowlist-common-D04lpEzb.js → resolve-allowlist-common-DIVXbD1P.js} +2 -2
  42. package/dist/{resolve-channels-Dm7jEeg6.js → resolve-channels-CGeUoIqb.js} +3 -3
  43. package/dist/{resolve-users-bktrCUUU.js → resolve-users-BtKxLUZv.js} +2 -2
  44. package/dist/{retry-CLpJcXXf.js → retry-DNsVTeTo.js} +18 -64
  45. package/dist/{runtime-DoHjckYm.js → runtime-CQovMsH3.js} +9 -10
  46. package/dist/{runtime-DGsSyDTS.js → runtime-D71_VFLr.js} +29 -43
  47. package/dist/runtime-api.actions.js +2 -2
  48. package/dist/runtime-api.js +22 -21
  49. package/dist/runtime-api.lookup.js +5 -5
  50. package/dist/runtime-api.monitor-CzeTYF32.js +6 -0
  51. package/dist/runtime-api.monitor.js +6 -5
  52. package/dist/runtime-api.send.js +6 -6
  53. package/dist/runtime-api.threads.js +4 -4
  54. package/dist/{sdk-runtime-QpY8PvCh.js → sdk-runtime-37OU6_Yh.js} +3 -4
  55. package/dist/{secret-config-contract-B1akrlyY.js → secret-config-contract-B3i6WxV5.js} +53 -25
  56. package/dist/secret-contract-api.js +1 -1
  57. package/dist/security-audit-contract-api.js +1 -1
  58. package/dist/{security-audit.runtime-CPN0xFYz.js → security-audit.runtime-BVKF9VtY.js} +1 -1
  59. package/dist/{send-B7Q6Oc1I.js → send-rQIffSYu.js} +10 -10
  60. package/dist/{send.components-iJyFXw9L.js → send.components-ChK1wS7w.js} +14 -24
  61. package/dist/{send.outbound-DS5tHwfR.js → send.outbound-HIkgji_7.js} +26 -16
  62. package/dist/{send.reactions-BAn0iiVQ.js → send.reactions-gmJ6yFPo.js} +2 -2
  63. package/dist/{send.receipt-IPI1p-SP.js → send.receipt-Cnhoautb.js} +11 -1
  64. package/dist/{send.shared-BmwFjW6T.js → send.shared-B3fpaLWJ.js} +104 -104
  65. package/dist/{sender-identity-QtalnCYv.js → sender-identity-BJtfyise.js} +1 -1
  66. package/dist/setup-plugin-api.js +1 -1
  67. package/dist/{shared-BIXIX6uJ.js → shared-CaAaoksy.js} +15 -10
  68. package/dist/subagent-hooks-CNT2ZJTJ.js +49 -0
  69. package/dist/subagent-hooks-api.js +2 -2
  70. package/dist/{subagent-progress-DhaE_h8a.js → subagent-progress-FPLqBY1s.js} +5 -4
  71. package/dist/{system-events-CTqDf6_s.js → system-events-Nuwoq_au.js} +2 -2
  72. package/dist/{target-resolver-maOKSqO0.js → target-resolver-DIXShHaZ.js} +3 -3
  73. package/dist/targets-B2pf49zc.js +3 -0
  74. package/dist/{thread-bindings-3L8p82GV.js → thread-bindings-VlymUnbz.js} +29 -26
  75. package/dist/{thread-bindings.manager-DCIH6WDC.js → thread-bindings.manager-CngsgErq.js} +9 -8
  76. package/dist/{thread-bindings.session-updates-bJ2KQFY6.js → thread-bindings.session-updates-CJb-BpPL.js} +1 -1
  77. package/dist/{thread-bindings.state-aeV8HNgV.js → thread-bindings.state-D8OMdk4O.js} +1 -1
  78. package/dist/threading-DU6pgeGm.js +456 -0
  79. package/dist/transcripts-source-DeIMNbRh.js +265 -0
  80. package/dist/transcripts-source-api.js +7 -2
  81. package/dist/{typing-CS-nNVoe.js → typing-oLiS5Z13.js} +1 -1
  82. package/dist/{voice-runtime-BEdqNcST.js → voice-runtime-CjNFaynA.js} +181 -91
  83. package/openclaw.plugin.json +12 -6
  84. package/package.json +4 -6
  85. package/dist/accounts-DJTf1LtA.js +0 -219
  86. package/dist/channel-api-CAJ0wMoV.js +0 -21
  87. package/dist/provider.runtime-C9PnJZbZ.js +0 -2
  88. package/dist/runtime-api.monitor-CHxrFPnW.js +0 -5
  89. package/dist/subagent-hooks-CTt5KCJr.js +0 -120
  90. package/dist/targets-yUFTHoAx.js +0 -3
  91. package/dist/transcripts-source-CfFMexGt.js +0 -123
  92. package/node_modules/p-map/index.d.ts +0 -155
  93. package/node_modules/p-map/index.js +0 -285
  94. package/node_modules/p-map/license +0 -9
  95. package/node_modules/p-map/package.json +0 -57
  96. package/node_modules/p-map/readme.md +0 -190
  97. package/dist/{allow-list-DnxIlPP2.js → allow-list-BDMimASD.js} +1 -1
  98. package/dist/{audit-core-xwjIczO0.js → audit-core-BCX8UeFH.js} +1 -1
  99. package/dist/{doctor-contract-DLa-BTiU.js → doctor-contract-DsWvKIXF.js} +1 -1
  100. package/dist/{security-audit-jGnJF__m.js → security-audit-BfJhAXZp.js} +1 -1
@@ -1,41 +1,44 @@
1
- import { St as deleteChannelMessage, a as chunkDiscordTextWithMode, h as discord_exports, m as resolveDiscordChannelId, wt as editChannelMessage, yt as createChannelMessage } from "./retry-CLpJcXXf.js";
2
- import { f as resolveDiscordMaxLinesPerMessage } from "./accounts-DJTf1LtA.js";
3
- import { F as createDiscordRestClient, I as createDiscordRuntimeAccountContext, _ as resolveDiscordMessageFlags, d as resolveDiscordTargetChannelId } from "./send.shared-BmwFjW6T.js";
4
- import { C as resolveTimestampMs, a as normalizeDiscordSlug, r as normalizeDiscordAllowList } from "./allow-list-DnxIlPP2.js";
5
- import { i as discordTextHasBroadcastMention } from "./send.outbound-DS5tHwfR.js";
6
- import { c as editMessageDiscord } from "./send-B7Q6Oc1I.js";
1
+ import { Ct as editChannelMessage, a as chunkDiscordTextWithMode, p as discord_exports, vt as createChannelMessage, xt as deleteChannelMessage } from "./retry-DNsVTeTo.js";
2
+ import { A as resolveDiscordChannelId, p as resolveDiscordMaxLinesPerMessage } from "./accounts-DNl-oCEw.js";
3
+ import { C as resolveTimestampMs, a as normalizeDiscordSlug, r as normalizeDiscordAllowList } from "./allow-list-BDMimASD.js";
4
+ import { A as resolveDiscordMessageFlags, F as createDiscordRestClient, I as createDiscordRuntimeAccountContext, d as resolveDiscordTargetChannelId } from "./send.shared-B3fpaLWJ.js";
5
+ import { i as discordTextHasBroadcastMention } from "./send.outbound-HIkgji_7.js";
6
+ import { c as editMessageDiscord } from "./send-rQIffSYu.js";
7
7
  import { n as DISCORD_ATTACHMENT_TOTAL_TIMEOUT_MS, t as DISCORD_ATTACHMENT_IDLE_TIMEOUT_MS } from "./timeouts-B9cy6RvQ.js";
8
- import { i as removeReactionDiscord, n as reactMessageDiscord } from "./send.reactions-BAn0iiVQ.js";
9
- import "./targets-yUFTHoAx.js";
10
- import { r as resolveDiscordConversationIdentity } from "./approval-message-safety-AcIxvrf3.js";
8
+ import { i as removeReactionDiscord, n as reactMessageDiscord } from "./send.reactions-gmJ6yFPo.js";
9
+ import "./targets-B2pf49zc.js";
10
+ import { i as buildDiscordRoutePeer, l as resolveDiscordConversationIdentity } from "./approval-message-safety-XGFPbDoI.js";
11
11
  import { t as discordInboundEventDelivery } from "./inbound-event-delivery-De2qxTrP.js";
12
- import { t as DISCORD_TEXT_CHUNK_LIMIT } from "./outbound-adapter-D9nRivT1.js";
13
- import { D as resolveDiscordAutoThreadReplyPlan, _ as buildDiscordInboundAccessContext, a as sanitizeDiscordFrontChannelReplyPayloads, c as resolveReplyContext, i as formatDiscordReplySkip, k as resolveDiscordThreadStarter, n as deliverDiscordReply, o as buildDirectLabel, r as formatDiscordReplyDeliveryFailure, s as buildGuildLabel, v as createDiscordSupplementalContextAccessChecker } from "./provider-DvSNb-2v.js";
14
- import { a as formatDiscordMediaText, c as resolveReferencedReplyMediaList, i as resolveDiscordMessageText, u as resolveDiscordMessageStickers } from "./message-utils-BSCPVgy0.js";
15
- import { n as resolveDiscordWebhookId } from "./sender-identity-QtalnCYv.js";
12
+ import { t as DISCORD_TEXT_CHUNK_LIMIT } from "./outbound-adapter-DxHTOqiN.js";
13
+ import { a as sanitizeDiscordFrontChannelReplyPayloads, c as resolveReplyContext, h as createDiscordSupplementalContextAccessChecker, i as formatDiscordReplySkip, m as buildDiscordInboundAccessContext, n as deliverDiscordReply, o as buildDirectLabel, r as formatDiscordReplyDeliveryFailure, s as buildGuildLabel } from "./provider-DlK_ynqt.js";
14
+ import { a as formatDiscordMediaText, c as resolveReferencedReplyMediaList, d as resolveDiscordMessageStickers, i as resolveDiscordMessageText } from "./message-utils-BXLLnFl6.js";
15
+ import { a as resolveDiscordThreadStarter, n as resolveDiscordAutoThreadReplyPlan } from "./threading-DU6pgeGm.js";
16
+ import { n as resolveDiscordWebhookId } from "./sender-identity-BJtfyise.js";
16
17
  import { t as beginDiscordActiveTurnThreadRoute } from "./active-turn-thread-route-fmHl1HNd.js";
17
18
  import { n as filterDiscordHistoryEntriesForContext, t as createDiscordHistorySenderProvenance } from "./message-handler.history-CJOsN9w5.js";
18
- import { t as sendTyping } from "./typing-CS-nNVoe.js";
19
- import { buildAgentSessionKey, resolveThreadSessionKeys } from "openclaw/plugin-sdk/routing";
19
+ import { t as sendTyping } from "./typing-oLiS5Z13.js";
20
20
  import { expectDefined } from "openclaw/plugin-sdk/expect-runtime";
21
21
  import { formatErrorMessage } from "openclaw/plugin-sdk/error-runtime";
22
+ import { buildAgentSessionKey, resolveThreadSessionKeys } from "openclaw/plugin-sdk/routing";
22
23
  import { danger, logVerbose, shouldLogVerbose, sleepWithAbort } from "openclaw/plugin-sdk/runtime-env";
23
24
  import { truncateUtf16Safe } from "openclaw/plugin-sdk/text-utility-runtime";
24
25
  import { resolveMarkdownTableMode } from "openclaw/plugin-sdk/markdown-table-runtime";
25
26
  import { resolveChunkMode } from "openclaw/plugin-sdk/reply-chunking";
26
27
  import { convertMarkdownTables, stripInlineDirectiveTagsForDelivery, stripReasoningTagsFromText } from "openclaw/plugin-sdk/text-chunking";
27
- import { bindIngressLifecycleToReplyOptions, buildChannelProgressDraftLine, buildChannelProgressDraftLineForEntry, createChannelMessageReplyPipeline, createChannelProgressDraftCompositor, createChannelProgressReceiptTracker, createFinalizableDraftLifecycle, createTypingCallbacks, defineFinalizableLivePreviewAdapter, deliverWithFinalizableLivePreviewAdapter, resolveChannelDraftStreamingChunking, resolveChannelMessageSourceReplyDeliveryMode, resolveChannelPreviewStreamMode, resolveChannelStreamingBlockEnabled, resolveChannelStreamingPreviewCommandText, resolveChannelStreamingPreviewToolProgress, resolveChannelStreamingProgressNarration, resolveChannelStreamingSuppressDefaultToolProgressMessages, resolveTranscriptBackedChannelFinalText } from "openclaw/plugin-sdk/channel-outbound";
28
+ import { bindIngressLifecycleToReplyOptions, buildChannelProgressDraftLine, buildChannelProgressDraftLineForEntry, createChannelMessageReplyPipeline, createChannelProgressDraftCompositor, createFinalizableDraftLifecycle, createTypingCallbacks, defineFinalizableLivePreviewAdapter, deliverWithFinalizableLivePreviewAdapter, resolveChannelDraftStreamingChunking, resolveChannelMessageSourceReplyDeliveryMode, resolveChannelPreviewStreamMode, resolveChannelStreamingBlockEnabled, resolveChannelStreamingPreviewCommandText, resolveChannelStreamingPreviewToolProgress, resolveChannelStreamingProgressNarration, resolveChannelStreamingSuppressDefaultToolProgressMessages, resolveTranscriptBackedChannelFinalText } from "openclaw/plugin-sdk/channel-outbound";
28
29
  import { getAgentScopedMediaLocalRoots } from "openclaw/plugin-sdk/media-runtime";
29
30
  import { getReplyPayloadTtsSupplement, isReplyPayloadNonTerminalToolErrorWarning, resolveSendableOutboundReplyParts } from "openclaw/plugin-sdk/reply-payload";
30
31
  import { evaluateSupplementalContextVisibility } from "openclaw/plugin-sdk/security-runtime";
31
32
  import { resolvePinnedMainDmOwnerFromAllowlist } from "openclaw/plugin-sdk/conversation-runtime";
32
- import { EmbeddedBlockChunker, resolveAckReaction, resolveAgentConfig, resolveHumanDelayConfig } from "openclaw/plugin-sdk/agent-runtime";
33
+ import { resolveAgentConfig } from "openclaw/plugin-sdk/agent-scope-runtime";
34
+ import { EmbeddedBlockChunker, resolveAckReaction, resolveAgentConfig as resolveAgentConfig$1, resolveHumanDelayConfig } from "openclaw/plugin-sdk/agent-runtime";
33
35
  import { isDangerousNameMatchingEnabled } from "openclaw/plugin-sdk/dangerous-name-runtime";
34
- import { buildChannelInboundEventContext, dispatchChannelInboundTurn, formatInboundEnvelope, formatInboundMediaUnavailableText, hasFinalInboundReplyDispatch, readAgentRunTerminalOutcome, resolveEnvelopeFormatOptions, toHistoryMediaEntries, toInboundMediaFactsWithMetadata } from "openclaw/plugin-sdk/channel-inbound";
35
36
  import { getSessionEntry, readSessionUpdatedAt, resolveStorePath } from "openclaw/plugin-sdk/session-store-runtime";
37
+ import { buildChannelInboundEventContext, createCommandTurnContext, dispatchChannelInboundTurn, formatInboundEnvelope, formatInboundMediaUnavailableText, hasFinalInboundReplyDispatch, readAgentRunTerminalOutcome, resolveEnvelopeFormatOptions, toHistoryMediaEntries, toInboundMediaFactsWithMetadata } from "openclaw/plugin-sdk/channel-inbound";
36
38
  import { getGlobalHookRunner } from "openclaw/plugin-sdk/plugin-runtime";
37
39
  import { buildHistoryContextFromEntries, buildInboundHistoryFromEntries, createChannelHistoryWindow } from "openclaw/plugin-sdk/reply-history";
38
40
  import { resolveChannelContextVisibilityMode } from "openclaw/plugin-sdk/context-visibility-runtime";
41
+ import { formatAudioTranscriptForAgent } from "openclaw/plugin-sdk/media-understanding-runtime";
39
42
  import { DEFAULT_TIMING, createStatusReactionController, logAckFailure, logTypingFailure, shouldAckReaction } from "openclaw/plugin-sdk/channel-feedback";
40
43
  import { readLatestAssistantTextByIdentity } from "openclaw/plugin-sdk/session-transcript-runtime";
41
44
  //#region extensions/discord/src/monitor/message-handler.retry.ts
@@ -78,7 +81,7 @@ function isContextAborted(abortSignal) {
78
81
  }
79
82
  async function buildDiscordMessageProcessContext(params) {
80
83
  const { ctx, text, mediaList } = params;
81
- const { cfg, discordConfig, accountId, runtime, botUserId, mediaMaxBytes, discordRestFetch, abortSignal, guildHistories, historyLimit, replyToMode, message, author, sender, canonicalMessageId, data, client, channelInfo, channelName, messageChannelId, isGuildMessage, isDirectMessage, baseText, preflightAudioTranscript, threadChannel, threadParentId, threadParentName, threadParentType, threadName, displayChannelSlug, guildInfo, guildSlug, memberRoleIds, channelConfig, baseSessionKey, boundSessionKey, route, commandAuthorized, resolveChannelIngress } = ctx;
84
+ const { cfg, discordConfig, accountId, runtime, botUserId, mediaMaxBytes, discordRestFetch, abortSignal, guildHistories, historyLimit, replyToMode, message, author, sender, canonicalMessageId, data, client, channelInfo, channelName, messageChannelId, isGuildMessage, isDirectMessage, isGroupDm, baseText, preflightAudioTranscript, threadChannel, threadParentId, threadParentName, threadParentType, threadName, displayChannelSlug, guildInfo, guildSlug, memberRoleIds, channelConfig, baseSessionKey, boundSessionKey, route, commandAuthorized, hasControlCommand, resolveChannelIngress } = ctx;
82
85
  const fromLabel = isDirectMessage ? buildDirectLabel(author) : buildGuildLabel({
83
86
  guild: data.guild ?? void 0,
84
87
  channelName: channelName ?? messageChannelId,
@@ -135,6 +138,7 @@ async function buildDiscordMessageProcessContext(params) {
135
138
  notice: `[discord ${unavailableMediaCount > 1 ? `${unavailableMediaCount} attachments` : "attachment"} unavailable]`
136
139
  }) : body;
137
140
  const bodyWithMediaNotice = appendMediaUnavailableNotice(text) ?? text;
141
+ const agentFacingBody = preflightAudioTranscript !== void 0 ? formatAudioTranscriptForAgent(preflightAudioTranscript) : baseText ?? text;
138
142
  let combinedBody = formatInboundEnvelope({
139
143
  channel: "Discord",
140
144
  from: fromLabel,
@@ -216,15 +220,17 @@ async function buildDiscordMessageProcessContext(params) {
216
220
  if (threadParentId) {
217
221
  parentSessionKey = buildAgentSessionKey({
218
222
  agentId: route.agentId,
223
+ mainKey: cfg.session?.mainKey,
219
224
  channel: route.channel,
220
225
  peer: {
221
226
  kind: "channel",
222
227
  id: threadParentId
223
- }
228
+ },
229
+ groupScope: route.groupScope
224
230
  });
225
- modelParentSessionKey = parentSessionKey;
231
+ modelParentSessionKey = parentSessionKey === baseSessionKey ? void 0 : parentSessionKey;
226
232
  }
227
- if (!threadParentInheritanceEnabled) parentSessionKey = void 0;
233
+ parentSessionKey = threadParentInheritanceEnabled ? modelParentSessionKey : void 0;
228
234
  }
229
235
  const preflightAudioIndex = preflightAudioTranscript === void 0 ? -1 : mediaList.findIndex((media) => media.contentType?.startsWith("audio/"));
230
236
  const threadKeys = resolveThreadSessionKeys({
@@ -249,12 +255,15 @@ async function buildDiscordMessageProcessContext(params) {
249
255
  agentId: route.agentId,
250
256
  channel: route.channel,
251
257
  cfg,
258
+ parentSessionKey: route.sessionKey,
259
+ groupScope: route.groupScope,
252
260
  threadParentInheritanceEnabled
253
261
  });
254
262
  const deliverTarget = replyPlan.deliverTarget;
255
263
  const replyTarget = replyPlan.replyTarget;
256
264
  const replyReference = replyPlan.replyReference;
257
265
  const autoThreadContext = replyPlan.autoThreadContext;
266
+ const conversationParentId = threadChannel ? threadParentId : autoThreadContext ? messageChannelId : void 0;
258
267
  const effectiveFrom = isDirectMessage ? `discord:${author.id}` : autoThreadContext?.From ?? `discord:channel:${messageChannelId}`;
259
268
  const dmConversationTarget = isDirectMessage ? resolveDiscordConversationIdentity({
260
269
  isDirectMessage,
@@ -282,7 +291,7 @@ async function buildDiscordMessageProcessContext(params) {
282
291
  messageId: canonicalMessageId ?? message.id,
283
292
  inboundEventKind: ctx.inboundEventKind
284
293
  }, {
285
- parentId: threadChannel ? threadParentId : void 0,
294
+ parentId: conversationParentId,
286
295
  threadId: threadChannel?.id ?? autoThreadContext?.createdThreadId ?? void 0
287
296
  });
288
297
  const ctxPayload = await (ctx.buildContext ?? buildChannelInboundEventContext)({
@@ -305,12 +314,19 @@ async function buildDiscordMessageProcessContext(params) {
305
314
  isBot: author.bot && !sender.isPluralKit ? true : void 0
306
315
  },
307
316
  conversation: {
308
- kind: isDirectMessage ? "direct" : "channel",
317
+ kind: isGroupDm ? "group" : isDirectMessage ? "direct" : "channel",
309
318
  id: messageChannelId,
319
+ routePeer: buildDiscordRoutePeer({
320
+ isDirectMessage,
321
+ isGroupDm,
322
+ directUserId: author.id,
323
+ conversationId: messageChannelId
324
+ }),
310
325
  nativeChannelId: messageChannelId,
326
+ avatar: ctx.conversationAvatar,
311
327
  label: fromLabel,
312
- spaceId: isGuildMessage ? (guildInfo?.id ?? guildSlug) || void 0 : void 0,
313
- parentId: threadChannel ? threadParentId : void 0,
328
+ spaceId: isGuildMessage ? (guildInfo?.id ?? data.guild?.id ?? data.guild_id ?? guildSlug) || void 0 : void 0,
329
+ parentId: conversationParentId,
314
330
  threadId: threadChannel?.id ?? autoThreadContext?.createdThreadId ?? void 0
315
331
  },
316
332
  route: {
@@ -329,9 +345,9 @@ async function buildDiscordMessageProcessContext(params) {
329
345
  message: {
330
346
  inboundEventKind: ctx.inboundEventKind,
331
347
  body: combinedBody,
332
- rawBody: preflightAudioTranscript ?? baseText,
333
- bodyForAgent: appendMediaUnavailableNotice(preflightAudioTranscript ?? baseText ?? text),
334
- commandBody: preflightAudioTranscript ?? baseText,
348
+ rawBody: baseText,
349
+ bodyForAgent: appendMediaUnavailableNotice(agentFacingBody),
350
+ commandBody: baseText,
335
351
  inboundHistory
336
352
  },
337
353
  sessionTranscript: { historyLimit: shouldIncludeChannelHistory ? historyLimit : 0 },
@@ -345,12 +361,10 @@ async function buildDiscordMessageProcessContext(params) {
345
361
  },
346
362
  commands: { authorized: commandAuthorized }
347
363
  },
348
- commandTurn: {
349
- kind: "text-slash",
350
- source: "text",
364
+ commandTurn: createCommandTurnContext(hasControlCommand ? "text" : "message", {
351
365
  authorized: commandAuthorized,
352
- body: preflightAudioTranscript ?? baseText
353
- },
366
+ body: baseText
367
+ }),
354
368
  media: await toInboundMediaFactsWithMetadata(mediaList, { transcribed: (_media, index) => index === preflightAudioIndex }),
355
369
  supplemental: {
356
370
  quote: replyContext && replyVisible ? {
@@ -367,7 +381,7 @@ async function buildDiscordMessageProcessContext(params) {
367
381
  totalTimeoutMs: DISCORD_ATTACHMENT_TOTAL_TIMEOUT_MS,
368
382
  abortSignal
369
383
  });
370
- return isContextAborted(abortSignal) ? [] : await toInboundMediaFactsWithMetadata(referencedReplyMediaList);
384
+ return isContextAborted(abortSignal) ? [] : await toInboundMediaFactsWithMetadata(referencedReplyMediaList, { messageId: replyContext.id });
371
385
  }
372
386
  } : void 0,
373
387
  thread: {
@@ -455,8 +469,7 @@ function createDiscordMessageProgressRuntime(params) {
455
469
  const { ctx, draftPreview } = params;
456
470
  const { cfg, route, abortSignal } = ctx;
457
471
  const reasoningLevel = (() => {
458
- const normalizedAgentId = (route.agentId ?? "").trim().toLowerCase() || "main";
459
- const cfgDefault = cfg.agents?.list?.find((entry) => ((entry?.id ?? "").trim().toLowerCase() || "main") === normalizedAgentId)?.reasoningDefault ?? cfg.agents?.defaults?.reasoningDefault;
472
+ const cfgDefault = resolveAgentConfig(cfg, route.agentId ?? "main")?.reasoningDefault ?? cfg.agents?.defaults?.reasoningDefault;
460
473
  const configDefault = cfgDefault === "on" || cfgDefault === "stream" ? cfgDefault : "off";
461
474
  if (!params.sessionKey) return configDefault;
462
475
  try {
@@ -475,103 +488,84 @@ function createDiscordMessageProgressRuntime(params) {
475
488
  const reasoningDurableEnabled = reasoningLevel === "on";
476
489
  const reasoningWindowEnabled = reasoningLevel === "stream";
477
490
  let shouldYieldDraftCommentary = () => false;
478
- const progressReceipt = createChannelProgressReceiptTracker();
479
- const resetTurnState = () => {
480
- progressReceipt.reset();
481
- };
482
491
  const handleAssistantMessageBoundary = () => {
483
- if (draftPreview.handleAssistantMessageBoundary()) {
484
- resetTurnState();
485
- params.onTurnReset();
486
- }
492
+ if (draftPreview.handleAssistantMessageBoundary()) params.onTurnReset();
487
493
  };
488
- const buildProgressSummaryLine = () => `-# ${progressReceipt.buildSummaryLine()}`;
489
- return {
490
- replyOptions: {
491
- onAssistantMessageStart: draftPreview.draftStream ? () => {
492
- handleAssistantMessageBoundary();
493
- return false;
494
- } : void 0,
495
- onReasoningEnd: draftPreview.draftStream ? () => {
496
- progressReceipt.closeReasoning();
497
- handleAssistantMessageBoundary();
498
- return false;
499
- } : void 0,
500
- onQueuedFollowupAdmitted: draftPreview.draftStream ? () => {
501
- if (draftPreview.handleQueuedFollowupAdmitted()) {
502
- resetTurnState();
503
- params.onTurnReset();
504
- }
505
- } : void 0,
506
- suppressDefaultToolProgressMessages: params.sourceRepliesAreToolOnly && params.reactions.statusReactionsExplicitlyEnabled || draftPreview.suppressDefaultToolProgressMessages ? true : void 0,
507
- allowToolLifecycleWhenProgressHidden: params.reactions.statusReactionsEnabled ? true : void 0,
508
- commentaryProgressEnabled: draftPreview.isProgressMode ? draftPreview.commentaryProgressEnabled : void 0,
509
- progressPreambleEnabled: draftPreview.draftStream && draftPreview.isProgressMode ? true : void 0,
510
- commentaryPayloadsEnabled: draftPreview.isProgressMode ? draftPreview.commentaryProgressEnabled : void 0,
511
- shouldDeliverCommentaryPayloads: draftPreview.isProgressMode && draftPreview.commentaryProgressEnabled ? () => shouldYieldDraftCommentary() : void 0,
512
- reasoningPayloadsEnabled: reasoningDurableEnabled,
513
- onVerboseProgressVisibility: (isActive) => {
514
- shouldYieldDraftCommentary = isActive;
515
- },
516
- onNarrationUpdate: draftPreview.narrationProgressEnabled ? async (payload) => {
517
- if (isProcessAborted$1(abortSignal) || shouldYieldDraftCommentary()) return;
518
- await draftPreview.pushNarrationProgress(payload.text);
519
- } : void 0,
520
- onProgressNarratorLifecycle: draftPreview.narrationProgressEnabled ? (lifecycle) => draftPreview.setProgressNarratorLifecycle(lifecycle) : void 0,
521
- isProgressDraftVisible: draftPreview.narrationProgressEnabled ? () => draftPreview.isProgressDraftVisible : void 0,
522
- narrationHideCommandText: draftPreview.narrationHideCommandText ? true : void 0,
523
- onReasoningStream: async (payload) => {
524
- if (payload?.requiresReasoningProgressOptIn === true && !reasoningWindowEnabled) return false;
525
- if (payload?.text) progressReceipt.noteReasoning();
526
- await params.reactions.controller.setThinking();
527
- return await draftPreview.pushReasoningProgress(payload?.text, { snapshot: payload?.isReasoningSnapshot === true });
528
- },
529
- streamReasoningInNonStreamModes: reasoningWindowEnabled,
530
- onToolStart: async (payload) => {
531
- if (isProcessAborted$1(abortSignal)) return false;
532
- await params.reactions.maybeBindToToolReaction(payload);
533
- await params.reactions.controller.setTool(payload.name);
534
- if (payload.phase === "start") progressReceipt.noteToolCall(payload.name);
535
- return await draftPreview.pushToolEvent(payload);
536
- },
537
- onItemEvent: async (payload) => {
538
- if (isFailedProgress(payload)) return false;
539
- if (payload.kind === "preamble") {
540
- if (shouldYieldDraftCommentary()) return;
541
- return await draftPreview.pushPreambleItemEvent(payload, (itemId, text) => {
542
- progressReceipt.noteCommentary(itemId, text);
543
- });
544
- }
545
- return await draftPreview.pushItemEvent(payload);
546
- },
547
- onPlanUpdate: async (payload) => {
548
- if (payload.phase === "update") return await draftPreview.pushPlanProgress(payload.steps, { explanation: payload.explanation });
549
- return false;
550
- },
551
- onApprovalEvent: async (payload) => {
552
- return await draftPreview.pushApprovalEvent(payload);
553
- },
554
- onCommandOutput: async (payload) => {
555
- if (isFailedProgress(payload)) return false;
556
- return await draftPreview.pushCommandOutputEvent(payload);
557
- },
558
- onPatchSummary: async (payload) => {
559
- return await draftPreview.pushPatchEvent(payload);
560
- },
561
- onCompactionStart: async () => {
562
- if (!isProcessAborted$1(abortSignal)) await params.reactions.controller.setCompacting();
563
- return false;
564
- },
565
- onCompactionEnd: async () => {
566
- if (!isProcessAborted$1(abortSignal)) {
567
- params.reactions.controller.cancelPending();
568
- await params.reactions.controller.setThinking();
569
- }
570
- return false;
494
+ return { replyOptions: {
495
+ onAssistantMessageStart: draftPreview.draftStream ? () => {
496
+ handleAssistantMessageBoundary();
497
+ return false;
498
+ } : void 0,
499
+ onReasoningEnd: draftPreview.draftStream ? () => {
500
+ handleAssistantMessageBoundary();
501
+ return false;
502
+ } : void 0,
503
+ onQueuedFollowupAdmitted: draftPreview.draftStream ? () => {
504
+ if (draftPreview.handleQueuedFollowupAdmitted()) params.onTurnReset();
505
+ } : void 0,
506
+ suppressDefaultToolProgressMessages: params.sourceRepliesAreToolOnly && params.reactions.statusReactionsExplicitlyEnabled || draftPreview.suppressDefaultToolProgressMessages ? true : void 0,
507
+ allowToolLifecycleWhenProgressHidden: params.reactions.statusReactionsEnabled ? true : void 0,
508
+ commentaryProgressEnabled: draftPreview.isProgressMode ? draftPreview.commentaryProgressEnabled : void 0,
509
+ progressPreambleEnabled: draftPreview.draftStream && draftPreview.isProgressMode ? true : void 0,
510
+ commentaryPayloadsEnabled: draftPreview.isProgressMode ? draftPreview.commentaryProgressEnabled : void 0,
511
+ shouldDeliverCommentaryPayloads: draftPreview.isProgressMode && draftPreview.commentaryProgressEnabled ? () => shouldYieldDraftCommentary() : void 0,
512
+ reasoningPayloadsEnabled: reasoningDurableEnabled,
513
+ onVerboseProgressVisibility: (isActive) => {
514
+ shouldYieldDraftCommentary = isActive;
515
+ },
516
+ onNarrationUpdate: draftPreview.narrationProgressEnabled ? async (payload) => {
517
+ if (isProcessAborted$1(abortSignal) || shouldYieldDraftCommentary()) return;
518
+ await draftPreview.pushNarrationProgress(payload.text);
519
+ } : void 0,
520
+ onProgressNarratorLifecycle: draftPreview.narrationProgressEnabled ? (lifecycle) => draftPreview.setProgressNarratorLifecycle(lifecycle) : void 0,
521
+ isProgressDraftVisible: draftPreview.narrationProgressEnabled ? () => draftPreview.isProgressDraftVisible : void 0,
522
+ narrationHideCommandText: draftPreview.narrationHideCommandText ? true : void 0,
523
+ onReasoningStream: async (payload) => {
524
+ if (payload?.requiresReasoningProgressOptIn === true && !reasoningWindowEnabled) return false;
525
+ await params.reactions.controller.setThinking();
526
+ return await draftPreview.pushReasoningProgress(payload?.text, { snapshot: payload?.isReasoningSnapshot === true });
527
+ },
528
+ streamReasoningInNonStreamModes: reasoningWindowEnabled,
529
+ onToolStart: async (payload) => {
530
+ if (isProcessAborted$1(abortSignal)) return false;
531
+ await params.reactions.maybeBindToToolReaction(payload);
532
+ await params.reactions.controller.setTool(payload.name);
533
+ return await draftPreview.pushToolEvent(payload);
534
+ },
535
+ onItemEvent: async (payload) => {
536
+ if (isFailedProgress(payload)) return false;
537
+ if (payload.kind === "preamble") {
538
+ if (shouldYieldDraftCommentary()) return;
539
+ return await draftPreview.pushPreambleItemEvent(payload);
571
540
  }
541
+ return await draftPreview.pushItemEvent(payload);
572
542
  },
573
- buildProgressSummaryLine
574
- };
543
+ onPlanUpdate: async (payload) => {
544
+ if (payload.phase === "update") return await draftPreview.pushPlanProgress(payload.steps, { explanation: payload.explanation });
545
+ return false;
546
+ },
547
+ onApprovalEvent: async (payload) => {
548
+ return await draftPreview.pushApprovalEvent(payload);
549
+ },
550
+ onCommandOutput: async (payload) => {
551
+ if (isFailedProgress(payload)) return false;
552
+ return await draftPreview.pushCommandOutputEvent(payload);
553
+ },
554
+ onPatchSummary: async (payload) => {
555
+ return await draftPreview.pushPatchEvent(payload);
556
+ },
557
+ onCompactionStart: async () => {
558
+ if (!isProcessAborted$1(abortSignal)) await params.reactions.controller.setCompacting();
559
+ return false;
560
+ },
561
+ onCompactionEnd: async () => {
562
+ if (!isProcessAborted$1(abortSignal)) {
563
+ params.reactions.controller.cancelPending();
564
+ await params.reactions.controller.setThinking();
565
+ }
566
+ return false;
567
+ }
568
+ } };
575
569
  }
576
570
  //#endregion
577
571
  //#region extensions/discord/src/monitor/ack-reactions.ts
@@ -1004,7 +998,7 @@ function createDiscordDraftPreviewController(params) {
1004
998
  let draftText = "";
1005
999
  let hasStreamedMessage = false;
1006
1000
  let finalizedViaPreviewMessage = false;
1007
- let finalReplyDelivered = false;
1001
+ let finalReplyError;
1008
1002
  let progressDraftStartedBeforeFinal = false;
1009
1003
  let progressDraftCollapsed = false;
1010
1004
  let progressNarratorLifecycle;
@@ -1067,7 +1061,7 @@ function createDiscordDraftPreviewController(params) {
1067
1061
  if (beganNewTurn) {
1068
1062
  progressDraftCollapsed = false;
1069
1063
  progressDraftStartedBeforeFinal = false;
1070
- finalReplyDelivered = false;
1064
+ finalReplyError = void 0;
1071
1065
  finalizedViaPreviewMessage = false;
1072
1066
  progressNarratorLifecycle?.beginTurn();
1073
1067
  }
@@ -1110,8 +1104,8 @@ function createDiscordDraftPreviewController(params) {
1110
1104
  progressDraft.markFinalReplyStarted();
1111
1105
  progressNarratorLifecycle?.stopTurn();
1112
1106
  },
1113
- markFinalReplyDelivered() {
1114
- finalReplyDelivered = true;
1107
+ markFinalReplyDelivered(isError = false) {
1108
+ finalReplyError = isError;
1115
1109
  progressDraft.markFinalReplyDelivered();
1116
1110
  },
1117
1111
  markPreviewFinalized() {
@@ -1120,14 +1114,11 @@ function createDiscordDraftPreviewController(params) {
1120
1114
  async retarget(channelId) {
1121
1115
  await draftStream?.retarget(channelId);
1122
1116
  },
1123
- async finalizeProgressReceipt(receiptLine) {
1117
+ async finalizeProgressDraft() {
1124
1118
  if (!draftStream || discordStreamMode !== "progress") return false;
1125
- const receipt = receiptLine.trim();
1126
- if (!receipt) return false;
1127
1119
  const progressText = lastPartialText.trimEnd();
1128
- const maxProgressChars = Math.max(0, draftMaxChars - receipt.length - 1);
1129
- const fittedProgressText = progressText.length > maxProgressChars ? progressText.slice(progressText.length - maxProgressChars).trimStart() : progressText;
1130
- draftStream.update(fittedProgressText ? `${fittedProgressText}\n${receipt}` : receipt);
1120
+ if (!progressText) return false;
1121
+ draftStream.update(progressText);
1131
1122
  await draftStream.stop();
1132
1123
  if (!draftStream.messageId()) return false;
1133
1124
  finalizedViaPreviewMessage = true;
@@ -1152,11 +1143,10 @@ function createDiscordDraftPreviewController(params) {
1152
1143
  return await progressDraft.pushNarrationProgress(text);
1153
1144
  },
1154
1145
  pushPreambleHeadline,
1155
- async pushPreambleItemEvent(payload, noteCommentary) {
1146
+ async pushPreambleItemEvent(payload) {
1156
1147
  const headlineAccepted = await pushPreambleHeadline(payload.progressText, { itemId: payload.itemId });
1157
1148
  if (!progressDraft.commentaryProgressEnabled) return headlineAccepted;
1158
1149
  const commentaryAccepted = await progressDraft.pushCommentaryProgress(payload.progressText, { itemId: payload.itemId });
1159
- if (commentaryAccepted) noteCommentary(payload.itemId, payload.progressText);
1160
1150
  return headlineAccepted || commentaryAccepted;
1161
1151
  },
1162
1152
  async pushCommentaryProgress(text, options) {
@@ -1240,8 +1230,8 @@ function createDiscordDraftPreviewController(params) {
1240
1230
  async cleanup() {
1241
1231
  try {
1242
1232
  progressDraft.cancel();
1243
- if (!finalReplyDelivered) await draftStream?.discardPending();
1244
- if (!finalizedViaPreviewMessage && draftStream?.messageId()) await draftStream.clear();
1233
+ if (finalReplyError !== false) await draftStream?.discardPending();
1234
+ if (finalReplyError !== true && !finalizedViaPreviewMessage && draftStream?.messageId()) await draftStream.clear();
1245
1235
  await draftStream?.cleanupRetargeted();
1246
1236
  } catch (err) {
1247
1237
  params.log(`discord: draft cleanup failed: ${String(err)}`);
@@ -1411,16 +1401,6 @@ function createDiscordMessageReplyRuntime(params) {
1411
1401
  }
1412
1402
  //#endregion
1413
1403
  //#region extensions/discord/src/monitor/message-handler.process-thread-route.ts
1414
- async function finalizeDiscordAdoptedThreadProgressReceipt(hasProgressDraft, receipt, finalizeDraft, deliverReceipt, onFinalizeError) {
1415
- const receiptLine = receipt.trim();
1416
- if (!hasProgressDraft || !receiptLine) return;
1417
- try {
1418
- if (await finalizeDraft(receiptLine)) return;
1419
- } catch (error) {
1420
- onFinalizeError?.(error);
1421
- }
1422
- await deliverReceipt(receiptLine);
1423
- }
1424
1404
  function createDiscordMessageActiveThreadRoute(params) {
1425
1405
  let adoptedThreadId;
1426
1406
  let threadReplyDelivered = false;
@@ -1487,7 +1467,7 @@ async function processDiscordMessageInner(ctx, observer) {
1487
1467
  }
1488
1468
  });
1489
1469
  const sourceRepliesAreToolOnly = sourceReplyDeliveryMode === "message_tool_only";
1490
- const configuredTypingMode = resolveAgentConfig(cfg, route.agentId)?.typingMode ?? cfg.agents?.defaults?.typingMode;
1470
+ const configuredTypingMode = resolveAgentConfig$1(cfg, route.agentId)?.typingMode ?? cfg.agents?.defaults?.typingMode;
1491
1471
  const configuredTypingInterval = cfg.agents?.defaults?.typingIntervalSeconds;
1492
1472
  const shouldDisableCoreTypingKeepalive = sourceRepliesAreToolOnly && configuredTypingMode === void 0 && configuredTypingInterval === void 0;
1493
1473
  const mediaLocalRoots = getAgentScopedMediaLocalRoots(cfg, route.agentId);
@@ -1547,21 +1527,21 @@ async function processDiscordMessageInner(ctx, observer) {
1547
1527
  let userFacingFinalDelivered = false;
1548
1528
  let userFacingFinalDeliveryFailed = false;
1549
1529
  let pendingToolWarningFinal;
1550
- const markUserFacingFinalDelivered = () => {
1551
- userFacingFinalDelivered = true;
1552
- userFacingFinalDeliveryFailed = false;
1553
- pendingToolWarningFinal = void 0;
1554
- draftPreview.markFinalReplyDelivered();
1555
- observer?.onFinalReplyDelivered?.();
1530
+ const markFinalReplyDelivered = (isError = false) => {
1531
+ draftPreview.markFinalReplyDelivered(isError);
1532
+ if (!isError) {
1533
+ userFacingFinalDelivered = true;
1534
+ userFacingFinalDeliveryFailed = false;
1535
+ pendingToolWarningFinal = void 0;
1536
+ observer?.onFinalReplyDelivered?.();
1537
+ }
1556
1538
  };
1557
- let progressReceiptLine;
1558
1539
  let clearProgressDraftAfterFinalDelivery = false;
1559
1540
  const resetDeliveryState = () => {
1560
1541
  finalReplyStartNotified = false;
1561
1542
  userFacingFinalDelivered = false;
1562
1543
  userFacingFinalDeliveryFailed = false;
1563
1544
  pendingToolWarningFinal = void 0;
1564
- progressReceiptLine = void 0;
1565
1545
  clearProgressDraftAfterFinalDelivery = false;
1566
1546
  };
1567
1547
  const progress = createDiscordMessageProgressRuntime({
@@ -1666,7 +1646,6 @@ async function processDiscordMessageInner(ctx, observer) {
1666
1646
  }
1667
1647
  if (draftStream && isFinal && draftPreview.isProgressMode && !deliverablePayload.isError && draftPreview.hasProgressDraftToCollapse && draftStream) {
1668
1648
  await draftPreview.flush();
1669
- progressReceiptLine = progress.buildProgressSummaryLine();
1670
1649
  clearProgressDraftAfterFinalDelivery = true;
1671
1650
  }
1672
1651
  if (draftStream && isFinal && !draftPreview.isProgressMode && !deliverablePayload.isError) {
@@ -1693,7 +1672,7 @@ async function processDiscordMessageInner(ctx, observer) {
1693
1672
  });
1694
1673
  },
1695
1674
  onPreviewFinalized: () => {
1696
- markUserFacingFinalDelivered();
1675
+ markFinalReplyDelivered();
1697
1676
  draftPreview.markPreviewFinalized();
1698
1677
  replyReference.markSent();
1699
1678
  },
@@ -1733,7 +1712,7 @@ async function processDiscordMessageInner(ctx, observer) {
1733
1712
  })).visibleReplySent;
1734
1713
  },
1735
1714
  onNormalDelivered: () => {
1736
- markUserFacingFinalDelivered();
1715
+ markFinalReplyDelivered();
1737
1716
  replyReference.markSent();
1738
1717
  }
1739
1718
  })).kind !== "normal-skipped") return { visibleReplySent: true };
@@ -1749,14 +1728,9 @@ async function processDiscordMessageInner(ctx, observer) {
1749
1728
  }
1750
1729
  const replyToId = replyReference.use();
1751
1730
  if (isFinal) notifyFinalReplyStart();
1752
- const receiptLine = isFinal && deliverablePayload.isError !== true ? progressReceiptLine : void 0;
1753
- const payloadForDelivery = receiptLine ? {
1754
- ...deliverablePayload,
1755
- text: deliverablePayload.text?.trim() ? `${deliverablePayload.text.trimEnd()}\n${receiptLine}` : receiptLine
1756
- } : deliverablePayload;
1757
1731
  const result = await deliverDiscordReply({
1758
1732
  cfg,
1759
- replies: [payloadForDelivery],
1733
+ replies: [deliverablePayload],
1760
1734
  target: deliverTarget,
1761
1735
  token,
1762
1736
  accountId,
@@ -1776,14 +1750,11 @@ async function processDiscordMessageInner(ctx, observer) {
1776
1750
  });
1777
1751
  if (!result.visibleReplySent) return result;
1778
1752
  replyReference.markSent();
1779
- if (isFinal && deliverablePayload.isError !== true) {
1780
- if (receiptLine) {
1781
- progressReceiptLine = void 0;
1782
- draftPreview.markProgressDraftCollapsed();
1783
- }
1784
- markUserFacingFinalDelivered();
1785
- if (clearProgressDraftAfterFinalDelivery) {
1753
+ if (isFinal) {
1754
+ markFinalReplyDelivered(deliverablePayload.isError === true);
1755
+ if (deliverablePayload.isError !== true && clearProgressDraftAfterFinalDelivery) {
1786
1756
  clearProgressDraftAfterFinalDelivery = false;
1757
+ draftPreview.markProgressDraftCollapsed();
1787
1758
  await draftStream?.discardPending();
1788
1759
  await draftStream?.clear();
1789
1760
  }
@@ -1880,8 +1851,12 @@ async function processDiscordMessageInner(ctx, observer) {
1880
1851
  }
1881
1852
  if (activeThreadRoute.threadReplyDelivered && !userFacingFinalDelivered) {
1882
1853
  draftPreview.markFinalReplyStarted();
1883
- await finalizeDiscordAdoptedThreadProgressReceipt(draftPreview.hasProgressDraftToCollapse, progress.buildProgressSummaryLine(), (receiptLine) => draftPreview.finalizeProgressReceipt(receiptLine), (receiptText) => deliverDiscordPayload({ text: receiptText }, { kind: "block" }, { allowProgressBlock: true }), (error) => logVerbose(`discord: failed to finalize adopted thread progress (${String(error)})`));
1884
- markUserFacingFinalDelivered();
1854
+ if (draftPreview.hasProgressDraftToCollapse) try {
1855
+ await draftPreview.finalizeProgressDraft();
1856
+ } catch (error) {
1857
+ logVerbose(`discord: failed to finalize adopted thread progress (${String(error)})`);
1858
+ }
1859
+ markFinalReplyDelivered();
1885
1860
  }
1886
1861
  } catch (err) {
1887
1862
  if (isProcessAborted(abortSignal)) {
@@ -1896,7 +1871,8 @@ async function processDiscordMessageInner(ctx, observer) {
1896
1871
  endDeliveryCorrelation();
1897
1872
  await draftPreview.cleanup();
1898
1873
  dispatchError ||= readAgentRunTerminalOutcome(dispatchResult) === "failed";
1899
- const finalDeliveryFailed = (dispatchResult?.failedCounts?.final ?? 0) > 0;
1874
+ const finalReceipt = dispatchResult?.settledReceipt?.counts.final;
1875
+ const finalDeliveryFailed = (finalReceipt?.failedBeforeSend ?? 0) + (finalReceipt?.failedAfterSend ?? 0) > 0;
1900
1876
  await reactions.finish({
1901
1877
  dispatchAborted,
1902
1878
  dispatchError,
@@ -1907,7 +1883,7 @@ async function processDiscordMessageInner(ctx, observer) {
1907
1883
  const finalDispatchResult = dispatchResult;
1908
1884
  if (!finalDispatchResult || !hasFinalInboundReplyDispatch(finalDispatchResult)) return;
1909
1885
  if (shouldLogVerbose()) {
1910
- const finalCount = finalDispatchResult.counts.final;
1886
+ const finalCount = finalDispatchResult.settledReceipt?.counts.final.delivered ?? 0;
1911
1887
  logVerbose(`discord: delivered ${finalCount} reply${finalCount === 1 ? "" : "ies"} to ${replyTarget}`);
1912
1888
  }
1913
1889
  }