feat(gateway): add QQBot platform adapter via qq-botpy SDK#8269
Closed
xing8star wants to merge 5 commits into
Closed
feat(gateway): add QQBot platform adapter via qq-botpy SDK#8269xing8star wants to merge 5 commits into
xing8star wants to merge 5 commits into
Conversation
Integrate QQ (Tencent) as a supported messaging platform in the Hermes
gateway, enabling bot interactions on guild channels, direct messages,
C2C (single-user apps), and group @-messages.
Changes:
- Add gateway/platforms/qqbot.py — full QQBotAdapter implementation
built on the official qq-botpy SDK, supporting four message scenes
(guild_at, direct_message, c2c, group_at) with WebSocket connection
lifecycle, message deduplication, auto-reconnect backoff, and an
embedded MessageHub for external tool / MCP polling access.
- Register Platform.QQBOT enum in gateway/config.py with env-var
overrides (QQBOT_APPID, QQBOT_SECRET, QQBOT_HOME_CHANNEL,
QQBOT_ALLOWED_USERS, QQBOT_ALLOW_ALL_USERS).
- Wire adapter factory in gateway/run.py with requirement checks and
per-platform allowlist / allow-all user config maps.
- Add interactive CLI setup flow (_setup_qqbot) in hermes_cli/gateway.py
with platform definition (emoji: cat), AppID/BotSecret credential
prompts, user allowlist, and open-access toggle.
- Register "qqbot" platform info in hermes_cli/platforms.py and status
check vars in hermes_cli/status.py.
- Add "hermes-qqbot" toolset to toolsets.py and include it in the
gateway union toolset.
- Extend send_message_tool.py with QQBot target format support
('qqbot:channel_id'), max length constant (2000), and _send_qqbot()
dispatch that instantiates the adapter for proactive outbound delivery.
- Add QQ-specific prompt hint in agent/prompt_builder.py (plain-text,
no markdown).
- Wire QQBot delivery target in cron/scheduler.py.
- Add qq-botpy>=1.2.1 to core dependencies and qq-botpy>=1.2.0,<2 to
optional [qqbot] group in pyproject.toml.
Contributor
|
Hi @xing8star 👋 I'm from the official QQ Bot team at Tencent. Really great to see this PR — a full-featured QQBot adapter following the existing platform patterns. Solid work! We'd love to get involved and help push this PR to a mergeable state together. Could you leave your QQ number so we can connect directly? It'd be much easier to coordinate in real-time. Looking forward to working together 🙏 |
teknium1
added a commit
that referenced
this pull request
Apr 14, 2026
… shared strip_markdown Improvements from our earlier #8269 salvage work applied to #7616: - Platform token lock: acquire_scoped_lock/release_scoped_lock prevents two profiles from double-connecting the same QQ bot simultaneously - Send retry with exponential backoff (3 attempts, 1s/2s/4s) with permanent vs transient error classification (matches Telegram pattern) - Proper long-message splitting via truncate_message() instead of hard-truncating at MAX_MESSAGE_LENGTH (preserves code blocks, adds 1/N) - REST-based one-shot send in send_message_tool — uses QQ Bot REST API directly with httpx instead of creating a full WebSocket adapter per message (fixes the connect→send race condition) - Use shared strip_markdown() from helpers.py instead of 15 lines of inline regex with import-inside-method (DRY, same as BlueBubbles/SMS) - format_message() now wired into send() pipeline
teknium1
added a commit
that referenced
this pull request
Apr 14, 2026
… shared strip_markdown Improvements from our earlier #8269 salvage work applied to #7616: - Platform token lock: acquire_scoped_lock/release_scoped_lock prevents two profiles from double-connecting the same QQ bot simultaneously - Send retry with exponential backoff (3 attempts, 1s/2s/4s) with permanent vs transient error classification (matches Telegram pattern) - Proper long-message splitting via truncate_message() instead of hard-truncating at MAX_MESSAGE_LENGTH (preserves code blocks, adds 1/N) - REST-based one-shot send in send_message_tool — uses QQ Bot REST API directly with httpx instead of creating a full WebSocket adapter per message (fixes the connect→send race condition) - Use shared strip_markdown() from helpers.py instead of 15 lines of inline regex with import-inside-method (DRY, same as BlueBubbles/SMS) - format_message() now wired into send() pipeline
Contributor
|
Merged via PR #9364. We initially salvaged your qq-botpy SDK adapter, then rebuilt on top of #7616's raw API v2 approach (zero new deps). Your follow-up commit (branding unification, PLATFORM_HINTS, streaming fix) was cherry-picked and ships in the final adapter. Thank you @xing8star for the contribution and for the Tencent team's support. |
ulasbilgen
pushed a commit
to ulasbilgen/hermes-adhd-agent
that referenced
this pull request
May 1, 2026
… shared strip_markdown Improvements from our earlier NousResearch#8269 salvage work applied to NousResearch#7616: - Platform token lock: acquire_scoped_lock/release_scoped_lock prevents two profiles from double-connecting the same QQ bot simultaneously - Send retry with exponential backoff (3 attempts, 1s/2s/4s) with permanent vs transient error classification (matches Telegram pattern) - Proper long-message splitting via truncate_message() instead of hard-truncating at MAX_MESSAGE_LENGTH (preserves code blocks, adds 1/N) - REST-based one-shot send in send_message_tool — uses QQ Bot REST API directly with httpx instead of creating a full WebSocket adapter per message (fixes the connect→send race condition) - Use shared strip_markdown() from helpers.py instead of 15 lines of inline regex with import-inside-method (DRY, same as BlueBubbles/SMS) - format_message() now wired into send() pipeline
aj-nt
pushed a commit
to aj-nt/hermes-agent
that referenced
this pull request
May 1, 2026
… shared strip_markdown Improvements from our earlier NousResearch#8269 salvage work applied to NousResearch#7616: - Platform token lock: acquire_scoped_lock/release_scoped_lock prevents two profiles from double-connecting the same QQ bot simultaneously - Send retry with exponential backoff (3 attempts, 1s/2s/4s) with permanent vs transient error classification (matches Telegram pattern) - Proper long-message splitting via truncate_message() instead of hard-truncating at MAX_MESSAGE_LENGTH (preserves code blocks, adds 1/N) - REST-based one-shot send in send_message_tool — uses QQ Bot REST API directly with httpx instead of creating a full WebSocket adapter per message (fixes the connect→send race condition) - Use shared strip_markdown() from helpers.py instead of 15 lines of inline regex with import-inside-method (DRY, same as BlueBubbles/SMS) - format_message() now wired into send() pipeline
02356abc
pushed a commit
to 02356abc/hermes-agent
that referenced
this pull request
May 14, 2026
… shared strip_markdown Improvements from our earlier NousResearch#8269 salvage work applied to NousResearch#7616: - Platform token lock: acquire_scoped_lock/release_scoped_lock prevents two profiles from double-connecting the same QQ bot simultaneously - Send retry with exponential backoff (3 attempts, 1s/2s/4s) with permanent vs transient error classification (matches Telegram pattern) - Proper long-message splitting via truncate_message() instead of hard-truncating at MAX_MESSAGE_LENGTH (preserves code blocks, adds 1/N) - REST-based one-shot send in send_message_tool — uses QQ Bot REST API directly with httpx instead of creating a full WebSocket adapter per message (fixes the connect→send race condition) - Use shared strip_markdown() from helpers.py instead of 15 lines of inline regex with import-inside-method (DRY, same as BlueBubbles/SMS) - format_message() now wired into send() pipeline
gweeteve
pushed a commit
to gweeteve/hermes-agent
that referenced
this pull request
Jun 2, 2026
… shared strip_markdown Improvements from our earlier NousResearch#8269 salvage work applied to NousResearch#7616: - Platform token lock: acquire_scoped_lock/release_scoped_lock prevents two profiles from double-connecting the same QQ bot simultaneously - Send retry with exponential backoff (3 attempts, 1s/2s/4s) with permanent vs transient error classification (matches Telegram pattern) - Proper long-message splitting via truncate_message() instead of hard-truncating at MAX_MESSAGE_LENGTH (preserves code blocks, adds 1/N) - REST-based one-shot send in send_message_tool — uses QQ Bot REST API directly with httpx instead of creating a full WebSocket adapter per message (fixes the connect→send race condition) - Use shared strip_markdown() from helpers.py instead of 15 lines of inline regex with import-inside-method (DRY, same as BlueBubbles/SMS) - format_message() now wired into send() pipeline
Egavasyug
pushed a commit
to Egavasyug/hermes-agent
that referenced
this pull request
Jun 10, 2026
… shared strip_markdown Improvements from our earlier NousResearch#8269 salvage work applied to NousResearch#7616: - Platform token lock: acquire_scoped_lock/release_scoped_lock prevents two profiles from double-connecting the same QQ bot simultaneously - Send retry with exponential backoff (3 attempts, 1s/2s/4s) with permanent vs transient error classification (matches Telegram pattern) - Proper long-message splitting via truncate_message() instead of hard-truncating at MAX_MESSAGE_LENGTH (preserves code blocks, adds 1/N) - REST-based one-shot send in send_message_tool — uses QQ Bot REST API directly with httpx instead of creating a full WebSocket adapter per message (fixes the connect→send race condition) - Use shared strip_markdown() from helpers.py instead of 15 lines of inline regex with import-inside-method (DRY, same as BlueBubbles/SMS) - format_message() now wired into send() pipeline
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Integrate QQ (Tencent) as a supported messaging platform in the Hermes gateway, enabling bot interactions on guild channels, direct messages, C2C (single-user apps), and group @-messages.
Changes:
Add gateway/platforms/qqbot.py — full QQBotAdapter implementation built on the official qq-botpy SDK, supporting four message scenes (guild_at, direct_message, c2c, group_at) with WebSocket connection lifecycle, message deduplication, auto-reconnect backoff, and an embedded MessageHub for external tool / MCP polling access.
Register Platform.QQBOT enum in gateway/config.py with env-var overrides (QQBOT_APPID, QQBOT_SECRET, QQBOT_HOME_CHANNEL, QQBOT_ALLOWED_USERS, QQBOT_ALLOW_ALL_USERS).
Wire adapter factory in gateway/run.py with requirement checks and per-platform allowlist / allow-all user config maps.
Add interactive CLI setup flow (_setup_qqbot) in hermes_cli/gateway.py with platform definition (emoji: cat), AppID/BotSecret credential prompts, user allowlist, and open-access toggle.
Register "qqbot" platform info in hermes_cli/platforms.py and status check vars in hermes_cli/status.py.
Add "hermes-qqbot" toolset to toolsets.py and include it in the gateway union toolset.
Extend send_message_tool.py with QQBot target format support ('qqbot:channel_id'), max length constant (2000), and _send_qqbot() dispatch that instantiates the adapter for proactive outbound delivery.
Add QQ-specific prompt hint in agent/prompt_builder.py (plain-text, no markdown).
Wire QQBot delivery target in cron/scheduler.py.
Add qq-botpy>=1.2.1 to core dependencies and qq-botpy>=1.2.0,<2 to optional [qqbot] group in pyproject.toml.
What does this PR do?
Adds QQBot (QQ / Tencent QQ) as a fully supported messaging platform in the Hermes gateway, enabling AI agent interactions on China's most popular social platform. This brings Hermes to millions of Chinese users who communicate primarily via QQ.
The implementation follows the same adapter pattern established by existing platforms (Telegram, Discord, WhatsApp, BlueBubbles, etc.) and integrates with the official qq-botpy SDK for WebSocket-based real-time messaging.
Key capabilities:
hermes gateway setup), allowlist/allow-all user authorizationsend_messagetool supportsqqbot:channel_idtarget format for cron jobs and notificationsWhy this approach?
The official qq-botpy SDK is the only blessed Python library for the QQ Bot Open Platform API. It handles WebSocket connection management, intent registration, and the four distinct message scenes — each with different reply APIs (
post_message,post_dms,message.reply). Building on this SDK (rather than raw HTTP) ensures compatibility with future QQ platform updates.Related Issue
Type of Change
Changes Made
New files:
gateway/platforms/qqbot.py— Full QQBotAdapter (~580 lines): botpy.Client subclass, _MessageHub event bus, connect/disconnect lifecycle, send/send_image/get_chat_info, four scene handlers (guild_at, direct_message, c2c, group_at), dedup, msg_seq management, responder cache for group/C2C reply routingModified files:
gateway/config.py— AddPlatform.QQBOTenum value; connected-platform detection (appid + token); env var overrides (QQBOT_APPID,QQBOT_SECRET/QQBOT_TOKENfallback,QQBOT_HOME_CHANNEL)gateway/run.py— Adapter factory branch for QQBot; allowlist/allow-all env var maps (QQBOT_ALLOWED_USERS,QQBOT_ALLOW_ALL_USERS)hermes_cli/gateway.py— Platform definition entry (emoji: cat emoji); full_setup_qqbot()interactive wizard (~90 lines): dependency check, AppID/BotSecret prompts, user allowlist, open-access toggle, home channelhermes_cli/platforms.py— Register"qqbot"->PlatformInfo(label="QQBot", default_toolset="hermes-qqbot")hermes_cli/status.py— Status check vars:("QQBot", ("QQBOT_APPID", None))toolsets.py— Add"hermes-qqbot"toolset definition; include it in"hermes-gateway"union includes listtools/send_message_tool.py— Target format docstring addqqbot:channel_id; platform map addqqbot->Platform.QQBOT; max length constant 2000;_send_qqbot()dispatch function (~25 lines)agent/prompt_builder.py—PLATFORM_HINTS["qqbot"]: plain-text hint (no markdown on QQ)cron/scheduler.py— Delivery platform map:"qqbot"->Platform.QQBOTpyproject.toml— Core dep:qq-botpy>=1.2.1; optional[qqbot]extra:qq-botpy>=1.2.0,<2How to Test
Prerequisites — create a QQ Bot application:
public_guild_messages,direct_message,public_messagesConfigure credentials:
Run gateway and verify connection:
hermes gateway start # Expected log: "INFO gateway.platforms.qqbot" + "[QQBot] Bot ready"Test inbound messages (all four scenes):
Checklist
Code
fix(scope):,feat(scope):, etc.)pytest tests/ -qand all tests passDocumentation & Housekeeping
docs/, docstrings) — or N/Acli-config.yaml.exampleif I added/changed config keys — or N/ACONTRIBUTING.mdorAGENTS.mdif I changed architecture or workflows — or N/AScreenshots / Logs