fix(qqofficial): allocate fresh msg_seq per inbound msg_id (#2290)#2294
Open
dadachann wants to merge 1 commit into
Open
fix(qqofficial): allocate fresh msg_seq per inbound msg_id (#2290)#2294dadachann wants to merge 1 commit into
dadachann wants to merge 1 commit into
Conversation
…0054005 dedup QQ Official v2 API deduplicates passive messages by (msg_id, msg_seq). The adapter reused msg_seq across multiple sends under the same inbound msg_id, so multi-part text replies, rich media, and especially streaming chunks (msg_seq pinned at 1) were rejected with: 40054005 消息被去重,请检查请求msgseq Add a per-inbound-msg_id sequence allocator (next_reply_msg_seq) on QQOfficialClient, backed by a bounded OrderedDict + asyncio lock, and use it for C2C/group text sends and rich media. Streaming now advances ctx['msg_seq'] per chunk. Proactive sends (no msg_id) fall back to the existing global counter. Closes #2290
Contributor
Author
CI 说明:当前红勾来自 base 分支 (
|
| Check | 失败原因 | 是否本 PR 引入 |
|---|---|---|
| Ruff Lint & Format | dev/4.11.x 上已有 48 个文件未通过 ruff format --check(涉及 slack / telegram / wecombot / agent-runner / alembic 等,本 PR 均未触碰) |
否 |
| Unit Tests 3.11/3.12/3.13 | 51 个 collection error,全部为 ModuleNotFoundError: No module named 'langbot_plugin.api.entities.builtin.agent_runner',即 CI 解析到的 langbot_plugin 版本尚无该模块 |
否 |
| E2E / Fast Integration | 同上,import 阶段即失败 | 否 |
| Frontend Lint | 前端检查,与后端改动无关 | 否 |
| Box Integration / CLA | ✅ pass | — |
验证:
- 直接 checkout 未带本改动的干净
origin/dev/4.11.x,执行uv run ruff format src --check同样报48 files would be reformatted—— 基线本身即红。 - 本 PR 改动的 3 个文件单独跑 CI 同版本 ruff(0.14.14):
All checks passed+3 files already formatted。 - 51 个 test collection error 中无任何 qqofficial 相关项;本 PR 新增的 3 个回归测试本地全部通过(
12 passed)。
结论:本 PR 代码与测试本身可通过全部相关检查。待 dev/4.11.x 的格式化债与 langbot_plugin 版本问题在 base 修复后 rerun 即可转绿。
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.
Summary
Fixes #2290. QQ Official v2 API deduplicates passive messages by
(msg_id, msg_seq). The adapter reusedmsg_seqfor multiple sends tied to the same inboundmsg_id, so QQ rejected later sends with:Three pre-existing strategies collided:
send_private_text_msg/send_group_text_msg): nomsg_seqat all → QQ defaulted it to1, so any 2nd text reply under the samemsg_idwas a duplicate._send_media_msg): used a global_msg_seq_counter— unique, but could still collide with the implicitmsg_seq=1of a text send under the samemsg_id.reply_message_chunk):msg_seqpinned at1forever, onlyindexadvanced → every chunk reusedmsg_seq=1(the most frequent trigger).Changes
QQOfficialClient.next_reply_msg_seq(msg_id)— a per-inbound-msg_idallocator backed by a boundedOrderedDict(max 1024 keys, LRU eviction) + anasyncio.Lockfor concurrency safety. Nomsg_id(proactive sends) falls back to the existing global counter.ctx['msg_seq']per chunk.send_channle_*) are intentionally left unchanged — they hit the legacy guild API, which does not use this dedup mechanism.Tests
Added 3 regression tests to
test_qqofficial_eba_adapter.py:msg_id, is independent across ids, falls back for missing id, and is gap-free under 50 concurrent allocations;msg_idcarrymsg_seq1, 2, 3;msg_seq.All 12 tests in the file pass;
ruff checkandruff format --checkclean.