@tencent-connect/dsh-qqbot 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (126) hide show
  1. package/.orange-ci.yml +68 -0
  2. package/LICENSE +21 -0
  3. package/README.md +142 -0
  4. package/README_EN.md +142 -0
  5. package/cordis.patch.yml +32 -0
  6. package/cordis.yml +69 -0
  7. package/dist/commands/help.d.ts +11 -0
  8. package/dist/commands/help.d.ts.map +1 -0
  9. package/dist/commands/help.js +21 -0
  10. package/dist/commands/help.js.map +1 -0
  11. package/dist/commands/index.d.ts +13 -0
  12. package/dist/commands/index.d.ts.map +1 -0
  13. package/dist/commands/index.js +27 -0
  14. package/dist/commands/index.js.map +1 -0
  15. package/dist/commands/misc.d.ts +12 -0
  16. package/dist/commands/misc.d.ts.map +1 -0
  17. package/dist/commands/misc.js +30 -0
  18. package/dist/commands/misc.js.map +1 -0
  19. package/dist/commands/model.d.ts +7 -0
  20. package/dist/commands/model.d.ts.map +1 -0
  21. package/dist/commands/model.js +58 -0
  22. package/dist/commands/model.js.map +1 -0
  23. package/dist/commands/session.d.ts +10 -0
  24. package/dist/commands/session.d.ts.map +1 -0
  25. package/dist/commands/session.js +26 -0
  26. package/dist/commands/session.js.map +1 -0
  27. package/dist/commands/status.d.ts +8 -0
  28. package/dist/commands/status.d.ts.map +1 -0
  29. package/dist/commands/status.js +24 -0
  30. package/dist/commands/status.js.map +1 -0
  31. package/dist/commands/types.d.ts +12 -0
  32. package/dist/commands/types.d.ts.map +1 -0
  33. package/dist/commands/types.js +2 -0
  34. package/dist/commands/types.js.map +1 -0
  35. package/dist/config.d.ts +50 -0
  36. package/dist/config.d.ts.map +1 -0
  37. package/dist/config.js +33 -0
  38. package/dist/config.js.map +1 -0
  39. package/dist/index.d.ts +14 -0
  40. package/dist/index.d.ts.map +1 -0
  41. package/dist/index.js +154 -0
  42. package/dist/index.js.map +1 -0
  43. package/dist/model/index.d.ts +10 -0
  44. package/dist/model/index.d.ts.map +1 -0
  45. package/dist/model/index.js +9 -0
  46. package/dist/model/index.js.map +1 -0
  47. package/dist/model/model-resolver.d.ts +82 -0
  48. package/dist/model/model-resolver.d.ts.map +1 -0
  49. package/dist/model/model-resolver.js +142 -0
  50. package/dist/model/model-resolver.js.map +1 -0
  51. package/dist/model/prefs-store.d.ts +24 -0
  52. package/dist/model/prefs-store.d.ts.map +1 -0
  53. package/dist/model/prefs-store.js +94 -0
  54. package/dist/model/prefs-store.js.map +1 -0
  55. package/dist/model/settings-reader.d.ts +19 -0
  56. package/dist/model/settings-reader.d.ts.map +1 -0
  57. package/dist/model/settings-reader.js +76 -0
  58. package/dist/model/settings-reader.js.map +1 -0
  59. package/dist/model/types.d.ts +15 -0
  60. package/dist/model/types.d.ts.map +1 -0
  61. package/dist/model/types.js +5 -0
  62. package/dist/model/types.js.map +1 -0
  63. package/dist/session/idle-evictor.d.ts +18 -0
  64. package/dist/session/idle-evictor.d.ts.map +1 -0
  65. package/dist/session/idle-evictor.js +31 -0
  66. package/dist/session/idle-evictor.js.map +1 -0
  67. package/dist/session/index.d.ts +9 -0
  68. package/dist/session/index.d.ts.map +1 -0
  69. package/dist/session/index.js +8 -0
  70. package/dist/session/index.js.map +1 -0
  71. package/dist/session/session-manager.d.ts +44 -0
  72. package/dist/session/session-manager.d.ts.map +1 -0
  73. package/dist/session/session-manager.js +341 -0
  74. package/dist/session/session-manager.js.map +1 -0
  75. package/dist/session/types.d.ts +124 -0
  76. package/dist/session/types.d.ts.map +1 -0
  77. package/dist/session/types.js +2 -0
  78. package/dist/session/types.js.map +1 -0
  79. package/dist/setup.d.ts +24 -0
  80. package/dist/setup.d.ts.map +1 -0
  81. package/dist/setup.js +135 -0
  82. package/dist/setup.js.map +1 -0
  83. package/dist/shared/index.d.ts +7 -0
  84. package/dist/shared/index.d.ts.map +1 -0
  85. package/dist/shared/index.js +7 -0
  86. package/dist/shared/index.js.map +1 -0
  87. package/dist/shared/scope.d.ts +14 -0
  88. package/dist/shared/scope.d.ts.map +1 -0
  89. package/dist/shared/scope.js +12 -0
  90. package/dist/shared/scope.js.map +1 -0
  91. package/dist/shared/send-helper.d.ts +11 -0
  92. package/dist/shared/send-helper.d.ts.map +1 -0
  93. package/dist/shared/send-helper.js +13 -0
  94. package/dist/shared/send-helper.js.map +1 -0
  95. package/dist/shared/utils.d.ts +19 -0
  96. package/dist/shared/utils.d.ts.map +1 -0
  97. package/dist/shared/utils.js +66 -0
  98. package/dist/shared/utils.js.map +1 -0
  99. package/dist/transport/chunker.d.ts +14 -0
  100. package/dist/transport/chunker.d.ts.map +1 -0
  101. package/dist/transport/chunker.js +78 -0
  102. package/dist/transport/chunker.js.map +1 -0
  103. package/dist/transport/inbound.d.ts +8 -0
  104. package/dist/transport/inbound.d.ts.map +1 -0
  105. package/dist/transport/inbound.js +223 -0
  106. package/dist/transport/inbound.js.map +1 -0
  107. package/dist/transport/index.d.ts +10 -0
  108. package/dist/transport/index.d.ts.map +1 -0
  109. package/dist/transport/index.js +10 -0
  110. package/dist/transport/index.js.map +1 -0
  111. package/dist/transport/outbound-buffer.d.ts +32 -0
  112. package/dist/transport/outbound-buffer.d.ts.map +1 -0
  113. package/dist/transport/outbound-buffer.js +65 -0
  114. package/dist/transport/outbound-buffer.js.map +1 -0
  115. package/dist/transport/outbound.d.ts +26 -0
  116. package/dist/transport/outbound.d.ts.map +1 -0
  117. package/dist/transport/outbound.js +92 -0
  118. package/dist/transport/outbound.js.map +1 -0
  119. package/dist/types.d.ts +34 -0
  120. package/dist/types.d.ts.map +1 -0
  121. package/dist/types.js +5 -0
  122. package/dist/types.js.map +1 -0
  123. package/install.sh +108 -0
  124. package/package.json +75 -0
  125. package/pnpm-workspace.yaml +16 -0
  126. package/scripts/prepare-test-pkg.js +23 -0
@@ -0,0 +1,142 @@
1
+ import { PrefsStore } from './prefs-store.js';
2
+ import { SettingsReader } from './settings-reader.js';
3
+ export class ModelResolver {
4
+ ctx;
5
+ config;
6
+ logger;
7
+ prefs;
8
+ settings;
9
+ constructor(ctx, config, logger) {
10
+ this.ctx = ctx;
11
+ this.config = config;
12
+ this.logger = logger;
13
+ this.prefs = new PrefsStore(config.debug ? (msg) => this.logger?.debug(msg) : undefined);
14
+ this.settings = new SettingsReader();
15
+ }
16
+ /**
17
+ * 获取指定 sessionKey 的有效模型路由(create 用)
18
+ *
19
+ * 优先级:per-peer 偏好 > config 显式指定 > settings.yaml > 宿主服务
20
+ */
21
+ getEffectiveRoute(sessionKey) {
22
+ return this.prefs.getOverride(sessionKey) ?? this.resolveDefault();
23
+ }
24
+ /**
25
+ * 获取 resume 时覆盖 session 的模型路由(对齐 dsh-TUI 语义)
26
+ *
27
+ * 仅「用户显式切换的 per-peer 偏好」和「cordis.yml 显式配置」才覆盖
28
+ * session 自己的 requestHeader;否则返回 undefined,让 session 沿用
29
+ * 自己历史里记录的模型(session 记住模型,避免重启后模型漂移)。
30
+ */
31
+ getResumeRoute(sessionKey) {
32
+ const override = this.prefs.getOverride(sessionKey);
33
+ if (override)
34
+ return override;
35
+ if (this.config.provider && this.config.model) {
36
+ return { provider: this.config.provider, model: this.config.model };
37
+ }
38
+ return undefined;
39
+ }
40
+ /**
41
+ * 设置 per-peer 模型偏好并持久化到隔离文件
42
+ */
43
+ setOverride(sessionKey, route) {
44
+ this.prefs.setOverride(sessionKey, route);
45
+ }
46
+ /**
47
+ * 清除 per-peer 模型偏好并持久化
48
+ */
49
+ clearOverride(sessionKey) {
50
+ this.prefs.clearOverride(sessionKey);
51
+ }
52
+ /**
53
+ * 是否存在指定 session 的模型偏好
54
+ */
55
+ hasOverride(sessionKey) {
56
+ return this.prefs.hasOverride(sessionKey);
57
+ }
58
+ /**
59
+ * 获取指定 sessionKey 的最新 sessionId(fork 后记录,重启恢复用)
60
+ */
61
+ getSessionId(sessionKey) {
62
+ return this.prefs.getSessionId(sessionKey);
63
+ }
64
+ /**
65
+ * 记录指定 sessionKey 的最新 sessionId(fork 后调用)并持久化
66
+ */
67
+ setSessionId(sessionKey, sessionId) {
68
+ this.prefs.setSessionId(sessionKey, sessionId);
69
+ }
70
+ /**
71
+ * 清除指定 sessionKey 的 sessionId 记录
72
+ */
73
+ clearSessionId(sessionKey) {
74
+ this.prefs.clearSessionId(sessionKey);
75
+ }
76
+ /**
77
+ * 解析默认模型路由(不含 per-peer 偏好)
78
+ *
79
+ * 优先级:config 显式指定 > settings.yaml(只读) > 宿主 agentDefaultModel
80
+ */
81
+ resolveDefault() {
82
+ if (this.config.provider && this.config.model) {
83
+ return { provider: this.config.provider, model: this.config.model };
84
+ }
85
+ const fromSettings = this.settings.readDefaultRoute();
86
+ if (fromSettings)
87
+ return fromSettings;
88
+ return this.readFromHost();
89
+ }
90
+ /**
91
+ * 列出所有可用模型
92
+ */
93
+ listModels() {
94
+ return this.settings.readModels();
95
+ }
96
+ /**
97
+ * 列出可用 provider 名称
98
+ */
99
+ listProviders() {
100
+ try {
101
+ const llm = this.getService('llm');
102
+ if (llm && typeof llm.listProviders === 'function') {
103
+ const providers = llm.listProviders();
104
+ if (providers.length > 0) {
105
+ const first = providers[0];
106
+ if (typeof first === 'string')
107
+ return providers;
108
+ return providers.map((p) => p.id);
109
+ }
110
+ }
111
+ }
112
+ catch {
113
+ // 忽略
114
+ }
115
+ return this.settings.readProviders();
116
+ }
117
+ // ── 私有方法 ──
118
+ readFromHost() {
119
+ try {
120
+ const agentDefaultModel = this.getService('agentDefaultModel');
121
+ if (agentDefaultModel && typeof agentDefaultModel.currentSelection === 'function') {
122
+ const selection = agentDefaultModel.currentSelection();
123
+ if (selection?.provider && selection?.model) {
124
+ return { provider: selection.provider, model: selection.model };
125
+ }
126
+ }
127
+ }
128
+ catch (err) {
129
+ if (this.config.debug) {
130
+ this.logger?.debug(`ModelResolver: host service failed: ${err instanceof Error ? err.message : String(err)}`);
131
+ }
132
+ }
133
+ return undefined;
134
+ }
135
+ /** 统一的 Cordis 服务访问 */
136
+ getService(name) {
137
+ const ctxAny = this.ctx;
138
+ return ctxAny[name] ??
139
+ (typeof ctxAny.get === 'function' ? ctxAny.get(name) : undefined);
140
+ }
141
+ }
142
+ //# sourceMappingURL=model-resolver.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"model-resolver.js","sourceRoot":"","sources":["../../src/model/model-resolver.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,24 @@
1
+ import type { ModelRoute } from './types.js';
2
+ /** 日志回调(可选) */
3
+ type DebugFn = (msg: string) => void;
4
+ export declare class PrefsStore {
5
+ /** per-peer 模型偏好(内存态) */
6
+ private overrides;
7
+ /** per-peer 最新 sessionId(fork 后更新,内存态) */
8
+ private sessionIds;
9
+ /** 隔离偏好文件路径 */
10
+ private readonly prefsPath;
11
+ private readonly debugLog?;
12
+ constructor(debugLog?: DebugFn);
13
+ getOverride(sessionKey: string): ModelRoute | undefined;
14
+ setOverride(sessionKey: string, route: ModelRoute): void;
15
+ clearOverride(sessionKey: string): boolean;
16
+ hasOverride(sessionKey: string): boolean;
17
+ getSessionId(sessionKey: string): string | undefined;
18
+ setSessionId(sessionKey: string, sessionId: string): void;
19
+ clearSessionId(sessionKey: string): boolean;
20
+ private load;
21
+ private write;
22
+ }
23
+ export {};
24
+ //# sourceMappingURL=prefs-store.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prefs-store.d.ts","sourceRoot":"","sources":["../../src/model/prefs-store.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAE7C,eAAe;AACf,KAAK,OAAO,GAAG,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;AASrC,qBAAa,UAAU;IACrB,yBAAyB;IACzB,OAAO,CAAC,SAAS,CAAiC;IAClD,0CAA0C;IAC1C,OAAO,CAAC,UAAU,CAA6B;IAC/C,eAAe;IACf,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;IACnC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAU;gBAExB,QAAQ,CAAC,EAAE,OAAO;IAQ9B,WAAW,CAAC,UAAU,EAAE,MAAM,GAAG,UAAU,GAAG,SAAS;IAIvD,WAAW,CAAC,UAAU,EAAE,MAAM,EAAE,KAAK,EAAE,UAAU,GAAG,IAAI;IAKxD,aAAa,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO;IAM1C,WAAW,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO;IAMxC,YAAY,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS;IAIpD,YAAY,CAAC,UAAU,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,IAAI;IAKzD,cAAc,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO;IAQ3C,OAAO,CAAC,IAAI;IAwBZ,OAAO,CAAC,KAAK;CAYd"}
@@ -0,0 +1,94 @@
1
+ /**
2
+ * PrefsStore — per-peer 模型偏好持久化
3
+ *
4
+ * 隔离文件 I/O 操作,便于单元测试时 mock。
5
+ * 存储路径:~/.dsh-qqbot/model-prefs.json
6
+ */
7
+ import { readFileSync, writeFileSync, existsSync, mkdirSync } from 'node:fs';
8
+ import { resolve, dirname } from 'node:path';
9
+ import { homedir } from 'node:os';
10
+ export class PrefsStore {
11
+ /** per-peer 模型偏好(内存态) */
12
+ overrides = new Map();
13
+ /** per-peer 最新 sessionId(fork 后更新,内存态) */
14
+ sessionIds = new Map();
15
+ /** 隔离偏好文件路径 */
16
+ prefsPath;
17
+ debugLog;
18
+ constructor(debugLog) {
19
+ this.prefsPath = resolve(homedir(), '.dsh-qqbot', 'model-prefs.json');
20
+ this.debugLog = debugLog;
21
+ this.load();
22
+ }
23
+ // ── Override 操作 ──
24
+ getOverride(sessionKey) {
25
+ return this.overrides.get(sessionKey);
26
+ }
27
+ setOverride(sessionKey, route) {
28
+ this.overrides.set(sessionKey, route);
29
+ this.write();
30
+ }
31
+ clearOverride(sessionKey) {
32
+ const deleted = this.overrides.delete(sessionKey);
33
+ if (deleted)
34
+ this.write();
35
+ return deleted;
36
+ }
37
+ hasOverride(sessionKey) {
38
+ return this.overrides.has(sessionKey);
39
+ }
40
+ // ── SessionId 操作 ──
41
+ getSessionId(sessionKey) {
42
+ return this.sessionIds.get(sessionKey);
43
+ }
44
+ setSessionId(sessionKey, sessionId) {
45
+ this.sessionIds.set(sessionKey, sessionId);
46
+ this.write();
47
+ }
48
+ clearSessionId(sessionKey) {
49
+ const deleted = this.sessionIds.delete(sessionKey);
50
+ if (deleted)
51
+ this.write();
52
+ return deleted;
53
+ }
54
+ // ── 私有方法 ──
55
+ load() {
56
+ try {
57
+ if (!existsSync(this.prefsPath))
58
+ return;
59
+ const content = readFileSync(this.prefsPath, 'utf8');
60
+ const data = JSON.parse(content);
61
+ if (data.overrides && typeof data.overrides === 'object') {
62
+ for (const [key, route] of Object.entries(data.overrides)) {
63
+ if (route.provider && route.model) {
64
+ this.overrides.set(key, { provider: route.provider, model: route.model });
65
+ }
66
+ }
67
+ }
68
+ if (data.sessionIds && typeof data.sessionIds === 'object') {
69
+ for (const [key, sessionId] of Object.entries(data.sessionIds)) {
70
+ if (typeof sessionId === 'string' && sessionId) {
71
+ this.sessionIds.set(key, sessionId);
72
+ }
73
+ }
74
+ }
75
+ }
76
+ catch (err) {
77
+ this.debugLog?.(`loadPrefs failed: ${err instanceof Error ? err.message : String(err)}`);
78
+ }
79
+ }
80
+ write() {
81
+ try {
82
+ mkdirSync(dirname(this.prefsPath), { recursive: true });
83
+ const data = {
84
+ overrides: Object.fromEntries(this.overrides.entries()),
85
+ sessionIds: Object.fromEntries(this.sessionIds.entries()),
86
+ };
87
+ writeFileSync(this.prefsPath, JSON.stringify(data, null, 2), 'utf8');
88
+ }
89
+ catch (err) {
90
+ this.debugLog?.(`writePrefs failed: ${err instanceof Error ? err.message : String(err)}`);
91
+ }
92
+ }
93
+ }
94
+ //# sourceMappingURL=prefs-store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prefs-store.js","sourceRoot":"","sources":["../../src/model/prefs-store.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,19 @@
1
+ import type { ModelRoute, ModelEntry } from './types.js';
2
+ export declare class SettingsReader {
3
+ /** settings.yaml 缓存 */
4
+ private settingsCache;
5
+ /**
6
+ * 从 settings.yaml 的 agent-default-model 字段读取默认模型路由
7
+ */
8
+ readDefaultRoute(): ModelRoute | undefined;
9
+ /**
10
+ * 列出 settings.yaml 中配置的所有模型
11
+ */
12
+ readModels(): ModelEntry[];
13
+ /**
14
+ * 列出 settings.yaml 中配置的 provider 名称
15
+ */
16
+ readProviders(): string[];
17
+ private loadSettings;
18
+ }
19
+ //# sourceMappingURL=settings-reader.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"settings-reader.d.ts","sourceRoot":"","sources":["../../src/model/settings-reader.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAazD,qBAAa,cAAc;IACzB,uBAAuB;IACvB,OAAO,CAAC,aAAa,CAA6C;IAElE;;OAEG;IACH,gBAAgB,IAAI,UAAU,GAAG,SAAS;IAc1C;;OAEG;IACH,UAAU,IAAI,UAAU,EAAE;IAsB1B;;OAEG;IACH,aAAa,IAAI,MAAM,EAAE;IAMzB,OAAO,CAAC,YAAY;CAiBrB"}
@@ -0,0 +1,76 @@
1
+ /**
2
+ * SettingsReader — settings.yaml 只读解析
3
+ *
4
+ * 从 ~/.dsh/settings.yaml 中读取模型配置信息。
5
+ * 只读,不修改 settings.yaml。
6
+ */
7
+ import { readFileSync, existsSync } from 'node:fs';
8
+ import { resolve } from 'node:path';
9
+ import { homedir } from 'node:os';
10
+ import yaml from 'js-yaml';
11
+ export class SettingsReader {
12
+ /** settings.yaml 缓存 */
13
+ settingsCache;
14
+ /**
15
+ * 从 settings.yaml 的 agent-default-model 字段读取默认模型路由
16
+ */
17
+ readDefaultRoute() {
18
+ const settings = this.loadSettings();
19
+ if (!settings)
20
+ return undefined;
21
+ const defaultModel = settings['agent-default-model'];
22
+ if (defaultModel?.provider && defaultModel?.model) {
23
+ return { provider: defaultModel.provider, model: defaultModel.model };
24
+ }
25
+ return undefined;
26
+ }
27
+ /**
28
+ * 列出 settings.yaml 中配置的所有模型
29
+ */
30
+ readModels() {
31
+ const settings = this.loadSettings();
32
+ if (!settings)
33
+ return [];
34
+ const models = [];
35
+ const llmPiAi = settings['llm-pi-ai'];
36
+ if (llmPiAi?.providers) {
37
+ for (const [providerName, providerConfig] of Object.entries(llmPiAi.providers)) {
38
+ if (Array.isArray(providerConfig?.models)) {
39
+ for (const m of providerConfig.models) {
40
+ if (m.id) {
41
+ models.push({ provider: providerName, id: m.id, name: m.name || undefined });
42
+ }
43
+ }
44
+ }
45
+ }
46
+ }
47
+ return models;
48
+ }
49
+ /**
50
+ * 列出 settings.yaml 中配置的 provider 名称
51
+ */
52
+ readProviders() {
53
+ const settings = this.loadSettings();
54
+ const llmPiAi = settings?.['llm-pi-ai'];
55
+ return llmPiAi?.providers ? Object.keys(llmPiAi.providers) : [];
56
+ }
57
+ loadSettings() {
58
+ if (this.settingsCache !== undefined)
59
+ return this.settingsCache;
60
+ try {
61
+ const settingsPath = resolve(homedir(), '.dsh', 'settings.yaml');
62
+ if (!existsSync(settingsPath)) {
63
+ this.settingsCache = null;
64
+ return null;
65
+ }
66
+ const content = readFileSync(settingsPath, 'utf8');
67
+ this.settingsCache = yaml.load(content);
68
+ return this.settingsCache;
69
+ }
70
+ catch {
71
+ this.settingsCache = null;
72
+ return null;
73
+ }
74
+ }
75
+ }
76
+ //# sourceMappingURL=settings-reader.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"settings-reader.js","sourceRoot":"","sources":["../../src/model/settings-reader.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,15 @@
1
+ /**
2
+ * 模型路由层类型定义
3
+ */
4
+ /** 模型路由 */
5
+ export interface ModelRoute {
6
+ provider: string;
7
+ model: string;
8
+ }
9
+ /** 模型信息条目 */
10
+ export interface ModelEntry {
11
+ provider: string;
12
+ id: string;
13
+ name?: string;
14
+ }
15
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/model/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,WAAW;AACX,MAAM,WAAW,UAAU;IACzB,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;CACf;AAED,aAAa;AACb,MAAM,WAAW,UAAU;IACzB,QAAQ,EAAE,MAAM,CAAC;IACjB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,CAAC,EAAE,MAAM,CAAC;CACf"}
@@ -0,0 +1,5 @@
1
+ /**
2
+ * 模型路由层类型定义
3
+ */
4
+ export {};
5
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/model/types.ts"],"names":[],"mappings":"AAAA;;GAEG"}
@@ -0,0 +1,18 @@
1
+ /**
2
+ * IdleEvictor — 闲置会话回收器
3
+ *
4
+ * 定期检查会话最后活跃时间,超时则自动回收释放资源。
5
+ */
6
+ import type { SessionRecord } from './types.js';
7
+ export declare class IdleEvictor {
8
+ private readonly sessions;
9
+ private readonly timeoutMs;
10
+ private readonly onEvict;
11
+ private timer;
12
+ constructor(sessions: Map<string, SessionRecord>, timeoutMs: number, onEvict: (key: string, record: SessionRecord) => void);
13
+ /** 执行一轮回收检查 */
14
+ check(): void;
15
+ /** 停止回收定时器 */
16
+ dispose(): void;
17
+ }
18
+ //# sourceMappingURL=idle-evictor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"idle-evictor.d.ts","sourceRoot":"","sources":["../../src/session/idle-evictor.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAEhD,qBAAa,WAAW;IAIpB,OAAO,CAAC,QAAQ,CAAC,QAAQ;IACzB,OAAO,CAAC,QAAQ,CAAC,SAAS;IAC1B,OAAO,CAAC,QAAQ,CAAC,OAAO;IAL1B,OAAO,CAAC,KAAK,CAA+C;gBAGzC,QAAQ,EAAE,GAAG,CAAC,MAAM,EAAE,aAAa,CAAC,EACpC,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,aAAa,KAAK,IAAI;IAOxE,eAAe;IACf,KAAK,IAAI,IAAI;IASb,cAAc;IACd,OAAO,IAAI,IAAI;CAMhB"}
@@ -0,0 +1,31 @@
1
+ export class IdleEvictor {
2
+ sessions;
3
+ timeoutMs;
4
+ onEvict;
5
+ timer = null;
6
+ constructor(sessions, timeoutMs, onEvict) {
7
+ this.sessions = sessions;
8
+ this.timeoutMs = timeoutMs;
9
+ this.onEvict = onEvict;
10
+ if (timeoutMs > 0) {
11
+ this.timer = setInterval(() => this.check(), 60_000);
12
+ }
13
+ }
14
+ /** 执行一轮回收检查 */
15
+ check() {
16
+ const now = Date.now();
17
+ for (const [key, record] of this.sessions) {
18
+ if (now - record.lastActivity > this.timeoutMs) {
19
+ this.onEvict(key, record);
20
+ }
21
+ }
22
+ }
23
+ /** 停止回收定时器 */
24
+ dispose() {
25
+ if (this.timer) {
26
+ clearInterval(this.timer);
27
+ this.timer = null;
28
+ }
29
+ }
30
+ }
31
+ //# sourceMappingURL=idle-evictor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"idle-evictor.js","sourceRoot":"","sources":["../../src/session/idle-evictor.ts"],"names":[],"mappings":"AAOA,MAAM,OAAO,WAAW;IAIH;IACA;IACA;IALX,KAAK,GAA0C,IAAI,CAAC;IAE5D,YACmB,QAAoC,EACpC,SAAiB,EACjB,OAAqD;QAFrD,aAAQ,GAAR,QAAQ,CAA4B;QACpC,cAAS,GAAT,SAAS,CAAQ;QACjB,YAAO,GAAP,OAAO,CAA8C;QAEtE,IAAI,SAAS,GAAG,CAAC,EAAE,CAAC;YAClB,IAAI,CAAC,KAAK,GAAG,WAAW,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,KAAK,EAAE,EAAE,MAAM,CAAC,CAAC;QACvD,CAAC;IACH,CAAC;IAED,eAAe;IACf,KAAK;QACH,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QACvB,KAAK,MAAM,CAAC,GAAG,EAAE,MAAM,CAAC,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;YAC1C,IAAI,GAAG,GAAG,MAAM,CAAC,YAAY,GAAG,IAAI,CAAC,SAAS,EAAE,CAAC;gBAC/C,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;YAC5B,CAAC;QACH,CAAC;IACH,CAAC;IAED,cAAc;IACd,OAAO;QACL,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;YACf,aAAa,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YAC1B,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC;QACpB,CAAC;IACH,CAAC;CACF"}
@@ -0,0 +1,9 @@
1
+ /**
2
+ * 会话管理层
3
+ *
4
+ * 管理 QQ peer → dsh Agent 的映射和生命周期。
5
+ */
6
+ export { SessionManager } from './session-manager.js';
7
+ export { IdleEvictor } from './idle-evictor.js';
8
+ export type { AgentSetup, SessionEventLike, DshAgent, DshAgentHandle, SessionsService, DshAgentRegistry, AgentPresetsLike, PresetComposition, SessionRecord, SessionStatus, TokenUsageStats, } from './types.js';
9
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/session/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,YAAY,EACV,UAAU,EACV,gBAAgB,EAChB,QAAQ,EACR,cAAc,EACd,eAAe,EACf,gBAAgB,EAChB,gBAAgB,EAChB,iBAAiB,EACjB,aAAa,EACb,aAAa,EACb,eAAe,GAChB,MAAM,YAAY,CAAC"}
@@ -0,0 +1,8 @@
1
+ /**
2
+ * 会话管理层
3
+ *
4
+ * 管理 QQ peer → dsh Agent 的映射和生命周期。
5
+ */
6
+ export { SessionManager } from './session-manager.js';
7
+ export { IdleEvictor } from './idle-evictor.js';
8
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/session/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC"}
@@ -0,0 +1,44 @@
1
+ import type { Context } from '@deepseek-ai/cordis';
2
+ import type { ChatScope, Logger, ReplyTarget } from '../types.js';
3
+ import type { ImQQBotConfig } from '../config.js';
4
+ import type { ModelRoute, ModelEntry } from '../model/types.js';
5
+ import type { DshAgent, DshAgentRegistry, SessionRecord, SessionStatus, TokenUsageStats } from './types.js';
6
+ export declare class SessionManager {
7
+ private readonly ctx;
8
+ private readonly agents;
9
+ private readonly config;
10
+ private readonly logger;
11
+ private sessions;
12
+ private readonly evictor;
13
+ private readonly modelResolver;
14
+ constructor(ctx: Context, agents: DshAgentRegistry, config: ImQQBotConfig, logger: Logger);
15
+ /**
16
+ * 动态获取 sessions 服务(fork 能力,可选)
17
+ */
18
+ private getSessionsService;
19
+ getEffectiveModel(scope: ChatScope, peerId: string): ModelRoute | undefined;
20
+ /**
21
+ * 切换模型(fork + 重建,对齐 dsh-TUI 的 switchModel)
22
+ */
23
+ setModelOverride(scope: ChatScope, peerId: string, route: ModelRoute): Promise<void>;
24
+ clearModelOverride(scope: ChatScope, peerId: string): void;
25
+ listAvailableModels(): ModelEntry[];
26
+ listProviders(): string[];
27
+ getSessionRecord(scope: ChatScope, peerId: string): SessionRecord | undefined;
28
+ getStatus(scope: ChatScope, peerId: string): SessionStatus;
29
+ getTokenUsage(scope: ChatScope, peerId: string): TokenUsageStats;
30
+ exportMarkdown(scope: ChatScope, peerId: string): string;
31
+ private countMessages;
32
+ private sessionKey;
33
+ private deriveSessionId;
34
+ private currentSessionId;
35
+ private composePreset;
36
+ /** 获取或恢复或创建会话(get → resume → create) */
37
+ getOrCreate(scope: ChatScope, peerId: string, senderId: string, replyTarget: ReplyTarget): Promise<SessionRecord>;
38
+ findBySessionId(sessionId: string): SessionRecord | undefined;
39
+ findByAgent(agent: DshAgent): SessionRecord | undefined;
40
+ remove(scope: ChatScope, peerId: string): Promise<void>;
41
+ disposeAll(): Promise<void>;
42
+ get size(): number;
43
+ }
44
+ //# sourceMappingURL=session-manager.d.ts.map
@@ -0,0 +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"}