@openclaw/discord 2026.9.1-beta.1 → 2026.9.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.
Files changed (93) hide show
  1. package/dist/account-inspect-BY-ve3yH.js +45 -0
  2. package/dist/account-inspect-api.js +1 -1
  3. package/dist/{accounts-CfQ-vSyf.js → accounts-CwJQoLjM.js} +89 -45
  4. package/dist/action-runtime-api.js +1 -1
  5. package/dist/{activities-api-q-9PaaHH.js → activities-api-E-segZn6.js} +30 -17
  6. package/dist/activities-api.js +1 -1
  7. package/dist/{allow-list-BDMimASD.js → allow-list-C2JuH-R0.js} +10 -6
  8. package/dist/{api-DNVbJyEy.js → api-BfmEP6wp.js} +6 -5
  9. package/dist/api.js +18 -18
  10. package/dist/{approval-handler.runtime-B7qhK3fR.js → approval-handler.runtime-CW5k3mSa.js} +19 -12
  11. package/dist/{audit-CBEv_ERu.js → audit-B9rydv5a.js} +8 -7
  12. package/dist/{channel-Dx1tMTfx.js → channel-D93LnbTE.js} +29 -23
  13. package/dist/{channel-actions.runtime-CLWWu9nC.js → channel-actions.runtime-DMFv4doE.js} +16 -13
  14. package/dist/channel-config-api.js +1 -1
  15. package/dist/channel-plugin-api.js +1 -1
  16. package/dist/{channel.setup-DOzXS2Pk.js → channel.setup-DTL7kPOM.js} +18 -18
  17. package/dist/{components-B9V5o361.js → components-DmXYIQ26.js} +111 -149
  18. package/dist/{config-schema-BR13IAx6.js → config-schema-B797-Spt.js} +19 -12
  19. package/dist/{conversation-binding-route-DJYrY2TQ.js → conversation-binding-route-24afmvEC.js} +1 -1
  20. package/dist/{directory-config-BK6eqekJ.js → directory-config-BD4YL7wT.js} +2 -2
  21. package/dist/directory-contract-api.js +1 -1
  22. package/dist/{directory-live-DSAJSrJk.js → directory-live-BrFVc1Ds.js} +4 -4
  23. package/dist/{doctor-Cm7Y1pJ2.js → doctor-BUB41_lr.js} +5 -5
  24. package/dist/{doctor-contract-DsWvKIXF.js → doctor-contract-Co5vRCZ6.js} +9 -6
  25. package/dist/doctor-contract-api.js +3 -2
  26. package/dist/{handle-action.guild-admin-BdwCRHmm.js → handle-action.guild-admin-B0egstYq.js} +2 -2
  27. package/dist/index.js +1 -1
  28. package/dist/ingress-identity-BCzfPPYM.js +60 -0
  29. package/dist/{message-handler-BXpWZyni.js → message-handler-Qdw9c0j4.js} +14 -10
  30. package/dist/{message-handler.preflight-Ba5LAY_X.js → message-handler.preflight-Dxi2yBfR.js} +41 -101
  31. package/dist/{message-handler.process-3HEzmemS.js → message-handler.process-BYDjtxZJ.js} +83 -109
  32. package/dist/{message-text-aiwO5R2F.js → message-text-BRVqYm-t.js} +11 -6
  33. package/dist/{outbound-adapter-BE4jSq2d.js → outbound-adapter-DEhthWTk.js} +52 -67
  34. package/dist/{outbound-components-oLpg8Qzb.js → outbound-components-DehyxvA4.js} +5 -4
  35. package/dist/{outbound-session-route-Cg15ZFJd.js → outbound-session-route-BFGRF9fE.js} +55 -12
  36. package/dist/{owner-access-UlYi9t0M.js → owner-access-yc1sX7Gx.js} +7 -6
  37. package/dist/{pluralkit-Tiyl70dx.js → pluralkit-XmmAHoV6.js} +2 -2
  38. package/dist/{probe-n6ZXxK8V.js → probe-3ovFAp3b.js} +3 -3
  39. package/dist/{probe.runtime-CN4bdPfZ.js → probe.runtime-BckHn3cJ.js} +1 -1
  40. package/dist/{provider-B11xwilq.js → provider-DuDtKbF8.js} +294 -131
  41. package/dist/{provider-session.runtime-B9xe-Qaf.js → provider-session.runtime-BA2BPyZ4.js} +3 -3
  42. package/dist/provider.runtime-Db8YwZBv.js +2 -0
  43. package/dist/{realtime-session.runtime-CU8IQUS-.js → realtime-session.runtime-DgSbX6ay.js} +103 -163
  44. package/dist/{resolve-allowlist-common-BLoYaxEG.js → resolve-allowlist-common-BJ5UZNNT.js} +3 -3
  45. package/dist/{resolve-channels-C2sT_n67.js → resolve-channels-CYseD5Uw.js} +4 -4
  46. package/dist/{resolve-users-CzpjLwjy.js → resolve-users-DrmhDrqm.js} +5 -4
  47. package/dist/{retry-Cv4jCU5Z.js → retry-BNCxiyyR.js} +120 -32
  48. package/dist/{retry-after-DdLPmPoa.js → retry-after-BrLjLUJi.js} +2 -1
  49. package/dist/{runtime-BHrTlFkf.js → runtime-BbWNtfyq.js} +127 -93
  50. package/dist/{runtime-CY4PRMF-.js → runtime-DB7Fb6AU.js} +2 -2
  51. package/dist/runtime-api.js +19 -19
  52. package/dist/{secret-config-contract-B3i6WxV5.js → secret-config-contract-DFu9hfU8.js} +14 -6
  53. package/dist/secret-contract-api.js +1 -1
  54. package/dist/{security-audit-BfJhAXZp.js → security-audit-DKfK-iPY.js} +10 -11
  55. package/dist/security-audit-contract-api.js +1 -1
  56. package/dist/{security-audit.runtime-BVKF9VtY.js → security-audit.runtime-sKZyKgpx.js} +1 -1
  57. package/dist/{send-C49MFF9j.js → send-BnTEIeLE.js} +132 -100
  58. package/dist/{send.components-DKKAw5VX.js → send.components-BWVEcjRP.js} +21 -15
  59. package/dist/{send.outbound-zam0TrZx.js → send.outbound-b5xwHTlL.js} +35 -22
  60. package/dist/{send.shared-JjljcV4O.js → send.shared-5vxBTagO.js} +25 -18
  61. package/dist/{sender-identity-BJtfyise.js → sender-identity-Dt0imZyY.js} +1 -1
  62. package/dist/setup-plugin-api.js +1 -1
  63. package/dist/{shared-_5EcP4jW.js → shared-BSJWHEMA.js} +20 -14
  64. package/dist/{subagent-hooks-DQzvOptn.js → subagent-hooks-IzQKX4RQ.js} +2 -2
  65. package/dist/subagent-hooks-api.js +1 -1
  66. package/dist/{system-events-C7yxaHWP.js → system-events-BOiDS8b3.js} +2 -2
  67. package/dist/{target-resolver-vxIh6O3-.js → target-resolver-BVI8xSSC.js} +6 -5
  68. package/dist/targets-DbxVbq8k.js +3 -0
  69. package/dist/{thread-bindings-DW5F9vat.js → thread-bindings-D7mcaXQC.js} +6 -5
  70. package/dist/{thread-bindings.manager-ByOtwjo_.js → thread-bindings.manager-B1oySiVc.js} +37 -28
  71. package/dist/{thread-bindings.session-updates-CJb-BpPL.js → thread-bindings.session-updates-CC7HoQvt.js} +2 -1
  72. package/dist/{threading-agH1T_6s.js → threading-OQnL-0Zx.js} +8 -6
  73. package/dist/{timeouts-B9cy6RvQ.js → timeouts-D86uWLt_.js} +1 -1
  74. package/dist/{transcripts-source-BR11iHA4.js → transcripts-source-D8lH7AkN.js} +9 -4
  75. package/dist/transcripts-source-api.js +1 -1
  76. package/dist/{typing-Dc_YMY2e.js → typing-C9q0AQMb.js} +2 -2
  77. package/dist/{voice-runtime-DIeaa8fJ.js → voice-runtime-Dfhjh1tV.js} +433 -93
  78. package/node_modules/@discord/embedded-app-sdk/node_modules/@types/lodash/README.md +1 -1
  79. package/node_modules/@discord/embedded-app-sdk/node_modules/@types/lodash/conforms.d.ts +2 -0
  80. package/node_modules/@discord/embedded-app-sdk/node_modules/@types/lodash/package.json +3 -3
  81. package/node_modules/@discord/embedded-app-sdk/node_modules/@types/lodash/stubArray.d.ts +2 -0
  82. package/node_modules/@discord/embedded-app-sdk/node_modules/@types/lodash/stubObject.d.ts +2 -0
  83. package/node_modules/@discord/embedded-app-sdk/node_modules/@types/lodash/stubString.d.ts +2 -0
  84. package/node_modules/typebox/build/format/email.mjs +1 -1
  85. package/node_modules/typebox/build/format/idna/idn-hostname.mjs +19 -1
  86. package/node_modules/typebox/package.json +1 -1
  87. package/openclaw.plugin.json +14 -6
  88. package/package.json +6 -5
  89. package/skills/discord/SKILL.md +1 -1
  90. package/dist/account-inspect-BDfKyuvL.js +0 -89
  91. package/dist/provider.runtime-DiYaHvOz.js +0 -2
  92. package/dist/sdk-runtime-4geQHtXc.js +0 -338
  93. package/dist/targets-CtTKvntJ.js +0 -3
@@ -1,24 +1,356 @@
1
- import { D as ReadyListener, L as isUnknownDiscordVoiceStateError, O as ResumedListener, Yt as getGuildVoiceState, _ as parseDiscordTarget, j as VoiceStateUpdateListener, y as discord_exports } from "./retry-Cv4jCU5Z.js";
1
+ import { M as VoiceStateUpdateListener, O as ReadyListener, R as isUnknownDiscordVoiceStateError, Xt as getGuildVoiceState, b as discord_exports, k as ResumedListener, sn as __exportAll, v as parseDiscordTarget } from "./retry-BNCxiyyR.js";
2
2
  import { t as getDiscordRuntime } from "./runtime-DgnVQ7zW.js";
3
- import { a as normalizeDiscordSlug, h as resolveDiscordOwnerAccess, x as formatDiscordUserTag } from "./allow-list-BDMimASD.js";
4
- import { a as formatMention } from "./send.outbound-zam0TrZx.js";
5
- import { n as resolveDiscordVoiceEnabled, r as authorizeDiscordVoiceIngress, t as resolveDiscordVoiceAccess } from "./owner-access-UlYi9t0M.js";
6
- import { p as buildDiscordGroupSystemPrompt, y as resolveFetchedDiscordThreadLikeChannelContext } from "./provider-B11xwilq.js";
7
- import { _ as decodeOpusStreamChunks, a as VOICE_CONNECT_READY_TIMEOUT_MS, b as maybeControlDiscordVoiceAgentRun, c as isVoiceChannel, d as resolveVoiceTimeoutMs, g as decodeOpusStream, h as createDiscordOpusPlaybackStream, i as PLAYBACK_READY_TIMEOUT_MS, l as logVoiceVerbose, n as CAPTURE_FINALIZE_GRACE_MS, o as VOICE_RECONNECT_GRACE_MS, s as isDiscordRealtimeVoiceMode, t as loadDiscordVoiceSdk, u as resolveDiscordVoiceMode, v as writeVoiceWavFile, x as formatVoiceLogPreview, y as formatVoiceIngressPrompt } from "./sdk-runtime-4geQHtXc.js";
3
+ import { a as normalizeDiscordSlug, h as resolveDiscordOwnerAccess, x as formatDiscordUserTag } from "./allow-list-C2JuH-R0.js";
4
+ import { a as formatMention } from "./send.outbound-b5xwHTlL.js";
5
+ import { n as resolveDiscordVoiceEnabled, r as authorizeDiscordVoiceIngress, t as resolveDiscordVoiceAccess } from "./owner-access-yc1sX7Gx.js";
6
+ import { b as resolveFetchedDiscordThreadLikeChannelContext, m as buildDiscordGroupSystemPrompt } from "./provider-DuDtKbF8.js";
7
+ import { createRequire } from "node:module";
8
+ import fs from "node:fs/promises";
8
9
  import { asDateTimestampMs, resolveExpiresAtMsFromDurationMs } from "openclaw/plugin-sdk/number-runtime";
9
10
  import { expectDefined } from "openclaw/plugin-sdk/expect-runtime";
11
+ import { readByteStreamWithLimit } from "openclaw/plugin-sdk/response-limit-runtime";
10
12
  import { formatErrorMessage } from "openclaw/plugin-sdk/ssrf-runtime";
11
13
  import { resolveAgentRoute } from "openclaw/plugin-sdk/routing";
12
14
  import { normalizeOptionalString } from "openclaw/plugin-sdk/string-coerce-runtime";
13
- import { createSubsystemLogger } from "openclaw/plugin-sdk/runtime-env";
15
+ import { createSubsystemLogger, logVerbose, shouldLogVerbose } from "openclaw/plugin-sdk/runtime-env";
14
16
  import { escapeRegExp, truncateUtf16Safe } from "openclaw/plugin-sdk/text-utility-runtime";
15
17
  import { stripInlineDirectiveTagsForDisplay } from "openclaw/plugin-sdk/text-chunking";
16
- import { unlinkIfExists } from "openclaw/plugin-sdk/media-runtime";
18
+ import { resolveFfmpegBin, unlinkIfExists } from "openclaw/plugin-sdk/media-runtime";
19
+ import { resolvePreferredOpenClawTmpDir, tempWorkspace } from "openclaw/plugin-sdk/temp-path";
17
20
  import { resolveAgentDir } from "openclaw/plugin-sdk/agent-runtime";
18
21
  import { enqueueRoutedSystemEvent } from "openclaw/plugin-sdk/system-event-runtime";
19
- import { Readable } from "node:stream";
20
- import { OpusError } from "libopus-wasm";
22
+ import { controlRealtimeVoiceAgentRun, resamplePcm, shouldAutoControlRealtimeVoiceAgentText } from "openclaw/plugin-sdk/realtime-voice";
23
+ import { spawn } from "node:child_process";
24
+ import { Readable, Transform } from "node:stream";
25
+ import { StringDecoder } from "node:string_decoder";
26
+ import { Application, OpusError, createDecoder, createEncoder } from "libopus-wasm";
21
27
  import { resolveRealtimeBootstrapContextInstructions } from "openclaw/plugin-sdk/realtime-bootstrap-context";
28
+ //#region extensions/discord/src/voice/log-preview.ts
29
+ const DISCORD_VOICE_LOG_PREVIEW_CHARS = 500;
30
+ function formatVoiceLogPreview(text) {
31
+ const oneLine = text.replace(/\s+/g, " ").trim();
32
+ if (oneLine.length <= DISCORD_VOICE_LOG_PREVIEW_CHARS) return oneLine;
33
+ return `${truncateUtf16Safe(oneLine, DISCORD_VOICE_LOG_PREVIEW_CHARS)}...`;
34
+ }
35
+ //#endregion
36
+ //#region extensions/discord/src/voice/agent-control.ts
37
+ async function maybeControlDiscordVoiceAgentRun(params) {
38
+ if (!shouldAutoControlRealtimeVoiceAgentText(params.text)) return { handled: false };
39
+ const result = await controlRealtimeVoiceAgentRun({
40
+ sessionKey: params.entry.route.sessionKey,
41
+ text: params.text
42
+ });
43
+ if (!result.active) return {
44
+ handled: false,
45
+ result
46
+ };
47
+ return {
48
+ handled: true,
49
+ result,
50
+ ...result.speak && !result.suppress ? { speakText: result.message } : {}
51
+ };
52
+ }
53
+ //#endregion
54
+ //#region extensions/discord/src/voice/prompt.ts
55
+ const DISCORD_VOICE_SPOKEN_OUTPUT_CONTRACT = [
56
+ "You are OpenClaw's Discord voice interface in a live voice channel.",
57
+ "Discord voice reply requirements:",
58
+ "- Return only the concise text that should be spoken aloud in the voice channel.",
59
+ "- Treat the transcript as speech-to-text from a live conversation; repair obvious transcription artifacts and ignore repeated partial fragments caused by voice buffering.",
60
+ "- If the transcript is garbled, incomplete, or missing the user's intent, ask one brief clarifying question instead of guessing.",
61
+ "- If the request needs deeper reasoning, current information, or tools, use the available tools before answering.",
62
+ "- Do not call the tts tool; Discord voice will synthesize and play the returned text.",
63
+ "- Do not reply with NO_REPLY unless no spoken response is appropriate.",
64
+ "- Keep the response brief, natural, and conversational. Prefer one to three short sentences.",
65
+ "- Avoid markdown tables, code fences, citations, and visual formatting unless the user explicitly asks for something that cannot be spoken naturally."
66
+ ].join("\n");
67
+ function formatVoiceIngressPrompt(transcript, speakerLabel) {
68
+ const cleanedTranscript = transcript.trim();
69
+ const cleanedLabel = speakerLabel?.trim();
70
+ const voiceInput = cleanedLabel ? [`Voice transcript from speaker "${cleanedLabel}":`, cleanedTranscript].join("\n") : cleanedTranscript;
71
+ return [DISCORD_VOICE_SPOKEN_OUTPUT_CONTRACT, voiceInput].join("\n\n");
72
+ }
73
+ //#endregion
74
+ //#region extensions/discord/src/voice/audio.ts
75
+ const SAMPLE_RATE = 48e3;
76
+ const CHANNELS = 2;
77
+ const BIT_DEPTH = 16;
78
+ const FFMPEG_ERROR_OUTPUT_BYTES = 8192;
79
+ const DISCORD_OPUS_FRAME_SIZE = 960;
80
+ const DISCORD_OPUS_FRAME_BYTES = DISCORD_OPUS_FRAME_SIZE * CHANNELS * (BIT_DEPTH / 8);
81
+ const FFMPEG_PCM_ARGUMENTS = [
82
+ "-analyzeduration",
83
+ "0",
84
+ "-loglevel",
85
+ "error",
86
+ "-vn",
87
+ "-sn",
88
+ "-dn",
89
+ "-f",
90
+ "s16le",
91
+ "-ar",
92
+ String(SAMPLE_RATE),
93
+ "-ac",
94
+ String(CHANNELS)
95
+ ];
96
+ let warnedOpusMissing = false;
97
+ function buildWavBuffer(pcm) {
98
+ const blockAlign = 4;
99
+ const byteRate = SAMPLE_RATE * blockAlign;
100
+ const header = Buffer.alloc(44);
101
+ header.write("RIFF", 0);
102
+ header.writeUInt32LE(36 + pcm.length, 4);
103
+ header.write("WAVE", 8);
104
+ header.write("fmt ", 12);
105
+ header.writeUInt32LE(16, 16);
106
+ header.writeUInt16LE(1, 20);
107
+ header.writeUInt16LE(CHANNELS, 22);
108
+ header.writeUInt32LE(SAMPLE_RATE, 24);
109
+ header.writeUInt32LE(byteRate, 28);
110
+ header.writeUInt16LE(blockAlign, 32);
111
+ header.writeUInt16LE(BIT_DEPTH, 34);
112
+ header.write("data", 36);
113
+ header.writeUInt32LE(pcm.length, 40);
114
+ return Buffer.concat([header, pcm]);
115
+ }
116
+ function createDiscordOpusEncodeStream() {
117
+ return new DiscordOpusEncodeStream();
118
+ }
119
+ function createDiscordOpusPlaybackStream(input) {
120
+ const inputSource = typeof input === "string" ? input : "pipe:0";
121
+ const ffmpeg = spawn(resolveFfmpegBin(), [
122
+ "-i",
123
+ inputSource,
124
+ ...FFMPEG_PCM_ARGUMENTS,
125
+ "pipe:1"
126
+ ], {
127
+ stdio: [
128
+ "pipe",
129
+ "pipe",
130
+ "pipe"
131
+ ],
132
+ windowsHide: true
133
+ });
134
+ const opusStream = createDiscordOpusEncodeStream();
135
+ const stderr = Buffer.alloc(FFMPEG_ERROR_OUTPUT_BYTES);
136
+ let stderrBytes = 0;
137
+ let ffmpegClosed = false;
138
+ const killFfmpeg = (signal = "SIGTERM") => {
139
+ if (!ffmpegClosed && !ffmpeg.killed) ffmpeg.kill(signal);
140
+ };
141
+ ffmpeg.stderr.on("data", (chunk) => {
142
+ if (stderrBytes < FFMPEG_ERROR_OUTPUT_BYTES) stderrBytes += chunk.copy(stderr, stderrBytes, 0, FFMPEG_ERROR_OUTPUT_BYTES - stderrBytes);
143
+ });
144
+ ffmpeg.once("error", (err) => {
145
+ opusStream.destroy(err);
146
+ });
147
+ ffmpeg.once("close", (code, signal) => {
148
+ ffmpegClosed = true;
149
+ if (code && code !== 0) {
150
+ const stderrText = new StringDecoder("utf8").write(stderr.subarray(0, stderrBytes)).trim();
151
+ const suffix = stderrText ? `: ${stderrText}` : "";
152
+ opusStream.destroy(/* @__PURE__ */ new Error(`ffmpeg exited with code ${code}${suffix}`));
153
+ return;
154
+ }
155
+ if (signal) opusStream.destroy(/* @__PURE__ */ new Error(`ffmpeg exited with signal ${signal}`));
156
+ });
157
+ for (const readable of [ffmpeg.stdout, ffmpeg.stderr]) readable.on("error", (err) => {
158
+ killFfmpeg("SIGKILL");
159
+ opusStream.destroy(err);
160
+ });
161
+ ffmpeg.stdin.on("error", (err) => {
162
+ if (err.code !== "EPIPE") opusStream.destroy(err);
163
+ });
164
+ ffmpeg.stdout.pipe(opusStream);
165
+ opusStream.once("close", () => {
166
+ if (!opusStream.readableEnded) killFfmpeg();
167
+ });
168
+ if (typeof input !== "string") {
169
+ input.on("error", (err) => {
170
+ ffmpeg.stdin.destroy(err);
171
+ opusStream.destroy(err);
172
+ });
173
+ input.pipe(ffmpeg.stdin);
174
+ } else ffmpeg.stdin.end();
175
+ return opusStream;
176
+ }
177
+ var DiscordOpusEncodeStream = class extends Transform {
178
+ #buffer = Buffer.alloc(0);
179
+ #encoder;
180
+ constructor() {
181
+ super({ readableObjectMode: true });
182
+ }
183
+ _construct(done) {
184
+ createEncoder({
185
+ application: Application.Audio,
186
+ channels: CHANNELS,
187
+ sampleRate: SAMPLE_RATE
188
+ }).then((encoder) => {
189
+ this.#encoder = encoder;
190
+ done();
191
+ }, (err) => done(err instanceof Error ? err : new Error(formatErrorMessage(err))));
192
+ }
193
+ _transform(chunk, _encoding, done) {
194
+ try {
195
+ this.#buffer = this.#buffer.length > 0 ? Buffer.concat([this.#buffer, chunk]) : Buffer.from(chunk);
196
+ while (this.#buffer.length >= DISCORD_OPUS_FRAME_BYTES) {
197
+ const frame = this.#buffer.subarray(0, DISCORD_OPUS_FRAME_BYTES);
198
+ this.#buffer = this.#buffer.subarray(DISCORD_OPUS_FRAME_BYTES);
199
+ this.#encodeFrame(frame);
200
+ }
201
+ done();
202
+ } catch (err) {
203
+ done(err instanceof Error ? err : new Error(formatErrorMessage(err)));
204
+ }
205
+ }
206
+ _flush(done) {
207
+ try {
208
+ if (this.#buffer.length > 0) {
209
+ const frame = Buffer.alloc(DISCORD_OPUS_FRAME_BYTES);
210
+ this.#buffer.copy(frame);
211
+ this.#buffer = Buffer.alloc(0);
212
+ this.#encodeFrame(frame);
213
+ }
214
+ done();
215
+ } catch (err) {
216
+ done(err instanceof Error ? err : new Error(formatErrorMessage(err)));
217
+ }
218
+ }
219
+ _destroy(err, done) {
220
+ this.#encoder?.free();
221
+ this.#buffer = Buffer.alloc(0);
222
+ done(err);
223
+ }
224
+ #encodeFrame(frame) {
225
+ this.push(Buffer.from(this.#encoder.encode(frame, { frameSize: DISCORD_OPUS_FRAME_SIZE })));
226
+ }
227
+ };
228
+ function pcmInt16ToBuffer(pcm) {
229
+ return Buffer.from(pcm.buffer, pcm.byteOffset, pcm.byteLength);
230
+ }
231
+ async function decodeOpusStream(stream, params) {
232
+ return await readByteStreamWithLimit(decodeOpusFrames(stream, params), {
233
+ maxBytes: params.maxBytes,
234
+ onOverflow: () => /* @__PURE__ */ new Error(`Discord voice capture exceeds the transcription PCM limit (${params.maxBytes} bytes); speak a shorter segment.`)
235
+ });
236
+ }
237
+ async function decodeOpusStreamChunks(stream, params) {
238
+ try {
239
+ for await (const pcm of decodeOpusFrames(stream, params)) params.onChunk(pcm);
240
+ } catch (err) {
241
+ params.onError?.(err);
242
+ }
243
+ }
244
+ async function* decodeOpusFrames(stream, params) {
245
+ let decoder;
246
+ try {
247
+ decoder = await createDecoder({
248
+ channels: CHANNELS,
249
+ sampleRate: SAMPLE_RATE
250
+ });
251
+ } catch (err) {
252
+ if (!warnedOpusMissing) {
253
+ warnedOpusMissing = true;
254
+ params.onWarn(`discord voice: no usable opus decoder available (libopus-wasm: ${formatErrorMessage(err)}); cannot decode voice audio`);
255
+ }
256
+ return;
257
+ }
258
+ params.onVerbose("opus decoder: libopus-wasm");
259
+ try {
260
+ for await (const chunk of stream) {
261
+ if (!chunk || !(chunk instanceof Buffer) || chunk.length === 0) continue;
262
+ const decoded = decoder.decode(chunk, { maxFrameSize: DISCORD_OPUS_FRAME_SIZE });
263
+ if (decoded.length > 0) yield pcmInt16ToBuffer(decoded);
264
+ }
265
+ } catch (err) {
266
+ params.onError?.(err);
267
+ if (shouldLogVerbose()) logVerbose(`discord voice: opus decode failed: ${formatErrorMessage(err)}`);
268
+ } finally {
269
+ decoder.free();
270
+ }
271
+ }
272
+ function convertDiscordPcm48kStereoToRealtimePcm24kMono(pcm) {
273
+ const frameCount = Math.floor(pcm.length / 4);
274
+ if (frameCount === 0) return Buffer.alloc(0);
275
+ const mono48k = Buffer.alloc(frameCount * 2);
276
+ for (let frame = 0; frame < frameCount; frame += 1) {
277
+ const offset = frame * 4;
278
+ const left = pcm.readInt16LE(offset);
279
+ const right = pcm.readInt16LE(offset + 2);
280
+ mono48k.writeInt16LE(Math.round((left + right) / 2), frame * 2);
281
+ }
282
+ return resamplePcm(mono48k, SAMPLE_RATE, 24e3);
283
+ }
284
+ function convertRealtimePcm24kMonoToDiscordPcm48kStereo(pcm) {
285
+ const mono48k = resamplePcm(pcm, 24e3, SAMPLE_RATE);
286
+ const sampleCount = Math.floor(mono48k.length / 2);
287
+ if (sampleCount === 0) return Buffer.alloc(0);
288
+ const stereo = Buffer.alloc(sampleCount * 4);
289
+ for (let sampleIndex = 0; sampleIndex < sampleCount; sampleIndex += 1) {
290
+ const sample = mono48k.readInt16LE(sampleIndex * 2);
291
+ const offset = sampleIndex * 4;
292
+ stereo.writeInt16LE(sample, offset);
293
+ stereo.writeInt16LE(sample, offset + 2);
294
+ }
295
+ return stereo;
296
+ }
297
+ function estimateDurationSeconds(pcm) {
298
+ const bytesPerSample = BIT_DEPTH / 8 * CHANNELS;
299
+ return pcm.length / (bytesPerSample * SAMPLE_RATE);
300
+ }
301
+ async function writeVoiceWavFile(pcm) {
302
+ const workspace = await tempWorkspace({
303
+ rootDir: resolvePreferredOpenClawTmpDir(),
304
+ prefix: "discord-voice-"
305
+ });
306
+ scheduleTempCleanup(workspace.dir);
307
+ const wav = buildWavBuffer(pcm);
308
+ return {
309
+ path: await workspace.write("segment.wav", wav),
310
+ durationSeconds: estimateDurationSeconds(pcm)
311
+ };
312
+ }
313
+ function scheduleTempCleanup(tempDir, delayMs = 18e5) {
314
+ setTimeout(() => {
315
+ fs.rm(tempDir, {
316
+ recursive: true,
317
+ force: true
318
+ }).catch((err) => {
319
+ if (shouldLogVerbose()) logVerbose(`discord voice: temp cleanup failed for ${tempDir}: ${formatErrorMessage(err)}`);
320
+ });
321
+ }, delayMs).unref();
322
+ }
323
+ const CAPTURE_FINALIZE_GRACE_MS = 2e3;
324
+ const VOICE_CONNECT_READY_TIMEOUT_MS = 3e4;
325
+ const VOICE_RECONNECT_GRACE_MS = 15e3;
326
+ const PLAYBACK_READY_TIMEOUT_MS = 6e4;
327
+ function resolveVoiceTimeoutMs(value, fallbackMs) {
328
+ if (typeof value !== "number" || !Number.isFinite(value) || value <= 0) return fallbackMs;
329
+ return Math.floor(value);
330
+ }
331
+ function resolveDiscordVoiceMode(voice) {
332
+ const mode = voice?.mode;
333
+ if (mode === "stt-tts" || mode === "bidi") return mode;
334
+ return "agent-proxy";
335
+ }
336
+ function isDiscordRealtimeVoiceMode(mode) {
337
+ return mode === "agent-proxy" || mode === "bidi";
338
+ }
339
+ function logVoiceVerbose(message) {
340
+ logVerbose(`discord voice: ${message}`);
341
+ }
342
+ function isVoiceChannel(type) {
343
+ return type === discord_exports.ChannelType.GuildVoice || type === discord_exports.ChannelType.GuildStageVoice;
344
+ }
345
+ //#endregion
346
+ //#region extensions/discord/src/voice/sdk-runtime.ts
347
+ let cachedDiscordVoiceSdk = null;
348
+ function loadDiscordVoiceSdk() {
349
+ if (cachedDiscordVoiceSdk) return cachedDiscordVoiceSdk;
350
+ cachedDiscordVoiceSdk = createRequire(import.meta.url)("@discordjs/voice");
351
+ return cachedDiscordVoiceSdk;
352
+ }
353
+ //#endregion
22
354
  //#region extensions/discord/src/voice/ingress.ts
23
355
  const DISCORD_VOICE_MESSAGE_PROVIDER = "discord-voice";
24
356
  const logger$7 = createSubsystemLogger("discord/voice");
@@ -1030,70 +1362,43 @@ var DiscordVoiceFollowing = class {
1030
1362
  //#endregion
1031
1363
  //#region extensions/discord/src/voice/capture-state.ts
1032
1364
  function createVoiceCaptureState() {
1033
- return {
1034
- activeSpeakers: /* @__PURE__ */ new Set(),
1035
- activeCaptureStreams: /* @__PURE__ */ new Map(),
1036
- captureFinalizeTimers: /* @__PURE__ */ new Map(),
1037
- captureGenerations: /* @__PURE__ */ new Map()
1038
- };
1365
+ return /* @__PURE__ */ new Map();
1039
1366
  }
1040
1367
  function stopVoiceCaptureState(state) {
1041
- for (const { timer } of state.captureFinalizeTimers.values()) clearTimeout(timer);
1042
- state.captureFinalizeTimers.clear();
1043
- for (const { stream } of state.activeCaptureStreams.values()) stream.destroy();
1044
- state.activeCaptureStreams.clear();
1045
- state.captureGenerations.clear();
1046
- state.activeSpeakers.clear();
1047
- }
1048
- function getActiveVoiceCapture(state, userId) {
1049
- return state.activeCaptureStreams.get(userId);
1050
- }
1051
- function isVoiceCaptureActive(state, userId) {
1052
- return state.activeSpeakers.has(userId);
1053
- }
1054
- function clearVoiceCaptureFinalizeTimer(state, userId, generation) {
1055
- const scheduled = state.captureFinalizeTimers.get(userId);
1056
- if (!scheduled || generation !== void 0 && scheduled.generation !== generation) return false;
1057
- clearTimeout(scheduled.timer);
1058
- state.captureFinalizeTimers.delete(userId);
1368
+ const captures = [...state.values()];
1369
+ state.clear();
1370
+ for (const capture of captures) {
1371
+ clearVoiceCaptureFinalizeTimer(capture);
1372
+ capture.stream?.destroy();
1373
+ }
1374
+ }
1375
+ function clearVoiceCaptureFinalizeTimer(capture) {
1376
+ if (!capture.finalizeTimer) return false;
1377
+ clearTimeout(capture.finalizeTimer);
1378
+ delete capture.finalizeTimer;
1059
1379
  return true;
1060
1380
  }
1061
1381
  function beginVoiceCapture(state, userId, stream) {
1062
- const generation = (state.captureGenerations.get(userId) ?? 0) + 1;
1063
- state.captureGenerations.set(userId, generation);
1064
- state.activeSpeakers.add(userId);
1065
- state.activeCaptureStreams.set(userId, {
1066
- generation,
1067
- stream
1068
- });
1069
- clearVoiceCaptureFinalizeTimer(state, userId, generation);
1070
- return generation;
1071
- }
1072
- function finishVoiceCapture(state, userId, generation) {
1073
- clearVoiceCaptureFinalizeTimer(state, userId, generation);
1074
- if (state.activeCaptureStreams.get(userId)?.generation !== generation) return false;
1075
- state.activeCaptureStreams.delete(userId);
1076
- state.activeSpeakers.delete(userId);
1382
+ const capture = { stream };
1383
+ state.set(userId, capture);
1384
+ return capture;
1385
+ }
1386
+ function finishVoiceCapture(state, userId, capture) {
1387
+ clearVoiceCaptureFinalizeTimer(capture);
1388
+ if (state.get(userId) !== capture) return false;
1389
+ state.delete(userId);
1077
1390
  return true;
1078
1391
  }
1079
1392
  function scheduleVoiceCaptureFinalize(params) {
1080
1393
  const { state, userId, delayMs, onFinalize } = params;
1081
- const capture = state.activeCaptureStreams.get(userId);
1394
+ const capture = state.get(userId);
1082
1395
  if (!capture) return false;
1083
- clearVoiceCaptureFinalizeTimer(state, userId, capture.generation);
1084
- const timer = setTimeout(() => {
1085
- const activeCapture = state.activeCaptureStreams.get(userId);
1086
- if (!activeCapture || activeCapture.generation !== capture.generation) return;
1087
- state.captureFinalizeTimers.delete(userId);
1088
- state.activeCaptureStreams.delete(userId);
1089
- state.activeSpeakers.delete(userId);
1090
- onFinalize?.(activeCapture);
1091
- activeCapture.stream.destroy();
1396
+ clearVoiceCaptureFinalizeTimer(capture);
1397
+ capture.finalizeTimer = setTimeout(() => {
1398
+ if (!finishVoiceCapture(state, userId, capture)) return;
1399
+ onFinalize?.(capture);
1400
+ capture.stream?.destroy();
1092
1401
  }, delayMs);
1093
- state.captureFinalizeTimers.set(userId, {
1094
- generation: capture.generation,
1095
- timer
1096
- });
1097
1402
  return true;
1098
1403
  }
1099
1404
  //#endregion
@@ -1115,12 +1420,13 @@ function sanitizeVoiceReplyTextForSpeech(text, speakerLabel) {
1115
1420
  //#endregion
1116
1421
  //#region extensions/discord/src/voice/tts.ts
1117
1422
  async function transcribeVoiceAudio(params) {
1118
- return normalizeOptionalString((await getDiscordRuntime().mediaUnderstanding.transcribeAudioFile({
1423
+ const result = await getDiscordRuntime().mediaUnderstanding.transcribeAudioFile({
1119
1424
  filePath: params.filePath,
1120
1425
  cfg: params.cfg,
1121
1426
  agentDir: resolveAgentDir(params.cfg, params.agentId),
1122
1427
  mime: "audio/wav"
1123
- })).text);
1428
+ });
1429
+ return normalizeOptionalString(result.text);
1124
1430
  }
1125
1431
  async function synthesizeVoiceReplyAudio(params) {
1126
1432
  const runtime = getDiscordRuntime();
@@ -1199,6 +1505,7 @@ async function processDiscordVoiceSegment(params) {
1199
1505
  logVoiceVerbose(`transcription ok (${transcript.length} chars): guild ${entry.guildId} channel ${entry.channelId}`);
1200
1506
  logVoiceVerbose(`transcript from ${ingress.speakerLabel} (${userId}) in guild ${entry.guildId} channel ${entry.channelId}: ${formatVoiceLogPreview(transcript)}`);
1201
1507
  if (params.transcripts) {
1508
+ if (entry.sessionLifecycle.status === "stopped" || entry.transcripts !== params.transcripts) return;
1202
1509
  await params.transcripts.onUtterance({
1203
1510
  sessionId: params.transcripts.sessionId,
1204
1511
  startedAt: (/* @__PURE__ */ new Date()).toISOString(),
@@ -1335,38 +1642,22 @@ var DiscordVoiceReceive = class {
1335
1642
  const botUserId = this.params.botUserId();
1336
1643
  if (botUserId && userId === botUserId) return;
1337
1644
  this.params.membership.notePresent(entry, userId);
1338
- if (isVoiceCaptureActive(entry.capture, userId)) {
1339
- const activeCapture = getActiveVoiceCapture(entry.capture, userId);
1340
- const extended = activeCapture ? clearVoiceCaptureFinalizeTimer(entry.capture, userId, activeCapture.generation) : false;
1645
+ const activeCapture = entry.capture.get(userId);
1646
+ if (activeCapture) {
1647
+ const extended = clearVoiceCaptureFinalizeTimer(activeCapture);
1341
1648
  logVoiceVerbose(`capture start ignored (already active): guild ${entry.guildId} channel ${entry.channelId} user ${userId}${extended ? " (finalize canceled)" : ""}`);
1342
1649
  return;
1343
1650
  }
1344
1651
  logVoiceVerbose(`capture start: guild ${entry.guildId} channel ${entry.channelId} user ${userId}`);
1345
1652
  const voiceSdk = loadDiscordVoiceSdk();
1653
+ const transcripts = entry.transcripts;
1346
1654
  const voiceMode = resolveDiscordVoiceMode(this.params.discordConfig.voice);
1347
1655
  const realtime = entry.realtimeLifecycle.status === "active" && isDiscordRealtimeVoiceMode(voiceMode) ? entry.realtimeLifecycle.instance : void 0;
1348
1656
  if (entry.player.state.status === voiceSdk.AudioPlayerStatus.Playing && !realtime) {
1349
1657
  logVoiceVerbose(`capture ignored during playback: guild ${entry.guildId} channel ${entry.channelId} user ${userId}`);
1350
1658
  return;
1351
1659
  }
1352
- const realtimeIngress = realtime ? await this.resolveDiscordVoiceIngressContext(entry, userId) : void 0;
1353
- if (realtime && !realtimeIngress) {
1354
- logVoiceVerbose(`realtime capture unauthorized: guild ${entry.guildId} channel ${entry.channelId} user ${userId}`);
1355
- return;
1356
- }
1357
- if (!this.params.isEntryCurrent(entry)) return;
1358
- if (entry.player.state.status === voiceSdk.AudioPlayerStatus.Playing && realtime) {
1359
- if (!realtime.isBargeInEnabled()) {
1360
- logger$3.info(`discord voice: realtime capture ignored during playback (barge-in disabled): guild ${entry.guildId} channel ${entry.channelId} user ${userId}`);
1361
- return;
1362
- }
1363
- logVoiceVerbose(`realtime barge-in: guild ${entry.guildId} channel ${entry.channelId} user ${userId}`);
1364
- logger$3.info(`discord voice: realtime barge-in detected source=speaker-start guild=${entry.guildId} channel=${entry.channelId} user=${userId} playerStatus=${entry.player.state.status}`);
1365
- realtime.handleBargeIn("speaker-start");
1366
- }
1367
- this.enableDaveReceivePassthrough(entry, `speaker ${userId} start`, 15);
1368
- const stream = entry.connection.receiver.subscribe(userId, { end: { behavior: voiceSdk.EndBehaviorType.Manual } });
1369
- const generation = beginVoiceCapture(entry.capture, userId, stream);
1660
+ const capture = beginVoiceCapture(entry.capture, userId);
1370
1661
  let streamAborted = false;
1371
1662
  let receiveFailureHandled = false;
1372
1663
  let receiveStreamEndHandled = false;
@@ -1383,8 +1674,25 @@ var DiscordVoiceReceive = class {
1383
1674
  receiveFailureHandled = true;
1384
1675
  this.handleReceiveError(entry, err);
1385
1676
  };
1386
- stream.on("error", handleStreamError);
1387
1677
  try {
1678
+ const realtimeIngress = realtime ? await this.resolveDiscordVoiceIngressContext(entry, userId) : void 0;
1679
+ if (realtime && !realtimeIngress) {
1680
+ logVoiceVerbose(`realtime capture unauthorized: guild ${entry.guildId} channel ${entry.channelId} user ${userId}`);
1681
+ return;
1682
+ }
1683
+ if (!this.params.isEntryCurrent(entry) || entry.capture.get(userId) !== capture) return;
1684
+ if (entry.player.state.status === voiceSdk.AudioPlayerStatus.Playing && realtime) {
1685
+ if (!realtime.isBargeInEnabled()) {
1686
+ logger$3.info(`discord voice: realtime capture ignored during playback (barge-in disabled): guild ${entry.guildId} channel ${entry.channelId} user ${userId}`);
1687
+ return;
1688
+ }
1689
+ logVoiceVerbose(`realtime barge-in: guild ${entry.guildId} channel ${entry.channelId} user ${userId}`);
1690
+ logger$3.info(`discord voice: realtime barge-in detected source=speaker-start guild=${entry.guildId} channel=${entry.channelId} user=${userId} playerStatus=${entry.player.state.status}`);
1691
+ realtime.handleBargeIn("speaker-start");
1692
+ }
1693
+ this.enableDaveReceivePassthrough(entry, `speaker ${userId} start`, 15);
1694
+ const stream = capture.stream = entry.connection.receiver.subscribe(userId, { end: { behavior: voiceSdk.EndBehaviorType.Manual } });
1695
+ stream.on("error", handleStreamError);
1388
1696
  if (realtime && realtimeIngress) {
1389
1697
  const turn = realtime.beginSpeakerTurn(realtimeIngress, userId);
1390
1698
  try {
@@ -1399,7 +1707,12 @@ var DiscordVoiceReceive = class {
1399
1707
  }
1400
1708
  return;
1401
1709
  }
1710
+ if (!entry.audioInputBudget.enabled) {
1711
+ logger$3.warn("discord voice: capture skipped: audio understanding is disabled; enable tools.media.audio.enabled to transcribe voice.");
1712
+ return;
1713
+ }
1402
1714
  const pcm = await decodeOpusStream(stream, {
1715
+ maxBytes: Math.max(0, entry.audioInputBudget.maxBytes - 44),
1403
1716
  onError: handleStreamError,
1404
1717
  onVerbose: logVoiceVerbose,
1405
1718
  onWarn: (message) => logger$3.warn(message)
@@ -1420,6 +1733,7 @@ var DiscordVoiceReceive = class {
1420
1733
  logVoiceVerbose(`capture ready (${durationSeconds.toFixed(2)}s): guild ${entry.guildId} channel ${entry.channelId} user ${userId}`);
1421
1734
  entry.processingQueue = entry.processingQueue.then(async () => {
1422
1735
  if (!this.params.isEntryCurrent(entry)) return;
1736
+ if (entry.transcripts !== transcripts) return;
1423
1737
  await this.processSegment({
1424
1738
  entry,
1425
1739
  wavPath,
@@ -1431,8 +1745,9 @@ var DiscordVoiceReceive = class {
1431
1745
  if (!receiveFailureHandled) this.handleReceiveError(entry, err);
1432
1746
  throw err;
1433
1747
  } finally {
1434
- stream.off?.("error", handleStreamError);
1435
- if (finishVoiceCapture(entry.capture, userId, generation) && !stream.destroyed) stream.destroy();
1748
+ const stream = capture.stream;
1749
+ stream?.off?.("error", handleStreamError);
1750
+ if (finishVoiceCapture(entry.capture, userId, capture) && stream && !stream.destroyed) stream.destroy();
1436
1751
  }
1437
1752
  }
1438
1753
  async processSegment(params) {
@@ -1613,6 +1928,17 @@ const REALTIME_PLAYBACK_MAX_MISSED_FRAMES = 100;
1613
1928
  function isVoiceSessionStopped(entry) {
1614
1929
  return entry.sessionLifecycle.status === "stopped";
1615
1930
  }
1931
+ function retireTranscripts(entry) {
1932
+ const transcripts = entry.transcripts;
1933
+ entry.transcripts = void 0;
1934
+ try {
1935
+ Promise.resolve(transcripts?.onStop?.()).catch((error) => {
1936
+ logger$2.warn(`discord voice: transcripts retirement failed: ${formatErrorMessage(error)}`);
1937
+ });
1938
+ } catch (error) {
1939
+ logger$2.warn(`discord voice: transcripts retirement failed: ${formatErrorMessage(error)}`);
1940
+ }
1941
+ }
1616
1942
  function isVoiceConnectionDestroyed(connection, voiceSdk) {
1617
1943
  return connection.state.status === voiceSdk.VoiceConnectionStatus.Destroyed;
1618
1944
  }
@@ -1699,7 +2025,10 @@ var DiscordVoiceSessions = class {
1699
2025
  if (existing && existing.channelId === channelId) {
1700
2026
  existing.autoJoinWhenOccupied = options?.autoJoinWhenOccupied === true;
1701
2027
  if (authority) existing.generation = authority.generation;
1702
- if (options?.transcripts) existing.transcripts = options.transcripts;
2028
+ if (options?.transcripts) {
2029
+ retireTranscripts(existing);
2030
+ existing.transcripts = options.transcripts;
2031
+ }
1703
2032
  if (!options?.transcripts && isDiscordRealtimeVoiceMode(voiceMode) && existing.realtimeLifecycle.status !== "active" && existing.realtimeLifecycle.status !== "starting") {
1704
2033
  const realtimeResult = await this.attachRealtimeSession(existing, voiceMode, {
1705
2034
  requireLiveEntry: true,
@@ -1751,6 +2080,8 @@ var DiscordVoiceSessions = class {
1751
2080
  ok: false,
1752
2081
  message: "Discord voice plugin is not available."
1753
2082
  };
2083
+ const audioInputBudget = await getDiscordRuntime().mediaUnderstanding.resolveAudioInputBudget({ cfg: this.params.cfg });
2084
+ if (authority && !authority.isCurrent()) return cancelledJoinResult();
1754
2085
  const adapterCreator = voicePlugin.getGatewayAdapterCreator(guildId);
1755
2086
  const daveEncryption = voiceConfig?.daveEncryption;
1756
2087
  const decryptionFailureTolerance = voiceConfig?.decryptionFailureTolerance;
@@ -1862,6 +2193,7 @@ var DiscordVoiceSessions = class {
1862
2193
  status: "stopped",
1863
2194
  reason: optionsLocal.reason
1864
2195
  };
2196
+ retireTranscripts(entry);
1865
2197
  if (this.params.sessions.get(guildId) === entry) this.params.sessions.delete(guildId);
1866
2198
  this.params.membership.deactivate(entry);
1867
2199
  connection.receiver.speaking.off("start", speakingHandler);
@@ -1900,6 +2232,7 @@ var DiscordVoiceSessions = class {
1900
2232
  player,
1901
2233
  playbackQueue: Promise.resolve(),
1902
2234
  processingQueue: Promise.resolve(),
2235
+ audioInputBudget,
1903
2236
  ttsStreamFallbackWarned: false,
1904
2237
  capture: createVoiceCaptureState(),
1905
2238
  transcripts: options?.transcripts,
@@ -2004,7 +2337,7 @@ var DiscordVoiceSessions = class {
2004
2337
  channelId: entry.channelId
2005
2338
  };
2006
2339
  if (entry.realtimeLifecycle.status === "active" || entry.realtimeLifecycle.status === "starting") {
2007
- entry.transcripts = void 0;
2340
+ retireTranscripts(entry);
2008
2341
  return {
2009
2342
  ok: true,
2010
2343
  message: `Stopped transcripts for ${formatMention({ channelId: entry.channelId })}.`,
@@ -2034,7 +2367,7 @@ var DiscordVoiceSessions = class {
2034
2367
  ok: false,
2035
2368
  message: "Discord realtime voice session stopped before startup completed."
2036
2369
  };
2037
- const { DiscordRealtimeVoiceSession } = await import("./realtime-session.runtime-CU8IQUS-.js");
2370
+ const { DiscordRealtimeVoiceSession } = await import("./realtime-session.runtime-DgSbX6ay.js");
2038
2371
  const realtime = new DiscordRealtimeVoiceSession({
2039
2372
  accountId: this.params.accountId,
2040
2373
  bootstrapContextInstructions,
@@ -2138,6 +2471,13 @@ var DiscordVoiceStateUpdateListener = class extends VoiceStateUpdateListener {
2138
2471
  };
2139
2472
  //#endregion
2140
2473
  //#region extensions/discord/src/voice/voice-runtime.ts
2474
+ var voice_runtime_exports = /* @__PURE__ */ __exportAll({
2475
+ DiscordVoiceGuildCreateListener: () => DiscordVoiceGuildCreateListener,
2476
+ DiscordVoiceManager: () => DiscordVoiceManager,
2477
+ DiscordVoiceReadyListener: () => DiscordVoiceReadyListener,
2478
+ DiscordVoiceResumedListener: () => DiscordVoiceResumedListener,
2479
+ DiscordVoiceStateUpdateListener: () => DiscordVoiceStateUpdateListener
2480
+ });
2141
2481
  const logger = createSubsystemLogger("discord/voice");
2142
2482
  const DISCORD_VOICE_FATAL_AUTOJOIN_ERROR_PATTERNS = [
2143
2483
  "api key missing",
@@ -2538,4 +2878,4 @@ var DiscordVoiceManager = class {
2538
2878
  }
2539
2879
  };
2540
2880
  //#endregion
2541
- export { DiscordVoiceGuildCreateListener, DiscordVoiceManager, DiscordVoiceReadyListener, DiscordVoiceResumedListener, DiscordVoiceStateUpdateListener };
2881
+ export { DiscordVoiceGuildCreateListener, DiscordVoiceManager, DiscordVoiceReadyListener, DiscordVoiceResumedListener, DiscordVoiceStateUpdateListener, convertRealtimePcm24kMonoToDiscordPcm48kStereo as a, maybeControlDiscordVoiceAgentRun as c, convertDiscordPcm48kStereoToRealtimePcm24kMono as i, formatVoiceLogPreview as l, loadDiscordVoiceSdk as n, createDiscordOpusEncodeStream as o, logVoiceVerbose as r, formatVoiceIngressPrompt as s, voice_runtime_exports as t };