opencode-qq-v2
v0.2.0
Published
QQ bot (C2C) <-> opencode bridge plugin (V2 port)
Readme
opencode-qq (V2 适配版)
把 OpenCode 接入 QQ 单聊的桥接插件:在 QQ 里和 AI 对话,驱动 opencode 干活。
本仓库基于 opencode-qq v0.1.0 移植,使其兼容 OpenCode v2(
@opencode/plugin2.x + EffectTS 运行时)。
功能
- 对话驱动 opencode:QQ 单聊消息直达 opencode 会话,AI 回复发回 QQ;每个 QQ 用户对应一个长期会话,重启后延续。
- 图片理解:单聊里发的图片转交给 opencode 多模态处理。
- 任务完成 / 出错推送:opencode 会话完成(✅)或出错(❌)时主动推送到 QQ。
- QQ 远程审批权限:opencode 发出权限请求时直接在 QQ 里回复「同意 / 拒绝」。
- 内置指令:
/new重置会话、/status查看状态、/help帮助。
V2 适配改动(相对原版 v0.1.0)
- 插件入口:
async (input) => Hooks(V1)→Plugin.define({ id, setup(ctx) })(V2 Promise API)。 - 客户端调用:
input.client.session.*→ctx.session.*(create / prompt / switchModel)、ctx.permission.reply、ctx.model.default。 - 事件模型:
message.part.updated→session.text.delta;完成事件session.idle→session.execution.succeeded;session.error→session.execution.failed。 - 工具钩子:
tool.execute.afterHooks 回调 →ctx.tool.hook("execute.after", cb)。 - 取网关地址补鉴权:
GET /gateway现在要求Authorization: QQBot <token>头,原版缺失导致一直 401。 - C2C 消息字段修正:发送者 openid 取
d.author.user_openid(原版误用d.openid),消息 ID 取d.id(原版误用d.msg_id)。 - 配置路径修正:Windows 上
process.env.HOME为空,改用os.homedir()。 - 双加载幂等保护:opencode 启动分两阶段加载本地插件,加
started标志避免重复启动 QQ 网关。 - 回复格式:单聊不支持 markdown 消息类型(
msg_type:2),默认改纯文本;流式stream_messages会产生不完整文本与●收尾标记,默认关闭流式。 - 单实例锁 + 自动接管:QQ 网关对同一 bot 只保留一个活跃连接,多实例会互踢。新增
proper-lockfile跨平台文件锁(锁文件~/.config/opencode/opencode-qq-<appId>.lock):只有抢到锁的实例连接 QQ;其余实例进入待命,每 5 秒重试,宿主退出后自动接管(崩溃则靠 30 秒心跳超时判定僵尸锁后接管)。
安装(本地路径)
- 克隆本仓库到本地,例如
~/.config/opencode/plugins/opencode-qq。 - 安装依赖:
npm install(只需ws)。 - 在
~/.config/opencode/opencode.json的plugin数组中加入本目录的反斜杠绝对路径:
{
"plugin": [
"C:\\Users\\<你>\\ .config\\opencode\\plugins\\opencode-qq"
]
}注意用反斜杠(Windows 原生分隔符),正斜杠会被 opencode 规范化为另一份,导致重复加载。
- 重启 opencode。
配置
创建 ~/.config/opencode/opencode-qq.json:
{
"appId": "你的AppID",
"appSecret": "你的AppSecret",
"sandbox": true,
"allowlist": [],
"model": "deepseek/deepseek-v4-pro",
"markdownReply": false,
"streaming": false,
"events": { "toolProgress": false }
}| 字段 | 默认 | 说明 |
|------|------|------|
| appId / appSecret | 必填 | QQ 开放平台机器人凭据 |
| sandbox | false | 未提审上线的 bot 用 true(沙箱环境);已上线用 false |
| allowlist | [] | openid 白名单,空 = 不限制 |
| model | 无 | 覆盖模型,providerID/modelID;不填用 opencode 全局默认模型 |
| markdownReply | true | 是否用 Markdown 发送(单聊请设 false,否则「该消息类型不支持查看」) |
| streaming | true | 流式打字机(有截断/● 尾巴问题,建议 false) |
| events.toolProgress | false | 是否推送工具执行进度 |
也可用环境变量 QQ_BOT_APPID / QQ_BOT_APPSECRET 代替文件凭据。
多实例行为(单实例锁)
QQ 网关对同一 bot 只保留一个活跃连接,多个 opencode 实例同时连接会互相踢下线。插件用 proper-lockfile 文件锁保证同一 bot 只有一个「宿主」实例连接 QQ。
| 场景 | 行为 | |---|---| | 第 1 个实例启动 | 抢到锁 → 成为宿主 → 连接 QQ | | 第 2 个实例启动 | 抢锁失败 → 待命(不连 QQ,不互踢) | | 宿主正常退出 | 释放锁 | | 宿主崩溃 | 心跳中断,30 秒后锁被判为僵尸锁 | | 待命实例 | 每 5 秒重试抢锁,成功后自动接管 |
- 锁文件:
~/.config/opencode/opencode-qq-<appId>.lock,按 AppID 隔离,不同 bot 互不影响。 - 心跳:宿主每 10 秒刷新一次锁,证明自己还活着。
- 僵尸锁:30 秒无心跳视为宿主已死,待命实例可抢占。
- 接管空窗:宿主退出后,待命实例最多 5 秒(重试间隔)内接管,QQ bot 短暂下线几秒后自动恢复。
前置条件
- 在 QQ 开放平台 创建机器人,拿到 AppID 与 AppSecret。
- 未上线阶段需在管理端配置沙箱单聊账号,并把
sandbox设为true。 - 正式环境需在管理端填写服务器公网出口 IP 白名单。
日志
调试日志写入 ~/.config/opencode/opencode-qq.log,包含网关连接、消息收发、会话处理全链路,便于排查。
License
MIT
