@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,9 @@
1
+ import type { AutoBotConfig } from "autobot/plugin-sdk/config-contracts";
2
+ import type { CommandArgValues } from "autobot/plugin-sdk/native-command-registry";
3
+
4
+ export type DiscordConfig = NonNullable<AutoBotConfig["channels"]>["discord"];
5
+
6
+ export type DiscordCommandArgs = {
7
+ raw?: string;
8
+ values?: CommandArgValues;
9
+ };
@@ -0,0 +1,50 @@
1
+ import { ChannelType } from "../internal/discord.js";
2
+ import type { DiscordChannelInfoClient } from "./message-utils.js";
3
+ import { resolveDiscordThreadLikeChannelContext } from "./thread-channel-context.js";
4
+
5
+ type DiscordInteractionChannel = {
6
+ id?: string;
7
+ type?: ChannelType;
8
+ };
9
+
10
+ type DiscordNativeInteractionChannelContext = {
11
+ channelType?: ChannelType;
12
+ isDirectMessage: boolean;
13
+ isGroupDm: boolean;
14
+ isThreadChannel: boolean;
15
+ channelName?: string;
16
+ channelSlug: string;
17
+ rawChannelId: string;
18
+ threadParentId?: string;
19
+ threadParentName?: string;
20
+ threadParentSlug: string;
21
+ };
22
+
23
+ export async function resolveDiscordNativeInteractionChannelContext(params: {
24
+ channel: DiscordInteractionChannel | null | undefined;
25
+ client: DiscordChannelInfoClient;
26
+ hasGuild: boolean;
27
+ channelIdFallback: string;
28
+ }): Promise<DiscordNativeInteractionChannelContext> {
29
+ const channelContext = await resolveDiscordThreadLikeChannelContext({
30
+ client: params.client,
31
+ channel: params.channel,
32
+ channelIdFallback: params.channelIdFallback,
33
+ });
34
+ const channelType = channelContext.channelType;
35
+ const isDirectMessage = channelType === ChannelType.DM;
36
+ const isGroupDm = channelType === ChannelType.GroupDM;
37
+
38
+ return {
39
+ channelType,
40
+ isDirectMessage,
41
+ isGroupDm,
42
+ isThreadChannel: channelContext.isThreadChannel,
43
+ channelName: channelContext.channelName,
44
+ channelSlug: channelContext.channelSlug,
45
+ rawChannelId: channelContext.channelId,
46
+ threadParentId: params.hasGuild ? channelContext.threadParentId : undefined,
47
+ threadParentName: params.hasGuild ? channelContext.threadParentName : undefined,
48
+ threadParentSlug: params.hasGuild ? channelContext.threadParentSlug : "",
49
+ };
50
+ }
@@ -0,0 +1,9 @@
1
+ import { transcribeFirstAudio as transcribeFirstAudioImpl } from "autobot/plugin-sdk/media-runtime";
2
+
3
+ type TranscribeFirstAudio = typeof import("autobot/plugin-sdk/media-runtime").transcribeFirstAudio;
4
+
5
+ export async function transcribeFirstAudio(
6
+ ...args: Parameters<TranscribeFirstAudio>
7
+ ): ReturnType<TranscribeFirstAudio> {
8
+ return await transcribeFirstAudioImpl(...args);
9
+ }
@@ -0,0 +1,130 @@
1
+ import type { AutoBotConfig } from "autobot/plugin-sdk/config-contracts";
2
+ import { getFileExtension } from "autobot/plugin-sdk/media-mime";
3
+ import { logVerbose } from "autobot/plugin-sdk/runtime-env";
4
+ import { normalizeOptionalString } from "autobot/plugin-sdk/string-coerce-runtime";
5
+
6
+ type DiscordPreflightAudioRuntime = typeof import("./preflight-audio.runtime.js");
7
+
8
+ let discordPreflightAudioRuntimePromise: Promise<DiscordPreflightAudioRuntime> | undefined;
9
+
10
+ function loadDiscordPreflightAudioRuntime(): Promise<DiscordPreflightAudioRuntime> {
11
+ discordPreflightAudioRuntimePromise ??= import("./preflight-audio.runtime.js");
12
+ return discordPreflightAudioRuntimePromise;
13
+ }
14
+
15
+ type DiscordAudioAttachment = {
16
+ content_type?: string;
17
+ duration_secs?: number;
18
+ filename?: string;
19
+ url?: string;
20
+ waveform?: string;
21
+ };
22
+
23
+ const AUDIO_ATTACHMENT_MIME_BY_EXT = new Map([
24
+ [".aac", "audio/aac"],
25
+ [".caf", "audio/x-caf"],
26
+ [".flac", "audio/flac"],
27
+ [".m4a", "audio/mp4"],
28
+ [".mp3", "audio/mpeg"],
29
+ [".oga", "audio/ogg"],
30
+ [".ogg", "audio/ogg"],
31
+ [".opus", "audio/opus"],
32
+ [".wav", "audio/wav"],
33
+ ]);
34
+
35
+ function inferAudioAttachmentMime(attachment: DiscordAudioAttachment): string | undefined {
36
+ const contentType = normalizeOptionalString(attachment.content_type);
37
+ if (contentType?.startsWith("audio/")) {
38
+ return contentType;
39
+ }
40
+ if (
41
+ typeof attachment.duration_secs === "number" ||
42
+ typeof normalizeOptionalString(attachment.waveform) === "string"
43
+ ) {
44
+ return "audio/ogg";
45
+ }
46
+ const ext = getFileExtension(attachment.filename ?? attachment.url);
47
+ return ext ? AUDIO_ATTACHMENT_MIME_BY_EXT.get(ext) : undefined;
48
+ }
49
+
50
+ function collectAudioAttachments(
51
+ attachments: DiscordAudioAttachment[] | undefined,
52
+ ): DiscordAudioAttachment[] {
53
+ if (!Array.isArray(attachments)) {
54
+ return [];
55
+ }
56
+ return attachments.filter(
57
+ (att) => normalizeOptionalString(att.url) && inferAudioAttachmentMime(att),
58
+ );
59
+ }
60
+
61
+ export async function resolveDiscordPreflightAudioMentionContext(params: {
62
+ message: {
63
+ attachments?: DiscordAudioAttachment[];
64
+ content?: string;
65
+ };
66
+ isDirectMessage: boolean;
67
+ shouldRequireMention: boolean;
68
+ mentionRegexes: RegExp[];
69
+ cfg: AutoBotConfig;
70
+ abortSignal?: AbortSignal;
71
+ }): Promise<{
72
+ hasAudioAttachment: boolean;
73
+ hasTypedText: boolean;
74
+ transcript?: string;
75
+ }> {
76
+ const audioAttachments = collectAudioAttachments(params.message.attachments);
77
+ const hasAudioAttachment = audioAttachments.length > 0;
78
+ const hasTypedText = Boolean(params.message.content?.trim());
79
+ const needsPreflightTranscription =
80
+ hasAudioAttachment &&
81
+ // `baseText` includes media placeholders; gate on typed text only.
82
+ !hasTypedText &&
83
+ (params.isDirectMessage || (params.shouldRequireMention && params.mentionRegexes.length > 0));
84
+
85
+ let transcript: string | undefined;
86
+ if (needsPreflightTranscription) {
87
+ if (params.abortSignal?.aborted) {
88
+ return {
89
+ hasAudioAttachment,
90
+ hasTypedText,
91
+ };
92
+ }
93
+ try {
94
+ const { transcribeFirstAudio } = await loadDiscordPreflightAudioRuntime();
95
+ if (params.abortSignal?.aborted) {
96
+ return {
97
+ hasAudioAttachment,
98
+ hasTypedText,
99
+ };
100
+ }
101
+ const audioUrls = audioAttachments
102
+ .map((att) => att.url)
103
+ .map((url) => normalizeOptionalString(url))
104
+ .filter((url): url is string => Boolean(url));
105
+ if (audioUrls.length > 0) {
106
+ transcript = await transcribeFirstAudio({
107
+ ctx: {
108
+ MediaUrls: audioUrls,
109
+ MediaTypes: audioAttachments
110
+ .map((att) => inferAudioAttachmentMime(att))
111
+ .filter((contentType): contentType is string => Boolean(contentType)),
112
+ },
113
+ cfg: params.cfg,
114
+ agentDir: undefined,
115
+ });
116
+ if (params.abortSignal?.aborted) {
117
+ transcript = undefined;
118
+ }
119
+ }
120
+ } catch (err) {
121
+ logVerbose(`discord: audio preflight transcription failed: ${String(err)}`);
122
+ }
123
+ }
124
+
125
+ return {
126
+ hasAudioAttachment,
127
+ hasTypedText,
128
+ transcript,
129
+ };
130
+ }
@@ -0,0 +1,61 @@
1
+ import type { GatewayPresenceUpdate } from "discord-api-types/v10";
2
+
3
+ /**
4
+ * In-memory cache of Discord user presence data.
5
+ * Populated by PRESENCE_UPDATE gateway events when the GuildPresences intent is enabled.
6
+ * Per-account maps are capped to prevent unbounded growth (#4948).
7
+ */
8
+ const MAX_PRESENCE_PER_ACCOUNT = 5000;
9
+ const presenceCache = new Map<string, Map<string, GatewayPresenceUpdate>>();
10
+
11
+ function resolveAccountKey(accountId?: string): string {
12
+ return accountId ?? "default";
13
+ }
14
+
15
+ /** Update cached presence for a user. */
16
+ export function setPresence(
17
+ accountId: string | undefined,
18
+ userId: string,
19
+ data: GatewayPresenceUpdate,
20
+ ): void {
21
+ const accountKey = resolveAccountKey(accountId);
22
+ let accountCache = presenceCache.get(accountKey);
23
+ if (!accountCache) {
24
+ accountCache = new Map();
25
+ presenceCache.set(accountKey, accountCache);
26
+ }
27
+ accountCache.set(userId, data);
28
+ // Evict oldest entries if cache exceeds limit
29
+ if (accountCache.size > MAX_PRESENCE_PER_ACCOUNT) {
30
+ const oldest = accountCache.keys().next().value;
31
+ if (oldest !== undefined) {
32
+ accountCache.delete(oldest);
33
+ }
34
+ }
35
+ }
36
+
37
+ /** Get cached presence for a user. Returns undefined if not cached. */
38
+ export function getPresence(
39
+ accountId: string | undefined,
40
+ userId: string,
41
+ ): GatewayPresenceUpdate | undefined {
42
+ return presenceCache.get(resolveAccountKey(accountId))?.get(userId);
43
+ }
44
+
45
+ /** Clear cached presence data. */
46
+ export function clearPresences(accountId?: string): void {
47
+ if (accountId) {
48
+ presenceCache.delete(resolveAccountKey(accountId));
49
+ return;
50
+ }
51
+ presenceCache.clear();
52
+ }
53
+
54
+ /** Get the number of cached presence entries. */
55
+ export function presenceCacheSize(): number {
56
+ let total = 0;
57
+ for (const accountCache of presenceCache.values()) {
58
+ total += accountCache.size;
59
+ }
60
+ return total;
61
+ }
@@ -0,0 +1,50 @@
1
+ import type { DiscordAccountConfig } from "autobot/plugin-sdk/config-contracts";
2
+ import { normalizeOptionalString } from "autobot/plugin-sdk/string-coerce-runtime";
3
+ import type { Activity, UpdatePresenceData } from "../internal/gateway.js";
4
+
5
+ const DEFAULT_CUSTOM_ACTIVITY_TYPE = 4;
6
+ const CUSTOM_STATUS_NAME = "Custom Status";
7
+
8
+ type DiscordPresenceConfig = Pick<
9
+ DiscordAccountConfig,
10
+ "activity" | "status" | "activityType" | "activityUrl"
11
+ >;
12
+
13
+ export function resolveDiscordPresenceUpdate(
14
+ config: DiscordPresenceConfig,
15
+ ): UpdatePresenceData | null {
16
+ const activityText = normalizeOptionalString(config.activity) ?? "";
17
+ const status = normalizeOptionalString(config.status) ?? "";
18
+ const activityType = config.activityType;
19
+ const activityUrl = normalizeOptionalString(config.activityUrl) ?? "";
20
+
21
+ const hasActivity = Boolean(activityText);
22
+ const hasStatus = Boolean(status);
23
+
24
+ if (!hasActivity && !hasStatus) {
25
+ return { since: null, activities: [], status: "online", afk: false };
26
+ }
27
+
28
+ const activities: Activity[] = [];
29
+
30
+ if (hasActivity) {
31
+ const resolvedType = activityType ?? DEFAULT_CUSTOM_ACTIVITY_TYPE;
32
+ const activity: Activity =
33
+ resolvedType === DEFAULT_CUSTOM_ACTIVITY_TYPE
34
+ ? { name: CUSTOM_STATUS_NAME, type: resolvedType, state: activityText }
35
+ : { name: activityText, type: resolvedType };
36
+
37
+ if (resolvedType === 1 && activityUrl) {
38
+ activity.url = activityUrl;
39
+ }
40
+
41
+ activities.push(activity);
42
+ }
43
+
44
+ return {
45
+ since: null,
46
+ activities,
47
+ status: (status || "online") as UpdatePresenceData["status"],
48
+ afk: false,
49
+ };
50
+ }
@@ -0,0 +1,12 @@
1
+ export { getAcpSessionManager, isAcpRuntimeError } from "autobot/plugin-sdk/acp-runtime";
2
+ export {
3
+ resolveThreadBindingIdleTimeoutMs,
4
+ resolveThreadBindingMaxAgeMs,
5
+ resolveThreadBindingsEnabled,
6
+ } from "autobot/plugin-sdk/conversation-runtime";
7
+ export { createDiscordMessageHandler } from "./message-handler.js";
8
+ export {
9
+ createNoopThreadBindingManager,
10
+ createThreadBindingManager,
11
+ reconcileAcpThreadBindingsOnStartup,
12
+ } from "./thread-bindings.js";
@@ -0,0 +1,89 @@
1
+ import type { AutoBotConfig } from "autobot/plugin-sdk/config-contracts";
2
+ import { formatErrorMessage } from "autobot/plugin-sdk/ssrf-runtime";
3
+ import { raceWithTimeout } from "./timeouts.js";
4
+
5
+ type DiscordProviderSessionRuntimeModule = typeof import("./provider-session.runtime.js");
6
+
7
+ const DISCORD_ACP_STATUS_PROBE_TIMEOUT_MS = 8_000;
8
+ const DISCORD_ACP_STALE_RUNNING_ACTIVITY_MS = 2 * 60 * 1000;
9
+
10
+ function isLegacyMissingSessionError(message: string): boolean {
11
+ return (
12
+ message.includes("Session is not ACP-enabled") ||
13
+ message.includes("ACP session metadata missing")
14
+ );
15
+ }
16
+
17
+ function classifyAcpStatusProbeError(params: {
18
+ error: unknown;
19
+ isStaleRunning: boolean;
20
+ isAcpRuntimeError: DiscordProviderSessionRuntimeModule["isAcpRuntimeError"];
21
+ }): {
22
+ status: "stale" | "uncertain";
23
+ reason: string;
24
+ } {
25
+ if (params.isAcpRuntimeError(params.error) && params.error.code === "ACP_SESSION_INIT_FAILED") {
26
+ return { status: "stale", reason: "session-init-failed" };
27
+ }
28
+
29
+ const message = formatErrorMessage(params.error);
30
+ if (isLegacyMissingSessionError(message)) {
31
+ return { status: "stale", reason: "session-missing" };
32
+ }
33
+
34
+ return params.isStaleRunning
35
+ ? { status: "stale", reason: "status-error-running-stale" }
36
+ : { status: "uncertain", reason: "status-error" };
37
+ }
38
+
39
+ export async function probeDiscordAcpBindingHealth(params: {
40
+ cfg: AutoBotConfig;
41
+ sessionKey: string;
42
+ storedState?: "idle" | "running" | "error";
43
+ lastActivityAt?: number;
44
+ providerSessionRuntime: DiscordProviderSessionRuntimeModule;
45
+ }): Promise<{ status: "healthy" | "stale" | "uncertain"; reason?: string }> {
46
+ const { getAcpSessionManager, isAcpRuntimeError } = params.providerSessionRuntime;
47
+ const manager = getAcpSessionManager();
48
+ const statusProbeAbortController = new AbortController();
49
+ const statusPromise = manager
50
+ .getSessionStatus({
51
+ cfg: params.cfg,
52
+ sessionKey: params.sessionKey,
53
+ signal: statusProbeAbortController.signal,
54
+ })
55
+ .then((status) => ({ kind: "status" as const, status }))
56
+ .catch((error: unknown) => ({ kind: "error" as const, error }));
57
+
58
+ const result = await raceWithTimeout({
59
+ promise: statusPromise,
60
+ timeoutMs: DISCORD_ACP_STATUS_PROBE_TIMEOUT_MS,
61
+ onTimeout: () => ({ kind: "timeout" as const }),
62
+ });
63
+ if (result.kind === "timeout") {
64
+ statusProbeAbortController.abort();
65
+ }
66
+ const runningForMs =
67
+ params.storedState === "running" && Number.isFinite(params.lastActivityAt)
68
+ ? Date.now() - Math.max(0, Math.floor(params.lastActivityAt ?? 0))
69
+ : 0;
70
+ const isStaleRunning =
71
+ params.storedState === "running" && runningForMs >= DISCORD_ACP_STALE_RUNNING_ACTIVITY_MS;
72
+
73
+ if (result.kind === "timeout") {
74
+ return isStaleRunning
75
+ ? { status: "stale", reason: "status-timeout-running-stale" }
76
+ : { status: "uncertain", reason: "status-timeout" };
77
+ }
78
+ if (result.kind === "error") {
79
+ return classifyAcpStatusProbeError({
80
+ error: result.error,
81
+ isStaleRunning,
82
+ isAcpRuntimeError,
83
+ });
84
+ }
85
+ if (result.status.state === "error") {
86
+ return { status: "uncertain", reason: "status-error-state" };
87
+ }
88
+ return { status: "healthy" };
89
+ }