@openclaw/discord 2026.9.6 → 2026.9.7
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/assets/icon.png +0 -0
- package/dist/.setup/{account-inspect-BwQj24ht.mjs → account-inspect-De8hOUxG.mjs} +1 -1
- package/dist/.setup/{accounts-CwJQoLjM.mjs → accounts-ChaMcixG.mjs} +1 -4
- package/dist/.setup/{activities-api-COU4-0nR.mjs → activities-api-tvbsU2e3.mjs} +38 -66
- package/dist/.setup/{api-CBK9zcq5.mjs → api-DVbJwZVt.mjs} +10 -2
- package/dist/.setup/{approval-handler.runtime-CbBktBb4.mjs → approval-handler.runtime-DxCK2Rux.mjs} +49 -125
- package/dist/.setup/{approval-message-updates-jf9zMaIC.mjs → approval-message-updates-BKFqavHZ.mjs} +2 -2
- package/dist/.setup/{audit-vKbh-LFR.mjs → audit-CLg9I71N.mjs} +5 -5
- package/dist/.setup/{channel-Dv4e3Jpc.mjs → channel-DxlUVU9t.mjs} +121 -227
- package/dist/.setup/{channel-type-DKnjV1XW.mjs → channel-type-DRCrEMss.mjs} +22 -22
- package/dist/.setup/{channel.setup-0NX6FFwi.mjs → channel.setup-CRo1GjV7.mjs} +6 -9
- package/dist/.setup/{components-yBEb75bB.mjs → components-Cq1PvIpN.mjs} +41 -69
- package/dist/.setup/{config-schema-CiZz-mtA.mjs → config-schema-oxELUSDx.mjs} +19 -44
- package/dist/.setup/{conversation-binding-route-B7qImK_b.mjs → conversation-binding-route-Caz_XuFH.mjs} +10 -5
- package/dist/.setup/{directory-config-BytTftz-.mjs → directory-config-esqNn0Eo.mjs} +6 -9
- package/dist/.setup/{directory-live--EGTH0DC.mjs → directory-live-DtKRHuGV.mjs} +6 -12
- package/dist/.setup/{discord-BXpHW-cu.mjs → discord-0xJYfdDD.mjs} +82 -386
- package/dist/.setup/{doctor-D1R-uFIu.mjs → doctor-BCl1H5tl.mjs} +21 -36
- package/dist/.setup/{doctor-contract-Co5vRCZ6.mjs → doctor-contract-CvvgwrrG.mjs} +41 -50
- package/dist/.setup/{channel-actions.runtime-leZuw01r.mjs → handle-action-CUvQWnE7.mjs} +67 -104
- package/dist/.setup/{handle-action.guild-admin-DcFa8NwA.mjs → handle-action.guild-admin-Df-8gVle.mjs} +62 -120
- package/dist/.setup/{live-policy-config-eKQ-PLdy.mjs → live-policy-config-8Pv20CHc.mjs} +2 -3
- package/dist/.setup/{message-handler-X6ejmbtY.mjs → message-handler-B-Jk4oDk.mjs} +18 -94
- package/dist/.setup/{message-handler.preflight-pluralkit-8Xji34AF.mjs → message-handler.preflight-pluralkit-CWLUBVcx.mjs} +8 -10
- package/dist/.setup/{message-handler.preflight-DE_POxFc.mjs → message-handler.preflight-v-__NSDq.mjs} +69 -180
- package/dist/.setup/{message-handler.process-CCmIVnxy.mjs → message-handler.process-BNFFuChn.mjs} +65 -86
- package/dist/.setup/{outbound-adapter-ClIgmu4F.mjs → outbound-adapter-BobT-kse.mjs} +105 -19
- package/dist/.setup/{outbound-session-route-VulUE0yV.mjs → outbound-session-route-zVGxxceg.mjs} +140 -108
- package/dist/.setup/{pluralkit-CdAt1G0P.mjs → pluralkit-a6_NLfH9.mjs} +1 -1
- package/dist/.setup/{presence-cache-dYSHPWMx.mjs → presence-cache-Di3H3DIU.mjs} +0 -4
- package/dist/.setup/{probe-CupW4we4.mjs → probe-LYrIHlBF.mjs} +13 -4
- package/dist/.setup/{provider-iOf73HW-.mjs → provider-B_G5hASF.mjs} +721 -1416
- package/dist/.setup/provider-session.runtime-BYlTBFD2.mjs +6 -0
- package/dist/.setup/provider.runtime-CUE3UxER.mjs +2 -0
- package/dist/.setup/{realtime-session.runtime-Dz8uVutq.mjs → realtime-session.runtime-oUd9DOcz.mjs} +41 -55
- package/dist/.setup/{receive-recovery-DHst8WRx.mjs → receive-recovery-CHPOsnLc.mjs} +1 -4
- package/dist/.setup/{resolve-allowlist-common-CwMBzbx9.mjs → resolve-allowlist-common-DPdRggu5.mjs} +4 -7
- package/dist/.setup/{resolve-channels-BbvsLQOZ.mjs → resolve-channels-BFPNRmVv.mjs} +21 -40
- package/dist/.setup/{resolve-users-ByFlR7LQ.mjs → resolve-users-0-aBuCy3.mjs} +4 -4
- package/dist/.setup/{retry-BEYkDy0P.mjs → retry-pz_cSha2.mjs} +3 -3
- package/dist/.setup/rolldown-runtime-B4FMCO8f.mjs +28 -0
- package/dist/.setup/{runtime-B8lJfyrA.mjs → runtime-FN000lxA.mjs} +60 -162
- package/dist/.setup/runtime-doctor-migrations-CshUGl36.mjs +159 -0
- package/dist/.setup/{runtime-DisDbixd.mjs → runtime-sUksZ--Q.mjs} +2 -5
- package/dist/.setup/{secret-config-contract-DFu9hfU8.mjs → secret-config-contract-uOE2J7yM.mjs} +15 -85
- package/dist/.setup/{security-audit-s5w50-Ly.mjs → security-audit-Cdaegq7C.mjs} +3 -1
- package/dist/.setup/{send-CIBzvXjS.mjs → send-CrfEI6Bs.mjs} +53 -108
- package/dist/.setup/{send.components-ChY21qr-.mjs → send.components-DxQAMfES.mjs} +62 -107
- package/dist/.setup/{send.outbound-QTyuFupn.mjs → send.outbound-BISKnb-a.mjs} +66 -140
- package/dist/.setup/{send.shared-VNvWfX2T.mjs → send.shared-DGFkbkQR.mjs} +10 -25
- package/dist/.setup/{sender-identity-0Ymgvmaj.mjs → sender-identity-B9X5Vb9R.mjs} +2 -3
- package/dist/.setup/setup-plugin-api-BQUBxbhe.mjs +3 -0
- package/dist/.setup/{shared-DHPDaMSx.mjs → shared-B3wZ4hN-.mjs} +25 -32
- package/dist/.setup/{subagent-hooks-CjW7r8Pe.mjs → subagent-hooks-nlUE9ow7.mjs} +5 -6
- package/dist/.setup/system-events-CdeZnvPV.mjs +33 -0
- package/dist/.setup/{target-resolver-BXpy6VT8.mjs → target-resolver-BuLapkhy.mjs} +9 -12
- package/dist/.setup/targets-0KUcEIYx.mjs +3 -0
- package/dist/.setup/{thread-bindings-CEh2dhqP.mjs → thread-bindings-D7TfgjR_.mjs} +33 -35
- package/dist/.setup/{thread-bindings.manager-ve-i6oqt.mjs → thread-bindings.manager-DN-NissX.mjs} +325 -233
- package/dist/.setup/thread-bindings.session-updates-CshfKghV.mjs +359 -0
- package/dist/.setup/{thread-bindings.state-BThFQEga.mjs → thread-bindings.state-g6v9zAym.mjs} +21 -62
- package/dist/.setup/{transcripts-source-DVegW0WI.mjs → transcripts-source-p8EV179h.mjs} +76 -235
- package/dist/.setup/{typing-BKZL5fGj.mjs → typing-BiHCzBRu.mjs} +2 -1
- package/dist/.setup/{voice-runtime-elTtjEIG.mjs → voice-runtime-B46rcwrG.mjs} +140 -244
- package/dist/account-inspect-api.js +1 -1
- package/dist/action-runtime-api.js +1 -1
- package/dist/activities-api.js +1 -1
- package/dist/api.js +18 -18
- package/dist/channel-config-api.js +1 -1
- package/dist/channel-plugin-api.js +1 -1
- package/dist/directory-contract-api.js +1 -1
- package/dist/doctor-contract-api.js +4 -4
- package/dist/index.js +1 -1
- package/dist/runtime-api.js +20 -20
- package/dist/secret-contract-api.js +1 -1
- package/dist/security-audit-contract-api.js +1 -1
- package/dist/setup-entry.js +1 -1
- package/dist/setup-plugin-api.js +1 -1
- package/dist/src/voice/audio-worker.runtime.js +15 -24
- package/dist/subagent-hooks-api.js +3 -4
- package/dist/transcripts-source-api.js +1 -1
- package/node_modules/@types/node/README.md +2 -2
- package/node_modules/@types/node/child_process.d.ts +1 -1
- package/node_modules/@types/node/crypto.d.ts +20 -8
- package/node_modules/@types/node/ffi.d.ts +14 -0
- package/node_modules/@types/node/http2.d.ts +3 -2
- package/node_modules/@types/node/net.d.ts +16 -4
- package/node_modules/@types/node/package.json +2 -17
- package/node_modules/@types/node/process.d.ts +1 -0
- package/node_modules/@types/node/quic.d.ts +39 -1
- package/node_modules/@types/node/stream/iter.d.ts +9 -12
- package/node_modules/@types/node/test/reporters.d.ts +1 -0
- package/node_modules/@types/node/test.d.ts +72 -0
- package/node_modules/@types/node/tls.d.ts +14 -10
- package/node_modules/@types/node/vm.d.ts +2 -1
- package/node_modules/@types/node/worker_threads.d.ts +4 -1
- package/node_modules/typebox/build/compile/code.mjs +1 -2
- package/node_modules/typebox/build/compile/validator.mjs +5 -1
- package/node_modules/typebox/build/format/iri.mjs +16 -9
- package/node_modules/typebox/build/guard/emit.mjs +2 -2
- package/node_modules/typebox/build/guard/guard.d.mts +7 -5
- package/node_modules/typebox/build/guard/guard.mjs +14 -9
- package/node_modules/typebox/build/guard/index.mjs +6 -0
- package/node_modules/typebox/build/guard/unicode/unicode.d.mts +6 -0
- package/node_modules/typebox/build/guard/unicode/unicode.mjs +35 -0
- package/node_modules/typebox/build/guard/{string.mjs → unicode/unicode_segment.mjs} +16 -19
- package/node_modules/typebox/build/schema/build.mjs +2 -3
- package/node_modules/typebox/build/schema/engine/_pathing.d.mts +1 -0
- package/node_modules/typebox/build/schema/engine/_pathing.mjs +11 -0
- package/node_modules/typebox/build/schema/engine/_refine.mjs +13 -5
- package/node_modules/typebox/build/schema/engine/additionalProperties.mjs +2 -1
- package/node_modules/typebox/build/schema/engine/dependencies.mjs +2 -1
- package/node_modules/typebox/build/schema/engine/dependentSchemas.mjs +2 -1
- package/node_modules/typebox/build/schema/engine/dynamicRef.d.mts +1 -1
- package/node_modules/typebox/build/schema/engine/dynamicRef.mjs +2 -2
- package/node_modules/typebox/build/schema/engine/format.mjs +9 -2
- package/node_modules/typebox/build/schema/engine/patternProperties.mjs +3 -2
- package/node_modules/typebox/build/schema/engine/properties.mjs +3 -2
- package/node_modules/typebox/build/schema/engine/propertyNames.mjs +2 -1
- package/node_modules/typebox/build/schema/engine/recursiveRef.d.mts +1 -1
- package/node_modules/typebox/build/schema/engine/recursiveRef.mjs +2 -2
- package/node_modules/typebox/build/schema/engine/ref.d.mts +1 -1
- package/node_modules/typebox/build/schema/engine/ref.mjs +2 -2
- package/node_modules/typebox/build/schema/engine/schema.mjs +24 -24
- package/node_modules/typebox/build/schema/parse.mjs +3 -0
- package/node_modules/typebox/build/schema/pointer/pointer.d.mts +1 -6
- package/node_modules/typebox/build/schema/pointer/pointer.mjs +47 -64
- package/node_modules/typebox/build/system/settings/internal.d.mts +2 -0
- package/node_modules/typebox/build/system/settings/internal.mjs +20 -0
- package/node_modules/typebox/build/system/settings/settings.d.mts +11 -0
- package/node_modules/typebox/build/system/settings/settings.mjs +14 -0
- package/node_modules/typebox/build/type/extends/inference.d.mts +1 -1
- package/node_modules/typebox/build/type/extends/inference.mjs +15 -2
- package/node_modules/typebox/build/type/extends/tuple.d.mts +2 -1
- package/node_modules/typebox/build/type/extends/tuple.mjs +21 -1
- package/node_modules/typebox/build/value/parse/parse.mjs +10 -4
- package/node_modules/typebox/package.json +1 -1
- package/node_modules/typebox/readme.md +3 -1
- package/openclaw.plugin.json +21 -1
- package/package.json +5 -5
- package/dist/.setup/agent-components.runtime-CEPrf2SY.mjs +0 -4
- package/dist/.setup/probe.runtime-DBQ_AGPe.mjs +0 -2
- package/dist/.setup/provider-session.runtime-DrGAYnZv.mjs +0 -6
- package/dist/.setup/provider.runtime-BmjW_pIw.mjs +0 -2
- package/dist/.setup/security-audit.runtime-DHtYenx9.mjs +0 -2
- package/dist/.setup/setup-plugin-api-Dvr41dyx.mjs +0 -3
- package/dist/.setup/system-events-B2YEEMbS.mjs +0 -34
- package/dist/.setup/targets-CvemhN3i.mjs +0 -3
- package/dist/.setup/thread-bindings.session-updates-DCQq1WZ5.mjs +0 -55
- /package/node_modules/typebox/build/guard/{string.d.mts → unicode/unicode_segment.d.mts} +0 -0
|
@@ -1,38 +1,39 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import { c as resolveDiscordAccount, f as resolveDiscordAccountDmPolicy, h as resolveDiscordToken, l as resolveDiscordAccountAllowFrom, m as normalizeDiscordToken, o as mergeDiscordAccountConfig, p as resolveDiscordMaxLinesPerMessage } from "./accounts-
|
|
5
|
-
import { a as registerDiscordComponentEntries, o as resolveDiscordComponentEntryWithPersistence, s as resolveDiscordModalEntryWithPersistence, t as editDiscordComponentMessage } from "./send.components-
|
|
1
|
+
import { C as parseDiscordActivityCustomIdForInteraction, D as parseDiscordModalCustomIdForInteraction, E as parseDiscordModalCustomId, O as decodeCustomIdComponent, T as parseDiscordComponentCustomIdForInteraction, c as parseExecApprovalData, d as buildDiscordComponentMessage, k as encodeCustomIdComponent, o as parseDiscordQuestionData, w as parseDiscordComponentCustomId, y as buildDiscordActivityCustomId } from "./components-Cq1PvIpN.mjs";
|
|
2
|
+
import { $ as BaseMessageInteractiveComponent, B as Container, D as Message, E as Guild, J as Separator, K as Row, O as User, P as Modal, R as Button, T as CommandWithSubcommands, X as TextDisplay, Y as StringSelectMenu, a as MessageCreateListener, c as PresenceUpdateListener, d as ThreadDeleteListener, f as ThreadUpdateListener, h as Plugin, i as InteractionCreateListener, k as hasDiscordV2Components, l as ReadyListener, m as Client, n as GuildCreateListener, o as MessageReactionAddListener, r as GuildDeleteListener, s as MessageReactionRemoveListener, t as discord_exports, v as RateLimitError, w as Command } from "./discord-0xJYfdDD.mjs";
|
|
3
|
+
import { D as getDiscordEndpointRuntime, E as assertDiscordEndpointGatewayUrl, S as formatDiscordUserTag, _ as resolveDiscordOwnerAllowFrom, a as normalizeDiscordDisplaySlug, b as shouldEmitDiscordReactionNotification, c as resolveDiscordChannelConfig, f as resolveDiscordGuildEntry, g as resolveDiscordOwnerAccess, i as normalizeDiscordAllowList, l as resolveDiscordChannelConfigWithFallback, m as resolveDiscordMemberAllowed, o as normalizeDiscordSlug, p as resolveDiscordMemberAccessState, r as isDiscordGroupAllowedByPolicy, s as resolveDiscordAllowListMatch, t as isDiscordThreadChannelType, u as resolveDiscordChannelPolicyCommandAuthorizer, w as resolveTimestampMs, x as formatDiscordReactionEmoji, y as resolveGroupDmAllow } from "./channel-type-DRCrEMss.mjs";
|
|
4
|
+
import { c as resolveDiscordAccount, f as resolveDiscordAccountDmPolicy, h as resolveDiscordToken, l as resolveDiscordAccountAllowFrom, m as normalizeDiscordToken, o as mergeDiscordAccountConfig, p as resolveDiscordMaxLinesPerMessage } from "./accounts-ChaMcixG.mjs";
|
|
5
|
+
import { a as registerDiscordComponentEntries, o as resolveDiscordComponentEntryWithPersistence, s as resolveDiscordModalEntryWithPersistence, t as editDiscordComponentMessage } from "./send.components-DxQAMfES.mjs";
|
|
6
6
|
import { t as getDiscordRuntime } from "./runtime-DgnVQ7zW.mjs";
|
|
7
|
-
import { a as isDiscordRateLimitResponseBody,
|
|
8
|
-
import { o as chunkDiscordTextWithMode } from "./retry-
|
|
9
|
-
import { B as
|
|
10
|
-
import { o as formatMention, t as sendMessageDiscord } from "./send.outbound-
|
|
11
|
-
import { n as getDiscordActivitiesRuntime } from "./runtime-
|
|
7
|
+
import { a as isDiscordRateLimitResponseBody, s as summarizeDiscordResponseBody } from "./api-DVbJwZVt.mjs";
|
|
8
|
+
import { o as chunkDiscordTextWithMode } from "./retry-pz_cSha2.mjs";
|
|
9
|
+
import { B as withValidatedDiscordProxy, C as hasAnyChannelPermissionDiscord, L as DISCORD_REST_TIMEOUT_MS, N as createDiscordRestClient, U as registerGateway, W as unregisterGateway, y as canViewDiscordGuildChannel, z as validateDiscordProxyUrl } from "./send.shared-DGFkbkQR.mjs";
|
|
10
|
+
import { o as formatMention, t as sendMessageDiscord } from "./send.outbound-BISKnb-a.mjs";
|
|
11
|
+
import { n as getDiscordActivitiesRuntime } from "./runtime-sUksZ--Q.mjs";
|
|
12
12
|
import { t as resolveDiscordCommandOwnerAllowFrom } from "./command-owners-D78sAoOz.mjs";
|
|
13
13
|
import { n as resolveDiscordChannelInfoSafe, o as resolveDiscordChannelTopicSafe, r as resolveDiscordChannelNameSafe } from "./channel-access-C12aDZ0p.mjs";
|
|
14
|
-
import { O as
|
|
15
|
-
import { i as setPresence, t as clearPresences } from "./presence-cache-
|
|
16
|
-
import { _ as readMessagesDiscord, s as sendVoiceMessageDiscord } from "./send-
|
|
14
|
+
import { D as resolveDiscordReferencedReplyMessage, O as resolveDiscordReferencedReplyMessageId, a as resolveDiscordVoiceEnabled, i as setDiscordTranscriptsVoiceManager, l as resolveDiscordThreadLikeChannelContext, o as authorizeDiscordVoiceIngress, s as resolveDiscordVoiceAccess, u as resolveFetchedDiscordThreadLikeChannelContext } from "./transcripts-source-p8EV179h.mjs";
|
|
15
|
+
import { i as setPresence, t as clearPresences } from "./presence-cache-Di3H3DIU.mjs";
|
|
16
|
+
import { _ as readMessagesDiscord, s as sendVoiceMessageDiscord } from "./send-CrfEI6Bs.mjs";
|
|
17
17
|
import { c as raceWithTimeout, u as withAbortTimeout } from "./timeouts-D86uWLt_.mjs";
|
|
18
|
-
import { D as isDiscordExecApprovalClientEnabled, T as getDiscordExecApprovalApprovers, a as resolveDiscordComponentSpec, c as formatDiscordApprovalDisplayValue, d as resolveDiscordBoundConversationRoute, h as resolveDiscordConversationIdentity, l as buildDiscordConversationRouteContext, n as DISCORD_PRESENTATION_CAPABILITIES, p as resolveDiscordEffectiveRoute, r as buildDiscordPresentationPayload, s as DISCORD_APPROVAL_ALLOWED_MENTIONS, u as buildDiscordRoutePeer } from "./outbound-session-route-
|
|
19
|
-
import { n as discordIngressIdentity, t as selectDiscordLivePolicyConfig } from "./live-policy-config-
|
|
20
|
-
import { t as resolveDiscordChannelAllowlist } from "./resolve-channels-
|
|
21
|
-
import { t as resolveDiscordUserAllowlist } from "./resolve-users-
|
|
22
|
-
import {
|
|
23
|
-
import { a as probeDiscordApplicationId, r as parseApplicationIdFromToken } from "./probe-
|
|
18
|
+
import { D as isDiscordExecApprovalClientEnabled, T as getDiscordExecApprovalApprovers, a as resolveDiscordComponentSpec, c as formatDiscordApprovalDisplayValue, d as resolveDiscordBoundConversationRoute, h as resolveDiscordConversationIdentity, l as buildDiscordConversationRouteContext, n as DISCORD_PRESENTATION_CAPABILITIES, p as resolveDiscordEffectiveRoute, r as buildDiscordPresentationPayload, s as DISCORD_APPROVAL_ALLOWED_MENTIONS, u as buildDiscordRoutePeer } from "./outbound-session-route-zVGxxceg.mjs";
|
|
19
|
+
import { n as discordIngressIdentity, t as selectDiscordLivePolicyConfig } from "./live-policy-config-8Pv20CHc.mjs";
|
|
20
|
+
import { t as resolveDiscordChannelAllowlist } from "./resolve-channels-BFPNRmVv.mjs";
|
|
21
|
+
import { t as resolveDiscordUserAllowlist } from "./resolve-users-0-aBuCy3.mjs";
|
|
22
|
+
import { a as isThreadArchived, n as getThreadBindingManager } from "./thread-bindings.manager-DN-NissX.mjs";
|
|
23
|
+
import { a as probeDiscordApplicationId, r as parseApplicationIdFromToken } from "./probe-LYrIHlBF.mjs";
|
|
24
24
|
import { i as sanitizeRecentModels, n as normalizeModelRef, r as preferenceTimestampMs, t as buildPreferenceModelKey } from "./model-picker-preference-primitives-BHT1LkR_.mjs";
|
|
25
|
-
import { t as resolveDiscordSenderIdentity } from "./sender-identity-
|
|
26
|
-
import { n as hasDiscordApprovalControl, t as discordApprovalMessageUpdates } from "./approval-message-updates-
|
|
25
|
+
import { t as resolveDiscordSenderIdentity } from "./sender-identity-B9X5Vb9R.mjs";
|
|
26
|
+
import { n as hasDiscordApprovalControl, t as discordApprovalMessageUpdates } from "./approval-message-updates-BKFqavHZ.mjs";
|
|
27
27
|
import { createRequire } from "node:module";
|
|
28
28
|
import { logDebug, logError } from "openclaw/plugin-sdk/logging-core";
|
|
29
29
|
import { ApplicationCommandOptionType, ButtonStyle, ChannelType, ComponentType, GatewayCloseCodes, GatewayCloseCodes as GatewayCloseCodes$1, GatewayDispatchEvents, GatewayIntentBits, GatewayOpcodes, PermissionFlagsBits } from "discord-api-types/v10";
|
|
30
30
|
import { Type } from "typebox";
|
|
31
31
|
import { Check, Errors } from "typebox/value";
|
|
32
32
|
import { createHash, randomUUID } from "node:crypto";
|
|
33
|
-
import { MAX_DATE_TIMESTAMP_MS, MAX_TIMER_TIMEOUT_MS, asDateTimestampMs, asSafeIntegerInRange, parseFiniteNumber, parseStrictInteger, parseStrictPositiveInteger, resolveDateTimestampMs, resolvePromptHistoryLimit, resolveTimestampMsToIsoString } from "openclaw/plugin-sdk/number-runtime";
|
|
34
33
|
import { expectDefined } from "openclaw/plugin-sdk/expect-runtime";
|
|
34
|
+
import { MAX_DATE_TIMESTAMP_MS, MAX_TIMER_TIMEOUT_MS, asDateTimestampMs, asSafeIntegerInRange, parseFiniteNumber, parseStrictInteger, parseStrictPositiveInteger, resolveDateTimestampMs, resolvePromptHistoryLimit, resolveTimestampMsToIsoString } from "openclaw/plugin-sdk/number-runtime";
|
|
35
35
|
import { inspect } from "node:util";
|
|
36
|
+
import * as fetchRuntimeSdk from "openclaw/plugin-sdk/fetch-runtime";
|
|
36
37
|
import { createHttp1EnvHttpProxyAgent, createHttp1ProxyAgent, createNodeProxyAgent, resolveEnvHttpProxyAgentOptions, wrapFetchWithAbortSignal } from "openclaw/plugin-sdk/fetch-runtime";
|
|
37
38
|
import { readResponseWithLimit } from "openclaw/plugin-sdk/response-limit-runtime";
|
|
38
39
|
import { fetchWithSsrFGuard, formatErrorMessage, resolvePinnedHostnameWithPolicy } from "openclaw/plugin-sdk/ssrf-runtime";
|
|
@@ -58,23 +59,23 @@ import { GROUP_POLICY_BLOCKED_LABEL, resolveDefaultGroupPolicy, resolveOpenProvi
|
|
|
58
59
|
import { pruneMapToMaxSize } from "openclaw/plugin-sdk/collection-runtime";
|
|
59
60
|
import { buildChannelInboundEventContext, createChannelPartialDeliveryError, createCommandTurnContext, dispatchChannelInboundTurn, formatInboundEnvelope, hasVisibleInboundReplyDispatch, isChannelPartialDeliveryError, resolveEnvelopeFormatOptions, resolveInboundSupplementalSenderAllowed, runChannelInboundEvent } from "openclaw/plugin-sdk/channel-inbound";
|
|
60
61
|
import path from "node:path";
|
|
61
|
-
import { resolvePinnedMainDmOwnerFromAllowlist
|
|
62
|
+
import { resolvePinnedMainDmOwnerFromAllowlist } from "openclaw/plugin-sdk/security-runtime";
|
|
62
63
|
import { createChannelPairingChallengeIssuer } from "openclaw/plugin-sdk/channel-pairing";
|
|
63
64
|
import { CHANNEL_APPROVAL_NATIVE_RUNTIME_CONTEXT_CAPABILITY } from "openclaw/plugin-sdk/approval-handler-adapter-runtime";
|
|
64
|
-
import { buildPairingReply,
|
|
65
|
+
import { buildPairingReply, formatThreadBindingDurationLabel, upsertChannelPairingRequest } from "openclaw/plugin-sdk/conversation-runtime";
|
|
65
66
|
import { ensureConfiguredBindingRouteReady, resolveConfiguredBindingRoute } from "openclaw/plugin-sdk/conversation-binding-runtime";
|
|
66
67
|
import { questionGatewayRuntime } from "openclaw/plugin-sdk/question-gateway-runtime";
|
|
67
68
|
import { readChannelIngressStoreAllowFromForDmPolicy } from "openclaw/plugin-sdk/channel-ingress-runtime";
|
|
68
69
|
import { isDangerousNameMatchingEnabled } from "openclaw/plugin-sdk/dangerous-name-runtime";
|
|
69
70
|
import { resolveNativeCommandsEnabled, resolveNativeSkillsEnabled } from "openclaw/plugin-sdk/native-command-config-runtime";
|
|
70
71
|
import { requestHeartbeat } from "openclaw/plugin-sdk/heartbeat-runtime";
|
|
71
|
-
import { enqueueRoutedSystemEvent
|
|
72
|
+
import { enqueueRoutedSystemEvent } from "openclaw/plugin-sdk/system-event-runtime";
|
|
72
73
|
import { clearExpiredCooldowns, ensureAuthProfileStore, formatReasoningMessage, getPreparedModelCatalogSnapshot, isProfileInCooldown, listAgentIds, loadPreparedModelCatalog, resolveAgentAvatar, resolveAgentDir, resolveDefaultModelForAgent, resolveHumanDelayConfig, resolveProfilesUnavailableReason } from "openclaw/plugin-sdk/agent-runtime";
|
|
73
|
-
import { deleteSessionEntry, getSessionEntry, listSessionEntries, readSessionUpdatedAt
|
|
74
|
-
import
|
|
74
|
+
import { deleteSessionEntry, getSessionEntry, listSessionEntries, readSessionUpdatedAt, resolveStorePath } from "openclaw/plugin-sdk/session-store-runtime";
|
|
75
|
+
import * as proxyCaptureSdk from "openclaw/plugin-sdk/proxy-capture";
|
|
76
|
+
import { resolveDebugProxySettings, resolveEffectiveDebugProxyUrl } from "openclaw/plugin-sdk/proxy-capture";
|
|
75
77
|
import { resolveRequestUrl } from "openclaw/plugin-sdk/request-url";
|
|
76
78
|
import { fetchWithRuntimeDispatcher } from "openclaw/plugin-sdk/runtime-fetch";
|
|
77
|
-
import { Agent } from "undici";
|
|
78
79
|
import * as dns from "node:dns";
|
|
79
80
|
import { buildCommandTextFromArgs as buildCommandTextFromArgs$1, findCommandByNativeName as findCommandByNativeName$1, mergeNativeCommandSpecs, parseCommandArgs, resolveCommandArgChoices, resolveCommandArgMenu, serializeCommandArgs as serializeCommandArgs$1 } from "openclaw/plugin-sdk/native-command-registry";
|
|
80
81
|
import { PLUGIN_COMMAND_DISPATCH } from "openclaw/plugin-sdk/plugin-command-runtime";
|
|
@@ -82,7 +83,7 @@ import { resolveDirectStatusReplyForSession } from "openclaw/plugin-sdk/command-
|
|
|
82
83
|
import * as modelsProviderRuntime from "openclaw/plugin-sdk/models-provider-runtime";
|
|
83
84
|
import { normalizeProviderId } from "openclaw/plugin-sdk/provider-model-shared";
|
|
84
85
|
import { EventEmitter } from "node:events";
|
|
85
|
-
import { Agent
|
|
86
|
+
import { Agent } from "node:https";
|
|
86
87
|
import { channelReadyPatch, createTransportActivityStatusPatch } from "openclaw/plugin-sdk/gateway-runtime";
|
|
87
88
|
import { registerChannelRuntimeContext } from "openclaw/plugin-sdk/channel-runtime-context";
|
|
88
89
|
import { stripPlainTextToolCallBlocks } from "openclaw/plugin-sdk/tool-payload";
|
|
@@ -528,22 +529,10 @@ async function runDiscordReactionHandler(initialParams) {
|
|
|
528
529
|
listener: params.listener,
|
|
529
530
|
event: params.event,
|
|
530
531
|
run: async () => handleDiscordReactionEvent({
|
|
532
|
+
...params.handlerParams,
|
|
531
533
|
data: params.data,
|
|
532
534
|
client: params.client,
|
|
533
|
-
action: params.action
|
|
534
|
-
cfg: params.handlerParams.cfg,
|
|
535
|
-
isPolicyCurrent: params.handlerParams.isPolicyCurrent,
|
|
536
|
-
accountId: params.handlerParams.accountId,
|
|
537
|
-
botUserId: params.handlerParams.botUserId,
|
|
538
|
-
dmEnabled: params.handlerParams.dmEnabled,
|
|
539
|
-
groupDmEnabled: params.handlerParams.groupDmEnabled,
|
|
540
|
-
groupDmChannels: params.handlerParams.groupDmChannels,
|
|
541
|
-
dmPolicy: params.handlerParams.dmPolicy,
|
|
542
|
-
allowFrom: params.handlerParams.allowFrom,
|
|
543
|
-
groupPolicy: params.handlerParams.groupPolicy,
|
|
544
|
-
allowNameMatching: params.handlerParams.allowNameMatching,
|
|
545
|
-
guildEntries: params.handlerParams.guildEntries,
|
|
546
|
-
logger: params.handlerParams.logger
|
|
535
|
+
action: params.action
|
|
547
536
|
})
|
|
548
537
|
});
|
|
549
538
|
}
|
|
@@ -625,51 +614,6 @@ async function authorizeDiscordReactionIngress(params) {
|
|
|
625
614
|
};
|
|
626
615
|
return { allowed: true };
|
|
627
616
|
}
|
|
628
|
-
async function handleDiscordThreadReactionNotification(params) {
|
|
629
|
-
if (params.reactionMode === "off") return;
|
|
630
|
-
if (params.reactionMode === "all" || params.reactionMode === "allowlist") {
|
|
631
|
-
const { access, channelConfig } = await params.resolveThreadChannelAccess();
|
|
632
|
-
if (!access.allowed || !params.shouldNotifyReaction({
|
|
633
|
-
mode: params.reactionMode,
|
|
634
|
-
channelConfig
|
|
635
|
-
})) return;
|
|
636
|
-
const { baseText } = params.resolveReactionBase();
|
|
637
|
-
params.emitReaction(baseText, params.parentId);
|
|
638
|
-
return;
|
|
639
|
-
}
|
|
640
|
-
const message = await params.message.fetch().catch(() => null);
|
|
641
|
-
const { access, channelConfig } = await params.resolveThreadChannelAccess();
|
|
642
|
-
const messageAuthorId = message?.author?.id ?? void 0;
|
|
643
|
-
if (!access.allowed || !params.shouldNotifyReaction({
|
|
644
|
-
mode: params.reactionMode,
|
|
645
|
-
messageAuthorId,
|
|
646
|
-
channelConfig
|
|
647
|
-
})) return;
|
|
648
|
-
params.emitReactionWithAuthor(message);
|
|
649
|
-
}
|
|
650
|
-
async function handleDiscordChannelReactionNotification(params) {
|
|
651
|
-
if (params.isGuildMessage) {
|
|
652
|
-
if (!(await params.authorizeReactionIngressForChannel(params.channelConfig)).allowed) return;
|
|
653
|
-
}
|
|
654
|
-
if (params.reactionMode === "off") return;
|
|
655
|
-
if (params.reactionMode === "all" || params.reactionMode === "allowlist") {
|
|
656
|
-
if (!params.shouldNotifyReaction({
|
|
657
|
-
mode: params.reactionMode,
|
|
658
|
-
channelConfig: params.channelConfig
|
|
659
|
-
})) return;
|
|
660
|
-
const { baseText } = params.resolveReactionBase();
|
|
661
|
-
params.emitReaction(baseText, params.parentId);
|
|
662
|
-
return;
|
|
663
|
-
}
|
|
664
|
-
const message = await params.message.fetch().catch(() => null);
|
|
665
|
-
const messageAuthorId = message?.author?.id ?? void 0;
|
|
666
|
-
if (!params.shouldNotifyReaction({
|
|
667
|
-
mode: params.reactionMode,
|
|
668
|
-
messageAuthorId,
|
|
669
|
-
channelConfig: params.channelConfig
|
|
670
|
-
})) return;
|
|
671
|
-
params.emitReactionWithAuthor(message);
|
|
672
|
-
}
|
|
673
617
|
function hasDiscordGuildChannelOverrides(guildInfo) {
|
|
674
618
|
return Boolean(guildInfo?.channels && Object.keys(guildInfo.channels).length > 0);
|
|
675
619
|
}
|
|
@@ -757,57 +701,10 @@ async function handleDiscordReactionEvent(params) {
|
|
|
757
701
|
const parentId = isThreadChannel ? channelContext.threadParentId : channelContext.parentId;
|
|
758
702
|
const parentName = isThreadChannel ? channelContext.threadParentName : void 0;
|
|
759
703
|
const parentSlug = isThreadChannel ? channelContext.threadParentSlug : "";
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
const actorLabel = formatDiscordUserTag(user) || user.id;
|
|
765
|
-
const guildSlug = guildInfo?.slug || (data.guild?.name ? normalizeDiscordSlug(data.guild.name) : data.guild_id ?? (isGroupDm ? "group-dm" : "dm"));
|
|
766
|
-
const channelLabel = channelSlug ? `#${channelSlug}` : channelName ? `#${normalizeDiscordSlug(channelName)}` : `#${data.channel_id}`;
|
|
767
|
-
reactionBase = {
|
|
768
|
-
baseText: `Discord ${data.burst ? "super " : ""}reaction ${action}: ${emojiLabel} by ${actorLabel} on ${guildSlug} ${channelLabel} msg ${data.message_id}`,
|
|
769
|
-
contextKey: `discord:reaction:${action}:${data.message_id}:${user.id}:${emojiLabel}${data.burst ? ":burst" : ""}`
|
|
770
|
-
};
|
|
771
|
-
return reactionBase;
|
|
772
|
-
};
|
|
773
|
-
const emitReaction = (text, parentPeerId) => {
|
|
774
|
-
const { contextKey } = resolveReactionBase();
|
|
775
|
-
const route = resolveAgentRoute({
|
|
776
|
-
cfg: params.cfg,
|
|
777
|
-
channel: "discord",
|
|
778
|
-
accountId: params.accountId,
|
|
779
|
-
guildId: data.guild_id ?? void 0,
|
|
780
|
-
memberRoleIds,
|
|
781
|
-
peer: {
|
|
782
|
-
kind: isDirectMessage ? "direct" : isGroupDm ? "group" : "channel",
|
|
783
|
-
id: isDirectMessage ? user.id : data.channel_id
|
|
784
|
-
},
|
|
785
|
-
parentPeer: parentPeerId ? {
|
|
786
|
-
kind: "channel",
|
|
787
|
-
id: parentPeerId
|
|
788
|
-
} : void 0
|
|
789
|
-
});
|
|
790
|
-
enqueueRoutedSystemEvent(text, route, { contextKey });
|
|
791
|
-
};
|
|
792
|
-
const shouldNotifyReaction = (options) => shouldEmitDiscordReactionNotification({
|
|
793
|
-
mode: options.mode,
|
|
794
|
-
botId: botUserId,
|
|
795
|
-
messageAuthorId: options.messageAuthorId,
|
|
796
|
-
userId: user.id,
|
|
797
|
-
userName: user.username,
|
|
798
|
-
userTag: formatDiscordUserTag(user),
|
|
799
|
-
channelConfig: options.channelConfig,
|
|
800
|
-
guildInfo,
|
|
801
|
-
memberRoleIds,
|
|
802
|
-
allowNameMatching: params.allowNameMatching
|
|
803
|
-
});
|
|
804
|
-
const emitReactionWithAuthor = (message) => {
|
|
805
|
-
const { baseText } = resolveReactionBase();
|
|
806
|
-
const authorLabel = message?.author ? formatDiscordUserTag(message.author) : void 0;
|
|
807
|
-
const text = authorLabel ? `${baseText} from ${authorLabel}` : baseText;
|
|
808
|
-
emitReaction(text, parentId);
|
|
809
|
-
};
|
|
810
|
-
const resolveThreadChannelConfig = () => resolveDiscordChannelConfigWithFallback({
|
|
704
|
+
if (isThreadChannel && reactionMode === "off") return;
|
|
705
|
+
let message = null;
|
|
706
|
+
if (isThreadChannel && reactionMode === "own") message = await data.message.fetch().catch(() => null);
|
|
707
|
+
const channelConfig = resolveDiscordChannelConfigWithFallback({
|
|
811
708
|
guildInfo,
|
|
812
709
|
channelId: data.channel_id,
|
|
813
710
|
channelName,
|
|
@@ -815,54 +712,51 @@ async function handleDiscordReactionEvent(params) {
|
|
|
815
712
|
parentId,
|
|
816
713
|
parentName,
|
|
817
714
|
parentSlug,
|
|
818
|
-
scope: "thread"
|
|
819
|
-
});
|
|
820
|
-
const authorizeReactionIngressForChannel = async (channelConfig) => await authorizeDiscordReactionIngress({
|
|
821
|
-
...reactionIngressBase,
|
|
822
|
-
channelConfig
|
|
715
|
+
scope: isThreadChannel ? "thread" : "channel"
|
|
823
716
|
});
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
access: await authorizeReactionIngressForChannel(channelConfig),
|
|
717
|
+
if (isGuildMessage || isThreadChannel) {
|
|
718
|
+
if (!(await authorizeDiscordReactionIngress({
|
|
719
|
+
...reactionIngressBase,
|
|
828
720
|
channelConfig
|
|
829
|
-
};
|
|
830
|
-
};
|
|
831
|
-
if (isThreadChannel) {
|
|
832
|
-
await handleDiscordThreadReactionNotification({
|
|
833
|
-
reactionMode,
|
|
834
|
-
message: data.message,
|
|
835
|
-
parentId,
|
|
836
|
-
resolveThreadChannelAccess,
|
|
837
|
-
shouldNotifyReaction,
|
|
838
|
-
resolveReactionBase,
|
|
839
|
-
emitReaction,
|
|
840
|
-
emitReactionWithAuthor
|
|
841
|
-
});
|
|
842
|
-
return;
|
|
721
|
+
})).allowed) return;
|
|
843
722
|
}
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
scope: "channel"
|
|
853
|
-
});
|
|
854
|
-
await handleDiscordChannelReactionNotification({
|
|
855
|
-
isGuildMessage,
|
|
856
|
-
reactionMode,
|
|
857
|
-
message: data.message,
|
|
723
|
+
if (!isThreadChannel && reactionMode === "own") message = await data.message.fetch().catch(() => null);
|
|
724
|
+
if (!shouldEmitDiscordReactionNotification({
|
|
725
|
+
mode: reactionMode,
|
|
726
|
+
botId: botUserId,
|
|
727
|
+
messageAuthorId: message?.author?.id,
|
|
728
|
+
userId: user.id,
|
|
729
|
+
userName: user.username,
|
|
730
|
+
userTag: formatDiscordUserTag(user),
|
|
858
731
|
channelConfig,
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
732
|
+
guildInfo,
|
|
733
|
+
memberRoleIds,
|
|
734
|
+
allowNameMatching: params.allowNameMatching
|
|
735
|
+
})) return;
|
|
736
|
+
const emojiLabel = formatDiscordReactionEmoji(data.emoji);
|
|
737
|
+
const actorLabel = formatDiscordUserTag(user) || user.id;
|
|
738
|
+
const guildSlug = guildInfo?.slug || (data.guild?.name ? normalizeDiscordSlug(data.guild.name) : data.guild_id ?? (isGroupDm ? "group-dm" : "dm"));
|
|
739
|
+
const channelLabel = channelSlug ? `#${channelSlug}` : channelName ? `#${normalizeDiscordSlug(channelName)}` : `#${data.channel_id}`;
|
|
740
|
+
const baseText = `Discord ${data.burst ? "super " : ""}reaction ${action}: ${emojiLabel} by ${actorLabel} on ${guildSlug} ${channelLabel} msg ${data.message_id}`;
|
|
741
|
+
const authorLabel = message?.author ? formatDiscordUserTag(message.author) : void 0;
|
|
742
|
+
const text = authorLabel ? `${baseText} from ${authorLabel}` : baseText;
|
|
743
|
+
const contextKey = `discord:reaction:${action}:${data.message_id}:${user.id}:${emojiLabel}${data.burst ? ":burst" : ""}`;
|
|
744
|
+
const route = resolveAgentRoute({
|
|
745
|
+
cfg: params.cfg,
|
|
746
|
+
channel: "discord",
|
|
747
|
+
accountId: params.accountId,
|
|
748
|
+
guildId: data.guild_id ?? void 0,
|
|
749
|
+
memberRoleIds,
|
|
750
|
+
peer: {
|
|
751
|
+
kind: isDirectMessage ? "direct" : isGroupDm ? "group" : "channel",
|
|
752
|
+
id: isDirectMessage ? user.id : data.channel_id
|
|
753
|
+
},
|
|
754
|
+
parentPeer: parentId ? {
|
|
755
|
+
kind: "channel",
|
|
756
|
+
id: parentId
|
|
757
|
+
} : void 0
|
|
865
758
|
});
|
|
759
|
+
enqueueRoutedSystemEvent(text, route, { contextKey });
|
|
866
760
|
} catch (err) {
|
|
867
761
|
params.logger.error(danger(`discord reaction handler failed: ${String(err)}`));
|
|
868
762
|
}
|
|
@@ -898,7 +792,7 @@ var DiscordInteractionListener = class extends InteractionCreateListener {
|
|
|
898
792
|
}
|
|
899
793
|
async handle(data, client) {
|
|
900
794
|
this.onEvent?.();
|
|
901
|
-
Promise.resolve().then(() => client.handleInteraction(data
|
|
795
|
+
Promise.resolve().then(() => client.handleInteraction(data)).catch((err) => {
|
|
902
796
|
(this.logger ?? discordEventQueueLog).error(danger(`discord interaction handler failed: ${String(err)}`));
|
|
903
797
|
});
|
|
904
798
|
}
|
|
@@ -1253,7 +1147,7 @@ var DiscordThreadDeleteListener = class extends ThreadDeleteListener {
|
|
|
1253
1147
|
event: this.type,
|
|
1254
1148
|
run: async () => {
|
|
1255
1149
|
const threadId = data.id;
|
|
1256
|
-
getThreadBindingManager(this.accountId)?.unbindThread({
|
|
1150
|
+
await getThreadBindingManager(this.accountId)?.unbindThread({
|
|
1257
1151
|
threadId,
|
|
1258
1152
|
reason: "thread-delete",
|
|
1259
1153
|
sendFarewell: false
|
|
@@ -1275,14 +1169,12 @@ var DiscordThreadDeleteListener = class extends ThreadDeleteListener {
|
|
|
1275
1169
|
};
|
|
1276
1170
|
//#endregion
|
|
1277
1171
|
//#region extensions/discord/src/internal/gateway-dispatch.ts
|
|
1278
|
-
function dispatchVoiceGatewayEvent(client,
|
|
1279
|
-
const guildId = readGuildId(
|
|
1172
|
+
function dispatchVoiceGatewayEvent(client, payload) {
|
|
1173
|
+
const guildId = readGuildId(payload.d);
|
|
1280
1174
|
if (!guildId) return;
|
|
1281
1175
|
const adapter = (client.getPlugin("voice")?.adapters)?.get(guildId);
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
if (type === voiceServerUpdate) adapter?.onVoiceServerUpdate?.(data);
|
|
1285
|
-
if (type === voiceStateUpdate) adapter?.onVoiceStateUpdate?.(data);
|
|
1176
|
+
if (payload.t === GatewayDispatchEvents.VoiceServerUpdate) adapter?.onVoiceServerUpdate?.(payload.d);
|
|
1177
|
+
if (payload.t === GatewayDispatchEvents.VoiceStateUpdate) adapter?.onVoiceStateUpdate?.(payload.d);
|
|
1286
1178
|
}
|
|
1287
1179
|
function mapGatewayDispatchData(client, type, data) {
|
|
1288
1180
|
const messageCreate = GatewayDispatchEvents.MessageCreate;
|
|
@@ -1513,10 +1405,8 @@ async function resolveAllowFromByUserAllowlist(params) {
|
|
|
1513
1405
|
function collectGuildUserEntries(guildEntries) {
|
|
1514
1406
|
const userEntries = /* @__PURE__ */ new Set();
|
|
1515
1407
|
for (const guild of Object.values(guildEntries)) {
|
|
1516
|
-
if (!guild || typeof guild !== "object") continue;
|
|
1517
1408
|
addAllowlistUserEntriesFromConfigEntry(userEntries, guild);
|
|
1518
|
-
const
|
|
1519
|
-
for (const channel of Object.values(channels)) addAllowlistUserEntriesFromConfigEntry(userEntries, channel);
|
|
1409
|
+
for (const channel of Object.values(guild.channels ?? {})) addAllowlistUserEntriesFromConfigEntry(userEntries, channel);
|
|
1520
1410
|
}
|
|
1521
1411
|
return userEntries;
|
|
1522
1412
|
}
|
|
@@ -1533,15 +1423,13 @@ async function resolveGuildEntriesByUserAllowlist(params) {
|
|
|
1533
1423
|
formatResolved: formatDiscordUserResolved,
|
|
1534
1424
|
formatUnresolved: formatDiscordUserUnresolved
|
|
1535
1425
|
});
|
|
1536
|
-
const nextGuilds = {
|
|
1537
|
-
|
|
1538
|
-
|
|
1426
|
+
const nextGuilds = patchAllowlistUsersInConfigEntries({
|
|
1427
|
+
entries: params.guildEntries,
|
|
1428
|
+
resolvedMap,
|
|
1429
|
+
strategy: "canonicalize"
|
|
1430
|
+
});
|
|
1431
|
+
for (const [guildKey, guildConfig] of Object.entries(nextGuilds)) {
|
|
1539
1432
|
const nextGuild = { ...guildConfig };
|
|
1540
|
-
const users = guildConfig.users;
|
|
1541
|
-
if (Array.isArray(users) && users.length > 0) nextGuild.users = canonicalizeAllowlistWithResolvedIds({
|
|
1542
|
-
existing: users,
|
|
1543
|
-
resolvedMap
|
|
1544
|
-
});
|
|
1545
1433
|
const channels = guildConfig.channels ?? {};
|
|
1546
1434
|
if (channels && typeof channels === "object") nextGuild.channels = patchAllowlistUsersInConfigEntries({
|
|
1547
1435
|
entries: channels,
|
|
@@ -1601,7 +1489,7 @@ function isDiscordTransportHostname(hostname) {
|
|
|
1601
1489
|
return DISCORD_DNS_HOSTS.some((target) => normalized === target || normalized.endsWith(`.${target}`));
|
|
1602
1490
|
}
|
|
1603
1491
|
function reorderLookupAddresses(addresses) {
|
|
1604
|
-
if (
|
|
1492
|
+
if (addresses.length < 2) return addresses;
|
|
1605
1493
|
const ipv4 = addresses.filter((entry) => entry.family === 4);
|
|
1606
1494
|
const ipv6 = addresses.filter((entry) => entry.family === 6);
|
|
1607
1495
|
if (ipv4.length === 0) return ipv6;
|
|
@@ -1654,13 +1542,9 @@ function createDiscordEndpointDnsLookup(endpointHostname) {
|
|
|
1654
1542
|
}
|
|
1655
1543
|
//#endregion
|
|
1656
1544
|
//#region extensions/discord/src/monitor/rest-fetch.ts
|
|
1545
|
+
const captureSdk$2 = proxyCaptureSdk;
|
|
1546
|
+
const fetchSdk = fetchRuntimeSdk;
|
|
1657
1547
|
const discordDnsLookup$1 = createDiscordDnsLookup();
|
|
1658
|
-
function createDirectDiscordRestDispatcher() {
|
|
1659
|
-
return new Agent({
|
|
1660
|
-
allowH2: false,
|
|
1661
|
-
connect: { lookup: discordDnsLookup$1 }
|
|
1662
|
-
});
|
|
1663
|
-
}
|
|
1664
1548
|
function createEnvProxyDiscordRestDispatcher(runtime) {
|
|
1665
1549
|
const envProxyOptions = resolveEnvHttpProxyAgentOptions();
|
|
1666
1550
|
if (!envProxyOptions) return;
|
|
@@ -1679,7 +1563,7 @@ function createDiscordRestFetchWithDispatcher(dispatcher) {
|
|
|
1679
1563
|
...init,
|
|
1680
1564
|
dispatcher
|
|
1681
1565
|
}).then((response) => {
|
|
1682
|
-
|
|
1566
|
+
captureSdk$2.captureHttpExchangeAsync?.({
|
|
1683
1567
|
url: resolveRequestUrl(input),
|
|
1684
1568
|
method: init?.method ?? "GET",
|
|
1685
1569
|
requestHeaders: init?.headers,
|
|
@@ -1687,7 +1571,7 @@ function createDiscordRestFetchWithDispatcher(dispatcher) {
|
|
|
1687
1571
|
response,
|
|
1688
1572
|
flowId: randomUUID(),
|
|
1689
1573
|
meta: { subsystem: "discord-rest" }
|
|
1690
|
-
});
|
|
1574
|
+
}).catch(() => {});
|
|
1691
1575
|
return response;
|
|
1692
1576
|
})));
|
|
1693
1577
|
}
|
|
@@ -1699,7 +1583,12 @@ function resolveDiscordRestFetch(proxyUrl, runtime) {
|
|
|
1699
1583
|
runtime.log?.("discord: rest proxy enabled");
|
|
1700
1584
|
return fetcher;
|
|
1701
1585
|
}
|
|
1702
|
-
return createDiscordRestFetchWithDispatcher(createEnvProxyDiscordRestDispatcher(runtime) ??
|
|
1586
|
+
return createDiscordRestFetchWithDispatcher(createEnvProxyDiscordRestDispatcher(runtime) ?? fetchSdk.createHttp1Agent?.({ connect: { lookup: discordDnsLookup$1 } }) ?? createHttp1EnvHttpProxyAgent({
|
|
1587
|
+
httpProxy: "",
|
|
1588
|
+
httpsProxy: "",
|
|
1589
|
+
noProxy: "*",
|
|
1590
|
+
connect: { lookup: discordDnsLookup$1 }
|
|
1591
|
+
}));
|
|
1703
1592
|
}
|
|
1704
1593
|
//#endregion
|
|
1705
1594
|
//#region extensions/discord/src/monitor/live-policy.ts
|
|
@@ -1847,6 +1736,13 @@ async function readDiscordInteractionPolicy(readPolicy) {
|
|
|
1847
1736
|
//#endregion
|
|
1848
1737
|
//#region extensions/discord/src/monitor/native-command-reply.ts
|
|
1849
1738
|
const DISCORD_EMPTY_VISIBLE_REPLY_WARNING = "⚠️ Command produced no visible reply.";
|
|
1739
|
+
function resolveDiscordInteractionReplyOptions(params) {
|
|
1740
|
+
return {
|
|
1741
|
+
textLimit: resolveTextChunkLimit(params.cfg, "discord", params.accountId, { fallbackLimit: 2e3 }),
|
|
1742
|
+
maxLinesPerMessage: resolveDiscordMaxLinesPerMessage(params),
|
|
1743
|
+
chunkMode: resolveChunkMode(params.cfg, "discord", params.accountId)
|
|
1744
|
+
};
|
|
1745
|
+
}
|
|
1850
1746
|
function isDiscordUnknownInteraction(error) {
|
|
1851
1747
|
if (!error || typeof error !== "object") return false;
|
|
1852
1748
|
const err = error;
|
|
@@ -1936,54 +1832,32 @@ async function deliverDiscordInteractionReply(params) {
|
|
|
1936
1832
|
if (!payloadDelivered) throw expiry;
|
|
1937
1833
|
throw createChannelPartialDeliveryError(expiry, { visibleReplySent: true });
|
|
1938
1834
|
};
|
|
1939
|
-
|
|
1940
|
-
const
|
|
1941
|
-
|
|
1942
|
-
|
|
1943
|
-
|
|
1944
|
-
|
|
1945
|
-
|
|
1946
|
-
|
|
1947
|
-
|
|
1948
|
-
const chunks = resolveTextChunksWithFallback(reply.text, chunkDiscordTextWithMode(reply.text, {
|
|
1949
|
-
maxChars: textLimit,
|
|
1950
|
-
maxLines: maxLinesPerMessage,
|
|
1951
|
-
chunkMode
|
|
1952
|
-
}));
|
|
1953
|
-
await sendMessage(chunks[0] ?? "", media, firstMessageComponents, firstMessageEmbeds);
|
|
1954
|
-
for (const chunk of chunks.slice(1)) {
|
|
1955
|
-
if (!chunk.trim()) continue;
|
|
1956
|
-
await sendMessage(chunk);
|
|
1957
|
-
}
|
|
1958
|
-
return payloadDelivered;
|
|
1959
|
-
}
|
|
1960
|
-
if (!reply.hasText && !firstMessageComponents && !firstMessageEmbeds) return false;
|
|
1835
|
+
const files = reply.hasMedia ? await Promise.all(reply.mediaUrls.map(async (url) => {
|
|
1836
|
+
const loaded = await loadWebMedia(url, { localRoots: params.mediaLocalRoots });
|
|
1837
|
+
return {
|
|
1838
|
+
name: loaded.fileName ?? "upload",
|
|
1839
|
+
data: loaded.buffer,
|
|
1840
|
+
contentType: loaded.contentType
|
|
1841
|
+
};
|
|
1842
|
+
})) : void 0;
|
|
1843
|
+
if (!files && !reply.hasText && !firstMessageComponents && !firstMessageEmbeds) return false;
|
|
1961
1844
|
const chunks = resolveTextChunksWithFallback(reply.text, chunkDiscordTextWithMode(reply.text, {
|
|
1962
1845
|
maxChars: textLimit,
|
|
1963
1846
|
maxLines: maxLinesPerMessage,
|
|
1964
1847
|
chunkMode
|
|
1965
1848
|
}));
|
|
1966
1849
|
if (chunks.length === 0) chunks.push("");
|
|
1967
|
-
for (const chunk of chunks) {
|
|
1968
|
-
|
|
1969
|
-
|
|
1850
|
+
for (const [index, chunk] of chunks.entries()) {
|
|
1851
|
+
const chunkFiles = index === 0 ? files : void 0;
|
|
1852
|
+
if (!chunk.trim() && !chunkFiles && !firstMessageComponents && !firstMessageEmbeds) continue;
|
|
1853
|
+
await sendMessage(chunk, chunkFiles, firstMessageComponents, firstMessageEmbeds);
|
|
1970
1854
|
}
|
|
1971
1855
|
return payloadDelivered;
|
|
1972
1856
|
}
|
|
1973
1857
|
//#endregion
|
|
1974
1858
|
//#region extensions/discord/src/monitor/native-command-route.ts
|
|
1975
1859
|
function resolveDiscordNativeInteractionRouteState(params) {
|
|
1976
|
-
const route = resolveDiscordBoundConversationRoute(
|
|
1977
|
-
cfg: params.cfg,
|
|
1978
|
-
accountId: params.accountId,
|
|
1979
|
-
guildId: params.guildId,
|
|
1980
|
-
memberRoleIds: params.memberRoleIds,
|
|
1981
|
-
isDirectMessage: params.isDirectMessage,
|
|
1982
|
-
isGroupDm: params.isGroupDm,
|
|
1983
|
-
directUserId: params.directUserId,
|
|
1984
|
-
conversationId: params.conversationId,
|
|
1985
|
-
parentConversationId: params.parentConversationId
|
|
1986
|
-
});
|
|
1860
|
+
const route = resolveDiscordBoundConversationRoute(params);
|
|
1987
1861
|
const configuredRoute = params.threadBinding == null ? resolveConfiguredBindingRoute({
|
|
1988
1862
|
cfg: params.cfg,
|
|
1989
1863
|
route,
|
|
@@ -2051,15 +1925,9 @@ async function dispatchDiscordNativeAgentReply(params) {
|
|
|
2051
1925
|
sessionKey: params.ctxPayload.CommandTargetSessionKey ?? params.effectiveRoute.sessionKey
|
|
2052
1926
|
},
|
|
2053
1927
|
mediaLocalRoots: params.mediaLocalRoots,
|
|
2054
|
-
|
|
2055
|
-
maxLinesPerMessage: resolveDiscordMaxLinesPerMessage({
|
|
2056
|
-
cfg: params.cfg,
|
|
2057
|
-
discordConfig: params.discordConfig,
|
|
2058
|
-
accountId: params.accountId
|
|
2059
|
-
}),
|
|
1928
|
+
...resolveDiscordInteractionReplyOptions(params),
|
|
2060
1929
|
preferFollowUp: params.preferFollowUp || didReply,
|
|
2061
|
-
responseEphemeral: params.responseEphemeral
|
|
2062
|
-
chunkMode: resolveChunkMode(params.cfg, "discord", params.accountId)
|
|
1930
|
+
responseEphemeral: params.responseEphemeral
|
|
2063
1931
|
});
|
|
2064
1932
|
didReply ||= payloadDelivered;
|
|
2065
1933
|
return payloadDelivered ? { visibleReplySent: true } : {
|
|
@@ -2105,11 +1973,7 @@ async function dispatchDiscordNativeAgentReply(params) {
|
|
|
2105
1973
|
content: DISCORD_EMPTY_VISIBLE_REPLY_WARNING,
|
|
2106
1974
|
ephemeral: true
|
|
2107
1975
|
};
|
|
2108
|
-
|
|
2109
|
-
await params.interaction.followUp(payload);
|
|
2110
|
-
return;
|
|
2111
|
-
}
|
|
2112
|
-
await params.interaction.reply(payload);
|
|
1976
|
+
await params.interaction[params.preferFollowUp ? "followUp" : "reply"](payload);
|
|
2113
1977
|
});
|
|
2114
1978
|
return dispatchResult;
|
|
2115
1979
|
}
|
|
@@ -2121,9 +1985,6 @@ function resolveDiscordSlashCommandConfig(raw) {
|
|
|
2121
1985
|
//#endregion
|
|
2122
1986
|
//#region extensions/discord/src/monitor/native-command-arg-ui.ts
|
|
2123
1987
|
const DISCORD_COMMAND_ARG_CUSTOM_ID_KEY = "cmdarg";
|
|
2124
|
-
function createCommandArgsWithValue(params) {
|
|
2125
|
-
return { values: { [params.argName]: params.value } };
|
|
2126
|
-
}
|
|
2127
1988
|
function buildDiscordCommandArgCustomId(params) {
|
|
2128
1989
|
return [
|
|
2129
1990
|
`${DISCORD_COMMAND_ARG_CUSTOM_ID_KEY}:command=${encodeCustomIdComponent(params.command)}`,
|
|
@@ -2168,46 +2029,33 @@ async function handleDiscordCommandArgInteraction(params) {
|
|
|
2168
2029
|
return;
|
|
2169
2030
|
}
|
|
2170
2031
|
if (await clearWithMessage(`⏳ Applying ${parsed.value}...`) === null) return;
|
|
2171
|
-
const commandArgs =
|
|
2172
|
-
argName: parsed.arg,
|
|
2173
|
-
value: parsed.value
|
|
2174
|
-
});
|
|
2032
|
+
const commandArgs = { values: { [parsed.arg]: parsed.value } };
|
|
2175
2033
|
const commandArgsWithRaw = {
|
|
2176
2034
|
...commandArgs,
|
|
2177
2035
|
raw: serializeCommandArgs(commandDefinition, commandArgs)
|
|
2178
2036
|
};
|
|
2179
2037
|
const prompt = buildCommandTextFromArgs(commandDefinition, commandArgsWithRaw);
|
|
2180
2038
|
await params.dispatchCommandInteraction({
|
|
2181
|
-
|
|
2039
|
+
...ctx,
|
|
2182
2040
|
interaction,
|
|
2183
2041
|
prompt,
|
|
2184
2042
|
command: commandDefinition,
|
|
2185
2043
|
commandArgs: commandArgsWithRaw,
|
|
2186
|
-
cfg: ctx.cfg,
|
|
2187
|
-
discordConfig: ctx.discordConfig,
|
|
2188
|
-
accountId: ctx.accountId,
|
|
2189
|
-
sessionPrefix: ctx.sessionPrefix,
|
|
2190
2044
|
preferFollowUp: true,
|
|
2191
|
-
threadBindings: ctx.threadBindings,
|
|
2192
2045
|
responseEphemeral: resolveDiscordSlashCommandConfig(ctx.discordConfig?.slashCommand).ephemeral,
|
|
2193
|
-
buildContext: ctx.buildContext,
|
|
2194
|
-
dispatchReplyFromConfig: ctx.dispatchReplyFromConfig,
|
|
2195
2046
|
pluginCommandDispatch: { kind: "non-plugin" }
|
|
2196
2047
|
});
|
|
2197
2048
|
}
|
|
2198
|
-
async function runDiscordCommandArgButton(params) {
|
|
2199
|
-
await handleDiscordCommandArgInteraction(params);
|
|
2200
|
-
}
|
|
2201
2049
|
var DiscordCommandArgButton = class extends Button {
|
|
2202
2050
|
constructor(params) {
|
|
2203
2051
|
super();
|
|
2204
|
-
this.
|
|
2052
|
+
this.params = params;
|
|
2205
2053
|
this.label = params.label;
|
|
2206
2054
|
this.customId = params.customId;
|
|
2207
|
-
this.
|
|
2055
|
+
this.style = params.style ?? ButtonStyle.Secondary;
|
|
2208
2056
|
}
|
|
2209
2057
|
async run(interaction, data) {
|
|
2210
|
-
await
|
|
2058
|
+
await handleDiscordCommandArgInteraction({
|
|
2211
2059
|
...this.params,
|
|
2212
2060
|
interaction,
|
|
2213
2061
|
data
|
|
@@ -2241,23 +2089,13 @@ function buildDiscordCommandArgMenu(params) {
|
|
|
2241
2089
|
components: rows
|
|
2242
2090
|
};
|
|
2243
2091
|
}
|
|
2244
|
-
var DiscordCommandArgFallbackButton = class extends Button {
|
|
2245
|
-
constructor(params) {
|
|
2246
|
-
super();
|
|
2247
|
-
this.params = params;
|
|
2248
|
-
this.label = "cmdarg";
|
|
2249
|
-
this.customId = "cmdarg:seed=1";
|
|
2250
|
-
}
|
|
2251
|
-
async run(interaction, data) {
|
|
2252
|
-
await runDiscordCommandArgButton({
|
|
2253
|
-
...this.params,
|
|
2254
|
-
interaction,
|
|
2255
|
-
data
|
|
2256
|
-
});
|
|
2257
|
-
}
|
|
2258
|
-
};
|
|
2259
2092
|
function createDiscordCommandArgFallbackButton$1(params) {
|
|
2260
|
-
return new
|
|
2093
|
+
return new DiscordCommandArgButton({
|
|
2094
|
+
...params,
|
|
2095
|
+
label: "cmdarg",
|
|
2096
|
+
customId: "cmdarg:seed=1",
|
|
2097
|
+
style: ButtonStyle.Primary
|
|
2098
|
+
});
|
|
2261
2099
|
}
|
|
2262
2100
|
//#endregion
|
|
2263
2101
|
//#region extensions/discord/src/monitor/inbound-context.ts
|
|
@@ -2286,15 +2124,13 @@ function buildDiscordGroupSystemPrompt(channelConfig) {
|
|
|
2286
2124
|
return channelConfig?.systemPrompt?.trim() || void 0;
|
|
2287
2125
|
}
|
|
2288
2126
|
function buildDiscordChannelStructuredContext(params) {
|
|
2289
|
-
if (!params.isGuild) return;
|
|
2290
|
-
|
|
2291
|
-
if (typeof params.channelTopic === "string" && params.channelTopic.trim().length > 0) entries.push({
|
|
2127
|
+
if (!params.isGuild || typeof params.channelTopic !== "string" || !params.channelTopic.trim()) return;
|
|
2128
|
+
return [{
|
|
2292
2129
|
label: "Discord channel metadata",
|
|
2293
2130
|
source: "discord",
|
|
2294
2131
|
type: "channel_metadata",
|
|
2295
2132
|
payload: { topic: params.channelTopic.trim() }
|
|
2296
|
-
}
|
|
2297
|
-
return entries.length > 0 ? entries : void 0;
|
|
2133
|
+
}];
|
|
2298
2134
|
}
|
|
2299
2135
|
function buildDiscordInboundAccessContext(params) {
|
|
2300
2136
|
return {
|
|
@@ -2502,9 +2338,7 @@ function createDiscordNativeCommandAuthority(params) {
|
|
|
2502
2338
|
}).senderIsOwner);
|
|
2503
2339
|
const commands = resolveDiscordNativeCommandAllowlistAccess({
|
|
2504
2340
|
cfg,
|
|
2505
|
-
accountId: params.accountId,
|
|
2506
2341
|
sender: params.sender,
|
|
2507
|
-
chatType: params.ctx.ChatType === "direct" ? "direct" : "channel",
|
|
2508
2342
|
guildId: params.guildId
|
|
2509
2343
|
});
|
|
2510
2344
|
return {
|
|
@@ -2574,10 +2408,7 @@ function resolveDiscordNativeCommandChannelAccessContext(params) {
|
|
|
2574
2408
|
const guild = params.guild ?? null;
|
|
2575
2409
|
const commandsAllowFromAccess = resolveDiscordNativeCommandAllowlistAccess({
|
|
2576
2410
|
cfg: params.cfg,
|
|
2577
|
-
accountId: params.accountId,
|
|
2578
2411
|
sender: params.sender,
|
|
2579
|
-
chatType: params.isDirectMessage ? "direct" : params.isThreadChannel ? "thread" : guild ? "channel" : "group",
|
|
2580
|
-
conversationId: params.rawChannelId || void 0,
|
|
2581
2412
|
guildId: guild?.id
|
|
2582
2413
|
});
|
|
2583
2414
|
const guildInfo = resolveDiscordGuildEntry({
|
|
@@ -2619,10 +2450,6 @@ async function resolveDiscordGuildNativeCommandAuthorized(params) {
|
|
|
2619
2450
|
sender: params.sender,
|
|
2620
2451
|
allowNameMatching: params.allowNameMatching
|
|
2621
2452
|
});
|
|
2622
|
-
const commandAllowlistAuthorizer = {
|
|
2623
|
-
configured: params.commandsAllowFromAccess.configured,
|
|
2624
|
-
allowed: params.commandsAllowFromAccess.allowed
|
|
2625
|
-
};
|
|
2626
2453
|
const ownerAuthorizer = {
|
|
2627
2454
|
configured: params.ownerAllowListConfigured,
|
|
2628
2455
|
allowed: params.ownerAllowed
|
|
@@ -2640,9 +2467,9 @@ async function resolveDiscordGuildNativeCommandAuthorized(params) {
|
|
|
2640
2467
|
ownerAuthorizer,
|
|
2641
2468
|
memberAuthorizer
|
|
2642
2469
|
];
|
|
2643
|
-
const authorizers = params.commandsAllowFromAccess.configured ? [
|
|
2470
|
+
const authorizers = params.commandsAllowFromAccess.configured ? [params.commandsAllowFromAccess] : fallbackAuthorizers;
|
|
2644
2471
|
return resolveCommandAuthorizedFromAuthorizers({
|
|
2645
|
-
useAccessGroups:
|
|
2472
|
+
useAccessGroups: true,
|
|
2646
2473
|
authorizers,
|
|
2647
2474
|
modeWhenAccessGroupsOff: "configured"
|
|
2648
2475
|
});
|
|
@@ -2678,38 +2505,25 @@ async function resolveDiscordNativeAutocompleteAuthorized(params) {
|
|
|
2678
2505
|
hasGuild: Boolean(interaction.guild),
|
|
2679
2506
|
channelIdFallback: interaction.rawData.channel_id ?? ""
|
|
2680
2507
|
});
|
|
2681
|
-
const { isDirectMessage, isGroupDm, isThreadChannel, channelName, channelSlug, rawChannelId, threadParentId
|
|
2508
|
+
const { isDirectMessage, isGroupDm, isThreadChannel, channelName, channelSlug, rawChannelId, threadParentId } = channelContext;
|
|
2682
2509
|
if (params.isPolicyCurrent?.() === false) return false;
|
|
2683
2510
|
const memberRoleIds = Array.isArray(interaction.rawData.member?.roles) ? interaction.rawData.member.roles.map((roleId) => roleId) : [];
|
|
2684
2511
|
const allowNameMatching = isDangerousNameMatchingEnabled(discordConfig);
|
|
2685
|
-
const useAccessGroups = true;
|
|
2686
2512
|
const configuredDmAllowFrom = resolveDiscordAccountAllowFrom({
|
|
2687
2513
|
cfg,
|
|
2688
2514
|
accountId
|
|
2689
2515
|
}) ?? [];
|
|
2690
2516
|
const { ownerAllowList, ownerAllowed: ownerOk } = resolveDiscordOwnerAccess({
|
|
2691
2517
|
allowFrom: configuredDmAllowFrom,
|
|
2692
|
-
sender
|
|
2693
|
-
id: sender.id,
|
|
2694
|
-
name: sender.name,
|
|
2695
|
-
tag: sender.tag
|
|
2696
|
-
},
|
|
2518
|
+
sender,
|
|
2697
2519
|
allowNameMatching
|
|
2698
2520
|
});
|
|
2699
2521
|
const { commandsAllowFromAccess, guildInfo, channelConfig } = resolveDiscordNativeCommandChannelAccessContext({
|
|
2700
2522
|
cfg,
|
|
2701
2523
|
discordConfig,
|
|
2702
|
-
accountId,
|
|
2703
2524
|
sender,
|
|
2704
|
-
|
|
2705
|
-
|
|
2706
|
-
guild: interaction.guild ?? null,
|
|
2707
|
-
rawChannelId,
|
|
2708
|
-
channelName,
|
|
2709
|
-
channelSlug,
|
|
2710
|
-
threadParentId,
|
|
2711
|
-
threadParentName,
|
|
2712
|
-
threadParentSlug
|
|
2525
|
+
...channelContext,
|
|
2526
|
+
guild: interaction.guild ?? null
|
|
2713
2527
|
});
|
|
2714
2528
|
if (channelConfig?.enabled === false) return false;
|
|
2715
2529
|
if (interaction.guild && channelConfig?.allowed === false) return false;
|
|
@@ -2736,11 +2550,7 @@ async function resolveDiscordNativeAutocompleteAuthorized(params) {
|
|
|
2736
2550
|
accountId,
|
|
2737
2551
|
dmPolicy,
|
|
2738
2552
|
configuredAllowFrom: configuredDmAllowFrom,
|
|
2739
|
-
sender
|
|
2740
|
-
id: sender.id,
|
|
2741
|
-
name: sender.name,
|
|
2742
|
-
tag: sender.tag
|
|
2743
|
-
},
|
|
2553
|
+
sender,
|
|
2744
2554
|
allowNameMatching,
|
|
2745
2555
|
cfg,
|
|
2746
2556
|
rest: interaction.client.rest
|
|
@@ -2758,9 +2568,7 @@ async function resolveDiscordNativeAutocompleteAuthorized(params) {
|
|
|
2758
2568
|
if (!isDirectMessage) {
|
|
2759
2569
|
if (!await resolveDiscordGuildNativeCommandAuthorized({
|
|
2760
2570
|
cfg,
|
|
2761
|
-
accountId,
|
|
2762
2571
|
discordConfig,
|
|
2763
|
-
useAccessGroups,
|
|
2764
2572
|
commandsAllowFromAccess,
|
|
2765
2573
|
guildInfo,
|
|
2766
2574
|
channelConfig,
|
|
@@ -2836,14 +2644,11 @@ function openPreferenceStore(env) {
|
|
|
2836
2644
|
...env ? { env } : {}
|
|
2837
2645
|
});
|
|
2838
2646
|
}
|
|
2839
|
-
function normalizeId(value) {
|
|
2840
|
-
return normalizeOptionalString(value) ?? "";
|
|
2841
|
-
}
|
|
2842
2647
|
function buildDiscordModelPickerPreferenceKey(scope) {
|
|
2843
|
-
const userId =
|
|
2648
|
+
const userId = normalizeOptionalString(scope.userId);
|
|
2844
2649
|
if (!userId) return null;
|
|
2845
2650
|
const accountId = normalizeAccountId(scope.accountId);
|
|
2846
|
-
const guildId =
|
|
2651
|
+
const guildId = normalizeOptionalString(scope.guildId);
|
|
2847
2652
|
if (guildId) return `discord:${accountId}:guild:${guildId}:user:${userId}`;
|
|
2848
2653
|
return `discord:${accountId}:dm:user:${userId}`;
|
|
2849
2654
|
}
|
|
@@ -2863,6 +2668,12 @@ function sanitizeStoredPreferenceEntry(value) {
|
|
|
2863
2668
|
function timestampOrder(value) {
|
|
2864
2669
|
return value !== void 0 && value >= 0 ? value : 0;
|
|
2865
2670
|
}
|
|
2671
|
+
function scopedPreferenceEntries(entries, scopeKey) {
|
|
2672
|
+
return entries.map((entry) => ({
|
|
2673
|
+
key: entry.key,
|
|
2674
|
+
value: sanitizeStoredPreferenceEntry(entry.value)
|
|
2675
|
+
})).filter((entry) => entry.value?.scopeKey === scopeKey);
|
|
2676
|
+
}
|
|
2866
2677
|
function comparePreferenceEntries(left, right) {
|
|
2867
2678
|
return preferenceTimestampMs(right.value.updatedAt) - preferenceTimestampMs(left.value.updatedAt) || timestampOrder(right.value.updatedOrder) - timestampOrder(left.value.updatedOrder) || left.key.localeCompare(right.key);
|
|
2868
2679
|
}
|
|
@@ -2881,10 +2692,7 @@ async function readDiscordModelPickerRecentModels(params) {
|
|
|
2881
2692
|
if (!key) return [];
|
|
2882
2693
|
const limit = Math.max(1, Math.min(params.limit ?? DEFAULT_RECENT_LIMIT, 10));
|
|
2883
2694
|
try {
|
|
2884
|
-
const recent = (await openPreferenceStore(params.env).entries()).map((entry) =>
|
|
2885
|
-
key: entry.key,
|
|
2886
|
-
value: sanitizeStoredPreferenceEntry(entry.value)
|
|
2887
|
-
})).filter((entry) => entry.value?.scopeKey === key).toSorted(comparePreferenceEntries).map((entry) => entry.value.modelRef);
|
|
2695
|
+
const recent = scopedPreferenceEntries(await openPreferenceStore(params.env).entries(), key).toSorted(comparePreferenceEntries).map((entry) => entry.value.modelRef);
|
|
2888
2696
|
if (!params.allowedModelRefs || params.allowedModelRefs.size === 0) return sanitizeRecentModels(recent, limit);
|
|
2889
2697
|
return sanitizeRecentModels(recent.filter((modelRef) => params.allowedModelRefs?.has(modelRef)), limit);
|
|
2890
2698
|
} catch {
|
|
@@ -2897,17 +2705,14 @@ async function recordDiscordModelPickerRecentModel(params) {
|
|
|
2897
2705
|
if (!key || !normalizedModelRef) return;
|
|
2898
2706
|
try {
|
|
2899
2707
|
const store = openPreferenceStore(params.env);
|
|
2900
|
-
const timestamp = nextPreferenceTimestamp((await store.entries()).map((entry) =>
|
|
2708
|
+
const timestamp = nextPreferenceTimestamp(scopedPreferenceEntries(await store.entries(), key).map((entry) => entry.value));
|
|
2901
2709
|
await store.register(buildPreferenceModelKey(key, normalizedModelRef), {
|
|
2902
2710
|
scopeKey: key,
|
|
2903
2711
|
modelRef: normalizedModelRef,
|
|
2904
2712
|
...timestamp
|
|
2905
2713
|
});
|
|
2906
2714
|
const limit = Math.max(1, Math.min(params.limit ?? DEFAULT_RECENT_LIMIT, 10));
|
|
2907
|
-
const scopedEntries = (await store.entries()).
|
|
2908
|
-
key: entry.key,
|
|
2909
|
-
value: sanitizeStoredPreferenceEntry(entry.value)
|
|
2910
|
-
})).filter((entry) => entry.value?.scopeKey === key).toSorted(comparePreferenceEntries);
|
|
2715
|
+
const scopedEntries = scopedPreferenceEntries(await store.entries(), key).toSorted(comparePreferenceEntries);
|
|
2911
2716
|
await Promise.all(scopedEntries.slice(limit).map((entry) => store.delete(entry.key)));
|
|
2912
2717
|
} catch {}
|
|
2913
2718
|
}
|
|
@@ -2950,11 +2755,6 @@ const PICKER_VIEWS = [
|
|
|
2950
2755
|
"models",
|
|
2951
2756
|
"recents"
|
|
2952
2757
|
];
|
|
2953
|
-
/**
|
|
2954
|
-
* Alpha buckets engage only when the sorted item list exceeds the single-page
|
|
2955
|
-
* select cap. Below this threshold the user gets the existing flat list +
|
|
2956
|
-
* prev/next behavior unchanged.
|
|
2957
|
-
*/
|
|
2958
2758
|
const DISCORD_MODEL_PICKER_BUCKET_THRESHOLD = DISCORD_COMPONENT_MAX_SELECT_OPTIONS;
|
|
2959
2759
|
/** Target items per alpha bucket. Discord caps selects at 25 options. */
|
|
2960
2760
|
const DISCORD_MODEL_PICKER_BUCKET_TARGET_SIZE = 20;
|
|
@@ -2976,9 +2776,7 @@ function isValidPickerView(value) {
|
|
|
2976
2776
|
return PICKER_VIEWS.includes(value);
|
|
2977
2777
|
}
|
|
2978
2778
|
function normalizeModelPickerPage(value) {
|
|
2979
|
-
|
|
2980
|
-
if (!Number.isFinite(numeric)) return 1;
|
|
2981
|
-
return Math.max(1, Math.floor(numeric));
|
|
2779
|
+
return normalizeOptionalModelPickerIndex(value) ?? 1;
|
|
2982
2780
|
}
|
|
2983
2781
|
function parseRawPage(value) {
|
|
2984
2782
|
if (typeof value === "number") return normalizeModelPickerPage(value);
|
|
@@ -3109,17 +2907,6 @@ function parseDiscordModelPickerData(data) {
|
|
|
3109
2907
|
...modelBucketRaw ? { modelBucket: modelBucketRaw } : {}
|
|
3110
2908
|
};
|
|
3111
2909
|
}
|
|
3112
|
-
/**
|
|
3113
|
-
* Split a sorted item list into letter-range buckets when its length exceeds
|
|
3114
|
-
* {@link DISCORD_MODEL_PICKER_BUCKET_THRESHOLD}. Items below the threshold
|
|
3115
|
-
* return a single "All" bucket so callers can render the same code path.
|
|
3116
|
-
*
|
|
3117
|
-
* The boundary extender keeps items sharing the same starting letter inside
|
|
3118
|
-
* the same bucket — selecting "A–G" never strands a stray "g" item in the
|
|
3119
|
-
* next bucket. If every item shares a first letter (e.g. all `qwen3-*`),
|
|
3120
|
-
* the function falls back to count-based numeric chunks so the user still
|
|
3121
|
-
* gets a finite-cardinality picker.
|
|
3122
|
-
*/
|
|
3123
2910
|
function computeAlphaBuckets(sortedItems) {
|
|
3124
2911
|
if (sortedItems.length === 0) return [];
|
|
3125
2912
|
if (sortedItems.length <= DISCORD_MODEL_PICKER_BUCKET_THRESHOLD) return [{
|
|
@@ -3154,16 +2941,8 @@ function computeAlphaBuckets(sortedItems) {
|
|
|
3154
2941
|
}
|
|
3155
2942
|
return buckets;
|
|
3156
2943
|
}
|
|
3157
|
-
/**
|
|
3158
|
-
* Pick the per-bucket target size such that the resulting bucket count never
|
|
3159
|
-
* exceeds {@link DISCORD_COMPONENT_MAX_SELECT_OPTIONS} (Discord's hard select
|
|
3160
|
-
* cap). Stays at the default {@link DISCORD_MODEL_PICKER_BUCKET_TARGET_SIZE}
|
|
3161
|
-
* for typical inputs and grows linearly for very large lists.
|
|
3162
|
-
*/
|
|
3163
2944
|
function computeBucketTargetSize(totalItems) {
|
|
3164
|
-
|
|
3165
|
-
const capByBucketCount = Math.ceil(totalItems / DISCORD_COMPONENT_MAX_SELECT_OPTIONS);
|
|
3166
|
-
return Math.max(minTarget, capByBucketCount);
|
|
2945
|
+
return Math.max(DISCORD_MODEL_PICKER_BUCKET_TARGET_SIZE, Math.ceil(totalItems / DISCORD_COMPONENT_MAX_SELECT_OPTIONS));
|
|
3167
2946
|
}
|
|
3168
2947
|
function chunkBucketsByCount(sortedItems) {
|
|
3169
2948
|
const buckets = [];
|
|
@@ -3179,37 +2958,15 @@ function chunkBucketsByCount(sortedItems) {
|
|
|
3179
2958
|
}
|
|
3180
2959
|
return buckets;
|
|
3181
2960
|
}
|
|
3182
|
-
/**
|
|
3183
|
-
* Resolve a bucket from a list given a (possibly user-supplied) bucket id.
|
|
3184
|
-
* Falls back to the first bucket when the id does not match — mirrors the
|
|
3185
|
-
* "bad customId → reset to defaults" semantics already used for other
|
|
3186
|
-
* state fields.
|
|
3187
|
-
*/
|
|
3188
2961
|
function resolveBucket(buckets, id) {
|
|
3189
|
-
|
|
3190
|
-
if (!id) return expectDefined(buckets.at(0), "non-empty model picker buckets");
|
|
3191
|
-
return buckets.find((bucket) => bucket.id === id) ?? expectDefined(buckets.at(0), "non-empty model picker buckets");
|
|
2962
|
+
return buckets.find((bucket) => bucket.id === id) ?? buckets[0] ?? null;
|
|
3192
2963
|
}
|
|
3193
|
-
/**
|
|
3194
|
-
* Derive the alpha-bucket id that contains a given provider id. Returns
|
|
3195
|
-
* `undefined` when bucketing is inactive (all providers fit in one bucket)
|
|
3196
|
-
* or the provider is unknown. Used by the interaction handler to recompute
|
|
3197
|
-
* `providerBucket` at re-render time without forcing every customId to
|
|
3198
|
-
* carry the bucket field — the bucket is a pure function of the provider
|
|
3199
|
-
* list + provider id.
|
|
3200
|
-
*/
|
|
3201
2964
|
function findProviderBucketId(data, provider) {
|
|
3202
2965
|
return findProviderBucketLocation(data, provider)?.bucket;
|
|
3203
2966
|
}
|
|
3204
2967
|
function findProviderBucketLocation(data, provider) {
|
|
3205
2968
|
return findModelPickerBucketLocation([...data.providers].toSorted(), normalizeProviderId(provider));
|
|
3206
2969
|
}
|
|
3207
|
-
/**
|
|
3208
|
-
* Derive the alpha-bucket id that contains a given model id within the
|
|
3209
|
-
* named provider. Same rationale as {@link findProviderBucketId} — saves
|
|
3210
|
-
* customId budget by recomputing the bucket from the durable state
|
|
3211
|
-
* (provider + model) rather than carrying it as a parameter.
|
|
3212
|
-
*/
|
|
3213
2970
|
function findModelBucketId(data, provider, model) {
|
|
3214
2971
|
const modelSet = data.byProvider.get(normalizeProviderId(provider));
|
|
3215
2972
|
return modelSet ? findModelPickerBucketLocation([...modelSet].toSorted(compareBucketItems), model)?.bucket : void 0;
|
|
@@ -3317,14 +3074,6 @@ function createModelSelect(params) {
|
|
|
3317
3074
|
}
|
|
3318
3075
|
return new DiscordModelPickerSelect();
|
|
3319
3076
|
}
|
|
3320
|
-
/**
|
|
3321
|
-
* Build the alpha-bucket select row that appears above the provider/model
|
|
3322
|
-
* surface when the list exceeds {@link DISCORD_MODEL_PICKER_BUCKET_THRESHOLD}.
|
|
3323
|
-
*
|
|
3324
|
-
* Selecting a bucket emits action=bucket. The chosen bucket travels in the
|
|
3325
|
-
* select value, while the custom_id carries only the stable context needed to
|
|
3326
|
-
* rebuild the picker under Discord's 100-character custom_id limit.
|
|
3327
|
-
*/
|
|
3328
3077
|
function buildBucketSelectRow(params) {
|
|
3329
3078
|
if (params.buckets.length <= 1) return null;
|
|
3330
3079
|
const options = params.buckets.map((bucket) => ({
|
|
@@ -3358,11 +3107,6 @@ function resolveExplicitRuntimeState(params) {
|
|
|
3358
3107
|
const runtime = params.pendingRuntime?.trim() || params.currentRuntime?.trim();
|
|
3359
3108
|
return runtime && runtime !== "auto" && runtime !== "default" ? runtime : void 0;
|
|
3360
3109
|
}
|
|
3361
|
-
function resolveSelectedRuntime(params) {
|
|
3362
|
-
const choices = getRuntimeChoices(params);
|
|
3363
|
-
const explicit = resolveExplicitRuntimeState(params);
|
|
3364
|
-
return explicit ? choices?.find((choice) => choice.id === explicit)?.id : choices?.[0]?.id;
|
|
3365
|
-
}
|
|
3366
3110
|
function getActiveBucketId(bucket) {
|
|
3367
3111
|
return bucket && bucket.id !== "all" ? bucket.id : void 0;
|
|
3368
3112
|
}
|
|
@@ -3398,18 +3142,18 @@ function buildRenderedShell(params) {
|
|
|
3398
3142
|
return { components: [new Container(containerComponents)] };
|
|
3399
3143
|
}
|
|
3400
3144
|
function buildProviderSelectRow(params) {
|
|
3401
|
-
if (params.page.items.length === 0) return null;
|
|
3402
3145
|
const options = params.page.items.map((provider) => ({
|
|
3403
3146
|
label: provider.id,
|
|
3404
3147
|
value: provider.id,
|
|
3405
3148
|
default: provider.id === params.currentProvider,
|
|
3406
|
-
description: `${provider.count} ${provider.count === 1 ? "model" : "models"}`
|
|
3149
|
+
...params.showModelCounts ? { description: `${provider.count} ${provider.count === 1 ? "model" : "models"}` } : {}
|
|
3407
3150
|
}));
|
|
3408
3151
|
return new Row([createModelSelect({
|
|
3409
3152
|
customId: buildDiscordModelPickerCustomId({
|
|
3410
3153
|
command: params.command,
|
|
3411
3154
|
action: "provider",
|
|
3412
3155
|
view: "models",
|
|
3156
|
+
provider: params.provider,
|
|
3413
3157
|
page: params.page.page,
|
|
3414
3158
|
providerPage: params.page.page,
|
|
3415
3159
|
providerBucket: params.providerBucket,
|
|
@@ -3453,40 +3197,27 @@ function buildModelRows(params) {
|
|
|
3453
3197
|
page: params.providerPage,
|
|
3454
3198
|
bucket: params.providerBucket
|
|
3455
3199
|
});
|
|
3456
|
-
const providerOptions = providerPage.items.map((provider) => ({
|
|
3457
|
-
label: provider.id,
|
|
3458
|
-
value: provider.id,
|
|
3459
|
-
default: provider.id === params.modelPage.provider
|
|
3460
|
-
}));
|
|
3461
3200
|
const activeProviderBucket = getActiveBucketId(providerPage.bucket);
|
|
3462
3201
|
const activeModelBucket = getActiveBucketId(params.modelPage.bucket);
|
|
3463
|
-
if (!((params.modelPage.buckets?.length ?? 0) > 1)) rows.push(
|
|
3464
|
-
|
|
3465
|
-
|
|
3466
|
-
|
|
3467
|
-
|
|
3468
|
-
|
|
3469
|
-
|
|
3470
|
-
|
|
3471
|
-
providerBucket: activeProviderBucket,
|
|
3472
|
-
userId: params.userId
|
|
3473
|
-
}),
|
|
3474
|
-
options: providerOptions,
|
|
3475
|
-
placeholder: "Select provider"
|
|
3476
|
-
})]));
|
|
3202
|
+
if (!((params.modelPage.buckets?.length ?? 0) > 1)) rows.push(buildProviderSelectRow({
|
|
3203
|
+
command: params.command,
|
|
3204
|
+
userId: params.userId,
|
|
3205
|
+
page: providerPage,
|
|
3206
|
+
provider: params.modelPage.provider,
|
|
3207
|
+
currentProvider: params.modelPage.provider,
|
|
3208
|
+
providerBucket: activeProviderBucket
|
|
3209
|
+
}));
|
|
3477
3210
|
const runtimeChoices = getRuntimeChoices({
|
|
3478
3211
|
data: params.data,
|
|
3479
3212
|
provider: params.modelPage.provider,
|
|
3480
3213
|
modelRef: params.pendingModel ?? params.currentModel
|
|
3481
3214
|
});
|
|
3482
3215
|
const currentRuntime = parsedCurrentModel?.provider === params.modelPage.provider ? params.currentRuntime : void 0;
|
|
3483
|
-
const
|
|
3484
|
-
data: params.data,
|
|
3485
|
-
provider: params.modelPage.provider,
|
|
3486
|
-
modelRef: params.pendingModel ?? params.currentModel,
|
|
3216
|
+
const explicitRuntime = resolveExplicitRuntimeState({
|
|
3487
3217
|
currentRuntime,
|
|
3488
3218
|
pendingRuntime: params.pendingRuntime
|
|
3489
3219
|
});
|
|
3220
|
+
const selectedRuntime = explicitRuntime ? runtimeChoices?.find((choice) => choice.id === explicitRuntime)?.id : runtimeChoices?.[0]?.id;
|
|
3490
3221
|
const compactRuntime = resolveCompactRuntimeState({
|
|
3491
3222
|
currentRuntime,
|
|
3492
3223
|
pendingRuntime: params.pendingRuntime
|
|
@@ -3548,7 +3279,7 @@ function buildModelRows(params) {
|
|
|
3548
3279
|
providerPage: providerPage.page,
|
|
3549
3280
|
modelIndex: params.pendingModelIndex,
|
|
3550
3281
|
modelToken: pendingModelToken,
|
|
3551
|
-
modelBucket:
|
|
3282
|
+
modelBucket: activeModelBucket
|
|
3552
3283
|
});
|
|
3553
3284
|
if (modelNavRow) rows.push(modelNavRow);
|
|
3554
3285
|
const resolvedDefault = params.data.resolvedDefault;
|
|
@@ -3615,7 +3346,9 @@ function buildModelRows(params) {
|
|
|
3615
3346
|
}));
|
|
3616
3347
|
return {
|
|
3617
3348
|
rows,
|
|
3618
|
-
buttonRow: new Row(buttonRowItems)
|
|
3349
|
+
buttonRow: new Row(buttonRowItems),
|
|
3350
|
+
runtimeChoices,
|
|
3351
|
+
selectedRuntime
|
|
3619
3352
|
};
|
|
3620
3353
|
}
|
|
3621
3354
|
function renderDiscordModelPickerProvidersView(params) {
|
|
@@ -3634,15 +3367,15 @@ function renderDiscordModelPickerProvidersView(params) {
|
|
|
3634
3367
|
currentBucketId: page.bucket?.id
|
|
3635
3368
|
});
|
|
3636
3369
|
if (bucketRow) rows.push(bucketRow);
|
|
3637
|
-
const activeProviderBucket = page.bucket
|
|
3638
|
-
|
|
3370
|
+
const activeProviderBucket = getActiveBucketId(page.bucket);
|
|
3371
|
+
if (page.items.length > 0) rows.push(buildProviderSelectRow({
|
|
3639
3372
|
command: params.command,
|
|
3640
3373
|
userId: params.userId,
|
|
3641
3374
|
page,
|
|
3642
3375
|
currentProvider: parsedCurrent?.provider,
|
|
3643
|
-
providerBucket: activeProviderBucket
|
|
3644
|
-
|
|
3645
|
-
|
|
3376
|
+
providerBucket: activeProviderBucket,
|
|
3377
|
+
showModelCounts: true
|
|
3378
|
+
}));
|
|
3646
3379
|
const navRow = buildPaginationRow({
|
|
3647
3380
|
command: params.command,
|
|
3648
3381
|
userId: params.userId,
|
|
@@ -3692,19 +3425,10 @@ function renderDiscordModelPickerModelsView(params) {
|
|
|
3692
3425
|
footer: "Choose a different provider."
|
|
3693
3426
|
});
|
|
3694
3427
|
}
|
|
3695
|
-
const { rows: modelRows, buttonRow } = buildModelRows({
|
|
3696
|
-
|
|
3697
|
-
userId: params.userId,
|
|
3698
|
-
data: params.data,
|
|
3428
|
+
const { rows: modelRows, buttonRow, runtimeChoices: choices, selectedRuntime } = buildModelRows({
|
|
3429
|
+
...params,
|
|
3699
3430
|
providerPage,
|
|
3700
|
-
modelPage
|
|
3701
|
-
currentModel: params.currentModel,
|
|
3702
|
-
currentRuntime: params.currentRuntime,
|
|
3703
|
-
pendingModel: params.pendingModel,
|
|
3704
|
-
pendingModelIndex: params.pendingModelIndex,
|
|
3705
|
-
pendingRuntime: params.pendingRuntime,
|
|
3706
|
-
quickModels: params.quickModels,
|
|
3707
|
-
providerBucket: params.providerBucket
|
|
3431
|
+
modelPage
|
|
3708
3432
|
});
|
|
3709
3433
|
const pendingRuntime = params.pendingRuntime?.trim();
|
|
3710
3434
|
const rows = [];
|
|
@@ -3716,24 +3440,11 @@ function renderDiscordModelPickerModelsView(params) {
|
|
|
3716
3440
|
currentBucketId: modelPage.bucket?.id,
|
|
3717
3441
|
provider: modelPage.provider,
|
|
3718
3442
|
runtimeToken: pendingRuntime ? createDiscordModelPickerRuntimeToken(pendingRuntime) : void 0,
|
|
3719
|
-
providerPage
|
|
3720
|
-
providerBucket: params.providerBucket
|
|
3443
|
+
providerPage
|
|
3721
3444
|
});
|
|
3722
3445
|
if (bucketRow) rows.push(bucketRow);
|
|
3723
3446
|
rows.push(...modelRows);
|
|
3724
3447
|
const defaultModel = `${params.data.resolvedDefault.provider}/${params.data.resolvedDefault.model}`;
|
|
3725
|
-
const choices = getRuntimeChoices({
|
|
3726
|
-
data: params.data,
|
|
3727
|
-
provider: modelPage.provider,
|
|
3728
|
-
modelRef: params.pendingModel ?? params.currentModel
|
|
3729
|
-
});
|
|
3730
|
-
const selectedRuntime = resolveSelectedRuntime({
|
|
3731
|
-
data: params.data,
|
|
3732
|
-
provider: modelPage.provider,
|
|
3733
|
-
modelRef: params.pendingModel ?? params.currentModel,
|
|
3734
|
-
currentRuntime: parseCurrentModelRef(params.currentModel)?.provider === modelPage.provider ? params.currentRuntime : void 0,
|
|
3735
|
-
pendingRuntime: params.pendingRuntime
|
|
3736
|
-
});
|
|
3737
3448
|
const selectedRuntimeLabel = choices?.find((choice) => choice.id === selectedRuntime)?.label;
|
|
3738
3449
|
const pendingLine = !params.pendingModel ? "Select a model, then press Submit." : !supportsDiscordModelPickerRuntimeChoices() ? `Selected: ${params.pendingModel} (press Submit)` : choices === void 0 ? "Could not confirm how to run this model. Open /models to try again." : choices.length === 0 ? "This model cannot run with your current connections. Choose another model." : selectedRuntimeLabel ? `Selected: ${params.pendingModel} · ${selectedRuntimeLabel} (press Submit)` : "Choose how to run this model, then press Submit.";
|
|
3739
3450
|
const detailLines = [formatCurrentModelLine(params.currentModel), `Default: ${defaultModel}`];
|
|
@@ -3872,21 +3583,11 @@ async function applyDiscordModelPickerSelection(params) {
|
|
|
3872
3583
|
}
|
|
3873
3584
|
//#endregion
|
|
3874
3585
|
//#region extensions/discord/src/monitor/native-command-model-picker-ui.ts
|
|
3875
|
-
function resolveDiscordModelPickerCommandContext(command) {
|
|
3876
|
-
const normalized = normalizeLowercaseStringOrEmpty(command.nativeName ?? command.key);
|
|
3877
|
-
if (normalized === "model" || normalized === "models") return normalized;
|
|
3878
|
-
return null;
|
|
3879
|
-
}
|
|
3880
|
-
function resolveCommandArgStringValue(args, key) {
|
|
3881
|
-
const value = args?.values?.[key];
|
|
3882
|
-
if (typeof value !== "string") return "";
|
|
3883
|
-
return value.trim();
|
|
3884
|
-
}
|
|
3885
3586
|
function shouldOpenDiscordModelPickerFromCommand(params) {
|
|
3886
|
-
const context =
|
|
3887
|
-
if (
|
|
3587
|
+
const context = normalizeLowercaseStringOrEmpty(params.command.nativeName ?? params.command.key);
|
|
3588
|
+
if (context !== "model" && context !== "models") return null;
|
|
3888
3589
|
const serializedArgs = normalizeOptionalString(serializeCommandArgs(params.command, params.commandArgs)) ?? "";
|
|
3889
|
-
if (context === "model") return !
|
|
3590
|
+
if (context === "model") return !normalizeOptionalString(params.commandArgs?.values?.model) && !serializedArgs ? context : null;
|
|
3890
3591
|
return serializedArgs ? null : context;
|
|
3891
3592
|
}
|
|
3892
3593
|
function buildDiscordModelPickerAllowedModelRefs(data) {
|
|
@@ -3908,7 +3609,7 @@ function resolveDiscordModelPickerPreferenceScope(params) {
|
|
|
3908
3609
|
function buildDiscordModelPickerNoticePayload(message) {
|
|
3909
3610
|
return { components: [new Container([new TextDisplay(message)])] };
|
|
3910
3611
|
}
|
|
3911
|
-
async function
|
|
3612
|
+
async function resolveDiscordModelPickerRoute(params) {
|
|
3912
3613
|
const { interaction, cfg, accountId } = params;
|
|
3913
3614
|
const { isDirectMessage, isGroupDm, isThreadChannel, rawChannelId, threadParentId } = await resolveDiscordNativeInteractionChannelContext({
|
|
3914
3615
|
channel: interaction.channel,
|
|
@@ -3929,10 +3630,7 @@ async function resolveDiscordModelPickerRouteState(params) {
|
|
|
3929
3630
|
conversationId: rawChannelId,
|
|
3930
3631
|
parentConversationId: threadParentId,
|
|
3931
3632
|
threadBinding
|
|
3932
|
-
});
|
|
3933
|
-
}
|
|
3934
|
-
async function resolveDiscordModelPickerRoute(params) {
|
|
3935
|
-
return (await resolveDiscordModelPickerRouteState(params)).effectiveRoute;
|
|
3633
|
+
}).effectiveRoute;
|
|
3936
3634
|
}
|
|
3937
3635
|
async function resolveDiscordNativeChoiceContext(params) {
|
|
3938
3636
|
try {
|
|
@@ -4051,8 +3749,6 @@ async function replyWithDiscordModelPickerProviders(params) {
|
|
|
4051
3749
|
provider: initialProvider,
|
|
4052
3750
|
model: parsedCurrentRef.model
|
|
4053
3751
|
}) : { page: 1 };
|
|
4054
|
-
const initialPage = initialResolved.page;
|
|
4055
|
-
const initialModelBucket = initialResolved.bucket;
|
|
4056
3752
|
const initialProviderLocation = findProviderBucketLocation(data, initialProvider);
|
|
4057
3753
|
const payload = {
|
|
4058
3754
|
...renderDiscordModelPickerModelsView({
|
|
@@ -4060,10 +3756,10 @@ async function replyWithDiscordModelPickerProviders(params) {
|
|
|
4060
3756
|
userId: params.userId,
|
|
4061
3757
|
data,
|
|
4062
3758
|
provider: initialProvider,
|
|
4063
|
-
page:
|
|
3759
|
+
page: initialResolved.page,
|
|
4064
3760
|
providerPage: initialProviderLocation?.page ?? 1,
|
|
4065
3761
|
providerBucket: initialProviderLocation?.bucket,
|
|
4066
|
-
modelBucket:
|
|
3762
|
+
modelBucket: initialResolved.bucket,
|
|
4067
3763
|
currentModel,
|
|
4068
3764
|
currentRuntime,
|
|
4069
3765
|
quickModels
|
|
@@ -4071,11 +3767,7 @@ async function replyWithDiscordModelPickerProviders(params) {
|
|
|
4071
3767
|
ephemeral: true
|
|
4072
3768
|
};
|
|
4073
3769
|
await params.safeInteractionCall("model picker reply", async () => {
|
|
4074
|
-
|
|
4075
|
-
await params.interaction.followUp(payload);
|
|
4076
|
-
return;
|
|
4077
|
-
}
|
|
4078
|
-
await params.interaction.reply(payload);
|
|
3770
|
+
await params.interaction[params.preferFollowUp ? "followUp" : "reply"](payload);
|
|
4079
3771
|
});
|
|
4080
3772
|
}
|
|
4081
3773
|
function splitDiscordModelRef(modelRef) {
|
|
@@ -4093,11 +3785,7 @@ function splitDiscordModelRef(modelRef) {
|
|
|
4093
3785
|
//#endregion
|
|
4094
3786
|
//#region extensions/discord/src/monitor/native-command-model-picker-interaction.ts
|
|
4095
3787
|
function resolveModelPickerSelectionValue(interaction) {
|
|
4096
|
-
|
|
4097
|
-
if (!Array.isArray(rawValues) || rawValues.length === 0) return null;
|
|
4098
|
-
const first = rawValues[0];
|
|
4099
|
-
if (typeof first !== "string") return null;
|
|
4100
|
-
return first.trim() || null;
|
|
3788
|
+
return normalizeOptionalString(interaction.values?.[0]) ?? null;
|
|
4101
3789
|
}
|
|
4102
3790
|
function resolveRuntimeToken(choices, token) {
|
|
4103
3791
|
if (!token) return;
|
|
@@ -4164,15 +3852,11 @@ function resolveDiscordModelPickerModelRefByToken(data, modelToken) {
|
|
|
4164
3852
|
return matchingRefs.length === 1 ? matchingRefs[0] ?? null : null;
|
|
4165
3853
|
}
|
|
4166
3854
|
function resolveDiscordModelPickerModelIndex(params) {
|
|
4167
|
-
const
|
|
4168
|
-
|
|
4169
|
-
const index = models.indexOf(params.model);
|
|
4170
|
-
if (index < 0) return null;
|
|
4171
|
-
return index + 1;
|
|
3855
|
+
const index = listDiscordModelPickerProviderModels(params.data, params.provider).indexOf(params.model);
|
|
3856
|
+
return index < 0 ? null : index + 1;
|
|
4172
3857
|
}
|
|
4173
3858
|
function resolveDiscordModelPickerModelSelection(params) {
|
|
4174
3859
|
const models = listDiscordModelPickerProviderModels(params.data, params.provider);
|
|
4175
|
-
if (!models.length) return null;
|
|
4176
3860
|
if (params.modelToken) {
|
|
4177
3861
|
const matchingModels = models.filter((model) => createDiscordModelPickerModelToken(params.provider, model) === params.modelToken);
|
|
4178
3862
|
return matchingModels.length === 1 ? matchingModels[0] ?? null : null;
|
|
@@ -4191,10 +3875,8 @@ async function handleDiscordModelPickerInteraction(params) {
|
|
|
4191
3875
|
await params.safeInteractionCall("model picker ack", () => interaction.acknowledge());
|
|
4192
3876
|
return;
|
|
4193
3877
|
}
|
|
4194
|
-
|
|
4195
|
-
if (!deferredUpdate) {
|
|
3878
|
+
if (!interaction.acknowledged) {
|
|
4196
3879
|
if (await params.safeInteractionCall("model picker defer", () => interaction.acknowledge()) === null) return;
|
|
4197
|
-
deferredUpdate = true;
|
|
4198
3880
|
}
|
|
4199
3881
|
const cfg = getRuntimeConfigSnapshot() ?? ctx.cfg;
|
|
4200
3882
|
const requireModelToken = cfg !== ctx.cfg;
|
|
@@ -4232,7 +3914,7 @@ async function handleDiscordModelPickerInteraction(params) {
|
|
|
4232
3914
|
allowedModelRefs,
|
|
4233
3915
|
limit: 5
|
|
4234
3916
|
});
|
|
4235
|
-
const updatePicker = async (payload) => await params.safeInteractionCall("model picker update", () =>
|
|
3917
|
+
const updatePicker = async (payload) => await params.safeInteractionCall("model picker update", () => interaction.editReply(payload));
|
|
4236
3918
|
const showNotice = async (message) => await updatePicker(buildDiscordModelPickerNoticePayload(message));
|
|
4237
3919
|
const updateModelsView = async (provider, state = {}) => {
|
|
4238
3920
|
const rendered = renderDiscordModelPickerModelsView({
|
|
@@ -4299,15 +3981,16 @@ async function handleDiscordModelPickerInteraction(params) {
|
|
|
4299
3981
|
}));
|
|
4300
3982
|
return;
|
|
4301
3983
|
}
|
|
4302
|
-
if (parsed.action === "bucket"
|
|
3984
|
+
if (parsed.view === "models" && (parsed.action === "bucket" || parsed.action === "back")) {
|
|
4303
3985
|
const provider = resolveModelPickerProvider({
|
|
4304
3986
|
parsedProvider,
|
|
4305
3987
|
currentModelRef,
|
|
4306
3988
|
data: pickerData
|
|
4307
3989
|
});
|
|
3990
|
+
const selectingBucket = parsed.action === "bucket";
|
|
4308
3991
|
await updateModelsView(provider, {
|
|
4309
|
-
page: 1,
|
|
4310
|
-
modelBucket: resolveSelectedBucket(interaction),
|
|
3992
|
+
page: selectingBucket ? 1 : parsed.page,
|
|
3993
|
+
modelBucket: selectingBucket ? resolveSelectedBucket(interaction) : parsed.modelBucket,
|
|
4311
3994
|
pendingRuntime: resolvePendingRuntime({
|
|
4312
3995
|
data: pickerData,
|
|
4313
3996
|
provider,
|
|
@@ -4350,22 +4033,6 @@ async function handleDiscordModelPickerInteraction(params) {
|
|
|
4350
4033
|
});
|
|
4351
4034
|
return;
|
|
4352
4035
|
}
|
|
4353
|
-
if (parsed.action === "back" && parsed.view === "models") {
|
|
4354
|
-
const provider = resolveModelPickerProvider({
|
|
4355
|
-
parsedProvider,
|
|
4356
|
-
currentModelRef,
|
|
4357
|
-
data: pickerData
|
|
4358
|
-
});
|
|
4359
|
-
await updateModelsView(provider, {
|
|
4360
|
-
modelBucket: parsed.modelBucket,
|
|
4361
|
-
pendingRuntime: resolvePendingRuntime({
|
|
4362
|
-
data: pickerData,
|
|
4363
|
-
provider,
|
|
4364
|
-
parsed
|
|
4365
|
-
})
|
|
4366
|
-
});
|
|
4367
|
-
return;
|
|
4368
|
-
}
|
|
4369
4036
|
if (parsed.action === "provider") {
|
|
4370
4037
|
const selectedProvider = resolveModelPickerSelectionValue(interaction) ?? parsed.provider;
|
|
4371
4038
|
if (!selectedProvider || !pickerData.byProvider.has(selectedProvider)) {
|
|
@@ -4437,9 +4104,8 @@ async function handleDiscordModelPickerInteraction(params) {
|
|
|
4437
4104
|
provider,
|
|
4438
4105
|
model: selectedModel
|
|
4439
4106
|
}) : void 0;
|
|
4440
|
-
const currentModelOnly = splitDiscordModelRef(currentModelRef ?? "");
|
|
4441
4107
|
await updateModelsView(provider, {
|
|
4442
|
-
modelBucket: parsed.modelBucket ?? (selectedModel ? findModelBucketId(pickerData, provider, selectedModel) :
|
|
4108
|
+
modelBucket: parsed.modelBucket ?? (selectedModel ? findModelBucketId(pickerData, provider, selectedModel) : currentModel && currentModel.provider === provider ? findModelBucketId(pickerData, provider, currentModel.model) : void 0),
|
|
4443
4109
|
...pendingModel ? { pendingModel } : {},
|
|
4444
4110
|
pendingModelIndex: pendingModelIndex ?? void 0,
|
|
4445
4111
|
pendingRuntime: selectedRuntime
|
|
@@ -4545,45 +4211,38 @@ async function handleDiscordModelPickerInteraction(params) {
|
|
|
4545
4211
|
}
|
|
4546
4212
|
if (parsed.action === "cancel") await showNotice(`ℹ️ Model kept as ${currentModelRef ?? "default"}.`);
|
|
4547
4213
|
}
|
|
4548
|
-
async function runDiscordModelPickerFallback(params) {
|
|
4549
|
-
await handleDiscordModelPickerInteraction(params);
|
|
4550
|
-
}
|
|
4551
|
-
var DiscordModelPickerFallbackButton = class extends Button {
|
|
4552
|
-
constructor(params) {
|
|
4553
|
-
super();
|
|
4554
|
-
this.params = params;
|
|
4555
|
-
this.label = "modelpick";
|
|
4556
|
-
this.customId = `${DISCORD_MODEL_PICKER_CUSTOM_ID_KEY}:seed=btn`;
|
|
4557
|
-
}
|
|
4558
|
-
async run(interaction, data) {
|
|
4559
|
-
await runDiscordModelPickerFallback({
|
|
4560
|
-
...this.params,
|
|
4561
|
-
interaction,
|
|
4562
|
-
data
|
|
4563
|
-
});
|
|
4564
|
-
}
|
|
4565
|
-
};
|
|
4566
|
-
var DiscordModelPickerFallbackSelect = class extends StringSelectMenu {
|
|
4567
|
-
constructor(params) {
|
|
4568
|
-
super();
|
|
4569
|
-
this.params = params;
|
|
4570
|
-
this.customId = `${DISCORD_MODEL_PICKER_CUSTOM_ID_KEY}:seed=sel`;
|
|
4571
|
-
this.options = [];
|
|
4572
|
-
}
|
|
4573
|
-
async run(interaction, data) {
|
|
4574
|
-
await runDiscordModelPickerFallback({
|
|
4575
|
-
...this.params,
|
|
4576
|
-
interaction,
|
|
4577
|
-
data
|
|
4578
|
-
});
|
|
4579
|
-
}
|
|
4580
|
-
};
|
|
4581
4214
|
function createDiscordModelPickerFallbackButton$1(params) {
|
|
4582
|
-
return new
|
|
4215
|
+
return new class extends Button {
|
|
4216
|
+
constructor(..._args) {
|
|
4217
|
+
super(..._args);
|
|
4218
|
+
this.label = "modelpick";
|
|
4219
|
+
this.customId = `${DISCORD_MODEL_PICKER_CUSTOM_ID_KEY}:seed=btn`;
|
|
4220
|
+
}
|
|
4221
|
+
async run(interaction, data) {
|
|
4222
|
+
await handleDiscordModelPickerInteraction({
|
|
4223
|
+
...params,
|
|
4224
|
+
interaction,
|
|
4225
|
+
data
|
|
4226
|
+
});
|
|
4227
|
+
}
|
|
4228
|
+
}();
|
|
4583
4229
|
}
|
|
4584
4230
|
function createDiscordModelPickerFallbackSelect$1(params) {
|
|
4585
|
-
return new
|
|
4586
|
-
|
|
4231
|
+
return new class extends StringSelectMenu {
|
|
4232
|
+
constructor(..._args2) {
|
|
4233
|
+
super(..._args2);
|
|
4234
|
+
this.customId = `${DISCORD_MODEL_PICKER_CUSTOM_ID_KEY}:seed=sel`;
|
|
4235
|
+
this.options = [];
|
|
4236
|
+
}
|
|
4237
|
+
async run(interaction, data) {
|
|
4238
|
+
await handleDiscordModelPickerInteraction({
|
|
4239
|
+
...params,
|
|
4240
|
+
interaction,
|
|
4241
|
+
data
|
|
4242
|
+
});
|
|
4243
|
+
}
|
|
4244
|
+
}();
|
|
4245
|
+
}
|
|
4587
4246
|
//#endregion
|
|
4588
4247
|
//#region extensions/discord/src/monitor/native-command-status.ts
|
|
4589
4248
|
async function maybeDeliverDiscordDirectStatus(params) {
|
|
@@ -4603,15 +4262,9 @@ async function maybeDeliverDiscordDirectStatus(params) {
|
|
|
4603
4262
|
interaction: params.interaction,
|
|
4604
4263
|
payload: statusReply,
|
|
4605
4264
|
mediaLocalRoots: params.mediaLocalRoots,
|
|
4606
|
-
|
|
4607
|
-
maxLinesPerMessage: resolveDiscordMaxLinesPerMessage({
|
|
4608
|
-
cfg: params.cfg,
|
|
4609
|
-
discordConfig: params.discordConfig,
|
|
4610
|
-
accountId: params.accountId
|
|
4611
|
-
}),
|
|
4265
|
+
...resolveDiscordInteractionReplyOptions(params),
|
|
4612
4266
|
preferFollowUp: params.preferFollowUp,
|
|
4613
|
-
responseEphemeral: params.responseEphemeral
|
|
4614
|
-
chunkMode: resolveChunkMode(params.cfg, "discord", params.accountId)
|
|
4267
|
+
responseEphemeral: params.responseEphemeral
|
|
4615
4268
|
});
|
|
4616
4269
|
return {
|
|
4617
4270
|
accepted: true,
|
|
@@ -4631,9 +4284,9 @@ function readDiscordCommandArgs(interaction, definitions) {
|
|
|
4631
4284
|
const values = {};
|
|
4632
4285
|
for (const definition of definitions) {
|
|
4633
4286
|
let value;
|
|
4634
|
-
if (definition.type === "number") value = interaction.options.getNumber(definition.name)
|
|
4635
|
-
else if (definition.type === "boolean") value = interaction.options.getBoolean(definition.name)
|
|
4636
|
-
else value = interaction.options.getString(definition.name)
|
|
4287
|
+
if (definition.type === "number") value = interaction.options.getNumber(definition.name);
|
|
4288
|
+
else if (definition.type === "boolean") value = interaction.options.getBoolean(definition.name);
|
|
4289
|
+
else value = interaction.options.getString(definition.name);
|
|
4637
4290
|
if (value != null) values[definition.name] = value;
|
|
4638
4291
|
}
|
|
4639
4292
|
return Object.keys(values).length > 0 ? { values } : void 0;
|
|
@@ -4668,26 +4321,21 @@ function truncateDiscordCommandDescriptionLocalizations(params) {
|
|
|
4668
4321
|
label: `${params.label} locale:${locale}`
|
|
4669
4322
|
})]));
|
|
4670
4323
|
}
|
|
4671
|
-
function resolveDiscordCommandLogLabel(command) {
|
|
4672
|
-
if (typeof command.nativeName === "string" && command.nativeName.trim().length > 0) return command.nativeName;
|
|
4673
|
-
return command.key;
|
|
4674
|
-
}
|
|
4675
4324
|
function buildDiscordCommandOptions(params) {
|
|
4676
4325
|
const { command, cfg, resolveConfig, authorizeChoiceContext, resolveChoiceContext } = params;
|
|
4677
|
-
const commandLabel =
|
|
4326
|
+
const commandLabel = command.nativeName?.trim() ? command.nativeName : command.key;
|
|
4678
4327
|
const args = command.args;
|
|
4679
4328
|
if (!args || args.length === 0) return;
|
|
4680
4329
|
return args.map((arg) => {
|
|
4681
|
-
const
|
|
4682
|
-
if (arg.type === "number" || arg.type === "boolean") return {
|
|
4330
|
+
const base = {
|
|
4683
4331
|
name: arg.name,
|
|
4684
4332
|
description: truncateDiscordCommandDescription({
|
|
4685
4333
|
value: arg.description,
|
|
4686
4334
|
label: `command:${commandLabel} arg:${arg.name}`
|
|
4687
4335
|
}),
|
|
4688
|
-
|
|
4689
|
-
required
|
|
4336
|
+
required: arg.required ?? false
|
|
4690
4337
|
};
|
|
4338
|
+
if (arg.type === "number" || arg.type === "boolean") return Object.assign(base, { type: arg.type === "number" ? ApplicationCommandOptionType.Number : ApplicationCommandOptionType.Boolean });
|
|
4691
4339
|
const resolvedChoices = resolveCommandArgChoices({
|
|
4692
4340
|
command,
|
|
4693
4341
|
arg,
|
|
@@ -4728,17 +4376,11 @@ function buildDiscordCommandOptions(params) {
|
|
|
4728
4376
|
name: choice.label,
|
|
4729
4377
|
value: choice.value
|
|
4730
4378
|
})) : void 0;
|
|
4731
|
-
return {
|
|
4732
|
-
name: arg.name,
|
|
4733
|
-
description: truncateDiscordCommandDescription({
|
|
4734
|
-
value: arg.description,
|
|
4735
|
-
label: `command:${commandLabel} arg:${arg.name}`
|
|
4736
|
-
}),
|
|
4379
|
+
return Object.assign(base, {
|
|
4737
4380
|
type: ApplicationCommandOptionType.String,
|
|
4738
|
-
required,
|
|
4739
4381
|
choices,
|
|
4740
4382
|
autocomplete
|
|
4741
|
-
};
|
|
4383
|
+
});
|
|
4742
4384
|
});
|
|
4743
4385
|
}
|
|
4744
4386
|
//#endregion
|
|
@@ -4842,14 +4484,9 @@ async function dispatchDiscordCommandInteraction(params) {
|
|
|
4842
4484
|
...ephemeral !== void 0 ? { ephemeral } : {}
|
|
4843
4485
|
};
|
|
4844
4486
|
await safeDiscordInteractionCall("interaction reply", async () => {
|
|
4845
|
-
|
|
4846
|
-
await interaction.followUp(payload);
|
|
4847
|
-
return;
|
|
4848
|
-
}
|
|
4849
|
-
await interaction.reply(payload);
|
|
4487
|
+
await interaction[preferFollowUp ? "followUp" : "reply"](payload);
|
|
4850
4488
|
});
|
|
4851
4489
|
};
|
|
4852
|
-
const useAccessGroups = true;
|
|
4853
4490
|
const user = interaction.user;
|
|
4854
4491
|
if (!user) return { accepted: false };
|
|
4855
4492
|
const sender = resolveDiscordSenderIdentity({
|
|
@@ -4863,7 +4500,7 @@ async function dispatchDiscordCommandInteraction(params) {
|
|
|
4863
4500
|
hasGuild: Boolean(interaction.guild),
|
|
4864
4501
|
channelIdFallback: interaction.rawData.channel_id ?? ""
|
|
4865
4502
|
});
|
|
4866
|
-
const { isDirectMessage, isGroupDm, isThreadChannel, channelName, channelSlug, rawChannelId, threadParentId
|
|
4503
|
+
const { isDirectMessage, isGroupDm, isThreadChannel, channelName, channelSlug, rawChannelId, threadParentId } = channelContext;
|
|
4867
4504
|
if (policy?.isCurrent() === false) {
|
|
4868
4505
|
await respond("Access policy changed. Try this interaction again.", { ephemeral: true });
|
|
4869
4506
|
return { accepted: false };
|
|
@@ -4874,31 +4511,17 @@ async function dispatchDiscordCommandInteraction(params) {
|
|
|
4874
4511
|
cfg,
|
|
4875
4512
|
accountId
|
|
4876
4513
|
}) ?? [];
|
|
4877
|
-
const { ownerAllowList
|
|
4514
|
+
const { ownerAllowList, ownerAllowed } = resolveDiscordOwnerAccess({
|
|
4878
4515
|
allowFrom: configuredDmAllowFrom,
|
|
4879
|
-
sender
|
|
4880
|
-
id: sender.id,
|
|
4881
|
-
name: sender.name,
|
|
4882
|
-
tag: sender.tag
|
|
4883
|
-
},
|
|
4516
|
+
sender,
|
|
4884
4517
|
allowNameMatching
|
|
4885
4518
|
});
|
|
4886
|
-
const ownerAllowListConfigured = discordOwnerAllowList != null;
|
|
4887
|
-
const ownerOk = discordOwnerOk;
|
|
4888
4519
|
const { commandsAllowFromAccess, guildInfo, channelConfig } = resolveDiscordNativeCommandChannelAccessContext({
|
|
4889
4520
|
cfg,
|
|
4890
4521
|
discordConfig,
|
|
4891
|
-
accountId,
|
|
4892
4522
|
sender,
|
|
4893
|
-
|
|
4894
|
-
|
|
4895
|
-
guild: interaction.guild ?? null,
|
|
4896
|
-
rawChannelId,
|
|
4897
|
-
channelName,
|
|
4898
|
-
channelSlug,
|
|
4899
|
-
threadParentId,
|
|
4900
|
-
threadParentName,
|
|
4901
|
-
threadParentSlug
|
|
4523
|
+
...channelContext,
|
|
4524
|
+
guild: interaction.guild ?? null
|
|
4902
4525
|
});
|
|
4903
4526
|
let nativeRouteState;
|
|
4904
4527
|
const getNativeRouteState = () => nativeRouteState ??= nativeCommandRuntime.resolveDiscordNativeInteractionRouteState({
|
|
@@ -4960,11 +4583,7 @@ async function dispatchDiscordCommandInteraction(params) {
|
|
|
4960
4583
|
accountId,
|
|
4961
4584
|
dmPolicy,
|
|
4962
4585
|
configuredAllowFrom: configuredDmAllowFrom,
|
|
4963
|
-
sender
|
|
4964
|
-
id: sender.id,
|
|
4965
|
-
name: sender.name,
|
|
4966
|
-
tag: sender.tag
|
|
4967
|
-
},
|
|
4586
|
+
sender,
|
|
4968
4587
|
allowNameMatching,
|
|
4969
4588
|
cfg,
|
|
4970
4589
|
rest: interaction.client.rest
|
|
@@ -5012,17 +4631,15 @@ async function dispatchDiscordCommandInteraction(params) {
|
|
|
5012
4631
|
if (!isDirectMessage) {
|
|
5013
4632
|
commandAuthorized = await resolveDiscordGuildNativeCommandAuthorized({
|
|
5014
4633
|
cfg,
|
|
5015
|
-
accountId,
|
|
5016
4634
|
discordConfig,
|
|
5017
|
-
useAccessGroups,
|
|
5018
4635
|
commandsAllowFromAccess,
|
|
5019
4636
|
guildInfo,
|
|
5020
4637
|
channelConfig,
|
|
5021
4638
|
memberRoleIds,
|
|
5022
4639
|
sender,
|
|
5023
4640
|
allowNameMatching,
|
|
5024
|
-
ownerAllowListConfigured,
|
|
5025
|
-
ownerAllowed
|
|
4641
|
+
ownerAllowListConfigured: ownerAllowList != null,
|
|
4642
|
+
ownerAllowed
|
|
5026
4643
|
});
|
|
5027
4644
|
if (!commandAuthorized && !canBypassConfiguredAcpGuildGuards()) {
|
|
5028
4645
|
await respond("You are not authorized to use this command.", { ephemeral: true });
|
|
@@ -5130,15 +4747,7 @@ async function dispatchDiscordCommandInteraction(params) {
|
|
|
5130
4747
|
safeInteractionCall: safeDiscordInteractionCall,
|
|
5131
4748
|
dispatchCommandInteraction: dispatchDiscordCommandInteraction
|
|
5132
4749
|
});
|
|
5133
|
-
|
|
5134
|
-
await safeDiscordInteractionCall("interaction follow-up", () => interaction.followUp({
|
|
5135
|
-
content: menuPayload.content,
|
|
5136
|
-
components: menuPayload.components,
|
|
5137
|
-
ephemeral: true
|
|
5138
|
-
}));
|
|
5139
|
-
return { accepted: true };
|
|
5140
|
-
}
|
|
5141
|
-
await safeDiscordInteractionCall("interaction reply", () => interaction.reply({
|
|
4750
|
+
await safeDiscordInteractionCall(preferFollowUp ? "interaction follow-up" : "interaction reply", () => interaction[preferFollowUp ? "followUp" : "reply"]({
|
|
5142
4751
|
content: menuPayload.content,
|
|
5143
4752
|
components: menuPayload.components,
|
|
5144
4753
|
ephemeral: true
|
|
@@ -5194,15 +4803,13 @@ async function dispatchDiscordCommandInteraction(params) {
|
|
|
5194
4803
|
await deliverDiscordInteractionReply({
|
|
5195
4804
|
interaction,
|
|
5196
4805
|
payload: pluginReply,
|
|
5197
|
-
|
|
5198
|
-
maxLinesPerMessage: resolveDiscordMaxLinesPerMessage({
|
|
4806
|
+
...resolveDiscordInteractionReplyOptions({
|
|
5199
4807
|
cfg,
|
|
5200
4808
|
discordConfig,
|
|
5201
4809
|
accountId
|
|
5202
4810
|
}),
|
|
5203
4811
|
preferFollowUp,
|
|
5204
|
-
responseEphemeral
|
|
5205
|
-
chunkMode: resolveChunkMode(cfg, "discord", accountId)
|
|
4812
|
+
responseEphemeral
|
|
5206
4813
|
});
|
|
5207
4814
|
return {
|
|
5208
4815
|
accepted: true,
|
|
@@ -5460,7 +5067,7 @@ var GatewaySendLimiter = class {
|
|
|
5460
5067
|
shouldEmitOverflowWarning = true;
|
|
5461
5068
|
}
|
|
5462
5069
|
}
|
|
5463
|
-
this.outboundQueue.push(
|
|
5070
|
+
this.outboundQueue.push(serialized);
|
|
5464
5071
|
if (shouldEmitOverflowWarning) this.emitOverflowWarning({
|
|
5465
5072
|
droppedEvents: this.droppedEvents,
|
|
5466
5073
|
maxQueuedEvents: GATEWAY_SEND_QUEUE_LIMIT,
|
|
@@ -5517,9 +5124,9 @@ var GatewaySendLimiter = class {
|
|
|
5517
5124
|
flush() {
|
|
5518
5125
|
while (this.outboundQueue.length > 0 && this.canSend(Date.now())) {
|
|
5519
5126
|
const queued = this.outboundQueue.shift();
|
|
5520
|
-
if (
|
|
5127
|
+
if (queued === void 0) continue;
|
|
5521
5128
|
try {
|
|
5522
|
-
this.sendSerialized(queued
|
|
5129
|
+
this.sendSerialized(queued);
|
|
5523
5130
|
} catch (error) {
|
|
5524
5131
|
this.emitError(error instanceof Error ? error : new Error(String(error), { cause: error }));
|
|
5525
5132
|
this.clear();
|
|
@@ -5654,9 +5261,6 @@ var GatewayPlugin = class extends Plugin {
|
|
|
5654
5261
|
};
|
|
5655
5262
|
this.gatewayInfo = gatewayInfo;
|
|
5656
5263
|
}
|
|
5657
|
-
get ping() {
|
|
5658
|
-
return null;
|
|
5659
|
-
}
|
|
5660
5264
|
listVoiceChannelStates(guildId, channelId) {
|
|
5661
5265
|
return this.voiceStateCache.listVoiceChannelStates(guildId, channelId);
|
|
5662
5266
|
}
|
|
@@ -5690,8 +5294,8 @@ var GatewayPlugin = class extends Plugin {
|
|
|
5690
5294
|
this.connect(false);
|
|
5691
5295
|
}
|
|
5692
5296
|
connect(resume = false) {
|
|
5693
|
-
this.
|
|
5694
|
-
this.
|
|
5297
|
+
this.reconnectTimer.stop();
|
|
5298
|
+
this.heartbeatTimers.stop();
|
|
5695
5299
|
if (this.isConnecting) return;
|
|
5696
5300
|
this.shouldReconnect = true;
|
|
5697
5301
|
this.lastHeartbeatAck = true;
|
|
@@ -5704,8 +5308,8 @@ var GatewayPlugin = class extends Plugin {
|
|
|
5704
5308
|
}
|
|
5705
5309
|
disconnect() {
|
|
5706
5310
|
this.shouldReconnect = false;
|
|
5707
|
-
this.
|
|
5708
|
-
this.
|
|
5311
|
+
this.reconnectTimer.stop();
|
|
5312
|
+
this.heartbeatTimers.stop();
|
|
5709
5313
|
this.outboundLimiter.clear();
|
|
5710
5314
|
this.ws?.close(1e3, "Client disconnect");
|
|
5711
5315
|
this.ws = null;
|
|
@@ -5738,7 +5342,7 @@ var GatewayPlugin = class extends Plugin {
|
|
|
5738
5342
|
socket.on("close", (code) => {
|
|
5739
5343
|
if (socket !== this.ws) return;
|
|
5740
5344
|
const closeCode = code;
|
|
5741
|
-
this.
|
|
5345
|
+
this.heartbeatTimers.stop();
|
|
5742
5346
|
this.outboundLimiter.clear();
|
|
5743
5347
|
this.isConnecting = false;
|
|
5744
5348
|
this.isConnected = false;
|
|
@@ -5823,12 +5427,6 @@ var GatewayPlugin = class extends Plugin {
|
|
|
5823
5427
|
}
|
|
5824
5428
|
});
|
|
5825
5429
|
}
|
|
5826
|
-
stopHeartbeat() {
|
|
5827
|
-
this.heartbeatTimers.stop();
|
|
5828
|
-
}
|
|
5829
|
-
stopReconnectTimer() {
|
|
5830
|
-
this.reconnectTimer.stop();
|
|
5831
|
-
}
|
|
5832
5430
|
sendHeartbeat() {
|
|
5833
5431
|
if (!this.ws || this.ws.readyState !== READY_STATE_OPEN) return;
|
|
5834
5432
|
this.lastHeartbeatAck = false;
|
|
@@ -5894,7 +5492,7 @@ var GatewayPlugin = class extends Plugin {
|
|
|
5894
5492
|
this.isConnected = true;
|
|
5895
5493
|
}
|
|
5896
5494
|
this.voiceStateCache.apply(payload);
|
|
5897
|
-
dispatchVoiceGatewayEvent(this.client, payload
|
|
5495
|
+
dispatchVoiceGatewayEvent(this.client, payload);
|
|
5898
5496
|
const data = payload.t === GatewayDispatchEvents.MessageCreate ? payload.d : mapGatewayDispatchData(this.client, payload.t, payload.d);
|
|
5899
5497
|
await this.client.dispatchGatewayEvent(payload.t, data);
|
|
5900
5498
|
if (payload.t === GatewayDispatchEvents.InteractionCreate && this.options.autoInteractions) await this.client.handleInteraction(payload.d);
|
|
@@ -5914,8 +5512,8 @@ var GatewayPlugin = class extends Plugin {
|
|
|
5914
5512
|
}
|
|
5915
5513
|
scheduleReconnect(options) {
|
|
5916
5514
|
if (!this.shouldReconnect) return;
|
|
5917
|
-
this.
|
|
5918
|
-
this.
|
|
5515
|
+
this.heartbeatTimers.stop();
|
|
5516
|
+
this.reconnectTimer.stop();
|
|
5919
5517
|
this.ws?.close();
|
|
5920
5518
|
this.ws = null;
|
|
5921
5519
|
this.isConnecting = false;
|
|
@@ -5953,43 +5551,24 @@ var GatewayPlugin = class extends Plugin {
|
|
|
5953
5551
|
d: data
|
|
5954
5552
|
}, true);
|
|
5955
5553
|
}
|
|
5956
|
-
requestGuildMembers(data) {
|
|
5957
|
-
if (!this.hasIntent(GatewayIntentBits.GuildMembers)) throw new Error("GUILD_MEMBERS intent is required for requestGuildMembers");
|
|
5958
|
-
if (data.presences && !this.hasIntent(GatewayIntentBits.GuildPresences)) throw new Error("GUILD_PRESENCES intent is required when requesting presences");
|
|
5959
|
-
if (!data.query && data.query !== "" && !data.user_ids) throw new Error("Either query or user_ids is required for requestGuildMembers");
|
|
5960
|
-
this.send({
|
|
5961
|
-
op: GatewayOpcodes.RequestGuildMembers,
|
|
5962
|
-
d: data
|
|
5963
|
-
});
|
|
5964
|
-
}
|
|
5965
5554
|
getRateLimitStatus() {
|
|
5966
5555
|
return this.outboundLimiter.getStatus();
|
|
5967
5556
|
}
|
|
5968
|
-
hasIntent(intent) {
|
|
5969
|
-
return Boolean((this.options.intents ?? 0) & intent);
|
|
5970
|
-
}
|
|
5971
5557
|
};
|
|
5972
5558
|
//#endregion
|
|
5973
5559
|
//#region extensions/discord/src/monitor/presence.ts
|
|
5974
|
-
const DEFAULT_CUSTOM_ACTIVITY_TYPE
|
|
5975
|
-
const CUSTOM_STATUS_NAME
|
|
5560
|
+
const DEFAULT_CUSTOM_ACTIVITY_TYPE = 4;
|
|
5561
|
+
const CUSTOM_STATUS_NAME = "Custom Status";
|
|
5976
5562
|
function resolveDiscordPresenceUpdate(config) {
|
|
5977
5563
|
const activityText = normalizeOptionalString(config.activity) ?? "";
|
|
5978
5564
|
const status = normalizeOptionalString(config.status) ?? "";
|
|
5979
5565
|
const activityType = config.activityType;
|
|
5980
5566
|
const activityUrl = normalizeOptionalString(config.activityUrl) ?? "";
|
|
5981
|
-
const hasActivity = Boolean(activityText);
|
|
5982
|
-
if (!hasActivity && !Boolean(status)) return {
|
|
5983
|
-
since: null,
|
|
5984
|
-
activities: [],
|
|
5985
|
-
status: "online",
|
|
5986
|
-
afk: false
|
|
5987
|
-
};
|
|
5988
5567
|
const activities = [];
|
|
5989
|
-
if (
|
|
5990
|
-
const resolvedType = activityType ?? DEFAULT_CUSTOM_ACTIVITY_TYPE
|
|
5991
|
-
const activity = resolvedType === DEFAULT_CUSTOM_ACTIVITY_TYPE
|
|
5992
|
-
name: CUSTOM_STATUS_NAME
|
|
5568
|
+
if (activityText) {
|
|
5569
|
+
const resolvedType = activityType ?? DEFAULT_CUSTOM_ACTIVITY_TYPE;
|
|
5570
|
+
const activity = resolvedType === DEFAULT_CUSTOM_ACTIVITY_TYPE ? {
|
|
5571
|
+
name: CUSTOM_STATUS_NAME,
|
|
5993
5572
|
type: resolvedType,
|
|
5994
5573
|
state: activityText
|
|
5995
5574
|
} : {
|
|
@@ -6008,8 +5587,6 @@ function resolveDiscordPresenceUpdate(config) {
|
|
|
6008
5587
|
}
|
|
6009
5588
|
//#endregion
|
|
6010
5589
|
//#region extensions/discord/src/monitor/auto-presence.ts
|
|
6011
|
-
const DEFAULT_CUSTOM_ACTIVITY_TYPE = 4;
|
|
6012
|
-
const CUSTOM_STATUS_NAME = "Custom Status";
|
|
6013
5590
|
const DEFAULT_INTERVAL_MS = 3e4;
|
|
6014
5591
|
const DEFAULT_MIN_UPDATE_INTERVAL_MS = 15e3;
|
|
6015
5592
|
const MIN_INTERVAL_MS = 5e3;
|
|
@@ -6029,13 +5606,6 @@ function resolveAutoPresenceConfig(config) {
|
|
|
6029
5606
|
minUpdateIntervalMs
|
|
6030
5607
|
};
|
|
6031
5608
|
}
|
|
6032
|
-
function buildCustomStatusActivity(text) {
|
|
6033
|
-
return {
|
|
6034
|
-
name: CUSTOM_STATUS_NAME,
|
|
6035
|
-
type: DEFAULT_CUSTOM_ACTIVITY_TYPE,
|
|
6036
|
-
state: text
|
|
6037
|
-
};
|
|
6038
|
-
}
|
|
6039
5609
|
function isExhaustedUnavailableReason(reason) {
|
|
6040
5610
|
if (!reason) return false;
|
|
6041
5611
|
return reason === "rate_limit" || reason === "overloaded" || reason === "billing" || reason === "auth" || reason === "auth_permanent";
|
|
@@ -6051,15 +5621,6 @@ function resolveAuthAvailability(params) {
|
|
|
6051
5621
|
now: params.now
|
|
6052
5622
|
})) ? "exhausted" : "degraded";
|
|
6053
5623
|
}
|
|
6054
|
-
function resolvePresenceActivities(params) {
|
|
6055
|
-
if (params.state === "healthy") return params.basePresence?.activities ?? [];
|
|
6056
|
-
return [buildCustomStatusActivity(params.state === "degraded" ? "runtime degraded" : "token exhausted")];
|
|
6057
|
-
}
|
|
6058
|
-
function resolvePresenceStatus(state) {
|
|
6059
|
-
if (state === "healthy") return "online";
|
|
6060
|
-
if (state === "exhausted") return "dnd";
|
|
6061
|
-
return "idle";
|
|
6062
|
-
}
|
|
6063
5624
|
function resolveDiscordAutoPresenceUpdate(params) {
|
|
6064
5625
|
if (!resolveAutoPresenceConfig(params.discordConfig.autoPresence).enabled) return null;
|
|
6065
5626
|
const now = params.now ?? Date.now();
|
|
@@ -6069,15 +5630,15 @@ function resolveDiscordAutoPresenceUpdate(params) {
|
|
|
6069
5630
|
now
|
|
6070
5631
|
});
|
|
6071
5632
|
const state = params.gatewayConnected ? availability : "degraded";
|
|
6072
|
-
return {
|
|
5633
|
+
return state === "healthy" ? {
|
|
6073
5634
|
since: null,
|
|
6074
|
-
activities:
|
|
6075
|
-
|
|
6076
|
-
basePresence
|
|
6077
|
-
}),
|
|
6078
|
-
status: resolvePresenceStatus(state),
|
|
5635
|
+
activities: basePresence.activities,
|
|
5636
|
+
status: "online",
|
|
6079
5637
|
afk: false
|
|
6080
|
-
}
|
|
5638
|
+
} : resolveDiscordPresenceUpdate({
|
|
5639
|
+
activity: state === "degraded" ? "runtime degraded" : "token exhausted",
|
|
5640
|
+
status: state === "degraded" ? "idle" : "dnd"
|
|
5641
|
+
});
|
|
6081
5642
|
}
|
|
6082
5643
|
function stablePresenceSignature(payload) {
|
|
6083
5644
|
return JSON.stringify({
|
|
@@ -6150,6 +5711,7 @@ function createDiscordAutoPresenceController(params) {
|
|
|
6150
5711
|
const DISCORD_GATEWAY_TRANSPORT_ACTIVITY_EVENT = "openclaw:discord-gateway-transport-activity";
|
|
6151
5712
|
//#endregion
|
|
6152
5713
|
//#region extensions/discord/src/monitor/gateway-metadata.ts
|
|
5714
|
+
const captureSdk$1 = proxyCaptureSdk;
|
|
6153
5715
|
const DISCORD_GATEWAY_BOT_URL = "https://discord.com/api/v10/gateway/bot";
|
|
6154
5716
|
const DISCORD_API_HOST = "discord.com";
|
|
6155
5717
|
const DEFAULT_DISCORD_GATEWAY_URL = "wss://gateway.discord.gg/";
|
|
@@ -6169,11 +5731,6 @@ const discordGatewayBotInfoSchema = Type.Object({
|
|
|
6169
5731
|
})
|
|
6170
5732
|
});
|
|
6171
5733
|
const gatewayMetadataFallbackLogLastAt = /* @__PURE__ */ new WeakMap();
|
|
6172
|
-
function resolveFetchInputUrl(input) {
|
|
6173
|
-
if (typeof input === "string") return input;
|
|
6174
|
-
if (input instanceof URL) return input.toString();
|
|
6175
|
-
return input.url;
|
|
6176
|
-
}
|
|
6177
5734
|
async function materializeGuardedResponse(response) {
|
|
6178
5735
|
const body = new Uint8Array(await readResponseWithLimit(response, DISCORD_GATEWAY_METADATA_MAX_BYTES, { onOverflow: ({ size, maxBytes }) => /* @__PURE__ */ new Error(`Discord gateway metadata response body too large: ${size} bytes (limit: ${maxBytes} bytes)`) }));
|
|
6179
5736
|
return new Response(body, {
|
|
@@ -6237,6 +5794,7 @@ function parseDiscordGatewayInfoBody(body) {
|
|
|
6237
5794
|
}
|
|
6238
5795
|
async function fetchDiscordGatewayInfo(params) {
|
|
6239
5796
|
let response;
|
|
5797
|
+
let body;
|
|
6240
5798
|
try {
|
|
6241
5799
|
response = await params.fetchImpl(params.gatewayBotUrl ?? DISCORD_GATEWAY_BOT_URL, {
|
|
6242
5800
|
...params.fetchInit,
|
|
@@ -6245,15 +5803,6 @@ async function fetchDiscordGatewayInfo(params) {
|
|
|
6245
5803
|
Authorization: `Bot ${params.token}`
|
|
6246
5804
|
}
|
|
6247
5805
|
});
|
|
6248
|
-
} catch (error) {
|
|
6249
|
-
throw createGatewayMetadataError({
|
|
6250
|
-
detail: formatErrorMessage$1(error),
|
|
6251
|
-
transient: true,
|
|
6252
|
-
cause: error
|
|
6253
|
-
});
|
|
6254
|
-
}
|
|
6255
|
-
let body;
|
|
6256
|
-
try {
|
|
6257
5806
|
body = await response.text();
|
|
6258
5807
|
} catch (error) {
|
|
6259
5808
|
throw createGatewayMetadataError({
|
|
@@ -6318,7 +5867,7 @@ async function fetchDiscordGatewayMetadataGuarded(input, init, options) {
|
|
|
6318
5867
|
const requestInit = init;
|
|
6319
5868
|
const signal = requestInit?.signal ?? void 0;
|
|
6320
5869
|
const guarded = await fetchWithSsrFGuard({
|
|
6321
|
-
url:
|
|
5870
|
+
url: input,
|
|
6322
5871
|
init: requestInit,
|
|
6323
5872
|
...signal ? { signal } : {},
|
|
6324
5873
|
policy: { allowedHostnames: [DISCORD_API_HOST] },
|
|
@@ -6339,7 +5888,7 @@ async function fetchDiscordGatewayMetadataGuarded(input, init, options) {
|
|
|
6339
5888
|
} finally {
|
|
6340
5889
|
await guarded.release();
|
|
6341
5890
|
}
|
|
6342
|
-
if (options?.capture)
|
|
5891
|
+
if (options?.capture) captureSdk$1.captureHttpExchangeAsync?.({
|
|
6343
5892
|
url: input,
|
|
6344
5893
|
method: init?.method ?? "GET",
|
|
6345
5894
|
requestHeaders: init?.headers,
|
|
@@ -6347,23 +5896,17 @@ async function fetchDiscordGatewayMetadataGuarded(input, init, options) {
|
|
|
6347
5896
|
response,
|
|
6348
5897
|
flowId: options.capture.flowId,
|
|
6349
5898
|
meta: options.capture.meta
|
|
6350
|
-
});
|
|
5899
|
+
}).catch(() => {});
|
|
6351
5900
|
return response;
|
|
6352
5901
|
}
|
|
6353
5902
|
//#endregion
|
|
6354
5903
|
//#region extensions/discord/src/monitor/gateway-plugin.ts
|
|
5904
|
+
const captureSdk = proxyCaptureSdk;
|
|
6355
5905
|
const DISCORD_GATEWAY_POLICY_VIOLATION_CLOSE_CODE = 1008;
|
|
6356
5906
|
const DISCORD_GATEWAY_WS_RECEIVER_LIMIT_CODE = "WS_ERR_TOO_MANY_BUFFERED_PARTS";
|
|
6357
5907
|
const DISCORD_GATEWAY_CLOSE_REASON_LOG_MAX_CHARS = 240;
|
|
6358
5908
|
const discordDnsLookup = createDiscordDnsLookup();
|
|
6359
5909
|
const registrationPromises = /* @__PURE__ */ new WeakMap();
|
|
6360
|
-
function assignGatewayClient(plugin, client) {
|
|
6361
|
-
plugin.client = client;
|
|
6362
|
-
}
|
|
6363
|
-
function hasGatewaySocketStarted(plugin) {
|
|
6364
|
-
const state = plugin;
|
|
6365
|
-
return state.ws != null || state.isConnecting === true;
|
|
6366
|
-
}
|
|
6367
5910
|
function readStringProperty(value, key) {
|
|
6368
5911
|
const property = value[key];
|
|
6369
5912
|
return typeof property === "string" && property ? property : void 0;
|
|
@@ -6439,7 +5982,7 @@ function createGatewayPlugin(params) {
|
|
|
6439
5982
|
return registration;
|
|
6440
5983
|
}
|
|
6441
5984
|
async registerClientInternal(client) {
|
|
6442
|
-
|
|
5985
|
+
this.client = client;
|
|
6443
5986
|
if (!this.gatewayInfo || this.gatewayInfoUsedFallback) {
|
|
6444
5987
|
const resolved = await fetchDiscordGatewayInfoWithTimeout({
|
|
6445
5988
|
token: client.options.token,
|
|
@@ -6464,7 +6007,7 @@ function createGatewayPlugin(params) {
|
|
|
6464
6007
|
await params.testing.registerClient(this, client);
|
|
6465
6008
|
return;
|
|
6466
6009
|
}
|
|
6467
|
-
if (
|
|
6010
|
+
if (this.ws != null || this.isConnecting) return;
|
|
6468
6011
|
return super.registerClient(client);
|
|
6469
6012
|
}
|
|
6470
6013
|
createWebSocket(url) {
|
|
@@ -6480,35 +6023,34 @@ function createGatewayPlugin(params) {
|
|
|
6480
6023
|
if (this.ws !== socket) return;
|
|
6481
6024
|
this.emitter.emit(DISCORD_GATEWAY_TRANSPORT_ACTIVITY_EVENT, { at: Date.now() });
|
|
6482
6025
|
};
|
|
6483
|
-
|
|
6484
|
-
|
|
6026
|
+
const captureEvent = (event) => {
|
|
6027
|
+
captureSdk.captureWsEventAsync?.({
|
|
6028
|
+
url,
|
|
6029
|
+
...event(),
|
|
6030
|
+
flowId: wsFlowId,
|
|
6031
|
+
meta: { subsystem: "discord-gateway" }
|
|
6032
|
+
}).catch(() => {});
|
|
6033
|
+
};
|
|
6034
|
+
captureEvent(() => ({
|
|
6485
6035
|
direction: "local",
|
|
6486
|
-
kind: "ws-open"
|
|
6487
|
-
|
|
6488
|
-
meta: { subsystem: "discord-gateway" }
|
|
6489
|
-
});
|
|
6036
|
+
kind: "ws-open"
|
|
6037
|
+
}));
|
|
6490
6038
|
socket.on?.("message", (data) => {
|
|
6491
6039
|
emitTransportActivity();
|
|
6492
|
-
|
|
6493
|
-
url,
|
|
6040
|
+
captureEvent(() => ({
|
|
6494
6041
|
direction: "inbound",
|
|
6495
6042
|
kind: "ws-frame",
|
|
6496
|
-
|
|
6497
|
-
|
|
6498
|
-
meta: { subsystem: "discord-gateway" }
|
|
6499
|
-
});
|
|
6043
|
+
payload: Buffer.isBuffer(data) ? data : Buffer.from(String(data))
|
|
6044
|
+
}));
|
|
6500
6045
|
});
|
|
6501
6046
|
socket.on?.("close", (code, reason) => {
|
|
6502
6047
|
const closeReason = Buffer.isBuffer(reason) ? reason : Buffer.from(String(reason ?? ""));
|
|
6503
|
-
|
|
6504
|
-
url,
|
|
6048
|
+
captureEvent(() => ({
|
|
6505
6049
|
direction: "local",
|
|
6506
6050
|
kind: "ws-close",
|
|
6507
|
-
flowId: wsFlowId,
|
|
6508
6051
|
closeCode: code,
|
|
6509
|
-
payload: closeReason
|
|
6510
|
-
|
|
6511
|
-
});
|
|
6052
|
+
payload: closeReason
|
|
6053
|
+
}));
|
|
6512
6054
|
if (shouldLogDiscordGatewayTransportClose({
|
|
6513
6055
|
code,
|
|
6514
6056
|
reason: closeReason,
|
|
@@ -6522,14 +6064,11 @@ function createGatewayPlugin(params) {
|
|
|
6522
6064
|
});
|
|
6523
6065
|
socket.on?.("error", (error) => {
|
|
6524
6066
|
lastTransportError = describeDiscordGatewayTransportError(error);
|
|
6525
|
-
|
|
6526
|
-
url,
|
|
6067
|
+
captureEvent(() => ({
|
|
6527
6068
|
direction: "local",
|
|
6528
6069
|
kind: "error",
|
|
6529
|
-
|
|
6530
|
-
|
|
6531
|
-
meta: { subsystem: "discord-gateway" }
|
|
6532
|
-
});
|
|
6070
|
+
errorText: error.message
|
|
6071
|
+
}));
|
|
6533
6072
|
params.runtime?.log?.(warn(formatDiscordGatewayTransportErrorLog({
|
|
6534
6073
|
flowId: wsFlowId,
|
|
6535
6074
|
error: lastTransportError
|
|
@@ -6580,7 +6119,7 @@ function createDiscordGatewayPlugin(params) {
|
|
|
6580
6119
|
} : void 0;
|
|
6581
6120
|
const endpointGatewayUrl = endpoint ? new URL(endpoint.gatewayOrigin) : void 0;
|
|
6582
6121
|
let fetchImpl = createDiscordGatewayMetadataFetch(debugProxySettings.enabled, endpoint ? { endpoint } : void 0);
|
|
6583
|
-
let wsAgent = endpointGatewayUrl?.protocol === "ws:" ? void 0 : new Agent
|
|
6122
|
+
let wsAgent = endpointGatewayUrl?.protocol === "ws:" ? void 0 : new Agent({ lookup: endpointGatewayUrl ? createDiscordEndpointDnsLookup(endpointGatewayUrl.hostname) : discordDnsLookup });
|
|
6584
6123
|
if (proxy && !endpoint) try {
|
|
6585
6124
|
validateDiscordProxyUrl(proxy);
|
|
6586
6125
|
wsAgent = params.testing?.createProxyAgent?.(proxy) ?? createNodeProxyAgent({
|
|
@@ -6659,29 +6198,16 @@ function formatDiscordGatewayErrorMessage(err) {
|
|
|
6659
6198
|
}
|
|
6660
6199
|
function classifyDiscordGatewayEvent(params) {
|
|
6661
6200
|
const message = formatDiscordGatewayErrorMessage(params.err);
|
|
6662
|
-
|
|
6663
|
-
|
|
6664
|
-
|
|
6665
|
-
|
|
6666
|
-
|
|
6667
|
-
};
|
|
6668
|
-
if (message.includes("Max reconnect attempts")) return {
|
|
6669
|
-
type: "reconnect-exhausted",
|
|
6670
|
-
err: params.err,
|
|
6671
|
-
message,
|
|
6672
|
-
shouldStopLifecycle: true
|
|
6673
|
-
};
|
|
6674
|
-
if (params.err instanceof TypeError || message.includes("Fatal Gateway error") || message.includes("Fatal gateway close code") || message.includes("Gateway HELLO missing heartbeat") || message.includes("Invalid gateway payload") || message.includes("Gateway socket emitted an unknown error")) return {
|
|
6675
|
-
type: "fatal",
|
|
6676
|
-
err: params.err,
|
|
6677
|
-
message,
|
|
6678
|
-
shouldStopLifecycle: true
|
|
6679
|
-
};
|
|
6201
|
+
let type;
|
|
6202
|
+
if (params.isDisallowedIntentsError(params.err)) type = "disallowed-intents";
|
|
6203
|
+
else if (message.includes("Max reconnect attempts")) type = "reconnect-exhausted";
|
|
6204
|
+
else if (params.err instanceof TypeError || message.includes("Fatal Gateway error") || message.includes("Fatal gateway close code") || message.includes("Gateway HELLO missing heartbeat") || message.includes("Invalid gateway payload") || message.includes("Gateway socket emitted an unknown error")) type = "fatal";
|
|
6205
|
+
else type = "other";
|
|
6680
6206
|
return {
|
|
6681
|
-
type
|
|
6207
|
+
type,
|
|
6682
6208
|
err: params.err,
|
|
6683
6209
|
message,
|
|
6684
|
-
shouldStopLifecycle:
|
|
6210
|
+
shouldStopLifecycle: type !== "other"
|
|
6685
6211
|
};
|
|
6686
6212
|
}
|
|
6687
6213
|
function createDiscordGatewaySupervisor(params) {
|
|
@@ -6697,7 +6223,7 @@ function createDiscordGatewaySupervisor(params) {
|
|
|
6697
6223
|
let lifecycleHandler;
|
|
6698
6224
|
let phase = "buffering";
|
|
6699
6225
|
const seenLateEventKeys = /* @__PURE__ */ new Set();
|
|
6700
|
-
const logLateEvent = (state
|
|
6226
|
+
const logLateEvent = (state, event) => {
|
|
6701
6227
|
const key = `${state}:${event.type}:${event.message}`;
|
|
6702
6228
|
if (seenLateEventKeys.has(key)) return;
|
|
6703
6229
|
seenLateEventKeys.add(key);
|
|
@@ -6710,13 +6236,13 @@ function createDiscordGatewaySupervisor(params) {
|
|
|
6710
6236
|
});
|
|
6711
6237
|
switch (phase) {
|
|
6712
6238
|
case "disposed":
|
|
6713
|
-
logLateEvent("disposed"
|
|
6239
|
+
logLateEvent("disposed", event);
|
|
6714
6240
|
return;
|
|
6715
6241
|
case "active":
|
|
6716
6242
|
lifecycleHandler?.(event);
|
|
6717
6243
|
return;
|
|
6718
6244
|
case "teardown":
|
|
6719
|
-
logLateEvent("teardown"
|
|
6245
|
+
logLateEvent("teardown", event);
|
|
6720
6246
|
return;
|
|
6721
6247
|
case "buffering": pending.push(event);
|
|
6722
6248
|
}
|
|
@@ -6868,12 +6394,6 @@ function normalizeGatewayReadyTimeoutMs(value) {
|
|
|
6868
6394
|
if (numeric === void 0) return;
|
|
6869
6395
|
return Math.min(numeric, MAX_DISCORD_GATEWAY_READY_TIMEOUT_MS);
|
|
6870
6396
|
}
|
|
6871
|
-
function resolveDiscordGatewayReadyTimeoutMs(params) {
|
|
6872
|
-
return normalizeGatewayReadyTimeoutMs(params?.env?.[DISCORD_GATEWAY_READY_TIMEOUT_ENV]) ?? DEFAULT_DISCORD_GATEWAY_READY_TIMEOUT_MS;
|
|
6873
|
-
}
|
|
6874
|
-
function resolveDiscordGatewayRuntimeReadyTimeoutMs(params) {
|
|
6875
|
-
return normalizeGatewayReadyTimeoutMs(params?.env?.[DISCORD_GATEWAY_RUNTIME_READY_TIMEOUT_ENV]) ?? DEFAULT_DISCORD_GATEWAY_RUNTIME_READY_TIMEOUT_MS;
|
|
6876
|
-
}
|
|
6877
6397
|
async function restartGatewayAfterReadyTimeout(params) {
|
|
6878
6398
|
if (!params.gateway || params.abortSignal?.aborted) return;
|
|
6879
6399
|
const socket = params.gateway.ws;
|
|
@@ -6902,44 +6422,32 @@ async function restartGatewayAfterReadyTimeout(params) {
|
|
|
6902
6422
|
socket.removeListener("close", onClose);
|
|
6903
6423
|
socket.removeListener("error", ignoreSocketError);
|
|
6904
6424
|
};
|
|
6905
|
-
const
|
|
6906
|
-
if (settled) return;
|
|
6907
|
-
settled = true;
|
|
6908
|
-
cleanup();
|
|
6909
|
-
resolve();
|
|
6910
|
-
};
|
|
6911
|
-
const finishReject = (error) => {
|
|
6912
|
-
if (params.abortSignal?.aborted) {
|
|
6913
|
-
finishResolve();
|
|
6914
|
-
return;
|
|
6915
|
-
}
|
|
6425
|
+
const finish = (error) => {
|
|
6916
6426
|
if (settled) return;
|
|
6917
6427
|
settled = true;
|
|
6918
6428
|
cleanup();
|
|
6919
|
-
reject(error);
|
|
6920
|
-
|
|
6921
|
-
const onClose = () => {
|
|
6922
|
-
finishResolve();
|
|
6429
|
+
if (error && !params.abortSignal?.aborted) reject(error);
|
|
6430
|
+
else resolve();
|
|
6923
6431
|
};
|
|
6432
|
+
const onClose = () => finish();
|
|
6433
|
+
const failClose = () => finish(/* @__PURE__ */ new Error(`discord gateway socket did not close within ${DISCORD_GATEWAY_STARTUP_DISCONNECT_DRAIN_TIMEOUT_MS}ms before restart`));
|
|
6924
6434
|
socket.on("error", ignoreSocketError);
|
|
6925
6435
|
socket.on("close", onClose);
|
|
6926
6436
|
params.gateway?.disconnect();
|
|
6927
6437
|
drainTimeout = setTimeout(() => {
|
|
6928
6438
|
if (settled) return;
|
|
6929
6439
|
if (typeof socket.terminate !== "function") {
|
|
6930
|
-
|
|
6440
|
+
failClose();
|
|
6931
6441
|
return;
|
|
6932
6442
|
}
|
|
6933
6443
|
params.runtime.error?.(danger(`discord: startup restart waiting on a stale gateway socket for ${DISCORD_GATEWAY_STARTUP_DISCONNECT_DRAIN_TIMEOUT_MS}ms; forcing terminate before reconnect`));
|
|
6934
6444
|
try {
|
|
6935
6445
|
socket.terminate();
|
|
6936
6446
|
} catch {
|
|
6937
|
-
|
|
6447
|
+
failClose();
|
|
6938
6448
|
return;
|
|
6939
6449
|
}
|
|
6940
|
-
terminateCloseTimeout = setTimeout(
|
|
6941
|
-
finishReject(/* @__PURE__ */ new Error(`discord gateway socket did not close within ${DISCORD_GATEWAY_STARTUP_DISCONNECT_DRAIN_TIMEOUT_MS}ms before restart`));
|
|
6942
|
-
}, DISCORD_GATEWAY_STARTUP_TERMINATE_CLOSE_TIMEOUT_MS);
|
|
6450
|
+
terminateCloseTimeout = setTimeout(failClose, DISCORD_GATEWAY_STARTUP_TERMINATE_CLOSE_TIMEOUT_MS);
|
|
6943
6451
|
terminateCloseTimeout.unref?.();
|
|
6944
6452
|
}, DISCORD_GATEWAY_STARTUP_DISCONNECT_DRAIN_TIMEOUT_MS);
|
|
6945
6453
|
drainTimeout.unref?.();
|
|
@@ -6980,9 +6488,6 @@ function createGatewayStatusObserver(params) {
|
|
|
6980
6488
|
}
|
|
6981
6489
|
queuedForceStopError = err;
|
|
6982
6490
|
};
|
|
6983
|
-
const pushConnectedStatus = (at) => {
|
|
6984
|
-
params.pushStatus(createDiscordReadyStatusPatch(at));
|
|
6985
|
-
};
|
|
6986
6491
|
const startReadyWatch = () => {
|
|
6987
6492
|
clearReadyWatch();
|
|
6988
6493
|
const pollConnected = () => {
|
|
@@ -6992,7 +6497,7 @@ function createGatewayStatusObserver(params) {
|
|
|
6992
6497
|
}
|
|
6993
6498
|
if (!params.gateway?.isConnected) return;
|
|
6994
6499
|
clearReadyWatch();
|
|
6995
|
-
|
|
6500
|
+
params.pushStatus(createDiscordReadyStatusPatch(Date.now()));
|
|
6996
6501
|
};
|
|
6997
6502
|
pollConnected();
|
|
6998
6503
|
if (!readyTimeoutId) {
|
|
@@ -7142,8 +6647,8 @@ async function runDiscordGatewayLifecycle(params) {
|
|
|
7142
6647
|
const pushStatus = (patch) => {
|
|
7143
6648
|
params.statusSink?.(patch);
|
|
7144
6649
|
};
|
|
7145
|
-
const gatewayReadyTimeoutMs =
|
|
7146
|
-
const gatewayRuntimeReadyTimeoutMs =
|
|
6650
|
+
const gatewayReadyTimeoutMs = normalizeGatewayReadyTimeoutMs(process.env[DISCORD_GATEWAY_READY_TIMEOUT_ENV]) ?? DEFAULT_DISCORD_GATEWAY_READY_TIMEOUT_MS;
|
|
6651
|
+
const gatewayRuntimeReadyTimeoutMs = normalizeGatewayReadyTimeoutMs(process.env[DISCORD_GATEWAY_RUNTIME_READY_TIMEOUT_ENV]) ?? DEFAULT_DISCORD_GATEWAY_RUNTIME_READY_TIMEOUT_MS;
|
|
7147
6652
|
const statusObserver = createGatewayStatusObserver({
|
|
7148
6653
|
gateway,
|
|
7149
6654
|
abortSignal: params.abortSignal,
|
|
@@ -7207,23 +6712,26 @@ async function runDiscordGatewayLifecycle(params) {
|
|
|
7207
6712
|
} catch (err) {
|
|
7208
6713
|
if (!sawDisallowedIntents && !params.isDisallowedIntentsError(err)) throw err;
|
|
7209
6714
|
} finally {
|
|
7210
|
-
|
|
7211
|
-
|
|
7212
|
-
|
|
7213
|
-
|
|
7214
|
-
|
|
7215
|
-
|
|
7216
|
-
|
|
7217
|
-
|
|
7218
|
-
|
|
7219
|
-
|
|
7220
|
-
|
|
7221
|
-
|
|
7222
|
-
|
|
7223
|
-
|
|
7224
|
-
|
|
6715
|
+
try {
|
|
6716
|
+
lifecycleStopping = true;
|
|
6717
|
+
params.gatewaySupervisor.detachLifecycle();
|
|
6718
|
+
unregisterGateway(params.accountId);
|
|
6719
|
+
stopGatewayLogging();
|
|
6720
|
+
statusObserver.dispose();
|
|
6721
|
+
gatewayEmitter?.removeListener("debug", statusObserver.onGatewayDebug);
|
|
6722
|
+
gatewayEmitter?.removeListener(DISCORD_GATEWAY_TRANSPORT_ACTIVITY_EVENT, onGatewayTransportActivity);
|
|
6723
|
+
if (params.voiceManager) {
|
|
6724
|
+
await params.voiceManager.destroy();
|
|
6725
|
+
setDiscordTranscriptsVoiceManager({
|
|
6726
|
+
accountId: params.accountId,
|
|
6727
|
+
manager: null,
|
|
6728
|
+
expectedManager: params.voiceManager
|
|
6729
|
+
});
|
|
6730
|
+
params.voiceManagerRef.current = null;
|
|
6731
|
+
}
|
|
6732
|
+
} finally {
|
|
6733
|
+
await params.threadBindings.stop();
|
|
7225
6734
|
}
|
|
7226
|
-
params.threadBindings.stop();
|
|
7227
6735
|
}
|
|
7228
6736
|
}
|
|
7229
6737
|
//#endregion
|
|
@@ -7231,7 +6739,7 @@ async function runDiscordGatewayLifecycle(params) {
|
|
|
7231
6739
|
let discordVoiceRuntimePromise;
|
|
7232
6740
|
let discordProviderSessionRuntimePromise;
|
|
7233
6741
|
async function loadDiscordVoiceRuntime() {
|
|
7234
|
-
const promise = discordVoiceRuntimePromise ?? import("./voice-runtime-
|
|
6742
|
+
const promise = discordVoiceRuntimePromise ?? import("./voice-runtime-B46rcwrG.mjs").then((n) => n.t);
|
|
7235
6743
|
discordVoiceRuntimePromise = promise;
|
|
7236
6744
|
try {
|
|
7237
6745
|
return await promise;
|
|
@@ -7241,7 +6749,7 @@ async function loadDiscordVoiceRuntime() {
|
|
|
7241
6749
|
}
|
|
7242
6750
|
}
|
|
7243
6751
|
async function loadDiscordProviderSessionRuntime() {
|
|
7244
|
-
const promise = discordProviderSessionRuntimePromise ?? import("./provider-session.runtime-
|
|
6752
|
+
const promise = discordProviderSessionRuntimePromise ?? import("./provider-session.runtime-BYlTBFD2.mjs");
|
|
7245
6753
|
discordProviderSessionRuntimePromise = promise;
|
|
7246
6754
|
try {
|
|
7247
6755
|
return await promise;
|
|
@@ -7345,22 +6853,49 @@ async function probeDiscordAcpBindingHealth(params) {
|
|
|
7345
6853
|
//#endregion
|
|
7346
6854
|
//#region extensions/discord/src/monitor/provider.cleanup.ts
|
|
7347
6855
|
async function cleanupDiscordProviderStartup(params) {
|
|
7348
|
-
const listenersStopped = params.stopMonitorListeners?.();
|
|
7349
6856
|
try {
|
|
7350
|
-
|
|
6857
|
+
const listenersStopped = params.stopMonitorListeners?.();
|
|
6858
|
+
try {
|
|
6859
|
+
await params.deactivateMessageHandler?.();
|
|
6860
|
+
} finally {
|
|
6861
|
+
await listenersStopped;
|
|
6862
|
+
}
|
|
6863
|
+
params.autoPresenceController?.stop();
|
|
6864
|
+
params.setStatus?.({ connected: false });
|
|
6865
|
+
if (params.onEarlyGatewayDebug) params.earlyGatewayEmitter?.removeListener("debug", params.onEarlyGatewayDebug);
|
|
6866
|
+
if (!params.lifecycleStarted) try {
|
|
6867
|
+
params.lifecycleGateway?.disconnect();
|
|
6868
|
+
} catch (err) {
|
|
6869
|
+
params.runtime.error?.(danger(`discord: failed to disconnect gateway during startup cleanup: ${String(err)}`));
|
|
6870
|
+
}
|
|
6871
|
+
params.gatewaySupervisor?.dispose();
|
|
7351
6872
|
} finally {
|
|
7352
|
-
await
|
|
7353
|
-
}
|
|
7354
|
-
params.autoPresenceController?.stop();
|
|
7355
|
-
params.setStatus?.({ connected: false });
|
|
7356
|
-
if (params.onEarlyGatewayDebug) params.earlyGatewayEmitter?.removeListener("debug", params.onEarlyGatewayDebug);
|
|
7357
|
-
if (!params.lifecycleStarted) try {
|
|
7358
|
-
params.lifecycleGateway?.disconnect();
|
|
7359
|
-
} catch (err) {
|
|
7360
|
-
params.runtime.error?.(danger(`discord: failed to disconnect gateway during startup cleanup: ${String(err)}`));
|
|
6873
|
+
if (!params.lifecycleStarted) await params.threadBindings.stop();
|
|
7361
6874
|
}
|
|
7362
|
-
|
|
7363
|
-
|
|
6875
|
+
}
|
|
6876
|
+
//#endregion
|
|
6877
|
+
//#region extensions/discord/src/voice/session.ts
|
|
6878
|
+
const MIN_SEGMENT_SECONDS = .35;
|
|
6879
|
+
const CAPTURE_FINALIZE_GRACE_MS = 2e3;
|
|
6880
|
+
const VOICE_CONNECT_READY_TIMEOUT_MS = 3e4;
|
|
6881
|
+
const VOICE_RECONNECT_GRACE_MS = 15e3;
|
|
6882
|
+
function resolveVoiceTimeoutMs(value, fallbackMs) {
|
|
6883
|
+
if (typeof value !== "number" || !Number.isFinite(value) || value <= 0) return fallbackMs;
|
|
6884
|
+
return Math.floor(value);
|
|
6885
|
+
}
|
|
6886
|
+
function resolveDiscordVoiceMode(voice) {
|
|
6887
|
+
const mode = voice?.mode;
|
|
6888
|
+
if (mode === "stt-tts" || mode === "bidi") return mode;
|
|
6889
|
+
return "agent-proxy";
|
|
6890
|
+
}
|
|
6891
|
+
function isDiscordRealtimeVoiceMode(mode) {
|
|
6892
|
+
return mode === "agent-proxy" || mode === "bidi";
|
|
6893
|
+
}
|
|
6894
|
+
function logVoiceVerbose(message) {
|
|
6895
|
+
logVerbose(`discord voice: ${message}`);
|
|
6896
|
+
}
|
|
6897
|
+
function isVoiceChannel(type) {
|
|
6898
|
+
return type === discord_exports.ChannelType.GuildVoice || type === discord_exports.ChannelType.GuildStageVoice;
|
|
7364
6899
|
}
|
|
7365
6900
|
//#endregion
|
|
7366
6901
|
//#region extensions/discord/src/voice/command.ts
|
|
@@ -7437,37 +6972,6 @@ async function authorizeVoiceCommand(interaction, params, options) {
|
|
|
7437
6972
|
guildId: interaction.guild.id
|
|
7438
6973
|
};
|
|
7439
6974
|
}
|
|
7440
|
-
async function resolveVoiceCommandRuntimeContext(interaction, params) {
|
|
7441
|
-
const guildId = interaction.guild?.id;
|
|
7442
|
-
if (!guildId) {
|
|
7443
|
-
await interaction.reply({
|
|
7444
|
-
content: "Unable to resolve guild for this command.",
|
|
7445
|
-
ephemeral: true
|
|
7446
|
-
});
|
|
7447
|
-
return null;
|
|
7448
|
-
}
|
|
7449
|
-
const manager = params.getManager();
|
|
7450
|
-
if (!manager) {
|
|
7451
|
-
await interaction.reply({
|
|
7452
|
-
content: "Voice manager is not available yet.",
|
|
7453
|
-
ephemeral: true
|
|
7454
|
-
});
|
|
7455
|
-
return null;
|
|
7456
|
-
}
|
|
7457
|
-
return {
|
|
7458
|
-
guildId,
|
|
7459
|
-
manager
|
|
7460
|
-
};
|
|
7461
|
-
}
|
|
7462
|
-
async function ensureVoiceCommandAccess(params) {
|
|
7463
|
-
const access = await authorizeVoiceCommand(params.interaction, params.context, { channelOverride: params.channelOverride });
|
|
7464
|
-
if (access.ok) return true;
|
|
7465
|
-
await params.interaction.reply({
|
|
7466
|
-
content: access.message ?? "Not authorized.",
|
|
7467
|
-
ephemeral: true
|
|
7468
|
-
});
|
|
7469
|
-
return false;
|
|
7470
|
-
}
|
|
7471
6975
|
function createDiscordVoiceCommand(startupParams) {
|
|
7472
6976
|
const params = {
|
|
7473
6977
|
...startupParams,
|
|
@@ -7483,7 +6987,6 @@ function createDiscordVoiceCommand(startupParams) {
|
|
|
7483
6987
|
}
|
|
7484
6988
|
})
|
|
7485
6989
|
};
|
|
7486
|
-
const resolveSessionChannelId = (manager, guildId) => manager.status().find((entry) => entry.guildId === guildId)?.channelId;
|
|
7487
6990
|
class JoinCommand extends Command {
|
|
7488
6991
|
constructor(..._args) {
|
|
7489
6992
|
super(..._args);
|
|
@@ -7519,7 +7022,7 @@ function createDiscordVoiceCommand(startupParams) {
|
|
|
7519
7022
|
});
|
|
7520
7023
|
return;
|
|
7521
7024
|
}
|
|
7522
|
-
if (!
|
|
7025
|
+
if (!isVoiceChannel(channel.type)) {
|
|
7523
7026
|
await interaction.reply({
|
|
7524
7027
|
content: "That is not a voice channel.",
|
|
7525
7028
|
ephemeral: true
|
|
@@ -7552,48 +7055,49 @@ function createDiscordVoiceCommand(startupParams) {
|
|
|
7552
7055
|
});
|
|
7553
7056
|
}
|
|
7554
7057
|
}
|
|
7555
|
-
class
|
|
7556
|
-
constructor(
|
|
7557
|
-
super(
|
|
7558
|
-
this.name =
|
|
7559
|
-
this.description = "Leave the current voice channel";
|
|
7560
|
-
this.defer = true;
|
|
7561
|
-
this.ephemeral = params.ephemeralDefault;
|
|
7562
|
-
}
|
|
7563
|
-
async run(interaction) {
|
|
7564
|
-
const runtimeContext = await resolveVoiceCommandRuntimeContext(interaction, params);
|
|
7565
|
-
if (!runtimeContext) return;
|
|
7566
|
-
const sessionChannelId = resolveSessionChannelId(runtimeContext.manager, runtimeContext.guildId);
|
|
7567
|
-
if (!await ensureVoiceCommandAccess({
|
|
7568
|
-
interaction,
|
|
7569
|
-
context: params,
|
|
7570
|
-
channelOverride: sessionChannelId ? { id: sessionChannelId } : void 0
|
|
7571
|
-
})) return;
|
|
7572
|
-
const result = await runtimeContext.manager.leave({ guildId: runtimeContext.guildId });
|
|
7573
|
-
await interaction.reply({
|
|
7574
|
-
content: result.message,
|
|
7575
|
-
ephemeral: true
|
|
7576
|
-
});
|
|
7577
|
-
}
|
|
7578
|
-
}
|
|
7579
|
-
class StatusCommand extends Command {
|
|
7580
|
-
constructor(..._args3) {
|
|
7581
|
-
super(..._args3);
|
|
7582
|
-
this.name = "status";
|
|
7583
|
-
this.description = "Show active voice sessions";
|
|
7058
|
+
class SessionCommand extends Command {
|
|
7059
|
+
constructor(name) {
|
|
7060
|
+
super();
|
|
7061
|
+
this.name = name;
|
|
7584
7062
|
this.defer = true;
|
|
7585
7063
|
this.ephemeral = params.ephemeralDefault;
|
|
7064
|
+
this.description = name === "leave" ? "Leave the current voice channel" : "Show active voice sessions";
|
|
7586
7065
|
}
|
|
7587
7066
|
async run(interaction) {
|
|
7588
|
-
const
|
|
7589
|
-
if (!
|
|
7590
|
-
|
|
7067
|
+
const guildId = interaction.guild?.id;
|
|
7068
|
+
if (!guildId) {
|
|
7069
|
+
await interaction.reply({
|
|
7070
|
+
content: "Unable to resolve guild for this command.",
|
|
7071
|
+
ephemeral: true
|
|
7072
|
+
});
|
|
7073
|
+
return;
|
|
7074
|
+
}
|
|
7075
|
+
const manager = params.getManager();
|
|
7076
|
+
if (!manager) {
|
|
7077
|
+
await interaction.reply({
|
|
7078
|
+
content: "Voice manager is not available yet.",
|
|
7079
|
+
ephemeral: true
|
|
7080
|
+
});
|
|
7081
|
+
return;
|
|
7082
|
+
}
|
|
7083
|
+
const sessions = manager.status().filter((entry) => entry.guildId === guildId);
|
|
7591
7084
|
const sessionChannelId = sessions[0]?.channelId;
|
|
7592
|
-
|
|
7593
|
-
|
|
7594
|
-
|
|
7595
|
-
|
|
7596
|
-
|
|
7085
|
+
const access = await authorizeVoiceCommand(interaction, params, { channelOverride: sessionChannelId ? { id: sessionChannelId } : void 0 });
|
|
7086
|
+
if (!access.ok) {
|
|
7087
|
+
await interaction.reply({
|
|
7088
|
+
content: access.message ?? "Not authorized.",
|
|
7089
|
+
ephemeral: true
|
|
7090
|
+
});
|
|
7091
|
+
return;
|
|
7092
|
+
}
|
|
7093
|
+
if (this.name === "leave") {
|
|
7094
|
+
const result = await manager.leave({ guildId });
|
|
7095
|
+
await interaction.reply({
|
|
7096
|
+
content: result.message,
|
|
7097
|
+
ephemeral: true
|
|
7098
|
+
});
|
|
7099
|
+
return;
|
|
7100
|
+
}
|
|
7597
7101
|
if (sessions.length === 0) {
|
|
7598
7102
|
await interaction.reply({
|
|
7599
7103
|
content: "No active voice sessions.",
|
|
@@ -7609,21 +7113,18 @@ function createDiscordVoiceCommand(startupParams) {
|
|
|
7609
7113
|
}
|
|
7610
7114
|
}
|
|
7611
7115
|
return new class extends CommandWithSubcommands {
|
|
7612
|
-
constructor(...
|
|
7613
|
-
super(...
|
|
7116
|
+
constructor(..._args2) {
|
|
7117
|
+
super(..._args2);
|
|
7614
7118
|
this.name = DISCORD_VOICE_COMMAND_SPEC.name;
|
|
7615
7119
|
this.description = DISCORD_VOICE_COMMAND_SPEC.description;
|
|
7616
7120
|
this.subcommands = [
|
|
7617
7121
|
new JoinCommand(),
|
|
7618
|
-
new
|
|
7619
|
-
new
|
|
7122
|
+
new SessionCommand("leave"),
|
|
7123
|
+
new SessionCommand("status")
|
|
7620
7124
|
];
|
|
7621
7125
|
}
|
|
7622
7126
|
}();
|
|
7623
7127
|
}
|
|
7624
|
-
function isVoiceChannelType(type) {
|
|
7625
|
-
return type === ChannelType.GuildVoice || type === ChannelType.GuildStageVoice;
|
|
7626
|
-
}
|
|
7627
7128
|
//#endregion
|
|
7628
7129
|
//#region extensions/discord/src/monitor/provider.commands.ts
|
|
7629
7130
|
const loadPluginCommandRuntime = createLazyRuntimeModule(() => import("openclaw/plugin-sdk/plugin-command-runtime"));
|
|
@@ -7705,7 +7206,6 @@ function attachDiscordDeployRestContext(err, context) {
|
|
|
7705
7206
|
if (typeof context.timeoutMs === "number" && Number.isFinite(context.timeoutMs)) deployErr.deployTimeoutMs = context.timeoutMs;
|
|
7706
7207
|
}
|
|
7707
7208
|
function stringifyDiscordDeployField(value) {
|
|
7708
|
-
if (typeof value === "string") return JSON.stringify(value);
|
|
7709
7209
|
try {
|
|
7710
7210
|
return JSON.stringify(value);
|
|
7711
7211
|
} catch {
|
|
@@ -7723,8 +7223,7 @@ function readDiscordDeployRejectedFields(value) {
|
|
|
7723
7223
|
function resolveDiscordRejectedDeployEntriesSource(rawBody) {
|
|
7724
7224
|
if (!rawBody || typeof rawBody !== "object") return null;
|
|
7725
7225
|
const payload = rawBody;
|
|
7726
|
-
|
|
7727
|
-
return source && typeof source === "object" ? source : null;
|
|
7226
|
+
return (payload.errors && typeof payload.errors === "object" ? payload.errors : void 0) ?? rawBody;
|
|
7728
7227
|
}
|
|
7729
7228
|
function readDiscordDeployObjectField(value, field) {
|
|
7730
7229
|
return value && typeof value === "object" && field in value ? value[field] : void 0;
|
|
@@ -7739,9 +7238,7 @@ function formatDiscordDeployRestOperation(err) {
|
|
|
7739
7238
|
const method = typeof err.deployRestMethod === "string" && err.deployRestMethod.trim().length > 0 ? err.deployRestMethod.toUpperCase() : void 0;
|
|
7740
7239
|
const path = typeof err.deployRestPath === "string" && err.deployRestPath.trim().length > 0 ? err.deployRestPath : void 0;
|
|
7741
7240
|
if (method && path) return `${method} ${path}`;
|
|
7742
|
-
|
|
7743
|
-
if (path) return path;
|
|
7744
|
-
return "request";
|
|
7241
|
+
return method ?? path ?? "request";
|
|
7745
7242
|
}
|
|
7746
7243
|
function formatDiscordDeployErrorMessage(err) {
|
|
7747
7244
|
if (!isAbortLikeError(err)) return formatErrorMessage(err);
|
|
@@ -7777,19 +7274,19 @@ function formatDiscordDeployRateLimitDetails(err) {
|
|
|
7777
7274
|
const rateLimit = resolveDiscordDeployRateLimitDetails(err);
|
|
7778
7275
|
if (!rateLimit) return "";
|
|
7779
7276
|
const details = [];
|
|
7780
|
-
if (
|
|
7781
|
-
if (
|
|
7277
|
+
if (rateLimit.status !== void 0) details.push(`status=${rateLimit.status}`);
|
|
7278
|
+
if (rateLimit.retryAfterMs !== void 0) details.push(`retryAfter=${formatDurationSeconds(rateLimit.retryAfterMs, { decimals: 1 })}`);
|
|
7782
7279
|
if (rateLimit.scope) details.push(`scope=${rateLimit.scope}`);
|
|
7783
|
-
if (
|
|
7280
|
+
if (rateLimit.discordCode !== void 0) details.push(`code=${rateLimit.discordCode}`);
|
|
7784
7281
|
return details.length > 0 ? ` (${details.join(", ")})` : "";
|
|
7785
7282
|
}
|
|
7786
7283
|
function formatDiscordDeployRateLimitWarning(err, accountId) {
|
|
7787
7284
|
const rateLimit = resolveDiscordDeployRateLimitDetails(err);
|
|
7788
7285
|
if (!rateLimit) return;
|
|
7789
7286
|
const parts = [`[${accountId}] slash command deploy rate limited`];
|
|
7790
|
-
if (
|
|
7287
|
+
if (rateLimit.retryAfterMs !== void 0) parts.push(`retry after ${formatDurationSeconds(rateLimit.retryAfterMs, { decimals: 1 })}`);
|
|
7791
7288
|
if (rateLimit.scope) parts.push(`scope=${rateLimit.scope}`);
|
|
7792
|
-
if (
|
|
7289
|
+
if (rateLimit.discordCode !== void 0) parts.push(`code=${rateLimit.discordCode}`);
|
|
7793
7290
|
return `${parts.join("; ")}. Existing slash commands stay active. Message send/receive is unaffected.`;
|
|
7794
7291
|
}
|
|
7795
7292
|
function formatDiscordRejectedDeployEntries(params) {
|
|
@@ -7818,10 +7315,7 @@ function formatDiscordDeployErrorDetails(err) {
|
|
|
7818
7315
|
if (!err || typeof err !== "object") return "";
|
|
7819
7316
|
const rateLimitDetails = formatDiscordDeployRateLimitDetails(err);
|
|
7820
7317
|
if (rateLimitDetails) return rateLimitDetails;
|
|
7821
|
-
const status = err
|
|
7822
|
-
const discordCode = err.discordCode;
|
|
7823
|
-
const rawBody = err.rawBody;
|
|
7824
|
-
const requestBody = err.deployRequestBody;
|
|
7318
|
+
const { status, discordCode, rawBody, deployRequestBody: requestBody } = err;
|
|
7825
7319
|
const details = [];
|
|
7826
7320
|
if (typeof status === "number") details.push(`status=${status}`);
|
|
7827
7321
|
if (typeof discordCode === "number" || typeof discordCode === "string") details.push(`code=${discordCode}`);
|
|
@@ -7862,7 +7356,7 @@ function formatDiscordStartupGatewayState(gateway) {
|
|
|
7862
7356
|
const reconnectAttempts = gateway.reconnectAttempts;
|
|
7863
7357
|
return `gatewayConnected=${gateway.isConnected ? "true" : "false"} reconnectAttempts=${typeof reconnectAttempts === "number" ? reconnectAttempts : "na"}`;
|
|
7864
7358
|
}
|
|
7865
|
-
function logDiscordStartupPhase
|
|
7359
|
+
function logDiscordStartupPhase(params) {
|
|
7866
7360
|
if (!(params.isVerbose ?? isVerbose)()) return;
|
|
7867
7361
|
const elapsedMs = Math.max(0, Date.now() - params.startAt);
|
|
7868
7362
|
const suffix = [params.details, formatDiscordStartupGatewayState(params.gateway)].filter((value) => Boolean(value)).join(" ");
|
|
@@ -7970,7 +7464,7 @@ async function deployDiscordCommands(params) {
|
|
|
7970
7464
|
}
|
|
7971
7465
|
function runDiscordCommandDeployInBackground(params) {
|
|
7972
7466
|
if (!params.enabled) return;
|
|
7973
|
-
logDiscordStartupPhase
|
|
7467
|
+
logDiscordStartupPhase({
|
|
7974
7468
|
runtime: params.runtime,
|
|
7975
7469
|
accountId: params.accountId,
|
|
7976
7470
|
phase: "deploy-commands:scheduled",
|
|
@@ -7979,7 +7473,7 @@ function runDiscordCommandDeployInBackground(params) {
|
|
|
7979
7473
|
isVerbose: params.isVerbose
|
|
7980
7474
|
});
|
|
7981
7475
|
deployDiscordCommands(params).then(() => {
|
|
7982
|
-
logDiscordStartupPhase
|
|
7476
|
+
logDiscordStartupPhase({
|
|
7983
7477
|
runtime: params.runtime,
|
|
7984
7478
|
accountId: params.accountId,
|
|
7985
7479
|
phase: "deploy-commands:done",
|
|
@@ -8056,7 +7550,7 @@ var DiscordActivityButton = class extends Button {
|
|
|
8056
7550
|
};
|
|
8057
7551
|
function createDiscordActivityButton(ctx, applicationId, deps = {}) {
|
|
8058
7552
|
const runtime = getDiscordActivitiesRuntime();
|
|
8059
|
-
if (!runtime
|
|
7553
|
+
if (!runtime) return null;
|
|
8060
7554
|
if (applicationId) runtime.registerApplicationId(ctx.accountId, applicationId);
|
|
8061
7555
|
if (!runtime.resolveAccount(ctx.accountId, ctx.cfg)) return null;
|
|
8062
7556
|
return new DiscordActivityButton(ctx, {
|
|
@@ -8171,36 +7665,134 @@ async function resolveComponentInteractionContext(params) {
|
|
|
8171
7665
|
};
|
|
8172
7666
|
}
|
|
8173
7667
|
//#endregion
|
|
8174
|
-
//#region extensions/discord/src/monitor/agent-components-
|
|
8175
|
-
|
|
8176
|
-
if (!
|
|
8177
|
-
|
|
8178
|
-
const policy = await readDiscordInteractionPolicy(params.ctx.readPolicy);
|
|
8179
|
-
if (!policy) {
|
|
8180
|
-
await replyUnavailableComponentInteraction(params.interaction, "Access policy is still updating. Try this interaction again.");
|
|
8181
|
-
return null;
|
|
8182
|
-
}
|
|
8183
|
-
return {
|
|
8184
|
-
...params.ctx,
|
|
8185
|
-
...policy,
|
|
8186
|
-
isPolicyCurrent: policy.isCurrent,
|
|
8187
|
-
readPolicy: void 0
|
|
8188
|
-
};
|
|
8189
|
-
} catch (error) {
|
|
8190
|
-
await replyUnavailableComponentInteraction(params.interaction, "Could not verify the current access policy. Try this interaction again.");
|
|
8191
|
-
throw error;
|
|
8192
|
-
}
|
|
7668
|
+
//#region extensions/discord/src/monitor/agent-components-data.ts
|
|
7669
|
+
function readParsedComponentId(data) {
|
|
7670
|
+
if (!data || typeof data !== "object") return;
|
|
7671
|
+
return "cid" in data ? data.cid : data.componentId;
|
|
8193
7672
|
}
|
|
8194
|
-
|
|
8195
|
-
|
|
8196
|
-
|
|
8197
|
-
|
|
8198
|
-
|
|
8199
|
-
if (
|
|
8200
|
-
|
|
8201
|
-
|
|
8202
|
-
|
|
8203
|
-
|
|
7673
|
+
function normalizeComponentId(value) {
|
|
7674
|
+
if (typeof value === "string") return normalizeOptionalString(value);
|
|
7675
|
+
if (typeof value === "number" && Number.isFinite(value)) return String(value);
|
|
7676
|
+
}
|
|
7677
|
+
function mapOptionLabels(options, values) {
|
|
7678
|
+
if (!options || options.length === 0) return values;
|
|
7679
|
+
const map = new Map(options.map((option) => [option.value, option.label]));
|
|
7680
|
+
return values.map((value) => map.get(value) ?? value);
|
|
7681
|
+
}
|
|
7682
|
+
function parseAgentComponentData(data) {
|
|
7683
|
+
const raw = readParsedComponentId(data);
|
|
7684
|
+
const componentId = typeof raw === "string" ? decodeCustomIdComponent(raw) : typeof raw === "number" ? String(raw) : null;
|
|
7685
|
+
if (!componentId) return null;
|
|
7686
|
+
return { componentId };
|
|
7687
|
+
}
|
|
7688
|
+
function parseDiscordComponentData(data, customId) {
|
|
7689
|
+
if (!data || typeof data !== "object") return null;
|
|
7690
|
+
const rawComponentId = readParsedComponentId(data);
|
|
7691
|
+
const rawModalId = "mid" in data ? data.mid : data.modalId;
|
|
7692
|
+
let componentId = normalizeComponentId(rawComponentId);
|
|
7693
|
+
let modalId = normalizeComponentId(rawModalId);
|
|
7694
|
+
if (!componentId && customId) {
|
|
7695
|
+
const parsed = parseDiscordComponentCustomId(customId);
|
|
7696
|
+
if (parsed) {
|
|
7697
|
+
componentId = parsed.componentId;
|
|
7698
|
+
modalId = parsed.modalId;
|
|
7699
|
+
}
|
|
7700
|
+
}
|
|
7701
|
+
if (!componentId) return null;
|
|
7702
|
+
return {
|
|
7703
|
+
componentId,
|
|
7704
|
+
modalId
|
|
7705
|
+
};
|
|
7706
|
+
}
|
|
7707
|
+
function parseDiscordModalId(data, customId) {
|
|
7708
|
+
if (data && typeof data === "object") {
|
|
7709
|
+
const modalId = normalizeComponentId("mid" in data ? data.mid : data.modalId);
|
|
7710
|
+
if (modalId) return modalId;
|
|
7711
|
+
}
|
|
7712
|
+
if (customId) return parseDiscordModalCustomId(customId);
|
|
7713
|
+
return null;
|
|
7714
|
+
}
|
|
7715
|
+
function resolveInteractionCustomId(interaction) {
|
|
7716
|
+
if (!interaction?.rawData || typeof interaction.rawData !== "object") return;
|
|
7717
|
+
if (!("data" in interaction.rawData)) return;
|
|
7718
|
+
return normalizeOptionalString(interaction.rawData.data?.custom_id);
|
|
7719
|
+
}
|
|
7720
|
+
function mapSelectValues(entry, values) {
|
|
7721
|
+
switch (entry.selectType) {
|
|
7722
|
+
case "string": return mapOptionLabels(entry.options, values);
|
|
7723
|
+
case "user":
|
|
7724
|
+
case "role":
|
|
7725
|
+
case "mentionable":
|
|
7726
|
+
case "channel": return values.map((value) => `${entry.selectType}:${value}`);
|
|
7727
|
+
default: return values;
|
|
7728
|
+
}
|
|
7729
|
+
}
|
|
7730
|
+
function resolveModalFieldValues(field, interaction) {
|
|
7731
|
+
const fields = interaction.fields;
|
|
7732
|
+
const required = field.required === true;
|
|
7733
|
+
try {
|
|
7734
|
+
switch (field.type) {
|
|
7735
|
+
case "text": {
|
|
7736
|
+
const value = fields.getText(field.id, required);
|
|
7737
|
+
return value ? [value] : [];
|
|
7738
|
+
}
|
|
7739
|
+
case "select":
|
|
7740
|
+
case "checkbox":
|
|
7741
|
+
case "radio": return mapOptionLabels(field.options, fields.getStringSelect(field.id, required));
|
|
7742
|
+
case "role-select": try {
|
|
7743
|
+
return fields.getRoleSelect(field.id, required).map((role) => role.name ?? role.id);
|
|
7744
|
+
} catch {
|
|
7745
|
+
return fields.getStringSelect(field.id, required);
|
|
7746
|
+
}
|
|
7747
|
+
case "user-select": return fields.getUserSelect(field.id, required).map((user) => formatDiscordUserTag(user));
|
|
7748
|
+
default: return [];
|
|
7749
|
+
}
|
|
7750
|
+
} catch (err) {
|
|
7751
|
+
logError(`agent modal: failed to read field ${field.id}: ${String(err)}`);
|
|
7752
|
+
return [];
|
|
7753
|
+
}
|
|
7754
|
+
}
|
|
7755
|
+
function formatModalSubmissionText(entry, interaction) {
|
|
7756
|
+
const lines = [`Form "${entry.title}" submitted.`];
|
|
7757
|
+
for (const field of entry.fields) {
|
|
7758
|
+
const values = resolveModalFieldValues(field, interaction);
|
|
7759
|
+
if (values.length === 0) continue;
|
|
7760
|
+
lines.push(`- ${field.label}: ${values.join(", ")}`);
|
|
7761
|
+
}
|
|
7762
|
+
if (lines.length === 1) lines.push("- (no values)");
|
|
7763
|
+
return lines.join("\n");
|
|
7764
|
+
}
|
|
7765
|
+
//#endregion
|
|
7766
|
+
//#region extensions/discord/src/monitor/agent-components-live-policy.ts
|
|
7767
|
+
async function resolveAgentComponentPolicyContext(params) {
|
|
7768
|
+
if (!params.ctx.readPolicy) return params.ctx;
|
|
7769
|
+
try {
|
|
7770
|
+
const policy = await readDiscordInteractionPolicy(params.ctx.readPolicy);
|
|
7771
|
+
if (!policy) {
|
|
7772
|
+
await replyUnavailableComponentInteraction(params.interaction, "Access policy is still updating. Try this interaction again.");
|
|
7773
|
+
return null;
|
|
7774
|
+
}
|
|
7775
|
+
return {
|
|
7776
|
+
...params.ctx,
|
|
7777
|
+
...policy,
|
|
7778
|
+
isPolicyCurrent: policy.isCurrent,
|
|
7779
|
+
readPolicy: void 0
|
|
7780
|
+
};
|
|
7781
|
+
} catch (error) {
|
|
7782
|
+
await replyUnavailableComponentInteraction(params.interaction, "Could not verify the current access policy. Try this interaction again.");
|
|
7783
|
+
throw error;
|
|
7784
|
+
}
|
|
7785
|
+
}
|
|
7786
|
+
//#endregion
|
|
7787
|
+
//#region extensions/discord/src/monitor/agent-components-dm-auth.ts
|
|
7788
|
+
async function ensureDmComponentAuthorized(params) {
|
|
7789
|
+
const { ctx, interaction, user, componentLabel, replyOpts } = params;
|
|
7790
|
+
const dmPolicy = ctx.dmPolicy ?? "pairing";
|
|
7791
|
+
if (ctx.discordConfig?.dm?.enabled === false || dmPolicy === "disabled") {
|
|
7792
|
+
logVerbose(`agent ${componentLabel}: blocked (DM policy disabled)`);
|
|
7793
|
+
await replySilently(interaction, {
|
|
7794
|
+
content: "DM interactions are disabled.",
|
|
7795
|
+
...replyOpts
|
|
8204
7796
|
});
|
|
8205
7797
|
return false;
|
|
8206
7798
|
}
|
|
@@ -8243,7 +7835,7 @@ async function ensureDmComponentAuthorized(params) {
|
|
|
8243
7835
|
channel: "discord",
|
|
8244
7836
|
accountId: ctx.accountId,
|
|
8245
7837
|
upsertPairingRequest: async ({ id, meta }) => {
|
|
8246
|
-
return await upsertChannelPairingRequest
|
|
7838
|
+
return await upsertChannelPairingRequest({
|
|
8247
7839
|
channel: "discord",
|
|
8248
7840
|
id,
|
|
8249
7841
|
accountId: ctx.accountId,
|
|
@@ -8393,7 +7985,7 @@ async function ensureGuildComponentMemberAllowed(params) {
|
|
|
8393
7985
|
return false;
|
|
8394
7986
|
}
|
|
8395
7987
|
async function ensureComponentUserAllowed(params) {
|
|
8396
|
-
const allowList = normalizeDiscordAllowList(params.
|
|
7988
|
+
const allowList = normalizeDiscordAllowList(params.allowedUsers, [
|
|
8397
7989
|
"discord:",
|
|
8398
7990
|
"user:",
|
|
8399
7991
|
"pk:"
|
|
@@ -8504,6 +8096,13 @@ async function resolveAuthorizedComponentInteraction(params) {
|
|
|
8504
8096
|
});
|
|
8505
8097
|
return null;
|
|
8506
8098
|
}
|
|
8099
|
+
if (params.allowedUsers !== void 0 && !await ensureComponentUserAllowed({
|
|
8100
|
+
...params,
|
|
8101
|
+
allowedUsers: params.allowedUsers,
|
|
8102
|
+
user,
|
|
8103
|
+
replyOpts,
|
|
8104
|
+
allowNameMatching
|
|
8105
|
+
})) return null;
|
|
8507
8106
|
return {
|
|
8508
8107
|
ctx,
|
|
8509
8108
|
interactionCtx,
|
|
@@ -8552,130 +8151,21 @@ async function resolveComponentCommandAuthorized(params) {
|
|
|
8552
8151
|
});
|
|
8553
8152
|
}
|
|
8554
8153
|
//#endregion
|
|
8555
|
-
//#region extensions/discord/src/monitor/agent-components-data.ts
|
|
8556
|
-
function readParsedComponentId(data) {
|
|
8557
|
-
if (!data || typeof data !== "object") return;
|
|
8558
|
-
return "cid" in data ? data.cid : data.componentId;
|
|
8559
|
-
}
|
|
8560
|
-
function normalizeComponentId(value) {
|
|
8561
|
-
if (typeof value === "string") {
|
|
8562
|
-
const trimmed = value.trim();
|
|
8563
|
-
return trimmed ? trimmed : void 0;
|
|
8564
|
-
}
|
|
8565
|
-
if (typeof value === "number" && Number.isFinite(value)) return String(value);
|
|
8566
|
-
}
|
|
8567
|
-
function mapOptionLabels(options, values) {
|
|
8568
|
-
if (!options || options.length === 0) return values;
|
|
8569
|
-
const map = new Map(options.map((option) => [option.value, option.label]));
|
|
8570
|
-
return values.map((value) => map.get(value) ?? value);
|
|
8571
|
-
}
|
|
8572
|
-
function parseAgentComponentData(data) {
|
|
8573
|
-
const raw = readParsedComponentId(data);
|
|
8574
|
-
const componentId = typeof raw === "string" ? decodeCustomIdComponent(raw) : typeof raw === "number" ? String(raw) : null;
|
|
8575
|
-
if (!componentId) return null;
|
|
8576
|
-
return { componentId };
|
|
8577
|
-
}
|
|
8578
|
-
function parseDiscordComponentData(data, customId) {
|
|
8579
|
-
if (!data || typeof data !== "object") return null;
|
|
8580
|
-
const rawComponentId = readParsedComponentId(data);
|
|
8581
|
-
const rawModalId = "mid" in data ? data.mid : data.modalId;
|
|
8582
|
-
let componentId = normalizeComponentId(rawComponentId);
|
|
8583
|
-
let modalId = normalizeComponentId(rawModalId);
|
|
8584
|
-
if (!componentId && customId) {
|
|
8585
|
-
const parsed = parseDiscordComponentCustomId(customId);
|
|
8586
|
-
if (parsed) {
|
|
8587
|
-
componentId = parsed.componentId;
|
|
8588
|
-
modalId = parsed.modalId;
|
|
8589
|
-
}
|
|
8590
|
-
}
|
|
8591
|
-
if (!componentId) return null;
|
|
8592
|
-
return {
|
|
8593
|
-
componentId,
|
|
8594
|
-
modalId
|
|
8595
|
-
};
|
|
8596
|
-
}
|
|
8597
|
-
function parseDiscordModalId(data, customId) {
|
|
8598
|
-
if (data && typeof data === "object") {
|
|
8599
|
-
const modalId = normalizeComponentId("mid" in data ? data.mid : data.modalId);
|
|
8600
|
-
if (modalId) return modalId;
|
|
8601
|
-
}
|
|
8602
|
-
if (customId) return parseDiscordModalCustomId(customId);
|
|
8603
|
-
return null;
|
|
8604
|
-
}
|
|
8605
|
-
function resolveInteractionCustomId(interaction) {
|
|
8606
|
-
if (!interaction?.rawData || typeof interaction.rawData !== "object") return;
|
|
8607
|
-
if (!("data" in interaction.rawData)) return;
|
|
8608
|
-
const customId = interaction.rawData.data?.custom_id;
|
|
8609
|
-
if (typeof customId !== "string") return;
|
|
8610
|
-
const trimmed = customId.trim();
|
|
8611
|
-
return trimmed ? trimmed : void 0;
|
|
8612
|
-
}
|
|
8613
|
-
function mapSelectValues(entry, values) {
|
|
8614
|
-
if (entry.selectType === "string") return mapOptionLabels(entry.options, values);
|
|
8615
|
-
if (entry.selectType === "user") return values.map((value) => `user:${value}`);
|
|
8616
|
-
if (entry.selectType === "role") return values.map((value) => `role:${value}`);
|
|
8617
|
-
if (entry.selectType === "mentionable") return values.map((value) => `mentionable:${value}`);
|
|
8618
|
-
if (entry.selectType === "channel") return values.map((value) => `channel:${value}`);
|
|
8619
|
-
return values;
|
|
8620
|
-
}
|
|
8621
|
-
function resolveModalFieldValues(field, interaction) {
|
|
8622
|
-
const fields = interaction.fields;
|
|
8623
|
-
const optionLabels = field.options?.map((option) => ({
|
|
8624
|
-
value: option.value,
|
|
8625
|
-
label: option.label
|
|
8626
|
-
}));
|
|
8627
|
-
const required = field.required === true;
|
|
8628
|
-
try {
|
|
8629
|
-
switch (field.type) {
|
|
8630
|
-
case "text": {
|
|
8631
|
-
const value = required ? fields.getText(field.id, true) : fields.getText(field.id);
|
|
8632
|
-
return value ? [value] : [];
|
|
8633
|
-
}
|
|
8634
|
-
case "select":
|
|
8635
|
-
case "checkbox":
|
|
8636
|
-
case "radio": return mapOptionLabels(optionLabels, required ? fields.getStringSelect(field.id, true) : fields.getStringSelect(field.id) ?? []);
|
|
8637
|
-
case "role-select": try {
|
|
8638
|
-
return (required ? fields.getRoleSelect(field.id, true) : fields.getRoleSelect(field.id) ?? []).map((role) => role.name ?? role.id);
|
|
8639
|
-
} catch {
|
|
8640
|
-
return required ? fields.getStringSelect(field.id, true) : fields.getStringSelect(field.id) ?? [];
|
|
8641
|
-
}
|
|
8642
|
-
case "user-select": return (required ? fields.getUserSelect(field.id, true) : fields.getUserSelect(field.id) ?? []).map((user) => formatDiscordUserTag(user));
|
|
8643
|
-
default: return [];
|
|
8644
|
-
}
|
|
8645
|
-
} catch (err) {
|
|
8646
|
-
logError(`agent modal: failed to read field ${field.id}: ${String(err)}`);
|
|
8647
|
-
return [];
|
|
8648
|
-
}
|
|
8649
|
-
}
|
|
8650
|
-
function formatModalSubmissionText(entry, interaction) {
|
|
8651
|
-
const lines = [`Form "${entry.title}" submitted.`];
|
|
8652
|
-
for (const field of entry.fields) {
|
|
8653
|
-
const values = resolveModalFieldValues(field, interaction);
|
|
8654
|
-
if (values.length === 0) continue;
|
|
8655
|
-
lines.push(`- ${field.label}: ${values.join(", ")}`);
|
|
8656
|
-
}
|
|
8657
|
-
if (lines.length === 1) lines.push("- (no values)");
|
|
8658
|
-
return lines.join("\n");
|
|
8659
|
-
}
|
|
8660
|
-
//#endregion
|
|
8661
|
-
//#region extensions/discord/src/monitor/agent-components-helpers.ts
|
|
8662
|
-
const AGENT_BUTTON_KEY = "agent";
|
|
8663
|
-
const AGENT_SELECT_KEY = "agentsel";
|
|
8664
|
-
//#endregion
|
|
8665
8154
|
//#region extensions/discord/src/monitor/reply-context.ts
|
|
8666
8155
|
function resolveReplyContext(message, resolveDiscordMessageText) {
|
|
8667
|
-
const
|
|
8668
|
-
if (!
|
|
8156
|
+
const id = resolveDiscordReferencedReplyMessageId(message);
|
|
8157
|
+
if (!id) return null;
|
|
8158
|
+
const referenced = resolveDiscordReferencedReplyMessage(message);
|
|
8159
|
+
const channelId = message.messageReference?.channel_id ?? message.channelId;
|
|
8160
|
+
if (!referenced?.author || referenced.id !== id) return null;
|
|
8669
8161
|
const referencedText = resolveDiscordMessageText(referenced, { includeForwarded: true });
|
|
8670
|
-
const hasVisibleMedia = referenced.attachments.length > 0 || !referencedText && resolveDiscordMessageStickers(referenced).length > 0;
|
|
8671
|
-
if (!referencedText && !hasVisibleMedia) return null;
|
|
8672
8162
|
const sender = resolveDiscordSenderIdentity({
|
|
8673
8163
|
author: referenced.author,
|
|
8674
8164
|
pluralkitInfo: null
|
|
8675
8165
|
});
|
|
8676
8166
|
return {
|
|
8677
|
-
id
|
|
8678
|
-
channelId
|
|
8167
|
+
id,
|
|
8168
|
+
channelId,
|
|
8679
8169
|
sender: sender.tag ?? sender.label ?? "unknown",
|
|
8680
8170
|
senderId: referenced.author.id,
|
|
8681
8171
|
senderName: referenced.author.username ?? void 0,
|
|
@@ -8759,14 +8249,10 @@ function formatDiscordReplySkip(params) {
|
|
|
8759
8249
|
const context = [`target=${params.target}`, params.sessionKey ? `session=${params.sessionKey}` : void 0].filter(Boolean).join(" ");
|
|
8760
8250
|
return `discord ${params.kind} reply skipped (${params.reason}): ${context}`;
|
|
8761
8251
|
}
|
|
8762
|
-
function resolveTargetChannelId(target) {
|
|
8763
|
-
if (!target.startsWith("channel:")) return;
|
|
8764
|
-
return target.slice(8).trim() || void 0;
|
|
8765
|
-
}
|
|
8766
8252
|
function resolveBoundThreadBinding(params) {
|
|
8767
8253
|
const sessionKey = params.sessionKey?.trim();
|
|
8768
8254
|
if (!params.threadBindings || !sessionKey) return;
|
|
8769
|
-
const targetChannelId =
|
|
8255
|
+
const targetChannelId = params.target.startsWith("channel:") ? params.target.slice(8).trim() : void 0;
|
|
8770
8256
|
if (!targetChannelId) return;
|
|
8771
8257
|
return params.threadBindings.listBySessionKey(sessionKey).find((entry) => entry.threadId === targetChannelId);
|
|
8772
8258
|
}
|
|
@@ -8797,27 +8283,6 @@ function createDiscordDeliveryDeps(params) {
|
|
|
8797
8283
|
})
|
|
8798
8284
|
};
|
|
8799
8285
|
}
|
|
8800
|
-
function resolveDiscordDeliveryOptions(params) {
|
|
8801
|
-
const binding = resolveBoundThreadBinding({
|
|
8802
|
-
threadBindings: params.threadBindings,
|
|
8803
|
-
sessionKey: params.sessionKey,
|
|
8804
|
-
target: params.target
|
|
8805
|
-
});
|
|
8806
|
-
return {
|
|
8807
|
-
to: binding ? `channel:${binding.channelId}` : params.target,
|
|
8808
|
-
threadId: binding?.threadId,
|
|
8809
|
-
agentId: binding?.agentId,
|
|
8810
|
-
identity: resolveBindingIdentity(params.cfg, binding),
|
|
8811
|
-
mediaAccess: params.mediaLocalRoots?.length ? { localRoots: params.mediaLocalRoots } : void 0,
|
|
8812
|
-
replyToMode: params.replyToMode ?? "all",
|
|
8813
|
-
formatting: {
|
|
8814
|
-
textLimit: params.textLimit,
|
|
8815
|
-
maxLinesPerMessage: params.maxLinesPerMessage,
|
|
8816
|
-
tableMode: params.tableMode,
|
|
8817
|
-
chunkMode: params.chunkMode
|
|
8818
|
-
}
|
|
8819
|
-
};
|
|
8820
|
-
}
|
|
8821
8286
|
function formatDiscordReasoningPayload(payload) {
|
|
8822
8287
|
if (payload.isReasoning !== true) return payload;
|
|
8823
8288
|
const text = typeof payload.text === "string" ? payload.text.trim() : "";
|
|
@@ -8829,8 +8294,8 @@ function formatDiscordReasoningPayload(payload) {
|
|
|
8829
8294
|
return nextPayload;
|
|
8830
8295
|
}
|
|
8831
8296
|
async function deliverDiscordReply(params) {
|
|
8832
|
-
params
|
|
8833
|
-
const
|
|
8297
|
+
const binding = resolveBoundThreadBinding(params);
|
|
8298
|
+
const to = binding ? `channel:${binding.channelId}` : params.target;
|
|
8834
8299
|
const payloads = sanitizeDiscordFrontChannelReplyPayloads(params.replies, { kind: params.kind }).map(formatDiscordReasoningPayload).map((payload) => params.bindPendingFinalDelivery?.(payload) ?? payload);
|
|
8835
8300
|
if (payloads.length === 0) return {
|
|
8836
8301
|
visibleReplySent: false,
|
|
@@ -8839,14 +8304,19 @@ async function deliverDiscordReply(params) {
|
|
|
8839
8304
|
const send = await sendDurableMessageBatch({
|
|
8840
8305
|
cfg: params.cfg,
|
|
8841
8306
|
channel: "discord",
|
|
8842
|
-
to
|
|
8307
|
+
to,
|
|
8843
8308
|
accountId: params.accountId,
|
|
8844
8309
|
payloads,
|
|
8845
8310
|
replyToId: normalizeOptionalString(params.replyToId),
|
|
8846
|
-
replyToMode:
|
|
8847
|
-
formatting:
|
|
8848
|
-
|
|
8849
|
-
|
|
8311
|
+
replyToMode: params.replyToMode ?? "all",
|
|
8312
|
+
formatting: {
|
|
8313
|
+
textLimit: params.textLimit,
|
|
8314
|
+
maxLinesPerMessage: params.maxLinesPerMessage,
|
|
8315
|
+
tableMode: params.tableMode,
|
|
8316
|
+
chunkMode: params.chunkMode
|
|
8317
|
+
},
|
|
8318
|
+
threadId: binding?.threadId,
|
|
8319
|
+
identity: resolveBindingIdentity(params.cfg, binding),
|
|
8850
8320
|
onPlatformSendDispatch: params.onPlatformSendDispatch,
|
|
8851
8321
|
assertDirectAdapterHandoff: params.assertPlatformSendAuthorized,
|
|
8852
8322
|
deps: createDiscordDeliveryDeps({
|
|
@@ -8855,11 +8325,11 @@ async function deliverDiscordReply(params) {
|
|
|
8855
8325
|
rest: params.rest,
|
|
8856
8326
|
allowedMentions: params.allowedMentions
|
|
8857
8327
|
}),
|
|
8858
|
-
mediaAccess:
|
|
8328
|
+
mediaAccess: params.mediaLocalRoots?.length ? { localRoots: params.mediaLocalRoots } : void 0,
|
|
8859
8329
|
session: buildOutboundSessionContext({
|
|
8860
8330
|
cfg: params.cfg,
|
|
8861
8331
|
sessionKey: params.sessionKey,
|
|
8862
|
-
agentId:
|
|
8332
|
+
agentId: binding?.agentId,
|
|
8863
8333
|
requesterAccountId: params.accountId
|
|
8864
8334
|
})
|
|
8865
8335
|
});
|
|
@@ -8875,7 +8345,7 @@ async function deliverDiscordReply(params) {
|
|
|
8875
8345
|
}
|
|
8876
8346
|
};
|
|
8877
8347
|
}
|
|
8878
|
-
if (send.results.length === 0) throw new Error(`discord final reply produced no delivered message for ${
|
|
8348
|
+
if (send.results.length === 0) throw new Error(`discord final reply produced no delivered message for ${to}`);
|
|
8879
8349
|
const deliveryResult = {
|
|
8880
8350
|
messageIds: listMessageReceiptPlatformIds(send.receipt),
|
|
8881
8351
|
receipt: send.receipt,
|
|
@@ -8886,8 +8356,8 @@ async function deliverDiscordReply(params) {
|
|
|
8886
8356
|
}
|
|
8887
8357
|
//#endregion
|
|
8888
8358
|
//#region extensions/discord/src/monitor/agent-components.dispatch.ts
|
|
8889
|
-
const
|
|
8890
|
-
const loadTypingRuntime = createLazyRuntimeModule(() => import("./typing-
|
|
8359
|
+
const loadReplyRuntime = createLazyRuntimeModule(() => import("openclaw/plugin-sdk/reply-runtime"));
|
|
8360
|
+
const loadTypingRuntime = createLazyRuntimeModule(() => import("./typing-BiHCzBRu.mjs").then((n) => n.n));
|
|
8891
8361
|
function buildDiscordComponentConversationLabel(params) {
|
|
8892
8362
|
if (params.interactionCtx.isDirectMessage) return buildDirectLabel(params.interactionCtx.user);
|
|
8893
8363
|
if (params.interactionCtx.isGroupDm) return `Group DM #${params.channelCtx.channelName ?? params.interactionCtx.channelId} channel id:${params.interactionCtx.channelId}`;
|
|
@@ -8902,16 +8372,8 @@ function resolveDiscordComponentChatType(interactionCtx) {
|
|
|
8902
8372
|
if (interactionCtx.isGroupDm) return "group";
|
|
8903
8373
|
return "channel";
|
|
8904
8374
|
}
|
|
8905
|
-
function resolveDiscordComponentOriginatingTo(interactionCtx) {
|
|
8906
|
-
return resolveDiscordConversationIdentity({
|
|
8907
|
-
isDirectMessage: interactionCtx.isDirectMessage,
|
|
8908
|
-
userId: interactionCtx.userId,
|
|
8909
|
-
channelId: interactionCtx.channelId
|
|
8910
|
-
});
|
|
8911
|
-
}
|
|
8912
8375
|
async function dispatchDiscordComponentEvent(params) {
|
|
8913
8376
|
const { ctx, interaction, interactionCtx, channelCtx, guildInfo, eventText } = params;
|
|
8914
|
-
const runtime = ctx.runtime ?? createNonExitingRuntime();
|
|
8915
8377
|
const route = resolveAgentComponentRoute({
|
|
8916
8378
|
ctx,
|
|
8917
8379
|
rawGuildId: interactionCtx.rawGuildId,
|
|
@@ -8925,7 +8387,6 @@ async function dispatchDiscordComponentEvent(params) {
|
|
|
8925
8387
|
const sessionKey = params.routeOverrides?.sessionKey ?? route.sessionKey;
|
|
8926
8388
|
const agentId = params.routeOverrides?.agentId ?? route.agentId;
|
|
8927
8389
|
const accountId = params.routeOverrides?.accountId ?? route.accountId;
|
|
8928
|
-
const inboundLastRouteSessionKey = sessionKey;
|
|
8929
8390
|
const fromLabel = buildDiscordComponentConversationLabel({
|
|
8930
8391
|
interactionCtx,
|
|
8931
8392
|
interaction,
|
|
@@ -8960,7 +8421,7 @@ async function dispatchDiscordComponentEvent(params) {
|
|
|
8960
8421
|
isGuild: !interactionCtx.isDirectMessage
|
|
8961
8422
|
});
|
|
8962
8423
|
const groupSystemPrompt = buildDiscordGroupSystemPrompt(channelConfig);
|
|
8963
|
-
const pinnedMainDmOwner = interactionCtx.isDirectMessage ? resolvePinnedMainDmOwnerFromAllowlist
|
|
8424
|
+
const pinnedMainDmOwner = interactionCtx.isDirectMessage ? resolvePinnedMainDmOwnerFromAllowlist({
|
|
8964
8425
|
dmScope: ctx.cfg.session?.dmScope,
|
|
8965
8426
|
allowFrom: channelConfig?.users ?? guildInfo?.users,
|
|
8966
8427
|
normalizeEntry: (entry) => {
|
|
@@ -8979,12 +8440,17 @@ async function dispatchDiscordComponentEvent(params) {
|
|
|
8979
8440
|
guildInfo,
|
|
8980
8441
|
allowNameMatching
|
|
8981
8442
|
});
|
|
8982
|
-
const storePath = resolveStorePath
|
|
8443
|
+
const storePath = resolveStorePath(ctx.cfg.session?.store, { agentId });
|
|
8983
8444
|
const envelopeOptions = resolveEnvelopeFormatOptions(ctx.cfg);
|
|
8984
|
-
const previousTimestamp = readSessionUpdatedAt
|
|
8445
|
+
const previousTimestamp = readSessionUpdatedAt({
|
|
8985
8446
|
storePath,
|
|
8986
8447
|
sessionKey
|
|
8987
8448
|
});
|
|
8449
|
+
const originatingTo = resolveDiscordConversationIdentity({
|
|
8450
|
+
isDirectMessage: interactionCtx.isDirectMessage,
|
|
8451
|
+
userId: interactionCtx.userId,
|
|
8452
|
+
channelId: interactionCtx.channelId
|
|
8453
|
+
});
|
|
8988
8454
|
const timestamp = Date.now();
|
|
8989
8455
|
const combinedBody = formatInboundEnvelope({
|
|
8990
8456
|
channel: "Discord",
|
|
@@ -8996,9 +8462,7 @@ async function dispatchDiscordComponentEvent(params) {
|
|
|
8996
8462
|
previousTimestamp,
|
|
8997
8463
|
envelope: envelopeOptions
|
|
8998
8464
|
});
|
|
8999
|
-
const { createReplyReferencePlanner, finalizeInboundContext, resolveChunkMode, resolveTextChunkLimit } = await (
|
|
9000
|
-
return { ...await loadConversationRuntime$1() };
|
|
9001
|
-
})();
|
|
8465
|
+
const { createReplyReferencePlanner, finalizeInboundContext, resolveChunkMode, resolveTextChunkLimit } = await loadReplyRuntime();
|
|
9002
8466
|
const ctxPayload = finalizeInboundContext({
|
|
9003
8467
|
Body: combinedBody,
|
|
9004
8468
|
BodyForAgent: eventText,
|
|
@@ -9040,7 +8504,7 @@ async function dispatchDiscordComponentEvent(params) {
|
|
|
9040
8504
|
MessageSid: interaction.rawData.id,
|
|
9041
8505
|
Timestamp: timestamp,
|
|
9042
8506
|
OriginatingChannel: "discord",
|
|
9043
|
-
OriginatingTo:
|
|
8507
|
+
OriginatingTo: originatingTo ?? `channel:${interactionCtx.channelId}`
|
|
9044
8508
|
});
|
|
9045
8509
|
const deliverTarget = `channel:${interactionCtx.channelId}`;
|
|
9046
8510
|
const typingChannelId = interactionCtx.channelId;
|
|
@@ -9086,11 +8550,11 @@ async function dispatchDiscordComponentEvent(params) {
|
|
|
9086
8550
|
dispatchReplyFromConfig: ctx.channelRuntime?.reply?.dispatchReplyFromConfig,
|
|
9087
8551
|
record: {
|
|
9088
8552
|
updateLastRoute: interactionCtx.isDirectMessage ? {
|
|
9089
|
-
sessionKey
|
|
8553
|
+
sessionKey,
|
|
9090
8554
|
channel: "discord",
|
|
9091
|
-
to:
|
|
8555
|
+
to: originatingTo ?? `user:${interactionCtx.userId}`,
|
|
9092
8556
|
accountId,
|
|
9093
|
-
mainDmOwnerPin:
|
|
8557
|
+
mainDmOwnerPin: sessionKey === route.mainSessionKey && pinnedMainDmOwner ? {
|
|
9094
8558
|
ownerRecipient: pinnedMainDmOwner,
|
|
9095
8559
|
senderRecipient: interactionCtx.userId,
|
|
9096
8560
|
onSkip: ({ ownerRecipient, senderRecipient }) => {
|
|
@@ -9112,7 +8576,6 @@ async function dispatchDiscordComponentEvent(params) {
|
|
|
9112
8576
|
token,
|
|
9113
8577
|
accountId,
|
|
9114
8578
|
rest: interaction.client.rest,
|
|
9115
|
-
runtime,
|
|
9116
8579
|
replyToId,
|
|
9117
8580
|
replyToMode,
|
|
9118
8581
|
textLimit,
|
|
@@ -9169,7 +8632,7 @@ async function dispatchDiscordPluginInteractiveHandler(params) {
|
|
|
9169
8632
|
}
|
|
9170
8633
|
//#endregion
|
|
9171
8634
|
//#region extensions/discord/src/monitor/agent-components.plugin-interactive.ts
|
|
9172
|
-
const loadConversationRuntime = createLazyRuntimeModule(() => import("
|
|
8635
|
+
const loadConversationRuntime = createLazyRuntimeModule(() => import("openclaw/plugin-sdk/conversation-runtime"));
|
|
9173
8636
|
async function dispatchPluginDiscordInteractiveEvent(params) {
|
|
9174
8637
|
const normalizedConversationId = params.interactionCtx.rawGuildId || params.channelCtx.channelType === ChannelType.GroupDM ? `channel:${params.interactionCtx.channelId}` : `user:${params.interactionCtx.userId}`;
|
|
9175
8638
|
let responded = false;
|
|
@@ -9224,13 +8687,16 @@ async function dispatchPluginDiscordInteractiveEvent(params) {
|
|
|
9224
8687
|
});
|
|
9225
8688
|
}
|
|
9226
8689
|
};
|
|
8690
|
+
const acknowledgeSilently = async () => {
|
|
8691
|
+
try {
|
|
8692
|
+
await respond.acknowledge();
|
|
8693
|
+
} catch {}
|
|
8694
|
+
};
|
|
9227
8695
|
const conversationRuntime = await loadConversationRuntime();
|
|
9228
8696
|
const pluginBindingApproval = conversationRuntime.parsePluginBindingApprovalCustomId(params.data);
|
|
9229
8697
|
if (pluginBindingApproval) {
|
|
9230
8698
|
const { buildPluginBindingResolvedText, resolvePluginConversationBindingApproval } = conversationRuntime;
|
|
9231
|
-
|
|
9232
|
-
await respond.acknowledge();
|
|
9233
|
-
} catch {}
|
|
8699
|
+
await acknowledgeSilently();
|
|
9234
8700
|
const resolved = await resolvePluginConversationBindingApproval({
|
|
9235
8701
|
approvalId: pluginBindingApproval.approvalId,
|
|
9236
8702
|
decision: pluginBindingApproval.decision,
|
|
@@ -9275,24 +8741,18 @@ async function dispatchPluginDiscordInteractiveEvent(params) {
|
|
|
9275
8741
|
}
|
|
9276
8742
|
},
|
|
9277
8743
|
respond,
|
|
9278
|
-
onMatched:
|
|
9279
|
-
try {
|
|
9280
|
-
await respond.acknowledge();
|
|
9281
|
-
} catch {}
|
|
9282
|
-
}
|
|
8744
|
+
onMatched: acknowledgeSilently
|
|
9283
8745
|
});
|
|
9284
8746
|
if (!dispatched.matched) return "unmatched";
|
|
9285
8747
|
if (dispatched.handled) {
|
|
9286
|
-
if (!responded)
|
|
9287
|
-
await respond.acknowledge();
|
|
9288
|
-
} catch {}
|
|
8748
|
+
if (!responded) await acknowledgeSilently();
|
|
9289
8749
|
return "handled";
|
|
9290
8750
|
}
|
|
9291
8751
|
return "unmatched";
|
|
9292
8752
|
}
|
|
9293
8753
|
//#endregion
|
|
9294
8754
|
//#region extensions/discord/src/monitor/agent-components.handlers.ts
|
|
9295
|
-
const loadComponentsRuntime = createLazyRuntimeModule(() => import("./components-
|
|
8755
|
+
const loadComponentsRuntime = createLazyRuntimeModule(() => import("./components-Cq1PvIpN.mjs").then((n) => n.t));
|
|
9296
8756
|
async function handleDiscordComponentEvent(params) {
|
|
9297
8757
|
const parsed = parseDiscordComponentData(params.data, resolveInteractionCustomId(params.interaction));
|
|
9298
8758
|
if (!parsed) {
|
|
@@ -9315,19 +8775,11 @@ async function handleDiscordComponentEvent(params) {
|
|
|
9315
8775
|
label: params.label,
|
|
9316
8776
|
componentLabel: params.componentLabel,
|
|
9317
8777
|
unauthorizedReply,
|
|
8778
|
+
allowedUsers: entry.allowedUsers,
|
|
9318
8779
|
defer: false
|
|
9319
8780
|
});
|
|
9320
8781
|
if (!authorized) return;
|
|
9321
|
-
const { ctx, interactionCtx, channelCtx, guildInfo,
|
|
9322
|
-
if (!await ensureComponentUserAllowed({
|
|
9323
|
-
entry,
|
|
9324
|
-
interaction: params.interaction,
|
|
9325
|
-
user,
|
|
9326
|
-
replyOpts,
|
|
9327
|
-
componentLabel: params.componentLabel,
|
|
9328
|
-
unauthorizedReply,
|
|
9329
|
-
allowNameMatching
|
|
9330
|
-
})) return;
|
|
8782
|
+
const { ctx, interactionCtx, channelCtx, guildInfo, commandAuthorized, replyOpts } = authorized;
|
|
9331
8783
|
const consumed = await resolveDiscordComponentEntryWithPersistence({
|
|
9332
8784
|
id: parsed.componentId,
|
|
9333
8785
|
consume: !entry.reusable
|
|
@@ -9363,14 +8815,11 @@ async function handleDiscordComponentEvent(params) {
|
|
|
9363
8815
|
label: consumed.label,
|
|
9364
8816
|
values
|
|
9365
8817
|
});
|
|
9366
|
-
|
|
9367
|
-
|
|
9368
|
-
|
|
9369
|
-
|
|
9370
|
-
|
|
9371
|
-
} catch (err) {
|
|
9372
|
-
logError(`${params.label}: failed to acknowledge interaction: ${String(err)}`);
|
|
9373
|
-
}
|
|
8818
|
+
await ackComponentInteraction({
|
|
8819
|
+
interaction: params.interaction,
|
|
8820
|
+
replyOpts,
|
|
8821
|
+
label: params.label
|
|
8822
|
+
});
|
|
9374
8823
|
await dispatchDiscordComponentEvent({
|
|
9375
8824
|
ctx,
|
|
9376
8825
|
interaction: params.interaction,
|
|
@@ -9407,25 +8856,14 @@ async function handleDiscordModalTrigger(params) {
|
|
|
9407
8856
|
await replyUnavailableComponentInteraction(params.interaction, "This form is no longer available.");
|
|
9408
8857
|
return;
|
|
9409
8858
|
}
|
|
9410
|
-
|
|
9411
|
-
const authorized = await resolveAuthorizedComponentInteraction({
|
|
8859
|
+
if (!await resolveAuthorizedComponentInteraction({
|
|
9412
8860
|
ctx: params.ctx,
|
|
9413
8861
|
interaction: params.interaction,
|
|
9414
8862
|
label: params.label,
|
|
9415
8863
|
componentLabel: "form",
|
|
9416
|
-
unauthorizedReply,
|
|
8864
|
+
unauthorizedReply: "You are not authorized to use this form.",
|
|
8865
|
+
allowedUsers: entry.allowedUsers,
|
|
9417
8866
|
defer: false
|
|
9418
|
-
});
|
|
9419
|
-
if (!authorized) return;
|
|
9420
|
-
const { user, replyOpts, allowNameMatching } = authorized;
|
|
9421
|
-
if (!await ensureComponentUserAllowed({
|
|
9422
|
-
entry,
|
|
9423
|
-
interaction: params.interaction,
|
|
9424
|
-
user,
|
|
9425
|
-
replyOpts,
|
|
9426
|
-
componentLabel: "form",
|
|
9427
|
-
unauthorizedReply,
|
|
9428
|
-
allowNameMatching
|
|
9429
8867
|
})) return;
|
|
9430
8868
|
const consumed = await resolveDiscordComponentEntryWithPersistence({
|
|
9431
8869
|
id: parsed.componentId,
|
|
@@ -9460,11 +8898,11 @@ const discordComponentControlHandlers = {
|
|
|
9460
8898
|
var DiscordComponentModal = class extends Modal {
|
|
9461
8899
|
constructor(ctx) {
|
|
9462
8900
|
super();
|
|
8901
|
+
this.ctx = ctx;
|
|
9463
8902
|
this.title = "OpenClaw form";
|
|
9464
8903
|
this.customId = "__openclaw_discord_component_modal_wildcard__";
|
|
9465
8904
|
this.components = [];
|
|
9466
8905
|
this.customIdParser = parseDiscordModalCustomIdForInteraction;
|
|
9467
|
-
this.ctx = ctx;
|
|
9468
8906
|
}
|
|
9469
8907
|
async run(interaction, data) {
|
|
9470
8908
|
const modalId = parseDiscordModalId(data, resolveInteractionCustomId(interaction));
|
|
@@ -9481,32 +8919,18 @@ var DiscordComponentModal = class extends Modal {
|
|
|
9481
8919
|
await replyUnavailableComponentInteraction(interaction, "This form has expired.");
|
|
9482
8920
|
return;
|
|
9483
8921
|
}
|
|
9484
|
-
const unauthorizedReply = "You are not authorized to use this form.";
|
|
9485
8922
|
const authorized = await resolveAuthorizedComponentInteraction({
|
|
9486
8923
|
ctx: this.ctx,
|
|
9487
8924
|
interaction,
|
|
9488
8925
|
label: "discord component modal",
|
|
9489
8926
|
componentLabel: "form",
|
|
9490
|
-
unauthorizedReply,
|
|
8927
|
+
unauthorizedReply: "You are not authorized to use this form.",
|
|
8928
|
+
allowedUsers: modalEntry.allowedUsers,
|
|
9491
8929
|
defer: false
|
|
9492
8930
|
});
|
|
9493
8931
|
if (!authorized) return;
|
|
9494
8932
|
const ctx = authorized.ctx;
|
|
9495
|
-
const { interactionCtx, channelCtx, guildInfo,
|
|
9496
|
-
if (!await ensureComponentUserAllowed({
|
|
9497
|
-
entry: {
|
|
9498
|
-
id: modalEntry.id,
|
|
9499
|
-
kind: "button",
|
|
9500
|
-
label: modalEntry.title,
|
|
9501
|
-
allowedUsers: modalEntry.allowedUsers
|
|
9502
|
-
},
|
|
9503
|
-
interaction,
|
|
9504
|
-
user,
|
|
9505
|
-
replyOpts,
|
|
9506
|
-
componentLabel: "form",
|
|
9507
|
-
unauthorizedReply,
|
|
9508
|
-
allowNameMatching
|
|
9509
|
-
})) return;
|
|
8933
|
+
const { interactionCtx, channelCtx, guildInfo, commandAuthorized } = authorized;
|
|
9510
8934
|
const consumed = await resolveDiscordModalEntryWithPersistence({
|
|
9511
8935
|
id: modalId,
|
|
9512
8936
|
consume: !modalEntry.reusable
|
|
@@ -9556,6 +8980,8 @@ var DiscordComponentModal = class extends Modal {
|
|
|
9556
8980
|
};
|
|
9557
8981
|
//#endregion
|
|
9558
8982
|
//#region extensions/discord/src/monitor/agent-components.system-controls.ts
|
|
8983
|
+
const AGENT_BUTTON_KEY = "agent";
|
|
8984
|
+
const AGENT_SELECT_KEY = "agentsel";
|
|
9559
8985
|
async function runAgentSystemControlInteraction(params) {
|
|
9560
8986
|
const parsed = parseAgentComponentData(params.data);
|
|
9561
8987
|
if (!parsed) {
|
|
@@ -9603,7 +9029,7 @@ async function runAgentSystemControlInteraction(params) {
|
|
|
9603
9029
|
userId
|
|
9604
9030
|
});
|
|
9605
9031
|
logDebug(`${params.label}: enqueuing event for channel ${channelId}: ${eventText}`);
|
|
9606
|
-
enqueueRoutedSystemEvent
|
|
9032
|
+
enqueueRoutedSystemEvent(eventText, route, { contextKey: `${params.contextKeyPrefix}:${channelId}:${componentId}:${userId}:${params.interaction.id}` });
|
|
9607
9033
|
await ackComponentInteraction({
|
|
9608
9034
|
interaction: params.interaction,
|
|
9609
9035
|
replyOpts,
|
|
@@ -9613,10 +9039,10 @@ async function runAgentSystemControlInteraction(params) {
|
|
|
9613
9039
|
var AgentComponentButton = class extends Button {
|
|
9614
9040
|
constructor(ctx) {
|
|
9615
9041
|
super();
|
|
9042
|
+
this.ctx = ctx;
|
|
9616
9043
|
this.label = AGENT_BUTTON_KEY;
|
|
9617
9044
|
this.customId = `${AGENT_BUTTON_KEY}:seed=1`;
|
|
9618
9045
|
this.style = ButtonStyle.Primary;
|
|
9619
|
-
this.ctx = ctx;
|
|
9620
9046
|
}
|
|
9621
9047
|
async run(interaction, data) {
|
|
9622
9048
|
await runAgentSystemControlInteraction({
|
|
@@ -9636,9 +9062,9 @@ var AgentComponentButton = class extends Button {
|
|
|
9636
9062
|
var AgentSelectMenu = class extends StringSelectMenu {
|
|
9637
9063
|
constructor(ctx) {
|
|
9638
9064
|
super();
|
|
9065
|
+
this.ctx = ctx;
|
|
9639
9066
|
this.customId = `${AGENT_SELECT_KEY}:seed=1`;
|
|
9640
9067
|
this.options = [];
|
|
9641
|
-
this.ctx = ctx;
|
|
9642
9068
|
}
|
|
9643
9069
|
async run(interaction, data) {
|
|
9644
9070
|
const values = interaction.values ?? [];
|
|
@@ -9757,11 +9183,8 @@ var DiscordComponentButton = class extends Button {
|
|
|
9757
9183
|
});
|
|
9758
9184
|
}
|
|
9759
9185
|
};
|
|
9760
|
-
function createSelectControl(spec, ctx, handlers) {
|
|
9761
|
-
return new DiscordComponentSelectControl(spec, ctx, handlers);
|
|
9762
|
-
}
|
|
9763
9186
|
function bindSelectControl(spec) {
|
|
9764
|
-
return (ctx, handlers) =>
|
|
9187
|
+
return (ctx, handlers) => new DiscordComponentSelectControl(spec, ctx, handlers);
|
|
9765
9188
|
}
|
|
9766
9189
|
function createDiscordComponentButtonControl(ctx, handlers) {
|
|
9767
9190
|
return new DiscordComponentButton(ctx, handlers);
|
|
@@ -9773,24 +9196,15 @@ const createDiscordComponentMentionableSelectControl = bindSelectControl(SELECT_
|
|
|
9773
9196
|
const createDiscordComponentChannelSelectControl = bindSelectControl(SELECT_CONTROLS.channel);
|
|
9774
9197
|
//#endregion
|
|
9775
9198
|
//#region extensions/discord/src/monitor/agent-components.ts
|
|
9776
|
-
function bindDiscordComponentControl(createControl) {
|
|
9777
|
-
return (ctx) => createControl(ctx, discordComponentControlHandlers);
|
|
9778
|
-
}
|
|
9779
|
-
const createDiscordComponentButton = bindDiscordComponentControl(createDiscordComponentButtonControl);
|
|
9780
|
-
const createDiscordComponentStringSelect = bindDiscordComponentControl(createDiscordComponentStringSelectControl);
|
|
9781
|
-
const createDiscordComponentUserSelect = bindDiscordComponentControl(createDiscordComponentUserSelectControl);
|
|
9782
|
-
const createDiscordComponentRoleSelect = bindDiscordComponentControl(createDiscordComponentRoleSelectControl);
|
|
9783
|
-
const createDiscordComponentMentionableSelect = bindDiscordComponentControl(createDiscordComponentMentionableSelectControl);
|
|
9784
|
-
const createDiscordComponentChannelSelect = bindDiscordComponentControl(createDiscordComponentChannelSelectControl);
|
|
9785
9199
|
const createAgentComponentControls = [createAgentComponentButton, createAgentSelectMenu];
|
|
9786
9200
|
const createDiscordComponentControls = [
|
|
9787
|
-
|
|
9788
|
-
|
|
9789
|
-
|
|
9790
|
-
|
|
9791
|
-
|
|
9792
|
-
|
|
9793
|
-
];
|
|
9201
|
+
createDiscordComponentButtonControl,
|
|
9202
|
+
createDiscordComponentStringSelectControl,
|
|
9203
|
+
createDiscordComponentUserSelectControl,
|
|
9204
|
+
createDiscordComponentRoleSelectControl,
|
|
9205
|
+
createDiscordComponentMentionableSelectControl,
|
|
9206
|
+
createDiscordComponentChannelSelectControl
|
|
9207
|
+
].map((createControl) => (ctx) => createControl(ctx, discordComponentControlHandlers));
|
|
9794
9208
|
function createDiscordComponentModal(ctx) {
|
|
9795
9209
|
return new DiscordComponentModal(ctx);
|
|
9796
9210
|
}
|
|
@@ -9835,23 +9249,19 @@ var ExecApprovalButton = class extends Button {
|
|
|
9835
9249
|
async run(interaction, data) {
|
|
9836
9250
|
const parsed = parseExecApprovalData(data);
|
|
9837
9251
|
if (!parsed) {
|
|
9838
|
-
|
|
9839
|
-
|
|
9840
|
-
|
|
9841
|
-
|
|
9842
|
-
});
|
|
9843
|
-
} catch {}
|
|
9252
|
+
await replySilently(interaction, {
|
|
9253
|
+
content: "This approval is no longer valid.",
|
|
9254
|
+
ephemeral: true
|
|
9255
|
+
});
|
|
9844
9256
|
return;
|
|
9845
9257
|
}
|
|
9846
9258
|
const approvers = this.ctx.getApprovers();
|
|
9847
9259
|
const userId = interaction.userId;
|
|
9848
9260
|
if (!approvers.some((id) => id === userId)) {
|
|
9849
|
-
|
|
9850
|
-
|
|
9851
|
-
|
|
9852
|
-
|
|
9853
|
-
});
|
|
9854
|
-
} catch {}
|
|
9261
|
+
await replySilently(interaction, {
|
|
9262
|
+
content: "⛔ You are not authorized to approve requests.",
|
|
9263
|
+
ephemeral: true
|
|
9264
|
+
});
|
|
9855
9265
|
return;
|
|
9856
9266
|
}
|
|
9857
9267
|
const decisionLabel = parsed.action === "allow-once" ? "Allowed (once)" : parsed.action === "allow-always" ? "Allowed (always)" : "Denied";
|
|
@@ -9989,6 +9399,16 @@ function createDiscordQuestionButton(params) {
|
|
|
9989
9399
|
//#region extensions/discord/src/monitor/provider.interactions.ts
|
|
9990
9400
|
function createDiscordProviderInteractionSurface(params) {
|
|
9991
9401
|
const createNativeCommand = params.createNativeCommand ?? createDiscordNativeCommand;
|
|
9402
|
+
const commandContext = {
|
|
9403
|
+
readPolicy: params.readPolicy,
|
|
9404
|
+
cfg: params.cfg,
|
|
9405
|
+
discordConfig: params.discordConfig,
|
|
9406
|
+
accountId: params.accountId,
|
|
9407
|
+
sessionPrefix: params.sessionPrefix,
|
|
9408
|
+
threadBindings: params.threadBindings,
|
|
9409
|
+
buildContext: params.channelRuntime?.inbound.buildContext,
|
|
9410
|
+
dispatchReplyFromConfig: params.channelRuntime?.reply?.dispatchReplyFromConfig
|
|
9411
|
+
};
|
|
9992
9412
|
const commands = params.commandSpecs.map((spec) => {
|
|
9993
9413
|
if (params.nativeEnabled && params.voiceEnabled && spec.name === DISCORD_VOICE_COMMAND_SPEC.name) return createDiscordVoiceCommand({
|
|
9994
9414
|
readPolicy: params.readPolicy,
|
|
@@ -10001,16 +9421,9 @@ function createDiscordProviderInteractionSurface(params) {
|
|
|
10001
9421
|
ephemeralDefault: params.ephemeralDefault
|
|
10002
9422
|
});
|
|
10003
9423
|
return createNativeCommand({
|
|
10004
|
-
|
|
9424
|
+
...commandContext,
|
|
10005
9425
|
command: spec,
|
|
10006
|
-
|
|
10007
|
-
discordConfig: params.discordConfig,
|
|
10008
|
-
accountId: params.accountId,
|
|
10009
|
-
sessionPrefix: params.sessionPrefix,
|
|
10010
|
-
ephemeralDefault: params.ephemeralDefault,
|
|
10011
|
-
threadBindings: params.threadBindings,
|
|
10012
|
-
buildContext: params.channelRuntime?.inbound.buildContext,
|
|
10013
|
-
dispatchReplyFromConfig: params.channelRuntime?.reply?.dispatchReplyFromConfig
|
|
9426
|
+
ephemeralDefault: params.ephemeralDefault
|
|
10014
9427
|
});
|
|
10015
9428
|
});
|
|
10016
9429
|
const execApprovalsConfig = params.discordConfig.execApprovals ?? {};
|
|
@@ -10035,64 +9448,29 @@ function createDiscordProviderInteractionSurface(params) {
|
|
|
10035
9448
|
},
|
|
10036
9449
|
abortSignal: params.abortSignal
|
|
10037
9450
|
});
|
|
10038
|
-
const
|
|
10039
|
-
createDiscordQuestionButton({
|
|
10040
|
-
cfg: params.cfg,
|
|
10041
|
-
accountId: params.accountId,
|
|
10042
|
-
authContext: {
|
|
10043
|
-
readPolicy: params.readPolicy,
|
|
10044
|
-
cfg: params.cfg,
|
|
10045
|
-
accountId: params.accountId,
|
|
10046
|
-
discordConfig: params.discordConfig,
|
|
10047
|
-
runtime: params.runtime,
|
|
10048
|
-
token: params.token,
|
|
10049
|
-
guildEntries: params.guildEntries,
|
|
10050
|
-
allowFrom: params.allowFrom,
|
|
10051
|
-
dmPolicy: params.dmPolicy
|
|
10052
|
-
}
|
|
10053
|
-
}),
|
|
10054
|
-
createDiscordCommandArgFallbackButton({
|
|
10055
|
-
readPolicy: params.readPolicy,
|
|
10056
|
-
cfg: params.cfg,
|
|
10057
|
-
discordConfig: params.discordConfig,
|
|
10058
|
-
accountId: params.accountId,
|
|
10059
|
-
sessionPrefix: params.sessionPrefix,
|
|
10060
|
-
threadBindings: params.threadBindings,
|
|
10061
|
-
buildContext: params.channelRuntime?.inbound.buildContext,
|
|
10062
|
-
dispatchReplyFromConfig: params.channelRuntime?.reply?.dispatchReplyFromConfig
|
|
10063
|
-
}),
|
|
10064
|
-
createDiscordModelPickerFallbackButton({
|
|
10065
|
-
readPolicy: params.readPolicy,
|
|
10066
|
-
cfg: params.cfg,
|
|
10067
|
-
discordConfig: params.discordConfig,
|
|
10068
|
-
accountId: params.accountId,
|
|
10069
|
-
sessionPrefix: params.sessionPrefix,
|
|
10070
|
-
threadBindings: params.threadBindings,
|
|
10071
|
-
buildContext: params.channelRuntime?.inbound.buildContext,
|
|
10072
|
-
dispatchReplyFromConfig: params.channelRuntime?.reply?.dispatchReplyFromConfig
|
|
10073
|
-
}),
|
|
10074
|
-
createDiscordModelPickerFallbackSelect({
|
|
10075
|
-
readPolicy: params.readPolicy,
|
|
10076
|
-
cfg: params.cfg,
|
|
10077
|
-
discordConfig: params.discordConfig,
|
|
10078
|
-
accountId: params.accountId,
|
|
10079
|
-
sessionPrefix: params.sessionPrefix,
|
|
10080
|
-
threadBindings: params.threadBindings,
|
|
10081
|
-
buildContext: params.channelRuntime?.inbound.buildContext,
|
|
10082
|
-
dispatchReplyFromConfig: params.channelRuntime?.reply?.dispatchReplyFromConfig
|
|
10083
|
-
})
|
|
10084
|
-
];
|
|
10085
|
-
const activityButton = createDiscordActivityButton({
|
|
9451
|
+
const componentContext = {
|
|
10086
9452
|
readPolicy: params.readPolicy,
|
|
10087
9453
|
cfg: params.cfg,
|
|
10088
|
-
discordConfig: params.discordConfig,
|
|
10089
9454
|
accountId: params.accountId,
|
|
9455
|
+
discordConfig: params.discordConfig,
|
|
9456
|
+
runtime: params.runtime,
|
|
9457
|
+
token: params.token,
|
|
10090
9458
|
guildEntries: params.guildEntries,
|
|
10091
9459
|
allowFrom: params.allowFrom,
|
|
10092
|
-
dmPolicy: params.dmPolicy
|
|
10093
|
-
|
|
10094
|
-
|
|
10095
|
-
|
|
9460
|
+
dmPolicy: params.dmPolicy
|
|
9461
|
+
};
|
|
9462
|
+
const components = [createDiscordQuestionButton({
|
|
9463
|
+
cfg: params.cfg,
|
|
9464
|
+
accountId: params.accountId,
|
|
9465
|
+
authContext: componentContext
|
|
9466
|
+
}), ...[
|
|
9467
|
+
createDiscordCommandArgFallbackButton,
|
|
9468
|
+
createDiscordModelPickerFallbackButton,
|
|
9469
|
+
createDiscordModelPickerFallbackSelect
|
|
9470
|
+
].map((create) => create(commandContext))];
|
|
9471
|
+
const activityButton = createDiscordActivityButton({
|
|
9472
|
+
...componentContext,
|
|
9473
|
+
channelRuntime: params.channelRuntime
|
|
10096
9474
|
}, params.applicationId);
|
|
10097
9475
|
if (activityButton) components.push(activityButton);
|
|
10098
9476
|
const modals = [];
|
|
@@ -10102,17 +9480,6 @@ function createDiscordProviderInteractionSurface(params) {
|
|
|
10102
9480
|
config: execApprovalsConfig
|
|
10103
9481
|
})));
|
|
10104
9482
|
if ((params.discordConfig.agentComponents ?? {}).enabled ?? true) {
|
|
10105
|
-
const componentContext = {
|
|
10106
|
-
readPolicy: params.readPolicy,
|
|
10107
|
-
cfg: params.cfg,
|
|
10108
|
-
discordConfig: params.discordConfig,
|
|
10109
|
-
accountId: params.accountId,
|
|
10110
|
-
guildEntries: params.guildEntries,
|
|
10111
|
-
allowFrom: params.allowFrom,
|
|
10112
|
-
dmPolicy: params.dmPolicy,
|
|
10113
|
-
runtime: params.runtime,
|
|
10114
|
-
token: params.token
|
|
10115
|
-
};
|
|
10116
9483
|
components.push(...createAgentComponentControls.map((create) => create(componentContext)));
|
|
10117
9484
|
components.push(...createDiscordComponentControls.map((create) => create(componentContext)));
|
|
10118
9485
|
modals.push(createDiscordComponentModal(componentContext));
|
|
@@ -10166,11 +9533,7 @@ function resolveDiscordPreflightChannelAccess(params) {
|
|
|
10166
9533
|
if (params.isGuildMessage && params.channelConfig?.enabled === false) {
|
|
10167
9534
|
logDebug(`[discord-preflight] drop: channel disabled`);
|
|
10168
9535
|
logVerbose(`Blocked discord channel ${params.messageChannelId} (channel disabled, ${params.channelMatchMeta})`);
|
|
10169
|
-
return
|
|
10170
|
-
allowed: false,
|
|
10171
|
-
channelAllowlistConfigured: false,
|
|
10172
|
-
channelAllowed: false
|
|
10173
|
-
};
|
|
9536
|
+
return false;
|
|
10174
9537
|
}
|
|
10175
9538
|
const groupDmAllowed = params.isGroupDm && resolveGroupDmAllow({
|
|
10176
9539
|
channels: params.groupDmChannels,
|
|
@@ -10178,11 +9541,7 @@ function resolveDiscordPreflightChannelAccess(params) {
|
|
|
10178
9541
|
channelName: params.displayChannelName,
|
|
10179
9542
|
channelSlug: params.displayChannelSlug
|
|
10180
9543
|
});
|
|
10181
|
-
if (params.isGroupDm && !groupDmAllowed) return
|
|
10182
|
-
allowed: false,
|
|
10183
|
-
channelAllowlistConfigured: false,
|
|
10184
|
-
channelAllowed: false
|
|
10185
|
-
};
|
|
9544
|
+
if (params.isGroupDm && !groupDmAllowed) return false;
|
|
10186
9545
|
const channelAllowlistConfigured = Boolean(params.guildInfo?.channels) && Object.keys(params.guildInfo?.channels ?? {}).length > 0;
|
|
10187
9546
|
const channelAllowed = params.channelConfig?.allowed !== false;
|
|
10188
9547
|
if (params.isGuildMessage && !isDiscordGroupAllowedByPolicy({
|
|
@@ -10201,30 +9560,18 @@ function resolveDiscordPreflightChannelAccess(params) {
|
|
|
10201
9560
|
logDebug(`[discord] Ignored message from channel ${params.messageChannelId} (not in guild allowlist). Add to guilds.<guildId>.channels to enable.`);
|
|
10202
9561
|
logVerbose(`Blocked discord channel ${params.messageChannelId} not in guild channel allowlist (groupPolicy: allowlist, ${params.channelMatchMeta})`);
|
|
10203
9562
|
}
|
|
10204
|
-
return
|
|
10205
|
-
allowed: false,
|
|
10206
|
-
channelAllowlistConfigured,
|
|
10207
|
-
channelAllowed
|
|
10208
|
-
};
|
|
9563
|
+
return false;
|
|
10209
9564
|
}
|
|
10210
9565
|
if (params.isGuildMessage && params.channelConfig?.allowed === false) {
|
|
10211
9566
|
logDebug(`[discord-preflight] drop: channelConfig.allowed===false`);
|
|
10212
9567
|
logVerbose(`Blocked discord channel ${params.messageChannelId} not in guild channel allowlist (${params.channelMatchMeta})`);
|
|
10213
|
-
return
|
|
10214
|
-
allowed: false,
|
|
10215
|
-
channelAllowlistConfigured,
|
|
10216
|
-
channelAllowed
|
|
10217
|
-
};
|
|
9568
|
+
return false;
|
|
10218
9569
|
}
|
|
10219
9570
|
if (params.isGuildMessage) {
|
|
10220
9571
|
logDebug(`[discord-preflight] pass: channel allowed`);
|
|
10221
9572
|
logVerbose(`discord: allow channel ${params.messageChannelId} (${params.channelMatchMeta})`);
|
|
10222
9573
|
}
|
|
10223
|
-
return
|
|
10224
|
-
allowed: true,
|
|
10225
|
-
channelAllowlistConfigured,
|
|
10226
|
-
channelAllowed
|
|
10227
|
-
};
|
|
9574
|
+
return true;
|
|
10228
9575
|
}
|
|
10229
9576
|
//#endregion
|
|
10230
9577
|
//#region extensions/discord/src/monitor/listeners.guild-join.ts
|
|
@@ -10281,7 +9628,7 @@ var DiscordGuildJoinIntroductionListener = class extends GuildCreateListener {
|
|
|
10281
9628
|
guildInfo,
|
|
10282
9629
|
channelConfig,
|
|
10283
9630
|
channelMatchMeta: `guild=${data.id} channel=${channel.id}`
|
|
10284
|
-
})
|
|
9631
|
+
});
|
|
10285
9632
|
if (roomAllowed) {
|
|
10286
9633
|
targetChannel = channel;
|
|
10287
9634
|
break;
|
|
@@ -10355,11 +9702,7 @@ var DiscordGuildJoinIntroductionListener = class extends GuildCreateListener {
|
|
|
10355
9702
|
//#region extensions/discord/src/monitor/provider.startup.ts
|
|
10356
9703
|
function registerLatePlugin(client, plugin) {
|
|
10357
9704
|
plugin.registerClient?.(client);
|
|
10358
|
-
plugin.
|
|
10359
|
-
if (!client.plugins.some((entry) => entry.id === plugin.id)) client.plugins.push({
|
|
10360
|
-
id: plugin.id,
|
|
10361
|
-
plugin
|
|
10362
|
-
});
|
|
9705
|
+
if (!client.plugins.some((entry) => entry.id === plugin.id)) client.plugins.push(plugin);
|
|
10363
9706
|
}
|
|
10364
9707
|
function createDiscordStatusReadyListener(params) {
|
|
10365
9708
|
return new class DiscordStatusReadyListener extends ReadyListener {
|
|
@@ -10371,21 +9714,17 @@ function createDiscordStatusReadyListener(params) {
|
|
|
10371
9714
|
}
|
|
10372
9715
|
const gateway = client.getPlugin("gateway");
|
|
10373
9716
|
if (!gateway) return;
|
|
10374
|
-
|
|
10375
|
-
if (!presence) return;
|
|
10376
|
-
gateway.updatePresence(presence);
|
|
9717
|
+
gateway.updatePresence(resolveDiscordPresenceUpdate(params.discordConfig));
|
|
10377
9718
|
}
|
|
10378
9719
|
}();
|
|
10379
9720
|
}
|
|
10380
9721
|
async function createDiscordMonitorClient(params) {
|
|
10381
9722
|
let autoPresenceController = null;
|
|
10382
|
-
const
|
|
9723
|
+
const constructorPlugins = [params.createGatewayPlugin({
|
|
10383
9724
|
discordConfig: params.discordConfig,
|
|
10384
9725
|
runtime: params.runtime
|
|
10385
9726
|
})];
|
|
10386
|
-
|
|
10387
|
-
const voicePlugin = clientPlugins.find((plugin) => plugin.id === "voice");
|
|
10388
|
-
const constructorPlugins = voicePlugin ? clientPlugins.filter((plugin) => plugin !== voicePlugin) : clientPlugins;
|
|
9727
|
+
const voicePlugin = params.voiceEnabled ? new VoicePlugin() : void 0;
|
|
10389
9728
|
const eventQueueOpts = {
|
|
10390
9729
|
listenerTimeout: 12e4,
|
|
10391
9730
|
slowListenerThreshold: 3e4
|
|
@@ -10395,16 +9734,11 @@ async function createDiscordMonitorClient(params) {
|
|
|
10395
9734
|
getAutoPresenceController: () => autoPresenceController
|
|
10396
9735
|
});
|
|
10397
9736
|
const client = params.createClient({
|
|
10398
|
-
baseUrl: "http://localhost",
|
|
10399
|
-
deploySecret: "a",
|
|
10400
9737
|
clientId: params.applicationId,
|
|
10401
|
-
publicKey: "a",
|
|
10402
9738
|
token: params.token,
|
|
10403
|
-
autoDeploy: false,
|
|
10404
9739
|
commandDeployHashStore: params.commandDeployHashStore,
|
|
10405
9740
|
requestOptions: {
|
|
10406
9741
|
timeout: DISCORD_REST_TIMEOUT_MS,
|
|
10407
|
-
runtimeProfile: "persistent",
|
|
10408
9742
|
maxQueueSize: 1e3,
|
|
10409
9743
|
...params.restFetch ? { fetch: params.restFetch } : {}
|
|
10410
9744
|
},
|
|
@@ -10458,9 +9792,8 @@ async function fetchDiscordBotIdentity(params) {
|
|
|
10458
9792
|
params.logStartupPhase("fetch-bot-identity:error", String(err));
|
|
10459
9793
|
throw new Error("Failed to resolve Discord bot identity", { cause: err });
|
|
10460
9794
|
}
|
|
10461
|
-
const
|
|
10462
|
-
const
|
|
10463
|
-
const botUserName = normalizeOptionalString(botUserRecord?.username) ?? normalizeOptionalString(botUserRecord?.globalName);
|
|
9795
|
+
const botUserId = normalizeOptionalString(botUser?.id);
|
|
9796
|
+
const botUserName = normalizeOptionalString(botUser?.username) ?? normalizeOptionalString(botUser?.globalName);
|
|
10464
9797
|
if (!botUserId) {
|
|
10465
9798
|
const details = "fetchUser(\"@me\") returned no usable id";
|
|
10466
9799
|
params.runtime.error?.(danger(`discord: failed to fetch bot identity: ${details}`));
|
|
@@ -10544,12 +9877,6 @@ function formatDiscordStartupStatusMessage(params) {
|
|
|
10544
9877
|
//#endregion
|
|
10545
9878
|
//#region extensions/discord/src/monitor/provider.ts
|
|
10546
9879
|
const DEFAULT_DISCORD_MEDIA_MAX_MB = 100;
|
|
10547
|
-
function logDiscordStartupPhase(params) {
|
|
10548
|
-
logDiscordStartupPhase$1({
|
|
10549
|
-
...params,
|
|
10550
|
-
isVerbose: discordProviderRuntime.isVerbose
|
|
10551
|
-
});
|
|
10552
|
-
}
|
|
10553
9880
|
const DISCORD_DISALLOWED_INTENTS_CODE = GatewayCloseCodes$1.DisallowedIntents;
|
|
10554
9881
|
function isDiscordDisallowedIntentsError(err) {
|
|
10555
9882
|
if (!err) return false;
|
|
@@ -10566,6 +9893,16 @@ async function monitorDiscordProvider(opts = {}) {
|
|
|
10566
9893
|
const token = normalizeDiscordToken(opts.token ?? void 0, "channels.discord.token") ?? account.token;
|
|
10567
9894
|
if (!token) throw new Error(`Discord bot token missing for account "${account.accountId}" (set discord.accounts.${account.accountId}.token or DISCORD_BOT_TOKEN for default).`);
|
|
10568
9895
|
const runtime = opts.runtime ?? createNonExitingRuntime();
|
|
9896
|
+
let lifecycleGateway;
|
|
9897
|
+
const logStartupPhase = (phase, details) => logDiscordStartupPhase({
|
|
9898
|
+
runtime,
|
|
9899
|
+
accountId: account.accountId,
|
|
9900
|
+
phase,
|
|
9901
|
+
startAt: startupStartedAt,
|
|
9902
|
+
gateway: lifecycleGateway,
|
|
9903
|
+
details,
|
|
9904
|
+
isVerbose: discordProviderRuntime.isVerbose
|
|
9905
|
+
});
|
|
10569
9906
|
const rawDiscordCfg = account.config;
|
|
10570
9907
|
const discordRestFetch = resolveDiscordRestFetch(rawDiscordCfg.proxy, runtime);
|
|
10571
9908
|
const dmConfig = rawDiscordCfg.dm;
|
|
@@ -10671,12 +10008,7 @@ async function monitorDiscordProvider(opts = {}) {
|
|
|
10671
10008
|
threadBindingIdleTimeoutMs,
|
|
10672
10009
|
threadBindingMaxAgeMs
|
|
10673
10010
|
});
|
|
10674
|
-
|
|
10675
|
-
runtime,
|
|
10676
|
-
accountId: account.accountId,
|
|
10677
|
-
phase: "fetch-application-id:start",
|
|
10678
|
-
startAt: startupStartedAt
|
|
10679
|
-
});
|
|
10011
|
+
logStartupPhase("fetch-application-id:start");
|
|
10680
10012
|
const parsedApplicationId = (typeof discordCfg.applicationId === "string" && discordCfg.applicationId.trim() ? discordCfg.applicationId.trim() : void 0) ?? parseApplicationIdFromToken(token);
|
|
10681
10013
|
const applicationIdProbe = parsedApplicationId ? {
|
|
10682
10014
|
kind: "resolved",
|
|
@@ -10702,13 +10034,7 @@ async function monitorDiscordProvider(opts = {}) {
|
|
|
10702
10034
|
throw new Error(message, { cause: applicationIdProbe.error });
|
|
10703
10035
|
}
|
|
10704
10036
|
const applicationId = applicationIdProbe.applicationId;
|
|
10705
|
-
|
|
10706
|
-
runtime,
|
|
10707
|
-
accountId: account.accountId,
|
|
10708
|
-
phase: "fetch-application-id:done",
|
|
10709
|
-
startAt: startupStartedAt,
|
|
10710
|
-
details: `applicationId=${applicationId}`
|
|
10711
|
-
});
|
|
10037
|
+
logStartupPhase("fetch-application-id:done", `applicationId=${applicationId}`);
|
|
10712
10038
|
const { commandSpecs } = await resolveDiscordProviderCommandSpecs({
|
|
10713
10039
|
cfg,
|
|
10714
10040
|
runtime,
|
|
@@ -10731,7 +10057,6 @@ async function monitorDiscordProvider(opts = {}) {
|
|
|
10731
10057
|
let deactivateMessageHandler;
|
|
10732
10058
|
let stopMonitorListeners;
|
|
10733
10059
|
let autoPresenceController = null;
|
|
10734
|
-
let lifecycleGateway;
|
|
10735
10060
|
let earlyGatewayEmitter = gatewaySupervisor?.emitter;
|
|
10736
10061
|
let onEarlyGatewayDebug;
|
|
10737
10062
|
try {
|
|
@@ -10811,14 +10136,7 @@ async function monitorDiscordProvider(opts = {}) {
|
|
|
10811
10136
|
runtime.log?.(`discord startup [${account.accountId}] gateway-debug ${Math.max(0, Date.now() - startupStartedAt)}ms ${String(msg)}`);
|
|
10812
10137
|
};
|
|
10813
10138
|
earlyGatewayEmitter?.on("debug", onEarlyGatewayDebug);
|
|
10814
|
-
|
|
10815
|
-
runtime,
|
|
10816
|
-
accountId: account.accountId,
|
|
10817
|
-
phase: "deploy-commands:schedule",
|
|
10818
|
-
startAt: startupStartedAt,
|
|
10819
|
-
gateway: lifecycleGateway,
|
|
10820
|
-
details: `native=${nativeEnabled ? "on" : "off"} reconcile=on commandCount=${commands.length}`
|
|
10821
|
-
});
|
|
10139
|
+
logStartupPhase("deploy-commands:schedule", `native=${nativeEnabled ? "on" : "off"} reconcile=on commandCount=${commands.length}`);
|
|
10822
10140
|
runDiscordCommandDeployInBackground({
|
|
10823
10141
|
client,
|
|
10824
10142
|
runtime,
|
|
@@ -10834,14 +10152,7 @@ async function monitorDiscordProvider(opts = {}) {
|
|
|
10834
10152
|
client,
|
|
10835
10153
|
token,
|
|
10836
10154
|
runtime,
|
|
10837
|
-
logStartupPhase
|
|
10838
|
-
runtime,
|
|
10839
|
-
accountId: account.accountId,
|
|
10840
|
-
phase,
|
|
10841
|
-
startAt: startupStartedAt,
|
|
10842
|
-
gateway: lifecycleGateway,
|
|
10843
|
-
details
|
|
10844
|
-
})
|
|
10155
|
+
logStartupPhase
|
|
10845
10156
|
});
|
|
10846
10157
|
let voiceManager = null;
|
|
10847
10158
|
if (voiceEnabled) {
|
|
@@ -10918,13 +10229,7 @@ async function monitorDiscordProvider(opts = {}) {
|
|
|
10918
10229
|
messageHandler,
|
|
10919
10230
|
trackInboundEvent
|
|
10920
10231
|
});
|
|
10921
|
-
|
|
10922
|
-
runtime,
|
|
10923
|
-
accountId: account.accountId,
|
|
10924
|
-
phase: "client-start",
|
|
10925
|
-
startAt: startupStartedAt,
|
|
10926
|
-
gateway: lifecycleGateway
|
|
10927
|
-
});
|
|
10232
|
+
logStartupPhase("client-start");
|
|
10928
10233
|
const botIdentity = botUserId && botUserName ? `${botUserId} (${botUserName})` : botUserId ?? botUserName ?? "";
|
|
10929
10234
|
runtime.log?.(formatDiscordStartupStatusMessage({
|
|
10930
10235
|
gatewayReady: lifecycleGateway?.isConnected === true,
|
|
@@ -10963,4 +10268,4 @@ async function monitorDiscordProvider(opts = {}) {
|
|
|
10963
10268
|
}
|
|
10964
10269
|
}
|
|
10965
10270
|
//#endregion
|
|
10966
|
-
export {
|
|
10271
|
+
export { resolveDiscordDmCommandAccess as A, buildDiscordGroupSystemPrompt as C, createDiscordLivePolicyReader as D, handleDiscordDmCommandDecision as E, mapGatewayDispatchData as O, createDiscordNativeCommand as S, createDiscordSupplementalContextAccessChecker as T, resolveDiscordVoiceMode as _, formatDiscordReplySkip as a, resolveDiscordGatewayIntents as b, buildGuildLabel as c, MIN_SEGMENT_SECONDS as d, VOICE_CONNECT_READY_TIMEOUT_MS as f, logVoiceVerbose as g, isVoiceChannel as h, formatDiscordReplyDeliveryFailure as i, resolveDiscordTextCommandAccess as j, registerDiscordListener as k, resolveReplyContext as l, isDiscordRealtimeVoiceMode as m, resolveDiscordPreflightChannelAccess as n, sanitizeDiscordFrontChannelReplyPayloads as o, VOICE_RECONNECT_GRACE_MS as p, deliverDiscordReply as r, buildDirectLabel as s, monitorDiscordProvider as t, CAPTURE_FINALIZE_GRACE_MS as u, resolveVoiceTimeoutMs as v, buildDiscordInboundAccessContext as w, waitForDiscordGatewayPluginRegistration as x, createDiscordGatewayPlugin as y };
|