@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.
- 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-BswuOAN6.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-Dq0mc5K0.js} +364 -22
- package/dist/{message-handler-1NV0WiHC.js → message-handler-wQJd4Peh.js} +7 -7
- package/dist/{message-handler.preflight-DQ-oPY7m.js → message-handler.preflight-ANdoLbtA.js} +16 -18
- package/dist/{message-handler.process-PpgZ0qC4.js → message-handler.process-DG4qm0sQ.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-CzKMDsSE.js} +45 -64
- package/dist/{provider-session.runtime-DVfzQxFH.js → provider-session.runtime-D0XbJS5X.js} +3 -3
- package/dist/provider.runtime-CUUefRl3.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-D1psRR2u.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-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 [
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
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 || !
|
|
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-
|
|
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-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-
|
|
176
|
+
messagePreflightRuntimePromise ??= import("./message-handler.preflight-ANdoLbtA.js");
|
|
177
177
|
return await messagePreflightRuntimePromise;
|
|
178
178
|
}
|
|
179
179
|
function isNonEmptyString(value) {
|
package/dist/{message-handler.preflight-DQ-oPY7m.js → message-handler.preflight-ANdoLbtA.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-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-
|
|
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-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
|
}
|