@openclaw/discord 2026.5.12 → 2026.5.14-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-D7jL5YDH.js → account-inspect-B_N30NV0.js} +1 -1
- package/dist/account-inspect-api.js +1 -1
- package/dist/{accounts-BcwyaFd-.js → accounts-DnNVBDfc.js} +95 -4
- package/dist/action-runtime-api.js +1 -1
- package/dist/{allow-list-n8Ki-Rt3.js → allow-list-CBI-M84K.js} +24 -2
- package/dist/api.js +19 -21
- package/dist/{approval-handler.runtime-S-ircYcz.js → approval-handler.runtime-Uco62pII.js} +4 -4
- package/dist/{audit-BliEqCEc.js → audit-eSlKbMHw.js} +5 -5
- package/dist/{channel-Bliqi-Qi.js → channel-BjBa8nYY.js} +23 -25
- package/dist/{channel-actions-Cn_K00Vy.js → channel-actions-DANVAtKL.js} +4 -4
- package/dist/{channel-actions.runtime-DcsRvPnx.js → channel-actions.runtime-CpIslHS9.js} +7 -5
- package/dist/channel-config-api.js +1 -1
- package/dist/channel-plugin-api.js +1 -1
- package/dist/{channel.setup-DR-xVYso.js → channel.setup-DBFcGRFD.js} +4 -5
- package/dist/{components-Dxq2mU57.js → components-Cgm7XT8-.js} +120 -3
- package/dist/{config-schema-D2KGskAp.js → config-schema-D7AtCpJa.js} +21 -1
- package/dist/contract-api.js +7 -7
- package/dist/{approval-native-Gtqpyfdj.js → conversation-identity-C3AI-1tz.js} +123 -6
- package/dist/{directory-config-CDl4JTCA.js → directory-config-CW_JusGS.js} +2 -2
- package/dist/directory-contract-api.js +1 -1
- package/dist/directory-live-MrDSKsMf.js +159 -0
- package/dist/doctor-contract-api.js +1 -1
- package/dist/{doctor-contract-BGjjFBdq.js → doctor-contract-ftWAMvBl.js} +1 -1
- package/dist/{doctor-jcX_qXsS.js → doctor-mn2XyjuF.js} +5 -5
- package/dist/{handle-action.guild-admin-C4phin-a.js → handle-action.guild-admin-DriifPwO.js} +1 -1
- package/dist/{inbound-context-jtKcY9on.js → inbound-context-DD7n3Q6U.js} +1 -1
- package/dist/{manager.runtime-DqMGETqp.js → manager.runtime-DauS2xA3.js} +107 -25
- package/dist/{message-handler-DIsnboy2.js → message-handler-CMHwRlxG.js} +7 -7
- package/dist/{message-handler.preflight-BRH-dv1o.js → message-handler.preflight-C0sT-ewp.js} +27 -17
- package/dist/{message-handler.process-Bs5wropA.js → message-handler.process-Cy7_-0H0.js} +46 -37
- package/dist/{message-utils-ByofKwPe.js → message-utils-N5UTOXQ2.js} +16 -12
- package/dist/{outbound-adapter-lWjkSeyP.js → outbound-adapter-Cw9JsRTY.js} +7 -10
- package/dist/{pluralkit-B1HTaBc9.js → pluralkit-B2AqgTHV.js} +1 -1
- package/dist/{preflight-audio-CD97vnac.js → preflight-audio-DFGpAvzi.js} +1 -1
- package/dist/{probe-BZtr8qle.js → probe-CiBYm-vD.js} +2 -2
- package/dist/{probe.runtime-0F0UzBoJ.js → probe.runtime-9hi1GYNU.js} +1 -1
- package/dist/{provider-DABvNRT0.js → provider-nzJg2k5t.js} +1039 -45
- package/dist/{provider-session.runtime-BZyP90-i.js → provider-session.runtime-DMxaLPB3.js} +3 -3
- package/dist/provider.runtime-S-wZdzK5.js +2 -0
- package/dist/{resolve-allowlist-common-CVHYb5Hb.js → resolve-allowlist-common-DybgkAjk.js} +3 -3
- package/dist/{resolve-channels-JNt3Ak6P.js → resolve-channels-u7_agBcm.js} +4 -4
- package/dist/{resolve-users-CrjbUxrL.js → resolve-users-Bc25I6OP.js} +3 -3
- package/dist/{runtime-CdnAT8R5.js → runtime-DL82ijB1.js} +102 -46
- package/dist/runtime-api.actions.js +2 -2
- package/dist/runtime-api.js +25 -26
- package/dist/runtime-api.lookup.js +6 -6
- package/dist/runtime-api.monitor-DbLcHuhE.js +5 -0
- package/dist/runtime-api.monitor.js +7 -8
- package/dist/runtime-api.send.js +5 -5
- package/dist/runtime-api.threads.js +5 -5
- package/dist/runtime-setter-api.js +1 -1
- package/dist/secret-contract-api.js +1 -1
- package/dist/{security-audit-BQ_sGK3J.js → security-audit-CLPZKYi4.js} +1 -1
- package/dist/security-audit-contract-api.js +1 -1
- package/dist/{security-audit.runtime-B7Gmz2DX.js → security-audit.runtime-CCm9leFJ.js} +1 -1
- package/dist/security-contract-api.js +1 -1
- package/dist/{send-DCFuSiBi.js → send-BqzTEkt9.js} +4 -6
- package/dist/{send.components-DxDqPJZQ.js → send.components-D6pXHVrU.js} +8 -10
- package/dist/{send.outbound-PM0J0F60.js → send.outbound-D8o8BW6q.js} +91 -7
- package/dist/{discord-BqYcwxvG.js → send.receipt-nKLxvA1s.js} +319 -1
- package/dist/{send.shared-Dza0jdso.js → send.shared-DSpva7uA.js} +4 -6
- package/dist/{sender-identity-w9rSI-nD.js → sender-identity-BTGL3VbF.js} +1 -1
- package/dist/session-key-api.js +1 -1
- package/dist/setup-plugin-api.js +1 -1
- package/dist/{shared-Yp_M6Cfp.js → shared-0kdaIxXP.js} +16 -14
- package/dist/{subagent-hooks-CtN-hfXy.js → subagent-hooks-DhuBhwRw.js} +3 -3
- package/dist/subagent-hooks-api.js +1 -1
- package/dist/{system-events-B04UOvPg.js → system-events-Bnit0zkQ.js} +2 -2
- package/dist/{target-resolver-CgJei-kD.js → target-resolver-BsGT9hI7.js} +3 -6
- package/dist/targets-DwW6OieO.js +3 -0
- package/dist/test-api.js +4 -4
- package/dist/{thread-bindings-B4of4OmR.js → thread-bindings-C1f7Iim4.js} +6 -7
- package/dist/{thread-bindings.discord-api-BAw15EQb.js → thread-bindings.discord-api-DJACBZJ1.js} +67 -8
- package/dist/{thread-bindings.manager-DNFl10CA.js → thread-bindings.manager-DN_q0IW7.js} +4 -5
- package/dist/{thread-bindings.session-updates-D18cCLmN.js → thread-bindings.session-updates-ZnRRzzgf.js} +1 -1
- package/dist/timeouts.js +1 -1
- package/dist/{typing-_jePdFIw.js → typing-C_8U8J7E.js} +2 -2
- package/openclaw.plugin.json +68 -0
- package/package.json +6 -6
- package/dist/access-Dxmzr0ix.js +0 -89
- package/dist/approval-shared-BFnWKSQD.js +0 -93
- package/dist/channel-access-BL-wemES.js +0 -62
- package/dist/chunk-DYl-_5RL.js +0 -179
- package/dist/conversation-identity-CvIx6J7M.js +0 -31
- package/dist/directory-cache-Ddl-Oxue.js +0 -62
- package/dist/directory-live-ApUXOSj0.js +0 -101
- package/dist/doctor-shared-D_QLzu30.js +0 -4
- package/dist/format-D8TsaXxW.js +0 -24
- package/dist/mentions-BZoGn0ul.js +0 -88
- package/dist/normalize-Cu94FOqy.js +0 -58
- package/dist/outbound-session-route-BaJRt05p.js +0 -43
- package/dist/provider.runtime-Cmv1SFtb.js +0 -2
- package/dist/reply-delivery-CUSK6SA_.js +0 -191
- package/dist/route-resolution-BFfF9xmG.js +0 -268
- package/dist/runtime-api.monitor-W_dJ5EQu.js +0 -6
- package/dist/send.receipt-BAZw2Zsz.js +0 -35
- package/dist/shared-interactive-DavY6jYt.js +0 -79
- package/dist/target-parsing-D-H7nnh2.js +0 -51
- package/dist/targets-DToZUkgV.js +0 -3
- package/dist/threading-CLZ3v7-y.js +0 -475
- package/dist/token-BZtonk7d.js +0 -93
- /package/dist/{agent-components.runtime-zT8qPsnM.js → agent-components.runtime-CEMbMQcQ.js} +0 -0
- /package/dist/{api-DzNBVTto.js → api-DgQLz1wq.js} +0 -0
- /package/dist/{audit-core-BgDZSkIR.js → audit-core-DRyoXREU.js} +0 -0
- /package/dist/{channel-api-CTSWMrnD.js → channel-api-JudoSiJv.js} +0 -0
- /package/dist/{config-api-CFZtoMaS.js → config-api-oLS_52S7.js} +0 -0
- /package/dist/{gateway-registry-BKG4KIVC.js → gateway-registry-BKSpa4GB.js} +0 -0
- /package/dist/{preflight-audio.runtime-fXnUxxBa.js → preflight-audio.runtime-Drc-OFcp.js} +0 -0
- /package/dist/{preview-streaming-DCPAe24T.js → preview-streaming-CXTZydhx.js} +0 -0
- /package/dist/{runtime-BqCoo-zp.js → runtime-Tqtvj5GX.js} +0 -0
- /package/dist/{secret-config-contract-BCQNNS7N.js → secret-config-contract-B3347_eU.js} +0 -0
- /package/dist/{security-contract-DkCMKSvb.js → security-contract-DyCRvz_Q.js} +0 -0
- /package/dist/{security-doctor-BJH5YIGL.js → security-doctor-Cp-NqNdS.js} +0 -0
- /package/dist/{session-contract-D871HDFG.js → session-contract-ugfEa9Xc.js} +0 -0
- /package/dist/{session-key-normalization-BV82IME9.js → session-key-normalization-B7h83qD2.js} +0 -0
- /package/dist/{thread-bindings.state-SPlv6mh7.js → thread-bindings.state-BdBeo7Rx.js} +0 -0
- /package/dist/{timeouts-C3FYXWJX.js → timeouts-snXNwR4m.js} +0 -0
|
@@ -1,35 +1,26 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import { a as resolveDiscordComponentEntryWithPersistence, o as resolveDiscordModalEntryWithPersistence, t as editDiscordComponentMessage } from "./send.components-
|
|
5
|
-
import { c as setPresence, i as unregisterGateway, r as registerGateway } from "./gateway-registry-
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import { a as
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
import { t as
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
14
|
-
import "./
|
|
15
|
-
import { t as
|
|
16
|
-
import {
|
|
17
|
-
import { t as
|
|
18
|
-
import {
|
|
19
|
-
import {
|
|
20
|
-
import
|
|
21
|
-
import { o as raceWithTimeout, s as withAbortTimeout } from "./timeouts-C3FYXWJX.js";
|
|
22
|
-
import { i as resolveDiscordEffectiveRoute, n as resolveDiscordBoundConversationRoute, o as handleDiscordDmCommandDecision, s as resolveDiscordDmCommandAccess } from "./route-resolution-BFfF9xmG.js";
|
|
23
|
-
import { c as resolveDiscordChannelInfo } from "./message-utils-ByofKwPe.js";
|
|
24
|
-
import { i as resolveDiscordThreadParentInfo } from "./threading-CLZ3v7-y.js";
|
|
25
|
-
import { t as resolveDiscordSenderIdentity } from "./sender-identity-w9rSI-nD.js";
|
|
26
|
-
import { n as buildDiscordInboundAccessContext, t as buildDiscordGroupSystemPrompt } from "./inbound-context-jtKcY9on.js";
|
|
27
|
-
import { n as resolveDiscordVoiceEnabled, t as authorizeDiscordVoiceIngress } from "./access-Dxmzr0ix.js";
|
|
28
|
-
import { n as buildDirectLabel, r as buildGuildLabel, t as deliverDiscordReply } from "./reply-delivery-CUSK6SA_.js";
|
|
29
|
-
import "./approval-handler.runtime-S-ircYcz.js";
|
|
1
|
+
import { $ as BaseMessageInteractiveComponent, A as Message, B as Container, C as RateLimitError, D as Command, F as Modal, J as Separator, K as Row, O as CommandWithSubcommands, R as Button, Wt as __exportAll, X as TextDisplay, Y as StringSelectMenu, b as Plugin, c as discord_exports, ct as createThread, d as MessageReactionAddListener, dt as editChannel, f as MessageReactionRemoveListener, g as ThreadUpdateListener, j as User, k as Guild, l as InteractionCreateListener, m as ReadyListener, mt as getChannelMessage, p as PresenceUpdateListener, s as chunkDiscordTextWithMode, u as MessageCreateListener, y as Client } from "./send.receipt-nKLxvA1s.js";
|
|
2
|
+
import { c as resolveDiscordAccountAllowFrom, d as resolveDiscordAccountDmPolicy, f as resolveDiscordMaxLinesPerMessage, p as normalizeDiscordToken, s as resolveDiscordAccount } from "./accounts-DnNVBDfc.js";
|
|
3
|
+
import { _ as parseDiscordComponentCustomId, b as parseDiscordModalCustomIdForInteraction, v as parseDiscordComponentCustomIdForInteraction, y as parseDiscordModalCustomId } from "./components-Cgm7XT8-.js";
|
|
4
|
+
import { a as resolveDiscordComponentEntryWithPersistence, o as resolveDiscordModalEntryWithPersistence, t as editDiscordComponentMessage } from "./send.components-D6pXHVrU.js";
|
|
5
|
+
import { c as setPresence, i as unregisterGateway, r as registerGateway } from "./gateway-registry-BKSpa4GB.js";
|
|
6
|
+
import { I as DISCORD_REST_TIMEOUT_MS, L as validateDiscordProxyUrl, M as createDiscordRestClient, R as withValidatedDiscordProxy, w as canViewDiscordGuildChannel } from "./send.shared-DSpva7uA.js";
|
|
7
|
+
import { a as summarizeDiscordResponseBody, i as isDiscordRateLimitResponseBody } from "./api-DgQLz1wq.js";
|
|
8
|
+
import { S as resolveTimestampMs, _ as resolveGroupDmAllow, a as normalizeDiscordSlug, b as formatDiscordUserTag, c as resolveDiscordChannelConfigWithFallback, d as resolveDiscordGuildEntry, f as resolveDiscordMemberAccessState, i as normalizeDiscordDisplaySlug, l as resolveDiscordChannelPolicyCommandAuthorizer, m as resolveDiscordOwnerAccess, n as isDiscordGroupAllowedByPolicy, o as resolveDiscordAllowListMatch, r as normalizeDiscordAllowList, v as shouldEmitDiscordReactionNotification, y as formatDiscordReactionEmoji } from "./allow-list-CBI-M84K.js";
|
|
9
|
+
import { s as sendVoiceMessageDiscord } from "./send-BqzTEkt9.js";
|
|
10
|
+
import { i as formatMention, t as sendMessageDiscord } from "./send.outbound-D8o8BW6q.js";
|
|
11
|
+
import { a as getDiscordExecApprovalApprovers, s as isDiscordExecApprovalClientEnabled, t as resolveDiscordConversationIdentity } from "./conversation-identity-C3AI-1tz.js";
|
|
12
|
+
import { t as resolveDiscordChannelAllowlist } from "./resolve-channels-u7_agBcm.js";
|
|
13
|
+
import { t as resolveDiscordUserAllowlist } from "./resolve-users-Bc25I6OP.js";
|
|
14
|
+
import { _ as formatThreadBindingDurationLabel, a as isThreadArchived, d as resolveDiscordChannelNameSafe, f as resolveDiscordChannelParentIdSafe, l as resolveDiscordChannelIdSafe, m as resolveDiscordChannelTopicSafe, p as resolveDiscordChannelParentSafe, u as resolveDiscordChannelInfoSafe } from "./thread-bindings.discord-api-DJACBZJ1.js";
|
|
15
|
+
import { r as parseApplicationIdFromToken, t as fetchDiscordApplicationId } from "./probe-CiBYm-vD.js";
|
|
16
|
+
import { o as raceWithTimeout, s as withAbortTimeout } from "./timeouts-snXNwR4m.js";
|
|
17
|
+
import { c as resolveDiscordChannelInfo, l as resolveDiscordMessageChannelId, n as resolveDiscordForwardedMessagesTextFromSnapshots, t as resolveDiscordEmbedText } from "./message-utils-N5UTOXQ2.js";
|
|
18
|
+
import { t as resolveDiscordSenderIdentity } from "./sender-identity-BTGL3VbF.js";
|
|
19
|
+
import { n as buildDiscordInboundAccessContext, t as buildDiscordGroupSystemPrompt } from "./inbound-context-DD7n3Q6U.js";
|
|
20
|
+
import "./approval-handler.runtime-Uco62pII.js";
|
|
30
21
|
import { normalizeAccountId } from "openclaw/plugin-sdk/account-id";
|
|
31
|
-
import { normalizeLowercaseStringOrEmpty, normalizeOptionalLowercaseString, normalizeOptionalString, normalizeStringEntries, summarizeStringEntries } from "openclaw/plugin-sdk/string-coerce-runtime";
|
|
32
|
-
import { resolveAgentRoute } from "openclaw/plugin-sdk/routing";
|
|
22
|
+
import { normalizeLowercaseStringOrEmpty, normalizeOptionalLowercaseString, normalizeOptionalString, normalizeOptionalStringifiedId, normalizeStringEntries, summarizeStringEntries } from "openclaw/plugin-sdk/string-coerce-runtime";
|
|
23
|
+
import { buildAgentSessionKey, deriveLastRoutePolicy, isAcpSessionKey, isSubagentSessionKey, parseAgentSessionKey, resolveAgentIdFromSessionKey, resolveAgentRoute } from "openclaw/plugin-sdk/routing";
|
|
33
24
|
import { getRuntimeConfig } from "openclaw/plugin-sdk/runtime-config-snapshot";
|
|
34
25
|
import { ApplicationCommandOptionType, ButtonStyle, ChannelType, ComponentType, GatewayCloseCodes, GatewayCloseCodes as GatewayCloseCodes$1, GatewayDispatchEvents, GatewayIntentBits, GatewayOpcodes } from "discord-api-types/v10";
|
|
35
26
|
import { randomUUID } from "node:crypto";
|
|
@@ -46,24 +37,27 @@ import { wrapFetchWithAbortSignal } from "openclaw/plugin-sdk/fetch-runtime";
|
|
|
46
37
|
import { createNonExitingRuntime, createSubsystemLogger, danger, formatDurationSeconds, isVerbose, logVerbose, shouldLogVerbose, warn } from "openclaw/plugin-sdk/runtime-env";
|
|
47
38
|
import { formatErrorMessage } from "openclaw/plugin-sdk/error-runtime";
|
|
48
39
|
import { resolveMarkdownTableMode } from "openclaw/plugin-sdk/markdown-table-runtime";
|
|
49
|
-
import { chunkItems } from "openclaw/plugin-sdk/text-chunking";
|
|
50
|
-
import { createChannelMessageReplyPipeline } from "openclaw/plugin-sdk/channel-message";
|
|
40
|
+
import { chunkItems, sanitizeAssistantVisibleText } from "openclaw/plugin-sdk/text-chunking";
|
|
41
|
+
import { createChannelMessageReplyPipeline, sendDurableMessageBatch } from "openclaw/plugin-sdk/channel-message";
|
|
51
42
|
import { fetchWithSsrFGuard, formatErrorMessage as formatErrorMessage$1 } from "openclaw/plugin-sdk/ssrf-runtime";
|
|
52
43
|
import { createChannelPairingChallengeIssuer } from "openclaw/plugin-sdk/channel-pairing";
|
|
53
44
|
import { CHANNEL_APPROVAL_NATIVE_RUNTIME_CONTEXT_CAPABILITY } from "openclaw/plugin-sdk/approval-handler-adapter-runtime";
|
|
54
45
|
import { readJsonFileWithFallback, writeJsonFileAtomically } from "openclaw/plugin-sdk/json-store";
|
|
55
46
|
import { resolveStateDir } from "openclaw/plugin-sdk/state-paths";
|
|
47
|
+
import { buildOutboundSessionContext } from "openclaw/plugin-sdk/outbound-runtime";
|
|
56
48
|
import { addAllowlistUserEntriesFromConfigEntry, buildAllowlistResolutionSummary, canonicalizeAllowlistWithResolvedIds, patchAllowlistUsersInConfigEntries, summarizeMapping } from "openclaw/plugin-sdk/allow-from";
|
|
57
49
|
import { resolveChannelStreamingBlockEnabled } from "openclaw/plugin-sdk/channel-streaming";
|
|
58
|
-
import { buildPairingReply, upsertChannelPairingRequest as upsertChannelPairingRequest$1 } from "openclaw/plugin-sdk/conversation-runtime";
|
|
59
|
-
import { clearExpiredCooldowns, ensureAuthProfileStore, isProfileInCooldown, resolveDefaultModelForAgent, resolveHumanDelayConfig, resolveProfilesUnavailableReason } from "openclaw/plugin-sdk/agent-runtime";
|
|
50
|
+
import { buildPairingReply, upsertChannelPairingRequest, upsertChannelPairingRequest as upsertChannelPairingRequest$1 } from "openclaw/plugin-sdk/conversation-runtime";
|
|
51
|
+
import { clearExpiredCooldowns, ensureAuthProfileStore, isProfileInCooldown, resolveAgentAvatar, resolveDefaultModelForAgent, resolveHumanDelayConfig, resolveProfilesUnavailableReason } from "openclaw/plugin-sdk/agent-runtime";
|
|
60
52
|
import { GROUP_POLICY_BLOCKED_LABEL, resolveDefaultGroupPolicy, resolveOpenProviderRuntimeGroupPolicy, warnMissingProviderGroupPolicyFallbackOnce } from "openclaw/plugin-sdk/runtime-group-policy";
|
|
61
|
-
import { withTimeout } from "openclaw/plugin-sdk/text-utility-runtime";
|
|
53
|
+
import { truncateUtf16Safe, withTimeout } from "openclaw/plugin-sdk/text-utility-runtime";
|
|
62
54
|
import { isDangerousNameMatchingEnabled } from "openclaw/plugin-sdk/dangerous-name-runtime";
|
|
63
55
|
import { resolveNativeCommandsEnabled, resolveNativeSkillsEnabled } from "openclaw/plugin-sdk/native-command-config-runtime";
|
|
64
56
|
import { enqueueSystemEvent, enqueueSystemEvent as enqueueSystemEvent$1 } from "openclaw/plugin-sdk/system-event-runtime";
|
|
65
|
-
import { readChannelIngressStoreAllowFromForDmPolicy } from "openclaw/plugin-sdk/channel-ingress-runtime";
|
|
66
|
-
import { applyModelOverrideToSessionEntry } from "openclaw/plugin-sdk/model-session-runtime";
|
|
57
|
+
import { createChannelIngressResolver, defineStableChannelIngressIdentity, readChannelIngressStoreAllowFromForDmPolicy } from "openclaw/plugin-sdk/channel-ingress-runtime";
|
|
58
|
+
import { applyModelOverrideToSessionEntry, resolveChannelModelOverride } from "openclaw/plugin-sdk/model-session-runtime";
|
|
59
|
+
import { completeWithPreparedSimpleCompletionModel, extractAssistantText, prepareSimpleCompletionModelForAgent } from "openclaw/plugin-sdk/simple-completion-runtime";
|
|
60
|
+
import { createReplyReferencePlanner } from "openclaw/plugin-sdk/reply-reference";
|
|
67
61
|
import { loadSessionStore, readSessionUpdatedAt as readSessionUpdatedAt$1, resolveStorePath, resolveStorePath as resolveStorePath$1, updateSessionStore } from "openclaw/plugin-sdk/session-store-runtime";
|
|
68
62
|
import { formatInboundEnvelope, resolveEnvelopeFormatOptions } from "openclaw/plugin-sdk/channel-inbound";
|
|
69
63
|
import { buildCommandTextFromArgs, findCommandByNativeName, formatCommandArgMenuTitle, listChatCommands, listNativeCommandSpecsForConfig, listSkillCommandsForAgents, resolveCommandAuthorizedFromAuthorizers, resolveNativeCommandSessionTargets, resolveStoredModelOverride, serializeCommandArgs } from "openclaw/plugin-sdk/command-auth-native";
|
|
@@ -147,6 +141,628 @@ async function runDiscordListenerWithSlowLog(params) {
|
|
|
147
141
|
}
|
|
148
142
|
}
|
|
149
143
|
//#endregion
|
|
144
|
+
//#region extensions/discord/src/monitor/dm-command-auth.ts
|
|
145
|
+
const DISCORD_ALLOW_LIST_PREFIXES = [
|
|
146
|
+
"discord:",
|
|
147
|
+
"user:",
|
|
148
|
+
"pk:"
|
|
149
|
+
];
|
|
150
|
+
const DISCORD_CHANNEL_ID = "discord";
|
|
151
|
+
const DISCORD_USER_ID_KIND = "stable-id";
|
|
152
|
+
const DISCORD_USER_NAME_KIND = "username";
|
|
153
|
+
function normalizeDiscordIdEntry(entry) {
|
|
154
|
+
const text = entry.trim();
|
|
155
|
+
if (!text) return null;
|
|
156
|
+
const maybeId = text.replace(/^<@!?/, "").replace(/>$/, "");
|
|
157
|
+
if (/^\d+$/.test(maybeId)) return maybeId;
|
|
158
|
+
const prefix = DISCORD_ALLOW_LIST_PREFIXES.find((entryPrefix) => text.startsWith(entryPrefix));
|
|
159
|
+
if (prefix) return text.slice(prefix.length).trim() || null;
|
|
160
|
+
return null;
|
|
161
|
+
}
|
|
162
|
+
function normalizeDiscordNameEntry(entry) {
|
|
163
|
+
const text = entry.trim();
|
|
164
|
+
if (!text || text === "*" || normalizeDiscordIdEntry(text)) return null;
|
|
165
|
+
const nameSlug = normalizeDiscordAllowList([text], DISCORD_ALLOW_LIST_PREFIXES)?.names.values().next().value;
|
|
166
|
+
return typeof nameSlug === "string" && nameSlug ? nameSlug : null;
|
|
167
|
+
}
|
|
168
|
+
function normalizeDiscordNameSubject(value) {
|
|
169
|
+
const nameSlug = normalizeDiscordAllowList([value], DISCORD_ALLOW_LIST_PREFIXES)?.names.values().next().value;
|
|
170
|
+
return typeof nameSlug === "string" && nameSlug ? nameSlug : null;
|
|
171
|
+
}
|
|
172
|
+
const discordIngressIdentity = defineStableChannelIngressIdentity({
|
|
173
|
+
key: "discordUserId",
|
|
174
|
+
kind: DISCORD_USER_ID_KIND,
|
|
175
|
+
normalizeEntry: normalizeDiscordIdEntry,
|
|
176
|
+
normalizeSubject: (value) => value.trim() || null,
|
|
177
|
+
sensitivity: "pii",
|
|
178
|
+
aliases: [["discordUserName", normalizeDiscordNameEntry], ["discordUserTag", () => null]].map(([key, normalizeEntry]) => ({
|
|
179
|
+
key,
|
|
180
|
+
kind: DISCORD_USER_NAME_KIND,
|
|
181
|
+
normalizeEntry,
|
|
182
|
+
normalizeSubject: normalizeDiscordNameSubject,
|
|
183
|
+
dangerous: true,
|
|
184
|
+
sensitivity: "pii"
|
|
185
|
+
}))
|
|
186
|
+
});
|
|
187
|
+
function createDiscordDmIngressSubject(sender) {
|
|
188
|
+
return {
|
|
189
|
+
stableId: sender.id,
|
|
190
|
+
aliases: {
|
|
191
|
+
discordUserName: sender.name,
|
|
192
|
+
discordUserTag: sender.tag
|
|
193
|
+
}
|
|
194
|
+
};
|
|
195
|
+
}
|
|
196
|
+
function createDiscordDynamicAccessGroupResolver(params) {
|
|
197
|
+
if (!params.cfg) return;
|
|
198
|
+
const cfg = params.cfg;
|
|
199
|
+
return async ({ name, group, accountId, subject }) => {
|
|
200
|
+
if (group.type !== "discord.channelAudience") return false;
|
|
201
|
+
const senderId = String(subject.stableId ?? "").trim();
|
|
202
|
+
if (!senderId) return false;
|
|
203
|
+
if ((group.membership ?? "canViewChannel") !== "canViewChannel") return false;
|
|
204
|
+
try {
|
|
205
|
+
return await canViewDiscordGuildChannel(group.guildId, group.channelId, senderId, {
|
|
206
|
+
cfg,
|
|
207
|
+
accountId,
|
|
208
|
+
token: params.token,
|
|
209
|
+
rest: params.rest
|
|
210
|
+
});
|
|
211
|
+
} catch (err) {
|
|
212
|
+
logVerbose(`discord: accessGroup:${name} lookup failed for user ${senderId}: ${String(err)}`);
|
|
213
|
+
throw err;
|
|
214
|
+
}
|
|
215
|
+
};
|
|
216
|
+
}
|
|
217
|
+
function createDiscordIngressResolver(params) {
|
|
218
|
+
return createChannelIngressResolver({
|
|
219
|
+
channelId: DISCORD_CHANNEL_ID,
|
|
220
|
+
accountId: params.accountId,
|
|
221
|
+
identity: discordIngressIdentity,
|
|
222
|
+
cfg: params.cfg,
|
|
223
|
+
resolveAccessGroupMembership: createDiscordDynamicAccessGroupResolver({
|
|
224
|
+
cfg: params.cfg,
|
|
225
|
+
token: params.token,
|
|
226
|
+
rest: params.rest
|
|
227
|
+
}),
|
|
228
|
+
...params.readStoreAllowFrom ? { readStoreAllowFrom: params.readStoreAllowFrom } : {},
|
|
229
|
+
...params.useDefaultPairingStore !== void 0 ? { useDefaultPairingStore: params.useDefaultPairingStore } : {}
|
|
230
|
+
});
|
|
231
|
+
}
|
|
232
|
+
function syntheticAccessGroupMembership(groupName, allowed) {
|
|
233
|
+
return allowed ? {
|
|
234
|
+
kind: "matched",
|
|
235
|
+
groupName,
|
|
236
|
+
source: "dynamic",
|
|
237
|
+
matchedEntryIds: [groupName]
|
|
238
|
+
} : {
|
|
239
|
+
kind: "not-matched",
|
|
240
|
+
groupName,
|
|
241
|
+
source: "dynamic"
|
|
242
|
+
};
|
|
243
|
+
}
|
|
244
|
+
async function resolveDiscordDmCommandAccess(params) {
|
|
245
|
+
return await createDiscordIngressResolver({
|
|
246
|
+
accountId: params.accountId,
|
|
247
|
+
cfg: params.cfg,
|
|
248
|
+
token: params.token,
|
|
249
|
+
rest: params.rest,
|
|
250
|
+
readStoreAllowFrom: params.readStoreAllowFrom,
|
|
251
|
+
useDefaultPairingStore: params.readStoreAllowFrom == null
|
|
252
|
+
}).message({
|
|
253
|
+
subject: createDiscordDmIngressSubject(params.sender),
|
|
254
|
+
conversation: {
|
|
255
|
+
kind: "direct",
|
|
256
|
+
id: params.sender.id
|
|
257
|
+
},
|
|
258
|
+
event: {
|
|
259
|
+
kind: params.eventKind ?? "native-command",
|
|
260
|
+
authMode: "inbound",
|
|
261
|
+
mayPair: true
|
|
262
|
+
},
|
|
263
|
+
dmPolicy: params.dmPolicy,
|
|
264
|
+
groupPolicy: "disabled",
|
|
265
|
+
policy: { mutableIdentifierMatching: params.allowNameMatching ? "enabled" : "disabled" },
|
|
266
|
+
allowFrom: params.configuredAllowFrom,
|
|
267
|
+
command: {
|
|
268
|
+
hasControlCommand: false,
|
|
269
|
+
modeWhenAccessGroupsOff: "configured"
|
|
270
|
+
}
|
|
271
|
+
});
|
|
272
|
+
}
|
|
273
|
+
async function resolveDiscordTextCommandAccess(params) {
|
|
274
|
+
const ownerAllowFrom = (params.ownerAllowFrom ?? []).filter((entry) => entry.trim() !== "*");
|
|
275
|
+
const memberAccessGroup = "discord-member-access";
|
|
276
|
+
const commandGroup = params.memberAccessConfigured ? [`accessGroup:${memberAccessGroup}`] : [];
|
|
277
|
+
const accessGroupMembership = params.memberAccessConfigured ? [syntheticAccessGroupMembership(memberAccessGroup, params.memberAllowed)] : [];
|
|
278
|
+
return (await createDiscordIngressResolver({
|
|
279
|
+
accountId: params.accountId,
|
|
280
|
+
cfg: params.cfg,
|
|
281
|
+
token: params.token,
|
|
282
|
+
rest: params.rest
|
|
283
|
+
}).command({
|
|
284
|
+
subject: createDiscordDmIngressSubject(params.sender),
|
|
285
|
+
conversation: {
|
|
286
|
+
kind: "group",
|
|
287
|
+
id: "discord-command"
|
|
288
|
+
},
|
|
289
|
+
accessGroupMembership,
|
|
290
|
+
dmPolicy: "allowlist",
|
|
291
|
+
groupPolicy: "allowlist",
|
|
292
|
+
policy: { mutableIdentifierMatching: params.allowNameMatching ? "enabled" : "disabled" },
|
|
293
|
+
allowFrom: ownerAllowFrom,
|
|
294
|
+
groupAllowFrom: commandGroup,
|
|
295
|
+
command: {
|
|
296
|
+
allowTextCommands: params.allowTextCommands,
|
|
297
|
+
hasControlCommand: params.hasControlCommand,
|
|
298
|
+
modeWhenAccessGroupsOff: "configured"
|
|
299
|
+
}
|
|
300
|
+
})).commandAccess;
|
|
301
|
+
}
|
|
302
|
+
//#endregion
|
|
303
|
+
//#region extensions/discord/src/monitor/thread-title.ts
|
|
304
|
+
const DEFAULT_THREAD_TITLE_TIMEOUT_MS = 1e4;
|
|
305
|
+
const MAX_THREAD_TITLE_SOURCE_CHARS = 600;
|
|
306
|
+
const MAX_THREAD_TITLE_CHANNEL_NAME_CHARS = 120;
|
|
307
|
+
const MAX_THREAD_TITLE_CHANNEL_DESCRIPTION_CHARS = 320;
|
|
308
|
+
const DISCORD_THREAD_TITLE_MAX_TOKENS = 512;
|
|
309
|
+
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
|
+
async function generateThreadTitle(params) {
|
|
311
|
+
const sourceText = params.messageText.trim();
|
|
312
|
+
if (!sourceText) return null;
|
|
313
|
+
const prepared = await prepareSimpleCompletionModelForAgent({
|
|
314
|
+
cfg: params.cfg,
|
|
315
|
+
agentId: params.agentId,
|
|
316
|
+
...params.modelRef ? { modelRef: params.modelRef } : {},
|
|
317
|
+
allowMissingApiKeyModes: ["aws-sdk"]
|
|
318
|
+
});
|
|
319
|
+
if ("error" in prepared) {
|
|
320
|
+
const modelLabel = prepared.selection ? `${prepared.selection.provider}/${prepared.selection.modelId}` : "unknown";
|
|
321
|
+
logVerbose(`thread-title: ${prepared.error} (agent=${params.agentId}, model=${modelLabel})`);
|
|
322
|
+
return null;
|
|
323
|
+
}
|
|
324
|
+
try {
|
|
325
|
+
const userMessage = buildThreadTitleUserMessage({
|
|
326
|
+
sourceText: truncateThreadTitleSourceText(sourceText),
|
|
327
|
+
channelName: params.channelName,
|
|
328
|
+
channelDescription: params.channelDescription
|
|
329
|
+
});
|
|
330
|
+
const timeoutMs = resolveThreadTitleTimeoutMs(params.timeoutMs);
|
|
331
|
+
return normalizeGeneratedThreadTitle(extractAssistantText(await completeThreadTitle({
|
|
332
|
+
model: prepared.model,
|
|
333
|
+
auth: prepared.auth,
|
|
334
|
+
userMessage,
|
|
335
|
+
timeoutMs
|
|
336
|
+
}))) || null;
|
|
337
|
+
} catch (err) {
|
|
338
|
+
logVerbose(`thread-title: title generation failed for agent ${params.agentId}: ${String(err)}`);
|
|
339
|
+
return null;
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
async function completeThreadTitle(params) {
|
|
343
|
+
return await withAbortTimeout({
|
|
344
|
+
timeoutMs: params.timeoutMs,
|
|
345
|
+
createTimeoutError: () => /* @__PURE__ */ new Error(`thread-title timed out after ${params.timeoutMs}ms`),
|
|
346
|
+
run: async (signal) => await completeWithPreparedSimpleCompletionModel({
|
|
347
|
+
model: params.model,
|
|
348
|
+
auth: params.auth,
|
|
349
|
+
context: {
|
|
350
|
+
systemPrompt: DISCORD_THREAD_TITLE_SYSTEM_PROMPT,
|
|
351
|
+
messages: [{
|
|
352
|
+
role: "user",
|
|
353
|
+
content: params.userMessage,
|
|
354
|
+
timestamp: Date.now()
|
|
355
|
+
}]
|
|
356
|
+
},
|
|
357
|
+
options: {
|
|
358
|
+
maxTokens: DISCORD_THREAD_TITLE_MAX_TOKENS,
|
|
359
|
+
signal
|
|
360
|
+
}
|
|
361
|
+
})
|
|
362
|
+
});
|
|
363
|
+
}
|
|
364
|
+
function buildThreadTitleUserMessage(params) {
|
|
365
|
+
const channelName = normalizeTitleContextField(params.channelName, MAX_THREAD_TITLE_CHANNEL_NAME_CHARS);
|
|
366
|
+
const channelDescription = normalizeTitleContextField(params.channelDescription, MAX_THREAD_TITLE_CHANNEL_DESCRIPTION_CHARS);
|
|
367
|
+
const messageLines = [];
|
|
368
|
+
if (channelName) messageLines.push(`Channel: ${channelName}`);
|
|
369
|
+
if (channelDescription) messageLines.push(`Channel description: ${channelDescription}`);
|
|
370
|
+
messageLines.push(`Message:\n${params.sourceText}`);
|
|
371
|
+
return messageLines.join("\n\n");
|
|
372
|
+
}
|
|
373
|
+
function truncateThreadTitleSourceText(sourceText) {
|
|
374
|
+
if (sourceText.length <= MAX_THREAD_TITLE_SOURCE_CHARS) return sourceText;
|
|
375
|
+
return `${sourceText.slice(0, MAX_THREAD_TITLE_SOURCE_CHARS)}...`;
|
|
376
|
+
}
|
|
377
|
+
function resolveThreadTitleTimeoutMs(timeoutMs) {
|
|
378
|
+
return Math.max(100, Math.floor(timeoutMs ?? DEFAULT_THREAD_TITLE_TIMEOUT_MS));
|
|
379
|
+
}
|
|
380
|
+
function normalizeGeneratedThreadTitle(raw) {
|
|
381
|
+
const lines = raw.replace(/\r/g, "").split("\n");
|
|
382
|
+
let firstLine = "";
|
|
383
|
+
for (const line of lines) {
|
|
384
|
+
const trimmed = line.trim();
|
|
385
|
+
if (!trimmed) continue;
|
|
386
|
+
if (!firstLine && trimmed.startsWith("```")) continue;
|
|
387
|
+
firstLine = trimmed;
|
|
388
|
+
break;
|
|
389
|
+
}
|
|
390
|
+
return stripThreadTitleWrappers(firstLine);
|
|
391
|
+
}
|
|
392
|
+
function stripThreadTitleWrappers(raw) {
|
|
393
|
+
let current = raw.trim();
|
|
394
|
+
let previous = "";
|
|
395
|
+
while (current && current !== previous) {
|
|
396
|
+
previous = current;
|
|
397
|
+
current = current.replace(/^["'`]+|["'`]+$/g, "").trim();
|
|
398
|
+
current = current.replace(/^\*\*(.+)\*\*$/u, "$1").trim();
|
|
399
|
+
current = current.replace(/^__(.+)__$/u, "$1").trim();
|
|
400
|
+
current = current.replace(/^\*(.+)\*$/u, "$1").trim();
|
|
401
|
+
current = current.replace(/^_(.+)_$/u, "$1").trim();
|
|
402
|
+
current = current.replace(/^~~(.+)~~$/u, "$1").trim();
|
|
403
|
+
}
|
|
404
|
+
return current;
|
|
405
|
+
}
|
|
406
|
+
function normalizeTitleContextField(raw, maxChars) {
|
|
407
|
+
const value = raw?.trim();
|
|
408
|
+
if (!value) return;
|
|
409
|
+
const singleLine = value.replace(/\s+/g, " ");
|
|
410
|
+
if (singleLine.length <= maxChars) return singleLine;
|
|
411
|
+
return `${singleLine.slice(0, maxChars)}...`;
|
|
412
|
+
}
|
|
413
|
+
//#endregion
|
|
414
|
+
//#region extensions/discord/src/monitor/threading.cache.ts
|
|
415
|
+
const DISCORD_THREAD_STARTER_CACHE_TTL_MS = 300 * 1e3;
|
|
416
|
+
const DISCORD_THREAD_STARTER_CACHE_MAX = 500;
|
|
417
|
+
const DISCORD_THREAD_STARTER_CACHE = /* @__PURE__ */ new Map();
|
|
418
|
+
function __resetDiscordThreadStarterCacheForTest() {
|
|
419
|
+
DISCORD_THREAD_STARTER_CACHE.clear();
|
|
420
|
+
}
|
|
421
|
+
function getCachedThreadStarter(key, now) {
|
|
422
|
+
const entry = DISCORD_THREAD_STARTER_CACHE.get(key);
|
|
423
|
+
if (!entry) return;
|
|
424
|
+
if (now - entry.updatedAt > DISCORD_THREAD_STARTER_CACHE_TTL_MS) {
|
|
425
|
+
DISCORD_THREAD_STARTER_CACHE.delete(key);
|
|
426
|
+
return;
|
|
427
|
+
}
|
|
428
|
+
DISCORD_THREAD_STARTER_CACHE.delete(key);
|
|
429
|
+
DISCORD_THREAD_STARTER_CACHE.set(key, {
|
|
430
|
+
...entry,
|
|
431
|
+
updatedAt: now
|
|
432
|
+
});
|
|
433
|
+
return entry.value;
|
|
434
|
+
}
|
|
435
|
+
function setCachedThreadStarter(key, value, now) {
|
|
436
|
+
DISCORD_THREAD_STARTER_CACHE.delete(key);
|
|
437
|
+
DISCORD_THREAD_STARTER_CACHE.set(key, {
|
|
438
|
+
value,
|
|
439
|
+
updatedAt: now
|
|
440
|
+
});
|
|
441
|
+
while (DISCORD_THREAD_STARTER_CACHE.size > DISCORD_THREAD_STARTER_CACHE_MAX) {
|
|
442
|
+
const iter = DISCORD_THREAD_STARTER_CACHE.keys().next();
|
|
443
|
+
if (iter.done) break;
|
|
444
|
+
DISCORD_THREAD_STARTER_CACHE.delete(iter.value);
|
|
445
|
+
}
|
|
446
|
+
}
|
|
447
|
+
//#endregion
|
|
448
|
+
//#region extensions/discord/src/monitor/threading.starter.ts
|
|
449
|
+
function isDiscordThreadType(type) {
|
|
450
|
+
return type === discord_exports.ChannelType.PublicThread || type === discord_exports.ChannelType.PrivateThread || type === discord_exports.ChannelType.AnnouncementThread;
|
|
451
|
+
}
|
|
452
|
+
function isDiscordForumParentType(parentType) {
|
|
453
|
+
return parentType === discord_exports.ChannelType.GuildForum || parentType === discord_exports.ChannelType.GuildMedia;
|
|
454
|
+
}
|
|
455
|
+
function resolveDiscordThreadChannel(params) {
|
|
456
|
+
if (!params.isGuildMessage) return null;
|
|
457
|
+
const { message, channelInfo } = params;
|
|
458
|
+
const channel = "channel" in message ? message.channel : void 0;
|
|
459
|
+
if (channel && typeof channel === "object" && "isThread" in channel && typeof channel.isThread === "function" && channel.isThread()) return channel;
|
|
460
|
+
if (!isDiscordThreadType(channelInfo?.type)) return null;
|
|
461
|
+
const messageChannelId = params.messageChannelId || resolveDiscordMessageChannelId({ message });
|
|
462
|
+
if (!messageChannelId) return null;
|
|
463
|
+
return {
|
|
464
|
+
id: messageChannelId,
|
|
465
|
+
name: channelInfo?.name ?? void 0,
|
|
466
|
+
parentId: channelInfo?.parentId ?? void 0,
|
|
467
|
+
parent: void 0,
|
|
468
|
+
ownerId: channelInfo?.ownerId ?? void 0
|
|
469
|
+
};
|
|
470
|
+
}
|
|
471
|
+
async function resolveDiscordThreadParentInfo(params) {
|
|
472
|
+
const { threadChannel, channelInfo, client } = params;
|
|
473
|
+
const parent = resolveDiscordChannelParentSafe(threadChannel);
|
|
474
|
+
let parentId = resolveDiscordChannelParentIdSafe(threadChannel) ?? resolveDiscordChannelIdSafe(parent) ?? channelInfo?.parentId ?? void 0;
|
|
475
|
+
if (!parentId && threadChannel.id) parentId = (await resolveDiscordChannelInfo(client, threadChannel.id))?.parentId ?? void 0;
|
|
476
|
+
if (!parentId) return {};
|
|
477
|
+
let parentName = resolveDiscordChannelNameSafe(parent);
|
|
478
|
+
const parentInfo = await resolveDiscordChannelInfo(client, parentId);
|
|
479
|
+
parentName = parentName ?? parentInfo?.name;
|
|
480
|
+
const parentType = parentInfo?.type;
|
|
481
|
+
return {
|
|
482
|
+
id: parentId,
|
|
483
|
+
name: parentName,
|
|
484
|
+
type: parentType
|
|
485
|
+
};
|
|
486
|
+
}
|
|
487
|
+
async function resolveDiscordThreadStarter(params) {
|
|
488
|
+
const cacheKey = params.channel.id;
|
|
489
|
+
const cached = getCachedThreadStarter(cacheKey, Date.now());
|
|
490
|
+
if (cached) return cached;
|
|
491
|
+
try {
|
|
492
|
+
const messageChannelId = resolveDiscordThreadStarterMessageChannelId(params);
|
|
493
|
+
if (!messageChannelId) return null;
|
|
494
|
+
const starter = await fetchDiscordThreadStarterMessage({
|
|
495
|
+
client: params.client,
|
|
496
|
+
messageChannelId,
|
|
497
|
+
threadId: params.channel.id
|
|
498
|
+
});
|
|
499
|
+
if (!starter) return null;
|
|
500
|
+
const payload = buildDiscordThreadStarterPayload({
|
|
501
|
+
starter,
|
|
502
|
+
resolveTimestampMs: params.resolveTimestampMs
|
|
503
|
+
});
|
|
504
|
+
if (!payload) return null;
|
|
505
|
+
setCachedThreadStarter(cacheKey, payload, Date.now());
|
|
506
|
+
return payload;
|
|
507
|
+
} catch {
|
|
508
|
+
return null;
|
|
509
|
+
}
|
|
510
|
+
}
|
|
511
|
+
function resolveDiscordThreadStarterMessageChannelId(params) {
|
|
512
|
+
return isDiscordForumParentType(params.parentType) ? params.channel.id : params.parentId;
|
|
513
|
+
}
|
|
514
|
+
async function fetchDiscordThreadStarterMessage(params) {
|
|
515
|
+
const starter = await getChannelMessage(params.client.rest, params.messageChannelId, params.threadId);
|
|
516
|
+
return starter ? starter : null;
|
|
517
|
+
}
|
|
518
|
+
function buildDiscordThreadStarterPayload(params) {
|
|
519
|
+
const text = resolveDiscordThreadStarterText(params.starter);
|
|
520
|
+
if (!text) return null;
|
|
521
|
+
return {
|
|
522
|
+
text,
|
|
523
|
+
...resolveDiscordThreadStarterIdentity(params.starter),
|
|
524
|
+
timestamp: params.resolveTimestampMs(params.starter.timestamp) ?? void 0
|
|
525
|
+
};
|
|
526
|
+
}
|
|
527
|
+
function resolveDiscordThreadStarterText(starter) {
|
|
528
|
+
const content = normalizeOptionalString(starter.content) ?? "";
|
|
529
|
+
const embedText = resolveDiscordEmbedText(starter.embeds?.[0]);
|
|
530
|
+
const forwardedText = resolveDiscordForwardedMessagesTextFromSnapshots(starter.message_snapshots);
|
|
531
|
+
return content || embedText || forwardedText;
|
|
532
|
+
}
|
|
533
|
+
function resolveDiscordThreadStarterIdentity(starter) {
|
|
534
|
+
return {
|
|
535
|
+
author: resolveDiscordThreadStarterAuthor(starter),
|
|
536
|
+
authorId: starter.author?.id ?? void 0,
|
|
537
|
+
authorName: starter.author?.username ?? void 0,
|
|
538
|
+
authorTag: resolveDiscordThreadStarterAuthorTag(starter.author),
|
|
539
|
+
memberRoleIds: resolveDiscordThreadStarterRoleIds(starter.member)
|
|
540
|
+
};
|
|
541
|
+
}
|
|
542
|
+
function resolveDiscordThreadStarterAuthor(starter) {
|
|
543
|
+
return starter.member?.nick ?? starter.member?.displayName ?? resolveDiscordThreadStarterAuthorTag(starter.author) ?? starter.author?.username ?? starter.author?.id ?? "Unknown";
|
|
544
|
+
}
|
|
545
|
+
function resolveDiscordThreadStarterAuthorTag(author) {
|
|
546
|
+
if (!author?.username || !author.discriminator) return;
|
|
547
|
+
if (author.discriminator !== "0") return `${author.username}#${author.discriminator}`;
|
|
548
|
+
return author.username;
|
|
549
|
+
}
|
|
550
|
+
function resolveDiscordThreadStarterRoleIds(member) {
|
|
551
|
+
return Array.isArray(member?.roles) ? member.roles : void 0;
|
|
552
|
+
}
|
|
553
|
+
function resolveDiscordReplyTarget(opts) {
|
|
554
|
+
if (opts.replyToMode === "off") return;
|
|
555
|
+
const replyToId = normalizeOptionalString(opts.replyToId);
|
|
556
|
+
if (!replyToId) return;
|
|
557
|
+
if (opts.replyToMode === "all") return replyToId;
|
|
558
|
+
return opts.hasReplied ? void 0 : replyToId;
|
|
559
|
+
}
|
|
560
|
+
function sanitizeDiscordThreadName(rawName, fallbackId) {
|
|
561
|
+
return truncateUtf16Safe(truncateUtf16Safe(rawName.replace(/<@!?\d+>/g, "").replace(/<@&\d+>/g, "").replace(/<#\d+>/g, "").replace(/\s+/g, " ").trim() || `Thread ${fallbackId}`, 80), 100) || `Thread ${fallbackId}`;
|
|
562
|
+
}
|
|
563
|
+
function resolveDiscordReplyDeliveryPlan(params) {
|
|
564
|
+
const originalReplyTarget = params.replyTarget;
|
|
565
|
+
let deliverTarget = originalReplyTarget;
|
|
566
|
+
let replyTarget = originalReplyTarget;
|
|
567
|
+
if (params.createdThreadId) {
|
|
568
|
+
deliverTarget = `channel:${params.createdThreadId}`;
|
|
569
|
+
replyTarget = deliverTarget;
|
|
570
|
+
}
|
|
571
|
+
const allowReference = deliverTarget === originalReplyTarget;
|
|
572
|
+
const replyReference = createReplyReferencePlanner({
|
|
573
|
+
replyToMode: allowReference ? params.replyToMode : "off",
|
|
574
|
+
existingId: params.threadChannel ? params.messageId : void 0,
|
|
575
|
+
startId: params.messageId,
|
|
576
|
+
allowReference
|
|
577
|
+
});
|
|
578
|
+
return {
|
|
579
|
+
deliverTarget,
|
|
580
|
+
replyTarget,
|
|
581
|
+
replyReference
|
|
582
|
+
};
|
|
583
|
+
}
|
|
584
|
+
//#endregion
|
|
585
|
+
//#region extensions/discord/src/monitor/threading.auto-thread.ts
|
|
586
|
+
function resolveTrimmedDiscordMessageChannelId(params) {
|
|
587
|
+
return (params.messageChannelId || resolveDiscordMessageChannelId({ message: params.message })).trim();
|
|
588
|
+
}
|
|
589
|
+
function resolveDiscordAutoThreadContext(params) {
|
|
590
|
+
const createdThreadId = normalizeOptionalStringifiedId(params.createdThreadId) ?? "";
|
|
591
|
+
if (!createdThreadId) return null;
|
|
592
|
+
const messageChannelId = normalizeOptionalString(params.messageChannelId) ?? "";
|
|
593
|
+
if (!messageChannelId) return null;
|
|
594
|
+
const threadSessionKey = buildAgentSessionKey({
|
|
595
|
+
agentId: params.agentId,
|
|
596
|
+
channel: params.channel,
|
|
597
|
+
peer: {
|
|
598
|
+
kind: "channel",
|
|
599
|
+
id: createdThreadId
|
|
600
|
+
}
|
|
601
|
+
});
|
|
602
|
+
const parentSessionKey = buildAgentSessionKey({
|
|
603
|
+
agentId: params.agentId,
|
|
604
|
+
channel: params.channel,
|
|
605
|
+
peer: {
|
|
606
|
+
kind: "channel",
|
|
607
|
+
id: messageChannelId
|
|
608
|
+
}
|
|
609
|
+
});
|
|
610
|
+
return {
|
|
611
|
+
createdThreadId,
|
|
612
|
+
From: `${params.channel}:channel:${createdThreadId}`,
|
|
613
|
+
To: `channel:${createdThreadId}`,
|
|
614
|
+
OriginatingTo: `channel:${createdThreadId}`,
|
|
615
|
+
SessionKey: threadSessionKey,
|
|
616
|
+
ModelParentSessionKey: parentSessionKey,
|
|
617
|
+
...params.parentInheritanceEnabled === true ? { ParentSessionKey: parentSessionKey } : {}
|
|
618
|
+
};
|
|
619
|
+
}
|
|
620
|
+
async function resolveDiscordAutoThreadReplyPlan(params) {
|
|
621
|
+
const messageChannelId = resolveTrimmedDiscordMessageChannelId(params);
|
|
622
|
+
const originalReplyTarget = `channel:${params.threadChannel?.id ?? (messageChannelId || "unknown")}`;
|
|
623
|
+
const createdThreadId = await maybeCreateDiscordAutoThread({
|
|
624
|
+
client: params.client,
|
|
625
|
+
message: params.message,
|
|
626
|
+
messageChannelId: messageChannelId || void 0,
|
|
627
|
+
channel: params.channel,
|
|
628
|
+
isGuildMessage: params.isGuildMessage,
|
|
629
|
+
channelConfig: params.channelConfig,
|
|
630
|
+
threadChannel: params.threadChannel,
|
|
631
|
+
channelType: params.channelType,
|
|
632
|
+
channelName: params.channelName,
|
|
633
|
+
channelDescription: params.channelDescription,
|
|
634
|
+
baseText: params.baseText,
|
|
635
|
+
combinedBody: params.combinedBody,
|
|
636
|
+
cfg: params.cfg,
|
|
637
|
+
agentId: params.agentId
|
|
638
|
+
});
|
|
639
|
+
const deliveryPlan = resolveDiscordReplyDeliveryPlan({
|
|
640
|
+
replyTarget: originalReplyTarget,
|
|
641
|
+
replyToMode: params.replyToMode,
|
|
642
|
+
messageId: params.message.id,
|
|
643
|
+
threadChannel: params.threadChannel,
|
|
644
|
+
createdThreadId
|
|
645
|
+
});
|
|
646
|
+
const autoThreadContext = params.isGuildMessage ? resolveDiscordAutoThreadContext({
|
|
647
|
+
agentId: params.agentId,
|
|
648
|
+
channel: params.channel,
|
|
649
|
+
messageChannelId,
|
|
650
|
+
createdThreadId,
|
|
651
|
+
parentInheritanceEnabled: params.threadParentInheritanceEnabled
|
|
652
|
+
}) : null;
|
|
653
|
+
return {
|
|
654
|
+
...deliveryPlan,
|
|
655
|
+
createdThreadId,
|
|
656
|
+
autoThreadContext
|
|
657
|
+
};
|
|
658
|
+
}
|
|
659
|
+
async function maybeCreateDiscordAutoThread(params) {
|
|
660
|
+
if (!params.isGuildMessage) return;
|
|
661
|
+
if (!params.channelConfig?.autoThread) return;
|
|
662
|
+
if (params.threadChannel) return;
|
|
663
|
+
if (params.channelType === discord_exports.ChannelType.GuildForum || params.channelType === discord_exports.ChannelType.GuildMedia || params.channelType === discord_exports.ChannelType.GuildVoice || params.channelType === discord_exports.ChannelType.GuildStageVoice) return;
|
|
664
|
+
const messageChannelId = resolveTrimmedDiscordMessageChannelId(params);
|
|
665
|
+
if (!messageChannelId) return;
|
|
666
|
+
try {
|
|
667
|
+
const rawThreadSource = params.baseText || params.combinedBody || "Thread";
|
|
668
|
+
const threadName = sanitizeDiscordThreadName(rawThreadSource, params.message.id);
|
|
669
|
+
const archiveDuration = params.channelConfig?.autoArchiveDuration ? Number(params.channelConfig.autoArchiveDuration) : 60;
|
|
670
|
+
const createdId = (await createThread(params.client.rest, messageChannelId, { body: {
|
|
671
|
+
name: threadName,
|
|
672
|
+
auto_archive_duration: archiveDuration
|
|
673
|
+
} }, params.message.id))?.id || "";
|
|
674
|
+
if (createdId && params.channelConfig?.autoThreadName === "generated" && params.cfg && params.agentId) {
|
|
675
|
+
const modelRef = resolveDiscordThreadTitleModelRef({
|
|
676
|
+
cfg: params.cfg,
|
|
677
|
+
channel: params.channel,
|
|
678
|
+
agentId: params.agentId,
|
|
679
|
+
threadId: createdId,
|
|
680
|
+
messageChannelId,
|
|
681
|
+
channelName: params.channelName
|
|
682
|
+
});
|
|
683
|
+
maybeRenameDiscordAutoThread({
|
|
684
|
+
client: params.client,
|
|
685
|
+
threadId: createdId,
|
|
686
|
+
currentName: threadName,
|
|
687
|
+
fallbackId: params.message.id,
|
|
688
|
+
sourceText: rawThreadSource,
|
|
689
|
+
modelRef,
|
|
690
|
+
channelName: params.channelName,
|
|
691
|
+
channelDescription: params.channelDescription,
|
|
692
|
+
cfg: params.cfg,
|
|
693
|
+
agentId: params.agentId
|
|
694
|
+
});
|
|
695
|
+
}
|
|
696
|
+
return createdId || void 0;
|
|
697
|
+
} catch (err) {
|
|
698
|
+
logVerbose(`discord: autoThread creation failed for ${messageChannelId}/${params.message.id}: ${String(err)}`);
|
|
699
|
+
try {
|
|
700
|
+
const existingThreadId = (await getChannelMessage(params.client.rest, messageChannelId, params.message.id))?.thread?.id || "";
|
|
701
|
+
if (existingThreadId) {
|
|
702
|
+
logVerbose(`discord: autoThread reusing existing thread ${existingThreadId} on ${messageChannelId}/${params.message.id}`);
|
|
703
|
+
return existingThreadId;
|
|
704
|
+
}
|
|
705
|
+
} catch {}
|
|
706
|
+
return;
|
|
707
|
+
}
|
|
708
|
+
}
|
|
709
|
+
function resolveDiscordThreadTitleModelRef(params) {
|
|
710
|
+
const channel = params.channel?.trim();
|
|
711
|
+
if (!channel) return;
|
|
712
|
+
const parentSessionKey = buildAgentSessionKey({
|
|
713
|
+
agentId: params.agentId,
|
|
714
|
+
channel,
|
|
715
|
+
peer: {
|
|
716
|
+
kind: "channel",
|
|
717
|
+
id: params.messageChannelId
|
|
718
|
+
}
|
|
719
|
+
});
|
|
720
|
+
const channelLabel = params.channelName?.trim();
|
|
721
|
+
const groupChannel = channelLabel ? `#${channelLabel}` : void 0;
|
|
722
|
+
return resolveChannelModelOverride({
|
|
723
|
+
cfg: params.cfg,
|
|
724
|
+
channel,
|
|
725
|
+
groupId: params.threadId,
|
|
726
|
+
groupChatType: "channel",
|
|
727
|
+
groupChannel,
|
|
728
|
+
groupSubject: groupChannel,
|
|
729
|
+
parentSessionKey
|
|
730
|
+
})?.model;
|
|
731
|
+
}
|
|
732
|
+
async function maybeRenameDiscordAutoThread(params) {
|
|
733
|
+
try {
|
|
734
|
+
const fallbackName = sanitizeDiscordThreadName("", params.fallbackId);
|
|
735
|
+
const generated = await generateThreadTitle({
|
|
736
|
+
cfg: params.cfg,
|
|
737
|
+
agentId: params.agentId,
|
|
738
|
+
messageText: params.sourceText,
|
|
739
|
+
modelRef: params.modelRef,
|
|
740
|
+
channelName: params.channelName,
|
|
741
|
+
channelDescription: params.channelDescription
|
|
742
|
+
});
|
|
743
|
+
if (!generated) return;
|
|
744
|
+
const nextName = sanitizeDiscordThreadName(generated, params.fallbackId);
|
|
745
|
+
if (!nextName || nextName === params.currentName || nextName === fallbackName) return;
|
|
746
|
+
await editChannel(params.client.rest, params.threadId, { body: { name: nextName } });
|
|
747
|
+
} catch (err) {
|
|
748
|
+
logVerbose(`discord: autoThread rename failed for ${params.threadId}: ${String(err)}`);
|
|
749
|
+
}
|
|
750
|
+
}
|
|
751
|
+
//#endregion
|
|
752
|
+
//#region extensions/discord/src/monitor/threading.ts
|
|
753
|
+
var threading_exports = /* @__PURE__ */ __exportAll({
|
|
754
|
+
__resetDiscordThreadStarterCacheForTest: () => __resetDiscordThreadStarterCacheForTest,
|
|
755
|
+
maybeCreateDiscordAutoThread: () => maybeCreateDiscordAutoThread,
|
|
756
|
+
resolveDiscordAutoThreadContext: () => resolveDiscordAutoThreadContext,
|
|
757
|
+
resolveDiscordAutoThreadReplyPlan: () => resolveDiscordAutoThreadReplyPlan,
|
|
758
|
+
resolveDiscordReplyDeliveryPlan: () => resolveDiscordReplyDeliveryPlan,
|
|
759
|
+
resolveDiscordReplyTarget: () => resolveDiscordReplyTarget,
|
|
760
|
+
resolveDiscordThreadChannel: () => resolveDiscordThreadChannel,
|
|
761
|
+
resolveDiscordThreadParentInfo: () => resolveDiscordThreadParentInfo,
|
|
762
|
+
resolveDiscordThreadStarter: () => resolveDiscordThreadStarter,
|
|
763
|
+
sanitizeDiscordThreadName: () => sanitizeDiscordThreadName
|
|
764
|
+
});
|
|
765
|
+
//#endregion
|
|
150
766
|
//#region extensions/discord/src/monitor/thread-channel-context.ts
|
|
151
767
|
function isDiscordThreadChannelType(type) {
|
|
152
768
|
return type === discord_exports.ChannelType.PublicThread || type === discord_exports.ChannelType.PrivateThread || type === discord_exports.ChannelType.AnnouncementThread;
|
|
@@ -694,6 +1310,35 @@ var DiscordThreadUpdateListener = class extends ThreadUpdateListener {
|
|
|
694
1310
|
}
|
|
695
1311
|
};
|
|
696
1312
|
//#endregion
|
|
1313
|
+
//#region extensions/discord/src/monitor/dm-command-decision.ts
|
|
1314
|
+
async function handleDiscordDmCommandDecision(params) {
|
|
1315
|
+
if (params.senderAccess.decision === "allow") return true;
|
|
1316
|
+
if (params.senderAccess.decision === "pairing") {
|
|
1317
|
+
const upsertPairingRequest = params.upsertPairingRequest ?? upsertChannelPairingRequest;
|
|
1318
|
+
const result = await createChannelPairingChallengeIssuer({
|
|
1319
|
+
channel: "discord",
|
|
1320
|
+
upsertPairingRequest: async ({ id, meta }) => await upsertPairingRequest({
|
|
1321
|
+
channel: "discord",
|
|
1322
|
+
id,
|
|
1323
|
+
accountId: params.accountId,
|
|
1324
|
+
meta
|
|
1325
|
+
})
|
|
1326
|
+
})({
|
|
1327
|
+
senderId: params.sender.id,
|
|
1328
|
+
senderIdLine: `Your Discord user id: ${params.sender.id}`,
|
|
1329
|
+
meta: {
|
|
1330
|
+
tag: params.sender.tag,
|
|
1331
|
+
name: params.sender.name
|
|
1332
|
+
},
|
|
1333
|
+
sendPairingReply: async () => {}
|
|
1334
|
+
});
|
|
1335
|
+
if (result.created && result.code) await params.onPairingCreated(result.code);
|
|
1336
|
+
return false;
|
|
1337
|
+
}
|
|
1338
|
+
await params.onUnauthorized();
|
|
1339
|
+
return false;
|
|
1340
|
+
}
|
|
1341
|
+
//#endregion
|
|
697
1342
|
//#region extensions/discord/src/monitor/native-command-reply.ts
|
|
698
1343
|
const DISCORD_EMPTY_VISIBLE_REPLY_WARNING = "⚠️ Command produced no visible reply.";
|
|
699
1344
|
function isDiscordUnknownInteraction(error) {
|
|
@@ -794,6 +1439,78 @@ async function deliverDiscordInteractionReply(params) {
|
|
|
794
1439
|
}
|
|
795
1440
|
}
|
|
796
1441
|
//#endregion
|
|
1442
|
+
//#region extensions/discord/src/monitor/route-resolution.ts
|
|
1443
|
+
function buildDiscordRoutePeer(params) {
|
|
1444
|
+
return {
|
|
1445
|
+
kind: params.isDirectMessage ? "direct" : params.isGroupDm ? "group" : "channel",
|
|
1446
|
+
id: params.isDirectMessage ? params.directUserId?.trim() || params.conversationId : params.conversationId
|
|
1447
|
+
};
|
|
1448
|
+
}
|
|
1449
|
+
function resolveDiscordConversationRoute(params) {
|
|
1450
|
+
return resolveAgentRoute({
|
|
1451
|
+
cfg: params.cfg,
|
|
1452
|
+
channel: "discord",
|
|
1453
|
+
accountId: params.accountId,
|
|
1454
|
+
guildId: params.guildId ?? void 0,
|
|
1455
|
+
memberRoleIds: params.memberRoleIds,
|
|
1456
|
+
peer: params.peer,
|
|
1457
|
+
parentPeer: params.parentConversationId ? {
|
|
1458
|
+
kind: "channel",
|
|
1459
|
+
id: params.parentConversationId
|
|
1460
|
+
} : void 0
|
|
1461
|
+
});
|
|
1462
|
+
}
|
|
1463
|
+
function resolveDiscordBoundConversationRoute(params) {
|
|
1464
|
+
return resolveDiscordEffectiveRoute({
|
|
1465
|
+
route: resolveDiscordConversationRoute({
|
|
1466
|
+
cfg: params.cfg,
|
|
1467
|
+
accountId: params.accountId,
|
|
1468
|
+
guildId: params.guildId,
|
|
1469
|
+
memberRoleIds: params.memberRoleIds,
|
|
1470
|
+
peer: buildDiscordRoutePeer({
|
|
1471
|
+
isDirectMessage: params.isDirectMessage,
|
|
1472
|
+
isGroupDm: params.isGroupDm,
|
|
1473
|
+
directUserId: params.directUserId,
|
|
1474
|
+
conversationId: params.conversationId
|
|
1475
|
+
}),
|
|
1476
|
+
parentConversationId: params.parentConversationId
|
|
1477
|
+
}),
|
|
1478
|
+
boundSessionKey: params.boundSessionKey,
|
|
1479
|
+
configuredRoute: params.configuredRoute,
|
|
1480
|
+
matchedBy: params.matchedBy
|
|
1481
|
+
});
|
|
1482
|
+
}
|
|
1483
|
+
function resolveDiscordEffectiveRoute(params) {
|
|
1484
|
+
const boundSessionKey = params.boundSessionKey?.trim();
|
|
1485
|
+
if (!boundSessionKey) return params.configuredRoute?.route ?? params.route;
|
|
1486
|
+
return {
|
|
1487
|
+
...params.route,
|
|
1488
|
+
sessionKey: boundSessionKey,
|
|
1489
|
+
agentId: resolveAgentIdFromSessionKey(boundSessionKey),
|
|
1490
|
+
lastRoutePolicy: deriveLastRoutePolicy({
|
|
1491
|
+
sessionKey: boundSessionKey,
|
|
1492
|
+
mainSessionKey: params.route.mainSessionKey
|
|
1493
|
+
}),
|
|
1494
|
+
...params.matchedBy ? { matchedBy: params.matchedBy } : {}
|
|
1495
|
+
};
|
|
1496
|
+
}
|
|
1497
|
+
function hasExplicitRuntimeBindingIntent(record) {
|
|
1498
|
+
if (record.targetKind === "subagent") return true;
|
|
1499
|
+
if (isAcpSessionKey(record.targetSessionKey) || isSubagentSessionKey(record.targetSessionKey)) return true;
|
|
1500
|
+
const metadata = record.metadata;
|
|
1501
|
+
if (!metadata || typeof metadata !== "object") return false;
|
|
1502
|
+
return typeof metadata.boundBy === "string" || typeof metadata.label === "string" || typeof metadata.threadName === "string" || metadata.pluginBindingOwner === "plugin";
|
|
1503
|
+
}
|
|
1504
|
+
function shouldIgnoreStaleDiscordRouteBinding(params) {
|
|
1505
|
+
const bindingRecord = params.bindingRecord;
|
|
1506
|
+
const boundSessionKey = bindingRecord?.targetSessionKey?.trim();
|
|
1507
|
+
if (!bindingRecord || !boundSessionKey || hasExplicitRuntimeBindingIntent(bindingRecord)) return false;
|
|
1508
|
+
const bound = parseAgentSessionKey(boundSessionKey);
|
|
1509
|
+
const routed = parseAgentSessionKey(params.route.sessionKey);
|
|
1510
|
+
if (!bound || !routed || bound.rest !== routed.rest) return false;
|
|
1511
|
+
return bound.agentId !== params.route.agentId;
|
|
1512
|
+
}
|
|
1513
|
+
//#endregion
|
|
797
1514
|
//#region extensions/discord/src/monitor/native-command-route.ts
|
|
798
1515
|
async function resolveDiscordNativeInteractionRouteState(params) {
|
|
799
1516
|
const route = resolveDiscordBoundConversationRoute({
|
|
@@ -1205,6 +1922,12 @@ function buildDiscordNativeCommandContext(params) {
|
|
|
1205
1922
|
MessageThreadId: params.isThreadChannel ? params.channelId : void 0,
|
|
1206
1923
|
Timestamp: params.timestampMs ?? Date.now(),
|
|
1207
1924
|
CommandAuthorized: params.commandAuthorized,
|
|
1925
|
+
CommandTurn: {
|
|
1926
|
+
kind: "native",
|
|
1927
|
+
source: "native",
|
|
1928
|
+
authorized: params.commandAuthorized,
|
|
1929
|
+
body: params.prompt
|
|
1930
|
+
},
|
|
1208
1931
|
CommandSource: "native",
|
|
1209
1932
|
OriginatingChannel: "discord",
|
|
1210
1933
|
OriginatingTo: resolveDiscordConversationIdentity({
|
|
@@ -3778,6 +4501,12 @@ var GatewayPlugin = class extends Plugin {
|
|
|
3778
4501
|
}
|
|
3779
4502
|
};
|
|
3780
4503
|
//#endregion
|
|
4504
|
+
//#region extensions/discord/src/voice/config.ts
|
|
4505
|
+
function resolveDiscordVoiceEnabled(voice) {
|
|
4506
|
+
if (voice?.enabled !== void 0) return voice.enabled;
|
|
4507
|
+
return voice !== void 0;
|
|
4508
|
+
}
|
|
4509
|
+
//#endregion
|
|
3781
4510
|
//#region extensions/discord/src/monitor/presence.ts
|
|
3782
4511
|
const DEFAULT_CUSTOM_ACTIVITY_TYPE$1 = 4;
|
|
3783
4512
|
const CUSTOM_STATUS_NAME$1 = "Custom Status";
|
|
@@ -5258,6 +5987,85 @@ function runDiscordCommandDeployInBackground(params) {
|
|
|
5258
5987
|
});
|
|
5259
5988
|
}
|
|
5260
5989
|
//#endregion
|
|
5990
|
+
//#region extensions/discord/src/voice/access.ts
|
|
5991
|
+
async function authorizeDiscordVoiceIngress(params) {
|
|
5992
|
+
const groupPolicy = params.groupPolicy ?? resolveOpenProviderRuntimeGroupPolicy({
|
|
5993
|
+
providerConfigPresent: params.cfg.channels?.discord !== void 0,
|
|
5994
|
+
groupPolicy: params.discordConfig.groupPolicy,
|
|
5995
|
+
defaultGroupPolicy: params.cfg.channels?.defaults?.groupPolicy
|
|
5996
|
+
}).groupPolicy;
|
|
5997
|
+
const guildInfo = resolveDiscordGuildEntry({
|
|
5998
|
+
guild: params.guild ?? {
|
|
5999
|
+
id: params.guildId,
|
|
6000
|
+
...params.guildName ? { name: params.guildName } : {}
|
|
6001
|
+
},
|
|
6002
|
+
guildId: params.guildId,
|
|
6003
|
+
guildEntries: params.discordConfig.guilds
|
|
6004
|
+
});
|
|
6005
|
+
const channelConfig = params.channelId ? resolveDiscordChannelConfigWithFallback({
|
|
6006
|
+
guildInfo,
|
|
6007
|
+
channelId: params.channelId,
|
|
6008
|
+
channelName: params.channelName,
|
|
6009
|
+
channelSlug: params.channelSlug,
|
|
6010
|
+
parentId: params.parentId,
|
|
6011
|
+
parentName: params.parentName,
|
|
6012
|
+
parentSlug: params.parentSlug,
|
|
6013
|
+
scope: params.scope
|
|
6014
|
+
}) : null;
|
|
6015
|
+
if (channelConfig?.enabled === false) return {
|
|
6016
|
+
ok: false,
|
|
6017
|
+
message: "This channel is disabled."
|
|
6018
|
+
};
|
|
6019
|
+
const channelAllowlistConfigured = Boolean(guildInfo?.channels) && Object.keys(guildInfo?.channels ?? {}).length > 0;
|
|
6020
|
+
if (!params.channelId && groupPolicy === "allowlist" && channelAllowlistConfigured) return {
|
|
6021
|
+
ok: false,
|
|
6022
|
+
message: `${params.channelLabel ?? "This channel"} is not allowlisted for voice commands.`
|
|
6023
|
+
};
|
|
6024
|
+
const channelAllowed = channelConfig ? channelConfig.allowed : !channelAllowlistConfigured;
|
|
6025
|
+
if (!isDiscordGroupAllowedByPolicy({
|
|
6026
|
+
groupPolicy,
|
|
6027
|
+
guildAllowlisted: Boolean(guildInfo),
|
|
6028
|
+
channelAllowlistConfigured,
|
|
6029
|
+
channelAllowed
|
|
6030
|
+
}) || channelConfig?.allowed === false) return {
|
|
6031
|
+
ok: false,
|
|
6032
|
+
message: `${params.channelLabel ?? "This channel"} is not allowlisted for voice commands.`
|
|
6033
|
+
};
|
|
6034
|
+
const { hasAccessRestrictions, memberAllowed } = resolveDiscordMemberAccessState({
|
|
6035
|
+
channelConfig,
|
|
6036
|
+
guildInfo,
|
|
6037
|
+
memberRoleIds: params.memberRoleIds,
|
|
6038
|
+
sender: params.sender,
|
|
6039
|
+
allowNameMatching: false
|
|
6040
|
+
});
|
|
6041
|
+
const { ownerAllowList, ownerAllowed } = resolveDiscordOwnerAccess({
|
|
6042
|
+
allowFrom: params.ownerAllowFrom ?? params.discordConfig.allowFrom ?? params.discordConfig.dm?.allowFrom,
|
|
6043
|
+
sender: params.sender,
|
|
6044
|
+
allowNameMatching: false
|
|
6045
|
+
});
|
|
6046
|
+
const useAccessGroups = params.useAccessGroups ?? params.cfg.commands?.useAccessGroups !== false;
|
|
6047
|
+
return resolveCommandAuthorizedFromAuthorizers({
|
|
6048
|
+
useAccessGroups,
|
|
6049
|
+
authorizers: useAccessGroups ? [{
|
|
6050
|
+
configured: ownerAllowList != null,
|
|
6051
|
+
allowed: ownerAllowed
|
|
6052
|
+
}, {
|
|
6053
|
+
configured: hasAccessRestrictions,
|
|
6054
|
+
allowed: memberAllowed
|
|
6055
|
+
}] : [{
|
|
6056
|
+
configured: hasAccessRestrictions,
|
|
6057
|
+
allowed: memberAllowed
|
|
6058
|
+
}],
|
|
6059
|
+
modeWhenAccessGroupsOff: "configured"
|
|
6060
|
+
}) ? {
|
|
6061
|
+
ok: true,
|
|
6062
|
+
channelConfig
|
|
6063
|
+
} : {
|
|
6064
|
+
ok: false,
|
|
6065
|
+
message: "You are not authorized to use this command."
|
|
6066
|
+
};
|
|
6067
|
+
}
|
|
6068
|
+
//#endregion
|
|
5261
6069
|
//#region extensions/discord/src/voice/command.ts
|
|
5262
6070
|
const VOICE_CHANNEL_TYPES = [ChannelType.GuildVoice, ChannelType.GuildStageVoice];
|
|
5263
6071
|
async function authorizeVoiceCommand(interaction, params, options) {
|
|
@@ -6054,15 +6862,195 @@ function resolveDiscordInteractionId(interaction) {
|
|
|
6054
6862
|
const AGENT_BUTTON_KEY = "agent";
|
|
6055
6863
|
const AGENT_SELECT_KEY = "agentsel";
|
|
6056
6864
|
//#endregion
|
|
6865
|
+
//#region extensions/discord/src/monitor/reply-context.ts
|
|
6866
|
+
function resolveReplyContext(message, resolveDiscordMessageText) {
|
|
6867
|
+
const referenced = message.referencedMessage;
|
|
6868
|
+
if (!referenced?.author) return null;
|
|
6869
|
+
const referencedText = resolveDiscordMessageText(referenced, { includeForwarded: true });
|
|
6870
|
+
if (!referencedText) return null;
|
|
6871
|
+
const sender = resolveDiscordSenderIdentity({
|
|
6872
|
+
author: referenced.author,
|
|
6873
|
+
pluralkitInfo: null
|
|
6874
|
+
});
|
|
6875
|
+
return {
|
|
6876
|
+
id: referenced.id,
|
|
6877
|
+
channelId: referenced.channelId,
|
|
6878
|
+
sender: sender.tag ?? sender.label ?? "unknown",
|
|
6879
|
+
senderId: referenced.author.id,
|
|
6880
|
+
senderName: referenced.author.username ?? void 0,
|
|
6881
|
+
senderTag: sender.tag ?? void 0,
|
|
6882
|
+
memberRoleIds: (() => {
|
|
6883
|
+
const roles = referenced.member?.roles;
|
|
6884
|
+
return Array.isArray(roles) ? roles.map((roleId) => roleId) : void 0;
|
|
6885
|
+
})(),
|
|
6886
|
+
body: referencedText,
|
|
6887
|
+
timestamp: resolveTimestampMs(referenced.timestamp)
|
|
6888
|
+
};
|
|
6889
|
+
}
|
|
6890
|
+
function buildDirectLabel(author, tagOverride) {
|
|
6891
|
+
return `${(tagOverride?.trim() || resolveDiscordSenderIdentity({
|
|
6892
|
+
author,
|
|
6893
|
+
pluralkitInfo: null
|
|
6894
|
+
}).tag) ?? "unknown"} user id:${author.id}`;
|
|
6895
|
+
}
|
|
6896
|
+
function buildGuildLabel(params) {
|
|
6897
|
+
const { guild, channelName, channelId } = params;
|
|
6898
|
+
return `${guild?.name ?? "Guild"} #${channelName} channel id:${channelId}`;
|
|
6899
|
+
}
|
|
6900
|
+
//#endregion
|
|
6901
|
+
//#region extensions/discord/src/monitor/reply-safety.ts
|
|
6902
|
+
const DISCORD_INTERNAL_TRACE_LINE_RE = /^(?:>\s*)?(?:📊|🛠️|📖|📝|🔍|🔎|⚙️)\s*(?:Session Status|Exec|Read|Edit|Write|Patch|Search|Open|Click|Find|Screenshot|Update Plan|Tool Call|Tool Result|Function Call|Shell|Command)\s*:/i;
|
|
6903
|
+
const DISCORD_INTERNAL_COMPACT_COMMAND_TRACE_LINE_RE = /^(?:>\s*)?🛠️\s*(?:(?:(?:elevated|pty)\b\s*(?:·|,)\s*)+)?(?:`{1,2}\s*\S|(?:run|check|fetch|pull|push|view|show|list|switch|create|merge|rebase|stage|restore|reset|stash|search|find|print|copy|move|remove|install|start|cd|git|pnpm|npm|yarn|bun|node|python|python3|bash|sh)\b)/i;
|
|
6904
|
+
const DISCORD_INTERNAL_CHANNEL_LINE_RE = /^(?:>\s*)?(?:analysis|commentary|tool[-_ ]?call|tool[-_ ]?result|function[-_ ]?call|thinking|reasoning)\s*[:=]/i;
|
|
6905
|
+
function hasNonEmptyRecord(value) {
|
|
6906
|
+
return Boolean(value && typeof value === "object" && !Array.isArray(value) && Object.keys(value).length > 0);
|
|
6907
|
+
}
|
|
6908
|
+
function hasInteractiveOrPresentationBlocks(value) {
|
|
6909
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return false;
|
|
6910
|
+
const record = value;
|
|
6911
|
+
if (typeof record.title === "string" && record.title.trim().length > 0) return true;
|
|
6912
|
+
return Array.isArray(record.blocks) && record.blocks.length > 0;
|
|
6913
|
+
}
|
|
6914
|
+
function hasNonTextReplyPayloadContent(payload) {
|
|
6915
|
+
return payload.audioAsVoice === true || hasNonEmptyRecord(payload.channelData) || hasInteractiveOrPresentationBlocks(payload.interactive) || hasInteractiveOrPresentationBlocks(payload.presentation);
|
|
6916
|
+
}
|
|
6917
|
+
function stripDiscordInternalTraceLines(text) {
|
|
6918
|
+
let inFence = false;
|
|
6919
|
+
const kept = [];
|
|
6920
|
+
for (const line of text.split(/\r?\n/)) {
|
|
6921
|
+
if (/^\s*```/.test(line)) {
|
|
6922
|
+
inFence = !inFence;
|
|
6923
|
+
kept.push(line);
|
|
6924
|
+
continue;
|
|
6925
|
+
}
|
|
6926
|
+
if (!inFence) {
|
|
6927
|
+
const trimmed = line.trim();
|
|
6928
|
+
if (DISCORD_INTERNAL_TRACE_LINE_RE.test(trimmed) || DISCORD_INTERNAL_COMPACT_COMMAND_TRACE_LINE_RE.test(trimmed) || DISCORD_INTERNAL_CHANNEL_LINE_RE.test(trimmed)) continue;
|
|
6929
|
+
}
|
|
6930
|
+
kept.push(line);
|
|
6931
|
+
}
|
|
6932
|
+
return kept.join("\n");
|
|
6933
|
+
}
|
|
6934
|
+
function collapseExcessBlankLines(text) {
|
|
6935
|
+
return text.replace(/[ \t]+\n/g, "\n").replace(/\n{3,}/g, "\n\n");
|
|
6936
|
+
}
|
|
6937
|
+
function sanitizeDiscordFrontChannelText(text) {
|
|
6938
|
+
return collapseExcessBlankLines(stripDiscordInternalTraceLines(sanitizeAssistantVisibleText(text))).trim();
|
|
6939
|
+
}
|
|
6940
|
+
function sanitizeDiscordFrontChannelReplyPayloads(payloads) {
|
|
6941
|
+
const safePayloads = [];
|
|
6942
|
+
for (const payload of payloads) {
|
|
6943
|
+
const safeText = typeof payload.text === "string" ? sanitizeDiscordFrontChannelText(payload.text) : payload.text;
|
|
6944
|
+
const nextPayload = safeText === payload.text ? payload : {
|
|
6945
|
+
...payload,
|
|
6946
|
+
text: safeText || void 0
|
|
6947
|
+
};
|
|
6948
|
+
if (!resolveSendableOutboundReplyParts(nextPayload).hasContent && !hasNonTextReplyPayloadContent(nextPayload)) continue;
|
|
6949
|
+
safePayloads.push(nextPayload);
|
|
6950
|
+
}
|
|
6951
|
+
return safePayloads;
|
|
6952
|
+
}
|
|
6953
|
+
//#endregion
|
|
6954
|
+
//#region extensions/discord/src/monitor/reply-delivery.ts
|
|
6955
|
+
function resolveTargetChannelId(target) {
|
|
6956
|
+
if (!target.startsWith("channel:")) return;
|
|
6957
|
+
return target.slice(8).trim() || void 0;
|
|
6958
|
+
}
|
|
6959
|
+
function resolveBoundThreadBinding(params) {
|
|
6960
|
+
const sessionKey = params.sessionKey?.trim();
|
|
6961
|
+
if (!params.threadBindings || !sessionKey) return;
|
|
6962
|
+
const targetChannelId = resolveTargetChannelId(params.target);
|
|
6963
|
+
if (!targetChannelId) return;
|
|
6964
|
+
return params.threadBindings.listBySessionKey(sessionKey).find((entry) => entry.threadId === targetChannelId);
|
|
6965
|
+
}
|
|
6966
|
+
function resolveBindingIdentity(cfg, binding) {
|
|
6967
|
+
if (!binding) return;
|
|
6968
|
+
const identity = { name: (`🤖 ${binding.label?.trim() || binding.agentId}`.trim() || "🤖 agent").slice(0, 80) };
|
|
6969
|
+
try {
|
|
6970
|
+
const avatar = resolveAgentAvatar(cfg, binding.agentId);
|
|
6971
|
+
if (avatar.kind === "remote") identity.avatarUrl = avatar.url;
|
|
6972
|
+
} catch {}
|
|
6973
|
+
return identity;
|
|
6974
|
+
}
|
|
6975
|
+
function createDiscordDeliveryDeps(params) {
|
|
6976
|
+
return {
|
|
6977
|
+
discord: (to, text, opts) => sendMessageDiscord(to, text, {
|
|
6978
|
+
...opts,
|
|
6979
|
+
cfg: opts?.cfg ?? params.cfg,
|
|
6980
|
+
token: params.token,
|
|
6981
|
+
rest: params.rest
|
|
6982
|
+
}),
|
|
6983
|
+
discordVoice: (to, audioPath, opts) => sendVoiceMessageDiscord(to, audioPath, {
|
|
6984
|
+
...opts,
|
|
6985
|
+
cfg: opts?.cfg ?? params.cfg,
|
|
6986
|
+
token: params.token,
|
|
6987
|
+
rest: params.rest
|
|
6988
|
+
})
|
|
6989
|
+
};
|
|
6990
|
+
}
|
|
6991
|
+
function resolveDiscordDeliveryOptions(params) {
|
|
6992
|
+
const binding = resolveBoundThreadBinding({
|
|
6993
|
+
threadBindings: params.threadBindings,
|
|
6994
|
+
sessionKey: params.sessionKey,
|
|
6995
|
+
target: params.target
|
|
6996
|
+
});
|
|
6997
|
+
return {
|
|
6998
|
+
to: binding ? `channel:${binding.channelId}` : params.target,
|
|
6999
|
+
threadId: binding?.threadId,
|
|
7000
|
+
agentId: binding?.agentId,
|
|
7001
|
+
identity: resolveBindingIdentity(params.cfg, binding),
|
|
7002
|
+
mediaAccess: params.mediaLocalRoots?.length ? { localRoots: params.mediaLocalRoots } : void 0,
|
|
7003
|
+
replyToMode: params.replyToMode ?? "all",
|
|
7004
|
+
formatting: {
|
|
7005
|
+
textLimit: params.textLimit,
|
|
7006
|
+
maxLinesPerMessage: params.maxLinesPerMessage,
|
|
7007
|
+
tableMode: params.tableMode,
|
|
7008
|
+
chunkMode: params.chunkMode
|
|
7009
|
+
}
|
|
7010
|
+
};
|
|
7011
|
+
}
|
|
7012
|
+
async function deliverDiscordReply(params) {
|
|
7013
|
+
params.runtime;
|
|
7014
|
+
const delivery = resolveDiscordDeliveryOptions(params);
|
|
7015
|
+
const payloads = sanitizeDiscordFrontChannelReplyPayloads(params.replies);
|
|
7016
|
+
if (payloads.length === 0) return;
|
|
7017
|
+
const send = await sendDurableMessageBatch({
|
|
7018
|
+
cfg: params.cfg,
|
|
7019
|
+
channel: "discord",
|
|
7020
|
+
to: delivery.to,
|
|
7021
|
+
accountId: params.accountId,
|
|
7022
|
+
payloads,
|
|
7023
|
+
replyToId: normalizeOptionalString(params.replyToId),
|
|
7024
|
+
replyToMode: delivery.replyToMode,
|
|
7025
|
+
formatting: delivery.formatting,
|
|
7026
|
+
threadId: delivery.threadId,
|
|
7027
|
+
identity: delivery.identity,
|
|
7028
|
+
deps: createDiscordDeliveryDeps({
|
|
7029
|
+
cfg: params.cfg,
|
|
7030
|
+
token: params.token,
|
|
7031
|
+
rest: params.rest
|
|
7032
|
+
}),
|
|
7033
|
+
mediaAccess: delivery.mediaAccess,
|
|
7034
|
+
session: buildOutboundSessionContext({
|
|
7035
|
+
cfg: params.cfg,
|
|
7036
|
+
sessionKey: params.sessionKey,
|
|
7037
|
+
agentId: delivery.agentId,
|
|
7038
|
+
requesterAccountId: params.accountId
|
|
7039
|
+
})
|
|
7040
|
+
});
|
|
7041
|
+
if (send.status === "failed" || send.status === "partial_failed") throw send.error;
|
|
7042
|
+
if ((send.status === "sent" ? send.results : []).length === 0) throw new Error(`discord final reply produced no delivered message for ${delivery.to}`);
|
|
7043
|
+
}
|
|
7044
|
+
//#endregion
|
|
6057
7045
|
//#region extensions/discord/src/monitor/agent-components.dispatch.ts
|
|
6058
7046
|
let conversationRuntimePromise$1;
|
|
6059
7047
|
let typingRuntimePromise;
|
|
6060
7048
|
async function loadConversationRuntime$1() {
|
|
6061
|
-
conversationRuntimePromise$1 ??= import("./agent-components.runtime-
|
|
7049
|
+
conversationRuntimePromise$1 ??= import("./agent-components.runtime-CEMbMQcQ.js");
|
|
6062
7050
|
return await conversationRuntimePromise$1;
|
|
6063
7051
|
}
|
|
6064
7052
|
async function loadTypingRuntime() {
|
|
6065
|
-
typingRuntimePromise ??= import("./typing-
|
|
7053
|
+
typingRuntimePromise ??= import("./typing-C_8U8J7E.js").then((n) => n.n);
|
|
6066
7054
|
return await typingRuntimePromise;
|
|
6067
7055
|
}
|
|
6068
7056
|
function buildDiscordComponentConversationLabel(params) {
|
|
@@ -6200,6 +7188,12 @@ async function dispatchDiscordComponentEvent(params) {
|
|
|
6200
7188
|
Surface: "discord",
|
|
6201
7189
|
WasMentioned: true,
|
|
6202
7190
|
CommandAuthorized: commandAuthorized,
|
|
7191
|
+
CommandTurn: {
|
|
7192
|
+
kind: "text-slash",
|
|
7193
|
+
source: "text",
|
|
7194
|
+
authorized: commandAuthorized,
|
|
7195
|
+
body: eventText
|
|
7196
|
+
},
|
|
6203
7197
|
CommandSource: "text",
|
|
6204
7198
|
MessageSid: interaction.rawData.id,
|
|
6205
7199
|
Timestamp: timestamp,
|
|
@@ -6349,7 +7343,7 @@ async function dispatchDiscordPluginInteractiveHandler(params) {
|
|
|
6349
7343
|
//#region extensions/discord/src/monitor/agent-components.plugin-interactive.ts
|
|
6350
7344
|
let conversationRuntimePromise;
|
|
6351
7345
|
async function loadConversationRuntime() {
|
|
6352
|
-
conversationRuntimePromise ??= import("./agent-components.runtime-
|
|
7346
|
+
conversationRuntimePromise ??= import("./agent-components.runtime-CEMbMQcQ.js");
|
|
6353
7347
|
return await conversationRuntimePromise;
|
|
6354
7348
|
}
|
|
6355
7349
|
async function dispatchPluginDiscordInteractiveEvent(params) {
|
|
@@ -6475,7 +7469,7 @@ async function dispatchPluginDiscordInteractiveEvent(params) {
|
|
|
6475
7469
|
//#region extensions/discord/src/monitor/agent-components.handlers.ts
|
|
6476
7470
|
let componentsRuntimePromise;
|
|
6477
7471
|
async function loadComponentsRuntime() {
|
|
6478
|
-
componentsRuntimePromise ??= import("./components-
|
|
7472
|
+
componentsRuntimePromise ??= import("./components-Cgm7XT8-.js").then((n) => n.t);
|
|
6479
7473
|
return await componentsRuntimePromise;
|
|
6480
7474
|
}
|
|
6481
7475
|
async function handleDiscordComponentEvent(params) {
|
|
@@ -7982,7 +8976,7 @@ function logDiscordStartupPhase(params) {
|
|
|
7982
8976
|
});
|
|
7983
8977
|
}
|
|
7984
8978
|
async function loadDiscordVoiceRuntime() {
|
|
7985
|
-
const promise = discordVoiceRuntimePromise ?? import("./manager.runtime-
|
|
8979
|
+
const promise = discordVoiceRuntimePromise ?? import("./manager.runtime-DauS2xA3.js");
|
|
7986
8980
|
discordVoiceRuntimePromise = promise;
|
|
7987
8981
|
try {
|
|
7988
8982
|
return await promise;
|
|
@@ -7992,7 +8986,7 @@ async function loadDiscordVoiceRuntime() {
|
|
|
7992
8986
|
}
|
|
7993
8987
|
}
|
|
7994
8988
|
async function loadDiscordProviderSessionRuntime() {
|
|
7995
|
-
const promise = discordProviderSessionRuntimePromise ?? import("./provider-session.runtime-
|
|
8989
|
+
const promise = discordProviderSessionRuntimePromise ?? import("./provider-session.runtime-DMxaLPB3.js");
|
|
7996
8990
|
discordProviderSessionRuntimePromise = promise;
|
|
7997
8991
|
try {
|
|
7998
8992
|
return await promise;
|
|
@@ -8362,4 +9356,4 @@ async function monitorDiscordProvider(opts = {}) {
|
|
|
8362
9356
|
}
|
|
8363
9357
|
}
|
|
8364
9358
|
//#endregion
|
|
8365
|
-
export {
|
|
9359
|
+
export { resolveDiscordDmCommandAccess as C, sanitizeDiscordThreadName as S, registerDiscordListener as _, resolveReplyContext as a, resolveDiscordReplyTarget as b, resolveDiscordGatewayIntents as c, createDiscordNativeCommand as d, buildDiscordRoutePeer as f, handleDiscordDmCommandDecision as g, shouldIgnoreStaleDiscordRouteBinding as h, buildGuildLabel as i, waitForDiscordGatewayPluginRegistration as l, resolveDiscordEffectiveRoute as m, deliverDiscordReply as n, authorizeDiscordVoiceIngress as o, resolveDiscordConversationRoute as p, buildDirectLabel as r, createDiscordGatewayPlugin as s, monitorDiscordProvider as t, resolveDiscordVoiceEnabled as u, threading_exports as v, resolveDiscordTextCommandAccess as w, resolveDiscordThreadStarter as x, resolveDiscordAutoThreadReplyPlan as y };
|