@openclaw/discord 2026.3.13 → 2026.5.2-beta.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.
Files changed (502) hide show
  1. package/account-inspect-api.ts +6 -0
  2. package/action-runtime-api.ts +1 -0
  3. package/api.ts +132 -0
  4. package/channel-config-api.ts +1 -0
  5. package/channel-plugin-api.ts +3 -0
  6. package/config-api.ts +4 -0
  7. package/configured-state.ts +6 -0
  8. package/contract-api.ts +21 -0
  9. package/directory-contract-api.ts +4 -0
  10. package/doctor-contract-api.ts +1 -0
  11. package/index.test.ts +13 -0
  12. package/index.ts +18 -13
  13. package/openclaw.plugin.json +3326 -1
  14. package/package.json +68 -2
  15. package/runtime-api.actions.ts +15 -0
  16. package/runtime-api.lookup.ts +22 -0
  17. package/runtime-api.monitor.ts +50 -0
  18. package/runtime-api.send.ts +79 -0
  19. package/runtime-api.threads.ts +30 -0
  20. package/runtime-api.ts +180 -0
  21. package/runtime-setter-api.ts +3 -0
  22. package/secret-contract-api.ts +4 -0
  23. package/security-audit-contract-api.ts +1 -0
  24. package/security-contract-api.ts +4 -0
  25. package/session-key-api.ts +1 -0
  26. package/setup-entry.ts +9 -0
  27. package/setup-plugin-api.ts +3 -0
  28. package/src/account-inspect.test.ts +126 -0
  29. package/src/account-inspect.ts +132 -0
  30. package/src/accounts.test.ts +247 -0
  31. package/src/accounts.ts +196 -0
  32. package/src/actions/handle-action.guild-admin.ts +411 -0
  33. package/src/actions/handle-action.test.ts +306 -0
  34. package/src/actions/handle-action.ts +372 -0
  35. package/src/actions/runtime.guild.ts +446 -0
  36. package/src/actions/runtime.messaging.messages.ts +205 -0
  37. package/src/actions/runtime.messaging.reactions.ts +67 -0
  38. package/src/actions/runtime.messaging.runtime.ts +69 -0
  39. package/src/actions/runtime.messaging.send.ts +248 -0
  40. package/src/actions/runtime.messaging.shared.ts +97 -0
  41. package/src/actions/runtime.messaging.ts +37 -0
  42. package/src/actions/runtime.moderation-shared.ts +48 -0
  43. package/src/actions/runtime.moderation.authz.test.ts +151 -0
  44. package/src/actions/runtime.moderation.ts +116 -0
  45. package/src/actions/runtime.presence.test.ts +160 -0
  46. package/src/actions/runtime.presence.ts +117 -0
  47. package/src/actions/runtime.shared.ts +83 -0
  48. package/src/actions/runtime.test.ts +1087 -0
  49. package/src/actions/runtime.ts +87 -0
  50. package/src/api-barrel.test.ts +80 -0
  51. package/src/api.test.ts +130 -0
  52. package/src/api.ts +169 -0
  53. package/src/approval-handler.runtime.test.ts +41 -0
  54. package/src/approval-handler.runtime.ts +632 -0
  55. package/src/approval-native.test.ts +330 -0
  56. package/src/approval-native.ts +219 -0
  57. package/src/approval-runtime.ts +14 -0
  58. package/src/approval-shared.ts +53 -0
  59. package/src/audit-core.ts +141 -0
  60. package/src/audit.test.ts +145 -0
  61. package/src/audit.ts +32 -0
  62. package/src/channel-actions.contract.test.ts +45 -0
  63. package/src/channel-actions.runtime.ts +1 -0
  64. package/src/channel-actions.test.ts +275 -0
  65. package/src/channel-actions.ts +203 -0
  66. package/src/channel-api.ts +29 -0
  67. package/src/channel.conversation.ts +159 -0
  68. package/src/channel.loaders.ts +47 -0
  69. package/src/channel.runtime.ts +1 -0
  70. package/src/channel.setup.ts +12 -0
  71. package/src/channel.test.ts +547 -12
  72. package/src/channel.ts +597 -430
  73. package/src/chunk.test.ts +157 -0
  74. package/src/chunk.ts +321 -0
  75. package/src/client.proxy.test.ts +176 -0
  76. package/src/client.test.ts +76 -0
  77. package/src/client.ts +132 -0
  78. package/src/component-custom-id.ts +72 -0
  79. package/src/components-registry.ts +356 -0
  80. package/src/components.builders.ts +409 -0
  81. package/src/components.modal.ts +124 -0
  82. package/src/components.parse.ts +407 -0
  83. package/src/components.test.ts +312 -0
  84. package/src/components.ts +54 -0
  85. package/src/components.types.ts +187 -0
  86. package/src/config-schema.test.ts +325 -0
  87. package/src/config-schema.ts +6 -0
  88. package/src/config-ui-hints.ts +249 -0
  89. package/src/conversation-identity.ts +58 -0
  90. package/src/delivery-retry.ts +56 -0
  91. package/src/directory-cache.ts +116 -0
  92. package/src/directory-config.ts +58 -0
  93. package/src/directory-contract.test.ts +129 -0
  94. package/src/directory-live.test.ts +126 -0
  95. package/src/directory-live.ts +135 -0
  96. package/src/doctor-contract.ts +477 -0
  97. package/src/doctor-shared.ts +5 -0
  98. package/src/doctor.test.ts +405 -0
  99. package/src/doctor.ts +340 -0
  100. package/src/draft-chunking.test.ts +64 -0
  101. package/src/draft-chunking.ts +43 -0
  102. package/src/draft-stream.test.ts +159 -0
  103. package/src/draft-stream.ts +154 -0
  104. package/src/error-body.ts +38 -0
  105. package/src/exec-approvals.test.ts +88 -0
  106. package/src/exec-approvals.ts +110 -0
  107. package/src/gateway-logging.test.ts +98 -0
  108. package/src/gateway-logging.ts +67 -0
  109. package/src/group-policy.ts +113 -0
  110. package/src/guilds.ts +29 -0
  111. package/src/inbound-context.contract.test.ts +11 -0
  112. package/src/interactive-dispatch.ts +104 -0
  113. package/src/internal/api.commands.ts +51 -0
  114. package/src/internal/api.guild.ts +164 -0
  115. package/src/internal/api.interactions.ts +53 -0
  116. package/src/internal/api.messages.ts +113 -0
  117. package/src/internal/api.reactions.ts +38 -0
  118. package/src/internal/api.test.ts +262 -0
  119. package/src/internal/api.ts +61 -0
  120. package/src/internal/api.users.ts +19 -0
  121. package/src/internal/api.webhooks.ts +13 -0
  122. package/src/internal/client.test.ts +408 -0
  123. package/src/internal/client.ts +308 -0
  124. package/src/internal/command-deploy.ts +237 -0
  125. package/src/internal/commands.ts +188 -0
  126. package/src/internal/components.base.ts +65 -0
  127. package/src/internal/components.message.ts +279 -0
  128. package/src/internal/components.modal.ts +95 -0
  129. package/src/internal/components.ts +31 -0
  130. package/src/internal/discord.ts +11 -0
  131. package/src/internal/embeds.ts +35 -0
  132. package/src/internal/entity-cache.ts +98 -0
  133. package/src/internal/event-queue.ts +162 -0
  134. package/src/internal/gateway-close-codes.ts +25 -0
  135. package/src/internal/gateway-dispatch.ts +96 -0
  136. package/src/internal/gateway-identify-limiter.ts +26 -0
  137. package/src/internal/gateway-lifecycle.ts +61 -0
  138. package/src/internal/gateway-rate-limit.ts +104 -0
  139. package/src/internal/gateway.test.ts +603 -0
  140. package/src/internal/gateway.ts +476 -0
  141. package/src/internal/interaction-dispatch.test.ts +148 -0
  142. package/src/internal/interaction-dispatch.ts +162 -0
  143. package/src/internal/interaction-options.ts +98 -0
  144. package/src/internal/interaction-response.ts +53 -0
  145. package/src/internal/interactions.test.ts +325 -0
  146. package/src/internal/interactions.ts +378 -0
  147. package/src/internal/listeners.ts +85 -0
  148. package/src/internal/live-smoke.live.test.ts +26 -0
  149. package/src/internal/modal-fields.ts +95 -0
  150. package/src/internal/payload.ts +69 -0
  151. package/src/internal/rest-body.ts +115 -0
  152. package/src/internal/rest-errors.ts +88 -0
  153. package/src/internal/rest-routes.ts +50 -0
  154. package/src/internal/rest-scheduler.ts +557 -0
  155. package/src/internal/rest.test.ts +673 -0
  156. package/src/internal/rest.ts +322 -0
  157. package/src/internal/schemas.ts +36 -0
  158. package/src/internal/structures.test.ts +43 -0
  159. package/src/internal/structures.ts +280 -0
  160. package/src/internal/test-builders.test-support.ts +163 -0
  161. package/src/internal/voice.ts +49 -0
  162. package/src/media-detection.ts +28 -0
  163. package/src/mentions.test.ts +111 -0
  164. package/src/mentions.ts +147 -0
  165. package/src/monitor/access-groups.ts +55 -0
  166. package/src/monitor/ack-reactions.ts +70 -0
  167. package/src/monitor/acp-bind-here.integration.test.ts +211 -0
  168. package/src/monitor/agent-components-auth.ts +7 -0
  169. package/src/monitor/agent-components-context.ts +154 -0
  170. package/src/monitor/agent-components-data.ts +224 -0
  171. package/src/monitor/agent-components-dm-auth.ts +221 -0
  172. package/src/monitor/agent-components-guild-auth.ts +322 -0
  173. package/src/monitor/agent-components-helpers.runtime.ts +5 -0
  174. package/src/monitor/agent-components-helpers.ts +34 -0
  175. package/src/monitor/agent-components-reply.ts +10 -0
  176. package/src/monitor/agent-components.deps.runtime.ts +2 -0
  177. package/src/monitor/agent-components.dispatch.ts +366 -0
  178. package/src/monitor/agent-components.handlers.ts +303 -0
  179. package/src/monitor/agent-components.modal.ts +160 -0
  180. package/src/monitor/agent-components.plugin-interactive.ts +187 -0
  181. package/src/monitor/agent-components.runtime.ts +14 -0
  182. package/src/monitor/agent-components.system-controls.ts +211 -0
  183. package/src/monitor/agent-components.ts +70 -0
  184. package/src/monitor/agent-components.types.ts +58 -0
  185. package/src/monitor/agent-components.wildcard-controls.ts +168 -0
  186. package/src/monitor/agent-components.wildcard.test.ts +71 -0
  187. package/src/monitor/allow-list.test.ts +14 -0
  188. package/src/monitor/allow-list.ts +633 -0
  189. package/src/monitor/auto-presence.test.ts +156 -0
  190. package/src/monitor/auto-presence.ts +356 -0
  191. package/src/monitor/channel-access.test.ts +99 -0
  192. package/src/monitor/channel-access.ts +102 -0
  193. package/src/monitor/commands.test.ts +24 -0
  194. package/src/monitor/commands.ts +9 -0
  195. package/src/monitor/dm-command-auth.test.ts +197 -0
  196. package/src/monitor/dm-command-auth.ts +158 -0
  197. package/src/monitor/dm-command-decision.test.ts +113 -0
  198. package/src/monitor/dm-command-decision.ts +49 -0
  199. package/src/monitor/exec-approvals.test.ts +226 -0
  200. package/src/monitor/exec-approvals.ts +158 -0
  201. package/src/monitor/format.ts +45 -0
  202. package/src/monitor/gateway-handle.ts +34 -0
  203. package/src/monitor/gateway-metadata.test.ts +29 -0
  204. package/src/monitor/gateway-metadata.ts +298 -0
  205. package/src/monitor/gateway-plugin.test.ts +297 -0
  206. package/src/monitor/gateway-plugin.ts +294 -0
  207. package/src/monitor/gateway-registry.ts +37 -0
  208. package/src/monitor/gateway-supervisor.test.ts +150 -0
  209. package/src/monitor/gateway-supervisor.ts +206 -0
  210. package/src/monitor/inbound-context.test-helpers.ts +37 -0
  211. package/src/monitor/inbound-context.test.ts +106 -0
  212. package/src/monitor/inbound-context.ts +103 -0
  213. package/src/monitor/inbound-dedupe.ts +79 -0
  214. package/src/monitor/inbound-job.test.ts +203 -0
  215. package/src/monitor/inbound-job.ts +118 -0
  216. package/src/monitor/listeners.queue.ts +91 -0
  217. package/src/monitor/listeners.reactions.ts +610 -0
  218. package/src/monitor/listeners.test.ts +200 -0
  219. package/src/monitor/listeners.ts +150 -0
  220. package/src/monitor/message-channel-info.ts +96 -0
  221. package/src/monitor/message-forwarded.ts +107 -0
  222. package/src/monitor/message-handler.batch-gate.test.ts +22 -0
  223. package/src/monitor/message-handler.batch-gate.ts +19 -0
  224. package/src/monitor/message-handler.bot-self-filter.test.ts +68 -0
  225. package/src/monitor/message-handler.context.ts +406 -0
  226. package/src/monitor/message-handler.dm-preflight.ts +123 -0
  227. package/src/monitor/message-handler.draft-preview.ts +246 -0
  228. package/src/monitor/message-handler.hydration.test.ts +80 -0
  229. package/src/monitor/message-handler.hydration.ts +198 -0
  230. package/src/monitor/message-handler.inbound-context.test.ts +59 -0
  231. package/src/monitor/message-handler.module-test-helpers.ts +31 -0
  232. package/src/monitor/message-handler.preflight-channel-access.ts +86 -0
  233. package/src/monitor/message-handler.preflight-channel-context.test.ts +18 -0
  234. package/src/monitor/message-handler.preflight-channel-context.ts +58 -0
  235. package/src/monitor/message-handler.preflight-context.ts +54 -0
  236. package/src/monitor/message-handler.preflight-helpers.ts +164 -0
  237. package/src/monitor/message-handler.preflight-history.ts +23 -0
  238. package/src/monitor/message-handler.preflight-logging.ts +36 -0
  239. package/src/monitor/message-handler.preflight-pluralkit.ts +26 -0
  240. package/src/monitor/message-handler.preflight-runtime.ts +28 -0
  241. package/src/monitor/message-handler.preflight-thread.ts +49 -0
  242. package/src/monitor/message-handler.preflight.acp-bindings.test.ts +369 -0
  243. package/src/monitor/message-handler.preflight.test-helpers.ts +111 -0
  244. package/src/monitor/message-handler.preflight.test.ts +1623 -0
  245. package/src/monitor/message-handler.preflight.ts +679 -0
  246. package/src/monitor/message-handler.preflight.types.ts +110 -0
  247. package/src/monitor/message-handler.process.test.ts +1369 -0
  248. package/src/monitor/message-handler.process.ts +686 -0
  249. package/src/monitor/message-handler.queue.test.ts +496 -0
  250. package/src/monitor/message-handler.routing-preflight.ts +112 -0
  251. package/src/monitor/message-handler.test-harness.ts +99 -0
  252. package/src/monitor/message-handler.test-helpers.ts +75 -0
  253. package/src/monitor/message-handler.ts +274 -0
  254. package/src/monitor/message-media.ts +509 -0
  255. package/src/monitor/message-run-queue.ts +101 -0
  256. package/src/monitor/message-text.ts +171 -0
  257. package/src/monitor/message-utils.test.ts +1157 -0
  258. package/src/monitor/message-utils.ts +32 -0
  259. package/src/monitor/model-picker-preferences.test.ts +67 -0
  260. package/src/monitor/model-picker-preferences.ts +184 -0
  261. package/src/monitor/model-picker.state.ts +364 -0
  262. package/src/monitor/model-picker.test-utils.ts +26 -0
  263. package/src/monitor/model-picker.test.ts +794 -0
  264. package/src/monitor/model-picker.ts +38 -0
  265. package/src/monitor/model-picker.view.ts +695 -0
  266. package/src/monitor/monitor.agent-components.test.ts +375 -0
  267. package/src/monitor/monitor.test.ts +849 -0
  268. package/src/monitor/monitor.threading-utils.test.ts +598 -0
  269. package/src/monitor/native-command-agent-reply.ts +125 -0
  270. package/src/monitor/native-command-arg-ui.ts +233 -0
  271. package/src/monitor/native-command-auth.ts +308 -0
  272. package/src/monitor/native-command-bypass.ts +13 -0
  273. package/src/monitor/native-command-context.test.ts +98 -0
  274. package/src/monitor/native-command-context.ts +103 -0
  275. package/src/monitor/native-command-dispatch.ts +35 -0
  276. package/src/monitor/native-command-model-picker-apply.ts +177 -0
  277. package/src/monitor/native-command-model-picker-interaction.ts +461 -0
  278. package/src/monitor/native-command-model-picker-ui.ts +368 -0
  279. package/src/monitor/native-command-reply.test.ts +68 -0
  280. package/src/monitor/native-command-reply.ts +185 -0
  281. package/src/monitor/native-command-route.ts +91 -0
  282. package/src/monitor/native-command-status.ts +76 -0
  283. package/src/monitor/native-command-ui.ts +26 -0
  284. package/src/monitor/native-command-ui.types.ts +20 -0
  285. package/src/monitor/native-command.args.ts +45 -0
  286. package/src/monitor/native-command.command-arg.test.ts +99 -0
  287. package/src/monitor/native-command.commands-allowfrom.test.ts +490 -0
  288. package/src/monitor/native-command.model-picker.test.ts +767 -0
  289. package/src/monitor/native-command.options.test.ts +369 -0
  290. package/src/monitor/native-command.options.ts +153 -0
  291. package/src/monitor/native-command.plugin-dispatch.test.ts +961 -0
  292. package/src/monitor/native-command.runtime.ts +50 -0
  293. package/src/monitor/native-command.status-direct.test.ts +272 -0
  294. package/src/monitor/native-command.test-helpers.ts +64 -0
  295. package/src/monitor/native-command.think-autocomplete.test.ts +416 -0
  296. package/src/monitor/native-command.ts +700 -0
  297. package/src/monitor/native-command.types.ts +9 -0
  298. package/src/monitor/native-interaction-channel-context.ts +50 -0
  299. package/src/monitor/preflight-audio.runtime.ts +9 -0
  300. package/src/monitor/preflight-audio.test.ts +157 -0
  301. package/src/monitor/preflight-audio.ts +130 -0
  302. package/src/monitor/presence-cache.ts +61 -0
  303. package/src/monitor/presence.test.ts +44 -0
  304. package/src/monitor/presence.ts +50 -0
  305. package/src/monitor/provider-session.runtime.ts +12 -0
  306. package/src/monitor/provider.acp.ts +89 -0
  307. package/src/monitor/provider.allowlist.test.ts +149 -0
  308. package/src/monitor/provider.allowlist.ts +394 -0
  309. package/src/monitor/provider.cleanup.ts +41 -0
  310. package/src/monitor/provider.commands.ts +129 -0
  311. package/src/monitor/provider.config-log.ts +45 -0
  312. package/src/monitor/provider.deploy-errors.ts +362 -0
  313. package/src/monitor/provider.deploy.ts +221 -0
  314. package/src/monitor/provider.interactions.ts +160 -0
  315. package/src/monitor/provider.lifecycle.test.ts +713 -0
  316. package/src/monitor/provider.lifecycle.ts +552 -0
  317. package/src/monitor/provider.proxy.test.ts +745 -0
  318. package/src/monitor/provider.rest-proxy.test.ts +121 -0
  319. package/src/monitor/provider.runtime.ts +1 -0
  320. package/src/monitor/provider.skill-dedupe.test.ts +42 -0
  321. package/src/monitor/provider.startup-log.ts +32 -0
  322. package/src/monitor/provider.startup.test.ts +426 -0
  323. package/src/monitor/provider.startup.ts +323 -0
  324. package/src/monitor/provider.test.ts +1111 -0
  325. package/src/monitor/provider.ts +713 -0
  326. package/src/monitor/reply-context.ts +64 -0
  327. package/src/monitor/reply-delivery.test.ts +244 -0
  328. package/src/monitor/reply-delivery.ts +203 -0
  329. package/src/monitor/rest-fetch.ts +43 -0
  330. package/src/monitor/route-resolution.test.ts +204 -0
  331. package/src/monitor/route-resolution.ts +140 -0
  332. package/src/monitor/sender-identity.ts +81 -0
  333. package/src/monitor/startup-status.test.ts +30 -0
  334. package/src/monitor/startup-status.ts +10 -0
  335. package/src/monitor/status.ts +22 -0
  336. package/src/monitor/system-events.ts +55 -0
  337. package/src/monitor/thread-bindings.config.ts +35 -0
  338. package/src/monitor/thread-bindings.discord-api.test.ts +229 -0
  339. package/src/monitor/thread-bindings.discord-api.ts +310 -0
  340. package/src/monitor/thread-bindings.lifecycle.test.ts +1871 -0
  341. package/src/monitor/thread-bindings.lifecycle.ts +354 -0
  342. package/src/monitor/thread-bindings.manager.ts +553 -0
  343. package/src/monitor/thread-bindings.messages.ts +6 -0
  344. package/src/monitor/thread-bindings.persona.test.ts +34 -0
  345. package/src/monitor/thread-bindings.persona.ts +25 -0
  346. package/src/monitor/thread-bindings.session-adapter.ts +229 -0
  347. package/src/monitor/thread-bindings.session-shared.ts +59 -0
  348. package/src/monitor/thread-bindings.session-updates.ts +35 -0
  349. package/src/monitor/thread-bindings.shared-state.test.ts +36 -0
  350. package/src/monitor/thread-bindings.state.ts +540 -0
  351. package/src/monitor/thread-bindings.ts +48 -0
  352. package/src/monitor/thread-bindings.types.ts +83 -0
  353. package/src/monitor/thread-channel-context.ts +112 -0
  354. package/src/monitor/thread-session-close.test.ts +180 -0
  355. package/src/monitor/thread-session-close.ts +63 -0
  356. package/src/monitor/thread-title.generate.test.ts +197 -0
  357. package/src/monitor/thread-title.test.ts +31 -0
  358. package/src/monitor/thread-title.ts +181 -0
  359. package/src/monitor/threading.auto-thread.test.ts +327 -0
  360. package/src/monitor/threading.auto-thread.ts +287 -0
  361. package/src/monitor/threading.cache.ts +45 -0
  362. package/src/monitor/threading.parent-info.test.ts +156 -0
  363. package/src/monitor/threading.starter.test.ts +260 -0
  364. package/src/monitor/threading.starter.ts +287 -0
  365. package/src/monitor/threading.ts +20 -0
  366. package/src/monitor/threading.types.ts +102 -0
  367. package/src/monitor/timeouts.ts +84 -0
  368. package/src/monitor/typing.test.ts +42 -0
  369. package/src/monitor/typing.ts +17 -0
  370. package/src/monitor.gateway.test.ts +187 -0
  371. package/src/monitor.gateway.ts +75 -0
  372. package/src/monitor.test.ts +1397 -0
  373. package/src/monitor.ts +28 -0
  374. package/src/normalize.test.ts +56 -0
  375. package/src/normalize.ts +86 -0
  376. package/src/outbound-adapter.interactive-order.test.ts +64 -0
  377. package/src/outbound-adapter.test-harness.ts +207 -0
  378. package/src/outbound-adapter.test.ts +696 -0
  379. package/src/outbound-adapter.ts +291 -0
  380. package/src/outbound-approval.ts +29 -0
  381. package/src/outbound-components.ts +81 -0
  382. package/src/outbound-payload.contract.test.ts +38 -0
  383. package/src/outbound-payload.ts +134 -0
  384. package/src/outbound-send-context.ts +92 -0
  385. package/src/outbound-session-route.test.ts +34 -0
  386. package/src/outbound-session-route.ts +72 -0
  387. package/src/pluralkit.test.ts +67 -0
  388. package/src/pluralkit.ts +58 -0
  389. package/src/preview-streaming.ts +32 -0
  390. package/src/probe.intents.test.ts +94 -0
  391. package/src/probe.parse-token.test.ts +43 -0
  392. package/src/probe.runtime.ts +1 -0
  393. package/src/probe.ts +237 -0
  394. package/src/proxy-fetch.ts +92 -0
  395. package/src/proxy-request-client.test.ts +78 -0
  396. package/src/proxy-request-client.ts +21 -0
  397. package/src/recipient-resolution.ts +39 -0
  398. package/src/resolve-allowlist-common.test.ts +36 -0
  399. package/src/resolve-allowlist-common.ts +39 -0
  400. package/src/resolve-channels.test.ts +340 -0
  401. package/src/resolve-channels.ts +369 -0
  402. package/src/resolve-users.test.ts +222 -0
  403. package/src/resolve-users.ts +184 -0
  404. package/src/retry.test.ts +83 -0
  405. package/src/retry.ts +98 -0
  406. package/src/runtime-api.ts +64 -0
  407. package/src/runtime.ts +22 -5
  408. package/src/secret-config-contract.ts +140 -0
  409. package/src/security-audit.runtime.ts +1 -0
  410. package/src/security-audit.test.ts +246 -0
  411. package/src/security-audit.ts +208 -0
  412. package/src/security-contract.ts +47 -0
  413. package/src/security-doctor.test.ts +25 -0
  414. package/src/security-doctor.ts +20 -0
  415. package/src/security.ts +60 -0
  416. package/src/send-target-parsing.ts +14 -0
  417. package/src/send.channels.ts +139 -0
  418. package/src/send.components.test.ts +275 -0
  419. package/src/send.components.ts +381 -0
  420. package/src/send.creates-thread.test.ts +643 -0
  421. package/src/send.emojis-stickers.ts +57 -0
  422. package/src/send.guild.ts +170 -0
  423. package/src/send.message-request.ts +97 -0
  424. package/src/send.messages.test.ts +53 -0
  425. package/src/send.messages.ts +225 -0
  426. package/src/send.outbound.ts +413 -0
  427. package/src/send.permissions.authz.test.ts +188 -0
  428. package/src/send.permissions.ts +283 -0
  429. package/src/send.reactions.ts +155 -0
  430. package/src/send.sends-basic-channel-messages.test.ts +941 -0
  431. package/src/send.shared.ts +447 -0
  432. package/src/send.test-harness.ts +56 -0
  433. package/src/send.ts +82 -0
  434. package/src/send.types.ts +188 -0
  435. package/src/send.typing.test.ts +41 -0
  436. package/src/send.typing.ts +9 -0
  437. package/src/send.voice.ts +134 -0
  438. package/src/send.webhook-activity.test.ts +105 -0
  439. package/src/send.webhook.proxy.test.ts +191 -0
  440. package/src/send.webhook.ts +133 -0
  441. package/src/session-contract.ts +3 -0
  442. package/src/session-key-normalization.test.ts +44 -0
  443. package/src/session-key-normalization.ts +47 -0
  444. package/src/setup-account-state.test.ts +91 -0
  445. package/src/setup-account-state.ts +144 -0
  446. package/src/setup-adapter.ts +12 -0
  447. package/src/setup-core.ts +212 -0
  448. package/src/setup-runtime-helpers.ts +10 -0
  449. package/src/setup-surface.test.ts +137 -0
  450. package/src/setup-surface.ts +129 -0
  451. package/src/shared-interactive.test.ts +153 -0
  452. package/src/shared-interactive.ts +124 -0
  453. package/src/shared.test.ts +165 -0
  454. package/src/shared.ts +190 -0
  455. package/src/status-issues.test.ts +70 -0
  456. package/src/status-issues.ts +169 -0
  457. package/src/subagent-hooks.test.ts +130 -81
  458. package/src/subagent-hooks.ts +184 -122
  459. package/src/target-parsing.ts +53 -0
  460. package/src/target-resolver.ts +129 -0
  461. package/src/targets.test.ts +367 -0
  462. package/src/targets.ts +12 -0
  463. package/src/test-http-helpers.ts +10 -0
  464. package/src/test-support/component-runtime.ts +190 -0
  465. package/src/test-support/config.ts +7 -0
  466. package/src/test-support/configured-binding-runtime.ts +29 -0
  467. package/src/test-support/partial-channel.ts +26 -0
  468. package/src/test-support/provider.test-support.ts +545 -0
  469. package/src/token.test.ts +107 -0
  470. package/src/token.ts +60 -0
  471. package/src/ui-colors.ts +27 -0
  472. package/src/ui.ts +20 -0
  473. package/src/voice/access.test.ts +217 -0
  474. package/src/voice/access.ts +124 -0
  475. package/src/voice/audio.ts +173 -0
  476. package/src/voice/capture-state.test.ts +48 -0
  477. package/src/voice/capture-state.ts +120 -0
  478. package/src/voice/command.test.ts +164 -0
  479. package/src/voice/command.ts +283 -0
  480. package/src/voice/config.ts +8 -0
  481. package/src/voice/manager.e2e.test.ts +928 -0
  482. package/src/voice/manager.ready-listener.test.ts +37 -0
  483. package/src/voice/manager.runtime.ts +11 -0
  484. package/src/voice/manager.ts +691 -0
  485. package/src/voice/prompt.test.ts +16 -0
  486. package/src/voice/prompt.ts +17 -0
  487. package/src/voice/receive-recovery.test.ts +79 -0
  488. package/src/voice/receive-recovery.ts +159 -0
  489. package/src/voice/sanitize.test.ts +34 -0
  490. package/src/voice/sanitize.ts +32 -0
  491. package/src/voice/sdk-runtime.ts +14 -0
  492. package/src/voice/segment.ts +156 -0
  493. package/src/voice/session.ts +50 -0
  494. package/src/voice/speaker-context.ts +127 -0
  495. package/src/voice/tts.ts +125 -0
  496. package/src/voice-message.test.ts +234 -0
  497. package/src/voice-message.ts +444 -0
  498. package/subagent-hooks-api.ts +27 -0
  499. package/test-api.ts +4 -0
  500. package/thread-binding-api.ts +1 -0
  501. package/timeouts.ts +6 -0
  502. package/tsconfig.json +16 -0
@@ -0,0 +1,160 @@
1
+ import { logError } from "openclaw/plugin-sdk/text-runtime";
2
+ import { parseDiscordModalCustomIdForInteraction } from "../component-custom-id.js";
3
+ import { resolveDiscordModalEntryWithPersistence } from "../components-registry.js";
4
+ import { Modal, type ComponentData, type ModalInteraction } from "../internal/discord.js";
5
+ import {
6
+ type AgentComponentContext,
7
+ ensureComponentUserAllowed,
8
+ formatModalSubmissionText,
9
+ parseDiscordModalId,
10
+ resolveAuthorizedComponentInteraction,
11
+ resolveInteractionCustomId,
12
+ resolveModalFieldValues,
13
+ } from "./agent-components-helpers.js";
14
+ import { dispatchDiscordComponentEvent } from "./agent-components.dispatch.js";
15
+ import { dispatchPluginDiscordInteractiveEvent } from "./agent-components.plugin-interactive.js";
16
+
17
+ export class DiscordComponentModal extends Modal {
18
+ title = "OpenClaw form";
19
+ customId = "__openclaw_discord_component_modal_wildcard__";
20
+ components = [];
21
+ customIdParser = parseDiscordModalCustomIdForInteraction;
22
+ private ctx: AgentComponentContext;
23
+
24
+ constructor(ctx: AgentComponentContext) {
25
+ super();
26
+ this.ctx = ctx;
27
+ }
28
+
29
+ async run(interaction: ModalInteraction, data: ComponentData): Promise<void> {
30
+ const modalId = parseDiscordModalId(data, resolveInteractionCustomId(interaction));
31
+ if (!modalId) {
32
+ logError("discord component modal: missing modal id");
33
+ try {
34
+ await interaction.reply({
35
+ content: "This form is no longer valid.",
36
+ ephemeral: true,
37
+ });
38
+ } catch {
39
+ // Interaction may have expired
40
+ }
41
+ return;
42
+ }
43
+
44
+ const modalEntry = await resolveDiscordModalEntryWithPersistence({
45
+ id: modalId,
46
+ consume: false,
47
+ });
48
+ if (!modalEntry) {
49
+ try {
50
+ await interaction.reply({
51
+ content: "This form has expired.",
52
+ ephemeral: true,
53
+ });
54
+ } catch {
55
+ // Interaction may have expired
56
+ }
57
+ return;
58
+ }
59
+
60
+ const unauthorizedReply = "You are not authorized to use this form.";
61
+ const authorized = await resolveAuthorizedComponentInteraction({
62
+ ctx: this.ctx,
63
+ interaction,
64
+ label: "discord component modal",
65
+ componentLabel: "form",
66
+ unauthorizedReply,
67
+ defer: false,
68
+ });
69
+ if (!authorized) {
70
+ return;
71
+ }
72
+ const {
73
+ interactionCtx,
74
+ channelCtx,
75
+ guildInfo,
76
+ allowNameMatching,
77
+ commandAuthorized,
78
+ user,
79
+ replyOpts,
80
+ } = authorized;
81
+
82
+ const modalAllowed = await ensureComponentUserAllowed({
83
+ entry: {
84
+ id: modalEntry.id,
85
+ kind: "button",
86
+ label: modalEntry.title,
87
+ allowedUsers: modalEntry.allowedUsers,
88
+ },
89
+ interaction,
90
+ user,
91
+ replyOpts,
92
+ componentLabel: "form",
93
+ unauthorizedReply,
94
+ allowNameMatching,
95
+ });
96
+ if (!modalAllowed) {
97
+ return;
98
+ }
99
+
100
+ const consumed = await resolveDiscordModalEntryWithPersistence({
101
+ id: modalId,
102
+ consume: !modalEntry.reusable,
103
+ });
104
+ if (!consumed) {
105
+ try {
106
+ await interaction.reply({
107
+ content: "This form has expired.",
108
+ ephemeral: true,
109
+ });
110
+ } catch {
111
+ // Interaction may have expired
112
+ }
113
+ return;
114
+ }
115
+
116
+ if (consumed.callbackData) {
117
+ const fields = consumed.fields.map((field) => ({
118
+ id: field.id,
119
+ name: field.name,
120
+ values: resolveModalFieldValues(field, interaction),
121
+ }));
122
+ const pluginDispatch = await dispatchPluginDiscordInteractiveEvent({
123
+ ctx: this.ctx,
124
+ interaction,
125
+ interactionCtx,
126
+ channelCtx,
127
+ isAuthorizedSender: commandAuthorized,
128
+ data: consumed.callbackData,
129
+ kind: "modal",
130
+ fields,
131
+ messageId: consumed.messageId,
132
+ });
133
+ if (pluginDispatch === "handled") {
134
+ return;
135
+ }
136
+ }
137
+
138
+ try {
139
+ await interaction.acknowledge();
140
+ } catch (err) {
141
+ logError(`discord component modal: failed to acknowledge: ${String(err)}`);
142
+ }
143
+
144
+ const eventText = formatModalSubmissionText(consumed, interaction);
145
+ await dispatchDiscordComponentEvent({
146
+ ctx: this.ctx,
147
+ interaction,
148
+ interactionCtx,
149
+ channelCtx,
150
+ guildInfo,
151
+ eventText,
152
+ replyToId: consumed.messageId,
153
+ routeOverrides: {
154
+ sessionKey: consumed.sessionKey,
155
+ agentId: consumed.agentId,
156
+ accountId: consumed.accountId,
157
+ },
158
+ });
159
+ }
160
+ }
@@ -0,0 +1,187 @@
1
+ import { ChannelType } from "discord-api-types/v10";
2
+ import { logError } from "openclaw/plugin-sdk/text-runtime";
3
+ import {
4
+ dispatchDiscordPluginInteractiveHandler,
5
+ type DiscordInteractiveHandlerContext,
6
+ } from "../interactive-dispatch.js";
7
+ import type { TopLevelComponents } from "../internal/discord.js";
8
+ import { editDiscordComponentMessage } from "../send.components.js";
9
+ import {
10
+ resolveDiscordInteractionId,
11
+ type AgentComponentContext,
12
+ type AgentComponentInteraction,
13
+ type ComponentInteractionContext,
14
+ type DiscordChannelContext,
15
+ } from "./agent-components-helpers.js";
16
+
17
+ let conversationRuntimePromise: Promise<typeof import("./agent-components.runtime.js")> | undefined;
18
+
19
+ async function loadConversationRuntime() {
20
+ conversationRuntimePromise ??= import("./agent-components.runtime.js");
21
+ return await conversationRuntimePromise;
22
+ }
23
+
24
+ export async function dispatchPluginDiscordInteractiveEvent(params: {
25
+ ctx: AgentComponentContext;
26
+ interaction: AgentComponentInteraction;
27
+ interactionCtx: ComponentInteractionContext;
28
+ channelCtx: DiscordChannelContext;
29
+ isAuthorizedSender: boolean;
30
+ data: string;
31
+ kind: "button" | "select" | "modal";
32
+ values?: string[];
33
+ fields?: Array<{ id: string; name: string; values: string[] }>;
34
+ messageId?: string;
35
+ }): Promise<"handled" | "unmatched"> {
36
+ const normalizedConversationId =
37
+ params.interactionCtx.rawGuildId || params.channelCtx.channelType === ChannelType.GroupDM
38
+ ? `channel:${params.interactionCtx.channelId}`
39
+ : `user:${params.interactionCtx.userId}`;
40
+ let responded = false;
41
+ let acknowledged = false;
42
+ const updateOriginalMessage = async (input: {
43
+ text?: string;
44
+ components?: TopLevelComponents[];
45
+ }) => {
46
+ const payload = {
47
+ ...(input.text !== undefined ? { content: input.text } : {}),
48
+ ...(input.components !== undefined ? { components: input.components } : {}),
49
+ };
50
+ if (acknowledged) {
51
+ await params.interaction.reply(payload);
52
+ return;
53
+ }
54
+ if (!("update" in params.interaction) || typeof params.interaction.update !== "function") {
55
+ throw new Error("Discord interaction cannot update the source message");
56
+ }
57
+ await params.interaction.update(payload);
58
+ };
59
+ const respond: DiscordInteractiveHandlerContext["respond"] = {
60
+ acknowledge: async () => {
61
+ if (responded) {
62
+ return;
63
+ }
64
+ await params.interaction.acknowledge();
65
+ acknowledged = true;
66
+ responded = true;
67
+ },
68
+ reply: async ({ text, ephemeral = true }: { text: string; ephemeral?: boolean }) => {
69
+ responded = true;
70
+ await params.interaction.reply({
71
+ content: text,
72
+ ephemeral,
73
+ });
74
+ },
75
+ followUp: async ({ text, ephemeral = true }: { text: string; ephemeral?: boolean }) => {
76
+ responded = true;
77
+ await params.interaction.followUp({
78
+ content: text,
79
+ ephemeral,
80
+ });
81
+ },
82
+ editMessage: async (
83
+ input: Parameters<DiscordInteractiveHandlerContext["respond"]["editMessage"]>[0],
84
+ ) => {
85
+ const { text, components } = input;
86
+ responded = true;
87
+ await updateOriginalMessage({
88
+ text,
89
+ components: components as TopLevelComponents[] | undefined,
90
+ });
91
+ },
92
+ clearComponents: async (input?: { text?: string }) => {
93
+ responded = true;
94
+ await updateOriginalMessage({
95
+ text: input?.text,
96
+ components: [],
97
+ });
98
+ },
99
+ };
100
+ const conversationRuntime = await loadConversationRuntime();
101
+ const pluginBindingApproval = conversationRuntime.parsePluginBindingApprovalCustomId(params.data);
102
+ if (pluginBindingApproval) {
103
+ const { buildPluginBindingResolvedText, resolvePluginConversationBindingApproval } =
104
+ conversationRuntime;
105
+ try {
106
+ await respond.acknowledge();
107
+ } catch {
108
+ // Interaction may have expired; try to continue anyway.
109
+ }
110
+ const resolved = await resolvePluginConversationBindingApproval({
111
+ approvalId: pluginBindingApproval.approvalId,
112
+ decision: pluginBindingApproval.decision,
113
+ senderId: params.interactionCtx.userId,
114
+ });
115
+ const approvalMessageId = params.messageId?.trim() || params.interaction.message?.id?.trim();
116
+ if (approvalMessageId) {
117
+ try {
118
+ await editDiscordComponentMessage(
119
+ normalizedConversationId,
120
+ approvalMessageId,
121
+ {
122
+ text: buildPluginBindingResolvedText(resolved),
123
+ },
124
+ {
125
+ cfg: params.ctx.cfg,
126
+ accountId: params.ctx.accountId,
127
+ },
128
+ );
129
+ } catch (err) {
130
+ logError(`discord plugin binding approval: failed to clear prompt: ${String(err)}`);
131
+ }
132
+ }
133
+ if (resolved.status !== "approved") {
134
+ try {
135
+ await respond.followUp({
136
+ text: buildPluginBindingResolvedText(resolved),
137
+ ephemeral: true,
138
+ });
139
+ } catch (err) {
140
+ logError(`discord plugin binding approval: failed to follow up: ${String(err)}`);
141
+ }
142
+ }
143
+ return "handled";
144
+ }
145
+ const dispatched = await dispatchDiscordPluginInteractiveHandler({
146
+ data: params.data,
147
+ interactionId: resolveDiscordInteractionId(params.interaction),
148
+ ctx: {
149
+ accountId: params.ctx.accountId,
150
+ interactionId: resolveDiscordInteractionId(params.interaction),
151
+ conversationId: normalizedConversationId,
152
+ parentConversationId: params.channelCtx.parentId,
153
+ guildId: params.interactionCtx.rawGuildId,
154
+ senderId: params.interactionCtx.userId,
155
+ senderUsername: params.interactionCtx.username,
156
+ auth: { isAuthorizedSender: params.isAuthorizedSender },
157
+ interaction: {
158
+ kind: params.kind,
159
+ messageId: params.messageId,
160
+ values: params.values,
161
+ fields: params.fields,
162
+ },
163
+ },
164
+ respond,
165
+ onMatched: async () => {
166
+ try {
167
+ await respond.acknowledge();
168
+ } catch {
169
+ // Interaction may have expired before the plugin handler ran.
170
+ }
171
+ },
172
+ });
173
+ if (!dispatched.matched) {
174
+ return "unmatched";
175
+ }
176
+ if (dispatched.handled) {
177
+ if (!responded) {
178
+ try {
179
+ await respond.acknowledge();
180
+ } catch {
181
+ // Interaction may have expired after the handler finished.
182
+ }
183
+ }
184
+ return "handled";
185
+ }
186
+ return "unmatched";
187
+ }
@@ -0,0 +1,14 @@
1
+ export {
2
+ buildPluginBindingResolvedText,
3
+ parsePluginBindingApprovalCustomId,
4
+ recordInboundSession,
5
+ resolvePluginConversationBindingApproval,
6
+ } from "openclaw/plugin-sdk/conversation-runtime";
7
+ export { dispatchPluginInteractiveHandler } from "openclaw/plugin-sdk/plugin-runtime";
8
+ export {
9
+ createReplyReferencePlanner,
10
+ dispatchReplyWithBufferedBlockDispatcher,
11
+ finalizeInboundContext,
12
+ resolveChunkMode,
13
+ resolveTextChunkLimit,
14
+ } from "openclaw/plugin-sdk/reply-runtime";
@@ -0,0 +1,211 @@
1
+ import type { APIStringSelectComponent } from "discord-api-types/v10";
2
+ import { ButtonStyle } from "discord-api-types/v10";
3
+ import { logDebug, logError } from "openclaw/plugin-sdk/text-runtime";
4
+ import {
5
+ Button,
6
+ StringSelectMenu,
7
+ type ButtonInteraction,
8
+ type ComponentData,
9
+ type StringSelectMenuInteraction,
10
+ } from "../internal/discord.js";
11
+ import {
12
+ AGENT_BUTTON_KEY,
13
+ AGENT_SELECT_KEY,
14
+ ackComponentInteraction,
15
+ ensureAgentComponentInteractionAllowed,
16
+ parseAgentComponentData,
17
+ resolveAgentComponentRoute,
18
+ resolveInteractionContextWithDmAuth,
19
+ type AgentComponentContext,
20
+ } from "./agent-components-helpers.js";
21
+ import { enqueueSystemEvent } from "./agent-components.deps.runtime.js";
22
+
23
+ export class AgentComponentButton extends Button {
24
+ label = AGENT_BUTTON_KEY;
25
+ customId = `${AGENT_BUTTON_KEY}:seed=1`;
26
+ style = ButtonStyle.Primary;
27
+ private ctx: AgentComponentContext;
28
+
29
+ constructor(ctx: AgentComponentContext) {
30
+ super();
31
+ this.ctx = ctx;
32
+ }
33
+
34
+ async run(interaction: ButtonInteraction, data: ComponentData): Promise<void> {
35
+ const parsed = parseAgentComponentData(data);
36
+ if (!parsed) {
37
+ logError("agent button: failed to parse component data");
38
+ try {
39
+ await interaction.reply({
40
+ content: "This button is no longer valid.",
41
+ ephemeral: true,
42
+ });
43
+ } catch {
44
+ // Interaction may have expired
45
+ }
46
+ return;
47
+ }
48
+
49
+ const { componentId } = parsed;
50
+
51
+ const interactionCtx = await resolveInteractionContextWithDmAuth({
52
+ ctx: this.ctx,
53
+ interaction,
54
+ label: "agent button",
55
+ componentLabel: "button",
56
+ defer: false,
57
+ });
58
+ if (!interactionCtx) {
59
+ return;
60
+ }
61
+ const {
62
+ channelId,
63
+ user,
64
+ username,
65
+ userId,
66
+ replyOpts,
67
+ rawGuildId,
68
+ isDirectMessage,
69
+ isGroupDm,
70
+ memberRoleIds,
71
+ } = interactionCtx;
72
+
73
+ const allowed = await ensureAgentComponentInteractionAllowed({
74
+ ctx: this.ctx,
75
+ interaction,
76
+ channelId,
77
+ rawGuildId,
78
+ memberRoleIds,
79
+ user,
80
+ replyOpts,
81
+ componentLabel: "button",
82
+ unauthorizedReply: "You are not authorized to use this button.",
83
+ });
84
+ if (!allowed) {
85
+ return;
86
+ }
87
+ const { parentId } = allowed;
88
+
89
+ const route = resolveAgentComponentRoute({
90
+ ctx: this.ctx,
91
+ rawGuildId,
92
+ memberRoleIds,
93
+ isDirectMessage,
94
+ isGroupDm,
95
+ userId,
96
+ channelId,
97
+ parentId,
98
+ });
99
+
100
+ const eventText = `[Discord component: ${componentId} clicked by ${username} (${userId})]`;
101
+
102
+ logDebug(`agent button: enqueuing event for channel ${channelId}: ${eventText}`);
103
+
104
+ enqueueSystemEvent(eventText, {
105
+ sessionKey: route.sessionKey,
106
+ contextKey: `discord:agent-button:${channelId}:${componentId}:${userId}`,
107
+ });
108
+
109
+ await ackComponentInteraction({ interaction, replyOpts, label: "agent button" });
110
+ }
111
+ }
112
+
113
+ export class AgentSelectMenu extends StringSelectMenu {
114
+ customId = `${AGENT_SELECT_KEY}:seed=1`;
115
+ options: APIStringSelectComponent["options"] = [];
116
+ private ctx: AgentComponentContext;
117
+
118
+ constructor(ctx: AgentComponentContext) {
119
+ super();
120
+ this.ctx = ctx;
121
+ }
122
+
123
+ async run(interaction: StringSelectMenuInteraction, data: ComponentData): Promise<void> {
124
+ const parsed = parseAgentComponentData(data);
125
+ if (!parsed) {
126
+ logError("agent select: failed to parse component data");
127
+ try {
128
+ await interaction.reply({
129
+ content: "This select menu is no longer valid.",
130
+ ephemeral: true,
131
+ });
132
+ } catch {
133
+ // Interaction may have expired
134
+ }
135
+ return;
136
+ }
137
+
138
+ const { componentId } = parsed;
139
+
140
+ const interactionCtx = await resolveInteractionContextWithDmAuth({
141
+ ctx: this.ctx,
142
+ interaction,
143
+ label: "agent select",
144
+ componentLabel: "select menu",
145
+ defer: false,
146
+ });
147
+ if (!interactionCtx) {
148
+ return;
149
+ }
150
+ const {
151
+ channelId,
152
+ user,
153
+ username,
154
+ userId,
155
+ replyOpts,
156
+ rawGuildId,
157
+ isDirectMessage,
158
+ isGroupDm,
159
+ memberRoleIds,
160
+ } = interactionCtx;
161
+
162
+ const allowed = await ensureAgentComponentInteractionAllowed({
163
+ ctx: this.ctx,
164
+ interaction,
165
+ channelId,
166
+ rawGuildId,
167
+ memberRoleIds,
168
+ user,
169
+ replyOpts,
170
+ componentLabel: "select",
171
+ unauthorizedReply: "You are not authorized to use this select menu.",
172
+ });
173
+ if (!allowed) {
174
+ return;
175
+ }
176
+ const { parentId } = allowed;
177
+
178
+ const values = interaction.values ?? [];
179
+ const valuesText = values.length > 0 ? ` (selected: ${values.join(", ")})` : "";
180
+
181
+ const route = resolveAgentComponentRoute({
182
+ ctx: this.ctx,
183
+ rawGuildId,
184
+ memberRoleIds,
185
+ isDirectMessage,
186
+ isGroupDm,
187
+ userId,
188
+ channelId,
189
+ parentId,
190
+ });
191
+
192
+ const eventText = `[Discord select menu: ${componentId} interacted by ${username} (${userId})${valuesText}]`;
193
+
194
+ logDebug(`agent select: enqueuing event for channel ${channelId}: ${eventText}`);
195
+
196
+ enqueueSystemEvent(eventText, {
197
+ sessionKey: route.sessionKey,
198
+ contextKey: `discord:agent-select:${channelId}:${componentId}:${userId}`,
199
+ });
200
+
201
+ await ackComponentInteraction({ interaction, replyOpts, label: "agent select" });
202
+ }
203
+ }
204
+
205
+ export function createAgentComponentButton(ctx: AgentComponentContext): Button {
206
+ return new AgentComponentButton(ctx);
207
+ }
208
+
209
+ export function createAgentSelectMenu(ctx: AgentComponentContext): StringSelectMenu {
210
+ return new AgentSelectMenu(ctx);
211
+ }
@@ -0,0 +1,70 @@
1
+ import { Modal, type BaseMessageInteractiveComponent } from "../internal/discord.js";
2
+ import type { AgentComponentContext } from "./agent-components-helpers.js";
3
+ import { discordComponentControlHandlers } from "./agent-components.handlers.js";
4
+ import { DiscordComponentModal } from "./agent-components.modal.js";
5
+ import {
6
+ createAgentComponentButton,
7
+ createAgentSelectMenu,
8
+ } from "./agent-components.system-controls.js";
9
+ import {
10
+ createDiscordComponentButtonControl,
11
+ createDiscordComponentChannelSelectControl,
12
+ createDiscordComponentMentionableSelectControl,
13
+ createDiscordComponentRoleSelectControl,
14
+ createDiscordComponentStringSelectControl,
15
+ createDiscordComponentUserSelectControl,
16
+ type DiscordComponentControlHandlers,
17
+ } from "./agent-components.wildcard-controls.js";
18
+
19
+ export { resolveDiscordComponentOriginatingTo } from "./agent-components.dispatch.js";
20
+ export {
21
+ AgentComponentButton,
22
+ AgentSelectMenu,
23
+ createAgentComponentButton,
24
+ createAgentSelectMenu,
25
+ } from "./agent-components.system-controls.js";
26
+
27
+ type ComponentFactory = (ctx: AgentComponentContext) => BaseMessageInteractiveComponent;
28
+
29
+ function bindDiscordComponentControl<T extends BaseMessageInteractiveComponent>(
30
+ createControl: (ctx: AgentComponentContext, handlers: DiscordComponentControlHandlers) => T,
31
+ ) {
32
+ return (ctx: AgentComponentContext): T => createControl(ctx, discordComponentControlHandlers);
33
+ }
34
+
35
+ export const createDiscordComponentButton = bindDiscordComponentControl(
36
+ createDiscordComponentButtonControl,
37
+ );
38
+ export const createDiscordComponentStringSelect = bindDiscordComponentControl(
39
+ createDiscordComponentStringSelectControl,
40
+ );
41
+ export const createDiscordComponentUserSelect = bindDiscordComponentControl(
42
+ createDiscordComponentUserSelectControl,
43
+ );
44
+ export const createDiscordComponentRoleSelect = bindDiscordComponentControl(
45
+ createDiscordComponentRoleSelectControl,
46
+ );
47
+ export const createDiscordComponentMentionableSelect = bindDiscordComponentControl(
48
+ createDiscordComponentMentionableSelectControl,
49
+ );
50
+ export const createDiscordComponentChannelSelect = bindDiscordComponentControl(
51
+ createDiscordComponentChannelSelectControl,
52
+ );
53
+
54
+ export const createAgentComponentControls = [
55
+ createAgentComponentButton,
56
+ createAgentSelectMenu,
57
+ ] satisfies readonly ComponentFactory[];
58
+
59
+ export const createDiscordComponentControls = [
60
+ createDiscordComponentButton,
61
+ createDiscordComponentStringSelect,
62
+ createDiscordComponentUserSelect,
63
+ createDiscordComponentRoleSelect,
64
+ createDiscordComponentMentionableSelect,
65
+ createDiscordComponentChannelSelect,
66
+ ] satisfies readonly ComponentFactory[];
67
+
68
+ export function createDiscordComponentModal(ctx: AgentComponentContext): Modal {
69
+ return new DiscordComponentModal(ctx);
70
+ }
@@ -0,0 +1,58 @@
1
+ import type { DiscordAccountConfig, OpenClawConfig } from "openclaw/plugin-sdk/config-types";
2
+ import type {
3
+ ButtonInteraction,
4
+ ChannelSelectMenuInteraction,
5
+ MentionableSelectMenuInteraction,
6
+ ModalInteraction,
7
+ RoleSelectMenuInteraction,
8
+ StringSelectMenuInteraction,
9
+ UserSelectMenuInteraction,
10
+ } from "../internal/discord.js";
11
+ import type { DiscordGuildEntryResolved } from "./allow-list.js";
12
+ import type { formatDiscordUserTag } from "./format.js";
13
+
14
+ export type DiscordUser = Parameters<typeof formatDiscordUserTag>[0];
15
+
16
+ export type AgentComponentMessageInteraction =
17
+ | ButtonInteraction
18
+ | StringSelectMenuInteraction
19
+ | RoleSelectMenuInteraction
20
+ | UserSelectMenuInteraction
21
+ | MentionableSelectMenuInteraction
22
+ | ChannelSelectMenuInteraction;
23
+
24
+ export type AgentComponentInteraction = AgentComponentMessageInteraction | ModalInteraction;
25
+
26
+ export type DiscordChannelContext = {
27
+ channelName: string | undefined;
28
+ channelSlug: string;
29
+ displayChannelSlug: string;
30
+ channelType: number | undefined;
31
+ isThread: boolean;
32
+ parentId: string | undefined;
33
+ parentName: string | undefined;
34
+ parentSlug: string;
35
+ };
36
+
37
+ export type AgentComponentContext = {
38
+ cfg: OpenClawConfig;
39
+ accountId: string;
40
+ discordConfig?: DiscordAccountConfig;
41
+ runtime?: import("openclaw/plugin-sdk/runtime-env").RuntimeEnv;
42
+ token?: string;
43
+ guildEntries?: Record<string, DiscordGuildEntryResolved>;
44
+ allowFrom?: string[];
45
+ dmPolicy?: "open" | "pairing" | "allowlist" | "disabled";
46
+ };
47
+
48
+ export type ComponentInteractionContext = {
49
+ channelId: string;
50
+ user: DiscordUser;
51
+ username: string;
52
+ userId: string;
53
+ replyOpts: { ephemeral?: boolean };
54
+ rawGuildId: string | undefined;
55
+ isDirectMessage: boolean;
56
+ isGroupDm: boolean;
57
+ memberRoleIds: string[];
58
+ };