@openclaw/discord 2026.5.19 → 2026.5.20-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 (99) hide show
  1. package/dist/{account-inspect-DCXwNu_u.js → account-inspect-CcJ-bl80.js} +1 -1
  2. package/dist/account-inspect-api.js +1 -1
  3. package/dist/action-runtime-api.js +1 -1
  4. package/dist/api.js +19 -19
  5. package/dist/{approval-handler.runtime-CRpNixJy.js → approval-handler.runtime-hi6B0JCi.js} +4 -4
  6. package/dist/{audit-DEF10R9j.js → audit-DJIvRRzY.js} +5 -5
  7. package/dist/{channel-CR9HckAC.js → channel-BswuOAN6.js} +22 -22
  8. package/dist/{channel-actions-CpmPx9PW.js → channel-actions-CSepY2Kq.js} +5 -5
  9. package/dist/{channel-actions.runtime-Be5OvB1r.js → channel-actions.runtime-CSjcHZNT.js} +6 -6
  10. package/dist/channel-config-api.js +1 -1
  11. package/dist/channel-plugin-api.js +1 -1
  12. package/dist/{channel.setup-DR3-U0wF.js → channel.setup-C0rcLtB9.js} +4 -4
  13. package/dist/{components-q41bHoCx.js → components-DDPGekgY.js} +1 -1
  14. package/dist/{config-schema-jz2FX2x5.js → config-schema-BGgg8U6A.js} +13 -1
  15. package/dist/contract-api.js +7 -7
  16. package/dist/{conversation-identity-BY7sjUQh.js → conversation-identity-CAyt5wzy.js} +3 -3
  17. package/dist/{directory-config-x3YzNdoX.js → directory-config-BcWtq4k8.js} +2 -2
  18. package/dist/directory-contract-api.js +1 -1
  19. package/dist/{directory-live-CJiEWQwK.js → directory-live-5HHCCe5Q.js} +4 -4
  20. package/dist/{doctor-CzcS8Yt1.js → doctor-BLcVWv42.js} +5 -5
  21. package/dist/{doctor-contract-AkgUZQHW.js → doctor-contract-Bia3BmP_.js} +1 -1
  22. package/dist/doctor-contract-api.js +1 -1
  23. package/dist/{handle-action.guild-admin-kAzbjGMw.js → handle-action.guild-admin-DX2D9qkG.js} +1 -1
  24. package/dist/{inbound-context-CzEAvKgx.js → inbound-context-B5EsqsSr.js} +1 -1
  25. package/dist/{manager.runtime-CGcJ0yjq.js → manager.runtime-Dq0mc5K0.js} +364 -22
  26. package/dist/{message-handler-1NV0WiHC.js → message-handler-wQJd4Peh.js} +7 -7
  27. package/dist/{message-handler.preflight-DQ-oPY7m.js → message-handler.preflight-ANdoLbtA.js} +16 -18
  28. package/dist/{message-handler.process-PpgZ0qC4.js → message-handler.process-DG4qm0sQ.js} +27 -16
  29. package/dist/{message-utils-BKrlzFtM.js → message-utils-Bw-wDr8G.js} +2 -2
  30. package/dist/{outbound-adapter-CaZzpMnE.js → outbound-adapter-TGbHliO_.js} +8 -8
  31. package/dist/{pluralkit-BnCH6cHK.js → pluralkit-sQLfeyIZ.js} +1 -1
  32. package/dist/{preflight-audio-B0keJeQe.js → preflight-audio-ClWbnQto.js} +1 -1
  33. package/dist/{probe-BLDNbk41.js → probe-CRWV5COl.js} +2 -2
  34. package/dist/{probe.runtime-DKB38YvU.js → probe.runtime-h9mEzmMs.js} +1 -1
  35. package/dist/{provider-BZtjA1y_.js → provider-CzKMDsSE.js} +45 -64
  36. package/dist/{provider-session.runtime-DVfzQxFH.js → provider-session.runtime-D0XbJS5X.js} +3 -3
  37. package/dist/provider.runtime-CUUefRl3.js +2 -0
  38. package/dist/{resolve-allowlist-common-C8L5MYFl.js → resolve-allowlist-common-Bec0FONA.js} +3 -3
  39. package/dist/{resolve-channels-Czrd7fOv.js → resolve-channels-DcWaMURg.js} +4 -4
  40. package/dist/{resolve-users-D7hQMaaq.js → resolve-users-TQPLKDeV.js} +3 -3
  41. package/dist/{runtime-BJUWt4mA.js → runtime-DP_0_5a0.js} +9 -9
  42. package/dist/runtime-api.actions.js +2 -2
  43. package/dist/runtime-api.js +25 -25
  44. package/dist/runtime-api.lookup.js +6 -6
  45. package/dist/runtime-api.monitor-D1psRR2u.js +5 -0
  46. package/dist/runtime-api.monitor.js +7 -7
  47. package/dist/runtime-api.send.js +5 -5
  48. package/dist/runtime-api.threads.js +5 -5
  49. package/dist/runtime-setter-api.js +1 -1
  50. package/dist/secret-contract-api.js +1 -1
  51. package/dist/{security-audit-Dx3j4a0l.js → security-audit-C_fzlczo.js} +1 -1
  52. package/dist/security-audit-contract-api.js +1 -1
  53. package/dist/{security-audit.runtime-C5nnf0k8.js → security-audit.runtime-Dt4zoGpL.js} +1 -1
  54. package/dist/security-contract-api.js +1 -1
  55. package/dist/{send-BsBy21Te.js → send-CEAtV0qd.js} +5 -6
  56. package/dist/{send.components-BuZBJysI.js → send.components-sY6aQV0K.js} +8 -8
  57. package/dist/{send.outbound-C0OzZAv_.js → send.outbound-1vG9pOh2.js} +4 -4
  58. package/dist/{send.shared-C6JLgsbp.js → send.shared-D4clao4K.js} +3 -3
  59. package/dist/{sender-identity-DC0FdEcU.js → sender-identity-BFp5w0F8.js} +1 -1
  60. package/dist/session-key-api.js +1 -1
  61. package/dist/setup-plugin-api.js +1 -1
  62. package/dist/{shared-CYe5A_Bs.js → shared-mo-r7V5W.js} +10 -10
  63. package/dist/{subagent-hooks-DCIt8Gt7.js → subagent-hooks-D65kqOor.js} +3 -3
  64. package/dist/subagent-hooks-api.js +1 -1
  65. package/dist/{system-events-DEuiLTl9.js → system-events-HgHeiMHg.js} +2 -2
  66. package/dist/{target-resolver-C5tK3vit.js → target-resolver-BpGdnBIZ.js} +3 -3
  67. package/dist/targets-DMdVjHOU.js +3 -0
  68. package/dist/test-api.js +4 -4
  69. package/dist/{thread-bindings-BcXgbZ3-.js → thread-bindings-BQz8z6MR.js} +6 -6
  70. package/dist/{thread-bindings.discord-api-BzelVdsY.js → thread-bindings.discord-api-Ddalj9wo.js} +5 -5
  71. package/dist/{thread-bindings.manager-CouT_qjE.js → thread-bindings.manager-I5f-Oykv.js} +4 -4
  72. package/dist/{thread-bindings.session-updates-CgOqEOPe.js → thread-bindings.session-updates-D5gY2ZTE.js} +1 -1
  73. package/dist/timeouts.js +1 -1
  74. package/dist/{typing-DtdZgo-g.js → typing-DUUjLsPr.js} +2 -2
  75. package/openclaw.plugin.json +72 -2
  76. package/package.json +4 -4
  77. package/dist/provider.runtime-DlegJeN5.js +0 -2
  78. package/dist/runtime-api.monitor-BlxEnLN_.js +0 -5
  79. package/dist/targets-JvlTzyfK.js +0 -3
  80. /package/dist/{accounts-ltxKLzxN.js → accounts-C2TOAmpo.js} +0 -0
  81. /package/dist/{agent-components.runtime-BIemD2Iz.js → agent-components.runtime-CEPrf2SY.js} +0 -0
  82. /package/dist/{allow-list-CBI-M84K.js → allow-list-BnkWtVpA.js} +0 -0
  83. /package/dist/{api-DgQLz1wq.js → api-Kq7vtaSO.js} +0 -0
  84. /package/dist/{audit-core-DRyoXREU.js → audit-core-xwjIczO0.js} +0 -0
  85. /package/dist/{channel-api-JudoSiJv.js → channel-api-CAJ0wMoV.js} +0 -0
  86. /package/dist/{config-api-oLS_52S7.js → config-api-JiPdJeb0.js} +0 -0
  87. /package/dist/{gateway-registry-BKSpa4GB.js → gateway-registry-DPxmW0Db.js} +0 -0
  88. /package/dist/{inbound-event-delivery-D8zHG9Lz.js → inbound-event-delivery-DTGIjZVJ.js} +0 -0
  89. /package/dist/{preflight-audio.runtime-DT1Hmhsq.js → preflight-audio.runtime-CoCXMM8r.js} +0 -0
  90. /package/dist/{preview-streaming-nClS_TQx.js → preview-streaming-CQ7PsV9J.js} +0 -0
  91. /package/dist/{runtime-Tqtvj5GX.js → runtime-DgnVQ7zW.js} +0 -0
  92. /package/dist/{secret-config-contract-57_WV6qt.js → secret-config-contract-BjM-1hr9.js} +0 -0
  93. /package/dist/{security-contract-BWDASKVo.js → security-contract-DSHk7I2w.js} +0 -0
  94. /package/dist/{security-doctor-DepqtNCI.js → security-doctor-uUo8hTD5.js} +0 -0
  95. /package/dist/{send.receipt-Dhym-qOF.js → send.receipt-spSPAC77.js} +0 -0
  96. /package/dist/{session-contract-Dwhw3RTY.js → session-contract-BO5tlIdl.js} +0 -0
  97. /package/dist/{session-key-normalization-DnCXUKGA.js → session-key-normalization-wJgsKPNF.js} +0 -0
  98. /package/dist/{thread-bindings.state-CSphZOiL.js → thread-bindings.state-BsOnj5NX.js} +0 -0
  99. /package/dist/{timeouts-CEwuGaWT.js → timeouts-l_PsHQvX.js} +0 -0
@@ -1,10 +1,10 @@
1
- import { Ht as parseDiscordTarget, _ as VoiceStateUpdateListener, c as discord_exports, h as ResumedListener, m as ReadyListener } from "./send.receipt-Dhym-qOF.js";
2
- import { c as resolveDiscordAccountAllowFrom } from "./accounts-ltxKLzxN.js";
3
- import { a as normalizeDiscordSlug, b as formatDiscordUserTag, m as resolveDiscordOwnerAccess } from "./allow-list-CBI-M84K.js";
4
- import { i as formatMention } from "./send.outbound-C0OzZAv_.js";
5
- import { t as getDiscordRuntime } from "./runtime-Tqtvj5GX.js";
6
- import { o as authorizeDiscordVoiceIngress, u as resolveDiscordVoiceEnabled } from "./provider-BZtjA1y_.js";
7
- import { t as buildDiscordGroupSystemPrompt } from "./inbound-context-CzEAvKgx.js";
1
+ import { Ht as parseDiscordTarget, _ as VoiceStateUpdateListener, c as discord_exports, h as ResumedListener, jt as getGuildVoiceState, m as ReadyListener } from "./send.receipt-spSPAC77.js";
2
+ import { c as resolveDiscordAccountAllowFrom } from "./accounts-C2TOAmpo.js";
3
+ import { a as normalizeDiscordSlug, b as formatDiscordUserTag, m as resolveDiscordOwnerAccess } from "./allow-list-BnkWtVpA.js";
4
+ import { i as formatMention } from "./send.outbound-1vG9pOh2.js";
5
+ import { t as getDiscordRuntime } from "./runtime-DgnVQ7zW.js";
6
+ import { o as authorizeDiscordVoiceIngress, u as resolveDiscordVoiceEnabled } from "./provider-CzKMDsSE.js";
7
+ import { t as buildDiscordGroupSystemPrompt } from "./inbound-context-B5EsqsSr.js";
8
8
  import { createRequire } from "node:module";
9
9
  import { normalizeOptionalString } from "openclaw/plugin-sdk/string-coerce-runtime";
10
10
  import { resolveAgentRoute } from "openclaw/plugin-sdk/routing";
@@ -17,6 +17,7 @@ import { formatErrorMessage } from "openclaw/plugin-sdk/ssrf-runtime";
17
17
  import { agentCommandFromIngress, getTtsProvider, resolveAgentDir, resolveTtsConfig, resolveTtsPrefsPath } from "openclaw/plugin-sdk/agent-runtime";
18
18
  import { escapeRegExp } from "openclaw/plugin-sdk/text-utility-runtime";
19
19
  import { REALTIME_VOICE_AGENT_CONSULT_TOOL_NAME, REALTIME_VOICE_AUDIO_FORMAT_PCM16_24KHZ, buildRealtimeVoiceAgentConsultChatMessage, buildRealtimeVoiceAgentConsultPolicyInstructions, buildRealtimeVoiceAgentConsultWorkingResponse, createRealtimeVoiceAgentTalkbackQueue, createRealtimeVoiceBridgeSession, resamplePcm, resolveConfiguredRealtimeVoiceProvider, resolveRealtimeVoiceAgentConsultToolPolicy, resolveRealtimeVoiceAgentConsultTools, resolveRealtimeVoiceAgentConsultToolsAllow } from "openclaw/plugin-sdk/realtime-voice";
20
+ import { resolveRealtimeBootstrapContextInstructions } from "openclaw/plugin-sdk/realtime-bootstrap-context";
20
21
  import { PassThrough, Readable } from "node:stream";
21
22
  import { parseTtsDirectives } from "openclaw/plugin-sdk/speech";
22
23
  //#region extensions/discord/src/voice/audio.ts
@@ -148,7 +149,6 @@ function convertRealtimePcm24kMonoToDiscordPcm48kStereo(pcm) {
148
149
  }
149
150
  function estimateDurationSeconds(pcm) {
150
151
  const bytesPerSample = BIT_DEPTH / 8 * CHANNELS;
151
- if (bytesPerSample <= 0) return 0;
152
152
  return pcm.length / (bytesPerSample * SAMPLE_RATE);
153
153
  }
154
154
  async function writeVoiceWavFile(pcm) {
@@ -312,7 +312,6 @@ async function runDiscordVoiceAgentTurn(params) {
312
312
  messageChannel: "discord",
313
313
  messageProvider: "discord-voice",
314
314
  extraSystemPrompt: context.extraSystemPrompt,
315
- senderIsOwner: context.senderIsOwner,
316
315
  allowModelOverride: Boolean(voiceModel),
317
316
  model: voiceModel,
318
317
  toolsAllow: params.toolsAllow,
@@ -325,6 +324,22 @@ async function runDiscordVoiceAgentTurn(params) {
325
324
  text
326
325
  };
327
326
  }
327
+ async function resolveDiscordVoiceRealtimeBootstrapContext(params) {
328
+ const files = (params.discordConfig.voice?.realtime)?.bootstrapContextFiles;
329
+ if (files?.length === 0) return;
330
+ try {
331
+ return await resolveRealtimeBootstrapContextInstructions({
332
+ config: params.cfg,
333
+ agentId: params.entry.route.agentId,
334
+ sessionKey: params.entry.route.sessionKey,
335
+ files,
336
+ warn: (message) => logger$3.warn(`discord voice: realtime bootstrap context: ${message}`)
337
+ });
338
+ } catch (error) {
339
+ logger$3.warn(`discord voice: realtime bootstrap context unavailable: ${error instanceof Error ? error.message : String(error)}`);
340
+ return;
341
+ }
342
+ }
328
343
  //#endregion
329
344
  //#region extensions/discord/src/voice/prompt.ts
330
345
  const DISCORD_VOICE_SPOKEN_OUTPUT_CONTRACT = [
@@ -599,6 +614,7 @@ var DiscordRealtimeVoiceSession = class {
599
614
  const instructions = buildDiscordRealtimeInstructions({
600
615
  mode: this.params.mode,
601
616
  instructions: this.realtimeConfig?.instructions,
617
+ bootstrapContextInstructions: this.params.bootstrapContextInstructions,
602
618
  toolPolicy,
603
619
  consultPolicy
604
620
  });
@@ -1197,6 +1213,7 @@ function buildDiscordRealtimeInstructions(params) {
1197
1213
  const base = params.instructions ?? ["You are OpenClaw's Discord voice interface.", "Keep spoken replies concise, natural, and suitable for a live Discord voice channel."].join("\n");
1198
1214
  if (isDiscordAgentProxyVoiceMode(params.mode)) return [
1199
1215
  base,
1216
+ params.bootstrapContextInstructions?.trim(),
1200
1217
  "Mode: OpenClaw agent proxy.",
1201
1218
  "You are the realtime voice surface for the same OpenClaw agent the user can message directly.",
1202
1219
  "Do not mention a backend, supervisor, helper, or separate system. Present the result as your own work.",
@@ -1209,10 +1226,14 @@ function buildDiscordRealtimeInstructions(params) {
1209
1226
  consultPolicy: params.consultPolicy
1210
1227
  })
1211
1228
  ].join("\n\n");
1212
- return [base, buildRealtimeVoiceAgentConsultPolicyInstructions({
1213
- toolPolicy: params.toolPolicy,
1214
- consultPolicy: params.consultPolicy
1215
- })].filter(Boolean).join("\n\n");
1229
+ return [
1230
+ base,
1231
+ params.bootstrapContextInstructions?.trim(),
1232
+ buildRealtimeVoiceAgentConsultPolicyInstructions({
1233
+ toolPolicy: params.toolPolicy,
1234
+ consultPolicy: params.consultPolicy
1235
+ })
1236
+ ].filter(Boolean).join("\n\n");
1216
1237
  }
1217
1238
  //#endregion
1218
1239
  //#region extensions/discord/src/voice/receive-recovery.ts
@@ -1582,6 +1603,9 @@ var DiscordVoiceSpeakerContextResolver = class {
1582
1603
  //#region extensions/discord/src/voice/manager.ts
1583
1604
  const logger = createSubsystemLogger("discord/voice");
1584
1605
  const VOICE_LOG_PREVIEW_CHARS = 500;
1606
+ const FOLLOW_USERS_RECONCILE_INTERVAL_MS = 1e4;
1607
+ const FOLLOW_USERS_RECONCILE_MAX_GUILDS_PER_RUN = 4;
1608
+ const FOLLOW_USERS_RECONCILE_MAX_REST_LOOKUPS_PER_RUN = 32;
1585
1609
  const DISCORD_VOICE_FATAL_AUTOJOIN_ERROR_PATTERNS = [
1586
1610
  "api key missing",
1587
1611
  "incorrect api key",
@@ -1627,6 +1651,22 @@ function normalizeVoiceChannelResidencies(entries) {
1627
1651
  }
1628
1652
  return normalized;
1629
1653
  }
1654
+ function normalizeDiscordUserId(value) {
1655
+ const trimmed = value.trim();
1656
+ const withoutDiscordPrefix = trimmed.startsWith("discord:") ? trimmed.slice(8) : trimmed;
1657
+ return (withoutDiscordPrefix.startsWith("user:") ? withoutDiscordPrefix.slice(5) : withoutDiscordPrefix).trim() || void 0;
1658
+ }
1659
+ function normalizeDiscordUserIds(entries) {
1660
+ const ids = /* @__PURE__ */ new Set();
1661
+ for (const entry of entries ?? []) {
1662
+ const id = normalizeDiscordUserId(entry);
1663
+ if (id) ids.add(id);
1664
+ }
1665
+ return ids;
1666
+ }
1667
+ function resolveFollowUsersEnabled(voiceConfig) {
1668
+ return voiceConfig?.followUsersEnabled !== false;
1669
+ }
1630
1670
  function isVoiceChannelAllowed(params) {
1631
1671
  return params.allowedChannels === null || params.allowedChannels.some((entry) => entry.guildId === params.guildId && entry.channelId === params.channelId);
1632
1672
  }
@@ -1637,6 +1677,9 @@ function isFatalAutoJoinFailure(message) {
1637
1677
  const normalized = message.toLowerCase();
1638
1678
  return DISCORD_VOICE_FATAL_AUTOJOIN_ERROR_PATTERNS.some((pattern) => normalized.includes(pattern));
1639
1679
  }
1680
+ function isUnknownDiscordVoiceStateError(err) {
1681
+ return (err && typeof err === "object" && "status" in err && typeof err.status === "number" ? err.status : void 0) === 404 || /unknown voice state/i.test(formatErrorMessage(err));
1682
+ }
1640
1683
  function startAutoJoin(manager) {
1641
1684
  manager.autoJoin().catch((err) => logger.warn(`discord voice: autoJoin failed: ${formatErrorMessage(err)}`));
1642
1685
  }
@@ -1684,6 +1727,14 @@ var DiscordVoiceManager$1 = class {
1684
1727
  this.sessions = /* @__PURE__ */ new Map();
1685
1728
  this.autoJoinTask = null;
1686
1729
  this.fatalAutoJoinFailures = /* @__PURE__ */ new Map();
1730
+ this.followedUserChannels = /* @__PURE__ */ new Map();
1731
+ this.followedVoiceGuilds = /* @__PURE__ */ new Set();
1732
+ this.followUsersReconcileTimer = null;
1733
+ this.followUsersReconcileTask = null;
1734
+ this.followUsersReconcileGuildCursor = 0;
1735
+ this.followUsersReconcileBotGuildCursor = 0;
1736
+ this.followUsersReconcileUserCursors = /* @__PURE__ */ new Map();
1737
+ this.destroyed = false;
1687
1738
  this.botUserId = params.botUserId;
1688
1739
  this.voiceEnabled = resolveDiscordVoiceEnabled(params.discordConfig.voice);
1689
1740
  this.ownerAllowFrom = resolveDiscordAccountAllowFrom({
@@ -1691,6 +1742,7 @@ var DiscordVoiceManager$1 = class {
1691
1742
  accountId: params.accountId
1692
1743
  }) ?? params.discordConfig.allowFrom ?? params.discordConfig.dm?.allowFrom ?? [];
1693
1744
  this.allowedChannels = params.discordConfig.voice?.allowedChannels === void 0 ? null : normalizeVoiceChannelResidencies(params.discordConfig.voice.allowedChannels);
1745
+ this.followUserIds = resolveFollowUsersEnabled(params.discordConfig.voice) ? normalizeDiscordUserIds(params.discordConfig.voice?.followUsers) : /* @__PURE__ */ new Set();
1694
1746
  this.speakerContext = new DiscordVoiceSpeakerContextResolver({
1695
1747
  client: params.client,
1696
1748
  ownerAllowFrom: this.ownerAllowFrom
@@ -1703,7 +1755,7 @@ var DiscordVoiceManager$1 = class {
1703
1755
  return this.voiceEnabled;
1704
1756
  }
1705
1757
  async autoJoin() {
1706
- if (!this.voiceEnabled) return;
1758
+ if (!this.voiceEnabled || this.destroyed) return;
1707
1759
  if (this.autoJoinTask) return this.autoJoinTask;
1708
1760
  this.autoJoinTask = (async () => {
1709
1761
  const entries = this.params.discordConfig.voice?.autoJoin ?? [];
@@ -1747,6 +1799,8 @@ var DiscordVoiceManager$1 = class {
1747
1799
  });
1748
1800
  }
1749
1801
  }
1802
+ this.ensureFollowUsersReconcileTimer();
1803
+ await this.reconcileFollowedUsers("startup");
1750
1804
  })().finally(() => {
1751
1805
  this.autoJoinTask = null;
1752
1806
  });
@@ -1767,7 +1821,11 @@ var DiscordVoiceManager$1 = class {
1767
1821
  channelId: params.channelId.trim()
1768
1822
  });
1769
1823
  }
1770
- async join(params) {
1824
+ async join(params, options) {
1825
+ if (this.destroyed) return {
1826
+ ok: false,
1827
+ message: "Discord voice manager is stopped."
1828
+ };
1771
1829
  if (!this.voiceEnabled) return {
1772
1830
  ok: false,
1773
1831
  message: "Discord voice is disabled (channels.discord.voice.enabled)."
@@ -1803,7 +1861,7 @@ var DiscordVoiceManager$1 = class {
1803
1861
  }
1804
1862
  if (existing) {
1805
1863
  logVoiceVerbose(`join: replacing existing session for guild ${guildId}`);
1806
- await this.leave({ guildId });
1864
+ await this.leave({ guildId }, { preserveFollowState: options?.preserveFollowState });
1807
1865
  }
1808
1866
  const channelInfo = await this.params.client.fetchChannel(channelId).catch(() => null);
1809
1867
  if (!channelInfo || "type" in channelInfo && !isVoiceChannel(channelInfo.type)) return {
@@ -1942,6 +2000,11 @@ var DiscordVoiceManager$1 = class {
1942
2000
  };
1943
2001
  if (voiceMode !== "stt-tts") {
1944
2002
  entry.realtime = new DiscordRealtimeVoiceSession({
2003
+ bootstrapContextInstructions: await resolveDiscordVoiceRealtimeBootstrapContext({
2004
+ entry,
2005
+ cfg: this.params.cfg,
2006
+ discordConfig: this.params.discordConfig
2007
+ }),
1945
2008
  cfg: this.params.cfg,
1946
2009
  discordConfig: this.params.discordConfig,
1947
2010
  entry,
@@ -2022,7 +2085,7 @@ var DiscordVoiceManager$1 = class {
2022
2085
  channelId
2023
2086
  };
2024
2087
  }
2025
- async leave(params) {
2088
+ async leave(params, options) {
2026
2089
  const guildId = params.guildId.trim();
2027
2090
  logVoiceVerbose(`leave requested: guild ${guildId} channel ${params.channelId ?? "current"}`);
2028
2091
  const entry = this.sessions.get(guildId);
@@ -2036,6 +2099,10 @@ var DiscordVoiceManager$1 = class {
2036
2099
  };
2037
2100
  entry.stop();
2038
2101
  this.sessions.delete(guildId);
2102
+ if (!options?.preserveFollowState) {
2103
+ this.followedVoiceGuilds.delete(guildId);
2104
+ this.deleteFollowedUserChannelsForGuild(guildId);
2105
+ }
2039
2106
  logVoiceVerbose(`leave: disconnected from guild ${guildId} channel ${entry.channelId}`);
2040
2107
  return {
2041
2108
  ok: true,
@@ -2045,10 +2112,26 @@ var DiscordVoiceManager$1 = class {
2045
2112
  };
2046
2113
  }
2047
2114
  async handleVoiceStateUpdate(data) {
2048
- if (!this.botUserId || data.user_id !== this.botUserId) return;
2049
2115
  const guildId = data.guild_id?.trim();
2116
+ const userId = data.user_id?.trim();
2050
2117
  const channelId = data.channel_id?.trim();
2051
- if (!guildId || !channelId) return;
2118
+ if (!guildId || !userId) return;
2119
+ if (this.botUserId && userId === this.botUserId) {
2120
+ await this.handleBotVoiceStateUpdate({
2121
+ guildId,
2122
+ channelId
2123
+ });
2124
+ return;
2125
+ }
2126
+ if (this.followUserIds.has(userId)) await this.handleFollowedUserVoiceStateUpdate({
2127
+ guildId,
2128
+ channelId,
2129
+ userId
2130
+ });
2131
+ }
2132
+ async handleBotVoiceStateUpdate(params) {
2133
+ const { guildId, channelId } = params;
2134
+ if (!channelId) return;
2052
2135
  const existing = this.sessions.get(guildId);
2053
2136
  if (this.isAllowedVoiceChannel({
2054
2137
  guildId,
@@ -2059,7 +2142,7 @@ var DiscordVoiceManager$1 = class {
2059
2142
  await this.join({
2060
2143
  guildId,
2061
2144
  channelId
2062
- });
2145
+ }, { preserveFollowState: this.isFollowOwnedGuild(guildId) });
2063
2146
  }
2064
2147
  return;
2065
2148
  }
@@ -2080,9 +2163,267 @@ var DiscordVoiceManager$1 = class {
2080
2163
  await this.join(target);
2081
2164
  }
2082
2165
  }
2166
+ async handleFollowedUserVoiceStateUpdate(params) {
2167
+ if (!this.voiceEnabled || this.destroyed) return;
2168
+ const { guildId, channelId, userId } = params;
2169
+ const followKey = this.formatFollowedUserKey({
2170
+ guildId,
2171
+ userId
2172
+ });
2173
+ const existing = this.sessions.get(guildId);
2174
+ const wasFollowedVoiceSession = this.followedUserChannels.has(followKey) || this.followedVoiceGuilds.has(guildId);
2175
+ if (!channelId) {
2176
+ this.followedUserChannels.delete(followKey);
2177
+ if (existing && wasFollowedVoiceSession && !this.hasFollowedUserInChannel(existing)) await this.handoffToAnotherFollowedUserOrLeave({
2178
+ guildId,
2179
+ userId,
2180
+ existing,
2181
+ reason: "disconnected"
2182
+ });
2183
+ return;
2184
+ }
2185
+ if (!this.isAllowedVoiceChannel({
2186
+ guildId,
2187
+ channelId
2188
+ })) {
2189
+ this.followedUserChannels.delete(followKey);
2190
+ logger.warn(`discord voice: followed user joined non-allowed channel guild=${guildId} user=${userId} channel=${channelId}; ignoring`);
2191
+ if (existing && wasFollowedVoiceSession && !this.hasFollowedUserInChannel(existing)) await this.handoffToAnotherFollowedUserOrLeave({
2192
+ guildId,
2193
+ userId,
2194
+ existing,
2195
+ reason: "joined non-allowed channel"
2196
+ });
2197
+ return;
2198
+ }
2199
+ this.followedUserChannels.set(followKey, {
2200
+ guildId,
2201
+ channelId
2202
+ });
2203
+ if (existing?.channelId === channelId) {
2204
+ this.followedVoiceGuilds.add(guildId);
2205
+ return;
2206
+ }
2207
+ logger.info(`discord voice: following user guild=${guildId} user=${userId} channel=${channelId}`);
2208
+ const result = await this.join({
2209
+ guildId,
2210
+ channelId
2211
+ }, { preserveFollowState: true });
2212
+ if (!result.ok) {
2213
+ if (this.sessions.get(guildId)?.channelId === channelId) this.followedVoiceGuilds.add(guildId);
2214
+ else this.followedUserChannels.delete(followKey);
2215
+ logger.warn(`discord voice: failed to follow user guild=${guildId} user=${userId} channel=${channelId}: ${result.message}`);
2216
+ return;
2217
+ }
2218
+ this.followedVoiceGuilds.add(guildId);
2219
+ }
2083
2220
  async destroy() {
2221
+ this.destroyed = true;
2222
+ if (this.followUsersReconcileTimer) {
2223
+ clearInterval(this.followUsersReconcileTimer);
2224
+ this.followUsersReconcileTimer = null;
2225
+ }
2084
2226
  for (const entry of this.sessions.values()) entry.stop();
2085
2227
  this.sessions.clear();
2228
+ this.followedUserChannels.clear();
2229
+ this.followedVoiceGuilds.clear();
2230
+ }
2231
+ resolveFollowGuildIds() {
2232
+ const guildIds = /* @__PURE__ */ new Set();
2233
+ for (const guildId of Object.keys(this.params.discordConfig.guilds ?? {})) {
2234
+ const normalized = guildId.trim();
2235
+ if (normalized) guildIds.add(normalized);
2236
+ }
2237
+ for (const entry of normalizeVoiceChannelResidencies(this.params.discordConfig.voice?.autoJoin)) guildIds.add(entry.guildId);
2238
+ for (const entry of this.allowedChannels ?? []) guildIds.add(entry.guildId);
2239
+ for (const entry of this.sessions.values()) guildIds.add(entry.guildId);
2240
+ return Array.from(guildIds);
2241
+ }
2242
+ ensureFollowUsersReconcileTimer() {
2243
+ if (this.followUserIds.size === 0) return;
2244
+ if (this.followUsersReconcileTimer) return;
2245
+ this.followUsersReconcileTimer = setInterval(() => {
2246
+ this.reconcileFollowedUsers("interval").catch((err) => {
2247
+ logger.warn(`discord voice: follow user reconciliation failed: ${formatErrorMessage(err)}`);
2248
+ });
2249
+ }, FOLLOW_USERS_RECONCILE_INTERVAL_MS);
2250
+ this.followUsersReconcileTimer.unref?.();
2251
+ }
2252
+ async reconcileFollowedUsers(reason) {
2253
+ if (this.followUserIds.size === 0 || this.destroyed) return;
2254
+ if (this.followUsersReconcileTask) return this.followUsersReconcileTask;
2255
+ this.followUsersReconcileTask = this.runFollowedUsersReconcile(reason).finally(() => {
2256
+ this.followUsersReconcileTask = null;
2257
+ });
2258
+ return this.followUsersReconcileTask;
2259
+ }
2260
+ async runFollowedUsersReconcile(reason) {
2261
+ if (this.destroyed) return;
2262
+ const guildIds = this.resolveFollowGuildIds();
2263
+ if (guildIds.length === 0) {
2264
+ logVoiceVerbose(`follow user reconcile skipped reason=${reason}: no Discord guild ids are configured`);
2265
+ return;
2266
+ }
2267
+ logVoiceVerbose(`follow user reconcile reason=${reason}: ${this.followUserIds.size} users across ${guildIds.length} guilds`);
2268
+ const plans = this.selectFollowUserReconcilePlans(guildIds, reason);
2269
+ for (const plan of plans) {
2270
+ for (const userId of plan.userIds) {
2271
+ const voiceState = await getGuildVoiceState(this.params.client.rest, plan.guildId, userId).catch((err) => {
2272
+ if (!isUnknownDiscordVoiceStateError(err)) {
2273
+ logger.warn(`discord voice: follow user reconcile skipped transient voice state error guild=${plan.guildId} user=${userId} reason=${reason}: ${formatErrorMessage(err)}`);
2274
+ return "transient-error";
2275
+ }
2276
+ logVoiceVerbose(`follow user reconcile reason=${reason}: no voice state guild ${plan.guildId} user ${userId}: ${formatErrorMessage(err)}`);
2277
+ });
2278
+ if (this.destroyed) return;
2279
+ if (voiceState === "transient-error") continue;
2280
+ const channelId = voiceState?.channel_id?.trim();
2281
+ await this.handleFollowedUserVoiceStateUpdate({
2282
+ guildId: plan.guildId,
2283
+ channelId,
2284
+ userId
2285
+ });
2286
+ }
2287
+ if (plan.checkBotVoiceState) {
2288
+ if (this.destroyed) return;
2289
+ await this.disconnectStaleFollowedBotVoiceState({
2290
+ guildId: plan.guildId,
2291
+ reason
2292
+ });
2293
+ }
2294
+ }
2295
+ }
2296
+ selectFollowUserReconcilePlans(guildIds, reason) {
2297
+ const followedUserIds = Array.from(this.followUserIds);
2298
+ if (followedUserIds.length === 0) return [];
2299
+ let remainingLookups = FOLLOW_USERS_RECONCILE_MAX_REST_LOOKUPS_PER_RUN;
2300
+ const guildLimit = Math.min(guildIds.length, FOLLOW_USERS_RECONCILE_MAX_GUILDS_PER_RUN);
2301
+ const start = this.followUsersReconcileGuildCursor % guildIds.length;
2302
+ const plans = [];
2303
+ for (let offset = 0; offset < guildLimit && remainingLookups > 0; offset += 1) {
2304
+ if (this.botUserId && remainingLookups === 1) break;
2305
+ const guildId = guildIds[(start + offset) % guildIds.length];
2306
+ const userLimit = this.resolveFollowUserReconcileUserLookupLimit(followedUserIds.length, remainingLookups);
2307
+ if (userLimit <= 0) break;
2308
+ const selection = this.selectFollowUserReconcileUserIds(guildId, followedUserIds, userLimit);
2309
+ plans.push({
2310
+ guildId,
2311
+ userIds: selection.userIds,
2312
+ checkedAllUsers: selection.completedCycle,
2313
+ checkBotVoiceState: false
2314
+ });
2315
+ remainingLookups -= selection.userIds.length;
2316
+ }
2317
+ this.followUsersReconcileGuildCursor = (start + plans.length) % guildIds.length;
2318
+ this.assignFollowUserReconcileBotChecks(guildIds, plans, remainingLookups);
2319
+ if (plans.length < guildIds.length || plans.some((plan) => plan.userIds.length < followedUserIds.length)) logVoiceVerbose(`follow user reconcile reason=${reason}: sampling ${plans.length}/${guildIds.length} guilds and up to ${FOLLOW_USERS_RECONCILE_MAX_REST_LOOKUPS_PER_RUN} REST lookups`);
2320
+ return plans;
2321
+ }
2322
+ assignFollowUserReconcileBotChecks(guildIds, plans, remainingLookups) {
2323
+ if (!this.botUserId || remainingLookups <= 0 || plans.length === 0) return;
2324
+ const plansByGuild = new Map(plans.map((plan) => [plan.guildId, plan]));
2325
+ const start = this.followUsersReconcileBotGuildCursor % guildIds.length;
2326
+ let scanned = 0;
2327
+ let assigned = 0;
2328
+ for (; scanned < guildIds.length && assigned < remainingLookups; scanned += 1) {
2329
+ const guildId = guildIds[(start + scanned) % guildIds.length];
2330
+ const plan = plansByGuild.get(guildId);
2331
+ if (!plan?.checkedAllUsers) continue;
2332
+ plan.checkBotVoiceState = true;
2333
+ assigned += 1;
2334
+ }
2335
+ this.followUsersReconcileBotGuildCursor = (start + scanned) % guildIds.length;
2336
+ }
2337
+ resolveFollowUserReconcileUserLookupLimit(followedUserCount, remainingLookups) {
2338
+ const userLimit = Math.min(followedUserCount, remainingLookups);
2339
+ if (this.botUserId && followedUserCount > userLimit && remainingLookups > 1) return remainingLookups - 1;
2340
+ return userLimit;
2341
+ }
2342
+ selectFollowUserReconcileUserIds(guildId, followedUserIds, limit) {
2343
+ if (followedUserIds.length <= limit) {
2344
+ this.followUsersReconcileUserCursors.set(guildId, 0);
2345
+ return {
2346
+ userIds: followedUserIds,
2347
+ completedCycle: true
2348
+ };
2349
+ }
2350
+ const start = this.followUsersReconcileUserCursors.get(guildId) ?? 0;
2351
+ const selected = Array.from({ length: limit }, (_, offset) => followedUserIds[(start + offset) % followedUserIds.length]);
2352
+ const completedCycle = start + selected.length >= followedUserIds.length;
2353
+ this.followUsersReconcileUserCursors.set(guildId, (start + selected.length) % followedUserIds.length);
2354
+ return {
2355
+ userIds: selected,
2356
+ completedCycle
2357
+ };
2358
+ }
2359
+ formatFollowedUserKey(params) {
2360
+ return `${params.guildId}:${params.userId}`;
2361
+ }
2362
+ hasFollowedUserInChannel(entry) {
2363
+ return Array.from(this.followedUserChannels.values()).some((candidate) => candidate.guildId === entry.guildId && candidate.channelId === entry.channelId);
2364
+ }
2365
+ resolveFollowedUserHandoffTarget(guildId, currentChannelId) {
2366
+ for (const entry of this.followedUserChannels.values()) if (entry.guildId === guildId && entry.channelId !== currentChannelId && this.isAllowedVoiceChannel(entry)) return entry;
2367
+ return null;
2368
+ }
2369
+ async handoffToAnotherFollowedUserOrLeave(params) {
2370
+ const target = this.resolveFollowedUserHandoffTarget(params.guildId, params.existing.channelId);
2371
+ if (target) {
2372
+ logger.info(`discord voice: followed user ${params.reason} guild=${params.guildId} user=${params.userId}; moving to remaining followed user channel=${target.channelId}`);
2373
+ const result = await this.join(target, { preserveFollowState: true });
2374
+ if (result.ok) this.followedVoiceGuilds.add(params.guildId);
2375
+ else {
2376
+ logger.warn(`discord voice: failed to hand off followed user session guild=${params.guildId} channel=${target.channelId}: ${result.message}`);
2377
+ this.followedVoiceGuilds.delete(params.guildId);
2378
+ this.deleteFollowedUserChannelsForGuild(params.guildId);
2379
+ await this.leave({ guildId: params.guildId });
2380
+ }
2381
+ return;
2382
+ }
2383
+ logger.info(`discord voice: followed user ${params.reason} guild=${params.guildId} user=${params.userId}; leaving channel=${params.existing.channelId}`);
2384
+ await this.leave({ guildId: params.guildId });
2385
+ }
2386
+ isFollowOwnedGuild(guildId) {
2387
+ return this.followedVoiceGuilds.has(guildId) || Array.from(this.followedUserChannels.values()).some((entry) => entry.guildId === guildId);
2388
+ }
2389
+ deleteFollowedUserChannelsForGuild(guildId) {
2390
+ for (const [key, entry] of this.followedUserChannels.entries()) if (entry.guildId === guildId) this.followedUserChannels.delete(key);
2391
+ }
2392
+ async disconnectStaleFollowedBotVoiceState(params) {
2393
+ if (this.destroyed) return;
2394
+ const { guildId, reason } = params;
2395
+ if (Array.from(this.followedUserChannels.values()).some((entry) => entry.guildId === guildId)) return;
2396
+ const existing = this.sessions.get(guildId);
2397
+ if (existing) {
2398
+ if (this.followedVoiceGuilds.has(guildId)) {
2399
+ logger.info(`discord voice: follow reconcile leaving local session guild=${guildId} channel=${existing.channelId} reason=${reason}`);
2400
+ await this.leave({ guildId });
2401
+ }
2402
+ return;
2403
+ }
2404
+ if (!this.botUserId) return;
2405
+ const botVoiceState = await getGuildVoiceState(this.params.client.rest, guildId, this.botUserId).catch((err) => {
2406
+ if (!isUnknownDiscordVoiceStateError(err)) {
2407
+ logger.warn(`discord voice: follow reconcile skipped transient bot voice state error guild=${guildId} reason=${reason}: ${formatErrorMessage(err)}`);
2408
+ return "transient-error";
2409
+ }
2410
+ logVoiceVerbose(`follow user reconcile reason=${reason}: no bot voice state guild ${guildId}: ${formatErrorMessage(err)}`);
2411
+ });
2412
+ if (this.destroyed || botVoiceState === "transient-error") return;
2413
+ const botChannelId = botVoiceState?.channel_id?.trim();
2414
+ if (!botChannelId) return;
2415
+ const gateway = this.params.client.getPlugin("voice")?.getGateway(guildId);
2416
+ if (!gateway) {
2417
+ logger.warn(`discord voice: follow reconcile cannot disconnect stale bot voice state guild=${guildId} channel=${botChannelId}; gateway unavailable`);
2418
+ return;
2419
+ }
2420
+ logger.info(`discord voice: follow reconcile disconnecting stale bot voice state guild=${guildId} channel=${botChannelId} reason=${reason}`);
2421
+ gateway.updateVoiceState({
2422
+ guild_id: guildId,
2423
+ channel_id: null,
2424
+ self_mute: false,
2425
+ self_deaf: false
2426
+ });
2086
2427
  }
2087
2428
  resolveVoiceResidencyTarget(guildId) {
2088
2429
  const autoJoinTarget = normalizeVoiceChannelResidencies(this.params.discordConfig.voice?.autoJoin).toReversed().find((entry) => entry.guildId === guildId);
@@ -2306,8 +2647,9 @@ var DiscordVoiceManager$1 = class {
2306
2647
  async recoverFromDecryptFailures(entry) {
2307
2648
  const active = this.sessions.get(entry.guildId);
2308
2649
  if (!active || active.connection !== entry.connection) return;
2650
+ const preserveFollowState = this.isFollowOwnedGuild(entry.guildId);
2309
2651
  logger.warn(`discord voice: repeated decrypt failures; attempting rejoin for guild ${entry.guildId} channel ${entry.channelId}`);
2310
- const leaveResult = await this.leave({ guildId: entry.guildId });
2652
+ const leaveResult = await this.leave({ guildId: entry.guildId }, { preserveFollowState });
2311
2653
  if (!leaveResult.ok) {
2312
2654
  logger.warn(`discord voice: decrypt recovery leave failed: ${leaveResult.message}`);
2313
2655
  return;
@@ -2315,7 +2657,7 @@ var DiscordVoiceManager$1 = class {
2315
2657
  const result = await this.join({
2316
2658
  guildId: entry.guildId,
2317
2659
  channelId: entry.channelId
2318
- });
2660
+ }, { preserveFollowState });
2319
2661
  if (!result.ok) logger.warn(`discord voice: rejoin after decrypt failures failed: ${result.message}`);
2320
2662
  }
2321
2663
  };
@@ -1,8 +1,8 @@
1
- import { N as createDiscordRestClient } from "./send.shared-C6JLgsbp.js";
2
- import { d as resolveDiscordChannelNameSafe, l as resolveDiscordChannelIdSafe, p as resolveDiscordChannelParentSafe, u as resolveDiscordChannelInfoSafe } from "./thread-bindings.discord-api-BzelVdsY.js";
3
- import { a as mergeAbortSignals } from "./timeouts-CEwuGaWT.js";
4
- import { c as hasDiscordMessageStickers, d as resolveDiscordMessageChannelId, r as resolveDiscordMessageText } from "./message-utils-BKrlzFtM.js";
5
- import { t as sendTyping } from "./typing-DtdZgo-g.js";
1
+ import { N as createDiscordRestClient } from "./send.shared-D4clao4K.js";
2
+ import { d as resolveDiscordChannelNameSafe, l as resolveDiscordChannelIdSafe, p as resolveDiscordChannelParentSafe, u as resolveDiscordChannelInfoSafe } from "./thread-bindings.discord-api-Ddalj9wo.js";
3
+ import { a as mergeAbortSignals } from "./timeouts-l_PsHQvX.js";
4
+ import { c as hasDiscordMessageStickers, d as resolveDiscordMessageChannelId, r as resolveDiscordMessageText } from "./message-utils-Bw-wDr8G.js";
5
+ import { t as sendTyping } from "./typing-DUUjLsPr.js";
6
6
  import { danger, logVerbose } from "openclaw/plugin-sdk/runtime-env";
7
7
  import { resolveOpenProviderRuntimeGroupPolicy } from "openclaw/plugin-sdk/runtime-group-policy";
8
8
  import { resolveBatchedReplyThreadingPolicy } from "openclaw/plugin-sdk/reply-reference";
@@ -121,7 +121,7 @@ function applyImplicitReplyBatchGate(ctx, replyToMode, isBatched) {
121
121
  //#region extensions/discord/src/monitor/message-run-queue.ts
122
122
  let messageProcessRuntimePromise;
123
123
  async function loadMessageProcessRuntime() {
124
- messageProcessRuntimePromise ??= import("./message-handler.process-PpgZ0qC4.js");
124
+ messageProcessRuntimePromise ??= import("./message-handler.process-DG4qm0sQ.js");
125
125
  return await messageProcessRuntimePromise;
126
126
  }
127
127
  async function processDiscordQueuedMessage(params) {
@@ -173,7 +173,7 @@ function createDiscordMessageRunQueue(params) {
173
173
  //#region extensions/discord/src/monitor/message-handler.ts
174
174
  let messagePreflightRuntimePromise;
175
175
  async function loadMessagePreflightRuntime() {
176
- messagePreflightRuntimePromise ??= import("./message-handler.preflight-DQ-oPY7m.js");
176
+ messagePreflightRuntimePromise ??= import("./message-handler.preflight-ANdoLbtA.js");
177
177
  return await messagePreflightRuntimePromise;
178
178
  }
179
179
  function isNonEmptyString(value) {
@@ -1,13 +1,13 @@
1
- import { A as Message, c as discord_exports, mt as getChannelMessage } from "./send.receipt-Dhym-qOF.js";
2
- import { o as resolveDefaultDiscordAccountId } from "./accounts-ltxKLzxN.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-BY7sjUQh.js";
5
- import { l as isRecentlyUnboundThreadWebhookMessage } from "./thread-bindings.state-CSphZOiL.js";
6
- import { d as resolveDiscordChannelNameSafe, u as resolveDiscordChannelInfoSafe } from "./thread-bindings.discord-api-BzelVdsY.js";
7
- import "./thread-bindings-BcXgbZ3-.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-BZtjA1y_.js";
9
- import { d as resolveDiscordMessageChannelId, l as resolveDiscordMessageStickers, o as resolveMediaList, r as resolveDiscordMessageText, u as resolveDiscordChannelInfo } from "./message-utils-BKrlzFtM.js";
10
- import { n as resolveDiscordWebhookId, t as resolveDiscordSenderIdentity } from "./sender-identity-DC0FdEcU.js";
1
+ import { A as Message, c as discord_exports, mt as getChannelMessage } from "./send.receipt-spSPAC77.js";
2
+ import { o as resolveDefaultDiscordAccountId } from "./accounts-C2TOAmpo.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-BnkWtVpA.js";
4
+ import { t as resolveDiscordConversationIdentity } from "./conversation-identity-CAyt5wzy.js";
5
+ import { l as isRecentlyUnboundThreadWebhookMessage } from "./thread-bindings.state-BsOnj5NX.js";
6
+ import { d as resolveDiscordChannelNameSafe, u as resolveDiscordChannelInfoSafe } from "./thread-bindings.discord-api-Ddalj9wo.js";
7
+ import "./thread-bindings-BQz8z6MR.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-CzKMDsSE.js";
9
+ import { d as resolveDiscordMessageChannelId, l as resolveDiscordMessageStickers, o as resolveMediaList, r as resolveDiscordMessageText, u as resolveDiscordChannelInfo } from "./message-utils-Bw-wDr8G.js";
10
+ import { n as resolveDiscordWebhookId, t as resolveDiscordSenderIdentity } from "./sender-identity-BFp5w0F8.js";
11
11
  import { normalizeOptionalString } from "openclaw/plugin-sdk/string-coerce-runtime";
12
12
  import { getChildLogger, logVerbose, shouldLogVerbose } from "openclaw/plugin-sdk/runtime-env";
13
13
  import { recordChannelActivity } from "openclaw/plugin-sdk/channel-activity-runtime";
@@ -29,7 +29,7 @@ async function loadConversationRuntime$1() {
29
29
  return await conversationRuntimePromise$1;
30
30
  }
31
31
  async function loadDiscordSendRuntime() {
32
- discordSendRuntimePromise ??= import("./send-BsBy21Te.js").then((n) => n.t);
32
+ discordSendRuntimePromise ??= import("./send-CEAtV0qd.js").then((n) => n.t);
33
33
  return await discordSendRuntimePromise;
34
34
  }
35
35
  async function resolveDiscordDmPreflightAccess(params) {
@@ -427,19 +427,19 @@ let preflightAudioRuntimePromise;
427
427
  let systemEventsRuntimePromise;
428
428
  let discordThreadingRuntimePromise;
429
429
  async function loadPluralKitRuntime() {
430
- pluralkitRuntimePromise ??= import("./pluralkit-BnCH6cHK.js").then((n) => n.n);
430
+ pluralkitRuntimePromise ??= import("./pluralkit-sQLfeyIZ.js").then((n) => n.n);
431
431
  return await pluralkitRuntimePromise;
432
432
  }
433
433
  async function loadPreflightAudioRuntime() {
434
- preflightAudioRuntimePromise ??= import("./preflight-audio-B0keJeQe.js");
434
+ preflightAudioRuntimePromise ??= import("./preflight-audio-ClWbnQto.js");
435
435
  return await preflightAudioRuntimePromise;
436
436
  }
437
437
  async function loadSystemEventsRuntime() {
438
- systemEventsRuntimePromise ??= import("./system-events-DEuiLTl9.js");
438
+ systemEventsRuntimePromise ??= import("./system-events-HgHeiMHg.js");
439
439
  return await systemEventsRuntimePromise;
440
440
  }
441
441
  async function loadDiscordThreadingRuntime() {
442
- discordThreadingRuntimePromise ??= import("./provider-BZtjA1y_.js").then((n) => n.v);
442
+ discordThreadingRuntimePromise ??= import("./provider-CzKMDsSE.js").then((n) => n.v);
443
443
  return await discordThreadingRuntimePromise;
444
444
  }
445
445
  function isPreflightAborted(abortSignal) {
@@ -1026,9 +1026,7 @@ async function preflightDiscordMessage(params) {
1026
1026
  logDebug(`[discord-preflight] drop: system event`);
1027
1027
  enqueueSystemEvent(systemText, {
1028
1028
  sessionKey: effectiveRoute.sessionKey,
1029
- contextKey: `discord:system:${messageChannelId}:${message.id}`,
1030
- forceSenderIsOwnerFalse: true,
1031
- trusted: false
1029
+ contextKey: `discord:system:${messageChannelId}:${message.id}`
1032
1030
  });
1033
1031
  return null;
1034
1032
  }