qwen-code/docs/design/channels/channels-design.md
tanzhenxin 0c1635c26c docs(channels): consolidate design docs into single file
- Fix broken references to non-existent files
- Replace "What's Next" with detailed "Future Work" roadmap
- Remove redundant implementation, roadmap, and testing guide files
- User docs already cover these topics in docs/users/features/channels/

This consolidates the channels design documentation into a single
authoritative design doc, reducing duplication and maintenance burden.

Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
2026-04-02 11:17:37 +08:00

10 KiB

Channels Design

External messaging integrations for Qwen Code — interact with an agent from Telegram, WeChat, and more.

User documentation: Channels Overview.

Overview

A channel connects an external messaging platform to a Qwen Code agent. Configured in settings.json, managed via qwen channel subcommands, multi-user (each user gets an isolated ACP session).

Architecture

┌──────────┐                        ┌─────────────────────────────────────┐
│ Telegram │    Platform API        │        Channel Service              │
│ User A   │◄──────────────────────►│                                     │
├──────────┤  (WebSocket/polling)   │  ┌───────────┐    ┌──────────────┐  │
│ WeChat   │◄──────────────────────►│  │ Platform   │    │  ACP Bridge  │  │
│ User B   │                        │  │ Adapter    │    │  (shared)    │  │
└──────────┘                        │  │            │    │              │  │
                                    │  │ - connect  │    │  - spawns    │  │
                                    │  │ - receive  │    │    qwen-code │  │
                                    │  │ - send     │    │  - manages   │  │
                                    │  │            │    │    sessions  │  │
                                    │  └─────┬──────┘    └──────┬───────┘  │
                                    │        │                  │          │
                                    │        ▼                  ▼          │
                                    │  ┌─────────────────────────────────┐ │
                                    │  │  SenderGate · GroupGate         │ │
                                    │  │  SessionRouter · ChannelBase    │ │
                                    │  └─────────────────────────────────┘ │
                                    └─────────────────────────────────────┘
                                                     │
                                                     │ stdio (ACP ndjson)
                                                     ▼
                                    ┌─────────────────────────────────────┐
                                    │        qwen-code --acp              │
                                    │   Session A (user alice, id: "abc") │
                                    │   Session B (user bob,   id: "def") │
                                    └─────────────────────────────────────┘

Platform Adapter — connects to external API, translates messages to/from Envelopes. ACP Bridge — spawns qwen-code --acp, manages sessions, emits textChunk/toolCall/disconnected events. Session Router — maps senders to ACP sessions via namespaced keys (<channel>:<sender>). Sender Gate / Group Gate — access control (allowlist / pairing / open) and mention gating. Channel Base — abstract base with Template Method pattern: plugins override connect, sendMessage, disconnect. Channel RegistryMap<string, ChannelPlugin> with collision detection.

Envelope

Normalized message format all platforms convert to:

  • Identity: senderId, senderName, chatId, channelName
  • Content: text, optional imageBase64/imageMimeType, optional referencedText
  • Context: isGroup, isMentioned, isReplyToBot, optional threadId

Plugin responsibilities: senderId must be stable/unique; chatId must distinguish DMs from groups; boolean flags must be accurate for gate logic; @mentions stripped from text.

Message Flow

Inbound:  User message → Adapter → GroupGate → SenderGate → Slash commands → SessionRouter → AcpBridge → Agent
Outbound: Agent response → AcpBridge → SessionRouter → Adapter → User

Slash commands (/clear, /help, /status) are handled in ChannelBase before reaching the agent.

Sessions

One qwen-code --acp process with multiple ACP sessions. Scope per channel: user (default), thread, or single. Routing keys namespaced as <channelName>:<key>.

Error Handling

  • Connection failures — logged; service continues if at least one channel connects
  • Bridge crashes — exponential backoff (max 3 retries), setBridge() on all channels, session restore
  • Session serialization — per-session promise chains prevent concurrent prompt collisions

Plugin System

The architecture is extensible — new adapters (including third-party) can be added without modifying core. Built-in channels use the same plugin interface (dogfooding).

Plugin Contract

A ChannelPlugin declares channelType, displayName, requiredConfigFields, and a createChannel() factory. Plugins implement three methods:

Method Responsibility
connect() Connect to platform and register message handlers
sendMessage(chatId, text) Format and deliver agent response
disconnect() Clean up on shutdown

On inbound messages, plugins build an Envelope and call this.handleInbound(envelope) — the base class handles the rest: access control, group gating, pairing, session routing, prompt serialization, slash commands, instructions injection, reply context, and crash recovery.

Extension Points

  • Custom slash commands via registerCommand()
  • Working indicators by wrapping handleInbound() with typing/reaction display
  • Tool call hooks via onToolCall()
  • Media handling by attaching to Envelope before handleInbound()

Discovery & Loading

External plugins are extensions managed by ExtensionManager, declared in qwen-extension.json:

{
  "name": "my-channel-extension",
  "version": "1.0.0",
  "channels": {
    "my-platform": {
      "entry": "dist/index.js",
      "displayName": "My Platform Channel"
    }
  }
}

Loading sequence at qwen channel start: load settings → register built-ins → scan extensions → dynamic import + validate → register (reject collisions) → validate config → createChannel()connect().

Plugins run in-process (no sandbox), same trust model as npm dependencies.

Configuration

{
  "channels": {
    "my-telegram": {
      "type": "telegram",
      "token": "$TELEGRAM_BOT_TOKEN", // env var reference
      "senderPolicy": "allowlist", // allowlist | pairing | open
      "allowedUsers": ["123456"],
      "sessionScope": "user", // user | thread | single
      "cwd": "/path/to/project",
      "model": "qwen3.5-plus",
      "instructions": "Keep responses short.",
      "groupPolicy": "disabled", // disabled | allowlist | open
      "groups": { "*": { "requireMention": true } },
    },
  },
}

Auth is plugin-specific: static token (Telegram), app credentials (DingTalk), QR code login (WeChat), proxy token (TMCP).

CLI Commands

# Channels
qwen channel start [name]                     # start all or one channel
qwen channel stop                             # stop running service
qwen channel status                           # show channels, sessions, uptime
qwen channel pairing list <ch>                # pending pairing requests
qwen channel pairing approve <ch> <code>      # approve a request

# Extensions
qwen extensions install <path-or-package>     # install
qwen extensions link <local-path>             # symlink for dev
qwen extensions list                          # show installed
qwen extensions remove <name>                 # uninstall

Package Structure

packages/channels/
├── base/                    # @qwen-code/channel-base
│   └── src/
│       ├── AcpBridge.ts     # ACP process lifecycle, session management
│       ├── SessionRouter.ts # sender ↔ session mapping, persistence
│       ├── SenderGate.ts    # allowlist / pairing / open
│       ├── GroupGate.ts     # group chat policy + mention gating
│       ├── PairingStore.ts  # pairing code generation + approval
│       ├── ChannelBase.ts   # abstract base: routing, slash commands
│       └── types.ts         # Envelope, ChannelConfig, etc.
├── telegram/                # @qwen-code/channel-telegram
├── weixin/                  # @qwen-code/channel-weixin
└── dingtalk/                # @qwen-code/channel-dingtalk

Future Work

Safety & Group Chat

  • Per-group tool restrictionstools/toolsBySender deny/allow lists per group
  • Group context history — ring buffer of recent skipped messages, prepended on @mention
  • Regex mention patterns — fallback mentionPatterns for unreliable @mention metadata
  • Per-group instructionsinstructions field on GroupConfig for per-group personas
  • /activation command — runtime toggle for requireMention, persisted to disk

Operational Tooling

  • qwen channel doctor — config validation, env vars, bot tokens, network checks
  • qwen channel status --probe — real connectivity checks per channel

Platform Expansion

  • Discord — Bot API + Gateway, servers/channels/DMs/threads
  • Slack — Bolt SDK, Socket Mode, workspaces/channels/DMs/threads

Multi-Agent

  • Multi-agent routing — multiple agents with bindings per channel/group/user
  • Broadcast groups — multiple agents respond to the same message

Plugin Ecosystem

  • Community plugin templatecreate-qwen-channel scaffolding tool
  • Plugin registry/discoveryqwen extensions search, version compatibility