@openclaw/discord 2026.5.12 → 2026.5.14-beta.2

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 (117) hide show
  1. package/dist/{account-inspect-D7jL5YDH.js → account-inspect-B_N30NV0.js} +1 -1
  2. package/dist/account-inspect-api.js +1 -1
  3. package/dist/{accounts-BcwyaFd-.js → accounts-DnNVBDfc.js} +95 -4
  4. package/dist/action-runtime-api.js +1 -1
  5. package/dist/{allow-list-n8Ki-Rt3.js → allow-list-CBI-M84K.js} +24 -2
  6. package/dist/api.js +19 -21
  7. package/dist/{approval-handler.runtime-S-ircYcz.js → approval-handler.runtime-Uco62pII.js} +4 -4
  8. package/dist/{audit-BliEqCEc.js → audit-eSlKbMHw.js} +5 -5
  9. package/dist/{channel-Bliqi-Qi.js → channel-BjBa8nYY.js} +23 -25
  10. package/dist/{channel-actions-Cn_K00Vy.js → channel-actions-DANVAtKL.js} +4 -4
  11. package/dist/{channel-actions.runtime-DcsRvPnx.js → channel-actions.runtime-CpIslHS9.js} +7 -5
  12. package/dist/channel-config-api.js +1 -1
  13. package/dist/channel-plugin-api.js +1 -1
  14. package/dist/{channel.setup-DR-xVYso.js → channel.setup-DBFcGRFD.js} +4 -5
  15. package/dist/{components-Dxq2mU57.js → components-Cgm7XT8-.js} +120 -3
  16. package/dist/{config-schema-D2KGskAp.js → config-schema-D7AtCpJa.js} +21 -1
  17. package/dist/contract-api.js +7 -7
  18. package/dist/{approval-native-Gtqpyfdj.js → conversation-identity-C3AI-1tz.js} +123 -6
  19. package/dist/{directory-config-CDl4JTCA.js → directory-config-CW_JusGS.js} +2 -2
  20. package/dist/directory-contract-api.js +1 -1
  21. package/dist/directory-live-MrDSKsMf.js +159 -0
  22. package/dist/doctor-contract-api.js +1 -1
  23. package/dist/{doctor-contract-BGjjFBdq.js → doctor-contract-ftWAMvBl.js} +1 -1
  24. package/dist/{doctor-jcX_qXsS.js → doctor-mn2XyjuF.js} +5 -5
  25. package/dist/{handle-action.guild-admin-C4phin-a.js → handle-action.guild-admin-DriifPwO.js} +1 -1
  26. package/dist/{inbound-context-jtKcY9on.js → inbound-context-DD7n3Q6U.js} +1 -1
  27. package/dist/{manager.runtime-DqMGETqp.js → manager.runtime-DauS2xA3.js} +107 -25
  28. package/dist/{message-handler-DIsnboy2.js → message-handler-CMHwRlxG.js} +7 -7
  29. package/dist/{message-handler.preflight-BRH-dv1o.js → message-handler.preflight-C0sT-ewp.js} +27 -17
  30. package/dist/{message-handler.process-Bs5wropA.js → message-handler.process-Cy7_-0H0.js} +46 -37
  31. package/dist/{message-utils-ByofKwPe.js → message-utils-N5UTOXQ2.js} +16 -12
  32. package/dist/{outbound-adapter-lWjkSeyP.js → outbound-adapter-Cw9JsRTY.js} +7 -10
  33. package/dist/{pluralkit-B1HTaBc9.js → pluralkit-B2AqgTHV.js} +1 -1
  34. package/dist/{preflight-audio-CD97vnac.js → preflight-audio-DFGpAvzi.js} +1 -1
  35. package/dist/{probe-BZtr8qle.js → probe-CiBYm-vD.js} +2 -2
  36. package/dist/{probe.runtime-0F0UzBoJ.js → probe.runtime-9hi1GYNU.js} +1 -1
  37. package/dist/{provider-DABvNRT0.js → provider-nzJg2k5t.js} +1039 -45
  38. package/dist/{provider-session.runtime-BZyP90-i.js → provider-session.runtime-DMxaLPB3.js} +3 -3
  39. package/dist/provider.runtime-S-wZdzK5.js +2 -0
  40. package/dist/{resolve-allowlist-common-CVHYb5Hb.js → resolve-allowlist-common-DybgkAjk.js} +3 -3
  41. package/dist/{resolve-channels-JNt3Ak6P.js → resolve-channels-u7_agBcm.js} +4 -4
  42. package/dist/{resolve-users-CrjbUxrL.js → resolve-users-Bc25I6OP.js} +3 -3
  43. package/dist/{runtime-CdnAT8R5.js → runtime-DL82ijB1.js} +102 -46
  44. package/dist/runtime-api.actions.js +2 -2
  45. package/dist/runtime-api.js +25 -26
  46. package/dist/runtime-api.lookup.js +6 -6
  47. package/dist/runtime-api.monitor-DbLcHuhE.js +5 -0
  48. package/dist/runtime-api.monitor.js +7 -8
  49. package/dist/runtime-api.send.js +5 -5
  50. package/dist/runtime-api.threads.js +5 -5
  51. package/dist/runtime-setter-api.js +1 -1
  52. package/dist/secret-contract-api.js +1 -1
  53. package/dist/{security-audit-BQ_sGK3J.js → security-audit-CLPZKYi4.js} +1 -1
  54. package/dist/security-audit-contract-api.js +1 -1
  55. package/dist/{security-audit.runtime-B7Gmz2DX.js → security-audit.runtime-CCm9leFJ.js} +1 -1
  56. package/dist/security-contract-api.js +1 -1
  57. package/dist/{send-DCFuSiBi.js → send-BqzTEkt9.js} +4 -6
  58. package/dist/{send.components-DxDqPJZQ.js → send.components-D6pXHVrU.js} +8 -10
  59. package/dist/{send.outbound-PM0J0F60.js → send.outbound-D8o8BW6q.js} +91 -7
  60. package/dist/{discord-BqYcwxvG.js → send.receipt-nKLxvA1s.js} +319 -1
  61. package/dist/{send.shared-Dza0jdso.js → send.shared-DSpva7uA.js} +4 -6
  62. package/dist/{sender-identity-w9rSI-nD.js → sender-identity-BTGL3VbF.js} +1 -1
  63. package/dist/session-key-api.js +1 -1
  64. package/dist/setup-plugin-api.js +1 -1
  65. package/dist/{shared-Yp_M6Cfp.js → shared-0kdaIxXP.js} +16 -14
  66. package/dist/{subagent-hooks-CtN-hfXy.js → subagent-hooks-DhuBhwRw.js} +3 -3
  67. package/dist/subagent-hooks-api.js +1 -1
  68. package/dist/{system-events-B04UOvPg.js → system-events-Bnit0zkQ.js} +2 -2
  69. package/dist/{target-resolver-CgJei-kD.js → target-resolver-BsGT9hI7.js} +3 -6
  70. package/dist/targets-DwW6OieO.js +3 -0
  71. package/dist/test-api.js +4 -4
  72. package/dist/{thread-bindings-B4of4OmR.js → thread-bindings-C1f7Iim4.js} +6 -7
  73. package/dist/{thread-bindings.discord-api-BAw15EQb.js → thread-bindings.discord-api-DJACBZJ1.js} +67 -8
  74. package/dist/{thread-bindings.manager-DNFl10CA.js → thread-bindings.manager-DN_q0IW7.js} +4 -5
  75. package/dist/{thread-bindings.session-updates-D18cCLmN.js → thread-bindings.session-updates-ZnRRzzgf.js} +1 -1
  76. package/dist/timeouts.js +1 -1
  77. package/dist/{typing-_jePdFIw.js → typing-C_8U8J7E.js} +2 -2
  78. package/openclaw.plugin.json +68 -0
  79. package/package.json +6 -6
  80. package/dist/access-Dxmzr0ix.js +0 -89
  81. package/dist/approval-shared-BFnWKSQD.js +0 -93
  82. package/dist/channel-access-BL-wemES.js +0 -62
  83. package/dist/chunk-DYl-_5RL.js +0 -179
  84. package/dist/conversation-identity-CvIx6J7M.js +0 -31
  85. package/dist/directory-cache-Ddl-Oxue.js +0 -62
  86. package/dist/directory-live-ApUXOSj0.js +0 -101
  87. package/dist/doctor-shared-D_QLzu30.js +0 -4
  88. package/dist/format-D8TsaXxW.js +0 -24
  89. package/dist/mentions-BZoGn0ul.js +0 -88
  90. package/dist/normalize-Cu94FOqy.js +0 -58
  91. package/dist/outbound-session-route-BaJRt05p.js +0 -43
  92. package/dist/provider.runtime-Cmv1SFtb.js +0 -2
  93. package/dist/reply-delivery-CUSK6SA_.js +0 -191
  94. package/dist/route-resolution-BFfF9xmG.js +0 -268
  95. package/dist/runtime-api.monitor-W_dJ5EQu.js +0 -6
  96. package/dist/send.receipt-BAZw2Zsz.js +0 -35
  97. package/dist/shared-interactive-DavY6jYt.js +0 -79
  98. package/dist/target-parsing-D-H7nnh2.js +0 -51
  99. package/dist/targets-DToZUkgV.js +0 -3
  100. package/dist/threading-CLZ3v7-y.js +0 -475
  101. package/dist/token-BZtonk7d.js +0 -93
  102. /package/dist/{agent-components.runtime-zT8qPsnM.js → agent-components.runtime-CEMbMQcQ.js} +0 -0
  103. /package/dist/{api-DzNBVTto.js → api-DgQLz1wq.js} +0 -0
  104. /package/dist/{audit-core-BgDZSkIR.js → audit-core-DRyoXREU.js} +0 -0
  105. /package/dist/{channel-api-CTSWMrnD.js → channel-api-JudoSiJv.js} +0 -0
  106. /package/dist/{config-api-CFZtoMaS.js → config-api-oLS_52S7.js} +0 -0
  107. /package/dist/{gateway-registry-BKG4KIVC.js → gateway-registry-BKSpa4GB.js} +0 -0
  108. /package/dist/{preflight-audio.runtime-fXnUxxBa.js → preflight-audio.runtime-Drc-OFcp.js} +0 -0
  109. /package/dist/{preview-streaming-DCPAe24T.js → preview-streaming-CXTZydhx.js} +0 -0
  110. /package/dist/{runtime-BqCoo-zp.js → runtime-Tqtvj5GX.js} +0 -0
  111. /package/dist/{secret-config-contract-BCQNNS7N.js → secret-config-contract-B3347_eU.js} +0 -0
  112. /package/dist/{security-contract-DkCMKSvb.js → security-contract-DyCRvz_Q.js} +0 -0
  113. /package/dist/{security-doctor-BJH5YIGL.js → security-doctor-Cp-NqNdS.js} +0 -0
  114. /package/dist/{session-contract-D871HDFG.js → session-contract-ugfEa9Xc.js} +0 -0
  115. /package/dist/{session-key-normalization-BV82IME9.js → session-key-normalization-B7h83qD2.js} +0 -0
  116. /package/dist/{thread-bindings.state-SPlv6mh7.js → thread-bindings.state-BdBeo7Rx.js} +0 -0
  117. /package/dist/{timeouts-C3FYXWJX.js → timeouts-snXNwR4m.js} +0 -0
@@ -1,14 +1,13 @@
1
- import { C as Message, st as getChannelMessage, t as discord_exports } from "./discord-BqYcwxvG.js";
2
- import { o as resolveDefaultDiscordAccountId } from "./accounts-BcwyaFd-.js";
3
- import { i as resolveTimestampMs, n as formatDiscordUserTag, r as resolveDiscordSystemLocation } from "./format-D8TsaXxW.js";
4
- import { _ as resolveGroupDmAllow, a as normalizeDiscordSlug, c as resolveDiscordChannelConfigWithFallback, d as resolveDiscordGuildEntry, f as resolveDiscordMemberAccessState, g as resolveDiscordShouldRequireMention, i as normalizeDiscordDisplaySlug, n as isDiscordGroupAllowedByPolicy } from "./allow-list-n8Ki-Rt3.js";
5
- import { t as resolveDiscordConversationIdentity } from "./conversation-identity-CvIx6J7M.js";
6
- import { l as isRecentlyUnboundThreadWebhookMessage } from "./thread-bindings.state-SPlv6mh7.js";
7
- import "./thread-bindings-B4of4OmR.js";
8
- import { n as resolveDiscordChannelInfoSafe, r as resolveDiscordChannelNameSafe } from "./channel-access-BL-wemES.js";
9
- import { a as shouldIgnoreStaleDiscordRouteBinding, c as resolveDiscordTextCommandAccess, i as resolveDiscordEffectiveRoute, o as handleDiscordDmCommandDecision, r as resolveDiscordConversationRoute, s as resolveDiscordDmCommandAccess, t as buildDiscordRoutePeer } from "./route-resolution-BFfF9xmG.js";
10
- import { c as resolveDiscordChannelInfo, l as resolveDiscordMessageChannelId, r as resolveDiscordMessageText } from "./message-utils-ByofKwPe.js";
11
- import { n as resolveDiscordWebhookId, t as resolveDiscordSenderIdentity } from "./sender-identity-w9rSI-nD.js";
1
+ import { A as Message, c as discord_exports, mt as getChannelMessage } from "./send.receipt-nKLxvA1s.js";
2
+ import { o as resolveDefaultDiscordAccountId } from "./accounts-DnNVBDfc.js";
3
+ import { S as resolveTimestampMs, _ as resolveGroupDmAllow, a as normalizeDiscordSlug, b as formatDiscordUserTag, c as resolveDiscordChannelConfigWithFallback, d as resolveDiscordGuildEntry, f as resolveDiscordMemberAccessState, g as resolveDiscordShouldRequireMention, i as normalizeDiscordDisplaySlug, n as isDiscordGroupAllowedByPolicy, x as resolveDiscordSystemLocation } from "./allow-list-CBI-M84K.js";
4
+ import { t as resolveDiscordConversationIdentity } from "./conversation-identity-C3AI-1tz.js";
5
+ import { l as isRecentlyUnboundThreadWebhookMessage } from "./thread-bindings.state-BdBeo7Rx.js";
6
+ import { d as resolveDiscordChannelNameSafe, u as resolveDiscordChannelInfoSafe } from "./thread-bindings.discord-api-DJACBZJ1.js";
7
+ import "./thread-bindings-C1f7Iim4.js";
8
+ import { C as resolveDiscordDmCommandAccess, f as buildDiscordRoutePeer, g as handleDiscordDmCommandDecision, h as shouldIgnoreStaleDiscordRouteBinding, m as resolveDiscordEffectiveRoute, p as resolveDiscordConversationRoute, w as resolveDiscordTextCommandAccess } from "./provider-nzJg2k5t.js";
9
+ import { c as resolveDiscordChannelInfo, l as resolveDiscordMessageChannelId, r as resolveDiscordMessageText } from "./message-utils-N5UTOXQ2.js";
10
+ import { n as resolveDiscordWebhookId, t as resolveDiscordSenderIdentity } from "./sender-identity-BTGL3VbF.js";
12
11
  import { normalizeOptionalString } from "openclaw/plugin-sdk/string-coerce-runtime";
13
12
  import { getChildLogger, logVerbose, shouldLogVerbose } from "openclaw/plugin-sdk/runtime-env";
14
13
  import { recordChannelActivity } from "openclaw/plugin-sdk/channel-activity-runtime";
@@ -28,7 +27,7 @@ async function loadConversationRuntime$1() {
28
27
  return await conversationRuntimePromise$1;
29
28
  }
30
29
  async function loadDiscordSendRuntime() {
31
- discordSendRuntimePromise ??= import("./send-DCFuSiBi.js").then((n) => n.t);
30
+ discordSendRuntimePromise ??= import("./send-BqzTEkt9.js").then((n) => n.t);
32
31
  return await discordSendRuntimePromise;
33
32
  }
34
33
  async function resolveDiscordDmPreflightAccess(params) {
@@ -426,19 +425,19 @@ let preflightAudioRuntimePromise;
426
425
  let systemEventsRuntimePromise;
427
426
  let discordThreadingRuntimePromise;
428
427
  async function loadPluralKitRuntime() {
429
- pluralkitRuntimePromise ??= import("./pluralkit-B1HTaBc9.js").then((n) => n.n);
428
+ pluralkitRuntimePromise ??= import("./pluralkit-B2AqgTHV.js").then((n) => n.n);
430
429
  return await pluralkitRuntimePromise;
431
430
  }
432
431
  async function loadPreflightAudioRuntime() {
433
- preflightAudioRuntimePromise ??= import("./preflight-audio-CD97vnac.js");
432
+ preflightAudioRuntimePromise ??= import("./preflight-audio-DFGpAvzi.js");
434
433
  return await preflightAudioRuntimePromise;
435
434
  }
436
435
  async function loadSystemEventsRuntime() {
437
- systemEventsRuntimePromise ??= import("./system-events-B04UOvPg.js");
436
+ systemEventsRuntimePromise ??= import("./system-events-Bnit0zkQ.js");
438
437
  return await systemEventsRuntimePromise;
439
438
  }
440
439
  async function loadDiscordThreadingRuntime() {
441
- discordThreadingRuntimePromise ??= import("./threading-CLZ3v7-y.js").then((n) => n.t);
440
+ discordThreadingRuntimePromise ??= import("./provider-nzJg2k5t.js").then((n) => n.v);
442
441
  return await discordThreadingRuntimePromise;
443
442
  }
444
443
  function isPreflightAborted(abortSignal) {
@@ -955,6 +954,16 @@ async function preflightDiscordMessage(params) {
955
954
  return null;
956
955
  }
957
956
  }
957
+ const botLoopProtection = author.bot && !sender.isPluralKit && allowBotsMode !== "off" && params.botUserId && author.id !== params.botUserId ? {
958
+ scopeId: params.accountId,
959
+ conversationId: messageChannelId,
960
+ senderId: author.id,
961
+ receiverId: params.botUserId,
962
+ config: params.discordConfig?.botLoopProtection,
963
+ defaultsConfig: params.cfg.channels?.defaults?.botLoopProtection,
964
+ defaultEnabled: true,
965
+ nowMs: resolveTimestampMs(message.timestamp)
966
+ } : void 0;
958
967
  logDebug(`[discord-preflight] success: route=${effectiveRoute.agentId} sessionKey=${effectiveRoute.sessionKey}`);
959
968
  return buildDiscordMessagePreflightContext({
960
969
  preflightParams: params,
@@ -1001,7 +1010,8 @@ async function preflightDiscordMessage(params) {
1001
1010
  shouldBypassMention: mentionDecision.shouldBypassMention,
1002
1011
  effectiveWasMentioned,
1003
1012
  canDetectMention,
1004
- historyEntry
1013
+ historyEntry,
1014
+ botLoopProtection
1005
1015
  });
1006
1016
  }
1007
1017
  //#endregion
@@ -1,21 +1,17 @@
1
- import { at as editChannelMessage, et as createChannelMessage, rt as deleteChannelMessage, t as discord_exports } from "./discord-BqYcwxvG.js";
2
- import { f as resolveDiscordMaxLinesPerMessage } from "./accounts-BcwyaFd-.js";
3
- import { n as resolveDiscordChannelId } from "./target-parsing-D-H7nnh2.js";
4
- import { t as chunkDiscordTextWithMode } from "./chunk-DYl-_5RL.js";
5
- import { M as createDiscordRuntimeAccountContext, d as resolveDiscordTargetChannelId, j as createDiscordRestClient } from "./send.shared-Dza0jdso.js";
6
- import { i as resolveTimestampMs } from "./format-D8TsaXxW.js";
7
- import { a as normalizeDiscordSlug, r as normalizeDiscordAllowList } from "./allow-list-n8Ki-Rt3.js";
8
- import { a as removeReactionDiscord, f as editMessageDiscord, r as reactMessageDiscord } from "./send-DCFuSiBi.js";
9
- import "./targets-DToZUkgV.js";
10
- import { t as resolveDiscordConversationIdentity } from "./conversation-identity-CvIx6J7M.js";
11
- import { t as DISCORD_TEXT_CHUNK_LIMIT } from "./outbound-adapter-lWjkSeyP.js";
12
- import { t as resolveDiscordPreviewStreamMode } from "./preview-streaming-DCPAe24T.js";
13
- import { n as DISCORD_ATTACHMENT_TOTAL_TIMEOUT_MS, t as DISCORD_ATTACHMENT_IDLE_TIMEOUT_MS } from "./timeouts-C3FYXWJX.js";
14
- import { a as resolveForwardedMediaList, i as buildDiscordMediaPayload, o as resolveMediaList, r as resolveDiscordMessageText } from "./message-utils-ByofKwPe.js";
15
- import { a as resolveDiscordThreadStarter, n as resolveDiscordAutoThreadReplyPlan } from "./threading-CLZ3v7-y.js";
16
- import { t as sendTyping } from "./typing-_jePdFIw.js";
17
- import { n as buildDiscordInboundAccessContext, r as createDiscordSupplementalContextAccessChecker } from "./inbound-context-jtKcY9on.js";
18
- import { i as resolveReplyContext, n as buildDirectLabel, r as buildGuildLabel, t as deliverDiscordReply } from "./reply-delivery-CUSK6SA_.js";
1
+ import { Ut as resolveDiscordChannelId, c as discord_exports, ft as editChannelMessage, s as chunkDiscordTextWithMode, st as createChannelMessage, ut as deleteChannelMessage } from "./send.receipt-nKLxvA1s.js";
2
+ import { f as resolveDiscordMaxLinesPerMessage } from "./accounts-DnNVBDfc.js";
3
+ import { M as createDiscordRestClient, N as createDiscordRuntimeAccountContext, d as resolveDiscordTargetChannelId } from "./send.shared-DSpva7uA.js";
4
+ import { S as resolveTimestampMs, a as normalizeDiscordSlug, r as normalizeDiscordAllowList } from "./allow-list-CBI-M84K.js";
5
+ import { a as removeReactionDiscord, f as editMessageDiscord, r as reactMessageDiscord } from "./send-BqzTEkt9.js";
6
+ import "./targets-DwW6OieO.js";
7
+ import { t as resolveDiscordConversationIdentity } from "./conversation-identity-C3AI-1tz.js";
8
+ import { t as DISCORD_TEXT_CHUNK_LIMIT } from "./outbound-adapter-Cw9JsRTY.js";
9
+ import { t as resolveDiscordPreviewStreamMode } from "./preview-streaming-CXTZydhx.js";
10
+ import { n as DISCORD_ATTACHMENT_TOTAL_TIMEOUT_MS, t as DISCORD_ATTACHMENT_IDLE_TIMEOUT_MS } from "./timeouts-snXNwR4m.js";
11
+ import { a as resolveReplyContext, i as buildGuildLabel, n as deliverDiscordReply, r as buildDirectLabel, x as resolveDiscordThreadStarter, y as resolveDiscordAutoThreadReplyPlan } from "./provider-nzJg2k5t.js";
12
+ import { a as resolveForwardedMediaList, i as buildDiscordMediaPayload, o as resolveMediaList, r as resolveDiscordMessageText } from "./message-utils-N5UTOXQ2.js";
13
+ import { t as sendTyping } from "./typing-C_8U8J7E.js";
14
+ import { n as buildDiscordInboundAccessContext, r as createDiscordSupplementalContextAccessChecker } from "./inbound-context-DD7n3Q6U.js";
19
15
  import { buildAgentSessionKey, normalizeAccountId, resolveAccountEntry, resolveThreadSessionKeys } from "openclaw/plugin-sdk/routing";
20
16
  import { evaluateSupplementalContextVisibility } from "openclaw/plugin-sdk/security-runtime";
21
17
  import { getAgentScopedMediaLocalRoots } from "openclaw/plugin-sdk/media-runtime";
@@ -26,7 +22,7 @@ import { formatErrorMessage } from "openclaw/plugin-sdk/error-runtime";
26
22
  import { resolveMarkdownTableMode } from "openclaw/plugin-sdk/markdown-table-runtime";
27
23
  import { convertMarkdownTables, stripInlineDirectiveTagsForDelivery, stripReasoningTagsFromText } from "openclaw/plugin-sdk/text-chunking";
28
24
  import { createChannelMessageReplyPipeline, defineFinalizableLivePreviewAdapter, deliverWithFinalizableLivePreviewAdapter, resolveChannelMessageSourceReplyDeliveryMode } from "openclaw/plugin-sdk/channel-message";
29
- import { buildChannelProgressDraftLine, buildChannelProgressDraftLineForEntry, createChannelProgressDraftGate, formatChannelProgressDraftText, isChannelProgressDraftWorkToolName, resolveChannelProgressDraftMaxLines, resolveChannelStreamingBlockEnabled, resolveChannelStreamingPreviewChunk, resolveChannelStreamingPreviewToolProgress, resolveChannelStreamingSuppressDefaultToolProgressMessages } from "openclaw/plugin-sdk/channel-streaming";
25
+ import { buildChannelProgressDraftLine, buildChannelProgressDraftLineForEntry, createChannelProgressDraftGate, formatChannelProgressDraftText, isChannelProgressDraftWorkToolName, mergeChannelProgressDraftLine, normalizeChannelProgressDraftLineIdentity, resolveChannelProgressDraftMaxLines, resolveChannelStreamingBlockEnabled, resolveChannelStreamingPreviewChunk, resolveChannelStreamingPreviewToolProgress, resolveChannelStreamingSuppressDefaultToolProgressMessages } from "openclaw/plugin-sdk/channel-streaming";
30
26
  import { recordInboundSession, resolvePinnedMainDmOwnerFromAllowlist } from "openclaw/plugin-sdk/conversation-runtime";
31
27
  import { EmbeddedBlockChunker, formatReasoningMessage, resolveAckReaction, resolveHumanDelayConfig } from "openclaw/plugin-sdk/agent-runtime";
32
28
  import { truncateUtf16Safe } from "openclaw/plugin-sdk/text-utility-runtime";
@@ -35,7 +31,7 @@ import { readSessionUpdatedAt, resolveStorePath } from "openclaw/plugin-sdk/sess
35
31
  import { formatInboundEnvelope, resolveEnvelopeFormatOptions } from "openclaw/plugin-sdk/channel-inbound";
36
32
  import { createFinalizableDraftLifecycle } from "openclaw/plugin-sdk/channel-lifecycle";
37
33
  import { finalizeInboundContext } from "openclaw/plugin-sdk/reply-dispatch-runtime";
38
- import { hasFinalInboundReplyDispatch, runInboundReplyTurn } from "openclaw/plugin-sdk/inbound-reply-dispatch";
34
+ import { hasFinalInboundReplyDispatch, recordChannelBotPairLoopAndCheckSuppression, runInboundReplyTurn } from "openclaw/plugin-sdk/inbound-reply-dispatch";
39
35
  import { buildPendingHistoryContextFromMap } from "openclaw/plugin-sdk/reply-history";
40
36
  import { DEFAULT_TIMING, createStatusReactionController, logAckFailure, logTypingFailure, shouldAckReaction } from "openclaw/plugin-sdk/channel-feedback";
41
37
  import { resolveChannelContextVisibilityMode } from "openclaw/plugin-sdk/context-visibility-runtime";
@@ -310,6 +306,12 @@ async function buildDiscordMessageProcessContext(params) {
310
306
  ...mediaPayload,
311
307
  ...preflightAudioIndex >= 0 ? { MediaTranscribedIndexes: [preflightAudioIndex] } : {},
312
308
  CommandAuthorized: commandAuthorized,
309
+ CommandTurn: {
310
+ kind: "text-slash",
311
+ source: "text",
312
+ authorized: commandAuthorized,
313
+ body: preflightAudioTranscript ?? baseText
314
+ },
313
315
  CommandSource: "text",
314
316
  OriginatingChannel: "discord",
315
317
  OriginatingTo: originatingTo
@@ -489,7 +491,7 @@ function createDiscordDraftPreviewController(params) {
489
491
  let draftText = "";
490
492
  let hasStreamedMessage = false;
491
493
  let finalizedViaPreviewMessage = false;
492
- let finalDeliveryHandled = false;
494
+ let finalReplyDelivered = false;
493
495
  const previewToolProgressEnabled = Boolean(draftStream) && resolveChannelStreamingPreviewToolProgress(params.discordConfig);
494
496
  const suppressDefaultToolProgressMessages = Boolean(draftStream) && resolveChannelStreamingSuppressDefaultToolProgressMessages(params.discordConfig, {
495
497
  draftStreamActive: true,
@@ -545,8 +547,8 @@ function createDiscordDraftPreviewController(params) {
545
547
  get finalizedViaPreviewMessage() {
546
548
  return finalizedViaPreviewMessage;
547
549
  },
548
- markFinalDeliveryHandled() {
549
- finalDeliveryHandled = true;
550
+ markFinalReplyDelivered() {
551
+ finalReplyDelivered = true;
550
552
  },
551
553
  markPreviewFinalized() {
552
554
  finalizedViaPreviewMessage = true;
@@ -560,13 +562,14 @@ function createDiscordDraftPreviewController(params) {
560
562
  if (!draftStream) return;
561
563
  if (options?.toolName !== void 0 && !isChannelProgressDraftWorkToolName(options.toolName)) return;
562
564
  if (isEmptyDiscordProgressLine(line)) return;
563
- const normalized = normalizeProgressLineIdentity(line);
565
+ const normalized = normalizeChannelProgressDraftLineIdentity(line);
564
566
  if (!normalized) return;
565
567
  const progressLine = typeof line === "object" && line !== void 0 ? line : normalized;
566
568
  if (discordStreamMode !== "progress") {
567
569
  if (!previewToolProgressEnabled || previewToolProgressSuppressed) return;
568
- if (normalizeProgressLineIdentity(previewToolProgressLines.at(-1)) === normalized) return;
569
- previewToolProgressLines = [...previewToolProgressLines, progressLine].slice(-resolveChannelProgressDraftMaxLines(params.discordConfig));
570
+ const nextLines = mergeChannelProgressDraftLine(previewToolProgressLines, progressLine, { maxLines: resolveChannelProgressDraftMaxLines(params.discordConfig) });
571
+ if (nextLines === previewToolProgressLines) return;
572
+ previewToolProgressLines = nextLines;
570
573
  const previewText = formatChannelProgressDraftText({
571
574
  entry: params.discordConfig,
572
575
  lines: previewToolProgressLines,
@@ -579,9 +582,7 @@ function createDiscordDraftPreviewController(params) {
579
582
  draftStream.update(previewText);
580
583
  return;
581
584
  }
582
- if (previewToolProgressEnabled && !previewToolProgressSuppressed && normalized) {
583
- if (normalizeProgressLineIdentity(previewToolProgressLines.at(-1)) !== normalized) previewToolProgressLines = [...previewToolProgressLines, progressLine].slice(-resolveChannelProgressDraftMaxLines(params.discordConfig));
584
- }
585
+ if (previewToolProgressEnabled && !previewToolProgressSuppressed && normalized) previewToolProgressLines = mergeChannelProgressDraftLine(previewToolProgressLines, progressLine, { maxLines: resolveChannelProgressDraftMaxLines(params.discordConfig) });
585
586
  const alreadyStarted = progressDraftGate.hasStarted;
586
587
  if (shouldStartDiscordProgressDraftNow(line)) await progressDraftGate.startNow();
587
588
  else await progressDraftGate.noteWork();
@@ -681,8 +682,8 @@ function createDiscordDraftPreviewController(params) {
681
682
  async cleanup() {
682
683
  try {
683
684
  progressDraftGate.cancel();
684
- if (!finalDeliveryHandled) await draftStream?.discardPending();
685
- if (!finalDeliveryHandled && !finalizedViaPreviewMessage && draftStream?.messageId()) await draftStream.clear();
685
+ if (!finalReplyDelivered) await draftStream?.discardPending();
686
+ if (!finalReplyDelivered && !finalizedViaPreviewMessage && draftStream?.messageId()) await draftStream.clear();
686
687
  } catch (err) {
687
688
  params.log(`discord: draft cleanup failed: ${String(err)}`);
688
689
  }
@@ -703,9 +704,6 @@ function mergeReasoningProgressText(current, incoming) {
703
704
  function isReasoningSnapshotText(text) {
704
705
  return /^\s*(?:>\s*)?Reasoning:\s*/i.test(text);
705
706
  }
706
- function normalizeProgressLineIdentity(line) {
707
- return (typeof line === "string" ? line : line?.text)?.replace(/\s+/g, " ").trim() ?? "";
708
- }
709
707
  function isEmptyDiscordProgressLine(line) {
710
708
  if (!line || typeof line === "string") return false;
711
709
  return line.toolName === "apply_patch" && !line.detail && !line.status;
@@ -741,8 +739,15 @@ function readToolBooleanArg(args, key) {
741
739
  return args[key] === true;
742
740
  }
743
741
  async function processDiscordMessage(ctx, observer) {
744
- const { cfg, discordConfig, accountId, token, runtime, guildHistories, historyLimit, mediaMaxBytes, textLimit, replyToMode, ackReactionScope, message, messageChannelId, isGuildMessage, isDirectMessage, isGroupDm, messageText, shouldRequireMention, canDetectMention, effectiveWasMentioned, shouldBypassMention, channelConfig, threadBindings, route, discordRestFetch, abortSignal } = ctx;
742
+ const { cfg, discordConfig, accountId, token, runtime, guildHistories, historyLimit, mediaMaxBytes, textLimit, replyToMode, ackReactionScope, message, messageChannelId, isGuildMessage, isDirectMessage, isGroupDm, messageText, shouldRequireMention, canDetectMention, effectiveWasMentioned, shouldBypassMention, channelConfig, threadBindings, route, discordRestFetch, abortSignal, botLoopProtection } = ctx;
745
743
  if (isProcessAborted(abortSignal)) return;
744
+ if (botLoopProtection) {
745
+ const botLoopResult = recordChannelBotPairLoopAndCheckSuppression(botLoopProtection);
746
+ if (botLoopResult.suppressed) {
747
+ logVerbose(`discord: bot-to-bot loop detected before dispatch setup, suppressing for ${Math.max(0, Math.ceil((botLoopResult.cooldownUntilMs - Date.now()) / 1e3))}s`);
748
+ return;
749
+ }
750
+ }
746
751
  const mediaResolveOptions = {
747
752
  fetchImpl: discordRestFetch,
748
753
  ssrfPolicy: cfg.browser?.ssrfPolicy,
@@ -967,7 +972,6 @@ async function processDiscordMessage(ctx, observer) {
967
972
  if (!resolveSendableOutboundReplyParts(payload).hasMedia && !payload.isError) return;
968
973
  }
969
974
  if (draftStream && isFinal && (!draftPreview.isProgressMode || draftPreview.hasProgressDraftStarted)) {
970
- draftPreview.markFinalDeliveryHandled();
971
975
  const hasMedia = resolveSendableOutboundReplyParts(payload).hasMedia;
972
976
  const finalText = payload.text;
973
977
  const previewFinalText = draftPreview.resolvePreviewFinalText(finalText);
@@ -997,6 +1001,7 @@ async function processDiscordMessage(ctx, observer) {
997
1001
  });
998
1002
  },
999
1003
  onPreviewFinalized: () => {
1004
+ draftPreview.markFinalReplyDelivered();
1000
1005
  draftPreview.markPreviewFinalized();
1001
1006
  replyReference.markSent();
1002
1007
  observer?.onFinalReplyDelivered?.();
@@ -1027,9 +1032,12 @@ async function processDiscordMessage(ctx, observer) {
1027
1032
  threadBindings,
1028
1033
  mediaLocalRoots
1029
1034
  });
1035
+ return true;
1036
+ },
1037
+ onNormalDelivered: () => {
1038
+ draftPreview.markFinalReplyDelivered();
1030
1039
  replyReference.markSent();
1031
1040
  observer?.onFinalReplyDelivered?.();
1032
- return true;
1033
1041
  }
1034
1042
  })).kind !== "normal-skipped") return;
1035
1043
  }
@@ -1155,6 +1163,7 @@ async function processDiscordMessage(ctx, observer) {
1155
1163
  onItemEvent: async (payload) => {
1156
1164
  await draftPreview.pushToolProgress(buildChannelProgressDraftLineForEntry(discordConfig, {
1157
1165
  event: "item",
1166
+ itemId: payload.itemId,
1158
1167
  itemKind: payload.kind,
1159
1168
  title: payload.title,
1160
1169
  name: payload.name,
@@ -1,8 +1,8 @@
1
- import { n as resolveDiscordChannelInfoSafe } from "./channel-access-BL-wemES.js";
2
- import { a as mergeAbortSignals } from "./timeouts-C3FYXWJX.js";
1
+ import { u as resolveDiscordChannelInfoSafe } from "./thread-bindings.discord-api-DJACBZJ1.js";
2
+ import { a as mergeAbortSignals } from "./timeouts-snXNwR4m.js";
3
3
  import { normalizeLowercaseStringOrEmpty, normalizeOptionalString, normalizeOptionalStringifiedId } from "openclaw/plugin-sdk/string-coerce-runtime";
4
4
  import { ComponentType, StickerFormatType } from "discord-api-types/v10";
5
- import { fetchRemoteMedia, saveMediaBuffer } from "openclaw/plugin-sdk/media-runtime";
5
+ import { saveRemoteMedia } from "openclaw/plugin-sdk/media-runtime";
6
6
  import { buildMediaPayload } from "openclaw/plugin-sdk/reply-payload";
7
7
  import { logVerbose } from "openclaw/plugin-sdk/runtime-env";
8
8
  import { getFileExtension } from "openclaw/plugin-sdk/media-mime";
@@ -236,20 +236,22 @@ async function fetchDiscordMedia(params) {
236
236
  const signal = mergeAbortSignals([params.abortSignal, timeoutAbortController?.signal]);
237
237
  let timedOut = false;
238
238
  let timeoutHandle = null;
239
- const fetchPromise = fetchRemoteMedia({
239
+ const savePromise = saveRemoteMedia({
240
240
  url: params.url,
241
241
  filePathHint: params.filePathHint,
242
242
  maxBytes: params.maxBytes,
243
243
  fetchImpl: params.fetchImpl,
244
244
  ssrfPolicy: params.ssrfPolicy,
245
245
  readIdleTimeoutMs: params.readIdleTimeoutMs,
246
+ fallbackContentType: params.fallbackContentType,
247
+ originalFilename: params.originalFilename,
246
248
  ...signal ? { requestInit: { signal } } : {}
247
249
  }).catch((error) => {
248
250
  if (timedOut) return new Promise(() => {});
249
251
  throw error;
250
252
  });
251
253
  try {
252
- if (!params.totalTimeoutMs) return await fetchPromise;
254
+ if (!params.totalTimeoutMs) return await savePromise;
253
255
  const timeoutPromise = new Promise((_, reject) => {
254
256
  timeoutHandle = setTimeout(() => {
255
257
  timedOut = true;
@@ -258,7 +260,7 @@ async function fetchDiscordMedia(params) {
258
260
  }, params.totalTimeoutMs);
259
261
  timeoutHandle.unref?.();
260
262
  });
261
- return await Promise.race([fetchPromise, timeoutPromise]);
263
+ return await Promise.race([savePromise, timeoutPromise]);
262
264
  } finally {
263
265
  if (timeoutHandle) clearTimeout(timeoutHandle);
264
266
  }
@@ -273,7 +275,7 @@ async function appendResolvedMediaFromAttachments(params) {
273
275
  continue;
274
276
  }
275
277
  try {
276
- const fetched = await fetchDiscordMedia({
278
+ const saved = await fetchDiscordMedia({
277
279
  url: attachmentUrl,
278
280
  filePathHint: attachment.filename ?? attachmentUrl,
279
281
  maxBytes: params.maxBytes,
@@ -281,9 +283,10 @@ async function appendResolvedMediaFromAttachments(params) {
281
283
  ssrfPolicy: params.ssrfPolicy,
282
284
  readIdleTimeoutMs: params.readIdleTimeoutMs,
283
285
  totalTimeoutMs: params.totalTimeoutMs,
284
- abortSignal: params.abortSignal
286
+ abortSignal: params.abortSignal,
287
+ fallbackContentType: attachment.content_type,
288
+ originalFilename: attachment.filename
285
289
  });
286
- const saved = await saveMediaBuffer(fetched.buffer, fetched.contentType ?? attachment.content_type, "inbound", params.maxBytes, attachment.filename);
287
290
  params.out.push({
288
291
  path: saved.path,
289
292
  contentType: saved.contentType,
@@ -347,7 +350,7 @@ async function appendResolvedMediaFromStickers(params) {
347
350
  const candidates = resolveStickerAssetCandidates(sticker);
348
351
  let lastError;
349
352
  for (const candidate of candidates) try {
350
- const fetched = await fetchDiscordMedia({
353
+ const saved = await fetchDiscordMedia({
351
354
  url: candidate.url,
352
355
  filePathHint: candidate.fileName,
353
356
  maxBytes: params.maxBytes,
@@ -355,9 +358,10 @@ async function appendResolvedMediaFromStickers(params) {
355
358
  ssrfPolicy: params.ssrfPolicy,
356
359
  readIdleTimeoutMs: params.readIdleTimeoutMs,
357
360
  totalTimeoutMs: params.totalTimeoutMs,
358
- abortSignal: params.abortSignal
361
+ abortSignal: params.abortSignal,
362
+ fallbackContentType: inferStickerContentType(sticker),
363
+ originalFilename: candidate.fileName
359
364
  });
360
- const saved = await saveMediaBuffer(fetched.buffer, fetched.contentType, "inbound", params.maxBytes, candidate.fileName);
361
365
  params.out.push({
362
366
  path: saved.path,
363
367
  contentType: saved.contentType,
@@ -1,9 +1,6 @@
1
- import { h as DiscordError } from "./discord-BqYcwxvG.js";
2
- import { s as resolveDiscordAccount } from "./accounts-BcwyaFd-.js";
3
- import { t as chunkDiscordTextWithMode } from "./chunk-DYl-_5RL.js";
4
- import { i as normalizeDiscordOutboundTarget } from "./normalize-Cu94FOqy.js";
5
- import { t as createDiscordSendReceipt } from "./send.receipt-BAZw2Zsz.js";
6
- import { c as readDiscordComponentSpec } from "./components-Dxq2mU57.js";
1
+ import { S as DiscordError, o as normalizeDiscordOutboundTarget, s as chunkDiscordTextWithMode, t as createDiscordSendReceipt } from "./send.receipt-nKLxvA1s.js";
2
+ import { s as resolveDiscordAccount } from "./accounts-DnNVBDfc.js";
3
+ import { d as readDiscordComponentSpec } from "./components-Cgm7XT8-.js";
7
4
  import { normalizeLowercaseStringOrEmpty, normalizeOptionalString, normalizeOptionalStringifiedId } from "openclaw/plugin-sdk/string-coerce-runtime";
8
5
  import { resolvePayloadMediaUrls, sendPayloadMediaSequenceOrFallback, sendTextMediaPayload } from "openclaw/plugin-sdk/reply-payload";
9
6
  import { resolveRetryConfig, retryAsync } from "openclaw/plugin-sdk/retry-runtime";
@@ -87,11 +84,11 @@ function normalizeDiscordApprovalPayload(payload) {
87
84
  let discordComponentSendPromise;
88
85
  let discordSharedInteractivePromise;
89
86
  async function sendDiscordComponentMessageLazy(...args) {
90
- discordComponentSendPromise ??= import("./send.components-DxDqPJZQ.js").then((n) => n.i).then((module) => module.sendDiscordComponentMessage);
87
+ discordComponentSendPromise ??= import("./send.components-D6pXHVrU.js").then((n) => n.i).then((module) => module.sendDiscordComponentMessage);
91
88
  return await (await discordComponentSendPromise)(...args);
92
89
  }
93
90
  function loadDiscordSharedInteractive() {
94
- discordSharedInteractivePromise ??= import("./shared-interactive-DavY6jYt.js").then((n) => n.r);
91
+ discordSharedInteractivePromise ??= import("./components-Cgm7XT8-.js").then((n) => n.a);
95
92
  return discordSharedInteractivePromise;
96
93
  }
97
94
  function addPayloadTextFallback(spec, payload) {
@@ -126,7 +123,7 @@ async function resolveDiscordComponentSpec(payload) {
126
123
  //#region extensions/discord/src/outbound-send-context.ts
127
124
  let discordSendRuntimePromise;
128
125
  async function loadDiscordSendRuntime() {
129
- discordSendRuntimePromise ??= import("./send-DCFuSiBi.js").then((n) => n.t);
126
+ discordSendRuntimePromise ??= import("./send-BqzTEkt9.js").then((n) => n.t);
130
127
  return await discordSendRuntimePromise;
131
128
  }
132
129
  function resolveDiscordOutboundTarget(params) {
@@ -316,7 +313,7 @@ function stripDiscordInternalRuntimeScaffolding(text) {
316
313
  }
317
314
  let discordThreadBindingsPromise;
318
315
  function loadDiscordThreadBindings() {
319
- discordThreadBindingsPromise ??= import("./thread-bindings-B4of4OmR.js").then((n) => n.t);
316
+ discordThreadBindingsPromise ??= import("./thread-bindings-C1f7Iim4.js").then((n) => n.t);
320
317
  return discordThreadBindingsPromise;
321
318
  }
322
319
  function resolveDiscordWebhookIdentity(params) {
@@ -1,4 +1,4 @@
1
- import { Ft as __exportAll } from "./discord-BqYcwxvG.js";
1
+ import { Wt as __exportAll } from "./send.receipt-nKLxvA1s.js";
2
2
  import { resolveFetch } from "openclaw/plugin-sdk/fetch-runtime";
3
3
  //#region extensions/discord/src/pluralkit.ts
4
4
  var pluralkit_exports = /* @__PURE__ */ __exportAll({ fetchPluralKitMessageInfo: () => fetchPluralKitMessageInfo });
@@ -4,7 +4,7 @@ import { getFileExtension } from "openclaw/plugin-sdk/media-mime";
4
4
  //#region extensions/discord/src/monitor/preflight-audio.ts
5
5
  let discordPreflightAudioRuntimePromise;
6
6
  function loadDiscordPreflightAudioRuntime() {
7
- discordPreflightAudioRuntimePromise ??= import("./preflight-audio.runtime-fXnUxxBa.js");
7
+ discordPreflightAudioRuntimePromise ??= import("./preflight-audio.runtime-Drc-OFcp.js");
8
8
  return discordPreflightAudioRuntimePromise;
9
9
  }
10
10
  const AUDIO_ATTACHMENT_MIME_BY_EXT = new Map([
@@ -1,5 +1,5 @@
1
- import { t as normalizeDiscordToken } from "./token-BZtonk7d.js";
2
- import { n as fetchDiscord, t as DiscordApiError } from "./api-DzNBVTto.js";
1
+ import { p as normalizeDiscordToken } from "./accounts-DnNVBDfc.js";
2
+ import { n as fetchDiscord, t as DiscordApiError } from "./api-DgQLz1wq.js";
3
3
  import { resolveFetch } from "openclaw/plugin-sdk/fetch-runtime";
4
4
  import { formatErrorMessage } from "openclaw/plugin-sdk/error-runtime";
5
5
  import { fetchWithTimeout } from "openclaw/plugin-sdk/text-utility-runtime";
@@ -1,2 +1,2 @@
1
- import { a as resolveDiscordPrivilegedIntentsFromFlags, i as probeDiscord, n as fetchDiscordApplicationSummary, r as parseApplicationIdFromToken, t as fetchDiscordApplicationId } from "./probe-BZtr8qle.js";
1
+ import { a as resolveDiscordPrivilegedIntentsFromFlags, i as probeDiscord, n as fetchDiscordApplicationSummary, r as parseApplicationIdFromToken, t as fetchDiscordApplicationId } from "./probe-CiBYm-vD.js";
2
2
  export { fetchDiscordApplicationId, fetchDiscordApplicationSummary, parseApplicationIdFromToken, probeDiscord, resolveDiscordPrivilegedIntentsFromFlags };