@gakr-gakr/discord 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (353) hide show
  1. package/account-inspect-api.ts +6 -0
  2. package/action-runtime-api.ts +1 -0
  3. package/api.ts +130 -0
  4. package/autobot.plugin.json +15 -0
  5. package/channel-config-api.ts +1 -0
  6. package/channel-plugin-api.ts +3 -0
  7. package/config-api.ts +4 -0
  8. package/configured-state.ts +6 -0
  9. package/contract-api.ts +21 -0
  10. package/directory-contract-api.ts +4 -0
  11. package/doctor-contract-api.ts +1 -0
  12. package/index.ts +24 -0
  13. package/package.json +79 -0
  14. package/runtime-api.actions.ts +15 -0
  15. package/runtime-api.lookup.ts +22 -0
  16. package/runtime-api.monitor.ts +50 -0
  17. package/runtime-api.send.ts +79 -0
  18. package/runtime-api.threads.ts +31 -0
  19. package/runtime-api.ts +181 -0
  20. package/runtime-setter-api.ts +3 -0
  21. package/secret-contract-api.ts +4 -0
  22. package/security-audit-contract-api.ts +1 -0
  23. package/security-contract-api.ts +4 -0
  24. package/session-key-api.ts +1 -0
  25. package/setup-entry.ts +9 -0
  26. package/setup-plugin-api.ts +3 -0
  27. package/src/account-inspect.ts +131 -0
  28. package/src/accounts.ts +205 -0
  29. package/src/actions/handle-action.guild-admin.ts +421 -0
  30. package/src/actions/handle-action.ts +402 -0
  31. package/src/actions/runtime.guild.ts +446 -0
  32. package/src/actions/runtime.messaging.messages.ts +226 -0
  33. package/src/actions/runtime.messaging.reactions.ts +67 -0
  34. package/src/actions/runtime.messaging.runtime.ts +73 -0
  35. package/src/actions/runtime.messaging.send.ts +336 -0
  36. package/src/actions/runtime.messaging.shared.ts +97 -0
  37. package/src/actions/runtime.messaging.ts +37 -0
  38. package/src/actions/runtime.moderation-shared.ts +48 -0
  39. package/src/actions/runtime.moderation.ts +116 -0
  40. package/src/actions/runtime.presence.ts +117 -0
  41. package/src/actions/runtime.shared.ts +86 -0
  42. package/src/actions/runtime.ts +87 -0
  43. package/src/api.ts +219 -0
  44. package/src/approval-handler.runtime.ts +636 -0
  45. package/src/approval-native.ts +219 -0
  46. package/src/approval-runtime.ts +14 -0
  47. package/src/approval-shared.ts +56 -0
  48. package/src/audit-core.ts +178 -0
  49. package/src/audit.ts +32 -0
  50. package/src/channel-actions.runtime.ts +1 -0
  51. package/src/channel-actions.ts +254 -0
  52. package/src/channel-api.ts +29 -0
  53. package/src/channel.conversation.ts +159 -0
  54. package/src/channel.loaders.ts +50 -0
  55. package/src/channel.runtime.ts +1 -0
  56. package/src/channel.setup.ts +12 -0
  57. package/src/channel.ts +728 -0
  58. package/src/chunk.ts +321 -0
  59. package/src/client.ts +143 -0
  60. package/src/component-custom-id.ts +72 -0
  61. package/src/components-registry.ts +356 -0
  62. package/src/components.builders.ts +410 -0
  63. package/src/components.modal.ts +124 -0
  64. package/src/components.parse.ts +407 -0
  65. package/src/components.ts +54 -0
  66. package/src/components.types.ts +187 -0
  67. package/src/config-schema.ts +6 -0
  68. package/src/config-ui-hints.ts +354 -0
  69. package/src/conversation-identity.ts +58 -0
  70. package/src/delivery-retry.ts +56 -0
  71. package/src/directory-cache.ts +116 -0
  72. package/src/directory-config.ts +58 -0
  73. package/src/directory-live.ts +135 -0
  74. package/src/doctor-contract.ts +477 -0
  75. package/src/doctor-shared.ts +5 -0
  76. package/src/doctor.ts +340 -0
  77. package/src/draft-chunking.ts +43 -0
  78. package/src/draft-stream.ts +162 -0
  79. package/src/error-body.ts +38 -0
  80. package/src/exec-approvals.ts +110 -0
  81. package/src/gateway-logging.ts +67 -0
  82. package/src/group-policy.ts +113 -0
  83. package/src/guilds.ts +29 -0
  84. package/src/inbound-event-delivery.ts +135 -0
  85. package/src/interactive-dispatch.ts +104 -0
  86. package/src/internal/api.commands.ts +51 -0
  87. package/src/internal/api.guild.ts +164 -0
  88. package/src/internal/api.interactions.ts +53 -0
  89. package/src/internal/api.messages.ts +113 -0
  90. package/src/internal/api.reactions.ts +38 -0
  91. package/src/internal/api.ts +61 -0
  92. package/src/internal/api.users.ts +19 -0
  93. package/src/internal/api.webhooks.ts +13 -0
  94. package/src/internal/client.ts +310 -0
  95. package/src/internal/command-deploy.ts +352 -0
  96. package/src/internal/commands.ts +188 -0
  97. package/src/internal/components.base.ts +65 -0
  98. package/src/internal/components.message.ts +279 -0
  99. package/src/internal/components.modal.ts +95 -0
  100. package/src/internal/components.ts +31 -0
  101. package/src/internal/discord.ts +11 -0
  102. package/src/internal/embeds.ts +35 -0
  103. package/src/internal/entity-cache.ts +98 -0
  104. package/src/internal/event-queue.ts +185 -0
  105. package/src/internal/gateway-close-codes.ts +25 -0
  106. package/src/internal/gateway-dispatch.ts +96 -0
  107. package/src/internal/gateway-identify-limiter.ts +26 -0
  108. package/src/internal/gateway-lifecycle.ts +75 -0
  109. package/src/internal/gateway-rate-limit.ts +104 -0
  110. package/src/internal/gateway.ts +479 -0
  111. package/src/internal/interaction-dispatch.ts +162 -0
  112. package/src/internal/interaction-options.ts +98 -0
  113. package/src/internal/interaction-response.ts +53 -0
  114. package/src/internal/interactions.ts +378 -0
  115. package/src/internal/listeners.ts +91 -0
  116. package/src/internal/modal-fields.ts +95 -0
  117. package/src/internal/payload.ts +69 -0
  118. package/src/internal/rest-body.ts +115 -0
  119. package/src/internal/rest-errors.ts +88 -0
  120. package/src/internal/rest-routes.ts +50 -0
  121. package/src/internal/rest-scheduler.ts +557 -0
  122. package/src/internal/rest.ts +322 -0
  123. package/src/internal/schemas.ts +36 -0
  124. package/src/internal/structures.ts +280 -0
  125. package/src/internal/test-builders.test-support.ts +167 -0
  126. package/src/internal/voice.ts +49 -0
  127. package/src/media-detection.ts +28 -0
  128. package/src/mentions.ts +147 -0
  129. package/src/monitor/ack-reactions.ts +70 -0
  130. package/src/monitor/agent-components-auth.ts +7 -0
  131. package/src/monitor/agent-components-context.ts +154 -0
  132. package/src/monitor/agent-components-data.ts +224 -0
  133. package/src/monitor/agent-components-dm-auth.ts +177 -0
  134. package/src/monitor/agent-components-guild-auth.ts +322 -0
  135. package/src/monitor/agent-components-helpers.runtime.ts +3 -0
  136. package/src/monitor/agent-components-helpers.ts +34 -0
  137. package/src/monitor/agent-components-reply.ts +10 -0
  138. package/src/monitor/agent-components.deps.runtime.ts +2 -0
  139. package/src/monitor/agent-components.dispatch.ts +359 -0
  140. package/src/monitor/agent-components.handlers.ts +303 -0
  141. package/src/monitor/agent-components.modal.ts +160 -0
  142. package/src/monitor/agent-components.plugin-interactive.ts +187 -0
  143. package/src/monitor/agent-components.runtime.ts +14 -0
  144. package/src/monitor/agent-components.system-controls.ts +215 -0
  145. package/src/monitor/agent-components.ts +70 -0
  146. package/src/monitor/agent-components.types.ts +58 -0
  147. package/src/monitor/agent-components.wildcard-controls.ts +171 -0
  148. package/src/monitor/allow-list.ts +631 -0
  149. package/src/monitor/auto-presence.ts +356 -0
  150. package/src/monitor/channel-access.ts +102 -0
  151. package/src/monitor/commands.ts +9 -0
  152. package/src/monitor/dm-command-auth.ts +259 -0
  153. package/src/monitor/dm-command-decision.ts +49 -0
  154. package/src/monitor/exec-approvals.ts +161 -0
  155. package/src/monitor/format.ts +45 -0
  156. package/src/monitor/gateway-handle.ts +34 -0
  157. package/src/monitor/gateway-metadata.ts +298 -0
  158. package/src/monitor/gateway-plugin.ts +302 -0
  159. package/src/monitor/gateway-registry.ts +37 -0
  160. package/src/monitor/gateway-supervisor.ts +206 -0
  161. package/src/monitor/inbound-context.ts +95 -0
  162. package/src/monitor/inbound-dedupe.ts +79 -0
  163. package/src/monitor/inbound-job.ts +118 -0
  164. package/src/monitor/listeners.queue.ts +91 -0
  165. package/src/monitor/listeners.reactions.ts +594 -0
  166. package/src/monitor/listeners.ts +150 -0
  167. package/src/monitor/message-channel-info.ts +96 -0
  168. package/src/monitor/message-forwarded.ts +114 -0
  169. package/src/monitor/message-handler.batch-gate.ts +19 -0
  170. package/src/monitor/message-handler.context.ts +492 -0
  171. package/src/monitor/message-handler.dm-preflight.ts +119 -0
  172. package/src/monitor/message-handler.draft-preview.ts +436 -0
  173. package/src/monitor/message-handler.hydration.ts +198 -0
  174. package/src/monitor/message-handler.module-test-helpers.ts +31 -0
  175. package/src/monitor/message-handler.preflight-channel-access.ts +86 -0
  176. package/src/monitor/message-handler.preflight-channel-context.ts +58 -0
  177. package/src/monitor/message-handler.preflight-context.ts +54 -0
  178. package/src/monitor/message-handler.preflight-helpers.ts +164 -0
  179. package/src/monitor/message-handler.preflight-history.ts +23 -0
  180. package/src/monitor/message-handler.preflight-logging.ts +36 -0
  181. package/src/monitor/message-handler.preflight-pluralkit.ts +28 -0
  182. package/src/monitor/message-handler.preflight-runtime.ts +28 -0
  183. package/src/monitor/message-handler.preflight-thread.ts +49 -0
  184. package/src/monitor/message-handler.preflight.ts +822 -0
  185. package/src/monitor/message-handler.preflight.types.ts +115 -0
  186. package/src/monitor/message-handler.process.ts +1033 -0
  187. package/src/monitor/message-handler.routing-preflight.ts +112 -0
  188. package/src/monitor/message-handler.ts +309 -0
  189. package/src/monitor/message-media.ts +536 -0
  190. package/src/monitor/message-run-queue.ts +101 -0
  191. package/src/monitor/message-text.ts +171 -0
  192. package/src/monitor/message-utils.ts +34 -0
  193. package/src/monitor/model-picker-preferences.ts +184 -0
  194. package/src/monitor/model-picker.state.ts +364 -0
  195. package/src/monitor/model-picker.test-utils.ts +26 -0
  196. package/src/monitor/model-picker.ts +38 -0
  197. package/src/monitor/model-picker.view.ts +722 -0
  198. package/src/monitor/native-command-agent-reply.ts +125 -0
  199. package/src/monitor/native-command-arg-ui.ts +233 -0
  200. package/src/monitor/native-command-auth.ts +309 -0
  201. package/src/monitor/native-command-bypass.ts +13 -0
  202. package/src/monitor/native-command-context.ts +109 -0
  203. package/src/monitor/native-command-dispatch.ts +35 -0
  204. package/src/monitor/native-command-model-picker-apply.ts +209 -0
  205. package/src/monitor/native-command-model-picker-interaction.ts +516 -0
  206. package/src/monitor/native-command-model-picker-ui.ts +357 -0
  207. package/src/monitor/native-command-reply.ts +185 -0
  208. package/src/monitor/native-command-route.ts +91 -0
  209. package/src/monitor/native-command-status.ts +76 -0
  210. package/src/monitor/native-command-ui.ts +26 -0
  211. package/src/monitor/native-command-ui.types.ts +20 -0
  212. package/src/monitor/native-command.args.ts +45 -0
  213. package/src/monitor/native-command.options.ts +153 -0
  214. package/src/monitor/native-command.runtime.ts +51 -0
  215. package/src/monitor/native-command.ts +747 -0
  216. package/src/monitor/native-command.types.ts +9 -0
  217. package/src/monitor/native-interaction-channel-context.ts +50 -0
  218. package/src/monitor/preflight-audio.runtime.ts +9 -0
  219. package/src/monitor/preflight-audio.ts +130 -0
  220. package/src/monitor/presence-cache.ts +61 -0
  221. package/src/monitor/presence.ts +50 -0
  222. package/src/monitor/provider-session.runtime.ts +12 -0
  223. package/src/monitor/provider.acp.ts +89 -0
  224. package/src/monitor/provider.allowlist.ts +398 -0
  225. package/src/monitor/provider.cleanup.ts +41 -0
  226. package/src/monitor/provider.commands.ts +129 -0
  227. package/src/monitor/provider.config-log.ts +45 -0
  228. package/src/monitor/provider.deploy-errors.ts +362 -0
  229. package/src/monitor/provider.deploy.ts +221 -0
  230. package/src/monitor/provider.interactions.ts +160 -0
  231. package/src/monitor/provider.lifecycle.ts +562 -0
  232. package/src/monitor/provider.runtime.ts +1 -0
  233. package/src/monitor/provider.startup-log.ts +32 -0
  234. package/src/monitor/provider.startup.ts +323 -0
  235. package/src/monitor/provider.ts +688 -0
  236. package/src/monitor/reply-context.ts +64 -0
  237. package/src/monitor/reply-delivery.ts +216 -0
  238. package/src/monitor/reply-safety.ts +96 -0
  239. package/src/monitor/rest-fetch.ts +97 -0
  240. package/src/monitor/route-resolution.ts +140 -0
  241. package/src/monitor/sender-identity.ts +81 -0
  242. package/src/monitor/startup-status.ts +10 -0
  243. package/src/monitor/status.ts +22 -0
  244. package/src/monitor/system-events.ts +55 -0
  245. package/src/monitor/thread-bindings.config.ts +35 -0
  246. package/src/monitor/thread-bindings.discord-api.ts +310 -0
  247. package/src/monitor/thread-bindings.lifecycle.ts +354 -0
  248. package/src/monitor/thread-bindings.manager.ts +554 -0
  249. package/src/monitor/thread-bindings.messages.ts +6 -0
  250. package/src/monitor/thread-bindings.persona.ts +25 -0
  251. package/src/monitor/thread-bindings.session-adapter.ts +229 -0
  252. package/src/monitor/thread-bindings.session-shared.ts +59 -0
  253. package/src/monitor/thread-bindings.session-updates.ts +35 -0
  254. package/src/monitor/thread-bindings.state.ts +540 -0
  255. package/src/monitor/thread-bindings.ts +48 -0
  256. package/src/monitor/thread-bindings.types.ts +83 -0
  257. package/src/monitor/thread-channel-context.ts +112 -0
  258. package/src/monitor/thread-session-close.ts +63 -0
  259. package/src/monitor/thread-title.ts +181 -0
  260. package/src/monitor/threading.auto-thread.ts +287 -0
  261. package/src/monitor/threading.cache.ts +45 -0
  262. package/src/monitor/threading.starter.ts +288 -0
  263. package/src/monitor/threading.ts +20 -0
  264. package/src/monitor/threading.types.ts +102 -0
  265. package/src/monitor/timeouts.ts +84 -0
  266. package/src/monitor/typing.ts +17 -0
  267. package/src/monitor.gateway.ts +75 -0
  268. package/src/monitor.ts +28 -0
  269. package/src/network-config.ts +79 -0
  270. package/src/normalize.ts +86 -0
  271. package/src/outbound-adapter.ts +327 -0
  272. package/src/outbound-approval.ts +29 -0
  273. package/src/outbound-components.ts +86 -0
  274. package/src/outbound-payload.ts +208 -0
  275. package/src/outbound-send-context.ts +92 -0
  276. package/src/outbound-session-route.ts +72 -0
  277. package/src/pluralkit.ts +58 -0
  278. package/src/preview-streaming.ts +18 -0
  279. package/src/probe.runtime.ts +1 -0
  280. package/src/probe.ts +237 -0
  281. package/src/proxy-fetch.ts +92 -0
  282. package/src/proxy-request-client.ts +21 -0
  283. package/src/recipient-resolution.ts +39 -0
  284. package/src/resolve-allowlist-common.ts +39 -0
  285. package/src/resolve-channels.ts +369 -0
  286. package/src/resolve-users.ts +184 -0
  287. package/src/retry.ts +98 -0
  288. package/src/runtime-api.ts +64 -0
  289. package/src/runtime-config.ts +16 -0
  290. package/src/runtime.ts +23 -0
  291. package/src/secret-config-contract.ts +140 -0
  292. package/src/security-audit.runtime.ts +1 -0
  293. package/src/security-audit.ts +208 -0
  294. package/src/security-contract.ts +47 -0
  295. package/src/security-doctor.ts +20 -0
  296. package/src/security.ts +60 -0
  297. package/src/send-target-parsing.ts +14 -0
  298. package/src/send.channels.ts +139 -0
  299. package/src/send.components.ts +391 -0
  300. package/src/send.emojis-stickers.ts +57 -0
  301. package/src/send.guild.ts +170 -0
  302. package/src/send.message-request.ts +112 -0
  303. package/src/send.messages.ts +229 -0
  304. package/src/send.outbound.ts +459 -0
  305. package/src/send.permissions.ts +283 -0
  306. package/src/send.reactions.ts +155 -0
  307. package/src/send.receipt.ts +69 -0
  308. package/src/send.shared.ts +469 -0
  309. package/src/send.ts +82 -0
  310. package/src/send.types.ts +191 -0
  311. package/src/send.typing.ts +9 -0
  312. package/src/send.voice.ts +140 -0
  313. package/src/send.webhook.ts +137 -0
  314. package/src/session-contract.ts +3 -0
  315. package/src/session-key-normalization.ts +47 -0
  316. package/src/setup-account-state.ts +144 -0
  317. package/src/setup-adapter.ts +14 -0
  318. package/src/setup-core.ts +215 -0
  319. package/src/setup-runtime-helpers.ts +10 -0
  320. package/src/setup-surface.ts +132 -0
  321. package/src/shared-interactive.ts +167 -0
  322. package/src/shared.ts +197 -0
  323. package/src/status-issues.ts +201 -0
  324. package/src/subagent-hooks.ts +232 -0
  325. package/src/target-parsing.ts +70 -0
  326. package/src/target-resolver.ts +129 -0
  327. package/src/targets.ts +12 -0
  328. package/src/token.ts +107 -0
  329. package/src/ui-colors.ts +27 -0
  330. package/src/ui.ts +20 -0
  331. package/src/voice/access.ts +126 -0
  332. package/src/voice/audio.ts +249 -0
  333. package/src/voice/capture-state.ts +120 -0
  334. package/src/voice/command.ts +284 -0
  335. package/src/voice/config.ts +8 -0
  336. package/src/voice/ingress.ts +164 -0
  337. package/src/voice/manager.runtime.ts +14 -0
  338. package/src/voice/manager.ts +1155 -0
  339. package/src/voice/prompt.ts +22 -0
  340. package/src/voice/realtime.ts +1370 -0
  341. package/src/voice/receive-recovery.ts +159 -0
  342. package/src/voice/sanitize.ts +29 -0
  343. package/src/voice/sdk-runtime.ts +14 -0
  344. package/src/voice/segment.ts +160 -0
  345. package/src/voice/session.ts +81 -0
  346. package/src/voice/speaker-context.ts +127 -0
  347. package/src/voice/tts.ts +151 -0
  348. package/src/voice-message.ts +474 -0
  349. package/subagent-hooks-api.ts +27 -0
  350. package/test-api.ts +4 -0
  351. package/thread-binding-api.ts +1 -0
  352. package/timeouts.ts +6 -0
  353. package/tsconfig.json +16 -0
@@ -0,0 +1,747 @@
1
+ import { ApplicationCommandOptionType } from "discord-api-types/v10";
2
+ import { resolveNativeCommandSessionTargets } from "autobot/plugin-sdk/command-auth-native";
3
+ import type { AutoBotConfig } from "autobot/plugin-sdk/config-contracts";
4
+ import { buildPairingReply } from "autobot/plugin-sdk/conversation-runtime";
5
+ import { isDangerousNameMatchingEnabled } from "autobot/plugin-sdk/dangerous-name-runtime";
6
+ import { getAgentScopedMediaLocalRoots } from "autobot/plugin-sdk/media-runtime";
7
+ import {
8
+ buildCommandTextFromArgs,
9
+ findCommandByNativeName,
10
+ parseCommandArgs,
11
+ resolveCommandArgMenu,
12
+ serializeCommandArgs,
13
+ type ChatCommandDefinition,
14
+ type NativeCommandSpec,
15
+ } from "autobot/plugin-sdk/native-command-registry";
16
+ import { resolveChunkMode, resolveTextChunkLimit } from "autobot/plugin-sdk/reply-chunking";
17
+ import { createSubsystemLogger, logVerbose } from "autobot/plugin-sdk/runtime-env";
18
+ import { resolveOpenProviderRuntimeGroupPolicy } from "autobot/plugin-sdk/runtime-group-policy";
19
+ import { normalizeOptionalString } from "autobot/plugin-sdk/string-coerce-runtime";
20
+ import {
21
+ resolveDiscordAccountAllowFrom,
22
+ resolveDiscordAccountDmPolicy,
23
+ resolveDiscordMaxLinesPerMessage,
24
+ } from "../accounts.js";
25
+ import {
26
+ Button,
27
+ Command,
28
+ StringSelectMenu,
29
+ type ButtonInteraction,
30
+ type CommandInteraction,
31
+ type CommandOptions,
32
+ type StringSelectMenuInteraction,
33
+ } from "../internal/discord.js";
34
+ import {
35
+ resolveDiscordChannelConfigWithFallback,
36
+ resolveDiscordChannelPolicyCommandAuthorizer,
37
+ resolveDiscordGuildEntry,
38
+ resolveDiscordOwnerAccess,
39
+ } from "./allow-list.js";
40
+ import { resolveDiscordChannelTopicSafe } from "./channel-access.js";
41
+ import { resolveDiscordDmCommandAccess } from "./dm-command-auth.js";
42
+ import { handleDiscordDmCommandDecision } from "./dm-command-decision.js";
43
+ import { dispatchDiscordNativeAgentReply } from "./native-command-agent-reply.js";
44
+ import {
45
+ resolveDiscordGuildNativeCommandAuthorized,
46
+ resolveDiscordNativeAutocompleteAuthorized,
47
+ resolveDiscordNativeCommandAllowlistAccess,
48
+ resolveDiscordNativeGroupDmAccess,
49
+ } from "./native-command-auth.js";
50
+ import {
51
+ shouldBypassConfiguredAcpEnsure,
52
+ shouldBypassConfiguredAcpGuildGuards,
53
+ } from "./native-command-bypass.js";
54
+ import { buildDiscordNativeCommandContext } from "./native-command-context.js";
55
+ import type { DispatchDiscordCommandInteractionResult } from "./native-command-dispatch.js";
56
+ import {
57
+ DISCORD_EMPTY_VISIBLE_REPLY_WARNING,
58
+ deliverDiscordInteractionReply,
59
+ hasRenderableReplyPayload,
60
+ safeDiscordInteractionCall,
61
+ } from "./native-command-reply.js";
62
+ import { maybeDeliverDiscordDirectStatus } from "./native-command-status.js";
63
+ import {
64
+ buildDiscordCommandArgMenu,
65
+ createDiscordCommandArgFallbackButton as createDiscordCommandArgFallbackButtonUi,
66
+ createDiscordModelPickerFallbackButton as createDiscordModelPickerFallbackButtonUi,
67
+ createDiscordModelPickerFallbackSelect as createDiscordModelPickerFallbackSelectUi,
68
+ replyWithDiscordModelPickerProviders,
69
+ resolveDiscordNativeChoiceContext,
70
+ shouldOpenDiscordModelPickerFromCommand,
71
+ type DiscordCommandArgContext,
72
+ type DiscordModelPickerContext,
73
+ } from "./native-command-ui.js";
74
+ import { createNativeCommandDefinition, readDiscordCommandArgs } from "./native-command.args.js";
75
+ import {
76
+ buildDiscordCommandOptions,
77
+ truncateDiscordCommandDescriptionLocalizations,
78
+ truncateDiscordCommandDescription,
79
+ } from "./native-command.options.js";
80
+ import { nativeCommandRuntime } from "./native-command.runtime.js";
81
+ import type { DiscordCommandArgs, DiscordConfig } from "./native-command.types.js";
82
+ import { resolveDiscordNativeInteractionChannelContext } from "./native-interaction-channel-context.js";
83
+ import { resolveDiscordSenderIdentity } from "./sender-identity.js";
84
+ import type { ThreadBindingManager } from "./thread-bindings.js";
85
+
86
+ const log = createSubsystemLogger("discord/native-command");
87
+ export { testing, testing as __testing } from "./native-command.runtime.js";
88
+
89
+ function resolveDiscordCommandOwnerAllowFrom(cfg: AutoBotConfig): string[] | undefined {
90
+ const raw = cfg.commands?.ownerAllowFrom;
91
+ if (!Array.isArray(raw) || raw.length === 0) {
92
+ return undefined;
93
+ }
94
+ const entries: string[] = [];
95
+ for (const entry of raw) {
96
+ const trimmed = normalizeOptionalString(String(entry ?? "")) ?? "";
97
+ if (!trimmed) {
98
+ continue;
99
+ }
100
+ const separatorIndex = trimmed.indexOf(":");
101
+ if (separatorIndex > 0) {
102
+ const prefix = trimmed.slice(0, separatorIndex).toLowerCase();
103
+ if (prefix === "discord") {
104
+ const remainder = normalizeOptionalString(trimmed.slice(separatorIndex + 1)) ?? "";
105
+ if (remainder) {
106
+ entries.push(remainder);
107
+ }
108
+ continue;
109
+ }
110
+ if (prefix !== "user" && prefix !== "pk") {
111
+ continue;
112
+ }
113
+ }
114
+ entries.push(trimmed);
115
+ }
116
+ return entries.length > 0 ? entries : undefined;
117
+ }
118
+
119
+ export function createDiscordNativeCommand(params: {
120
+ command: NativeCommandSpec;
121
+ cfg: AutoBotConfig;
122
+ discordConfig: DiscordConfig;
123
+ accountId: string;
124
+ sessionPrefix: string;
125
+ ephemeralDefault: boolean;
126
+ threadBindings: ThreadBindingManager;
127
+ }): Command {
128
+ const {
129
+ command,
130
+ cfg,
131
+ discordConfig,
132
+ accountId,
133
+ sessionPrefix,
134
+ ephemeralDefault,
135
+ threadBindings,
136
+ } = params;
137
+ const fallbackCommandDefinition = createNativeCommandDefinition(command);
138
+ const commandDefinition =
139
+ nativeCommandRuntime.matchPluginCommand(`/${command.name}`) !== null
140
+ ? fallbackCommandDefinition
141
+ : (findCommandByNativeName(command.name, "discord", {
142
+ includeBundledChannelFallback: false,
143
+ }) ?? fallbackCommandDefinition);
144
+ const argDefinitions = commandDefinition.args ?? command.args;
145
+ const commandOptions = buildDiscordCommandOptions({
146
+ command: commandDefinition,
147
+ cfg,
148
+ authorizeChoiceContext: async (interaction) =>
149
+ await resolveDiscordNativeAutocompleteAuthorized({
150
+ interaction,
151
+ cfg,
152
+ discordConfig,
153
+ accountId,
154
+ }),
155
+ resolveChoiceContext: async (interaction) =>
156
+ resolveDiscordNativeChoiceContext({
157
+ interaction,
158
+ cfg,
159
+ accountId,
160
+ threadBindings,
161
+ }),
162
+ });
163
+ const options = commandOptions
164
+ ? (commandOptions satisfies CommandOptions)
165
+ : command.acceptsArgs
166
+ ? ([
167
+ {
168
+ name: "input",
169
+ description: "Command input",
170
+ type: ApplicationCommandOptionType.String,
171
+ required: false,
172
+ },
173
+ ] satisfies CommandOptions)
174
+ : undefined;
175
+
176
+ return new (class extends Command {
177
+ override name = command.name;
178
+ override description = truncateDiscordCommandDescription({
179
+ value: command.description,
180
+ label: `command:${command.name}`,
181
+ });
182
+ override descriptionLocalizations = truncateDiscordCommandDescriptionLocalizations({
183
+ value: command.descriptionLocalizations,
184
+ label: `command:${command.name}`,
185
+ });
186
+ override defer = false;
187
+ override ephemeral = ephemeralDefault;
188
+ override options = options;
189
+
190
+ async run(interaction: CommandInteraction) {
191
+ const deferred = await safeDiscordInteractionCall("interaction defer", () =>
192
+ interaction.defer({ ephemeral: this.ephemeral }),
193
+ );
194
+ if (deferred === null) {
195
+ return;
196
+ }
197
+ const commandArgs = argDefinitions?.length
198
+ ? readDiscordCommandArgs(interaction, argDefinitions)
199
+ : command.acceptsArgs
200
+ ? parseCommandArgs(commandDefinition, interaction.options.getString("input") ?? "")
201
+ : undefined;
202
+ const commandArgsWithRaw = commandArgs
203
+ ? ({
204
+ ...commandArgs,
205
+ raw: serializeCommandArgs(commandDefinition, commandArgs) ?? commandArgs.raw,
206
+ } satisfies DiscordCommandArgs)
207
+ : undefined;
208
+ const prompt = buildCommandTextFromArgs(commandDefinition, commandArgsWithRaw);
209
+ await dispatchDiscordCommandInteraction({
210
+ interaction,
211
+ prompt,
212
+ command: commandDefinition,
213
+ commandArgs: commandArgsWithRaw,
214
+ cfg,
215
+ discordConfig,
216
+ accountId,
217
+ sessionPrefix,
218
+ // Slash commands are deferred up front, so all later responses must use
219
+ // follow-up/edit semantics instead of the initial reply endpoint.
220
+ preferFollowUp: true,
221
+ threadBindings,
222
+ responseEphemeral: ephemeralDefault,
223
+ });
224
+ }
225
+ })();
226
+ }
227
+
228
+ async function dispatchDiscordCommandInteraction(params: {
229
+ interaction: CommandInteraction | ButtonInteraction | StringSelectMenuInteraction;
230
+ prompt: string;
231
+ command: ChatCommandDefinition;
232
+ commandArgs?: DiscordCommandArgs;
233
+ cfg: AutoBotConfig;
234
+ discordConfig: DiscordConfig;
235
+ accountId: string;
236
+ sessionPrefix: string;
237
+ preferFollowUp: boolean;
238
+ threadBindings: ThreadBindingManager;
239
+ responseEphemeral?: boolean;
240
+ suppressReplies?: boolean;
241
+ }): Promise<DispatchDiscordCommandInteractionResult> {
242
+ const {
243
+ interaction,
244
+ prompt,
245
+ command,
246
+ commandArgs,
247
+ cfg,
248
+ discordConfig,
249
+ accountId,
250
+ sessionPrefix,
251
+ preferFollowUp,
252
+ threadBindings,
253
+ responseEphemeral,
254
+ suppressReplies,
255
+ } = params;
256
+ const commandName = command.nativeName ?? command.key;
257
+ const respond = async (content: string, options?: { ephemeral?: boolean }) => {
258
+ const ephemeral = options?.ephemeral ?? responseEphemeral;
259
+ const payload = {
260
+ content,
261
+ ...(ephemeral !== undefined ? { ephemeral } : {}),
262
+ };
263
+ await safeDiscordInteractionCall("interaction reply", async () => {
264
+ if (preferFollowUp) {
265
+ await interaction.followUp(payload);
266
+ return;
267
+ }
268
+ await interaction.reply(payload);
269
+ });
270
+ };
271
+
272
+ const useAccessGroups = cfg.commands?.useAccessGroups !== false;
273
+ const user = interaction.user;
274
+ if (!user) {
275
+ return { accepted: false };
276
+ }
277
+ const sender = resolveDiscordSenderIdentity({ author: user, pluralkitInfo: null });
278
+ const channel = interaction.channel;
279
+ const {
280
+ isDirectMessage,
281
+ isGroupDm,
282
+ isThreadChannel,
283
+ channelName,
284
+ channelSlug,
285
+ rawChannelId,
286
+ threadParentId,
287
+ threadParentName,
288
+ threadParentSlug,
289
+ } = await resolveDiscordNativeInteractionChannelContext({
290
+ channel,
291
+ client: interaction.client,
292
+ hasGuild: Boolean(interaction.guild),
293
+ channelIdFallback: "",
294
+ });
295
+ const memberRoleIds = Array.isArray(interaction.rawData.member?.roles)
296
+ ? interaction.rawData.member.roles.map((roleId: string) => roleId)
297
+ : [];
298
+ const allowNameMatching = isDangerousNameMatchingEnabled(discordConfig);
299
+ const configuredDmAllowFrom =
300
+ resolveDiscordAccountAllowFrom({
301
+ cfg,
302
+ accountId,
303
+ }) ?? [];
304
+ const commandOwnerAllowFrom = resolveDiscordCommandOwnerAllowFrom(cfg);
305
+ const { ownerAllowList: discordOwnerAllowList, ownerAllowed: discordOwnerOk } =
306
+ resolveDiscordOwnerAccess({
307
+ allowFrom: configuredDmAllowFrom,
308
+ sender: {
309
+ id: sender.id,
310
+ name: sender.name,
311
+ tag: sender.tag,
312
+ },
313
+ allowNameMatching,
314
+ });
315
+ const { ownerAllowed: commandOwnerOk } = resolveDiscordOwnerAccess({
316
+ allowFrom: commandOwnerAllowFrom,
317
+ sender: {
318
+ id: sender.id,
319
+ name: sender.name,
320
+ tag: sender.tag,
321
+ },
322
+ allowNameMatching,
323
+ });
324
+ const commandOwnerAllowAll = commandOwnerAllowFrom?.includes("*") === true;
325
+ const senderIsCommandOwner = commandOwnerOk || commandOwnerAllowAll;
326
+ const ownerAllowListConfigured = discordOwnerAllowList != null;
327
+ const ownerOk = discordOwnerOk;
328
+ const commandsAllowFromAccess = resolveDiscordNativeCommandAllowlistAccess({
329
+ cfg,
330
+ accountId,
331
+ sender: {
332
+ id: sender.id,
333
+ name: sender.name,
334
+ tag: sender.tag,
335
+ },
336
+ chatType: isDirectMessage
337
+ ? "direct"
338
+ : isThreadChannel
339
+ ? "thread"
340
+ : interaction.guild
341
+ ? "channel"
342
+ : "group",
343
+ conversationId: rawChannelId || undefined,
344
+ guildId: interaction.guild?.id,
345
+ });
346
+ const guildInfo = resolveDiscordGuildEntry({
347
+ guild: interaction.guild ?? undefined,
348
+ guildId: interaction.guild?.id ?? undefined,
349
+ guildEntries: discordConfig?.guilds,
350
+ });
351
+ const channelConfig = interaction.guild
352
+ ? resolveDiscordChannelConfigWithFallback({
353
+ guildInfo,
354
+ channelId: rawChannelId,
355
+ channelName,
356
+ channelSlug,
357
+ parentId: threadParentId,
358
+ parentName: threadParentName,
359
+ parentSlug: threadParentSlug,
360
+ scope: isThreadChannel ? "thread" : "channel",
361
+ })
362
+ : null;
363
+ let nativeRouteStatePromise:
364
+ | ReturnType<typeof nativeCommandRuntime.resolveDiscordNativeInteractionRouteState>
365
+ | undefined;
366
+ const getNativeRouteState = () =>
367
+ (nativeRouteStatePromise ??= nativeCommandRuntime.resolveDiscordNativeInteractionRouteState({
368
+ cfg,
369
+ accountId,
370
+ guildId: interaction.guild?.id ?? undefined,
371
+ memberRoleIds,
372
+ isDirectMessage,
373
+ isGroupDm,
374
+ directUserId: user.id,
375
+ conversationId: rawChannelId || "unknown",
376
+ parentConversationId: threadParentId,
377
+ threadBinding: isThreadChannel ? threadBindings.getByThreadId(rawChannelId) : undefined,
378
+ enforceConfiguredBindingReadiness: !shouldBypassConfiguredAcpEnsure(commandName),
379
+ }));
380
+ const canBypassConfiguredAcpGuildGuards = async () => {
381
+ if (!interaction.guild || !shouldBypassConfiguredAcpGuildGuards(commandName)) {
382
+ return false;
383
+ }
384
+ const routeState = await getNativeRouteState();
385
+ return (
386
+ routeState.effectiveRoute.matchedBy === "binding.channel" ||
387
+ routeState.boundSessionKey != null ||
388
+ routeState.configuredBinding != null ||
389
+ routeState.configuredRoute != null
390
+ );
391
+ };
392
+ if (channelConfig?.enabled === false && !(await canBypassConfiguredAcpGuildGuards())) {
393
+ await respond("This channel is disabled.");
394
+ return { accepted: false };
395
+ }
396
+ if (
397
+ interaction.guild &&
398
+ channelConfig?.allowed === false &&
399
+ !(await canBypassConfiguredAcpGuildGuards())
400
+ ) {
401
+ await respond("This channel is not allowed.");
402
+ return { accepted: false };
403
+ }
404
+ if (useAccessGroups && interaction.guild) {
405
+ const { groupPolicy } = resolveOpenProviderRuntimeGroupPolicy({
406
+ providerConfigPresent: cfg.channels?.discord !== undefined,
407
+ groupPolicy: discordConfig?.groupPolicy,
408
+ defaultGroupPolicy: cfg.channels?.defaults?.groupPolicy,
409
+ });
410
+ const policyAuthorizer = resolveDiscordChannelPolicyCommandAuthorizer({
411
+ groupPolicy,
412
+ guildInfo,
413
+ channelConfig,
414
+ });
415
+ if (!policyAuthorizer.allowed && !(await canBypassConfiguredAcpGuildGuards())) {
416
+ await respond("This channel is not allowed.");
417
+ return { accepted: false };
418
+ }
419
+ }
420
+ const dmEnabled = discordConfig?.dm?.enabled ?? true;
421
+ const dmPolicy = resolveDiscordAccountDmPolicy({ cfg, accountId }) ?? "pairing";
422
+ let commandAuthorized = true;
423
+ if (isDirectMessage) {
424
+ if (!dmEnabled || dmPolicy === "disabled") {
425
+ await respond("Discord DMs are disabled.");
426
+ return { accepted: false };
427
+ }
428
+ const dmAccess = await resolveDiscordDmCommandAccess({
429
+ accountId,
430
+ dmPolicy,
431
+ configuredAllowFrom: configuredDmAllowFrom,
432
+ sender: {
433
+ id: sender.id,
434
+ name: sender.name,
435
+ tag: sender.tag,
436
+ },
437
+ allowNameMatching,
438
+ cfg,
439
+ rest: interaction.client.rest,
440
+ });
441
+ commandAuthorized = dmAccess.senderAccess.allowed ? dmAccess.commandAccess.authorized : false;
442
+ if (dmAccess.senderAccess.decision !== "allow") {
443
+ await handleDiscordDmCommandDecision({
444
+ senderAccess: dmAccess.senderAccess,
445
+ accountId,
446
+ sender: {
447
+ id: user.id,
448
+ tag: sender.tag,
449
+ name: sender.name,
450
+ },
451
+ onPairingCreated: async (code) => {
452
+ await respond(
453
+ buildPairingReply({
454
+ channel: "discord",
455
+ idLine: `Your Discord user id: ${user.id}`,
456
+ code,
457
+ }),
458
+ { ephemeral: true },
459
+ );
460
+ },
461
+ onUnauthorized: async () => {
462
+ await respond("You are not authorized to use this command.", { ephemeral: true });
463
+ },
464
+ });
465
+ return { accepted: false };
466
+ }
467
+ }
468
+ const groupDmAccess = resolveDiscordNativeGroupDmAccess({
469
+ isGroupDm,
470
+ groupEnabled: discordConfig?.dm?.groupEnabled,
471
+ groupChannels: discordConfig?.dm?.groupChannels,
472
+ channelId: rawChannelId,
473
+ channelName,
474
+ channelSlug,
475
+ });
476
+ if (!groupDmAccess.allowed) {
477
+ await respond(
478
+ groupDmAccess.reason === "disabled"
479
+ ? "Discord group DMs are disabled."
480
+ : "This group DM is not allowed.",
481
+ );
482
+ return { accepted: false };
483
+ }
484
+ if (!isDirectMessage) {
485
+ commandAuthorized = await resolveDiscordGuildNativeCommandAuthorized({
486
+ cfg,
487
+ accountId,
488
+ discordConfig,
489
+ useAccessGroups,
490
+ commandsAllowFromAccess,
491
+ guildInfo,
492
+ channelConfig,
493
+ memberRoleIds,
494
+ sender,
495
+ allowNameMatching,
496
+ ownerAllowListConfigured,
497
+ ownerAllowed: ownerOk,
498
+ });
499
+ if (!commandAuthorized && !(await canBypassConfiguredAcpGuildGuards())) {
500
+ await respond("You are not authorized to use this command.", { ephemeral: true });
501
+ return { accepted: false };
502
+ }
503
+ }
504
+
505
+ const menuNeedsModelContext =
506
+ !(commandArgs?.raw && !commandArgs.values) &&
507
+ command.args?.some(
508
+ (arg) => typeof arg.choices === "function" && commandArgs?.values?.[arg.name] == null,
509
+ );
510
+ const menuModelContext = menuNeedsModelContext
511
+ ? await resolveDiscordNativeChoiceContext({
512
+ interaction: interaction as CommandInteraction,
513
+ cfg,
514
+ accountId,
515
+ threadBindings,
516
+ })
517
+ : null;
518
+ const menu = resolveCommandArgMenu({
519
+ command,
520
+ args: commandArgs,
521
+ cfg,
522
+ provider: menuModelContext?.provider,
523
+ model: menuModelContext?.model,
524
+ });
525
+ if (menu) {
526
+ const menuPayload = buildDiscordCommandArgMenu({
527
+ command,
528
+ menu,
529
+ interaction: interaction as CommandInteraction,
530
+ ctx: {
531
+ cfg,
532
+ discordConfig,
533
+ accountId,
534
+ sessionPrefix,
535
+ threadBindings,
536
+ },
537
+ safeInteractionCall: safeDiscordInteractionCall,
538
+ dispatchCommandInteraction: dispatchDiscordCommandInteraction,
539
+ });
540
+ if (preferFollowUp) {
541
+ await safeDiscordInteractionCall("interaction follow-up", () =>
542
+ interaction.followUp({
543
+ content: menuPayload.content,
544
+ components: menuPayload.components,
545
+ ephemeral: true,
546
+ }),
547
+ );
548
+ return { accepted: true };
549
+ }
550
+ await safeDiscordInteractionCall("interaction reply", () =>
551
+ interaction.reply({
552
+ content: menuPayload.content,
553
+ components: menuPayload.components,
554
+ ephemeral: true,
555
+ }),
556
+ );
557
+ return { accepted: true };
558
+ }
559
+
560
+ const pluginMatch = nativeCommandRuntime.matchPluginCommand(prompt);
561
+ if (pluginMatch && commandName !== "status") {
562
+ if (suppressReplies) {
563
+ return { accepted: true };
564
+ }
565
+ const channelId = rawChannelId || "unknown";
566
+ const messageThreadId = !isDirectMessage && isThreadChannel ? channelId : undefined;
567
+ const pluginThreadParentId = !isDirectMessage && isThreadChannel ? threadParentId : undefined;
568
+ const { effectiveRoute } = await getNativeRouteState();
569
+ const pluginReply = await nativeCommandRuntime.executePluginCommand({
570
+ command: pluginMatch.command,
571
+ args: pluginMatch.args,
572
+ senderId: sender.id,
573
+ channel: "discord",
574
+ channelId,
575
+ isAuthorizedSender: commandAuthorized,
576
+ senderIsOwner: senderIsCommandOwner,
577
+ sessionKey: effectiveRoute.sessionKey,
578
+ commandBody: prompt,
579
+ config: cfg,
580
+ from: isDirectMessage
581
+ ? `discord:${user.id}`
582
+ : isGroupDm
583
+ ? `discord:group:${channelId}`
584
+ : `discord:channel:${channelId}`,
585
+ to: `slash:${user.id}`,
586
+ accountId,
587
+ messageThreadId,
588
+ threadParentId: pluginThreadParentId,
589
+ });
590
+ if (!hasRenderableReplyPayload(pluginReply)) {
591
+ await respond(DISCORD_EMPTY_VISIBLE_REPLY_WARNING);
592
+ return { accepted: true, effectiveRoute };
593
+ }
594
+ await deliverDiscordInteractionReply({
595
+ interaction,
596
+ payload: pluginReply,
597
+ textLimit: resolveTextChunkLimit(cfg, "discord", accountId, {
598
+ fallbackLimit: 2000,
599
+ }),
600
+ maxLinesPerMessage: resolveDiscordMaxLinesPerMessage({ cfg, discordConfig, accountId }),
601
+ preferFollowUp,
602
+ responseEphemeral,
603
+ chunkMode: resolveChunkMode(cfg, "discord", accountId),
604
+ });
605
+ return { accepted: true, effectiveRoute };
606
+ }
607
+
608
+ const pickerCommandContext = shouldOpenDiscordModelPickerFromCommand({
609
+ command,
610
+ commandArgs,
611
+ });
612
+ if (pickerCommandContext) {
613
+ await replyWithDiscordModelPickerProviders({
614
+ interaction,
615
+ cfg,
616
+ command: pickerCommandContext,
617
+ userId: user.id,
618
+ accountId,
619
+ threadBindings,
620
+ preferFollowUp,
621
+ safeInteractionCall: safeDiscordInteractionCall,
622
+ });
623
+ return { accepted: true };
624
+ }
625
+
626
+ const isGuild = Boolean(interaction.guild);
627
+ const channelId = rawChannelId || "unknown";
628
+ const interactionId = interaction.rawData.id;
629
+ const routeState = await getNativeRouteState();
630
+ if (routeState.bindingReadiness && !routeState.bindingReadiness.ok) {
631
+ const configuredBinding = routeState.configuredBinding;
632
+ if (configuredBinding) {
633
+ logVerbose(
634
+ `discord native command: configured ACP binding unavailable for channel ${configuredBinding.record.conversation.conversationId}: ${routeState.bindingReadiness.error}`,
635
+ );
636
+ await respond("Configured ACP binding is unavailable right now. Please try again.");
637
+ return { accepted: false };
638
+ }
639
+ }
640
+ const boundSessionKey = routeState.boundSessionKey;
641
+ const effectiveRoute = routeState.effectiveRoute;
642
+ const { sessionKey, commandTargetSessionKey } = resolveNativeCommandSessionTargets({
643
+ agentId: effectiveRoute.agentId,
644
+ sessionPrefix,
645
+ userId: user.id,
646
+ targetSessionKey: effectiveRoute.sessionKey,
647
+ boundSessionKey,
648
+ });
649
+ const mediaLocalRoots = getAgentScopedMediaLocalRoots(cfg, effectiveRoute.agentId);
650
+ const directStatusResult = await maybeDeliverDiscordDirectStatus({
651
+ commandName,
652
+ suppressReplies,
653
+ resolveDirectStatusReplyForSession: nativeCommandRuntime.resolveDirectStatusReplyForSession,
654
+ cfg,
655
+ discordConfig,
656
+ accountId,
657
+ sessionKey,
658
+ commandTargetSessionKey,
659
+ channel: "discord",
660
+ senderId: sender.id,
661
+ senderIsOwner: senderIsCommandOwner,
662
+ isAuthorizedSender: commandAuthorized,
663
+ isGroup: isGuild || isGroupDm,
664
+ defaultGroupActivation: () =>
665
+ !isGuild ? "always" : channelConfig?.requireMention === false ? "always" : "mention",
666
+ interaction,
667
+ mediaLocalRoots,
668
+ preferFollowUp,
669
+ responseEphemeral,
670
+ effectiveRoute,
671
+ respond,
672
+ });
673
+ if (directStatusResult) {
674
+ return directStatusResult;
675
+ }
676
+ const ctxPayload = buildDiscordNativeCommandContext({
677
+ prompt,
678
+ commandArgs: commandArgs ?? {},
679
+ sessionKey,
680
+ commandTargetSessionKey,
681
+ accountId: effectiveRoute.accountId,
682
+ interactionId,
683
+ channelId,
684
+ threadParentId,
685
+ memberRoleIds,
686
+ guildId: interaction.guild?.id,
687
+ guildName: interaction.guild?.name,
688
+ channelTopic: resolveDiscordChannelTopicSafe(channel),
689
+ channelConfig,
690
+ guildInfo,
691
+ allowNameMatching,
692
+ commandAuthorized,
693
+ isDirectMessage,
694
+ isGroupDm,
695
+ isGuild,
696
+ isThreadChannel,
697
+ user: {
698
+ id: user.id,
699
+ username: user.username,
700
+ globalName: user.globalName,
701
+ },
702
+ sender: { id: sender.id, name: sender.name, tag: sender.tag },
703
+ });
704
+
705
+ await dispatchDiscordNativeAgentReply({
706
+ cfg,
707
+ discordConfig,
708
+ accountId,
709
+ interaction,
710
+ ctxPayload,
711
+ effectiveRoute,
712
+ channelConfig,
713
+ mediaLocalRoots,
714
+ preferFollowUp,
715
+ responseEphemeral,
716
+ suppressReplies,
717
+ log,
718
+ });
719
+
720
+ return { accepted: true, effectiveRoute };
721
+ }
722
+
723
+ export function createDiscordCommandArgFallbackButton(params: DiscordCommandArgContext): Button {
724
+ return createDiscordCommandArgFallbackButtonUi({
725
+ ctx: params,
726
+ safeInteractionCall: safeDiscordInteractionCall,
727
+ dispatchCommandInteraction: dispatchDiscordCommandInteraction,
728
+ });
729
+ }
730
+
731
+ export function createDiscordModelPickerFallbackButton(params: DiscordModelPickerContext): Button {
732
+ return createDiscordModelPickerFallbackButtonUi({
733
+ ctx: params,
734
+ safeInteractionCall: safeDiscordInteractionCall,
735
+ dispatchCommandInteraction: dispatchDiscordCommandInteraction,
736
+ });
737
+ }
738
+
739
+ export function createDiscordModelPickerFallbackSelect(
740
+ params: DiscordModelPickerContext,
741
+ ): StringSelectMenu {
742
+ return createDiscordModelPickerFallbackSelectUi({
743
+ ctx: params,
744
+ safeInteractionCall: safeDiscordInteractionCall,
745
+ dispatchCommandInteraction: dispatchDiscordCommandInteraction,
746
+ });
747
+ }