feat(services): 新增 QQ OneBot 适配器 (services/qq-bot)#1668
feat(services): 新增 QQ OneBot 适配器 (services/qq-bot)#1668PhoenixForrestLin wants to merge 31 commits intomoeru-ai:mainfrom
Conversation
⏳ Approval required for deploying to Cloudflare Workers (Preview) for stage-web.
Hey, maintainers, kindly take some time to review and approve this deployment when you are available. Thank you! 🙏 |
|
只有一个commit是我的失误😂,我之前忘记配gitignore了,不小心把API KEY和涉及我隐私的AI聊天记录传进去了,所以后面直接重新fork重新上传了,我发现似乎还有一些环境配置没搞好,我现在解决 |
There was a problem hiding this comment.
Code Review
This pull request introduces the services/qq-bot service, a QQ OneBot adapter built for Project AIRI. The implementation includes a 7-stage message pipeline, SQLite-based persistence, and integration with the AIRI server. My review identified several areas for improvement: the Dockerfile requires a multi-stage build for production readiness, dependencies should be pinned to avoid breaking changes, and internal library access should be avoided in favor of public APIs. Additionally, I recommended improving type safety by replacing any types with explicit interfaces and correcting language identifiers in documentation.
There was a problem hiding this comment.
Pull request overview
This PR introduces a new services/qq-bot service to add QQ platform support for AIRI via the OneBot V11 protocol (NapCat + NapLink), implementing a staged pipeline to normalize events, apply rules (wake/rate-limit/context), call AIRI server for LLM replies, and dispatch responses.
Changes:
- Added a full QQ OneBot adapter service with config loading (Valibot + YAML), logging, NapLink client wiring, and a multi-stage message pipeline.
- Implemented persistence and context features (SQLite message history, conversation tracking, semantic retrieval + optional compression).
- Added deployment scaffolding and docs (Dockerfile, docker-compose, example config, README, Copilot instructions).
Reviewed changes
Copilot reviewed 51 out of 52 changed files in this pull request and generated 11 comments.
Show a summary per file
| File | Description |
|---|---|
| services/qq-bot/tsconfig.json | TypeScript compiler configuration for the service. |
| services/qq-bot/package.json | Service package manifest and dependencies (NapLink, libsql, tokenizer, valibot, etc.). |
| services/qq-bot/Dockerfile | Container build for running the service. |
| services/qq-bot/docker-compose.yaml | Compose setup for running the service container. |
| services/qq-bot/config.example.yaml | Example YAML configuration for users. |
| services/qq-bot/README.md | Service documentation and setup guide. |
| services/qq-bot/.gitignore | Ignores local config and data artifacts. |
| services/qq-bot/.env | Local env file placeholder. |
| services/qq-bot/.github/copilot-instructions.md | Service-specific contributor/Copilot guidance. |
| services/qq-bot/airi-client.ts | Root barrel export for src/airi-client. |
| services/qq-bot/src/index.ts | Runtime entrypoint wiring config/logging/db/client/pipeline and graceful shutdown. |
| services/qq-bot/src/config.ts | Valibot schemas + YAML loading + runtime validation/defaults. |
| services/qq-bot/src/client.ts | NapLink client factory and a createBot composition-root style API. |
| services/qq-bot/src/airi-client.ts | AIRI server SDK channel wrapper and event logging hooks. |
| services/qq-bot/src/normalizer/index.ts | NapLink event → internal QQMessageEvent normalization. |
| services/qq-bot/src/dispatcher/index.ts | Converts internal ResponsePayload into NapLink API calls with retry/delay. |
| services/qq-bot/src/types/index.ts | Barrel exports for internal types. |
| services/qq-bot/src/types/context.ts | Pipeline blackboard types (PipelineContext, StageResult, OpenAIMessage, etc.). |
| services/qq-bot/src/types/event.ts | Unified event model QQMessageEvent and sessionId helper. |
| services/qq-bot/src/types/message.ts | Strongly-typed OneBot message segment unions + chain utilities. |
| services/qq-bot/src/types/response.ts | Response payload union + factory helpers + text merging utility. |
| services/qq-bot/src/pipeline/stage.ts | Base stage abstraction (timing/logging/error wrapper). |
| services/qq-bot/src/pipeline/extensions.ts | Typed cross-stage extensions contract and rules. |
| services/qq-bot/src/pipeline/filter.ts | Stage ①: basic filtering (system/bw-list/empty message). |
| services/qq-bot/src/pipeline/wake.ts | Stage ②: wakeup decision (private/@/reply/keyword/random). |
| services/qq-bot/src/pipeline/rate-limit.ts | Stage ③: sliding-window rate limits + cooldown. |
| services/qq-bot/src/pipeline/session.ts | Context injection stage (recent history + semantic retrieval). |
| services/qq-bot/src/pipeline/conversation.ts | Conversation persistence + optional compression + token usage tracking. |
| services/qq-bot/src/pipeline/process.ts | Core stage: commands + send to AIRI server + wait for reply. |
| services/qq-bot/src/pipeline/decorate.ts | Post-processing stage: filtering/replacement/splitting/reply behavior. |
| services/qq-bot/src/pipeline/respond.ts | Final stage that triggers dispatch of context.response. |
| services/qq-bot/src/pipeline/passive-record.ts | Passive capture of message history into memory + DB + embeddings. |
| services/qq-bot/src/pipeline/plugins.ts | Plugin registration/listing for processing hooks. |
| services/qq-bot/src/pipeline/runner.ts | Orchestrates the pipeline stages and dispatch flow. |
| services/qq-bot/src/db/index.ts | SQLite/libsql initialization + schema (history, conversations, embeddings). |
| services/qq-bot/src/db/message-history-repo.ts | Message history repository APIs (insert/query/prune/list). |
| services/qq-bot/src/db/conversation-repo.ts | Conversation repository APIs (create/switch/update/delete/list). |
| services/qq-bot/src/context/embedding-provider.ts | Embedding provider interface + Bailian implementation. |
| services/qq-bot/src/context/semantic-retriever.ts | sqlite-vec retrieval with fallback to brute-force scan. |
| services/qq-bot/src/context/compressor.ts | Context compression (truncate or LLM summary via AIRI channel). |
| services/qq-bot/src/agent/loop.ts | Optional proactive AgentLoop using unread DB history + AIRI decision. |
| services/qq-bot/src/commands/types.ts | Command handler typing. |
| services/qq-bot/src/commands/index.ts | Command registry creation from config enabled list. |
| services/qq-bot/src/commands/help.ts | Built-in help command. |
| services/qq-bot/src/commands/status.ts | Built-in status command. |
| services/qq-bot/src/commands/clear.ts | Built-in clear command (delegates actual clearing to runner flag). |
| services/qq-bot/src/utils/logger.ts | Two-phase logger with registry + optional ANSI colors. |
| services/qq-bot/src/utils/naplink-logger-adapter.ts | Adapts internal logger to NapLink logger interface. |
| services/qq-bot/src/utils/rate-limiter.ts | Sliding window limiter + cooldown tracker utility. |
| services/qq-bot/src/utils/message-buffer.ts | Ring buffer for per-session message history. |
| services/qq-bot/src/utils/chain-serializer.ts | Serializes message segments into single-line context text. |
| services/qq-bot/src/utils/token-estimator.ts | Local token estimation using gpt-tokenizer. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 9efb7e54a0
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 20bc27d6ea
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 896352b22d
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 23348d0a4d
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 7a7d7999a5
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 60e53a22e8
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
|
我发现给AIRI提供历史聊天数据的时候似乎忘记给他提供时间戳了,导致他只能看到消息的先后顺序没法看到时间 |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 5038ccf0e0
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 5559a805c0
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
|
我着手修改一下文档,主要是增加 |
|
额,搞错了,这个 commit 其实是根据 |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: f814f54a73
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
| if (event.context.rateLimitPassed) | ||
| this.rateLimitStage.startCooldown(event.source.sessionId) |
There was a problem hiding this comment.
Skip cooldown when response is silent
ProcessStage explicitly emits createSilentResponse() when AIRI send/reply fails, but PipelineRunner starts the per-session cooldown for every respond action regardless of payload kind. In those failure paths, dispatcher.send() is a no-op, so users receive no message yet their next retry in the same session can be dropped by cooldown, which makes transient AIRI outages look like persistent bot silence. Gate cooldown on non-silent payloads (or successful dispatch of an actual message).
Useful? React with 👍 / 👎.
|
我在想,我的 QQbot 的群聊部分是不是比重太大了 |
|
我觉得我可以砍掉一部分群聊功能,专注做私聊部分 |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 32628ff417
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
| const decisionSessionId = `${sessionId}${AGENT_SESSION_SUFFIX}` | ||
| const prompt = this.buildDecisionPrompt(unread) |
There was a problem hiding this comment.
Use unique correlation IDs for agent-loop decisions
The proactive loop reuses a constant decisionSessionId per session (${sessionId}:agent-loop) and keys pendingReplies by that value, so a delayed response from an earlier timed-out decision can incorrectly resolve a later decision request for the same group. This can make the bot act on stale context (e.g., send or suppress proactive replies based on an old batch) whenever AIRI responses arrive late or out of order. Use a per-request correlation key (and echo it in overrides) instead of a stable per-session key.
Useful? React with 👍 / 👎.
| return null | ||
|
|
||
| const { prefix, enabled } = commandConfig | ||
| const text = event.text.trim() |
There was a problem hiding this comment.
Parse commands from chain after removing @bot mentions
WakeStage removes @bot segments from event.chain, but command parsing still uses event.text from raw input. For mention-prefixed commands in groups (for example, users sending @bot /help), text.startsWith(prefix) fails and the command falls through to LLM processing instead of the built-in handler. Command parsing should derive text from the normalized chain (or keep event.text synchronized) so mention cleanup actually affects command detection.
Useful? React with 👍 / 👎.
|
我需要重构一部分代码,对私聊功能做一等公民支持,同时优化聊天记录存储,对话流 |
概述
为 AIRI 新增 QQ 平台支持,基于 OneBot V11 协议,通过 NapLink SDK 以正向 WebSocket 连接 NapCat,采用 7 阶段流水线架构处理消息。
动机
AIRI 目前已有 Telegram 和 Discord 适配器,但缺少 QQ 平台的接入。QQ 拥有大量中文用户群体,本 PR 补齐这一空缺。
架构设计
四大模块
QQMessageEvent流水线阶段
@xsai/generate-text)设计原则
类型架构亮点
switch(seg.type)自动窄化InputMessageSegment(含 ReplySegment)用于输入侧,OutputMessageSegment(不含)用于输出侧;ReplySegment 仅由 Dispatcher 根据replyTo声明式注入kind判别字段强制 message/forward/silent 三分支互斥,工厂函数 fail-fast 校验PipelineContext、WakeReason、StageResult抽离到types/context.ts,打破 event ↔ stage 环路createLogger()import 时安全调用,initLoggers(config)后统一刷新级别,支持热重载群聊上下文持久化
在设计文档的内存环形缓冲区基础上,额外实现了:
src/db/— 基于 sql.js / libsql 的 SQLite 持久化层message-history-repo.ts— 群聊消息历史持久存储conversation-repo.ts— 会话元数据管理src/context/— 语义检索与上下文压缩embedding-provider.ts— Embedding 生成semantic-retriever.ts— 基于 sqlite-vec 的向量语义检索compressor.ts— 上下文窗口压缩(token 预算内最大化相关信息)src/pipeline/passive-record.ts— 被动记录阶段,所有经过 Filter 的消息均入库src/pipeline/conversation.ts— 会话管理阶段,融合内存缓冲 + DB 持久化 + 语义检索新增文件
依赖
@naplink/naplink— NapCat SDK(正向 WS、类型安全、内置重连)@xsai/generate-text+@xsai/shared-chat— OpenAI 兼容 LLM 调用@proj-airi/server-sdk+@proj-airi/server-shared— AIRI 内部 SDKvalibot— 配置 schema 验证yaml— YAML 配置解析sql.js+@libsql/client+sqlite-vec— 本地持久化 + 向量检索gpt-tokenizer— Token 计数es-toolkit— 工具函数致谢
7 阶段流水线架构深受 AstrBot 启发,本适配器是其架构在 QQ OneBot 场景下的精简版。感谢 AstrBot 团队的开源工作 🙏