From a22465e07ab4b71019f711e7a6463f6590c50742 Mon Sep 17 00:00:00 2001 From: MottledShadow <159539633+MottledShadow@users.noreply.github.com> Date: Sun, 3 May 2026 00:21:26 +0800 Subject: [PATCH] fix(weixin): send_weixin_direct cross-loop session check MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When send_message tool is called from inside a running gateway, the _run_async bridge spawns a worker thread with a separate event loop. send_weixin_direct then reuses the live adapter's aiohttp session which was created on the gateway's main loop. aiohttp's TimerContext checks asyncio.current_task(loop=session._loop) and sees None because we're executing on the worker thread's loop → raises 'Timeout context manager should be used inside a task'. Fix: skip the live-adapter shortcut when the session belongs to a different event loop, falling through to the fresh-session path. --- gateway/platforms/weixin.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/gateway/platforms/weixin.py b/gateway/platforms/weixin.py index 72b7d2a4df..3fd7174270 100644 --- a/gateway/platforms/weixin.py +++ b/gateway/platforms/weixin.py @@ -2030,7 +2030,9 @@ async def send_weixin_direct( live_adapter = _LIVE_ADAPTERS.get(resolved_token) send_session = getattr(live_adapter, '_send_session', None) - if live_adapter is not None and send_session is not None and not send_session.closed: + if (live_adapter is not None and send_session is not None + and not send_session.closed + and send_session._loop is asyncio.get_running_loop()): last_result: Optional[SendResult] = None cleaned = live_adapter.format_message(message) if cleaned: