@openclaw/discord 2026.7.2-beta.7 → 2026.8.1-beta.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{account-inspect-SXiCBCgP.js → account-inspect-CqzrH14k.js} +48 -42
- package/dist/account-inspect-api.js +1 -1
- package/dist/action-runtime-api.js +1 -1
- package/dist/{active-turn-thread-route-MlKWp8RD.js → active-turn-thread-route-fmHl1HNd.js} +9 -11
- package/dist/{activities-api-DTKsuDxf.js → activities-api-DS7vpdtp.js} +4 -4
- package/dist/activities-api.js +1 -1
- package/dist/{allow-list-DzKrtfah.js → allow-list-DnxIlPP2.js} +2 -3
- package/dist/{api-DnrK9gML.js → api-DNVbJyEy.js} +7 -2
- package/dist/api.js +15 -15
- package/dist/{approval-handler.runtime-HymvFTYn.js → approval-handler.runtime-B6yEV79q.js} +5 -5
- package/dist/{approval-message-safety-DEyKVsAw.js → approval-message-safety-AcIxvrf3.js} +1 -1
- package/dist/{audit-CjsrabP8.js → audit-Db-rlntl.js} +4 -4
- package/dist/{channel-vKa-76xY.js → channel-CnnbJSt5.js} +46 -72
- package/dist/{channel-actions-uXFTJX3o.js → channel-actions-5s_hjYKd.js} +4 -4
- package/dist/{channel-actions.runtime-CIYU90sl.js → channel-actions.runtime-CLKrx6tr.js} +53 -36
- package/dist/channel-config-api.js +1 -1
- package/dist/channel-plugin-api.js +1 -1
- package/dist/{channel.setup-CmcwZ_qd.js → channel.setup-BFAO-V1P.js} +15 -53
- package/dist/{config-schema-WHRQcY19.js → config-schema-BgEskFAs.js} +9 -4
- package/dist/{directory-config-D_LojtCe.js → directory-config-BVX7Cflc.js} +1 -1
- package/dist/directory-contract-api.js +1 -1
- package/dist/{directory-live-Bw5Ephzv.js → directory-live-DGIGxpIo.js} +6 -3
- package/dist/{doctor-Bc4S1qyd.js → doctor-BzC-TLnB.js} +4 -4
- package/dist/{doctor-contract-CCFMIDk9.js → doctor-contract-DLa-BTiU.js} +2 -3
- package/dist/doctor-contract-api.js +147 -2
- package/dist/{handle-action.guild-admin-D6VRRW-C.js → handle-action.guild-admin-BNVTUISF.js} +4 -7
- package/dist/{inbound-event-delivery-CEPlt2uz.js → inbound-event-delivery-De2qxTrP.js} +4 -25
- package/dist/index.js +4 -2
- package/dist/{message-handler-CeiSulIw.js → message-handler-Unk_f10F.js} +41 -32
- package/dist/{message-handler.preflight-DibgQFf2.js → message-handler.preflight-C9zecxR9.js} +50 -26
- package/dist/{message-handler.process-Dnc_oz9y.js → message-handler.process-DWQ6UHHu.js} +130 -166
- package/dist/{message-utils-BgTwT_q7.js → message-utils-BSCPVgy0.js} +4 -4
- package/dist/{model-picker-preference-primitives-D25pnCOu.js → model-picker-preference-primitives-BHT1LkR_.js} +3 -3
- package/dist/{outbound-adapter-DtE-i2OJ.js → outbound-adapter-D9nRivT1.js} +91 -32
- package/dist/{outbound-components-C7GVyfPh.js → outbound-components-cTzwBJ60.js} +3 -3
- package/dist/{outbound-session-route-H-HoyH5U.js → outbound-session-route-DxLkrgKQ.js} +68 -95
- package/dist/{pluralkit-CD4B11JB.js → pluralkit-DdiJ9KMK.js} +1 -1
- package/dist/{preflight-audio-BjnQZ5yS.js → preflight-audio-DrnqFA8U.js} +22 -28
- package/dist/{probe-BeWKhjqX.js → probe-Bl-k5_Ku.js} +36 -12
- package/dist/probe.runtime-M9fREKvp.js +2 -0
- package/dist/{provider-DfQJX3z5.js → provider-DvSNb-2v.js} +969 -1248
- package/dist/{provider-session.runtime-Bo88k0pV.js → provider-session.runtime-BUEqD0rA.js} +3 -3
- package/dist/provider.runtime-C9PnJZbZ.js +2 -0
- package/dist/realtime-session.runtime-C7wen-aF.js +1340 -0
- package/dist/{resolve-allowlist-common-DHERApxi.js → resolve-allowlist-common-D04lpEzb.js} +2 -2
- package/dist/{resolve-channels-BjepAj8b.js → resolve-channels-Dm7jEeg6.js} +4 -4
- package/dist/{resolve-users-Bc28htgt.js → resolve-users-bktrCUUU.js} +3 -3
- package/dist/{chunk-DX4jpFQP.js → retry-CLpJcXXf.js} +291 -68
- package/dist/{runtime-_aRC6V2s.js → runtime-DGsSyDTS.js} +30 -25
- package/dist/{runtime-BmW_j_hl.js → runtime-DoHjckYm.js} +4 -6
- package/dist/runtime-api.actions.js +2 -2
- package/dist/runtime-api.js +22 -23
- package/dist/runtime-api.lookup.js +5 -5
- package/dist/runtime-api.monitor-CHxrFPnW.js +5 -0
- package/dist/runtime-api.monitor.js +5 -5
- package/dist/runtime-api.send.js +6 -6
- package/dist/runtime-api.threads.js +5 -6
- package/dist/sdk-runtime-QpY8PvCh.js +370 -0
- package/dist/{send-CdkZ6zeW.js → send-B7Q6Oc1I.js} +175 -86
- package/dist/{send.components-5uqwkjgE.js → send.components-iJyFXw9L.js} +24 -28
- package/dist/{send.outbound-D-80Ej-t.js → send.outbound-DS5tHwfR.js} +37 -24
- package/dist/{send.reactions-CtlmGd_o.js → send.reactions-BAn0iiVQ.js} +14 -21
- package/dist/{send.receipt-CuwRrpFz.js → send.receipt-IPI1p-SP.js} +19 -1
- package/dist/{send.shared-jpvAG_u6.js → send.shared-BmwFjW6T.js} +16 -85
- package/dist/{sender-identity-mG_zsdox.js → sender-identity-QtalnCYv.js} +1 -1
- package/dist/setup-entry.js +0 -5
- package/dist/setup-plugin-api.js +1 -1
- package/dist/{shared-CXF1tup1.js → shared-BIXIX6uJ.js} +16 -17
- package/dist/{subagent-hooks-Dxy7Fmnq.js → subagent-hooks-CTt5KCJr.js} +2 -2
- package/dist/subagent-hooks-api.js +2 -6
- package/dist/subagent-progress-DhaE_h8a.js +109 -0
- package/dist/{system-events-DdUqf91B.js → system-events-CTqDf6_s.js} +2 -2
- package/dist/{target-resolver-C3s_2m0t.js → target-resolver-maOKSqO0.js} +2 -2
- package/dist/targets-yUFTHoAx.js +3 -0
- package/dist/{thread-bindings-C-M-ly7P.js → thread-bindings-3L8p82GV.js} +5 -7
- package/dist/{thread-bindings.manager-DYvSlrva.js → thread-bindings.manager-DCIH6WDC.js} +257 -29
- package/dist/{thread-bindings.session-updates-DAIlp7Px.js → thread-bindings.session-updates-bJ2KQFY6.js} +1 -1
- package/dist/{thread-bindings.state-Cgi5uRn-.js → thread-bindings.state-aeV8HNgV.js} +2 -15
- package/dist/{transcripts-source-DIKGsTGT.js → transcripts-source-CfFMexGt.js} +1 -1
- package/dist/transcripts-source-api.js +1 -1
- package/dist/{typing--Mzo2kM7.js → typing-CS-nNVoe.js} +1 -1
- package/dist/voice-runtime-BEdqNcST.js +2459 -0
- package/openclaw.plugin.json +203 -19
- package/package.json +15 -9
- package/skills/discord/SKILL.md +22 -115
- package/dist/legacy-state-migrations-api.js +0 -138
- package/dist/manager.runtime-Bjav3pfC.js +0 -3655
- package/dist/preflight-audio.runtime-CoCXMM8r.js +0 -7
- package/dist/probe.runtime-DqFGFMbZ.js +0 -2
- package/dist/provider.runtime-Cy7XZmyh.js +0 -2
- package/dist/runtime-api.monitor-CCRubd3-.js +0 -5
- package/dist/session-binding-contract-api.js +0 -2
- package/dist/subagent-progress-DI3sYLLo.js +0 -664
- package/dist/targets-Dv_RN7vT.js +0 -3
- package/dist/thread-bindings.discord-api-BoDNqamb.js +0 -246
|
@@ -1,38 +1,38 @@
|
|
|
1
|
-
import { C as
|
|
1
|
+
import { B as Message, C as ReadyListener, Ct as editChannel, E as ThreadUpdateListener, Et as getChannelMessage, K as Modal, L as Command, M as RateLimitError, O as Client, R as CommandWithSubcommands, S as PresenceUpdateListener, T as ThreadDeleteListener, V as User, Y as Button, Z as Container, _ as GuildDeleteListener, a as chunkDiscordTextWithMode, at as Separator, b as MessageReactionAddListener, bt as createThread, g as GuildCreateListener, h as discord_exports, k as Plugin, ot as StringSelectMenu, rt as Row, st as TextDisplay, tn as __exportAll, ut as BaseMessageInteractiveComponent, v as InteractionCreateListener, x as MessageReactionRemoveListener, y as MessageCreateListener, z as Guild } from "./retry-CLpJcXXf.js";
|
|
2
2
|
import { c as resolveDiscordAccountAllowFrom, d as resolveDiscordAccountDmPolicy, f as resolveDiscordMaxLinesPerMessage, p as normalizeDiscordToken, s as resolveDiscordAccount } from "./accounts-DJTf1LtA.js";
|
|
3
|
-
import { n as getDiscordActivitiesRuntime } from "./runtime-
|
|
4
|
-
import { C as parseDiscordActivityCustomIdForInteraction, D as parseDiscordModalCustomIdForInteraction, E as parseDiscordModalCustomId, O as decodeCustomIdComponent, T as parseDiscordComponentCustomIdForInteraction, k as encodeCustomIdComponent, l as parseExecApprovalData, s as parseDiscordQuestionData, w as parseDiscordComponentCustomId, y as buildDiscordActivityCustomId } from "./outbound-session-route-
|
|
5
|
-
import { D as canViewDiscordGuildChannel, F as createDiscordRestClient, H as registerGateway, K as validateDiscordProxyUrl, U as unregisterGateway, q as withValidatedDiscordProxy, z as DISCORD_REST_TIMEOUT_MS } from "./send.shared-
|
|
6
|
-
import { _ as resolveDiscordModalEntryWithPersistence, g as resolveDiscordComponentEntryWithPersistence, t as editDiscordComponentMessage } from "./send.components-
|
|
3
|
+
import { n as getDiscordActivitiesRuntime } from "./runtime-DoHjckYm.js";
|
|
4
|
+
import { C as parseDiscordActivityCustomIdForInteraction, D as parseDiscordModalCustomIdForInteraction, E as parseDiscordModalCustomId, O as decodeCustomIdComponent, T as parseDiscordComponentCustomIdForInteraction, k as encodeCustomIdComponent, l as parseExecApprovalData, s as parseDiscordQuestionData, w as parseDiscordComponentCustomId, y as buildDiscordActivityCustomId } from "./outbound-session-route-DxLkrgKQ.js";
|
|
5
|
+
import { D as canViewDiscordGuildChannel, F as createDiscordRestClient, H as registerGateway, K as validateDiscordProxyUrl, U as unregisterGateway, q as withValidatedDiscordProxy, z as DISCORD_REST_TIMEOUT_MS } from "./send.shared-BmwFjW6T.js";
|
|
6
|
+
import { _ as resolveDiscordModalEntryWithPersistence, g as resolveDiscordComponentEntryWithPersistence, t as editDiscordComponentMessage } from "./send.components-iJyFXw9L.js";
|
|
7
7
|
import { t as getDiscordRuntime } from "./runtime-DgnVQ7zW.js";
|
|
8
|
-
import { a as isDiscordRateLimitResponseBody, o as summarizeDiscordResponseBody } from "./api-
|
|
9
|
-
import { C as resolveTimestampMs, a as normalizeDiscordSlug, b as formatDiscordReactionEmoji, c as resolveDiscordChannelConfigWithFallback, d as resolveDiscordCommandOwnerAllowFrom, f as resolveDiscordGuildEntry, g as resolveDiscordOwnerAllowFrom, h as resolveDiscordOwnerAccess, i as normalizeDiscordDisplaySlug, l as resolveDiscordChannelPolicyCommandAuthorizer, m as resolveDiscordMemberAllowed, n as isDiscordGroupAllowedByPolicy, o as resolveDiscordAllowListMatch, p as resolveDiscordMemberAccessState, r as normalizeDiscordAllowList, t as allowListMatches, v as resolveGroupDmAllow, x as formatDiscordUserTag, y as shouldEmitDiscordReactionNotification } from "./allow-list-
|
|
10
|
-
import { a as formatMention, t as sendMessageDiscord } from "./send.outbound-
|
|
8
|
+
import { a as isDiscordRateLimitResponseBody, o as summarizeDiscordResponseBody } from "./api-DNVbJyEy.js";
|
|
9
|
+
import { C as resolveTimestampMs, a as normalizeDiscordSlug, b as formatDiscordReactionEmoji, c as resolveDiscordChannelConfigWithFallback, d as resolveDiscordCommandOwnerAllowFrom, f as resolveDiscordGuildEntry, g as resolveDiscordOwnerAllowFrom, h as resolveDiscordOwnerAccess, i as normalizeDiscordDisplaySlug, l as resolveDiscordChannelPolicyCommandAuthorizer, m as resolveDiscordMemberAllowed, n as isDiscordGroupAllowedByPolicy, o as resolveDiscordAllowListMatch, p as resolveDiscordMemberAccessState, r as normalizeDiscordAllowList, t as allowListMatches, v as resolveGroupDmAllow, x as formatDiscordUserTag, y as shouldEmitDiscordReactionNotification } from "./allow-list-DnxIlPP2.js";
|
|
10
|
+
import { a as formatMention, t as sendMessageDiscord } from "./send.outbound-DS5tHwfR.js";
|
|
11
11
|
import { i as setPresence, t as clearPresences } from "./presence-cache-z1N8MbJ3.js";
|
|
12
|
-
import {
|
|
12
|
+
import { r as sendVoiceMessageDiscord } from "./send-B7Q6Oc1I.js";
|
|
13
13
|
import { c as raceWithTimeout, u as withAbortTimeout } from "./timeouts-B9cy6RvQ.js";
|
|
14
|
-
import { a as getDiscordExecApprovalApprovers, n as formatDiscordApprovalDisplayValue, r as resolveDiscordConversationIdentity, s as isDiscordExecApprovalClientEnabled, t as DISCORD_APPROVAL_ALLOWED_MENTIONS } from "./approval-message-safety-
|
|
15
|
-
import { t as resolveDiscordChannelAllowlist } from "./resolve-channels-
|
|
16
|
-
import { t as resolveDiscordUserAllowlist } from "./resolve-users-
|
|
17
|
-
import { a as isThreadArchived,
|
|
18
|
-
import {
|
|
19
|
-
import { i as
|
|
20
|
-
import { a as formatDiscordMediaText, d as resolveDiscordChannelInfo, f as resolveDiscordMessageChannelId, n as resolveDiscordForwardedMessagesTextFromSnapshots, t as resolveDiscordEmbedText } from "./message-utils-
|
|
21
|
-
import { t as resolveDiscordSenderIdentity } from "./sender-identity-
|
|
14
|
+
import { a as getDiscordExecApprovalApprovers, n as formatDiscordApprovalDisplayValue, r as resolveDiscordConversationIdentity, s as isDiscordExecApprovalClientEnabled, t as DISCORD_APPROVAL_ALLOWED_MENTIONS } from "./approval-message-safety-AcIxvrf3.js";
|
|
15
|
+
import { t as resolveDiscordChannelAllowlist } from "./resolve-channels-Dm7jEeg6.js";
|
|
16
|
+
import { t as resolveDiscordUserAllowlist } from "./resolve-users-bktrCUUU.js";
|
|
17
|
+
import { a as isThreadArchived, c as resolveDiscordChannelInfoSafe, d as resolveDiscordChannelParentSafe, f as resolveDiscordChannelTopicSafe, h as formatThreadBindingDurationLabel, l as resolveDiscordChannelNameSafe, r as getThreadBindingManager, s as resolveDiscordChannelIdSafe, u as resolveDiscordChannelParentIdSafe } from "./thread-bindings.manager-DCIH6WDC.js";
|
|
18
|
+
import { a as probeDiscordApplicationId, r as parseApplicationIdFromToken } from "./probe-Bl-k5_Ku.js";
|
|
19
|
+
import { i as sanitizeRecentModels, n as normalizeModelRef, r as preferenceTimestampMs, t as buildPreferenceModelKey } from "./model-picker-preference-primitives-BHT1LkR_.js";
|
|
20
|
+
import { a as formatDiscordMediaText, d as resolveDiscordChannelInfo, f as resolveDiscordMessageChannelId, n as resolveDiscordForwardedMessagesTextFromSnapshots, t as resolveDiscordEmbedText } from "./message-utils-BSCPVgy0.js";
|
|
21
|
+
import { t as resolveDiscordSenderIdentity } from "./sender-identity-QtalnCYv.js";
|
|
22
22
|
import { normalizeAccountId } from "openclaw/plugin-sdk/account-id";
|
|
23
23
|
import { buildAgentSessionKey, deriveLastRoutePolicy, isAcpSessionKey, isSubagentSessionKey, parseAgentSessionKey, resolveAgentIdFromSessionKey, resolveAgentRoute } from "openclaw/plugin-sdk/routing";
|
|
24
|
-
import { normalizeLowercaseStringOrEmpty, normalizeOptionalLowercaseString, normalizeOptionalString, normalizeOptionalStringifiedId, normalizeStringEntries,
|
|
24
|
+
import { asFiniteNumber, normalizeLowercaseStringOrEmpty, normalizeOptionalLowercaseString, normalizeOptionalString, normalizeOptionalStringifiedId, normalizeStringEntries, parseFiniteNumber, parseStrictNonNegativeInteger, summarizeStringEntries } from "openclaw/plugin-sdk/string-coerce-runtime";
|
|
25
25
|
import { getRuntimeConfig, getRuntimeConfigSnapshot } from "openclaw/plugin-sdk/runtime-config-snapshot";
|
|
26
26
|
import { logDebug, logError } from "openclaw/plugin-sdk/logging-core";
|
|
27
27
|
import { ApplicationCommandOptionType, ButtonStyle, ChannelType, ComponentType, GatewayCloseCodes, GatewayCloseCodes as GatewayCloseCodes$1, GatewayDispatchEvents, GatewayIntentBits, GatewayOpcodes } from "discord-api-types/v10";
|
|
28
28
|
import { createHash, randomUUID } from "node:crypto";
|
|
29
|
-
import { MAX_DATE_TIMESTAMP_MS, asDateTimestampMs, parseFiniteNumber
|
|
29
|
+
import { MAX_DATE_TIMESTAMP_MS, asDateTimestampMs, parseFiniteNumber as parseFiniteNumber$1, parseStrictInteger, parseStrictPositiveInteger, resolveDateTimestampMs, resolveTimestampMsToIsoString } from "openclaw/plugin-sdk/number-runtime";
|
|
30
30
|
import { expectDefined } from "openclaw/plugin-sdk/expect-runtime";
|
|
31
31
|
import { Type } from "typebox";
|
|
32
32
|
import { Check, Errors } from "typebox/value";
|
|
33
33
|
import { inspect } from "node:util";
|
|
34
34
|
import { readResponseWithLimit } from "openclaw/plugin-sdk/response-limit-runtime";
|
|
35
|
-
import { PlatformMessageNotDispatchedError, formatErrorMessage } from "openclaw/plugin-sdk/error-runtime";
|
|
35
|
+
import { PlatformMessageNotDispatchedError, formatErrorMessage, toErrorObject } from "openclaw/plugin-sdk/error-runtime";
|
|
36
36
|
import { fetchWithSsrFGuard, formatErrorMessage as formatErrorMessage$1 } from "openclaw/plugin-sdk/ssrf-runtime";
|
|
37
37
|
import { createHttp1EnvHttpProxyAgent, createHttp1ProxyAgent, createNodeProxyAgent, resolveEnvHttpProxyAgentOptions, wrapFetchWithAbortSignal } from "openclaw/plugin-sdk/fetch-runtime";
|
|
38
38
|
import { createNonExitingRuntime, createSubsystemLogger, danger, formatDurationSeconds, isVerbose, logVerbose, shouldLogVerbose, sleepWithAbort, warn } from "openclaw/plugin-sdk/runtime-env";
|
|
@@ -40,45 +40,44 @@ import { sliceUtf16Safe, truncateUtf16Safe, withTimeout } from "openclaw/plugin-
|
|
|
40
40
|
import { addAllowlistUserEntriesFromConfigEntry, buildAllowlistResolutionSummary, canonicalizeAllowlistWithResolvedIds, patchAllowlistUsersInConfigEntries, summarizeMapping } from "openclaw/plugin-sdk/allow-from";
|
|
41
41
|
import { resolveMarkdownTableMode } from "openclaw/plugin-sdk/markdown-table-runtime";
|
|
42
42
|
import { resolveChunkMode, resolveTextChunkLimit } from "openclaw/plugin-sdk/reply-chunking";
|
|
43
|
-
import { chunkItems, sanitizeAssistantVisibleText, sanitizeAssistantVisibleTextWithProfile } from "openclaw/plugin-sdk/text-chunking";
|
|
43
|
+
import { chunkItems, findCodeRegions, sanitizeAssistantVisibleText, sanitizeAssistantVisibleTextWithProfile } from "openclaw/plugin-sdk/text-chunking";
|
|
44
44
|
import { createReplyReferencePlanner } from "openclaw/plugin-sdk/reply-reference";
|
|
45
|
-
import { buildOutboundSessionContext, resolveChannelStreamingBlockEnabled, sendDurableMessageBatch } from "openclaw/plugin-sdk/channel-outbound";
|
|
45
|
+
import { buildOutboundSessionContext, listMessageReceiptPlatformIds, resolveChannelStreamingBlockEnabled, sendDurableMessageBatch } from "openclaw/plugin-sdk/channel-outbound";
|
|
46
46
|
import { getAgentScopedMediaLocalRoots } from "openclaw/plugin-sdk/media-runtime";
|
|
47
47
|
import { resolveSendableOutboundReplyParts, resolveTextChunksWithFallback } from "openclaw/plugin-sdk/reply-payload";
|
|
48
48
|
import { loadWebMedia } from "openclaw/plugin-sdk/web-media";
|
|
49
|
-
import { createLazyRuntimeModule
|
|
49
|
+
import { createLazyRuntimeModule } from "openclaw/plugin-sdk/lazy-runtime";
|
|
50
50
|
import { resolvePinnedMainDmOwnerFromAllowlist as resolvePinnedMainDmOwnerFromAllowlist$1 } from "openclaw/plugin-sdk/security-runtime";
|
|
51
51
|
import { GROUP_POLICY_BLOCKED_LABEL, resolveDefaultGroupPolicy, resolveOpenProviderRuntimeGroupPolicy, warnMissingProviderGroupPolicyFallbackOnce } from "openclaw/plugin-sdk/runtime-group-policy";
|
|
52
52
|
import { createChannelPairingChallengeIssuer } from "openclaw/plugin-sdk/channel-pairing";
|
|
53
53
|
import { CHANNEL_APPROVAL_NATIVE_RUNTIME_CONTEXT_CAPABILITY } from "openclaw/plugin-sdk/approval-handler-adapter-runtime";
|
|
54
54
|
import { questionGatewayRuntime } from "openclaw/plugin-sdk/question-gateway-runtime";
|
|
55
55
|
import { buildPairingReply, upsertChannelPairingRequest, upsertChannelPairingRequest as upsertChannelPairingRequest$1 } from "openclaw/plugin-sdk/conversation-runtime";
|
|
56
|
-
import { clearExpiredCooldowns, ensureAuthProfileStore, formatReasoningMessage, getPreparedModelCatalogSnapshot, isProfileInCooldown, loadPreparedModelCatalog, resolveAgentAvatar, resolveAgentDir, resolveDefaultModelForAgent, resolveHumanDelayConfig, resolveProfilesUnavailableReason } from "openclaw/plugin-sdk/agent-runtime";
|
|
56
|
+
import { clearExpiredCooldowns, ensureAuthProfileStore, formatReasoningMessage, getPreparedModelCatalogSnapshot, isProfileInCooldown, listAgentIds, loadPreparedModelCatalog, resolveAgentAvatar, resolveAgentDir, resolveDefaultModelForAgent, resolveHumanDelayConfig, resolveProfilesUnavailableReason } from "openclaw/plugin-sdk/agent-runtime";
|
|
57
57
|
import { isDangerousNameMatchingEnabled } from "openclaw/plugin-sdk/dangerous-name-runtime";
|
|
58
58
|
import { resolveNativeCommandsEnabled, resolveNativeSkillsEnabled } from "openclaw/plugin-sdk/native-command-config-runtime";
|
|
59
|
-
import { normalizeProviderId } from "openclaw/plugin-sdk/provider-model-shared";
|
|
60
59
|
import { requestHeartbeat } from "openclaw/plugin-sdk/heartbeat-runtime";
|
|
61
|
-
import {
|
|
60
|
+
import { enqueueRoutedSystemEvent, enqueueRoutedSystemEvent as enqueueRoutedSystemEvent$1 } from "openclaw/plugin-sdk/system-event-runtime";
|
|
62
61
|
import { createChannelIngressResolver, defineStableChannelIngressIdentity, readChannelIngressStoreAllowFromForDmPolicy } from "openclaw/plugin-sdk/channel-ingress-runtime";
|
|
63
62
|
import { createChannelPartialDeliveryError, dispatchChannelInboundTurn, formatInboundEnvelope, hasVisibleInboundReplyDispatch, isChannelPartialDeliveryError, resolveEnvelopeFormatOptions, resolveInboundSupplementalSenderAllowed, runChannelInboundEvent } from "openclaw/plugin-sdk/channel-inbound";
|
|
64
|
-
import {
|
|
65
|
-
import {
|
|
66
|
-
import { deleteSessionEntry, getSessionEntry, listSessionEntries,
|
|
63
|
+
import { resolveChannelModelOverride } from "openclaw/plugin-sdk/model-session-runtime";
|
|
64
|
+
import { finalizeInboundContext, generateConversationLabel } from "openclaw/plugin-sdk/reply-dispatch-runtime";
|
|
65
|
+
import { deleteSessionEntry, getSessionEntry, listSessionEntries, readSessionUpdatedAt as readSessionUpdatedAt$1, resolveStorePath, resolveStorePath as resolveStorePath$1 } from "openclaw/plugin-sdk/session-store-runtime";
|
|
67
66
|
import { buildCommandTextFromArgs, findCommandByNativeName, formatCommandArgMenuTitle, listChatCommands, listNativeCommandSpecsForConfig, listSkillCommandsForAgents, resolveCommandAuthorizedFromAuthorizers, resolveEffectiveAgentRuntime, resolveNativeCommandSessionTargets, resolveStoredModelOverride, serializeCommandArgs } from "openclaw/plugin-sdk/command-auth-native";
|
|
68
|
-
import { buildCommandTextFromArgs as buildCommandTextFromArgs$1, findCommandByNativeName as findCommandByNativeName$1, parseCommandArgs, resolveCommandArgChoices, resolveCommandArgMenu, serializeCommandArgs as serializeCommandArgs$1 } from "openclaw/plugin-sdk/native-command-registry";
|
|
67
|
+
import { buildCommandTextFromArgs as buildCommandTextFromArgs$1, findCommandByNativeName as findCommandByNativeName$1, mergeNativeCommandSpecs, parseCommandArgs, resolveCommandArgChoices, resolveCommandArgMenu, serializeCommandArgs as serializeCommandArgs$1 } from "openclaw/plugin-sdk/native-command-registry";
|
|
68
|
+
import { PLUGIN_COMMAND_DISPATCH } from "openclaw/plugin-sdk/plugin-command-runtime";
|
|
69
69
|
import { resolveDirectStatusReplyForSession } from "openclaw/plugin-sdk/command-status-runtime";
|
|
70
|
-
import * as pluginRuntime from "openclaw/plugin-sdk/plugin-runtime";
|
|
71
|
-
import { createInteractiveConversationBindingHelpers, dispatchPluginInteractiveHandler } from "openclaw/plugin-sdk/plugin-runtime";
|
|
72
70
|
import * as conversationRuntime from "openclaw/plugin-sdk/conversation-binding-runtime";
|
|
73
|
-
import {
|
|
74
|
-
import { createConnectedChannelStatusPatch, createTransportActivityStatusPatch } from "openclaw/plugin-sdk/gateway-runtime";
|
|
71
|
+
import { normalizeProviderId } from "openclaw/plugin-sdk/provider-model-shared";
|
|
75
72
|
import { EventEmitter } from "node:events";
|
|
76
73
|
import * as ws from "ws";
|
|
77
74
|
import { Agent } from "node:https";
|
|
78
75
|
import { captureHttpExchange, captureWsEvent, resolveDebugProxySettings, resolveEffectiveDebugProxyUrl } from "openclaw/plugin-sdk/proxy-capture";
|
|
79
76
|
import * as dns from "node:dns";
|
|
77
|
+
import { channelReadyPatch, createTransportActivityStatusPatch } from "openclaw/plugin-sdk/gateway-runtime";
|
|
80
78
|
import { registerChannelRuntimeContext } from "openclaw/plugin-sdk/channel-runtime-context";
|
|
81
79
|
import { stripPlainTextToolCallBlocks } from "openclaw/plugin-sdk/tool-payload";
|
|
80
|
+
import { createChannelInteractiveDispatcher } from "openclaw/plugin-sdk/plugin-runtime";
|
|
82
81
|
import { resolveApprovalOverGateway } from "openclaw/plugin-sdk/approval-gateway-runtime";
|
|
83
82
|
import { resolveRequestUrl } from "openclaw/plugin-sdk/request-url";
|
|
84
83
|
import { fetchWithRuntimeDispatcher } from "openclaw/plugin-sdk/runtime-fetch";
|
|
@@ -253,8 +252,11 @@ async function resolveDiscordDmCommandAccess(params) {
|
|
|
253
252
|
subject: createDiscordDmIngressSubject(params.sender),
|
|
254
253
|
conversation: {
|
|
255
254
|
kind: "direct",
|
|
256
|
-
id: params.sender.id
|
|
255
|
+
id: params.conversationId ?? params.sender.id,
|
|
256
|
+
parentId: params.conversationParentId,
|
|
257
|
+
threadId: params.conversationThreadId
|
|
257
258
|
},
|
|
259
|
+
...params.contextBinding ? { contextBinding: params.contextBinding } : {},
|
|
258
260
|
event: {
|
|
259
261
|
kind: params.eventKind ?? "native-command",
|
|
260
262
|
authMode: "inbound",
|
|
@@ -275,7 +277,7 @@ async function resolveDiscordTextCommandAccess(params) {
|
|
|
275
277
|
const memberAccessGroup = "discord-member-access";
|
|
276
278
|
const commandGroup = params.memberAccessConfigured ? [`accessGroup:${memberAccessGroup}`] : [];
|
|
277
279
|
const accessGroupMembership = params.memberAccessConfigured ? [syntheticAccessGroupMembership(memberAccessGroup, params.memberAllowed)] : [];
|
|
278
|
-
return
|
|
280
|
+
return await createDiscordIngressResolver({
|
|
279
281
|
accountId: params.accountId,
|
|
280
282
|
cfg: params.cfg,
|
|
281
283
|
token: params.token,
|
|
@@ -283,9 +285,12 @@ async function resolveDiscordTextCommandAccess(params) {
|
|
|
283
285
|
}).command({
|
|
284
286
|
subject: createDiscordDmIngressSubject(params.sender),
|
|
285
287
|
conversation: {
|
|
286
|
-
kind: "
|
|
287
|
-
id: "discord-command"
|
|
288
|
+
kind: "channel",
|
|
289
|
+
id: params.conversationId ?? "discord-command",
|
|
290
|
+
parentId: params.conversationParentId,
|
|
291
|
+
threadId: params.conversationThreadId
|
|
288
292
|
},
|
|
293
|
+
...params.contextBinding ? { contextBinding: params.contextBinding } : {},
|
|
289
294
|
accessGroupMembership,
|
|
290
295
|
dmPolicy: "allowlist",
|
|
291
296
|
groupPolicy: "allowlist",
|
|
@@ -297,7 +302,7 @@ async function resolveDiscordTextCommandAccess(params) {
|
|
|
297
302
|
hasControlCommand: params.hasControlCommand,
|
|
298
303
|
modeWhenAccessGroupsOff: "configured"
|
|
299
304
|
}
|
|
300
|
-
})
|
|
305
|
+
});
|
|
301
306
|
}
|
|
302
307
|
//#endregion
|
|
303
308
|
//#region extensions/discord/src/monitor/thread-title.ts
|
|
@@ -305,23 +310,10 @@ const DEFAULT_THREAD_TITLE_TIMEOUT_MS = 6e4;
|
|
|
305
310
|
const MAX_THREAD_TITLE_SOURCE_CHARS = 600;
|
|
306
311
|
const MAX_THREAD_TITLE_CHANNEL_NAME_CHARS = 120;
|
|
307
312
|
const MAX_THREAD_TITLE_CHANNEL_DESCRIPTION_CHARS = 320;
|
|
308
|
-
const DISCORD_THREAD_TITLE_MAX_TOKENS = 4096;
|
|
309
313
|
const DISCORD_THREAD_TITLE_SYSTEM_PROMPT = "Generate a concise Discord thread title (3-6 words). Return only the title. Use channel context when provided and avoid redundant channel-name words unless needed for clarity.";
|
|
310
314
|
async function generateThreadTitle(params) {
|
|
311
315
|
const sourceText = params.messageText.trim();
|
|
312
316
|
if (!sourceText) return null;
|
|
313
|
-
const prepared = await prepareSimpleCompletionModelForAgent({
|
|
314
|
-
cfg: params.cfg,
|
|
315
|
-
agentId: params.agentId,
|
|
316
|
-
...params.modelRef ? { modelRef: params.modelRef } : {},
|
|
317
|
-
useUtilityModel: true,
|
|
318
|
-
allowMissingApiKeyModes: ["aws-sdk"]
|
|
319
|
-
});
|
|
320
|
-
if ("error" in prepared) {
|
|
321
|
-
const modelLabel = prepared.selection ? `${prepared.selection.provider}/${prepared.selection.modelId}` : "unknown";
|
|
322
|
-
logVerbose(`thread-title: ${prepared.error} (agent=${params.agentId}, model=${modelLabel})`);
|
|
323
|
-
return null;
|
|
324
|
-
}
|
|
325
317
|
try {
|
|
326
318
|
const userMessage = buildThreadTitleCompletionUserMessage({
|
|
327
319
|
sourceText,
|
|
@@ -329,40 +321,21 @@ async function generateThreadTitle(params) {
|
|
|
329
321
|
channelDescription: params.channelDescription
|
|
330
322
|
});
|
|
331
323
|
const timeoutMs = resolveThreadTitleTimeoutMs(params.timeoutMs);
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
324
|
+
const generated = await generateConversationLabel({
|
|
325
|
+
cfg: params.cfg,
|
|
326
|
+
agentId: params.agentId,
|
|
335
327
|
userMessage,
|
|
336
|
-
|
|
337
|
-
|
|
328
|
+
prompt: DISCORD_THREAD_TITLE_SYSTEM_PROMPT,
|
|
329
|
+
...params.modelRef ? { modelRef: params.modelRef } : {},
|
|
330
|
+
timeoutMs,
|
|
331
|
+
maxLength: MAX_THREAD_TITLE_SOURCE_CHARS
|
|
332
|
+
});
|
|
333
|
+
return generated ? normalizeGeneratedThreadTitle(generated) : null;
|
|
338
334
|
} catch (err) {
|
|
339
335
|
logVerbose(`thread-title: title generation failed for agent ${params.agentId}: ${String(err)}`);
|
|
340
336
|
return null;
|
|
341
337
|
}
|
|
342
338
|
}
|
|
343
|
-
async function completeThreadTitle(params) {
|
|
344
|
-
const maxTokens = Math.min(DISCORD_THREAD_TITLE_MAX_TOKENS, Math.floor(params.model.maxTokens));
|
|
345
|
-
return await withAbortTimeout({
|
|
346
|
-
timeoutMs: params.timeoutMs,
|
|
347
|
-
createTimeoutError: () => /* @__PURE__ */ new Error(`thread-title timed out after ${params.timeoutMs}ms`),
|
|
348
|
-
run: async (signal) => await completeWithPreparedSimpleCompletionModel({
|
|
349
|
-
model: params.model,
|
|
350
|
-
auth: params.auth,
|
|
351
|
-
context: {
|
|
352
|
-
systemPrompt: DISCORD_THREAD_TITLE_SYSTEM_PROMPT,
|
|
353
|
-
messages: [{
|
|
354
|
-
role: "user",
|
|
355
|
-
content: params.userMessage,
|
|
356
|
-
timestamp: Date.now()
|
|
357
|
-
}]
|
|
358
|
-
},
|
|
359
|
-
options: {
|
|
360
|
-
maxTokens,
|
|
361
|
-
signal
|
|
362
|
-
}
|
|
363
|
-
})
|
|
364
|
-
});
|
|
365
|
-
}
|
|
366
339
|
function buildThreadTitleCompletionUserMessage(params) {
|
|
367
340
|
const sourceText = truncateThreadTitleSourceText(params.sourceText);
|
|
368
341
|
const channelName = normalizeTitleContextField(params.channelName, MAX_THREAD_TITLE_CHANNEL_NAME_CHARS);
|
|
@@ -1113,7 +1086,7 @@ async function handleDiscordReactionEvent(params) {
|
|
|
1113
1086
|
const resolveReactionBase = () => {
|
|
1114
1087
|
if (reactionBase) return reactionBase;
|
|
1115
1088
|
const emojiLabel = formatDiscordReactionEmoji(data.emoji);
|
|
1116
|
-
const actorLabel = formatDiscordUserTag(user);
|
|
1089
|
+
const actorLabel = formatDiscordUserTag(user) || user.id;
|
|
1117
1090
|
const guildSlug = guildInfo?.slug || (data.guild?.name ? normalizeDiscordSlug(data.guild.name) : data.guild_id ?? (isGroupDm ? "group-dm" : "dm"));
|
|
1118
1091
|
const channelLabel = channelSlug ? `#${channelSlug}` : channelName ? `#${normalizeDiscordSlug(channelName)}` : `#${data.channel_id}`;
|
|
1119
1092
|
reactionBase = {
|
|
@@ -1124,24 +1097,21 @@ async function handleDiscordReactionEvent(params) {
|
|
|
1124
1097
|
};
|
|
1125
1098
|
const emitReaction = (text, parentPeerId) => {
|
|
1126
1099
|
const { contextKey } = resolveReactionBase();
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
}).sessionKey,
|
|
1143
|
-
contextKey
|
|
1144
|
-
});
|
|
1100
|
+
enqueueRoutedSystemEvent(text, resolveAgentRoute({
|
|
1101
|
+
cfg: params.cfg,
|
|
1102
|
+
channel: "discord",
|
|
1103
|
+
accountId: params.accountId,
|
|
1104
|
+
guildId: data.guild_id ?? void 0,
|
|
1105
|
+
memberRoleIds,
|
|
1106
|
+
peer: {
|
|
1107
|
+
kind: isDirectMessage ? "direct" : isGroupDm ? "group" : "channel",
|
|
1108
|
+
id: isDirectMessage ? user.id : data.channel_id
|
|
1109
|
+
},
|
|
1110
|
+
parentPeer: parentPeerId ? {
|
|
1111
|
+
kind: "channel",
|
|
1112
|
+
id: parentPeerId
|
|
1113
|
+
} : void 0
|
|
1114
|
+
}), { contextKey });
|
|
1145
1115
|
};
|
|
1146
1116
|
const shouldNotifyReaction = (options) => shouldEmitDiscordReactionNotification({
|
|
1147
1117
|
mode: options.mode,
|
|
@@ -1393,24 +1363,30 @@ var DiscordPresenceBaselineCache = class {
|
|
|
1393
1363
|
* that a later inbound message starts a fresh session in every reset mode.
|
|
1394
1364
|
*/
|
|
1395
1365
|
async function closeDiscordThreadSessions(params) {
|
|
1396
|
-
const { cfg,
|
|
1366
|
+
const { cfg, threadId } = params;
|
|
1397
1367
|
const normalizedThreadId = normalizeOptionalLowercaseString(threadId) ?? "";
|
|
1398
1368
|
if (!normalizedThreadId) return 0;
|
|
1399
1369
|
const segmentRe = new RegExp(`:${normalizedThreadId}(?::|$)`, "i");
|
|
1400
1370
|
function sessionKeyContainsThreadId(key) {
|
|
1401
1371
|
return segmentRe.test(key);
|
|
1402
1372
|
}
|
|
1403
|
-
const storePath = resolveStorePath(cfg.session?.store, { agentId: accountId });
|
|
1404
1373
|
let resetCount = 0;
|
|
1405
|
-
for (const
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
|
|
1374
|
+
for (const agentId of listAgentIds(cfg)) {
|
|
1375
|
+
const storePath = resolveStorePath(cfg.session?.store, { agentId });
|
|
1376
|
+
for (const { sessionKey, entry } of listSessionEntries({
|
|
1377
|
+
agentId,
|
|
1378
|
+
storePath,
|
|
1379
|
+
readOnly: true
|
|
1380
|
+
})) {
|
|
1381
|
+
if (!sessionKeyContainsThreadId(sessionKey)) continue;
|
|
1382
|
+
if (await deleteSessionEntry({
|
|
1383
|
+
archiveTranscript: true,
|
|
1384
|
+
expectedSessionId: entry.sessionId ?? null,
|
|
1385
|
+
expectedUpdatedAt: entry.updatedAt,
|
|
1386
|
+
sessionKey,
|
|
1387
|
+
storePath
|
|
1388
|
+
})) resetCount += 1;
|
|
1389
|
+
}
|
|
1414
1390
|
}
|
|
1415
1391
|
return resetCount;
|
|
1416
1392
|
}
|
|
@@ -1612,8 +1588,7 @@ var DiscordPresenceListener = class extends PresenceUpdateListener {
|
|
|
1612
1588
|
(this.params.logger ?? discordEventQueueLog).warn(danger(`discord presence cooldown persistence failed: ${String(err)}`));
|
|
1613
1589
|
return;
|
|
1614
1590
|
}
|
|
1615
|
-
if (!
|
|
1616
|
-
sessionKey: route.sessionKey,
|
|
1591
|
+
if (!enqueueRoutedSystemEvent(presenceEvent.text, route, {
|
|
1617
1592
|
contextKey: `discord:presence-online:${this.params.accountId}:${data.guild_id}:${userId}`,
|
|
1618
1593
|
deliveryContext: {
|
|
1619
1594
|
channel: "discord",
|
|
@@ -1679,10 +1654,9 @@ var DiscordPresenceReadyListener = class extends ReadyListener {
|
|
|
1679
1654
|
}
|
|
1680
1655
|
};
|
|
1681
1656
|
var DiscordThreadUpdateListener = class extends ThreadUpdateListener {
|
|
1682
|
-
constructor(cfg,
|
|
1657
|
+
constructor(cfg, logger) {
|
|
1683
1658
|
super();
|
|
1684
1659
|
this.cfg = cfg;
|
|
1685
|
-
this.accountId = accountId;
|
|
1686
1660
|
this.logger = logger;
|
|
1687
1661
|
}
|
|
1688
1662
|
async handle(data) {
|
|
@@ -1697,7 +1671,6 @@ var DiscordThreadUpdateListener = class extends ThreadUpdateListener {
|
|
|
1697
1671
|
const logger = this.logger ?? discordEventQueueLog;
|
|
1698
1672
|
const count = await closeDiscordThreadSessions({
|
|
1699
1673
|
cfg: this.cfg,
|
|
1700
|
-
accountId: this.accountId,
|
|
1701
1674
|
threadId
|
|
1702
1675
|
});
|
|
1703
1676
|
if (count > 0) logger.info("Discord thread archived — reset sessions", {
|
|
@@ -1711,6 +1684,40 @@ var DiscordThreadUpdateListener = class extends ThreadUpdateListener {
|
|
|
1711
1684
|
});
|
|
1712
1685
|
}
|
|
1713
1686
|
};
|
|
1687
|
+
var DiscordThreadDeleteListener = class extends ThreadDeleteListener {
|
|
1688
|
+
constructor(cfg, accountId, logger) {
|
|
1689
|
+
super();
|
|
1690
|
+
this.cfg = cfg;
|
|
1691
|
+
this.accountId = accountId;
|
|
1692
|
+
this.logger = logger;
|
|
1693
|
+
}
|
|
1694
|
+
async handle(data) {
|
|
1695
|
+
await runDiscordListenerWithSlowLog({
|
|
1696
|
+
logger: this.logger,
|
|
1697
|
+
listener: this.constructor.name,
|
|
1698
|
+
event: this.type,
|
|
1699
|
+
run: async () => {
|
|
1700
|
+
const threadId = data.id;
|
|
1701
|
+
getThreadBindingManager(this.accountId)?.unbindThread({
|
|
1702
|
+
threadId,
|
|
1703
|
+
reason: "thread-delete",
|
|
1704
|
+
sendFarewell: false
|
|
1705
|
+
});
|
|
1706
|
+
const count = await closeDiscordThreadSessions({
|
|
1707
|
+
cfg: this.cfg,
|
|
1708
|
+
threadId
|
|
1709
|
+
});
|
|
1710
|
+
if (count > 0) (this.logger ?? discordEventQueueLog).info("Discord thread deleted — reset sessions", {
|
|
1711
|
+
threadId,
|
|
1712
|
+
count
|
|
1713
|
+
});
|
|
1714
|
+
},
|
|
1715
|
+
onError: (err) => {
|
|
1716
|
+
(this.logger ?? discordEventQueueLog).error(danger(`discord thread-delete handler failed: ${String(err)}`));
|
|
1717
|
+
}
|
|
1718
|
+
});
|
|
1719
|
+
}
|
|
1720
|
+
};
|
|
1714
1721
|
//#endregion
|
|
1715
1722
|
//#region extensions/discord/src/internal/gateway-dispatch.ts
|
|
1716
1723
|
function dispatchVoiceGatewayEvent(client, type, data) {
|
|
@@ -1841,17 +1848,7 @@ async function deliverDiscordInteractionReply(params) {
|
|
|
1841
1848
|
...contentPayload,
|
|
1842
1849
|
...components ? { components } : {},
|
|
1843
1850
|
...params.responseEphemeral !== void 0 ? { ephemeral: params.responseEphemeral } : {},
|
|
1844
|
-
files
|
|
1845
|
-
if (file.data instanceof Blob) return {
|
|
1846
|
-
name: file.name,
|
|
1847
|
-
data: file.data
|
|
1848
|
-
};
|
|
1849
|
-
const arrayBuffer = Uint8Array.from(file.data).buffer;
|
|
1850
|
-
return {
|
|
1851
|
-
name: file.name,
|
|
1852
|
-
data: new Blob([arrayBuffer])
|
|
1853
|
-
};
|
|
1854
|
-
})
|
|
1851
|
+
files
|
|
1855
1852
|
} : {
|
|
1856
1853
|
...contentPayload,
|
|
1857
1854
|
...components ? { components } : {},
|
|
@@ -1884,7 +1881,8 @@ async function deliverDiscordInteractionReply(params) {
|
|
|
1884
1881
|
const loaded = await loadWebMedia(url, { localRoots: params.mediaLocalRoots });
|
|
1885
1882
|
return {
|
|
1886
1883
|
name: loaded.fileName ?? "upload",
|
|
1887
|
-
data: loaded.buffer
|
|
1884
|
+
data: loaded.buffer,
|
|
1885
|
+
contentType: loaded.contentType
|
|
1888
1886
|
};
|
|
1889
1887
|
}));
|
|
1890
1888
|
const chunks = resolveTextChunksWithFallback(reply.text, chunkDiscordTextWithMode(reply.text, {
|
|
@@ -2031,8 +2029,6 @@ async function resolveDiscordNativeInteractionRouteState(params) {
|
|
|
2031
2029
|
//#endregion
|
|
2032
2030
|
//#region extensions/discord/src/monitor/native-command.runtime.ts
|
|
2033
2031
|
const nativeCommandRuntime = {
|
|
2034
|
-
matchPluginCommand: pluginRuntime.matchPluginCommand,
|
|
2035
|
-
executePluginCommand: pluginRuntime.executePluginCommand,
|
|
2036
2032
|
dispatchChannelInboundTurn,
|
|
2037
2033
|
resolveDirectStatusReplyForSession,
|
|
2038
2034
|
resolveDiscordNativeInteractionRouteState,
|
|
@@ -2043,7 +2039,8 @@ const nativeCommandRuntime = {
|
|
|
2043
2039
|
async function dispatchDiscordNativeAgentReply(params) {
|
|
2044
2040
|
const blockStreamingEnabled = resolveChannelStreamingBlockEnabled(params.discordConfig);
|
|
2045
2041
|
let didReply = false;
|
|
2046
|
-
let
|
|
2042
|
+
let finalReplyOutcome;
|
|
2043
|
+
let hiddenFinalReply;
|
|
2047
2044
|
const turnResult = await nativeCommandRuntime.dispatchChannelInboundTurn({
|
|
2048
2045
|
cfg: params.cfg,
|
|
2049
2046
|
channel: "discord",
|
|
@@ -2079,14 +2076,17 @@ async function dispatchDiscordNativeAgentReply(params) {
|
|
|
2079
2076
|
suppression: { reason: "no_visible_result" }
|
|
2080
2077
|
};
|
|
2081
2078
|
},
|
|
2082
|
-
onDelivered: (
|
|
2083
|
-
if (result?.
|
|
2079
|
+
onDelivered: (payload, info, result) => {
|
|
2080
|
+
if (params.suppressReplies && info.kind === "final" && result?.suppression?.reason === "no_visible_result" && payload.text?.trim()) hiddenFinalReply = payload;
|
|
2081
|
+
if (info.kind === "final" && result?.visibleReplySent !== void 0 && (result.visibleReplySent || finalReplyOutcome !== "failed")) finalReplyOutcome = result.visibleReplySent ? "accepted" : "suppressed";
|
|
2084
2082
|
},
|
|
2085
2083
|
onError: (err, info) => {
|
|
2086
|
-
|
|
2084
|
+
const partialDelivery = isChannelPartialDeliveryError(err);
|
|
2085
|
+
if (partialDelivery) {
|
|
2087
2086
|
didReply = true;
|
|
2088
2087
|
logVerbose("discord: interaction reply partially delivered before expiry");
|
|
2089
2088
|
}
|
|
2089
|
+
if (info.kind === "final") finalReplyOutcome = partialDelivery ? "accepted" : "failed";
|
|
2090
2090
|
const message = err instanceof Error ? err.stack ?? err.message : String(err);
|
|
2091
2091
|
params.log.error(`discord slash ${info.kind} reply failed: ${message}`);
|
|
2092
2092
|
}
|
|
@@ -2095,14 +2095,20 @@ async function dispatchDiscordNativeAgentReply(params) {
|
|
|
2095
2095
|
dispatcherOptions: { humanDelay: resolveHumanDelayConfig(params.cfg, params.effectiveRoute.agentId) },
|
|
2096
2096
|
replyOptions: {
|
|
2097
2097
|
skillFilter: params.channelConfig?.skills,
|
|
2098
|
+
[PLUGIN_COMMAND_DISPATCH]: params.pluginCommandDispatch,
|
|
2098
2099
|
disableBlockStreaming: typeof blockStreamingEnabled === "boolean" ? !blockStreamingEnabled : void 0
|
|
2099
2100
|
}
|
|
2100
2101
|
});
|
|
2101
|
-
|
|
2102
|
+
const deliberateSilentTerminalReply = turnResult.dispatched && turnResult.dispatchResult.deliberateSilentTerminalReply === true;
|
|
2103
|
+
const dispatchResult = {
|
|
2104
|
+
dispatched: turnResult.dispatched,
|
|
2105
|
+
...hiddenFinalReply ? { hiddenFinalReply } : {}
|
|
2106
|
+
};
|
|
2107
|
+
if (!didReply && (params.suppressReplies || finalReplyOutcome === "suppressed" || deliberateSilentTerminalReply)) {
|
|
2102
2108
|
await settleDiscordInteractionWithoutVisibleReply(params.interaction);
|
|
2103
|
-
return;
|
|
2109
|
+
return dispatchResult;
|
|
2104
2110
|
}
|
|
2105
|
-
if (
|
|
2111
|
+
if (didReply || turnResult.dispatched && hasVisibleInboundReplyDispatch(turnResult.dispatchResult)) return dispatchResult;
|
|
2106
2112
|
await safeDiscordInteractionCall("interaction empty fallback", async () => {
|
|
2107
2113
|
const payload = {
|
|
2108
2114
|
content: DISCORD_EMPTY_VISIBLE_REPLY_WARNING,
|
|
@@ -2114,6 +2120,7 @@ async function dispatchDiscordNativeAgentReply(params) {
|
|
|
2114
2120
|
}
|
|
2115
2121
|
await params.interaction.reply(payload);
|
|
2116
2122
|
});
|
|
2123
|
+
return dispatchResult;
|
|
2117
2124
|
}
|
|
2118
2125
|
//#endregion
|
|
2119
2126
|
//#region extensions/discord/src/monitor/native-interaction-channel-context.ts
|
|
@@ -2623,7 +2630,8 @@ async function handleDiscordCommandArgInteraction(params) {
|
|
|
2623
2630
|
sessionPrefix: ctx.sessionPrefix,
|
|
2624
2631
|
preferFollowUp: true,
|
|
2625
2632
|
threadBindings: ctx.threadBindings,
|
|
2626
|
-
responseEphemeral: resolveDiscordSlashCommandConfig(ctx.discordConfig?.slashCommand).ephemeral
|
|
2633
|
+
responseEphemeral: resolveDiscordSlashCommandConfig(ctx.discordConfig?.slashCommand).ephemeral,
|
|
2634
|
+
pluginCommandDispatch: { kind: "non-plugin" }
|
|
2627
2635
|
});
|
|
2628
2636
|
}
|
|
2629
2637
|
async function runDiscordCommandArgButton(params) {
|
|
@@ -2730,10 +2738,10 @@ function timestampOrder(value) {
|
|
|
2730
2738
|
return value !== void 0 && value >= 0 ? value : 0;
|
|
2731
2739
|
}
|
|
2732
2740
|
function comparePreferenceEntries(left, right) {
|
|
2733
|
-
return
|
|
2741
|
+
return preferenceTimestampMs(right.value.updatedAt) - preferenceTimestampMs(left.value.updatedAt) || timestampOrder(right.value.updatedOrder) - timestampOrder(left.value.updatedOrder) || left.key.localeCompare(right.key);
|
|
2734
2742
|
}
|
|
2735
2743
|
function nextPreferenceTimestamp(existingEntries) {
|
|
2736
|
-
const existingMaxTimestampMs = existingEntries.reduce((max, entry) => Math.max(max,
|
|
2744
|
+
const existingMaxTimestampMs = existingEntries.reduce((max, entry) => Math.max(max, preferenceTimestampMs(entry.updatedAt)), 0);
|
|
2737
2745
|
lastPreferenceTimestampMs = Math.min(Math.max(resolveDateTimestampMs(Date.now(), 0), lastPreferenceTimestampMs + 1, existingMaxTimestampMs + 1), MAX_DATE_TIMESTAMP_MS);
|
|
2738
2746
|
const existingMaxOrder = existingEntries.reduce((max, entry) => Math.max(max, timestampOrder(entry.updatedOrder)), 0);
|
|
2739
2747
|
lastPreferenceOrder = Math.max(lastPreferenceOrder + 1, existingMaxOrder + 1);
|
|
@@ -2782,8 +2790,6 @@ async function recordDiscordModelPickerRecentModel(params) {
|
|
|
2782
2790
|
const DISCORD_MODEL_PICKER_CUSTOM_ID_KEY = "mdlpk";
|
|
2783
2791
|
const DISCORD_CUSTOM_ID_MAX_CHARS = 100;
|
|
2784
2792
|
const DISCORD_COMPONENT_MAX_SELECT_OPTIONS = 25;
|
|
2785
|
-
const DISCORD_MODEL_PICKER_PROVIDER_PAGE_SIZE = DISCORD_COMPONENT_MAX_SELECT_OPTIONS;
|
|
2786
|
-
const DISCORD_MODEL_PICKER_MODEL_PAGE_SIZE = DISCORD_COMPONENT_MAX_SELECT_OPTIONS;
|
|
2787
2793
|
function compareBucketItems(left, right) {
|
|
2788
2794
|
const normalized = left.toLowerCase().localeCompare(right.toLowerCase());
|
|
2789
2795
|
return normalized === 0 ? left.localeCompare(right) : normalized;
|
|
@@ -2843,15 +2849,15 @@ function parseRawPage(value) {
|
|
|
2843
2849
|
}
|
|
2844
2850
|
return 1;
|
|
2845
2851
|
}
|
|
2846
|
-
function parseRawPositiveInt(value) {
|
|
2847
|
-
return parseStrictPositiveInteger(value);
|
|
2848
|
-
}
|
|
2849
2852
|
function coerceString(value) {
|
|
2850
2853
|
return typeof value === "string" || typeof value === "number" ? String(value) : "";
|
|
2851
2854
|
}
|
|
2852
|
-
function clampPageSize(rawPageSize
|
|
2853
|
-
if (!Number.isFinite(rawPageSize)) return
|
|
2854
|
-
return Math.min(
|
|
2855
|
+
function clampPageSize(rawPageSize) {
|
|
2856
|
+
if (!Number.isFinite(rawPageSize)) return DISCORD_COMPONENT_MAX_SELECT_OPTIONS;
|
|
2857
|
+
return Math.min(DISCORD_COMPONENT_MAX_SELECT_OPTIONS, Math.max(1, Math.floor(rawPageSize ?? DISCORD_COMPONENT_MAX_SELECT_OPTIONS)));
|
|
2858
|
+
}
|
|
2859
|
+
function normalizeOptionalModelPickerIndex(value) {
|
|
2860
|
+
return typeof value === "number" && Number.isFinite(value) ? Math.max(1, Math.floor(value)) : void 0;
|
|
2855
2861
|
}
|
|
2856
2862
|
function paginateItems(params) {
|
|
2857
2863
|
const totalItems = params.items.length;
|
|
@@ -2877,10 +2883,10 @@ function buildDiscordModelPickerCustomId(params) {
|
|
|
2877
2883
|
const userId = params.userId.trim();
|
|
2878
2884
|
if (!userId) throw new Error("Discord model picker custom_id requires userId");
|
|
2879
2885
|
const page = normalizeModelPickerPage(params.page);
|
|
2880
|
-
const providerPage =
|
|
2886
|
+
const providerPage = normalizeOptionalModelPickerIndex(params.providerPage);
|
|
2881
2887
|
const normalizedProvider = params.provider ? normalizeProviderId(params.provider) : void 0;
|
|
2882
|
-
const modelIndex =
|
|
2883
|
-
const recentSlot =
|
|
2888
|
+
const modelIndex = normalizeOptionalModelPickerIndex(params.modelIndex);
|
|
2889
|
+
const recentSlot = normalizeOptionalModelPickerIndex(params.recentSlot);
|
|
2884
2890
|
const modelToken = params.modelToken?.trim();
|
|
2885
2891
|
if (modelToken && !DISCORD_MODEL_PICKER_MODEL_TOKEN_PATTERN.test(modelToken)) throw new Error("Discord model picker model token is invalid");
|
|
2886
2892
|
const parts = [
|
|
@@ -2893,7 +2899,7 @@ function buildDiscordModelPickerCustomId(params) {
|
|
|
2893
2899
|
if (normalizedProvider) parts.push(`p=${encodeCustomIdComponent(normalizedProvider)}`);
|
|
2894
2900
|
const runtime = params.runtime?.trim();
|
|
2895
2901
|
if (runtime) parts.push(`r=${encodeCustomIdComponent(runtime)}`);
|
|
2896
|
-
const runtimeIndex =
|
|
2902
|
+
const runtimeIndex = normalizeOptionalModelPickerIndex(params.runtimeIndex);
|
|
2897
2903
|
if (runtimeIndex) parts.push(`ri=${String(runtimeIndex)}`);
|
|
2898
2904
|
if (providerPage) parts.push(`pp=${String(providerPage)}`);
|
|
2899
2905
|
if (modelToken) parts.push(`m=${modelToken}`);
|
|
@@ -2917,13 +2923,13 @@ function parseDiscordModelPickerData(data) {
|
|
|
2917
2923
|
const userId = decodeCustomIdComponent(coerceString(data.u));
|
|
2918
2924
|
const providerRaw = decodeCustomIdComponent(coerceString(data.p));
|
|
2919
2925
|
const runtimeRaw = decodeCustomIdComponent(coerceString(data.r));
|
|
2920
|
-
const runtimeIndex =
|
|
2926
|
+
const runtimeIndex = parseStrictPositiveInteger(data.ri);
|
|
2921
2927
|
const page = parseRawPage(data.g ?? data.pg);
|
|
2922
|
-
const providerPage =
|
|
2923
|
-
const modelIndex =
|
|
2928
|
+
const providerPage = parseStrictPositiveInteger(data.pp);
|
|
2929
|
+
const modelIndex = parseStrictPositiveInteger(data.mi);
|
|
2924
2930
|
const modelTokenRaw = coerceString(data.m).trim();
|
|
2925
2931
|
const modelToken = DISCORD_MODEL_PICKER_MODEL_TOKEN_PATTERN.test(modelTokenRaw) ? modelTokenRaw : void 0;
|
|
2926
|
-
const recentSlot =
|
|
2932
|
+
const recentSlot = parseStrictPositiveInteger(data.rs);
|
|
2927
2933
|
const providerBucketRaw = decodeCustomIdComponent(coerceString(data.pb)).trim().toLowerCase();
|
|
2928
2934
|
const modelBucketRaw = decodeCustomIdComponent(coerceString(data.mb)).trim().toLowerCase();
|
|
2929
2935
|
if (!isValidCommandContext(command) || !isValidPickerAction(action) || !isValidPickerView(view)) return null;
|
|
@@ -3039,17 +3045,7 @@ function findProviderBucketId(data, provider) {
|
|
|
3039
3045
|
return findProviderBucketLocation(data, provider)?.bucket;
|
|
3040
3046
|
}
|
|
3041
3047
|
function findProviderBucketLocation(data, provider) {
|
|
3042
|
-
|
|
3043
|
-
const sorted = [...data.providers].toSorted();
|
|
3044
|
-
const idx = sorted.indexOf(normalized);
|
|
3045
|
-
if (idx < 0) return;
|
|
3046
|
-
const containing = computeAlphaBuckets(sorted).find((bucket) => idx >= bucket.start && idx < bucket.end);
|
|
3047
|
-
if (!containing) return;
|
|
3048
|
-
const page = Math.floor((idx - containing.start) / DISCORD_MODEL_PICKER_PROVIDER_PAGE_SIZE) + 1;
|
|
3049
|
-
return {
|
|
3050
|
-
...containing.id !== "all" ? { bucket: containing.id } : {},
|
|
3051
|
-
page
|
|
3052
|
-
};
|
|
3048
|
+
return findModelPickerBucketLocation([...data.providers].toSorted(), normalizeProviderId(provider));
|
|
3053
3049
|
}
|
|
3054
3050
|
/**
|
|
3055
3051
|
* Derive the alpha-bucket id that contains a given model id within the
|
|
@@ -3059,28 +3055,24 @@ function findProviderBucketLocation(data, provider) {
|
|
|
3059
3055
|
*/
|
|
3060
3056
|
function findModelBucketId(data, provider, model) {
|
|
3061
3057
|
const modelSet = data.byProvider.get(normalizeProviderId(provider));
|
|
3062
|
-
|
|
3063
|
-
|
|
3064
|
-
|
|
3065
|
-
|
|
3066
|
-
const
|
|
3067
|
-
return
|
|
3068
|
-
}
|
|
3069
|
-
|
|
3070
|
-
|
|
3071
|
-
|
|
3072
|
-
|
|
3073
|
-
|
|
3074
|
-
}
|
|
3075
|
-
function getDiscordModelPickerProviderPage(params) {
|
|
3076
|
-
const allItems = buildDiscordModelPickerProviderItems(params.data);
|
|
3077
|
-
const buckets = computeAlphaBuckets(allItems.map((item) => item.id));
|
|
3058
|
+
return modelSet ? findModelPickerBucketLocation([...modelSet].toSorted(compareBucketItems), model)?.bucket : void 0;
|
|
3059
|
+
}
|
|
3060
|
+
function findModelPickerBucketLocation(sortedItems, item, pageSize = DISCORD_COMPONENT_MAX_SELECT_OPTIONS) {
|
|
3061
|
+
const index = sortedItems.indexOf(item);
|
|
3062
|
+
const bucket = index < 0 ? void 0 : computeAlphaBuckets(sortedItems).find((entry) => index >= entry.start && index < entry.end);
|
|
3063
|
+
return bucket ? {
|
|
3064
|
+
...bucket.id === "all" ? {} : { bucket: bucket.id },
|
|
3065
|
+
page: Math.floor((index - bucket.start) / pageSize) + 1
|
|
3066
|
+
} : void 0;
|
|
3067
|
+
}
|
|
3068
|
+
function paginateDiscordModelPickerBucket(params) {
|
|
3069
|
+
const buckets = computeAlphaBuckets(params.itemLabels);
|
|
3078
3070
|
const bucket = resolveBucket(buckets, params.bucket);
|
|
3079
|
-
const
|
|
3080
|
-
const pageSize = clampPageSize(params.pageSize
|
|
3071
|
+
const items = bucket ? params.items.slice(bucket.start, bucket.end) : params.items;
|
|
3072
|
+
const pageSize = clampPageSize(params.pageSize);
|
|
3081
3073
|
return {
|
|
3082
3074
|
...paginateItems({
|
|
3083
|
-
items
|
|
3075
|
+
items,
|
|
3084
3076
|
page: normalizeModelPickerPage(params.page),
|
|
3085
3077
|
pageSize
|
|
3086
3078
|
}),
|
|
@@ -3088,24 +3080,29 @@ function getDiscordModelPickerProviderPage(params) {
|
|
|
3088
3080
|
buckets
|
|
3089
3081
|
};
|
|
3090
3082
|
}
|
|
3083
|
+
function getDiscordModelPickerProviderPage(params) {
|
|
3084
|
+
const providers = [...params.data.providers].toSorted();
|
|
3085
|
+
return paginateDiscordModelPickerBucket({
|
|
3086
|
+
...params,
|
|
3087
|
+
itemLabels: providers,
|
|
3088
|
+
items: providers.map((provider) => ({
|
|
3089
|
+
id: provider,
|
|
3090
|
+
count: params.data.byProvider.get(provider)?.size ?? 0
|
|
3091
|
+
}))
|
|
3092
|
+
});
|
|
3093
|
+
}
|
|
3091
3094
|
function getDiscordModelPickerModelPage(params) {
|
|
3092
3095
|
const provider = normalizeProviderId(params.provider);
|
|
3093
3096
|
const modelSet = params.data.byProvider.get(provider);
|
|
3094
3097
|
if (!modelSet) return null;
|
|
3095
3098
|
const allModels = [...modelSet].toSorted(compareBucketItems);
|
|
3096
|
-
const buckets = computeAlphaBuckets(allModels);
|
|
3097
|
-
const bucket = resolveBucket(buckets, params.bucket);
|
|
3098
|
-
const bucketItems = bucket ? allModels.slice(bucket.start, bucket.end) : allModels;
|
|
3099
|
-
const pageSize = clampPageSize(params.pageSize, DISCORD_MODEL_PICKER_MODEL_PAGE_SIZE, DISCORD_MODEL_PICKER_MODEL_PAGE_SIZE);
|
|
3100
3099
|
return {
|
|
3101
|
-
...
|
|
3102
|
-
|
|
3103
|
-
|
|
3104
|
-
|
|
3100
|
+
...paginateDiscordModelPickerBucket({
|
|
3101
|
+
...params,
|
|
3102
|
+
items: allModels,
|
|
3103
|
+
itemLabels: allModels
|
|
3105
3104
|
}),
|
|
3106
|
-
provider
|
|
3107
|
-
bucket,
|
|
3108
|
-
buckets
|
|
3105
|
+
provider
|
|
3109
3106
|
};
|
|
3110
3107
|
}
|
|
3111
3108
|
function resolveDiscordModelPickerPageForModel(params) {
|
|
@@ -3113,16 +3110,8 @@ function resolveDiscordModelPickerPageForModel(params) {
|
|
|
3113
3110
|
const modelSet = params.data.byProvider.get(provider);
|
|
3114
3111
|
if (!modelSet) return { page: 1 };
|
|
3115
3112
|
const sorted = [...modelSet].toSorted(compareBucketItems);
|
|
3116
|
-
const
|
|
3117
|
-
|
|
3118
|
-
const pageSize = clampPageSize(params.pageSize, DISCORD_MODEL_PICKER_MODEL_PAGE_SIZE, DISCORD_MODEL_PICKER_MODEL_PAGE_SIZE);
|
|
3119
|
-
const containingBucket = computeAlphaBuckets(sorted).find((bucket) => index >= bucket.start && index < bucket.end);
|
|
3120
|
-
if (!containingBucket) return { page: Math.floor(index / pageSize) + 1 };
|
|
3121
|
-
const offsetInBucket = index - containingBucket.start;
|
|
3122
|
-
return {
|
|
3123
|
-
page: Math.floor(offsetInBucket / pageSize) + 1,
|
|
3124
|
-
bucket: containingBucket.id === "all" ? void 0 : containingBucket.id
|
|
3125
|
-
};
|
|
3113
|
+
const pageSize = clampPageSize(params.pageSize);
|
|
3114
|
+
return findModelPickerBucketLocation(sorted, params.model, pageSize) ?? { page: 1 };
|
|
3126
3115
|
}
|
|
3127
3116
|
//#endregion
|
|
3128
3117
|
//#region extensions/discord/src/monitor/model-picker.view.ts
|
|
@@ -3302,53 +3291,25 @@ function buildProviderSelectRow(params) {
|
|
|
3302
3291
|
}
|
|
3303
3292
|
function buildPaginationRow(params) {
|
|
3304
3293
|
if (params.totalPages <= 1) return null;
|
|
3305
|
-
|
|
3306
|
-
|
|
3307
|
-
|
|
3308
|
-
|
|
3309
|
-
|
|
3310
|
-
|
|
3311
|
-
|
|
3312
|
-
|
|
3313
|
-
view: params.view,
|
|
3314
|
-
provider: params.provider,
|
|
3315
|
-
runtime: params.runtime,
|
|
3316
|
-
runtimeIndex: params.runtimeIndex,
|
|
3317
|
-
page: Math.max(1, params.page - 1),
|
|
3318
|
-
providerPage: params.providerPage,
|
|
3319
|
-
modelIndex: params.modelIndex,
|
|
3320
|
-
modelToken: params.modelToken,
|
|
3321
|
-
providerBucket: params.providerBucket,
|
|
3322
|
-
modelBucket: params.modelBucket,
|
|
3323
|
-
userId: params.userId
|
|
3324
|
-
})
|
|
3325
|
-
}),
|
|
3326
|
-
createModelPickerButton({
|
|
3327
|
-
label: `Page ${params.page}/${params.totalPages}`,
|
|
3328
|
-
style: ButtonStyle.Secondary,
|
|
3329
|
-
disabled: true,
|
|
3330
|
-
customId: DISCORD_MODEL_PICKER_PAGE_INDICATOR_CUSTOM_ID
|
|
3331
|
-
}),
|
|
3332
|
-
createModelPickerButton({
|
|
3333
|
-
label: "Next ▶",
|
|
3334
|
-
style: ButtonStyle.Secondary,
|
|
3335
|
-
disabled: !params.hasNext,
|
|
3336
|
-
customId: buildDiscordModelPickerCustomId({
|
|
3337
|
-
command: params.command,
|
|
3338
|
-
action: "nav",
|
|
3339
|
-
view: params.view,
|
|
3340
|
-
provider: params.provider,
|
|
3341
|
-
runtime: params.runtime,
|
|
3342
|
-
runtimeIndex: params.runtimeIndex,
|
|
3343
|
-
page: Math.min(params.totalPages, params.page + 1),
|
|
3344
|
-
providerPage: params.providerPage,
|
|
3345
|
-
modelIndex: params.modelIndex,
|
|
3346
|
-
modelToken: params.modelToken,
|
|
3347
|
-
providerBucket: params.providerBucket,
|
|
3348
|
-
modelBucket: params.modelBucket,
|
|
3349
|
-
userId: params.userId
|
|
3350
|
-
})
|
|
3294
|
+
const { page, totalPages, hasPrev, hasNext, ...navigationState } = params;
|
|
3295
|
+
const createNavigationButton = (label, targetPage, enabled) => createModelPickerButton({
|
|
3296
|
+
label,
|
|
3297
|
+
disabled: !enabled,
|
|
3298
|
+
customId: buildDiscordModelPickerCustomId({
|
|
3299
|
+
...navigationState,
|
|
3300
|
+
action: "nav",
|
|
3301
|
+
page: targetPage
|
|
3351
3302
|
})
|
|
3303
|
+
});
|
|
3304
|
+
const indicatorButton = createModelPickerButton({
|
|
3305
|
+
label: `Page ${page}/${totalPages}`,
|
|
3306
|
+
disabled: true,
|
|
3307
|
+
customId: DISCORD_MODEL_PICKER_PAGE_INDICATOR_CUSTOM_ID
|
|
3308
|
+
});
|
|
3309
|
+
return new Row([
|
|
3310
|
+
createNavigationButton("◀ Prev", Math.max(1, page - 1), hasPrev),
|
|
3311
|
+
indicatorButton,
|
|
3312
|
+
createNavigationButton("Next ▶", Math.min(totalPages, page + 1), hasNext)
|
|
3352
3313
|
]);
|
|
3353
3314
|
}
|
|
3354
3315
|
function buildModelRows(params) {
|
|
@@ -3461,10 +3422,17 @@ function buildModelRows(params) {
|
|
|
3461
3422
|
const resolvedDefault = params.data.resolvedDefault;
|
|
3462
3423
|
const shouldDisableReset = Boolean(parsedCurrentModel) && parsedCurrentModel?.provider === resolvedDefault.provider && parsedCurrentModel?.model === resolvedDefault.model;
|
|
3463
3424
|
const hasPendingSelection = Boolean(parsedPendingModel) && parsedPendingModel?.provider === params.modelPage.provider && typeof params.pendingModelIndex === "number" && params.pendingModelIndex > 0;
|
|
3425
|
+
const modelActionState = {
|
|
3426
|
+
command: params.command,
|
|
3427
|
+
provider: params.modelPage.provider,
|
|
3428
|
+
...compactRuntime,
|
|
3429
|
+
page: params.modelPage.page,
|
|
3430
|
+
providerPage: providerPage.page,
|
|
3431
|
+
userId: params.userId
|
|
3432
|
+
};
|
|
3464
3433
|
const buttonRowItems = [
|
|
3465
3434
|
createModelPickerButton({
|
|
3466
3435
|
label: "Providers",
|
|
3467
|
-
style: ButtonStyle.Secondary,
|
|
3468
3436
|
customId: buildDiscordModelPickerCustomId({
|
|
3469
3437
|
command: params.command,
|
|
3470
3438
|
action: "back",
|
|
@@ -3476,47 +3444,29 @@ function buildModelRows(params) {
|
|
|
3476
3444
|
}),
|
|
3477
3445
|
createModelPickerButton({
|
|
3478
3446
|
label: "Cancel",
|
|
3479
|
-
style: ButtonStyle.Secondary,
|
|
3480
3447
|
customId: buildDiscordModelPickerCustomId({
|
|
3481
|
-
|
|
3448
|
+
...modelActionState,
|
|
3482
3449
|
action: "cancel",
|
|
3483
|
-
view: "models"
|
|
3484
|
-
provider: params.modelPage.provider,
|
|
3485
|
-
...compactRuntime,
|
|
3486
|
-
page: params.modelPage.page,
|
|
3487
|
-
providerPage: providerPage.page,
|
|
3488
|
-
userId: params.userId
|
|
3450
|
+
view: "models"
|
|
3489
3451
|
})
|
|
3490
3452
|
}),
|
|
3491
3453
|
createModelPickerButton({
|
|
3492
3454
|
label: "Reset to default",
|
|
3493
|
-
style: ButtonStyle.Secondary,
|
|
3494
3455
|
disabled: shouldDisableReset,
|
|
3495
3456
|
customId: buildDiscordModelPickerCustomId({
|
|
3496
|
-
|
|
3457
|
+
...modelActionState,
|
|
3497
3458
|
action: "reset",
|
|
3498
|
-
view: "models"
|
|
3499
|
-
provider: params.modelPage.provider,
|
|
3500
|
-
...compactRuntime,
|
|
3501
|
-
page: params.modelPage.page,
|
|
3502
|
-
providerPage: providerPage.page,
|
|
3503
|
-
userId: params.userId
|
|
3459
|
+
view: "models"
|
|
3504
3460
|
})
|
|
3505
3461
|
})
|
|
3506
3462
|
];
|
|
3507
3463
|
if (hasQuickModels) buttonRowItems.push(createModelPickerButton({
|
|
3508
3464
|
label: "Recents",
|
|
3509
|
-
style: ButtonStyle.Secondary,
|
|
3510
3465
|
customId: buildDiscordModelPickerCustomId({
|
|
3511
|
-
|
|
3466
|
+
...modelActionState,
|
|
3512
3467
|
action: "recents",
|
|
3513
3468
|
view: "recents",
|
|
3514
|
-
|
|
3515
|
-
...compactRuntime,
|
|
3516
|
-
page: params.modelPage.page,
|
|
3517
|
-
providerPage: providerPage.page,
|
|
3518
|
-
modelBucket: activeModelBucket,
|
|
3519
|
-
userId: params.userId
|
|
3469
|
+
modelBucket: activeModelBucket
|
|
3520
3470
|
})
|
|
3521
3471
|
}));
|
|
3522
3472
|
buttonRowItems.push(createModelPickerButton({
|
|
@@ -3524,16 +3474,11 @@ function buildModelRows(params) {
|
|
|
3524
3474
|
style: ButtonStyle.Primary,
|
|
3525
3475
|
disabled: !hasPendingSelection,
|
|
3526
3476
|
customId: buildDiscordModelPickerCustomId({
|
|
3527
|
-
|
|
3477
|
+
...modelActionState,
|
|
3528
3478
|
action: "submit",
|
|
3529
3479
|
view: "models",
|
|
3530
|
-
provider: params.modelPage.provider,
|
|
3531
|
-
...compactRuntime,
|
|
3532
|
-
page: params.modelPage.page,
|
|
3533
|
-
providerPage: providerPage.page,
|
|
3534
3480
|
modelIndex: params.pendingModelIndex,
|
|
3535
|
-
modelToken: pendingModelToken
|
|
3536
|
-
userId: params.userId
|
|
3481
|
+
modelToken: pendingModelToken
|
|
3537
3482
|
})
|
|
3538
3483
|
}));
|
|
3539
3484
|
return {
|
|
@@ -3680,32 +3625,14 @@ function createModelRefToken(modelRef) {
|
|
|
3680
3625
|
function renderDiscordModelPickerRecentsView(params) {
|
|
3681
3626
|
const defaultModelRef = `${params.data.resolvedDefault.provider}/${params.data.resolvedDefault.model}`;
|
|
3682
3627
|
const rows = [];
|
|
3683
|
-
const
|
|
3684
|
-
rows.push(new Row([createModelPickerButton({
|
|
3685
|
-
label: formatRecentsButtonLabel(
|
|
3686
|
-
style: ButtonStyle.Secondary,
|
|
3687
|
-
customId: buildDiscordModelPickerCustomId({
|
|
3688
|
-
command: params.command,
|
|
3689
|
-
action: "submit",
|
|
3690
|
-
view: "recents",
|
|
3691
|
-
recentSlot: 1,
|
|
3692
|
-
modelToken: createModelRefToken(defaultModelRef),
|
|
3693
|
-
provider: params.provider,
|
|
3694
|
-
runtime: params.runtime,
|
|
3695
|
-
runtimeIndex: params.runtimeIndex,
|
|
3696
|
-
page: params.page,
|
|
3697
|
-
providerPage: params.providerPage,
|
|
3698
|
-
userId: params.userId
|
|
3699
|
-
})
|
|
3700
|
-
})]));
|
|
3701
|
-
for (const [i, modelRef] of dedupedQuickModels.entries()) rows.push(new Row([createModelPickerButton({
|
|
3702
|
-
label: formatRecentsButtonLabel(modelRef),
|
|
3703
|
-
style: ButtonStyle.Secondary,
|
|
3628
|
+
const recentModels = [defaultModelRef, ...params.quickModels.filter((modelRef) => modelRef !== defaultModelRef)];
|
|
3629
|
+
for (const [index, modelRef] of recentModels.entries()) rows.push(new Row([createModelPickerButton({
|
|
3630
|
+
label: formatRecentsButtonLabel(modelRef, index === 0 ? "(default)" : void 0),
|
|
3704
3631
|
customId: buildDiscordModelPickerCustomId({
|
|
3705
3632
|
command: params.command,
|
|
3706
3633
|
action: "submit",
|
|
3707
3634
|
view: "recents",
|
|
3708
|
-
recentSlot:
|
|
3635
|
+
recentSlot: index + 1,
|
|
3709
3636
|
modelToken: createModelRefToken(modelRef),
|
|
3710
3637
|
provider: params.provider,
|
|
3711
3638
|
runtime: params.runtime,
|
|
@@ -3717,7 +3644,6 @@ function renderDiscordModelPickerRecentsView(params) {
|
|
|
3717
3644
|
})]));
|
|
3718
3645
|
const backRow = new Row([createModelPickerButton({
|
|
3719
3646
|
label: "Back",
|
|
3720
|
-
style: ButtonStyle.Secondary,
|
|
3721
3647
|
customId: buildDiscordModelPickerCustomId({
|
|
3722
3648
|
command: params.command,
|
|
3723
3649
|
action: "back",
|
|
@@ -3749,43 +3675,10 @@ function toDiscordModelPickerMessagePayload(view) {
|
|
|
3749
3675
|
}
|
|
3750
3676
|
//#endregion
|
|
3751
3677
|
//#region extensions/discord/src/monitor/native-command-model-picker-apply.ts
|
|
3752
|
-
|
|
3753
|
-
const
|
|
3754
|
-
|
|
3755
|
-
|
|
3756
|
-
storePath,
|
|
3757
|
-
sessionKey: params.route.sessionKey,
|
|
3758
|
-
fallbackEntry: {
|
|
3759
|
-
sessionId: randomUUID(),
|
|
3760
|
-
updatedAt: Date.now()
|
|
3761
|
-
},
|
|
3762
|
-
replaceEntry: true,
|
|
3763
|
-
update: (entry) => {
|
|
3764
|
-
persisted = applyModelOverrideToSessionEntry({
|
|
3765
|
-
entry,
|
|
3766
|
-
selection: {
|
|
3767
|
-
provider: params.provider,
|
|
3768
|
-
model: params.model,
|
|
3769
|
-
isDefault: params.isDefault
|
|
3770
|
-
},
|
|
3771
|
-
markLiveSwitchPending: true
|
|
3772
|
-
}).updated || persisted;
|
|
3773
|
-
const runtime = params.runtime?.trim();
|
|
3774
|
-
if (runtime && runtime !== "auto" && runtime !== "default") {
|
|
3775
|
-
if (entry.agentRuntimeOverride !== runtime) {
|
|
3776
|
-
entry.agentRuntimeOverride = runtime;
|
|
3777
|
-
delete entry.agentHarnessId;
|
|
3778
|
-
persisted = true;
|
|
3779
|
-
}
|
|
3780
|
-
} else if (runtime && entry.agentRuntimeOverride) {
|
|
3781
|
-
delete entry.agentRuntimeOverride;
|
|
3782
|
-
delete entry.agentHarnessId;
|
|
3783
|
-
persisted = true;
|
|
3784
|
-
}
|
|
3785
|
-
return entry;
|
|
3786
|
-
}
|
|
3787
|
-
});
|
|
3788
|
-
return persisted;
|
|
3678
|
+
function normalizeExpectedRuntime(value) {
|
|
3679
|
+
const runtime = value?.trim();
|
|
3680
|
+
if (!runtime) return;
|
|
3681
|
+
return runtime === "auto" || runtime === "default" ? "auto" : runtime;
|
|
3789
3682
|
}
|
|
3790
3683
|
async function applyDiscordModelPickerSelection(params) {
|
|
3791
3684
|
try {
|
|
@@ -3800,79 +3693,42 @@ async function applyDiscordModelPickerSelection(params) {
|
|
|
3800
3693
|
sessionPrefix: params.sessionPrefix,
|
|
3801
3694
|
preferFollowUp: true,
|
|
3802
3695
|
threadBindings: params.threadBindings,
|
|
3803
|
-
suppressReplies: true
|
|
3696
|
+
suppressReplies: true,
|
|
3697
|
+
pluginCommandDispatch: { kind: "non-plugin" }
|
|
3804
3698
|
}), 12e3);
|
|
3805
3699
|
if (!dispatchResult.accepted) return {
|
|
3806
3700
|
status: "rejected",
|
|
3807
3701
|
noticeMessage: `❌ Failed to apply ${params.resolvedModelRef}. Try /model ${params.resolvedModelRef} directly.`
|
|
3808
3702
|
};
|
|
3809
|
-
const
|
|
3703
|
+
const hiddenFinalReply = dispatchResult.hiddenFinalReply;
|
|
3704
|
+
const effectiveRoute = dispatchResult.effectiveRoute ?? params.route;
|
|
3810
3705
|
if (params.settleMs > 0) await new Promise((resolve) => {
|
|
3811
3706
|
setTimeout(resolve, params.settleMs);
|
|
3812
3707
|
});
|
|
3813
|
-
|
|
3814
|
-
|
|
3815
|
-
|
|
3816
|
-
|
|
3817
|
-
|
|
3818
|
-
|
|
3819
|
-
|
|
3820
|
-
|
|
3821
|
-
|
|
3822
|
-
|
|
3823
|
-
});
|
|
3824
|
-
await new Promise((resolve) => {
|
|
3825
|
-
setTimeout(resolve, 100);
|
|
3826
|
-
});
|
|
3827
|
-
effectiveModelRef = params.resolveCurrentModel(fallbackRoute);
|
|
3828
|
-
persisted = effectiveModelRef === params.resolvedModelRef;
|
|
3829
|
-
}
|
|
3830
|
-
if (!persisted) {
|
|
3831
|
-
logVerbose(`discord: model picker override mismatch — expected ${params.resolvedModelRef} but read ${effectiveModelRef} from session key ${fallbackRoute.sessionKey}; attempting direct session override persist`);
|
|
3832
|
-
try {
|
|
3833
|
-
const directlyPersisted = await persistDiscordModelPickerOverride({
|
|
3834
|
-
cfg: params.cfg,
|
|
3835
|
-
route: fallbackRoute,
|
|
3836
|
-
provider: params.selectedProvider,
|
|
3837
|
-
model: params.selectedModel,
|
|
3838
|
-
isDefault: params.selectedProvider === params.defaultProvider && params.selectedModel === params.defaultModel,
|
|
3839
|
-
runtime: params.selectedRuntime
|
|
3840
|
-
});
|
|
3841
|
-
await new Promise((resolve) => {
|
|
3842
|
-
setTimeout(resolve, 100);
|
|
3843
|
-
});
|
|
3844
|
-
effectiveModelRef = params.resolveCurrentModel(fallbackRoute);
|
|
3845
|
-
persisted = effectiveModelRef === params.resolvedModelRef;
|
|
3846
|
-
if (!persisted) logVerbose(`discord: direct session override persist failed — expected ${params.resolvedModelRef} but read ${effectiveModelRef} from session key ${fallbackRoute.sessionKey}`);
|
|
3847
|
-
else if (!directlyPersisted) logVerbose(`discord: direct session override persist became a no-op because ${params.resolvedModelRef} was already present on re-read for session key ${fallbackRoute.sessionKey}`);
|
|
3848
|
-
} catch (error) {
|
|
3849
|
-
if (error instanceof ModelSelectionLockedError) return {
|
|
3850
|
-
status: "rejected",
|
|
3851
|
-
noticeMessage: `❌ ${error.message}`
|
|
3852
|
-
};
|
|
3853
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
3854
|
-
logVerbose(`discord: direct session override persist threw for session key ${fallbackRoute.sessionKey}: ${message}`);
|
|
3855
|
-
}
|
|
3856
|
-
}
|
|
3857
|
-
if (persisted) await recordDiscordModelPickerRecentModel({
|
|
3708
|
+
const effectiveModelRef = params.resolveCurrentModel(effectiveRoute);
|
|
3709
|
+
const effectiveRuntime = params.resolveCurrentRuntime(effectiveRoute);
|
|
3710
|
+
const currentSelection = `Current selection: ${effectiveModelRef} with runtime ${effectiveRuntime}.`;
|
|
3711
|
+
if (hiddenFinalReply?.isError) return {
|
|
3712
|
+
status: "rejected",
|
|
3713
|
+
noticeMessage: `${hiddenFinalReply.text?.trim()}\n${currentSelection}`
|
|
3714
|
+
};
|
|
3715
|
+
const expectedRuntime = normalizeExpectedRuntime(params.selectedRuntime);
|
|
3716
|
+
const verified = effectiveModelRef === params.resolvedModelRef && (expectedRuntime === void 0 || effectiveRuntime === expectedRuntime);
|
|
3717
|
+
if (verified) await recordDiscordModelPickerRecentModel({
|
|
3858
3718
|
scope: params.preferenceScope,
|
|
3859
3719
|
modelRef: params.resolvedModelRef,
|
|
3860
3720
|
limit: 5
|
|
3861
3721
|
}).catch(() => void 0);
|
|
3862
|
-
return
|
|
3722
|
+
return verified ? {
|
|
3863
3723
|
status: "success",
|
|
3864
3724
|
effectiveModelRef,
|
|
3865
|
-
noticeMessage: `✅ Model set to ${params.resolvedModelRef}.`
|
|
3725
|
+
noticeMessage: hiddenFinalReply?.text?.trim() || `✅ Model set to ${params.resolvedModelRef}.`
|
|
3866
3726
|
} : {
|
|
3867
3727
|
status: "mismatch",
|
|
3868
3728
|
effectiveModelRef,
|
|
3869
|
-
noticeMessage: `⚠️ Tried to set ${params.resolvedModelRef}, but current
|
|
3729
|
+
noticeMessage: `⚠️ Tried to set ${params.resolvedModelRef}${expectedRuntime ? ` with runtime ${expectedRuntime}` : ""}, but current selection is ${effectiveModelRef} with runtime ${effectiveRuntime}.`
|
|
3870
3730
|
};
|
|
3871
3731
|
} catch (error) {
|
|
3872
|
-
if (error instanceof ModelSelectionLockedError) return {
|
|
3873
|
-
status: "rejected",
|
|
3874
|
-
noticeMessage: `❌ ${error.message}`
|
|
3875
|
-
};
|
|
3876
3732
|
if (error instanceof Error && error.message === "timeout") return {
|
|
3877
3733
|
status: "timeout",
|
|
3878
3734
|
noticeMessage: `⏳ Model change to ${params.resolvedModelRef} is still processing. Check /status in a few seconds.`
|
|
@@ -3902,9 +3758,6 @@ function shouldOpenDiscordModelPickerFromCommand(params) {
|
|
|
3902
3758
|
if (context === "model") return !resolveCommandArgStringValue(params.commandArgs, "model") && !serializedArgs ? context : null;
|
|
3903
3759
|
return serializedArgs ? null : context;
|
|
3904
3760
|
}
|
|
3905
|
-
function buildDiscordModelPickerCurrentModel(defaultProvider, defaultModel) {
|
|
3906
|
-
return `${defaultProvider}/${defaultModel}`;
|
|
3907
|
-
}
|
|
3908
3761
|
function buildDiscordModelPickerAllowedModelRefs(data) {
|
|
3909
3762
|
const out = /* @__PURE__ */ new Set();
|
|
3910
3763
|
for (const provider of data.providers) {
|
|
@@ -4000,7 +3853,7 @@ async function resolveDiscordNativeChoiceContext(params) {
|
|
|
4000
3853
|
}
|
|
4001
3854
|
}
|
|
4002
3855
|
function resolveDiscordModelPickerCurrentModel(params) {
|
|
4003
|
-
const fallback =
|
|
3856
|
+
const fallback = `${params.data.resolvedDefault.provider}/${params.data.resolvedDefault.model}`;
|
|
4004
3857
|
try {
|
|
4005
3858
|
const storePath = resolveStorePath(params.cfg.session?.store, { agentId: params.route.agentId });
|
|
4006
3859
|
const override = resolveStoredModelOverride({
|
|
@@ -4175,7 +4028,7 @@ function buildDiscordModelPickerSelectionCommand(params) {
|
|
|
4175
4028
|
if (!commandDefinition) return null;
|
|
4176
4029
|
const commandArgs = {
|
|
4177
4030
|
values: { model: params.modelRef },
|
|
4178
|
-
raw: params.modelRef
|
|
4031
|
+
raw: params.runtime ? `${params.modelRef} --runtime ${params.runtime}` : params.modelRef
|
|
4179
4032
|
};
|
|
4180
4033
|
return {
|
|
4181
4034
|
command: commandDefinition,
|
|
@@ -4186,7 +4039,7 @@ function buildDiscordModelPickerSelectionCommand(params) {
|
|
|
4186
4039
|
function listDiscordModelPickerProviderModels(data, provider) {
|
|
4187
4040
|
const modelSet = data.byProvider.get(provider);
|
|
4188
4041
|
if (!modelSet) return [];
|
|
4189
|
-
return [...modelSet].toSorted();
|
|
4042
|
+
return [...modelSet].toSorted((left, right) => left < right ? -1 : left > right ? 1 : 0);
|
|
4190
4043
|
}
|
|
4191
4044
|
function resolveDiscordModelPickerModelRefByToken(data, modelToken) {
|
|
4192
4045
|
const matchingRefs = [];
|
|
@@ -4224,10 +4077,6 @@ function resolveDiscordModelPickerSubmissionRuntime(params) {
|
|
|
4224
4077
|
provider: params.provider,
|
|
4225
4078
|
runtime: params.parsedRuntime,
|
|
4226
4079
|
allowResetRuntime: true
|
|
4227
|
-
}) ?? resolveDiscordModelPickerRuntimeForProvider({
|
|
4228
|
-
data: params.data,
|
|
4229
|
-
provider: params.provider,
|
|
4230
|
-
runtime: params.currentRuntime
|
|
4231
4080
|
});
|
|
4232
4081
|
}
|
|
4233
4082
|
async function handleDiscordModelPickerInteraction(params) {
|
|
@@ -4277,6 +4126,22 @@ async function handleDiscordModelPickerInteraction(params) {
|
|
|
4277
4126
|
});
|
|
4278
4127
|
const updatePicker = async (payload) => await params.safeInteractionCall("model picker update", () => deferredUpdate ? interaction.editReply(payload) : interaction.update(payload));
|
|
4279
4128
|
const showNotice = async (message) => await updatePicker(buildDiscordModelPickerNoticePayload(message));
|
|
4129
|
+
const updateModelsView = async (provider, state = {}) => {
|
|
4130
|
+
const rendered = renderDiscordModelPickerModelsView({
|
|
4131
|
+
command: parsed.command,
|
|
4132
|
+
userId: parsed.userId,
|
|
4133
|
+
data: pickerData,
|
|
4134
|
+
provider,
|
|
4135
|
+
page: parsed.page,
|
|
4136
|
+
providerPage: parsed.providerPage ?? 1,
|
|
4137
|
+
providerBucket: parsed.providerBucket ?? findProviderBucketId(pickerData, provider),
|
|
4138
|
+
currentModel: currentModelRef,
|
|
4139
|
+
currentRuntime,
|
|
4140
|
+
quickModels,
|
|
4141
|
+
...state
|
|
4142
|
+
});
|
|
4143
|
+
return await updatePicker(toDiscordModelPickerMessagePayload(rendered));
|
|
4144
|
+
};
|
|
4280
4145
|
if (parsed.action === "recents") {
|
|
4281
4146
|
await updatePicker(toDiscordModelPickerMessagePayload(renderDiscordModelPickerRecentsView({
|
|
4282
4147
|
command: parsed.command,
|
|
@@ -4293,35 +4158,14 @@ async function handleDiscordModelPickerInteraction(params) {
|
|
|
4293
4158
|
})));
|
|
4294
4159
|
return;
|
|
4295
4160
|
}
|
|
4296
|
-
if (parsed.action === "back"
|
|
4297
|
-
|
|
4298
|
-
command: parsed.command,
|
|
4299
|
-
userId: parsed.userId,
|
|
4300
|
-
data: pickerData,
|
|
4301
|
-
page: parsed.page,
|
|
4302
|
-
providerBucket: parsed.providerBucket,
|
|
4303
|
-
currentModel: currentModelRef
|
|
4304
|
-
})));
|
|
4305
|
-
return;
|
|
4306
|
-
}
|
|
4307
|
-
if (parsed.action === "nav" && parsed.view === "providers") {
|
|
4308
|
-
await updatePicker(toDiscordModelPickerMessagePayload(renderDiscordModelPickerProvidersView({
|
|
4309
|
-
command: parsed.command,
|
|
4310
|
-
userId: parsed.userId,
|
|
4311
|
-
data: pickerData,
|
|
4312
|
-
page: parsed.page,
|
|
4313
|
-
providerBucket: parsed.providerBucket,
|
|
4314
|
-
currentModel: currentModelRef
|
|
4315
|
-
})));
|
|
4316
|
-
return;
|
|
4317
|
-
}
|
|
4318
|
-
if (parsed.action === "bucket" && parsed.view === "providers") {
|
|
4161
|
+
if (parsed.view === "providers" && (parsed.action === "back" || parsed.action === "nav" || parsed.action === "bucket")) {
|
|
4162
|
+
const selectingBucket = parsed.action === "bucket";
|
|
4319
4163
|
await updatePicker(toDiscordModelPickerMessagePayload(renderDiscordModelPickerProvidersView({
|
|
4320
4164
|
command: parsed.command,
|
|
4321
4165
|
userId: parsed.userId,
|
|
4322
4166
|
data: pickerData,
|
|
4323
|
-
page: 1,
|
|
4324
|
-
providerBucket: resolveSelectedBucket(interaction),
|
|
4167
|
+
page: selectingBucket ? 1 : parsed.page,
|
|
4168
|
+
providerBucket: selectingBucket ? resolveSelectedBucket(interaction) : parsed.providerBucket,
|
|
4325
4169
|
currentModel: currentModelRef
|
|
4326
4170
|
})));
|
|
4327
4171
|
return;
|
|
@@ -4332,24 +4176,15 @@ async function handleDiscordModelPickerInteraction(params) {
|
|
|
4332
4176
|
currentModelRef,
|
|
4333
4177
|
data: pickerData
|
|
4334
4178
|
});
|
|
4335
|
-
await
|
|
4336
|
-
command: parsed.command,
|
|
4337
|
-
userId: parsed.userId,
|
|
4338
|
-
data: pickerData,
|
|
4339
|
-
provider,
|
|
4179
|
+
await updateModelsView(provider, {
|
|
4340
4180
|
page: 1,
|
|
4341
|
-
providerPage: parsed.providerPage ?? 1,
|
|
4342
|
-
providerBucket: parsed.providerBucket ?? findProviderBucketId(pickerData, provider),
|
|
4343
4181
|
modelBucket: resolveSelectedBucket(interaction),
|
|
4344
|
-
currentModel: currentModelRef,
|
|
4345
|
-
currentRuntime,
|
|
4346
4182
|
pendingRuntime: resolvePendingRuntime({
|
|
4347
4183
|
data: pickerData,
|
|
4348
4184
|
provider,
|
|
4349
4185
|
parsed
|
|
4350
|
-
})
|
|
4351
|
-
|
|
4352
|
-
})));
|
|
4186
|
+
})
|
|
4187
|
+
});
|
|
4353
4188
|
return;
|
|
4354
4189
|
}
|
|
4355
4190
|
if (parsed.action === "nav" && parsed.view === "models") {
|
|
@@ -4374,26 +4209,16 @@ async function handleDiscordModelPickerInteraction(params) {
|
|
|
4374
4209
|
provider,
|
|
4375
4210
|
model: pendingModel
|
|
4376
4211
|
}) : void 0;
|
|
4377
|
-
await
|
|
4378
|
-
command: parsed.command,
|
|
4379
|
-
userId: parsed.userId,
|
|
4380
|
-
data: pickerData,
|
|
4381
|
-
provider,
|
|
4382
|
-
page: parsed.page,
|
|
4383
|
-
providerPage: parsed.providerPage ?? 1,
|
|
4384
|
-
providerBucket: parsed.providerBucket ?? findProviderBucketId(pickerData, provider),
|
|
4212
|
+
await updateModelsView(provider, {
|
|
4385
4213
|
modelBucket: parsed.modelBucket,
|
|
4386
|
-
currentModel: currentModelRef,
|
|
4387
|
-
currentRuntime,
|
|
4388
4214
|
...pendingModel ? { pendingModel: `${provider}/${pendingModel}` } : {},
|
|
4389
4215
|
pendingModelIndex: pendingModelIndex ?? void 0,
|
|
4390
4216
|
pendingRuntime: resolvePendingRuntime({
|
|
4391
4217
|
data: pickerData,
|
|
4392
4218
|
provider,
|
|
4393
4219
|
parsed
|
|
4394
|
-
})
|
|
4395
|
-
|
|
4396
|
-
})));
|
|
4220
|
+
})
|
|
4221
|
+
});
|
|
4397
4222
|
return;
|
|
4398
4223
|
}
|
|
4399
4224
|
if (parsed.action === "back" && parsed.view === "models") {
|
|
@@ -4402,24 +4227,14 @@ async function handleDiscordModelPickerInteraction(params) {
|
|
|
4402
4227
|
currentModelRef,
|
|
4403
4228
|
data: pickerData
|
|
4404
4229
|
});
|
|
4405
|
-
await
|
|
4406
|
-
command: parsed.command,
|
|
4407
|
-
userId: parsed.userId,
|
|
4408
|
-
data: pickerData,
|
|
4409
|
-
provider,
|
|
4410
|
-
page: parsed.page ?? 1,
|
|
4411
|
-
providerPage: parsed.providerPage ?? 1,
|
|
4412
|
-
providerBucket: parsed.providerBucket ?? findProviderBucketId(pickerData, provider),
|
|
4230
|
+
await updateModelsView(provider, {
|
|
4413
4231
|
modelBucket: parsed.modelBucket,
|
|
4414
|
-
currentModel: currentModelRef,
|
|
4415
|
-
currentRuntime,
|
|
4416
4232
|
pendingRuntime: resolvePendingRuntime({
|
|
4417
4233
|
data: pickerData,
|
|
4418
4234
|
provider,
|
|
4419
4235
|
parsed
|
|
4420
|
-
})
|
|
4421
|
-
|
|
4422
|
-
})));
|
|
4236
|
+
})
|
|
4237
|
+
});
|
|
4423
4238
|
return;
|
|
4424
4239
|
}
|
|
4425
4240
|
if (parsed.action === "provider") {
|
|
@@ -4428,18 +4243,10 @@ async function handleDiscordModelPickerInteraction(params) {
|
|
|
4428
4243
|
await showNotice("Sorry, that provider isn't available anymore.");
|
|
4429
4244
|
return;
|
|
4430
4245
|
}
|
|
4431
|
-
await
|
|
4432
|
-
command: parsed.command,
|
|
4433
|
-
userId: parsed.userId,
|
|
4434
|
-
data: pickerData,
|
|
4435
|
-
provider: selectedProvider,
|
|
4246
|
+
await updateModelsView(selectedProvider, {
|
|
4436
4247
|
page: 1,
|
|
4437
|
-
providerPage: parsed.providerPage ?? parsed.page
|
|
4438
|
-
|
|
4439
|
-
currentModel: currentModelRef,
|
|
4440
|
-
currentRuntime,
|
|
4441
|
-
quickModels
|
|
4442
|
-
})));
|
|
4248
|
+
providerPage: parsed.providerPage ?? parsed.page
|
|
4249
|
+
});
|
|
4443
4250
|
return;
|
|
4444
4251
|
}
|
|
4445
4252
|
if (parsed.action === "model") {
|
|
@@ -4459,28 +4266,16 @@ async function handleDiscordModelPickerInteraction(params) {
|
|
|
4459
4266
|
return;
|
|
4460
4267
|
}
|
|
4461
4268
|
const modelRef = `${provider}/${selectedModel}`;
|
|
4462
|
-
|
|
4463
|
-
|
|
4464
|
-
await updatePicker(toDiscordModelPickerMessagePayload(renderDiscordModelPickerModelsView({
|
|
4465
|
-
command: parsed.command,
|
|
4466
|
-
userId: parsed.userId,
|
|
4467
|
-
data: pickerData,
|
|
4468
|
-
provider,
|
|
4469
|
-
page: parsed.page,
|
|
4470
|
-
providerPage: parsed.providerPage ?? 1,
|
|
4471
|
-
providerBucket: derivedProviderBucket,
|
|
4472
|
-
modelBucket: derivedModelBucket,
|
|
4473
|
-
currentModel: currentModelRef,
|
|
4474
|
-
currentRuntime,
|
|
4269
|
+
await updateModelsView(provider, {
|
|
4270
|
+
modelBucket: parsed.modelBucket ?? findModelBucketId(pickerData, provider, selectedModel),
|
|
4475
4271
|
pendingModel: modelRef,
|
|
4476
4272
|
pendingModelIndex: modelIndex,
|
|
4477
4273
|
pendingRuntime: resolvePendingRuntime({
|
|
4478
4274
|
data: pickerData,
|
|
4479
4275
|
provider,
|
|
4480
4276
|
parsed
|
|
4481
|
-
})
|
|
4482
|
-
|
|
4483
|
-
})));
|
|
4277
|
+
})
|
|
4278
|
+
});
|
|
4484
4279
|
return;
|
|
4485
4280
|
}
|
|
4486
4281
|
if (parsed.action === "runtime") {
|
|
@@ -4507,25 +4302,13 @@ async function handleDiscordModelPickerInteraction(params) {
|
|
|
4507
4302
|
provider,
|
|
4508
4303
|
model: selectedModel
|
|
4509
4304
|
}) : void 0;
|
|
4510
|
-
const derivedProviderBucket = parsed.providerBucket ?? findProviderBucketId(pickerData, provider);
|
|
4511
4305
|
const currentModelOnly = splitDiscordModelRef(currentModelRef ?? "");
|
|
4512
|
-
|
|
4513
|
-
|
|
4514
|
-
command: parsed.command,
|
|
4515
|
-
userId: parsed.userId,
|
|
4516
|
-
data: pickerData,
|
|
4517
|
-
provider,
|
|
4518
|
-
page: parsed.page,
|
|
4519
|
-
providerPage: parsed.providerPage ?? 1,
|
|
4520
|
-
providerBucket: derivedProviderBucket,
|
|
4521
|
-
modelBucket: derivedModelBucket,
|
|
4522
|
-
currentModel: currentModelRef,
|
|
4523
|
-
currentRuntime,
|
|
4306
|
+
await updateModelsView(provider, {
|
|
4307
|
+
modelBucket: parsed.modelBucket ?? (selectedModel ? findModelBucketId(pickerData, provider, selectedModel) : currentModelOnly && currentModelOnly.provider === provider ? findModelBucketId(pickerData, provider, currentModelOnly.model) : void 0),
|
|
4524
4308
|
...pendingModel ? { pendingModel } : {},
|
|
4525
4309
|
pendingModelIndex: pendingModelIndex ?? void 0,
|
|
4526
|
-
pendingRuntime: selectedRuntime
|
|
4527
|
-
|
|
4528
|
-
})));
|
|
4310
|
+
pendingRuntime: selectedRuntime
|
|
4311
|
+
});
|
|
4529
4312
|
return;
|
|
4530
4313
|
}
|
|
4531
4314
|
if (parsed.action === "submit" || parsed.action === "reset" || parsed.action === "quick") {
|
|
@@ -4548,10 +4331,12 @@ async function handleDiscordModelPickerInteraction(params) {
|
|
|
4548
4331
|
data: pickerData,
|
|
4549
4332
|
parsed,
|
|
4550
4333
|
selectedProvider: parsedModelRef.provider
|
|
4551
|
-
})
|
|
4552
|
-
|
|
4334
|
+
})
|
|
4335
|
+
});
|
|
4336
|
+
const selectionCommand = buildDiscordModelPickerSelectionCommand({
|
|
4337
|
+
modelRef: resolvedModelRef,
|
|
4338
|
+
runtime: selectedRuntime
|
|
4553
4339
|
});
|
|
4554
|
-
const selectionCommand = buildDiscordModelPickerSelectionCommand({ modelRef: resolvedModelRef });
|
|
4555
4340
|
if (!selectionCommand) {
|
|
4556
4341
|
await showNotice("Sorry, /model is unavailable right now.");
|
|
4557
4342
|
return;
|
|
@@ -4568,17 +4353,17 @@ async function handleDiscordModelPickerInteraction(params) {
|
|
|
4568
4353
|
threadBindings: ctx.threadBindings,
|
|
4569
4354
|
route,
|
|
4570
4355
|
resolvedModelRef,
|
|
4571
|
-
selectedProvider: parsedModelRef.provider,
|
|
4572
|
-
selectedModel: parsedModelRef.model,
|
|
4573
4356
|
selectedRuntime,
|
|
4574
|
-
defaultProvider: pickerData.resolvedDefault.provider,
|
|
4575
|
-
defaultModel: pickerData.resolvedDefault.model,
|
|
4576
4357
|
preferenceScope,
|
|
4577
4358
|
settleMs: ctx.postApplySettleMs ?? 250,
|
|
4578
4359
|
resolveCurrentModel: (currentRoute) => resolveDiscordModelPickerCurrentModel({
|
|
4579
4360
|
cfg,
|
|
4580
4361
|
route: currentRoute,
|
|
4581
4362
|
data: pickerData
|
|
4363
|
+
}),
|
|
4364
|
+
resolveCurrentRuntime: (currentRoute) => resolveDiscordModelPickerCurrentRuntime({
|
|
4365
|
+
cfg,
|
|
4366
|
+
route: currentRoute
|
|
4582
4367
|
})
|
|
4583
4368
|
});
|
|
4584
4369
|
await params.safeInteractionCall("model picker follow-up", () => interaction.followUp({
|
|
@@ -4756,12 +4541,13 @@ function buildDiscordCommandOptions(params) {
|
|
|
4756
4541
|
//#endregion
|
|
4757
4542
|
//#region extensions/discord/src/monitor/native-command.ts
|
|
4758
4543
|
const log = createSubsystemLogger("discord/native-command");
|
|
4544
|
+
const NON_PLUGIN_COMMAND_DISPATCH = Object.freeze({ kind: "non-plugin" });
|
|
4759
4545
|
function createDiscordNativeCommand(params) {
|
|
4760
4546
|
const { command, cfg, discordConfig, accountId, sessionPrefix, ephemeralDefault, threadBindings } = params;
|
|
4761
4547
|
const fallbackCommandDefinition = createNativeCommandDefinition(command);
|
|
4762
|
-
const
|
|
4763
|
-
const commandDefinition =
|
|
4764
|
-
const argDefinitions = commandDefinition.args ?? command.args;
|
|
4548
|
+
const pluginCommandCandidate = "prepareDispatch" in command ? command : void 0;
|
|
4549
|
+
const commandDefinition = pluginCommandCandidate ? fallbackCommandDefinition : findCommandByNativeName$1(command.name, "discord", { includeBundledChannelFallback: false }) ?? fallbackCommandDefinition;
|
|
4550
|
+
const argDefinitions = commandDefinition.args ?? ("args" in command ? command.args : void 0);
|
|
4765
4551
|
const resolveCurrentConfig = () => getRuntimeConfigSnapshot() ?? cfg;
|
|
4766
4552
|
const commandOptions = buildDiscordCommandOptions({
|
|
4767
4553
|
command: commandDefinition,
|
|
@@ -4772,7 +4558,7 @@ function createDiscordNativeCommand(params) {
|
|
|
4772
4558
|
cfg: resolveCurrentConfig(),
|
|
4773
4559
|
discordConfig,
|
|
4774
4560
|
accountId,
|
|
4775
|
-
skipCommandOwnerAllowFrom:
|
|
4561
|
+
skipCommandOwnerAllowFrom: pluginCommandCandidate !== void 0
|
|
4776
4562
|
}),
|
|
4777
4563
|
resolveChoiceContext: async (interaction) => resolveDiscordNativeChoiceContext({
|
|
4778
4564
|
interaction,
|
|
@@ -4810,9 +4596,11 @@ function createDiscordNativeCommand(params) {
|
|
|
4810
4596
|
...commandArgs,
|
|
4811
4597
|
raw: serializeCommandArgs$1(commandDefinition, commandArgs) ?? commandArgs.raw
|
|
4812
4598
|
} : void 0;
|
|
4599
|
+
const prompt = buildCommandTextFromArgs$1(commandDefinition, commandArgsWithRaw);
|
|
4600
|
+
const preparedPluginCommand = pluginCommandCandidate?.prepareDispatch(commandArgsWithRaw?.raw);
|
|
4813
4601
|
await dispatchDiscordCommandInteraction({
|
|
4814
4602
|
interaction,
|
|
4815
|
-
prompt
|
|
4603
|
+
prompt,
|
|
4816
4604
|
command: commandDefinition,
|
|
4817
4605
|
commandArgs: commandArgsWithRaw,
|
|
4818
4606
|
cfg,
|
|
@@ -4821,7 +4609,8 @@ function createDiscordNativeCommand(params) {
|
|
|
4821
4609
|
sessionPrefix,
|
|
4822
4610
|
preferFollowUp: true,
|
|
4823
4611
|
threadBindings,
|
|
4824
|
-
responseEphemeral: ephemeralDefault
|
|
4612
|
+
responseEphemeral: ephemeralDefault,
|
|
4613
|
+
pluginCommandDispatch: preparedPluginCommand ?? NON_PLUGIN_COMMAND_DISPATCH
|
|
4825
4614
|
});
|
|
4826
4615
|
}
|
|
4827
4616
|
}();
|
|
@@ -4884,7 +4673,8 @@ async function dispatchDiscordCommandInteraction(params) {
|
|
|
4884
4673
|
allowNameMatching
|
|
4885
4674
|
});
|
|
4886
4675
|
const commandOwnerAllowAll = commandOwnerAllowFrom?.includes("*") === true;
|
|
4887
|
-
const senderIsCommandOwner = commandOwnerOk
|
|
4676
|
+
const senderIsCommandOwner = commandOwnerOk;
|
|
4677
|
+
const commandOwnerAccessAllowed = senderIsCommandOwner || commandOwnerAllowAll;
|
|
4888
4678
|
const ownerAllowListConfigured = discordOwnerAllowList != null;
|
|
4889
4679
|
const ownerOk = discordOwnerOk;
|
|
4890
4680
|
const { commandsAllowFromAccess, guildInfo, channelConfig } = resolveDiscordNativeCommandChannelAccessContext({
|
|
@@ -5024,8 +4814,7 @@ async function dispatchDiscordCommandInteraction(params) {
|
|
|
5024
4814
|
return { accepted: false };
|
|
5025
4815
|
}
|
|
5026
4816
|
}
|
|
5027
|
-
|
|
5028
|
-
if (commandOwnerAllowFrom && !senderIsCommandOwner && !commandsAllowFromAccess.allowed && commandName !== "status" && !pluginMatch) {
|
|
4817
|
+
if (commandOwnerAllowFrom && !commandOwnerAccessAllowed && !commandsAllowFromAccess.allowed && commandName !== "status" && params.pluginCommandDispatch.kind !== "plugin") {
|
|
5029
4818
|
await respond("You are not authorized to use this command.", { ephemeral: true });
|
|
5030
4819
|
return { accepted: false };
|
|
5031
4820
|
}
|
|
@@ -5085,7 +4874,7 @@ async function dispatchDiscordCommandInteraction(params) {
|
|
|
5085
4874
|
}));
|
|
5086
4875
|
return { accepted: true };
|
|
5087
4876
|
}
|
|
5088
|
-
if (
|
|
4877
|
+
if (params.pluginCommandDispatch.kind === "plugin" && commandName !== "status") {
|
|
5089
4878
|
if (suppressReplies) {
|
|
5090
4879
|
await settleDiscordInteractionWithoutVisibleReply(interaction);
|
|
5091
4880
|
return { accepted: true };
|
|
@@ -5099,9 +4888,7 @@ async function dispatchDiscordCommandInteraction(params) {
|
|
|
5099
4888
|
agentId: pluginCommandAgentId,
|
|
5100
4889
|
sessionKey: effectiveRoute.sessionKey
|
|
5101
4890
|
});
|
|
5102
|
-
const pluginReply = await
|
|
5103
|
-
command: pluginMatch.command,
|
|
5104
|
-
args: pluginMatch.args,
|
|
4891
|
+
const pluginReply = await params.pluginCommandDispatch.execute({
|
|
5105
4892
|
senderId: sender.id,
|
|
5106
4893
|
channel: "discord",
|
|
5107
4894
|
channelId,
|
|
@@ -5242,7 +5029,7 @@ async function dispatchDiscordCommandInteraction(params) {
|
|
|
5242
5029
|
respond
|
|
5243
5030
|
});
|
|
5244
5031
|
if (directStatusResult) return directStatusResult;
|
|
5245
|
-
await dispatchDiscordNativeAgentReply({
|
|
5032
|
+
const { dispatched, hiddenFinalReply } = await dispatchDiscordNativeAgentReply({
|
|
5246
5033
|
cfg,
|
|
5247
5034
|
discordConfig,
|
|
5248
5035
|
accountId,
|
|
@@ -5254,11 +5041,13 @@ async function dispatchDiscordCommandInteraction(params) {
|
|
|
5254
5041
|
preferFollowUp,
|
|
5255
5042
|
responseEphemeral,
|
|
5256
5043
|
suppressReplies,
|
|
5257
|
-
log
|
|
5044
|
+
log,
|
|
5045
|
+
pluginCommandDispatch: params.pluginCommandDispatch
|
|
5258
5046
|
});
|
|
5259
5047
|
return {
|
|
5260
|
-
accepted:
|
|
5261
|
-
effectiveRoute
|
|
5048
|
+
accepted: dispatched,
|
|
5049
|
+
effectiveRoute,
|
|
5050
|
+
hiddenFinalReply
|
|
5262
5051
|
};
|
|
5263
5052
|
}
|
|
5264
5053
|
function createDiscordCommandArgFallbackButton(params) {
|
|
@@ -5308,7 +5097,7 @@ function canResumeAfterGatewayClose(code) {
|
|
|
5308
5097
|
//#region extensions/discord/src/internal/gateway-identify-limiter.ts
|
|
5309
5098
|
const IDENTIFY_WINDOW_MS = 5e3;
|
|
5310
5099
|
function normalizeMaxConcurrency(value) {
|
|
5311
|
-
const parsed = parseFiniteNumber(value);
|
|
5100
|
+
const parsed = parseFiniteNumber$1(value);
|
|
5312
5101
|
return parsed === void 0 ? 1 : Math.max(1, Math.floor(parsed));
|
|
5313
5102
|
}
|
|
5314
5103
|
var GatewayIdentifyLimiter = class {
|
|
@@ -6429,8 +6218,7 @@ function readStringProperty(value, key) {
|
|
|
6429
6218
|
return typeof property === "string" && property ? property : void 0;
|
|
6430
6219
|
}
|
|
6431
6220
|
function readNumberProperty(value, key) {
|
|
6432
|
-
|
|
6433
|
-
return typeof property === "number" && Number.isFinite(property) ? property : void 0;
|
|
6221
|
+
return asFiniteNumber(value[key]);
|
|
6434
6222
|
}
|
|
6435
6223
|
function describeDiscordGatewayTransportError(error) {
|
|
6436
6224
|
const code = readStringProperty(error, "code");
|
|
@@ -6480,7 +6268,8 @@ function resolveDiscordGatewayIntents(params) {
|
|
|
6480
6268
|
const intentsConfig = params?.intentsConfig;
|
|
6481
6269
|
const voiceEnabled = params?.voiceEnabled;
|
|
6482
6270
|
const voiceStatesEnabled = intentsConfig?.voiceStates ?? voiceEnabled ?? false;
|
|
6483
|
-
let intents = GatewayIntents.Guilds | GatewayIntents.GuildMessages | GatewayIntents.
|
|
6271
|
+
let intents = GatewayIntents.Guilds | GatewayIntents.GuildMessages | GatewayIntents.DirectMessages | GatewayIntents.GuildMessageReactions | GatewayIntents.DirectMessageReactions;
|
|
6272
|
+
if (intentsConfig?.messageContent !== false) intents |= GatewayIntents.MessageContent;
|
|
6484
6273
|
if (voiceStatesEnabled) intents |= GatewayIntents.GuildVoiceStates;
|
|
6485
6274
|
if (intentsConfig?.presence) intents |= GatewayIntents.GuildPresences;
|
|
6486
6275
|
if (intentsConfig?.guildMembers) intents |= GatewayIntents.GuildMembers;
|
|
@@ -6860,7 +6649,7 @@ async function waitForDiscordGatewayStop(params) {
|
|
|
6860
6649
|
gateway?.disconnect?.();
|
|
6861
6650
|
} finally {
|
|
6862
6651
|
cleanup();
|
|
6863
|
-
reject(
|
|
6652
|
+
reject(toErrorObject(err, "Non-Error rejection"));
|
|
6864
6653
|
}
|
|
6865
6654
|
};
|
|
6866
6655
|
const onAbort = () => {
|
|
@@ -6881,12 +6670,15 @@ async function waitForDiscordGatewayStop(params) {
|
|
|
6881
6670
|
params.registerForceStop?.(onForceStop);
|
|
6882
6671
|
});
|
|
6883
6672
|
}
|
|
6884
|
-
|
|
6885
|
-
|
|
6886
|
-
|
|
6887
|
-
|
|
6888
|
-
|
|
6889
|
-
|
|
6673
|
+
//#endregion
|
|
6674
|
+
//#region extensions/discord/src/monitor/status.ts
|
|
6675
|
+
/** READY proves a prior terminal failure was repaired, so the account is restartable again. */
|
|
6676
|
+
function createDiscordReadyStatusPatch(at = Date.now()) {
|
|
6677
|
+
return channelReadyPatch({
|
|
6678
|
+
lastConnectedAt: at,
|
|
6679
|
+
lastEventAt: at,
|
|
6680
|
+
lastDisconnect: null
|
|
6681
|
+
});
|
|
6890
6682
|
}
|
|
6891
6683
|
//#endregion
|
|
6892
6684
|
//#region extensions/discord/src/monitor/provider.lifecycle.ts
|
|
@@ -7018,11 +6810,7 @@ function createGatewayStatusObserver(params) {
|
|
|
7018
6810
|
queuedForceStopError = err;
|
|
7019
6811
|
};
|
|
7020
6812
|
const pushConnectedStatus = (at) => {
|
|
7021
|
-
params.pushStatus(
|
|
7022
|
-
...createConnectedChannelStatusPatch(at),
|
|
7023
|
-
lastDisconnect: null,
|
|
7024
|
-
lastError: null
|
|
7025
|
-
});
|
|
6813
|
+
params.pushStatus(createDiscordReadyStatusPatch(at));
|
|
7026
6814
|
};
|
|
7027
6815
|
const startReadyWatch = () => {
|
|
7028
6816
|
clearReadyWatch();
|
|
@@ -7046,6 +6834,7 @@ function createGatewayStatusObserver(params) {
|
|
|
7046
6834
|
const error = /* @__PURE__ */ new Error(`discord gateway opened but did not reach READY within ${params.runtimeReadyTimeoutMs}ms`);
|
|
7047
6835
|
params.pushStatus({
|
|
7048
6836
|
connected: false,
|
|
6837
|
+
lifecycle: "recovering",
|
|
7049
6838
|
lastEventAt: at,
|
|
7050
6839
|
lastDisconnect: {
|
|
7051
6840
|
at,
|
|
@@ -7074,8 +6863,14 @@ function createGatewayStatusObserver(params) {
|
|
|
7074
6863
|
if (message.includes("Gateway websocket closed")) {
|
|
7075
6864
|
clearReadyWatch();
|
|
7076
6865
|
const code = parseGatewayCloseCode(message);
|
|
6866
|
+
const terminalDisconnect = code !== void 0 && isFatalGatewayCloseCode(code);
|
|
7077
6867
|
params.pushStatus({
|
|
7078
6868
|
connected: false,
|
|
6869
|
+
lifecycle: terminalDisconnect ? "blocked" : "recovering",
|
|
6870
|
+
...terminalDisconnect ? {
|
|
6871
|
+
terminalDisconnect: true,
|
|
6872
|
+
lastError: message
|
|
6873
|
+
} : {},
|
|
7079
6874
|
lastEventAt: at,
|
|
7080
6875
|
lastDisconnect: {
|
|
7081
6876
|
at,
|
|
@@ -7088,6 +6883,7 @@ function createGatewayStatusObserver(params) {
|
|
|
7088
6883
|
clearReadyWatch();
|
|
7089
6884
|
params.pushStatus({
|
|
7090
6885
|
connected: false,
|
|
6886
|
+
lifecycle: "recovering",
|
|
7091
6887
|
lastEventAt: at,
|
|
7092
6888
|
lastError: message
|
|
7093
6889
|
});
|
|
@@ -7118,11 +6914,7 @@ async function waitForGatewayReady(params) {
|
|
|
7118
6914
|
if (await params.beforePoll?.() === "stop") return "stopped";
|
|
7119
6915
|
if (params.gateway?.isConnected === true) {
|
|
7120
6916
|
const at = Date.now();
|
|
7121
|
-
params.pushStatus?.(
|
|
7122
|
-
...createConnectedChannelStatusPatch(at),
|
|
7123
|
-
lastDisconnect: null,
|
|
7124
|
-
lastError: null
|
|
7125
|
-
});
|
|
6917
|
+
params.pushStatus?.(createDiscordReadyStatusPatch(at));
|
|
7126
6918
|
return "ready";
|
|
7127
6919
|
}
|
|
7128
6920
|
if (Date.now() >= deadlineAt) return "timeout";
|
|
@@ -7144,6 +6936,7 @@ async function waitForGatewayReady(params) {
|
|
|
7144
6936
|
params.runtime.error?.(danger(`discord: gateway READY wait timed out after ${params.readyTimeoutMs}ms; reconnecting with backoff (attempt ${attempt})`));
|
|
7145
6937
|
params.pushStatus?.({
|
|
7146
6938
|
connected: false,
|
|
6939
|
+
lifecycle: "recovering",
|
|
7147
6940
|
lastEventAt: restartAt,
|
|
7148
6941
|
lastDisconnect: {
|
|
7149
6942
|
at: restartAt,
|
|
@@ -7252,7 +7045,7 @@ async function runDiscordGatewayLifecycle(params) {
|
|
|
7252
7045
|
gatewayEmitter?.removeListener(DISCORD_GATEWAY_TRANSPORT_ACTIVITY_EVENT, onGatewayTransportActivity);
|
|
7253
7046
|
if (params.voiceManager) {
|
|
7254
7047
|
await params.voiceManager.destroy();
|
|
7255
|
-
const { setDiscordTranscriptsVoiceManager } = await import("./transcripts-source-
|
|
7048
|
+
const { setDiscordTranscriptsVoiceManager } = await import("./transcripts-source-CfFMexGt.js").then((n) => n.n);
|
|
7256
7049
|
setDiscordTranscriptsVoiceManager({
|
|
7257
7050
|
accountId: params.accountId,
|
|
7258
7051
|
manager: null
|
|
@@ -7267,7 +7060,7 @@ async function runDiscordGatewayLifecycle(params) {
|
|
|
7267
7060
|
let discordVoiceRuntimePromise;
|
|
7268
7061
|
let discordProviderSessionRuntimePromise;
|
|
7269
7062
|
async function loadDiscordVoiceRuntime() {
|
|
7270
|
-
const promise = discordVoiceRuntimePromise ?? import("./
|
|
7063
|
+
const promise = discordVoiceRuntimePromise ?? import("./voice-runtime-BEdqNcST.js");
|
|
7271
7064
|
discordVoiceRuntimePromise = promise;
|
|
7272
7065
|
try {
|
|
7273
7066
|
return await promise;
|
|
@@ -7277,7 +7070,7 @@ async function loadDiscordVoiceRuntime() {
|
|
|
7277
7070
|
}
|
|
7278
7071
|
}
|
|
7279
7072
|
async function loadDiscordProviderSessionRuntime() {
|
|
7280
|
-
const promise = discordProviderSessionRuntimePromise ?? import("./provider-session.runtime-
|
|
7073
|
+
const promise = discordProviderSessionRuntimePromise ?? import("./provider-session.runtime-BUEqD0rA.js");
|
|
7281
7074
|
discordProviderSessionRuntimePromise = promise;
|
|
7282
7075
|
try {
|
|
7283
7076
|
return await promise;
|
|
@@ -7287,13 +7080,12 @@ async function loadDiscordProviderSessionRuntime() {
|
|
|
7287
7080
|
}
|
|
7288
7081
|
}
|
|
7289
7082
|
const discordProviderRuntime = {
|
|
7290
|
-
|
|
7083
|
+
probeDiscordApplicationId,
|
|
7291
7084
|
createDiscordNativeCommand,
|
|
7292
7085
|
runDiscordGatewayLifecycle,
|
|
7293
7086
|
loadDiscordVoiceRuntime,
|
|
7294
7087
|
loadDiscordProviderSessionRuntime,
|
|
7295
7088
|
createClient: (...args) => new Client(...args),
|
|
7296
|
-
getPluginCommandSpecs: void 0,
|
|
7297
7089
|
resolveDiscordAccount,
|
|
7298
7090
|
resolveNativeCommandsEnabled,
|
|
7299
7091
|
resolveNativeSkillsEnabled,
|
|
@@ -7639,112 +7431,431 @@ async function cleanupDiscordProviderStartup(params) {
|
|
|
7639
7431
|
if (!params.lifecycleStarted) params.threadBindings.stop();
|
|
7640
7432
|
}
|
|
7641
7433
|
//#endregion
|
|
7642
|
-
//#region extensions/discord/src/
|
|
7643
|
-
|
|
7644
|
-
|
|
7645
|
-
|
|
7646
|
-
|
|
7647
|
-
|
|
7648
|
-
|
|
7649
|
-
|
|
7650
|
-
|
|
7651
|
-
|
|
7652
|
-
params.
|
|
7653
|
-
|
|
7654
|
-
|
|
7655
|
-
|
|
7656
|
-
merged.push({
|
|
7657
|
-
name: pluginCommand.name,
|
|
7658
|
-
description: pluginCommand.description,
|
|
7659
|
-
acceptsArgs: pluginCommand.acceptsArgs
|
|
7660
|
-
});
|
|
7661
|
-
}
|
|
7662
|
-
return merged;
|
|
7663
|
-
}
|
|
7664
|
-
async function resolveDiscordProviderCommandSpecs(params) {
|
|
7665
|
-
const listSkillCommands = params.listSkillCommandsForAgents ?? listSkillCommandsForAgents;
|
|
7666
|
-
const listNativeCommandSpecs = params.listNativeCommandSpecsForConfig ?? listNativeCommandSpecsForConfig;
|
|
7667
|
-
const maxDiscordCommands = params.maxDiscordCommands ?? 100;
|
|
7668
|
-
let skillCommands = params.nativeEnabled && params.nativeSkillsEnabled ? listSkillCommands({ cfg: params.cfg }) : [];
|
|
7669
|
-
let commandSpecs = params.nativeEnabled ? listNativeCommandSpecs(params.cfg, {
|
|
7670
|
-
skillCommands,
|
|
7671
|
-
provider: "discord"
|
|
7672
|
-
}) : [];
|
|
7673
|
-
if (params.nativeEnabled) commandSpecs = await appendPluginCommandSpecs({
|
|
7674
|
-
commandSpecs,
|
|
7675
|
-
runtime: params.runtime,
|
|
7676
|
-
cfg: params.cfg,
|
|
7677
|
-
getPluginCommandSpecs: params.getPluginCommandSpecs
|
|
7434
|
+
//#region extensions/discord/src/voice/access.ts
|
|
7435
|
+
async function authorizeDiscordVoiceIngress(params) {
|
|
7436
|
+
const groupPolicy = params.groupPolicy ?? resolveOpenProviderRuntimeGroupPolicy({
|
|
7437
|
+
providerConfigPresent: params.cfg.channels?.discord !== void 0,
|
|
7438
|
+
groupPolicy: params.discordConfig.groupPolicy,
|
|
7439
|
+
defaultGroupPolicy: params.cfg.channels?.defaults?.groupPolicy
|
|
7440
|
+
}).groupPolicy;
|
|
7441
|
+
const guildInfo = resolveDiscordGuildEntry({
|
|
7442
|
+
guild: params.guild ?? {
|
|
7443
|
+
id: params.guildId,
|
|
7444
|
+
...params.guildName ? { name: params.guildName } : {}
|
|
7445
|
+
},
|
|
7446
|
+
guildId: params.guildId,
|
|
7447
|
+
guildEntries: params.discordConfig.guilds
|
|
7678
7448
|
});
|
|
7679
|
-
const
|
|
7680
|
-
|
|
7681
|
-
|
|
7682
|
-
|
|
7683
|
-
|
|
7684
|
-
|
|
7685
|
-
|
|
7686
|
-
|
|
7687
|
-
|
|
7688
|
-
|
|
7689
|
-
|
|
7690
|
-
|
|
7691
|
-
|
|
7692
|
-
|
|
7693
|
-
}
|
|
7694
|
-
if (params.
|
|
7695
|
-
|
|
7696
|
-
|
|
7697
|
-
|
|
7449
|
+
const channelConfig = params.channelId ? resolveDiscordChannelConfigWithFallback({
|
|
7450
|
+
guildInfo,
|
|
7451
|
+
channelId: params.channelId,
|
|
7452
|
+
channelName: params.channelName,
|
|
7453
|
+
channelSlug: params.channelSlug,
|
|
7454
|
+
parentId: params.parentId,
|
|
7455
|
+
parentName: params.parentName,
|
|
7456
|
+
parentSlug: params.parentSlug,
|
|
7457
|
+
scope: params.scope
|
|
7458
|
+
}) : null;
|
|
7459
|
+
if (channelConfig?.enabled === false) return {
|
|
7460
|
+
ok: false,
|
|
7461
|
+
message: "This channel is disabled."
|
|
7462
|
+
};
|
|
7463
|
+
const channelAllowlistConfigured = Boolean(guildInfo?.channels) && Object.keys(guildInfo?.channels ?? {}).length > 0;
|
|
7464
|
+
if (!params.channelId && groupPolicy === "allowlist" && channelAllowlistConfigured) return {
|
|
7465
|
+
ok: false,
|
|
7466
|
+
message: `${params.channelLabel ?? "This channel"} is not allowlisted for voice commands.`
|
|
7467
|
+
};
|
|
7468
|
+
const channelAllowed = channelConfig ? channelConfig.allowed : !channelAllowlistConfigured;
|
|
7469
|
+
if (!isDiscordGroupAllowedByPolicy({
|
|
7470
|
+
groupPolicy,
|
|
7471
|
+
guildAllowlisted: Boolean(guildInfo),
|
|
7472
|
+
channelAllowlistConfigured,
|
|
7473
|
+
channelAllowed
|
|
7474
|
+
}) || channelConfig?.allowed === false) return {
|
|
7475
|
+
ok: false,
|
|
7476
|
+
message: `${params.channelLabel ?? "This channel"} is not allowlisted for voice commands.`
|
|
7477
|
+
};
|
|
7478
|
+
const { hasAccessRestrictions, memberAllowed } = resolveDiscordMemberAccessState({
|
|
7479
|
+
channelConfig,
|
|
7480
|
+
guildInfo,
|
|
7481
|
+
memberRoleIds: params.memberRoleIds,
|
|
7482
|
+
sender: params.sender,
|
|
7483
|
+
allowNameMatching: false
|
|
7484
|
+
});
|
|
7485
|
+
const admissionAllowList = normalizeDiscordAllowList(params.admissionAllowFrom ?? params.discordConfig.allowFrom ?? params.discordConfig.allowFrom, [
|
|
7486
|
+
"discord:",
|
|
7487
|
+
"user:",
|
|
7488
|
+
"pk:"
|
|
7489
|
+
]);
|
|
7490
|
+
const admissionAllowed = admissionAllowList ? allowListMatches(admissionAllowList, params.sender, { allowNameMatching: false }) : false;
|
|
7491
|
+
const useAccessGroups = params.useAccessGroups ?? true;
|
|
7492
|
+
return resolveCommandAuthorizedFromAuthorizers({
|
|
7493
|
+
useAccessGroups,
|
|
7494
|
+
authorizers: useAccessGroups ? [{
|
|
7495
|
+
configured: admissionAllowList != null,
|
|
7496
|
+
allowed: admissionAllowed
|
|
7497
|
+
}, {
|
|
7498
|
+
configured: hasAccessRestrictions,
|
|
7499
|
+
allowed: memberAllowed
|
|
7500
|
+
}] : [{
|
|
7501
|
+
configured: hasAccessRestrictions,
|
|
7502
|
+
allowed: memberAllowed
|
|
7503
|
+
}],
|
|
7504
|
+
modeWhenAccessGroupsOff: "configured"
|
|
7505
|
+
}) ? {
|
|
7506
|
+
ok: true,
|
|
7507
|
+
channelConfig
|
|
7508
|
+
} : {
|
|
7509
|
+
ok: false,
|
|
7510
|
+
message: "You are not authorized to use this command."
|
|
7698
7511
|
};
|
|
7699
7512
|
}
|
|
7700
7513
|
//#endregion
|
|
7701
|
-
//#region extensions/discord/src/
|
|
7702
|
-
function
|
|
7703
|
-
const
|
|
7704
|
-
|
|
7514
|
+
//#region extensions/discord/src/voice/owner-access.ts
|
|
7515
|
+
function resolveDiscordVoiceAccess(params) {
|
|
7516
|
+
const commandOwnerAllowFrom = resolveDiscordCommandOwnerAllowFrom(params.cfg);
|
|
7517
|
+
if (commandOwnerAllowFrom) return {
|
|
7518
|
+
admissionAllowFrom: commandOwnerAllowFrom,
|
|
7519
|
+
ownerAllowFrom: commandOwnerAllowFrom
|
|
7520
|
+
};
|
|
7521
|
+
return {
|
|
7522
|
+
admissionAllowFrom: resolveDiscordAccountAllowFrom({
|
|
7523
|
+
cfg: params.cfg,
|
|
7524
|
+
accountId: params.accountId
|
|
7525
|
+
}) ?? params.discordConfig.allowFrom ?? [],
|
|
7526
|
+
ownerAllowFrom: []
|
|
7527
|
+
};
|
|
7705
7528
|
}
|
|
7706
|
-
|
|
7707
|
-
|
|
7708
|
-
|
|
7709
|
-
|
|
7710
|
-
|
|
7529
|
+
//#endregion
|
|
7530
|
+
//#region extensions/discord/src/voice/command.ts
|
|
7531
|
+
const VOICE_CHANNEL_TYPES = [ChannelType.GuildVoice, ChannelType.GuildStageVoice];
|
|
7532
|
+
const DISCORD_VOICE_COMMAND_SPEC = {
|
|
7533
|
+
name: "vc",
|
|
7534
|
+
description: "Voice channel controls",
|
|
7535
|
+
acceptsArgs: false
|
|
7536
|
+
};
|
|
7537
|
+
async function authorizeVoiceCommand(interaction, params, options) {
|
|
7538
|
+
const channelOverride = options?.channelOverride;
|
|
7539
|
+
const channel = channelOverride ? void 0 : interaction.channel;
|
|
7540
|
+
if (!interaction.guild) return {
|
|
7541
|
+
ok: false,
|
|
7542
|
+
message: "Voice commands are only available in guilds."
|
|
7543
|
+
};
|
|
7544
|
+
const user = interaction.user;
|
|
7545
|
+
if (!user) return {
|
|
7546
|
+
ok: false,
|
|
7547
|
+
message: "Unable to resolve command user."
|
|
7548
|
+
};
|
|
7549
|
+
const channelId = channelOverride?.id ?? channel?.id ?? "";
|
|
7550
|
+
const channelContext = await resolveDiscordThreadLikeChannelContext({
|
|
7551
|
+
client: interaction.client,
|
|
7552
|
+
channel: channelOverride ?? channel,
|
|
7553
|
+
channelIdFallback: channelId
|
|
7711
7554
|
});
|
|
7712
|
-
const
|
|
7713
|
-
|
|
7714
|
-
|
|
7715
|
-
|
|
7555
|
+
const channelName = channelOverride?.name ?? channelContext.channelName;
|
|
7556
|
+
const memberRoleIds = Array.isArray(interaction.rawData.member?.roles) ? interaction.rawData.member.roles.map((roleId) => roleId) : [];
|
|
7557
|
+
const sender = resolveDiscordSenderIdentity({
|
|
7558
|
+
author: user,
|
|
7559
|
+
member: interaction.rawData.member
|
|
7716
7560
|
});
|
|
7717
|
-
const
|
|
7718
|
-
|
|
7719
|
-
|
|
7720
|
-
|
|
7561
|
+
const voiceAccess = resolveDiscordVoiceAccess(params);
|
|
7562
|
+
const access = await authorizeDiscordVoiceIngress({
|
|
7563
|
+
cfg: params.cfg,
|
|
7564
|
+
discordConfig: params.discordConfig,
|
|
7565
|
+
accountId: params.accountId,
|
|
7566
|
+
groupPolicy: params.groupPolicy,
|
|
7567
|
+
useAccessGroups: params.useAccessGroups,
|
|
7568
|
+
guild: interaction.guild,
|
|
7569
|
+
guildId: interaction.guild.id,
|
|
7570
|
+
channelId,
|
|
7571
|
+
channelName,
|
|
7572
|
+
channelSlug: channelContext.channelSlug,
|
|
7573
|
+
parentId: channelOverride?.parentId ?? channelContext.threadParentId,
|
|
7574
|
+
parentName: channelContext.threadParentName,
|
|
7575
|
+
parentSlug: channelContext.threadParentSlug,
|
|
7576
|
+
scope: channelContext.isThreadChannel ? "thread" : "channel",
|
|
7577
|
+
channelLabel: channelId ? formatMention({ channelId }) : "This channel",
|
|
7578
|
+
memberRoleIds,
|
|
7579
|
+
admissionAllowFrom: voiceAccess.admissionAllowFrom,
|
|
7580
|
+
sender: {
|
|
7581
|
+
id: sender.id,
|
|
7582
|
+
name: sender.name,
|
|
7583
|
+
tag: sender.tag
|
|
7584
|
+
}
|
|
7721
7585
|
});
|
|
7722
|
-
|
|
7723
|
-
|
|
7724
|
-
|
|
7725
|
-
|
|
7726
|
-
|
|
7727
|
-
|
|
7728
|
-
|
|
7729
|
-
|
|
7730
|
-
if (deployErr.deployRequestBody === void 0) deployErr.deployRequestBody = body;
|
|
7731
|
-
}
|
|
7732
|
-
function attachDiscordDeployRestContext(err, context) {
|
|
7733
|
-
if (!err || typeof err !== "object") return;
|
|
7734
|
-
const deployErr = err;
|
|
7735
|
-
deployErr.deployRestMethod = context.method;
|
|
7736
|
-
deployErr.deployRestPath = context.path;
|
|
7737
|
-
deployErr.deployRequestMs = context.requestMs;
|
|
7738
|
-
if (typeof context.timeoutMs === "number" && Number.isFinite(context.timeoutMs)) deployErr.deployTimeoutMs = context.timeoutMs;
|
|
7586
|
+
if (!access.ok) return {
|
|
7587
|
+
ok: false,
|
|
7588
|
+
message: access.message
|
|
7589
|
+
};
|
|
7590
|
+
return {
|
|
7591
|
+
ok: true,
|
|
7592
|
+
guildId: interaction.guild.id
|
|
7593
|
+
};
|
|
7739
7594
|
}
|
|
7740
|
-
function
|
|
7741
|
-
|
|
7742
|
-
|
|
7743
|
-
|
|
7744
|
-
|
|
7745
|
-
|
|
7746
|
-
|
|
7747
|
-
|
|
7595
|
+
async function resolveVoiceCommandRuntimeContext(interaction, params) {
|
|
7596
|
+
const guildId = interaction.guild?.id;
|
|
7597
|
+
if (!guildId) {
|
|
7598
|
+
await interaction.reply({
|
|
7599
|
+
content: "Unable to resolve guild for this command.",
|
|
7600
|
+
ephemeral: true
|
|
7601
|
+
});
|
|
7602
|
+
return null;
|
|
7603
|
+
}
|
|
7604
|
+
const manager = params.getManager();
|
|
7605
|
+
if (!manager) {
|
|
7606
|
+
await interaction.reply({
|
|
7607
|
+
content: "Voice manager is not available yet.",
|
|
7608
|
+
ephemeral: true
|
|
7609
|
+
});
|
|
7610
|
+
return null;
|
|
7611
|
+
}
|
|
7612
|
+
return {
|
|
7613
|
+
guildId,
|
|
7614
|
+
manager
|
|
7615
|
+
};
|
|
7616
|
+
}
|
|
7617
|
+
async function ensureVoiceCommandAccess(params) {
|
|
7618
|
+
const access = await authorizeVoiceCommand(params.interaction, params.context, { channelOverride: params.channelOverride });
|
|
7619
|
+
if (access.ok) return true;
|
|
7620
|
+
await params.interaction.reply({
|
|
7621
|
+
content: access.message ?? "Not authorized.",
|
|
7622
|
+
ephemeral: true
|
|
7623
|
+
});
|
|
7624
|
+
return false;
|
|
7625
|
+
}
|
|
7626
|
+
function createDiscordVoiceCommand(params) {
|
|
7627
|
+
const resolveSessionChannelId = (manager, guildId) => manager.status().find((entry) => entry.guildId === guildId)?.channelId;
|
|
7628
|
+
class JoinCommand extends Command {
|
|
7629
|
+
constructor(..._args) {
|
|
7630
|
+
super(..._args);
|
|
7631
|
+
this.name = "join";
|
|
7632
|
+
this.description = "Join a voice channel";
|
|
7633
|
+
this.defer = true;
|
|
7634
|
+
this.ephemeral = params.ephemeralDefault;
|
|
7635
|
+
this.options = [{
|
|
7636
|
+
name: "channel",
|
|
7637
|
+
description: "Voice channel to join",
|
|
7638
|
+
type: ApplicationCommandOptionType.Channel,
|
|
7639
|
+
required: true,
|
|
7640
|
+
channel_types: VOICE_CHANNEL_TYPES
|
|
7641
|
+
}];
|
|
7642
|
+
}
|
|
7643
|
+
async run(interaction) {
|
|
7644
|
+
const channel = await interaction.options.getChannel("channel", true);
|
|
7645
|
+
if (!channel || !("id" in channel)) {
|
|
7646
|
+
await interaction.reply({
|
|
7647
|
+
content: "Voice channel not found.",
|
|
7648
|
+
ephemeral: true
|
|
7649
|
+
});
|
|
7650
|
+
return;
|
|
7651
|
+
}
|
|
7652
|
+
const access = await authorizeVoiceCommand(interaction, params, { channelOverride: {
|
|
7653
|
+
id: channel.id,
|
|
7654
|
+
name: resolveDiscordChannelNameSafe(channel)
|
|
7655
|
+
} });
|
|
7656
|
+
if (!access.ok) {
|
|
7657
|
+
await interaction.reply({
|
|
7658
|
+
content: access.message ?? "Not authorized.",
|
|
7659
|
+
ephemeral: true
|
|
7660
|
+
});
|
|
7661
|
+
return;
|
|
7662
|
+
}
|
|
7663
|
+
if (!isVoiceChannelType(channel.type)) {
|
|
7664
|
+
await interaction.reply({
|
|
7665
|
+
content: "That is not a voice channel.",
|
|
7666
|
+
ephemeral: true
|
|
7667
|
+
});
|
|
7668
|
+
return;
|
|
7669
|
+
}
|
|
7670
|
+
const guildId = access.guildId ?? ("guildId" in channel ? channel.guildId : void 0);
|
|
7671
|
+
if (!guildId) {
|
|
7672
|
+
await interaction.reply({
|
|
7673
|
+
content: "Unable to resolve guild for this voice channel.",
|
|
7674
|
+
ephemeral: true
|
|
7675
|
+
});
|
|
7676
|
+
return;
|
|
7677
|
+
}
|
|
7678
|
+
const manager = params.getManager();
|
|
7679
|
+
if (!manager) {
|
|
7680
|
+
await interaction.reply({
|
|
7681
|
+
content: "Voice manager is not available yet.",
|
|
7682
|
+
ephemeral: true
|
|
7683
|
+
});
|
|
7684
|
+
return;
|
|
7685
|
+
}
|
|
7686
|
+
const result = await manager.join({
|
|
7687
|
+
guildId,
|
|
7688
|
+
channelId: channel.id
|
|
7689
|
+
});
|
|
7690
|
+
await interaction.reply({
|
|
7691
|
+
content: result.message,
|
|
7692
|
+
ephemeral: true
|
|
7693
|
+
});
|
|
7694
|
+
}
|
|
7695
|
+
}
|
|
7696
|
+
class LeaveCommand extends Command {
|
|
7697
|
+
constructor(..._args2) {
|
|
7698
|
+
super(..._args2);
|
|
7699
|
+
this.name = "leave";
|
|
7700
|
+
this.description = "Leave the current voice channel";
|
|
7701
|
+
this.defer = true;
|
|
7702
|
+
this.ephemeral = params.ephemeralDefault;
|
|
7703
|
+
}
|
|
7704
|
+
async run(interaction) {
|
|
7705
|
+
const runtimeContext = await resolveVoiceCommandRuntimeContext(interaction, params);
|
|
7706
|
+
if (!runtimeContext) return;
|
|
7707
|
+
const sessionChannelId = resolveSessionChannelId(runtimeContext.manager, runtimeContext.guildId);
|
|
7708
|
+
if (!await ensureVoiceCommandAccess({
|
|
7709
|
+
interaction,
|
|
7710
|
+
context: params,
|
|
7711
|
+
channelOverride: sessionChannelId ? { id: sessionChannelId } : void 0
|
|
7712
|
+
})) return;
|
|
7713
|
+
const result = await runtimeContext.manager.leave({ guildId: runtimeContext.guildId });
|
|
7714
|
+
await interaction.reply({
|
|
7715
|
+
content: result.message,
|
|
7716
|
+
ephemeral: true
|
|
7717
|
+
});
|
|
7718
|
+
}
|
|
7719
|
+
}
|
|
7720
|
+
class StatusCommand extends Command {
|
|
7721
|
+
constructor(..._args3) {
|
|
7722
|
+
super(..._args3);
|
|
7723
|
+
this.name = "status";
|
|
7724
|
+
this.description = "Show active voice sessions";
|
|
7725
|
+
this.defer = true;
|
|
7726
|
+
this.ephemeral = params.ephemeralDefault;
|
|
7727
|
+
}
|
|
7728
|
+
async run(interaction) {
|
|
7729
|
+
const runtimeContext = await resolveVoiceCommandRuntimeContext(interaction, params);
|
|
7730
|
+
if (!runtimeContext) return;
|
|
7731
|
+
const sessions = runtimeContext.manager.status().filter((entry) => entry.guildId === runtimeContext.guildId);
|
|
7732
|
+
const sessionChannelId = sessions[0]?.channelId;
|
|
7733
|
+
if (!await ensureVoiceCommandAccess({
|
|
7734
|
+
interaction,
|
|
7735
|
+
context: params,
|
|
7736
|
+
channelOverride: sessionChannelId ? { id: sessionChannelId } : void 0
|
|
7737
|
+
})) return;
|
|
7738
|
+
if (sessions.length === 0) {
|
|
7739
|
+
await interaction.reply({
|
|
7740
|
+
content: "No active voice sessions.",
|
|
7741
|
+
ephemeral: true
|
|
7742
|
+
});
|
|
7743
|
+
return;
|
|
7744
|
+
}
|
|
7745
|
+
const lines = sessions.map((entry) => `• ${formatMention({ channelId: entry.channelId })} (guild ${entry.guildId})`);
|
|
7746
|
+
await interaction.reply({
|
|
7747
|
+
content: lines.join("\n"),
|
|
7748
|
+
ephemeral: true
|
|
7749
|
+
});
|
|
7750
|
+
}
|
|
7751
|
+
}
|
|
7752
|
+
return new class extends CommandWithSubcommands {
|
|
7753
|
+
constructor(..._args4) {
|
|
7754
|
+
super(..._args4);
|
|
7755
|
+
this.name = DISCORD_VOICE_COMMAND_SPEC.name;
|
|
7756
|
+
this.description = DISCORD_VOICE_COMMAND_SPEC.description;
|
|
7757
|
+
this.subcommands = [
|
|
7758
|
+
new JoinCommand(),
|
|
7759
|
+
new LeaveCommand(),
|
|
7760
|
+
new StatusCommand()
|
|
7761
|
+
];
|
|
7762
|
+
}
|
|
7763
|
+
}();
|
|
7764
|
+
}
|
|
7765
|
+
function isVoiceChannelType(type) {
|
|
7766
|
+
return type === ChannelType.GuildVoice || type === ChannelType.GuildStageVoice;
|
|
7767
|
+
}
|
|
7768
|
+
//#endregion
|
|
7769
|
+
//#region extensions/discord/src/monitor/provider.commands.ts
|
|
7770
|
+
const loadPluginCommandRuntime = createLazyRuntimeModule(() => import("openclaw/plugin-sdk/plugin-command-runtime"));
|
|
7771
|
+
async function resolveDiscordProviderCommandSpecs(params) {
|
|
7772
|
+
const listSkillCommands = params.listSkillCommandsForAgents ?? listSkillCommandsForAgents;
|
|
7773
|
+
const listNativeCommandSpecs = params.listNativeCommandSpecsForConfig ?? listNativeCommandSpecsForConfig;
|
|
7774
|
+
const maxDiscordCommands = params.maxDiscordCommands ?? 100;
|
|
7775
|
+
let pluginCommandRuntime;
|
|
7776
|
+
if (params.nativeEnabled) pluginCommandRuntime = (await loadPluginCommandRuntime()).createPluginCommandRuntime();
|
|
7777
|
+
const pluginCommandSpecs = pluginCommandRuntime?.listNativeCandidates("discord") ?? [];
|
|
7778
|
+
const onCollision = (normalizedName) => {
|
|
7779
|
+
params.runtime.error?.(danger(`discord: plugin command "/${normalizedName}" duplicates an existing native command. Skipping.`));
|
|
7780
|
+
};
|
|
7781
|
+
const mergePluginCommandSpecs = (primary, collisionHandler) => mergeNativeCommandSpecs({
|
|
7782
|
+
primary,
|
|
7783
|
+
secondary: pluginCommandSpecs,
|
|
7784
|
+
onCollision: collisionHandler
|
|
7785
|
+
});
|
|
7786
|
+
const listPrimaryCommandSpecs = (skillCommands) => {
|
|
7787
|
+
const standardSpecs = listNativeCommandSpecs(params.cfg, {
|
|
7788
|
+
skillCommands,
|
|
7789
|
+
provider: "discord"
|
|
7790
|
+
});
|
|
7791
|
+
if (!params.voiceEnabled) return standardSpecs;
|
|
7792
|
+
const voiceName = DISCORD_VOICE_COMMAND_SPEC.name;
|
|
7793
|
+
return [...standardSpecs.filter((spec) => normalizeLowercaseStringOrEmpty(spec.name) !== voiceName), DISCORD_VOICE_COMMAND_SPEC];
|
|
7794
|
+
};
|
|
7795
|
+
const provisionalCollisions = [];
|
|
7796
|
+
let skillCommands = params.nativeEnabled && params.nativeSkillsEnabled ? listSkillCommands({ cfg: params.cfg }) : [];
|
|
7797
|
+
let commandSpecs = params.nativeEnabled ? mergePluginCommandSpecs(listPrimaryCommandSpecs(skillCommands), (normalizedName) => provisionalCollisions.push(normalizedName)) : [];
|
|
7798
|
+
const initialCommandCount = commandSpecs.length;
|
|
7799
|
+
if (params.nativeEnabled && params.nativeSkillsEnabled && commandSpecs.length > maxDiscordCommands) {
|
|
7800
|
+
skillCommands = [];
|
|
7801
|
+
commandSpecs = mergePluginCommandSpecs(listPrimaryCommandSpecs([]), onCollision);
|
|
7802
|
+
params.runtime.log?.(warn(`${initialCommandCount} commands exceed the ${maxDiscordCommands}-command Discord limit; removing per-skill commands and keeping /skill.`));
|
|
7803
|
+
} else for (const normalizedName of provisionalCollisions) onCollision(normalizedName);
|
|
7804
|
+
if (params.nativeEnabled && commandSpecs.length > maxDiscordCommands) params.runtime.log?.(warn(`${commandSpecs.length} commands exceed the ${maxDiscordCommands}-command Discord limit; some commands may fail to deploy.`));
|
|
7805
|
+
if (commandSpecs.some((command) => "prepareDispatch" in command)) pluginCommandRuntime?.retainNativeCatalog("discord");
|
|
7806
|
+
return {
|
|
7807
|
+
skillCommands,
|
|
7808
|
+
commandSpecs
|
|
7809
|
+
};
|
|
7810
|
+
}
|
|
7811
|
+
//#endregion
|
|
7812
|
+
//#region extensions/discord/src/monitor/provider.config-log.ts
|
|
7813
|
+
function formatThreadBindingDurationForConfigLabel(durationMs) {
|
|
7814
|
+
const label = formatThreadBindingDurationLabel(durationMs);
|
|
7815
|
+
return label === "disabled" ? "off" : label;
|
|
7816
|
+
}
|
|
7817
|
+
function logDiscordResolvedConfig(params) {
|
|
7818
|
+
const allowFromSummary = summarizeStringEntries({
|
|
7819
|
+
entries: params.allowFrom ?? [],
|
|
7820
|
+
limit: 4,
|
|
7821
|
+
emptyText: "any"
|
|
7822
|
+
});
|
|
7823
|
+
const groupDmChannelSummary = summarizeStringEntries({
|
|
7824
|
+
entries: params.groupDmChannels ?? [],
|
|
7825
|
+
limit: 4,
|
|
7826
|
+
emptyText: "any"
|
|
7827
|
+
});
|
|
7828
|
+
const guildSummary = summarizeStringEntries({
|
|
7829
|
+
entries: Object.keys(params.guildEntries ?? {}),
|
|
7830
|
+
limit: 4,
|
|
7831
|
+
emptyText: "any"
|
|
7832
|
+
});
|
|
7833
|
+
logVerbose(`discord: config dm=${params.dmEnabled ? "on" : "off"} dmPolicy=${params.dmPolicy} allowFrom=${allowFromSummary} groupDm=${params.groupDmEnabled ? "on" : "off"} groupDmChannels=${groupDmChannelSummary} groupPolicy=${params.groupPolicy} guilds=${guildSummary} historyLimit=${params.historyLimit} mediaMaxMb=${Math.round(params.mediaMaxBytes / (1024 * 1024))} native=${params.nativeEnabled ? "on" : "off"} nativeSkills=${params.nativeSkillsEnabled ? "on" : "off"} accessGroups=${params.useAccessGroups ? "on" : "off"} threadBindings=${params.threadBindingsEnabled ? "on" : "off"} threadIdleTimeout=${formatThreadBindingDurationForConfigLabel(params.threadBindingIdleTimeoutMs)} threadMaxAge=${formatThreadBindingDurationForConfigLabel(params.threadBindingMaxAgeMs)}`);
|
|
7834
|
+
}
|
|
7835
|
+
//#endregion
|
|
7836
|
+
//#region extensions/discord/src/monitor/provider.deploy-errors.ts
|
|
7837
|
+
const DISCORD_DEPLOY_REJECTED_ENTRY_LIMIT = 3;
|
|
7838
|
+
function attachDiscordDeployRequestBody(err, body) {
|
|
7839
|
+
if (!err || typeof err !== "object" || body === void 0) return;
|
|
7840
|
+
const deployErr = err;
|
|
7841
|
+
if (deployErr.deployRequestBody === void 0) deployErr.deployRequestBody = body;
|
|
7842
|
+
}
|
|
7843
|
+
function attachDiscordDeployRestContext(err, context) {
|
|
7844
|
+
if (!err || typeof err !== "object") return;
|
|
7845
|
+
const deployErr = err;
|
|
7846
|
+
deployErr.deployRestMethod = context.method;
|
|
7847
|
+
deployErr.deployRestPath = context.path;
|
|
7848
|
+
deployErr.deployRequestMs = context.requestMs;
|
|
7849
|
+
if (typeof context.timeoutMs === "number" && Number.isFinite(context.timeoutMs)) deployErr.deployTimeoutMs = context.timeoutMs;
|
|
7850
|
+
}
|
|
7851
|
+
function stringifyDiscordDeployField(value) {
|
|
7852
|
+
if (typeof value === "string") return JSON.stringify(value);
|
|
7853
|
+
try {
|
|
7854
|
+
return JSON.stringify(value);
|
|
7855
|
+
} catch {
|
|
7856
|
+
return inspect(value, {
|
|
7857
|
+
depth: 2,
|
|
7858
|
+
breakLength: 120
|
|
7748
7859
|
});
|
|
7749
7860
|
}
|
|
7750
7861
|
}
|
|
@@ -7762,13 +7873,6 @@ function resolveDiscordRejectedDeployEntriesSource(rawBody) {
|
|
|
7762
7873
|
function readDiscordDeployObjectField(value, field) {
|
|
7763
7874
|
return value && typeof value === "object" && field in value ? value[field] : void 0;
|
|
7764
7875
|
}
|
|
7765
|
-
function readFiniteNumber(value) {
|
|
7766
|
-
if (typeof value === "number" && Number.isFinite(value)) return value;
|
|
7767
|
-
if (typeof value === "string" && value.trim().length > 0) return parseStrictFiniteNumber(value);
|
|
7768
|
-
}
|
|
7769
|
-
function readNonNegativeInteger(value) {
|
|
7770
|
-
return parseStrictNonNegativeInteger(value);
|
|
7771
|
-
}
|
|
7772
7876
|
function isAbortLikeError(err) {
|
|
7773
7877
|
if (!err || typeof err !== "object") return false;
|
|
7774
7878
|
const name = "name" in err && typeof err.name === "string" ? err.name : void 0;
|
|
@@ -7786,8 +7890,8 @@ function formatDiscordDeployRestOperation(err) {
|
|
|
7786
7890
|
function formatDiscordDeployErrorMessage(err) {
|
|
7787
7891
|
if (!isAbortLikeError(err)) return formatErrorMessage$1(err);
|
|
7788
7892
|
const deployErr = err && typeof err === "object" ? err : {};
|
|
7789
|
-
const requestMs =
|
|
7790
|
-
const timeoutMs =
|
|
7893
|
+
const requestMs = parseFiniteNumber(deployErr.deployRequestMs);
|
|
7894
|
+
const timeoutMs = parseFiniteNumber(deployErr.deployTimeoutMs);
|
|
7791
7895
|
const operation = formatDiscordDeployRestOperation(deployErr);
|
|
7792
7896
|
if (!(requestMs !== void 0 || timeoutMs !== void 0 || deployErr.deployRestMethod !== void 0 || deployErr.deployRestPath !== void 0)) return "Discord REST request was aborted";
|
|
7793
7897
|
const timing = [];
|
|
@@ -7800,8 +7904,8 @@ function formatDiscordDeployErrorMessage(err) {
|
|
|
7800
7904
|
function resolveDiscordDeployRateLimitDetails(err) {
|
|
7801
7905
|
if (!err || typeof err !== "object") return;
|
|
7802
7906
|
const deployErr = err;
|
|
7803
|
-
const status =
|
|
7804
|
-
const retryAfterSeconds =
|
|
7907
|
+
const status = parseStrictNonNegativeInteger(deployErr.status) ?? parseStrictNonNegativeInteger(deployErr.statusCode);
|
|
7908
|
+
const retryAfterSeconds = parseFiniteNumber(deployErr.retryAfter) ?? parseFiniteNumber(readDiscordDeployObjectField(deployErr.rawBody, "retry_after"));
|
|
7805
7909
|
if (!(err instanceof RateLimitError || status === 429 || retryAfterSeconds !== void 0)) return;
|
|
7806
7910
|
const rawGlobal = readDiscordDeployObjectField(deployErr.rawBody, "global");
|
|
7807
7911
|
const scope = typeof deployErr.scope === "string" && deployErr.scope.trim().length > 0 ? deployErr.scope : rawGlobal === true ? "global" : rawGlobal === false ? "route" : void 0;
|
|
@@ -7891,8 +7995,8 @@ function formatDiscordDeployErrorDetails(err) {
|
|
|
7891
7995
|
function isDiscordDeployDailyCreateLimit(err) {
|
|
7892
7996
|
if (!err || typeof err !== "object") return false;
|
|
7893
7997
|
const deployErr = err;
|
|
7894
|
-
const discordCode =
|
|
7895
|
-
const rawCode =
|
|
7998
|
+
const discordCode = parseStrictNonNegativeInteger(deployErr.discordCode);
|
|
7999
|
+
const rawCode = parseStrictNonNegativeInteger(readDiscordDeployObjectField(deployErr.rawBody, "code"));
|
|
7896
8000
|
return (discordCode === 30034 || rawCode === 30034) && /daily application command creates/i.test(formatErrorMessage$1(err));
|
|
7897
8001
|
}
|
|
7898
8002
|
//#endregion
|
|
@@ -8011,430 +8115,98 @@ async function deployDiscordCommands(params) {
|
|
|
8011
8115
|
function runDiscordCommandDeployInBackground(params) {
|
|
8012
8116
|
if (!params.enabled) return;
|
|
8013
8117
|
logDiscordStartupPhase$1({
|
|
8014
|
-
runtime: params.runtime,
|
|
8015
|
-
accountId: params.accountId,
|
|
8016
|
-
phase: "deploy-commands:scheduled",
|
|
8017
|
-
startAt: params.startupStartedAt,
|
|
8018
|
-
details: "mode=reconcile background=true",
|
|
8019
|
-
isVerbose: params.isVerbose
|
|
8020
|
-
});
|
|
8021
|
-
deployDiscordCommands(params).then(() => {
|
|
8022
|
-
logDiscordStartupPhase$1({
|
|
8023
|
-
runtime: params.runtime,
|
|
8024
|
-
accountId: params.accountId,
|
|
8025
|
-
phase: "deploy-commands:done",
|
|
8026
|
-
startAt: params.startupStartedAt,
|
|
8027
|
-
details: "background=true",
|
|
8028
|
-
isVerbose: params.isVerbose
|
|
8029
|
-
});
|
|
8030
|
-
}).catch((err) => {
|
|
8031
|
-
params.runtime.log?.(warn(`[${params.accountId}] slash command deploy failed in background (message send/receive unaffected): ${formatErrorMessage$1(err)}`));
|
|
8032
|
-
});
|
|
8033
|
-
}
|
|
8034
|
-
//#endregion
|
|
8035
|
-
//#region extensions/discord/src/monitor/agent-components-reply.ts
|
|
8036
|
-
async function replySilently(interaction, params) {
|
|
8037
|
-
try {
|
|
8038
|
-
await interaction.reply(params);
|
|
8039
|
-
} catch {}
|
|
8040
|
-
}
|
|
8041
|
-
//#endregion
|
|
8042
|
-
//#region extensions/discord/src/activities/interaction.ts
|
|
8043
|
-
const REGISTRATION_WIDGET_ID = "AAAAAAAAAAAAAAAAAAAAAA";
|
|
8044
|
-
const PENDING_LAUNCH_WRITE_BUDGET_MS = 250;
|
|
8045
|
-
var DiscordActivityButton = class extends Button {
|
|
8046
|
-
constructor(ctx, deps) {
|
|
8047
|
-
super();
|
|
8048
|
-
this.ctx = ctx;
|
|
8049
|
-
this.deps = deps;
|
|
8050
|
-
this.label = "Open widget";
|
|
8051
|
-
this.customId = buildDiscordActivityCustomId(REGISTRATION_WIDGET_ID);
|
|
8052
|
-
this.customIdParser = parseDiscordActivityCustomIdForInteraction;
|
|
8053
|
-
this.pendingLaunchFailureLogged = false;
|
|
8054
|
-
}
|
|
8055
|
-
logPendingLaunchFailure(error) {
|
|
8056
|
-
if (this.pendingLaunchFailureLogged) return;
|
|
8057
|
-
this.pendingLaunchFailureLogged = true;
|
|
8058
|
-
this.deps.logError(`discord activity: failed to record pending launch: ${String(error)}`);
|
|
8059
|
-
}
|
|
8060
|
-
async run(interaction, data) {
|
|
8061
|
-
if (typeof data.widgetId !== "string") {
|
|
8062
|
-
await this.deps.reply(interaction, {
|
|
8063
|
-
content: "This widget is no longer valid.",
|
|
8064
|
-
ephemeral: true
|
|
8065
|
-
});
|
|
8066
|
-
return;
|
|
8067
|
-
}
|
|
8068
|
-
const runtime = getDiscordActivitiesRuntime();
|
|
8069
|
-
const channelId = interaction.rawData.channel_id;
|
|
8070
|
-
const discordUserId = interaction.userId;
|
|
8071
|
-
if (!runtime || !channelId || !discordUserId) this.logPendingLaunchFailure(/* @__PURE__ */ new Error("missing activity runtime or interaction identity"));
|
|
8072
|
-
else {
|
|
8073
|
-
const write = runtime.store.recordPendingLaunch({
|
|
8074
|
-
accountId: this.ctx.accountId,
|
|
8075
|
-
channelId,
|
|
8076
|
-
discordUserId,
|
|
8077
|
-
widgetId: data.widgetId,
|
|
8078
|
-
createdAt: Date.now()
|
|
8079
|
-
}).then(() => "written").catch((error) => {
|
|
8080
|
-
this.logPendingLaunchFailure(error);
|
|
8081
|
-
return "failed";
|
|
8082
|
-
});
|
|
8083
|
-
let timer;
|
|
8084
|
-
const timeout = new Promise((resolve) => {
|
|
8085
|
-
timer = setTimeout(() => resolve("timeout"), PENDING_LAUNCH_WRITE_BUDGET_MS);
|
|
8086
|
-
timer.unref?.();
|
|
8087
|
-
});
|
|
8088
|
-
try {
|
|
8089
|
-
if (await Promise.race([write, timeout]) === "timeout") this.logPendingLaunchFailure(/* @__PURE__ */ new Error(`pending launch write exceeded ${PENDING_LAUNCH_WRITE_BUDGET_MS}ms`));
|
|
8090
|
-
} finally {
|
|
8091
|
-
if (timer) clearTimeout(timer);
|
|
8092
|
-
}
|
|
8093
|
-
}
|
|
8094
|
-
await interaction.launchActivity();
|
|
8095
|
-
}
|
|
8096
|
-
};
|
|
8097
|
-
function createDiscordActivityButton(ctx, applicationId, deps = {}) {
|
|
8098
|
-
const runtime = getDiscordActivitiesRuntime();
|
|
8099
|
-
if (!runtime || !runtime.isAccountEnabled(ctx.accountId, ctx.cfg)) return null;
|
|
8100
|
-
if (applicationId) runtime.registerApplicationId(ctx.accountId, applicationId);
|
|
8101
|
-
if (!runtime.resolveAccount(ctx.accountId, ctx.cfg)) return null;
|
|
8102
|
-
return new DiscordActivityButton(ctx, {
|
|
8103
|
-
reply: deps.reply ?? replySilently,
|
|
8104
|
-
logError: deps.logError ?? logError
|
|
8105
|
-
});
|
|
8106
|
-
}
|
|
8107
|
-
//#endregion
|
|
8108
|
-
//#region extensions/discord/src/voice/access.ts
|
|
8109
|
-
async function authorizeDiscordVoiceIngress(params) {
|
|
8110
|
-
const groupPolicy = params.groupPolicy ?? resolveOpenProviderRuntimeGroupPolicy({
|
|
8111
|
-
providerConfigPresent: params.cfg.channels?.discord !== void 0,
|
|
8112
|
-
groupPolicy: params.discordConfig.groupPolicy,
|
|
8113
|
-
defaultGroupPolicy: params.cfg.channels?.defaults?.groupPolicy
|
|
8114
|
-
}).groupPolicy;
|
|
8115
|
-
const guildInfo = resolveDiscordGuildEntry({
|
|
8116
|
-
guild: params.guild ?? {
|
|
8117
|
-
id: params.guildId,
|
|
8118
|
-
...params.guildName ? { name: params.guildName } : {}
|
|
8119
|
-
},
|
|
8120
|
-
guildId: params.guildId,
|
|
8121
|
-
guildEntries: params.discordConfig.guilds
|
|
8122
|
-
});
|
|
8123
|
-
const channelConfig = params.channelId ? resolveDiscordChannelConfigWithFallback({
|
|
8124
|
-
guildInfo,
|
|
8125
|
-
channelId: params.channelId,
|
|
8126
|
-
channelName: params.channelName,
|
|
8127
|
-
channelSlug: params.channelSlug,
|
|
8128
|
-
parentId: params.parentId,
|
|
8129
|
-
parentName: params.parentName,
|
|
8130
|
-
parentSlug: params.parentSlug,
|
|
8131
|
-
scope: params.scope
|
|
8132
|
-
}) : null;
|
|
8133
|
-
if (channelConfig?.enabled === false) return {
|
|
8134
|
-
ok: false,
|
|
8135
|
-
message: "This channel is disabled."
|
|
8136
|
-
};
|
|
8137
|
-
const channelAllowlistConfigured = Boolean(guildInfo?.channels) && Object.keys(guildInfo?.channels ?? {}).length > 0;
|
|
8138
|
-
if (!params.channelId && groupPolicy === "allowlist" && channelAllowlistConfigured) return {
|
|
8139
|
-
ok: false,
|
|
8140
|
-
message: `${params.channelLabel ?? "This channel"} is not allowlisted for voice commands.`
|
|
8141
|
-
};
|
|
8142
|
-
const channelAllowed = channelConfig ? channelConfig.allowed : !channelAllowlistConfigured;
|
|
8143
|
-
if (!isDiscordGroupAllowedByPolicy({
|
|
8144
|
-
groupPolicy,
|
|
8145
|
-
guildAllowlisted: Boolean(guildInfo),
|
|
8146
|
-
channelAllowlistConfigured,
|
|
8147
|
-
channelAllowed
|
|
8148
|
-
}) || channelConfig?.allowed === false) return {
|
|
8149
|
-
ok: false,
|
|
8150
|
-
message: `${params.channelLabel ?? "This channel"} is not allowlisted for voice commands.`
|
|
8151
|
-
};
|
|
8152
|
-
const { hasAccessRestrictions, memberAllowed } = resolveDiscordMemberAccessState({
|
|
8153
|
-
channelConfig,
|
|
8154
|
-
guildInfo,
|
|
8155
|
-
memberRoleIds: params.memberRoleIds,
|
|
8156
|
-
sender: params.sender,
|
|
8157
|
-
allowNameMatching: false
|
|
8158
|
-
});
|
|
8159
|
-
const admissionAllowList = normalizeDiscordAllowList(params.admissionAllowFrom ?? params.discordConfig.allowFrom ?? params.discordConfig.allowFrom, [
|
|
8160
|
-
"discord:",
|
|
8161
|
-
"user:",
|
|
8162
|
-
"pk:"
|
|
8163
|
-
]);
|
|
8164
|
-
const admissionAllowed = admissionAllowList ? allowListMatches(admissionAllowList, params.sender, { allowNameMatching: false }) : false;
|
|
8165
|
-
const useAccessGroups = params.useAccessGroups ?? true;
|
|
8166
|
-
return resolveCommandAuthorizedFromAuthorizers({
|
|
8167
|
-
useAccessGroups,
|
|
8168
|
-
authorizers: useAccessGroups ? [{
|
|
8169
|
-
configured: admissionAllowList != null,
|
|
8170
|
-
allowed: admissionAllowed
|
|
8171
|
-
}, {
|
|
8172
|
-
configured: hasAccessRestrictions,
|
|
8173
|
-
allowed: memberAllowed
|
|
8174
|
-
}] : [{
|
|
8175
|
-
configured: hasAccessRestrictions,
|
|
8176
|
-
allowed: memberAllowed
|
|
8177
|
-
}],
|
|
8178
|
-
modeWhenAccessGroupsOff: "configured"
|
|
8179
|
-
}) ? {
|
|
8180
|
-
ok: true,
|
|
8181
|
-
channelConfig
|
|
8182
|
-
} : {
|
|
8183
|
-
ok: false,
|
|
8184
|
-
message: "You are not authorized to use this command."
|
|
8185
|
-
};
|
|
8186
|
-
}
|
|
8187
|
-
//#endregion
|
|
8188
|
-
//#region extensions/discord/src/voice/owner-access.ts
|
|
8189
|
-
function resolveDiscordVoiceAccess(params) {
|
|
8190
|
-
const commandOwnerAllowFrom = resolveDiscordCommandOwnerAllowFrom(params.cfg);
|
|
8191
|
-
if (commandOwnerAllowFrom) return {
|
|
8192
|
-
admissionAllowFrom: commandOwnerAllowFrom,
|
|
8193
|
-
ownerAllowFrom: commandOwnerAllowFrom,
|
|
8194
|
-
ownerAllowAll: commandOwnerAllowFrom.includes("*")
|
|
8195
|
-
};
|
|
8196
|
-
return {
|
|
8197
|
-
admissionAllowFrom: resolveDiscordAccountAllowFrom({
|
|
8198
|
-
cfg: params.cfg,
|
|
8199
|
-
accountId: params.accountId
|
|
8200
|
-
}) ?? params.discordConfig.allowFrom ?? params.discordConfig.allowFrom ?? [],
|
|
8201
|
-
ownerAllowFrom: [],
|
|
8202
|
-
ownerAllowAll: false
|
|
8203
|
-
};
|
|
8204
|
-
}
|
|
8205
|
-
//#endregion
|
|
8206
|
-
//#region extensions/discord/src/voice/command.ts
|
|
8207
|
-
const VOICE_CHANNEL_TYPES = [ChannelType.GuildVoice, ChannelType.GuildStageVoice];
|
|
8208
|
-
async function authorizeVoiceCommand(interaction, params, options) {
|
|
8209
|
-
const channelOverride = options?.channelOverride;
|
|
8210
|
-
const channel = channelOverride ? void 0 : interaction.channel;
|
|
8211
|
-
if (!interaction.guild) return {
|
|
8212
|
-
ok: false,
|
|
8213
|
-
message: "Voice commands are only available in guilds."
|
|
8214
|
-
};
|
|
8215
|
-
const user = interaction.user;
|
|
8216
|
-
if (!user) return {
|
|
8217
|
-
ok: false,
|
|
8218
|
-
message: "Unable to resolve command user."
|
|
8219
|
-
};
|
|
8220
|
-
const channelId = channelOverride?.id ?? channel?.id ?? "";
|
|
8221
|
-
const channelContext = await resolveDiscordThreadLikeChannelContext({
|
|
8222
|
-
client: interaction.client,
|
|
8223
|
-
channel: channelOverride ?? channel,
|
|
8224
|
-
channelIdFallback: channelId
|
|
8225
|
-
});
|
|
8226
|
-
const channelName = channelOverride?.name ?? channelContext.channelName;
|
|
8227
|
-
const memberRoleIds = Array.isArray(interaction.rawData.member?.roles) ? interaction.rawData.member.roles.map((roleId) => roleId) : [];
|
|
8228
|
-
const sender = resolveDiscordSenderIdentity({
|
|
8229
|
-
author: user,
|
|
8230
|
-
member: interaction.rawData.member
|
|
8231
|
-
});
|
|
8232
|
-
const voiceAccess = resolveDiscordVoiceAccess(params);
|
|
8233
|
-
const access = await authorizeDiscordVoiceIngress({
|
|
8234
|
-
cfg: params.cfg,
|
|
8235
|
-
discordConfig: params.discordConfig,
|
|
8236
|
-
accountId: params.accountId,
|
|
8237
|
-
groupPolicy: params.groupPolicy,
|
|
8238
|
-
useAccessGroups: params.useAccessGroups,
|
|
8239
|
-
guild: interaction.guild,
|
|
8240
|
-
guildId: interaction.guild.id,
|
|
8241
|
-
channelId,
|
|
8242
|
-
channelName,
|
|
8243
|
-
channelSlug: channelContext.channelSlug,
|
|
8244
|
-
parentId: channelOverride?.parentId ?? channelContext.threadParentId,
|
|
8245
|
-
parentName: channelContext.threadParentName,
|
|
8246
|
-
parentSlug: channelContext.threadParentSlug,
|
|
8247
|
-
scope: channelContext.isThreadChannel ? "thread" : "channel",
|
|
8248
|
-
channelLabel: channelId ? formatMention({ channelId }) : "This channel",
|
|
8249
|
-
memberRoleIds,
|
|
8250
|
-
admissionAllowFrom: voiceAccess.admissionAllowFrom,
|
|
8251
|
-
sender: {
|
|
8252
|
-
id: sender.id,
|
|
8253
|
-
name: sender.name,
|
|
8254
|
-
tag: sender.tag
|
|
8255
|
-
}
|
|
8256
|
-
});
|
|
8257
|
-
if (!access.ok) return {
|
|
8258
|
-
ok: false,
|
|
8259
|
-
message: access.message
|
|
8260
|
-
};
|
|
8261
|
-
return {
|
|
8262
|
-
ok: true,
|
|
8263
|
-
guildId: interaction.guild.id
|
|
8264
|
-
};
|
|
8265
|
-
}
|
|
8266
|
-
async function resolveVoiceCommandRuntimeContext(interaction, params) {
|
|
8267
|
-
const guildId = interaction.guild?.id;
|
|
8268
|
-
if (!guildId) {
|
|
8269
|
-
await interaction.reply({
|
|
8270
|
-
content: "Unable to resolve guild for this command.",
|
|
8271
|
-
ephemeral: true
|
|
8272
|
-
});
|
|
8273
|
-
return null;
|
|
8274
|
-
}
|
|
8275
|
-
const manager = params.getManager();
|
|
8276
|
-
if (!manager) {
|
|
8277
|
-
await interaction.reply({
|
|
8278
|
-
content: "Voice manager is not available yet.",
|
|
8279
|
-
ephemeral: true
|
|
8280
|
-
});
|
|
8281
|
-
return null;
|
|
8282
|
-
}
|
|
8283
|
-
return {
|
|
8284
|
-
guildId,
|
|
8285
|
-
manager
|
|
8286
|
-
};
|
|
8287
|
-
}
|
|
8288
|
-
async function ensureVoiceCommandAccess(params) {
|
|
8289
|
-
const access = await authorizeVoiceCommand(params.interaction, params.context, { channelOverride: params.channelOverride });
|
|
8290
|
-
if (access.ok) return true;
|
|
8291
|
-
await params.interaction.reply({
|
|
8292
|
-
content: access.message ?? "Not authorized.",
|
|
8293
|
-
ephemeral: true
|
|
8294
|
-
});
|
|
8295
|
-
return false;
|
|
8296
|
-
}
|
|
8297
|
-
function createDiscordVoiceCommand(params) {
|
|
8298
|
-
const resolveSessionChannelId = (manager, guildId) => manager.status().find((entry) => entry.guildId === guildId)?.channelId;
|
|
8299
|
-
class JoinCommand extends Command {
|
|
8300
|
-
constructor(..._args) {
|
|
8301
|
-
super(..._args);
|
|
8302
|
-
this.name = "join";
|
|
8303
|
-
this.description = "Join a voice channel";
|
|
8304
|
-
this.defer = true;
|
|
8305
|
-
this.ephemeral = params.ephemeralDefault;
|
|
8306
|
-
this.options = [{
|
|
8307
|
-
name: "channel",
|
|
8308
|
-
description: "Voice channel to join",
|
|
8309
|
-
type: ApplicationCommandOptionType.Channel,
|
|
8310
|
-
required: true,
|
|
8311
|
-
channel_types: VOICE_CHANNEL_TYPES
|
|
8312
|
-
}];
|
|
8313
|
-
}
|
|
8314
|
-
async run(interaction) {
|
|
8315
|
-
const channel = await interaction.options.getChannel("channel", true);
|
|
8316
|
-
if (!channel || !("id" in channel)) {
|
|
8317
|
-
await interaction.reply({
|
|
8318
|
-
content: "Voice channel not found.",
|
|
8319
|
-
ephemeral: true
|
|
8320
|
-
});
|
|
8321
|
-
return;
|
|
8322
|
-
}
|
|
8323
|
-
const access = await authorizeVoiceCommand(interaction, params, { channelOverride: {
|
|
8324
|
-
id: channel.id,
|
|
8325
|
-
name: resolveDiscordChannelNameSafe(channel)
|
|
8326
|
-
} });
|
|
8327
|
-
if (!access.ok) {
|
|
8328
|
-
await interaction.reply({
|
|
8329
|
-
content: access.message ?? "Not authorized.",
|
|
8330
|
-
ephemeral: true
|
|
8331
|
-
});
|
|
8332
|
-
return;
|
|
8333
|
-
}
|
|
8334
|
-
if (!isVoiceChannelType(channel.type)) {
|
|
8335
|
-
await interaction.reply({
|
|
8336
|
-
content: "That is not a voice channel.",
|
|
8337
|
-
ephemeral: true
|
|
8338
|
-
});
|
|
8339
|
-
return;
|
|
8340
|
-
}
|
|
8341
|
-
const guildId = access.guildId ?? ("guildId" in channel ? channel.guildId : void 0);
|
|
8342
|
-
if (!guildId) {
|
|
8343
|
-
await interaction.reply({
|
|
8344
|
-
content: "Unable to resolve guild for this voice channel.",
|
|
8345
|
-
ephemeral: true
|
|
8346
|
-
});
|
|
8347
|
-
return;
|
|
8348
|
-
}
|
|
8349
|
-
const manager = params.getManager();
|
|
8350
|
-
if (!manager) {
|
|
8351
|
-
await interaction.reply({
|
|
8352
|
-
content: "Voice manager is not available yet.",
|
|
8353
|
-
ephemeral: true
|
|
8354
|
-
});
|
|
8355
|
-
return;
|
|
8356
|
-
}
|
|
8357
|
-
const result = await manager.join({
|
|
8358
|
-
guildId,
|
|
8359
|
-
channelId: channel.id
|
|
8360
|
-
});
|
|
8361
|
-
await interaction.reply({
|
|
8362
|
-
content: result.message,
|
|
8363
|
-
ephemeral: true
|
|
8364
|
-
});
|
|
8365
|
-
}
|
|
8118
|
+
runtime: params.runtime,
|
|
8119
|
+
accountId: params.accountId,
|
|
8120
|
+
phase: "deploy-commands:scheduled",
|
|
8121
|
+
startAt: params.startupStartedAt,
|
|
8122
|
+
details: "mode=reconcile background=true",
|
|
8123
|
+
isVerbose: params.isVerbose
|
|
8124
|
+
});
|
|
8125
|
+
deployDiscordCommands(params).then(() => {
|
|
8126
|
+
logDiscordStartupPhase$1({
|
|
8127
|
+
runtime: params.runtime,
|
|
8128
|
+
accountId: params.accountId,
|
|
8129
|
+
phase: "deploy-commands:done",
|
|
8130
|
+
startAt: params.startupStartedAt,
|
|
8131
|
+
details: "background=true",
|
|
8132
|
+
isVerbose: params.isVerbose
|
|
8133
|
+
});
|
|
8134
|
+
}).catch((err) => {
|
|
8135
|
+
params.runtime.log?.(warn(`[${params.accountId}] slash command deploy failed in background (message send/receive unaffected): ${formatErrorMessage$1(err)}`));
|
|
8136
|
+
});
|
|
8137
|
+
}
|
|
8138
|
+
//#endregion
|
|
8139
|
+
//#region extensions/discord/src/monitor/agent-components-reply.ts
|
|
8140
|
+
async function replySilently(interaction, params) {
|
|
8141
|
+
try {
|
|
8142
|
+
await interaction.reply(params);
|
|
8143
|
+
} catch {}
|
|
8144
|
+
}
|
|
8145
|
+
//#endregion
|
|
8146
|
+
//#region extensions/discord/src/activities/interaction.ts
|
|
8147
|
+
const REGISTRATION_WIDGET_ID = "AAAAAAAAAAAAAAAAAAAAAA";
|
|
8148
|
+
const PENDING_LAUNCH_WRITE_BUDGET_MS = 250;
|
|
8149
|
+
var DiscordActivityButton = class extends Button {
|
|
8150
|
+
constructor(ctx, deps) {
|
|
8151
|
+
super();
|
|
8152
|
+
this.ctx = ctx;
|
|
8153
|
+
this.deps = deps;
|
|
8154
|
+
this.label = "Open widget";
|
|
8155
|
+
this.customId = buildDiscordActivityCustomId(REGISTRATION_WIDGET_ID);
|
|
8156
|
+
this.customIdParser = parseDiscordActivityCustomIdForInteraction;
|
|
8157
|
+
this.pendingLaunchFailureLogged = false;
|
|
8366
8158
|
}
|
|
8367
|
-
|
|
8368
|
-
|
|
8369
|
-
|
|
8370
|
-
|
|
8371
|
-
|
|
8372
|
-
|
|
8373
|
-
|
|
8374
|
-
|
|
8375
|
-
|
|
8376
|
-
const runtimeContext = await resolveVoiceCommandRuntimeContext(interaction, params);
|
|
8377
|
-
if (!runtimeContext) return;
|
|
8378
|
-
const sessionChannelId = resolveSessionChannelId(runtimeContext.manager, runtimeContext.guildId);
|
|
8379
|
-
if (!await ensureVoiceCommandAccess({
|
|
8380
|
-
interaction,
|
|
8381
|
-
context: params,
|
|
8382
|
-
channelOverride: sessionChannelId ? { id: sessionChannelId } : void 0
|
|
8383
|
-
})) return;
|
|
8384
|
-
const result = await runtimeContext.manager.leave({ guildId: runtimeContext.guildId });
|
|
8385
|
-
await interaction.reply({
|
|
8386
|
-
content: result.message,
|
|
8159
|
+
logPendingLaunchFailure(error) {
|
|
8160
|
+
if (this.pendingLaunchFailureLogged) return;
|
|
8161
|
+
this.pendingLaunchFailureLogged = true;
|
|
8162
|
+
this.deps.logError(`discord activity: failed to record pending launch: ${String(error)}`);
|
|
8163
|
+
}
|
|
8164
|
+
async run(interaction, data) {
|
|
8165
|
+
if (typeof data.widgetId !== "string") {
|
|
8166
|
+
await this.deps.reply(interaction, {
|
|
8167
|
+
content: "This widget is no longer valid.",
|
|
8387
8168
|
ephemeral: true
|
|
8388
8169
|
});
|
|
8170
|
+
return;
|
|
8389
8171
|
}
|
|
8390
|
-
|
|
8391
|
-
|
|
8392
|
-
|
|
8393
|
-
|
|
8394
|
-
|
|
8395
|
-
|
|
8396
|
-
|
|
8397
|
-
|
|
8398
|
-
|
|
8399
|
-
|
|
8400
|
-
|
|
8401
|
-
|
|
8402
|
-
|
|
8403
|
-
|
|
8404
|
-
|
|
8405
|
-
|
|
8406
|
-
|
|
8407
|
-
|
|
8408
|
-
|
|
8409
|
-
if (sessions.length === 0) {
|
|
8410
|
-
await interaction.reply({
|
|
8411
|
-
content: "No active voice sessions.",
|
|
8412
|
-
ephemeral: true
|
|
8413
|
-
});
|
|
8414
|
-
return;
|
|
8415
|
-
}
|
|
8416
|
-
const lines = sessions.map((entry) => `• ${formatMention({ channelId: entry.channelId })} (guild ${entry.guildId})`);
|
|
8417
|
-
await interaction.reply({
|
|
8418
|
-
content: lines.join("\n"),
|
|
8419
|
-
ephemeral: true
|
|
8172
|
+
const runtime = getDiscordActivitiesRuntime();
|
|
8173
|
+
const channelId = interaction.rawData.channel_id;
|
|
8174
|
+
const discordUserId = interaction.userId;
|
|
8175
|
+
if (!runtime || !channelId || !discordUserId) this.logPendingLaunchFailure(/* @__PURE__ */ new Error("missing activity runtime or interaction identity"));
|
|
8176
|
+
else {
|
|
8177
|
+
const write = runtime.store.recordPendingLaunch({
|
|
8178
|
+
accountId: this.ctx.accountId,
|
|
8179
|
+
channelId,
|
|
8180
|
+
discordUserId,
|
|
8181
|
+
widgetId: data.widgetId,
|
|
8182
|
+
createdAt: Date.now()
|
|
8183
|
+
}).then(() => "written").catch((error) => {
|
|
8184
|
+
this.logPendingLaunchFailure(error);
|
|
8185
|
+
return "failed";
|
|
8186
|
+
});
|
|
8187
|
+
let timer;
|
|
8188
|
+
const timeout = new Promise((resolve) => {
|
|
8189
|
+
timer = setTimeout(() => resolve("timeout"), PENDING_LAUNCH_WRITE_BUDGET_MS);
|
|
8190
|
+
timer.unref?.();
|
|
8420
8191
|
});
|
|
8192
|
+
try {
|
|
8193
|
+
if (await Promise.race([write, timeout]) === "timeout") this.logPendingLaunchFailure(/* @__PURE__ */ new Error(`pending launch write exceeded ${PENDING_LAUNCH_WRITE_BUDGET_MS}ms`));
|
|
8194
|
+
} finally {
|
|
8195
|
+
if (timer) clearTimeout(timer);
|
|
8196
|
+
}
|
|
8421
8197
|
}
|
|
8198
|
+
await interaction.launchActivity();
|
|
8422
8199
|
}
|
|
8423
|
-
|
|
8424
|
-
|
|
8425
|
-
|
|
8426
|
-
|
|
8427
|
-
|
|
8428
|
-
|
|
8429
|
-
|
|
8430
|
-
|
|
8431
|
-
|
|
8432
|
-
|
|
8433
|
-
}
|
|
8434
|
-
}();
|
|
8435
|
-
}
|
|
8436
|
-
function isVoiceChannelType(type) {
|
|
8437
|
-
return type === ChannelType.GuildVoice || type === ChannelType.GuildStageVoice;
|
|
8200
|
+
};
|
|
8201
|
+
function createDiscordActivityButton(ctx, applicationId, deps = {}) {
|
|
8202
|
+
const runtime = getDiscordActivitiesRuntime();
|
|
8203
|
+
if (!runtime || !runtime.isAccountEnabled(ctx.accountId, ctx.cfg)) return null;
|
|
8204
|
+
if (applicationId) runtime.registerApplicationId(ctx.accountId, applicationId);
|
|
8205
|
+
if (!runtime.resolveAccount(ctx.accountId, ctx.cfg)) return null;
|
|
8206
|
+
return new DiscordActivityButton(ctx, {
|
|
8207
|
+
reply: deps.reply ?? replySilently,
|
|
8208
|
+
logError: deps.logError ?? logError
|
|
8209
|
+
});
|
|
8438
8210
|
}
|
|
8439
8211
|
//#endregion
|
|
8440
8212
|
//#region extensions/discord/src/monitor/agent-components-context.ts
|
|
@@ -8472,6 +8244,14 @@ async function ackComponentInteraction(params) {
|
|
|
8472
8244
|
logError(`${params.label}: failed to acknowledge interaction: ${String(err)}`);
|
|
8473
8245
|
}
|
|
8474
8246
|
}
|
|
8247
|
+
async function replyUnavailableComponentInteraction(interaction, content) {
|
|
8248
|
+
try {
|
|
8249
|
+
await interaction.reply({
|
|
8250
|
+
content,
|
|
8251
|
+
ephemeral: true
|
|
8252
|
+
});
|
|
8253
|
+
} catch {}
|
|
8254
|
+
}
|
|
8475
8255
|
function resolveDiscordChannelContext(interaction) {
|
|
8476
8256
|
const channel = interaction.channel;
|
|
8477
8257
|
const channelInfo = resolveDiscordChannelInfoSafe(channel);
|
|
@@ -8967,12 +8747,6 @@ function formatModalSubmissionText(entry, interaction) {
|
|
|
8967
8747
|
if (lines.length === 1) lines.push("- (no values)");
|
|
8968
8748
|
return lines.join("\n");
|
|
8969
8749
|
}
|
|
8970
|
-
function resolveDiscordInteractionId(interaction) {
|
|
8971
|
-
const rawId = interaction.rawData && typeof interaction.rawData === "object" && "id" in interaction.rawData ? interaction.rawData.id : void 0;
|
|
8972
|
-
if (typeof rawId === "string" && rawId.trim()) return rawId.trim();
|
|
8973
|
-
if (typeof rawId === "number" && Number.isFinite(rawId)) return String(rawId);
|
|
8974
|
-
return `discord-interaction:${Date.now()}`;
|
|
8975
|
-
}
|
|
8976
8750
|
//#endregion
|
|
8977
8751
|
//#region extensions/discord/src/monitor/agent-components-helpers.ts
|
|
8978
8752
|
const AGENT_BUTTON_KEY = "agent";
|
|
@@ -9046,7 +8820,7 @@ function stripDiscordInternalChannelLines(text) {
|
|
|
9046
8820
|
return kept.join("\n");
|
|
9047
8821
|
}
|
|
9048
8822
|
function sanitizeDiscordFrontChannelText(text) {
|
|
9049
|
-
return collapseExcessBlankLines(stripDiscordInternalChannelLines(stripPlainTextToolCallBlocks(sanitizeAssistantVisibleText(stripPlainTextToolCallBlocks(text))))).trim();
|
|
8823
|
+
return collapseExcessBlankLines(stripDiscordInternalChannelLines(stripPlainTextToolCallBlocks(sanitizeAssistantVisibleText(stripPlainTextToolCallBlocks(text, { resolveProtectedRanges: findCodeRegions })), { resolveProtectedRanges: findCodeRegions }))).trim();
|
|
9050
8824
|
}
|
|
9051
8825
|
function sanitizeDiscordFrontChannelReplyPayloads(payloads, options = {}) {
|
|
9052
8826
|
const preserveVerboseToolProgress = options.kind === "tool";
|
|
@@ -9143,7 +8917,7 @@ function formatDiscordReasoningPayload(payload) {
|
|
|
9143
8917
|
async function deliverDiscordReply(params) {
|
|
9144
8918
|
params.runtime;
|
|
9145
8919
|
const delivery = resolveDiscordDeliveryOptions(params);
|
|
9146
|
-
const payloads = sanitizeDiscordFrontChannelReplyPayloads(params.replies, { kind: params.kind }).map(formatDiscordReasoningPayload);
|
|
8920
|
+
const payloads = sanitizeDiscordFrontChannelReplyPayloads(params.replies, { kind: params.kind }).map(formatDiscordReasoningPayload).map((payload) => params.bindPendingFinalDelivery?.(payload) ?? payload);
|
|
9147
8921
|
if (payloads.length === 0) return {
|
|
9148
8922
|
visibleReplySent: false,
|
|
9149
8923
|
suppression: { reason: "no_visible_result" }
|
|
@@ -9173,7 +8947,7 @@ async function deliverDiscordReply(params) {
|
|
|
9173
8947
|
requesterAccountId: params.accountId
|
|
9174
8948
|
})
|
|
9175
8949
|
});
|
|
9176
|
-
if (send.status === "failed"
|
|
8950
|
+
if (send.status === "failed") throw send.error;
|
|
9177
8951
|
if (send.status === "suppressed") {
|
|
9178
8952
|
const hookEffect = send.payloadOutcomes?.find((outcome) => outcome.status === "suppressed")?.hookEffect;
|
|
9179
8953
|
return {
|
|
@@ -9185,17 +8959,19 @@ async function deliverDiscordReply(params) {
|
|
|
9185
8959
|
}
|
|
9186
8960
|
};
|
|
9187
8961
|
}
|
|
9188
|
-
|
|
9189
|
-
|
|
9190
|
-
|
|
9191
|
-
|
|
8962
|
+
if (send.results.length === 0) throw new Error(`discord final reply produced no delivered message for ${delivery.to}`);
|
|
8963
|
+
const deliveryResult = {
|
|
8964
|
+
messageIds: listMessageReceiptPlatformIds(send.receipt),
|
|
8965
|
+
receipt: send.receipt,
|
|
9192
8966
|
visibleReplySent: true
|
|
9193
8967
|
};
|
|
8968
|
+
if (send.status === "partial_failed") throw createChannelPartialDeliveryError(send.error, deliveryResult);
|
|
8969
|
+
return deliveryResult;
|
|
9194
8970
|
}
|
|
9195
8971
|
//#endregion
|
|
9196
8972
|
//#region extensions/discord/src/monitor/agent-components.dispatch.ts
|
|
9197
8973
|
const loadConversationRuntime$1 = createLazyRuntimeModule(() => import("./agent-components.runtime-CEPrf2SY.js"));
|
|
9198
|
-
const loadTypingRuntime = createLazyRuntimeModule(() => import("./typing
|
|
8974
|
+
const loadTypingRuntime = createLazyRuntimeModule(() => import("./typing-CS-nNVoe.js").then((n) => n.n));
|
|
9199
8975
|
function buildDiscordComponentConversationLabel(params) {
|
|
9200
8976
|
if (params.interactionCtx.isDirectMessage) return buildDirectLabel(params.interactionCtx.user);
|
|
9201
8977
|
if (params.interactionCtx.isGroupDm) return `Group DM #${params.channelCtx.channelName ?? params.interactionCtx.channelId} channel id:${params.interactionCtx.channelId}`;
|
|
@@ -9425,7 +9201,8 @@ async function dispatchDiscordComponentEvent(params) {
|
|
|
9425
9201
|
tableMode,
|
|
9426
9202
|
chunkMode: resolveChunkMode(ctx.cfg, "discord", accountId),
|
|
9427
9203
|
mediaLocalRoots,
|
|
9428
|
-
kind: info.kind
|
|
9204
|
+
kind: info.kind,
|
|
9205
|
+
bindPendingFinalDelivery: info.bindPendingFinalDelivery
|
|
9429
9206
|
});
|
|
9430
9207
|
if (result.visibleReplySent) replyReference.markSent();
|
|
9431
9208
|
return result;
|
|
@@ -9455,33 +9232,14 @@ async function dispatchDiscordComponentEvent(params) {
|
|
|
9455
9232
|
}
|
|
9456
9233
|
//#endregion
|
|
9457
9234
|
//#region extensions/discord/src/interactive-dispatch.ts
|
|
9235
|
+
const dispatchDiscordInteractive = createChannelInteractiveDispatcher({
|
|
9236
|
+
channel: "discord",
|
|
9237
|
+
interactiveKey: "interaction"
|
|
9238
|
+
});
|
|
9458
9239
|
async function dispatchDiscordPluginInteractiveHandler(params) {
|
|
9459
|
-
return await
|
|
9460
|
-
|
|
9461
|
-
|
|
9462
|
-
dedupeId: params.interactionId,
|
|
9463
|
-
onMatched: params.onMatched,
|
|
9464
|
-
invoke: ({ registration, namespace, payload }) => registration.handler({
|
|
9465
|
-
...params.ctx,
|
|
9466
|
-
channel: "discord",
|
|
9467
|
-
interaction: {
|
|
9468
|
-
...params.ctx.interaction,
|
|
9469
|
-
data: params.data,
|
|
9470
|
-
namespace,
|
|
9471
|
-
payload
|
|
9472
|
-
},
|
|
9473
|
-
respond: params.respond,
|
|
9474
|
-
...createInteractiveConversationBindingHelpers({
|
|
9475
|
-
registration,
|
|
9476
|
-
senderId: params.ctx.senderId,
|
|
9477
|
-
conversation: {
|
|
9478
|
-
channel: "discord",
|
|
9479
|
-
accountId: params.ctx.accountId,
|
|
9480
|
-
conversationId: params.ctx.conversationId,
|
|
9481
|
-
parentConversationId: params.ctx.parentConversationId
|
|
9482
|
-
}
|
|
9483
|
-
})
|
|
9484
|
-
})
|
|
9240
|
+
return await dispatchDiscordInteractive({
|
|
9241
|
+
...params,
|
|
9242
|
+
dedupeId: params.interactionId
|
|
9485
9243
|
});
|
|
9486
9244
|
}
|
|
9487
9245
|
//#endregion
|
|
@@ -9512,10 +9270,11 @@ async function dispatchPluginDiscordInteractiveEvent(params) {
|
|
|
9512
9270
|
},
|
|
9513
9271
|
reply: async ({ text, ephemeral = true }) => {
|
|
9514
9272
|
responded = true;
|
|
9515
|
-
|
|
9273
|
+
const payload = {
|
|
9516
9274
|
content: text,
|
|
9517
9275
|
ephemeral
|
|
9518
|
-
}
|
|
9276
|
+
};
|
|
9277
|
+
await (acknowledged ? params.interaction.followUp(payload) : params.interaction.reply(payload));
|
|
9519
9278
|
},
|
|
9520
9279
|
followUp: async ({ text, ephemeral = true }) => {
|
|
9521
9280
|
responded = true;
|
|
@@ -9573,10 +9332,10 @@ async function dispatchPluginDiscordInteractiveEvent(params) {
|
|
|
9573
9332
|
}
|
|
9574
9333
|
const dispatched = await dispatchDiscordPluginInteractiveHandler({
|
|
9575
9334
|
data: params.data,
|
|
9576
|
-
interactionId:
|
|
9335
|
+
interactionId: params.interaction.id,
|
|
9577
9336
|
ctx: {
|
|
9578
9337
|
accountId: params.ctx.accountId,
|
|
9579
|
-
interactionId:
|
|
9338
|
+
interactionId: params.interaction.id,
|
|
9580
9339
|
conversationId: normalizedConversationId,
|
|
9581
9340
|
parentConversationId: params.channelCtx.parentId,
|
|
9582
9341
|
guildId: params.interactionCtx.rawGuildId,
|
|
@@ -9608,17 +9367,12 @@ async function dispatchPluginDiscordInteractiveEvent(params) {
|
|
|
9608
9367
|
}
|
|
9609
9368
|
//#endregion
|
|
9610
9369
|
//#region extensions/discord/src/monitor/agent-components.handlers.ts
|
|
9611
|
-
const loadComponentsRuntime = createLazyRuntimeModule(() => import("./outbound-session-route-
|
|
9370
|
+
const loadComponentsRuntime = createLazyRuntimeModule(() => import("./outbound-session-route-DxLkrgKQ.js").then((n) => n.n));
|
|
9612
9371
|
async function handleDiscordComponentEvent(params) {
|
|
9613
9372
|
const parsed = parseDiscordComponentData(params.data, resolveInteractionCustomId(params.interaction));
|
|
9614
9373
|
if (!parsed) {
|
|
9615
9374
|
logError(`${params.label}: failed to parse component data`);
|
|
9616
|
-
|
|
9617
|
-
await params.interaction.reply({
|
|
9618
|
-
content: "This component is no longer valid.",
|
|
9619
|
-
ephemeral: true
|
|
9620
|
-
});
|
|
9621
|
-
} catch {}
|
|
9375
|
+
await replyUnavailableComponentInteraction(params.interaction, "This component is no longer valid.");
|
|
9622
9376
|
return;
|
|
9623
9377
|
}
|
|
9624
9378
|
const entry = await resolveDiscordComponentEntryWithPersistence({
|
|
@@ -9626,12 +9380,7 @@ async function handleDiscordComponentEvent(params) {
|
|
|
9626
9380
|
consume: false
|
|
9627
9381
|
});
|
|
9628
9382
|
if (!entry) {
|
|
9629
|
-
|
|
9630
|
-
await params.interaction.reply({
|
|
9631
|
-
content: "This component has expired.",
|
|
9632
|
-
ephemeral: true
|
|
9633
|
-
});
|
|
9634
|
-
} catch {}
|
|
9383
|
+
await replyUnavailableComponentInteraction(params.interaction, "This component has expired.");
|
|
9635
9384
|
return;
|
|
9636
9385
|
}
|
|
9637
9386
|
const unauthorizedReply = `You are not authorized to use this ${params.componentLabel}.`;
|
|
@@ -9659,21 +9408,11 @@ async function handleDiscordComponentEvent(params) {
|
|
|
9659
9408
|
consume: !entry.reusable
|
|
9660
9409
|
});
|
|
9661
9410
|
if (!consumed) {
|
|
9662
|
-
|
|
9663
|
-
await params.interaction.reply({
|
|
9664
|
-
content: "This component has expired.",
|
|
9665
|
-
ephemeral: true
|
|
9666
|
-
});
|
|
9667
|
-
} catch {}
|
|
9411
|
+
await replyUnavailableComponentInteraction(params.interaction, "This component has expired.");
|
|
9668
9412
|
return;
|
|
9669
9413
|
}
|
|
9670
9414
|
if (consumed.kind === "modal-trigger") {
|
|
9671
|
-
|
|
9672
|
-
await params.interaction.reply({
|
|
9673
|
-
content: "This form is no longer available.",
|
|
9674
|
-
ephemeral: true
|
|
9675
|
-
});
|
|
9676
|
-
} catch {}
|
|
9415
|
+
await replyUnavailableComponentInteraction(params.interaction, "This form is no longer available.");
|
|
9677
9416
|
return;
|
|
9678
9417
|
}
|
|
9679
9418
|
const values = params.values ? mapSelectValues(consumed, params.values) : void 0;
|
|
@@ -9726,12 +9465,7 @@ async function handleDiscordModalTrigger(params) {
|
|
|
9726
9465
|
const parsed = parseDiscordComponentData(params.data, resolveInteractionCustomId(params.interaction));
|
|
9727
9466
|
if (!parsed) {
|
|
9728
9467
|
logError(`${params.label}: failed to parse modal trigger data`);
|
|
9729
|
-
|
|
9730
|
-
await params.interaction.reply({
|
|
9731
|
-
content: "This button is no longer valid.",
|
|
9732
|
-
ephemeral: true
|
|
9733
|
-
});
|
|
9734
|
-
} catch {}
|
|
9468
|
+
await replyUnavailableComponentInteraction(params.interaction, "This button is no longer valid.");
|
|
9735
9469
|
return;
|
|
9736
9470
|
}
|
|
9737
9471
|
const entry = await resolveDiscordComponentEntryWithPersistence({
|
|
@@ -9739,22 +9473,12 @@ async function handleDiscordModalTrigger(params) {
|
|
|
9739
9473
|
consume: false
|
|
9740
9474
|
});
|
|
9741
9475
|
if (!entry || entry.kind !== "modal-trigger") {
|
|
9742
|
-
|
|
9743
|
-
await params.interaction.reply({
|
|
9744
|
-
content: "This button has expired.",
|
|
9745
|
-
ephemeral: true
|
|
9746
|
-
});
|
|
9747
|
-
} catch {}
|
|
9476
|
+
await replyUnavailableComponentInteraction(params.interaction, "This button has expired.");
|
|
9748
9477
|
return;
|
|
9749
9478
|
}
|
|
9750
9479
|
const modalId = entry.modalId ?? parsed.modalId;
|
|
9751
9480
|
if (!modalId) {
|
|
9752
|
-
|
|
9753
|
-
await params.interaction.reply({
|
|
9754
|
-
content: "This form is no longer available.",
|
|
9755
|
-
ephemeral: true
|
|
9756
|
-
});
|
|
9757
|
-
} catch {}
|
|
9481
|
+
await replyUnavailableComponentInteraction(params.interaction, "This form is no longer available.");
|
|
9758
9482
|
return;
|
|
9759
9483
|
}
|
|
9760
9484
|
const unauthorizedReply = "You are not authorized to use this form.";
|
|
@@ -9782,12 +9506,7 @@ async function handleDiscordModalTrigger(params) {
|
|
|
9782
9506
|
consume: !entry.reusable
|
|
9783
9507
|
});
|
|
9784
9508
|
if (!consumed) {
|
|
9785
|
-
|
|
9786
|
-
await params.interaction.reply({
|
|
9787
|
-
content: "This form has expired.",
|
|
9788
|
-
ephemeral: true
|
|
9789
|
-
});
|
|
9790
|
-
} catch {}
|
|
9509
|
+
await replyUnavailableComponentInteraction(params.interaction, "This form has expired.");
|
|
9791
9510
|
return;
|
|
9792
9511
|
}
|
|
9793
9512
|
const modalEntry = await resolveDiscordModalEntryWithPersistence({
|
|
@@ -9795,18 +9514,14 @@ async function handleDiscordModalTrigger(params) {
|
|
|
9795
9514
|
consume: false
|
|
9796
9515
|
});
|
|
9797
9516
|
if (!modalEntry) {
|
|
9798
|
-
|
|
9799
|
-
await params.interaction.reply({
|
|
9800
|
-
content: "This form has expired.",
|
|
9801
|
-
ephemeral: true
|
|
9802
|
-
});
|
|
9803
|
-
} catch {}
|
|
9517
|
+
await replyUnavailableComponentInteraction(params.interaction, "This form has expired.");
|
|
9804
9518
|
return;
|
|
9805
9519
|
}
|
|
9806
9520
|
try {
|
|
9807
9521
|
await params.interaction.showModal((await loadComponentsRuntime()).createDiscordFormModal(modalEntry));
|
|
9808
9522
|
} catch (err) {
|
|
9809
9523
|
logError(`${params.label}: failed to show modal: ${String(err)}`);
|
|
9524
|
+
await replyUnavailableComponentInteraction(params.interaction, "Could not open this form. Request a new form and try again.");
|
|
9810
9525
|
}
|
|
9811
9526
|
}
|
|
9812
9527
|
const discordComponentControlHandlers = {
|
|
@@ -9828,12 +9543,7 @@ var DiscordComponentModal = class extends Modal {
|
|
|
9828
9543
|
const modalId = parseDiscordModalId(data, resolveInteractionCustomId(interaction));
|
|
9829
9544
|
if (!modalId) {
|
|
9830
9545
|
logError("discord component modal: missing modal id");
|
|
9831
|
-
|
|
9832
|
-
await interaction.reply({
|
|
9833
|
-
content: "This form is no longer valid.",
|
|
9834
|
-
ephemeral: true
|
|
9835
|
-
});
|
|
9836
|
-
} catch {}
|
|
9546
|
+
await replyUnavailableComponentInteraction(interaction, "This form is no longer valid.");
|
|
9837
9547
|
return;
|
|
9838
9548
|
}
|
|
9839
9549
|
const modalEntry = await resolveDiscordModalEntryWithPersistence({
|
|
@@ -9841,12 +9551,7 @@ var DiscordComponentModal = class extends Modal {
|
|
|
9841
9551
|
consume: false
|
|
9842
9552
|
});
|
|
9843
9553
|
if (!modalEntry) {
|
|
9844
|
-
|
|
9845
|
-
await interaction.reply({
|
|
9846
|
-
content: "This form has expired.",
|
|
9847
|
-
ephemeral: true
|
|
9848
|
-
});
|
|
9849
|
-
} catch {}
|
|
9554
|
+
await replyUnavailableComponentInteraction(interaction, "This form has expired.");
|
|
9850
9555
|
return;
|
|
9851
9556
|
}
|
|
9852
9557
|
const unauthorizedReply = "You are not authorized to use this form.";
|
|
@@ -9879,12 +9584,7 @@ var DiscordComponentModal = class extends Modal {
|
|
|
9879
9584
|
consume: !modalEntry.reusable
|
|
9880
9585
|
});
|
|
9881
9586
|
if (!consumed) {
|
|
9882
|
-
|
|
9883
|
-
await interaction.reply({
|
|
9884
|
-
content: "This form has expired.",
|
|
9885
|
-
ephemeral: true
|
|
9886
|
-
});
|
|
9887
|
-
} catch {}
|
|
9587
|
+
await replyUnavailableComponentInteraction(interaction, "This form has expired.");
|
|
9888
9588
|
return;
|
|
9889
9589
|
}
|
|
9890
9590
|
if (consumed.callbackData) {
|
|
@@ -9933,12 +9633,7 @@ async function runAgentSystemControlInteraction(params) {
|
|
|
9933
9633
|
const parsed = parseAgentComponentData(params.data);
|
|
9934
9634
|
if (!parsed) {
|
|
9935
9635
|
logError(`${params.label}: failed to parse component data`);
|
|
9936
|
-
|
|
9937
|
-
await params.interaction.reply({
|
|
9938
|
-
content: params.invalidReply,
|
|
9939
|
-
ephemeral: true
|
|
9940
|
-
});
|
|
9941
|
-
} catch {}
|
|
9636
|
+
await replyUnavailableComponentInteraction(params.interaction, params.invalidReply);
|
|
9942
9637
|
return;
|
|
9943
9638
|
}
|
|
9944
9639
|
const { componentId } = parsed;
|
|
@@ -9979,10 +9674,7 @@ async function runAgentSystemControlInteraction(params) {
|
|
|
9979
9674
|
userId
|
|
9980
9675
|
});
|
|
9981
9676
|
logDebug(`${params.label}: enqueuing event for channel ${channelId}: ${eventText}`);
|
|
9982
|
-
|
|
9983
|
-
sessionKey: route.sessionKey,
|
|
9984
|
-
contextKey: `${params.contextKeyPrefix}:${channelId}:${componentId}:${userId}`
|
|
9985
|
-
});
|
|
9677
|
+
enqueueRoutedSystemEvent$1(eventText, route, { contextKey: `${params.contextKeyPrefix}:${channelId}:${componentId}:${userId}:${params.interaction.id}` });
|
|
9986
9678
|
await ackComponentInteraction({
|
|
9987
9679
|
interaction: params.interaction,
|
|
9988
9680
|
replyOpts,
|
|
@@ -10237,7 +9929,7 @@ var ExecApprovalButton = class extends Button {
|
|
|
10237
9929
|
try {
|
|
10238
9930
|
await interaction.acknowledge();
|
|
10239
9931
|
} catch {}
|
|
10240
|
-
const result = await this.ctx.resolveApproval(parsed.approvalId, parsed.approvalKind, parsed.action);
|
|
9932
|
+
const result = await this.ctx.resolveApproval(parsed.approvalId, parsed.approvalKind, parsed.action, userId);
|
|
10241
9933
|
if (!result.ok) {
|
|
10242
9934
|
try {
|
|
10243
9935
|
await interaction.followUp({
|
|
@@ -10274,7 +9966,7 @@ function createDiscordExecApprovalButtonContext(params) {
|
|
|
10274
9966
|
accountId: params.accountId,
|
|
10275
9967
|
configOverride: params.config
|
|
10276
9968
|
}),
|
|
10277
|
-
resolveApproval: async (approvalId, approvalKind, decision) => {
|
|
9969
|
+
resolveApproval: async (approvalId, approvalKind, decision, senderId) => {
|
|
10278
9970
|
try {
|
|
10279
9971
|
return {
|
|
10280
9972
|
ok: true,
|
|
@@ -10283,8 +9975,10 @@ function createDiscordExecApprovalButtonContext(params) {
|
|
|
10283
9975
|
approvalId,
|
|
10284
9976
|
approvalKind,
|
|
10285
9977
|
decision,
|
|
10286
|
-
|
|
10287
|
-
|
|
9978
|
+
channel: "discord",
|
|
9979
|
+
accountId: params.accountId,
|
|
9980
|
+
senderId,
|
|
9981
|
+
gatewayUrl: params.gatewayUrl
|
|
10288
9982
|
})
|
|
10289
9983
|
};
|
|
10290
9984
|
} catch (err) {
|
|
@@ -10368,24 +10062,26 @@ function createDiscordQuestionButton(params) {
|
|
|
10368
10062
|
//#region extensions/discord/src/monitor/provider.interactions.ts
|
|
10369
10063
|
function createDiscordProviderInteractionSurface(params) {
|
|
10370
10064
|
const createNativeCommand = params.createNativeCommand ?? createDiscordNativeCommand;
|
|
10371
|
-
const commands = params.commandSpecs.map((spec) =>
|
|
10372
|
-
|
|
10373
|
-
|
|
10374
|
-
|
|
10375
|
-
|
|
10376
|
-
|
|
10377
|
-
|
|
10378
|
-
|
|
10379
|
-
|
|
10380
|
-
|
|
10381
|
-
|
|
10382
|
-
|
|
10383
|
-
|
|
10384
|
-
|
|
10385
|
-
|
|
10386
|
-
|
|
10387
|
-
|
|
10388
|
-
|
|
10065
|
+
const commands = params.commandSpecs.map((spec) => {
|
|
10066
|
+
if (params.nativeEnabled && params.voiceEnabled && spec.name === DISCORD_VOICE_COMMAND_SPEC.name) return createDiscordVoiceCommand({
|
|
10067
|
+
cfg: params.cfg,
|
|
10068
|
+
discordConfig: params.discordConfig,
|
|
10069
|
+
accountId: params.accountId,
|
|
10070
|
+
groupPolicy: params.groupPolicy,
|
|
10071
|
+
useAccessGroups: params.useAccessGroups,
|
|
10072
|
+
getManager: () => params.voiceManagerRef.current,
|
|
10073
|
+
ephemeralDefault: params.ephemeralDefault
|
|
10074
|
+
});
|
|
10075
|
+
return createNativeCommand({
|
|
10076
|
+
command: spec,
|
|
10077
|
+
cfg: params.cfg,
|
|
10078
|
+
discordConfig: params.discordConfig,
|
|
10079
|
+
accountId: params.accountId,
|
|
10080
|
+
sessionPrefix: params.sessionPrefix,
|
|
10081
|
+
ephemeralDefault: params.ephemeralDefault,
|
|
10082
|
+
threadBindings: params.threadBindings
|
|
10083
|
+
});
|
|
10084
|
+
});
|
|
10389
10085
|
const execApprovalsConfig = params.discordConfig.execApprovals ?? {};
|
|
10390
10086
|
const execApprovalsEnabled = isDiscordExecApprovalClientEnabled({
|
|
10391
10087
|
cfg: params.cfg,
|
|
@@ -10665,7 +10361,8 @@ function registerDiscordMonitorListeners(params) {
|
|
|
10665
10361
|
registerDiscordListener(params.client.listeners, new DiscordReactionListener(reactionListenerOptions));
|
|
10666
10362
|
registerDiscordListener(params.client.listeners, new DiscordReactionRemoveListener(reactionListenerOptions));
|
|
10667
10363
|
}
|
|
10668
|
-
registerDiscordListener(params.client.listeners, new DiscordThreadUpdateListener(params.cfg, params.
|
|
10364
|
+
registerDiscordListener(params.client.listeners, new DiscordThreadUpdateListener(params.cfg, params.logger));
|
|
10365
|
+
registerDiscordListener(params.client.listeners, new DiscordThreadDeleteListener(params.cfg, params.accountId, params.logger));
|
|
10669
10366
|
if (params.discordConfig.intents?.presence) {
|
|
10670
10367
|
const presenceListener = new DiscordPresenceListener({
|
|
10671
10368
|
cfg: params.cfg,
|
|
@@ -10866,8 +10563,31 @@ async function monitorDiscordProvider(opts = {}) {
|
|
|
10866
10563
|
phase: "fetch-application-id:start",
|
|
10867
10564
|
startAt: startupStartedAt
|
|
10868
10565
|
});
|
|
10869
|
-
const
|
|
10870
|
-
|
|
10566
|
+
const parsedApplicationId = (typeof discordCfg.applicationId === "string" && discordCfg.applicationId.trim() ? discordCfg.applicationId.trim() : void 0) ?? parseApplicationIdFromToken(token);
|
|
10567
|
+
const applicationIdProbe = parsedApplicationId ? {
|
|
10568
|
+
kind: "resolved",
|
|
10569
|
+
applicationId: parsedApplicationId
|
|
10570
|
+
} : await discordProviderRuntime.probeDiscordApplicationId(token, 4e3, discordRestFetch);
|
|
10571
|
+
if (applicationIdProbe.kind !== "resolved") {
|
|
10572
|
+
const at = Date.now();
|
|
10573
|
+
const terminal = applicationIdProbe.kind === "rejected";
|
|
10574
|
+
const probeError = formatErrorMessage$1(applicationIdProbe.error);
|
|
10575
|
+
const message = `Failed to resolve Discord application id: ${probeError}`;
|
|
10576
|
+
opts.setStatus?.({
|
|
10577
|
+
connected: false,
|
|
10578
|
+
lifecycle: terminal ? "blocked" : "recovering",
|
|
10579
|
+
terminalDisconnect: terminal ? true : void 0,
|
|
10580
|
+
lastEventAt: at,
|
|
10581
|
+
lastDisconnect: {
|
|
10582
|
+
at,
|
|
10583
|
+
...applicationIdProbe.status !== null ? { status: applicationIdProbe.status } : {},
|
|
10584
|
+
error: probeError
|
|
10585
|
+
},
|
|
10586
|
+
lastError: message
|
|
10587
|
+
});
|
|
10588
|
+
throw new Error(message, { cause: applicationIdProbe.error });
|
|
10589
|
+
}
|
|
10590
|
+
const applicationId = applicationIdProbe.applicationId;
|
|
10871
10591
|
logDiscordStartupPhase({
|
|
10872
10592
|
runtime,
|
|
10873
10593
|
accountId: account.accountId,
|
|
@@ -10880,9 +10600,9 @@ async function monitorDiscordProvider(opts = {}) {
|
|
|
10880
10600
|
runtime,
|
|
10881
10601
|
nativeEnabled,
|
|
10882
10602
|
nativeSkillsEnabled,
|
|
10603
|
+
voiceEnabled,
|
|
10883
10604
|
listSkillCommandsForAgents: discordProviderRuntime.listSkillCommandsForAgents,
|
|
10884
|
-
listNativeCommandSpecsForConfig: discordProviderRuntime.listNativeCommandSpecsForConfig
|
|
10885
|
-
getPluginCommandSpecs: discordProviderRuntime.getPluginCommandSpecs
|
|
10605
|
+
listNativeCommandSpecsForConfig: discordProviderRuntime.listNativeCommandSpecsForConfig
|
|
10886
10606
|
});
|
|
10887
10607
|
const voiceManagerRef = { current: null };
|
|
10888
10608
|
const threadBindings = threadBindingsEnabled ? discordProviderSessionRuntime.createThreadBindingManager({
|
|
@@ -11014,7 +10734,7 @@ async function monitorDiscordProvider(opts = {}) {
|
|
|
11014
10734
|
runtime,
|
|
11015
10735
|
botUserId
|
|
11016
10736
|
});
|
|
11017
|
-
const { setDiscordTranscriptsVoiceManager } = await import("./transcripts-source-
|
|
10737
|
+
const { setDiscordTranscriptsVoiceManager } = await import("./transcripts-source-CfFMexGt.js").then((n) => n.n);
|
|
11018
10738
|
setDiscordTranscriptsVoiceManager({
|
|
11019
10739
|
accountId: account.accountId,
|
|
11020
10740
|
manager: voiceManager
|
|
@@ -11032,6 +10752,7 @@ async function monitorDiscordProvider(opts = {}) {
|
|
|
11032
10752
|
accountId: account.accountId,
|
|
11033
10753
|
token,
|
|
11034
10754
|
runtime,
|
|
10755
|
+
buildContext: opts.channelRuntime?.inbound.buildContext,
|
|
11035
10756
|
setStatus: opts.setStatus,
|
|
11036
10757
|
abortSignal: opts.abortSignal,
|
|
11037
10758
|
botUserId,
|
|
@@ -11087,7 +10808,7 @@ async function monitorDiscordProvider(opts = {}) {
|
|
|
11087
10808
|
gatewayReady: lifecycleGateway?.isConnected === true,
|
|
11088
10809
|
botIdentity: botIdentity || void 0
|
|
11089
10810
|
}));
|
|
11090
|
-
if (lifecycleGateway?.isConnected) opts.setStatus?.(
|
|
10811
|
+
if (lifecycleGateway?.isConnected) opts.setStatus?.(createDiscordReadyStatusPatch());
|
|
11091
10812
|
lifecycleStarted = true;
|
|
11092
10813
|
earlyGatewayEmitter?.removeListener("debug", onEarlyGatewayDebug);
|
|
11093
10814
|
onEarlyGatewayDebug = void 0;
|