@zaofan/dsh-qqbot 1.10.26 → 1.10.28

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 (50) hide show
  1. package/README.md +164 -74
  2. package/client/qqbot-settings.js +956 -4
  3. package/dist/channel-tools.d.ts +1 -12
  4. package/dist/channel-tools.d.ts.map +1 -1
  5. package/dist/channel-tools.js +83 -2
  6. package/dist/channel-tools.js.map +1 -1
  7. package/dist/commands/session.js +3 -3
  8. package/dist/commands/session.js.map +1 -1
  9. package/dist/features/ext-config.d.ts +7 -0
  10. package/dist/features/ext-config.d.ts.map +1 -0
  11. package/dist/features/ext-config.js +40 -0
  12. package/dist/features/ext-config.js.map +1 -0
  13. package/dist/features/ext-hooks.d.ts.map +1 -1
  14. package/dist/features/ext-hooks.js +11 -18
  15. package/dist/features/ext-hooks.js.map +1 -1
  16. package/dist/features/ext-inbound.d.ts.map +1 -1
  17. package/dist/features/ext-inbound.js +11 -19
  18. package/dist/features/ext-inbound.js.map +1 -1
  19. package/dist/features/ext-outbound.d.ts.map +1 -1
  20. package/dist/features/ext-outbound.js +10 -17
  21. package/dist/features/ext-outbound.js.map +1 -1
  22. package/dist/features/ext-packs.d.ts +70 -0
  23. package/dist/features/ext-packs.d.ts.map +1 -0
  24. package/dist/features/ext-packs.js +210 -0
  25. package/dist/features/ext-packs.js.map +1 -0
  26. package/dist/features/ext-tool-interaction.d.ts.map +1 -1
  27. package/dist/features/ext-tool-interaction.js +9 -1
  28. package/dist/features/ext-tool-interaction.js.map +1 -1
  29. package/dist/features/extension-store.d.ts.map +1 -1
  30. package/dist/features/extension-store.js +17 -22
  31. package/dist/features/extension-store.js.map +1 -1
  32. package/dist/features/qun-login.d.ts.map +1 -1
  33. package/dist/features/qun-login.js +8 -1
  34. package/dist/features/qun-login.js.map +1 -1
  35. package/dist/gateway/data-root.d.ts.map +1 -1
  36. package/dist/gateway/data-root.js +4 -1
  37. package/dist/gateway/data-root.js.map +1 -1
  38. package/dist/gateway/middleware-setup.d.ts.map +1 -1
  39. package/dist/gateway/middleware-setup.js +27 -0
  40. package/dist/gateway/middleware-setup.js.map +1 -1
  41. package/dist/session/session-manager.d.ts +6 -0
  42. package/dist/session/session-manager.d.ts.map +1 -1
  43. package/dist/session/session-manager.js +12 -4
  44. package/dist/session/session-manager.js.map +1 -1
  45. package/dist/util/abs-path.d.ts +21 -0
  46. package/dist/util/abs-path.d.ts.map +1 -0
  47. package/dist/util/abs-path.js +44 -0
  48. package/dist/util/abs-path.js.map +1 -0
  49. package/package.json +1 -1
  50. package/settings-host.js +957 -4
@@ -110,18 +110,7 @@ export declare function syncContextTools(agentCtx: unknown, shouldHave: boolean,
110
110
  */
111
111
  export declare function ensureExtToolsGlobal(globalCtx: unknown): void;
112
112
  export declare function ensureContextToolsGlobal(globalCtx: unknown): void;
113
- /**
114
- * 按会话**实时剪枝**三个上下文工具的可见性(2026-10-09 起;2026-10-21 按 `dsh-computer-use` 的实测修)。
115
- *
116
- * 语义:**开了「无上下文模式 + 智能判断」**的会话 → 看得见那三个工具;
117
- * 否则该会话**连工具名都看不到**(模型清单里没有 = 零 token),而**注册表纹丝不动**。
118
- * 面板一改开关 → 下一次 pre-step(下一回合 / 下一 step)即生效。
119
- *
120
- * 2026-10-21 修两处(对齐 `dsh-plugins/dsh-computer-use/internal/schema-visibility.mjs`):
121
- * ① `ctx.tools` 在未 inject 时会抛 ⇒ 必须退化到 `ctx.get('tools')`,否则"剪枝"整段被 catch 吞掉;
122
- * ② `restrict()` 的返回值是**函数**,释放必须走 {@link liftRestriction}。
123
- * 幂等:同一作用域状态没变化就直接 return,不重复设/撤 restriction(避免无谓变更通知与抖动)。
124
- */
113
+ export declare function applyExtDisabledRestrict(agentCtx: unknown, dataRoot: string, extToolNames: string[]): void;
125
114
  export declare function restrictContextTools(agentCtx: unknown, shouldHave: boolean, env?: {
126
115
  dataRoot?: string;
127
116
  sessionKey?: string;
@@ -1 +1 @@
1
- {"version":3,"file":"channel-tools.d.ts","sourceRoot":"","sources":["../src/channel-tools.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"channel-tools.d.ts","sourceRoot":"","sources":["../src/channel-tools.ts"],"names":[],"mappings":"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"}
@@ -3153,6 +3153,24 @@ export async function apply(ctx) {
3153
3153
  extDiag(`注册失败: ${def.name} → ${msg}`);
3154
3154
  }
3155
3155
  }
3156
+ // ★ 2026-10-24(主人实测驱动):回收「本轮没扫到」的旧工具。
3157
+ // 原实现只在 for(def of defs) 里按名字替换 —— 停用/删除的扩展**不在 defs 里**,
3158
+ // 于是它上次注册的 disposer 永远躺在 myDisposers 里不被调用 ⇒ 工具残留在 AI 侧,
3159
+ // 表现就是"能热启动、不能热关闭"。这里循环结束后统一比对,多余的统统 dispose。
3160
+ try {
3161
+ const current = new Set(defs.map((d) => d.name));
3162
+ for (const [name, dispose] of [...myDisposers]) {
3163
+ if (current.has(name))
3164
+ continue;
3165
+ try {
3166
+ dispose();
3167
+ }
3168
+ catch { /* 旧句柄已失效 */ }
3169
+ myDisposers.delete(name);
3170
+ extDiag('回收停用/删除的扩展工具: ' + name);
3171
+ }
3172
+ }
3173
+ catch { /* 清理失败不影响主流程 */ }
3156
3174
  }
3157
3175
  catch (err) {
3158
3176
  ctx.logger?.warn?.(`[channel-tools] 扩展工具加载异常(已忽略): ${err instanceof Error ? err.message : String(err)}`);
@@ -3184,8 +3202,8 @@ export async function askAiToWriteSamples(ns, scope, peerId) {
3184
3202
  })();
3185
3203
  const prompt = [
3186
3204
  '【样例库维护】主人点了面板上的「让ai写(有聊天记录最好)」, 请你来维护本地小模型的"开口标准"样例库。',
3187
- `· 样例库(你要写的): ${root}\\.qqbot\\value-samples.jsonl —— 一行一条 {"m":"群消息文本","y":1} / y=0; 1=你会想接话, 0=你不会理`,
3188
- `· 评分记录(你来读): ${root}\\.qqbot\\value-scores.jsonl —— 一行一行 JSON, 字段: text=消息原文, score=本地小模型给的分, worth=是否判值得接, min=本会话门槛, gate=当时生效的模式(block=低分不唤醒/log=只记录不拦), conf=置信度(越接近1越有把握), mention=是否被@, top=最近邻样例, agg=聚合条数`,
3205
+ `· 样例库(你要写的): ${root}/.qqbot/value-samples.jsonl —— 一行一条 {"m":"群消息文本","y":1} / y=0; 1=你会想接话, 0=你不会理`,
3206
+ `· 评分记录(你来读): ${root}/.qqbot/value-scores.jsonl —— 一行一行 JSON, 字段: text=消息原文, score=本地小模型给的分, worth=是否判值得接, min=本会话门槛, gate=当时生效的模式(block=低分不唤醒/log=只记录不拦), conf=置信度(越接近1越有把握), mention=是否被@, top=最近邻样例, agg=聚合条数`,
3189
3207
  '做法: ①读评分记录最近 100~200 条(用文件工具) ②挑出标注可疑的 —— 尤其 conf<0.5(地图上没这类样本)、mention=true 却 worth=false(被点名却没打算回)、内容与分数明显不符的',
3190
3208
  '③对照真人群聊语境, 提炼 20~40 条新样例 ④用文件工具把它们**追加**写入样例库(不要覆盖整库) ⑤回报加了几条、都补了哪类。',
3191
3209
  '样例写法(一行一条 JSON): {"m":"消息文本","y":1或0} —— y=1 她会想接话(提问/求助/@她/她接得住的梗) / y=0 她不会理(群友互聊/短应答/表情)。',
@@ -3973,6 +3991,69 @@ function toolsOfScope(agentCtx) {
3973
3991
  * ② `restrict()` 的返回值是**函数**,释放必须走 {@link liftRestriction}。
3974
3992
  * 幂等:同一作用域状态没变化就直接 return,不重复设/撤 restriction(避免无谓变更通知与抖动)。
3975
3993
  */
3994
+ /**
3995
+ * 扩展工具启停:用 per-scope restrict 剪枝(2026-10-24)
3996
+ *
3997
+ * 为什么不能只靠"扫描时跳过":
3998
+ * hotReloadChannelTools 的实现是 **重新 apply**(只注册新工具),
3999
+ * 而工具注册表按名字覆盖 —— **停用的工具因为这次没注册,就留在原地不动**。
4000
+ * 所以"关掉开关"对 AI 侧无效,必须显式让它不可见。
4001
+ *
4002
+ * DSH 自己的做法就是这个(见 session-manager 里 ensureContextToolsGlobal 那段注释):
4003
+ * 工具全局注册一次、永不注销,再用 ctx.tools.restrict({ deny }) 按会话剪枝。
4004
+ * 我们照抄:停用的扩展工具名进 deny 列表。
4005
+ *
4006
+ * 幂等:restrict 返回 dispose;每次 apply 先撤销上一次的,再按当前 disabled 重挂。
4007
+ */
4008
+ let __extRestrictDispose;
4009
+ export function applyExtDisabledRestrict(agentCtx, dataRoot, extToolNames) {
4010
+ try {
4011
+ // 先把上一次的剪枝撤掉(否则换开关后会叠加)
4012
+ if (__extRestrictDispose) {
4013
+ __extRestrictDispose();
4014
+ __extRestrictDispose = undefined;
4015
+ }
4016
+ if (!agentCtx || !dataRoot || extToolNames.length === 0)
4017
+ return;
4018
+ const toolsObj = toolsOfScope(agentCtx);
4019
+ const restrict = toolsObj?.restrict;
4020
+ if (typeof restrict !== 'function')
4021
+ return;
4022
+ // 读「已停用」集合,与每个扩展工具的真实路径比对,得出要 deny 的名字
4023
+ let disabled = new Set();
4024
+ try {
4025
+ const mod = require('../features/ext-packs.js');
4026
+ if (typeof mod.readDisabledKeys === 'function')
4027
+ disabled = mod.readDisabledKeys(dataRoot);
4028
+ }
4029
+ catch { /* 拿不到就当全启用 */ }
4030
+ if (disabled.size === 0)
4031
+ return;
4032
+ // extToolNames 里我们放的是 "toolName\u0000absPath"
4033
+ const deny = [];
4034
+ const norm = (p) => String(p).split('\\').join('/');
4035
+ const root = norm(dataRoot);
4036
+ for (const entry of extToolNames) {
4037
+ const [name, abs] = entry.split('\u0000');
4038
+ if (!name || !abs)
4039
+ continue;
4040
+ const rel = norm(abs);
4041
+ const key = rel.indexOf(root + '/') === 0 ? rel.slice(root.length + 1) : rel;
4042
+ if (disabled.has(key))
4043
+ deny.push(name);
4044
+ }
4045
+ if (deny.length === 0)
4046
+ return;
4047
+ const d = restrict.call(toolsObj, { deny });
4048
+ if (typeof d === 'function')
4049
+ __extRestrictDispose = d;
4050
+ else if (d && typeof d.dispose === 'function') {
4051
+ const dd = d;
4052
+ __extRestrictDispose = () => { dd.dispose(); };
4053
+ }
4054
+ }
4055
+ catch { /* 剪枝失败不影响主流程:工具会多留一个,但不是致命错 */ }
4056
+ }
3976
4057
  export function restrictContextTools(agentCtx, shouldHave, env) {
3977
4058
  try {
3978
4059
  if (!agentCtx || typeof agentCtx !== 'object')