@openclaw/discord 2026.7.1-beta.4 → 2026.7.1-beta.6

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
@@ -6,7 +6,7 @@ import { n as fetchDiscord, r as requestDiscord, t as DiscordApiError } from "./
6
6
  import { i as parseDiscordSendTarget, n as resolveDiscordTarget } from "./target-resolver-CwHaSLt3.js";
7
7
  import "./targets-69w7c3vU.js";
8
8
  import { a as getDiscordExecApprovalApprovers, c as shouldSuppressLocalDiscordExecApprovalPrompt, o as isDiscordExecApprovalApprover, s as isDiscordExecApprovalClientEnabled } from "./conversation-identity-DWC5d8Sy.js";
9
- import { i as resolveDiscordGroupToolPolicy, n as collectDiscordStatusIssues, r as resolveDiscordGroupRequireMention, t as discordPlugin } from "./channel-kBTCV_g9.js";
9
+ import { i as resolveDiscordGroupToolPolicy, n as collectDiscordStatusIssues, r as resolveDiscordGroupRequireMention, t as discordPlugin } from "./channel-DGWPH5u3.js";
10
10
  import { i as DISCORD_DEFAULT_LISTENER_TIMEOUT_MS, n as DISCORD_ATTACHMENT_TOTAL_TIMEOUT_MS, o as mergeAbortSignals, r as DISCORD_DEFAULT_INBOUND_WORKER_TIMEOUT_MS, t as DISCORD_ATTACHMENT_IDLE_TIMEOUT_MS } from "./timeouts-C5TBc_9x.js";
11
11
  import { t as normalizeExplicitDiscordSessionKey } from "./session-key-normalization-wJgsKPNF.js";
12
12
  import { t as discordSetupPlugin } from "./channel.setup-tZcpIn4e.js";
@@ -126,7 +126,7 @@ const loadDiscordResolveChannelsModule = createLazyRuntimeModule(() => import(".
126
126
  const loadDiscordResolveUsersModule = createLazyRuntimeModule(() => import("./resolve-users-DJamun9s.js").then((n) => n.n));
127
127
  const loadDiscordThreadBindingsManagerModule = createLazyRuntimeModule(() => import("./thread-bindings.manager-Bwmtqc3E.js").then((n) => n.a));
128
128
  const loadDiscordTargetResolverModule = createLazyRuntimeModule(() => import("./target-resolver-CwHaSLt3.js").then((n) => n.r));
129
- const loadDiscordProviderRuntime = createLazyRuntimeModule(() => import("./provider.runtime-BIHvVXCg.js"));
129
+ const loadDiscordProviderRuntime = createLazyRuntimeModule(() => import("./provider.runtime-WrJXikSv.js"));
130
130
  const loadDiscordProbeRuntime = createLazyRuntimeModule(() => import("./probe.runtime-B1dsEeBD.js"));
131
131
  const loadDiscordAuditModule = createLazyRuntimeModule(() => import("./audit-MLpDpN3Z.js").then((n) => n.n));
132
132
  const loadDiscordSendModule = createLazyRuntimeModule(() => import("./send-iJ0B4bAX.js").then((n) => n.t));
@@ -1,2 +1,2 @@
1
- import { t as discordPlugin } from "./channel-kBTCV_g9.js";
1
+ import { t as discordPlugin } from "./channel-DGWPH5u3.js";
2
2
  export { discordPlugin };
@@ -3,7 +3,7 @@ import { c as resolveDiscordAccountAllowFrom } from "./accounts-P19jm1lf.js";
3
3
  import { a as normalizeDiscordSlug, b as formatDiscordUserTag, m as resolveDiscordOwnerAccess } from "./allow-list-C-MqM-B_.js";
4
4
  import { a as formatMention } from "./send.outbound-Bj61Q3a0.js";
5
5
  import { t as getDiscordRuntime } from "./runtime-DgnVQ7zW.js";
6
- import { d as resolveDiscordVoiceEnabled, p as buildDiscordGroupSystemPrompt, s as authorizeDiscordVoiceIngress } from "./provider-Cm9QSAO8.js";
6
+ import { d as resolveDiscordVoiceEnabled, p as buildDiscordGroupSystemPrompt, s as authorizeDiscordVoiceIngress } from "./provider-BkfbC9FQ.js";
7
7
  import { createRequire } from "node:module";
8
8
  import { asBoolean, normalizeOptionalString, uniqueStrings } from "openclaw/plugin-sdk/string-coerce-runtime";
9
9
  import { resolveAgentRoute } from "openclaw/plugin-sdk/routing";
@@ -20,6 +20,7 @@ import { REALTIME_VOICE_AGENT_CONSULT_TOOL_NAME, REALTIME_VOICE_AGENT_CONTROL_TO
20
20
  import { agentCommandFromIngress, getTtsProvider, resolveAgentDir, resolveTtsConfig, resolveTtsPrefsPath } from "openclaw/plugin-sdk/agent-runtime";
21
21
  import { spawn } from "node:child_process";
22
22
  import { PassThrough, Readable, Transform, pipeline } from "node:stream";
23
+ import { StringDecoder } from "node:string_decoder";
23
24
  import { Application, OpusError, createDecoder, createEncoder } from "libopus-wasm";
24
25
  import { resolveRealtimeBootstrapContextInstructions } from "openclaw/plugin-sdk/realtime-bootstrap-context";
25
26
  import { parseTtsDirectives } from "openclaw/plugin-sdk/speech";
@@ -107,14 +108,14 @@ function createDiscordOpusPlaybackStream(input) {
107
108
  windowsHide: true
108
109
  });
109
110
  const opusStream = createDiscordOpusEncodeStream();
110
- let stderr = "";
111
+ const stderr = Buffer.alloc(FFMPEG_ERROR_OUTPUT_BYTES);
112
+ let stderrBytes = 0;
111
113
  let ffmpegClosed = false;
112
114
  const killFfmpeg = (signal = "SIGTERM") => {
113
115
  if (!ffmpegClosed && !ffmpeg.killed) ffmpeg.kill(signal);
114
116
  };
115
- ffmpeg.stderr.setEncoding("utf8");
116
117
  ffmpeg.stderr.on("data", (chunk) => {
117
- if (stderr.length < FFMPEG_ERROR_OUTPUT_BYTES) stderr = `${stderr}${chunk}`.slice(0, FFMPEG_ERROR_OUTPUT_BYTES);
118
+ if (stderrBytes < FFMPEG_ERROR_OUTPUT_BYTES) stderrBytes += chunk.copy(stderr, stderrBytes, 0, FFMPEG_ERROR_OUTPUT_BYTES - stderrBytes);
118
119
  });
119
120
  ffmpeg.once("error", (err) => {
120
121
  opusStream.destroy(err);
@@ -122,7 +123,8 @@ function createDiscordOpusPlaybackStream(input) {
122
123
  ffmpeg.once("close", (code, signal) => {
123
124
  ffmpegClosed = true;
124
125
  if (code && code !== 0) {
125
- const suffix = stderr.trim() ? `: ${stderr.trim()}` : "";
126
+ const stderrText = new StringDecoder("utf8").write(stderr.subarray(0, stderrBytes)).trim();
127
+ const suffix = stderrText ? `: ${stderrText}` : "";
126
128
  opusStream.destroy(/* @__PURE__ */ new Error(`ffmpeg exited with code ${code}${suffix}`));
127
129
  return;
128
130
  }
@@ -178,7 +178,7 @@ function resolveDiscordAcceptedTypingPrestart(ctx) {
178
178
  }
179
179
  //#endregion
180
180
  //#region extensions/discord/src/monitor/message-run-queue.ts
181
- const loadMessageProcessRuntime = createLazyRuntimeModule(() => import("./message-handler.process-CV1GmuBj.js"));
181
+ const loadMessageProcessRuntime = createLazyRuntimeModule(() => import("./message-handler.process-Cjf30P_B.js"));
182
182
  async function processDiscordQueuedMessage(params) {
183
183
  const processDiscordMessageImpl = params.testing?.processDiscordMessage ?? (await loadMessageProcessRuntime()).processDiscordMessage;
184
184
  const abortSignal = mergeAbortSignals([params.job.runtime.abortSignal, params.lifecycleSignal]);
@@ -307,7 +307,7 @@ function createDiscordReplyTypingFeedback(params) {
307
307
  }
308
308
  //#endregion
309
309
  //#region extensions/discord/src/monitor/message-handler.ts
310
- const loadMessagePreflightRuntime = createLazyRuntimeModule(() => import("./message-handler.preflight-Dd-xQ-qv.js"));
310
+ const loadMessagePreflightRuntime = createLazyRuntimeModule(() => import("./message-handler.preflight-DvLXiYVH.js"));
311
311
  function isNonEmptyString(value) {
312
312
  return typeof value === "string" && value.length > 0;
313
313
  }
@@ -6,7 +6,7 @@ import { d as isRecentlyUnboundThreadWebhookMessage } from "./thread-bindings.st
6
6
  import { n as DISCORD_ATTACHMENT_TOTAL_TIMEOUT_MS, t as DISCORD_ATTACHMENT_IDLE_TIMEOUT_MS } from "./timeouts-C5TBc_9x.js";
7
7
  import { d as resolveDiscordChannelNameSafe, u as resolveDiscordChannelInfoSafe } from "./thread-bindings.discord-api-BjIf9lGs.js";
8
8
  import "./thread-bindings-DsTxqu3E.js";
9
- import { D as resolveDiscordDmCommandAccess, O as resolveDiscordTextCommandAccess, _ as resolveDiscordConversationRoute, b as handleDiscordDmCommandDecision, g as buildDiscordRoutePeer, v as resolveDiscordEffectiveRoute, y as shouldIgnoreStaleDiscordRouteBinding } from "./provider-Cm9QSAO8.js";
9
+ import { D as resolveDiscordDmCommandAccess, O as resolveDiscordTextCommandAccess, _ as resolveDiscordConversationRoute, b as handleDiscordDmCommandDecision, g as buildDiscordRoutePeer, v as resolveDiscordEffectiveRoute, y as shouldIgnoreStaleDiscordRouteBinding } from "./provider-BkfbC9FQ.js";
10
10
  import { a as resolveForwardedMediaList, d as resolveDiscordMessageChannelId, l as resolveDiscordMessageStickers, o as resolveMediaList, r as resolveDiscordMessageText, u as resolveDiscordChannelInfo } from "./message-utils-B_3yA5bN.js";
11
11
  import { n as resolveDiscordWebhookId, t as resolveDiscordSenderIdentity } from "./sender-identity-CEsfDF0L.js";
12
12
  import { createLazyRuntimeModule } from "openclaw/plugin-sdk/lazy-runtime";
@@ -427,7 +427,7 @@ function logDiscordPreflightInboundSummary(params) {
427
427
  const loadPluralKitRuntime = createLazyRuntimeModule(() => import("./pluralkit-DcD-3EcL.js").then((n) => n.n));
428
428
  const loadPreflightAudioRuntime = createLazyRuntimeModule(() => import("./preflight-audio-DYL2ABgA.js"));
429
429
  const loadSystemEventsRuntime = createLazyRuntimeModule(() => import("./system-events-DVnqSyTt.js"));
430
- const loadDiscordThreadingRuntime = createLazyRuntimeModule(() => import("./provider-Cm9QSAO8.js").then((n) => n.S));
430
+ const loadDiscordThreadingRuntime = createLazyRuntimeModule(() => import("./provider-BkfbC9FQ.js").then((n) => n.S));
431
431
  function isPreflightAborted(abortSignal) {
432
432
  return Boolean(abortSignal?.aborted);
433
433
  }
@@ -10,9 +10,9 @@ import { t as beginDiscordInboundEventDeliveryCorrelation } from "./inbound-even
10
10
  import { n as DISCORD_ATTACHMENT_TOTAL_TIMEOUT_MS, t as DISCORD_ATTACHMENT_IDLE_TIMEOUT_MS } from "./timeouts-C5TBc_9x.js";
11
11
  import { t as DISCORD_TEXT_CHUNK_LIMIT } from "./outbound-adapter-82RWi_SR.js";
12
12
  import { t as resolveDiscordPreviewStreamMode } from "./preview-streaming-DXT8oJdo.js";
13
- import { C as resolveDiscordAutoThreadReplyPlan, T as resolveDiscordThreadStarter, a as buildGuildLabel, h as createDiscordSupplementalContextAccessChecker, i as buildDirectLabel, m as buildDiscordInboundAccessContext, n as deliverDiscordReply, o as resolveReplyContext, r as sanitizeDiscordFrontChannelReplyPayloads } from "./provider-Cm9QSAO8.js";
13
+ import { C as resolveDiscordAutoThreadReplyPlan, T as resolveDiscordThreadStarter, a as buildGuildLabel, h as createDiscordSupplementalContextAccessChecker, i as buildDirectLabel, m as buildDiscordInboundAccessContext, n as deliverDiscordReply, o as resolveReplyContext, r as sanitizeDiscordFrontChannelReplyPayloads } from "./provider-BkfbC9FQ.js";
14
14
  import { r as resolveDiscordMessageText, s as resolveReferencedReplyMediaList } from "./message-utils-B_3yA5bN.js";
15
- import { n as createDiscordReplyTypingFeedback } from "./message-handler-DbrX-sHg.js";
15
+ import { n as createDiscordReplyTypingFeedback } from "./message-handler-DcgvugZt.js";
16
16
  import { createLazyRuntimeModule } from "openclaw/plugin-sdk/lazy-runtime";
17
17
  import { buildAgentSessionKey, resolveThreadSessionKeys } from "openclaw/plugin-sdk/routing";
18
18
  import { MessageFlags } from "discord-api-types/v10";
@@ -60,7 +60,7 @@ import { applyModelOverrideToSessionEntry, resolveChannelModelOverride } from "o
60
60
  import { completeWithPreparedSimpleCompletionModel, extractAssistantText, prepareSimpleCompletionModelForAgent } from "openclaw/plugin-sdk/simple-completion-runtime";
61
61
  import { getSessionEntry, listSessionEntries, patchSessionEntry, readSessionUpdatedAt as readSessionUpdatedAt$1, resolveStorePath, resolveStorePath as resolveStorePath$1 } from "openclaw/plugin-sdk/session-store-runtime";
62
62
  import { formatInboundEnvelope, resolveEnvelopeFormatOptions, runChannelInboundEvent } from "openclaw/plugin-sdk/channel-inbound";
63
- import { buildCommandTextFromArgs, findCommandByNativeName, formatCommandArgMenuTitle, listChatCommands, listNativeCommandSpecsForConfig, listSkillCommandsForAgents, resolveCommandAuthorizedFromAuthorizers, resolveNativeCommandSessionTargets, resolveStoredModelOverride, serializeCommandArgs } from "openclaw/plugin-sdk/command-auth-native";
63
+ import { buildCommandTextFromArgs, findCommandByNativeName, formatCommandArgMenuTitle, listChatCommands, listNativeCommandSpecsForConfig, listSkillCommandsForAgents, resolveCommandAuthorizedFromAuthorizers, resolveEffectiveAgentRuntime, resolveNativeCommandSessionTargets, resolveStoredModelOverride, serializeCommandArgs } from "openclaw/plugin-sdk/command-auth-native";
64
64
  import { buildCommandTextFromArgs as buildCommandTextFromArgs$1, findCommandByNativeName as findCommandByNativeName$1, parseCommandArgs, resolveCommandArgChoices, resolveCommandArgMenu, serializeCommandArgs as serializeCommandArgs$1 } from "openclaw/plugin-sdk/native-command-registry";
65
65
  import { resolveDirectStatusReplyForSession } from "openclaw/plugin-sdk/command-status-runtime";
66
66
  import * as pluginRuntime from "openclaw/plugin-sdk/plugin-runtime";
@@ -3537,11 +3537,12 @@ async function resolveDiscordNativeChoiceContext(params) {
3537
3537
  agentId: route.agentId
3538
3538
  });
3539
3539
  const storePath = resolveStorePath(params.cfg.session?.store, { agentId: route.agentId });
3540
+ const sessionEntry = getSessionEntry({
3541
+ storePath,
3542
+ sessionKey: route.sessionKey
3543
+ });
3540
3544
  const override = resolveStoredModelOverride({
3541
- sessionEntry: getSessionEntry({
3542
- storePath,
3543
- sessionKey: route.sessionKey
3544
- }),
3545
+ sessionEntry,
3545
3546
  loadSessionEntry: (sessionKey) => getSessionEntry({
3546
3547
  storePath,
3547
3548
  sessionKey
@@ -3549,13 +3550,19 @@ async function resolveDiscordNativeChoiceContext(params) {
3549
3550
  sessionKey: route.sessionKey,
3550
3551
  defaultProvider: fallback.provider
3551
3552
  });
3552
- if (!override?.model) return {
3553
- provider: fallback.provider,
3554
- model: fallback.model
3555
- };
3553
+ const provider = override?.provider || fallback.provider;
3554
+ const model = override?.model || fallback.model;
3556
3555
  return {
3557
- provider: override.provider || fallback.provider,
3558
- model: override.model
3556
+ provider,
3557
+ model,
3558
+ agentRuntime: resolveEffectiveAgentRuntime({
3559
+ cfg: params.cfg,
3560
+ provider,
3561
+ modelId: model,
3562
+ agentId: route.agentId,
3563
+ sessionKey: route.sessionKey,
3564
+ sessionEntry
3565
+ })
3559
3566
  };
3560
3567
  } catch {
3561
3568
  return null;
@@ -4244,6 +4251,7 @@ function buildDiscordCommandOptions(params) {
4244
4251
  cfg: currentCfg,
4245
4252
  provider: context?.provider,
4246
4253
  model: context?.model,
4254
+ agentRuntime: context?.agentRuntime,
4247
4255
  ...choiceCatalog?.length ? { catalog: choiceCatalog } : {}
4248
4256
  });
4249
4257
  const filtered = focusValue ? choices.filter((choice) => normalizeLowercaseStringOrEmpty(choice.label).includes(focusValue)) : choices;
@@ -4565,6 +4573,7 @@ async function dispatchDiscordCommandInteraction(params) {
4565
4573
  cfg,
4566
4574
  provider: menuModelContext?.provider,
4567
4575
  model: menuModelContext?.model,
4576
+ agentRuntime: menuModelContext?.agentRuntime,
4568
4577
  ...menuModelCatalog?.length ? { catalog: menuModelCatalog } : {}
4569
4578
  });
4570
4579
  if (menu) {
@@ -5035,6 +5044,7 @@ const DISCORD_GATEWAY_PAYLOAD_LIMIT_BYTES = 4096;
5035
5044
  const DISCORD_GATEWAY_WS_CLIENT_OPTIONS = Object.freeze({ maxPayload: 16 * 1024 * 1024 });
5036
5045
  const INVALID_SESSION_MIN_DELAY_MS = 1e3;
5037
5046
  const INVALID_SESSION_JITTER_MS = 4e3;
5047
+ const RESUME_FAILURE_THRESHOLD = 3;
5038
5048
  function ensureGatewayParams(url) {
5039
5049
  const parsed = new URL(url);
5040
5050
  parsed.searchParams.set("v", parsed.searchParams.get("v") ?? "10");
@@ -5061,6 +5071,7 @@ var GatewayPlugin = class extends Plugin {
5061
5071
  this.sessionId = null;
5062
5072
  this.resumeGatewayUrl = null;
5063
5073
  this.reconnectAttempts = 0;
5074
+ this.consecutiveResumeFailures = 0;
5064
5075
  this.shouldReconnect = false;
5065
5076
  this.isConnecting = false;
5066
5077
  this.heartbeatTimers = new GatewayHeartbeatTimers();
@@ -5126,6 +5137,7 @@ var GatewayPlugin = class extends Plugin {
5126
5137
  this.isConnecting = false;
5127
5138
  this.isConnected = false;
5128
5139
  this.reconnectAttempts = 0;
5140
+ this.consecutiveResumeFailures = 0;
5129
5141
  }
5130
5142
  createWebSocket(url) {
5131
5143
  return new ws.WebSocket(url, DISCORD_GATEWAY_WS_CLIENT_OPTIONS);
@@ -5163,7 +5175,11 @@ var GatewayPlugin = class extends Plugin {
5163
5175
  }
5164
5176
  const canResume = canResumeAfterGatewayClose(closeCode);
5165
5177
  if (!canResume) this.resetSessionState();
5166
- this.scheduleReconnect(canResume, closeCode);
5178
+ this.scheduleReconnect({
5179
+ reason: "close",
5180
+ preferResume: canResume,
5181
+ closeCode
5182
+ });
5167
5183
  });
5168
5184
  socket.on("error", (error) => {
5169
5185
  if (socket !== this.ws) return;
@@ -5173,20 +5189,22 @@ var GatewayPlugin = class extends Plugin {
5173
5189
  handlePayload(payload, resume, sourceSocket) {
5174
5190
  if (payload.s !== null && payload.s !== void 0) this.sequence = payload.s;
5175
5191
  switch (payload.op) {
5176
- case GatewayOpcodes.Hello:
5192
+ case GatewayOpcodes.Hello: {
5177
5193
  this.startHeartbeat(payload.d.heartbeat_interval ?? 45e3);
5178
- if (resume && this.sessionId) this.send({
5194
+ const resumeState = resume ? this.getResumeState() : null;
5195
+ if (resumeState) this.send({
5179
5196
  op: GatewayOpcodes.Resume,
5180
5197
  d: {
5181
5198
  token: this.client?.options.token ?? "",
5182
- session_id: this.sessionId,
5183
- seq: this.sequence ?? 0
5199
+ session_id: resumeState.sessionId,
5200
+ seq: resumeState.sequence
5184
5201
  }
5185
5202
  }, true);
5186
5203
  else this.identifyWithConcurrency(sourceSocket).catch((error) => {
5187
5204
  this.emitter.emit("error", error instanceof Error ? error : new Error(String(error), { cause: error }));
5188
5205
  });
5189
5206
  break;
5207
+ }
5190
5208
  case GatewayOpcodes.HeartbeatAck:
5191
5209
  this.lastHeartbeatAck = true;
5192
5210
  break;
@@ -5200,10 +5218,17 @@ var GatewayPlugin = class extends Plugin {
5200
5218
  break;
5201
5219
  case GatewayOpcodes.InvalidSession:
5202
5220
  if (!payload.d) this.resetSessionState();
5203
- this.scheduleReconnect(payload.d, void 0, INVALID_SESSION_MIN_DELAY_MS + Math.floor(Math.random() * INVALID_SESSION_JITTER_MS));
5221
+ this.scheduleReconnect({
5222
+ reason: "invalid-session",
5223
+ preferResume: payload.d,
5224
+ minDelayMs: INVALID_SESSION_MIN_DELAY_MS + Math.floor(Math.random() * INVALID_SESSION_JITTER_MS)
5225
+ });
5204
5226
  break;
5205
5227
  case GatewayOpcodes.Reconnect:
5206
- this.scheduleReconnect(true);
5228
+ this.scheduleReconnect({
5229
+ reason: "reconnect-opcode",
5230
+ preferResume: true
5231
+ });
5207
5232
  break;
5208
5233
  }
5209
5234
  }
@@ -5214,7 +5239,10 @@ var GatewayPlugin = class extends Plugin {
5214
5239
  onHeartbeat: () => this.sendHeartbeat(),
5215
5240
  onAckTimeout: () => {
5216
5241
  this.emitter.emit("error", /* @__PURE__ */ new Error("Gateway heartbeat ACK timeout"));
5217
- this.scheduleReconnect(true);
5242
+ this.scheduleReconnect({
5243
+ reason: "zombie",
5244
+ preferResume: true
5245
+ });
5218
5246
  }
5219
5247
  });
5220
5248
  }
@@ -5255,7 +5283,10 @@ var GatewayPlugin = class extends Plugin {
5255
5283
  const socket = sourceSocket ?? this.ws;
5256
5284
  if (!socket || socket !== this.ws) return;
5257
5285
  if (socket.readyState !== READY_STATE_OPEN) {
5258
- this.scheduleReconnect(false);
5286
+ this.scheduleReconnect({
5287
+ reason: "identify",
5288
+ preferResume: false
5289
+ });
5259
5290
  return;
5260
5291
  }
5261
5292
  this.identify();
@@ -5277,10 +5308,12 @@ var GatewayPlugin = class extends Plugin {
5277
5308
  this.sessionId = ready.session_id ?? null;
5278
5309
  this.resumeGatewayUrl = ready.resume_gateway_url ?? null;
5279
5310
  this.reconnectAttempts = 0;
5311
+ this.consecutiveResumeFailures = 0;
5280
5312
  this.isConnected = true;
5281
5313
  }
5282
5314
  if (payload.t === GatewayDispatchEvents.Resumed) {
5283
5315
  this.reconnectAttempts = 0;
5316
+ this.consecutiveResumeFailures = 0;
5284
5317
  this.isConnected = true;
5285
5318
  }
5286
5319
  dispatchVoiceGatewayEvent(this.client, payload.t, payload.d);
@@ -5292,8 +5325,15 @@ var GatewayPlugin = class extends Plugin {
5292
5325
  this.sessionId = null;
5293
5326
  this.resumeGatewayUrl = null;
5294
5327
  this.sequence = null;
5328
+ this.consecutiveResumeFailures = 0;
5295
5329
  }
5296
- scheduleReconnect(resume, closeCode, minDelayMs = 0) {
5330
+ getResumeState() {
5331
+ return this.sessionId && this.sequence !== null ? {
5332
+ sessionId: this.sessionId,
5333
+ sequence: this.sequence
5334
+ } : null;
5335
+ }
5336
+ scheduleReconnect(options) {
5297
5337
  if (!this.shouldReconnect) return;
5298
5338
  this.stopHeartbeat();
5299
5339
  this.stopReconnectTimer();
@@ -5305,12 +5345,21 @@ var GatewayPlugin = class extends Plugin {
5305
5345
  this.reconnectAttempts += 1;
5306
5346
  if (this.reconnectAttempts > (this.options.reconnect?.maxAttempts ?? 50)) {
5307
5347
  const maxAttempts = this.options.reconnect?.maxAttempts ?? 50;
5308
- this.emitter.emit("error", /* @__PURE__ */ new Error(`Max reconnect attempts (${maxAttempts}) reached${closeCode !== void 0 ? ` after close code ${closeCode}` : ""}`));
5348
+ this.emitter.emit("error", /* @__PURE__ */ new Error(`Max reconnect attempts (${maxAttempts}) reached${options.closeCode !== void 0 ? ` after close code ${options.closeCode}` : ""}`));
5309
5349
  return;
5310
5350
  }
5311
- const delay = Math.max(minDelayMs, Math.min(3e4, 1e3 * 2 ** Math.min(this.reconnectAttempts, 5)));
5351
+ let shouldResume = options.preferResume && this.getResumeState() !== null;
5352
+ if (shouldResume && this.consecutiveResumeFailures >= RESUME_FAILURE_THRESHOLD) {
5353
+ this.resetSessionState();
5354
+ shouldResume = false;
5355
+ this.emitter.emit("debug", `Gateway forcing fresh IDENTIFY after ${RESUME_FAILURE_THRESHOLD} failed resume attempts`);
5356
+ }
5357
+ if (shouldResume) this.consecutiveResumeFailures += 1;
5358
+ else this.consecutiveResumeFailures = 0;
5359
+ const delay = Math.max(options.minDelayMs ?? 0, Math.min(3e4, 1e3 * 2 ** Math.min(this.reconnectAttempts, 5)));
5360
+ this.emitter.emit("debug", `Gateway reconnect scheduled in ${delay}ms (${options.reason}, resume=${String(shouldResume)})`);
5312
5361
  this.reconnectTimer.schedule(delay, () => {
5313
- this.connect(resume);
5362
+ this.connect(shouldResume);
5314
5363
  });
5315
5364
  }
5316
5365
  updatePresence(data) {
@@ -9897,7 +9946,7 @@ function logDiscordStartupPhase(params) {
9897
9946
  });
9898
9947
  }
9899
9948
  async function loadDiscordVoiceRuntime() {
9900
- const promise = discordVoiceRuntimePromise ?? import("./manager.runtime-D-ZJn56X.js");
9949
+ const promise = discordVoiceRuntimePromise ?? import("./manager.runtime-DaB-CTrt.js");
9901
9950
  discordVoiceRuntimePromise = promise;
9902
9951
  try {
9903
9952
  return await promise;
@@ -9907,7 +9956,7 @@ async function loadDiscordVoiceRuntime() {
9907
9956
  }
9908
9957
  }
9909
9958
  async function loadDiscordProviderSessionRuntime() {
9910
- const promise = discordProviderSessionRuntimePromise ?? import("./provider-session.runtime-DYKny61v.js");
9959
+ const promise = discordProviderSessionRuntimePromise ?? import("./provider-session.runtime-BDjyFw6Y.js");
9911
9960
  discordProviderSessionRuntimePromise = promise;
9912
9961
  try {
9913
9962
  return await promise;
@@ -1,6 +1,6 @@
1
1
  import { a as reconcileAcpThreadBindingsOnStartup } from "./thread-bindings-DsTxqu3E.js";
2
2
  import { n as createThreadBindingManager, t as createNoopThreadBindingManager } from "./thread-bindings.manager-Bwmtqc3E.js";
3
- import { t as createDiscordMessageHandler } from "./message-handler-DbrX-sHg.js";
3
+ import { t as createDiscordMessageHandler } from "./message-handler-DcgvugZt.js";
4
4
  import { resolveThreadBindingIdleTimeoutMs, resolveThreadBindingMaxAgeMs, resolveThreadBindingsEnabled } from "openclaw/plugin-sdk/conversation-runtime";
5
5
  import { getAcpSessionManager, isAcpRuntimeError } from "openclaw/plugin-sdk/acp-runtime";
6
6
  export { createDiscordMessageHandler, createNoopThreadBindingManager, createThreadBindingManager, getAcpSessionManager, isAcpRuntimeError, reconcileAcpThreadBindingsOnStartup, resolveThreadBindingIdleTimeoutMs, resolveThreadBindingMaxAgeMs, resolveThreadBindingsEnabled };
@@ -0,0 +1,2 @@
1
+ import { t as monitorDiscordProvider } from "./provider-BkfbC9FQ.js";
2
+ export { monitorDiscordProvider };
@@ -21,10 +21,10 @@ import { a as resolveDiscordPrivilegedIntentsFromFlags, i as probeDiscord, n as
21
21
  import "./runtime-api.actions.js";
22
22
  import { r as collectDiscordAuditChannelIds, t as auditDiscordChannelPermissions } from "./audit-MLpDpN3Z.js";
23
23
  import "./runtime-api.lookup.js";
24
- import { E as sanitizeDiscordThreadName, c as createDiscordGatewayPlugin, f as createDiscordNativeCommand, l as resolveDiscordGatewayIntents, t as monitorDiscordProvider, u as waitForDiscordGatewayPluginRegistration, w as resolveDiscordReplyTarget, x as registerDiscordListener } from "./provider-Cm9QSAO8.js";
24
+ import { E as sanitizeDiscordThreadName, c as createDiscordGatewayPlugin, f as createDiscordNativeCommand, l as resolveDiscordGatewayIntents, t as monitorDiscordProvider, u as waitForDiscordGatewayPluginRegistration, w as resolveDiscordReplyTarget, x as registerDiscordListener } from "./provider-BkfbC9FQ.js";
25
25
  import { i as buildDiscordMediaPayload } from "./message-utils-B_3yA5bN.js";
26
- import { t as createDiscordMessageHandler } from "./message-handler-DbrX-sHg.js";
27
- import "./runtime-api.monitor-DoCAqUlv.js";
26
+ import { t as createDiscordMessageHandler } from "./message-handler-DcgvugZt.js";
27
+ import "./runtime-api.monitor-C2_WVtJf.js";
28
28
  import "./runtime-api.send.js";
29
29
  import "./runtime-api.threads.js";
30
30
  export { DISCORD_ATTACHMENT_IDLE_TIMEOUT_MS, DISCORD_ATTACHMENT_TOTAL_TIMEOUT_MS, DISCORD_DEFAULT_INBOUND_WORKER_TIMEOUT_MS, DISCORD_DEFAULT_LISTENER_TIMEOUT_MS, DiscordSendError, testing as __testing, 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, isAbortError, isDiscordGroupAllowedByPolicy, isDiscordModerationAction, isRecentlyUnboundThreadWebhookMessage, kickMemberDiscord, listDiscordDirectoryGroupsLive, listDiscordDirectoryPeersLive, listGuildChannelsDiscord, listGuildEmojisDiscord, listPinsDiscord, listScheduledEventsDiscord, listThreadBindingsBySessionKey, listThreadBindingsForAccount, listThreadsDiscord, mergeAbortSignals, monitorDiscordProvider, moveChannelDiscord, normalizeDiscordAllowList, normalizeDiscordInboundWorkerTimeoutMs, normalizeDiscordListenerTimeoutMs, 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, runDiscordTaskWithTimeout, sanitizeDiscordThreadName, searchMessagesDiscord, sendDiscordComponentMessage, sendMessageDiscord, sendPollDiscord, sendStickerDiscord, sendTypingDiscord, sendVoiceMessageDiscord, sendWebhookMessageDiscord, setChannelPermissionDiscord, setDiscordRuntime, setPresence, setThreadBindingIdleTimeoutBySessionKey, setThreadBindingMaxAgeBySessionKey, shouldEmitDiscordReactionNotification, timeoutMemberDiscord, unbindThreadBindingsBySessionKey, unpinMessageDiscord, unregisterGateway, uploadEmojiDiscord, uploadStickerDiscord, waitForDiscordGatewayPluginRegistration };
@@ -1,6 +1,6 @@
1
1
  import "./allow-list-C-MqM-B_.js";
2
2
  import "./timeouts-C5TBc_9x.js";
3
- import "./provider-Cm9QSAO8.js";
3
+ import "./provider-BkfbC9FQ.js";
4
4
  import "./message-utils-B_3yA5bN.js";
5
- import "./message-handler-DbrX-sHg.js";
5
+ import "./message-handler-DcgvugZt.js";
6
6
  export {};
@@ -2,8 +2,8 @@ import { i as setPresence, n as getPresence, r as presenceCacheSize, t as clearP
2
2
  import { G as registerGateway, K as unregisterGateway, U as clearGateways, W as getGateway } from "./send.shared-wAwMhHDN.js";
3
3
  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-C-MqM-B_.js";
4
4
  import { a as isAbortError, c as normalizeDiscordListenerTimeoutMs, i as DISCORD_DEFAULT_LISTENER_TIMEOUT_MS, n as DISCORD_ATTACHMENT_TOTAL_TIMEOUT_MS, o as mergeAbortSignals, r as DISCORD_DEFAULT_INBOUND_WORKER_TIMEOUT_MS, s as normalizeDiscordInboundWorkerTimeoutMs, t as DISCORD_ATTACHMENT_IDLE_TIMEOUT_MS, u as runDiscordTaskWithTimeout } from "./timeouts-C5TBc_9x.js";
5
- import { E as sanitizeDiscordThreadName, c as createDiscordGatewayPlugin, f as createDiscordNativeCommand, l as resolveDiscordGatewayIntents, t as monitorDiscordProvider, u as waitForDiscordGatewayPluginRegistration, w as resolveDiscordReplyTarget, x as registerDiscordListener } from "./provider-Cm9QSAO8.js";
5
+ import { E as sanitizeDiscordThreadName, c as createDiscordGatewayPlugin, f as createDiscordNativeCommand, l as resolveDiscordGatewayIntents, t as monitorDiscordProvider, u as waitForDiscordGatewayPluginRegistration, w as resolveDiscordReplyTarget, x as registerDiscordListener } from "./provider-BkfbC9FQ.js";
6
6
  import { i as buildDiscordMediaPayload } from "./message-utils-B_3yA5bN.js";
7
- import { t as createDiscordMessageHandler } from "./message-handler-DbrX-sHg.js";
8
- import "./runtime-api.monitor-DoCAqUlv.js";
7
+ import { t as createDiscordMessageHandler } from "./message-handler-DcgvugZt.js";
8
+ import "./runtime-api.monitor-C2_WVtJf.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, isAbortError, isDiscordGroupAllowedByPolicy, mergeAbortSignals, monitorDiscordProvider, normalizeDiscordAllowList, normalizeDiscordInboundWorkerTimeoutMs, normalizeDiscordListenerTimeoutMs, normalizeDiscordSlug, presenceCacheSize, registerDiscordListener, registerGateway, resolveDiscordChannelConfig, resolveDiscordChannelConfigWithFallback, resolveDiscordCommandAuthorized, resolveDiscordGatewayIntents, resolveDiscordGuildEntry, resolveDiscordReplyTarget, resolveDiscordShouldRequireMention, resolveGroupDmAllow, runDiscordTaskWithTimeout, sanitizeDiscordThreadName, setPresence, shouldEmitDiscordReactionNotification, unregisterGateway, waitForDiscordGatewayPluginRegistration };
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "@openclaw/discord",
3
- "version": "2026.7.1-beta.4",
3
+ "version": "2026.7.1-beta.6",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "@openclaw/discord",
9
- "version": "2026.7.1-beta.4",
9
+ "version": "2026.7.1-beta.6",
10
10
  "dependencies": {
11
11
  "@discordjs/voice": "0.19.2",
12
12
  "discord-api-types": "0.38.49",
@@ -16,7 +16,7 @@
16
16
  "ws": "8.21.0"
17
17
  },
18
18
  "peerDependencies": {
19
- "openclaw": ">=2026.7.1-beta.4"
19
+ "openclaw": ">=2026.7.1-beta.6"
20
20
  },
21
21
  "peerDependenciesMeta": {
22
22
  "openclaw": {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openclaw/discord",
3
- "version": "2026.7.1-beta.4",
3
+ "version": "2026.7.1-beta.6",
4
4
  "description": "OpenClaw Discord channel plugin for channels, DMs, commands, and app events.",
5
5
  "repository": {
6
6
  "type": "git",
@@ -16,7 +16,7 @@
16
16
  "ws": "8.21.0"
17
17
  },
18
18
  "peerDependencies": {
19
- "openclaw": ">=2026.7.1-beta.4"
19
+ "openclaw": ">=2026.7.1-beta.6"
20
20
  },
21
21
  "peerDependenciesMeta": {
22
22
  "openclaw": {
@@ -63,10 +63,10 @@
63
63
  "allowInvalidConfigRecovery": true
64
64
  },
65
65
  "compat": {
66
- "pluginApi": ">=2026.7.1-beta.4"
66
+ "pluginApi": ">=2026.7.1-beta.6"
67
67
  },
68
68
  "build": {
69
- "openclawVersion": "2026.7.1-beta.4"
69
+ "openclawVersion": "2026.7.1-beta.6"
70
70
  },
71
71
  "release": {
72
72
  "publishToClawHub": true,
@@ -1,2 +0,0 @@
1
- import { t as monitorDiscordProvider } from "./provider-Cm9QSAO8.js";
2
- export { monitorDiscordProvider };