Connects QQ Bot private and group chats to DeepSeek Harness Desktop, with per-chat personas, interactive questions, and optional image understanding.
Install
# from GitHub (first run asks for allowBuilds approval — follow the hint, retry)
dsh plugin --profile web add github:yjrqz777/dsh-qqbot-lite
Any plugin you install runs third-party code with your own permissions — it can read your files, use your credentials, and reach the network, and tool approvals don’t sandbox it. GitHub-sourced plugins also run build scripts at install time — pnpm blocks those until you allow them, so an install can stop with ERR_PNPM_GIT_DEP_PREPARE_NOT_ALLOWED or ERR_PNPM_IGNORED_BUILDS; dsh prints the exact key to add under allowBuilds in your profile’s pnpm-workspace.yaml, and the install works on the next run. Allowing a build is a trust decision: only install sources you trust, and pin a commit (github:owner/repo#sha).
README
A QQ Bot plugin for deepseek-harness (dsh), connecting DeepSeek AI assistants to QQ private and group chats.
This project is further developed from Tencent Connect's open-source
@tencent-connect/dsh-qqbotv0.5.0.
Only dsh Desktop mode has been tested; other runtime modes have not been tested.
简体中文 | English
Scan to join the QQ group / channel
Screenshots
Architecture
QQ User → QQ WebSocket → dsh-qqbot → ctx.agents → dsh agent loop → LLM
↑ │
└── session/event ──────────┘
(assistant reply → QQ sendMarkdown)
Installation (Desktop)
This project has only been tested with dsh Desktop. CLI,
--patch, and other runtime modes have not been tested.
Prerequisites
Install Git, Node.js 18 or later, pnpm, and dsh Desktop.
1. Clone the repository
git clone https://github.com/yjrqz777/dsh-qqbot-lite.git
cd dsh-qqbot-lite
2. Install dependencies
pnpm install
If pnpm reports ERR_PNPM_TARBALL_URL_MISMATCH, rebuild the lockfile as suggested by pnpm, then install again:
pnpm clean --lockfile
pnpm install
3. Build the plugin
pnpm build
This creates the dist directory in the project root.
4. Install it in Desktop
- Open dsh Desktop and go to Plugins.
- Enter the path to the cloned project root (the directory containing
package.json). - Click Install.
Example: D:\code\dsh-qqbot-lite.
5. Configure QQ Bot
After installation, open Settings → QQ Bot, enter the AppID and AppSecret, then save and connect. You can also click Get credentials to open the QQ Bot website.
Desktop does not require the QQBOT_APPID or QQBOT_SECRET environment variables. Without credentials, Desktop and dsh still start; only the QQ Bot remains unconnected.
Configuration
| Config | Type | Default | Description |
|---|---|---|---|
appId |
string | required | QQ Bot AppID (or via QQBOT_APPID env var) |
appSecret |
string | required | QQ Bot AppSecret (or via QQBOT_SECRET env var) |
provider |
string | deepseek-official |
LLM provider name |
model |
string | deepseek-chat |
Model name |
preset |
string | - | Agent preset id |
cwd |
string | process.cwd() |
Agent working directory |
requireMention |
boolean | true |
Whether group messages require @bot to trigger |
groupPrompt |
string | - | Extra system prompt for group chats |
directPrompt |
string | - | Extra system prompt for direct chats |
personaPrompt |
string | empty | Custom persona prompt shared by group and direct chats; editable as multiline text in settings |
personaPresets |
object[] | built-in 苏晴 and 土豆小猫 |
Persona presets saved from settings; 自定义 starts with a blank prompt |
textChunkLimit |
number | 4500 |
Max chars per message |
streaming |
boolean | true |
Enable streaming output (always disabled in groups) |
sessionIdleTimeout |
number | 1800000 |
Session idle timeout (ms), default 30 min |
processingTimeoutMs |
number | 1800000 |
Processing timeout (ms), aborts the current LLM call |
maxQueue |
number | 20 |
Max concurrent queue length |
historyLimit |
number | 10 |
Group history buffer size |
askTimeoutMs |
number | 300000 |
Question timeout (ms), default 5 min (ask_user_question) |
showToolResults |
boolean | false |
Show successful tool-call results (errors always shown) |
debug |
boolean | false |
Debug mode |
Access control (access)
| Config | Type | Default | Description |
|---|---|---|---|
access.c2cMode |
open/allowlist/disabled |
open |
Direct-chat access mode |
access.c2cAllow |
string[] | [] |
Direct-chat allowlist (user openid) |
access.groupMode |
open/allowlist/disabled |
open |
Group access mode |
access.groupAllow |
string[] | [] |
Group allowlist (group openid) |
Rich media (media)
| Config | Type | Default | Description |
|---|---|---|---|
media.enabled |
boolean | true |
Enable rich media understanding (image/video download + tool analysis) |
media.maxMB |
number | 200 |
Max download size (MB) |
media.ttlHours |
number | 24 |
Media lifetime (hours), 0 = never expire |
Vision (vision)
| Config | Type | Default | Description |
|---|---|---|---|
vision.enabled |
boolean | false |
Enable vision (qqbot_describe_image tool) |
vision.provider |
string | - | Vision model provider (e.g. pi-ai) |
vision.model |
string | - | Vision model id (e.g. qwen-vl-max) |
vision.maxBytes |
number | 10MB |
Max image bytes |
vision.maxTokens |
number | 1024 |
Max output tokens |
vision.timeoutMs |
number | 120000 |
Vision call timeout (ms) |
File sending (sendFile)
| Config | Type | Default | Description |
|---|---|---|---|
sendFile.restrictPaths |
boolean | true |
Enable path allowlist (media + cwd + extraRoots only) |
sendFile.extraRoots |
string[] | [] |
Extra allowed root directories |
All QQ Bot settings, including AppID, AppSecret, model, access control, persona prompt, and presets, are stored in dsh-qqbot-settings.json in the active profile directory. On first startup, the file is initialized from the existing Cordis profile configuration; the settings page uses this file afterward.
Interactive questions (buttons)
QQ conversations can collect single-choice answers through clickable buttons; users can also reply with a number or text. The model can start a question from a natural-language request, so users do not need to mention an internal tool name. For example: “What should I have for lunch? Give me a few clickable options.”
The interactive question tool accepts one question and 2–8 options. After the user clicks a button or replies with text, the answer is returned to the model. If QQ rejects a keyboard message, the plugin falls back to text options and includes the API error reason in the message.
Built-in Commands
| Command | Description |
|---|---|
/new (aliases /reset /clear) |
Start a new session (clear context) |
/compact |
Compact session history (replace old records with a summary) |
/model |
View or switch model |
/preset |
View or switch agent preset (applies to new sessions) |
/stop |
Abort the current generation |
/bot-ping |
Network latency test (transport & processing time) |
/bot-version |
View version info |
/bot-status |
View current session status |
/help |
View all commands |
Core Modules
src/
├── index.ts # Cordis plugin entry (async apply)
├── config.ts # Config schema
├── types.ts # Global types
├── setup.ts # Credential binding (QR)
├── gateway/ # Gateway assembly
│ ├── bootstrap.ts # Startup wiring (session/event listeners, etc.)
│ └── middleware-setup.ts # Middleware chain config
├── transport/ # Transport layer
│ ├── inbound.ts # QQ inbound message → agent.followup()
│ ├── outbound.ts # session/event → QQ sendMarkdown
│ ├── outbound-buffer.ts # Streaming buffer
│ ├── streaming-writer.ts # Streaming writer
│ ├── reply-target.ts # Reply target resolution
│ ├── msgid-cache.ts # Passive reply msgid cache
│ ├── reply-limiter.ts # Passive reply rate limiter
│ ├── tool-presenter.ts # Tool-call presentation
│ └── chunker.ts # Markdown chunking
├── session/ # Session management
│ ├── session-manager.ts # QQ peer → Agent mapping
│ └── idle-evictor.ts # Idle eviction
├── model/ # Model routing
│ ├── model-resolver.ts # Route resolution
│ ├── prefs-store.ts # Per-peer preference persistence
│ └── settings-reader.ts # settings.yaml read-only
├── features/ # Interaction features
│ ├── question-channel.ts # ask_user_question Q&A channel
│ ├── approval-channel.ts # approval confirmation channel
│ └── answer-parser.ts # Answer parsing
├── media/ # Media
│ ├── vision-tool.ts # Image vision understanding
│ ├── send-file-tool.ts # Send local files
│ └── media-cleaner.ts # Media TTL cleanup
├── middleware/ # Middleware
│ ├── question-answer.ts # Q&A answer handling
│ └── attachment.ts # Attachment handling
├── shared/ # Shared utilities
│ ├── utils.ts # Common helpers
│ ├── scope.ts # scope/peer extraction
│ └── send-helper.ts # Chunked send
└── commands/ # Slash commands
Session Routing
sessionKey: qqbot:${appId}:${scope}:${peerId}, with the SessionId derived deterministically via SHA-256 so sessions survive restarts.
Resolution strategy: in-process reuse → persisted resume → fresh create.
Design Principles
- Pure Cordis plugin — follows the dsh "Plugins, not loop changes" principle
- Declarative dependencies —
inject = ['agents'], no direct coupling to other plugins - Session isolation — one independent Agent per QQ direct user / group
- Preset support — mount presets (toolkits, prompts, etc.) via the
agent-presetsservice - Idle eviction — auto-dispose Agents on timeout to prevent memory leaks
- Markdown output — replies sent as Markdown with code-block/table-aware chunking
- Image understanding — supports
qqbot_describe_imagevision to analyze images sent by users - File sending — supports
qqbot_send_fileto send local files to users (path allowlist enabled by default) - Question interaction — supports
ask_user_questionwith inline keyboard buttons (mutually exclusive) or numbered replies, one question at a time with timeout - Approval confirmation — supports
approval/requestto ask for user confirmation on critical actions via allow/deny buttons
Local Development
pnpm install
pnpm build
pnpm test
License and Third-Party Content
The software code in this project is licensed under MIT; see LICENSE. This project is derived from Tencent Connect's dsh-qqbot v0.5.0, and retains the upstream MIT copyright notice.
The Suqing persona preset is not covered by this project's MIT license. It is authored by yjrqz777. When using, copying, or redistributing the preset, retain the attribution “Author: yjrqz777” and link to the author's GitHub profile. Follow any additional terms published by the author.
Links
More in this category
xmanrui/dsh-im★ 2061
Connect IM bots to DeepSeek Harness via QR codes or bot credentials (9 channels: Feishu, WeChat, DingTalk, WeCom, QQ, Slack, Telegram, Discord, and WhatsApp).
shaobeichen/dsh-pocket★ 1793
Remote phone access to the DSH Web UI: scan a QR code for LAN or public (cloudflared tunnel) access with real-time sync, a mobile-adaptive layout, and a settings tab.
inclusionAI/Avernet#deepseek-harness-channel-bcn★ 642
Connects DeepSeek Harness to Avernet's Bot Collaboration Network over WebSocket V2, with automatic onboarding, isolated agent sessions, tool-call events, and multi-bot routing tools.
Oscar-Williams/dsh-deepcanary★ 90
Evidence-first attention supervision for DeepSeek Harness with C0–C3 policy, deduplicated Inbox alerts, quiet hours, and redacted outcome records.
omdsh-dev/dsh-notification★ 88
Desktop notifications for turn completions, with per-outcome controls and keyword rules.
MichengAI/dsh-im-connect★ 61
Connects WeChat, WeCom, DingTalk, Feishu, Lark, QQ, and Telegram to a local DeepSeek Harness agent, with each IM chat as a separate workspace channel.
Community comments
Comments are public GitHub Discussions. Loading them connects to GitHub and Giscus; a GitHub account is required to post.