Skip to content

文档同步

本页由 plugins/adapters/icqq/README.md 自动生成。请修改包内 README 后运行 pnpm sync:adapter-docs

@zhin.js/adapter-icqq

ICQQ Plugin Runtime 适配器 — 进程内直接使用 @icqqjs/icqq Client

功能特性

  • 群聊 / 私聊 / 群临时会话 / QQ 频道消息
  • 入站:ICQQ Client 原始事件经 Endpoint.emit(...) 唯一入口上送;文本与图片 / 语音 / 视频 / 文件统一归一为 canonical Segment + MediaRef
  • 出站:canonical Segment 直接投影为 ICQQ 原生 Sendable,再由 sendGroupMsg / sendPrivateMsg / …发送
  • 群聊 reaction:control.addReaction / removeReaction(协议 ACK 失败不阻塞后续发送)
  • Agent 工具:包根 tools/@zhin.js/tool Feature;模型侧名为 icqq__send_user_like 等)
  • Console Endpoint 管理:src/endpoint.ts 显式实现 EndpointManagement(好友/群/群成员列表、请求审批、删好友、踢人、禁言、设管理)

安装

bash
pnpm add @zhin.js/adapter-icqq @icqqjs/icqq
# 可选:未配置 signApiAddr 时走本地签名
pnpm add @icqqjs/qqsign

@icqqjs/icqq 是适配器的可选对等依赖peerDependencies + optional)。应用侧需自行安装;monorepo 内另在 devDependencies 声明以便构建/测试。

@icqqjs/* 发布在 GitHub Packages,需:

ini
@icqqjs:registry=https://npm.pkg.github.com
//npm.pkg.github.com/:_authToken=${NPM_TOKEN}

并设置具有 read:packages 权限的 NPM_TOKEN(CI 使用仓库 secret PERSONAL_TOKEN)。

签名:未配置 signApiAddr 时,若已安装 @icqqjs/qqsign 则自动走本地签名。

前置条件

  1. 准备可登录的 QQ 账号,并选择远程 signApiAddr 或安装本地 @icqqjs/qqsign
  2. 确保运行目录可持久化设备与登录状态;容器部署应挂载对应数据目录。
  3. 首次登录可能要求二维码、滑块或设备确认,可在 Console 登录待办或终端完成。

配置(Plugin Runtime)

yaml
plugins:
  icqq:
    master: "1659488338"        # 必填,顶层共享(/approve 与 master 角色)
    autoReconnect: true
    endpoints:
      - id: "${ICQQ_ACCOUNT}"   # QQ 号
        # password: "${ICQQ_PASSWORD}"  # 可选;不填则扫码登录

多账号:一个插件实例挂多个 endpoint(endpoints 数组逐项覆盖顶层字段,id 必填):

yaml
plugins:
  icqq:
    master: "1659488338"
    endpoints:
      - id: "${ICQQ_ACCOUNT}"
      - id: "${ICQQ_ACCOUNT_2}"
      - id: "${ICQQ_ACCOUNT_3}"

Send conversation

类型conversation
私聊{ kind: 'private', id: uin }
群聊{ kind: 'group', id: gid }
群临时会话{ kind: 'private', id: uin, parent: { kind: 'group', id: gid } }
频道{ kind: 'channel', id: channelId, parent: { kind: 'channel', id: guildId } }

直接使用完整 ICQQ Client

适配器把 icqq 注册为 @icqqjs/icqq.Client 与 SDK EventMap 的类型判别项。 所有 Feature 都使用同一个 adapter 字段完成类型缩窄与运行时过滤:

ts
import { defineHandler } from 'zhin.js/handler'
import '@zhin.js/adapter-icqq'

export default defineHandler({
  adapter: 'icqq',
  event: 'request.group.add',
  async handle({ client, event }) {
    await client.setGroupAddRequest(event.flag, true)
  },
})

client 就是当前账号的真实 ICQQ SDK 实例,不是 Endpoint facade。未知扩展事件可显式使用 event: '*';此时 Client 类型保持完整,事件 payload 为 unknown。普通消息回复仍应走 Message.$reply;群管理、请求审批与 ICQQ 专属查询可直接调用当前事件的 client

Command context 的 $client 是按需读取的 getter:

ts
export default defineCommand({
  adapter: 'icqq',
  async execute(context) {
    await context.$client.sendLike(Number(context.sender!.id), 10)
    return 'ok'
  },
})

Middleware 使用同一个判别字段;不声明 adapter$client 的类型是 unknown

ts
export default defineMiddleware<Message>({
  target: 'inbound',
  adapter: 'icqq',
  async handle(context, next) {
    console.log(context.$client.uin, context.input.content)
    await next()
  },
})

Agent tool 的 IM turn 同样直接读取当前 Client:

ts
export default defineAgentTool({
  adapter: 'icqq',
  description: '获取群列表',
  async execute(_input, context) {
    return context.$client.getGroupList()
  },
})

adapter 缺失时 $client 静态类型为 unknown;声明后若实际 operation 不属于 ICQQ, 运行时会在执行前拒绝。Client 只能在当前 operation 内使用。task、schedule 或 Host 等脱离 IM turn 的场景,才使用 icqqClient.get(context, endpointId) 显式选择账号。

架构

  • plugin.ts + adapters/icqq.tsdefineAdapter
  • Client token:src/client.ts(直接引用 ICQQ Client / EventMap
  • Endpoint:src/endpoint.ts(组合 ICQQ Client,负责账号 transport 与 Zhin lifecycle)
  • 协议常量 / 配置:src/protocol.ts
  • Agent 工具:tools/*.ts;权限说明见 agent/PERMITS.md

Plugin Runtime 迁移说明

  • 不再经过 @icqqjs/cli IPC 守护进程;登录态与协议栈都在本进程。
  • autoReconnect:Client 断线后按配置自动重连(stop() 为主动断开,不触发重连)。
  • outboundMedia: file | base64file 在发送期间把 segment base64 物化为临时文件并于发送结束清理;base64 使用 ICQQ 原生支持的 base64:// file 参数。
  • ICQQ 的语音、视频、文件是独立消息元素;它们与其他段混发时适配器会明确拒绝,避免协议栈静默丢段。
  • 入站语音 / 视频在 Endpoint 持有原生 Client 时解析可下载 URL;解析失败则保留真实平台引用,不伪造或丢弃媒体。
  • Console 社交/群管 RPC 已接线:endpoint 把好友/群/群成员列表、请求审批和群管操作归一化为冻结的 EndpointManagement。Host 只消费该语义端口。
  • 好友/入群请求与通知:经 the unified Endpoint.emit(...) ingress 分发到 handlersnotice.receive / request.receive);审批走 Request.$approve / EndpointManagement.approveRequest。Console request.list 优先读 management.listRequests()getSystemMsg),不再写入 unified_inbox_request/notice
  • system.*(登录扫码等)分发到 system.receive
  • 登录辅助system.login.qrcode|slider|device|authloginAssistTokenLoginAssist)挂起待办;刷新后可用 Console login.list / login.submit 或终端 stdin 继续(对齐 icqq 官方 stdin 流程)。system.online / login.error 会清理该 endpoint 待办。

故障排查

现象排查
一直停在登录中打开 Console 登录待办,完成二维码、滑块或设备确认
签名失败检查 signApiAddr;本地模式确认 @icqqjs/qqsign 已安装且版本匹配
重启后重复登录持久化设备与会话数据目录,避免每次生成新设备
请求或通知未显示在 Endpoint 详情检查请求视图;ICQQ 优先读取平台请求列表

License

MIT