|
|
4a9705ca41
|
feat(hmapdev): 构建期告警「同一 stage 被重复注册」+ qq 合并写法
## 用户指出的关键:告警要给**开发者**看,所以必须在构建期
我第一版把告警放进了工具链生成的 proc_main 模板(插件**运行期**打日志)。
用户直接指出:「本身工具链这个编译器警告就是给开发者看的」——运行期日志
是给运维/用户看的,开发者看不到。已撤销,改为构建期静态检查。
## 缺陷(真实事故,2026-10-18)
插件侧把 stage handler 存在 `map[string]sdk.StageHandler`(stage 名为键)⇒
**同一 stage 注册两次,后者静默覆盖前者**。
QQ 插件当时写成:
RegisterStage(BeforeToolcall, 权限门) ← 被下一条覆盖
RegisterStage(BeforeToolcall, 切状态) ← 实际生效
后果不只是状态不切换 —— **权限门被静默关掉了**(那几版部署里任何人
发消息都能调任何工具)。编译器不报、运行时不报错、内核日志还显示
`2 handlers [qq qq]`(看着完全正常)。只有静态检查能发现。
## 实现
· `stage_dup_check.go`:扫构建目录下的 .go(排除 _test.go 与 z_proc*),
统计每个 stage 常量被 RegisterStage 引用几次,>1 就告警
· 接入 `buildTarget` 开头 ⇒ 所有 target(含 lua)都检查
· **只告警不中断**:存量插件里重复注册可能是本意,直接 fail 会让它们
升 SDK 后无法构建
· `example/qq`:三个重复 stage 合并成单 handler(权限门 + 状态切换)
## 判据(4 条)
· 同 stage 两次 ⇒ 报出来
· 不同 stage 各一次 ⇒ 不误报
· **注释里的示例注册不计入**
· 测试文件 / 工具链生成文件不计入
★ 「注释」这条是这个检查器**第一版自己栽的坑**:直接对全文跑正则,
把插件里「当初写错了、留在注释里当教训」的那几行也统计进去,于是
修好之后照样报「注册了 3 次」(实测)。现在逐行跳 `//` 与跨行 `/* */`。
本项目已多次绊倒在「注释里有、代码里没有」上,这次轮到检查器自己。
## 实测
qq 修好后构建: packaged qq_linux_amd64.hmap(无告警)
故意加一条重复: ⚠️ 警告: stage StageBeforeOutput 注册了 2 次
建议:把多个功能合并进同一个 handler
|
2026-10-18 15:38:52 +08:00 |
|
|
|
61a871cf88
|
feat(qq): 在线状态随内核阶段自动切换 + 手动设置工具
## 用户要的两件事
1. 「在不同内核工作阶段自动切换 QQ 状态,比如 toolcall 阶段切忙碌中、
生成文字阶段切思考中」
2. 失败不阻塞、不重试、只写日志(完全非致命错误)
## 取值以 NapCat 源码为准(不是我猜的)
我最初拿 `status=11` 试探,NapCat 返回 retcode=0 **但那是无效状态**
(它不校验)。拉了源码 `SetOnlineStatus.ts` 的 actionDescription 才拿到
权威取值表:
在线 status=10 ext=0 忙碌 status=50 ext=0
离开 status=30 ext=0 请勿打扰 status=70 ext=0
隐身 status=40 ext=0 搬砖中 status=10 ext=2023
学习中 status=10 ext=1018 听歌中 status=10 ext=1028
## 阶段映射
StageBeforeToolcall → 搬砖中(status=10, ext=2023)
StageBeforeOutput → 学习中(status=10, ext=1018)★ QQ 无"思考中"预置项
StageAfterOutput → 在线 (status=10, ext=0)
`after_toolcall` 不切:工具刚结束还要继续,频繁切换只会闪。
## 失败处理(用户明确要求的设计)
三个钩子**永远 return nil**,不重试:
· 不返回 error ⇒ 内核不会因状态失败而中断工具调用或改写回复
· 不重试 ⇒ NapCat 掉线时不会每轮打 HTTP + 打日志
· 失败只在 applyStatus 记日志(首次 + 每 10 次),不刷屏
## 其它
· 默认**关闭**(`status_auto`):改 QQ 状态对外可见,属于"内核替用户
做决定",与 offload 同类的显式特权。
· 手动工具两个:`qq_set_status`(预置状态,收中英文名)、
`qq_set_diy_status`(自定义 face_id + wording)。
· 防抖:同状态跳过、最短间隔 2s —— stage 每轮都触发,不防抖会打满 NapCat。
· `Stop()` 里恢复在线:否则停机时停在"搬砖中",用户看到一个永久错位
且不知道是谁改的状态。★ 恢复判据用**实际应用过什么**(applied),
不能用 status_auto —— 手动工具设的状态在开关关闭时也要能恢复。
## 判据(5 条,变异 2/2 咬)
· 指向必拒绝的地址时三个钩子仍返回 nil(不阻塞)
· 开关关闭时完全不发请求
· 状态名归一化(含中文别名)
· 阶段映射用**权威取值**(忙碌必须是 50,不是 11)
· 未知状态名被拒且不发请求
## 实机验证(生产 NapCat 192.168.2.106:25570)
qq_set_status busy → map[ext_status:0 status:忙碌 status_num:50]
qq_set_status working → map[ext_status:2023 status:搬砖中 status_num:10]
qq_set_status online → map[ext_status:0 status:在线 status_num:10]
qq_set_status 乱写的 → 未知状态名: 乱写的(拒绝,未发请求)
注:`get_status` 只返回 online/good,不回显具体状态 —— 那是该接口的
特性,不是设置失败。
|
2026-10-18 14:34:17 +08:00 |
|