@tencent-connect/dsh-qqbot 0.2.0 → 0.3.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 (61) hide show
  1. package/CHANGELOG.md +39 -0
  2. package/dist/config.d.ts +4 -2
  3. package/dist/config.d.ts.map +1 -1
  4. package/dist/config.js +2 -1
  5. package/dist/config.js.map +1 -1
  6. package/dist/features/history-store.d.ts +8 -0
  7. package/dist/features/history-store.d.ts.map +1 -0
  8. package/dist/features/history-store.js +24 -0
  9. package/dist/features/history-store.js.map +1 -0
  10. package/dist/gateway/bootstrap.d.ts +12 -0
  11. package/dist/gateway/bootstrap.d.ts.map +1 -0
  12. package/dist/gateway/bootstrap.js +71 -0
  13. package/dist/gateway/bootstrap.js.map +1 -0
  14. package/dist/gateway/index.d.ts +3 -0
  15. package/dist/gateway/index.d.ts.map +1 -0
  16. package/dist/gateway/index.js +3 -0
  17. package/dist/gateway/index.js.map +1 -0
  18. package/dist/gateway/middleware-setup.d.ts +12 -0
  19. package/dist/gateway/middleware-setup.d.ts.map +1 -0
  20. package/dist/gateway/middleware-setup.js +80 -0
  21. package/dist/gateway/middleware-setup.js.map +1 -0
  22. package/dist/index.d.ts +1 -1
  23. package/dist/index.d.ts.map +1 -1
  24. package/dist/index.js +3 -128
  25. package/dist/index.js.map +1 -1
  26. package/dist/middleware/attachment.d.ts +11 -0
  27. package/dist/middleware/attachment.d.ts.map +1 -0
  28. package/dist/middleware/attachment.js +17 -0
  29. package/dist/middleware/attachment.js.map +1 -0
  30. package/dist/session/session-manager.d.ts.map +1 -1
  31. package/dist/session/session-manager.js +4 -5
  32. package/dist/session/session-manager.js.map +1 -1
  33. package/dist/setup.js +6 -6
  34. package/dist/setup.js.map +1 -1
  35. package/dist/transport/attachment.d.ts +18 -0
  36. package/dist/transport/attachment.d.ts.map +1 -0
  37. package/dist/transport/attachment.js +106 -0
  38. package/dist/transport/attachment.js.map +1 -0
  39. package/dist/transport/events.d.ts +80 -0
  40. package/dist/transport/events.d.ts.map +1 -0
  41. package/dist/transport/events.js +62 -0
  42. package/dist/transport/events.js.map +1 -0
  43. package/dist/transport/inbound.d.ts +1 -1
  44. package/dist/transport/inbound.d.ts.map +1 -1
  45. package/dist/transport/inbound.js +39 -14
  46. package/dist/transport/inbound.js.map +1 -1
  47. package/dist/transport/outbound-buffer.d.ts +12 -7
  48. package/dist/transport/outbound-buffer.d.ts.map +1 -1
  49. package/dist/transport/outbound-buffer.js +20 -22
  50. package/dist/transport/outbound-buffer.js.map +1 -1
  51. package/dist/transport/outbound.d.ts +7 -6
  52. package/dist/transport/outbound.d.ts.map +1 -1
  53. package/dist/transport/outbound.js +116 -111
  54. package/dist/transport/outbound.js.map +1 -1
  55. package/dist/transport/streaming-writer.d.ts +47 -0
  56. package/dist/transport/streaming-writer.d.ts.map +1 -0
  57. package/dist/transport/streaming-writer.js +110 -0
  58. package/dist/transport/streaming-writer.js.map +1 -0
  59. package/dist/types.d.ts +11 -0
  60. package/dist/types.d.ts.map +1 -1
  61. package/package.json +6 -4
package/CHANGELOG.md ADDED
@@ -0,0 +1,39 @@
1
+ # Changelog
2
+
3
+ 本文件从产品视角记录 dsh-qqbot 的重要更新,聚焦用户可感知的变化。
4
+
5
+ 格式遵循 [Keep a Changelog](https://keepachangelog.com/zh-CN/1.0.0/)。
6
+
7
+ ## [0.3.0] - 2026-08-15
8
+
9
+ ### 新功能
10
+
11
+ - **文件理解**:给机器人发送文件,它会自动下载并理解文件内容,支持解压、读取、分析等操作。
12
+ - **流式回复**:回复内容实时逐段显示,无需等待全部生成,体验更流畅自然。
13
+ - **过程可见**:机器人执行任务(运行命令、读写文件)时,用户可以看到它在做什么,不再是一个"黑盒"。
14
+ - **出错提示**:任务异常结束时,机器人会明确告知错误原因,不再出现"半截回复"或"毫无反应"。
15
+
16
+ ### 体验优化
17
+
18
+ - 群聊中正确显示发言者昵称,不再显示一串看不懂的字符。
19
+ - 群聊回复后自动清理历史上下文,避免多轮对话相互干扰。
20
+ - 语音消息识别后只保留文字,不再附带无效链接。
21
+ - 机器人现在会"真正动手"了:面对「下载、解压、安装」这类请求,会用工具实际执行,而不是只复述操作步骤。
22
+
23
+ ### 问题修复
24
+
25
+ - 修复机器人无法读写文件的问题(此前工作目录配置错误)。
26
+ - 修复流式回复中可能出现的重复内容、分片过少等显示问题。
27
+
28
+ ## [0.1.0] - 2026-08-14
29
+
30
+ ### 新功能
31
+
32
+ - **首个版本**:QQ 机器人接入 AI 助手,支持私聊与群聊对话。
33
+ - **模型切换**:支持切换不同的 AI 模型。
34
+ - **常用指令**:内置帮助、状态查询、会话管理等指令。
35
+ - **扫码绑定**:首次使用扫码即可完成机器人绑定,配置简单。
36
+
37
+ ### 问题修复
38
+
39
+ - 修复配置解析问题。
package/dist/config.d.ts CHANGED
@@ -23,8 +23,8 @@ export interface ImQQBotConfig {
23
23
  model?: string;
24
24
  /** Agent preset id */
25
25
  preset?: string;
26
- /** Agent 工作目录 */
27
- cwd: string;
26
+ /** Agent 工作目录(缺省回落到进程 cwd) */
27
+ cwd?: string;
28
28
  /** 是否启用群消息 @mention 门控 */
29
29
  requireMention: boolean;
30
30
  /** 群聊额外 system prompt */
@@ -33,6 +33,8 @@ export interface ImQQBotConfig {
33
33
  directPrompt?: string;
34
34
  /** 单条消息最大长度(QQ 限制约 5000 字符) */
35
35
  textChunkLimit: number;
36
+ /** 是否启用流式输出(群聊始终不启用) */
37
+ streaming: boolean;
36
38
  /** 每会话最大闲置时长(ms),超时自动回收 */
37
39
  sessionIdleTimeout: number;
38
40
  /** 并发队列最大长度 */
@@ -1 +1 @@
1
- {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,OAAO,MAAM,MAAM,0BAA0B,CAAC;AAE9C,MAAM,WAAW,mBAAmB;IAClC,eAAe;IACf,OAAO,EAAE,MAAM,GAAG,WAAW,GAAG,UAAU,CAAC;IAC3C,2BAA2B;IAC3B,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,aAAa;IACb,SAAS,EAAE,MAAM,GAAG,WAAW,GAAG,UAAU,CAAC;IAC7C,0BAA0B;IAC1B,UAAU,EAAE,MAAM,EAAE,CAAC;CACtB;AAED,MAAM,WAAW,aAAa;IAC5B,mBAAmB;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,uBAAuB;IACvB,SAAS,EAAE,MAAM,CAAC;IAClB,oBAAoB;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,WAAW;IACX,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,sBAAsB;IACtB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,iBAAiB;IACjB,GAAG,EAAE,MAAM,CAAC;IACZ,0BAA0B;IAC1B,cAAc,EAAE,OAAO,CAAC;IACxB,yBAAyB;IACzB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,yBAAyB;IACzB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,+BAA+B;IAC/B,cAAc,EAAE,MAAM,CAAC;IACvB,2BAA2B;IAC3B,kBAAkB,EAAE,MAAM,CAAC;IAC3B,eAAe;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,6BAA6B;IAC7B,mBAAmB,EAAE,MAAM,CAAC;IAC5B,cAAc;IACd,YAAY,EAAE,MAAM,CAAC;IACrB,WAAW;IACX,MAAM,EAAE,mBAAmB,CAAC;IAC5B,6BAA6B;IAC7B,eAAe,EAAE,OAAO,CAAC;IACzB,WAAW;IACX,KAAK,EAAE,OAAO,CAAC;CAChB;AAED,eAAO,MAAM,YAAY,EAAE,MAAM,CAAC,aAAa,CA4B7C,CAAC"}
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,OAAO,MAAM,MAAM,0BAA0B,CAAC;AAE9C,MAAM,WAAW,mBAAmB;IAClC,eAAe;IACf,OAAO,EAAE,MAAM,GAAG,WAAW,GAAG,UAAU,CAAC;IAC3C,2BAA2B;IAC3B,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,aAAa;IACb,SAAS,EAAE,MAAM,GAAG,WAAW,GAAG,UAAU,CAAC;IAC7C,0BAA0B;IAC1B,UAAU,EAAE,MAAM,EAAE,CAAC;CACtB;AAED,MAAM,WAAW,aAAa;IAC5B,mBAAmB;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,uBAAuB;IACvB,SAAS,EAAE,MAAM,CAAC;IAClB,oBAAoB;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,WAAW;IACX,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,sBAAsB;IACtB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,8BAA8B;IAC9B,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,0BAA0B;IAC1B,cAAc,EAAE,OAAO,CAAC;IACxB,yBAAyB;IACzB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,yBAAyB;IACzB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,+BAA+B;IAC/B,cAAc,EAAE,MAAM,CAAC;IACvB,wBAAwB;IACxB,SAAS,EAAE,OAAO,CAAC;IACnB,2BAA2B;IAC3B,kBAAkB,EAAE,MAAM,CAAC;IAC3B,eAAe;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,6BAA6B;IAC7B,mBAAmB,EAAE,MAAM,CAAC;IAC5B,cAAc;IACd,YAAY,EAAE,MAAM,CAAC;IACrB,WAAW;IACX,MAAM,EAAE,mBAAmB,CAAC;IAC5B,6BAA6B;IAC7B,eAAe,EAAE,OAAO,CAAC;IACzB,WAAW;IACX,KAAK,EAAE,OAAO,CAAC;CAChB;AAED,eAAO,MAAM,YAAY,EAAE,MAAM,CAAC,aAAa,CA6B7C,CAAC"}
package/dist/config.js CHANGED
@@ -8,11 +8,12 @@ export const ConfigSchema = Schema.object({
8
8
  provider: Schema.string().description('LLM provider name'),
9
9
  model: Schema.string().description('Model name'),
10
10
  preset: Schema.string().description('Agent preset id'),
11
- cwd: Schema.string().default('/').description('Agent working directory'),
11
+ cwd: Schema.string().description('Agent working directory'),
12
12
  requireMention: Schema.boolean().default(true).description('群聊是否需要@bot触发'),
13
13
  groupPrompt: Schema.string().description('群聊额外system prompt'),
14
14
  directPrompt: Schema.string().description('私聊额外system prompt'),
15
15
  textChunkLimit: Schema.number().default(4500).description('单条消息最大字符数'),
16
+ streaming: Schema.boolean().default(true).description('是否启用流式输出(群聊始终不启用)'),
16
17
  sessionIdleTimeout: Schema.number().default(30 * 60 * 1000).description('会话闲置超时(ms)'),
17
18
  maxQueue: Schema.number().default(20).description('并发队列最大长度'),
18
19
  processingTimeoutMs: Schema.number().default(120000).description('处理超时(ms)'),
@@ -1 +1 @@
1
- {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,OAAO,MAAM,MAAM,0BAA0B,CAAC;AAoD9C,MAAM,CAAC,MAAM,YAAY,GAA0B,MAAM,CAAC,MAAM,CAAC;IAC/D,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,WAAW,CAAC,cAAc,CAAC;IAC9D,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,WAAW,CAAC,kBAAkB,CAAC;IACtE,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,WAAW,CAAC,mBAAmB,CAAC;IAC1D,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,WAAW,CAAC,YAAY,CAAC;IAChD,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,WAAW,CAAC,iBAAiB,CAAC;IACtD,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,WAAW,CAAC,yBAAyB,CAAC;IAC3D,cAAc,EAAE,MAAM,CAAC,OAAO,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,WAAW,CAAC,cAAc,CAAC;IAC1E,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,WAAW,CAAC,mBAAmB,CAAC;IAC7D,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,WAAW,CAAC,mBAAmB,CAAC;IAC9D,cAAc,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,WAAW,CAAC,WAAW,CAAC;IACtE,SAAS,EAAE,MAAM,CAAC,OAAO,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,WAAW,CAAC,mBAAmB,CAAC;IAC1E,kBAAkB,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC,WAAW,CAAC,YAAY,CAAC;IACrF,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,WAAW,CAAC,UAAU,CAAC;IAC7D,mBAAmB,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,WAAW,CAAC,UAAU,CAAC;IAC5E,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,WAAW,CAAC,SAAS,CAAC;IAChE,MAAM,EAAE,MAAM,CAAC,MAAM,CAAC;QACpB,OAAO,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC,MAAM,EAAE,WAAW,EAAE,UAAU,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,WAAW,CAAC,SAAS,CAAC;QAC/F,QAAQ,EAAE,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,WAAW,CAAC,QAAQ,CAAC;QACzE,SAAS,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC,MAAM,EAAE,WAAW,EAAE,UAAU,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,WAAW,CAAC,QAAQ,CAAC;QAChG,UAAU,EAAE,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,WAAW,CAAC,OAAO,CAAC;KAC3E,CAAC,CAAC,OAAO,CAAC;QACT,OAAO,EAAE,MAAM;QACf,QAAQ,EAAE,EAAE;QACZ,SAAS,EAAE,MAAM;QACjB,UAAU,EAAE,EAAE;KACf,CAAC,CAAC,WAAW,CAAC,MAAM,CAAC;IACtB,eAAe,EAAE,MAAM,CAAC,OAAO,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,WAAW,CAAC,sBAAsB,CAAC;IACpF,KAAK,EAAE,MAAM,CAAC,OAAO,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC;CACvC,CAAC,CAAC"}
@@ -0,0 +1,8 @@
1
+ import type { HistoryStore } from '@tencent-connect/qqbot-nodejs';
2
+ /** 获取共享历史存储(单例) */
3
+ export declare function getHistoryStore(): HistoryStore;
4
+ /** 用 appId 前缀隔离群历史(单账号下等价于 groupOpenid,保留多账号扩展) */
5
+ export declare function historyGroupKey(appId: string, groupId: string): string;
6
+ /** 清空群历史(回复后调用,避免下次 @ 时重复组包) */
7
+ export declare function clearGroupHistory(appId: string, groupId: string): void;
8
+ //# sourceMappingURL=history-store.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"history-store.d.ts","sourceRoot":"","sources":["../../src/features/history-store.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,+BAA+B,CAAC;AAIlE,mBAAmB;AACnB,wBAAgB,eAAe,IAAI,YAAY,CAG9C;AAED,mDAAmD;AACnD,wBAAgB,eAAe,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CAEtE;AAED,gCAAgC;AAChC,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI,CAEtE"}
@@ -0,0 +1,24 @@
1
+ /**
2
+ * 群历史存储共享模块
3
+ *
4
+ * historyBuffer 中间件需要一个跨调用可访问的 HistoryStore 实例,
5
+ * 以便在回复完成后清空某群的历史缓存(避免下次 @ 时重复组包)。
6
+ * 对齐 openclaw-qqbot 的 features/history-store。
7
+ */
8
+ import { MemoryHistoryStore } from '@tencent-connect/qqbot-nodejs';
9
+ let _store = null;
10
+ /** 获取共享历史存储(单例) */
11
+ export function getHistoryStore() {
12
+ if (!_store)
13
+ _store = new MemoryHistoryStore();
14
+ return _store;
15
+ }
16
+ /** 用 appId 前缀隔离群历史(单账号下等价于 groupOpenid,保留多账号扩展) */
17
+ export function historyGroupKey(appId, groupId) {
18
+ return `${appId}:${groupId}`;
19
+ }
20
+ /** 清空群历史(回复后调用,避免下次 @ 时重复组包) */
21
+ export function clearGroupHistory(appId, groupId) {
22
+ _store?.clear?.(historyGroupKey(appId, groupId));
23
+ }
24
+ //# sourceMappingURL=history-store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"history-store.js","sourceRoot":"","sources":["../../src/features/history-store.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,EAAE,kBAAkB,EAAE,MAAM,+BAA+B,CAAC;AAGnE,IAAI,MAAM,GAAwB,IAAI,CAAC;AAEvC,mBAAmB;AACnB,MAAM,UAAU,eAAe;IAC7B,IAAI,CAAC,MAAM;QAAE,MAAM,GAAG,IAAI,kBAAkB,EAAE,CAAC;IAC/C,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,mDAAmD;AACnD,MAAM,UAAU,eAAe,CAAC,KAAa,EAAE,OAAe;IAC5D,OAAO,GAAG,KAAK,IAAI,OAAO,EAAE,CAAC;AAC/B,CAAC;AAED,gCAAgC;AAChC,MAAM,UAAU,iBAAiB,CAAC,KAAa,EAAE,OAAe;IAC9D,MAAM,EAAE,KAAK,EAAE,CAAC,eAAe,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC,CAAC;AACnD,CAAC"}
@@ -0,0 +1,12 @@
1
+ /**
2
+ * 网关组装 — 创建 bot、编排中间件、注册事件、出站、生命周期
3
+ *
4
+ * 将 QQ 消息平台作为 dsh 前端协议驱动:入站消息 → handleInbound → dsh agent,
5
+ * dsh session/event → createOutboundHandler → QQ 出站。
6
+ */
7
+ import type { Context } from '@deepseek-ai/cordis';
8
+ import { type DshAgentRegistry } from '../session/index.js';
9
+ import type { ImQQBotConfig } from '../config.js';
10
+ import type { Logger } from '../types.js';
11
+ export declare function bootstrapGateway(ctx: Context, agents: DshAgentRegistry, config: ImQQBotConfig, logger: Logger): Promise<void>;
12
+ //# sourceMappingURL=bootstrap.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bootstrap.d.ts","sourceRoot":"","sources":["../../src/gateway/bootstrap.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAC;AAGnD,OAAO,EAAkB,KAAK,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAK5E,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAClD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAG1C,wBAAsB,gBAAgB,CACpC,GAAG,EAAE,OAAO,EACZ,MAAM,EAAE,gBAAgB,EACxB,MAAM,EAAE,aAAa,EACrB,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,IAAI,CAAC,CAyEf"}
@@ -0,0 +1,71 @@
1
+ import { QQBot } from '@tencent-connect/qqbot-nodejs';
2
+ import { SessionManager } from '../session/index.js';
3
+ import { handleInbound, createOutboundHandler } from '../transport/index.js';
4
+ import { buildUserAgent } from '../shared/index.js';
5
+ import { setupMiddlewares } from './middleware-setup.js';
6
+ export async function bootstrapGateway(ctx, agents, config, logger) {
7
+ const manager = new SessionManager(ctx, agents, config, logger);
8
+ // ── 初始化 QQ Bot SDK ──
9
+ const userAgent = buildUserAgent();
10
+ const bot = new QQBot({
11
+ appId: config.appId,
12
+ appSecret: config.appSecret,
13
+ transport: 'websocket',
14
+ userAgent,
15
+ logger,
16
+ });
17
+ logger.info(`QQBot SDK initialized (UA: ${userAgent})`);
18
+ // ── 中间件链 ──
19
+ setupMiddlewares(bot, config, manager, logger);
20
+ // ── 入站:经过中间件链后的消息交给 dsh agent ──
21
+ bot.on('message', async (mCtx) => {
22
+ const msg = mCtx.message;
23
+ if (config.debug) {
24
+ logger.debug(`← message (post-middleware): ${JSON.stringify(msg, null, 2).slice(0, 500)}`);
25
+ }
26
+ await handleInbound(msg, manager, config, logger, mCtx.state);
27
+ });
28
+ // ── 出站:dsh session/event → QQ 消息 ──
29
+ // 获取 tools 服务(工具结果结构化展示,参考 dsh-TUI presentResult),可选
30
+ let toolsRegistry;
31
+ try {
32
+ toolsRegistry = ctx.get('tools');
33
+ }
34
+ catch {
35
+ toolsRegistry = undefined;
36
+ }
37
+ // 发送适配器:将 QQBot 实例适配为 QQBotSender(openStream 参数形态不同)
38
+ const sender = {
39
+ sendMarkdown: (target, content) => bot.sendMarkdown(target, content),
40
+ openStream: (target) => bot.openStream({
41
+ target: {
42
+ scope: target.scope,
43
+ targetId: target.targetId,
44
+ msgId: target.msgId,
45
+ },
46
+ }),
47
+ };
48
+ const outboundHandler = createOutboundHandler(manager, sender, config, logger, toolsRegistry);
49
+ ctx
50
+ .on('session/event', outboundHandler);
51
+ bot.on('error', (err) => {
52
+ logger.error(`bot error: ${err instanceof Error ? err.message : String(err)}`);
53
+ });
54
+ bot.on('ready', () => {
55
+ console.log(`[im-qqbot] Bot ready! appId=${config.appId}`);
56
+ });
57
+ // ── 生命周期 ──
58
+ ctx
59
+ .effect(() => {
60
+ logger.info(`Starting bot (appId=${config.appId})`);
61
+ bot.start().catch((err) => {
62
+ logger.error(`Bot start failed: ${err instanceof Error ? err.message : String(err)}`);
63
+ });
64
+ return async () => {
65
+ logger.info('Shutting down');
66
+ await manager.disposeAll();
67
+ bot.stop();
68
+ };
69
+ }, 'im-qqbot.lifecycle');
70
+ }
71
+ //# sourceMappingURL=bootstrap.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bootstrap.js","sourceRoot":"","sources":["../../src/gateway/bootstrap.ts"],"names":[],"mappings":"AAOA,OAAO,EAAE,KAAK,EAAE,MAAM,+BAA+B,CAAC;AAEtD,OAAO,EAAE,cAAc,EAAyB,MAAM,qBAAqB,CAAC;AAC5E,OAAO,EAAE,aAAa,EAAE,qBAAqB,EAAE,MAAM,uBAAuB,CAAC;AAG7E,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAGpD,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAEzD,MAAM,CAAC,KAAK,UAAU,gBAAgB,CACpC,GAAY,EACZ,MAAwB,EACxB,MAAqB,EACrB,MAAc;IAEd,MAAM,OAAO,GAAG,IAAI,cAAc,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;IAEhE,uBAAuB;IACvB,MAAM,SAAS,GAAG,cAAc,EAAE,CAAC;IACnC,MAAM,GAAG,GAAG,IAAI,KAAK,CAAC;QACpB,KAAK,EAAE,MAAM,CAAC,KAAK;QACnB,SAAS,EAAE,MAAM,CAAC,SAAS;QAC3B,SAAS,EAAE,WAAW;QACtB,SAAS;QACT,MAAM;KACmC,CAAC,CAAC;IAC7C,MAAM,CAAC,IAAI,CAAC,8BAA8B,SAAS,GAAG,CAAC,CAAC;IAExD,aAAa;IACb,gBAAgB,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,CAAC,CAAC;IAE/C,kCAAkC;IAClC,GAAG,CAAC,EAAE,CAAC,SAAS,EAAE,KAAK,EAAE,IAAuB,EAAE,EAAE;QAClD,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC;QACzB,IAAI,MAAM,CAAC,KAAK,EAAE,CAAC;YACjB,MAAM,CAAC,KAAK,CAAC,gCAAgC,IAAI,CAAC,SAAS,CAAC,GAAG,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,CAAC,CAAC;QAC7F,CAAC;QACD,MAAM,aAAa,CAAC,GAAG,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC;IAChE,CAAC,CAAC,CAAC;IAEH,qCAAqC;IACrC,qDAAqD;IACrD,IAAI,aAA4C,CAAC;IACjD,IAAI,CAAC;QACH,aAAa,GAAG,GAAG,CAAC,GAAG,CAAC,OAAO,CAAkC,CAAC;IACpE,CAAC;IAAC,MAAM,CAAC;QACP,aAAa,GAAG,SAAS,CAAC;IAC5B,CAAC;IAED,qDAAqD;IACrD,MAAM,MAAM,GAAgB;QAC1B,YAAY,EAAE,CAAC,MAAM,EAAE,OAAO,EAAE,EAAE,CAAC,GAAG,CAAC,YAAY,CAAC,MAAM,EAAE,OAAO,CAAC;QACpE,UAAU,EAAE,CAAC,MAAM,EAAE,EAAE,CAAC,GAAG,CAAC,UAAU,CAAC;YACrC,MAAM,EAAE;gBACN,KAAK,EAAE,MAAM,CAAC,KAAK;gBACnB,QAAQ,EAAE,MAAM,CAAC,QAAQ;gBACzB,KAAK,EAAE,MAAM,CAAC,KAAe;aAC9B;SACF,CAAC;KACH,CAAC;IAEF,MAAM,eAAe,GAAG,qBAAqB,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,aAAa,CAAC,CAAC;IAC7F,GAAqF;SACnF,EAAE,CAAC,eAAe,EAAE,eAA+C,CAAC,CAAC;IAExE,GAAG,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,GAAY,EAAE,EAAE;QAC/B,MAAM,CAAC,KAAK,CAAC,cAAc,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IACjF,CAAC,CAAC,CAAC;IAEH,GAAG,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE;QACnB,OAAO,CAAC,GAAG,CAAC,+BAA+B,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC;IAC7D,CAAC,CAAC,CAAC;IAEH,aAAa;IACZ,GAA0F;SACxF,MAAM,CAAC,GAAG,EAAE;QACX,MAAM,CAAC,IAAI,CAAC,uBAAuB,MAAM,CAAC,KAAK,GAAG,CAAC,CAAC;QACpD,GAAG,CAAC,KAAK,EAAE,CAAC,KAAK,CAAC,CAAC,GAAY,EAAE,EAAE;YACjC,MAAM,CAAC,KAAK,CAAC,qBAAqB,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QACxF,CAAC,CAAC,CAAC;QAEH,OAAO,KAAK,IAAI,EAAE;YAChB,MAAM,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC;YAC7B,MAAM,OAAO,CAAC,UAAU,EAAE,CAAC;YAC3B,GAAG,CAAC,IAAI,EAAE,CAAC;QACb,CAAC,CAAC;IACJ,CAAC,EAAE,oBAAoB,CAAC,CAAC;AAC7B,CAAC"}
@@ -0,0 +1,3 @@
1
+ export { setupMiddlewares } from './middleware-setup.js';
2
+ export { bootstrapGateway } from './bootstrap.js';
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/gateway/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AACzD,OAAO,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC"}
@@ -0,0 +1,3 @@
1
+ export { setupMiddlewares } from './middleware-setup.js';
2
+ export { bootstrapGateway } from './bootstrap.js';
3
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/gateway/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AACzD,OAAO,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC"}
@@ -0,0 +1,12 @@
1
+ /**
2
+ * SDK 中间件编排
3
+ *
4
+ * 根据插件配置组装 SDK 内置中间件链(洋葱模型)。
5
+ * 中间件负责过滤与上下文富化;最终消息统一由 bot.on('message') 处理转发。
6
+ */
7
+ import type { QQBot } from '@tencent-connect/qqbot-nodejs';
8
+ import type { ImQQBotConfig } from '../config.js';
9
+ import type { SessionManager } from '../session/index.js';
10
+ import type { Logger } from '../types.js';
11
+ export declare function setupMiddlewares(bot: QQBot, config: ImQQBotConfig, manager: SessionManager, logger: Logger): void;
12
+ //# sourceMappingURL=middleware-setup.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"middleware-setup.d.ts","sourceRoot":"","sources":["../../src/gateway/middleware-setup.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,KAAK,EAAE,KAAK,EAAqB,MAAM,+BAA+B,CAAC;AAe9E,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAClD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAC1D,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAK1C,wBAAgB,gBAAgB,CAC9B,GAAG,EAAE,KAAK,EACV,MAAM,EAAE,aAAa,EACrB,OAAO,EAAE,cAAc,EACvB,MAAM,EAAE,MAAM,GACb,IAAI,CAqFN"}
@@ -0,0 +1,80 @@
1
+ import { errorHandler, messageFilter, accessPolicy, mentionGate, contentSanitizer, rateLimiter, slashCommand, concurrencyGuard, typingIndicator, quoteRef, historyBuffer, envelopeFormatter, } from '@tencent-connect/qqbot-nodejs';
2
+ import { buildCommandList } from '../commands/index.js';
3
+ import { attachmentProcessor } from '../middleware/attachment.js';
4
+ import { getHistoryStore, historyGroupKey } from '../features/history-store.js';
5
+ export function setupMiddlewares(bot, config, manager, logger) {
6
+ // 1. 错误兜底(最外层洋葱皮)
7
+ bot.use(errorHandler());
8
+ // 2. 消息过滤:bot 回声 + 消息去重
9
+ bot.use(messageFilter({ skipSelfEcho: false }));
10
+ // 3. 访问控制(白名单/开放/禁用)
11
+ bot.use(accessPolicy({
12
+ c2c: {
13
+ mode: config.access.c2cMode,
14
+ allow: config.access.c2cAllow.length > 0 ? config.access.c2cAllow : ['*'],
15
+ },
16
+ group: {
17
+ mode: config.access.groupMode,
18
+ allow: config.access.groupAllow.length > 0 ? config.access.groupAllow : ['*'],
19
+ },
20
+ onBlock: (_mCtx, reason) => {
21
+ if (config.debug) {
22
+ logger.debug(`Access blocked: ${reason}`);
23
+ }
24
+ },
25
+ }));
26
+ // 4. 群历史缓冲 — 放在门控之前,确保所有消息(含未 @bot)都计入上下文
27
+ // store 走共享单例(getHistoryStore),groupKey 带 appId 前缀,供回复后清空
28
+ bot.use(historyBuffer({
29
+ limit: config.historyLimit,
30
+ store: getHistoryStore(),
31
+ recordOnSkip: true,
32
+ groupKey: (ctx) => {
33
+ const gid = ctx.message.groupOpenid;
34
+ if (ctx.message.kind !== 'group' || !gid)
35
+ return undefined;
36
+ return historyGroupKey(config.appId, gid);
37
+ },
38
+ }));
39
+ // 5. 群聊 @bot 门控
40
+ bot.use(mentionGate({
41
+ requireMentionInGroup: config.requireMention,
42
+ }));
43
+ // 6. 内容清洗(去 @marker、表情标签、多余空白)
44
+ bot.use(contentSanitizer({
45
+ parseFaceTags: true,
46
+ }));
47
+ // 7. 三层限流(sender / group / global)
48
+ bot.use(rateLimiter());
49
+ // 8. 斜杠命令(在 concurrencyGuard 之前,命令匹配后不排队直接响应)
50
+ const slash = slashCommand({
51
+ autoHelp: true,
52
+ commands: buildCommandList({ manager, config }),
53
+ });
54
+ bot.use(slash.middleware);
55
+ // 9. 并发串行 + 消息合并(同 peer 排队,避免 session 冲突)
56
+ bot.use(concurrencyGuard({
57
+ strategy: 'merge',
58
+ maxQueue: config.maxQueue,
59
+ maxProcessingMs: config.processingTimeoutMs,
60
+ urgentPredicate: (mCtx) => {
61
+ return (mCtx.message.content ?? '').trim() === '/bot-stop';
62
+ },
63
+ }));
64
+ // 10. C2C 输入状态指示
65
+ bot.use(typingIndicator());
66
+ // 11. 引用消息解析(记录 + 解析被引用原文)
67
+ bot.use(quoteRef({
68
+ maxSize: 500,
69
+ preferMsgElements: true,
70
+ }));
71
+ // 11.5. 附件下载(file 附件下载到本地,供 @提及 / 工具访问)
72
+ bot.use(attachmentProcessor(config, logger));
73
+ // 12. 上下文组装(将 history + quote + sender 组成 envelope)
74
+ bot.use(envelopeFormatter({
75
+ historyLimit: config.historyLimit,
76
+ includeQuote: true,
77
+ includeSender: true,
78
+ }));
79
+ }
80
+ //# sourceMappingURL=middleware-setup.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"middleware-setup.js","sourceRoot":"","sources":["../../src/gateway/middleware-setup.ts"],"names":[],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -2,7 +2,7 @@
2
2
  * dsh-im-qqbot — QQ Bot IM channel plugin for deepseek-harness
3
3
  *
4
4
  * Cordis 插件入口。将 QQ 消息平台作为 dsh 的前端协议驱动。
5
- * 复用 @tencent-connect/qqbot-nodejs SDK 全套中间件链。
5
+ * 网关组装(中间件编排 + 事件 + 出站 + 生命周期)见 src/gateway/。
6
6
  */
7
7
  import type { Context } from '@deepseek-ai/cordis';
8
8
  import { type ImQQBotConfig } from './config.js';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAC;AAmBnD,OAAO,EAAgB,KAAK,aAAa,EAAE,MAAM,aAAa,CAAC;AAU/D,eAAO,MAAM,IAAI,aAAa,CAAC;AAC/B,eAAO,MAAM,MAAM,UAAa,CAAC;AACjC,eAAO,MAAM,MAAM,2DAAe,CAAC;AAEnC,YAAY,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAGjD,wBAAsB,KAAK,CAAC,GAAG,EAAE,OAAO,EAAE,MAAM,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CAmC9E"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAC;AACnD,OAAO,EAAgB,KAAK,aAAa,EAAE,MAAM,aAAa,CAAC;AAQ/D,eAAO,MAAM,IAAI,aAAa,CAAC;AAC/B,eAAO,MAAM,MAAM,UAAa,CAAC;AACjC,eAAO,MAAM,MAAM,2DAAe,CAAC;AAEnC,YAAY,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAGjD,wBAAsB,KAAK,CAAC,GAAG,EAAE,OAAO,EAAE,MAAM,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CAmC9E"}
package/dist/index.js CHANGED
@@ -1,9 +1,6 @@
1
- import { QQBot, errorHandler, messageFilter, accessPolicy, mentionGate, contentSanitizer, rateLimiter, slashCommand, concurrencyGuard, typingIndicator, quoteRef, historyBuffer, envelopeFormatter, MemoryHistoryStore, } from '@tencent-connect/qqbot-nodejs';
2
1
  import { ConfigSchema } from './config.js';
3
- import { SessionManager } from './session/index.js';
4
- import { handleInbound, createOutboundHandler } from './transport/index.js';
5
- import { buildCommandList } from './commands/index.js';
6
- import { getProfileDir, resolveEnv, buildUserAgent } from './shared/index.js';
2
+ import { bootstrapGateway } from './gateway/index.js';
3
+ import { getProfileDir, resolveEnv } from './shared/index.js';
7
4
  import { runQrSetup, persistCredentialsToProfile } from './setup.js';
8
5
  // ── Cordis 插件元数据 ──
9
6
  export const name = 'im-qqbot';
@@ -35,128 +32,6 @@ export async function apply(ctx, config) {
35
32
  return;
36
33
  }
37
34
  const resolvedConfig = { ...config, appId, appSecret };
38
- await bootstrap(ctx, agents, resolvedConfig, logger);
39
- }
40
- async function bootstrap(ctx, agents, config, logger) {
41
- const manager = new SessionManager(ctx, agents, config, logger);
42
- // ── 初始化 QQ Bot SDK ──
43
- const userAgent = buildUserAgent();
44
- const bot = new QQBot({
45
- appId: config.appId,
46
- appSecret: config.appSecret,
47
- transport: 'websocket',
48
- userAgent,
49
- logger,
50
- });
51
- logger.info(`QQBot SDK initialized (UA: ${userAgent})`);
52
- // ══════════════════════════════════════════════════════════════
53
- // SDK 中间件链(洋葱模型,按执行顺序编排)
54
- // ══════════════════════════════════════════════════════════════
55
- // 1. 错误兜底(最外层洋葱皮)
56
- bot.use(errorHandler());
57
- // 2. 消息过滤:bot 回声 + 消息去重
58
- bot.use(messageFilter({ skipSelfEcho: false }));
59
- // 3. 访问控制(白名单/开放/禁用)
60
- bot.use(accessPolicy({
61
- c2c: {
62
- mode: config.access.c2cMode,
63
- allow: config.access.c2cAllow.length > 0 ? config.access.c2cAllow : ['*'],
64
- },
65
- group: {
66
- mode: config.access.groupMode,
67
- allow: config.access.groupAllow.length > 0 ? config.access.groupAllow : ['*'],
68
- },
69
- onBlock: (_mCtx, reason) => {
70
- if (config.debug) {
71
- logger.debug(`Access blocked: ${reason}`);
72
- }
73
- },
74
- }));
75
- // 4. 群历史缓冲 — 放在门控之前,确保所有消息(含未 @bot)都计入上下文
76
- const historyStore = new MemoryHistoryStore();
77
- bot.use(historyBuffer({
78
- limit: config.historyLimit,
79
- store: historyStore,
80
- recordOnSkip: true,
81
- }));
82
- // 5. 群聊 @bot 门控
83
- bot.use(mentionGate({
84
- requireMentionInGroup: config.requireMention,
85
- }));
86
- // 6. 内容清洗(去 @marker、表情标签、多余空白)
87
- bot.use(contentSanitizer({
88
- parseFaceTags: true,
89
- }));
90
- // 7. 三层限流(sender / group / global)
91
- bot.use(rateLimiter());
92
- // 8. 斜杠命令(在 concurrencyGuard 之前,命令匹配后不排队直接响应)
93
- const slash = slashCommand({
94
- autoHelp: true,
95
- commands: buildCommandList({ manager, config }),
96
- });
97
- bot.use(slash.middleware);
98
- // 9. 并发串行 + 消息合并(同 peer 排队,避免 session 冲突)
99
- bot.use(concurrencyGuard({
100
- strategy: 'merge',
101
- maxQueue: config.maxQueue,
102
- maxProcessingMs: config.processingTimeoutMs,
103
- urgentPredicate: (mCtx) => {
104
- return (mCtx.message.content ?? '').trim() === '/bot-stop';
105
- },
106
- }));
107
- // 10. C2C 输入状态指示
108
- bot.use(typingIndicator());
109
- // 11. 引用消息解析(记录 + 解析被引用原文)
110
- bot.use(quoteRef({
111
- maxSize: 500,
112
- preferMsgElements: true,
113
- }));
114
- // 12. 上下文组装(将 history + quote + sender 组成 envelope)
115
- bot.use(envelopeFormatter({
116
- historyLimit: config.historyLimit,
117
- includeQuote: true,
118
- includeSender: true,
119
- }));
120
- // ══════════════════════════════════════════════════════════════
121
- // 最终处理:经过中间件链后的消息交给 dsh agent
122
- // ══════════════════════════════════════════════════════════════
123
- bot.on('message', async (mCtx) => {
124
- const msg = mCtx.message;
125
- if (config.debug) {
126
- logger.debug(`← message (post-middleware): ${JSON.stringify(msg, null, 2).slice(0, 500)}`);
127
- }
128
- await handleInbound(msg, manager, config, logger, mCtx.state);
129
- });
130
- // ── 出站 ──
131
- // 获取 tools 服务(工具结果结构化展示,参考 dsh-TUI presentResult),可选
132
- let toolsRegistry;
133
- try {
134
- toolsRegistry = ctx.get('tools');
135
- }
136
- catch {
137
- toolsRegistry = undefined;
138
- }
139
- const outboundHandler = createOutboundHandler(manager, bot, config, logger, toolsRegistry);
140
- ctx
141
- .on('session/event', outboundHandler);
142
- bot.on('error', (err) => {
143
- logger.error(`bot error: ${err instanceof Error ? err.message : String(err)}`);
144
- });
145
- bot.on('ready', () => {
146
- console.log(`[im-qqbot] Bot ready! appId=${config.appId}`);
147
- });
148
- // ── 生命周期 ──
149
- ctx
150
- .effect(() => {
151
- logger.info(`Starting bot (appId=${config.appId})`);
152
- bot.start().catch((err) => {
153
- logger.error(`Bot start failed: ${err instanceof Error ? err.message : String(err)}`);
154
- });
155
- return async () => {
156
- logger.info('Shutting down');
157
- await manager.disposeAll();
158
- bot.stop();
159
- };
160
- }, 'im-qqbot.lifecycle');
35
+ await bootstrapGateway(ctx, agents, resolvedConfig, logger);
161
36
  }
162
37
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAOA,OAAO,EAAE,YAAY,EAAsB,MAAM,aAAa,CAAC;AAC/D,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAEtD,OAAO,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAC9D,OAAO,EAAE,UAAU,EAAE,2BAA2B,EAAE,MAAM,YAAY,CAAC;AAGrE,qBAAqB;AACrB,MAAM,CAAC,MAAM,IAAI,GAAG,UAAU,CAAC;AAC/B,MAAM,CAAC,MAAM,MAAM,GAAG,CAAC,QAAQ,CAAC,CAAC;AACjC,MAAM,CAAC,MAAM,MAAM,GAAG,YAAY,CAAC;AAInC,aAAa;AACb,MAAM,CAAC,KAAK,UAAU,KAAK,CAAC,GAAY,EAAE,MAAqB;IAC7D,MAAM,MAAM,GAAI,GAA0C,CAAC,MAA0B,CAAC;IACtF,MAAM,MAAM,GAAa,GAA0C,CAAC,MAAiB,IAAI,OAAO,CAAC;IAEjG,OAAO,CAAC,GAAG,CAAC,2BAA2B,CAAC,CAAC;IAEzC,IAAI,KAAK,GAAG,UAAU,CAAC,MAAM,CAAC,KAAK,EAAE,aAAa,CAAC,CAAC;IACpD,IAAI,SAAS,GAAG,UAAU,CAAC,MAAM,CAAC,SAAS,EAAE,cAAc,CAAC,CAAC;IAE7D,oBAAoB;IACpB,IAAI,CAAC,KAAK,IAAI,CAAC,SAAS,EAAE,CAAC;QACzB,MAAM,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC;QAC/B,MAAM,WAAW,GAAG,MAAM,UAAU,EAAE,CAAC;QAEvC,IAAI,CAAC,WAAW,EAAE,CAAC;YACjB,MAAM,CAAC,KAAK,CAAC,sBAAsB,CAAC,CAAC;YACrC,OAAO;QACT,CAAC;QAED,kBAAkB;QAClB,2BAA2B,CAAC,WAAW,EAAE,aAAa,EAAE,IAAI,SAAS,EAAE,MAAM,CAAC,CAAC;QAE/E,0BAA0B;QAC1B,OAAO,CAAC,GAAG,CAAC,WAAW,GAAG,WAAW,CAAC,KAAK,CAAC;QAC5C,OAAO,CAAC,GAAG,CAAC,YAAY,GAAG,WAAW,CAAC,SAAS,CAAC;QAEjD,4CAA4C;QAC5C,oBAAoB;QACpB,MAAM,CAAC,IAAI,CAAC,oBAAoB,CAAC,CAAC;QAClC,OAAO;IACT,CAAC;IAED,MAAM,cAAc,GAAkB,EAAE,GAAG,MAAM,EAAE,KAAK,EAAE,SAAS,EAAE,CAAC;IAEtE,MAAM,gBAAgB,CAAC,GAAG,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,CAAC,CAAC;AAC9D,CAAC"}
@@ -0,0 +1,11 @@
1
+ /**
2
+ * 附件下载中间件 — 在中间件链中下载 file 附件
3
+ *
4
+ * 结果写入 ctx.state.downloadedFiles,供 handleInbound 读取。
5
+ * 下载失败不阻断消息(记录告警后放行),确保附件异常不影响正常文本处理。
6
+ */
7
+ import type { MiddlewareContext } from '@tencent-connect/qqbot-nodejs';
8
+ import type { ImQQBotConfig } from '../config.js';
9
+ import type { Logger } from '../types.js';
10
+ export declare function attachmentProcessor(config: ImQQBotConfig, logger: Logger): (ctx: MiddlewareContext, next: () => Promise<void>) => Promise<void>;
11
+ //# sourceMappingURL=attachment.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"attachment.d.ts","sourceRoot":"","sources":["../../src/middleware/attachment.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,+BAA+B,CAAC;AAEvE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAClD,OAAO,KAAK,EAAE,MAAM,EAAiB,MAAM,aAAa,CAAC;AAEzD,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,aAAa,EAAE,MAAM,EAAE,MAAM,IACzD,KAAK,iBAAiB,EAAE,MAAM,MAAM,OAAO,CAAC,IAAI,CAAC,KAAG,OAAO,CAAC,IAAI,CAAC,CAchF"}
@@ -0,0 +1,17 @@
1
+ import { downloadFileAttachments } from '../transport/attachment.js';
2
+ export function attachmentProcessor(config, logger) {
3
+ return async (ctx, next) => {
4
+ const msg = ctx.message;
5
+ const cwd = config.cwd || process.cwd();
6
+ const messageId = msg.messageId ?? 'unknown';
7
+ try {
8
+ const downloaded = await downloadFileAttachments(msg.attachments, cwd, messageId, logger);
9
+ ctx.state.downloadedFiles = downloaded;
10
+ }
11
+ catch (err) {
12
+ logger.warn(`im-qqbot: attachment download failed: ${err instanceof Error ? err.message : String(err)}`);
13
+ }
14
+ await next();
15
+ };
16
+ }
17
+ //# sourceMappingURL=attachment.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"attachment.js","sourceRoot":"","sources":["../../src/middleware/attachment.ts"],"names":[],"mappings":"AAOA,OAAO,EAAE,uBAAuB,EAAE,MAAM,4BAA4B,CAAC;AAIrE,MAAM,UAAU,mBAAmB,CAAC,MAAqB,EAAE,MAAc;IACvE,OAAO,KAAK,EAAE,GAAsB,EAAE,IAAyB,EAAiB,EAAE;QAChF,MAAM,GAAG,GAAG,GAAG,CAAC,OAAgE,CAAC;QACjF,MAAM,GAAG,GAAG,MAAM,CAAC,GAAG,IAAI,OAAO,CAAC,GAAG,EAAE,CAAC;QACxC,MAAM,SAAS,GAAG,GAAG,CAAC,SAAS,IAAI,SAAS,CAAC;QAE7C,IAAI,CAAC;YACH,MAAM,UAAU,GAAG,MAAM,uBAAuB,CAAC,GAAG,CAAC,WAAW,EAAE,GAAG,EAAE,SAAS,EAAE,MAAM,CAAC,CAAC;YAC1F,GAAG,CAAC,KAAK,CAAC,eAAe,GAAG,UAAU,CAAC;QACzC,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,MAAM,CAAC,IAAI,CAAC,yCAAyC,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAC3G,CAAC;QAED,MAAM,IAAI,EAAE,CAAC;IACf,CAAC,CAAC;AACJ,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"session-manager.d.ts","sourceRoot":"","sources":["../../src/session/session-manager.ts"],"names":[],"mappings":"AAgBA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAC;AACnD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAClE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAElD,OAAO,KAAK,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAEhE,OAAO,KAAK,EAEV,QAAQ,EAGR,gBAAgB,EAGhB,aAAa,EACb,aAAa,EACb,eAAe,EAChB,MAAM,YAAY,CAAC;AAEpB,qBAAa,cAAc;IAMvB,OAAO,CAAC,QAAQ,CAAC,GAAG;IACpB,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,QAAQ,CAAC,MAAM;IARzB,OAAO,CAAC,QAAQ,CAAoC;IACpD,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAc;IACtC,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAgB;gBAG3B,GAAG,EAAE,OAAO,EACZ,MAAM,EAAE,gBAAgB,EACxB,MAAM,EAAE,aAAa,EACrB,MAAM,EAAE,MAAM;IAgBjC;;OAEG;IACH,OAAO,CAAC,kBAAkB;IAU1B,iBAAiB,CAAC,KAAK,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,GAAG,UAAU,GAAG,SAAS;IAI3E;;OAEG;IACG,gBAAgB,CAAC,KAAK,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC;IA4D1F,kBAAkB,CAAC,KAAK,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI;IAM1D,mBAAmB,IAAI,UAAU,EAAE;IAInC,aAAa,IAAI,MAAM,EAAE;IAMzB,gBAAgB,CAAC,KAAK,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,GAAG,aAAa,GAAG,SAAS;IAI7E,SAAS,CAAC,KAAK,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,GAAG,aAAa;IAe1D,aAAa,CAAC,KAAK,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,GAAG,eAAe;IAkBhE,cAAc,CAAC,KAAK,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM;IAsBxD,OAAO,CAAC,aAAa;IAerB,OAAO,CAAC,UAAU;IAIlB,OAAO,CAAC,eAAe;IAKvB,OAAO,CAAC,gBAAgB;YAIV,aAAa;IA2B3B,wCAAwC;IAClC,WAAW,CACf,KAAK,EAAE,SAAS,EAChB,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,MAAM,EAChB,WAAW,EAAE,WAAW,GACvB,OAAO,CAAC,aAAa,CAAC;IAsEzB,eAAe,CAAC,SAAS,EAAE,MAAM,GAAG,aAAa,GAAG,SAAS;IAO7D,WAAW,CAAC,KAAK,EAAE,QAAQ,GAAG,aAAa,GAAG,SAAS;IAOjD,MAAM,CAAC,KAAK,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAWvD,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAWjC,IAAI,IAAI,IAAI,MAAM,CAEjB;CACF"}
1
+ {"version":3,"file":"session-manager.d.ts","sourceRoot":"","sources":["../../src/session/session-manager.ts"],"names":[],"mappings":"AAgBA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAC;AACnD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAClE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAElD,OAAO,KAAK,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAEhE,OAAO,KAAK,EAEV,QAAQ,EAGR,gBAAgB,EAGhB,aAAa,EACb,aAAa,EACb,eAAe,EAChB,MAAM,YAAY,CAAC;AAEpB,qBAAa,cAAc;IAMvB,OAAO,CAAC,QAAQ,CAAC,GAAG;IACpB,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,QAAQ,CAAC,MAAM;IARzB,OAAO,CAAC,QAAQ,CAAoC;IACpD,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAc;IACtC,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAgB;gBAG3B,GAAG,EAAE,OAAO,EACZ,MAAM,EAAE,gBAAgB,EACxB,MAAM,EAAE,aAAa,EACrB,MAAM,EAAE,MAAM;IAgBjC;;OAEG;IACH,OAAO,CAAC,kBAAkB;IAU1B,iBAAiB,CAAC,KAAK,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,GAAG,UAAU,GAAG,SAAS;IAI3E;;OAEG;IACG,gBAAgB,CAAC,KAAK,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC;IA4D1F,kBAAkB,CAAC,KAAK,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI;IAM1D,mBAAmB,IAAI,UAAU,EAAE;IAInC,aAAa,IAAI,MAAM,EAAE;IAMzB,gBAAgB,CAAC,KAAK,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,GAAG,aAAa,GAAG,SAAS;IAI7E,SAAS,CAAC,KAAK,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,GAAG,aAAa;IAe1D,aAAa,CAAC,KAAK,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,GAAG,eAAe;IAkBhE,cAAc,CAAC,KAAK,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM;IAsBxD,OAAO,CAAC,aAAa;IAerB,OAAO,CAAC,UAAU;IAIlB,OAAO,CAAC,eAAe;IAKvB,OAAO,CAAC,gBAAgB;YAIV,aAAa;IA2B3B,wCAAwC;IAClC,WAAW,CACf,KAAK,EAAE,SAAS,EAChB,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,MAAM,EAChB,WAAW,EAAE,WAAW,GACvB,OAAO,CAAC,aAAa,CAAC;IAqEzB,eAAe,CAAC,SAAS,EAAE,MAAM,GAAG,aAAa,GAAG,SAAS;IAO7D,WAAW,CAAC,KAAK,EAAE,QAAQ,GAAG,aAAa,GAAG,SAAS;IAOjD,MAAM,CAAC,KAAK,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAWvD,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAWjC,IAAI,IAAI,IAAI,MAAM,CAEjB;CACF"}
@@ -198,7 +198,7 @@ export class SessionManager {
198
198
  async composePreset(presetId) {
199
199
  let presets;
200
200
  try {
201
- presets = this.ctx.agentPresets;
201
+ presets = this.ctx.get('agentPresets');
202
202
  }
203
203
  catch {
204
204
  // agentPresets 服务未注入,降级跳过
@@ -241,9 +241,10 @@ export class SessionManager {
241
241
  this.logger.info(`reusing live agent: key=${key}`);
242
242
  }
243
243
  else {
244
+ // preset 只解析一次:resume/create 共用同一组合,避免重复 resolve/mount 目录
245
+ const composed = await this.composePreset(this.config.preset);
246
+ agentPreset = composed.agentPreset;
244
247
  try {
245
- const composed = await this.composePreset(this.config.preset);
246
- agentPreset = composed.agentPreset;
247
248
  const resumeRoute = this.modelResolver.getResumeRoute(key);
248
249
  const resumed = await this.agents.resume({
249
250
  resumeSessionId: sessionId,
@@ -255,8 +256,6 @@ export class SessionManager {
255
256
  this.logger.info(`resumed session: key=${key} preset=${agentPreset ?? 'none'} route=${resumeRoute ? `${resumeRoute.provider}/${resumeRoute.model}` : 'session-own'}`);
256
257
  }
257
258
  catch {
258
- const composed = await this.composePreset(this.config.preset);
259
- agentPreset = composed.agentPreset;
260
259
  const created = await this.agents.create({
261
260
  sessionId,
262
261
  meta: {