@openclaw/discord 2026.8.1-beta.2 → 2026.8.1
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-CqzrH14k.js → account-inspect-BDfKyuvL.js} +1 -1
- package/dist/account-inspect-api.js +1 -1
- package/dist/{accounts-DJTf1LtA.js → accounts-CfQ-vSyf.js} +34 -1
- package/dist/action-runtime-api.js +1 -1
- package/dist/{activities-api-DS7vpdtp.js → activities-api-Dl-TOyOX.js} +134 -175
- package/dist/activities-api.js +1 -1
- package/dist/api.js +17 -17
- package/dist/{approval-handler.runtime-B6yEV79q.js → approval-handler.runtime-q4Zqo44V.js} +29 -106
- package/dist/{audit-Db-rlntl.js → audit-DgrvFPGt.js} +5 -5
- package/dist/{channel-CnnbJSt5.js → channel-BsQUalPw.js} +72 -50
- package/dist/{channel-actions.runtime-CLKrx6tr.js → channel-actions.runtime-UMGGIfSy.js} +31 -45
- package/dist/channel-config-api.js +1 -1
- package/dist/channel-plugin-api.js +1 -1
- package/dist/channel-type-CVLZyGYS.js +7 -0
- package/dist/{channel.setup-BFAO-V1P.js → channel.setup-rPs4dsk_.js} +5 -5
- package/dist/{outbound-session-route-DxLkrgKQ.js → components-Dk35LTf_.js} +34 -76
- package/dist/{config-schema-BgEskFAs.js → config-schema-CxPqtVI1.js} +46 -14
- package/dist/conversation-binding-route-BjvX4e35.js +43 -0
- package/dist/{directory-config-BVX7Cflc.js → directory-config-B7DY_pNG.js} +2 -2
- package/dist/directory-contract-api.js +1 -1
- package/dist/{directory-live-DGIGxpIo.js → directory-live-DuAXKkan.js} +3 -3
- package/dist/doctor-contract-api.js +2 -2
- package/dist/{doctor-BzC-TLnB.js → doctor-zQTtn6hm.js} +33 -12
- package/dist/{handle-action.guild-admin-BNVTUISF.js → handle-action.guild-admin-DZewwLr1.js} +9 -5
- package/dist/index.js +3 -4
- package/dist/ingress-identity-CzZKcPK8.js +60 -0
- package/dist/{message-handler-Unk_f10F.js → message-handler-C5By3yl5.js} +82 -6
- package/dist/{message-handler.preflight-C9zecxR9.js → message-handler.preflight-DrszWuHw.js} +44 -118
- package/dist/{message-handler.process-DWQ6UHHu.js → message-handler.process-DyFPDLCt.js} +205 -235
- package/dist/{message-utils-BSCPVgy0.js → message-text-Ca8M6TU8.js} +43 -42
- package/dist/{outbound-adapter-D9nRivT1.js → outbound-adapter-Dif8p481.js} +118 -91
- package/dist/{outbound-components-cTzwBJ60.js → outbound-components-wjv7yyAj.js} +5 -4
- package/dist/outbound-session-route-Bn4uXaoE.js +665 -0
- package/dist/owner-access-UlYi9t0M.js +107 -0
- package/dist/{pluralkit-DdiJ9KMK.js → pluralkit-9EuEN4UD.js} +1 -1
- package/dist/{probe-Bl-k5_Ku.js → probe-n6ZXxK8V.js} +1 -1
- package/dist/{probe.runtime-M9fREKvp.js → probe.runtime-CN4bdPfZ.js} +1 -1
- package/dist/{provider-DvSNb-2v.js → provider-LXiOcJrH.js} +887 -1350
- package/dist/{provider-session.runtime-BUEqD0rA.js → provider-session.runtime-DSNe7r2W.js} +3 -3
- package/dist/provider.runtime-DiInaDXO.js +2 -0
- package/dist/{realtime-session.runtime-C7wen-aF.js → realtime-session.runtime-DOViOIjY.js} +129 -134
- package/dist/{resolve-allowlist-common-D04lpEzb.js → resolve-allowlist-common-BLoYaxEG.js} +2 -2
- package/dist/{resolve-channels-Dm7jEeg6.js → resolve-channels-D2yl_2CN.js} +5 -4
- package/dist/{resolve-users-bktrCUUU.js → resolve-users-BLxfqajZ.js} +2 -2
- package/dist/{retry-CLpJcXXf.js → retry-DqHCW6PV.js} +187 -19
- package/dist/{runtime-DGsSyDTS.js → runtime-BYamRVPN.js} +89 -86
- package/dist/{runtime-DoHjckYm.js → runtime-DrxVBTtp.js} +9 -10
- package/dist/runtime-api.js +19 -25
- package/dist/{sdk-runtime-QpY8PvCh.js → sdk-runtime-6tfgYDjY.js} +57 -89
- package/dist/{secret-config-contract-B1akrlyY.js → secret-config-contract-B3i6WxV5.js} +53 -25
- package/dist/secret-contract-api.js +1 -1
- package/dist/{security-audit-jGnJF__m.js → security-audit-DKfK-iPY.js} +11 -12
- package/dist/security-audit-contract-api.js +1 -1
- package/dist/{security-audit.runtime-CPN0xFYz.js → security-audit.runtime-sKZyKgpx.js} +1 -1
- package/dist/{send-B7Q6Oc1I.js → send-UJHiAm4C.js} +82 -19
- package/dist/{send.components-iJyFXw9L.js → send.components-CrBJpGT_.js} +22 -39
- package/dist/{send.outbound-DS5tHwfR.js → send.outbound-D7JYmfm9.js} +77 -78
- package/dist/{send.shared-BmwFjW6T.js → send.shared-DZJ1akvQ.js} +136 -121
- package/dist/{sender-identity-QtalnCYv.js → sender-identity-BJtfyise.js} +1 -1
- package/dist/setup-plugin-api.js +1 -1
- package/dist/{shared-BIXIX6uJ.js → shared-Dii2HTn7.js} +41 -14
- package/dist/subagent-hooks-JyGrtQIl.js +49 -0
- package/dist/subagent-hooks-api.js +1 -6
- package/dist/{system-events-CTqDf6_s.js → system-events-BEmcj4xJ.js} +2 -2
- package/dist/{target-resolver-maOKSqO0.js → target-resolver-V-IYae6s.js} +3 -3
- package/dist/targets-CQp53cGj.js +3 -0
- package/dist/{thread-bindings-3L8p82GV.js → thread-bindings-DvYP79fy.js} +28 -26
- package/dist/{thread-bindings.manager-DCIH6WDC.js → thread-bindings.manager-Clm77DBM.js} +11 -14
- package/dist/{thread-bindings.session-updates-bJ2KQFY6.js → thread-bindings.session-updates-CJb-BpPL.js} +1 -1
- package/dist/{thread-bindings.state-aeV8HNgV.js → thread-bindings.state-D8OMdk4O.js} +1 -1
- package/dist/threading-CXuu_7o9.js +478 -0
- package/dist/transcripts-source-BLEMH_yi.js +270 -0
- package/dist/transcripts-source-api.js +7 -2
- package/dist/{typing-CS-nNVoe.js → typing-B9snnwMe.js} +1 -1
- package/dist/{voice-runtime-BEdqNcST.js → voice-runtime-DY6_o73o.js} +250 -150
- package/node_modules/@discord/embedded-app-sdk/node_modules/uuid/README.md +19 -19
- package/node_modules/@discord/embedded-app-sdk/node_modules/uuid/dist/v1.js +7 -3
- package/node_modules/@discord/embedded-app-sdk/node_modules/uuid/dist/v7.js +5 -2
- package/node_modules/@discord/embedded-app-sdk/node_modules/uuid/dist-node/v1.js +7 -3
- package/node_modules/@discord/embedded-app-sdk/node_modules/uuid/dist-node/v7.js +5 -2
- package/node_modules/@discord/embedded-app-sdk/node_modules/uuid/package.json +4 -3
- package/node_modules/@discordjs/voice/node_modules/@types/node/README.md +1 -1
- package/node_modules/@discordjs/voice/node_modules/@types/node/child_process.d.ts +0 -1
- package/node_modules/@discordjs/voice/node_modules/@types/node/crypto.d.ts +6 -6
- package/node_modules/@discordjs/voice/node_modules/@types/node/dns/promises.d.ts +5 -5
- package/node_modules/@discordjs/voice/node_modules/@types/node/dns.d.ts +5 -5
- package/node_modules/@discordjs/voice/node_modules/@types/node/fs.d.ts +7 -0
- package/node_modules/@discordjs/voice/node_modules/@types/node/http.d.ts +30 -0
- package/node_modules/@discordjs/voice/node_modules/@types/node/http2.d.ts +4 -4
- package/node_modules/@discordjs/voice/node_modules/@types/node/os.d.ts +30 -30
- package/node_modules/@discordjs/voice/node_modules/@types/node/package.json +2 -2
- package/node_modules/@discordjs/voice/node_modules/@types/node/perf_hooks.d.ts +2 -1
- package/node_modules/@discordjs/voice/node_modules/@types/node/process.d.ts +42 -43
- package/node_modules/@discordjs/voice/node_modules/@types/node/quic.d.ts +1049 -84
- package/node_modules/@discordjs/voice/node_modules/@types/node/sqlite.d.ts +14 -1
- package/node_modules/@discordjs/voice/node_modules/@types/node/stream/iter.d.ts +3 -2
- package/node_modules/@discordjs/voice/node_modules/@types/node/test.d.ts +61 -0
- package/node_modules/@discordjs/voice/node_modules/@types/node/v8.d.ts +20 -23
- package/node_modules/discord-api-types/CHANGELOG.md +8 -0
- package/node_modules/discord-api-types/package.json +4 -4
- package/node_modules/discord-api-types/payloads/v10/channel.d.ts +2 -2
- package/node_modules/discord-api-types/payloads/v10/channel.d.ts.map +1 -1
- package/node_modules/discord-api-types/payloads/v10/gateway.d.ts +4 -0
- package/node_modules/discord-api-types/payloads/v10/gateway.d.ts.map +1 -1
- package/node_modules/discord-api-types/payloads/v10/gateway.js.map +1 -1
- package/node_modules/discord-api-types/payloads/v10/message.d.ts +4 -1
- package/node_modules/discord-api-types/payloads/v10/message.d.ts.map +1 -1
- package/node_modules/discord-api-types/payloads/v10/message.js +1 -0
- package/node_modules/discord-api-types/payloads/v10/message.js.map +1 -1
- package/node_modules/discord-api-types/payloads/v9/channel.d.ts +2 -2
- package/node_modules/discord-api-types/payloads/v9/channel.d.ts.map +1 -1
- package/node_modules/discord-api-types/payloads/v9/gateway.d.ts +4 -0
- package/node_modules/discord-api-types/payloads/v9/gateway.d.ts.map +1 -1
- package/node_modules/discord-api-types/payloads/v9/gateway.js.map +1 -1
- package/node_modules/discord-api-types/payloads/v9/message.d.ts +4 -1
- package/node_modules/discord-api-types/payloads/v9/message.d.ts.map +1 -1
- package/node_modules/discord-api-types/payloads/v9/message.js +1 -0
- package/node_modules/discord-api-types/payloads/v9/message.js.map +1 -1
- package/node_modules/typebox/build/format/date.d.mts +1 -1
- package/node_modules/typebox/build/format/date.mjs +1 -1
- package/node_modules/typebox/build/format/date_time.d.mts +2 -2
- package/node_modules/typebox/build/format/date_time.mjs +3 -3
- package/node_modules/typebox/build/format/email.d.mts +1 -1
- package/node_modules/typebox/build/format/email.mjs +2 -2
- package/node_modules/typebox/build/format/hostname.mjs +2 -10
- package/node_modules/typebox/build/format/idn_email.d.mts +1 -1
- package/node_modules/typebox/build/format/idn_email.mjs +3 -3
- package/node_modules/typebox/build/format/idn_hostname.d.mts +1 -0
- package/node_modules/typebox/build/format/idn_hostname.mjs +3 -11
- package/node_modules/typebox/build/format/idna/format/bidi.d.mts +3 -0
- package/node_modules/typebox/build/format/idna/format/bidi.mjs +98 -0
- package/node_modules/typebox/build/format/idna/format/puny.d.mts +3 -0
- package/node_modules/typebox/build/format/idna/format/puny.mjs +144 -0
- package/node_modules/typebox/build/format/idna/hostname.d.mts +1 -0
- package/node_modules/typebox/build/format/idna/hostname.mjs +16 -0
- package/node_modules/typebox/build/format/idna/idn-hostname.d.mts +1 -0
- package/node_modules/typebox/build/format/idna/idn-hostname.mjs +23 -0
- package/node_modules/typebox/build/format/idna/index.d.mts +2 -0
- package/node_modules/typebox/build/format/idna/index.mjs +2 -0
- package/node_modules/typebox/build/format/idna/label/ascii.d.mts +1 -0
- package/node_modules/typebox/build/format/idna/label/ascii.mjs +9 -0
- package/node_modules/typebox/build/format/idna/label/puny.d.mts +1 -0
- package/node_modules/typebox/build/format/idna/label/puny.mjs +28 -0
- package/node_modules/typebox/build/format/idna/label/unicode.d.mts +1 -0
- package/node_modules/typebox/build/format/idna/label/unicode.mjs +106 -0
- package/node_modules/typebox/build/format/idna/pattern/pattern.d.mts +30 -0
- package/node_modules/typebox/build/format/idna/pattern/pattern.mjs +70 -0
- package/node_modules/typebox/build/format/ipv4.d.mts +0 -1
- package/node_modules/typebox/build/format/ipv4.mjs +2 -32
- package/node_modules/typebox/build/format/ipv6.mjs +2 -61
- package/node_modules/typebox/build/format/iri.d.mts +2 -2
- package/node_modules/typebox/build/format/iri.mjs +26 -8
- package/node_modules/typebox/build/format/iri_reference.d.mts +2 -2
- package/node_modules/typebox/build/format/iri_reference.mjs +9 -55
- package/node_modules/typebox/build/format/regex.d.mts +1 -2
- package/node_modules/typebox/build/format/regex.mjs +2 -6
- package/node_modules/typebox/build/format/time.d.mts +2 -2
- package/node_modules/typebox/build/format/time.mjs +19 -14
- package/node_modules/typebox/build/format/uri.d.mts +1 -1
- package/node_modules/typebox/build/format/uri.mjs +3 -130
- package/node_modules/typebox/build/format/uri_reference.d.mts +1 -1
- package/node_modules/typebox/build/format/uri_reference.mjs +2 -3
- package/node_modules/typebox/build/format/uri_template.d.mts +2 -3
- package/node_modules/typebox/build/format/uri_template.mjs +4 -5
- package/node_modules/typebox/build/format/url.d.mts +3 -3
- package/node_modules/typebox/build/format/url.mjs +4 -5
- package/node_modules/typebox/build/guard/emit.d.mts +3 -1
- package/node_modules/typebox/build/guard/emit.mjs +12 -5
- package/node_modules/typebox/build/guard/guard.d.mts +8 -2
- package/node_modules/typebox/build/guard/guard.mjs +25 -4
- package/node_modules/typebox/build/guard/string.d.mts +2 -2
- package/node_modules/typebox/build/guard/string.mjs +7 -7
- package/node_modules/typebox/build/schema/engine/_context.mjs +3 -3
- package/node_modules/typebox/build/schema/engine/_functions.mjs +1 -2
- package/node_modules/typebox/build/schema/engine/_regexp.d.mts +2 -0
- package/node_modules/typebox/build/schema/engine/_regexp.mjs +4 -0
- package/node_modules/typebox/build/schema/engine/_stack.mjs +12 -13
- package/node_modules/typebox/build/schema/engine/additionalItems.mjs +17 -7
- package/node_modules/typebox/build/schema/engine/additionalProperties.mjs +4 -3
- package/node_modules/typebox/build/schema/engine/contains.mjs +18 -6
- package/node_modules/typebox/build/schema/engine/enum.mjs +1 -1
- package/node_modules/typebox/build/schema/engine/items.mjs +26 -6
- package/node_modules/typebox/build/schema/engine/maxContains.mjs +3 -3
- package/node_modules/typebox/build/schema/engine/minContains.mjs +14 -4
- package/node_modules/typebox/build/schema/engine/not.mjs +4 -2
- package/node_modules/typebox/build/schema/engine/oneOf.mjs +7 -6
- package/node_modules/typebox/build/schema/engine/pattern.mjs +3 -2
- package/node_modules/typebox/build/schema/engine/patternProperties.mjs +4 -3
- package/node_modules/typebox/build/schema/engine/ref.mjs +1 -7
- package/node_modules/typebox/build/schema/engine/schema.mjs +13 -4
- package/node_modules/typebox/build/schema/engine/type.mjs +1 -1
- package/node_modules/typebox/build/schema/resolve/resolve.d.mts +4 -1
- package/node_modules/typebox/build/schema/resolve/resolve.mjs +202 -1
- package/node_modules/typebox/build/schema/static/propertyNames.d.mts +5 -0
- package/node_modules/typebox/build/schema/static/propertyNames.mjs +3 -0
- package/node_modules/typebox/build/schema/static/schema.d.mts +3 -0
- package/node_modules/typebox/build/schema/types/index.d.mts +0 -2
- package/node_modules/typebox/build/schema/types/index.mjs +0 -2
- package/node_modules/typebox/build/system/memory/clone.mjs +14 -11
- package/node_modules/typebox/build/system/memory/discard.mjs +6 -5
- package/node_modules/typebox/build/system/settings/settings.d.mts +9 -0
- package/node_modules/typebox/build/system/settings/settings.mjs +2 -0
- package/node_modules/typebox/build/type/engine/call/distribute_arguments.d.mts +6 -1
- package/node_modules/typebox/build/type/engine/call/distribute_arguments.mjs +16 -3
- package/node_modules/typebox/build/type/engine/call/instantiate.mjs +34 -4
- package/node_modules/typebox/build/type/engine/evaluate/broaden.d.mts +5 -5
- package/node_modules/typebox/build/type/engine/evaluate/broaden.mjs +20 -26
- package/node_modules/typebox/build/type/engine/evaluate/compare.d.mts +6 -10
- package/node_modules/typebox/build/type/engine/evaluate/compare.mjs +9 -13
- package/node_modules/typebox/build/type/engine/evaluate/composite.d.mts +7 -4
- package/node_modules/typebox/build/type/engine/evaluate/composite.mjs +12 -19
- package/node_modules/typebox/build/type/engine/evaluate/distribute.d.mts +4 -20
- package/node_modules/typebox/build/type/engine/evaluate/distribute.mjs +8 -20
- package/node_modules/typebox/build/type/engine/evaluate/evaluate.d.mts +4 -4
- package/node_modules/typebox/build/type/engine/evaluate/evaluate.mjs +11 -8
- package/node_modules/typebox/build/type/engine/evaluate/flatten.d.mts +1 -1
- package/node_modules/typebox/build/type/engine/evaluate/flatten.mjs +3 -4
- package/node_modules/typebox/build/type/engine/evaluate/narrow.d.mts +17 -2
- package/node_modules/typebox/build/type/engine/evaluate/narrow.mjs +26 -6
- package/node_modules/typebox/build/type/engine/exclude/operation.mjs +3 -4
- package/node_modules/typebox/build/type/engine/extract/operation.d.mts +1 -1
- package/node_modules/typebox/build/type/engine/extract/operation.mjs +3 -4
- package/node_modules/typebox/build/type/engine/priority/priority.d.mts +2 -2
- package/node_modules/typebox/build/type/engine/priority/priority.mjs +3 -4
- package/node_modules/typebox/build/type/script/mapping.d.mts +32 -29
- package/node_modules/typebox/build/type/script/mapping.mjs +18 -25
- package/node_modules/typebox/build/type/script/parser.d.mts +19 -25
- package/node_modules/typebox/build/type/script/parser.mjs +27 -23
- package/node_modules/typebox/build/value/errors/errors.d.mts +2 -2
- package/node_modules/typebox/build/value/errors/errors.mjs +1 -1
- package/node_modules/typebox/package.json +27 -27
- package/node_modules/typebox/readme.md +79 -82
- package/node_modules/undici/docs/docs/api/Client.md +21 -8
- package/node_modules/undici/lib/api/readable.js +33 -43
- package/node_modules/undici/lib/core/connect.js +16 -2
- package/node_modules/undici/lib/core/symbols.js +1 -0
- package/node_modules/undici/lib/dispatcher/client-h1.js +3 -3
- package/node_modules/undici/lib/dispatcher/client-h2.js +179 -10
- package/node_modules/undici/lib/dispatcher/client.js +74 -29
- package/node_modules/undici/lib/dispatcher/env-http-proxy-agent.js +28 -6
- package/node_modules/undici/lib/dispatcher/socks5-proxy-agent.js +15 -1
- package/node_modules/undici/lib/handler/retry-handler.js +7 -2
- package/node_modules/undici/lib/interceptor/cache.js +5 -2
- package/node_modules/undici/lib/interceptor/deduplicate.js +1 -1
- package/node_modules/undici/lib/mock/mock-utils.js +213 -24
- package/node_modules/undici/lib/util/cache.js +2 -4
- package/node_modules/undici/lib/web/websocket/websocket.js +22 -0
- package/node_modules/undici/package.json +1 -1
- package/node_modules/undici/types/client.d.ts +40 -0
- package/node_modules/ws/lib/permessage-deflate.js +3 -1
- package/node_modules/ws/package.json +1 -1
- package/openclaw.plugin.json +24 -10
- package/package.json +8 -10
- package/skills/discord/SKILL.md +1 -1
- package/dist/approval-message-safety-AcIxvrf3.js +0 -140
- package/dist/audit-core-xwjIczO0.js +0 -105
- package/dist/channel-actions-5s_hjYKd.js +0 -208
- package/dist/channel-api-CAJ0wMoV.js +0 -21
- package/dist/inbound-event-delivery-De2qxTrP.js +0 -39
- package/dist/provider.runtime-C9PnJZbZ.js +0 -2
- package/dist/runtime-api.actions.js +0 -3
- package/dist/runtime-api.lookup.js +0 -7
- package/dist/runtime-api.monitor-CHxrFPnW.js +0 -5
- package/dist/runtime-api.monitor.js +0 -8
- package/dist/runtime-api.send.js +0 -7
- package/dist/runtime-api.threads.js +0 -5
- package/dist/send.reactions-BAn0iiVQ.js +0 -78
- package/dist/send.receipt-IPI1p-SP.js +0 -66
- package/dist/subagent-hooks-CTt5KCJr.js +0 -120
- package/dist/subagent-progress-DhaE_h8a.js +0 -109
- package/dist/targets-yUFTHoAx.js +0 -3
- package/dist/transcripts-source-CfFMexGt.js +0 -123
- package/node_modules/p-map/index.d.ts +0 -155
- package/node_modules/p-map/index.js +0 -285
- package/node_modules/p-map/license +0 -9
- package/node_modules/p-map/package.json +0 -57
- package/node_modules/p-map/readme.md +0 -190
- package/node_modules/typebox/build/format/_idna.d.mts +0 -2
- package/node_modules/typebox/build/format/_idna.mjs +0 -246
- package/node_modules/typebox/build/format/_puny.d.mts +0 -1
- package/node_modules/typebox/build/format/_puny.mjs +0 -77
- package/node_modules/typebox/build/schema/resolve/ref.d.mts +0 -3
- package/node_modules/typebox/build/schema/resolve/ref.mjs +0 -146
- package/node_modules/typebox/build/schema/types/contentEncoding.d.mts +0 -9
- package/node_modules/typebox/build/schema/types/contentEncoding.mjs +0 -13
- package/node_modules/typebox/build/schema/types/contentMediaType.d.mts +0 -9
- package/node_modules/typebox/build/schema/types/contentMediaType.mjs +0 -13
- package/dist/{allow-list-DnxIlPP2.js → allow-list-BDMimASD.js} +1 -1
- package/dist/{doctor-contract-DLa-BTiU.js → doctor-contract-DsWvKIXF.js} +1 -1
|
@@ -1,39 +1,44 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { c as
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
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";
|
|
1
|
+
import { A as ThreadUpdateListener, C as MessageCreateListener, D as ReadyListener, E as PresenceUpdateListener, G as User, H as CommandWithSubcommands, I as RateLimitError, K as hasDiscordV2Components, M as Client, N as Plugin, S as InteractionCreateListener, T as MessageReactionRemoveListener, U as Guild, V as Command, W as Message, Z as Modal, a as chunkDiscordTextWithMode, b as GuildCreateListener, ct as Row, dt as StringSelectMenu, et as Button, ft as TextDisplay, ht as BaseMessageInteractiveComponent, k as ThreadDeleteListener, nt as Container, ut as Separator, w as MessageReactionAddListener, x as GuildDeleteListener, y as discord_exports } from "./retry-DqHCW6PV.js";
|
|
2
|
+
import { C as parseDiscordActivityCustomIdForInteraction, D as parseDiscordModalCustomIdForInteraction, E as parseDiscordModalCustomId, O as decodeCustomIdComponent, T as parseDiscordComponentCustomIdForInteraction, c as parseExecApprovalData, k as encodeCustomIdComponent, o as parseDiscordQuestionData, w as parseDiscordComponentCustomId, y as buildDiscordActivityCustomId } from "./components-Dk35LTf_.js";
|
|
3
|
+
import { c as resolveDiscordAccount, f as resolveDiscordAccountDmPolicy, l as resolveDiscordAccountAllowFrom, m as normalizeDiscordToken, p as resolveDiscordMaxLinesPerMessage } from "./accounts-CfQ-vSyf.js";
|
|
4
|
+
import { a as resolveDiscordComponentEntryWithPersistence, o as resolveDiscordModalEntryWithPersistence, t as editDiscordComponentMessage } from "./send.components-CrBJpGT_.js";
|
|
7
5
|
import { t as getDiscordRuntime } from "./runtime-DgnVQ7zW.js";
|
|
8
6
|
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,
|
|
10
|
-
import {
|
|
7
|
+
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, s as resolveDiscordChannelConfig, v as resolveGroupDmAllow, x as formatDiscordUserTag, y as shouldEmitDiscordReactionNotification } from "./allow-list-BDMimASD.js";
|
|
8
|
+
import { B as validateDiscordProxyUrl, G as unregisterGateway, P as createDiscordRestClient, R as DISCORD_REST_TIMEOUT_MS, V as withValidatedDiscordProxy, W as registerGateway, b as canViewDiscordGuildChannel, w as hasAnyChannelPermissionDiscord } from "./send.shared-DZJ1akvQ.js";
|
|
9
|
+
import { a as formatMention, t as sendMessageDiscord } from "./send.outbound-D7JYmfm9.js";
|
|
10
|
+
import { t as isDiscordThreadChannelType } from "./channel-type-CVLZyGYS.js";
|
|
11
|
+
import { n as getDiscordActivitiesRuntime } from "./runtime-DrxVBTtp.js";
|
|
12
|
+
import { n as resolveDiscordVoiceEnabled, r as authorizeDiscordVoiceIngress, t as resolveDiscordVoiceAccess } from "./owner-access-UlYi9t0M.js";
|
|
11
13
|
import { i as setPresence, t as clearPresences } from "./presence-cache-z1N8MbJ3.js";
|
|
12
|
-
import {
|
|
14
|
+
import { _ as readMessagesDiscord, s as sendVoiceMessageDiscord } from "./send-UJHiAm4C.js";
|
|
13
15
|
import { c as raceWithTimeout, u as withAbortTimeout } from "./timeouts-B9cy6RvQ.js";
|
|
14
|
-
import {
|
|
15
|
-
import { t as
|
|
16
|
-
import { t as
|
|
17
|
-
import {
|
|
18
|
-
import { a as
|
|
16
|
+
import { S as isDiscordExecApprovalClientEnabled, b as getDiscordExecApprovalApprovers, c as resolveDiscordEffectiveRoute, i as buildDiscordConversationRouteContext, n as DISCORD_APPROVAL_ALLOWED_MENTIONS, o as resolveDiscordBoundConversationRoute, r as formatDiscordApprovalDisplayValue, u as resolveDiscordConversationIdentity } from "./outbound-session-route-Bn4uXaoE.js";
|
|
17
|
+
import { t as discordIngressIdentity } from "./ingress-identity-CzZKcPK8.js";
|
|
18
|
+
import { t as resolveDiscordChannelAllowlist } from "./resolve-channels-D2yl_2CN.js";
|
|
19
|
+
import { t as resolveDiscordUserAllowlist } from "./resolve-users-BLxfqajZ.js";
|
|
20
|
+
import { a as isThreadArchived, c as resolveDiscordChannelInfoSafe, f as resolveDiscordChannelTopicSafe, h as formatThreadBindingDurationLabel, l as resolveDiscordChannelNameSafe, r as getThreadBindingManager, s as resolveDiscordChannelIdSafe, u as resolveDiscordChannelParentIdSafe } from "./thread-bindings.manager-Clm77DBM.js";
|
|
21
|
+
import { a as probeDiscordApplicationId, r as parseApplicationIdFromToken } from "./probe-n6ZXxK8V.js";
|
|
19
22
|
import { i as sanitizeRecentModels, n as normalizeModelRef, r as preferenceTimestampMs, t as buildPreferenceModelKey } from "./model-picker-preference-primitives-BHT1LkR_.js";
|
|
20
|
-
import {
|
|
21
|
-
import {
|
|
22
|
-
import {
|
|
23
|
-
import { buildAgentSessionKey, deriveLastRoutePolicy, isAcpSessionKey, isSubagentSessionKey, parseAgentSessionKey, resolveAgentIdFromSessionKey, resolveAgentRoute } from "openclaw/plugin-sdk/routing";
|
|
24
|
-
import { asFiniteNumber, normalizeLowercaseStringOrEmpty, normalizeOptionalLowercaseString, normalizeOptionalString, normalizeOptionalStringifiedId, normalizeStringEntries, parseFiniteNumber, parseStrictNonNegativeInteger, summarizeStringEntries } from "openclaw/plugin-sdk/string-coerce-runtime";
|
|
25
|
-
import { getRuntimeConfig, getRuntimeConfigSnapshot } from "openclaw/plugin-sdk/runtime-config-snapshot";
|
|
23
|
+
import { f as resolveDiscordChannelInfo, u as resolveDiscordMessageStickers } from "./message-text-Ca8M6TU8.js";
|
|
24
|
+
import { i as resolveDiscordThreadParentInfo } from "./threading-CXuu_7o9.js";
|
|
25
|
+
import { t as resolveDiscordSenderIdentity } from "./sender-identity-BJtfyise.js";
|
|
26
26
|
import { logDebug, logError } from "openclaw/plugin-sdk/logging-core";
|
|
27
|
-
import { ApplicationCommandOptionType, ButtonStyle, ChannelType, ComponentType, GatewayCloseCodes, GatewayCloseCodes as GatewayCloseCodes$1, GatewayDispatchEvents, GatewayIntentBits, GatewayOpcodes } from "discord-api-types/v10";
|
|
28
|
-
import { createHash, randomUUID } from "node:crypto";
|
|
29
|
-
import { MAX_DATE_TIMESTAMP_MS, asDateTimestampMs, parseFiniteNumber as parseFiniteNumber$1, parseStrictInteger, parseStrictPositiveInteger, resolveDateTimestampMs, resolveTimestampMsToIsoString } from "openclaw/plugin-sdk/number-runtime";
|
|
30
|
-
import { expectDefined } from "openclaw/plugin-sdk/expect-runtime";
|
|
27
|
+
import { ApplicationCommandOptionType, ButtonStyle, ChannelType, ComponentType, GatewayCloseCodes, GatewayCloseCodes as GatewayCloseCodes$1, GatewayDispatchEvents, GatewayIntentBits, GatewayOpcodes, PermissionFlagsBits } from "discord-api-types/v10";
|
|
31
28
|
import { Type } from "typebox";
|
|
32
29
|
import { Check, Errors } from "typebox/value";
|
|
30
|
+
import { createHash, randomUUID } from "node:crypto";
|
|
31
|
+
import { MAX_DATE_TIMESTAMP_MS, MAX_TIMER_TIMEOUT_MS, asDateTimestampMs, asSafeIntegerInRange, parseFiniteNumber, parseStrictInteger, parseStrictPositiveInteger, resolveDateTimestampMs, resolveTimestampMsToIsoString } from "openclaw/plugin-sdk/number-runtime";
|
|
32
|
+
import { expectDefined } from "openclaw/plugin-sdk/expect-runtime";
|
|
33
33
|
import { inspect } from "node:util";
|
|
34
34
|
import { readResponseWithLimit } from "openclaw/plugin-sdk/response-limit-runtime";
|
|
35
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
|
+
import { normalizeAccountId } from "openclaw/plugin-sdk/account-id";
|
|
38
|
+
import { resolveAgentRoute } from "openclaw/plugin-sdk/routing";
|
|
39
|
+
import { asFiniteNumber, asOptionalRecord, normalizeLowercaseStringOrEmpty, normalizeOptionalLowercaseString, normalizeOptionalString, normalizeStringEntries, parseFiniteNumber as parseFiniteNumber$1, parseStrictNonNegativeInteger as parseStrictNonNegativeInteger$1, summarizeStringEntries } from "openclaw/plugin-sdk/string-coerce-runtime";
|
|
40
|
+
import { getRuntimeConfig, getRuntimeConfigSnapshot } from "openclaw/plugin-sdk/runtime-config-snapshot";
|
|
41
|
+
import { resolveSendableOutboundReplyParts, resolveTextChunksWithFallback } from "openclaw/plugin-sdk/reply-payload";
|
|
37
42
|
import { createHttp1EnvHttpProxyAgent, createHttp1ProxyAgent, createNodeProxyAgent, resolveEnvHttpProxyAgentOptions, wrapFetchWithAbortSignal } from "openclaw/plugin-sdk/fetch-runtime";
|
|
38
43
|
import { createNonExitingRuntime, createSubsystemLogger, danger, formatDurationSeconds, isVerbose, logVerbose, shouldLogVerbose, sleepWithAbort, warn } from "openclaw/plugin-sdk/runtime-env";
|
|
39
44
|
import { sliceUtf16Safe, truncateUtf16Safe, withTimeout } from "openclaw/plugin-sdk/text-utility-runtime";
|
|
@@ -41,33 +46,30 @@ import { addAllowlistUserEntriesFromConfigEntry, buildAllowlistResolutionSummary
|
|
|
41
46
|
import { resolveMarkdownTableMode } from "openclaw/plugin-sdk/markdown-table-runtime";
|
|
42
47
|
import { resolveChunkMode, resolveTextChunkLimit } from "openclaw/plugin-sdk/reply-chunking";
|
|
43
48
|
import { chunkItems, findCodeRegions, sanitizeAssistantVisibleText, sanitizeAssistantVisibleTextWithProfile } from "openclaw/plugin-sdk/text-chunking";
|
|
44
|
-
import { createReplyReferencePlanner } from "openclaw/plugin-sdk/reply-reference";
|
|
45
49
|
import { buildOutboundSessionContext, listMessageReceiptPlatformIds, resolveChannelStreamingBlockEnabled, sendDurableMessageBatch } from "openclaw/plugin-sdk/channel-outbound";
|
|
46
50
|
import { getAgentScopedMediaLocalRoots } from "openclaw/plugin-sdk/media-runtime";
|
|
47
|
-
import { resolveSendableOutboundReplyParts, resolveTextChunksWithFallback } from "openclaw/plugin-sdk/reply-payload";
|
|
48
51
|
import { loadWebMedia } from "openclaw/plugin-sdk/web-media";
|
|
49
52
|
import { createLazyRuntimeModule } from "openclaw/plugin-sdk/lazy-runtime";
|
|
50
|
-
import {
|
|
53
|
+
import { buildCommandTextFromArgs, findCommandByNativeName, formatCommandArgMenuTitle, listChatCommands, listNativeCommandSpecsForConfig, listSkillCommandsForAgents, resolveCommandAuthorizedFromAuthorizers, resolveEffectiveAgentRuntime, resolveNativeCommandSessionTargets, resolveStoredModelOverride, serializeCommandArgs } from "openclaw/plugin-sdk/command-auth-native";
|
|
51
54
|
import { GROUP_POLICY_BLOCKED_LABEL, resolveDefaultGroupPolicy, resolveOpenProviderRuntimeGroupPolicy, warnMissingProviderGroupPolicyFallbackOnce } from "openclaw/plugin-sdk/runtime-group-policy";
|
|
55
|
+
import { resolvePinnedMainDmOwnerFromAllowlist as resolvePinnedMainDmOwnerFromAllowlist$1 } from "openclaw/plugin-sdk/security-runtime";
|
|
52
56
|
import { createChannelPairingChallengeIssuer } from "openclaw/plugin-sdk/channel-pairing";
|
|
53
57
|
import { CHANNEL_APPROVAL_NATIVE_RUNTIME_CONTEXT_CAPABILITY } from "openclaw/plugin-sdk/approval-handler-adapter-runtime";
|
|
54
|
-
import { questionGatewayRuntime } from "openclaw/plugin-sdk/question-gateway-runtime";
|
|
55
58
|
import { buildPairingReply, upsertChannelPairingRequest, upsertChannelPairingRequest as upsertChannelPairingRequest$1 } from "openclaw/plugin-sdk/conversation-runtime";
|
|
59
|
+
import * as conversationRuntime from "openclaw/plugin-sdk/conversation-binding-runtime";
|
|
60
|
+
import { questionGatewayRuntime } from "openclaw/plugin-sdk/question-gateway-runtime";
|
|
61
|
+
import { createChannelIngressResolver, readChannelIngressStoreAllowFromForDmPolicy } from "openclaw/plugin-sdk/channel-ingress-runtime";
|
|
56
62
|
import { clearExpiredCooldowns, ensureAuthProfileStore, formatReasoningMessage, getPreparedModelCatalogSnapshot, isProfileInCooldown, listAgentIds, loadPreparedModelCatalog, resolveAgentAvatar, resolveAgentDir, resolveDefaultModelForAgent, resolveHumanDelayConfig, resolveProfilesUnavailableReason } from "openclaw/plugin-sdk/agent-runtime";
|
|
57
63
|
import { isDangerousNameMatchingEnabled } from "openclaw/plugin-sdk/dangerous-name-runtime";
|
|
58
64
|
import { resolveNativeCommandsEnabled, resolveNativeSkillsEnabled } from "openclaw/plugin-sdk/native-command-config-runtime";
|
|
59
65
|
import { requestHeartbeat } from "openclaw/plugin-sdk/heartbeat-runtime";
|
|
60
66
|
import { enqueueRoutedSystemEvent, enqueueRoutedSystemEvent as enqueueRoutedSystemEvent$1 } from "openclaw/plugin-sdk/system-event-runtime";
|
|
61
|
-
import { createChannelIngressResolver, defineStableChannelIngressIdentity, readChannelIngressStoreAllowFromForDmPolicy } from "openclaw/plugin-sdk/channel-ingress-runtime";
|
|
62
|
-
import { createChannelPartialDeliveryError, dispatchChannelInboundTurn, formatInboundEnvelope, hasVisibleInboundReplyDispatch, isChannelPartialDeliveryError, resolveEnvelopeFormatOptions, resolveInboundSupplementalSenderAllowed, runChannelInboundEvent } from "openclaw/plugin-sdk/channel-inbound";
|
|
63
|
-
import { resolveChannelModelOverride } from "openclaw/plugin-sdk/model-session-runtime";
|
|
64
|
-
import { finalizeInboundContext, generateConversationLabel } from "openclaw/plugin-sdk/reply-dispatch-runtime";
|
|
65
67
|
import { deleteSessionEntry, getSessionEntry, listSessionEntries, readSessionUpdatedAt as readSessionUpdatedAt$1, resolveStorePath, resolveStorePath as resolveStorePath$1 } from "openclaw/plugin-sdk/session-store-runtime";
|
|
66
|
-
import {
|
|
68
|
+
import { finalizeInboundContext } from "openclaw/plugin-sdk/reply-dispatch-runtime";
|
|
69
|
+
import { createChannelPartialDeliveryError, dispatchChannelInboundTurn, formatInboundEnvelope, hasVisibleInboundReplyDispatch, isChannelPartialDeliveryError, resolveEnvelopeFormatOptions, resolveInboundSupplementalSenderAllowed, runChannelInboundEvent } from "openclaw/plugin-sdk/channel-inbound";
|
|
67
70
|
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
71
|
import { PLUGIN_COMMAND_DISPATCH } from "openclaw/plugin-sdk/plugin-command-runtime";
|
|
69
72
|
import { resolveDirectStatusReplyForSession } from "openclaw/plugin-sdk/command-status-runtime";
|
|
70
|
-
import * as conversationRuntime from "openclaw/plugin-sdk/conversation-binding-runtime";
|
|
71
73
|
import { normalizeProviderId } from "openclaw/plugin-sdk/provider-model-shared";
|
|
72
74
|
import { EventEmitter } from "node:events";
|
|
73
75
|
import * as ws from "ws";
|
|
@@ -79,6 +81,7 @@ import { registerChannelRuntimeContext } from "openclaw/plugin-sdk/channel-runti
|
|
|
79
81
|
import { stripPlainTextToolCallBlocks } from "openclaw/plugin-sdk/tool-payload";
|
|
80
82
|
import { createChannelInteractiveDispatcher } from "openclaw/plugin-sdk/plugin-runtime";
|
|
81
83
|
import { resolveApprovalOverGateway } from "openclaw/plugin-sdk/approval-gateway-runtime";
|
|
84
|
+
import { reportChannelRoomJoin } from "openclaw/plugin-sdk/channel-join-intro-runtime";
|
|
82
85
|
import { resolveRequestUrl } from "openclaw/plugin-sdk/request-url";
|
|
83
86
|
import { fetchWithRuntimeDispatcher } from "openclaw/plugin-sdk/runtime-fetch";
|
|
84
87
|
import { Agent as Agent$1 } from "undici";
|
|
@@ -140,56 +143,216 @@ async function runDiscordListenerWithSlowLog(params) {
|
|
|
140
143
|
}
|
|
141
144
|
}
|
|
142
145
|
//#endregion
|
|
146
|
+
//#region extensions/discord/src/monitor/presence-events.ts
|
|
147
|
+
const DISCORD_PRESENCE_GREETING_COOLDOWN_MS = 480 * 60 * 1e3;
|
|
148
|
+
function isDiscordOnlineStatus(status) {
|
|
149
|
+
return status === "online" || status === "idle" || status === "dnd";
|
|
150
|
+
}
|
|
151
|
+
function isDiscordOfflineStatus(status) {
|
|
152
|
+
return status === "offline";
|
|
153
|
+
}
|
|
154
|
+
function resolveDiscordOnlinePresenceEvent(params) {
|
|
155
|
+
const config = params.config;
|
|
156
|
+
const userId = params.data.user?.id?.trim();
|
|
157
|
+
if (!config || config.enabled === false || !userId || userId === params.botUserId || params.data.user.bot === true || !isDiscordOnlineStatus(params.data.status) || !params.availabilityKind) return null;
|
|
158
|
+
if (config.users !== void 0 && !config.users.includes(userId)) return null;
|
|
159
|
+
if (params.lastEmittedAtMs !== void 0 && params.nowMs - params.lastEmittedAtMs < 288e5) return null;
|
|
160
|
+
const lines = [
|
|
161
|
+
"Discord online-presence event:",
|
|
162
|
+
params.availabilityKind === "observed-offline" ? `A human member became available online after being observed offline in guild_id=${JSON.stringify(params.data.guild_id)} user_id=${JSON.stringify(userId)} status=${JSON.stringify(params.data.status)}.` : `A human member became newly visible online since the current guild snapshot in guild_id=${JSON.stringify(params.data.guild_id)} user_id=${JSON.stringify(userId)} status=${JSON.stringify(params.data.status)}. They may have come online or joined after the snapshot; do not claim an exact prior status.`,
|
|
163
|
+
`The authorized greeting target is channel_id=${JSON.stringify(config.channelId)}.`,
|
|
164
|
+
"Before greeting, retrieve relevant memory and wiki context for this immutable user_id, including a known timezone when available. Use their local time for the greeting; if their timezone is unknown, do not guess.",
|
|
165
|
+
"Send at most one short, natural greeting to the target channel. Do not reveal private memory. If no greeting is appropriate, stay silent."
|
|
166
|
+
];
|
|
167
|
+
return {
|
|
168
|
+
channelId: config.channelId,
|
|
169
|
+
userId,
|
|
170
|
+
text: lines.join("\n")
|
|
171
|
+
};
|
|
172
|
+
}
|
|
173
|
+
//#endregion
|
|
174
|
+
//#region extensions/discord/src/monitor/presence-cooldown-store.ts
|
|
175
|
+
const DISCORD_PRESENCE_COOLDOWN_MAX_ENTRIES = 25e3;
|
|
176
|
+
function openDiscordPresenceCooldownStore() {
|
|
177
|
+
return getDiscordRuntime().state.openSyncKeyedStore({
|
|
178
|
+
namespace: "presence-greeting-cooldowns",
|
|
179
|
+
maxEntries: DISCORD_PRESENCE_COOLDOWN_MAX_ENTRIES,
|
|
180
|
+
overflowPolicy: "reject-new",
|
|
181
|
+
defaultTtlMs: DISCORD_PRESENCE_GREETING_COOLDOWN_MS
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
//#endregion
|
|
185
|
+
//#region extensions/discord/src/monitor/presence-emission-gate.ts
|
|
186
|
+
const DISCORD_PRESENCE_RECONNECT_SUPPRESS_MS = 300 * 1e3;
|
|
187
|
+
const DISCORD_PRESENCE_BURST_LIMIT = 8;
|
|
188
|
+
const DISCORD_PRESENCE_BURST_WINDOW_MS = 60 * 1e3;
|
|
189
|
+
function resolveDiscordPresenceGateOptions(config) {
|
|
190
|
+
return {
|
|
191
|
+
reconnectSuppressMs: config?.reconnectSuppressSeconds !== void 0 ? config.reconnectSuppressSeconds * 1e3 : DISCORD_PRESENCE_RECONNECT_SUPPRESS_MS,
|
|
192
|
+
burstLimit: config?.burstLimit ?? DISCORD_PRESENCE_BURST_LIMIT,
|
|
193
|
+
burstWindowMs: config?.burstWindowSeconds !== void 0 ? config.burstWindowSeconds * 1e3 : DISCORD_PRESENCE_BURST_WINDOW_MS
|
|
194
|
+
};
|
|
195
|
+
}
|
|
196
|
+
/**
|
|
197
|
+
* Per-account lifecycle gate for online-presence events. Reconnect state belongs to the Gateway
|
|
198
|
+
* session, while burst state follows the guild-owned configuration that supplies its limits.
|
|
199
|
+
*/
|
|
200
|
+
var DiscordPresenceEmissionGate = class {
|
|
201
|
+
constructor() {
|
|
202
|
+
this.reconnectLogged = false;
|
|
203
|
+
this.burstByGuild = /* @__PURE__ */ new Map();
|
|
204
|
+
this.nextReservationId = 0;
|
|
205
|
+
}
|
|
206
|
+
noteGatewaySessionReset(nowMs) {
|
|
207
|
+
this.lastSessionResetAtMs = nowMs;
|
|
208
|
+
this.reconnectLogged = false;
|
|
209
|
+
}
|
|
210
|
+
evaluateReconnectWindow(nowMs, options) {
|
|
211
|
+
if (this.lastSessionResetAtMs !== void 0 && options.reconnectSuppressMs > 0 && nowMs - this.lastSessionResetAtMs < options.reconnectSuppressMs) {
|
|
212
|
+
const shouldLog = !this.reconnectLogged;
|
|
213
|
+
this.reconnectLogged = true;
|
|
214
|
+
return {
|
|
215
|
+
allowed: false,
|
|
216
|
+
reason: "reconnect-window",
|
|
217
|
+
shouldLog
|
|
218
|
+
};
|
|
219
|
+
}
|
|
220
|
+
return { allowed: true };
|
|
221
|
+
}
|
|
222
|
+
reserveBurst(guildId, nowMs, options) {
|
|
223
|
+
const state = this.burstByGuild.get(guildId) ?? {
|
|
224
|
+
reservations: [],
|
|
225
|
+
logged: false
|
|
226
|
+
};
|
|
227
|
+
state.reservations = state.reservations.filter((reservation) => !reservation.committed || nowMs - reservation.atMs < options.burstWindowMs);
|
|
228
|
+
this.burstByGuild.set(guildId, state);
|
|
229
|
+
if (state.reservations.length >= options.burstLimit) {
|
|
230
|
+
const shouldLog = !state.logged;
|
|
231
|
+
state.logged = true;
|
|
232
|
+
return {
|
|
233
|
+
allowed: false,
|
|
234
|
+
reason: state.reservations.some((reservation) => !reservation.committed) ? "burst-pending" : "burst",
|
|
235
|
+
shouldLog
|
|
236
|
+
};
|
|
237
|
+
}
|
|
238
|
+
state.logged = false;
|
|
239
|
+
const reservation = {
|
|
240
|
+
id: this.nextReservationId++,
|
|
241
|
+
atMs: nowMs,
|
|
242
|
+
committed: false
|
|
243
|
+
};
|
|
244
|
+
state.reservations.push(reservation);
|
|
245
|
+
return {
|
|
246
|
+
allowed: true,
|
|
247
|
+
reservation: reservation.id
|
|
248
|
+
};
|
|
249
|
+
}
|
|
250
|
+
commitBurst(guildId, reservation, nowMs) {
|
|
251
|
+
const entry = this.burstByGuild.get(guildId)?.reservations.find((candidate) => candidate.id === reservation);
|
|
252
|
+
if (!entry) return;
|
|
253
|
+
entry.atMs = nowMs;
|
|
254
|
+
entry.committed = true;
|
|
255
|
+
}
|
|
256
|
+
releaseBurst(guildId, reservation) {
|
|
257
|
+
const state = this.burstByGuild.get(guildId);
|
|
258
|
+
if (!state) return;
|
|
259
|
+
state.reservations = state.reservations.filter((candidate) => candidate.id !== reservation);
|
|
260
|
+
if (state.reservations.length === 0 && !state.logged) this.burstByGuild.delete(guildId);
|
|
261
|
+
}
|
|
262
|
+
};
|
|
263
|
+
//#endregion
|
|
264
|
+
//#region extensions/discord/src/monitor/presence-transition-cache.ts
|
|
265
|
+
const DEFAULT_PRESENCE_BASELINE_MAX_ENTRIES = 75e3;
|
|
266
|
+
var DiscordPresenceBaselineCache = class {
|
|
267
|
+
constructor(maxEntries = DEFAULT_PRESENCE_BASELINE_MAX_ENTRIES) {
|
|
268
|
+
this.maxEntries = maxEntries;
|
|
269
|
+
this.offlineByKey = /* @__PURE__ */ new Map();
|
|
270
|
+
this.onlineByKey = /* @__PURE__ */ new Map();
|
|
271
|
+
}
|
|
272
|
+
clear() {
|
|
273
|
+
this.offlineByKey.clear();
|
|
274
|
+
this.onlineByKey.clear();
|
|
275
|
+
}
|
|
276
|
+
clearScope(scope) {
|
|
277
|
+
for (const markers of [this.offlineByKey, this.onlineByKey]) for (const [key, markerScope] of markers) if (markerScope === scope) markers.delete(key);
|
|
278
|
+
}
|
|
279
|
+
isOffline(scope, key) {
|
|
280
|
+
return this.offlineByKey.get(key) === scope;
|
|
281
|
+
}
|
|
282
|
+
isOnline(scope, key) {
|
|
283
|
+
return this.onlineByKey.get(key) === scope;
|
|
284
|
+
}
|
|
285
|
+
observeOffline(scope, key) {
|
|
286
|
+
this.deleteMarker(this.onlineByKey, scope, key);
|
|
287
|
+
return this.observe(this.offlineByKey, scope, key);
|
|
288
|
+
}
|
|
289
|
+
observeOnline(scope, key) {
|
|
290
|
+
this.deleteMarker(this.offlineByKey, scope, key);
|
|
291
|
+
return this.observe(this.onlineByKey, scope, key);
|
|
292
|
+
}
|
|
293
|
+
deleteMarker(markers, scope, key) {
|
|
294
|
+
if (markers.get(key) === scope) markers.delete(key);
|
|
295
|
+
}
|
|
296
|
+
observe(markers, scope, key) {
|
|
297
|
+
markers.delete(key);
|
|
298
|
+
markers.set(key, scope);
|
|
299
|
+
let evictedScope;
|
|
300
|
+
while (markers.size > this.maxEntries) {
|
|
301
|
+
const oldestKey = markers.keys().next().value;
|
|
302
|
+
if (oldestKey === void 0) break;
|
|
303
|
+
evictedScope = markers.get(oldestKey);
|
|
304
|
+
markers.delete(oldestKey);
|
|
305
|
+
}
|
|
306
|
+
return evictedScope;
|
|
307
|
+
}
|
|
308
|
+
};
|
|
309
|
+
//#endregion
|
|
310
|
+
//#region extensions/discord/src/monitor/thread-session-close.ts
|
|
311
|
+
/**
|
|
312
|
+
* Closes every session entry in the store whose key contains {@link threadId}.
|
|
313
|
+
* The explicit lifecycle deletion archives the old transcript and guarantees
|
|
314
|
+
* that a later inbound message starts a fresh session in every reset mode.
|
|
315
|
+
*/
|
|
316
|
+
async function closeDiscordThreadSessions(params) {
|
|
317
|
+
const { cfg, threadId } = params;
|
|
318
|
+
const normalizedThreadId = normalizeOptionalLowercaseString(threadId) ?? "";
|
|
319
|
+
if (!normalizedThreadId) return 0;
|
|
320
|
+
const segmentRe = new RegExp(`:${normalizedThreadId}(?::|$)`, "i");
|
|
321
|
+
function sessionKeyContainsThreadId(key) {
|
|
322
|
+
return segmentRe.test(key);
|
|
323
|
+
}
|
|
324
|
+
let resetCount = 0;
|
|
325
|
+
for (const agentId of listAgentIds(cfg)) {
|
|
326
|
+
const storePath = resolveStorePath(cfg.session?.store, { agentId });
|
|
327
|
+
for (const { sessionKey, entry } of listSessionEntries({
|
|
328
|
+
agentId,
|
|
329
|
+
storePath,
|
|
330
|
+
readOnly: true
|
|
331
|
+
})) {
|
|
332
|
+
if (!sessionKeyContainsThreadId(sessionKey)) continue;
|
|
333
|
+
if (await deleteSessionEntry({
|
|
334
|
+
archiveTranscript: true,
|
|
335
|
+
expectedSessionId: entry.sessionId ?? null,
|
|
336
|
+
expectedUpdatedAt: entry.updatedAt,
|
|
337
|
+
sessionKey,
|
|
338
|
+
storePath
|
|
339
|
+
})) resetCount += 1;
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
return resetCount;
|
|
343
|
+
}
|
|
344
|
+
//#endregion
|
|
143
345
|
//#region extensions/discord/src/monitor/dm-command-auth.ts
|
|
144
|
-
const DISCORD_ALLOW_LIST_PREFIXES = [
|
|
145
|
-
"discord:",
|
|
146
|
-
"user:",
|
|
147
|
-
"pk:"
|
|
148
|
-
];
|
|
149
346
|
const DISCORD_CHANNEL_ID = "discord";
|
|
150
|
-
const DISCORD_USER_ID_KIND = "stable-id";
|
|
151
|
-
const DISCORD_USER_NAME_KIND = "username";
|
|
152
|
-
function normalizeDiscordIdEntry(entry) {
|
|
153
|
-
const text = entry.trim();
|
|
154
|
-
if (!text) return null;
|
|
155
|
-
const maybeId = text.replace(/^<@!?/, "").replace(/>$/, "");
|
|
156
|
-
if (/^\d+$/.test(maybeId)) return maybeId;
|
|
157
|
-
const prefix = DISCORD_ALLOW_LIST_PREFIXES.find((entryPrefix) => text.startsWith(entryPrefix));
|
|
158
|
-
if (prefix) return text.slice(prefix.length).trim() || null;
|
|
159
|
-
return null;
|
|
160
|
-
}
|
|
161
|
-
function normalizeDiscordNameEntry(entry) {
|
|
162
|
-
const text = entry.trim();
|
|
163
|
-
if (!text || text === "*" || normalizeDiscordIdEntry(text)) return null;
|
|
164
|
-
const nameSlug = normalizeDiscordAllowList([text], DISCORD_ALLOW_LIST_PREFIXES)?.names.values().next().value;
|
|
165
|
-
return typeof nameSlug === "string" && nameSlug ? nameSlug : null;
|
|
166
|
-
}
|
|
167
|
-
function normalizeDiscordNameSubject(value) {
|
|
168
|
-
const nameSlug = normalizeDiscordAllowList([value], DISCORD_ALLOW_LIST_PREFIXES)?.names.values().next().value;
|
|
169
|
-
return typeof nameSlug === "string" && nameSlug ? nameSlug : null;
|
|
170
|
-
}
|
|
171
|
-
const discordIngressIdentity = defineStableChannelIngressIdentity({
|
|
172
|
-
key: "discordUserId",
|
|
173
|
-
kind: DISCORD_USER_ID_KIND,
|
|
174
|
-
normalizeEntry: normalizeDiscordIdEntry,
|
|
175
|
-
normalizeSubject: (value) => value.trim() || null,
|
|
176
|
-
sensitivity: "pii",
|
|
177
|
-
aliases: [["discordUserName", normalizeDiscordNameEntry], ["discordUserTag", () => null]].map(([key, normalizeEntry]) => ({
|
|
178
|
-
key,
|
|
179
|
-
kind: DISCORD_USER_NAME_KIND,
|
|
180
|
-
normalizeEntry,
|
|
181
|
-
normalizeSubject: normalizeDiscordNameSubject,
|
|
182
|
-
dangerous: true,
|
|
183
|
-
sensitivity: "pii"
|
|
184
|
-
}))
|
|
185
|
-
});
|
|
186
347
|
function createDiscordDmIngressSubject(sender) {
|
|
187
348
|
return {
|
|
188
349
|
stableId: sender.id,
|
|
189
350
|
aliases: {
|
|
190
351
|
discordUserName: sender.name,
|
|
191
|
-
discordUserTag: sender.tag
|
|
192
|
-
|
|
352
|
+
discordUserTag: sender.tag,
|
|
353
|
+
participantKind: sender.isPluralKit ? "pluralkit-member" : sender.authorKind
|
|
354
|
+
},
|
|
355
|
+
...sender.isPluralKit ? { authentication: { discordUserId: "asserted" } } : {}
|
|
193
356
|
};
|
|
194
357
|
}
|
|
195
358
|
function createDiscordDynamicAccessGroupResolver(params) {
|
|
@@ -264,7 +427,10 @@ async function resolveDiscordDmCommandAccess(params) {
|
|
|
264
427
|
},
|
|
265
428
|
dmPolicy: params.dmPolicy,
|
|
266
429
|
groupPolicy: "disabled",
|
|
267
|
-
policy: {
|
|
430
|
+
policy: {
|
|
431
|
+
mutableIdentifierMatching: params.allowNameMatching ? "enabled" : "disabled",
|
|
432
|
+
...params.minIdentifierAuthentication ? { minIdentifierAuthentication: params.minIdentifierAuthentication } : {}
|
|
433
|
+
},
|
|
268
434
|
allowFrom: params.configuredAllowFrom,
|
|
269
435
|
command: {
|
|
270
436
|
hasControlCommand: false,
|
|
@@ -294,7 +460,10 @@ async function resolveDiscordTextCommandAccess(params) {
|
|
|
294
460
|
accessGroupMembership,
|
|
295
461
|
dmPolicy: "allowlist",
|
|
296
462
|
groupPolicy: "allowlist",
|
|
297
|
-
policy: {
|
|
463
|
+
policy: {
|
|
464
|
+
mutableIdentifierMatching: params.allowNameMatching ? "enabled" : "disabled",
|
|
465
|
+
...params.minIdentifierAuthentication ? { minIdentifierAuthentication: params.minIdentifierAuthentication } : {}
|
|
466
|
+
},
|
|
298
467
|
allowFrom: ownerAllowFrom,
|
|
299
468
|
groupAllowFrom: commandGroup,
|
|
300
469
|
command: {
|
|
@@ -305,474 +474,16 @@ async function resolveDiscordTextCommandAccess(params) {
|
|
|
305
474
|
});
|
|
306
475
|
}
|
|
307
476
|
//#endregion
|
|
308
|
-
//#region extensions/discord/src/monitor/thread-
|
|
309
|
-
|
|
310
|
-
const
|
|
311
|
-
|
|
312
|
-
const MAX_THREAD_TITLE_CHANNEL_DESCRIPTION_CHARS = 320;
|
|
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.";
|
|
314
|
-
async function generateThreadTitle(params) {
|
|
315
|
-
const sourceText = params.messageText.trim();
|
|
316
|
-
if (!sourceText) return null;
|
|
317
|
-
try {
|
|
318
|
-
const userMessage = buildThreadTitleCompletionUserMessage({
|
|
319
|
-
sourceText,
|
|
320
|
-
channelName: params.channelName,
|
|
321
|
-
channelDescription: params.channelDescription
|
|
322
|
-
});
|
|
323
|
-
const timeoutMs = resolveThreadTitleTimeoutMs(params.timeoutMs);
|
|
324
|
-
const generated = await generateConversationLabel({
|
|
325
|
-
cfg: params.cfg,
|
|
326
|
-
agentId: params.agentId,
|
|
327
|
-
userMessage,
|
|
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;
|
|
334
|
-
} catch (err) {
|
|
335
|
-
logVerbose(`thread-title: title generation failed for agent ${params.agentId}: ${String(err)}`);
|
|
336
|
-
return null;
|
|
337
|
-
}
|
|
338
|
-
}
|
|
339
|
-
function buildThreadTitleCompletionUserMessage(params) {
|
|
340
|
-
const sourceText = truncateThreadTitleSourceText(params.sourceText);
|
|
341
|
-
const channelName = normalizeTitleContextField(params.channelName, MAX_THREAD_TITLE_CHANNEL_NAME_CHARS);
|
|
342
|
-
const channelDescription = normalizeTitleContextField(params.channelDescription, MAX_THREAD_TITLE_CHANNEL_DESCRIPTION_CHARS);
|
|
343
|
-
const messageLines = [];
|
|
344
|
-
if (channelName) messageLines.push(`Channel: ${channelName}`);
|
|
345
|
-
if (channelDescription) messageLines.push(`Channel description: ${channelDescription}`);
|
|
346
|
-
messageLines.push(`Message:\n${sourceText}`);
|
|
347
|
-
return messageLines.join("\n\n");
|
|
348
|
-
}
|
|
349
|
-
function truncateThreadTitleSourceText(sourceText) {
|
|
350
|
-
if (sourceText.length <= MAX_THREAD_TITLE_SOURCE_CHARS) return sourceText;
|
|
351
|
-
return `${truncateUtf16Safe(sourceText, MAX_THREAD_TITLE_SOURCE_CHARS)}...`;
|
|
352
|
-
}
|
|
353
|
-
function resolveThreadTitleTimeoutMs(timeoutMs) {
|
|
354
|
-
return Math.max(100, Math.floor(timeoutMs ?? DEFAULT_THREAD_TITLE_TIMEOUT_MS));
|
|
355
|
-
}
|
|
356
|
-
function normalizeGeneratedThreadTitle(raw) {
|
|
357
|
-
const lines = raw.replace(/\r/g, "").split("\n");
|
|
358
|
-
let firstLine = "";
|
|
359
|
-
for (const line of lines) {
|
|
360
|
-
const trimmed = line.trim();
|
|
361
|
-
if (!trimmed) continue;
|
|
362
|
-
if (!firstLine && trimmed.startsWith("```")) continue;
|
|
363
|
-
firstLine = trimmed;
|
|
364
|
-
break;
|
|
365
|
-
}
|
|
366
|
-
return stripThreadTitleWrappers(firstLine);
|
|
367
|
-
}
|
|
368
|
-
function stripThreadTitleWrappers(raw) {
|
|
369
|
-
let current = raw.trim();
|
|
370
|
-
let previous = "";
|
|
371
|
-
while (current && current !== previous) {
|
|
372
|
-
previous = current;
|
|
373
|
-
current = current.replace(/^["'`]+|["'`]+$/g, "").trim();
|
|
374
|
-
current = stripBalancedWrapper(current, "**");
|
|
375
|
-
current = stripBalancedWrapper(current, "__");
|
|
376
|
-
current = stripBalancedWrapper(current, "*");
|
|
377
|
-
current = stripBalancedWrapper(current, "_");
|
|
378
|
-
current = stripBalancedWrapper(current, "~~");
|
|
379
|
-
}
|
|
380
|
-
return current;
|
|
381
|
-
}
|
|
382
|
-
function stripBalancedWrapper(text, marker) {
|
|
383
|
-
if (text.length < marker.length * 2 + 1) return text;
|
|
384
|
-
if (!text.startsWith(marker) || !text.endsWith(marker)) return text;
|
|
385
|
-
const inner = text.slice(marker.length, text.length - marker.length);
|
|
386
|
-
if (!inner || inner.includes(marker)) return text;
|
|
387
|
-
return inner;
|
|
388
|
-
}
|
|
389
|
-
function normalizeTitleContextField(raw, maxChars) {
|
|
390
|
-
const value = raw?.trim();
|
|
391
|
-
if (!value) return;
|
|
392
|
-
const singleLine = value.replace(/\s+/g, " ");
|
|
393
|
-
if (singleLine.length <= maxChars) return singleLine;
|
|
394
|
-
return `${truncateUtf16Safe(singleLine, maxChars)}...`;
|
|
395
|
-
}
|
|
396
|
-
//#endregion
|
|
397
|
-
//#region extensions/discord/src/monitor/threading.cache.ts
|
|
398
|
-
const DISCORD_THREAD_STARTER_CACHE_TTL_MS = 300 * 1e3;
|
|
399
|
-
const DISCORD_THREAD_STARTER_CACHE_MAX = 500;
|
|
400
|
-
const DISCORD_THREAD_STARTER_CACHE = /* @__PURE__ */ new Map();
|
|
401
|
-
function resetDiscordThreadStarterCacheForTest() {
|
|
402
|
-
DISCORD_THREAD_STARTER_CACHE.clear();
|
|
403
|
-
}
|
|
404
|
-
function getCachedThreadStarter(key, now) {
|
|
405
|
-
const entry = DISCORD_THREAD_STARTER_CACHE.get(key);
|
|
406
|
-
if (!entry) return;
|
|
407
|
-
if (now - entry.updatedAt > DISCORD_THREAD_STARTER_CACHE_TTL_MS) {
|
|
408
|
-
DISCORD_THREAD_STARTER_CACHE.delete(key);
|
|
409
|
-
return;
|
|
410
|
-
}
|
|
411
|
-
DISCORD_THREAD_STARTER_CACHE.delete(key);
|
|
412
|
-
DISCORD_THREAD_STARTER_CACHE.set(key, {
|
|
413
|
-
...entry,
|
|
414
|
-
updatedAt: now
|
|
415
|
-
});
|
|
416
|
-
return entry.value;
|
|
417
|
-
}
|
|
418
|
-
function setCachedThreadStarter(key, value, now) {
|
|
419
|
-
DISCORD_THREAD_STARTER_CACHE.delete(key);
|
|
420
|
-
DISCORD_THREAD_STARTER_CACHE.set(key, {
|
|
421
|
-
value,
|
|
422
|
-
updatedAt: now
|
|
423
|
-
});
|
|
424
|
-
while (DISCORD_THREAD_STARTER_CACHE.size > DISCORD_THREAD_STARTER_CACHE_MAX) {
|
|
425
|
-
const iter = DISCORD_THREAD_STARTER_CACHE.keys().next();
|
|
426
|
-
if (iter.done) break;
|
|
427
|
-
DISCORD_THREAD_STARTER_CACHE.delete(iter.value);
|
|
428
|
-
}
|
|
429
|
-
}
|
|
430
|
-
//#endregion
|
|
431
|
-
//#region extensions/discord/src/monitor/threading.starter.ts
|
|
432
|
-
function isDiscordThreadType(type) {
|
|
433
|
-
return type === discord_exports.ChannelType.PublicThread || type === discord_exports.ChannelType.PrivateThread || type === discord_exports.ChannelType.AnnouncementThread;
|
|
434
|
-
}
|
|
435
|
-
function isDiscordForumParentType(parentType) {
|
|
436
|
-
return parentType === discord_exports.ChannelType.GuildForum || parentType === discord_exports.ChannelType.GuildMedia;
|
|
437
|
-
}
|
|
438
|
-
function resolveDiscordThreadChannel(params) {
|
|
439
|
-
if (!params.isGuildMessage) return null;
|
|
440
|
-
const { message, channelInfo } = params;
|
|
441
|
-
const channel = "channel" in message ? message.channel : void 0;
|
|
442
|
-
if (channel && typeof channel === "object" && "isThread" in channel && typeof channel.isThread === "function" && channel.isThread()) return channel;
|
|
443
|
-
if (!isDiscordThreadType(channelInfo?.type)) return null;
|
|
444
|
-
const messageChannelId = params.messageChannelId || resolveDiscordMessageChannelId({ message });
|
|
445
|
-
if (!messageChannelId) return null;
|
|
446
|
-
return {
|
|
447
|
-
id: messageChannelId,
|
|
448
|
-
name: channelInfo?.name ?? void 0,
|
|
449
|
-
parentId: channelInfo?.parentId ?? void 0,
|
|
450
|
-
parent: void 0,
|
|
451
|
-
ownerId: channelInfo?.ownerId ?? void 0
|
|
452
|
-
};
|
|
453
|
-
}
|
|
454
|
-
async function resolveDiscordThreadParentInfo(params) {
|
|
455
|
-
const { threadChannel, channelInfo, client } = params;
|
|
456
|
-
const parent = resolveDiscordChannelParentSafe(threadChannel);
|
|
457
|
-
let parentId = resolveDiscordChannelParentIdSafe(threadChannel) ?? resolveDiscordChannelIdSafe(parent) ?? channelInfo?.parentId ?? void 0;
|
|
458
|
-
if (!parentId && threadChannel.id) parentId = (await resolveDiscordChannelInfo(client, threadChannel.id))?.parentId ?? void 0;
|
|
459
|
-
if (!parentId) return {};
|
|
460
|
-
let parentName = resolveDiscordChannelNameSafe(parent);
|
|
461
|
-
const parentInfo = await resolveDiscordChannelInfo(client, parentId);
|
|
462
|
-
parentName = parentName ?? parentInfo?.name;
|
|
463
|
-
const parentType = parentInfo?.type;
|
|
477
|
+
//#region extensions/discord/src/monitor/thread-channel-context.ts
|
|
478
|
+
function buildFetchedChannelInfo(channel) {
|
|
479
|
+
const channelInfo = resolveDiscordChannelInfoSafe(channel);
|
|
480
|
+
if (channelInfo.type === void 0) return null;
|
|
464
481
|
return {
|
|
465
|
-
|
|
466
|
-
name:
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
async function resolveDiscordThreadStarter(params) {
|
|
471
|
-
const cacheKey = params.channel.id;
|
|
472
|
-
const cached = getCachedThreadStarter(cacheKey, Date.now());
|
|
473
|
-
if (cached) return cached;
|
|
474
|
-
try {
|
|
475
|
-
const messageChannelId = resolveDiscordThreadStarterMessageChannelId(params);
|
|
476
|
-
if (!messageChannelId) return null;
|
|
477
|
-
const starter = await fetchDiscordThreadStarterMessage({
|
|
478
|
-
client: params.client,
|
|
479
|
-
messageChannelId,
|
|
480
|
-
threadId: params.channel.id
|
|
481
|
-
});
|
|
482
|
-
if (!starter) return null;
|
|
483
|
-
const payload = buildDiscordThreadStarterPayload({
|
|
484
|
-
starter,
|
|
485
|
-
resolveTimestampMs: params.resolveTimestampMs
|
|
486
|
-
});
|
|
487
|
-
if (!payload) return null;
|
|
488
|
-
setCachedThreadStarter(cacheKey, payload, Date.now());
|
|
489
|
-
return payload;
|
|
490
|
-
} catch {
|
|
491
|
-
return null;
|
|
492
|
-
}
|
|
493
|
-
}
|
|
494
|
-
function resolveDiscordThreadStarterMessageChannelId(params) {
|
|
495
|
-
return isDiscordForumParentType(params.parentType) ? params.channel.id : params.parentId;
|
|
496
|
-
}
|
|
497
|
-
async function fetchDiscordThreadStarterMessage(params) {
|
|
498
|
-
const starter = await getChannelMessage(params.client.rest, params.messageChannelId, params.threadId);
|
|
499
|
-
return starter ? starter : null;
|
|
500
|
-
}
|
|
501
|
-
function buildDiscordThreadStarterPayload(params) {
|
|
502
|
-
const text = resolveDiscordThreadStarterText(params.starter);
|
|
503
|
-
if (!text) return null;
|
|
504
|
-
return {
|
|
505
|
-
text,
|
|
506
|
-
...resolveDiscordThreadStarterIdentity(params.starter),
|
|
507
|
-
timestamp: params.resolveTimestampMs(params.starter.timestamp) ?? void 0
|
|
508
|
-
};
|
|
509
|
-
}
|
|
510
|
-
function resolveDiscordThreadStarterText(starter) {
|
|
511
|
-
const content = normalizeOptionalString(starter.content) ?? "";
|
|
512
|
-
const embedText = resolveDiscordEmbedText(starter.embeds?.[0]);
|
|
513
|
-
const forwardedText = resolveDiscordForwardedMessagesTextFromSnapshots(starter.message_snapshots);
|
|
514
|
-
return [content || embedText || forwardedText, formatDiscordMediaText({
|
|
515
|
-
attachments: starter.attachments ?? void 0,
|
|
516
|
-
stickers: starter.sticker_items ?? void 0
|
|
517
|
-
})].filter(Boolean).join("\n");
|
|
518
|
-
}
|
|
519
|
-
function resolveDiscordThreadStarterIdentity(starter) {
|
|
520
|
-
return {
|
|
521
|
-
author: resolveDiscordThreadStarterAuthor(starter),
|
|
522
|
-
authorId: starter.author?.id ?? void 0,
|
|
523
|
-
authorName: starter.author?.username ?? void 0,
|
|
524
|
-
authorTag: resolveDiscordThreadStarterAuthorTag(starter.author),
|
|
525
|
-
memberRoleIds: resolveDiscordThreadStarterRoleIds(starter.member)
|
|
526
|
-
};
|
|
527
|
-
}
|
|
528
|
-
function resolveDiscordThreadStarterAuthor(starter) {
|
|
529
|
-
return starter.member?.nick ?? starter.member?.displayName ?? resolveDiscordThreadStarterAuthorTag(starter.author) ?? starter.author?.username ?? starter.author?.id ?? "Unknown";
|
|
530
|
-
}
|
|
531
|
-
function resolveDiscordThreadStarterAuthorTag(author) {
|
|
532
|
-
if (!author?.username || !author.discriminator) return;
|
|
533
|
-
if (author.discriminator !== "0") return `${author.username}#${author.discriminator}`;
|
|
534
|
-
return author.username;
|
|
535
|
-
}
|
|
536
|
-
function resolveDiscordThreadStarterRoleIds(member) {
|
|
537
|
-
return Array.isArray(member?.roles) ? member.roles : void 0;
|
|
538
|
-
}
|
|
539
|
-
function resolveDiscordReplyTarget(opts) {
|
|
540
|
-
if (opts.replyToMode === "off") return;
|
|
541
|
-
const replyToId = normalizeOptionalString(opts.replyToId);
|
|
542
|
-
if (!replyToId) return;
|
|
543
|
-
if (opts.replyToMode === "all") return replyToId;
|
|
544
|
-
return opts.hasReplied ? void 0 : replyToId;
|
|
545
|
-
}
|
|
546
|
-
function sanitizeDiscordThreadName(rawName, fallbackId) {
|
|
547
|
-
return truncateUtf16Safe(truncateUtf16Safe(rawName.replace(/<@!?\d+>/g, "").replace(/<@&\d+>/g, "").replace(/<#\d+>/g, "").replace(/\s+/g, " ").trim() || `Thread ${fallbackId}`, 80), 100) || `Thread ${fallbackId}`;
|
|
548
|
-
}
|
|
549
|
-
function resolveDiscordReplyDeliveryPlan(params) {
|
|
550
|
-
const originalReplyTarget = params.replyTarget;
|
|
551
|
-
let deliverTarget = originalReplyTarget;
|
|
552
|
-
let replyTarget = originalReplyTarget;
|
|
553
|
-
if (params.createdThreadId) {
|
|
554
|
-
deliverTarget = `channel:${params.createdThreadId}`;
|
|
555
|
-
replyTarget = deliverTarget;
|
|
556
|
-
}
|
|
557
|
-
const allowReference = deliverTarget === originalReplyTarget;
|
|
558
|
-
const replyReference = createReplyReferencePlanner({
|
|
559
|
-
replyToMode: allowReference ? params.replyToMode : "off",
|
|
560
|
-
existingId: params.threadChannel ? params.messageId : void 0,
|
|
561
|
-
startId: params.messageId,
|
|
562
|
-
allowReference
|
|
563
|
-
});
|
|
564
|
-
return {
|
|
565
|
-
deliverTarget,
|
|
566
|
-
replyTarget,
|
|
567
|
-
replyReference
|
|
568
|
-
};
|
|
569
|
-
}
|
|
570
|
-
//#endregion
|
|
571
|
-
//#region extensions/discord/src/monitor/threading.auto-thread.ts
|
|
572
|
-
function resolveTrimmedDiscordMessageChannelId(params) {
|
|
573
|
-
return (params.messageChannelId || resolveDiscordMessageChannelId({ message: params.message })).trim();
|
|
574
|
-
}
|
|
575
|
-
function resolveDiscordAutoThreadContext(params) {
|
|
576
|
-
const createdThreadId = normalizeOptionalStringifiedId(params.createdThreadId) ?? "";
|
|
577
|
-
if (!createdThreadId) return null;
|
|
578
|
-
const messageChannelId = normalizeOptionalString(params.messageChannelId) ?? "";
|
|
579
|
-
if (!messageChannelId) return null;
|
|
580
|
-
const threadSessionKey = buildAgentSessionKey({
|
|
581
|
-
agentId: params.agentId,
|
|
582
|
-
channel: params.channel,
|
|
583
|
-
peer: {
|
|
584
|
-
kind: "channel",
|
|
585
|
-
id: createdThreadId
|
|
586
|
-
}
|
|
587
|
-
});
|
|
588
|
-
const parentSessionKey = buildAgentSessionKey({
|
|
589
|
-
agentId: params.agentId,
|
|
590
|
-
channel: params.channel,
|
|
591
|
-
peer: {
|
|
592
|
-
kind: "channel",
|
|
593
|
-
id: messageChannelId
|
|
594
|
-
}
|
|
595
|
-
});
|
|
596
|
-
return {
|
|
597
|
-
createdThreadId,
|
|
598
|
-
From: `${params.channel}:channel:${createdThreadId}`,
|
|
599
|
-
To: `channel:${createdThreadId}`,
|
|
600
|
-
OriginatingTo: `channel:${createdThreadId}`,
|
|
601
|
-
SessionKey: threadSessionKey,
|
|
602
|
-
ModelParentSessionKey: parentSessionKey,
|
|
603
|
-
...params.parentInheritanceEnabled === true ? { ParentSessionKey: parentSessionKey } : {}
|
|
604
|
-
};
|
|
605
|
-
}
|
|
606
|
-
async function resolveDiscordAutoThreadReplyPlan(params) {
|
|
607
|
-
const messageChannelId = resolveTrimmedDiscordMessageChannelId(params);
|
|
608
|
-
const originalReplyTarget = `channel:${params.threadChannel?.id ?? (messageChannelId || "unknown")}`;
|
|
609
|
-
const createdThreadId = await maybeCreateDiscordAutoThread({
|
|
610
|
-
client: params.client,
|
|
611
|
-
message: params.message,
|
|
612
|
-
messageChannelId: messageChannelId || void 0,
|
|
613
|
-
channel: params.channel,
|
|
614
|
-
isGuildMessage: params.isGuildMessage,
|
|
615
|
-
channelConfig: params.channelConfig,
|
|
616
|
-
threadChannel: params.threadChannel,
|
|
617
|
-
channelType: params.channelType,
|
|
618
|
-
channelName: params.channelName,
|
|
619
|
-
channelDescription: params.channelDescription,
|
|
620
|
-
baseText: params.baseText,
|
|
621
|
-
combinedBody: params.combinedBody,
|
|
622
|
-
cfg: params.cfg,
|
|
623
|
-
agentId: params.agentId
|
|
624
|
-
});
|
|
625
|
-
const deliveryPlan = resolveDiscordReplyDeliveryPlan({
|
|
626
|
-
replyTarget: originalReplyTarget,
|
|
627
|
-
replyToMode: params.replyToMode,
|
|
628
|
-
messageId: params.message.id,
|
|
629
|
-
threadChannel: params.threadChannel,
|
|
630
|
-
createdThreadId
|
|
631
|
-
});
|
|
632
|
-
const autoThreadContext = params.isGuildMessage ? resolveDiscordAutoThreadContext({
|
|
633
|
-
agentId: params.agentId,
|
|
634
|
-
channel: params.channel,
|
|
635
|
-
messageChannelId,
|
|
636
|
-
createdThreadId,
|
|
637
|
-
parentInheritanceEnabled: params.threadParentInheritanceEnabled
|
|
638
|
-
}) : null;
|
|
639
|
-
return {
|
|
640
|
-
...deliveryPlan,
|
|
641
|
-
createdThreadId,
|
|
642
|
-
autoThreadContext
|
|
643
|
-
};
|
|
644
|
-
}
|
|
645
|
-
async function maybeCreateDiscordAutoThread(params) {
|
|
646
|
-
if (!params.isGuildMessage) return;
|
|
647
|
-
if (!params.channelConfig?.autoThread) return;
|
|
648
|
-
if (params.threadChannel) return;
|
|
649
|
-
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;
|
|
650
|
-
const messageChannelId = resolveTrimmedDiscordMessageChannelId(params);
|
|
651
|
-
if (!messageChannelId) return;
|
|
652
|
-
try {
|
|
653
|
-
try {
|
|
654
|
-
const existingThreadId = (await getChannelMessage(params.client.rest, messageChannelId, params.message.id))?.thread?.id;
|
|
655
|
-
if (existingThreadId) {
|
|
656
|
-
logVerbose(`discord: autoThread reusing existing thread ${existingThreadId} on ${messageChannelId}/${params.message.id}`);
|
|
657
|
-
return existingThreadId;
|
|
658
|
-
}
|
|
659
|
-
} catch {}
|
|
660
|
-
if (params.message.author?.bot) {
|
|
661
|
-
logVerbose(`discord: autoThread skipped for bot-authored message ${messageChannelId}/${params.message.id}`);
|
|
662
|
-
return;
|
|
663
|
-
}
|
|
664
|
-
const rawThreadSource = params.baseText || params.combinedBody || "Thread";
|
|
665
|
-
const threadName = sanitizeDiscordThreadName(rawThreadSource, params.message.id);
|
|
666
|
-
const archiveDuration = params.channelConfig?.autoArchiveDuration ? Number(params.channelConfig.autoArchiveDuration) : 60;
|
|
667
|
-
const createdId = (await createThread(params.client.rest, messageChannelId, { body: {
|
|
668
|
-
name: threadName,
|
|
669
|
-
auto_archive_duration: archiveDuration
|
|
670
|
-
} }, params.message.id))?.id || "";
|
|
671
|
-
if (createdId && params.channelConfig?.autoThreadName === "generated" && params.cfg && params.agentId) {
|
|
672
|
-
const modelRef = resolveDiscordThreadTitleModelRef({
|
|
673
|
-
cfg: params.cfg,
|
|
674
|
-
channel: params.channel,
|
|
675
|
-
agentId: params.agentId,
|
|
676
|
-
threadId: createdId,
|
|
677
|
-
messageChannelId,
|
|
678
|
-
channelName: params.channelName
|
|
679
|
-
});
|
|
680
|
-
maybeRenameDiscordAutoThread({
|
|
681
|
-
client: params.client,
|
|
682
|
-
threadId: createdId,
|
|
683
|
-
currentName: threadName,
|
|
684
|
-
fallbackId: params.message.id,
|
|
685
|
-
sourceText: rawThreadSource,
|
|
686
|
-
modelRef,
|
|
687
|
-
channelName: params.channelName,
|
|
688
|
-
channelDescription: params.channelDescription,
|
|
689
|
-
cfg: params.cfg,
|
|
690
|
-
agentId: params.agentId
|
|
691
|
-
});
|
|
692
|
-
}
|
|
693
|
-
return createdId || void 0;
|
|
694
|
-
} catch (err) {
|
|
695
|
-
logVerbose(`discord: autoThread creation failed for ${messageChannelId}/${params.message.id}: ${String(err)}`);
|
|
696
|
-
try {
|
|
697
|
-
const existingThreadId = (await getChannelMessage(params.client.rest, messageChannelId, params.message.id))?.thread?.id || "";
|
|
698
|
-
if (existingThreadId) {
|
|
699
|
-
logVerbose(`discord: autoThread reusing existing thread ${existingThreadId} on ${messageChannelId}/${params.message.id}`);
|
|
700
|
-
return existingThreadId;
|
|
701
|
-
}
|
|
702
|
-
} catch {}
|
|
703
|
-
return;
|
|
704
|
-
}
|
|
705
|
-
}
|
|
706
|
-
function resolveDiscordThreadTitleModelRef(params) {
|
|
707
|
-
const channel = params.channel?.trim();
|
|
708
|
-
if (!channel) return;
|
|
709
|
-
const parentSessionKey = buildAgentSessionKey({
|
|
710
|
-
agentId: params.agentId,
|
|
711
|
-
channel,
|
|
712
|
-
peer: {
|
|
713
|
-
kind: "channel",
|
|
714
|
-
id: params.messageChannelId
|
|
715
|
-
}
|
|
716
|
-
});
|
|
717
|
-
const channelLabel = params.channelName?.trim();
|
|
718
|
-
const groupChannel = channelLabel ? `#${channelLabel}` : void 0;
|
|
719
|
-
return resolveChannelModelOverride({
|
|
720
|
-
cfg: params.cfg,
|
|
721
|
-
channel,
|
|
722
|
-
groupId: params.threadId,
|
|
723
|
-
groupChatType: "channel",
|
|
724
|
-
groupChannel,
|
|
725
|
-
groupSubject: groupChannel,
|
|
726
|
-
parentSessionKey
|
|
727
|
-
})?.model;
|
|
728
|
-
}
|
|
729
|
-
async function maybeRenameDiscordAutoThread(params) {
|
|
730
|
-
try {
|
|
731
|
-
const fallbackName = sanitizeDiscordThreadName("", params.fallbackId);
|
|
732
|
-
const generated = await generateThreadTitle({
|
|
733
|
-
cfg: params.cfg,
|
|
734
|
-
agentId: params.agentId,
|
|
735
|
-
messageText: params.sourceText,
|
|
736
|
-
modelRef: params.modelRef,
|
|
737
|
-
channelName: params.channelName,
|
|
738
|
-
channelDescription: params.channelDescription
|
|
739
|
-
});
|
|
740
|
-
if (!generated) return;
|
|
741
|
-
const nextName = sanitizeDiscordThreadName(generated, params.fallbackId);
|
|
742
|
-
if (!nextName || nextName === params.currentName || nextName === fallbackName) return;
|
|
743
|
-
await editChannel(params.client.rest, params.threadId, { body: { name: nextName } });
|
|
744
|
-
} catch (err) {
|
|
745
|
-
logVerbose(`discord: autoThread rename failed for ${params.threadId}: ${String(err)}`);
|
|
746
|
-
}
|
|
747
|
-
}
|
|
748
|
-
//#endregion
|
|
749
|
-
//#region extensions/discord/src/monitor/threading.ts
|
|
750
|
-
var threading_exports = /* @__PURE__ */ __exportAll({
|
|
751
|
-
maybeCreateDiscordAutoThread: () => maybeCreateDiscordAutoThread,
|
|
752
|
-
resetDiscordThreadStarterCacheForTest: () => resetDiscordThreadStarterCacheForTest,
|
|
753
|
-
resolveDiscordAutoThreadContext: () => resolveDiscordAutoThreadContext,
|
|
754
|
-
resolveDiscordAutoThreadReplyPlan: () => resolveDiscordAutoThreadReplyPlan,
|
|
755
|
-
resolveDiscordReplyDeliveryPlan: () => resolveDiscordReplyDeliveryPlan,
|
|
756
|
-
resolveDiscordReplyTarget: () => resolveDiscordReplyTarget,
|
|
757
|
-
resolveDiscordThreadChannel: () => resolveDiscordThreadChannel,
|
|
758
|
-
resolveDiscordThreadParentInfo: () => resolveDiscordThreadParentInfo,
|
|
759
|
-
resolveDiscordThreadStarter: () => resolveDiscordThreadStarter,
|
|
760
|
-
sanitizeDiscordThreadName: () => sanitizeDiscordThreadName
|
|
761
|
-
});
|
|
762
|
-
//#endregion
|
|
763
|
-
//#region extensions/discord/src/monitor/thread-channel-context.ts
|
|
764
|
-
function isDiscordThreadChannelType(type) {
|
|
765
|
-
return type === discord_exports.ChannelType.PublicThread || type === discord_exports.ChannelType.PrivateThread || type === discord_exports.ChannelType.AnnouncementThread;
|
|
766
|
-
}
|
|
767
|
-
function buildFetchedChannelInfo(channel) {
|
|
768
|
-
const channelInfo = resolveDiscordChannelInfoSafe(channel);
|
|
769
|
-
if (channelInfo.type === void 0) return null;
|
|
770
|
-
return {
|
|
771
|
-
type: channelInfo.type,
|
|
772
|
-
name: channelInfo.name,
|
|
773
|
-
topic: channelInfo.topic,
|
|
774
|
-
parentId: channelInfo.parentId,
|
|
775
|
-
ownerId: channelInfo.ownerId
|
|
482
|
+
type: channelInfo.type,
|
|
483
|
+
name: channelInfo.name,
|
|
484
|
+
topic: channelInfo.topic,
|
|
485
|
+
parentId: channelInfo.parentId,
|
|
486
|
+
ownerId: channelInfo.ownerId
|
|
776
487
|
};
|
|
777
488
|
}
|
|
778
489
|
async function resolveDiscordThreadLikeChannelContext(params) {
|
|
@@ -1090,305 +801,106 @@ async function handleDiscordReactionEvent(params) {
|
|
|
1090
801
|
const guildSlug = guildInfo?.slug || (data.guild?.name ? normalizeDiscordSlug(data.guild.name) : data.guild_id ?? (isGroupDm ? "group-dm" : "dm"));
|
|
1091
802
|
const channelLabel = channelSlug ? `#${channelSlug}` : channelName ? `#${normalizeDiscordSlug(channelName)}` : `#${data.channel_id}`;
|
|
1092
803
|
reactionBase = {
|
|
1093
|
-
baseText: `Discord reaction ${action}: ${emojiLabel} by ${actorLabel} on ${guildSlug} ${channelLabel} msg ${data.message_id}`,
|
|
1094
|
-
contextKey: `discord:reaction:${action}:${data.message_id}:${user.id}:${emojiLabel}`
|
|
1095
|
-
};
|
|
1096
|
-
return reactionBase;
|
|
1097
|
-
};
|
|
1098
|
-
const emitReaction = (text, parentPeerId) => {
|
|
1099
|
-
const { contextKey } = resolveReactionBase();
|
|
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 });
|
|
1115
|
-
};
|
|
1116
|
-
const shouldNotifyReaction = (options) => shouldEmitDiscordReactionNotification({
|
|
1117
|
-
mode: options.mode,
|
|
1118
|
-
botId: botUserId,
|
|
1119
|
-
messageAuthorId: options.messageAuthorId,
|
|
1120
|
-
userId: user.id,
|
|
1121
|
-
userName: user.username,
|
|
1122
|
-
userTag: formatDiscordUserTag(user),
|
|
1123
|
-
channelConfig: options.channelConfig,
|
|
1124
|
-
guildInfo,
|
|
1125
|
-
memberRoleIds,
|
|
1126
|
-
allowNameMatching: params.allowNameMatching
|
|
1127
|
-
});
|
|
1128
|
-
const emitReactionWithAuthor = (message) => {
|
|
1129
|
-
const { baseText } = resolveReactionBase();
|
|
1130
|
-
const authorLabel = message?.author ? formatDiscordUserTag(message.author) : void 0;
|
|
1131
|
-
const text = authorLabel ? `${baseText} from ${authorLabel}` : baseText;
|
|
1132
|
-
emitReaction(text, parentId);
|
|
1133
|
-
};
|
|
1134
|
-
const resolveThreadChannelConfig = () => resolveDiscordChannelConfigWithFallback({
|
|
1135
|
-
guildInfo,
|
|
1136
|
-
channelId: data.channel_id,
|
|
1137
|
-
channelName,
|
|
1138
|
-
channelSlug,
|
|
1139
|
-
parentId,
|
|
1140
|
-
parentName,
|
|
1141
|
-
parentSlug,
|
|
1142
|
-
scope: "thread"
|
|
1143
|
-
});
|
|
1144
|
-
const authorizeReactionIngressForChannel = async (channelConfig) => await authorizeDiscordReactionIngress({
|
|
1145
|
-
...reactionIngressBase,
|
|
1146
|
-
channelConfig
|
|
1147
|
-
});
|
|
1148
|
-
const resolveThreadChannelAccess = async () => {
|
|
1149
|
-
const channelConfig = resolveThreadChannelConfig();
|
|
1150
|
-
return {
|
|
1151
|
-
access: await authorizeReactionIngressForChannel(channelConfig),
|
|
1152
|
-
channelConfig
|
|
1153
|
-
};
|
|
1154
|
-
};
|
|
1155
|
-
if (isThreadChannel) {
|
|
1156
|
-
await handleDiscordThreadReactionNotification({
|
|
1157
|
-
reactionMode,
|
|
1158
|
-
message: data.message,
|
|
1159
|
-
parentId,
|
|
1160
|
-
resolveThreadChannelAccess,
|
|
1161
|
-
shouldNotifyReaction,
|
|
1162
|
-
resolveReactionBase,
|
|
1163
|
-
emitReaction,
|
|
1164
|
-
emitReactionWithAuthor
|
|
1165
|
-
});
|
|
1166
|
-
return;
|
|
1167
|
-
}
|
|
1168
|
-
const channelConfig = resolveDiscordChannelConfigWithFallback({
|
|
1169
|
-
guildInfo,
|
|
1170
|
-
channelId: data.channel_id,
|
|
1171
|
-
channelName,
|
|
1172
|
-
channelSlug,
|
|
1173
|
-
parentId,
|
|
1174
|
-
parentName,
|
|
1175
|
-
parentSlug,
|
|
1176
|
-
scope: "channel"
|
|
1177
|
-
});
|
|
1178
|
-
await handleDiscordChannelReactionNotification({
|
|
1179
|
-
isGuildMessage,
|
|
1180
|
-
reactionMode,
|
|
1181
|
-
message: data.message,
|
|
1182
|
-
channelConfig,
|
|
1183
|
-
parentId,
|
|
1184
|
-
authorizeReactionIngressForChannel,
|
|
1185
|
-
shouldNotifyReaction,
|
|
1186
|
-
resolveReactionBase,
|
|
1187
|
-
emitReaction,
|
|
1188
|
-
emitReactionWithAuthor
|
|
1189
|
-
});
|
|
1190
|
-
} catch (err) {
|
|
1191
|
-
params.logger.error(danger(`discord reaction handler failed: ${String(err)}`));
|
|
1192
|
-
}
|
|
1193
|
-
}
|
|
1194
|
-
//#endregion
|
|
1195
|
-
//#region extensions/discord/src/monitor/presence-events.ts
|
|
1196
|
-
const DISCORD_PRESENCE_GREETING_COOLDOWN_MS = 480 * 60 * 1e3;
|
|
1197
|
-
function isDiscordOnlineStatus(status) {
|
|
1198
|
-
return status === "online" || status === "idle" || status === "dnd";
|
|
1199
|
-
}
|
|
1200
|
-
function isDiscordOfflineStatus(status) {
|
|
1201
|
-
return status === "offline";
|
|
1202
|
-
}
|
|
1203
|
-
function resolveDiscordOnlinePresenceEvent(params) {
|
|
1204
|
-
const config = params.config;
|
|
1205
|
-
const userId = params.data.user?.id?.trim();
|
|
1206
|
-
if (!config || config.enabled === false || !userId || userId === params.botUserId || params.data.user.bot === true || !isDiscordOnlineStatus(params.data.status) || !params.availabilityKind) return null;
|
|
1207
|
-
if (config.users !== void 0 && !config.users.includes(userId)) return null;
|
|
1208
|
-
if (params.lastEmittedAtMs !== void 0 && params.nowMs - params.lastEmittedAtMs < 288e5) return null;
|
|
1209
|
-
const lines = [
|
|
1210
|
-
"Discord online-presence event:",
|
|
1211
|
-
params.availabilityKind === "observed-offline" ? `A human member became available online after being observed offline in guild_id=${JSON.stringify(params.data.guild_id)} user_id=${JSON.stringify(userId)} status=${JSON.stringify(params.data.status)}.` : `A human member became newly visible online since the current guild snapshot in guild_id=${JSON.stringify(params.data.guild_id)} user_id=${JSON.stringify(userId)} status=${JSON.stringify(params.data.status)}. They may have come online or joined after the snapshot; do not claim an exact prior status.`,
|
|
1212
|
-
`The authorized greeting target is channel_id=${JSON.stringify(config.channelId)}.`,
|
|
1213
|
-
"Before greeting, retrieve relevant memory and wiki context for this immutable user_id, including a known timezone when available. Use their local time for the greeting; if their timezone is unknown, do not guess.",
|
|
1214
|
-
"Send at most one short, natural greeting to the target channel. Do not reveal private memory. If no greeting is appropriate, stay silent."
|
|
1215
|
-
];
|
|
1216
|
-
return {
|
|
1217
|
-
channelId: config.channelId,
|
|
1218
|
-
userId,
|
|
1219
|
-
text: lines.join("\n")
|
|
1220
|
-
};
|
|
1221
|
-
}
|
|
1222
|
-
//#endregion
|
|
1223
|
-
//#region extensions/discord/src/monitor/presence-cooldown-store.ts
|
|
1224
|
-
const DISCORD_PRESENCE_COOLDOWN_MAX_ENTRIES = 25e3;
|
|
1225
|
-
function openDiscordPresenceCooldownStore() {
|
|
1226
|
-
return getDiscordRuntime().state.openSyncKeyedStore({
|
|
1227
|
-
namespace: "presence-greeting-cooldowns",
|
|
1228
|
-
maxEntries: DISCORD_PRESENCE_COOLDOWN_MAX_ENTRIES,
|
|
1229
|
-
overflowPolicy: "reject-new",
|
|
1230
|
-
defaultTtlMs: DISCORD_PRESENCE_GREETING_COOLDOWN_MS
|
|
1231
|
-
});
|
|
1232
|
-
}
|
|
1233
|
-
//#endregion
|
|
1234
|
-
//#region extensions/discord/src/monitor/presence-emission-gate.ts
|
|
1235
|
-
const DISCORD_PRESENCE_RECONNECT_SUPPRESS_MS = 300 * 1e3;
|
|
1236
|
-
const DISCORD_PRESENCE_BURST_LIMIT = 8;
|
|
1237
|
-
const DISCORD_PRESENCE_BURST_WINDOW_MS = 60 * 1e3;
|
|
1238
|
-
function resolveDiscordPresenceGateOptions(config) {
|
|
1239
|
-
return {
|
|
1240
|
-
reconnectSuppressMs: config?.reconnectSuppressSeconds !== void 0 ? config.reconnectSuppressSeconds * 1e3 : DISCORD_PRESENCE_RECONNECT_SUPPRESS_MS,
|
|
1241
|
-
burstLimit: config?.burstLimit ?? DISCORD_PRESENCE_BURST_LIMIT,
|
|
1242
|
-
burstWindowMs: config?.burstWindowSeconds !== void 0 ? config.burstWindowSeconds * 1e3 : DISCORD_PRESENCE_BURST_WINDOW_MS
|
|
1243
|
-
};
|
|
1244
|
-
}
|
|
1245
|
-
/**
|
|
1246
|
-
* Per-account lifecycle gate for online-presence events. Reconnect state belongs to the Gateway
|
|
1247
|
-
* session, while burst state follows the guild-owned configuration that supplies its limits.
|
|
1248
|
-
*/
|
|
1249
|
-
var DiscordPresenceEmissionGate = class {
|
|
1250
|
-
constructor() {
|
|
1251
|
-
this.reconnectLogged = false;
|
|
1252
|
-
this.burstByGuild = /* @__PURE__ */ new Map();
|
|
1253
|
-
this.nextReservationId = 0;
|
|
1254
|
-
}
|
|
1255
|
-
noteGatewaySessionReset(nowMs) {
|
|
1256
|
-
this.lastSessionResetAtMs = nowMs;
|
|
1257
|
-
this.reconnectLogged = false;
|
|
1258
|
-
}
|
|
1259
|
-
evaluateReconnectWindow(nowMs, options) {
|
|
1260
|
-
if (this.lastSessionResetAtMs !== void 0 && options.reconnectSuppressMs > 0 && nowMs - this.lastSessionResetAtMs < options.reconnectSuppressMs) {
|
|
1261
|
-
const shouldLog = !this.reconnectLogged;
|
|
1262
|
-
this.reconnectLogged = true;
|
|
1263
|
-
return {
|
|
1264
|
-
allowed: false,
|
|
1265
|
-
reason: "reconnect-window",
|
|
1266
|
-
shouldLog
|
|
1267
|
-
};
|
|
1268
|
-
}
|
|
1269
|
-
return { allowed: true };
|
|
1270
|
-
}
|
|
1271
|
-
reserveBurst(guildId, nowMs, options) {
|
|
1272
|
-
const state = this.burstByGuild.get(guildId) ?? {
|
|
1273
|
-
reservations: [],
|
|
1274
|
-
logged: false
|
|
1275
|
-
};
|
|
1276
|
-
state.reservations = state.reservations.filter((reservation) => !reservation.committed || nowMs - reservation.atMs < options.burstWindowMs);
|
|
1277
|
-
this.burstByGuild.set(guildId, state);
|
|
1278
|
-
if (state.reservations.length >= options.burstLimit) {
|
|
1279
|
-
const shouldLog = !state.logged;
|
|
1280
|
-
state.logged = true;
|
|
1281
|
-
return {
|
|
1282
|
-
allowed: false,
|
|
1283
|
-
reason: state.reservations.some((reservation) => !reservation.committed) ? "burst-pending" : "burst",
|
|
1284
|
-
shouldLog
|
|
1285
|
-
};
|
|
1286
|
-
}
|
|
1287
|
-
state.logged = false;
|
|
1288
|
-
const reservation = {
|
|
1289
|
-
id: this.nextReservationId++,
|
|
1290
|
-
atMs: nowMs,
|
|
1291
|
-
committed: false
|
|
1292
|
-
};
|
|
1293
|
-
state.reservations.push(reservation);
|
|
1294
|
-
return {
|
|
1295
|
-
allowed: true,
|
|
1296
|
-
reservation: reservation.id
|
|
1297
|
-
};
|
|
1298
|
-
}
|
|
1299
|
-
commitBurst(guildId, reservation, nowMs) {
|
|
1300
|
-
const entry = this.burstByGuild.get(guildId)?.reservations.find((candidate) => candidate.id === reservation);
|
|
1301
|
-
if (!entry) return;
|
|
1302
|
-
entry.atMs = nowMs;
|
|
1303
|
-
entry.committed = true;
|
|
1304
|
-
}
|
|
1305
|
-
releaseBurst(guildId, reservation) {
|
|
1306
|
-
const state = this.burstByGuild.get(guildId);
|
|
1307
|
-
if (!state) return;
|
|
1308
|
-
state.reservations = state.reservations.filter((candidate) => candidate.id !== reservation);
|
|
1309
|
-
if (state.reservations.length === 0 && !state.logged) this.burstByGuild.delete(guildId);
|
|
1310
|
-
}
|
|
1311
|
-
};
|
|
1312
|
-
//#endregion
|
|
1313
|
-
//#region extensions/discord/src/monitor/presence-transition-cache.ts
|
|
1314
|
-
const DEFAULT_PRESENCE_BASELINE_MAX_ENTRIES = 75e3;
|
|
1315
|
-
var DiscordPresenceBaselineCache = class {
|
|
1316
|
-
constructor(maxEntries = DEFAULT_PRESENCE_BASELINE_MAX_ENTRIES) {
|
|
1317
|
-
this.maxEntries = maxEntries;
|
|
1318
|
-
this.offlineByKey = /* @__PURE__ */ new Map();
|
|
1319
|
-
this.onlineByKey = /* @__PURE__ */ new Map();
|
|
1320
|
-
}
|
|
1321
|
-
clear() {
|
|
1322
|
-
this.offlineByKey.clear();
|
|
1323
|
-
this.onlineByKey.clear();
|
|
1324
|
-
}
|
|
1325
|
-
clearScope(scope) {
|
|
1326
|
-
for (const markers of [this.offlineByKey, this.onlineByKey]) for (const [key, markerScope] of markers) if (markerScope === scope) markers.delete(key);
|
|
1327
|
-
}
|
|
1328
|
-
isOffline(scope, key) {
|
|
1329
|
-
return this.offlineByKey.get(key) === scope;
|
|
1330
|
-
}
|
|
1331
|
-
isOnline(scope, key) {
|
|
1332
|
-
return this.onlineByKey.get(key) === scope;
|
|
1333
|
-
}
|
|
1334
|
-
observeOffline(scope, key) {
|
|
1335
|
-
this.deleteMarker(this.onlineByKey, scope, key);
|
|
1336
|
-
return this.observe(this.offlineByKey, scope, key);
|
|
1337
|
-
}
|
|
1338
|
-
observeOnline(scope, key) {
|
|
1339
|
-
this.deleteMarker(this.offlineByKey, scope, key);
|
|
1340
|
-
return this.observe(this.onlineByKey, scope, key);
|
|
1341
|
-
}
|
|
1342
|
-
deleteMarker(markers, scope, key) {
|
|
1343
|
-
if (markers.get(key) === scope) markers.delete(key);
|
|
1344
|
-
}
|
|
1345
|
-
observe(markers, scope, key) {
|
|
1346
|
-
markers.delete(key);
|
|
1347
|
-
markers.set(key, scope);
|
|
1348
|
-
let evictedScope;
|
|
1349
|
-
while (markers.size > this.maxEntries) {
|
|
1350
|
-
const oldestKey = markers.keys().next().value;
|
|
1351
|
-
if (oldestKey === void 0) break;
|
|
1352
|
-
evictedScope = markers.get(oldestKey);
|
|
1353
|
-
markers.delete(oldestKey);
|
|
1354
|
-
}
|
|
1355
|
-
return evictedScope;
|
|
1356
|
-
}
|
|
1357
|
-
};
|
|
1358
|
-
//#endregion
|
|
1359
|
-
//#region extensions/discord/src/monitor/thread-session-close.ts
|
|
1360
|
-
/**
|
|
1361
|
-
* Closes every session entry in the store whose key contains {@link threadId}.
|
|
1362
|
-
* The explicit lifecycle deletion archives the old transcript and guarantees
|
|
1363
|
-
* that a later inbound message starts a fresh session in every reset mode.
|
|
1364
|
-
*/
|
|
1365
|
-
async function closeDiscordThreadSessions(params) {
|
|
1366
|
-
const { cfg, threadId } = params;
|
|
1367
|
-
const normalizedThreadId = normalizeOptionalLowercaseString(threadId) ?? "";
|
|
1368
|
-
if (!normalizedThreadId) return 0;
|
|
1369
|
-
const segmentRe = new RegExp(`:${normalizedThreadId}(?::|$)`, "i");
|
|
1370
|
-
function sessionKeyContainsThreadId(key) {
|
|
1371
|
-
return segmentRe.test(key);
|
|
1372
|
-
}
|
|
1373
|
-
let resetCount = 0;
|
|
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;
|
|
804
|
+
baseText: `Discord ${data.burst ? "super " : ""}reaction ${action}: ${emojiLabel} by ${actorLabel} on ${guildSlug} ${channelLabel} msg ${data.message_id}`,
|
|
805
|
+
contextKey: `discord:reaction:${action}:${data.message_id}:${user.id}:${emojiLabel}${data.burst ? ":burst" : ""}`
|
|
806
|
+
};
|
|
807
|
+
return reactionBase;
|
|
808
|
+
};
|
|
809
|
+
const emitReaction = (text, parentPeerId) => {
|
|
810
|
+
const { contextKey } = resolveReactionBase();
|
|
811
|
+
enqueueRoutedSystemEvent(text, resolveAgentRoute({
|
|
812
|
+
cfg: params.cfg,
|
|
813
|
+
channel: "discord",
|
|
814
|
+
accountId: params.accountId,
|
|
815
|
+
guildId: data.guild_id ?? void 0,
|
|
816
|
+
memberRoleIds,
|
|
817
|
+
peer: {
|
|
818
|
+
kind: isDirectMessage ? "direct" : isGroupDm ? "group" : "channel",
|
|
819
|
+
id: isDirectMessage ? user.id : data.channel_id
|
|
820
|
+
},
|
|
821
|
+
parentPeer: parentPeerId ? {
|
|
822
|
+
kind: "channel",
|
|
823
|
+
id: parentPeerId
|
|
824
|
+
} : void 0
|
|
825
|
+
}), { contextKey });
|
|
826
|
+
};
|
|
827
|
+
const shouldNotifyReaction = (options) => shouldEmitDiscordReactionNotification({
|
|
828
|
+
mode: options.mode,
|
|
829
|
+
botId: botUserId,
|
|
830
|
+
messageAuthorId: options.messageAuthorId,
|
|
831
|
+
userId: user.id,
|
|
832
|
+
userName: user.username,
|
|
833
|
+
userTag: formatDiscordUserTag(user),
|
|
834
|
+
channelConfig: options.channelConfig,
|
|
835
|
+
guildInfo,
|
|
836
|
+
memberRoleIds,
|
|
837
|
+
allowNameMatching: params.allowNameMatching
|
|
838
|
+
});
|
|
839
|
+
const emitReactionWithAuthor = (message) => {
|
|
840
|
+
const { baseText } = resolveReactionBase();
|
|
841
|
+
const authorLabel = message?.author ? formatDiscordUserTag(message.author) : void 0;
|
|
842
|
+
const text = authorLabel ? `${baseText} from ${authorLabel}` : baseText;
|
|
843
|
+
emitReaction(text, parentId);
|
|
844
|
+
};
|
|
845
|
+
const resolveThreadChannelConfig = () => resolveDiscordChannelConfigWithFallback({
|
|
846
|
+
guildInfo,
|
|
847
|
+
channelId: data.channel_id,
|
|
848
|
+
channelName,
|
|
849
|
+
channelSlug,
|
|
850
|
+
parentId,
|
|
851
|
+
parentName,
|
|
852
|
+
parentSlug,
|
|
853
|
+
scope: "thread"
|
|
854
|
+
});
|
|
855
|
+
const authorizeReactionIngressForChannel = async (channelConfig) => await authorizeDiscordReactionIngress({
|
|
856
|
+
...reactionIngressBase,
|
|
857
|
+
channelConfig
|
|
858
|
+
});
|
|
859
|
+
const resolveThreadChannelAccess = async () => {
|
|
860
|
+
const channelConfig = resolveThreadChannelConfig();
|
|
861
|
+
return {
|
|
862
|
+
access: await authorizeReactionIngressForChannel(channelConfig),
|
|
863
|
+
channelConfig
|
|
864
|
+
};
|
|
865
|
+
};
|
|
866
|
+
if (isThreadChannel) {
|
|
867
|
+
await handleDiscordThreadReactionNotification({
|
|
868
|
+
reactionMode,
|
|
869
|
+
message: data.message,
|
|
870
|
+
parentId,
|
|
871
|
+
resolveThreadChannelAccess,
|
|
872
|
+
shouldNotifyReaction,
|
|
873
|
+
resolveReactionBase,
|
|
874
|
+
emitReaction,
|
|
875
|
+
emitReactionWithAuthor
|
|
876
|
+
});
|
|
877
|
+
return;
|
|
1389
878
|
}
|
|
879
|
+
const channelConfig = resolveDiscordChannelConfigWithFallback({
|
|
880
|
+
guildInfo,
|
|
881
|
+
channelId: data.channel_id,
|
|
882
|
+
channelName,
|
|
883
|
+
channelSlug,
|
|
884
|
+
parentId,
|
|
885
|
+
parentName,
|
|
886
|
+
parentSlug,
|
|
887
|
+
scope: "channel"
|
|
888
|
+
});
|
|
889
|
+
await handleDiscordChannelReactionNotification({
|
|
890
|
+
isGuildMessage,
|
|
891
|
+
reactionMode,
|
|
892
|
+
message: data.message,
|
|
893
|
+
channelConfig,
|
|
894
|
+
parentId,
|
|
895
|
+
authorizeReactionIngressForChannel,
|
|
896
|
+
shouldNotifyReaction,
|
|
897
|
+
resolveReactionBase,
|
|
898
|
+
emitReaction,
|
|
899
|
+
emitReactionWithAuthor
|
|
900
|
+
});
|
|
901
|
+
} catch (err) {
|
|
902
|
+
params.logger.error(danger(`discord reaction handler failed: ${String(err)}`));
|
|
1390
903
|
}
|
|
1391
|
-
return resetCount;
|
|
1392
904
|
}
|
|
1393
905
|
//#endregion
|
|
1394
906
|
//#region extensions/discord/src/monitor/listeners.ts
|
|
@@ -1815,11 +1327,16 @@ function isDiscordUnknownInteraction(error) {
|
|
|
1815
1327
|
if (/Unknown interaction/i.test(err.rawBody?.message ?? "")) return true;
|
|
1816
1328
|
return false;
|
|
1817
1329
|
}
|
|
1330
|
+
function resolveDiscordInteractionMessageParts(payload) {
|
|
1331
|
+
const { components, embeds } = payload.channelData?.discord ?? {};
|
|
1332
|
+
return {
|
|
1333
|
+
components: Array.isArray(components) && components.length > 0 ? components : void 0,
|
|
1334
|
+
embeds: Array.isArray(embeds) && embeds.length > 0 ? embeds : void 0
|
|
1335
|
+
};
|
|
1336
|
+
}
|
|
1818
1337
|
function hasRenderableReplyPayload(payload) {
|
|
1819
|
-
|
|
1820
|
-
|
|
1821
|
-
if (Array.isArray(discordData?.components) && discordData.components.length > 0) return true;
|
|
1822
|
-
return false;
|
|
1338
|
+
const { components, embeds } = resolveDiscordInteractionMessageParts(payload);
|
|
1339
|
+
return resolveSendableOutboundReplyParts(payload).hasContent || Boolean(components || embeds);
|
|
1823
1340
|
}
|
|
1824
1341
|
async function safeDiscordInteractionCall(label, fn) {
|
|
1825
1342
|
try {
|
|
@@ -1839,33 +1356,25 @@ async function settleDiscordInteractionWithoutVisibleReply(interaction) {
|
|
|
1839
1356
|
async function deliverDiscordInteractionReply(params) {
|
|
1840
1357
|
const { interaction, payload, textLimit, maxLinesPerMessage, preferFollowUp, chunkMode } = params;
|
|
1841
1358
|
const reply = resolveSendableOutboundReplyParts(payload);
|
|
1842
|
-
|
|
1843
|
-
let firstMessageComponents = Array.isArray(discordData?.components) && discordData.components.length > 0 ? discordData.components : void 0;
|
|
1359
|
+
let { components: firstMessageComponents, embeds: firstMessageEmbeds } = resolveDiscordInteractionMessageParts(payload);
|
|
1844
1360
|
let payloadDelivered = false;
|
|
1845
|
-
const sendMessage = async (content, files, components) => {
|
|
1846
|
-
const
|
|
1847
|
-
const payloadLocal =
|
|
1848
|
-
...
|
|
1361
|
+
const sendMessage = async (content, files, components, embeds) => {
|
|
1362
|
+
const hasV2 = hasDiscordV2Components(components);
|
|
1363
|
+
const payloadLocal = {
|
|
1364
|
+
...content && !hasV2 ? { content } : {},
|
|
1849
1365
|
...components ? { components } : {},
|
|
1366
|
+
...embeds && !hasV2 ? { embeds } : {},
|
|
1850
1367
|
...params.responseEphemeral !== void 0 ? { ephemeral: params.responseEphemeral } : {},
|
|
1851
|
-
files
|
|
1852
|
-
} : {
|
|
1853
|
-
...contentPayload,
|
|
1854
|
-
...components ? { components } : {},
|
|
1855
|
-
...params.responseEphemeral !== void 0 ? { ephemeral: params.responseEphemeral } : {}
|
|
1368
|
+
...files?.length ? { files } : {}
|
|
1856
1369
|
};
|
|
1857
1370
|
let result;
|
|
1858
1371
|
try {
|
|
1859
1372
|
result = await safeDiscordInteractionCall("interaction send", async () => {
|
|
1860
|
-
if (!preferFollowUp && !payloadDelivered)
|
|
1861
|
-
|
|
1862
|
-
payloadDelivered = true;
|
|
1863
|
-
firstMessageComponents = void 0;
|
|
1864
|
-
return;
|
|
1865
|
-
}
|
|
1866
|
-
await interaction.followUp(payloadLocal);
|
|
1373
|
+
if (!preferFollowUp && !payloadDelivered) await interaction.reply(payloadLocal);
|
|
1374
|
+
else await interaction.followUp(payloadLocal);
|
|
1867
1375
|
payloadDelivered = true;
|
|
1868
1376
|
firstMessageComponents = void 0;
|
|
1377
|
+
firstMessageEmbeds = void 0;
|
|
1869
1378
|
});
|
|
1870
1379
|
} catch (error) {
|
|
1871
1380
|
if (!payloadDelivered) throw error;
|
|
@@ -1890,99 +1399,27 @@ async function deliverDiscordInteractionReply(params) {
|
|
|
1890
1399
|
maxLines: maxLinesPerMessage,
|
|
1891
1400
|
chunkMode
|
|
1892
1401
|
}));
|
|
1893
|
-
await sendMessage(chunks[0] ?? "", media, firstMessageComponents);
|
|
1402
|
+
await sendMessage(chunks[0] ?? "", media, firstMessageComponents, firstMessageEmbeds);
|
|
1894
1403
|
for (const chunk of chunks.slice(1)) {
|
|
1895
1404
|
if (!chunk.trim()) continue;
|
|
1896
1405
|
await sendMessage(chunk);
|
|
1897
1406
|
}
|
|
1898
1407
|
return payloadDelivered;
|
|
1899
1408
|
}
|
|
1900
|
-
if (!reply.hasText && !firstMessageComponents) return false;
|
|
1901
|
-
|
|
1409
|
+
if (!reply.hasText && !firstMessageComponents && !firstMessageEmbeds) return false;
|
|
1410
|
+
const chunks = resolveTextChunksWithFallback(reply.text, chunkDiscordTextWithMode(reply.text, {
|
|
1902
1411
|
maxChars: textLimit,
|
|
1903
1412
|
maxLines: maxLinesPerMessage,
|
|
1904
1413
|
chunkMode
|
|
1905
|
-
}))
|
|
1906
|
-
if (chunks.length === 0
|
|
1414
|
+
}));
|
|
1415
|
+
if (chunks.length === 0) chunks.push("");
|
|
1907
1416
|
for (const chunk of chunks) {
|
|
1908
|
-
if (!chunk.trim() && !firstMessageComponents) continue;
|
|
1909
|
-
await sendMessage(chunk, void 0, firstMessageComponents);
|
|
1417
|
+
if (!chunk.trim() && !firstMessageComponents && !firstMessageEmbeds) continue;
|
|
1418
|
+
await sendMessage(chunk, void 0, firstMessageComponents, firstMessageEmbeds);
|
|
1910
1419
|
}
|
|
1911
1420
|
return payloadDelivered;
|
|
1912
1421
|
}
|
|
1913
1422
|
//#endregion
|
|
1914
|
-
//#region extensions/discord/src/monitor/route-resolution.ts
|
|
1915
|
-
function buildDiscordRoutePeer(params) {
|
|
1916
|
-
return {
|
|
1917
|
-
kind: params.isDirectMessage ? "direct" : params.isGroupDm ? "group" : "channel",
|
|
1918
|
-
id: params.isDirectMessage ? params.directUserId?.trim() || params.conversationId : params.conversationId
|
|
1919
|
-
};
|
|
1920
|
-
}
|
|
1921
|
-
function resolveDiscordConversationRoute(params) {
|
|
1922
|
-
return resolveAgentRoute({
|
|
1923
|
-
cfg: params.cfg,
|
|
1924
|
-
channel: "discord",
|
|
1925
|
-
accountId: params.accountId,
|
|
1926
|
-
guildId: params.guildId ?? void 0,
|
|
1927
|
-
memberRoleIds: params.memberRoleIds,
|
|
1928
|
-
peer: params.peer,
|
|
1929
|
-
parentPeer: params.parentConversationId ? {
|
|
1930
|
-
kind: "channel",
|
|
1931
|
-
id: params.parentConversationId
|
|
1932
|
-
} : void 0
|
|
1933
|
-
});
|
|
1934
|
-
}
|
|
1935
|
-
function resolveDiscordBoundConversationRoute(params) {
|
|
1936
|
-
return resolveDiscordEffectiveRoute({
|
|
1937
|
-
route: resolveDiscordConversationRoute({
|
|
1938
|
-
cfg: params.cfg,
|
|
1939
|
-
accountId: params.accountId,
|
|
1940
|
-
guildId: params.guildId,
|
|
1941
|
-
memberRoleIds: params.memberRoleIds,
|
|
1942
|
-
peer: buildDiscordRoutePeer({
|
|
1943
|
-
isDirectMessage: params.isDirectMessage,
|
|
1944
|
-
isGroupDm: params.isGroupDm,
|
|
1945
|
-
directUserId: params.directUserId,
|
|
1946
|
-
conversationId: params.conversationId
|
|
1947
|
-
}),
|
|
1948
|
-
parentConversationId: params.parentConversationId
|
|
1949
|
-
}),
|
|
1950
|
-
boundSessionKey: params.boundSessionKey,
|
|
1951
|
-
configuredRoute: params.configuredRoute,
|
|
1952
|
-
matchedBy: params.matchedBy
|
|
1953
|
-
});
|
|
1954
|
-
}
|
|
1955
|
-
function resolveDiscordEffectiveRoute(params) {
|
|
1956
|
-
const boundSessionKey = params.boundSessionKey?.trim();
|
|
1957
|
-
if (!boundSessionKey) return params.configuredRoute?.route ?? params.route;
|
|
1958
|
-
return {
|
|
1959
|
-
...params.route,
|
|
1960
|
-
sessionKey: boundSessionKey,
|
|
1961
|
-
agentId: resolveAgentIdFromSessionKey(boundSessionKey),
|
|
1962
|
-
lastRoutePolicy: deriveLastRoutePolicy({
|
|
1963
|
-
sessionKey: boundSessionKey,
|
|
1964
|
-
mainSessionKey: params.route.mainSessionKey
|
|
1965
|
-
}),
|
|
1966
|
-
...params.matchedBy ? { matchedBy: params.matchedBy } : {}
|
|
1967
|
-
};
|
|
1968
|
-
}
|
|
1969
|
-
function hasExplicitRuntimeBindingIntent(record) {
|
|
1970
|
-
if (record.targetKind === "subagent") return true;
|
|
1971
|
-
if (isAcpSessionKey(record.targetSessionKey) || isSubagentSessionKey(record.targetSessionKey)) return true;
|
|
1972
|
-
const metadata = record.metadata;
|
|
1973
|
-
if (!metadata || typeof metadata !== "object") return false;
|
|
1974
|
-
return typeof metadata.boundBy === "string" || typeof metadata.label === "string" || typeof metadata.threadName === "string" || metadata.pluginBindingOwner === "plugin";
|
|
1975
|
-
}
|
|
1976
|
-
function shouldIgnoreStaleDiscordRouteBinding(params) {
|
|
1977
|
-
const bindingRecord = params.bindingRecord;
|
|
1978
|
-
const boundSessionKey = bindingRecord?.targetSessionKey?.trim();
|
|
1979
|
-
if (!bindingRecord || !boundSessionKey || hasExplicitRuntimeBindingIntent(bindingRecord)) return false;
|
|
1980
|
-
const bound = parseAgentSessionKey(boundSessionKey);
|
|
1981
|
-
const routed = parseAgentSessionKey(params.route.sessionKey);
|
|
1982
|
-
if (!bound || !routed || bound.rest !== routed.rest) return false;
|
|
1983
|
-
return bound.agentId !== params.route.agentId;
|
|
1984
|
-
}
|
|
1985
|
-
//#endregion
|
|
1986
1423
|
//#region extensions/discord/src/monitor/native-command-route.ts
|
|
1987
1424
|
async function resolveDiscordNativeInteractionRouteState(params) {
|
|
1988
1425
|
const route = resolveDiscordBoundConversationRoute({
|
|
@@ -2050,6 +1487,7 @@ async function dispatchDiscordNativeAgentReply(params) {
|
|
|
2050
1487
|
sessionKey: params.ctxPayload.SessionKey ?? params.effectiveRoute.sessionKey
|
|
2051
1488
|
},
|
|
2052
1489
|
ctxPayload: params.ctxPayload,
|
|
1490
|
+
dispatchReplyFromConfig: params.dispatchReplyFromConfig,
|
|
2053
1491
|
delivery: {
|
|
2054
1492
|
deliver: async (payload) => {
|
|
2055
1493
|
if (params.suppressReplies) return {
|
|
@@ -2099,28 +1537,171 @@ async function dispatchDiscordNativeAgentReply(params) {
|
|
|
2099
1537
|
disableBlockStreaming: typeof blockStreamingEnabled === "boolean" ? !blockStreamingEnabled : void 0
|
|
2100
1538
|
}
|
|
2101
1539
|
});
|
|
2102
|
-
const
|
|
2103
|
-
const dispatchResult = {
|
|
2104
|
-
dispatched: turnResult.dispatched,
|
|
2105
|
-
...hiddenFinalReply ? { hiddenFinalReply } : {}
|
|
1540
|
+
const shouldSettleWithoutVisibleReply = params.suppressReplies || finalReplyOutcome === "suppressed" || turnResult.dispatched && (turnResult.dispatchResult.deliberateSilentTerminalReply === true || turnResult.dispatchResult.deferredToActiveRun !== void 0);
|
|
1541
|
+
const dispatchResult = {
|
|
1542
|
+
dispatched: turnResult.dispatched,
|
|
1543
|
+
...hiddenFinalReply ? { hiddenFinalReply } : {}
|
|
1544
|
+
};
|
|
1545
|
+
if (!didReply && shouldSettleWithoutVisibleReply) {
|
|
1546
|
+
await settleDiscordInteractionWithoutVisibleReply(params.interaction);
|
|
1547
|
+
return dispatchResult;
|
|
1548
|
+
}
|
|
1549
|
+
if (didReply || turnResult.dispatched && hasVisibleInboundReplyDispatch(turnResult.dispatchResult)) return dispatchResult;
|
|
1550
|
+
await safeDiscordInteractionCall("interaction empty fallback", async () => {
|
|
1551
|
+
const payload = {
|
|
1552
|
+
content: DISCORD_EMPTY_VISIBLE_REPLY_WARNING,
|
|
1553
|
+
ephemeral: true
|
|
1554
|
+
};
|
|
1555
|
+
if (params.preferFollowUp) {
|
|
1556
|
+
await params.interaction.followUp(payload);
|
|
1557
|
+
return;
|
|
1558
|
+
}
|
|
1559
|
+
await params.interaction.reply(payload);
|
|
1560
|
+
});
|
|
1561
|
+
return dispatchResult;
|
|
1562
|
+
}
|
|
1563
|
+
//#endregion
|
|
1564
|
+
//#region extensions/discord/src/monitor/commands.ts
|
|
1565
|
+
function resolveDiscordSlashCommandConfig(raw) {
|
|
1566
|
+
return { ephemeral: raw?.ephemeral !== false };
|
|
1567
|
+
}
|
|
1568
|
+
//#endregion
|
|
1569
|
+
//#region extensions/discord/src/monitor/native-command-arg-ui.ts
|
|
1570
|
+
const DISCORD_COMMAND_ARG_CUSTOM_ID_KEY = "cmdarg";
|
|
1571
|
+
function createCommandArgsWithValue(params) {
|
|
1572
|
+
return { values: { [params.argName]: params.value } };
|
|
1573
|
+
}
|
|
1574
|
+
function buildDiscordCommandArgCustomId(params) {
|
|
1575
|
+
return [
|
|
1576
|
+
`${DISCORD_COMMAND_ARG_CUSTOM_ID_KEY}:command=${encodeCustomIdComponent(params.command)}`,
|
|
1577
|
+
`arg=${encodeCustomIdComponent(params.arg)}`,
|
|
1578
|
+
`value=${encodeCustomIdComponent(params.value)}`,
|
|
1579
|
+
`user=${encodeCustomIdComponent(params.userId)}`
|
|
1580
|
+
].join(";");
|
|
1581
|
+
}
|
|
1582
|
+
function parseDiscordCommandArgData(data) {
|
|
1583
|
+
if (!data || typeof data !== "object") return null;
|
|
1584
|
+
const coerce = (value) => typeof value === "string" || typeof value === "number" ? String(value) : "";
|
|
1585
|
+
const rawCommand = coerce(data.command);
|
|
1586
|
+
const rawArg = coerce(data.arg);
|
|
1587
|
+
const rawValue = coerce(data.value);
|
|
1588
|
+
const rawUser = coerce(data.user);
|
|
1589
|
+
if (!rawCommand || !rawArg || !rawValue || !rawUser) return null;
|
|
1590
|
+
return {
|
|
1591
|
+
command: decodeCustomIdComponent(rawCommand),
|
|
1592
|
+
arg: decodeCustomIdComponent(rawArg),
|
|
1593
|
+
value: decodeCustomIdComponent(rawValue),
|
|
1594
|
+
userId: decodeCustomIdComponent(rawUser)
|
|
1595
|
+
};
|
|
1596
|
+
}
|
|
1597
|
+
async function handleDiscordCommandArgInteraction(params) {
|
|
1598
|
+
const { interaction, data, ctx } = params;
|
|
1599
|
+
const clearWithMessage = async (content) => await params.safeInteractionCall("command arg update", () => interaction.update({
|
|
1600
|
+
content,
|
|
1601
|
+
components: []
|
|
1602
|
+
}));
|
|
1603
|
+
const parsed = parseDiscordCommandArgData(data);
|
|
1604
|
+
if (!parsed) {
|
|
1605
|
+
await clearWithMessage("Sorry, that selection is no longer available.");
|
|
1606
|
+
return;
|
|
1607
|
+
}
|
|
1608
|
+
if (interaction.user?.id && interaction.user.id !== parsed.userId) {
|
|
1609
|
+
await params.safeInteractionCall("command arg ack", () => interaction.acknowledge());
|
|
1610
|
+
return;
|
|
1611
|
+
}
|
|
1612
|
+
const commandDefinition = findCommandByNativeName(parsed.command, "discord") ?? listChatCommands().find((entry) => entry.key === parsed.command);
|
|
1613
|
+
if (!commandDefinition) {
|
|
1614
|
+
await clearWithMessage("Sorry, that command is no longer available.");
|
|
1615
|
+
return;
|
|
1616
|
+
}
|
|
1617
|
+
if (await clearWithMessage(`⏳ Applying ${parsed.value}...`) === null) return;
|
|
1618
|
+
const commandArgs = createCommandArgsWithValue({
|
|
1619
|
+
argName: parsed.arg,
|
|
1620
|
+
value: parsed.value
|
|
1621
|
+
});
|
|
1622
|
+
const commandArgsWithRaw = {
|
|
1623
|
+
...commandArgs,
|
|
1624
|
+
raw: serializeCommandArgs(commandDefinition, commandArgs)
|
|
1625
|
+
};
|
|
1626
|
+
const prompt = buildCommandTextFromArgs(commandDefinition, commandArgsWithRaw);
|
|
1627
|
+
await params.dispatchCommandInteraction({
|
|
1628
|
+
interaction,
|
|
1629
|
+
prompt,
|
|
1630
|
+
command: commandDefinition,
|
|
1631
|
+
commandArgs: commandArgsWithRaw,
|
|
1632
|
+
cfg: ctx.cfg,
|
|
1633
|
+
discordConfig: ctx.discordConfig,
|
|
1634
|
+
accountId: ctx.accountId,
|
|
1635
|
+
sessionPrefix: ctx.sessionPrefix,
|
|
1636
|
+
preferFollowUp: true,
|
|
1637
|
+
threadBindings: ctx.threadBindings,
|
|
1638
|
+
responseEphemeral: resolveDiscordSlashCommandConfig(ctx.discordConfig?.slashCommand).ephemeral,
|
|
1639
|
+
dispatchReplyFromConfig: ctx.dispatchReplyFromConfig,
|
|
1640
|
+
pluginCommandDispatch: { kind: "non-plugin" }
|
|
1641
|
+
});
|
|
1642
|
+
}
|
|
1643
|
+
async function runDiscordCommandArgButton(params) {
|
|
1644
|
+
await handleDiscordCommandArgInteraction(params);
|
|
1645
|
+
}
|
|
1646
|
+
var DiscordCommandArgButton = class extends Button {
|
|
1647
|
+
constructor(params) {
|
|
1648
|
+
super();
|
|
1649
|
+
this.style = ButtonStyle.Secondary;
|
|
1650
|
+
this.label = params.label;
|
|
1651
|
+
this.customId = params.customId;
|
|
1652
|
+
this.params = params;
|
|
1653
|
+
}
|
|
1654
|
+
async run(interaction, data) {
|
|
1655
|
+
await runDiscordCommandArgButton({
|
|
1656
|
+
...this.params,
|
|
1657
|
+
interaction,
|
|
1658
|
+
data
|
|
1659
|
+
});
|
|
1660
|
+
}
|
|
1661
|
+
};
|
|
1662
|
+
function buildDiscordCommandArgMenu(params) {
|
|
1663
|
+
const { command, menu, interaction } = params;
|
|
1664
|
+
const commandLabel = command.nativeName ?? command.key;
|
|
1665
|
+
const userId = interaction.user?.id ?? "";
|
|
1666
|
+
const rows = chunkItems(menu.choices, 4).map((choices) => {
|
|
1667
|
+
return new Row(choices.map((choice) => new DiscordCommandArgButton({
|
|
1668
|
+
label: choice.label,
|
|
1669
|
+
customId: buildDiscordCommandArgCustomId({
|
|
1670
|
+
command: commandLabel,
|
|
1671
|
+
arg: menu.arg.name,
|
|
1672
|
+
value: choice.value,
|
|
1673
|
+
userId
|
|
1674
|
+
}),
|
|
1675
|
+
ctx: params.ctx,
|
|
1676
|
+
safeInteractionCall: params.safeInteractionCall,
|
|
1677
|
+
dispatchCommandInteraction: params.dispatchCommandInteraction
|
|
1678
|
+
})));
|
|
1679
|
+
});
|
|
1680
|
+
return {
|
|
1681
|
+
content: formatCommandArgMenuTitle({
|
|
1682
|
+
command,
|
|
1683
|
+
menu
|
|
1684
|
+
}),
|
|
1685
|
+
components: rows
|
|
2106
1686
|
};
|
|
2107
|
-
|
|
2108
|
-
|
|
2109
|
-
|
|
1687
|
+
}
|
|
1688
|
+
var DiscordCommandArgFallbackButton = class extends Button {
|
|
1689
|
+
constructor(params) {
|
|
1690
|
+
super();
|
|
1691
|
+
this.params = params;
|
|
1692
|
+
this.label = "cmdarg";
|
|
1693
|
+
this.customId = "cmdarg:seed=1";
|
|
2110
1694
|
}
|
|
2111
|
-
|
|
2112
|
-
|
|
2113
|
-
|
|
2114
|
-
|
|
2115
|
-
|
|
2116
|
-
};
|
|
2117
|
-
|
|
2118
|
-
|
|
2119
|
-
|
|
2120
|
-
|
|
2121
|
-
await params.interaction.reply(payload);
|
|
2122
|
-
});
|
|
2123
|
-
return dispatchResult;
|
|
1695
|
+
async run(interaction, data) {
|
|
1696
|
+
await runDiscordCommandArgButton({
|
|
1697
|
+
...this.params,
|
|
1698
|
+
interaction,
|
|
1699
|
+
data
|
|
1700
|
+
});
|
|
1701
|
+
}
|
|
1702
|
+
};
|
|
1703
|
+
function createDiscordCommandArgFallbackButton$1(params) {
|
|
1704
|
+
return new DiscordCommandArgFallbackButton(params);
|
|
2124
1705
|
}
|
|
2125
1706
|
//#endregion
|
|
2126
1707
|
//#region extensions/discord/src/monitor/native-interaction-channel-context.ts
|
|
@@ -2398,11 +1979,11 @@ async function resolveDiscordNativeAutocompleteAuthorized(params) {
|
|
|
2398
1979
|
//#endregion
|
|
2399
1980
|
//#region extensions/discord/src/monitor/native-command-bypass.ts
|
|
2400
1981
|
function shouldBypassConfiguredAcpEnsure(commandName) {
|
|
2401
|
-
return
|
|
1982
|
+
return commandName.trim().toLowerCase() === "acp";
|
|
2402
1983
|
}
|
|
2403
1984
|
function shouldBypassConfiguredAcpGuildGuards(commandName) {
|
|
2404
|
-
const
|
|
2405
|
-
return
|
|
1985
|
+
const command = commandName.trim().toLowerCase();
|
|
1986
|
+
return command === "new" || command === "reset";
|
|
2406
1987
|
}
|
|
2407
1988
|
//#endregion
|
|
2408
1989
|
//#region extensions/discord/src/monitor/inbound-context.ts
|
|
@@ -2465,237 +2046,61 @@ function buildDiscordNativeCommandContext(params) {
|
|
|
2465
2046
|
channelConfig: params.channelConfig,
|
|
2466
2047
|
guildInfo: params.guildInfo,
|
|
2467
2048
|
sender: params.sender,
|
|
2468
|
-
allowNameMatching: params.allowNameMatching,
|
|
2469
|
-
isGuild: params.isGuild,
|
|
2470
|
-
channelTopic: params.channelTopic
|
|
2471
|
-
});
|
|
2472
|
-
return finalizeInboundContext({
|
|
2473
|
-
Body: params.prompt,
|
|
2474
|
-
BodyForAgent: params.prompt,
|
|
2475
|
-
RawBody: params.prompt,
|
|
2476
|
-
CommandBody: params.prompt,
|
|
2477
|
-
CommandArgs: params.commandArgs,
|
|
2478
|
-
From: params.isDirectMessage ? `discord:${params.user.id}` : params.isGroupDm ? `discord:group:${params.channelId}` : `discord:channel:${params.channelId}`,
|
|
2479
|
-
To: `slash:${params.user.id}`,
|
|
2480
|
-
SessionKey: params.sessionKey,
|
|
2481
|
-
CommandTargetSessionKey: params.commandTargetSessionKey,
|
|
2482
|
-
AccountId: params.accountId ?? void 0,
|
|
2483
|
-
ChatType: params.isDirectMessage ? "direct" : params.isGroupDm ? "group" : "channel",
|
|
2484
|
-
ConversationLabel: conversationLabel,
|
|
2485
|
-
GroupSubject: params.isGuild ? params.guildName : void 0,
|
|
2486
|
-
GroupSpace: params.isGuild ? params.guildInfo?.id ?? params.guildInfo?.slug ?? params.guildId : void 0,
|
|
2487
|
-
MemberRoleIds: params.memberRoleIds,
|
|
2488
|
-
GroupSystemPrompt: groupSystemPrompt,
|
|
2489
|
-
ChannelStructuredContext: channelStructuredContext,
|
|
2490
|
-
OwnerAllowFrom: ownerAllowFrom,
|
|
2491
|
-
SenderName: params.user.globalName ?? params.user.username,
|
|
2492
|
-
SenderId: params.user.id,
|
|
2493
|
-
SenderUsername: params.user.username,
|
|
2494
|
-
SenderTag: params.sender.tag,
|
|
2495
|
-
Provider: "discord",
|
|
2496
|
-
Surface: "discord",
|
|
2497
|
-
WasMentioned: true,
|
|
2498
|
-
MessageSid: params.interactionId,
|
|
2499
|
-
MessageThreadId: params.isThreadChannel ? params.channelId : void 0,
|
|
2500
|
-
Timestamp: params.timestampMs ?? Date.now(),
|
|
2501
|
-
CommandAuthorized: params.commandAuthorized,
|
|
2502
|
-
CommandTurn: {
|
|
2503
|
-
kind: "native",
|
|
2504
|
-
source: "native",
|
|
2505
|
-
authorized: params.commandAuthorized,
|
|
2506
|
-
body: params.prompt
|
|
2507
|
-
},
|
|
2508
|
-
CommandSource: "native",
|
|
2509
|
-
OriginatingChannel: "discord",
|
|
2510
|
-
OriginatingTo: resolveDiscordConversationIdentity({
|
|
2511
|
-
isDirectMessage: params.isDirectMessage,
|
|
2512
|
-
userId: params.user.id,
|
|
2513
|
-
channelId: params.channelId
|
|
2514
|
-
}) ?? (params.isDirectMessage ? `user:${params.user.id}` : `channel:${params.channelId}`),
|
|
2515
|
-
ThreadParentId: params.isThreadChannel ? params.threadParentId : void 0
|
|
2516
|
-
});
|
|
2517
|
-
}
|
|
2518
|
-
//#endregion
|
|
2519
|
-
//#region extensions/discord/src/monitor/native-command-status.ts
|
|
2520
|
-
async function maybeDeliverDiscordDirectStatus(params) {
|
|
2521
|
-
if (params.suppressReplies || params.commandName !== "status") return null;
|
|
2522
|
-
const statusReply = await params.resolveDirectStatusReplyForSession({
|
|
2523
|
-
cfg: params.cfg,
|
|
2524
|
-
sessionKey: params.commandTargetSessionKey?.trim() || params.sessionKey,
|
|
2525
|
-
channel: params.channel,
|
|
2526
|
-
senderId: params.senderId,
|
|
2527
|
-
senderIsOwner: params.senderIsOwner,
|
|
2528
|
-
isAuthorizedSender: params.isAuthorizedSender,
|
|
2529
|
-
isGroup: params.isGroup,
|
|
2530
|
-
defaultGroupActivation: params.defaultGroupActivation
|
|
2531
|
-
});
|
|
2532
|
-
if (statusReply && hasRenderableReplyPayload(statusReply)) {
|
|
2533
|
-
await deliverDiscordInteractionReply({
|
|
2534
|
-
interaction: params.interaction,
|
|
2535
|
-
payload: statusReply,
|
|
2536
|
-
mediaLocalRoots: params.mediaLocalRoots,
|
|
2537
|
-
textLimit: resolveTextChunkLimit(params.cfg, "discord", params.accountId, { fallbackLimit: 2e3 }),
|
|
2538
|
-
maxLinesPerMessage: resolveDiscordMaxLinesPerMessage({
|
|
2539
|
-
cfg: params.cfg,
|
|
2540
|
-
discordConfig: params.discordConfig,
|
|
2541
|
-
accountId: params.accountId
|
|
2542
|
-
}),
|
|
2543
|
-
preferFollowUp: params.preferFollowUp,
|
|
2544
|
-
responseEphemeral: params.responseEphemeral,
|
|
2545
|
-
chunkMode: resolveChunkMode(params.cfg, "discord", params.accountId)
|
|
2546
|
-
});
|
|
2547
|
-
return {
|
|
2548
|
-
accepted: true,
|
|
2549
|
-
effectiveRoute: params.effectiveRoute
|
|
2550
|
-
};
|
|
2551
|
-
}
|
|
2552
|
-
await params.respond("Status unavailable.");
|
|
2553
|
-
return {
|
|
2554
|
-
accepted: true,
|
|
2555
|
-
effectiveRoute: params.effectiveRoute
|
|
2556
|
-
};
|
|
2557
|
-
}
|
|
2558
|
-
//#endregion
|
|
2559
|
-
//#region extensions/discord/src/monitor/commands.ts
|
|
2560
|
-
function resolveDiscordSlashCommandConfig(raw) {
|
|
2561
|
-
return { ephemeral: raw?.ephemeral !== false };
|
|
2562
|
-
}
|
|
2563
|
-
//#endregion
|
|
2564
|
-
//#region extensions/discord/src/monitor/native-command-arg-ui.ts
|
|
2565
|
-
const DISCORD_COMMAND_ARG_CUSTOM_ID_KEY = "cmdarg";
|
|
2566
|
-
function createCommandArgsWithValue(params) {
|
|
2567
|
-
return { values: { [params.argName]: params.value } };
|
|
2568
|
-
}
|
|
2569
|
-
function buildDiscordCommandArgCustomId(params) {
|
|
2570
|
-
return [
|
|
2571
|
-
`${DISCORD_COMMAND_ARG_CUSTOM_ID_KEY}:command=${encodeCustomIdComponent(params.command)}`,
|
|
2572
|
-
`arg=${encodeCustomIdComponent(params.arg)}`,
|
|
2573
|
-
`value=${encodeCustomIdComponent(params.value)}`,
|
|
2574
|
-
`user=${encodeCustomIdComponent(params.userId)}`
|
|
2575
|
-
].join(";");
|
|
2576
|
-
}
|
|
2577
|
-
function parseDiscordCommandArgData(data) {
|
|
2578
|
-
if (!data || typeof data !== "object") return null;
|
|
2579
|
-
const coerce = (value) => typeof value === "string" || typeof value === "number" ? String(value) : "";
|
|
2580
|
-
const rawCommand = coerce(data.command);
|
|
2581
|
-
const rawArg = coerce(data.arg);
|
|
2582
|
-
const rawValue = coerce(data.value);
|
|
2583
|
-
const rawUser = coerce(data.user);
|
|
2584
|
-
if (!rawCommand || !rawArg || !rawValue || !rawUser) return null;
|
|
2585
|
-
return {
|
|
2586
|
-
command: decodeCustomIdComponent(rawCommand),
|
|
2587
|
-
arg: decodeCustomIdComponent(rawArg),
|
|
2588
|
-
value: decodeCustomIdComponent(rawValue),
|
|
2589
|
-
userId: decodeCustomIdComponent(rawUser)
|
|
2590
|
-
};
|
|
2591
|
-
}
|
|
2592
|
-
async function handleDiscordCommandArgInteraction(params) {
|
|
2593
|
-
const { interaction, data, ctx } = params;
|
|
2594
|
-
const clearWithMessage = async (content) => await params.safeInteractionCall("command arg update", () => interaction.update({
|
|
2595
|
-
content,
|
|
2596
|
-
components: []
|
|
2597
|
-
}));
|
|
2598
|
-
const parsed = parseDiscordCommandArgData(data);
|
|
2599
|
-
if (!parsed) {
|
|
2600
|
-
await clearWithMessage("Sorry, that selection is no longer available.");
|
|
2601
|
-
return;
|
|
2602
|
-
}
|
|
2603
|
-
if (interaction.user?.id && interaction.user.id !== parsed.userId) {
|
|
2604
|
-
await params.safeInteractionCall("command arg ack", () => interaction.acknowledge());
|
|
2605
|
-
return;
|
|
2606
|
-
}
|
|
2607
|
-
const commandDefinition = findCommandByNativeName(parsed.command, "discord") ?? listChatCommands().find((entry) => entry.key === parsed.command);
|
|
2608
|
-
if (!commandDefinition) {
|
|
2609
|
-
await clearWithMessage("Sorry, that command is no longer available.");
|
|
2610
|
-
return;
|
|
2611
|
-
}
|
|
2612
|
-
if (await clearWithMessage(`⏳ Applying ${parsed.value}...`) === null) return;
|
|
2613
|
-
const commandArgs = createCommandArgsWithValue({
|
|
2614
|
-
argName: parsed.arg,
|
|
2615
|
-
value: parsed.value
|
|
2616
|
-
});
|
|
2617
|
-
const commandArgsWithRaw = {
|
|
2618
|
-
...commandArgs,
|
|
2619
|
-
raw: serializeCommandArgs(commandDefinition, commandArgs)
|
|
2620
|
-
};
|
|
2621
|
-
const prompt = buildCommandTextFromArgs(commandDefinition, commandArgsWithRaw);
|
|
2622
|
-
await params.dispatchCommandInteraction({
|
|
2623
|
-
interaction,
|
|
2624
|
-
prompt,
|
|
2625
|
-
command: commandDefinition,
|
|
2626
|
-
commandArgs: commandArgsWithRaw,
|
|
2627
|
-
cfg: ctx.cfg,
|
|
2628
|
-
discordConfig: ctx.discordConfig,
|
|
2629
|
-
accountId: ctx.accountId,
|
|
2630
|
-
sessionPrefix: ctx.sessionPrefix,
|
|
2631
|
-
preferFollowUp: true,
|
|
2632
|
-
threadBindings: ctx.threadBindings,
|
|
2633
|
-
responseEphemeral: resolveDiscordSlashCommandConfig(ctx.discordConfig?.slashCommand).ephemeral,
|
|
2634
|
-
pluginCommandDispatch: { kind: "non-plugin" }
|
|
2635
|
-
});
|
|
2636
|
-
}
|
|
2637
|
-
async function runDiscordCommandArgButton(params) {
|
|
2638
|
-
await handleDiscordCommandArgInteraction(params);
|
|
2639
|
-
}
|
|
2640
|
-
var DiscordCommandArgButton = class extends Button {
|
|
2641
|
-
constructor(params) {
|
|
2642
|
-
super();
|
|
2643
|
-
this.style = ButtonStyle.Secondary;
|
|
2644
|
-
this.label = params.label;
|
|
2645
|
-
this.customId = params.customId;
|
|
2646
|
-
this.params = params;
|
|
2647
|
-
}
|
|
2648
|
-
async run(interaction, data) {
|
|
2649
|
-
await runDiscordCommandArgButton({
|
|
2650
|
-
...this.params,
|
|
2651
|
-
interaction,
|
|
2652
|
-
data
|
|
2653
|
-
});
|
|
2654
|
-
}
|
|
2655
|
-
};
|
|
2656
|
-
function buildDiscordCommandArgMenu(params) {
|
|
2657
|
-
const { command, menu, interaction } = params;
|
|
2658
|
-
const commandLabel = command.nativeName ?? command.key;
|
|
2659
|
-
const userId = interaction.user?.id ?? "";
|
|
2660
|
-
const rows = chunkItems(menu.choices, 4).map((choices) => {
|
|
2661
|
-
return new Row(choices.map((choice) => new DiscordCommandArgButton({
|
|
2662
|
-
label: choice.label,
|
|
2663
|
-
customId: buildDiscordCommandArgCustomId({
|
|
2664
|
-
command: commandLabel,
|
|
2665
|
-
arg: menu.arg.name,
|
|
2666
|
-
value: choice.value,
|
|
2667
|
-
userId
|
|
2668
|
-
}),
|
|
2669
|
-
ctx: params.ctx,
|
|
2670
|
-
safeInteractionCall: params.safeInteractionCall,
|
|
2671
|
-
dispatchCommandInteraction: params.dispatchCommandInteraction
|
|
2672
|
-
})));
|
|
2049
|
+
allowNameMatching: params.allowNameMatching,
|
|
2050
|
+
isGuild: params.isGuild,
|
|
2051
|
+
channelTopic: params.channelTopic
|
|
2673
2052
|
});
|
|
2674
|
-
return {
|
|
2675
|
-
|
|
2676
|
-
|
|
2677
|
-
|
|
2053
|
+
return finalizeInboundContext({
|
|
2054
|
+
Body: params.prompt,
|
|
2055
|
+
BodyForAgent: params.prompt,
|
|
2056
|
+
RawBody: params.prompt,
|
|
2057
|
+
CommandBody: params.prompt,
|
|
2058
|
+
CommandArgs: params.commandArgs,
|
|
2059
|
+
From: params.isDirectMessage ? `discord:${params.user.id}` : params.isGroupDm ? `discord:group:${params.channelId}` : `discord:channel:${params.channelId}`,
|
|
2060
|
+
To: `slash:${params.user.id}`,
|
|
2061
|
+
SessionKey: params.sessionKey,
|
|
2062
|
+
CommandTargetSessionKey: params.commandTargetSessionKey,
|
|
2063
|
+
AccountId: params.accountId ?? void 0,
|
|
2064
|
+
ChatType: params.isDirectMessage ? "direct" : params.isGroupDm ? "group" : "channel",
|
|
2065
|
+
...buildDiscordConversationRouteContext({
|
|
2066
|
+
isDirectMessage: params.isDirectMessage,
|
|
2067
|
+
isGroupDm: params.isGroupDm,
|
|
2068
|
+
directUserId: params.user.id,
|
|
2069
|
+
conversationId: params.channelId,
|
|
2070
|
+
isThread: params.isThreadChannel,
|
|
2071
|
+
parentConversationId: params.threadParentId
|
|
2678
2072
|
}),
|
|
2679
|
-
|
|
2680
|
-
|
|
2681
|
-
|
|
2682
|
-
|
|
2683
|
-
|
|
2684
|
-
|
|
2685
|
-
|
|
2686
|
-
|
|
2687
|
-
|
|
2688
|
-
|
|
2689
|
-
|
|
2690
|
-
|
|
2691
|
-
|
|
2692
|
-
|
|
2693
|
-
|
|
2694
|
-
|
|
2695
|
-
|
|
2696
|
-
|
|
2697
|
-
|
|
2698
|
-
|
|
2073
|
+
ConversationLabel: conversationLabel,
|
|
2074
|
+
GroupSubject: params.isGuild ? params.guildName : void 0,
|
|
2075
|
+
GroupSpace: params.isGuild ? params.guildInfo?.id ?? params.guildInfo?.slug ?? params.guildId : void 0,
|
|
2076
|
+
MemberRoleIds: params.memberRoleIds,
|
|
2077
|
+
GroupSystemPrompt: groupSystemPrompt,
|
|
2078
|
+
ChannelStructuredContext: channelStructuredContext,
|
|
2079
|
+
OwnerAllowFrom: ownerAllowFrom,
|
|
2080
|
+
SenderName: params.user.globalName ?? params.user.username,
|
|
2081
|
+
SenderId: params.user.id,
|
|
2082
|
+
SenderUsername: params.user.username,
|
|
2083
|
+
SenderTag: params.sender.tag,
|
|
2084
|
+
Provider: "discord",
|
|
2085
|
+
Surface: "discord",
|
|
2086
|
+
WasMentioned: true,
|
|
2087
|
+
MessageSid: params.interactionId,
|
|
2088
|
+
Timestamp: params.timestampMs ?? Date.now(),
|
|
2089
|
+
CommandAuthorized: params.commandAuthorized,
|
|
2090
|
+
CommandTurn: {
|
|
2091
|
+
kind: "native",
|
|
2092
|
+
source: "native",
|
|
2093
|
+
authorized: params.commandAuthorized,
|
|
2094
|
+
body: params.prompt
|
|
2095
|
+
},
|
|
2096
|
+
CommandSource: "native",
|
|
2097
|
+
OriginatingChannel: "discord",
|
|
2098
|
+
OriginatingTo: resolveDiscordConversationIdentity({
|
|
2099
|
+
isDirectMessage: params.isDirectMessage,
|
|
2100
|
+
userId: params.user.id,
|
|
2101
|
+
channelId: params.channelId
|
|
2102
|
+
}) ?? (params.isDirectMessage ? `user:${params.user.id}` : `channel:${params.channelId}`)
|
|
2103
|
+
});
|
|
2699
2104
|
}
|
|
2700
2105
|
//#endregion
|
|
2701
2106
|
//#region extensions/discord/src/monitor/model-picker-preferences.ts
|
|
@@ -2876,8 +2281,8 @@ function paginateItems(params) {
|
|
|
2876
2281
|
};
|
|
2877
2282
|
}
|
|
2878
2283
|
async function loadDiscordModelPickerData(cfg, agentId) {
|
|
2879
|
-
const {
|
|
2880
|
-
return
|
|
2284
|
+
const { buildPreparedModelsProviderData } = await loadModelsProviderRuntime();
|
|
2285
|
+
return buildPreparedModelsProviderData(cfg, agentId);
|
|
2881
2286
|
}
|
|
2882
2287
|
function buildDiscordModelPickerCustomId(params) {
|
|
2883
2288
|
const userId = params.userId.trim();
|
|
@@ -3694,6 +3099,7 @@ async function applyDiscordModelPickerSelection(params) {
|
|
|
3694
3099
|
preferFollowUp: true,
|
|
3695
3100
|
threadBindings: params.threadBindings,
|
|
3696
3101
|
suppressReplies: true,
|
|
3102
|
+
dispatchReplyFromConfig: params.dispatchReplyFromConfig,
|
|
3697
3103
|
pluginCommandDispatch: { kind: "non-plugin" }
|
|
3698
3104
|
}), 12e3);
|
|
3699
3105
|
if (!dispatchResult.accepted) return {
|
|
@@ -4351,6 +3757,7 @@ async function handleDiscordModelPickerInteraction(params) {
|
|
|
4351
3757
|
accountId: ctx.accountId,
|
|
4352
3758
|
sessionPrefix: ctx.sessionPrefix,
|
|
4353
3759
|
threadBindings: ctx.threadBindings,
|
|
3760
|
+
dispatchReplyFromConfig: ctx.dispatchReplyFromConfig,
|
|
4354
3761
|
route,
|
|
4355
3762
|
resolvedModelRef,
|
|
4356
3763
|
selectedRuntime,
|
|
@@ -4414,6 +3821,46 @@ function createDiscordModelPickerFallbackSelect$1(params) {
|
|
|
4414
3821
|
return new DiscordModelPickerFallbackSelect(params);
|
|
4415
3822
|
}
|
|
4416
3823
|
//#endregion
|
|
3824
|
+
//#region extensions/discord/src/monitor/native-command-status.ts
|
|
3825
|
+
async function maybeDeliverDiscordDirectStatus(params) {
|
|
3826
|
+
if (params.suppressReplies || params.commandName !== "status") return null;
|
|
3827
|
+
const statusReply = await params.resolveDirectStatusReplyForSession({
|
|
3828
|
+
cfg: params.cfg,
|
|
3829
|
+
sessionKey: params.commandTargetSessionKey?.trim() || params.sessionKey,
|
|
3830
|
+
channel: params.channel,
|
|
3831
|
+
senderId: params.senderId,
|
|
3832
|
+
senderIsOwner: params.senderIsOwner,
|
|
3833
|
+
isAuthorizedSender: params.isAuthorizedSender,
|
|
3834
|
+
isGroup: params.isGroup,
|
|
3835
|
+
defaultGroupActivation: params.defaultGroupActivation
|
|
3836
|
+
});
|
|
3837
|
+
if (statusReply && hasRenderableReplyPayload(statusReply)) {
|
|
3838
|
+
await deliverDiscordInteractionReply({
|
|
3839
|
+
interaction: params.interaction,
|
|
3840
|
+
payload: statusReply,
|
|
3841
|
+
mediaLocalRoots: params.mediaLocalRoots,
|
|
3842
|
+
textLimit: resolveTextChunkLimit(params.cfg, "discord", params.accountId, { fallbackLimit: 2e3 }),
|
|
3843
|
+
maxLinesPerMessage: resolveDiscordMaxLinesPerMessage({
|
|
3844
|
+
cfg: params.cfg,
|
|
3845
|
+
discordConfig: params.discordConfig,
|
|
3846
|
+
accountId: params.accountId
|
|
3847
|
+
}),
|
|
3848
|
+
preferFollowUp: params.preferFollowUp,
|
|
3849
|
+
responseEphemeral: params.responseEphemeral,
|
|
3850
|
+
chunkMode: resolveChunkMode(params.cfg, "discord", params.accountId)
|
|
3851
|
+
});
|
|
3852
|
+
return {
|
|
3853
|
+
accepted: true,
|
|
3854
|
+
effectiveRoute: params.effectiveRoute
|
|
3855
|
+
};
|
|
3856
|
+
}
|
|
3857
|
+
await params.respond("Status unavailable.");
|
|
3858
|
+
return {
|
|
3859
|
+
accepted: true,
|
|
3860
|
+
effectiveRoute: params.effectiveRoute
|
|
3861
|
+
};
|
|
3862
|
+
}
|
|
3863
|
+
//#endregion
|
|
4417
3864
|
//#region extensions/discord/src/monitor/native-command.args.ts
|
|
4418
3865
|
function readDiscordCommandArgs(interaction, definitions) {
|
|
4419
3866
|
if (!definitions || definitions.length === 0) return;
|
|
@@ -4446,7 +3893,7 @@ const DISCORD_COMMAND_DESCRIPTION_MAX = 100;
|
|
|
4446
3893
|
function truncateDiscordCommandDescription(params) {
|
|
4447
3894
|
const { value, label } = params;
|
|
4448
3895
|
if (value.length <= DISCORD_COMMAND_DESCRIPTION_MAX) return value;
|
|
4449
|
-
log$1.
|
|
3896
|
+
log$1.debug(`discord: truncating native command description (${label}) from ${value.length} to ${DISCORD_COMMAND_DESCRIPTION_MAX}: ${JSON.stringify(value)}`);
|
|
4450
3897
|
return truncateUtf16Safe(value, DISCORD_COMMAND_DESCRIPTION_MAX);
|
|
4451
3898
|
}
|
|
4452
3899
|
function truncateDiscordCommandDescriptionLocalizations(params) {
|
|
@@ -4543,7 +3990,7 @@ function buildDiscordCommandOptions(params) {
|
|
|
4543
3990
|
const log = createSubsystemLogger("discord/native-command");
|
|
4544
3991
|
const NON_PLUGIN_COMMAND_DISPATCH = Object.freeze({ kind: "non-plugin" });
|
|
4545
3992
|
function createDiscordNativeCommand(params) {
|
|
4546
|
-
const { command, cfg, discordConfig, accountId, sessionPrefix, ephemeralDefault, threadBindings } = params;
|
|
3993
|
+
const { command, cfg, discordConfig, accountId, sessionPrefix, ephemeralDefault, threadBindings, dispatchReplyFromConfig } = params;
|
|
4547
3994
|
const fallbackCommandDefinition = createNativeCommandDefinition(command);
|
|
4548
3995
|
const pluginCommandCandidate = "prepareDispatch" in command ? command : void 0;
|
|
4549
3996
|
const commandDefinition = pluginCommandCandidate ? fallbackCommandDefinition : findCommandByNativeName$1(command.name, "discord", { includeBundledChannelFallback: false }) ?? fallbackCommandDefinition;
|
|
@@ -4610,13 +4057,14 @@ function createDiscordNativeCommand(params) {
|
|
|
4610
4057
|
preferFollowUp: true,
|
|
4611
4058
|
threadBindings,
|
|
4612
4059
|
responseEphemeral: ephemeralDefault,
|
|
4060
|
+
dispatchReplyFromConfig,
|
|
4613
4061
|
pluginCommandDispatch: preparedPluginCommand ?? NON_PLUGIN_COMMAND_DISPATCH
|
|
4614
4062
|
});
|
|
4615
4063
|
}
|
|
4616
4064
|
}();
|
|
4617
4065
|
}
|
|
4618
4066
|
async function dispatchDiscordCommandInteraction(params) {
|
|
4619
|
-
const { interaction, prompt, command, commandArgs, cfg: inputConfig, discordConfig, accountId, sessionPrefix, preferFollowUp, threadBindings, responseEphemeral, suppressReplies } = params;
|
|
4067
|
+
const { interaction, prompt, command, commandArgs, cfg: inputConfig, discordConfig, accountId, sessionPrefix, preferFollowUp, threadBindings, responseEphemeral, suppressReplies, dispatchReplyFromConfig } = params;
|
|
4620
4068
|
const cfg = getRuntimeConfigSnapshot() ?? inputConfig;
|
|
4621
4069
|
const commandName = command.nativeName ?? command.key;
|
|
4622
4070
|
const respond = async (content, options) => {
|
|
@@ -4854,7 +4302,8 @@ async function dispatchDiscordCommandInteraction(params) {
|
|
|
4854
4302
|
discordConfig,
|
|
4855
4303
|
accountId,
|
|
4856
4304
|
sessionPrefix,
|
|
4857
|
-
threadBindings
|
|
4305
|
+
threadBindings,
|
|
4306
|
+
dispatchReplyFromConfig
|
|
4858
4307
|
},
|
|
4859
4308
|
safeInteractionCall: safeDiscordInteractionCall,
|
|
4860
4309
|
dispatchCommandInteraction: dispatchDiscordCommandInteraction
|
|
@@ -5041,6 +4490,7 @@ async function dispatchDiscordCommandInteraction(params) {
|
|
|
5041
4490
|
preferFollowUp,
|
|
5042
4491
|
responseEphemeral,
|
|
5043
4492
|
suppressReplies,
|
|
4493
|
+
dispatchReplyFromConfig,
|
|
5044
4494
|
log,
|
|
5045
4495
|
pluginCommandDispatch: params.pluginCommandDispatch
|
|
5046
4496
|
});
|
|
@@ -5097,7 +4547,7 @@ function canResumeAfterGatewayClose(code) {
|
|
|
5097
4547
|
//#region extensions/discord/src/internal/gateway-identify-limiter.ts
|
|
5098
4548
|
const IDENTIFY_WINDOW_MS = 5e3;
|
|
5099
4549
|
function normalizeMaxConcurrency(value) {
|
|
5100
|
-
const parsed = parseFiniteNumber
|
|
4550
|
+
const parsed = parseFiniteNumber(value);
|
|
5101
4551
|
return parsed === void 0 ? 1 : Math.max(1, Math.floor(parsed));
|
|
5102
4552
|
}
|
|
5103
4553
|
var GatewayIdentifyLimiter = class {
|
|
@@ -5305,7 +4755,7 @@ var DiscordGatewayVoiceStateCache = class {
|
|
|
5305
4755
|
}
|
|
5306
4756
|
listVoiceChannelStates(guildId, channelId) {
|
|
5307
4757
|
const states = this.statesByGuild.get(guildId);
|
|
5308
|
-
if (!states) return
|
|
4758
|
+
if (!states) return null;
|
|
5309
4759
|
const result = [];
|
|
5310
4760
|
for (const state of states.values()) if (state.channel_id === channelId) result.push({ ...state });
|
|
5311
4761
|
return result;
|
|
@@ -5375,7 +4825,10 @@ const GatewayIntents = GatewayIntentBits;
|
|
|
5375
4825
|
const READY_STATE_OPEN = 1;
|
|
5376
4826
|
const DEFAULT_GATEWAY_URL = "wss://gateway.discord.gg/";
|
|
5377
4827
|
const DISCORD_GATEWAY_PAYLOAD_LIMIT_BYTES = 4096;
|
|
5378
|
-
const DISCORD_GATEWAY_WS_CLIENT_OPTIONS = Object.freeze({
|
|
4828
|
+
const DISCORD_GATEWAY_WS_CLIENT_OPTIONS = Object.freeze({
|
|
4829
|
+
maxPayload: 16 * 1024 * 1024,
|
|
4830
|
+
handshakeTimeout: 3e4
|
|
4831
|
+
});
|
|
5379
4832
|
const INVALID_SESSION_MIN_DELAY_MS = 1e3;
|
|
5380
4833
|
const INVALID_SESSION_JITTER_MS = 4e3;
|
|
5381
4834
|
const RESUME_FAILURE_THRESHOLD = 3;
|
|
@@ -5415,6 +4868,9 @@ var GatewayPlugin = class extends Plugin {
|
|
|
5415
4868
|
listVoiceChannelStates(guildId, channelId) {
|
|
5416
4869
|
return this.voiceStateCache.listVoiceChannelStates(guildId, channelId);
|
|
5417
4870
|
}
|
|
4871
|
+
async fetchGuildEmojis(guildId, fetcher) {
|
|
4872
|
+
return this.client ? await this.client.fetchGuildEmojis(guildId, fetcher) : await fetcher();
|
|
4873
|
+
}
|
|
5418
4874
|
takeVoiceStateTransition(state) {
|
|
5419
4875
|
return this.voiceStateCache.takeTransition(state);
|
|
5420
4876
|
}
|
|
@@ -5518,7 +4974,10 @@ var GatewayPlugin = class extends Plugin {
|
|
|
5518
4974
|
if (payload.s !== null && payload.s !== void 0) this.sequence = payload.s;
|
|
5519
4975
|
switch (payload.op) {
|
|
5520
4976
|
case GatewayOpcodes.Hello: {
|
|
5521
|
-
this.startHeartbeat(payload.d
|
|
4977
|
+
this.startHeartbeat(asSafeIntegerInRange(asOptionalRecord(payload.d)?.heartbeat_interval, {
|
|
4978
|
+
min: 1,
|
|
4979
|
+
max: MAX_TIMER_TIMEOUT_MS
|
|
4980
|
+
}) ?? 45e3);
|
|
5522
4981
|
const resumeState = resume ? this.getResumeState() : null;
|
|
5523
4982
|
if (resumeState) this.send({
|
|
5524
4983
|
op: GatewayOpcodes.Resume,
|
|
@@ -5721,12 +5180,6 @@ var GatewayPlugin = class extends Plugin {
|
|
|
5721
5180
|
}
|
|
5722
5181
|
};
|
|
5723
5182
|
//#endregion
|
|
5724
|
-
//#region extensions/discord/src/voice/config.ts
|
|
5725
|
-
function resolveDiscordVoiceEnabled(voice) {
|
|
5726
|
-
if (voice?.enabled !== void 0) return voice.enabled;
|
|
5727
|
-
return voice !== void 0;
|
|
5728
|
-
}
|
|
5729
|
-
//#endregion
|
|
5730
5183
|
//#region extensions/discord/src/monitor/presence.ts
|
|
5731
5184
|
const DEFAULT_CUSTOM_ACTIVITY_TYPE$1 = 4;
|
|
5732
5185
|
const CUSTOM_STATUS_NAME$1 = "Custom Status";
|
|
@@ -6200,7 +5653,6 @@ async function fetchDiscordGatewayMetadataGuarded(input, init, options) {
|
|
|
6200
5653
|
}
|
|
6201
5654
|
//#endregion
|
|
6202
5655
|
//#region extensions/discord/src/monitor/gateway-plugin.ts
|
|
6203
|
-
const DISCORD_GATEWAY_HANDSHAKE_TIMEOUT_MS = 3e4;
|
|
6204
5656
|
const DISCORD_GATEWAY_POLICY_VIOLATION_CLOSE_CODE = 1008;
|
|
6205
5657
|
const DISCORD_GATEWAY_WS_RECEIVER_LIMIT_CODE = "WS_ERR_TOO_MANY_BUFFERED_PARTS";
|
|
6206
5658
|
const DISCORD_GATEWAY_CLOSE_REASON_LOG_MAX_CHARS = 240;
|
|
@@ -6268,7 +5720,7 @@ function resolveDiscordGatewayIntents(params) {
|
|
|
6268
5720
|
const intentsConfig = params?.intentsConfig;
|
|
6269
5721
|
const voiceEnabled = params?.voiceEnabled;
|
|
6270
5722
|
const voiceStatesEnabled = intentsConfig?.voiceStates ?? voiceEnabled ?? false;
|
|
6271
|
-
let intents = GatewayIntents.Guilds | GatewayIntents.GuildMessages | GatewayIntents.DirectMessages | GatewayIntents.GuildMessageReactions | GatewayIntents.DirectMessageReactions;
|
|
5723
|
+
let intents = GatewayIntents.Guilds | GatewayIntents.GuildExpressions | GatewayIntents.GuildMessages | GatewayIntents.DirectMessages | GatewayIntents.GuildMessageReactions | GatewayIntents.DirectMessageReactions;
|
|
6272
5724
|
if (intentsConfig?.messageContent !== false) intents |= GatewayIntents.MessageContent;
|
|
6273
5725
|
if (voiceStatesEnabled) intents |= GatewayIntents.GuildVoiceStates;
|
|
6274
5726
|
if (intentsConfig?.presence) intents |= GatewayIntents.GuildPresences;
|
|
@@ -6317,7 +5769,6 @@ function createGatewayPlugin(params) {
|
|
|
6317
5769
|
const wsFlowId = randomUUID();
|
|
6318
5770
|
const socket = new ((params.testing?.webSocketCtor) ?? ws.default)(url, {
|
|
6319
5771
|
...DISCORD_GATEWAY_WS_CLIENT_OPTIONS,
|
|
6320
|
-
handshakeTimeout: DISCORD_GATEWAY_HANDSHAKE_TIMEOUT_MS,
|
|
6321
5772
|
...params.wsAgent ? { agent: params.wsAgent } : {}
|
|
6322
5773
|
});
|
|
6323
5774
|
let lastTransportError;
|
|
@@ -7045,7 +6496,7 @@ async function runDiscordGatewayLifecycle(params) {
|
|
|
7045
6496
|
gatewayEmitter?.removeListener(DISCORD_GATEWAY_TRANSPORT_ACTIVITY_EVENT, onGatewayTransportActivity);
|
|
7046
6497
|
if (params.voiceManager) {
|
|
7047
6498
|
await params.voiceManager.destroy();
|
|
7048
|
-
const { setDiscordTranscriptsVoiceManager } = await import("./transcripts-source-
|
|
6499
|
+
const { setDiscordTranscriptsVoiceManager } = await import("./transcripts-source-BLEMH_yi.js").then((n) => n.n);
|
|
7049
6500
|
setDiscordTranscriptsVoiceManager({
|
|
7050
6501
|
accountId: params.accountId,
|
|
7051
6502
|
manager: null
|
|
@@ -7060,7 +6511,7 @@ async function runDiscordGatewayLifecycle(params) {
|
|
|
7060
6511
|
let discordVoiceRuntimePromise;
|
|
7061
6512
|
let discordProviderSessionRuntimePromise;
|
|
7062
6513
|
async function loadDiscordVoiceRuntime() {
|
|
7063
|
-
const promise = discordVoiceRuntimePromise ?? import("./voice-runtime-
|
|
6514
|
+
const promise = discordVoiceRuntimePromise ?? import("./voice-runtime-DY6_o73o.js");
|
|
7064
6515
|
discordVoiceRuntimePromise = promise;
|
|
7065
6516
|
try {
|
|
7066
6517
|
return await promise;
|
|
@@ -7070,7 +6521,7 @@ async function loadDiscordVoiceRuntime() {
|
|
|
7070
6521
|
}
|
|
7071
6522
|
}
|
|
7072
6523
|
async function loadDiscordProviderSessionRuntime() {
|
|
7073
|
-
const promise = discordProviderSessionRuntimePromise ?? import("./provider-session.runtime-
|
|
6524
|
+
const promise = discordProviderSessionRuntimePromise ?? import("./provider-session.runtime-DSNe7r2W.js");
|
|
7074
6525
|
discordProviderSessionRuntimePromise = promise;
|
|
7075
6526
|
try {
|
|
7076
6527
|
return await promise;
|
|
@@ -7431,102 +6882,6 @@ async function cleanupDiscordProviderStartup(params) {
|
|
|
7431
6882
|
if (!params.lifecycleStarted) params.threadBindings.stop();
|
|
7432
6883
|
}
|
|
7433
6884
|
//#endregion
|
|
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
|
|
7448
|
-
});
|
|
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."
|
|
7511
|
-
};
|
|
7512
|
-
}
|
|
7513
|
-
//#endregion
|
|
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
|
-
};
|
|
7528
|
-
}
|
|
7529
|
-
//#endregion
|
|
7530
6885
|
//#region extensions/discord/src/voice/command.ts
|
|
7531
6886
|
const VOICE_CHANNEL_TYPES = [ChannelType.GuildVoice, ChannelType.GuildStageVoice];
|
|
7532
6887
|
const DISCORD_VOICE_COMMAND_SPEC = {
|
|
@@ -7890,8 +7245,8 @@ function formatDiscordDeployRestOperation(err) {
|
|
|
7890
7245
|
function formatDiscordDeployErrorMessage(err) {
|
|
7891
7246
|
if (!isAbortLikeError(err)) return formatErrorMessage$1(err);
|
|
7892
7247
|
const deployErr = err && typeof err === "object" ? err : {};
|
|
7893
|
-
const requestMs = parseFiniteNumber(deployErr.deployRequestMs);
|
|
7894
|
-
const timeoutMs = parseFiniteNumber(deployErr.deployTimeoutMs);
|
|
7248
|
+
const requestMs = parseFiniteNumber$1(deployErr.deployRequestMs);
|
|
7249
|
+
const timeoutMs = parseFiniteNumber$1(deployErr.deployTimeoutMs);
|
|
7895
7250
|
const operation = formatDiscordDeployRestOperation(deployErr);
|
|
7896
7251
|
if (!(requestMs !== void 0 || timeoutMs !== void 0 || deployErr.deployRestMethod !== void 0 || deployErr.deployRestPath !== void 0)) return "Discord REST request was aborted";
|
|
7897
7252
|
const timing = [];
|
|
@@ -7904,8 +7259,8 @@ function formatDiscordDeployErrorMessage(err) {
|
|
|
7904
7259
|
function resolveDiscordDeployRateLimitDetails(err) {
|
|
7905
7260
|
if (!err || typeof err !== "object") return;
|
|
7906
7261
|
const deployErr = err;
|
|
7907
|
-
const status = parseStrictNonNegativeInteger(deployErr.status) ?? parseStrictNonNegativeInteger(deployErr.statusCode);
|
|
7908
|
-
const retryAfterSeconds = parseFiniteNumber(deployErr.retryAfter) ?? parseFiniteNumber(readDiscordDeployObjectField(deployErr.rawBody, "retry_after"));
|
|
7262
|
+
const status = parseStrictNonNegativeInteger$1(deployErr.status) ?? parseStrictNonNegativeInteger$1(deployErr.statusCode);
|
|
7263
|
+
const retryAfterSeconds = parseFiniteNumber$1(deployErr.retryAfter) ?? parseFiniteNumber$1(readDiscordDeployObjectField(deployErr.rawBody, "retry_after"));
|
|
7909
7264
|
if (!(err instanceof RateLimitError || status === 429 || retryAfterSeconds !== void 0)) return;
|
|
7910
7265
|
const rawGlobal = readDiscordDeployObjectField(deployErr.rawBody, "global");
|
|
7911
7266
|
const scope = typeof deployErr.scope === "string" && deployErr.scope.trim().length > 0 ? deployErr.scope : rawGlobal === true ? "global" : rawGlobal === false ? "route" : void 0;
|
|
@@ -7995,8 +7350,8 @@ function formatDiscordDeployErrorDetails(err) {
|
|
|
7995
7350
|
function isDiscordDeployDailyCreateLimit(err) {
|
|
7996
7351
|
if (!err || typeof err !== "object") return false;
|
|
7997
7352
|
const deployErr = err;
|
|
7998
|
-
const discordCode = parseStrictNonNegativeInteger(deployErr.discordCode);
|
|
7999
|
-
const rawCode = parseStrictNonNegativeInteger(readDiscordDeployObjectField(deployErr.rawBody, "code"));
|
|
7353
|
+
const discordCode = parseStrictNonNegativeInteger$1(deployErr.discordCode);
|
|
7354
|
+
const rawCode = parseStrictNonNegativeInteger$1(readDiscordDeployObjectField(deployErr.rawBody, "code"));
|
|
8000
7355
|
return (discordCode === 30034 || rawCode === 30034) && /daily application command creates/i.test(formatErrorMessage$1(err));
|
|
8001
7356
|
}
|
|
8002
7357
|
//#endregion
|
|
@@ -8214,9 +7569,6 @@ function formatUsername(user) {
|
|
|
8214
7569
|
if (user.discriminator && user.discriminator !== "0") return `${user.username}#${user.discriminator}`;
|
|
8215
7570
|
return user.username;
|
|
8216
7571
|
}
|
|
8217
|
-
function isThreadChannelType(channelType) {
|
|
8218
|
-
return channelType === ChannelType.PublicThread || channelType === ChannelType.PrivateThread || channelType === ChannelType.AnnouncementThread;
|
|
8219
|
-
}
|
|
8220
7572
|
function resolveAgentComponentRoute(params) {
|
|
8221
7573
|
return resolveAgentRoute({
|
|
8222
7574
|
cfg: params.ctx.cfg,
|
|
@@ -8259,7 +7611,7 @@ function resolveDiscordChannelContext(interaction) {
|
|
|
8259
7611
|
const channelSlug = channelName ? normalizeDiscordSlug(channelName) : "";
|
|
8260
7612
|
const displayChannelSlug = channelName ? normalizeDiscordDisplaySlug(channelName) : "";
|
|
8261
7613
|
const channelType = channelInfo.type;
|
|
8262
|
-
const isThread =
|
|
7614
|
+
const isThread = isDiscordThreadChannelType(channelType);
|
|
8263
7615
|
let parentId;
|
|
8264
7616
|
let parentName;
|
|
8265
7617
|
let parentSlug = "";
|
|
@@ -8757,7 +8109,8 @@ function resolveReplyContext(message, resolveDiscordMessageText) {
|
|
|
8757
8109
|
const referenced = message.referencedMessage;
|
|
8758
8110
|
if (!referenced?.author) return null;
|
|
8759
8111
|
const referencedText = resolveDiscordMessageText(referenced, { includeForwarded: true });
|
|
8760
|
-
|
|
8112
|
+
const hasVisibleMedia = referenced.attachments.length > 0 || !referencedText && resolveDiscordMessageStickers(referenced).length > 0;
|
|
8113
|
+
if (!referencedText && !hasVisibleMedia) return null;
|
|
8761
8114
|
const sender = resolveDiscordSenderIdentity({
|
|
8762
8115
|
author: referenced.author,
|
|
8763
8116
|
pluralkitInfo: null
|
|
@@ -8773,7 +8126,7 @@ function resolveReplyContext(message, resolveDiscordMessageText) {
|
|
|
8773
8126
|
const roles = referenced.member?.roles;
|
|
8774
8127
|
return Array.isArray(roles) ? roles.map((roleId) => roleId) : void 0;
|
|
8775
8128
|
})(),
|
|
8776
|
-
body: referencedText,
|
|
8129
|
+
...referencedText ? { body: referencedText } : {},
|
|
8777
8130
|
timestamp: resolveTimestampMs(referenced.timestamp)
|
|
8778
8131
|
};
|
|
8779
8132
|
}
|
|
@@ -8933,6 +8286,7 @@ async function deliverDiscordReply(params) {
|
|
|
8933
8286
|
formatting: delivery.formatting,
|
|
8934
8287
|
threadId: delivery.threadId,
|
|
8935
8288
|
identity: delivery.identity,
|
|
8289
|
+
onPlatformSendDispatch: params.onPlatformSendDispatch,
|
|
8936
8290
|
deps: createDiscordDeliveryDeps({
|
|
8937
8291
|
cfg: params.cfg,
|
|
8938
8292
|
token: params.token,
|
|
@@ -8971,7 +8325,7 @@ async function deliverDiscordReply(params) {
|
|
|
8971
8325
|
//#endregion
|
|
8972
8326
|
//#region extensions/discord/src/monitor/agent-components.dispatch.ts
|
|
8973
8327
|
const loadConversationRuntime$1 = createLazyRuntimeModule(() => import("./agent-components.runtime-CEPrf2SY.js"));
|
|
8974
|
-
const loadTypingRuntime = createLazyRuntimeModule(() => import("./typing-
|
|
8328
|
+
const loadTypingRuntime = createLazyRuntimeModule(() => import("./typing-B9snnwMe.js").then((n) => n.n));
|
|
8975
8329
|
function buildDiscordComponentConversationLabel(params) {
|
|
8976
8330
|
if (params.interactionCtx.isDirectMessage) return buildDirectLabel(params.interactionCtx.user);
|
|
8977
8331
|
if (params.interactionCtx.isGroupDm) return `Group DM #${params.channelCtx.channelName ?? params.interactionCtx.channelId} channel id:${params.interactionCtx.channelId}`;
|
|
@@ -9093,6 +8447,14 @@ async function dispatchDiscordComponentEvent(params) {
|
|
|
9093
8447
|
SessionKey: sessionKey,
|
|
9094
8448
|
AccountId: accountId,
|
|
9095
8449
|
ChatType: chatType,
|
|
8450
|
+
...buildDiscordConversationRouteContext({
|
|
8451
|
+
isDirectMessage: interactionCtx.isDirectMessage,
|
|
8452
|
+
isGroupDm: interactionCtx.isGroupDm,
|
|
8453
|
+
directUserId: interactionCtx.userId,
|
|
8454
|
+
conversationId: interactionCtx.channelId,
|
|
8455
|
+
isThread: channelCtx.isThread,
|
|
8456
|
+
parentConversationId: channelCtx.parentId
|
|
8457
|
+
}),
|
|
9096
8458
|
ConversationLabel: fromLabel,
|
|
9097
8459
|
SenderName: senderName,
|
|
9098
8460
|
SenderId: interactionCtx.userId,
|
|
@@ -9161,6 +8523,7 @@ async function dispatchDiscordComponentEvent(params) {
|
|
|
9161
8523
|
sessionKey
|
|
9162
8524
|
},
|
|
9163
8525
|
ctxPayload,
|
|
8526
|
+
dispatchReplyFromConfig: ctx.channelRuntime?.reply?.dispatchReplyFromConfig,
|
|
9164
8527
|
record: {
|
|
9165
8528
|
updateLastRoute: interactionCtx.isDirectMessage ? {
|
|
9166
8529
|
sessionKey: inboundLastRouteSessionKey,
|
|
@@ -9202,7 +8565,8 @@ async function dispatchDiscordComponentEvent(params) {
|
|
|
9202
8565
|
chunkMode: resolveChunkMode(ctx.cfg, "discord", accountId),
|
|
9203
8566
|
mediaLocalRoots,
|
|
9204
8567
|
kind: info.kind,
|
|
9205
|
-
bindPendingFinalDelivery: info.bindPendingFinalDelivery
|
|
8568
|
+
bindPendingFinalDelivery: info.bindPendingFinalDelivery,
|
|
8569
|
+
onPlatformSendDispatch: info.onPlatformSendDispatch
|
|
9206
8570
|
});
|
|
9207
8571
|
if (result.visibleReplySent) replyReference.markSent();
|
|
9208
8572
|
return result;
|
|
@@ -9367,7 +8731,7 @@ async function dispatchPluginDiscordInteractiveEvent(params) {
|
|
|
9367
8731
|
}
|
|
9368
8732
|
//#endregion
|
|
9369
8733
|
//#region extensions/discord/src/monitor/agent-components.handlers.ts
|
|
9370
|
-
const loadComponentsRuntime = createLazyRuntimeModule(() => import("./
|
|
8734
|
+
const loadComponentsRuntime = createLazyRuntimeModule(() => import("./components-Dk35LTf_.js").then((n) => n.t));
|
|
9371
8735
|
async function handleDiscordComponentEvent(params) {
|
|
9372
8736
|
const parsed = parseDiscordComponentData(params.data, resolveInteractionCustomId(params.interaction));
|
|
9373
8737
|
if (!parsed) {
|
|
@@ -10013,29 +9377,24 @@ var QuestionButton = class extends Button {
|
|
|
10013
9377
|
try {
|
|
10014
9378
|
await interaction.acknowledge();
|
|
10015
9379
|
} catch {}
|
|
10016
|
-
let
|
|
9380
|
+
let content;
|
|
10017
9381
|
try {
|
|
10018
|
-
|
|
9382
|
+
content = (await this.ctx.resolveQuestion({
|
|
10019
9383
|
cfg: this.ctx.cfg,
|
|
10020
9384
|
questionId: callback.questionId,
|
|
10021
9385
|
optionIndex: callback.optionIndex,
|
|
10022
9386
|
senderId: interaction.userId,
|
|
10023
9387
|
clientDisplayName: `Discord question (${this.ctx.accountId})`
|
|
10024
|
-
});
|
|
9388
|
+
})).status === "answered" ? "Answer submitted." : "This question was already answered.";
|
|
10025
9389
|
} catch {
|
|
10026
|
-
|
|
10027
|
-
await interaction.followUp({
|
|
10028
|
-
content: "Could not submit this answer.",
|
|
10029
|
-
ephemeral: true
|
|
10030
|
-
});
|
|
10031
|
-
} catch {}
|
|
10032
|
-
return;
|
|
9390
|
+
content = "Could not submit this answer.";
|
|
10033
9391
|
}
|
|
10034
9392
|
try {
|
|
10035
|
-
|
|
10036
|
-
content
|
|
9393
|
+
const feedback = {
|
|
9394
|
+
content,
|
|
10037
9395
|
ephemeral: true
|
|
10038
|
-
}
|
|
9396
|
+
};
|
|
9397
|
+
await (interaction.responseState === "unacknowledged" ? interaction.reply(feedback) : interaction.followUp(feedback));
|
|
10039
9398
|
} catch {}
|
|
10040
9399
|
}
|
|
10041
9400
|
};
|
|
@@ -10079,7 +9438,8 @@ function createDiscordProviderInteractionSurface(params) {
|
|
|
10079
9438
|
accountId: params.accountId,
|
|
10080
9439
|
sessionPrefix: params.sessionPrefix,
|
|
10081
9440
|
ephemeralDefault: params.ephemeralDefault,
|
|
10082
|
-
threadBindings: params.threadBindings
|
|
9441
|
+
threadBindings: params.threadBindings,
|
|
9442
|
+
dispatchReplyFromConfig: params.channelRuntime?.reply?.dispatchReplyFromConfig
|
|
10083
9443
|
});
|
|
10084
9444
|
});
|
|
10085
9445
|
const execApprovalsConfig = params.discordConfig.execApprovals ?? {};
|
|
@@ -10124,21 +9484,24 @@ function createDiscordProviderInteractionSurface(params) {
|
|
|
10124
9484
|
discordConfig: params.discordConfig,
|
|
10125
9485
|
accountId: params.accountId,
|
|
10126
9486
|
sessionPrefix: params.sessionPrefix,
|
|
10127
|
-
threadBindings: params.threadBindings
|
|
9487
|
+
threadBindings: params.threadBindings,
|
|
9488
|
+
dispatchReplyFromConfig: params.channelRuntime?.reply?.dispatchReplyFromConfig
|
|
10128
9489
|
}),
|
|
10129
9490
|
createDiscordModelPickerFallbackButton({
|
|
10130
9491
|
cfg: params.cfg,
|
|
10131
9492
|
discordConfig: params.discordConfig,
|
|
10132
9493
|
accountId: params.accountId,
|
|
10133
9494
|
sessionPrefix: params.sessionPrefix,
|
|
10134
|
-
threadBindings: params.threadBindings
|
|
9495
|
+
threadBindings: params.threadBindings,
|
|
9496
|
+
dispatchReplyFromConfig: params.channelRuntime?.reply?.dispatchReplyFromConfig
|
|
10135
9497
|
}),
|
|
10136
9498
|
createDiscordModelPickerFallbackSelect({
|
|
10137
9499
|
cfg: params.cfg,
|
|
10138
9500
|
discordConfig: params.discordConfig,
|
|
10139
9501
|
accountId: params.accountId,
|
|
10140
9502
|
sessionPrefix: params.sessionPrefix,
|
|
10141
|
-
threadBindings: params.threadBindings
|
|
9503
|
+
threadBindings: params.threadBindings,
|
|
9504
|
+
dispatchReplyFromConfig: params.channelRuntime?.reply?.dispatchReplyFromConfig
|
|
10142
9505
|
})
|
|
10143
9506
|
];
|
|
10144
9507
|
const activityButton = createDiscordActivityButton({
|
|
@@ -10149,6 +9512,7 @@ function createDiscordProviderInteractionSurface(params) {
|
|
|
10149
9512
|
allowFrom: params.allowFrom,
|
|
10150
9513
|
dmPolicy: params.dmPolicy,
|
|
10151
9514
|
runtime: params.runtime,
|
|
9515
|
+
channelRuntime: params.channelRuntime,
|
|
10152
9516
|
token: params.token
|
|
10153
9517
|
}, params.applicationId);
|
|
10154
9518
|
if (activityButton) components.push(activityButton);
|
|
@@ -10217,6 +9581,170 @@ var VoicePlugin = class extends Plugin {
|
|
|
10217
9581
|
}
|
|
10218
9582
|
};
|
|
10219
9583
|
//#endregion
|
|
9584
|
+
//#region extensions/discord/src/monitor/message-handler.preflight-channel-access.ts
|
|
9585
|
+
function resolveDiscordPreflightChannelAccess(params) {
|
|
9586
|
+
if (params.isGuildMessage && params.channelConfig?.enabled === false) {
|
|
9587
|
+
logDebug(`[discord-preflight] drop: channel disabled`);
|
|
9588
|
+
logVerbose(`Blocked discord channel ${params.messageChannelId} (channel disabled, ${params.channelMatchMeta})`);
|
|
9589
|
+
return {
|
|
9590
|
+
allowed: false,
|
|
9591
|
+
channelAllowlistConfigured: false,
|
|
9592
|
+
channelAllowed: false
|
|
9593
|
+
};
|
|
9594
|
+
}
|
|
9595
|
+
const groupDmAllowed = params.isGroupDm && resolveGroupDmAllow({
|
|
9596
|
+
channels: params.groupDmChannels,
|
|
9597
|
+
channelId: params.messageChannelId,
|
|
9598
|
+
channelName: params.displayChannelName,
|
|
9599
|
+
channelSlug: params.displayChannelSlug
|
|
9600
|
+
});
|
|
9601
|
+
if (params.isGroupDm && !groupDmAllowed) return {
|
|
9602
|
+
allowed: false,
|
|
9603
|
+
channelAllowlistConfigured: false,
|
|
9604
|
+
channelAllowed: false
|
|
9605
|
+
};
|
|
9606
|
+
const channelAllowlistConfigured = Boolean(params.guildInfo?.channels) && Object.keys(params.guildInfo?.channels ?? {}).length > 0;
|
|
9607
|
+
const channelAllowed = params.channelConfig?.allowed !== false;
|
|
9608
|
+
if (params.isGuildMessage && !isDiscordGroupAllowedByPolicy({
|
|
9609
|
+
groupPolicy: params.groupPolicy,
|
|
9610
|
+
guildAllowlisted: Boolean(params.guildInfo),
|
|
9611
|
+
channelAllowlistConfigured,
|
|
9612
|
+
channelAllowed
|
|
9613
|
+
})) {
|
|
9614
|
+
if (params.groupPolicy === "disabled") {
|
|
9615
|
+
logDebug(`[discord-preflight] drop: groupPolicy disabled`);
|
|
9616
|
+
logVerbose(`discord: drop guild message (groupPolicy: disabled, ${params.channelMatchMeta})`);
|
|
9617
|
+
} else if (!channelAllowlistConfigured) {
|
|
9618
|
+
logDebug(`[discord-preflight] drop: groupPolicy allowlist, no channel allowlist configured`);
|
|
9619
|
+
logVerbose(`discord: drop guild message (groupPolicy: allowlist, no channel allowlist, ${params.channelMatchMeta})`);
|
|
9620
|
+
} else {
|
|
9621
|
+
logDebug(`[discord] Ignored message from channel ${params.messageChannelId} (not in guild allowlist). Add to guilds.<guildId>.channels to enable.`);
|
|
9622
|
+
logVerbose(`Blocked discord channel ${params.messageChannelId} not in guild channel allowlist (groupPolicy: allowlist, ${params.channelMatchMeta})`);
|
|
9623
|
+
}
|
|
9624
|
+
return {
|
|
9625
|
+
allowed: false,
|
|
9626
|
+
channelAllowlistConfigured,
|
|
9627
|
+
channelAllowed
|
|
9628
|
+
};
|
|
9629
|
+
}
|
|
9630
|
+
if (params.isGuildMessage && params.channelConfig?.allowed === false) {
|
|
9631
|
+
logDebug(`[discord-preflight] drop: channelConfig.allowed===false`);
|
|
9632
|
+
logVerbose(`Blocked discord channel ${params.messageChannelId} not in guild channel allowlist (${params.channelMatchMeta})`);
|
|
9633
|
+
return {
|
|
9634
|
+
allowed: false,
|
|
9635
|
+
channelAllowlistConfigured,
|
|
9636
|
+
channelAllowed
|
|
9637
|
+
};
|
|
9638
|
+
}
|
|
9639
|
+
if (params.isGuildMessage) {
|
|
9640
|
+
logDebug(`[discord-preflight] pass: channel allowed`);
|
|
9641
|
+
logVerbose(`discord: allow channel ${params.messageChannelId} (${params.channelMatchMeta})`);
|
|
9642
|
+
}
|
|
9643
|
+
return {
|
|
9644
|
+
allowed: true,
|
|
9645
|
+
channelAllowlistConfigured,
|
|
9646
|
+
channelAllowed
|
|
9647
|
+
};
|
|
9648
|
+
}
|
|
9649
|
+
//#endregion
|
|
9650
|
+
//#region extensions/discord/src/monitor/listeners.guild-join.ts
|
|
9651
|
+
const DISCORD_GUILD_JOIN_INTRO_MAX_AGE_MS = 300 * 1e3;
|
|
9652
|
+
var DiscordGuildJoinIntroductionListener = class extends GuildCreateListener {
|
|
9653
|
+
constructor(params) {
|
|
9654
|
+
super();
|
|
9655
|
+
this.params = params;
|
|
9656
|
+
}
|
|
9657
|
+
async handle(data, client) {
|
|
9658
|
+
if (!("joined_at" in data) || data.unavailable || !this.params.botUserId) return;
|
|
9659
|
+
const joinAgeMs = Date.now() - Date.parse(data.joined_at);
|
|
9660
|
+
if (!Number.isFinite(joinAgeMs) || joinAgeMs < 0 || joinAgeMs > DISCORD_GUILD_JOIN_INTRO_MAX_AGE_MS) return;
|
|
9661
|
+
const textChannels = data.channels.filter((channel) => channel.type === ChannelType.GuildText);
|
|
9662
|
+
const systemChannel = textChannels.find((channel) => channel.id === data.system_channel_id);
|
|
9663
|
+
const candidateChannels = systemChannel ? [systemChannel, ...textChannels.filter((channel) => channel !== systemChannel)] : textChannels;
|
|
9664
|
+
const discordOptions = {
|
|
9665
|
+
cfg: this.params.cfg,
|
|
9666
|
+
accountId: this.params.accountId,
|
|
9667
|
+
rest: client.rest
|
|
9668
|
+
};
|
|
9669
|
+
const guildInfo = resolveDiscordGuildEntry({
|
|
9670
|
+
guild: new Guild(client, data),
|
|
9671
|
+
guildId: data.id,
|
|
9672
|
+
guildEntries: this.params.guildEntries
|
|
9673
|
+
});
|
|
9674
|
+
const guildConfigured = !this.params.guildEntries || Object.keys(this.params.guildEntries).length === 0 || Boolean(guildInfo);
|
|
9675
|
+
let targetChannel;
|
|
9676
|
+
let roomAllowed = false;
|
|
9677
|
+
for (const channel of candidateChannels) if (await canViewDiscordGuildChannel(data.id, channel.id, this.params.botUserId, discordOptions) && await hasAnyChannelPermissionDiscord(data.id, channel.id, this.params.botUserId, [PermissionFlagsBits.SendMessages], discordOptions)) {
|
|
9678
|
+
targetChannel ??= channel;
|
|
9679
|
+
const channelConfig = resolveDiscordChannelConfig({
|
|
9680
|
+
guildInfo,
|
|
9681
|
+
channelId: channel.id,
|
|
9682
|
+
channelName: channel.name,
|
|
9683
|
+
channelSlug: normalizeDiscordSlug(channel.name)
|
|
9684
|
+
});
|
|
9685
|
+
roomAllowed = guildConfigured && resolveDiscordPreflightChannelAccess({
|
|
9686
|
+
isGuildMessage: true,
|
|
9687
|
+
isGroupDm: false,
|
|
9688
|
+
groupPolicy: this.params.groupPolicy,
|
|
9689
|
+
messageChannelId: channel.id,
|
|
9690
|
+
displayChannelName: channel.name,
|
|
9691
|
+
displayChannelSlug: normalizeDiscordDisplaySlug(channel.name),
|
|
9692
|
+
guildInfo,
|
|
9693
|
+
channelConfig,
|
|
9694
|
+
channelMatchMeta: `guild=${data.id} channel=${channel.id}`
|
|
9695
|
+
}).allowed;
|
|
9696
|
+
if (roomAllowed) {
|
|
9697
|
+
targetChannel = channel;
|
|
9698
|
+
break;
|
|
9699
|
+
}
|
|
9700
|
+
}
|
|
9701
|
+
if (!targetChannel) {
|
|
9702
|
+
this.params.logger?.info("Discord guild join introduction skipped: no writable text channel", {
|
|
9703
|
+
guildId: data.id,
|
|
9704
|
+
accountId: this.params.accountId
|
|
9705
|
+
});
|
|
9706
|
+
return;
|
|
9707
|
+
}
|
|
9708
|
+
const selectedChannel = targetChannel;
|
|
9709
|
+
await reportChannelRoomJoin({
|
|
9710
|
+
cfg: this.params.cfg,
|
|
9711
|
+
channel: "discord",
|
|
9712
|
+
accountId: this.params.accountId,
|
|
9713
|
+
conversationId: data.id,
|
|
9714
|
+
deliverTo: `channel:${selectedChannel.id}`,
|
|
9715
|
+
route: resolveAgentRoute({
|
|
9716
|
+
cfg: this.params.cfg,
|
|
9717
|
+
channel: "discord",
|
|
9718
|
+
accountId: this.params.accountId,
|
|
9719
|
+
guildId: data.id,
|
|
9720
|
+
peer: {
|
|
9721
|
+
kind: "channel",
|
|
9722
|
+
id: selectedChannel.id
|
|
9723
|
+
}
|
|
9724
|
+
}),
|
|
9725
|
+
roomAllowed,
|
|
9726
|
+
resolveRoomContext: async ({ messageLimit }) => {
|
|
9727
|
+
const roomContext = {
|
|
9728
|
+
title: `#${selectedChannel.name}`,
|
|
9729
|
+
purpose: selectedChannel.topic ?? void 0
|
|
9730
|
+
};
|
|
9731
|
+
try {
|
|
9732
|
+
const messages = await readMessagesDiscord(selectedChannel.id, { limit: messageLimit }, discordOptions);
|
|
9733
|
+
return {
|
|
9734
|
+
...roomContext,
|
|
9735
|
+
recentMessages: messages.toReversed().flatMap(({ author, content }) => content.trim() ? [{
|
|
9736
|
+
sender: author.global_name ?? author.username,
|
|
9737
|
+
text: content
|
|
9738
|
+
}] : [])
|
|
9739
|
+
};
|
|
9740
|
+
} catch {
|
|
9741
|
+
return roomContext;
|
|
9742
|
+
}
|
|
9743
|
+
}
|
|
9744
|
+
});
|
|
9745
|
+
}
|
|
9746
|
+
};
|
|
9747
|
+
//#endregion
|
|
10220
9748
|
//#region extensions/discord/src/monitor/provider.startup.ts
|
|
10221
9749
|
function registerLatePlugin(client, plugin) {
|
|
10222
9750
|
plugin.registerClient?.(client);
|
|
@@ -10341,6 +9869,14 @@ async function fetchDiscordBotIdentity(params) {
|
|
|
10341
9869
|
function registerDiscordMonitorListeners(params) {
|
|
10342
9870
|
registerDiscordListener(params.client.listeners, new DiscordInteractionListener(params.logger, params.trackInboundEvent));
|
|
10343
9871
|
registerDiscordListener(params.client.listeners, new DiscordMessageListener(params.messageHandler, params.logger, params.trackInboundEvent));
|
|
9872
|
+
registerDiscordListener(params.client.listeners, new DiscordGuildJoinIntroductionListener({
|
|
9873
|
+
cfg: params.cfg,
|
|
9874
|
+
accountId: params.accountId,
|
|
9875
|
+
botUserId: params.botUserId,
|
|
9876
|
+
groupPolicy: params.groupPolicy,
|
|
9877
|
+
guildEntries: params.guildEntries,
|
|
9878
|
+
logger: params.logger
|
|
9879
|
+
}));
|
|
10344
9880
|
if (shouldRegisterDiscordReactionListeners(params)) {
|
|
10345
9881
|
const reactionListenerOptions = {
|
|
10346
9882
|
cfg: params.cfg,
|
|
@@ -10641,6 +10177,7 @@ async function monitorDiscordProvider(opts = {}) {
|
|
|
10641
10177
|
let earlyGatewayEmitter = gatewaySupervisor?.emitter;
|
|
10642
10178
|
let onEarlyGatewayDebug;
|
|
10643
10179
|
try {
|
|
10180
|
+
const pluginChannelRuntime = opts.channelRuntime;
|
|
10644
10181
|
const { commands, components, modals } = createDiscordProviderInteractionSurface({
|
|
10645
10182
|
cfg,
|
|
10646
10183
|
discordConfig: discordCfg,
|
|
@@ -10660,7 +10197,7 @@ async function monitorDiscordProvider(opts = {}) {
|
|
|
10660
10197
|
allowFrom,
|
|
10661
10198
|
dmPolicy,
|
|
10662
10199
|
runtime,
|
|
10663
|
-
channelRuntime:
|
|
10200
|
+
channelRuntime: pluginChannelRuntime,
|
|
10664
10201
|
abortSignal: opts.abortSignal,
|
|
10665
10202
|
createNativeCommand: discordProviderRuntime.createDiscordNativeCommand
|
|
10666
10203
|
});
|
|
@@ -10734,7 +10271,7 @@ async function monitorDiscordProvider(opts = {}) {
|
|
|
10734
10271
|
runtime,
|
|
10735
10272
|
botUserId
|
|
10736
10273
|
});
|
|
10737
|
-
const { setDiscordTranscriptsVoiceManager } = await import("./transcripts-source-
|
|
10274
|
+
const { setDiscordTranscriptsVoiceManager } = await import("./transcripts-source-BLEMH_yi.js").then((n) => n.n);
|
|
10738
10275
|
setDiscordTranscriptsVoiceManager({
|
|
10739
10276
|
accountId: account.accountId,
|
|
10740
10277
|
manager: voiceManager
|
|
@@ -10752,7 +10289,7 @@ async function monitorDiscordProvider(opts = {}) {
|
|
|
10752
10289
|
accountId: account.accountId,
|
|
10753
10290
|
token,
|
|
10754
10291
|
runtime,
|
|
10755
|
-
buildContext:
|
|
10292
|
+
buildContext: pluginChannelRuntime?.inbound.buildContext,
|
|
10756
10293
|
setStatus: opts.setStatus,
|
|
10757
10294
|
abortSignal: opts.abortSignal,
|
|
10758
10295
|
botUserId,
|
|
@@ -10840,4 +10377,4 @@ async function monitorDiscordProvider(opts = {}) {
|
|
|
10840
10377
|
}
|
|
10841
10378
|
}
|
|
10842
10379
|
//#endregion
|
|
10843
|
-
export {
|
|
10380
|
+
export { resolveDiscordTextCommandAccess as S, handleDiscordDmCommandDecision as _, formatDiscordReplySkip as a, resolveFetchedDiscordThreadLikeChannelContext as b, buildGuildLabel as c, resolveDiscordGatewayIntents as d, waitForDiscordGatewayPluginRegistration as f, createDiscordSupplementalContextAccessChecker as g, buildDiscordInboundAccessContext as h, formatDiscordReplyDeliveryFailure as i, resolveReplyContext as l, buildDiscordGroupSystemPrompt as m, resolveDiscordPreflightChannelAccess as n, sanitizeDiscordFrontChannelReplyPayloads as o, createDiscordNativeCommand as p, deliverDiscordReply as r, buildDirectLabel as s, monitorDiscordProvider as t, createDiscordGatewayPlugin as u, mapGatewayDispatchData as v, resolveDiscordDmCommandAccess as x, registerDiscordListener as y };
|