Notifications & Integrations
dsh-qqbot
tencent-connect/dsh-qqbot · ★ 468
让 QQ Bot 接入 DeepSeek Harness(dsh)的官方插件
An English summary is not available; the Chinese summary is shown.
安装
dsh plugin --profile web add github:tencent-connect/dsh-qqbotGitHub 源码安装:首次需按提示配置 allowBuilds 构建授权后重试
For install and environment setup, plus plugin development tutorials, see DSH community docs ↗
README
Table of contents
- Architecture
- Installation
- Method 1: Desktop install (recommended)
- Method 2: Manual
- Method 3: Local path
- Method 4: --patch dev mode
- Configuration
- Access control (access)
- Rich media (media)
- Vision (vision)
- File sending (sendFile)
- Built-in Commands
- Core Modules
- Session Routing
- Design Principles
- Local Development
- License
A QQ Bot plugin for deepseek-harness (dsh), connecting DeepSeek AI assistants to QQ private and group chats.
简体中文 | English
Scan to join the QQ group / channel
Architecture
QQ User → QQ WebSocket → dsh-qqbot → ctx.agents → dsh agent loop → LLM
↑ │
└── session/event ──────────┘
(assistant reply → QQ sendMarkdown)
Installation
Method 1: Desktop install (recommended)
No command line needed — everything happens inside the app:
- Install: click "Plugins" in the left sidebar → "Add plugin" → enter
@tencent-connect/dsh-qqbot@latest→ install and start now
- Connect: avatar at the bottom-left → Settings → "QQ Bots" → scan the QR code with mobile QQ
Credentials are saved automatically after the scan; later launches need no re-scan.
Method 2: Manual
# Add to a profile
npx @deepseek-ai/dsh plugin --profile qqbot add @tencent-connect/dsh-qqbot
# Start
npx @deepseek-ai/dsh --profile qqbot
On first launch, the plugin detects missing credentials and automatically starts the QR flow: a QR code is printed in the terminal → scan it with the QQ mobile app → credentials are saved to the profile, so subsequent launches require no re-scan.
In environments without the in-app binding page (pure CLI), set QQBOT_BIND_OPEN_BROWSER=1 to additionally open a browser QR page as a fallback.
Note: Upgrade to
0.4.0or later for browser-link scanning, which avoids QR code misalignment in some terminals.
Method 3: Local path
# Build
cd /path/to/dsh-qqbot
pnpm install && pnpm build
# Add to a profile (local path)
npx @deepseek-ai/dsh plugin --profile qqbot add /path/to/dsh-qqbot
# Start
export QQBOT_APPID="yourAppID" QQBOT_SECRET="yourAppSecret"
npx @deepseek-ai/dsh --profile qqbot
Method 4: --patch dev mode
export QQBOT_APPID="yourAppID" QQBOT_SECRET="yourAppSecret"
npx @deepseek-ai/dsh web --patch /path/to/dsh-qqbot/cordis.dev.yml
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 |
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 |
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 |
/bot-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}; a UUID session id is minted for new sessions and persisted to model-prefs.json, resuming by the persisted id after restarts; pre-0.6 sessions keep their originally derived ids.
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
# Install dependencies
pnpm install
# Build
pnpm build
# Dev mode (watch)
pnpm dev
# Debug via --patch
export QQBOT_APPID="xxx" QQBOT_SECRET="xxx"
npx @deepseek-ai/dsh web --patch /path/to/dsh-qqbot/cordis.dev.yml