mirror of
https://gitcode.com/JianFeeeee/homeagent-sdk.git
synced 2026-10-31 06:17:25 +00:00
现场(2026-10-19 内核日志,13 次调用全灭):
用户反复说"gethistory 拉不到私聊消息",纠正多次仍不改。
查日志:qq_get_history 失败 13 次,错误全部是
napcat get_group_msg_history: retcode=200: 消息undefined不存在
而 get_friend_msg_history 一次都没被调用过。
## 根因
handleGetHistory 用 `convInt64(args["group_id"])` 的 **err==nil** 判"调用方给了群号",
而 convInt64 对 0 也成功返回。于是:
模型 qq_get_message 取私聊正文
→ 返回体无条件带 "group_id": 0(QQ 协议里私聊群号就是 0)
→ 模型把字段原样抄进 qq_get_history
→ 代码认为"要查群 0" → get_group_msg_history(group_id=0)
→ NapCat 回「消息undefined不存在」,看起来像历史拉不到
实机验证:直接 POST NapCat
get_group_msg_history {"group_id":0} → retcode=200 消息undefined不存在
get_friend_msg_history {"user_id":…} → retcode=0 正常
## 改动
1. 新增 argPeerID:把 0 判为"未提供"(群号/QQ号都是正整数,0 从不是合法会话)。
权限门用的 argInt64 早有 parsed!=0 检查 —— 本仓此前是「权限门严、取数松」。
2. handleGetHistory 改用它,并区分三种情况:只给 user_id 走私聊、只给 group_id
走群聊、两个都给直接报错(旧实现静默选群分支,把私聊打成群查询)。
3. 同一零值缺陷一并修:handleSendFile(group_id=0 会发往不存在的群)、
handleMarkRead(markChatRead(0) 静默清空不存在的会话)、
handleResolveNickname(group_id=0 打群成员端点)。
4. **msgToGetMsgResult 私聊不再输出 group_id** —— 这是根因的上游。只改下游判据
只能止血,模型仍会一次次把 0 抄回来。
5. schema 写死参数语义:「私聊必须省略 group_id、只传 user_id;不要传 0」。
模型需要知道自己该传什么,否则会反复试错。
6. skill 补「拉私聊历史」整节 + 常见报错对照表;顺带修正一句错述
(原文称"本插件声明 auto_start: false",实际三方都未声明,按契约默认自启)。
7. 新增 history_endpoint_test.go:5 条判据钉住端点选择与返回体契约,
用 httptest 打桩 NapCat,断言真实命中的 action。
## 版本
1.4.3 → 1.4.4。已构建 hmap 并经 plugin_install 装到本机生产实例,
增量重载后 qq 子进程换新、工具全部重注册、skill 移交 skillmgr。
3.8 KiB
3.8 KiB
name, description
| name | description |
|---|---|
| qq-tools | QQ 消息收发(NapCat 协议桥接)。本插件**常驻自启**:它在监听外部消息,不能按需加载。 |
QQ 消息
本插件为什么常驻
QQ 插件在 HTTP 端口上监听 NapCat 推送。用户发来的 QQ 消息随时可能到达, 到达后它立刻注入给 agent。
如果把本插件改成按需加载:
- 内核启动时它不会被拉起
- 没有人会去拉起它 —— 因为没有人知道有消息在等着
- 结果:QQ 消息静默丢失,用户以为 agent 不理他
所以 auto_start 必须保持默认(true)。这不是性能取舍,是功能正确性。
工具
| 工具 | 用途 |
|---|---|
qq_get_message |
按 message_id 取单条正文(消息刚到时先用它) |
qq_get_history |
按会话拉最近历史(群聊传 group_id,私聊传 user_id) |
qq_list_chats |
会话列表,按最新消息排序,带未读数与摘要 |
qq_mark_read |
清零某会话未读数 |
output_send__qq |
主动发消息(群/私聊由 meta 决定) |
★★ 拉私聊历史:只传 user_id,不要传 group_id
这是本插件最容易踩的坑,已经真实咬过人(2026-10-19 连续 13 次调用全失败):
qq_get_history(user_id=2198972886) ✅ 拉私聊
qq_get_history(group_id=123456) ✅ 拉群聊
qq_get_history(group_id=0, user_id=2198972886) ❌ 报「消息undefined不存在」
为什么容易错:qq_get_message 取回一条私聊消息时,QQ 协议里群号
就是 0。如果返回体带了这个字段,把它原样抄进 qq_get_history 就会去查
"群 0" —— 而群 0 不存在,NapCat 只会回一句含糊的
retcode=200 消息undefined不存在,看起来像"历史拉不到",其实是参数用错。
现在的行为(已修):
- 私聊消息的返回体不再包含
group_id—— 没这个字段就别去抄它 - 后端把
group_id=0判为"未提供",走私聊端点 - 两个都传会直接报错并说明"只能二选一",而不是静默选错分支
判断该传哪个:看消息来源。私聊注入会带 user_id=...;群聊注入带
group_id=...。拿不准就先 qq_list_chats,它会标明每个会话是群还是私聊。
常见报错怎么读
| 现象 | 含义 | 怎么办 |
|---|---|---|
消息undefined不存在 |
通常是把私聊当群聊查了(group_id=0 或群号错) | 私聊改传 user_id,别传 group_id |
message_id 可能已过期 |
NapCat 侧短号有时效(约 7 天) | 改用 qq_get_history 按会话拉 |
只能访问当前 QQ 会话 |
权限门:非 owner 只能读本轮会话 | 不是 bug;需要跨会话请让 owner 操作 |
注意
- 依赖 NapCat 服务在运行且已登录。
- 消息可能过期(NapCat 侧有时效),发送失败时会明确报错。
- 不要在群里 @全体成员、不要连续刷屏。
★ 用 plugin_stop / plugin_start,不要用 plugin_disable / plugin_enable
四个工具看着像同义词,语义差别很大:
| 工具 | 作用 | 跨重启 |
|---|---|---|
plugin_stop |
运行态关闭,现在停掉 | 不影响,重启照常加载 |
plugin_start |
运行态拉起,现在开回来 | 不影响 |
plugin_disable |
持久禁用 | 会记下来,开机也不自启 |
plugin_enable |
解除持久禁用 | 会记下来 |
释放上下文用 plugin_stop。 用 plugin_disable 会顺手把"开机自启"
永久关掉 —— 用户下次开机发现插件没了,得再手动开回来。
(本插件没有声明 auto_start: false,即按契约默认自启 —— 这是对的,
它必须常驻。所以这里更要小心:plugin_disable 会写进持久禁用清单,
让重启后的自启也失效,只能再用 plugin_enable 解。)