@tencent-connect/openclaw-qqbot 1.7.1 → 2.0.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 (283) hide show
  1. package/README.md +206 -4
  2. package/README.zh.md +207 -4
  3. package/bin/qqbot-cli.js +5 -2
  4. package/dist/index.cjs +15549 -0
  5. package/dist/index.cjs.map +1 -0
  6. package/dist/index.d.cts +890 -0
  7. package/index.ts +56 -18
  8. package/openclaw.plugin.json +19 -3
  9. package/package.json +14 -23
  10. package/preload.cjs +17 -14
  11. package/scripts/link-sdk-core.cjs +133 -50
  12. package/scripts/upgrade-via-npm.sh +400 -73
  13. package/scripts/upgrade-via-source.sh +126 -89
  14. package/skills/qqbot-channel/SKILL.md +34 -12
  15. package/src/adapter/contract.ts +69 -0
  16. package/src/adapter/gateway.ts +61 -0
  17. package/src/adapter/index.ts +15 -0
  18. package/src/adapter/lint.ts +144 -0
  19. package/src/adapter/media.ts +112 -0
  20. package/src/adapter/pairing.ts +99 -0
  21. package/src/adapter/resolve.ts +333 -0
  22. package/src/adapter/setup.ts +55 -0
  23. package/src/adapter/webhook.ts +248 -0
  24. package/src/adapter/workspace.ts +29 -0
  25. package/src/bot-instance.ts +60 -0
  26. package/src/channel.ts +202 -413
  27. package/src/commands/bot-approve.ts +143 -0
  28. package/src/commands/bot-clear-storage.ts +114 -0
  29. package/src/commands/bot-group-always.ts +62 -0
  30. package/src/commands/bot-help.ts +40 -0
  31. package/src/commands/bot-logs.ts +248 -0
  32. package/src/commands/bot-me.ts +18 -0
  33. package/src/commands/bot-pairing.ts +57 -0
  34. package/src/commands/bot-ping.ts +33 -0
  35. package/src/commands/bot-streaming.ts +55 -0
  36. package/src/commands/bot-upgrade.ts +56 -0
  37. package/src/commands/bot-version.ts +41 -0
  38. package/src/commands/config-util.ts +96 -0
  39. package/src/commands/index.ts +49 -0
  40. package/src/config.ts +59 -19
  41. package/src/dispatch/body-assembler.ts +356 -0
  42. package/src/dispatch/ctx-builder.ts +110 -0
  43. package/src/dispatch/dispatch.ts +352 -0
  44. package/src/dispatch/envelope-builder.ts +112 -0
  45. package/src/dispatch/index.ts +2 -0
  46. package/src/{approval-handler.ts → features/approval-handler.ts} +40 -94
  47. package/src/features/approval-utils.ts +41 -0
  48. package/src/features/credential-backup.ts +82 -0
  49. package/src/features/history-store.ts +19 -0
  50. package/src/features/msgid-cache.ts +55 -0
  51. package/src/features/onboarding.ts +38 -0
  52. package/src/{proactive.ts → features/proactive.ts} +68 -49
  53. package/src/features/ref-index-store.ts +282 -0
  54. package/src/{update-checker.ts → features/update-checker.ts} +15 -35
  55. package/src/gateway/event-handlers.ts +241 -0
  56. package/src/gateway/index.ts +3 -0
  57. package/src/gateway/lifecycle.ts +221 -0
  58. package/src/gateway/middleware-setup.ts +139 -0
  59. package/src/gateway/qqbot-gateway.ts +342 -0
  60. package/src/middleware/access-control.ts +130 -0
  61. package/src/middleware/attachment.ts +314 -0
  62. package/src/middleware/policy-injector.ts +66 -0
  63. package/src/openclaw-plugin-sdk.d.ts +81 -10
  64. package/src/outbound/cron-scheduler.ts +130 -0
  65. package/src/outbound/debounce.ts +102 -0
  66. package/src/outbound/deliver-pipeline.ts +235 -0
  67. package/src/outbound/image-size.ts +123 -0
  68. package/src/outbound/index.ts +3 -0
  69. package/src/outbound/local-file-router.ts +145 -0
  70. package/src/outbound/media-send.ts +377 -0
  71. package/src/outbound/outbound-service.ts +222 -0
  72. package/src/outbound/reply-limiter.ts +128 -0
  73. package/src/outbound/sanitize.ts +32 -0
  74. package/src/outbound/streaming-controller.ts +228 -0
  75. package/src/outbound/target.ts +63 -0
  76. package/src/outbound/tts-provider.ts +84 -0
  77. package/src/request-context.ts +9 -8
  78. package/src/runtime.ts +31 -6
  79. package/src/setup/account-key.ts +41 -0
  80. package/src/setup/finalize.ts +110 -0
  81. package/src/setup/login.ts +197 -0
  82. package/src/setup/surface.ts +40 -0
  83. package/src/tools/platform.ts +149 -0
  84. package/src/tools/remind.ts +1 -1
  85. package/src/types-augment.d.ts +54 -0
  86. package/src/types.ts +71 -8
  87. package/src/typings/openclaw-webhook-ingress.d.ts +66 -0
  88. package/src/utils/mention.ts +52 -0
  89. package/src/utils/pkg-version.ts +84 -47
  90. package/src/utils/platform.ts +31 -7
  91. package/src/utils/plugin-logger.ts +104 -0
  92. package/src/utils/ssrf-guard.ts +32 -2
  93. package/src/utils/stt.ts +137 -0
  94. package/src/utils/voice-text.ts +61 -0
  95. package/tsconfig.json +2 -1
  96. package/tsup.config.ts +57 -0
  97. package/dist/index.d.ts +0 -17
  98. package/dist/index.js +0 -26
  99. package/dist/src/admin-resolver.d.ts +0 -33
  100. package/dist/src/admin-resolver.js +0 -157
  101. package/dist/src/api.d.ts +0 -307
  102. package/dist/src/api.js +0 -910
  103. package/dist/src/approval-handler.d.ts +0 -47
  104. package/dist/src/approval-handler.js +0 -372
  105. package/dist/src/channel.d.ts +0 -29
  106. package/dist/src/channel.js +0 -528
  107. package/dist/src/config.d.ts +0 -56
  108. package/dist/src/config.js +0 -278
  109. package/dist/src/credential-backup.d.ts +0 -31
  110. package/dist/src/credential-backup.js +0 -66
  111. package/dist/src/deliver-debounce.d.ts +0 -74
  112. package/dist/src/deliver-debounce.js +0 -174
  113. package/dist/src/gateway.d.ts +0 -18
  114. package/dist/src/gateway.js +0 -2063
  115. package/dist/src/group-history.d.ts +0 -136
  116. package/dist/src/group-history.js +0 -226
  117. package/dist/src/image-server.d.ts +0 -87
  118. package/dist/src/image-server.js +0 -570
  119. package/dist/src/inbound-attachments.d.ts +0 -60
  120. package/dist/src/inbound-attachments.js +0 -248
  121. package/dist/src/known-users.d.ts +0 -100
  122. package/dist/src/known-users.js +0 -263
  123. package/dist/src/message-gating.d.ts +0 -53
  124. package/dist/src/message-gating.js +0 -107
  125. package/dist/src/message-queue.d.ts +0 -91
  126. package/dist/src/message-queue.js +0 -257
  127. package/dist/src/onboarding.d.ts +0 -10
  128. package/dist/src/onboarding.js +0 -203
  129. package/dist/src/outbound-deliver.d.ts +0 -48
  130. package/dist/src/outbound-deliver.js +0 -392
  131. package/dist/src/outbound.d.ts +0 -220
  132. package/dist/src/outbound.js +0 -975
  133. package/dist/src/proactive.d.ts +0 -170
  134. package/dist/src/proactive.js +0 -399
  135. package/dist/src/ref-index-store.d.ts +0 -101
  136. package/dist/src/ref-index-store.js +0 -298
  137. package/dist/src/reply-dispatcher.d.ts +0 -35
  138. package/dist/src/reply-dispatcher.js +0 -311
  139. package/dist/src/request-context.d.ts +0 -25
  140. package/dist/src/request-context.js +0 -37
  141. package/dist/src/runtime.d.ts +0 -3
  142. package/dist/src/runtime.js +0 -13
  143. package/dist/src/session-store.d.ts +0 -52
  144. package/dist/src/session-store.js +0 -254
  145. package/dist/src/slash-commands.d.ts +0 -82
  146. package/dist/src/slash-commands.js +0 -2117
  147. package/dist/src/startup-greeting.d.ts +0 -30
  148. package/dist/src/startup-greeting.js +0 -97
  149. package/dist/src/streaming.d.ts +0 -247
  150. package/dist/src/streaming.js +0 -899
  151. package/dist/src/stt.d.ts +0 -21
  152. package/dist/src/stt.js +0 -70
  153. package/dist/src/tools/channel.d.ts +0 -16
  154. package/dist/src/tools/channel.js +0 -234
  155. package/dist/src/tools/remind.d.ts +0 -2
  156. package/dist/src/tools/remind.js +0 -256
  157. package/dist/src/types.d.ts +0 -443
  158. package/dist/src/types.js +0 -22
  159. package/dist/src/typing-keepalive.d.ts +0 -27
  160. package/dist/src/typing-keepalive.js +0 -64
  161. package/dist/src/update-checker.d.ts +0 -36
  162. package/dist/src/update-checker.js +0 -171
  163. package/dist/src/utils/audio-convert.d.ts +0 -98
  164. package/dist/src/utils/audio-convert.js +0 -755
  165. package/dist/src/utils/chunked-upload.d.ts +0 -68
  166. package/dist/src/utils/chunked-upload.js +0 -341
  167. package/dist/src/utils/file-utils.d.ts +0 -61
  168. package/dist/src/utils/file-utils.js +0 -172
  169. package/dist/src/utils/image-size.d.ts +0 -51
  170. package/dist/src/utils/image-size.js +0 -234
  171. package/dist/src/utils/media-send.d.ts +0 -158
  172. package/dist/src/utils/media-send.js +0 -502
  173. package/dist/src/utils/media-tags.d.ts +0 -14
  174. package/dist/src/utils/media-tags.js +0 -165
  175. package/dist/src/utils/payload.d.ts +0 -112
  176. package/dist/src/utils/payload.js +0 -186
  177. package/dist/src/utils/pkg-version.d.ts +0 -5
  178. package/dist/src/utils/pkg-version.js +0 -61
  179. package/dist/src/utils/platform.d.ts +0 -137
  180. package/dist/src/utils/platform.js +0 -390
  181. package/dist/src/utils/ssrf-guard.d.ts +0 -25
  182. package/dist/src/utils/ssrf-guard.js +0 -91
  183. package/dist/src/utils/text-parsing.d.ts +0 -31
  184. package/dist/src/utils/text-parsing.js +0 -74
  185. package/dist/src/utils/upload-cache.d.ts +0 -34
  186. package/dist/src/utils/upload-cache.js +0 -93
  187. package/node_modules/@eshaz/web-worker/LICENSE +0 -201
  188. package/node_modules/@eshaz/web-worker/README.md +0 -134
  189. package/node_modules/@eshaz/web-worker/browser.js +0 -17
  190. package/node_modules/@eshaz/web-worker/cjs/browser.js +0 -16
  191. package/node_modules/@eshaz/web-worker/cjs/node.js +0 -219
  192. package/node_modules/@eshaz/web-worker/index.d.ts +0 -4
  193. package/node_modules/@eshaz/web-worker/node.js +0 -223
  194. package/node_modules/@eshaz/web-worker/package.json +0 -54
  195. package/node_modules/@wasm-audio-decoders/common/index.js +0 -5
  196. package/node_modules/@wasm-audio-decoders/common/package.json +0 -36
  197. package/node_modules/@wasm-audio-decoders/common/src/WASMAudioDecoderCommon.js +0 -231
  198. package/node_modules/@wasm-audio-decoders/common/src/WASMAudioDecoderWorker.js +0 -129
  199. package/node_modules/@wasm-audio-decoders/common/src/puff/README +0 -67
  200. package/node_modules/@wasm-audio-decoders/common/src/puff/build_puff.js +0 -31
  201. package/node_modules/@wasm-audio-decoders/common/src/puff/puff.c +0 -863
  202. package/node_modules/@wasm-audio-decoders/common/src/puff/puff.h +0 -35
  203. package/node_modules/@wasm-audio-decoders/common/src/utilities.js +0 -3
  204. package/node_modules/@wasm-audio-decoders/common/types.d.ts +0 -7
  205. package/node_modules/mpg123-decoder/README.md +0 -265
  206. package/node_modules/mpg123-decoder/dist/mpg123-decoder.min.js +0 -185
  207. package/node_modules/mpg123-decoder/dist/mpg123-decoder.min.js.map +0 -1
  208. package/node_modules/mpg123-decoder/index.js +0 -8
  209. package/node_modules/mpg123-decoder/package.json +0 -58
  210. package/node_modules/mpg123-decoder/src/EmscriptenWasm.js +0 -464
  211. package/node_modules/mpg123-decoder/src/MPEGDecoder.js +0 -200
  212. package/node_modules/mpg123-decoder/src/MPEGDecoderWebWorker.js +0 -21
  213. package/node_modules/mpg123-decoder/types.d.ts +0 -30
  214. package/node_modules/silk-wasm/LICENSE +0 -21
  215. package/node_modules/silk-wasm/README.md +0 -85
  216. package/node_modules/silk-wasm/lib/index.cjs +0 -16
  217. package/node_modules/silk-wasm/lib/index.d.ts +0 -70
  218. package/node_modules/silk-wasm/lib/index.mjs +0 -16
  219. package/node_modules/silk-wasm/lib/silk.wasm +0 -0
  220. package/node_modules/silk-wasm/lib/utils.d.ts +0 -4
  221. package/node_modules/silk-wasm/package.json +0 -39
  222. package/node_modules/simple-yenc/.github/FUNDING.yml +0 -1
  223. package/node_modules/simple-yenc/.prettierignore +0 -1
  224. package/node_modules/simple-yenc/LICENSE +0 -7
  225. package/node_modules/simple-yenc/README.md +0 -163
  226. package/node_modules/simple-yenc/dist/esm.js +0 -1
  227. package/node_modules/simple-yenc/dist/index.js +0 -1
  228. package/node_modules/simple-yenc/package.json +0 -50
  229. package/node_modules/simple-yenc/rollup.config.js +0 -27
  230. package/node_modules/simple-yenc/src/simple-yenc.js +0 -302
  231. package/node_modules/ws/LICENSE +0 -20
  232. package/node_modules/ws/README.md +0 -548
  233. package/node_modules/ws/browser.js +0 -8
  234. package/node_modules/ws/index.js +0 -13
  235. package/node_modules/ws/lib/buffer-util.js +0 -131
  236. package/node_modules/ws/lib/constants.js +0 -19
  237. package/node_modules/ws/lib/event-target.js +0 -292
  238. package/node_modules/ws/lib/extension.js +0 -203
  239. package/node_modules/ws/lib/limiter.js +0 -55
  240. package/node_modules/ws/lib/permessage-deflate.js +0 -528
  241. package/node_modules/ws/lib/receiver.js +0 -706
  242. package/node_modules/ws/lib/sender.js +0 -602
  243. package/node_modules/ws/lib/stream.js +0 -161
  244. package/node_modules/ws/lib/subprotocol.js +0 -62
  245. package/node_modules/ws/lib/validation.js +0 -152
  246. package/node_modules/ws/lib/websocket-server.js +0 -554
  247. package/node_modules/ws/lib/websocket.js +0 -1393
  248. package/node_modules/ws/package.json +0 -69
  249. package/node_modules/ws/wrapper.mjs +0 -8
  250. package/scripts/postinstall-link-sdk.js +0 -126
  251. package/skills/qqbot-media/SKILL.md +0 -60
  252. package/src/admin-resolver.ts +0 -181
  253. package/src/api.ts +0 -1319
  254. package/src/credential-backup.ts +0 -72
  255. package/src/deliver-debounce.ts +0 -229
  256. package/src/gateway.ts +0 -2304
  257. package/src/group-history.ts +0 -328
  258. package/src/image-server.ts +0 -675
  259. package/src/inbound-attachments.ts +0 -321
  260. package/src/known-users.ts +0 -353
  261. package/src/message-gating.ts +0 -190
  262. package/src/message-queue.ts +0 -354
  263. package/src/onboarding.ts +0 -274
  264. package/src/outbound-deliver.ts +0 -486
  265. package/src/outbound.ts +0 -1179
  266. package/src/ref-index-store.ts +0 -412
  267. package/src/reply-dispatcher.ts +0 -334
  268. package/src/session-store.ts +0 -303
  269. package/src/slash-commands.ts +0 -2297
  270. package/src/startup-greeting.ts +0 -120
  271. package/src/streaming.ts +0 -1077
  272. package/src/stt.ts +0 -86
  273. package/src/tools/channel.ts +0 -281
  274. package/src/typing-keepalive.ts +0 -59
  275. package/src/utils/audio-convert.ts +0 -859
  276. package/src/utils/chunked-upload.ts +0 -483
  277. package/src/utils/file-utils.ts +0 -193
  278. package/src/utils/image-size.ts +0 -266
  279. package/src/utils/media-send.ts +0 -636
  280. package/src/utils/media-tags.ts +0 -183
  281. package/src/utils/payload.ts +0 -265
  282. package/src/utils/text-parsing.ts +0 -85
  283. package/src/utils/upload-cache.ts +0 -128
@@ -0,0 +1,890 @@
1
+ import { PluginRuntime, ChannelOnboardingAdapter, OpenClawConfig, GroupPolicy as GroupPolicy$1, OpenClawPluginApi } from 'openclaw/plugin-sdk';
2
+ import { ChannelPlugin } from 'openclaw/plugin-sdk/core';
3
+ import { QQBot, ReplyTarget, MessageResponse, MediaFileType, StreamSession, MiddlewareContext, QQBotInboundMessage, RefIndexStore, RefEntry } from '@tencent-connect/qqbot-nodejs';
4
+
5
+ /** 普通文本消息 */
6
+ declare const MSG_TYPE_TEXT = 0;
7
+ /** 引用(回复)消息 */
8
+ declare const MSG_TYPE_QUOTE = 103;
9
+ /**
10
+ * QQ Bot 配置类型
11
+ */
12
+ interface QQBotConfig {
13
+ appId: string;
14
+ clientSecret?: string;
15
+ clientSecretFile?: string;
16
+ }
17
+ /**
18
+ * 解析后的 QQ Bot 账户
19
+ */
20
+ interface ResolvedQQBotAccount {
21
+ accountId: string;
22
+ name?: string;
23
+ enabled: boolean;
24
+ appId: string;
25
+ clientSecret: string;
26
+ secretSource: "config" | "file" | "env" | "none";
27
+ /** 系统提示词 */
28
+ systemPrompt?: string;
29
+ /** 是否支持 markdown 消息(默认 true) */
30
+ markdownSupport: boolean;
31
+ /** User-Agent 尾部追加内容 */
32
+ userAgentSuffix: string;
33
+ /**
34
+ * 单条消息最大处理时间(ms)。超时后 concurrencyGuard 会 abort 处理链,
35
+ * 释放锁并排空缓冲消息。0 表示不限制。默认 0(不限制)。
36
+ */
37
+ processingTimeoutMs: number;
38
+ config: QQBotAccountConfig;
39
+ }
40
+ /** 群消息策略:open=全响应 | allowlist=白名单 | disabled=不响应 */
41
+ type GroupPolicy = "open" | "allowlist" | "disabled";
42
+ /** 工具策略:full=全部 | restricted=限制敏感工具 | none=禁止 */
43
+ type ToolPolicy = "full" | "restricted" | "none";
44
+ /** 单个群的配置 */
45
+ interface GroupConfig {
46
+ /** 是否需要 @机器人才响应(默认 true) */
47
+ requireMention?: boolean;
48
+ /**
49
+ * 是否忽略 @了其他用户但没有 @机器人的消息(默认 false)。
50
+ * 开启后,消息中 @了其他人但未 @bot 时直接丢弃(不记录历史、不触发 AI)。
51
+ */
52
+ ignoreOtherMentions?: boolean;
53
+ /** 群聊中 AI 可使用的工具范围(默认 restricted) */
54
+ toolPolicy?: ToolPolicy;
55
+ /** 群名称 */
56
+ name?: string;
57
+ /** 群消息行为 PE(未配置时使用内置默认值) */
58
+ prompt?: string;
59
+ /** 群历史消息缓存条数(0 禁用,默认 20) */
60
+ historyLimit?: number;
61
+ }
62
+ /** 消息接收传输方式 */
63
+ type TransportMode = "websocket" | "webhook";
64
+ /** Webhook 传输配置 */
65
+ interface WebhookTransportConfig {
66
+ /** 监听路径(默认 /qqbot/webhook) */
67
+ path?: string;
68
+ }
69
+ /**
70
+ * QQ Bot 账户配置
71
+ */
72
+ interface QQBotAccountConfig {
73
+ enabled?: boolean;
74
+ name?: string;
75
+ appId?: string;
76
+ clientSecret?: string;
77
+ clientSecretFile?: string;
78
+ dmPolicy?: "open" | "pairing" | "allowlist" | "disabled";
79
+ allowFrom?: string[];
80
+ /** 消息接收传输方式:websocket(默认)| webhook */
81
+ transport?: TransportMode;
82
+ /** webhook 传输配置(transport="webhook" 时生效) */
83
+ webhook?: WebhookTransportConfig;
84
+ /** 群消息策略(默认 allowlist) */
85
+ groupPolicy?: GroupPolicy;
86
+ /** 群白名单(groupPolicy 为 allowlist 时生效) */
87
+ groupAllowFrom?: string[];
88
+ /** 群配置映射(按 groupOpenid 索引,"*" 为默认) */
89
+ groups?: Record<string, GroupConfig>;
90
+ /** 系统提示词,会添加在用户消息前面 */
91
+ systemPrompt?: string;
92
+ /** 是否支持 markdown 消息(默认 true,设为 false 可禁用) */
93
+ markdownSupport?: boolean;
94
+ /**
95
+ * @deprecated 请使用 audioFormatPolicy.uploadDirectFormats
96
+ * 可直接上传的音频格式(不转换为 SILK),向后兼容
97
+ */
98
+ voiceDirectUploadFormats?: string[];
99
+ /**
100
+ * 音频格式策略配置
101
+ * 统一管理入站(STT)和出站(上传)的音频格式转换行为
102
+ */
103
+ audioFormatPolicy?: AudioFormatPolicy;
104
+ /**
105
+ * 是否启用公网 URL 直传 QQ 平台(默认 true)
106
+ * 启用时:公网 URL 先直传给 QQ 开放平台的富媒体 API,平台自行拉取;失败后自动 fallback 到插件下载再 Base64 上传
107
+ * 禁用时:公网 URL 始终由插件先下载到本地,再以 Base64 上传(适用于 QQ 平台无法访问目标 URL 的场景)
108
+ */
109
+ urlDirectUpload?: boolean;
110
+ /**
111
+ * /bot-upgrade 指令返回的升级指引网址
112
+ * 默认: https://doc.weixin.qq.com/doc/w3_AKEAGQaeACgCNHrh1CbHzTAKtT2gB?scode=AJEAIQdfAAozxFEnLZAKEAGQaeACg
113
+ */
114
+ upgradeUrl?: string;
115
+ /**
116
+ * /bot-upgrade 指令的行为模式
117
+ * - "doc":展示升级文档链接(安全模式)
118
+ * - "hot-reload":检测到新版本时直接执行 npm 升级脚本进行热更新(默认)
119
+ */
120
+ upgradeMode?: "doc" | "hot-reload";
121
+ /**
122
+ * /bot-upgrade 热更新时使用的 npm 包名
123
+ * 支持 "scope/name"(自动补 @)或 "@scope/name" 格式
124
+ * 默认: "@tencent-connect/openclaw-qqbot"
125
+ * 示例: "ryantest/openclaw-qqbot"
126
+ */
127
+ upgradePkg?: string;
128
+ /**
129
+ * 群消息是否默认需要 @机器人才响应(默认 true)
130
+ * 优先级低于 groups.{groupId}.requireMention 和 groups."*".requireMention
131
+ * 设为 false 时,所有群默认无需 @ 即触发回复(仍可被群级配置覆盖)
132
+ */
133
+ defaultRequireMention?: boolean;
134
+ /**
135
+ * 出站消息合并回复(debounce)配置
136
+ * 当短时间内收到多次 deliver 时,将文本合并为一条消息发送,避免消息轰炸
137
+ */
138
+ deliverDebounce?: DeliverDebounceConfig;
139
+ /**
140
+ * 是否启用流式消息(默认 false)
141
+ * 启用后,AI 的回复会以流式形式逐步显示在 QQ 聊天中,
142
+ * 用户可以看到文字逐字出现的打字机效果。
143
+ *
144
+ * 兼容布尔值和对象格式,对齐框架 schema:
145
+ * - true / false 旧版布尔格式(自动转换为对象)
146
+ * - { mode: "partial" } 开启(对齐 StreamingMode.partial)
147
+ * - { mode: "off" } 关闭
148
+ *
149
+ * 注意:仅 C2C(私聊)支持流式消息 API。
150
+ */
151
+ streaming?: boolean | {
152
+ mode: 'partial' | 'off';
153
+ };
154
+ /**
155
+ * STT (语音转文字) 配置
156
+ * 配置后,收到语音消息时会自动调用 STT 服务转录为文字
157
+ */
158
+ stt?: STTChannelConfig;
159
+ /**
160
+ * 单条消息最大处理时间(毫秒)。
161
+ * 超时后 concurrencyGuard 会 abort 处理链(取消 LLM 调用、工具执行等),
162
+ * 释放并发锁并排空缓冲消息。
163
+ *
164
+ * 设为 0 表示不限制超时。默认 0(不限制)。
165
+ *
166
+ * 可通过环境变量 OPENCLAW_PROCESSING_TIMEOUT_MS 覆盖全局默认值,
167
+ * 账户级配置优先级高于环境变量。
168
+ */
169
+ processingTimeoutMs?: number;
170
+ /**
171
+ * User-Agent 尾部追加内容(用于私有化部署标识等场景)
172
+ * 追加在 `QQBotPlugin/{version} (Node/{nodeVersion}; {os}; OpenClaw/{version})` 之后
173
+ */
174
+ userAgentSuffix?: string;
175
+ }
176
+ /**
177
+ * 出站消息合并回复配置
178
+ */
179
+ interface DeliverDebounceConfig {
180
+ /**
181
+ * 是否启用合并回复(默认 true)
182
+ */
183
+ enabled?: boolean;
184
+ /**
185
+ * 合并窗口时长(毫秒),在此时间内的连续 deliver 会被合并
186
+ * 默认 1500ms
187
+ */
188
+ windowMs?: number;
189
+ /**
190
+ * 最大等待时长(毫秒),从第一条 deliver 开始计算,超过此时间强制发送
191
+ * 防止持续有新 deliver 导致一直不发送
192
+ * 默认 8000ms
193
+ */
194
+ maxWaitMs?: number;
195
+ /**
196
+ * 合并文本之间的分隔符
197
+ * 默认 "\n\n---\n\n"
198
+ */
199
+ separator?: string;
200
+ }
201
+ /**
202
+ * 音频格式策略:控制哪些格式可跳过转换
203
+ */
204
+ interface AudioFormatPolicy {
205
+ /**
206
+ * STT 模型直接支持的音频格式(入站:跳过 SILK→WAV 转换)
207
+ * 如果 STT 服务支持直接处理某些格式(如 silk/amr),可将其加入此列表
208
+ * 例如: [".silk", ".amr", ".wav", ".mp3", ".ogg"]
209
+ * 默认为空(所有语音都先转换为 WAV 再送 STT)
210
+ */
211
+ sttDirectFormats?: string[];
212
+ /**
213
+ * QQ 平台支持直传的音频格式(出站:跳过→SILK 转换)
214
+ * 默认为 [".wav", ".mp3", ".silk"](QQ Bot API 原生支持的三种格式)
215
+ * 仅当需要覆盖默认值时才配置此项
216
+ */
217
+ uploadDirectFormats?: string[];
218
+ /**
219
+ * 是否启用语音转码(默认 true)
220
+ * 设为 false 可在环境无 ffmpeg 时跳过转码,直接以文件形式发送
221
+ * 当禁用时,非原生格式的音频会 fallback 到 sendDocument(文件发送)
222
+ */
223
+ transcodeEnabled?: boolean;
224
+ }
225
+ /**
226
+ * STT (语音转文字) 配置
227
+ */
228
+ interface STTChannelConfig {
229
+ /** 是否启用 STT(默认 true,配置了 baseUrl+apiKey 即自动启用) */
230
+ enabled?: boolean;
231
+ /** STT 服务提供商 ID(对应 models.providers 中的 key,默认 "openai") */
232
+ provider?: string;
233
+ /** STT API 地址(如 https://api.openai.com/v1) */
234
+ baseUrl?: string;
235
+ /** STT API 密钥 */
236
+ apiKey?: string;
237
+ /** STT 模型名称(默认 "whisper-1") */
238
+ model?: string;
239
+ }
240
+ /**
241
+ * 富媒体附件
242
+ */
243
+ interface MessageAttachment {
244
+ content_type: string;
245
+ filename?: string;
246
+ height?: number;
247
+ width?: number;
248
+ size?: number;
249
+ url: string;
250
+ voice_wav_url?: string;
251
+ asr_refer_text?: string;
252
+ }
253
+ /**
254
+ * C2C 消息事件
255
+ */
256
+ interface C2CMessageEvent {
257
+ author: {
258
+ id: string;
259
+ union_openid: string;
260
+ user_openid: string;
261
+ };
262
+ content: string;
263
+ id: string;
264
+ timestamp: string;
265
+ message_scene?: {
266
+ source: string;
267
+ /** ext 数组,可能包含 ref_msg_idx=REFIDX_xxx(引用的消息)和 msg_idx=REFIDX_xxx(自身索引) */
268
+ ext?: string[];
269
+ };
270
+ attachments?: MessageAttachment[];
271
+ /** 消息类型,参见 MSG_TYPE_* */
272
+ message_type?: number;
273
+ /** 消息元素列表,引用消息时 [0] 为被引用的原始消息 */
274
+ msg_elements?: MsgElement[];
275
+ }
276
+ /**
277
+ * 频道 AT 消息事件
278
+ */
279
+ interface GuildMessageEvent {
280
+ id: string;
281
+ channel_id: string;
282
+ guild_id: string;
283
+ content: string;
284
+ timestamp: string;
285
+ author: {
286
+ id: string;
287
+ username?: string;
288
+ bot?: boolean;
289
+ };
290
+ member?: {
291
+ nick?: string;
292
+ joined_at?: string;
293
+ };
294
+ attachments?: MessageAttachment[];
295
+ }
296
+ /** 消息元素结点,引用消息时 msg_elements[0] 为被引用的原始消息 */
297
+ interface MsgElement {
298
+ /** 消息索引标识 */
299
+ msg_idx?: string;
300
+ /** 消息类型,参见 MSG_TYPE_* 常量 */
301
+ message_type?: number;
302
+ /** 文本内容 */
303
+ content?: string;
304
+ /** 附件列表 */
305
+ attachments?: MessageAttachment[];
306
+ /** 嵌套消息元素(引用消息场景下可能存在) */
307
+ msg_elements?: MsgElement[];
308
+ }
309
+ /**
310
+ * 群聊 AT 消息事件
311
+ */
312
+ interface GroupMessageEvent {
313
+ author: {
314
+ id: string;
315
+ member_openid: string;
316
+ username?: string;
317
+ bot?: boolean;
318
+ };
319
+ content: string;
320
+ id: string;
321
+ timestamp: string;
322
+ group_id: string;
323
+ group_openid: string;
324
+ message_scene?: {
325
+ source: string;
326
+ ext?: string[];
327
+ };
328
+ attachments?: MessageAttachment[];
329
+ /** @提及列表 */
330
+ mentions?: Array<{
331
+ scope?: "all" | "single";
332
+ id?: string;
333
+ user_openid?: string;
334
+ member_openid?: string;
335
+ nickname?: string;
336
+ bot?: boolean;
337
+ /** 是否 @机器人自身 */
338
+ is_you?: boolean;
339
+ }>;
340
+ /** 消息类型,参见 MSG_TYPE_* */
341
+ message_type?: number;
342
+ /** 消息元素列表,引用消息时 [0] 为被引用的原始消息 */
343
+ msg_elements?: MsgElement[];
344
+ }
345
+ /**
346
+ * 按钮交互事件(INTERACTION_CREATE)
347
+ */
348
+ interface InteractionEvent {
349
+ /** 事件 ID,用于回应交互(PUT /interactions/{id}) */
350
+ id: string;
351
+ /** 事件类型:11=消息按钮 12=单聊快捷菜单 */
352
+ type: number;
353
+ /** 场景:c2c / group / guild */
354
+ scene?: string;
355
+ /** 场景类型:0=频道 1=群聊 2=单聊 */
356
+ chat_type?: number;
357
+ /** 触发时间 RFC3339 */
358
+ timestamp?: string;
359
+ /** 频道 openid(仅频道场景) */
360
+ guild_id?: string;
361
+ /** 子频道 openid(仅频道场景) */
362
+ channel_id?: string;
363
+ /** 单聊用户 openid(仅 c2c 场景) */
364
+ user_openid?: string;
365
+ /** 群 openid(仅群聊场景) */
366
+ group_openid?: string;
367
+ /** 群内触发用户 openid(仅群聊场景) */
368
+ group_member_openid?: string;
369
+ version: number;
370
+ data: {
371
+ type: number;
372
+ resolved: {
373
+ /** 按钮 action.data 值 */
374
+ button_data?: string;
375
+ /** 按钮 id */
376
+ button_id?: string;
377
+ /** 操作用户 userid(仅频道场景) */
378
+ user_id?: string;
379
+ /** 自定义菜单 id(仅菜单场景) */
380
+ feature_id?: string;
381
+ /** 操作的消息 id(仅频道场景) */
382
+ message_id?: string;
383
+ /** 配置更新:群消息模式 "mention"=@机器人时激活 "always"=总是激活 */
384
+ require_mention?: string;
385
+ /** 配置更新:群消息策略 */
386
+ group_policy?: GroupPolicy;
387
+ /** 配置更新:@文本的名称提及BOT名,多个使用,分隔 */
388
+ mention_patterns?: string;
389
+ };
390
+ };
391
+ }
392
+ /**
393
+ * 按钮 Action 类型
394
+ * 0=跳转链接 1=回调型(INTERACTION_CREATE) 2=指令型(直接发文本) 3=mqqapi
395
+ */
396
+ type KeyboardActionType = 0 | 1 | 2 | 3;
397
+ /** 按钮权限 */
398
+ interface KeyboardPermission {
399
+ /** 0=全体 1=管理员 2=按钮指定 3=身份组 */
400
+ type: 0 | 1 | 2 | 3;
401
+ specify_role_ids?: string[];
402
+ specify_user_ids?: string[];
403
+ }
404
+ /** 二次确认弹窗 */
405
+ interface KeyboardModal {
406
+ content: string;
407
+ confirm_text?: string;
408
+ cancel_text?: string;
409
+ }
410
+ /** 按钮 Action */
411
+ interface KeyboardAction {
412
+ type: KeyboardActionType;
413
+ data?: string;
414
+ /** true = 点击后直接发出(Enter)*/
415
+ enter?: boolean;
416
+ /** 仅指令型(type=2):是否把指令发到输入框(reply=true)还是静默发出 */
417
+ reply?: boolean;
418
+ permission?: KeyboardPermission;
419
+ click_limit?: number;
420
+ unsupport_tips?: string;
421
+ modal?: KeyboardModal;
422
+ }
423
+ /** 按钮渲染数据 */
424
+ interface KeyboardRenderData {
425
+ label: string;
426
+ visited_label?: string;
427
+ /** 0=灰色线框 1=蓝色线框 2=推荐回复专用 3=红色字体 4=蓝色背景 */
428
+ style?: 0 | 1 | 2 | 3 | 4;
429
+ }
430
+ /** 单个按钮 */
431
+ interface KeyboardButton {
432
+ id: string;
433
+ render_data?: KeyboardRenderData;
434
+ action?: KeyboardAction;
435
+ group_id?: string;
436
+ }
437
+ /** 一行按钮 */
438
+ interface KeyboardRow {
439
+ buttons: KeyboardButton[];
440
+ }
441
+ /** CustomKeyboard(自定义按钮内容) */
442
+ interface CustomKeyboard {
443
+ rows: KeyboardRow[];
444
+ }
445
+ /** MessageKeyboard(keyboard / prompt_keyboard.keyboard 共用) */
446
+ interface MessageKeyboard {
447
+ /** 模板 ID(与 content 二选一) */
448
+ id?: string;
449
+ /** 自定义内容 */
450
+ content?: CustomKeyboard;
451
+ }
452
+ /**
453
+ * Inline Keyboard(消息内嵌按钮,需平台审核)
454
+ * 发送字段:keyboard
455
+ * JSON: { "keyboard": { "id": "...", "content": { "rows": [...] } } }
456
+ */
457
+ type InlineKeyboard = MessageKeyboard;
458
+ /**
459
+ * WebSocket 事件负载
460
+ */
461
+ interface WSPayload {
462
+ op: number;
463
+ d?: unknown;
464
+ s?: number;
465
+ t?: string;
466
+ }
467
+ /** 流式消息输入模式 */
468
+ declare const StreamInputMode: {
469
+ /** 每次发送的 content_raw 替换整条消息内容 */
470
+ readonly REPLACE: "replace";
471
+ };
472
+ type StreamInputMode = (typeof StreamInputMode)[keyof typeof StreamInputMode];
473
+ /** 流式消息输入状态 */
474
+ declare const StreamInputState: {
475
+ /** 正文生成中 */
476
+ readonly GENERATING: 1;
477
+ /** 正文生成结束(终结状态) */
478
+ readonly DONE: 10;
479
+ };
480
+ type StreamInputState = (typeof StreamInputState)[keyof typeof StreamInputState];
481
+ /** 流式消息内容类型 */
482
+ declare const StreamContentType: {
483
+ readonly MARKDOWN: "markdown";
484
+ };
485
+ type StreamContentType = (typeof StreamContentType)[keyof typeof StreamContentType];
486
+ /**
487
+ * 流式消息请求体
488
+ * 对应 StreamReq proto
489
+ */
490
+ interface StreamMessageRequest {
491
+ /** 输入模式 */
492
+ input_mode: StreamInputMode;
493
+ /** 输入状态 */
494
+ input_state: StreamInputState;
495
+ /** 内容类型 */
496
+ content_type: StreamContentType;
497
+ /** markdown 内容 */
498
+ content_raw: string;
499
+ /** 事件 ID */
500
+ event_id: string;
501
+ /** 原始消息 ID */
502
+ msg_id: string;
503
+ /** 流式消息 ID,首次发送后返回,后续分片需携带 */
504
+ stream_msg_id?: string;
505
+ /** 递增序号 */
506
+ msg_seq: number;
507
+ /** 同一条流式会话内的发送索引,从 0 开始,每次发送前递增;新流式会话重新从 0 开始 */
508
+ index: number;
509
+ }
510
+
511
+ /**
512
+ * QQ Bot ChannelPlugin 定义
513
+ *
514
+ * 薄壳编排层 — 实现 OpenClaw ChannelPlugin 接口,
515
+ * 将各子模块(gateway/outbound/config/features)连接为完整通道插件。
516
+ */
517
+
518
+ declare const qqbotPlugin: ChannelPlugin<ResolvedQQBotAccount>;
519
+
520
+ /**
521
+ * QQBot 插件运行时管理。
522
+ *
523
+ * 日志统一由 `utils/plugin-logger.ts` 提供,此处只管理 runtime 实例。
524
+ */
525
+
526
+ declare function setQQBotRuntime(next: PluginRuntime): void;
527
+ declare function getQQBotRuntime(): PluginRuntime;
528
+
529
+ declare function buildUserAgent(suffix?: string): string;
530
+ /**
531
+ * 获取指定账户的 QQBot SDK 实例。
532
+ *
533
+ * @throws 如果该账户的 gateway 尚未启动
534
+ *
535
+ * @example
536
+ * ```ts
537
+ * const bot = getBotForAccount(accountId);
538
+ * await bot.send({ target, content: 'hello' });
539
+ * const guilds = await bot.api.get('/users/@me/guilds');
540
+ * const token = await bot.api.getToken();
541
+ * ```
542
+ */
543
+ declare function getBotForAccount(accountId: string): QQBot;
544
+ /**
545
+ * 尝试获取指定账户的 QQBot SDK 实例(不抛异常)。
546
+ * 返回 null 表示 gateway 尚未启动。
547
+ */
548
+ declare function tryGetBotForAccount(accountId: string): QQBot | null;
549
+
550
+ /**
551
+ * QQBot CLI Onboarding Adapter
552
+ *
553
+ * 提供 openclaw onboard 命令的交互式配置支持。
554
+ * 从原 src/onboarding.ts 迁移,保持接口兼容。
555
+ */
556
+
557
+ /**
558
+ * Onboarding adapter — 导出给 ChannelPlugin 使用
559
+ *
560
+ * 注:完整 onboarding 交互逻辑较复杂(约 300 行),
561
+ * 此处仅保留 adapter 骨架,完整实现从原文件迁移。
562
+ */
563
+ declare const qqbotOnboardingAdapter: ChannelOnboardingAdapter;
564
+
565
+ /**
566
+ * PluginLogger — 统一日志接口
567
+ *
568
+ * 默认后端为 OpenClaw 框架 logger(`runtime.logging.getChildLogger`),
569
+ * 运行时不可用时临时降级 console,就绪后自动切换缓存。
570
+ */
571
+ interface PluginLogger {
572
+ info(msg: string, meta?: Record<string, unknown>): void;
573
+ warn(msg: string, meta?: Record<string, unknown>): void;
574
+ error(msg: string, meta?: Record<string, unknown>): void;
575
+ debug(msg: string, meta?: Record<string, unknown>): void;
576
+ child(tag: string): PluginLogger;
577
+ }
578
+
579
+ /**
580
+ * QQBotGateway — 封装单个 Bot 实例的完整生命周期
581
+ */
582
+
583
+ interface GatewayCallbacks {
584
+ onReady?: () => void;
585
+ onError?: (error: Error) => void;
586
+ }
587
+ interface SendOptions {
588
+ msgId?: string;
589
+ text?: string;
590
+ }
591
+ declare class QQBotGateway {
592
+ readonly bot: QQBot;
593
+ private readonly account;
594
+ private readonly runtime;
595
+ readonly log: PluginLogger;
596
+ private readonly textTimeout;
597
+ private readonly mediaTimeout;
598
+ constructor(account: ResolvedQQBotAccount, runtime: PluginRuntime, log?: PluginLogger);
599
+ start(callbacks?: GatewayCallbacks, signal?: AbortSignal): Promise<void>;
600
+ stop(): Promise<void>;
601
+ sendText(target: ReplyTarget, text: string, opts?: SendOptions): Promise<MessageResponse>;
602
+ sendMedia(target: ReplyTarget, source: string, opts?: SendOptions & {
603
+ fileType?: MediaFileType;
604
+ }): Promise<MessageResponse>;
605
+ sendVoice(target: ReplyTarget, source: {
606
+ url?: string;
607
+ base64?: string;
608
+ localPath?: string;
609
+ }, opts?: SendOptions): Promise<MessageResponse>;
610
+ sendVideo(target: ReplyTarget, source: string, opts?: SendOptions): Promise<MessageResponse>;
611
+ sendFile(target: ReplyTarget, source: string, opts?: SendOptions & {
612
+ fileName?: string;
613
+ }): Promise<MessageResponse>;
614
+ openStream(target: ReplyTarget, msgId: string): StreamSession;
615
+ sendTyping(target: ReplyTarget): Promise<void>;
616
+ private wrapBotSendForRefIndex;
617
+ }
618
+
619
+ type MediaKind = 'image' | 'voice' | 'video' | 'file';
620
+ interface SendResult {
621
+ messageId?: string;
622
+ error?: string;
623
+ errorCode?: string;
624
+ qqBizCode?: number;
625
+ }
626
+ declare function sendText(params: {
627
+ to: string;
628
+ text: string;
629
+ accountId?: string;
630
+ replyToId?: string;
631
+ account: ResolvedQQBotAccount;
632
+ }): Promise<SendResult>;
633
+ declare function sendMedia(params: {
634
+ to: string;
635
+ text?: string;
636
+ mediaUrl: string;
637
+ mediaKind?: MediaKind;
638
+ accountId?: string;
639
+ replyToId?: string;
640
+ account: ResolvedQQBotAccount;
641
+ }): Promise<SendResult>;
642
+
643
+ /**
644
+ * 出站目标地址解析
645
+ *
646
+ * 将 OpenClaw 规范的目标地址字符串(如 qqbot:c2c:xxx / qqbot:group:xxx)
647
+ * 转换为 SDK 的 ReplyTarget 结构。
648
+ *
649
+ * 也导出共享的正则常量供 channel.ts messaging 段复用。
650
+ */
651
+
652
+ /**
653
+ * 解析目标地址字符串为 SDK ReplyTarget
654
+ */
655
+ declare function parseTarget(to: string): ReplyTarget;
656
+
657
+ /**
658
+ * 消息转发 — 入站消息 → OpenClaw AI
659
+ *
660
+ * 核心职责:
661
+ * 1. 从 SDK MiddlewareContext 构建 OpenClaw 标准信封
662
+ * 2. 通过 runtime-adapter 将消息交给 AI 处理
663
+ *
664
+ * 架构说明:
665
+ * - 所有 runtime.channel.* 访问均通过 runtime-adapter 隔离
666
+ * - log: 前缀由 PluginLogger + 框架自动注入,消息体不重复 accountId
667
+ */
668
+
669
+ /**
670
+ * 将经过中间件处理的入站消息转发给 OpenClaw AI
671
+ */
672
+ declare function dispatchToOpenClaw(ctx: MiddlewareContext, msg: QQBotInboundMessage, account: ResolvedQQBotAccount, runtime: PluginRuntime, log?: PluginLogger): Promise<void>;
673
+
674
+ /**
675
+ * 持久化 RefIndex 存储
676
+ *
677
+ * SDK 提供的 MemoryRefIndexStore 在进程重启后即丢失,
678
+ * 而 QQ 引用消息(REFIDX_xxx)入站事件只携带 key,必须本地缓存才能回查。
679
+ *
680
+ * 设计:
681
+ * - 内存 LRU(与 SDK 同款)保证 O(1) 读取
682
+ * - JSONL 追加写持久化,进程重启时按时间顺序回放重建 LRU
683
+ * - 写入触发 compact 阈值时重写文件(去重 + 截断到 maxEntries)
684
+ * - 文件路径: ~/.openclaw/qqbot/data/ref-index.jsonl
685
+ *
686
+ * 实现 SDK 的 RefIndexStore 接口,可直接通过 `quoteRef({ store })` 注入。
687
+ */
688
+
689
+ interface PersistedRefIndexStoreOptions {
690
+ /** 内存与磁盘的最大条目数。默认 2000。 */
691
+ maxEntries?: number;
692
+ /** 自定义存储文件路径。默认 ~/.openclaw/qqbot/data/ref-index.jsonl */
693
+ filePath?: string;
694
+ }
695
+ /**
696
+ * 持久化版本的 RefIndexStore
697
+ *
698
+ * - get:仅查内存(启动时从磁盘回放重建)
699
+ * - set:内存 + JSONL 追加写;磁盘行数过多时触发 compact
700
+ */
701
+ declare class PersistedRefIndexStore implements RefIndexStore {
702
+ private readonly memory;
703
+ private readonly maxEntries;
704
+ private readonly filePath;
705
+ /** 当前磁盘累计写入的行数(用于 compact 阈值判断) */
706
+ private diskLineCount;
707
+ /** 是否已成功初始化(磁盘回放完成) */
708
+ private initialized;
709
+ /** 串行化写入,防止并发 append 撕裂行 */
710
+ private writeChain;
711
+ constructor(options?: PersistedRefIndexStoreOptions);
712
+ /**
713
+ * 初始化:按时间顺序回放 JSONL 重建内存 LRU
714
+ */
715
+ private init;
716
+ get(key: string): RefEntry | undefined;
717
+ set(key: string, entry: RefEntry): void;
718
+ private touchMemory;
719
+ private appendToDisk;
720
+ /**
721
+ * 异步 compact:将内存 LRU 状态完整重写到磁盘,丢弃历史冗余。
722
+ */
723
+ private compact;
724
+ /**
725
+ * 同步 compact(仅 init 阶段使用,避免回放后立刻保留巨大磁盘文件)
726
+ */
727
+ private compactSync;
728
+ /** 当前内存中的条目数 */
729
+ get size(): number;
730
+ /** 是否已完成初始化(磁盘回放) */
731
+ get isInitialized(): boolean;
732
+ /** 诊断快照 */
733
+ stats(): {
734
+ memoryEntries: number;
735
+ diskLines: number;
736
+ maxEntries: number;
737
+ filePath: string;
738
+ };
739
+ /**
740
+ * 强制将当前内存状态持久化到磁盘(进程退出前调用)
741
+ */
742
+ flush(): void;
743
+ }
744
+ /**
745
+ * 获取按 accountId 隔离的持久化 RefIndexStore 单例。
746
+ *
747
+ * 每个账户独立存储文件,避免多账户混用同一个 refIdx 命名空间。
748
+ */
749
+ declare function getPersistedRefIndexStore(accountId: string): PersistedRefIndexStore;
750
+ /**
751
+ * 进程退出前 flush 所有 store
752
+ */
753
+ declare function flushAllRefIndexStores(): void;
754
+
755
+ /**
756
+ * QQ Bot 流式消息控制器
757
+ *
758
+ * 核心约束:QQ 流式 API 替换模式下,已下发文本的**前缀不可变更**。
759
+ *
760
+ * 状态机:
761
+ * IDLE → (first chunk) → STREAMING → (complete) → DONE
762
+ * → (prefix changed) → DONE
763
+ * → (new reply) → IDLE → …
764
+ *
765
+ * onPartialReply(text) 输入:模型全量文本,持续增长。
766
+ * finalize() 标记:框架通知回复结束,用 lastAccepted 收尾。
767
+ */
768
+
769
+ type StreamingPhase = 'idle' | 'streaming' | 'done' | 'failed';
770
+ interface StreamingControllerDeps {
771
+ gateway: QQBotGateway;
772
+ target: ReplyTarget;
773
+ accountId: string;
774
+ replyToId: string;
775
+ log?: PluginLogger;
776
+ }
777
+ declare class StreamingController {
778
+ private readonly deps;
779
+ private phase;
780
+ private session;
781
+ /** QQ 已接受的最新文本 — 单源真理 */
782
+ private lastAcceptedFull;
783
+ /** 已成功发送的分片数(降级:=0 则走静态消息兜底) */
784
+ private sentChunkCount;
785
+ /** 同步标志:收到第一个 onPartialReply 即置 true(不等 async 完成) */
786
+ private _hasStarted;
787
+ /** 串行队列 */
788
+ private chain;
789
+ constructor(deps: StreamingControllerDeps);
790
+ get currentPhase(): StreamingPhase;
791
+ /** 是否已成功发送至少一个流式分片 */
792
+ get hasSentChunks(): boolean;
793
+ /** 同步标志:流式已启动(不等异步完成),用于 final 去重 */
794
+ get hasStarted(): boolean;
795
+ get isTerminal(): boolean;
796
+ get shouldFallbackToStatic(): boolean;
797
+ onPartialReply(text: string): Promise<void>;
798
+ finalize(): Promise<void>;
799
+ abort(reason?: string): Promise<void>;
800
+ private handleChunk;
801
+ private handleFinalize;
802
+ private sendUpdate;
803
+ private completeSession;
804
+ private transition;
805
+ }
806
+
807
+ declare function shouldUseStreaming(account: ResolvedQQBotAccount, targetScope: 'c2c' | 'group' | 'channel'): boolean;
808
+
809
+ /**
810
+ * 解析 mentionPatterns(agent → global → 空数组)
811
+ *
812
+ * 优先级:
813
+ * 1. agents.list[agentId].groupChat.mentionPatterns
814
+ * 2. messages.groupChat.mentionPatterns
815
+ * 3. []
816
+ */
817
+ declare function resolveMentionPatterns(cfg: OpenClawConfig, agentId?: string): string[];
818
+ declare const DEFAULT_ACCOUNT_ID = "default";
819
+ /** 解析群消息策略 */
820
+ declare function resolveGroupPolicy(cfg: OpenClawConfig, accountId?: string): GroupPolicy$1;
821
+ /** 解析群白名单(统一转大写) */
822
+ declare function resolveGroupAllowFrom(cfg: OpenClawConfig, accountId?: string): string[];
823
+ /** 检查指定群是否被允许(使用标准策略引擎) */
824
+ declare function isGroupAllowed(cfg: OpenClawConfig, groupOpenid: string, accountId?: string): boolean;
825
+ type ResolvedGroupConfig = Required<GroupConfig>;
826
+ declare function resolveGroupConfigFromAccount(account: ResolvedQQBotAccount, groupOpenid: string): ResolvedGroupConfig;
827
+ declare function resolveGroupConfig(cfg: OpenClawConfig, groupOpenid: string, accountId?: string): ResolvedGroupConfig;
828
+ /** 解析群历史消息缓存条数 */
829
+ declare function resolveHistoryLimit(cfg: OpenClawConfig, groupOpenid: string, accountId?: string): number;
830
+ /** 解析群行为 PE(具体群 > "*" > 默认值) */
831
+ declare function resolveGroupPrompt(cfg: OpenClawConfig, groupOpenid: string, accountId?: string): string;
832
+ /** 解析群是否需要 @机器人才响应 */
833
+ declare function resolveRequireMention(cfg: OpenClawConfig, groupOpenid: string, accountId?: string): boolean;
834
+ /** 解析群是否忽略 @了其他人(非 bot)的消息 */
835
+ declare function resolveIgnoreOtherMentions(cfg: OpenClawConfig, groupOpenid: string, accountId?: string): boolean;
836
+ /** 解析群工具策略 */
837
+ declare function resolveToolPolicy(cfg: OpenClawConfig, groupOpenid: string, accountId?: string): ToolPolicy;
838
+ /** 解析群名称(优先配置,fallback 为 openid 前 8 位) */
839
+ declare function resolveGroupName(cfg: OpenClawConfig, groupOpenid: string, accountId?: string): string;
840
+ /**
841
+ * 解析 User-Agent 追加后缀(仅通道级:channels.qqbot.userAgentSuffix)
842
+ */
843
+ declare function resolveUserAgentSuffix(cfg: OpenClawConfig): string;
844
+ /**
845
+ * 列出所有 QQBot 账户 ID
846
+ */
847
+ declare function listQQBotAccountIds(cfg: OpenClawConfig): string[];
848
+ /**
849
+ * 获取默认账户 ID
850
+ */
851
+ declare function resolveDefaultQQBotAccountId(cfg: OpenClawConfig): string;
852
+ /**
853
+ * 解析单条消息处理超时时间(ms)。
854
+ * 优先级:账户配置 > 环境变量 OPENCLAW_PROCESSING_TIMEOUT_MS > 默认
855
+ * 返回 0 表示不限制超时。
856
+ */
857
+ declare function resolveProcessingTimeoutMs(accountConfig?: QQBotAccountConfig): number;
858
+ /**
859
+ * 解析 QQBot 账户配置
860
+ */
861
+ declare function resolveQQBotAccount(cfg: OpenClawConfig, accountId?: string | null): ResolvedQQBotAccount;
862
+ /**
863
+ * 应用账户配置
864
+ */
865
+ declare function applyQQBotAccountConfig(cfg: OpenClawConfig, accountId: string, input: {
866
+ appId?: string;
867
+ clientSecret?: string;
868
+ clientSecretFile?: string;
869
+ name?: string;
870
+ }): OpenClawConfig;
871
+
872
+ /**
873
+ * @tencent-connect/openclaw-qqbot
874
+ *
875
+ * 独立版 QQ Bot 通道插件 — 基于 @tencent-connect/qqbot-nodejs SDK 重构。
876
+ *
877
+ * 直接依赖:
878
+ * - openclaw/plugin-sdk:OpenClaw 插件框架
879
+ * - @tencent-connect/qqbot-nodejs:QQ 开放平台 Node.js SDK
880
+ */
881
+
882
+ declare const plugin: {
883
+ id: string;
884
+ name: string;
885
+ description: string;
886
+ configSchema: unknown;
887
+ register(api: OpenClawPluginApi): void;
888
+ };
889
+
890
+ export { type AudioFormatPolicy, type C2CMessageEvent, type CustomKeyboard, DEFAULT_ACCOUNT_ID, type DeliverDebounceConfig, type GroupConfig, type GroupMessageEvent, type GroupPolicy, type GuildMessageEvent, type InlineKeyboard, type InteractionEvent, type KeyboardAction, type KeyboardActionType, type KeyboardButton, type KeyboardModal, type KeyboardPermission, type KeyboardRenderData, type KeyboardRow, MSG_TYPE_QUOTE, MSG_TYPE_TEXT, type MessageAttachment, type MessageKeyboard, type MsgElement, PersistedRefIndexStore, type QQBotAccountConfig, type QQBotConfig, QQBotGateway, type ResolvedGroupConfig, type ResolvedQQBotAccount, type STTChannelConfig, StreamContentType, StreamInputMode, StreamInputState, type StreamMessageRequest, StreamingController, type ToolPolicy, type TransportMode, type WSPayload, type WebhookTransportConfig, applyQQBotAccountConfig, buildUserAgent, plugin as default, dispatchToOpenClaw, flushAllRefIndexStores, getBotForAccount, getPersistedRefIndexStore, getQQBotRuntime, isGroupAllowed, listQQBotAccountIds, parseTarget, qqbotOnboardingAdapter, qqbotPlugin, resolveDefaultQQBotAccountId, resolveGroupAllowFrom, resolveGroupConfig, resolveGroupConfigFromAccount, resolveGroupName, resolveGroupPolicy, resolveGroupPrompt, resolveHistoryLimit, resolveIgnoreOtherMentions, resolveMentionPatterns, resolveProcessingTimeoutMs, resolveQQBotAccount, resolveRequireMention, resolveToolPolicy, resolveUserAgentSuffix, sendMedia, sendText, setQQBotRuntime, shouldUseStreaming, tryGetBotForAccount };