
# QQ Agent Plus
A QQ group-chat agent for Linux servers, with split-bubble replies, sticker support, long-term memory and a built-in operations CLI.
[](https://github.com/sakurawwwxh/qq-agent-plus/actions/workflows/ci.yml)
[](LICENSE)
[](https://github.com/sakurawwwxh/qq-agent-plus/stargazers)
[](https://github.com/sakurawwwxh/qq-agent-plus/commits/main)
[](package.json)
[](docs/LINUX.md)
[](https://github.com/botuniverse/onebot-11)
[](#highlights)
[简体中文](README.md) | **English**
QQ Agent Plus is a QQ group-chat agent for Linux servers. It connects to an external OneBot v11
service and runs each turn as an isolated OpenAI Chat Completions session; it does not depend on
DSH, MCP, Electron or a Windows runtime.
## Highlights
Every capability below originates from a failure observed in a production group chat; the failure
mode and its resolution are recorded in [CHANGES](docs/CHANGES.md).
- **Conversation behaviour** — split replies across bubbles, judge image sentiment before
replying, keep the sticker catalogue in the system prompt, self-check before finishing.
- **Send path** — retry transient network failures, QQ system faces, message-id normalisation,
fallback parsing for inline tool calls.
- **Network fetch** — all host-side fetches go through `safe-fetch`. HTTPS GETs and media downloads
prefer HTTP/2 (ALPN), falling back to HTTP/1.1 when the server or connection cannot use it. DNS
pinning, private-address blocking, per-hop redirect validation, cross-origin credential stripping,
body/decompression caps and timeouts remain in force. POST stays on HTTP/1.1 to avoid duplicate
writes. Cloudflare sites that challenge HTTP/1.1 (e926/e621) now work.
- **Sticker system** — auto-collect with QQ favourites first, fuzzy lookup fallback, sync guard so
an API failure cannot wipe the local library.
- **Games & reminders** — hosts mini-games: stateless ones run straight from the prompt (word chain,
guess-the-number, 20 questions, truth-or-dare), with `dice` plus the group member list for rolls, draws
and random picks; a **state-machine host** covers turn-based multiplayer games (number bomb,
who-is-the-spy, werewolf — turns, vote counting and verdicts live in code, identities and night
actions travel by private message only and never enter the model context; experimental, off by
default, werewolf additionally needs to be whitelisted in the console). "Remind me at X"
becomes a **persistent reminder** (survives restarts); it supports daily / weekly / 5-field cron
schedules with an IANA timezone, a quiet-hours window and jitter, and only the most recent
missed occurrence is caught up. It is delivered in its own voice when the time comes.
- **Proactive talk** — three independently switchable links (cold-topic opener / follow-up
nudge when nobody answers / model-scheduled wake-up), multiple active windows. Group and
private proactive loops keep separate timers, rolls and last-attempt state, so one scope
cannot consume the other's chance. Interval guard, skip-reason logging, catch-up for messages
missed during restarts.
- **Life feed** — optionally forages Bilibili's public API, ranks candidates by the persona's
interests and recent group topics, and lets the bot choose what to share. Off by default; it
reuses the existing proactive quiet hours, budget and send queue. See [LIFE-FEED](docs/LIFE-FEED.md).
- **Model access** — thinking levels translated per channel preset, settable per provider and per
task (Settings -> Model API -> "Advanced: thinking"), retry on provider moderation refusals,
automatic fallback model.
- **Speech & video input** — voice/audio files and video soundtracks are transcribed before they
reach the chat model (no multimodal requirement). Hosted ASR by default (SiliconFlow endpoint
preset: paste one key, pull the model list once); switchable to Groq / Volcano Seed-ASR /
Alibaba / iFlytek / Tencent / Baidu / self-hosted, most with free tiers for new users. Also
**keyless local whisper.cpp** (offline, free, one click to install or fully remove in the
console, or `node scripts/install-asr-local.mjs`). QQ voice (SILK) is decoded locally — no
protocol-side transcoding; videos also get a 2x2 frame strip for the vision model plus separate
soundtrack transcription, so it sees and hears. With a TTS endpoint configured (off by default)
it can also reply by voice — OpenAI-compatible endpoints plus Volcano (v1) / Doubao 2.0 / MiniMax presets.
ASR keys are configured separately from search;
an hourly quota gate applies, and muted-group pre-checks report the reason instead of sending
blindly.
- **Image generation** — when someone asks for a picture, the model calls `generate_image`; the
result lands straight in the sticker library and is sent as a sticker (off by default, see the
config examples). The console has an Image generation block with a test-draw button under the
voice page, and one preset (Pollinations) needs no key at all for a zero-setup try. Billed per
image, gated by an hourly cap. A stored key never follows you to a different host (same
credential-binding guard as ASR).
- **Plugins** — third-party capabilities (model tools, message observers, scheduled jobs). Each
plugin runs in its **own child process**; it only receives the capabilities it declared, and every
capability is implemented host-side — a plugin cannot read your config file or bypass the send
queue's mute pre-check and rate limits. Since apiVersion 2 a plugin can declare a **settings
panel** in its manifest (text / number / boolean / select / secret; the console renders it, and
secrets are stored with AES-256-GCM and never echoed). Tools that change external account data go
through a **write trust model**: per-action switches default off, every call needs the owner's
approval for that exact target, daily quotas apply, two writes from the same plugin are at least
60 seconds apart, failures and idempotent skips refund their approval and quota, and every write is
audited host-side. Upgrades diff the manifest first; any permission-surface change must be
confirmed, grants are bound to the manifest hash, and approvals/switches are reset by scope after
an upgrade. The console's Plugins page installs from the official index (13 plugins, all
zero-dependency, including Bilibili: search / understand a video / download and merge into the
chat / interactions with per-call approval), from a local package, or from your own index.
**Writing one** is documented in [docs/PLUGINS.md](docs/PLUGINS.md) (scaffold → debug against the
real runtime → pack and self-test, three commands); submitting to the official index goes through
the [index repository](https://github.com/sakurawwwxh/qq-agent-plugins) PR flow. The console's
Plugins → Publish pane lists both, with the commands. Plugins are third-party code — read the
declared capabilities on the detail page before installing.
- **Skill packs** — read-only Markdown workflows plus a tool allowlist; no third-party code is executed.
When asked to follow a method, the model calls `skill_list` and then `skill_use`; only the tools allowed
by that skill remain available for the turn. Off by default, enable per chat. Built-ins: chat summary,
video digest, comment analysis. The Skills page also has a Market sub-tab: it previews a skill's
SKILL.md, tool allowlist and per-file sha256, installs into `data/skills/`, and can uninstall user
skills (built-ins are protected). See [SKILLS](docs/SKILLS.md).
- **Long-term semantic memory (experimental, off by default)** — per-scope memory cards plus local
vectors in SQLite; shadow mode audits keyword recall without touching replies, and active mode injects
scope-filtered memories as untrusted background. Source turns are kept 7 days and deleted with the
memory. See [LIVING-MEMORY](docs/LIVING-MEMORY.md).
- **Long-term memory & retrieval** — beyond people impressions and session handoffs, `memory_query`
searches keywords and short phrases with SQLite FTS5 and Chinese bigrams. Defaults: 50 impressions per person, manual
entries never pruned, no time-based expiry by default (0–3650 days configurable). See [MEMORY](docs/MEMORY.md).
- **Operations & observability** — backups are AES-256-GCM encrypted by default, with restore and
drill support; message APIs use cursor pagination and support JSONL/CSV export plus `ops prune`;
`/api/metrics` returns JSON or Prometheus text, and logs can be emitted as structured JSON.
- **Qzone moments** — source can be the persona's own interests (default; no group-log collection),
group observations, or persona-first with a light group touch. Scheduled runs only produce a
draft by default; you review or edit it in the console before publishing.
- **MCP read-only resources** — `node src/mcp/resource-server.js` exposes global people memory, the
group meme library and pending reminders to any MCP client. Output is sanitised, and there is no
access to conversations, config or credentials, and no write path.
Configuration examples are in [docs/CONFIG-EXAMPLES.md](docs/CONFIG-EXAMPLES.md). Operations
commands are collected in [src/ops.js](src/ops.js) and documented in [docs/OPS.md](docs/OPS.md).
## Screenshots
The screenshots below use the current default light + liquid-glass theme and anonymised demo data,
and show the overview, message archive, voice-reply settings and plugin page: