@tencent-connect/dsh-qqbot 0.3.0 → 0.5.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 (183) hide show
  1. package/.orange-ci.yml +2 -68
  2. package/CHANGELOG.md +45 -0
  3. package/CHANGELOG_EN.md +84 -0
  4. package/README.md +107 -17
  5. package/README_EN.md +107 -17
  6. package/cordis.patch.yml +1 -1
  7. package/cordis.yml +46 -3
  8. package/dist/commands/help.d.ts +6 -7
  9. package/dist/commands/help.d.ts.map +1 -1
  10. package/dist/commands/help.js +23 -7
  11. package/dist/commands/help.js.map +1 -1
  12. package/dist/commands/index.d.ts +7 -5
  13. package/dist/commands/index.d.ts.map +1 -1
  14. package/dist/commands/index.js +12 -12
  15. package/dist/commands/index.js.map +1 -1
  16. package/dist/commands/misc.d.ts +10 -8
  17. package/dist/commands/misc.d.ts.map +1 -1
  18. package/dist/commands/misc.js +45 -8
  19. package/dist/commands/misc.js.map +1 -1
  20. package/dist/commands/model.d.ts +3 -4
  21. package/dist/commands/model.d.ts.map +1 -1
  22. package/dist/commands/model.js +8 -7
  23. package/dist/commands/model.js.map +1 -1
  24. package/dist/commands/preset.d.ts +8 -0
  25. package/dist/commands/preset.d.ts.map +1 -0
  26. package/dist/commands/preset.js +52 -0
  27. package/dist/commands/preset.js.map +1 -0
  28. package/dist/commands/session.d.ts +11 -7
  29. package/dist/commands/session.d.ts.map +1 -1
  30. package/dist/commands/session.js +29 -13
  31. package/dist/commands/session.js.map +1 -1
  32. package/dist/commands/status.d.ts +3 -4
  33. package/dist/commands/status.d.ts.map +1 -1
  34. package/dist/commands/status.js +2 -1
  35. package/dist/commands/status.js.map +1 -1
  36. package/dist/commands/types.d.ts +9 -2
  37. package/dist/commands/types.d.ts.map +1 -1
  38. package/dist/config.d.ts +38 -0
  39. package/dist/config.d.ts.map +1 -1
  40. package/dist/config.js +35 -1
  41. package/dist/config.js.map +1 -1
  42. package/dist/features/answer-parser.d.ts +9 -0
  43. package/dist/features/answer-parser.d.ts.map +1 -0
  44. package/dist/features/answer-parser.js +23 -0
  45. package/dist/features/answer-parser.js.map +1 -0
  46. package/dist/features/approval-channel.d.ts +76 -0
  47. package/dist/features/approval-channel.d.ts.map +1 -0
  48. package/dist/features/approval-channel.js +142 -0
  49. package/dist/features/approval-channel.js.map +1 -0
  50. package/dist/features/approval-renderer.d.ts +18 -0
  51. package/dist/features/approval-renderer.d.ts.map +1 -0
  52. package/dist/features/approval-renderer.js +52 -0
  53. package/dist/features/approval-renderer.js.map +1 -0
  54. package/dist/features/button-utils.d.ts +33 -0
  55. package/dist/features/button-utils.d.ts.map +1 -0
  56. package/dist/features/button-utils.js +27 -0
  57. package/dist/features/button-utils.js.map +1 -0
  58. package/dist/features/history-store.d.ts.map +1 -1
  59. package/dist/features/history-store.js +0 -1
  60. package/dist/features/history-store.js.map +1 -1
  61. package/dist/features/question-channel.d.ts +96 -0
  62. package/dist/features/question-channel.d.ts.map +1 -0
  63. package/dist/features/question-channel.js +234 -0
  64. package/dist/features/question-channel.js.map +1 -0
  65. package/dist/features/question-renderer.d.ts +20 -0
  66. package/dist/features/question-renderer.d.ts.map +1 -0
  67. package/dist/features/question-renderer.js +70 -0
  68. package/dist/features/question-renderer.js.map +1 -0
  69. package/dist/gateway/bootstrap.d.ts +3 -3
  70. package/dist/gateway/bootstrap.d.ts.map +1 -1
  71. package/dist/gateway/bootstrap.js +76 -8
  72. package/dist/gateway/bootstrap.js.map +1 -1
  73. package/dist/gateway/index.d.ts +2 -2
  74. package/dist/gateway/index.js +2 -2
  75. package/dist/gateway/middleware-setup.d.ts +3 -3
  76. package/dist/gateway/middleware-setup.d.ts.map +1 -1
  77. package/dist/gateway/middleware-setup.js +9 -7
  78. package/dist/gateway/middleware-setup.js.map +1 -1
  79. package/dist/index.d.ts +2 -2
  80. package/dist/index.d.ts.map +1 -1
  81. package/dist/index.js +16 -11
  82. package/dist/index.js.map +1 -1
  83. package/dist/media/media-cleaner.d.ts +19 -0
  84. package/dist/media/media-cleaner.d.ts.map +1 -0
  85. package/dist/media/media-cleaner.js +81 -0
  86. package/dist/media/media-cleaner.js.map +1 -0
  87. package/dist/media/send-file-tool.d.ts +35 -0
  88. package/dist/media/send-file-tool.d.ts.map +1 -0
  89. package/dist/media/send-file-tool.js +150 -0
  90. package/dist/media/send-file-tool.js.map +1 -0
  91. package/dist/media/vision-tool.d.ts +16 -0
  92. package/dist/media/vision-tool.d.ts.map +1 -0
  93. package/dist/media/vision-tool.js +241 -0
  94. package/dist/media/vision-tool.js.map +1 -0
  95. package/dist/middleware/attachment.d.ts +3 -3
  96. package/dist/middleware/attachment.d.ts.map +1 -1
  97. package/dist/middleware/attachment.js +17 -4
  98. package/dist/middleware/attachment.js.map +1 -1
  99. package/dist/middleware/question-answer.d.ts +10 -0
  100. package/dist/middleware/question-answer.d.ts.map +1 -0
  101. package/dist/middleware/question-answer.js +19 -0
  102. package/dist/middleware/question-answer.js.map +1 -0
  103. package/dist/model/index.d.ts +4 -4
  104. package/dist/model/index.js +3 -3
  105. package/dist/model/model-resolver.d.ts +27 -13
  106. package/dist/model/model-resolver.d.ts.map +1 -1
  107. package/dist/model/model-resolver.js +82 -27
  108. package/dist/model/model-resolver.js.map +1 -1
  109. package/dist/model/prefs-store.d.ts +6 -1
  110. package/dist/model/prefs-store.d.ts.map +1 -1
  111. package/dist/model/prefs-store.js +25 -1
  112. package/dist/model/prefs-store.js.map +1 -1
  113. package/dist/model/settings-reader.d.ts +1 -1
  114. package/dist/session/idle-evictor.d.ts +2 -2
  115. package/dist/session/idle-evictor.d.ts.map +1 -1
  116. package/dist/session/idle-evictor.js +1 -1
  117. package/dist/session/idle-evictor.js.map +1 -1
  118. package/dist/session/index.d.ts +3 -3
  119. package/dist/session/index.d.ts.map +1 -1
  120. package/dist/session/index.js +2 -2
  121. package/dist/session/session-manager.d.ts +67 -9
  122. package/dist/session/session-manager.d.ts.map +1 -1
  123. package/dist/session/session-manager.js +216 -20
  124. package/dist/session/session-manager.js.map +1 -1
  125. package/dist/session/types.d.ts +47 -1
  126. package/dist/session/types.d.ts.map +1 -1
  127. package/dist/setup.d.ts +4 -4
  128. package/dist/setup.d.ts.map +1 -1
  129. package/dist/setup.js +63 -28
  130. package/dist/setup.js.map +1 -1
  131. package/dist/shared/index.d.ts +3 -3
  132. package/dist/shared/index.d.ts.map +1 -1
  133. package/dist/shared/index.js +3 -3
  134. package/dist/shared/index.js.map +1 -1
  135. package/dist/shared/send-helper.js +1 -1
  136. package/dist/shared/utils.d.ts +8 -1
  137. package/dist/shared/utils.d.ts.map +1 -1
  138. package/dist/shared/utils.js +18 -7
  139. package/dist/shared/utils.js.map +1 -1
  140. package/dist/transport/attachment.d.ts +18 -7
  141. package/dist/transport/attachment.d.ts.map +1 -1
  142. package/dist/transport/attachment.js +77 -30
  143. package/dist/transport/attachment.js.map +1 -1
  144. package/dist/transport/inbound.d.ts +5 -4
  145. package/dist/transport/inbound.d.ts.map +1 -1
  146. package/dist/transport/inbound.js +120 -80
  147. package/dist/transport/inbound.js.map +1 -1
  148. package/dist/transport/index.d.ts +4 -4
  149. package/dist/transport/index.js +4 -4
  150. package/dist/transport/msgid-cache.d.ts +23 -0
  151. package/dist/transport/msgid-cache.d.ts.map +1 -0
  152. package/dist/transport/msgid-cache.js +57 -0
  153. package/dist/transport/msgid-cache.js.map +1 -0
  154. package/dist/transport/outbound-buffer.d.ts +9 -6
  155. package/dist/transport/outbound-buffer.d.ts.map +1 -1
  156. package/dist/transport/outbound-buffer.js +5 -5
  157. package/dist/transport/outbound-buffer.js.map +1 -1
  158. package/dist/transport/outbound.d.ts +9 -9
  159. package/dist/transport/outbound.d.ts.map +1 -1
  160. package/dist/transport/outbound.js +7 -7
  161. package/dist/transport/outbound.js.map +1 -1
  162. package/dist/transport/reply-limiter.d.ts +31 -0
  163. package/dist/transport/reply-limiter.d.ts.map +1 -0
  164. package/dist/transport/reply-limiter.js +50 -0
  165. package/dist/transport/reply-limiter.js.map +1 -0
  166. package/dist/transport/reply-target.d.ts +29 -0
  167. package/dist/transport/reply-target.d.ts.map +1 -0
  168. package/dist/transport/reply-target.js +55 -0
  169. package/dist/transport/reply-target.js.map +1 -0
  170. package/dist/transport/streaming-writer.d.ts +3 -3
  171. package/dist/transport/streaming-writer.d.ts.map +1 -1
  172. package/dist/transport/streaming-writer.js +1 -1
  173. package/dist/transport/streaming-writer.js.map +1 -1
  174. package/dist/transport/tool-presenter.d.ts +0 -1
  175. package/dist/transport/tool-presenter.d.ts.map +1 -1
  176. package/dist/transport/tool-presenter.js +0 -1
  177. package/dist/transport/tool-presenter.js.map +1 -1
  178. package/dist/types.d.ts +9 -15
  179. package/dist/types.d.ts.map +1 -1
  180. package/docs/assets/qqchannel.jpg +0 -0
  181. package/docs/assets/qqgroup.jpg +0 -0
  182. package/docs/assets/qrcode.png +0 -0
  183. package/package.json +21 -4
package/.orange-ci.yml CHANGED
@@ -1,68 +1,2 @@
1
- $:
2
- tag_push:
3
- - services:
4
- - docker
5
- docker:
6
- image: node:24
7
- runner:
8
- network: devnet
9
- stages:
10
- - name: 安装依赖
11
- script: npm install
12
- - name: 构建项目
13
- script: npm run build
14
- - name: 配置 npm 官方源
15
- script: npm config set registry https://registry.npmjs.org
16
- - name: 配置 token
17
- imports: https://git.woa.com/qq-ai/web/secret/blob/master/envs/npm/npmjs.txt
18
- script: npm config set //registry.npmjs.org/:_authToken=$NPM_TOKEN
19
- - name: 设置 npm 包版本号
20
- script: npm version ${ORANGE_BRANCH} --no-git-tag-version --allow-same-version
21
- - name: 发布 npm 包
22
- script: npm publish --access public
23
- - name: 生成通知
24
- script: echo "@tencent-connect/dsh-qqbot@${ORANGE_BRANCH} 发布成功" > message.txt
25
- - name: 发送通知
26
- type: wework:message
27
- options:
28
- fromFile: message.txt
29
-
30
- # ── master 分支:MR 检查 ──
31
- master:
32
- merge_request:
33
- - docker:
34
- image: node:24
35
- wework:
36
- silent: true
37
- stages:
38
- - name: 安装依赖
39
- script: npm install
40
- - name: TypeScript 类型检查
41
- script: npx tsc --noEmit
42
-
43
- # ── feat/fix 分支 push:内网发布 dev 版本 ──
44
- (feat|fix)/**:
45
- push:
46
- - docker:
47
- image: node:24
48
- runner:
49
- network: devnet
50
- stages:
51
- - name: 安装依赖
52
- script: npm install
53
- - name: 构建项目
54
- script: npm run build
55
- - name: 设置测试包名
56
- script: npm run ci:prepare-test-pkg
57
- - name: 设置测试版本
58
- script: npm version "0.0.0-dev.${ORANGE_COMMIT_SHORT}" --no-git-tag-version
59
- - name: 发布 npm 包
60
- image: tencentcom/npm:latest
61
- imports: https://git.woa.com/qq-ai/web/secret/blob/master/envs/npm/public.txt
62
- settings:
63
- username: $USER
64
- password: $PWD
65
- email: $EMAIL
66
- registry: https://mirrors.tencent.com/npm/
67
- folder: ./
68
- tag: dev
1
+ include:
2
+ - https://git.woa.com/qq-ai/web/secret/blob/master/ci/tencent-connect/dsh-qqbot.yml
package/CHANGELOG.md CHANGED
@@ -1,9 +1,54 @@
1
1
  # Changelog
2
2
 
3
+ > [English](./CHANGELOG_EN.md)
4
+
3
5
  本文件从产品视角记录 dsh-qqbot 的重要更新,聚焦用户可感知的变化。
4
6
 
5
7
  格式遵循 [Keep a Changelog](https://keepachangelog.com/zh-CN/1.0.0/)。
6
8
 
9
+ ## [0.5.0] - 2026-09-08
10
+
11
+ ### 新功能
12
+
13
+ - **图片理解**:发送图片给机器人,它会自动理解图片内容(截图、照片、图表等),可结合文字指令一起分析。
14
+ - **发送文件**:机器人可将本地文件(文档、图片等)直接发送给你,不再局限于纯文字回复。
15
+ - **主动提问**:机器人遇到不确定的信息时,会主动向你提问,并通过按钮让你一键选择,交互更顺畅。
16
+ - **操作确认**:执行敏感或关键操作前,机器人会先发起确认,你通过「允许/拒绝」按钮即可放行或拦截。
17
+ - **会话压缩**:新增 `/compact` 指令,一键压缩当前会话历史,保留上下文的同时释放空间,适合超长对话。
18
+ - **预设切换**:新增 `/preset` 指令,查看或切换机器人的人格/行为预设。
19
+ - **网络延迟检测**:`/bot-ping` 升级,返回网络传输耗时与插件处理耗时,方便排查连接延迟。
20
+
21
+ ### 体验优化
22
+
23
+ - 长任务执行超时延长到 30 分钟,复杂任务不再中途中断。
24
+ - 私聊与群聊按场景注入更贴合的系统提示词,回复更符合语境。
25
+ - 主动消息推送失败时自动降级为被动回复,减少「机器人没反应」的情况。
26
+ - 图片等媒体文件使用后自动清理,避免长期占用磁盘空间。
27
+
28
+ ### 问题修复
29
+
30
+ - 修复 `/stop` 指令无法真正中止正在生成内容的问题(此前为无效操作)。
31
+ - 修复操作确认通道的注册顺序问题,确保确认请求能被正确捕获和处理。
32
+
33
+ ### 文档
34
+
35
+ - README 补充 `/preset`、`/compact` 等新增指令说明,以及扫码升级引导。
36
+
37
+ ## [0.4.0] - 2026-08-16
38
+
39
+ ### 新功能
40
+
41
+ - **扫码链接**:二维码显示异常时,可直接点击终端输出的链接,在浏览器中完成扫码。
42
+
43
+ ### 体验优化
44
+
45
+ - 支持 Windows 平台自动保存扫码凭据(此前会因路径问题失效)。
46
+ - 凭据自动保存失败时,会明确引导手动配置,不再静默丢失已有配置。
47
+
48
+ ### 文档
49
+
50
+ - 新增扫码示意图与升级引导。
51
+
7
52
  ## [0.3.0] - 2026-08-15
8
53
 
9
54
  ### 新功能
@@ -0,0 +1,84 @@
1
+ # Changelog
2
+
3
+ > [简体中文](./CHANGELOG.md)
4
+
5
+ This file records significant dsh-qqbot updates from a product perspective, focusing on user-visible changes.
6
+
7
+ The format follows [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
8
+
9
+ ## [0.5.0] - 2026-09-08
10
+
11
+ ### Added
12
+
13
+ - **Image understanding**: send images to the bot and it will automatically understand their content (screenshots, photos, charts, etc.), and can analyze them together with text instructions.
14
+ - **File sending**: the bot can send local files (documents, images, etc.) directly to you, no longer limited to plain-text replies.
15
+ - **Proactive questions**: when the bot encounters uncertain information, it proactively asks you questions, letting you pick an answer with a single tap for smoother interaction.
16
+ - **Action confirmation**: before performing sensitive or critical operations, the bot requests confirmation, which you approve or block via "Allow/Deny" buttons.
17
+ - **Session compaction**: new `/compact` command to compress the current session history in one step, preserving context while freeing space — ideal for very long conversations.
18
+ - **Preset switching**: new `/preset` command to view or switch the bot's persona/behavior preset.
19
+ - **Network latency test**: upgraded `/bot-ping` to return network transport time and plugin processing time, making it easier to diagnose connection latency.
20
+
21
+ ### Improved
22
+
23
+ - Long-task execution timeout extended to 30 minutes, so complex tasks are no longer interrupted mid-way.
24
+ - Direct and group chats now receive more context-appropriate system prompts.
25
+ - Failed proactive message pushes automatically fall back to passive replies, reducing "the bot didn't respond" situations.
26
+ - Media files such as images are automatically cleaned up after use, avoiding long-term disk usage.
27
+
28
+ ### Fixed
29
+
30
+ - Fixed the `/stop` command not actually aborting in-progress generation (it was previously a no-op).
31
+ - Fixed the registration order of the approval channel, ensuring confirmation requests are captured and handled correctly.
32
+
33
+ ### Documentation
34
+
35
+ - README updated with the new `/preset` and `/compact` commands, plus QR-code upgrade guidance.
36
+
37
+ ## [0.4.0] - 2026-08-16
38
+
39
+ ### Added
40
+
41
+ - **QR link**: when the QR code renders incorrectly, you can click the link printed in the terminal to complete scanning in a browser.
42
+
43
+ ### Improved
44
+
45
+ - Supports auto-saving QR credentials on Windows (previously failed due to path issues).
46
+ - When auto-saving credentials fails, it now clearly guides manual configuration instead of silently dropping existing config.
47
+
48
+ ### Documentation
49
+
50
+ - Added QR-code screenshots and upgrade guidance.
51
+
52
+ ## [0.3.0] - 2026-08-15
53
+
54
+ ### Added
55
+
56
+ - **File understanding**: send a file to the bot and it will automatically download and understand its contents, supporting extract, read, analyze, and more.
57
+ - **Streaming replies**: replies are displayed incrementally in real time, no need to wait for full generation — a smoother, more natural experience.
58
+ - **Visible progress**: when the bot runs tasks (running commands, reading/writing files), you can see what it is doing — no longer a "black box".
59
+ - **Error feedback**: when a task ends abnormally, the bot clearly explains the reason, no more "half replies" or "no response at all".
60
+
61
+ ### Improved
62
+
63
+ - Correctly displays the speaker's nickname in group chats instead of an unreadable string.
64
+ - Automatically clears group chat history after replying to avoid cross-conversation interference.
65
+ - Voice messages are recognized and kept as text only, without extra invalid links.
66
+ - The bot now "actually gets things done": for requests like "download, extract, install", it executes real tool actions instead of just restating the steps.
67
+
68
+ ### Fixed
69
+
70
+ - Fixed the bot being unable to read/write files (the working directory was misconfigured).
71
+ - Fixed duplicate content and too-few chunks in streaming replies.
72
+
73
+ ## [0.1.0] - 2026-08-14
74
+
75
+ ### Added
76
+
77
+ - **First release**: QQ bot integrated with an AI assistant, supporting direct and group chats.
78
+ - **Model switching**: supports switching between different AI models.
79
+ - **Common commands**: built-in help, status query, session management, and more.
80
+ - **QR binding**: bind the bot by scanning a QR code on first use, with simple setup.
81
+
82
+ ### Fixed
83
+
84
+ - Fixed config parsing issues.
package/README.md CHANGED
@@ -1,13 +1,33 @@
1
- # @tencent-connect/dsh-qqbot
1
+ <div align="center">
2
2
 
3
- 基于 [deepseek-harness](https://github.com/deepseek-ai/deepseek-harness) (dsh) 的 QQ Bot IM 插件,将 QQ 消息平台作为 dsh agent 的前端协议驱动。
3
+ <img width="120" src="https://img.shields.io/badge/🤖-QQ_Bot-blue?style=for-the-badge" alt="QQ Bot" />
4
4
 
5
- 中文 | [English](./README_EN.md)
5
+ **基于 [deepseek-harness](https://github.com/deepseek-ai/deepseek-harness) (dsh) 的 QQ Bot 插件,将 DeepSeek AI 助手接入 QQ 私聊与群聊。**
6
+
7
+ [![npm version](https://img.shields.io/npm/v/@tencent-connect/dsh-qqbot)](https://www.npmjs.com/package/@tencent-connect/dsh-qqbot)
8
+ [![License](https://img.shields.io/badge/license-MIT-green)](./LICENSE)
9
+ [![GitHub stars](https://img.shields.io/github/stars/tencent-connect/dsh-qqbot)](https://github.com/tencent-connect/dsh-qqbot)
10
+ [![QQ Bot](https://img.shields.io/badge/QQ_Bot-API_v2-red)](https://bot.q.qq.com/wiki/)
11
+
12
+ <br/>
13
+
14
+ **[English](./README_EN.md) | 简体中文**
15
+
16
+ 扫码加入 QQ 群 / 频道
17
+
18
+ <table>
19
+ <tr>
20
+ <td align="center" width="50%"><img src="./docs/assets/qqgroup.jpg" height="360" alt="QQ 群二维码" /><br /><b>QQ 开发者交流群</b><br /><sub>群号: 1032635674</sub></td>
21
+ <td align="center" width="50%"><img src="./docs/assets/qqchannel.jpg" height="360" alt="QQ 频道二维码" /><br /><b>QQ 开发者社区频道</b><br /><sub>频道号: 20dnumts4z</sub></td>
22
+ </tr>
23
+ </table>
24
+
25
+ </div>
6
26
 
7
27
  ## 架构
8
28
 
9
29
  ```
10
- QQ 用户 → QQ WebSocket → dsh-im-qqbot → ctx.agents → dsh agent loop → LLM
30
+ QQ 用户 → QQ WebSocket → dsh-qqbot → ctx.agents → dsh agent loop → LLM
11
31
  ↑ │
12
32
  └── session/event ──────────┘
13
33
  (assistant reply → QQ sendMarkdown)
@@ -19,14 +39,18 @@ QQ 用户 → QQ WebSocket → dsh-im-qqbot → ctx.agents → dsh agent loop
19
39
 
20
40
  ```bash
21
41
  # 安装到 profile
22
- dsh plugin --profile qqbot add @tencent-connect/dsh-qqbot
42
+ npx @deepseek-ai/dsh plugin --profile qqbot add @tencent-connect/dsh-qqbot
23
43
 
24
44
  # 启动
25
- dsh --profile qqbot
45
+ npx @deepseek-ai/dsh --profile qqbot
26
46
  ```
27
47
 
28
48
  首次启动时,插件检测到凭据未配置会自动进入扫码引导:终端输出二维码 → 手机 QQ 扫码绑定 → 凭据自动保存到 profile,后续启动无需再次扫码。
29
49
 
50
+ <img src="./docs/assets/qrcode.png" alt="二维码扫码示意图" width="280" />
51
+
52
+ > **提示**:建议升级至 `0.4.0` 以上版本扫码,支持点击链接在浏览器打开,避免部分终端二维码渲染错位的问题。
53
+
30
54
  ### 方式二:本地路径安装
31
55
 
32
56
  ```bash
@@ -35,19 +59,18 @@ cd /path/to/dsh-qqbot
35
59
  pnpm install && pnpm build
36
60
 
37
61
  # 安装到 profile(本地路径)
38
- dsh plugin --profile qqbot add /path/to/dsh-qqbot
62
+ npx @deepseek-ai/dsh plugin --profile qqbot add /path/to/dsh-qqbot
39
63
 
40
64
  # 启动
41
65
  export QQBOT_APPID="你的AppID" QQBOT_SECRET="你的AppSecret"
42
- dsh --profile qqbot
66
+ npx @deepseek-ai/dsh --profile qqbot
43
67
  ```
44
68
 
45
69
  ### 方式三:--patch 开发模式
46
70
 
47
71
  ```bash
48
- cd /path/to/deepseek-harness
49
72
  export QQBOT_APPID="你的AppID" QQBOT_SECRET="你的AppSecret"
50
- pnpm dsh web --patch /path/to/dsh-qqbot/cordis.dev.yml
73
+ npx @deepseek-ai/dsh web --patch /path/to/dsh-qqbot/cordis.dev.yml
51
74
  ```
52
75
 
53
76
  ## 配置项
@@ -64,15 +87,61 @@ pnpm dsh web --patch /path/to/dsh-qqbot/cordis.dev.yml
64
87
  | `groupPrompt` | string | - | 群聊额外 system prompt |
65
88
  | `directPrompt` | string | - | 私聊额外 system prompt |
66
89
  | `textChunkLimit` | number | `4500` | 单条消息最大字符数 |
90
+ | `streaming` | boolean | `true` | 是否启用流式输出(群聊始终不启用) |
67
91
  | `sessionIdleTimeout` | number | `1800000` | 会话闲置超时(ms),默认 30 分钟 |
92
+ | `processingTimeoutMs` | number | `1800000` | 处理超时(ms),超时中断当前 LLM 调用 |
93
+ | `maxQueue` | number | `20` | 并发队列最大长度 |
94
+ | `historyLimit` | number | `10` | 群历史缓冲条数 |
95
+ | `askTimeoutMs` | number | `300000` | 待答问题超时(ms),默认 5 分钟(ask_user_question) |
96
+ | `showToolResults` | boolean | `false` | 是否展示工具调用成功结果(错误始终展示) |
68
97
  | `debug` | boolean | `false` | 调试模式 |
69
98
 
99
+ ### 访问控制(access)
100
+
101
+ | 配置 | 类型 | 默认值 | 说明 |
102
+ |------|------|--------|------|
103
+ | `access.c2cMode` | `open`/`allowlist`/`disabled` | `open` | 私聊访问模式 |
104
+ | `access.c2cAllow` | string[] | `[]` | 私聊白名单(user openid) |
105
+ | `access.groupMode` | `open`/`allowlist`/`disabled` | `open` | 群聊访问模式 |
106
+ | `access.groupAllow` | string[] | `[]` | 群聊白名单(group openid) |
107
+
108
+ ### 富媒体理解(media)
109
+
110
+ | 配置 | 类型 | 默认值 | 说明 |
111
+ |------|------|--------|------|
112
+ | `media.enabled` | boolean | `true` | 是否启用富媒体理解(图片/视频下载 + 工具分析) |
113
+ | `media.maxMB` | number | `200` | 富媒体下载大小上限(MB) |
114
+ | `media.ttlHours` | number | `24` | 富媒体存活时长(小时),0=永不过期 |
115
+
116
+ ### 视觉理解(vision)
117
+
118
+ | 配置 | 类型 | 默认值 | 说明 |
119
+ |------|------|--------|------|
120
+ | `vision.enabled` | boolean | `false` | 是否启用视觉理解(qqbot_describe_image 工具) |
121
+ | `vision.provider` | string | - | 视觉模型 provider(如 pi-ai) |
122
+ | `vision.model` | string | - | 视觉模型 id(如 qwen-vl-max) |
123
+ | `vision.maxBytes` | number | `10MB` | 图片字节上限 |
124
+ | `vision.maxTokens` | number | `1024` | 输出 token 上限 |
125
+ | `vision.timeoutMs` | number | `120000` | 视觉调用超时(ms) |
126
+
127
+ ### 附件发送(sendFile)
128
+
129
+ | 配置 | 类型 | 默认值 | 说明 |
130
+ |------|------|--------|------|
131
+ | `sendFile.restrictPaths` | boolean | `true` | 是否启用路径白名单(仅 media + cwd + extraRoots) |
132
+ | `sendFile.extraRoots` | string[] | `[]` | 额外允许访问的根目录 |
133
+
70
134
  ## 内置命令
71
135
 
72
136
  | 命令 | 说明 |
73
137
  |------|------|
74
- | `/bot-reset` | 重置当前会话(清除上下文) |
75
- | `/bot-model` | 查看或切换模型 |
138
+ | `/new`(别名 `/reset` `/clear`) | 开始新会话(清空上下文) |
139
+ | `/compact` | 压缩会话历史(摘要替换旧记录,保留上下文) |
140
+ | `/model` | 查看或切换模型 |
141
+ | `/preset` | 查看或切换 agent preset(新会话生效) |
142
+ | `/stop` | 中止当前生成 |
143
+ | `/bot-ping` | 网络延迟检测(返回传输与处理耗时) |
144
+ | `/bot-version` | 查看版本信息 |
76
145
  | `/bot-status` | 查看当前会话状态 |
77
146
  | `/bot-help` | 查看所有指令 |
78
147
 
@@ -84,10 +153,18 @@ src/
84
153
  ├── config.ts # 配置 Schema
85
154
  ├── types.ts # 全局类型定义
86
155
  ├── setup.ts # 凭据绑定(扫码)
156
+ ├── gateway/ # 网关装配
157
+ │ ├── bootstrap.ts # 启动装配(监听 session/event 等)
158
+ │ └── middleware-setup.ts # 中间件链配置
87
159
  ├── transport/ # 传输层
88
160
  │ ├── inbound.ts # QQ 入站消息 → agent.followup()
89
161
  │ ├── outbound.ts # session/event → QQ sendMarkdown
90
162
  │ ├── outbound-buffer.ts # 流式缓冲
163
+ │ ├── streaming-writer.ts # 流式写入
164
+ │ ├── reply-target.ts # 回复目标解析
165
+ │ ├── msgid-cache.ts # 被动回复 msgid 缓存
166
+ │ ├── reply-limiter.ts # 被动回复限流
167
+ │ ├── tool-presenter.ts # 工具调用展示
91
168
  │ └── chunker.ts # Markdown 文本切分
92
169
  ├── session/ # 会话管理层
93
170
  │ ├── session-manager.ts # QQ peer → Agent 映射
@@ -96,12 +173,22 @@ src/
96
173
  │ ├── model-resolver.ts # 路由解析
97
174
  │ ├── prefs-store.ts # per-peer 偏好持久化
98
175
  │ └── settings-reader.ts # settings.yaml 只读
176
+ ├── features/ # 交互特性
177
+ │ ├── question-channel.ts # ask_user_question 问答通道
178
+ │ ├── approval-channel.ts # approval 审批确认通道
179
+ │ └── answer-parser.ts # 答案解析
180
+ ├── media/ # 多媒体
181
+ │ ├── vision-tool.ts # 图片视觉理解
182
+ │ ├── send-file-tool.ts # 发送本地文件
183
+ │ └── media-cleaner.ts # 媒体 TTL 清理
184
+ ├── middleware/ # 中间件
185
+ │ ├── question-answer.ts # 问答答案处理
186
+ │ └── attachment.ts # 附件处理
99
187
  ├── shared/ # 共享工具
100
188
  │ ├── utils.ts # 通用函数
101
189
  │ ├── scope.ts # scope/peer 提取
102
190
  │ └── send-helper.ts # 分块发送
103
- ├── commands/ # 斜杠命令
104
- └── typings/ # 外部模块声明
191
+ └── commands/ # 斜杠命令
105
192
  ```
106
193
 
107
194
  ## 会话路由
@@ -118,6 +205,10 @@ sessionKey: `qqbot:${appId}:${scope}:${peerId}`,由 SHA-256 确定性派生 Se
118
205
  - **Preset 支持** — 可通过 `agent-presets` 服务挂载预设(工具集、prompt 等)
119
206
  - **闲置回收** — 超时自动 dispose Agent,防止内存泄漏
120
207
  - **Markdown 输出** — 回复以 Markdown 格式发送,支持代码块/表格感知切分
208
+ - **图片理解** — 支持 `qqbot_describe_image` 视觉理解,可分析用户发送的图片
209
+ - **附件发送** — 支持 `qqbot_send_file` 将本地文件发送给用户(默认启用路径白名单)
210
+ - **问答互动** — 支持 `ask_user_question`,单选生成内联按钮(点一个其余变灰)、多选回复编号,逐题推进 + 问题级超时
211
+ - **操作确认** — 支持 `approval/request`,关键操作通过「允许/拒绝」按钮请求用户确认
121
212
 
122
213
  ## 本地开发
123
214
 
@@ -131,10 +222,9 @@ pnpm build
131
222
  # 开发模式(watch)
132
223
  pnpm dev
133
224
 
134
- # 用 --patch 方式调试(在 dsh monorepo 中)
135
- cd /path/to/deepseek-harness
225
+ # 用 --patch 方式调试
136
226
  export QQBOT_APPID="xxx" QQBOT_SECRET="xxx"
137
- pnpm dsh web --patch /path/to/dsh-qqbot/cordis.dev.yml
227
+ npx @deepseek-ai/dsh web --patch /path/to/dsh-qqbot/cordis.dev.yml
138
228
  ```
139
229
 
140
230
  ## License
package/README_EN.md CHANGED
@@ -1,13 +1,33 @@
1
- # @tencent-connect/dsh-qqbot
1
+ <div align="center">
2
2
 
3
- A QQ Bot IM plugin for [deepseek-harness](https://github.com/deepseek-ai/deepseek-harness) (dsh), driving the dsh agent loop with the QQ messaging platform as the frontend protocol.
3
+ <img width="120" src="https://img.shields.io/badge/🤖-QQ_Bot-blue?style=for-the-badge" alt="QQ Bot" />
4
4
 
5
- [中文文档](./README.md) | English
5
+ **A QQ Bot plugin for [deepseek-harness](https://github.com/deepseek-ai/deepseek-harness) (dsh), connecting DeepSeek AI assistants to QQ private and group chats.**
6
+
7
+ [![npm version](https://img.shields.io/npm/v/@tencent-connect/dsh-qqbot)](https://www.npmjs.com/package/@tencent-connect/dsh-qqbot)
8
+ [![License](https://img.shields.io/badge/license-MIT-green)](./LICENSE)
9
+ [![GitHub stars](https://img.shields.io/github/stars/tencent-connect/dsh-qqbot)](https://github.com/tencent-connect/dsh-qqbot)
10
+ [![QQ Bot](https://img.shields.io/badge/QQ_Bot-API_v2-red)](https://bot.q.qq.com/wiki/)
11
+
12
+ <br/>
13
+
14
+ **[简体中文](./README.md) | English**
15
+
16
+ Scan to join the QQ group / channel
17
+
18
+ <table>
19
+ <tr>
20
+ <td align="center" width="50%"><img src="./docs/assets/qqgroup.jpg" height="360" alt="QQ Group QR Code" /><br /><b>QQ Developer Group</b><br /><sub>Group ID: 1032635674</sub></td>
21
+ <td align="center" width="50%"><img src="./docs/assets/qqchannel.jpg" height="360" alt="QQ Channel QR Code" /><br /><b>QQ Developer Channel</b><br /><sub>Channel ID: 20dnumts4z</sub></td>
22
+ </tr>
23
+ </table>
24
+
25
+ </div>
6
26
 
7
27
  ## Architecture
8
28
 
9
29
  ```
10
- QQ User → QQ WebSocket → dsh-im-qqbot → ctx.agents → dsh agent loop → LLM
30
+ QQ User → QQ WebSocket → dsh-qqbot → ctx.agents → dsh agent loop → LLM
11
31
  ↑ │
12
32
  └── session/event ──────────┘
13
33
  (assistant reply → QQ sendMarkdown)
@@ -19,14 +39,18 @@ QQ User → QQ WebSocket → dsh-im-qqbot → ctx.agents → dsh agent loop →
19
39
 
20
40
  ```bash
21
41
  # Add to a profile
22
- dsh plugin --profile qqbot add @tencent-connect/dsh-qqbot
42
+ npx @deepseek-ai/dsh plugin --profile qqbot add @tencent-connect/dsh-qqbot
23
43
 
24
44
  # Start
25
- dsh --profile qqbot
45
+ npx @deepseek-ai/dsh --profile qqbot
26
46
  ```
27
47
 
28
48
  On first launch, the plugin detects missing credentials and automatically starts the QR flow: a QR code is printed in the terminal → scan it with the QQ mobile app → credentials are saved to the profile, so subsequent launches require no re-scan.
29
49
 
50
+ <img src="./docs/assets/qrcode.png" alt="QR code scan example" width="280" />
51
+
52
+ > **Note**: Upgrade to `0.4.0` or later for browser-link scanning, which avoids QR code misalignment in some terminals.
53
+
30
54
  ### Method 2: Local path
31
55
 
32
56
  ```bash
@@ -35,19 +59,18 @@ cd /path/to/dsh-qqbot
35
59
  pnpm install && pnpm build
36
60
 
37
61
  # Add to a profile (local path)
38
- dsh plugin --profile qqbot add /path/to/dsh-qqbot
62
+ npx @deepseek-ai/dsh plugin --profile qqbot add /path/to/dsh-qqbot
39
63
 
40
64
  # Start
41
65
  export QQBOT_APPID="yourAppID" QQBOT_SECRET="yourAppSecret"
42
- dsh --profile qqbot
66
+ npx @deepseek-ai/dsh --profile qqbot
43
67
  ```
44
68
 
45
69
  ### Method 3: --patch dev mode
46
70
 
47
71
  ```bash
48
- cd /path/to/deepseek-harness
49
72
  export QQBOT_APPID="yourAppID" QQBOT_SECRET="yourAppSecret"
50
- pnpm dsh web --patch /path/to/dsh-qqbot/cordis.dev.yml
73
+ npx @deepseek-ai/dsh web --patch /path/to/dsh-qqbot/cordis.dev.yml
51
74
  ```
52
75
 
53
76
  ## Configuration
@@ -64,15 +87,61 @@ pnpm dsh web --patch /path/to/dsh-qqbot/cordis.dev.yml
64
87
  | `groupPrompt` | string | - | Extra system prompt for group chats |
65
88
  | `directPrompt` | string | - | Extra system prompt for direct chats |
66
89
  | `textChunkLimit` | number | `4500` | Max chars per message |
90
+ | `streaming` | boolean | `true` | Enable streaming output (always disabled in groups) |
67
91
  | `sessionIdleTimeout` | number | `1800000` | Session idle timeout (ms), default 30 min |
92
+ | `processingTimeoutMs` | number | `1800000` | Processing timeout (ms), aborts the current LLM call |
93
+ | `maxQueue` | number | `20` | Max concurrent queue length |
94
+ | `historyLimit` | number | `10` | Group history buffer size |
95
+ | `askTimeoutMs` | number | `300000` | Question timeout (ms), default 5 min (ask_user_question) |
96
+ | `showToolResults` | boolean | `false` | Show successful tool-call results (errors always shown) |
68
97
  | `debug` | boolean | `false` | Debug mode |
69
98
 
99
+ ### Access control (access)
100
+
101
+ | Config | Type | Default | Description |
102
+ |------|------|--------|------|
103
+ | `access.c2cMode` | `open`/`allowlist`/`disabled` | `open` | Direct-chat access mode |
104
+ | `access.c2cAllow` | string[] | `[]` | Direct-chat allowlist (user openid) |
105
+ | `access.groupMode` | `open`/`allowlist`/`disabled` | `open` | Group access mode |
106
+ | `access.groupAllow` | string[] | `[]` | Group allowlist (group openid) |
107
+
108
+ ### Rich media (media)
109
+
110
+ | Config | Type | Default | Description |
111
+ |------|------|--------|------|
112
+ | `media.enabled` | boolean | `true` | Enable rich media understanding (image/video download + tool analysis) |
113
+ | `media.maxMB` | number | `200` | Max download size (MB) |
114
+ | `media.ttlHours` | number | `24` | Media lifetime (hours), 0 = never expire |
115
+
116
+ ### Vision (vision)
117
+
118
+ | Config | Type | Default | Description |
119
+ |------|------|--------|------|
120
+ | `vision.enabled` | boolean | `false` | Enable vision (qqbot_describe_image tool) |
121
+ | `vision.provider` | string | - | Vision model provider (e.g. pi-ai) |
122
+ | `vision.model` | string | - | Vision model id (e.g. qwen-vl-max) |
123
+ | `vision.maxBytes` | number | `10MB` | Max image bytes |
124
+ | `vision.maxTokens` | number | `1024` | Max output tokens |
125
+ | `vision.timeoutMs` | number | `120000` | Vision call timeout (ms) |
126
+
127
+ ### File sending (sendFile)
128
+
129
+ | Config | Type | Default | Description |
130
+ |------|------|--------|------|
131
+ | `sendFile.restrictPaths` | boolean | `true` | Enable path allowlist (media + cwd + extraRoots only) |
132
+ | `sendFile.extraRoots` | string[] | `[]` | Extra allowed root directories |
133
+
70
134
  ## Built-in Commands
71
135
 
72
136
  | Command | Description |
73
137
  |------|------|
74
- | `/bot-reset` | Reset the current session (clear context) |
75
- | `/bot-model` | View or switch model |
138
+ | `/new` (aliases `/reset` `/clear`) | Start a new session (clear context) |
139
+ | `/compact` | Compact session history (replace old records with a summary) |
140
+ | `/model` | View or switch model |
141
+ | `/preset` | View or switch agent preset (applies to new sessions) |
142
+ | `/stop` | Abort the current generation |
143
+ | `/bot-ping` | Network latency test (transport & processing time) |
144
+ | `/bot-version` | View version info |
76
145
  | `/bot-status` | View current session status |
77
146
  | `/bot-help` | View all commands |
78
147
 
@@ -84,10 +153,18 @@ src/
84
153
  ├── config.ts # Config schema
85
154
  ├── types.ts # Global types
86
155
  ├── setup.ts # Credential binding (QR)
156
+ ├── gateway/ # Gateway assembly
157
+ │ ├── bootstrap.ts # Startup wiring (session/event listeners, etc.)
158
+ │ └── middleware-setup.ts # Middleware chain config
87
159
  ├── transport/ # Transport layer
88
160
  │ ├── inbound.ts # QQ inbound message → agent.followup()
89
161
  │ ├── outbound.ts # session/event → QQ sendMarkdown
90
162
  │ ├── outbound-buffer.ts # Streaming buffer
163
+ │ ├── streaming-writer.ts # Streaming writer
164
+ │ ├── reply-target.ts # Reply target resolution
165
+ │ ├── msgid-cache.ts # Passive reply msgid cache
166
+ │ ├── reply-limiter.ts # Passive reply rate limiter
167
+ │ ├── tool-presenter.ts # Tool-call presentation
91
168
  │ └── chunker.ts # Markdown chunking
92
169
  ├── session/ # Session management
93
170
  │ ├── session-manager.ts # QQ peer → Agent mapping
@@ -96,12 +173,22 @@ src/
96
173
  │ ├── model-resolver.ts # Route resolution
97
174
  │ ├── prefs-store.ts # Per-peer preference persistence
98
175
  │ └── settings-reader.ts # settings.yaml read-only
176
+ ├── features/ # Interaction features
177
+ │ ├── question-channel.ts # ask_user_question Q&A channel
178
+ │ ├── approval-channel.ts # approval confirmation channel
179
+ │ └── answer-parser.ts # Answer parsing
180
+ ├── media/ # Media
181
+ │ ├── vision-tool.ts # Image vision understanding
182
+ │ ├── send-file-tool.ts # Send local files
183
+ │ └── media-cleaner.ts # Media TTL cleanup
184
+ ├── middleware/ # Middleware
185
+ │ ├── question-answer.ts # Q&A answer handling
186
+ │ └── attachment.ts # Attachment handling
99
187
  ├── shared/ # Shared utilities
100
188
  │ ├── utils.ts # Common helpers
101
189
  │ ├── scope.ts # scope/peer extraction
102
190
  │ └── send-helper.ts # Chunked send
103
- ├── commands/ # Slash commands
104
- └── typings/ # External module declarations
191
+ └── commands/ # Slash commands
105
192
  ```
106
193
 
107
194
  ## Session Routing
@@ -118,6 +205,10 @@ Resolution strategy: in-process reuse → persisted resume → fresh create.
118
205
  - **Preset support** — mount presets (toolkits, prompts, etc.) via the `agent-presets` service
119
206
  - **Idle eviction** — auto-dispose Agents on timeout to prevent memory leaks
120
207
  - **Markdown output** — replies sent as Markdown with code-block/table-aware chunking
208
+ - **Image understanding** — supports `qqbot_describe_image` vision to analyze images sent by users
209
+ - **File sending** — supports `qqbot_send_file` to send local files to users (path allowlist enabled by default)
210
+ - **Question interaction** — supports `ask_user_question` with inline keyboard buttons (mutually exclusive) or numbered replies, one question at a time with timeout
211
+ - **Approval confirmation** — supports `approval/request` to ask for user confirmation on critical actions via allow/deny buttons
121
212
 
122
213
  ## Local Development
123
214
 
@@ -131,10 +222,9 @@ pnpm build
131
222
  # Dev mode (watch)
132
223
  pnpm dev
133
224
 
134
- # Debug via --patch (inside the dsh monorepo)
135
- cd /path/to/deepseek-harness
225
+ # Debug via --patch
136
226
  export QQBOT_APPID="xxx" QQBOT_SECRET="xxx"
137
- pnpm dsh web --patch /path/to/dsh-qqbot/cordis.dev.yml
227
+ npx @deepseek-ai/dsh web --patch /path/to/dsh-qqbot/cordis.dev.yml
138
228
  ```
139
229
 
140
230
  ## License
package/cordis.patch.yml CHANGED
@@ -22,7 +22,7 @@
22
22
  textChunkLimit: 4500
23
23
  sessionIdleTimeout: 1800000
24
24
  maxQueue: 20
25
- processingTimeoutMs: 120000
25
+ processingTimeoutMs: 1800000
26
26
  historyLimit: 10
27
27
  access:
28
28
  c2cMode: open