@openclaw/discord 2026.5.10-beta.1 → 2026.5.10-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/api.js CHANGED
@@ -8,7 +8,7 @@ import { _ as parseDiscordModalCustomIdForInteraction, a as buildDiscordComponen
8
8
  import { t as buildDiscordInteractiveComponents } from "./shared-interactive-D39V9Wtn.js";
9
9
  import "./targets-Dj-qyUaE.js";
10
10
  import { a as shouldSuppressLocalDiscordExecApprovalPrompt, i as isDiscordExecApprovalClientEnabled, n as getDiscordExecApprovalApprovers, r as isDiscordExecApprovalApprover } from "./approval-shared-Ckk65xSG.js";
11
- import { i as resolveDiscordGroupToolPolicy, n as collectDiscordStatusIssues, r as resolveDiscordGroupRequireMention, t as discordPlugin } from "./channel-DTBEGHsT.js";
11
+ import { i as resolveDiscordGroupToolPolicy, n as collectDiscordStatusIssues, r as resolveDiscordGroupRequireMention, t as discordPlugin } from "./channel-D0GnZ6j1.js";
12
12
  import { t as normalizeExplicitDiscordSessionKey } from "./session-key-normalization-BQNCS1gu.js";
13
13
  import { t as discordSetupPlugin } from "./channel.setup-EQXuueIk.js";
14
14
  import { n as handleDiscordSubagentEnded, r as handleDiscordSubagentSpawning, t as handleDiscordSubagentDeliveryTarget } from "./subagent-hooks-BDy1pJD5.js";
@@ -135,7 +135,7 @@ const loadDiscordResolveUsersModule = createLazyRuntimeModule(() => import("./re
135
135
  const loadDiscordThreadBindingsManagerModule = createLazyRuntimeModule(() => import("./thread-bindings.manager-DTuwm8Tk.js").then((n) => n.a));
136
136
  const loadDiscordTargetResolverModule = createLazyRuntimeModule(() => import("./target-resolver-DzOelJEt.js").then((n) => n.r));
137
137
  async function loadDiscordProviderRuntime() {
138
- discordProviderRuntimePromise ??= import("./provider.runtime-BlbOt97W.js");
138
+ discordProviderRuntimePromise ??= import("./provider.runtime-bgZEewCO.js");
139
139
  return await discordProviderRuntimePromise;
140
140
  }
141
141
  async function loadDiscordProbeRuntime() {
@@ -1,2 +1,2 @@
1
- import { t as discordPlugin } from "./channel-DTBEGHsT.js";
1
+ import { t as discordPlugin } from "./channel-D0GnZ6j1.js";
2
2
  export { discordPlugin };
@@ -46,18 +46,20 @@ function buildWavBuffer(pcm) {
46
46
  return Buffer.concat([header, pcm]);
47
47
  }
48
48
  function resolveOpusDecoderFactory(params) {
49
- const factories = [{
49
+ const nativeFactory = {
50
+ name: "@discordjs/opus",
51
+ load: () => {
52
+ return new (require("@discordjs/opus")).OpusEncoder(SAMPLE_RATE, CHANNELS);
53
+ }
54
+ };
55
+ const opusscriptFactory = {
50
56
  name: "opusscript",
51
57
  load: () => {
52
58
  const OpusScript = require("opusscript");
53
59
  return new OpusScript(SAMPLE_RATE, CHANNELS, OpusScript.Application.AUDIO);
54
60
  }
55
- }, {
56
- name: "@discordjs/opus",
57
- load: () => {
58
- return new (require("@discordjs/opus")).OpusEncoder(SAMPLE_RATE, CHANNELS);
59
- }
60
- }];
61
+ };
62
+ const factories = resolveOpusDecoderPreference() === "native" ? [nativeFactory, opusscriptFactory] : [opusscriptFactory, nativeFactory];
61
63
  const failures = [];
62
64
  for (const factory of factories) try {
63
65
  factory.load();
@@ -71,6 +73,11 @@ function resolveOpusDecoderFactory(params) {
71
73
  }
72
74
  return null;
73
75
  }
76
+ function resolveOpusDecoderPreference(value = process.env.OPENCLAW_DISCORD_OPUS_DECODER) {
77
+ const normalized = value?.trim().toLowerCase();
78
+ if (normalized === "native" || normalized === "@discordjs/opus") return "native";
79
+ return "opusscript";
80
+ }
74
81
  function getOrCreateOpusDecoderFactory(params) {
75
82
  if (cachedOpusDecoderFactory !== "unresolved") return cachedOpusDecoderFactory;
76
83
  cachedOpusDecoderFactory = resolveOpusDecoderFactory(params);
@@ -348,6 +355,35 @@ const DISCORD_REALTIME_LOG_PREVIEW_CHARS = 500;
348
355
  const DISCORD_REALTIME_DEFAULT_MIN_BARGE_IN_AUDIO_END_MS = 250;
349
356
  const DISCORD_REALTIME_FORCED_CONSULT_FALLBACK_DELAY_MS = 200;
350
357
  const REALTIME_PCM16_BYTES_PER_SAMPLE = 2;
358
+ const DISCORD_REALTIME_FORCED_CONSULT_TRAILING_FRAGMENT_WORDS = new Set([
359
+ "a",
360
+ "about",
361
+ "an",
362
+ "and",
363
+ "as",
364
+ "at",
365
+ "because",
366
+ "but",
367
+ "by",
368
+ "for",
369
+ "from",
370
+ "in",
371
+ "of",
372
+ "on",
373
+ "or",
374
+ "so",
375
+ "that",
376
+ "the",
377
+ "then",
378
+ "to",
379
+ "with"
380
+ ]);
381
+ const DISCORD_REALTIME_VERBOSE_OMITTED_EVENTS = new Set([
382
+ "conversation.output_audio.delta",
383
+ "input_audio_buffer.append",
384
+ "response.audio.delta",
385
+ "response.output_audio.delta"
386
+ ]);
351
387
  function formatRealtimeLogPreview(text) {
352
388
  const oneLine = text.replace(/\s+/g, " ").trim();
353
389
  if (oneLine.length <= DISCORD_REALTIME_LOG_PREVIEW_CHARS) return oneLine;
@@ -366,6 +402,17 @@ function formatRealtimeInterruptionLog(event) {
366
402
  if (event.type === "error" && event.detail === "Cancellation failed: no active response found") return `discord voice: realtime model interrupt raced ${event.direction}:${event.type}${detail}`;
367
403
  }
368
404
  }
405
+ function shouldLogRealtimeVerboseEvent(event) {
406
+ return !DISCORD_REALTIME_VERBOSE_OMITTED_EVENTS.has(event.type);
407
+ }
408
+ function classifySkippableForcedAgentProxyTranscript(text) {
409
+ const normalized = text.replace(/\s+/g, " ").trim().toLowerCase();
410
+ if (!normalized) return "empty";
411
+ if (/(\.\.\.|…)\s*$/.test(normalized)) return "incomplete-transcript";
412
+ const lastWord = normalized.match(/[a-z']+$/)?.[0]?.replace(/^'+|'+$/g, "");
413
+ if (lastWord && DISCORD_REALTIME_FORCED_CONSULT_TRAILING_FRAGMENT_WORDS.has(lastWord)) return "trailing-fragment";
414
+ if (!normalized.includes("?") && (/^(i'?ll|i will) be (right )?back\b/.test(normalized) || /\b(see you|bye(?:-bye)?|goodbye)\b/.test(normalized))) return "non-actionable-closing";
415
+ }
369
416
  function readProviderConfigString(config, key) {
370
417
  const value = config[key];
371
418
  return typeof value === "string" && value.trim() ? value.trim() : void 0;
@@ -546,7 +593,7 @@ var DiscordRealtimeVoiceSession = class {
546
593
  onToolCall: (event, session) => this.handleToolCall(event, session),
547
594
  onEvent: (event) => {
548
595
  const detail = event.detail ? ` ${event.detail}` : "";
549
- logVoiceVerbose(`realtime ${event.direction}:${event.type}${detail}`);
596
+ if (shouldLogRealtimeVerboseEvent(event)) logVoiceVerbose(`realtime ${event.direction}:${event.type}${detail}`);
550
597
  if (event.direction === "server" && (event.type === "response.done" || event.type === "response.cancelled")) {
551
598
  if (this.exactSpeechResponseActive && !this.exactSpeechAudioStarted) this.completeExactSpeechResponse(event.type);
552
599
  this.finishOutputAudioStream(event.type);
@@ -660,6 +707,10 @@ var DiscordRealtimeVoiceSession = class {
660
707
  const discordPcm = convertRealtimePcm24kMonoToDiscordPcm48kStereo(realtimePcm24kMono);
661
708
  if (discordPcm.length === 0) return;
662
709
  this.syncOutputAudioTimestamp();
710
+ if (this.outputStreamEnding) {
711
+ logVoiceVerbose(`realtime output audio ignored after stream ending: guild ${this.params.entry.guildId} channel ${this.params.entry.channelId}`);
712
+ return;
713
+ }
663
714
  const stream = this.ensureOutputStream();
664
715
  if (this.exactSpeechResponseActive) this.exactSpeechAudioStarted = true;
665
716
  stream.write(discordPcm);
@@ -669,7 +720,7 @@ var DiscordRealtimeVoiceSession = class {
669
720
  this.outputAudioTimestampMs += pcm16MonoDurationMs(realtimePcm24kMono, REALTIME_VOICE_AUDIO_FORMAT_PCM16_24KHZ.sampleRateHz);
670
721
  }
671
722
  ensureOutputStream() {
672
- if (this.outputStream && !this.outputStream.destroyed) return this.outputStream;
723
+ if (this.outputStream && !this.outputStream.destroyed && !this.outputStream.writableEnded) return this.outputStream;
673
724
  const voiceSdk = loadDiscordVoiceSdk();
674
725
  const stream = new PassThrough();
675
726
  this.outputStream = stream;
@@ -679,7 +730,7 @@ var DiscordRealtimeVoiceSession = class {
679
730
  this.logOutputAudioStopped("stream-close");
680
731
  this.outputStream = null;
681
732
  this.resetOutputAudioStats();
682
- this.completeExactSpeechResponse("stream-close");
733
+ this.completeExactSpeechResponse("stream-close", { drain: false });
683
734
  }
684
735
  });
685
736
  const resource = voiceSdk.createAudioResource(stream, { inputType: voiceSdk.StreamType.Raw });
@@ -722,10 +773,11 @@ var DiscordRealtimeVoiceSession = class {
722
773
  this.exactSpeechAudioStarted = false;
723
774
  this.bridge?.sendUserMessage(buildDiscordSpeakExactUserMessage(text));
724
775
  }
725
- completeExactSpeechResponse(reason) {
776
+ completeExactSpeechResponse(reason, options) {
726
777
  if (!this.exactSpeechResponseActive && this.queuedExactSpeechMessages.length === 0) return;
727
778
  this.exactSpeechResponseActive = false;
728
779
  this.exactSpeechAudioStarted = false;
780
+ if (options?.drain === false) return;
729
781
  this.drainQueuedExactSpeechMessages(reason);
730
782
  }
731
783
  drainQueuedExactSpeechMessages(reason) {
@@ -834,6 +886,11 @@ var DiscordRealtimeVoiceSession = class {
834
886
  const question = transcript.trim();
835
887
  if (!question) return;
836
888
  const context = this.consumePendingSpeakerContext();
889
+ const skipReason = classifySkippableForcedAgentProxyTranscript(question);
890
+ if (skipReason) {
891
+ logger$2.info(`discord voice: realtime forced agent consult skipped reason=${skipReason} chars=${question.length} speaker=${context?.speakerLabel ?? "unknown"} transcript=${formatRealtimeLogPreview(question)}`);
892
+ return;
893
+ }
837
894
  if (!context) {
838
895
  const recent = this.findRecentAgentProxyConsultContext(question);
839
896
  if (recent) {
@@ -8101,7 +8101,7 @@ function logDiscordStartupPhase(params) {
8101
8101
  });
8102
8102
  }
8103
8103
  async function loadDiscordVoiceRuntime() {
8104
- const promise = discordVoiceRuntimePromise ?? import("./manager.runtime-DGvCDWI5.js");
8104
+ const promise = discordVoiceRuntimePromise ?? import("./manager.runtime-Dz8Mzdnq.js");
8105
8105
  discordVoiceRuntimePromise = promise;
8106
8106
  try {
8107
8107
  return await promise;
@@ -0,0 +1,2 @@
1
+ import { t as monitorDiscordProvider } from "./provider-B7B8R5Lm.js";
2
+ export { monitorDiscordProvider };
@@ -21,11 +21,11 @@ import { a as mergeAbortSignals, i as DISCORD_DEFAULT_LISTENER_TIMEOUT_MS, n as
21
21
  import "./runtime-api.actions.js";
22
22
  import { r as collectDiscordAuditChannelIds, t as auditDiscordChannelPermissions } from "./audit-BRBe8xFv.js";
23
23
  import "./runtime-api.lookup.js";
24
- import { a as createDiscordNativeCommand, i as waitForDiscordGatewayPluginRegistration, n as createDiscordGatewayPlugin, o as registerDiscordListener, r as resolveDiscordGatewayIntents, t as monitorDiscordProvider } from "./provider-DBvvDP9A.js";
24
+ import { a as createDiscordNativeCommand, i as waitForDiscordGatewayPluginRegistration, n as createDiscordGatewayPlugin, o as registerDiscordListener, r as resolveDiscordGatewayIntents, t as monitorDiscordProvider } from "./provider-B7B8R5Lm.js";
25
25
  import { i as buildDiscordMediaPayload } from "./message-utils-DEjCwCRz.js";
26
26
  import { o as sanitizeDiscordThreadName, r as resolveDiscordReplyTarget } from "./threading-CTUnZtNi.js";
27
27
  import { t as createDiscordMessageHandler } from "./message-handler-BWHSteQf.js";
28
- import "./runtime-api.monitor-CsetE9pd.js";
28
+ import "./runtime-api.monitor-DvOaEiyt.js";
29
29
  import "./runtime-api.send.js";
30
30
  import "./runtime-api.threads.js";
31
31
  export { DISCORD_ATTACHMENT_IDLE_TIMEOUT_MS, DISCORD_ATTACHMENT_TOTAL_TIMEOUT_MS, DISCORD_DEFAULT_INBOUND_WORKER_TIMEOUT_MS, DISCORD_DEFAULT_LISTENER_TIMEOUT_MS, DiscordSendError, __testing, addRoleDiscord, allowListMatches, auditDiscordChannelPermissions, autoBindSpawnedDiscordSubagent, banMemberDiscord, buildDiscordMediaPayload, clearGateways, clearPresences, collectDiscordAuditChannelIds, createChannelDiscord, createDiscordGatewayPlugin, createDiscordMessageHandler, createDiscordNativeCommand, createNoopThreadBindingManager, createScheduledEventDiscord, createThreadBindingManager, createThreadDiscord, deleteChannelDiscord, deleteMessageDiscord, discordMessageActions, editChannelDiscord, editDiscordComponentMessage, editMessageDiscord, fetchChannelInfoDiscord, fetchChannelPermissionsDiscord, fetchDiscordApplicationId, fetchDiscordApplicationSummary, fetchMemberGuildPermissionsDiscord, fetchMemberInfoDiscord, fetchMessageDiscord, fetchReactionsDiscord, fetchRoleInfoDiscord, fetchVoiceStatusDiscord, formatThreadBindingDurationLabel, getGateway, getPresence, getThreadBindingManager, handleDiscordAction, hasAllGuildPermissionsDiscord, hasAnyGuildPermissionDiscord, isDiscordGroupAllowedByPolicy, isDiscordModerationAction, isRecentlyUnboundThreadWebhookMessage, kickMemberDiscord, listDiscordDirectoryGroupsLive, listDiscordDirectoryPeersLive, listGuildChannelsDiscord, listGuildEmojisDiscord, listPinsDiscord, listScheduledEventsDiscord, listThreadBindingsBySessionKey, listThreadBindingsForAccount, listThreadsDiscord, mergeAbortSignals, monitorDiscordProvider, moveChannelDiscord, normalizeDiscordAllowList, normalizeDiscordSlug, parseApplicationIdFromToken, pinMessageDiscord, presenceCacheSize, probeDiscord, reactMessageDiscord, readDiscordChannelCreateParams, readDiscordChannelEditParams, readDiscordChannelMoveParams, readDiscordModerationCommand, readDiscordParentIdParam, readMessagesDiscord, reconcileAcpThreadBindingsOnStartup, registerBuiltDiscordComponentMessage, registerDiscordListener, registerGateway, removeChannelPermissionDiscord, removeOwnReactionsDiscord, removeReactionDiscord, removeRoleDiscord, requiredGuildPermissionForModerationAction, resolveDiscordChannelAllowlist, resolveDiscordChannelConfig, resolveDiscordChannelConfigWithFallback, resolveDiscordCommandAuthorized, resolveDiscordGatewayIntents, resolveDiscordGuildEntry, resolveDiscordOutboundSessionRoute, resolveDiscordPrivilegedIntentsFromFlags, resolveDiscordReplyTarget, resolveDiscordShouldRequireMention, resolveDiscordThreadBindingIdleTimeoutMs, resolveDiscordThreadBindingMaxAgeMs, resolveDiscordUserAllowlist, resolveEventCoverImage, resolveGroupDmAllow, resolveThreadBindingIdleTimeoutMs, resolveThreadBindingInactivityExpiresAt, resolveThreadBindingIntroText, resolveThreadBindingMaxAgeExpiresAt, resolveThreadBindingMaxAgeMs, resolveThreadBindingPersona, resolveThreadBindingPersonaFromRecord, resolveThreadBindingThreadName, resolveThreadBindingsEnabled, sanitizeDiscordThreadName, searchMessagesDiscord, sendDiscordComponentMessage, sendMessageDiscord, sendPollDiscord, sendStickerDiscord, sendTypingDiscord, sendVoiceMessageDiscord, sendWebhookMessageDiscord, setChannelPermissionDiscord, setDiscordRuntime, setPresence, setThreadBindingIdleTimeoutBySessionKey, setThreadBindingMaxAgeBySessionKey, shouldEmitDiscordReactionNotification, timeoutMemberDiscord, unbindThreadBindingsBySessionKey, unpinMessageDiscord, unregisterGateway, uploadEmojiDiscord, uploadStickerDiscord, waitForDiscordGatewayPluginRegistration };
@@ -1,5 +1,5 @@
1
1
  import "./allow-list-4wnZg5P9.js";
2
- import "./provider-DBvvDP9A.js";
2
+ import "./provider-B7B8R5Lm.js";
3
3
  import "./message-utils-DEjCwCRz.js";
4
4
  import "./threading-CTUnZtNi.js";
5
5
  import "./message-handler-BWHSteQf.js";
@@ -1,9 +1,9 @@
1
1
  import { a as clearPresences, c as setPresence, i as unregisterGateway, n as getGateway, o as getPresence, r as registerGateway, s as presenceCacheSize, t as clearGateways } from "./gateway-registry-BKG4KIVC.js";
2
2
  import { _ as resolveGroupDmAllow, a as normalizeDiscordSlug, c as resolveDiscordChannelConfigWithFallback, d as resolveDiscordGuildEntry, g as resolveDiscordShouldRequireMention, n as isDiscordGroupAllowedByPolicy, r as normalizeDiscordAllowList, s as resolveDiscordChannelConfig, t as allowListMatches, u as resolveDiscordCommandAuthorized, v as shouldEmitDiscordReactionNotification } from "./allow-list-4wnZg5P9.js";
3
3
  import { a as mergeAbortSignals, i as DISCORD_DEFAULT_LISTENER_TIMEOUT_MS, n as DISCORD_ATTACHMENT_TOTAL_TIMEOUT_MS, r as DISCORD_DEFAULT_INBOUND_WORKER_TIMEOUT_MS, t as DISCORD_ATTACHMENT_IDLE_TIMEOUT_MS } from "./timeouts-C3FYXWJX.js";
4
- import { a as createDiscordNativeCommand, i as waitForDiscordGatewayPluginRegistration, n as createDiscordGatewayPlugin, o as registerDiscordListener, r as resolveDiscordGatewayIntents, t as monitorDiscordProvider } from "./provider-DBvvDP9A.js";
4
+ import { a as createDiscordNativeCommand, i as waitForDiscordGatewayPluginRegistration, n as createDiscordGatewayPlugin, o as registerDiscordListener, r as resolveDiscordGatewayIntents, t as monitorDiscordProvider } from "./provider-B7B8R5Lm.js";
5
5
  import { i as buildDiscordMediaPayload } from "./message-utils-DEjCwCRz.js";
6
6
  import { o as sanitizeDiscordThreadName, r as resolveDiscordReplyTarget } from "./threading-CTUnZtNi.js";
7
7
  import { t as createDiscordMessageHandler } from "./message-handler-BWHSteQf.js";
8
- import "./runtime-api.monitor-CsetE9pd.js";
8
+ import "./runtime-api.monitor-DvOaEiyt.js";
9
9
  export { DISCORD_ATTACHMENT_IDLE_TIMEOUT_MS, DISCORD_ATTACHMENT_TOTAL_TIMEOUT_MS, DISCORD_DEFAULT_INBOUND_WORKER_TIMEOUT_MS, DISCORD_DEFAULT_LISTENER_TIMEOUT_MS, allowListMatches, buildDiscordMediaPayload, clearGateways, clearPresences, createDiscordGatewayPlugin, createDiscordMessageHandler, createDiscordNativeCommand, getGateway, getPresence, isDiscordGroupAllowedByPolicy, mergeAbortSignals, monitorDiscordProvider, normalizeDiscordAllowList, normalizeDiscordSlug, presenceCacheSize, registerDiscordListener, registerGateway, resolveDiscordChannelConfig, resolveDiscordChannelConfigWithFallback, resolveDiscordCommandAuthorized, resolveDiscordGatewayIntents, resolveDiscordGuildEntry, resolveDiscordReplyTarget, resolveDiscordShouldRequireMention, resolveGroupDmAllow, sanitizeDiscordThreadName, setPresence, shouldEmitDiscordReactionNotification, unregisterGateway, waitForDiscordGatewayPluginRegistration };
package/dist/test-api.js CHANGED
@@ -1,4 +1,4 @@
1
- import { t as discordPlugin } from "./channel-DTBEGHsT.js";
1
+ import { t as discordPlugin } from "./channel-D0GnZ6j1.js";
2
2
  import { n as discordOutbound } from "./outbound-adapter-Bt8FL3yO.js";
3
3
  import { t as __testing } from "./thread-bindings.manager-DTuwm8Tk.js";
4
4
  import { n as buildDiscordInboundAccessContext } from "./inbound-context-BAwOn5Iq.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openclaw/discord",
3
- "version": "2026.5.10-beta.1",
3
+ "version": "2026.5.10-beta.2",
4
4
  "description": "OpenClaw Discord channel plugin",
5
5
  "repository": {
6
6
  "type": "git",
@@ -21,7 +21,7 @@
21
21
  "openclaw": "workspace:*"
22
22
  },
23
23
  "peerDependencies": {
24
- "openclaw": ">=2026.5.10-beta.1"
24
+ "openclaw": ">=2026.5.10-beta.2"
25
25
  },
26
26
  "peerDependenciesMeta": {
27
27
  "openclaw": {
@@ -65,10 +65,10 @@
65
65
  "allowInvalidConfigRecovery": true
66
66
  },
67
67
  "compat": {
68
- "pluginApi": ">=2026.5.10-beta.1"
68
+ "pluginApi": ">=2026.5.10-beta.2"
69
69
  },
70
70
  "build": {
71
- "openclawVersion": "2026.5.10-beta.1"
71
+ "openclawVersion": "2026.5.10-beta.2"
72
72
  },
73
73
  "release": {
74
74
  "publishToClawHub": true,
@@ -1,2 +0,0 @@
1
- import { t as monitorDiscordProvider } from "./provider-DBvvDP9A.js";
2
- export { monitorDiscordProvider };