Skip to content

Commit 9cd50c5

Browse files
steipetefrankekndocaohieu2808
committed
fix(discord): harden voice DAVE receive reliability (#25861)
Reimplements and consolidates related work: - #24339 stale disconnect/destroyed session guards - #25312 voice listener cleanup on stop - #23036 restore @snazzah/davey runtime dependency Adds Discord voice DAVE config passthrough, repeated decrypt failure rejoin recovery, regression tests, docs, and changelog updates. Co-authored-by: Frank Yang <[email protected]> Co-authored-by: Do Cao Hieu <[email protected]>
1 parent 1839ba8 commit 9cd50c5

File tree

11 files changed

+555
-12
lines changed

11 files changed

+555
-12
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ Docs: https://docs.openclaw.ai
3232
- Automation/Subagent/Cron reliability: honor `ANNOUNCE_SKIP` in `sessions_spawn` completion/direct announce flows (no user-visible token leaks), add transient direct-announce retries for channel unavailability (for example WhatsApp listener reconnect windows), and include `cron` in the `coding` tool profile so `/tools/invoke` can execute cron actions when explicitly allowed by gateway policy. (#25800, #25656, #25842, #25813, #25822, #25821) Thanks @astra-fer, @aaajiao, @dwight11232-coder, @kevinWangSheng, @widingmarcus-cyber, and @stakeswky.
3333
- Discord/Proxy + reactions + model picker: thread channel proxy fetch into inbound media/sticker downloads, use proxy-aware gateway metadata fetch for WSL/corporate proxy setups, wire `messages.statusReactions.{emojis,timing}` into Discord reaction lifecycle control, and compact model-picker `custom_id` keys to stay under Discord's 100-char limit while keeping backward-compatible parsing. (#25232, #25507, #25564, #25695) Thanks @openperf, @chilu18, @Yipsh, @lbo728, and @s1korrrr.
3434
- Discord/Block streaming: restore block-streamed reply delivery by suppressing only reasoning payloads (instead of all `block` payloads), fixing missing Discord replies in `channels.discord.streaming=block` mode. (#25839, #25836, #25792) Thanks @pewallin.
35+
- Discord/Voice reliability: restore runtime DAVE dependency (`@snazzah/davey`), add configurable DAVE join options (`channels.discord.voice.daveEncryption` and `channels.discord.voice.decryptionFailureTolerance`), clean up voice listeners/session teardown, guard against stale connection events, and trigger controlled rejoin recovery after repeated decrypt failures to improve inbound STT stability under DAVE receive errors. (#25861, #25372, #24883, #24825, #23890, #23105, #22961, #23421, #23278, #23032)
3536
- Matrix/Read receipts: send read receipts as soon as Matrix messages arrive (before handler pipeline work), so clients no longer show long-lived unread/sent states while replies are processing. (#25841, #25840) Thanks @joshjhall.
3637
- Sandbox/FS bridge: build canonical-path shell scripts with newline separators (not `; ` joins) to avoid POSIX `sh` `do;` syntax errors that broke sandbox file/image read-write operations. (#25737, #25824, #25868) Thanks @DennisGoldfinger and @peteragility.
3738
- Routing/Session isolation: harden followup routing so explicit cross-channel origin replies never fall back to the active dispatcher on route failure, preserve queued overflow summary routing metadata (`channel`/`to`/`thread`) across followup drain, and prefer originating channel context over internal provider tags for embedded followup runs. This prevents webchat/control-ui context from hijacking Discord-targeted replies in shared sessions. (#25864) Thanks @Gamedesigner.

docs/channels/discord.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -919,6 +919,8 @@ Auto-join example:
919919
channelId: "234567890123456789",
920920
},
921921
],
922+
daveEncryption: true,
923+
decryptionFailureTolerance: 24,
922924
tts: {
923925
provider: "openai",
924926
openai: { voice: "alloy" },
@@ -933,6 +935,8 @@ Notes:
933935

934936
- `voice.tts` overrides `messages.tts` for voice playback only.
935937
- Voice is enabled by default; set `channels.discord.voice.enabled=false` to disable it.
938+
- `voice.daveEncryption` and `voice.decryptionFailureTolerance` pass through to `@discordjs/voice` join options.
939+
- If receive logs repeatedly show `DecryptionFailed(UnencryptedWhenPassthroughDisabled)`, this may be the upstream `@discordjs/voice` receive bug tracked in [discord.js #11419](https://github.com/discordjs/discord.js/issues/11419).
936940

937941
## Voice messages
938942

docs/gateway/configuration-reference.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -255,6 +255,8 @@ WhatsApp runs through the gateway's web channel (Baileys Web). It starts automat
255255
channelId: "234567890123456789",
256256
},
257257
],
258+
daveEncryption: true,
259+
decryptionFailureTolerance: 24,
258260
tts: {
259261
provider: "openai",
260262
openai: { voice: "alloy" },
@@ -282,6 +284,7 @@ WhatsApp runs through the gateway's web channel (Baileys Web). It starts automat
282284
- `spawnSubagentSessions`: opt-in switch for `sessions_spawn({ thread: true })` auto thread creation/binding
283285
- `channels.discord.ui.components.accentColor` sets the accent color for Discord components v2 containers.
284286
- `channels.discord.voice` enables Discord voice channel conversations and optional auto-join + TTS overrides.
287+
- `channels.discord.voice.daveEncryption` and `channels.discord.voice.decryptionFailureTolerance` pass through to `@discordjs/voice` DAVE options.
285288
- `channels.discord.streaming` is the canonical stream mode key. Legacy `streamMode` and boolean `streaming` values are auto-migrated.
286289
- `channels.discord.dangerouslyAllowNameMatching` re-enables mutable name/tag matching (break-glass compatibility mode).
287290

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,7 @@
159159
"@sinclair/typebox": "0.34.48",
160160
"@slack/bolt": "^4.6.0",
161161
"@slack/web-api": "^7.14.1",
162+
"@snazzah/davey": "^0.1.9",
162163
"@whiskeysockets/baileys": "7.0.0-rc.9",
163164
"ajv": "^8.18.0",
164165
"chalk": "^5.6.2",

pnpm-lock.yaml

Lines changed: 151 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/config/schema.help.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1364,6 +1364,10 @@ export const FIELD_HELP: Record<string, string> = {
13641364
"Enable Discord voice channel conversations (default: true). Omit channels.discord.voice to keep voice support disabled for the account.",
13651365
"channels.discord.voice.autoJoin":
13661366
"Voice channels to auto-join on startup (list of guildId/channelId entries).",
1367+
"channels.discord.voice.daveEncryption":
1368+
"Toggle DAVE end-to-end encryption for Discord voice joins (default: true in @discordjs/voice; Discord may require this).",
1369+
"channels.discord.voice.decryptionFailureTolerance":
1370+
"Consecutive decrypt failures before DAVE attempts session recovery (passed to @discordjs/voice; default: 24).",
13671371
"channels.discord.voice.tts":
13681372
"Optional TTS overrides for Discord voice playback (merged with messages.tts).",
13691373
"channels.discord.intents.presence":

src/config/schema.labels.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -677,6 +677,8 @@ export const FIELD_LABELS: Record<string, string> = {
677677
"channels.discord.intents.guildMembers": "Discord Guild Members Intent",
678678
"channels.discord.voice.enabled": "Discord Voice Enabled",
679679
"channels.discord.voice.autoJoin": "Discord Voice Auto-Join",
680+
"channels.discord.voice.daveEncryption": "Discord Voice DAVE Encryption",
681+
"channels.discord.voice.decryptionFailureTolerance": "Discord Voice Decrypt Failure Tolerance",
680682
"channels.discord.voice.tts": "Discord Voice Text-to-Speech",
681683
"channels.discord.pluralkit.enabled": "Discord PluralKit Enabled",
682684
"channels.discord.pluralkit.token": "Discord PluralKit Token",

src/config/types.discord.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,10 @@ export type DiscordVoiceConfig = {
107107
enabled?: boolean;
108108
/** Voice channels to auto-join on startup. */
109109
autoJoin?: DiscordVoiceAutoJoinConfig[];
110+
/** Enable/disable DAVE end-to-end encryption (default: true; Discord may require this). */
111+
daveEncryption?: boolean;
112+
/** Consecutive decrypt failures before DAVE session reinitialization (default: 24). */
113+
decryptionFailureTolerance?: number;
110114
/** Optional TTS overrides for Discord voice output. */
111115
tts?: TtsConfig;
112116
};

src/config/zod-schema.providers-core.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -315,6 +315,8 @@ const DiscordVoiceSchema = z
315315
.object({
316316
enabled: z.boolean().optional(),
317317
autoJoin: z.array(DiscordVoiceAutoJoinSchema).optional(),
318+
daveEncryption: z.boolean().optional(),
319+
decryptionFailureTolerance: z.number().int().min(0).optional(),
318320
tts: TtsConfigSchema.optional(),
319321
})
320322
.strict()

0 commit comments

Comments
 (0)