fix: 改进微信公众号被动回复处理机制,引入缓冲与分片回复,并优化超时行为#5224
Merged
Soulter merged 2 commits intoAstrBotDevs:masterfrom Feb 19, 2026
Merged
Conversation
Contributor
There was a problem hiding this comment.
嗨,我发现了 2 个问题,并给出了一些整体层面的反馈:
- 在 adapter 的回调里,
result只在else分支(future被新创建时)被赋值,但在if/else之后总是会被使用;如果某个future已经存在,这里会触发UnboundLocalError——应当把wait_for(...)和对result的赋值移动到分支外面,这样两个分支都会对其进行赋值。 - 引入新的被动回复逻辑后,
WeixinOfficialAccountPlatformEvent.send在处理纯文本消息时不再调用future.set_result(...),但callback仍然会创建并等待一个future的结果;这意味着该 future 永远不会被 resolve,180 秒的超时时间路径会始终触发——要么在被动模式下移除future/wexin_event_workers机制,要么保证仍然有某段代码会设置这个 future 的结果。
Prompt for AI Agents
Please address the comments from this code review:
## Overall Comments
- In the adapter callback, `result` is only assigned in the `else` branch (when `future` is newly created), but it is always used after the `if/else`; if a `future` already exists, this will raise an `UnboundLocalError`—move the `wait_for(...)` and `result` assignment outside the branch so both paths set it.
- With the new passive reply logic, `WeixinOfficialAccountPlatformEvent.send` no longer calls `future.set_result(...)` for plain-text messages, but `callback` still creates and awaits a `future` result; this means the future will never be resolved and the 180s timeout path will always trigger—either remove the `future`/`wexin_event_workers` mechanism for passive mode or ensure some code still sets the future result.
## Individual Comments
### Comment 1
<location> `astrbot/core/platform/sources/weixin_official_account/weixin_offacc_adapter.py:41-42` </location>
<code_context>
self.callback: Callable[[BaseMessage], Awaitable[None]] | None = None
self.shutdown_event = asyncio.Event()
+ self._wx_msg_time_out = 4.0 # 微信服务器要求 5 秒内回复
+ self.user_buffer: dict[str, dict[str, Any]] = user_buffer # from_user -> state
+ self.active_send_mode = False # 是否启用主动发送模式,启用后 callback 将直接返回回复内容,无需等待微信回调
+
</code_context>
<issue_to_address>
**suggestion:** 统一构造函数参数和实例属性中 user_buffer 的类型注解。
参数类型是 `dict[Any, dict[str, Any]]`,而属性类型是 `dict[str, dict[str, Any]]`。请将两者对齐:如果 `from_user` 始终为字符串,就收窄参数类型;如果允许非字符串键,则应将属性类型放宽为 `dict[Any, dict[str, Any]]`。
```suggestion
class WeixinOfficialAccountServer:
def __init__(self, event_queue: asyncio.Queue, config: dict, user_buffer: dict[str, dict[str, Any]]) -> None:
```
</issue_to_address>
### Comment 2
<location> `astrbot/core/platform/sources/weixin_official_account/weixin_offacc_event.py:90-97` </location>
<code_context>
+ plain_chunks = await self.split_plain(comp.text)
</code_context>
<issue_to_address>
**issue (bug_risk):** 缓存的纯文本分片被覆盖而不是追加,可能导致较早的分片丢失。
每个 `Plain` 组件都会执行 `self.message_out['cached_xml'] = plain_chunks` 赋值操作。如果存在多个 `Plain` 组件(或对同一条消息多次调用 `send()`),这会覆盖之前的值并丢弃早先的文本。相反,当 `'cached_xml'` 已经存在时,应当在现有列表上追加(例如通过 `extend`),而不是重新赋值覆盖。
</issue_to_address>帮我变得更有用!请在每条评论上点 👍 或 👎,我会根据你的反馈持续改进审查质量。
Original comment in English
Hey - I've found 2 issues, and left some high level feedback:
- In the adapter callback,
resultis only assigned in theelsebranch (whenfutureis newly created), but it is always used after theif/else; if afuturealready exists, this will raise anUnboundLocalError—move thewait_for(...)andresultassignment outside the branch so both paths set it. - With the new passive reply logic,
WeixinOfficialAccountPlatformEvent.sendno longer callsfuture.set_result(...)for plain-text messages, butcallbackstill creates and awaits afutureresult; this means the future will never be resolved and the 180s timeout path will always trigger—either remove thefuture/wexin_event_workersmechanism for passive mode or ensure some code still sets the future result.
Prompt for AI Agents
Please address the comments from this code review:
## Overall Comments
- In the adapter callback, `result` is only assigned in the `else` branch (when `future` is newly created), but it is always used after the `if/else`; if a `future` already exists, this will raise an `UnboundLocalError`—move the `wait_for(...)` and `result` assignment outside the branch so both paths set it.
- With the new passive reply logic, `WeixinOfficialAccountPlatformEvent.send` no longer calls `future.set_result(...)` for plain-text messages, but `callback` still creates and awaits a `future` result; this means the future will never be resolved and the 180s timeout path will always trigger—either remove the `future`/`wexin_event_workers` mechanism for passive mode or ensure some code still sets the future result.
## Individual Comments
### Comment 1
<location> `astrbot/core/platform/sources/weixin_official_account/weixin_offacc_adapter.py:41-42` </location>
<code_context>
self.callback: Callable[[BaseMessage], Awaitable[None]] | None = None
self.shutdown_event = asyncio.Event()
+ self._wx_msg_time_out = 4.0 # 微信服务器要求 5 秒内回复
+ self.user_buffer: dict[str, dict[str, Any]] = user_buffer # from_user -> state
+ self.active_send_mode = False # 是否启用主动发送模式,启用后 callback 将直接返回回复内容,无需等待微信回调
+
</code_context>
<issue_to_address>
**suggestion:** Unify type annotation for user_buffer between constructor arg and instance attribute.
The parameter is typed as `dict[Any, dict[str, Any]]` but the attribute as `dict[str, dict[str, Any]]`. Please align these: if `from_user` is always a string, narrow the parameter type; if non-string keys are valid, widen the attribute type to `dict[Any, dict[str, Any]]` instead.
```suggestion
class WeixinOfficialAccountServer:
def __init__(self, event_queue: asyncio.Queue, config: dict, user_buffer: dict[str, dict[str, Any]]) -> None:
```
</issue_to_address>
### Comment 2
<location> `astrbot/core/platform/sources/weixin_official_account/weixin_offacc_event.py:90-97` </location>
<code_context>
+ plain_chunks = await self.split_plain(comp.text)
</code_context>
<issue_to_address>
**issue (bug_risk):** Buffered plain chunks are overwritten rather than appended, which may drop earlier segments.
Each `Plain` component assigns `self.message_out['cached_xml'] = plain_chunks`. With multiple `Plain` components (or repeated `send()` calls for the same message), this overwrites the prior value and drops earlier text. Instead, when `'cached_xml'` already exists, append to the existing list (e.g., via `extend`) rather than reassigning.
</issue_to_address>Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
astrbot/core/platform/sources/weixin_official_account/weixin_offacc_adapter.py
Outdated
Show resolved
Hide resolved
astrbot/core/platform/sources/weixin_official_account/weixin_offacc_event.py
Outdated
Show resolved
Hide resolved
Soulter
approved these changes
Feb 19, 2026
astrbot-doc-agent bot
pushed a commit
to AstrBotDevs/AstrBot-docs
that referenced
this pull request
Feb 19, 2026
|
Generated docs update PR (pending manual review): AI change summary:
Experimental bot notice:
|
YukiRa1n
pushed a commit
to YukiRa1n/AstrBot
that referenced
this pull request
Feb 24, 2026
* 修复wechat official 被动回复功能 * ruff format --------- Co-authored-by: Soulter <905617992@qq.com>
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.
fixes: #2076
Modifications / 改动点
user_buffer实现异步存储功能,修复了 [Bug]接入微信公众号平台经常漏消息 #2076Screenshots or Test Results / 运行截图或测试结果
在本人个人公众号上测试后修复有效,新增代码能正常回复提示消息和在微信公众号post窗口内进行分段回复。并能正常返回pipline的所有信息,包括报错消息。
以下是客户端截图



以下是服务器端截图
Checklist / 检查清单
requirements.txt和pyproject.toml文件相应位置。/ I have ensured that no new dependencies are introduced, OR if new dependencies are introduced, they have been added to the appropriate locations inrequirements.txtandpyproject.toml.测试时发现的额外补充
Summary by Sourcery
改进微信公众号被动回复处理机制,引入缓冲与分片回复,并优化超时行为。
New Features:
Bug Fixes:
Enhancements:
Original summary in English
Summary by Sourcery
Improve WeChat Official Account passive reply handling with buffered, chunked responses and better timeout behavior.
New Features:
Bug Fixes:
Enhancements: