fix(qqbot): markdown-first send, replyMsgId TTL, and dead code removal - #6201
Merged
wenshao merged 10 commits intoJul 3, 2026
Conversation
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.
What this PR does
Core bug fixes for the QQ Bot channel adapter's message sending. This is PR 2 of 4 splitting the closed PR #5902.
Message sending: Adopts a markdown-first send strategy — always sends as markdown (msg_type: 2) first, falls back to active message retry on non-4xx failure, with a plain-text fallback for active messages without reply context. msgSeqMap tracks sequence with rollback on failure, and errors are re-thrown for
.catch()callers.replyMsgId TTL: Adds a 5-minute TTL with periodic cleanup (60s interval) to prevent stale reply context. replyMsgId storage changes from
Map<string, string>toMap<string, {msgId, timestamp}>with cascaded msgSeqMap cleanup and asetReplyMsgId()helper that cleans up old entries.restoreQQState()has backward-compatible migration from the old string format.Dead code removal: Removes
hasMarkdownSyntax(),hasLinkSyntax(), andsplitText()exports — no longer needed with the markdown-first strategy.Test updates: Updated send.test.ts with TTL expiry, markdown fallback chain, and noreply suppression tests. 63 tests pass, typecheck is clean.
Why it's needed
The original code had three problems: (1) the chunking-based send strategy was unreliable and
splitText()produced incorrect splits for CJK text, (2) replyMsgId entries accumulated indefinitely with no TTL, causing stale reply context across long-running bot sessions, and (3) errors were silently swallowed withbreakinstead of propagating to error handlers. This PR fixes all three.Reviewer Test Plan
How to verify
sendMessage()always uses markdown (msg_type: 2) as the first send attempt.saveQQState().cd packages/channels/qqbot && npx vitest run— all 63 tests must pass.npx tsc --noEmit— QQChannel.ts must typecheck clean.Evidence (Before & After)
N/A — behavior change is in the send strategy and data structure, verified by unit tests. No user-visible UI.
Tested on
Environment (optional)
Local vitest + tsc validation.
Risk & Scope
splitText()means messages exceeding ~2000 characters will be sent as a single oversized request and may silently fail on the QQ API side. The system instruction was updated to reflect manual 2000-char limit.hasMarkdownSyntax,hasLinkSyntax, andsplitTextexports are removed.restoreQQState()auto-migrates the old string-format replyMsgId on next startup.Linked Issues
N/A — this is part of a multi-PR split from #5902.
中文说明
本 PR 做了什么
QQ Bot 频道适配器消息发送的核心错误修复。这是从已关闭的 PR #5902 拆分出的 4 个 PR 中的第 2 个。
消息发送:采用 markdown 优先发送策略 — 始终优先以 markdown(msg_type: 2)发送,非 4xx 失败时重试为主动消息,无回复上下文时回退到纯文本。msgSeqMap 跟踪序列并在失败时回滚,错误会被重新抛出让
.catch()调用方处理。replyMsgId TTL:添加 5 分钟 TTL 和 60 秒清理定时器,防止回复上下文过期。replyMsgId 存储从
Map<string, string>改为Map<string, {msgId, timestamp}>,附带级联 msgSeqMap 清理和setReplyMsgId()辅助函数。restoreQQState()兼容旧字符串格式迁移。死代码删除:移除
hasMarkdownSyntax()、hasLinkSyntax()和splitText()导出 — 在 markdown 优先策略下不再需要。测试更新:更新 send.test.ts 添加 TTL 过期、markdown 回退链和 noreply 抑制测试。63 个测试通过,类型检查通过。
为什么需要
原代码有三个问题:(1) 基于分块的发送策略不可靠,
splitText()对中文字符串分割不正确;(2) replyMsgId 条目无 TTL 持续累积,导致长期运行的 Bot 会话中出现过期的回复上下文;(3) 错误被break静默吞掉而不传播到错误处理器。本 PR 修复了这三个问题。Reviewer 测试计划
如何验证
sendMessage()是否始终先以 markdown(msg_type: 2)发送saveQQState()持久化删除cd packages/channels/qqbot && npx vitest run— 所有 63 个测试必须通过npx tsc --noEmit— QQChannel.ts 类型检查必须通过测试环境
风险与范围
splitText()后,超过约 2000 字符的消息将作为单次请求发送,可能在 QQ API 端静默失败。系统指令已更新以反映手动 2000 字符限制。hasMarkdownSyntax、hasLinkSyntax、splitText导出已移除。restoreQQState()在下次启动时自动迁移旧字符串格式的 replyMsgId。关联 Issue
无 — 这是从 #5902 拆分出的多 PR 工作的一部分。