omp packages

pi-qq-integration0.5.3

QQ integration for pi — control pi from QQ | pi QQ 集成 — 在 QQ 中操控 pi

nu11dev Published 2 months ago MIT ~403 downloads/mo

Untested on omp

This is a pi package. No one has reported whether it works on omp yet. If you try it, add your result below.

Did it work for you?

Result

One report per person. A new report replaces your old one.

Reports 0

No reports yet.

Readme

English

pi-qq-integration — 中文版

在 QQ 中操控 pi。安装此扩展后,pi 启动时会自动加载扩展并默认自动连接 QQ Bot(可在配置中关闭)。连接后即可通过 QQ 向 pi 发消息、查看 session 列表、浏览历史对话;也可随时用 /qq-connect、/qq-disconnect 手动控制连接。


安装

pi install npm:pi-qq-integration

快速开始

1. 注册 QQ Bot

在 QQ 开放平台 创建一个机器人应用,获取 AppID 和 AppSecret。

2. 创建配置文件

创建 ~/.pi/agent/qq-integration-config.json:

{
  "appId": "你的 AppID",
  "appSecret": "你的 AppSecret"
}

3. 启动 pi

pi

扩展加载后,pi 会话启动时会自动连接 QQ Bot(默认行为)。如需关闭自动连接,在配置文件加 "autoConnect": false 后重启 pi,再用 /qq-connect 手动连接;断开用 /qq-disconnect。

现在在 QQ 中给机器人发消息,就能和 pi 对话了。


配置项(qq-integration-config.json)

配置文件路径:~/.pi/agent/qq-integration-config.json(位于 pi 的 agent 数据目录,与扩展代码目录无关)。

顶层字段

字段 类型 必填 默认值 说明
appId string ✅ — QQ 开放平台机器人应用的 AppID
appSecret string ✅ — QQ 开放平台机器人应用的 AppSecret(敏感,勿提交 git)
instanceId string ❌ PID 多实例下本实例的唯一 ID(默认取进程 PID,用于 #to <PID> 切换与消息署名)
role "auto" | "leader" | "follower" ❌ "auto" 多实例角色:auto 由文件锁自动选举;leader 强制持有 QQ 连接;follower 强制经 IPC 接入 leader
autoConnect boolean ❌ true pi 启动时是否自动连接 QQ Bot;设为 false 则需手动 /qq-connect
allowedUsers string[] ❌ — 允许向 pi 发 prompt 的 c2c 用户 openid 白名单。未配置则放行所有私聊消息(会输出安全告警)。强烈建议配置,以防远程提示词注入
allowedGroups string[] ❌ — 允许向 pi 发 prompt 的群 openid 白名单。未配置则放行所有 @机器人消息

settings 字段(转发设置)

字段 类型 默认值 说明
forwardDesktopMessages boolean false 桌面端(pi 终端)输入的消息是否转发到 QQ
forwardToolCalls boolean false 工具调用及其结果是否转发到 QQ(与 lastMessageOnly 互斥;开启一个会自动关闭另一个,配置文件与 #settings 均强制)
lastMessageOnly boolean false 只转发整次 agent 运行的最后一条 assistant 回复(与 forwardToolCalls 互斥;开启一个会自动关闭另一个)
defaultSession object | undefined undefined 默认 QQ 转发目标。收到 QQ 消息时会自动更新为该消息来源会话;也可由 /qq-target 或 QQ #target 设置

settings 内的字段既可在配置文件里静态写死,也可在 QQ 内用 #settings 命令动态调整并持久化。#settings 命令对前两个开关使用了简写别名:forwardMessages 对应 forwardDesktopMessages,forwardTools 对应 forwardToolCalls。

完整示例

{
  "appId": "你的 AppID",
  "appSecret": "你的 AppSecret",
  "autoConnect": true,
  "role": "auto",
  "settings": {
    "forwardDesktopMessages": false,
    "forwardToolCalls": false,
    "lastMessageOnly": false
  }
}

环境变量

变量 说明
QQ_INTEGRATION_DATA_DIR 覆盖数据目录(默认 ~/.pi/agent)
QQ_API_BASE 覆盖 QQ API 域名(默认 https://api.sgroup.qq.com)
QQ_TOKEN_API 覆盖 Token API 地址(默认 https://bots.qq.com/app/getAppAccessToken)

多实例

同时运行多个 pi 实例时,用文件锁选举唯一的 leader 持有 QQ 连接;其余实例作为 follower 经本地 IPC 把 QQ 收发委托给 leader(macOS/Linux 用 Unix socket,Windows 用命名管道)。

  • role: "auto"(默认):谁先抢到锁谁是 leader,其余自动成为 follower。
  • role: "leader" / "follower":强制角色。follower 即使 leader 宕机也不会尝试接管成为 leader。
  • instanceId:默认即进程 PID,同时作为实例署名与 #to <PID> 定向路由的标识;仅在需要固定 ID 时手动设置。

消息署名 — 所有发往 QQ 的消息都会带一段引用块署名,标明消息来自哪个实例:

> 【session名-3863】

<消息内容>

(session 名为当前 pi session 名;未命名时署名为 > 【PID】。)该署名同时是引用消息路由的兜底依据(见下)。

引用消息定向路由 — 在 QQ 中引用(回复)某条消息时,消息会自动路由回发送被引用消息的那个实例(基于 ref_idx 映射,60 分钟 TTL;未命中时按被引用内容中的署名唯一匹配兜底)。也就是说,想给某个特定实例发消息,直接引用它之前发的消息回复即可。


架构

QQ 用户
  │
  ├─ 发消息 → QQ Bot 服务器 → WebSocket
  │                                │
  │                     ┌──────────▼──────────┐
  │                     │  pi-qq-integration  │
  │                     │  ws-client.ts       │
  │                     │    ↕ WebSocket      │
  │                     │  command-handler.ts │
  │                     │    ↕ #cmd 解析      │
  │                     │  index.ts           │
  │                     │    ↕ sendUserMessage│
  │                     └──────────┬──────────┘
  │                                │
  │                     ┌──────────▼──────────┐
  │                     │      pi 引擎         │
  │                     │   处理 prompt 并回复   │
  │                     └──────────┬──────────┘
  │                                │
  └─────── REST API ←──── 回复内容

两个独立通道:

  • WebSocket — 接收 QQ 消息(长连接,带心跳和断线重连)
  • REST API — 发送回复到 QQ,按会话类型 POST 到对应端点:/v2/users/{openid}/messages(c2c)、/v2/groups/{group_openid}/messages(群)、/channels/{channel_id}/messages(频道)

pi Slash 命令

命令 说明
/qq-connect 手动连接 QQ Bot
/qq-disconnect 断开 QQ Bot 连接
/qq-status 查看连接状态概览(角色、锁、WebSocket、Token)
/qq-diagnose 查看详细诊断信息
/qq-logs 查看最近 30 条日志
/qq-logs-path 查看日志文件路径
/qq-logs-clear 清空日志文件
/qq-target 设置/查看默认 QQ 转发目标

QQ 命令

在 QQ 中给机器人发送的消息,如果不以 # 开头,会直接作为 prompt 发给 pi。

命令 说明
#help 显示帮助
#sessions [页码] 跨项目列出全部 session,每页 10 条,最近使用在前
#history [N] 查看当前实例 session 的最近 N 条消息(默认 5)
#target 将当前 QQ 会话设为默认转发目标
#settings 查看/修改转发设置(#setting 为别名)
#instances 列出在线实例(ID、角色、认领会话的名字/最近消息摘要)
#to <PID/名称> [内容] 查看当前绑定实例 / 切换会话到指定实例 / 向指定实例定向发送内容
#create <序号/名称> 创建新实例并复用指定 session
#create new [--dir <目录>] 创建全新 session 的新实例(可指定工作目录)
#close <PID> [PID...] 关闭实例(支持空格分隔多个 PID)

桌面端消息转发

开启桌面端转发(#settings forwardMessages on)后,桌面端输入的消息会同步转发到 QQ。目标按优先级选择:

  1. 最近一条 QQ 消息来源的会话(收到 QQ 消息时会自动更新 defaultSession)
  2. 手动设置的默认目标(/qq-target 或 QQ #target)——仅在尚未收到任何 QQ 消息时生效

注: 从 QQ 转发进 pi 的消息会带来源标签前缀(私聊 [QQ]、群聊 [QQ群])。该前缀也用于识别并跳过桌面端回响,避免转发回环。

/qq-target c2c <用户openid> [备注]        # 私聊(备注可选)
/qq-target group <群openid> [备注]         # 群聊
/qq-target channel <频道id> [备注]         # 频道
/qq-target                                 # 查看当前目标(别名:show)
/qq-target clear                           # 清除

#settings 示例

你: #settings
Bot: ## ⚙️ QQ Bot 设置
     | 选项 | 状态 | 说明 |
     | forwardMessages | ❌ 关 | 桌面端消息转发到 QQ |
     | forwardTools | ✅ 开 | 工具调用转发到 QQ |
     | lastMessageOnly | ❌ 关 | 只转发整次回复的最后一条 assistant 回复 |

你: #settings forwardTools on
Bot: ✅ **工具调用转发** 已开启,同时 `lastMessageOnly` 已自动关闭。

你: #settings lastMessageOnly on
Bot: ✅ **只转发最后一条回复** 已开启,assistant 整次运行仅发送一条最终回复;`forwardTools` 已自动关闭。

文件结构

pi-qq-integration/
├── index.ts              # 入口:初始化、事件、slash 命令
├── constants.ts          # 集中常量(路径、URL、超时值)
├── config.ts             # 配置文件读写(原子写入)
├── auth.ts               # Token 管理 + 自动刷新
├── lock.ts               # 文件锁(O_EXCL 原子创建)
├── ws-client.ts          # WebSocket 客户端
├── api-client.ts         # REST API 客户端
├── ipc.ts                # IPC(leader-follower 委派;Unix socket / Windows 命名管道)
├── registry.ts           # 实例注册表(原子写入)
├── routing.ts            # 引用消息路由纯函数(ref_idx + 署名兜底)
├── validation.ts         # session/sessionKey 校验、参考名清洗
├── session-manager.ts    # Session 浏览
├── command-handler.ts    # #命令解析
├── logger.ts             # 文件日志(自动截断)
├── types.ts              # 类型定义
└── package.json

多实例细节

~/.pi/agent/
├── qq-integration.lock          # 文件锁(O_EXCL 原子创建)
│   └─ JSON: { pid, startedAt, heartbeatAt } (心跳每 30 秒更新)
└── qq-integration/
    ├── registry.json             # 实例注册表(原子写入)
    └── instances/
        └── <pid>.sock            # IPC Unix socket(leader;Windows 为命名管道)
  • 第一个实例获取锁 → 成为 leader → 连接 QQ Bot
  • 后续实例检测到锁 → 成为 follower → 通过 IPC 连接 leader
  • leader 崩溃或退出后 PID 失效 → follower 在重连循环中自动接管锁升级为 leader(故障转移);role: follower 强制跟随时不升级
  • leader 宕机期间 follower 静默重试(仅写日志,不刷 UI 提示),连接恢复时才通知

日志

所有调试日志写入 ~/.pi/agent/qq-integration.log。使用 /qq-logs 查看最近 30 条,/qq-logs-path 查看路径。日志文件达到 5 MB 自动截断。


注意事项

  1. Token 安全 — Token 有效期约 2 小时,自动刷新。连续 3 次刷新失败后自动断开并通知。
  2. 消息频率 — 主动消息每月每用户/群限 4 条(QQ 官方平台限制),被动回复较宽松。
  3. Session 管理 — 用 #create 创建新实例(复用 session 或全新开始),#sessions 列出全部 session,#close 关闭实例。实例内不再支持会话切换(用 #create + #to 替代)。
  4. 设置持久化 — #settings 变更保存到配置文件,/reload 不丢失。
  5. 群聊消息 — 仅接收 @机器人的消息。
  6. 配置文件 — 含 AppSecret,勿提交 git。

开发

cd ~/.pi/agent/extensions/pi-qq-integration
npm install          # 安装依赖
npm run build        # 编译 TypeScript
npm run typecheck    # 仅类型检查
npm test             # 运行测试套件(node:test,无额外开发依赖)
# 编辑代码后在 pi 中 /reload 热重载

依赖 — 唯一的运行时第三方依赖是 ws(WebSocket 客户端,用于 ws-client.ts),其余全部使用 Node.js 内置模块。


贡献者

Star-233 illusionlie

感谢 @illusionlie 报告 Windows IPC bug (#1) 并提交修复 PR (#2)。