@openclaw/discord 2026.5.19 → 2026.5.20-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{account-inspect-DCXwNu_u.js → account-inspect-CcJ-bl80.js} +1 -1
- package/dist/account-inspect-api.js +1 -1
- package/dist/action-runtime-api.js +1 -1
- package/dist/api.js +19 -19
- package/dist/{approval-handler.runtime-CRpNixJy.js → approval-handler.runtime-hi6B0JCi.js} +4 -4
- package/dist/{audit-DEF10R9j.js → audit-DJIvRRzY.js} +5 -5
- package/dist/{channel-CR9HckAC.js → channel-V98WbX-k.js} +22 -22
- package/dist/{channel-actions-CpmPx9PW.js → channel-actions-CSepY2Kq.js} +5 -5
- package/dist/{channel-actions.runtime-Be5OvB1r.js → channel-actions.runtime-CSjcHZNT.js} +6 -6
- package/dist/channel-config-api.js +1 -1
- package/dist/channel-plugin-api.js +1 -1
- package/dist/{channel.setup-DR3-U0wF.js → channel.setup-C0rcLtB9.js} +4 -4
- package/dist/{components-q41bHoCx.js → components-DDPGekgY.js} +1 -1
- package/dist/{config-schema-jz2FX2x5.js → config-schema-BGgg8U6A.js} +13 -1
- package/dist/contract-api.js +7 -7
- package/dist/{conversation-identity-BY7sjUQh.js → conversation-identity-CAyt5wzy.js} +3 -3
- package/dist/{directory-config-x3YzNdoX.js → directory-config-BcWtq4k8.js} +2 -2
- package/dist/directory-contract-api.js +1 -1
- package/dist/{directory-live-CJiEWQwK.js → directory-live-5HHCCe5Q.js} +4 -4
- package/dist/{doctor-CzcS8Yt1.js → doctor-BLcVWv42.js} +5 -5
- package/dist/{doctor-contract-AkgUZQHW.js → doctor-contract-Bia3BmP_.js} +1 -1
- package/dist/doctor-contract-api.js +1 -1
- package/dist/{handle-action.guild-admin-kAzbjGMw.js → handle-action.guild-admin-DX2D9qkG.js} +1 -1
- package/dist/{inbound-context-CzEAvKgx.js → inbound-context-B5EsqsSr.js} +1 -1
- package/dist/{manager.runtime-CGcJ0yjq.js → manager.runtime-BbDV8jY7.js} +364 -21
- package/dist/{message-handler-1NV0WiHC.js → message-handler-DGEpF6pb.js} +7 -7
- package/dist/{message-handler.preflight-DQ-oPY7m.js → message-handler.preflight-DsNzvkrd.js} +15 -15
- package/dist/{message-handler.process-PpgZ0qC4.js → message-handler.process-AA6doeek.js} +27 -16
- package/dist/{message-utils-BKrlzFtM.js → message-utils-Bw-wDr8G.js} +2 -2
- package/dist/{outbound-adapter-CaZzpMnE.js → outbound-adapter-TGbHliO_.js} +8 -8
- package/dist/{pluralkit-BnCH6cHK.js → pluralkit-sQLfeyIZ.js} +1 -1
- package/dist/{preflight-audio-B0keJeQe.js → preflight-audio-ClWbnQto.js} +1 -1
- package/dist/{probe-BLDNbk41.js → probe-CRWV5COl.js} +2 -2
- package/dist/{probe.runtime-DKB38YvU.js → probe.runtime-h9mEzmMs.js} +1 -1
- package/dist/{provider-BZtjA1y_.js → provider-CfxRE5oz.js} +42 -55
- package/dist/{provider-session.runtime-DVfzQxFH.js → provider-session.runtime-DxOvTd-z.js} +3 -3
- package/dist/provider.runtime-ChDLWrdw.js +2 -0
- package/dist/{resolve-allowlist-common-C8L5MYFl.js → resolve-allowlist-common-Bec0FONA.js} +3 -3
- package/dist/{resolve-channels-Czrd7fOv.js → resolve-channels-DcWaMURg.js} +4 -4
- package/dist/{resolve-users-D7hQMaaq.js → resolve-users-TQPLKDeV.js} +3 -3
- package/dist/{runtime-BJUWt4mA.js → runtime-DP_0_5a0.js} +9 -9
- package/dist/runtime-api.actions.js +2 -2
- package/dist/runtime-api.js +25 -25
- package/dist/runtime-api.lookup.js +6 -6
- package/dist/runtime-api.monitor-BL4xboSm.js +5 -0
- package/dist/runtime-api.monitor.js +7 -7
- package/dist/runtime-api.send.js +5 -5
- package/dist/runtime-api.threads.js +5 -5
- package/dist/runtime-setter-api.js +1 -1
- package/dist/secret-contract-api.js +1 -1
- package/dist/{security-audit-Dx3j4a0l.js → security-audit-C_fzlczo.js} +1 -1
- package/dist/security-audit-contract-api.js +1 -1
- package/dist/{security-audit.runtime-C5nnf0k8.js → security-audit.runtime-Dt4zoGpL.js} +1 -1
- package/dist/security-contract-api.js +1 -1
- package/dist/{send-BsBy21Te.js → send-CEAtV0qd.js} +5 -6
- package/dist/{send.components-BuZBJysI.js → send.components-sY6aQV0K.js} +8 -8
- package/dist/{send.outbound-C0OzZAv_.js → send.outbound-1vG9pOh2.js} +4 -4
- package/dist/{send.shared-C6JLgsbp.js → send.shared-D4clao4K.js} +3 -3
- package/dist/{sender-identity-DC0FdEcU.js → sender-identity-BFp5w0F8.js} +1 -1
- package/dist/session-key-api.js +1 -1
- package/dist/setup-plugin-api.js +1 -1
- package/dist/{shared-CYe5A_Bs.js → shared-mo-r7V5W.js} +10 -10
- package/dist/{subagent-hooks-DCIt8Gt7.js → subagent-hooks-D65kqOor.js} +3 -3
- package/dist/subagent-hooks-api.js +1 -1
- package/dist/{system-events-DEuiLTl9.js → system-events-HgHeiMHg.js} +2 -2
- package/dist/{target-resolver-C5tK3vit.js → target-resolver-BpGdnBIZ.js} +3 -3
- package/dist/targets-DMdVjHOU.js +3 -0
- package/dist/test-api.js +4 -4
- package/dist/{thread-bindings-BcXgbZ3-.js → thread-bindings-BQz8z6MR.js} +6 -6
- package/dist/{thread-bindings.discord-api-BzelVdsY.js → thread-bindings.discord-api-Ddalj9wo.js} +5 -5
- package/dist/{thread-bindings.manager-CouT_qjE.js → thread-bindings.manager-I5f-Oykv.js} +4 -4
- package/dist/{thread-bindings.session-updates-CgOqEOPe.js → thread-bindings.session-updates-D5gY2ZTE.js} +1 -1
- package/dist/timeouts.js +1 -1
- package/dist/{typing-DtdZgo-g.js → typing-DUUjLsPr.js} +2 -2
- package/openclaw.plugin.json +72 -2
- package/package.json +4 -4
- package/dist/provider.runtime-DlegJeN5.js +0 -2
- package/dist/runtime-api.monitor-BlxEnLN_.js +0 -5
- package/dist/targets-JvlTzyfK.js +0 -3
- /package/dist/{accounts-ltxKLzxN.js → accounts-C2TOAmpo.js} +0 -0
- /package/dist/{agent-components.runtime-BIemD2Iz.js → agent-components.runtime-CEPrf2SY.js} +0 -0
- /package/dist/{allow-list-CBI-M84K.js → allow-list-BnkWtVpA.js} +0 -0
- /package/dist/{api-DgQLz1wq.js → api-Kq7vtaSO.js} +0 -0
- /package/dist/{audit-core-DRyoXREU.js → audit-core-xwjIczO0.js} +0 -0
- /package/dist/{channel-api-JudoSiJv.js → channel-api-CAJ0wMoV.js} +0 -0
- /package/dist/{config-api-oLS_52S7.js → config-api-JiPdJeb0.js} +0 -0
- /package/dist/{gateway-registry-BKSpa4GB.js → gateway-registry-DPxmW0Db.js} +0 -0
- /package/dist/{inbound-event-delivery-D8zHG9Lz.js → inbound-event-delivery-DTGIjZVJ.js} +0 -0
- /package/dist/{preflight-audio.runtime-DT1Hmhsq.js → preflight-audio.runtime-CoCXMM8r.js} +0 -0
- /package/dist/{preview-streaming-nClS_TQx.js → preview-streaming-CQ7PsV9J.js} +0 -0
- /package/dist/{runtime-Tqtvj5GX.js → runtime-DgnVQ7zW.js} +0 -0
- /package/dist/{secret-config-contract-57_WV6qt.js → secret-config-contract-BjM-1hr9.js} +0 -0
- /package/dist/{security-contract-BWDASKVo.js → security-contract-DSHk7I2w.js} +0 -0
- /package/dist/{security-doctor-DepqtNCI.js → security-doctor-uUo8hTD5.js} +0 -0
- /package/dist/{send.receipt-Dhym-qOF.js → send.receipt-spSPAC77.js} +0 -0
- /package/dist/{session-contract-Dwhw3RTY.js → session-contract-BO5tlIdl.js} +0 -0
- /package/dist/{session-key-normalization-DnCXUKGA.js → session-key-normalization-wJgsKPNF.js} +0 -0
- /package/dist/{thread-bindings.state-CSphZOiL.js → thread-bindings.state-BsOnj5NX.js} +0 -0
- /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-
|
|
2
|
-
import { c as resolveDiscordAccountAllowFrom } from "./accounts-
|
|
3
|
-
import { a as normalizeDiscordSlug, b as formatDiscordUserTag, m as resolveDiscordOwnerAccess } from "./allow-list-
|
|
4
|
-
import { i as formatMention } from "./send.outbound-
|
|
5
|
-
import { t as getDiscordRuntime } from "./runtime-
|
|
6
|
-
import { o as authorizeDiscordVoiceIngress, u as resolveDiscordVoiceEnabled } from "./provider-
|
|
7
|
-
import { t as buildDiscordGroupSystemPrompt } from "./inbound-context-
|
|
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-CfxRE5oz.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) {
|
|
@@ -325,6 +325,22 @@ async function runDiscordVoiceAgentTurn(params) {
|
|
|
325
325
|
text
|
|
326
326
|
};
|
|
327
327
|
}
|
|
328
|
+
async function resolveDiscordVoiceRealtimeBootstrapContext(params) {
|
|
329
|
+
const files = (params.discordConfig.voice?.realtime)?.bootstrapContextFiles;
|
|
330
|
+
if (files?.length === 0) return;
|
|
331
|
+
try {
|
|
332
|
+
return await resolveRealtimeBootstrapContextInstructions({
|
|
333
|
+
config: params.cfg,
|
|
334
|
+
agentId: params.entry.route.agentId,
|
|
335
|
+
sessionKey: params.entry.route.sessionKey,
|
|
336
|
+
files,
|
|
337
|
+
warn: (message) => logger$3.warn(`discord voice: realtime bootstrap context: ${message}`)
|
|
338
|
+
});
|
|
339
|
+
} catch (error) {
|
|
340
|
+
logger$3.warn(`discord voice: realtime bootstrap context unavailable: ${error instanceof Error ? error.message : String(error)}`);
|
|
341
|
+
return;
|
|
342
|
+
}
|
|
343
|
+
}
|
|
328
344
|
//#endregion
|
|
329
345
|
//#region extensions/discord/src/voice/prompt.ts
|
|
330
346
|
const DISCORD_VOICE_SPOKEN_OUTPUT_CONTRACT = [
|
|
@@ -599,6 +615,7 @@ var DiscordRealtimeVoiceSession = class {
|
|
|
599
615
|
const instructions = buildDiscordRealtimeInstructions({
|
|
600
616
|
mode: this.params.mode,
|
|
601
617
|
instructions: this.realtimeConfig?.instructions,
|
|
618
|
+
bootstrapContextInstructions: this.params.bootstrapContextInstructions,
|
|
602
619
|
toolPolicy,
|
|
603
620
|
consultPolicy
|
|
604
621
|
});
|
|
@@ -1197,6 +1214,7 @@ function buildDiscordRealtimeInstructions(params) {
|
|
|
1197
1214
|
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
1215
|
if (isDiscordAgentProxyVoiceMode(params.mode)) return [
|
|
1199
1216
|
base,
|
|
1217
|
+
params.bootstrapContextInstructions?.trim(),
|
|
1200
1218
|
"Mode: OpenClaw agent proxy.",
|
|
1201
1219
|
"You are the realtime voice surface for the same OpenClaw agent the user can message directly.",
|
|
1202
1220
|
"Do not mention a backend, supervisor, helper, or separate system. Present the result as your own work.",
|
|
@@ -1209,10 +1227,14 @@ function buildDiscordRealtimeInstructions(params) {
|
|
|
1209
1227
|
consultPolicy: params.consultPolicy
|
|
1210
1228
|
})
|
|
1211
1229
|
].join("\n\n");
|
|
1212
|
-
return [
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1230
|
+
return [
|
|
1231
|
+
base,
|
|
1232
|
+
params.bootstrapContextInstructions?.trim(),
|
|
1233
|
+
buildRealtimeVoiceAgentConsultPolicyInstructions({
|
|
1234
|
+
toolPolicy: params.toolPolicy,
|
|
1235
|
+
consultPolicy: params.consultPolicy
|
|
1236
|
+
})
|
|
1237
|
+
].filter(Boolean).join("\n\n");
|
|
1216
1238
|
}
|
|
1217
1239
|
//#endregion
|
|
1218
1240
|
//#region extensions/discord/src/voice/receive-recovery.ts
|
|
@@ -1582,6 +1604,9 @@ var DiscordVoiceSpeakerContextResolver = class {
|
|
|
1582
1604
|
//#region extensions/discord/src/voice/manager.ts
|
|
1583
1605
|
const logger = createSubsystemLogger("discord/voice");
|
|
1584
1606
|
const VOICE_LOG_PREVIEW_CHARS = 500;
|
|
1607
|
+
const FOLLOW_USERS_RECONCILE_INTERVAL_MS = 1e4;
|
|
1608
|
+
const FOLLOW_USERS_RECONCILE_MAX_GUILDS_PER_RUN = 4;
|
|
1609
|
+
const FOLLOW_USERS_RECONCILE_MAX_REST_LOOKUPS_PER_RUN = 32;
|
|
1585
1610
|
const DISCORD_VOICE_FATAL_AUTOJOIN_ERROR_PATTERNS = [
|
|
1586
1611
|
"api key missing",
|
|
1587
1612
|
"incorrect api key",
|
|
@@ -1627,6 +1652,22 @@ function normalizeVoiceChannelResidencies(entries) {
|
|
|
1627
1652
|
}
|
|
1628
1653
|
return normalized;
|
|
1629
1654
|
}
|
|
1655
|
+
function normalizeDiscordUserId(value) {
|
|
1656
|
+
const trimmed = value.trim();
|
|
1657
|
+
const withoutDiscordPrefix = trimmed.startsWith("discord:") ? trimmed.slice(8) : trimmed;
|
|
1658
|
+
return (withoutDiscordPrefix.startsWith("user:") ? withoutDiscordPrefix.slice(5) : withoutDiscordPrefix).trim() || void 0;
|
|
1659
|
+
}
|
|
1660
|
+
function normalizeDiscordUserIds(entries) {
|
|
1661
|
+
const ids = /* @__PURE__ */ new Set();
|
|
1662
|
+
for (const entry of entries ?? []) {
|
|
1663
|
+
const id = normalizeDiscordUserId(entry);
|
|
1664
|
+
if (id) ids.add(id);
|
|
1665
|
+
}
|
|
1666
|
+
return ids;
|
|
1667
|
+
}
|
|
1668
|
+
function resolveFollowUsersEnabled(voiceConfig) {
|
|
1669
|
+
return voiceConfig?.followUsersEnabled !== false;
|
|
1670
|
+
}
|
|
1630
1671
|
function isVoiceChannelAllowed(params) {
|
|
1631
1672
|
return params.allowedChannels === null || params.allowedChannels.some((entry) => entry.guildId === params.guildId && entry.channelId === params.channelId);
|
|
1632
1673
|
}
|
|
@@ -1637,6 +1678,9 @@ function isFatalAutoJoinFailure(message) {
|
|
|
1637
1678
|
const normalized = message.toLowerCase();
|
|
1638
1679
|
return DISCORD_VOICE_FATAL_AUTOJOIN_ERROR_PATTERNS.some((pattern) => normalized.includes(pattern));
|
|
1639
1680
|
}
|
|
1681
|
+
function isUnknownDiscordVoiceStateError(err) {
|
|
1682
|
+
return (err && typeof err === "object" && "status" in err && typeof err.status === "number" ? err.status : void 0) === 404 || /unknown voice state/i.test(formatErrorMessage(err));
|
|
1683
|
+
}
|
|
1640
1684
|
function startAutoJoin(manager) {
|
|
1641
1685
|
manager.autoJoin().catch((err) => logger.warn(`discord voice: autoJoin failed: ${formatErrorMessage(err)}`));
|
|
1642
1686
|
}
|
|
@@ -1684,6 +1728,14 @@ var DiscordVoiceManager$1 = class {
|
|
|
1684
1728
|
this.sessions = /* @__PURE__ */ new Map();
|
|
1685
1729
|
this.autoJoinTask = null;
|
|
1686
1730
|
this.fatalAutoJoinFailures = /* @__PURE__ */ new Map();
|
|
1731
|
+
this.followedUserChannels = /* @__PURE__ */ new Map();
|
|
1732
|
+
this.followedVoiceGuilds = /* @__PURE__ */ new Set();
|
|
1733
|
+
this.followUsersReconcileTimer = null;
|
|
1734
|
+
this.followUsersReconcileTask = null;
|
|
1735
|
+
this.followUsersReconcileGuildCursor = 0;
|
|
1736
|
+
this.followUsersReconcileBotGuildCursor = 0;
|
|
1737
|
+
this.followUsersReconcileUserCursors = /* @__PURE__ */ new Map();
|
|
1738
|
+
this.destroyed = false;
|
|
1687
1739
|
this.botUserId = params.botUserId;
|
|
1688
1740
|
this.voiceEnabled = resolveDiscordVoiceEnabled(params.discordConfig.voice);
|
|
1689
1741
|
this.ownerAllowFrom = resolveDiscordAccountAllowFrom({
|
|
@@ -1691,6 +1743,7 @@ var DiscordVoiceManager$1 = class {
|
|
|
1691
1743
|
accountId: params.accountId
|
|
1692
1744
|
}) ?? params.discordConfig.allowFrom ?? params.discordConfig.dm?.allowFrom ?? [];
|
|
1693
1745
|
this.allowedChannels = params.discordConfig.voice?.allowedChannels === void 0 ? null : normalizeVoiceChannelResidencies(params.discordConfig.voice.allowedChannels);
|
|
1746
|
+
this.followUserIds = resolveFollowUsersEnabled(params.discordConfig.voice) ? normalizeDiscordUserIds(params.discordConfig.voice?.followUsers) : /* @__PURE__ */ new Set();
|
|
1694
1747
|
this.speakerContext = new DiscordVoiceSpeakerContextResolver({
|
|
1695
1748
|
client: params.client,
|
|
1696
1749
|
ownerAllowFrom: this.ownerAllowFrom
|
|
@@ -1703,7 +1756,7 @@ var DiscordVoiceManager$1 = class {
|
|
|
1703
1756
|
return this.voiceEnabled;
|
|
1704
1757
|
}
|
|
1705
1758
|
async autoJoin() {
|
|
1706
|
-
if (!this.voiceEnabled) return;
|
|
1759
|
+
if (!this.voiceEnabled || this.destroyed) return;
|
|
1707
1760
|
if (this.autoJoinTask) return this.autoJoinTask;
|
|
1708
1761
|
this.autoJoinTask = (async () => {
|
|
1709
1762
|
const entries = this.params.discordConfig.voice?.autoJoin ?? [];
|
|
@@ -1747,6 +1800,8 @@ var DiscordVoiceManager$1 = class {
|
|
|
1747
1800
|
});
|
|
1748
1801
|
}
|
|
1749
1802
|
}
|
|
1803
|
+
this.ensureFollowUsersReconcileTimer();
|
|
1804
|
+
await this.reconcileFollowedUsers("startup");
|
|
1750
1805
|
})().finally(() => {
|
|
1751
1806
|
this.autoJoinTask = null;
|
|
1752
1807
|
});
|
|
@@ -1767,7 +1822,11 @@ var DiscordVoiceManager$1 = class {
|
|
|
1767
1822
|
channelId: params.channelId.trim()
|
|
1768
1823
|
});
|
|
1769
1824
|
}
|
|
1770
|
-
async join(params) {
|
|
1825
|
+
async join(params, options) {
|
|
1826
|
+
if (this.destroyed) return {
|
|
1827
|
+
ok: false,
|
|
1828
|
+
message: "Discord voice manager is stopped."
|
|
1829
|
+
};
|
|
1771
1830
|
if (!this.voiceEnabled) return {
|
|
1772
1831
|
ok: false,
|
|
1773
1832
|
message: "Discord voice is disabled (channels.discord.voice.enabled)."
|
|
@@ -1803,7 +1862,7 @@ var DiscordVoiceManager$1 = class {
|
|
|
1803
1862
|
}
|
|
1804
1863
|
if (existing) {
|
|
1805
1864
|
logVoiceVerbose(`join: replacing existing session for guild ${guildId}`);
|
|
1806
|
-
await this.leave({ guildId });
|
|
1865
|
+
await this.leave({ guildId }, { preserveFollowState: options?.preserveFollowState });
|
|
1807
1866
|
}
|
|
1808
1867
|
const channelInfo = await this.params.client.fetchChannel(channelId).catch(() => null);
|
|
1809
1868
|
if (!channelInfo || "type" in channelInfo && !isVoiceChannel(channelInfo.type)) return {
|
|
@@ -1942,6 +2001,11 @@ var DiscordVoiceManager$1 = class {
|
|
|
1942
2001
|
};
|
|
1943
2002
|
if (voiceMode !== "stt-tts") {
|
|
1944
2003
|
entry.realtime = new DiscordRealtimeVoiceSession({
|
|
2004
|
+
bootstrapContextInstructions: await resolveDiscordVoiceRealtimeBootstrapContext({
|
|
2005
|
+
entry,
|
|
2006
|
+
cfg: this.params.cfg,
|
|
2007
|
+
discordConfig: this.params.discordConfig
|
|
2008
|
+
}),
|
|
1945
2009
|
cfg: this.params.cfg,
|
|
1946
2010
|
discordConfig: this.params.discordConfig,
|
|
1947
2011
|
entry,
|
|
@@ -2022,7 +2086,7 @@ var DiscordVoiceManager$1 = class {
|
|
|
2022
2086
|
channelId
|
|
2023
2087
|
};
|
|
2024
2088
|
}
|
|
2025
|
-
async leave(params) {
|
|
2089
|
+
async leave(params, options) {
|
|
2026
2090
|
const guildId = params.guildId.trim();
|
|
2027
2091
|
logVoiceVerbose(`leave requested: guild ${guildId} channel ${params.channelId ?? "current"}`);
|
|
2028
2092
|
const entry = this.sessions.get(guildId);
|
|
@@ -2036,6 +2100,10 @@ var DiscordVoiceManager$1 = class {
|
|
|
2036
2100
|
};
|
|
2037
2101
|
entry.stop();
|
|
2038
2102
|
this.sessions.delete(guildId);
|
|
2103
|
+
if (!options?.preserveFollowState) {
|
|
2104
|
+
this.followedVoiceGuilds.delete(guildId);
|
|
2105
|
+
this.deleteFollowedUserChannelsForGuild(guildId);
|
|
2106
|
+
}
|
|
2039
2107
|
logVoiceVerbose(`leave: disconnected from guild ${guildId} channel ${entry.channelId}`);
|
|
2040
2108
|
return {
|
|
2041
2109
|
ok: true,
|
|
@@ -2045,10 +2113,26 @@ var DiscordVoiceManager$1 = class {
|
|
|
2045
2113
|
};
|
|
2046
2114
|
}
|
|
2047
2115
|
async handleVoiceStateUpdate(data) {
|
|
2048
|
-
if (!this.botUserId || data.user_id !== this.botUserId) return;
|
|
2049
2116
|
const guildId = data.guild_id?.trim();
|
|
2117
|
+
const userId = data.user_id?.trim();
|
|
2050
2118
|
const channelId = data.channel_id?.trim();
|
|
2051
|
-
if (!guildId || !
|
|
2119
|
+
if (!guildId || !userId) return;
|
|
2120
|
+
if (this.botUserId && userId === this.botUserId) {
|
|
2121
|
+
await this.handleBotVoiceStateUpdate({
|
|
2122
|
+
guildId,
|
|
2123
|
+
channelId
|
|
2124
|
+
});
|
|
2125
|
+
return;
|
|
2126
|
+
}
|
|
2127
|
+
if (this.followUserIds.has(userId)) await this.handleFollowedUserVoiceStateUpdate({
|
|
2128
|
+
guildId,
|
|
2129
|
+
channelId,
|
|
2130
|
+
userId
|
|
2131
|
+
});
|
|
2132
|
+
}
|
|
2133
|
+
async handleBotVoiceStateUpdate(params) {
|
|
2134
|
+
const { guildId, channelId } = params;
|
|
2135
|
+
if (!channelId) return;
|
|
2052
2136
|
const existing = this.sessions.get(guildId);
|
|
2053
2137
|
if (this.isAllowedVoiceChannel({
|
|
2054
2138
|
guildId,
|
|
@@ -2059,7 +2143,7 @@ var DiscordVoiceManager$1 = class {
|
|
|
2059
2143
|
await this.join({
|
|
2060
2144
|
guildId,
|
|
2061
2145
|
channelId
|
|
2062
|
-
});
|
|
2146
|
+
}, { preserveFollowState: this.isFollowOwnedGuild(guildId) });
|
|
2063
2147
|
}
|
|
2064
2148
|
return;
|
|
2065
2149
|
}
|
|
@@ -2080,9 +2164,267 @@ var DiscordVoiceManager$1 = class {
|
|
|
2080
2164
|
await this.join(target);
|
|
2081
2165
|
}
|
|
2082
2166
|
}
|
|
2167
|
+
async handleFollowedUserVoiceStateUpdate(params) {
|
|
2168
|
+
if (!this.voiceEnabled || this.destroyed) return;
|
|
2169
|
+
const { guildId, channelId, userId } = params;
|
|
2170
|
+
const followKey = this.formatFollowedUserKey({
|
|
2171
|
+
guildId,
|
|
2172
|
+
userId
|
|
2173
|
+
});
|
|
2174
|
+
const existing = this.sessions.get(guildId);
|
|
2175
|
+
const wasFollowedVoiceSession = this.followedUserChannels.has(followKey) || this.followedVoiceGuilds.has(guildId);
|
|
2176
|
+
if (!channelId) {
|
|
2177
|
+
this.followedUserChannels.delete(followKey);
|
|
2178
|
+
if (existing && wasFollowedVoiceSession && !this.hasFollowedUserInChannel(existing)) await this.handoffToAnotherFollowedUserOrLeave({
|
|
2179
|
+
guildId,
|
|
2180
|
+
userId,
|
|
2181
|
+
existing,
|
|
2182
|
+
reason: "disconnected"
|
|
2183
|
+
});
|
|
2184
|
+
return;
|
|
2185
|
+
}
|
|
2186
|
+
if (!this.isAllowedVoiceChannel({
|
|
2187
|
+
guildId,
|
|
2188
|
+
channelId
|
|
2189
|
+
})) {
|
|
2190
|
+
this.followedUserChannels.delete(followKey);
|
|
2191
|
+
logger.warn(`discord voice: followed user joined non-allowed channel guild=${guildId} user=${userId} channel=${channelId}; ignoring`);
|
|
2192
|
+
if (existing && wasFollowedVoiceSession && !this.hasFollowedUserInChannel(existing)) await this.handoffToAnotherFollowedUserOrLeave({
|
|
2193
|
+
guildId,
|
|
2194
|
+
userId,
|
|
2195
|
+
existing,
|
|
2196
|
+
reason: "joined non-allowed channel"
|
|
2197
|
+
});
|
|
2198
|
+
return;
|
|
2199
|
+
}
|
|
2200
|
+
this.followedUserChannels.set(followKey, {
|
|
2201
|
+
guildId,
|
|
2202
|
+
channelId
|
|
2203
|
+
});
|
|
2204
|
+
if (existing?.channelId === channelId) {
|
|
2205
|
+
this.followedVoiceGuilds.add(guildId);
|
|
2206
|
+
return;
|
|
2207
|
+
}
|
|
2208
|
+
logger.info(`discord voice: following user guild=${guildId} user=${userId} channel=${channelId}`);
|
|
2209
|
+
const result = await this.join({
|
|
2210
|
+
guildId,
|
|
2211
|
+
channelId
|
|
2212
|
+
}, { preserveFollowState: true });
|
|
2213
|
+
if (!result.ok) {
|
|
2214
|
+
if (this.sessions.get(guildId)?.channelId === channelId) this.followedVoiceGuilds.add(guildId);
|
|
2215
|
+
else this.followedUserChannels.delete(followKey);
|
|
2216
|
+
logger.warn(`discord voice: failed to follow user guild=${guildId} user=${userId} channel=${channelId}: ${result.message}`);
|
|
2217
|
+
return;
|
|
2218
|
+
}
|
|
2219
|
+
this.followedVoiceGuilds.add(guildId);
|
|
2220
|
+
}
|
|
2083
2221
|
async destroy() {
|
|
2222
|
+
this.destroyed = true;
|
|
2223
|
+
if (this.followUsersReconcileTimer) {
|
|
2224
|
+
clearInterval(this.followUsersReconcileTimer);
|
|
2225
|
+
this.followUsersReconcileTimer = null;
|
|
2226
|
+
}
|
|
2084
2227
|
for (const entry of this.sessions.values()) entry.stop();
|
|
2085
2228
|
this.sessions.clear();
|
|
2229
|
+
this.followedUserChannels.clear();
|
|
2230
|
+
this.followedVoiceGuilds.clear();
|
|
2231
|
+
}
|
|
2232
|
+
resolveFollowGuildIds() {
|
|
2233
|
+
const guildIds = /* @__PURE__ */ new Set();
|
|
2234
|
+
for (const guildId of Object.keys(this.params.discordConfig.guilds ?? {})) {
|
|
2235
|
+
const normalized = guildId.trim();
|
|
2236
|
+
if (normalized) guildIds.add(normalized);
|
|
2237
|
+
}
|
|
2238
|
+
for (const entry of normalizeVoiceChannelResidencies(this.params.discordConfig.voice?.autoJoin)) guildIds.add(entry.guildId);
|
|
2239
|
+
for (const entry of this.allowedChannels ?? []) guildIds.add(entry.guildId);
|
|
2240
|
+
for (const entry of this.sessions.values()) guildIds.add(entry.guildId);
|
|
2241
|
+
return Array.from(guildIds);
|
|
2242
|
+
}
|
|
2243
|
+
ensureFollowUsersReconcileTimer() {
|
|
2244
|
+
if (this.followUserIds.size === 0) return;
|
|
2245
|
+
if (this.followUsersReconcileTimer) return;
|
|
2246
|
+
this.followUsersReconcileTimer = setInterval(() => {
|
|
2247
|
+
this.reconcileFollowedUsers("interval").catch((err) => {
|
|
2248
|
+
logger.warn(`discord voice: follow user reconciliation failed: ${formatErrorMessage(err)}`);
|
|
2249
|
+
});
|
|
2250
|
+
}, FOLLOW_USERS_RECONCILE_INTERVAL_MS);
|
|
2251
|
+
this.followUsersReconcileTimer.unref?.();
|
|
2252
|
+
}
|
|
2253
|
+
async reconcileFollowedUsers(reason) {
|
|
2254
|
+
if (this.followUserIds.size === 0 || this.destroyed) return;
|
|
2255
|
+
if (this.followUsersReconcileTask) return this.followUsersReconcileTask;
|
|
2256
|
+
this.followUsersReconcileTask = this.runFollowedUsersReconcile(reason).finally(() => {
|
|
2257
|
+
this.followUsersReconcileTask = null;
|
|
2258
|
+
});
|
|
2259
|
+
return this.followUsersReconcileTask;
|
|
2260
|
+
}
|
|
2261
|
+
async runFollowedUsersReconcile(reason) {
|
|
2262
|
+
if (this.destroyed) return;
|
|
2263
|
+
const guildIds = this.resolveFollowGuildIds();
|
|
2264
|
+
if (guildIds.length === 0) {
|
|
2265
|
+
logVoiceVerbose(`follow user reconcile skipped reason=${reason}: no Discord guild ids are configured`);
|
|
2266
|
+
return;
|
|
2267
|
+
}
|
|
2268
|
+
logVoiceVerbose(`follow user reconcile reason=${reason}: ${this.followUserIds.size} users across ${guildIds.length} guilds`);
|
|
2269
|
+
const plans = this.selectFollowUserReconcilePlans(guildIds, reason);
|
|
2270
|
+
for (const plan of plans) {
|
|
2271
|
+
for (const userId of plan.userIds) {
|
|
2272
|
+
const voiceState = await getGuildVoiceState(this.params.client.rest, plan.guildId, userId).catch((err) => {
|
|
2273
|
+
if (!isUnknownDiscordVoiceStateError(err)) {
|
|
2274
|
+
logger.warn(`discord voice: follow user reconcile skipped transient voice state error guild=${plan.guildId} user=${userId} reason=${reason}: ${formatErrorMessage(err)}`);
|
|
2275
|
+
return "transient-error";
|
|
2276
|
+
}
|
|
2277
|
+
logVoiceVerbose(`follow user reconcile reason=${reason}: no voice state guild ${plan.guildId} user ${userId}: ${formatErrorMessage(err)}`);
|
|
2278
|
+
});
|
|
2279
|
+
if (this.destroyed) return;
|
|
2280
|
+
if (voiceState === "transient-error") continue;
|
|
2281
|
+
const channelId = voiceState?.channel_id?.trim();
|
|
2282
|
+
await this.handleFollowedUserVoiceStateUpdate({
|
|
2283
|
+
guildId: plan.guildId,
|
|
2284
|
+
channelId,
|
|
2285
|
+
userId
|
|
2286
|
+
});
|
|
2287
|
+
}
|
|
2288
|
+
if (plan.checkBotVoiceState) {
|
|
2289
|
+
if (this.destroyed) return;
|
|
2290
|
+
await this.disconnectStaleFollowedBotVoiceState({
|
|
2291
|
+
guildId: plan.guildId,
|
|
2292
|
+
reason
|
|
2293
|
+
});
|
|
2294
|
+
}
|
|
2295
|
+
}
|
|
2296
|
+
}
|
|
2297
|
+
selectFollowUserReconcilePlans(guildIds, reason) {
|
|
2298
|
+
const followedUserIds = Array.from(this.followUserIds);
|
|
2299
|
+
if (followedUserIds.length === 0) return [];
|
|
2300
|
+
let remainingLookups = FOLLOW_USERS_RECONCILE_MAX_REST_LOOKUPS_PER_RUN;
|
|
2301
|
+
const guildLimit = Math.min(guildIds.length, FOLLOW_USERS_RECONCILE_MAX_GUILDS_PER_RUN);
|
|
2302
|
+
const start = this.followUsersReconcileGuildCursor % guildIds.length;
|
|
2303
|
+
const plans = [];
|
|
2304
|
+
for (let offset = 0; offset < guildLimit && remainingLookups > 0; offset += 1) {
|
|
2305
|
+
if (this.botUserId && remainingLookups === 1) break;
|
|
2306
|
+
const guildId = guildIds[(start + offset) % guildIds.length];
|
|
2307
|
+
const userLimit = this.resolveFollowUserReconcileUserLookupLimit(followedUserIds.length, remainingLookups);
|
|
2308
|
+
if (userLimit <= 0) break;
|
|
2309
|
+
const selection = this.selectFollowUserReconcileUserIds(guildId, followedUserIds, userLimit);
|
|
2310
|
+
plans.push({
|
|
2311
|
+
guildId,
|
|
2312
|
+
userIds: selection.userIds,
|
|
2313
|
+
checkedAllUsers: selection.completedCycle,
|
|
2314
|
+
checkBotVoiceState: false
|
|
2315
|
+
});
|
|
2316
|
+
remainingLookups -= selection.userIds.length;
|
|
2317
|
+
}
|
|
2318
|
+
this.followUsersReconcileGuildCursor = (start + plans.length) % guildIds.length;
|
|
2319
|
+
this.assignFollowUserReconcileBotChecks(guildIds, plans, remainingLookups);
|
|
2320
|
+
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`);
|
|
2321
|
+
return plans;
|
|
2322
|
+
}
|
|
2323
|
+
assignFollowUserReconcileBotChecks(guildIds, plans, remainingLookups) {
|
|
2324
|
+
if (!this.botUserId || remainingLookups <= 0 || plans.length === 0) return;
|
|
2325
|
+
const plansByGuild = new Map(plans.map((plan) => [plan.guildId, plan]));
|
|
2326
|
+
const start = this.followUsersReconcileBotGuildCursor % guildIds.length;
|
|
2327
|
+
let scanned = 0;
|
|
2328
|
+
let assigned = 0;
|
|
2329
|
+
for (; scanned < guildIds.length && assigned < remainingLookups; scanned += 1) {
|
|
2330
|
+
const guildId = guildIds[(start + scanned) % guildIds.length];
|
|
2331
|
+
const plan = plansByGuild.get(guildId);
|
|
2332
|
+
if (!plan?.checkedAllUsers) continue;
|
|
2333
|
+
plan.checkBotVoiceState = true;
|
|
2334
|
+
assigned += 1;
|
|
2335
|
+
}
|
|
2336
|
+
this.followUsersReconcileBotGuildCursor = (start + scanned) % guildIds.length;
|
|
2337
|
+
}
|
|
2338
|
+
resolveFollowUserReconcileUserLookupLimit(followedUserCount, remainingLookups) {
|
|
2339
|
+
const userLimit = Math.min(followedUserCount, remainingLookups);
|
|
2340
|
+
if (this.botUserId && followedUserCount > userLimit && remainingLookups > 1) return remainingLookups - 1;
|
|
2341
|
+
return userLimit;
|
|
2342
|
+
}
|
|
2343
|
+
selectFollowUserReconcileUserIds(guildId, followedUserIds, limit) {
|
|
2344
|
+
if (followedUserIds.length <= limit) {
|
|
2345
|
+
this.followUsersReconcileUserCursors.set(guildId, 0);
|
|
2346
|
+
return {
|
|
2347
|
+
userIds: followedUserIds,
|
|
2348
|
+
completedCycle: true
|
|
2349
|
+
};
|
|
2350
|
+
}
|
|
2351
|
+
const start = this.followUsersReconcileUserCursors.get(guildId) ?? 0;
|
|
2352
|
+
const selected = Array.from({ length: limit }, (_, offset) => followedUserIds[(start + offset) % followedUserIds.length]);
|
|
2353
|
+
const completedCycle = start + selected.length >= followedUserIds.length;
|
|
2354
|
+
this.followUsersReconcileUserCursors.set(guildId, (start + selected.length) % followedUserIds.length);
|
|
2355
|
+
return {
|
|
2356
|
+
userIds: selected,
|
|
2357
|
+
completedCycle
|
|
2358
|
+
};
|
|
2359
|
+
}
|
|
2360
|
+
formatFollowedUserKey(params) {
|
|
2361
|
+
return `${params.guildId}:${params.userId}`;
|
|
2362
|
+
}
|
|
2363
|
+
hasFollowedUserInChannel(entry) {
|
|
2364
|
+
return Array.from(this.followedUserChannels.values()).some((candidate) => candidate.guildId === entry.guildId && candidate.channelId === entry.channelId);
|
|
2365
|
+
}
|
|
2366
|
+
resolveFollowedUserHandoffTarget(guildId, currentChannelId) {
|
|
2367
|
+
for (const entry of this.followedUserChannels.values()) if (entry.guildId === guildId && entry.channelId !== currentChannelId && this.isAllowedVoiceChannel(entry)) return entry;
|
|
2368
|
+
return null;
|
|
2369
|
+
}
|
|
2370
|
+
async handoffToAnotherFollowedUserOrLeave(params) {
|
|
2371
|
+
const target = this.resolveFollowedUserHandoffTarget(params.guildId, params.existing.channelId);
|
|
2372
|
+
if (target) {
|
|
2373
|
+
logger.info(`discord voice: followed user ${params.reason} guild=${params.guildId} user=${params.userId}; moving to remaining followed user channel=${target.channelId}`);
|
|
2374
|
+
const result = await this.join(target, { preserveFollowState: true });
|
|
2375
|
+
if (result.ok) this.followedVoiceGuilds.add(params.guildId);
|
|
2376
|
+
else {
|
|
2377
|
+
logger.warn(`discord voice: failed to hand off followed user session guild=${params.guildId} channel=${target.channelId}: ${result.message}`);
|
|
2378
|
+
this.followedVoiceGuilds.delete(params.guildId);
|
|
2379
|
+
this.deleteFollowedUserChannelsForGuild(params.guildId);
|
|
2380
|
+
await this.leave({ guildId: params.guildId });
|
|
2381
|
+
}
|
|
2382
|
+
return;
|
|
2383
|
+
}
|
|
2384
|
+
logger.info(`discord voice: followed user ${params.reason} guild=${params.guildId} user=${params.userId}; leaving channel=${params.existing.channelId}`);
|
|
2385
|
+
await this.leave({ guildId: params.guildId });
|
|
2386
|
+
}
|
|
2387
|
+
isFollowOwnedGuild(guildId) {
|
|
2388
|
+
return this.followedVoiceGuilds.has(guildId) || Array.from(this.followedUserChannels.values()).some((entry) => entry.guildId === guildId);
|
|
2389
|
+
}
|
|
2390
|
+
deleteFollowedUserChannelsForGuild(guildId) {
|
|
2391
|
+
for (const [key, entry] of this.followedUserChannels.entries()) if (entry.guildId === guildId) this.followedUserChannels.delete(key);
|
|
2392
|
+
}
|
|
2393
|
+
async disconnectStaleFollowedBotVoiceState(params) {
|
|
2394
|
+
if (this.destroyed) return;
|
|
2395
|
+
const { guildId, reason } = params;
|
|
2396
|
+
if (Array.from(this.followedUserChannels.values()).some((entry) => entry.guildId === guildId)) return;
|
|
2397
|
+
const existing = this.sessions.get(guildId);
|
|
2398
|
+
if (existing) {
|
|
2399
|
+
if (this.followedVoiceGuilds.has(guildId)) {
|
|
2400
|
+
logger.info(`discord voice: follow reconcile leaving local session guild=${guildId} channel=${existing.channelId} reason=${reason}`);
|
|
2401
|
+
await this.leave({ guildId });
|
|
2402
|
+
}
|
|
2403
|
+
return;
|
|
2404
|
+
}
|
|
2405
|
+
if (!this.botUserId) return;
|
|
2406
|
+
const botVoiceState = await getGuildVoiceState(this.params.client.rest, guildId, this.botUserId).catch((err) => {
|
|
2407
|
+
if (!isUnknownDiscordVoiceStateError(err)) {
|
|
2408
|
+
logger.warn(`discord voice: follow reconcile skipped transient bot voice state error guild=${guildId} reason=${reason}: ${formatErrorMessage(err)}`);
|
|
2409
|
+
return "transient-error";
|
|
2410
|
+
}
|
|
2411
|
+
logVoiceVerbose(`follow user reconcile reason=${reason}: no bot voice state guild ${guildId}: ${formatErrorMessage(err)}`);
|
|
2412
|
+
});
|
|
2413
|
+
if (this.destroyed || botVoiceState === "transient-error") return;
|
|
2414
|
+
const botChannelId = botVoiceState?.channel_id?.trim();
|
|
2415
|
+
if (!botChannelId) return;
|
|
2416
|
+
const gateway = this.params.client.getPlugin("voice")?.getGateway(guildId);
|
|
2417
|
+
if (!gateway) {
|
|
2418
|
+
logger.warn(`discord voice: follow reconcile cannot disconnect stale bot voice state guild=${guildId} channel=${botChannelId}; gateway unavailable`);
|
|
2419
|
+
return;
|
|
2420
|
+
}
|
|
2421
|
+
logger.info(`discord voice: follow reconcile disconnecting stale bot voice state guild=${guildId} channel=${botChannelId} reason=${reason}`);
|
|
2422
|
+
gateway.updateVoiceState({
|
|
2423
|
+
guild_id: guildId,
|
|
2424
|
+
channel_id: null,
|
|
2425
|
+
self_mute: false,
|
|
2426
|
+
self_deaf: false
|
|
2427
|
+
});
|
|
2086
2428
|
}
|
|
2087
2429
|
resolveVoiceResidencyTarget(guildId) {
|
|
2088
2430
|
const autoJoinTarget = normalizeVoiceChannelResidencies(this.params.discordConfig.voice?.autoJoin).toReversed().find((entry) => entry.guildId === guildId);
|
|
@@ -2306,8 +2648,9 @@ var DiscordVoiceManager$1 = class {
|
|
|
2306
2648
|
async recoverFromDecryptFailures(entry) {
|
|
2307
2649
|
const active = this.sessions.get(entry.guildId);
|
|
2308
2650
|
if (!active || active.connection !== entry.connection) return;
|
|
2651
|
+
const preserveFollowState = this.isFollowOwnedGuild(entry.guildId);
|
|
2309
2652
|
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 });
|
|
2653
|
+
const leaveResult = await this.leave({ guildId: entry.guildId }, { preserveFollowState });
|
|
2311
2654
|
if (!leaveResult.ok) {
|
|
2312
2655
|
logger.warn(`discord voice: decrypt recovery leave failed: ${leaveResult.message}`);
|
|
2313
2656
|
return;
|
|
@@ -2315,7 +2658,7 @@ var DiscordVoiceManager$1 = class {
|
|
|
2315
2658
|
const result = await this.join({
|
|
2316
2659
|
guildId: entry.guildId,
|
|
2317
2660
|
channelId: entry.channelId
|
|
2318
|
-
});
|
|
2661
|
+
}, { preserveFollowState });
|
|
2319
2662
|
if (!result.ok) logger.warn(`discord voice: rejoin after decrypt failures failed: ${result.message}`);
|
|
2320
2663
|
}
|
|
2321
2664
|
};
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { N as createDiscordRestClient } from "./send.shared-
|
|
2
|
-
import { d as resolveDiscordChannelNameSafe, l as resolveDiscordChannelIdSafe, p as resolveDiscordChannelParentSafe, u as resolveDiscordChannelInfoSafe } from "./thread-bindings.discord-api-
|
|
3
|
-
import { a as mergeAbortSignals } from "./timeouts-
|
|
4
|
-
import { c as hasDiscordMessageStickers, d as resolveDiscordMessageChannelId, r as resolveDiscordMessageText } from "./message-utils-
|
|
5
|
-
import { t as sendTyping } from "./typing-
|
|
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-
|
|
124
|
+
messageProcessRuntimePromise ??= import("./message-handler.process-AA6doeek.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-
|
|
176
|
+
messagePreflightRuntimePromise ??= import("./message-handler.preflight-DsNzvkrd.js");
|
|
177
177
|
return await messagePreflightRuntimePromise;
|
|
178
178
|
}
|
|
179
179
|
function isNonEmptyString(value) {
|
package/dist/{message-handler.preflight-DQ-oPY7m.js → message-handler.preflight-DsNzvkrd.js}
RENAMED
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
import { A as Message, c as discord_exports, mt as getChannelMessage } from "./send.receipt-
|
|
2
|
-
import { o as resolveDefaultDiscordAccountId } from "./accounts-
|
|
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-
|
|
4
|
-
import { t as resolveDiscordConversationIdentity } from "./conversation-identity-
|
|
5
|
-
import { l as isRecentlyUnboundThreadWebhookMessage } from "./thread-bindings.state-
|
|
6
|
-
import { d as resolveDiscordChannelNameSafe, u as resolveDiscordChannelInfoSafe } from "./thread-bindings.discord-api-
|
|
7
|
-
import "./thread-bindings-
|
|
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-
|
|
9
|
-
import { d as resolveDiscordMessageChannelId, l as resolveDiscordMessageStickers, o as resolveMediaList, r as resolveDiscordMessageText, u as resolveDiscordChannelInfo } from "./message-utils-
|
|
10
|
-
import { n as resolveDiscordWebhookId, t as resolveDiscordSenderIdentity } from "./sender-identity-
|
|
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-CfxRE5oz.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-
|
|
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-
|
|
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-
|
|
434
|
+
preflightAudioRuntimePromise ??= import("./preflight-audio-ClWbnQto.js");
|
|
435
435
|
return await preflightAudioRuntimePromise;
|
|
436
436
|
}
|
|
437
437
|
async function loadSystemEventsRuntime() {
|
|
438
|
-
systemEventsRuntimePromise ??= import("./system-events-
|
|
438
|
+
systemEventsRuntimePromise ??= import("./system-events-HgHeiMHg.js");
|
|
439
439
|
return await systemEventsRuntimePromise;
|
|
440
440
|
}
|
|
441
441
|
async function loadDiscordThreadingRuntime() {
|
|
442
|
-
discordThreadingRuntimePromise ??= import("./provider-
|
|
442
|
+
discordThreadingRuntimePromise ??= import("./provider-CfxRE5oz.js").then((n) => n.v);
|
|
443
443
|
return await discordThreadingRuntimePromise;
|
|
444
444
|
}
|
|
445
445
|
function isPreflightAborted(abortSignal) {
|