DEV Community

Rock
Rock

Posted on

QQ friend requests and group invites: two approvals, one Agent

Scenario

A QQ bot mostly does not chat; it handles two requests: a stranger asks to add it as a friend, or it gets pulled into a group. A pipeline built for "message in → reply out" cannot catch them — they are not messages.

On 4.10, OneBot v11 was a protocol adapter reaching protocol ends like NapCat or Lagrange, but every event landed in one pipeline — splitting by event meant writing that logic yourself. 4.11 promotes it to an event-driven adapter, where request events land on an Agent.

How it works in 4.11

A new package. src/langbot/pkg/platform/adapters/aiocqhttp/ is a standalone adapter package added in v4.11.0. git diff --stat v4.10.11 v4.11.0 lists, verbatim (source): __init__.py (+5), adapter.py (+243), api_impl.py (+238), event_converter.py (+275), manifest.yaml (+149), message_converter.py (+285), onebot.png, platform_api.py (+84), transport.py (+125), types.py (+9) — eleven files with the old entry point, +1416 / -1.

The old config is downgraded. The previous src/langbot/pkg/platform/sources/aiocqhttp.yaml changed by four lines: spec.legacy: true added, spec.categories going from [protocol] to [popular, protocol] (source). So the wizard now generates a reverse-WS URL instead.

One event, one row. A bot stores rows of event pattern → processor (a pipeline, an Agent or a plugin processor). Rows are tried in order: enabled → pattern matches → filters pass → target declares the event; the first row clearing all four wins, the rest skipped (official docs docs/event-based-agents/04-event-routing.md §3).

The event scope decides the tools. Only friend.request_received brings "处理好友请求", only bot.invited_to_group brings "处理入群邀请". Both carry an event trigger and risk dangerous (source LangBot/src/langbot/pkg/agent/runner/platform_tools.py:176-203). Both act immediately, so never hand them to an Agent that does not need them. Support depends on the adapter and platform — check the support matrix first.

Hands-on steps

Start a local demo instance:

docker network create a4
docker run -d --name a4-core --network a4 --restart on-failure -e TZ=Asia/Shanghai \
  -e BOX__ENABLED=false -e SPACE__DISABLE_TELEMETRY=true -p 15800:5300 \
  -v "$PWD/deploy/a4/data:/app/data" rockchin/langbot:v4.11.0
docker run -d --name a4-runtime --network a4 --network-alias langbot_plugin_runtime --restart on-failure \
  -e TZ=Asia/Shanghai -e SPACE__DISABLE_TELEMETRY=true -v "$PWD/deploy/a4/data/plugins:/app/data/plugins" \
  rockchin/langbot:v4.11.0 uv run --no-sync -m langbot_plugin.cli.__init__ rt
Enter fullscreen mode Exit fullscreen mode

Admin demo@langbot.local / LangBot411!demo (local demo value — replace with your own). Demo bot QQ 演示机器人, adapter onebot-v11.

  1. Step 2 of the wizard: pick OneBot v11. Its card reads, verbatim, "OneBot v11 适配器,用于接入 QQ 兼容协议端,支持事件驱动编排".

Wizard, platform step: OneBot v11 selected

  1. Configure the adapter. Mode 反向 WS — 协议端连接 LangBot (protocol end dials LangBot); the protocol-end URL is generated on save; token demo-onebot-token-replace-me (local demo value — replace with your own); expected account 10001; 保存并启用 gives 保存成功 and badge 已启用. Put that URL and token into your own NapCat / Lagrange.

Adapter config: reverse WS, URL, token, expected account

  1. Read the event catalog. The routing card reports "共 12 类" — "机器人状态 · 4", "好友 · 2", "群组 · 3", "消息 · 2" and one more; the full list is supported_events in the adapter's manifest.yaml. Support depends on the adapter and platform — check the support matrix first.

Event catalog: 12 event types

  1. Route 1 uses the preset 审核好友请求. The "添加行为" menu offers six presets, 回复收到的消息 / 欢迎新成员 / 处理成员离群 / 审核好友请求 / 处理群管理事件 / 配置其他事件, intersected with the adapter's declared events (source LangBot/web/src/app/home/bots/components/bot-form/EventBindingsEditor.tsx:1554-1559), so the preset Telegram filters out survives here; the trigger is 收到好友请求 / friend.request_received.

Add-behavior menu: six presets, one being review friend request

  1. Create the Agent inline. 创建新处理器, runner 本地 Agent (plugin:langbot-team/LocalAgent/default), name qq-approvals-agent; on submit, 创建成功, and route 1's processor becomes ⚙️ qq-approvals-agent.

Create-processor dialog: runner Local Agent, name qq-approvals-agent

Route 1: friend request received points at qq-approvals-agent

  1. Route 2. 添加行为 → 配置其他事件 → 机器人被邀入群 (bot.invited_to_group), same processor ⚙️ qq-approvals-agent — only Agents declaring the event are offered.

Both routes saved side by side, both pointing at the Agent

  1. Pin the Agent's event scope. It starts as one wildcard chip 全部事件 *; the two events replace the wildcard, the card reports "共 2 项", each with three tools:
friend.request_received → 回复当前会话(操作)/ 查询事件发起者(只读)/ 处理好友请求(敏感)
bot.invited_to_group    → 查询事件发起者(只读)/ 查询当前群组(只读)/ 处理入群邀请(敏感)
Enter fullscreen mode Exit fullscreen mode

Other-tool counters on that page, verbatim: 平台工具14 沙盒0 MCP0 插件0 已选 0.

Agent event scope: two events, three available tools each

Select a model first — this Agent's 模型 reads 请选择模型, so 保存 first pops 运行器配置待完善, then 保存成功.

Verify

Both rows persist. Read back from bots.event_bindings:

# Event pattern Processor order enabled
route 1 friend.request_received Agent · qq-approvals-agent 0 true
route 2 bot.invited_to_group Agent · qq-approvals-agent 1 true

Both target_uuid values are 69159ec4-3941-4a1a-994f-45c0b532d01d; the bot row has enable=1.

Check-route hits twice. Measured 2026-10-16, 检查事件路由 with "收到好友请求": 已命中路由 | 目标处理器 | Agent · qq-approvals-agent | 命中规则 | 第 1 条路由 | 诊断步骤:已选择第 1 条路由。第 2 条路由已跳过。事件与此路由不匹配。 With "机器人被邀入群": 第 1 条路由已跳过。事件与此路由不匹配。已选择第 2 条路由。 Its listbox holds twelve entries, matching the adapter declaration.

Check route: friend request received hits route 1

Check route: bot invited to group hits route 2

Scope and tools agree. The three tools in step 7 are the source's event-bound group: event_respond_friend_request bound only to friend.request_received, event_respond_group_invite only to bot.invited_to_group.

Limits and caveats

  • No real QQ traffic, and 运行测试 was never run. The instance has no QQ protocol end (no NapCat, no Lagrange), the token is a local demo value (local demo value — replace with your own), and the Agent has no model, so a test run would prove nothing.
  • Platform tools run under Mock. The note hides in the tooltip of the 事件调试 card's info icon, verbatim: "平台工具使用 Mock:Agent 真实调用工具,回复、发送等平台动作模拟执行,不发送真实消息。其他工具仍按实际配置执行。"

Event-debug card: the platform-tools-use-Mock note as a tooltip

  • Select a model before saving, otherwise the save reports 运行器配置待完善.
  • Old config, new home. Reverse WS has the protocol end dial LangBot's main port, with no extra listener; HTTP is unsupported — old host/port config is the legacy adapter now.
  • A menu entry is not a capability. The menu renders from the adapter declaration — twelve types here, which is why the friend-request preset survives. Support depends on the adapter and platform — check the support matrix first (official docs docs/event-based-agents/01-event-system.md:453-476).
  • 待确认: verified at the config layer only; no real protocol end was attached, and the approve/reject policy is prompt and model behaviour that was not evaluated.
  • [Inference] "one event to two processors" was not measured; arbitration selects one row and skips the rest.

Summary and next steps

Wiring these two approvals is not about a longer prompt. It is two rows of event pattern → processor — friend.request_received and bot.invited_to_group wake the same qq-approvals-agent — and with the scope narrowed to those two, both sensitive tools live on that Agent alone. Coming from 4.10, start at the v4.11.0 release page; the migration map is docs/pipeline-migration-config-map.zh-CN.md; runner plugins live in the langbot-plugins repository. Managed hosting at space.langbot.app is another option.

Top comments (0)