@openclaw/discord 2026.7.2-beta.7 → 2026.8.1-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.
Files changed (95) hide show
  1. package/dist/{account-inspect-SXiCBCgP.js → account-inspect-CqzrH14k.js} +48 -42
  2. package/dist/account-inspect-api.js +1 -1
  3. package/dist/action-runtime-api.js +1 -1
  4. package/dist/{active-turn-thread-route-MlKWp8RD.js → active-turn-thread-route-fmHl1HNd.js} +9 -11
  5. package/dist/{activities-api-DTKsuDxf.js → activities-api-DS7vpdtp.js} +4 -4
  6. package/dist/activities-api.js +1 -1
  7. package/dist/{allow-list-DzKrtfah.js → allow-list-DnxIlPP2.js} +2 -3
  8. package/dist/{api-DnrK9gML.js → api-DNVbJyEy.js} +7 -2
  9. package/dist/api.js +15 -15
  10. package/dist/{approval-handler.runtime-HymvFTYn.js → approval-handler.runtime-B6yEV79q.js} +5 -5
  11. package/dist/{approval-message-safety-DEyKVsAw.js → approval-message-safety-AcIxvrf3.js} +1 -1
  12. package/dist/{audit-CjsrabP8.js → audit-Db-rlntl.js} +4 -4
  13. package/dist/{channel-vKa-76xY.js → channel-CnnbJSt5.js} +46 -72
  14. package/dist/{channel-actions-uXFTJX3o.js → channel-actions-5s_hjYKd.js} +4 -4
  15. package/dist/{channel-actions.runtime-CIYU90sl.js → channel-actions.runtime-CLKrx6tr.js} +53 -36
  16. package/dist/channel-config-api.js +1 -1
  17. package/dist/channel-plugin-api.js +1 -1
  18. package/dist/{channel.setup-CmcwZ_qd.js → channel.setup-BFAO-V1P.js} +15 -53
  19. package/dist/{config-schema-WHRQcY19.js → config-schema-BgEskFAs.js} +9 -4
  20. package/dist/{directory-config-D_LojtCe.js → directory-config-BVX7Cflc.js} +1 -1
  21. package/dist/directory-contract-api.js +1 -1
  22. package/dist/{directory-live-Bw5Ephzv.js → directory-live-DGIGxpIo.js} +6 -3
  23. package/dist/{doctor-Bc4S1qyd.js → doctor-BzC-TLnB.js} +4 -4
  24. package/dist/{doctor-contract-CCFMIDk9.js → doctor-contract-DLa-BTiU.js} +2 -3
  25. package/dist/doctor-contract-api.js +147 -2
  26. package/dist/{handle-action.guild-admin-D6VRRW-C.js → handle-action.guild-admin-BNVTUISF.js} +4 -7
  27. package/dist/{inbound-event-delivery-CEPlt2uz.js → inbound-event-delivery-De2qxTrP.js} +4 -25
  28. package/dist/index.js +4 -2
  29. package/dist/{message-handler-CeiSulIw.js → message-handler-Unk_f10F.js} +41 -32
  30. package/dist/{message-handler.preflight-DibgQFf2.js → message-handler.preflight-C9zecxR9.js} +50 -26
  31. package/dist/{message-handler.process-Dnc_oz9y.js → message-handler.process-DWQ6UHHu.js} +130 -166
  32. package/dist/{message-utils-BgTwT_q7.js → message-utils-BSCPVgy0.js} +4 -4
  33. package/dist/{model-picker-preference-primitives-D25pnCOu.js → model-picker-preference-primitives-BHT1LkR_.js} +3 -3
  34. package/dist/{outbound-adapter-DtE-i2OJ.js → outbound-adapter-D9nRivT1.js} +91 -32
  35. package/dist/{outbound-components-C7GVyfPh.js → outbound-components-cTzwBJ60.js} +3 -3
  36. package/dist/{outbound-session-route-H-HoyH5U.js → outbound-session-route-DxLkrgKQ.js} +68 -95
  37. package/dist/{pluralkit-CD4B11JB.js → pluralkit-DdiJ9KMK.js} +1 -1
  38. package/dist/{preflight-audio-BjnQZ5yS.js → preflight-audio-DrnqFA8U.js} +22 -28
  39. package/dist/{probe-BeWKhjqX.js → probe-Bl-k5_Ku.js} +36 -12
  40. package/dist/probe.runtime-M9fREKvp.js +2 -0
  41. package/dist/{provider-DfQJX3z5.js → provider-DvSNb-2v.js} +969 -1248
  42. package/dist/{provider-session.runtime-Bo88k0pV.js → provider-session.runtime-BUEqD0rA.js} +3 -3
  43. package/dist/provider.runtime-C9PnJZbZ.js +2 -0
  44. package/dist/realtime-session.runtime-C7wen-aF.js +1340 -0
  45. package/dist/{resolve-allowlist-common-DHERApxi.js → resolve-allowlist-common-D04lpEzb.js} +2 -2
  46. package/dist/{resolve-channels-BjepAj8b.js → resolve-channels-Dm7jEeg6.js} +4 -4
  47. package/dist/{resolve-users-Bc28htgt.js → resolve-users-bktrCUUU.js} +3 -3
  48. package/dist/{chunk-DX4jpFQP.js → retry-CLpJcXXf.js} +291 -68
  49. package/dist/{runtime-_aRC6V2s.js → runtime-DGsSyDTS.js} +30 -25
  50. package/dist/{runtime-BmW_j_hl.js → runtime-DoHjckYm.js} +4 -6
  51. package/dist/runtime-api.actions.js +2 -2
  52. package/dist/runtime-api.js +22 -23
  53. package/dist/runtime-api.lookup.js +5 -5
  54. package/dist/runtime-api.monitor-CHxrFPnW.js +5 -0
  55. package/dist/runtime-api.monitor.js +5 -5
  56. package/dist/runtime-api.send.js +6 -6
  57. package/dist/runtime-api.threads.js +5 -6
  58. package/dist/sdk-runtime-QpY8PvCh.js +370 -0
  59. package/dist/{send-CdkZ6zeW.js → send-B7Q6Oc1I.js} +175 -86
  60. package/dist/{send.components-5uqwkjgE.js → send.components-iJyFXw9L.js} +24 -28
  61. package/dist/{send.outbound-D-80Ej-t.js → send.outbound-DS5tHwfR.js} +37 -24
  62. package/dist/{send.reactions-CtlmGd_o.js → send.reactions-BAn0iiVQ.js} +14 -21
  63. package/dist/{send.receipt-CuwRrpFz.js → send.receipt-IPI1p-SP.js} +19 -1
  64. package/dist/{send.shared-jpvAG_u6.js → send.shared-BmwFjW6T.js} +16 -85
  65. package/dist/{sender-identity-mG_zsdox.js → sender-identity-QtalnCYv.js} +1 -1
  66. package/dist/setup-entry.js +0 -5
  67. package/dist/setup-plugin-api.js +1 -1
  68. package/dist/{shared-CXF1tup1.js → shared-BIXIX6uJ.js} +16 -17
  69. package/dist/{subagent-hooks-Dxy7Fmnq.js → subagent-hooks-CTt5KCJr.js} +2 -2
  70. package/dist/subagent-hooks-api.js +2 -6
  71. package/dist/subagent-progress-DhaE_h8a.js +109 -0
  72. package/dist/{system-events-DdUqf91B.js → system-events-CTqDf6_s.js} +2 -2
  73. package/dist/{target-resolver-C3s_2m0t.js → target-resolver-maOKSqO0.js} +2 -2
  74. package/dist/targets-yUFTHoAx.js +3 -0
  75. package/dist/{thread-bindings-C-M-ly7P.js → thread-bindings-3L8p82GV.js} +5 -7
  76. package/dist/{thread-bindings.manager-DYvSlrva.js → thread-bindings.manager-DCIH6WDC.js} +257 -29
  77. package/dist/{thread-bindings.session-updates-DAIlp7Px.js → thread-bindings.session-updates-bJ2KQFY6.js} +1 -1
  78. package/dist/{thread-bindings.state-Cgi5uRn-.js → thread-bindings.state-aeV8HNgV.js} +2 -15
  79. package/dist/{transcripts-source-DIKGsTGT.js → transcripts-source-CfFMexGt.js} +1 -1
  80. package/dist/transcripts-source-api.js +1 -1
  81. package/dist/{typing--Mzo2kM7.js → typing-CS-nNVoe.js} +1 -1
  82. package/dist/voice-runtime-BEdqNcST.js +2459 -0
  83. package/openclaw.plugin.json +203 -19
  84. package/package.json +15 -9
  85. package/skills/discord/SKILL.md +22 -115
  86. package/dist/legacy-state-migrations-api.js +0 -138
  87. package/dist/manager.runtime-Bjav3pfC.js +0 -3655
  88. package/dist/preflight-audio.runtime-CoCXMM8r.js +0 -7
  89. package/dist/probe.runtime-DqFGFMbZ.js +0 -2
  90. package/dist/provider.runtime-Cy7XZmyh.js +0 -2
  91. package/dist/runtime-api.monitor-CCRubd3-.js +0 -5
  92. package/dist/session-binding-contract-api.js +0 -2
  93. package/dist/subagent-progress-DI3sYLLo.js +0 -664
  94. package/dist/targets-Dv_RN7vT.js +0 -3
  95. package/dist/thread-bindings.discord-api-BoDNqamb.js +0 -246
@@ -1,15 +1,15 @@
1
- import { c as normalizeDiscordOutboundTarget, i as resolveDiscordReplyReference, t as chunkDiscordTextWithMode } from "./chunk-DX4jpFQP.js";
2
- import { t as createDiscordSendReceipt } from "./send.receipt-CuwRrpFz.js";
3
- import { n as formatDiscordApprovalDisplayValue } from "./approval-message-safety-DEyKVsAw.js";
4
- import { n as notifyDiscordInboundEventOutboundPayloadSuccess } from "./inbound-event-delivery-CEPlt2uz.js";
5
- import { a as sendDiscordComponentMessageLazy, i as resolveDiscordComponentSpec, n as buildDiscordPresentationPayload, t as DISCORD_PRESENTATION_CAPABILITIES } from "./outbound-components-C7GVyfPh.js";
1
+ import { a as chunkDiscordTextWithMode, c as resolveDiscordReplyReference, f as normalizeDiscordOutboundTarget, r as hasDiscordMessageCreateAmbiguity } from "./retry-CLpJcXXf.js";
2
+ import { n as createDiscordSendReceiptFromResults, t as createDiscordSendReceipt } from "./send.receipt-IPI1p-SP.js";
3
+ import { n as formatDiscordApprovalDisplayValue } from "./approval-message-safety-AcIxvrf3.js";
4
+ import { n as notifyDiscordInboundEventOutboundPayloadSuccess } from "./inbound-event-delivery-De2qxTrP.js";
5
+ import { a as sendDiscordComponentMessageLazy, i as resolveDiscordComponentSpec, n as buildDiscordPresentationPayload, t as DISCORD_PRESENTATION_CAPABILITIES } from "./outbound-components-cTzwBJ60.js";
6
6
  import { normalizeLowercaseStringOrEmpty, normalizeOptionalString, normalizeOptionalStringifiedId } from "openclaw/plugin-sdk/string-coerce-runtime";
7
7
  import { expectDefined } from "openclaw/plugin-sdk/expect-runtime";
8
8
  import { truncateUtf16Safe } from "openclaw/plugin-sdk/text-utility-runtime";
9
9
  import { createReplyToFanout, resolveOutboundSendDep } from "openclaw/plugin-sdk/channel-outbound";
10
+ import { attachChannelToResult, createAttachedChannelResultAdapter } from "openclaw/plugin-sdk/channel-send-result";
10
11
  import { getReplyPayloadTtsSupplement, resolvePayloadMediaUrls, sendPayloadMediaSequenceOrFallback, sendTextMediaPayload } from "openclaw/plugin-sdk/reply-payload";
11
12
  import { createLazyRuntimeModule } from "openclaw/plugin-sdk/lazy-runtime";
12
- import { attachChannelToResult, createAttachedChannelResultAdapter } from "openclaw/plugin-sdk/channel-send-result";
13
13
  import { questionGatewayRuntime } from "openclaw/plugin-sdk/question-gateway-runtime";
14
14
  //#region extensions/discord/src/media-detection.ts
15
15
  const DISCORD_VIDEO_MEDIA_EXTENSIONS = /* @__PURE__ */ new Set([
@@ -59,7 +59,7 @@ function normalizeDiscordApprovalPayload(payload) {
59
59
  }
60
60
  //#endregion
61
61
  //#region extensions/discord/src/outbound-send-context.ts
62
- const loadDiscordSendRuntime = createLazyRuntimeModule(() => import("./send-CdkZ6zeW.js").then((n) => n.t));
62
+ const loadDiscordSendRuntime = createLazyRuntimeModule(() => import("./send-B7Q6Oc1I.js").then((n) => n.t));
63
63
  function resolveDiscordOutboundTarget(params) {
64
64
  if (params.threadId == null) return params.to;
65
65
  const threadId = normalizeOptionalStringifiedId(params.threadId) ?? "";
@@ -116,7 +116,8 @@ function resolveDiscordDeliveryOptions(ctx, sendContext, reply = sendContext.res
116
116
  reply,
117
117
  accountId: ctx.accountId ?? void 0,
118
118
  silent: ctx.silent ?? void 0,
119
- cfg: ctx.cfg
119
+ cfg: ctx.cfg,
120
+ onPlatformSendDispatch: ctx.onPlatformSendDispatch
120
121
  };
121
122
  }
122
123
  function resolveDiscordFormattedDeliveryOptions(ctx, sendContext, reply = sendContext.resolveReply()) {
@@ -148,9 +149,15 @@ async function sendDiscordOutboundPayload(params) {
148
149
  let lastResult;
149
150
  try {
150
151
  const voiceUrl = expectDefined(mediaUrls.at(0), "non-empty Discord voice media URLs");
151
- lastResult = await sendContext.sendVoice(sendContext.target, voiceUrl, { ...resolveDiscordDeliveryOptions(ctx, sendContext, voiceReply) });
152
+ lastResult = await sendContext.sendVoice(sendContext.target, voiceUrl, {
153
+ ...resolveDiscordDeliveryOptions(ctx, sendContext, voiceReply),
154
+ mediaAccess: ctx.mediaAccess,
155
+ mediaLocalRoots: ctx.mediaLocalRoots,
156
+ mediaReadFile: ctx.mediaReadFile
157
+ });
152
158
  deliveredVoice = true;
153
159
  } catch (err) {
160
+ if (hasDiscordMessageCreateAmbiguity(err)) throw err;
154
161
  const supplement = getReplyPayloadTtsSupplement(payload);
155
162
  const visibleFallbackText = payload.text?.trim() ? payload.text : void 0;
156
163
  const hiddenFallbackText = supplement?.visibleTextAlreadyDelivered ? void 0 : supplement?.spokenText;
@@ -203,14 +210,37 @@ async function sendDiscordOutboundPayload(params) {
203
210
  onDeliveryResult: resolveDiscordDeliveryProgress(ctx)
204
211
  })
205
212
  }));
206
- return await sendTextMediaPayload({
213
+ const payloadContext = {
214
+ ...ctx,
215
+ payload
216
+ };
217
+ const deliveredResults = [];
218
+ let createdThreadId;
219
+ payloadContext.onDeliveryResult = async (result) => {
220
+ await ctx.onDeliveryResult?.(result);
221
+ const threadId = result.receipt?.threadId;
222
+ if (threadId && payloadContext.threadId == null) {
223
+ payloadContext.threadId = threadId;
224
+ createdThreadId = threadId;
225
+ }
226
+ if (createdThreadId && result.channelId && result.receipt) deliveredResults.push({
227
+ messageId: result.messageId,
228
+ channelId: result.channelId,
229
+ receipt: result.receipt
230
+ });
231
+ };
232
+ const result = await sendTextMediaPayload({
207
233
  channel: "discord",
208
- ctx: {
209
- ...ctx,
210
- payload
211
- },
234
+ ctx: payloadContext,
212
235
  adapter: params.fallbackAdapter
213
236
  });
237
+ return createdThreadId ? {
238
+ ...result,
239
+ receipt: createDiscordSendReceiptFromResults({
240
+ results: deliveredResults,
241
+ threadId: createdThreadId
242
+ })
243
+ } : result;
214
244
  }
215
245
  return attachChannelToResult("discord", await sendPayloadMediaSequenceOrFallback({
216
246
  text: payload.text ?? "",
@@ -238,8 +268,8 @@ async function sendDiscordOutboundPayload(params) {
238
268
  //#endregion
239
269
  //#region extensions/discord/src/outbound-adapter.ts
240
270
  const DISCORD_TEXT_CHUNK_LIMIT = 2e3;
241
- const loadDiscordThreadBindings = createLazyRuntimeModule(() => import("./thread-bindings-C-M-ly7P.js").then((n) => n.t));
242
- const loadDiscordComponentSendRuntime = createLazyRuntimeModule(() => import("./send.components-5uqwkjgE.js").then((n) => n.i));
271
+ const loadDiscordThreadBindings = createLazyRuntimeModule(() => import("./thread-bindings-3L8p82GV.js").then((n) => n.t));
272
+ const loadDiscordComponentSendRuntime = createLazyRuntimeModule(() => import("./send.components-iJyFXw9L.js").then((n) => n.i));
243
273
  function resolveDiscordWebhookIdentity(params) {
244
274
  const usernameRaw = normalizeOptionalString(params.identity?.name);
245
275
  const fallbackUsername = normalizeOptionalString(params.binding.label) ?? params.binding.agentId;
@@ -270,7 +300,8 @@ async function maybeSendDiscordWebhookText(params) {
270
300
  cfg: params.cfg,
271
301
  replyTo: params.replyToId ?? void 0,
272
302
  username: persona.username,
273
- avatarUrl: persona.avatarUrl
303
+ avatarUrl: persona.avatarUrl,
304
+ onPlatformSendDispatch: params.onPlatformSendDispatch
274
305
  });
275
306
  }
276
307
  async function resolveDiscordOutboundMessageSend(params) {
@@ -295,7 +326,8 @@ async function resolveDiscordOutboundMessageSend(params) {
295
326
  ...resolveDiscordFormattingOptions({ formatting: params.formatting }),
296
327
  onDeliveryResult: params.onDeliveryResult ? async (result) => {
297
328
  await params.onDeliveryResult?.(attachChannelToResult("discord", result));
298
- } : void 0
329
+ } : void 0,
330
+ onPlatformSendDispatch: params.onPlatformSendDispatch
299
331
  }
300
332
  };
301
333
  }
@@ -334,15 +366,24 @@ const discordOutbound = {
334
366
  channel: "discord",
335
367
  sendText: async (ctx) => {
336
368
  if (!ctx.silent) {
337
- const webhookResult = await maybeSendDiscordWebhookText({
338
- cfg: ctx.cfg,
339
- text: ctx.text,
340
- threadId: ctx.threadId,
341
- accountId: ctx.accountId,
342
- identity: ctx.identity,
343
- replyToId: ctx.replyToId
344
- }).catch(() => null);
345
- if (webhookResult) return webhookResult;
369
+ let webhookSelected = false;
370
+ try {
371
+ const webhookResult = await maybeSendDiscordWebhookText({
372
+ cfg: ctx.cfg,
373
+ text: ctx.text,
374
+ threadId: ctx.threadId,
375
+ accountId: ctx.accountId,
376
+ identity: ctx.identity,
377
+ replyToId: ctx.replyToId,
378
+ onPlatformSendDispatch: ctx.onPlatformSendDispatch ? async () => {
379
+ webhookSelected = true;
380
+ await ctx.onPlatformSendDispatch?.();
381
+ } : void 0
382
+ });
383
+ if (webhookResult) return webhookResult;
384
+ } catch (error) {
385
+ if (webhookSelected) throw error;
386
+ }
346
387
  }
347
388
  const { send, target, options } = await resolveDiscordOutboundMessageSend(ctx);
348
389
  return await send(target, ctx.text, options);
@@ -353,7 +394,11 @@ const discordOutbound = {
353
394
  cfg: ctx.cfg,
354
395
  reply: options.reply,
355
396
  accountId: ctx.accountId ?? void 0,
356
- silent: ctx.silent ?? void 0
397
+ silent: ctx.silent ?? void 0,
398
+ mediaAccess: ctx.mediaAccess,
399
+ mediaLocalRoots: ctx.mediaLocalRoots,
400
+ mediaReadFile: ctx.mediaReadFile,
401
+ onPlatformSendDispatch: ctx.onPlatformSendDispatch
357
402
  });
358
403
  const mediaOptions = {
359
404
  ...options,
@@ -363,23 +408,37 @@ const discordOutbound = {
363
408
  mediaReadFile: ctx.mediaReadFile
364
409
  };
365
410
  if (ctx.text.trim() && ctx.mediaUrl && isLikelyDiscordVideoMedia(ctx.mediaUrl)) {
366
- await send(target, ctx.text, options);
367
- return await send(target, "", {
411
+ const captionResult = await send(target, ctx.text, options);
412
+ const mediaResult = await send(captionResult.receipt?.threadId ? `channel:${captionResult.receipt.threadId}` : target, "", {
368
413
  ...mediaOptions,
369
414
  reply: options.reply?.scope === "all" ? options.reply : void 0
370
415
  });
416
+ const threadId = captionResult.receipt?.threadId;
417
+ if (!threadId) return mediaResult;
418
+ return {
419
+ ...captionResult,
420
+ receipt: createDiscordSendReceiptFromResults({
421
+ results: [captionResult, mediaResult],
422
+ threadId
423
+ })
424
+ };
371
425
  }
372
426
  return await send(target, ctx.text, mediaOptions);
373
427
  },
374
- sendPoll: async ({ cfg, to, poll, accountId, threadId, silent }) => await (await loadDiscordSendRuntime()).sendPollDiscord(resolveDiscordOutboundTarget({
428
+ sendPoll: async ({ cfg, to, poll, accountId, threadId, silent, onPlatformSendDispatch }) => await (await loadDiscordSendRuntime()).sendPollDiscord(resolveDiscordOutboundTarget({
375
429
  to,
376
430
  threadId
377
431
  }), poll, {
378
432
  accountId: accountId ?? void 0,
379
433
  silent: silent ?? void 0,
380
- cfg
434
+ cfg,
435
+ onPlatformSendDispatch
381
436
  })
382
437
  }),
438
+ adoptTargetFromDelivery: ({ result }) => {
439
+ const threadId = normalizeOptionalStringifiedId(result.receipt?.threadId);
440
+ return threadId ? { threadId } : null;
441
+ },
383
442
  afterDeliverPayload: async ({ cfg, target, payload, results }) => {
384
443
  notifyDiscordInboundEventOutboundPayloadSuccess({
385
444
  payload,
@@ -1,4 +1,4 @@
1
- import { h as readDiscordComponentSpec } from "./outbound-session-route-H-HoyH5U.js";
1
+ import { h as readDiscordComponentSpec } from "./outbound-session-route-DxLkrgKQ.js";
2
2
  import { createLazyRuntimeModule, createLazyRuntimeNamedExport } from "openclaw/plugin-sdk/lazy-runtime";
3
3
  //#region extensions/discord/src/outbound-components.ts
4
4
  const DISCORD_MESSAGE_COMPONENT_LIMIT = 40;
@@ -30,11 +30,11 @@ const DISCORD_PRESENTATION_CAPABILITIES = {
30
30
  }
31
31
  }
32
32
  };
33
- const loadDiscordComponentSend = createLazyRuntimeNamedExport(() => import("./send.components-5uqwkjgE.js").then((n) => n.i), "sendDiscordComponentMessage");
33
+ const loadDiscordComponentSend = createLazyRuntimeNamedExport(() => import("./send.components-iJyFXw9L.js").then((n) => n.i), "sendDiscordComponentMessage");
34
34
  async function sendDiscordComponentMessageLazy(...args) {
35
35
  return await (await loadDiscordComponentSend())(...args);
36
36
  }
37
- const loadDiscordSharedInteractive = createLazyRuntimeModule(() => import("./outbound-session-route-H-HoyH5U.js").then((n) => n.o));
37
+ const loadDiscordSharedInteractive = createLazyRuntimeModule(() => import("./outbound-session-route-DxLkrgKQ.js").then((n) => n.o));
38
38
  function addPayloadTextFallback(spec, payload) {
39
39
  return spec.text ? spec : {
40
40
  ...spec,
@@ -1,9 +1,9 @@
1
- import { $ as Section, B as Label, G as ChannelSelectMenu, H as RadioGroup, J as LinkButton, K as Container, Q as Row, U as TextInput, V as Modal, W as Button, X as MentionableSelectMenu, Y as MediaGallery, Yt as __exportAll, Z as RoleSelectMenu, et as Separator, it as UserSelectMenu, l as parseDiscordTarget, nt as TextDisplay, ot as parseCustomId, q as File, rt as Thumbnail, tt as StringSelectMenu, z as CheckboxGroup } from "./chunk-DX4jpFQP.js";
1
+ import { $ as LinkButton, G as Label, J as TextInput, K as Modal, Q as File, W as CheckboxGroup, X as ChannelSelectMenu, Y as Button, Z as Container, at as Separator, ct as Thumbnail, dt as parseCustomId, et as MediaGallery, it as Section, lt as UserSelectMenu, nt as RoleSelectMenu, ot as StringSelectMenu, p as parseDiscordTarget, q as RadioGroup, rt as Row, st as TextDisplay, tn as __exportAll, tt as MentionableSelectMenu } from "./retry-CLpJcXXf.js";
2
2
  import { buildOutboundBaseSessionKey } from "openclaw/plugin-sdk/routing";
3
- import { normalizeLowercaseStringOrEmpty } from "openclaw/plugin-sdk/string-coerce-runtime";
3
+ import { normalizeLowercaseStringOrEmpty, normalizeOptionalString } from "openclaw/plugin-sdk/string-coerce-runtime";
4
4
  import { ButtonStyle, MessageFlags, TextInputStyle } from "discord-api-types/v10";
5
5
  import crypto from "node:crypto";
6
- import { reduceLegacyInteractiveReply, resolveMessagePresentationButtonAction, resolveMessagePresentationOptionAction } from "openclaw/plugin-sdk/interactive-runtime";
6
+ import { reduceLegacyInteractiveReply, resolveMessagePresentationActionValue, resolveMessagePresentationButtonAction, resolveMessagePresentationOptionAction } from "openclaw/plugin-sdk/interactive-runtime";
7
7
  import { buildApprovalResolutionRef } from "openclaw/plugin-sdk/approval-reference-runtime";
8
8
  import { buildThreadAwareOutboundSessionRoute } from "openclaw/plugin-sdk/channel-core";
9
9
  //#region extensions/discord/src/custom-id-codec.ts
@@ -136,19 +136,14 @@ function requireObject(value, label) {
136
136
  if (!value || typeof value !== "object" || Array.isArray(value)) throw new Error(`${label} must be an object`);
137
137
  return value;
138
138
  }
139
- function readString(value, label, opts) {
139
+ function readRequiredString(value, label, opts) {
140
140
  if (typeof value !== "string") throw new Error(`${label} must be a string`);
141
141
  const trimmed = value.trim();
142
142
  if (!opts?.allowEmpty && !trimmed) throw new Error(`${label} cannot be empty`);
143
143
  return opts?.allowEmpty ? value : trimmed;
144
144
  }
145
- function readOptionalString(value) {
146
- if (typeof value !== "string") return;
147
- const trimmed = value.trim();
148
- return trimmed ? trimmed : void 0;
149
- }
150
145
  function readOptionalCallbackDataKind(value, label) {
151
- const kind = readOptionalString(value);
146
+ const kind = normalizeOptionalString(value);
152
147
  if (kind === void 0) return;
153
148
  if (kind === "command" || kind === "callback") return kind;
154
149
  throw new Error(`${label} must be one of command, callback`);
@@ -157,7 +152,7 @@ function readOptionalStringArray(value, label) {
157
152
  if (value === void 0) return;
158
153
  if (!Array.isArray(value)) throw new Error(`${label} must be an array`);
159
154
  if (value.length === 0) return;
160
- return value.map((entry, index) => readString(entry, `${label}[${index}]`));
155
+ return value.map((entry, index) => readRequiredString(entry, `${label}[${index}]`));
161
156
  }
162
157
  function readOptionalInteger(value, label, bounds) {
163
158
  if (value == null) return;
@@ -170,8 +165,8 @@ function readOptionalEmoji(value, label) {
170
165
  if (!value || typeof value !== "object" || Array.isArray(value)) return;
171
166
  const obj = value;
172
167
  return {
173
- name: readString(obj.name, `${label}.name`),
174
- id: readOptionalString(obj.id),
168
+ name: readRequiredString(obj.name, `${label}.name`),
169
+ id: normalizeOptionalString(obj.id),
175
170
  animated: typeof obj.animated === "boolean" ? obj.animated : void 0
176
171
  };
177
172
  }
@@ -216,9 +211,9 @@ function parseSelectOptions(raw, label) {
216
211
  return raw.map((entry, index) => {
217
212
  const obj = requireObject(entry, `${label}[${index}]`);
218
213
  return {
219
- label: readString(obj.label, `${label}[${index}].label`),
220
- value: readString(obj.value, `${label}[${index}].value`),
221
- description: readOptionalString(obj.description),
214
+ label: readRequiredString(obj.label, `${label}[${index}].label`),
215
+ value: readRequiredString(obj.value, `${label}[${index}].value`),
216
+ description: normalizeOptionalString(obj.description),
222
217
  emoji: readOptionalEmoji(obj.emoji, `${label}[${index}].emoji`),
223
218
  default: typeof obj.default === "boolean" ? obj.default : void 0
224
219
  };
@@ -226,14 +221,14 @@ function parseSelectOptions(raw, label) {
226
221
  }
227
222
  function parseButtonSpec(raw, label) {
228
223
  const obj = requireObject(raw, label);
229
- const style = readOptionalString(obj.style);
230
- const url = readOptionalString(obj.url);
224
+ const style = normalizeOptionalString(obj.style);
225
+ const url = normalizeOptionalString(obj.url);
231
226
  if ((style === "link" || url) && !url) throw new Error(`${label}.url is required for link buttons`);
232
227
  return {
233
- label: readString(obj.label, `${label}.label`),
228
+ label: readRequiredString(obj.label, `${label}.label`),
234
229
  style,
235
230
  url,
236
- callbackData: readOptionalString(obj.callbackData),
231
+ callbackData: normalizeOptionalString(obj.callbackData),
237
232
  callbackDataKind: readOptionalCallbackDataKind(obj.callbackDataKind, `${label}.callbackDataKind`),
238
233
  emoji: readOptionalEmoji(obj.emoji, `${label}.emoji`),
239
234
  disabled: typeof obj.disabled === "boolean" ? obj.disabled : void 0,
@@ -242,7 +237,7 @@ function parseButtonSpec(raw, label) {
242
237
  }
243
238
  function parseSelectSpec(raw, label) {
244
239
  const obj = requireObject(raw, label);
245
- const type = readOptionalString(obj.type);
240
+ const type = normalizeOptionalString(obj.type);
246
241
  const allowedTypes = [
247
242
  "string",
248
243
  "user",
@@ -253,9 +248,9 @@ function parseSelectSpec(raw, label) {
253
248
  if (type && !allowedTypes.includes(type)) throw new Error(`${label}.type must be one of ${allowedTypes.join(", ")}`);
254
249
  return {
255
250
  type,
256
- callbackData: readOptionalString(obj.callbackData),
251
+ callbackData: normalizeOptionalString(obj.callbackData),
257
252
  callbackDataKind: readOptionalCallbackDataKind(obj.callbackDataKind, `${label}.callbackDataKind`),
258
- placeholder: readOptionalString(obj.placeholder),
253
+ placeholder: normalizeOptionalString(obj.placeholder),
259
254
  minValues: readOptionalInteger(obj.minValues, `${label}.minValues`, {
260
255
  min: 0,
261
256
  max: 25
@@ -270,7 +265,7 @@ function parseSelectSpec(raw, label) {
270
265
  }
271
266
  function parseModalField(raw, label, index) {
272
267
  const obj = requireObject(raw, label);
273
- const type = normalizeLowercaseStringOrEmpty(readString(obj.type, `${label}.type`));
268
+ const type = normalizeLowercaseStringOrEmpty(readRequiredString(obj.type, `${label}.type`));
274
269
  const supported = [
275
270
  "text",
276
271
  "checkbox",
@@ -291,10 +286,10 @@ function parseModalField(raw, label, index) {
291
286
  const maxValues = type === "checkbox" ? 10 : 25;
292
287
  return {
293
288
  type,
294
- name: normalizeModalFieldName(readOptionalString(obj.name), index),
295
- label: readString(obj.label, `${label}.label`),
296
- description: readOptionalString(obj.description),
297
- placeholder: readOptionalString(obj.placeholder),
289
+ name: normalizeModalFieldName(normalizeOptionalString(obj.name), index),
290
+ label: readRequiredString(obj.label, `${label}.label`),
291
+ description: normalizeOptionalString(obj.description),
292
+ placeholder: normalizeOptionalString(obj.placeholder),
298
293
  required,
299
294
  options,
300
295
  minValues: readOptionalInteger(obj.minValues, `${label}.minValues`, {
@@ -313,28 +308,28 @@ function parseModalField(raw, label, index) {
313
308
  min: 1,
314
309
  max: 4e3
315
310
  }),
316
- style: readOptionalString(obj.style)
311
+ style: normalizeOptionalString(obj.style)
317
312
  };
318
313
  }
319
314
  function parseComponentBlock(raw, label) {
320
315
  const obj = requireObject(raw, label);
321
- switch (normalizeBlockType(normalizeLowercaseStringOrEmpty(readString(obj.type, `${label}.type`)))) {
316
+ switch (normalizeBlockType(normalizeLowercaseStringOrEmpty(readRequiredString(obj.type, `${label}.type`)))) {
322
317
  case "text": return {
323
318
  type: "text",
324
- text: readString(obj.text, `${label}.text`)
319
+ text: readRequiredString(obj.text, `${label}.text`)
325
320
  };
326
321
  case "section": {
327
- const text = readOptionalString(obj.text);
322
+ const text = normalizeOptionalString(obj.text);
328
323
  const textsRaw = obj.texts;
329
- const texts = Array.isArray(textsRaw) ? textsRaw.map((entry, idx) => readString(entry, `${label}.texts[${idx}]`)) : void 0;
324
+ const texts = Array.isArray(textsRaw) ? textsRaw.map((entry, idx) => readRequiredString(entry, `${label}.texts[${idx}]`)) : void 0;
330
325
  if (!text && (!texts || texts.length === 0)) throw new Error(`${label}.text or ${label}.texts is required for section blocks`);
331
326
  let accessory;
332
327
  if (obj.accessory !== void 0) {
333
328
  const accessoryObj = requireObject(obj.accessory, `${label}.accessory`);
334
- const accessoryType = normalizeLowercaseStringOrEmpty(readString(accessoryObj.type, `${label}.accessory.type`));
329
+ const accessoryType = normalizeLowercaseStringOrEmpty(readRequiredString(accessoryObj.type, `${label}.accessory.type`));
335
330
  if (accessoryType === "thumbnail") accessory = {
336
331
  type: "thumbnail",
337
- url: readString(accessoryObj.url, `${label}.accessory.url`)
332
+ url: readRequiredString(accessoryObj.url, `${label}.accessory.url`)
338
333
  };
339
334
  else if (accessoryType === "button") accessory = {
340
335
  type: "button",
@@ -382,8 +377,8 @@ function parseComponentBlock(raw, label) {
382
377
  items: itemsRaw.map((entry, idx) => {
383
378
  const itemObj = requireObject(entry, `${label}.items[${idx}]`);
384
379
  return {
385
- url: readString(itemObj.url, `${label}.items[${idx}].url`),
386
- description: readOptionalString(itemObj.description),
380
+ url: readRequiredString(itemObj.url, `${label}.items[${idx}].url`),
381
+ description: normalizeOptionalString(itemObj.description),
387
382
  spoiler: typeof itemObj.spoiler === "boolean" ? itemObj.spoiler : void 0
388
383
  };
389
384
  })
@@ -391,7 +386,7 @@ function parseComponentBlock(raw, label) {
391
386
  }
392
387
  case "file": return {
393
388
  type: "file",
394
- file: normalizeAttachmentRef(readString(obj.file, `${label}.file`), `${label}.file`),
389
+ file: normalizeAttachmentRef(readRequiredString(obj.file, `${label}.file`), `${label}.file`),
395
390
  spoiler: typeof obj.spoiler === "boolean" ? obj.spoiler : void 0
396
391
  };
397
392
  default: throw new Error(`${label}.type must be a supported component block`);
@@ -412,16 +407,16 @@ function readDiscordComponentSpec(raw) {
412
407
  if (fieldsRaw.length > 5) throw new Error("components.modal.fields supports up to 5 inputs");
413
408
  const fields = fieldsRaw.map((entry, idx) => parseModalField(entry, `components.modal.fields[${idx}]`, idx));
414
409
  modal = {
415
- title: readString(modalObj.title, "components.modal.title"),
416
- callbackData: readOptionalString(modalObj.callbackData),
417
- triggerLabel: readOptionalString(modalObj.triggerLabel),
418
- triggerStyle: readOptionalString(modalObj.triggerStyle),
410
+ title: readRequiredString(modalObj.title, "components.modal.title"),
411
+ callbackData: normalizeOptionalString(modalObj.callbackData),
412
+ triggerLabel: normalizeOptionalString(modalObj.triggerLabel),
413
+ triggerStyle: normalizeOptionalString(modalObj.triggerStyle),
419
414
  allowedUsers: readOptionalStringArray(modalObj.allowedUsers, "components.modal.allowedUsers"),
420
415
  fields
421
416
  };
422
417
  }
423
418
  return {
424
- text: readOptionalString(obj.text),
419
+ text: normalizeOptionalString(obj.text),
425
420
  reusable,
426
421
  container: typeof obj.container === "object" && obj.container && !Array.isArray(obj.container) ? {
427
422
  accentColor: obj.container.accentColor,
@@ -916,14 +911,13 @@ function resolveDiscordInteractiveButtonStyle(style) {
916
911
  return style ?? "secondary";
917
912
  }
918
913
  function resolveDiscordSelectOptionValue(option) {
919
- const action = resolveMessagePresentationOptionAction(option);
920
- if (action?.type === "command") return action.command;
921
- if (action?.type === "callback") return action.value;
914
+ return resolveMessagePresentationActionValue(resolveMessagePresentationOptionAction(option));
922
915
  }
923
916
  function resolveDiscordSelectCallbackDataKind(options) {
924
917
  const renderableOptions = options.filter((option) => resolveDiscordSelectOptionValue(option));
925
- if (renderableOptions.length > 0 && renderableOptions.every((option) => option.action?.type === "command")) return "command";
926
- if (renderableOptions.length > 0 && renderableOptions.every((option) => option.action?.type === "callback")) return "callback";
918
+ if (renderableOptions.length === 0) return;
919
+ if (renderableOptions.every((option) => option.action?.type === "command")) return "command";
920
+ if (renderableOptions.every((option) => option.action?.type === "callback")) return "callback";
927
921
  if (renderableOptions.some((option) => option.action)) return "mixed";
928
922
  }
929
923
  const DISCORD_INTERACTIVE_BUTTON_ROW_SIZE = 5;
@@ -980,6 +974,24 @@ function appendDiscordButtonBlocks(blocks, buttons) {
980
974
  buttons: components.slice(index, index + DISCORD_INTERACTIVE_BUTTON_ROW_SIZE)
981
975
  });
982
976
  }
977
+ function appendDiscordSelectBlock(blocks, block) {
978
+ const options = block.options.map((option) => ({
979
+ label: option.label,
980
+ value: resolveDiscordSelectOptionValue(option)
981
+ })).filter((option) => Boolean(option.value));
982
+ if (options.length === 0) return;
983
+ const callbackDataKind = resolveDiscordSelectCallbackDataKind(block.options);
984
+ if (callbackDataKind === "mixed") return;
985
+ blocks.push({
986
+ type: "actions",
987
+ select: {
988
+ type: "string",
989
+ placeholder: block.placeholder,
990
+ options,
991
+ callbackDataKind
992
+ }
993
+ });
994
+ }
983
995
  /**
984
996
  * @deprecated Use buildDiscordPresentationComponents with MessagePresentation.
985
997
  */
@@ -997,77 +1009,38 @@ function buildDiscordInteractiveComponents(interactive) {
997
1009
  appendDiscordButtonBlocks(state, block.buttons);
998
1010
  return state;
999
1011
  }
1000
- if (block.type === "select" && block.options.length > 0) {
1001
- const options = block.options.map((option) => ({
1002
- label: option.label,
1003
- value: resolveDiscordSelectOptionValue(option)
1004
- })).filter((option) => Boolean(option.value));
1005
- if (options.length === 0) return state;
1006
- const callbackDataKind = resolveDiscordSelectCallbackDataKind(block.options);
1007
- if (callbackDataKind === "mixed") return state;
1008
- state.push({
1009
- type: "actions",
1010
- select: {
1011
- type: "string",
1012
- placeholder: block.placeholder,
1013
- options,
1014
- callbackDataKind
1015
- }
1016
- });
1017
- }
1012
+ if (block.type === "select") appendDiscordSelectBlock(state, block);
1018
1013
  return state;
1019
1014
  });
1020
1015
  return blocks.length > 0 ? { blocks } : void 0;
1021
1016
  }
1022
1017
  function buildDiscordPresentationComponents(presentation) {
1023
1018
  if (!presentation) return;
1024
- const spec = { blocks: [] };
1025
- if (presentation.title) spec.blocks?.push({
1019
+ const blocks = [];
1020
+ if (presentation.title) blocks.push({
1026
1021
  type: "text",
1027
1022
  text: presentation.title
1028
1023
  });
1029
1024
  for (const block of presentation.blocks) {
1030
1025
  if (block.type === "text" || block.type === "context") {
1031
1026
  const text = block.text.trim();
1032
- if (text) spec.blocks?.push({
1027
+ if (text) blocks.push({
1033
1028
  type: "text",
1034
1029
  text: block.type === "context" ? `-# ${text}` : text
1035
1030
  });
1036
1031
  continue;
1037
1032
  }
1038
1033
  if (block.type === "divider") {
1039
- spec.blocks?.push({ type: "separator" });
1034
+ blocks.push({ type: "separator" });
1040
1035
  continue;
1041
1036
  }
1042
- }
1043
- for (const block of presentation.blocks) {
1044
1037
  if (block.type === "buttons") {
1045
- appendDiscordPresentationButtonBlocks(spec, block.buttons);
1038
+ appendDiscordButtonBlocks(blocks, block.buttons);
1046
1039
  continue;
1047
1040
  }
1048
- if (block.type === "select" && block.options.length > 0) {
1049
- const options = block.options.map((option) => ({
1050
- label: option.label,
1051
- value: resolveDiscordSelectOptionValue(option)
1052
- })).filter((option) => Boolean(option.value));
1053
- if (options.length === 0) continue;
1054
- const callbackDataKind = resolveDiscordSelectCallbackDataKind(block.options);
1055
- if (callbackDataKind === "mixed") continue;
1056
- spec.blocks?.push({
1057
- type: "actions",
1058
- select: {
1059
- type: "string",
1060
- placeholder: block.placeholder,
1061
- options,
1062
- callbackDataKind
1063
- }
1064
- });
1065
- }
1041
+ if (block.type === "select") appendDiscordSelectBlock(blocks, block);
1066
1042
  }
1067
- return spec.blocks?.length ? spec : void 0;
1068
- }
1069
- function appendDiscordPresentationButtonBlocks(spec, buttons) {
1070
- if (spec.blocks) appendDiscordButtonBlocks(spec.blocks, buttons);
1043
+ return blocks.length ? { blocks } : void 0;
1071
1044
  }
1072
1045
  //#endregion
1073
1046
  //#region extensions/discord/src/components.ts
@@ -1,4 +1,4 @@
1
- import { Yt as __exportAll } from "./chunk-DX4jpFQP.js";
1
+ import { tn as __exportAll } from "./retry-CLpJcXXf.js";
2
2
  import { readProviderJsonObjectResponse, readResponseTextLimited } from "openclaw/plugin-sdk/provider-http";
3
3
  import { resolveFetch } from "openclaw/plugin-sdk/fetch-runtime";
4
4
  import { buildTimeoutAbortSignal } from "openclaw/plugin-sdk/extension-shared";
@@ -1,9 +1,7 @@
1
1
  import { normalizeOptionalString } from "openclaw/plugin-sdk/string-coerce-runtime";
2
- import { logVerbose } from "openclaw/plugin-sdk/runtime-env";
3
- import { createLazyRuntimeModule } from "openclaw/plugin-sdk/lazy-runtime";
4
2
  import { getFileExtension } from "openclaw/plugin-sdk/media-mime";
3
+ import { createChannelPreflightAudio } from "openclaw/plugin-sdk/media-understanding-runtime";
5
4
  //#region extensions/discord/src/monitor/preflight-audio.ts
6
- const loadDiscordPreflightAudioRuntime = createLazyRuntimeModule(() => import("./preflight-audio.runtime-CoCXMM8r.js"));
7
5
  const AUDIO_ATTACHMENT_MIME_BY_EXT = /* @__PURE__ */ new Map([
8
6
  [".aac", "audio/aac"],
9
7
  [".caf", "audio/x-caf"],
@@ -22,9 +20,14 @@ function inferAudioAttachmentMime(attachment) {
22
20
  const ext = getFileExtension(attachment.filename ?? attachment.url);
23
21
  return ext ? AUDIO_ATTACHMENT_MIME_BY_EXT.get(ext) : void 0;
24
22
  }
23
+ const discordPreflightAudio = createChannelPreflightAudio({
24
+ channel: "discord",
25
+ isAudio: (attachment) => Boolean(normalizeOptionalString(attachment.url) && inferAudioAttachmentMime(attachment)),
26
+ deferTranscriptEcho: false
27
+ });
25
28
  function collectAudioAttachments(attachments) {
26
29
  if (!Array.isArray(attachments)) return [];
27
- return attachments.filter((att) => normalizeOptionalString(att.url) && inferAudioAttachmentMime(att));
30
+ return attachments.filter(discordPreflightAudio.isAudio);
28
31
  }
29
32
  async function resolveDiscordPreflightAudioMentionContext(params) {
30
33
  const audioAttachments = collectAudioAttachments(params.message.attachments);
@@ -37,30 +40,21 @@ async function resolveDiscordPreflightAudioMentionContext(params) {
37
40
  hasAudioAttachment,
38
41
  hasTypedText
39
42
  };
40
- try {
41
- const { transcribeFirstAudio } = await loadDiscordPreflightAudioRuntime();
42
- if (params.abortSignal?.aborted) return {
43
- hasAudioAttachment,
44
- hasTypedText
45
- };
46
- const media = audioAttachments.flatMap((attachment) => {
47
- const url = normalizeOptionalString(attachment.url);
48
- return url ? [{
49
- url,
50
- contentType: inferAudioAttachmentMime(attachment)
51
- }] : [];
52
- });
53
- if (media.length > 0) {
54
- transcript = await transcribeFirstAudio({
55
- ctx: { media },
56
- cfg: params.cfg,
57
- agentDir: void 0
58
- });
59
- if (params.abortSignal?.aborted) transcript = void 0;
60
- }
61
- } catch (err) {
62
- logVerbose(`discord: audio preflight transcription failed: ${String(err)}`);
63
- }
43
+ const media = audioAttachments.flatMap((attachment) => {
44
+ const url = normalizeOptionalString(attachment.url);
45
+ return url ? [{
46
+ url,
47
+ contentType: inferAudioAttachmentMime(attachment)
48
+ }] : [];
49
+ });
50
+ if (media.length > 0) transcript = await discordPreflightAudio.resolve({
51
+ request: {
52
+ ctx: { media },
53
+ cfg: params.cfg,
54
+ agentDir: void 0
55
+ },
56
+ abortSignal: params.abortSignal
57
+ });
64
58
  }
65
59
  return {
66
60
  hasAudioAttachment,