Skip to content

fix(weixin): split poll/send sessions and reuse live adapter to prevent message loss - #10091

Closed
LLQWQ wants to merge 1 commit into
NousResearch:mainfrom
LLQWQ:fix/weixin-reuse-live-adapter
Closed

fix(weixin): split poll/send sessions and reuse live adapter to prevent message loss#10091
LLQWQ wants to merge 1 commit into
NousResearch:mainfrom
LLQWQ:fix/weixin-reuse-live-adapter

Conversation

@LLQWQ

@LLQWQ LLQWQ commented Apr 15, 2026

Copy link
Copy Markdown
Contributor

Summary

This is a comprehensive fix for silent Weixin message loss when the gateway is running.

Root Cause

When the gateway is running, cron jobs and send_message targeting Weixin would create a competing iLink session with the same bot token. The iLink backend sometimes returns HTTP 200, but messages are silently dropped or severely delayed because the long-poll session and the standalone session conflict.

Changes

gateway/platforms/weixin.py

  • Split aiohttp.ClientSession into _poll_session (inbound long-poll) and _send_session (outbound sends)
  • Add _LIVE_ADAPTERS registry that maps bot tokens to the currently-connected gateway adapter
  • send_weixin_direct() now prefers reusing the live adapter's _send_session and only falls back to a fresh short-lived session when the gateway is not running
  • This completely eliminates iLink token contention between poll and send paths

cron/scheduler.py

  • Support comma-separated deliver values (e.g. "feishu,weixin") for multi-target delivery
  • Delay the pconfig.enabled check until the standalone fallback path, so live adapters work even when the platform is not explicitly listed in gateway.json / config.yaml

tools/send_message_tool.py

  • Synthesize a PlatformConfig from WEIXIN_* environment variables when the gateway config lacks a Weixin entry
  • Fall back to WEIXIN_HOME_CHANNEL env var for home channel resolution
  • This allows send_message(target="weixin:...") to work with pure .env configuration

tests/gateway/test_weixin.py

  • Update mocks to include _send_session

Testing

  • All existing tests pass (tests/gateway/test_weixin.py, tests/cron/test_scheduler.py, tests/tools/test_send_message_tool.py)
  • Verified multi-target cron delivery to both Feishu and Weixin simultaneously
  • Verified standalone send_message to Weixin via both live adapter and fallback paths

Closes #10089

… cron & send_message

- gateway/platforms/weixin.py:
  - Split aiohttp.ClientSession into _poll_session and _send_session
  - Add _LIVE_ADAPTERS registry so send_weixin_direct() reuses the connected gateway adapter instead of creating a competing session
  - Fixes silent message loss when gateway is running (iLink token contention)

- cron/scheduler.py:
  - Support comma-separated deliver values (e.g. 'feishu,weixin') for multi-target delivery
  - Delay pconfig/enabled check until standalone fallback so live adapters work even when platform is not in gateway config

- tools/send_message_tool.py:
  - Synthesize PlatformConfig from WEIXIN_* env vars when gateway config lacks a weixin entry
  - Fall back to WEIXIN_HOME_CHANNEL env var for home channel resolution

- tests/gateway/test_weixin.py:
  - Update mocks to include _send_session
@LLQWQ
LLQWQ force-pushed the fix/weixin-reuse-live-adapter branch from f16e120 to 520c8d1 Compare April 16, 2026 07:11
@LLQWQ LLQWQ changed the title fix(weixin): reuse live gateway adapter in send_weixin_direct to prevent message loss fix(weixin): split poll/send sessions and reuse live adapter to prevent message loss Apr 16, 2026
teknium1 added a commit that referenced this pull request Apr 17, 2026
…x Weixin test mocks

Cron origin fallback extension (builds on #9193's _HOME_TARGET_ENV_VARS):
adds the three remaining origin-fallback-eligible platforms that have
home channel env vars configured in gateway/config.py but use non-generic
env var names:

- email    → EMAIL_HOME_ADDRESS   (non-standard suffix)
- dingtalk → DINGTALK_HOME_CHANNEL
- qqbot    → QQ_HOME_CHANNEL      (non-standard prefix: QQ_ not QQBOT_)

Picks up the completeness intent of @Xowiek's PR #11317 using the
architecturally-correct dict-based lookup from #9193, so platforms with
non-standard env var names actually resolve instead of silently missing.
Extended the parametrized regression test to cover the new three.

Weixin test mock alignment (builds on #10091's _send_session split):
Three test sites added in Batch 1 (TestWeixinSendImageFileParameterName)
and Batch 3 (TestWeixinVoiceSending) mocked only adapter._session, but
#10091 switched the send paths to check self._send_session. Added the
companion setter so the tests stay green with the session split in place.
teknium1 added a commit that referenced this pull request Apr 17, 2026
…x Weixin test mocks

Cron origin fallback extension (builds on #9193's _HOME_TARGET_ENV_VARS):
adds the three remaining origin-fallback-eligible platforms that have
home channel env vars configured in gateway/config.py but use non-generic
env var names:

- email    → EMAIL_HOME_ADDRESS   (non-standard suffix)
- dingtalk → DINGTALK_HOME_CHANNEL
- qqbot    → QQ_HOME_CHANNEL      (non-standard prefix: QQ_ not QQBOT_)

Picks up the completeness intent of @Xowiek's PR #11317 using the
architecturally-correct dict-based lookup from #9193, so platforms with
non-standard env var names actually resolve instead of silently missing.
Extended the parametrized regression test to cover the new three.

Weixin test mock alignment (builds on #10091's _send_session split):
Three test sites added in Batch 1 (TestWeixinSendImageFileParameterName)
and Batch 3 (TestWeixinVoiceSending) mocked only adapter._session, but
#10091 switched the send paths to check self._send_session. Added the
companion setter so the tests stay green with the session split in place.
@teknium1

Copy link
Copy Markdown
Contributor

Merged as part of Batch-4 salvage: #11594

Full PR cherry-picked onto current main with your authorship preserved. All three bundled changes landed:

  1. Weixin session split + _LIVE_ADAPTERS registry — the core fix for [Bug]: Weixin messages from cron/send_message are silently dropped when gateway is running #10089. When send_weixin_direct() is called while the gateway is running, it now reuses the connected adapter's _send_session instead of creating a competing iLink session under the same bot token.
  2. Cron multi-target deliver supportdeliver: "feishu,weixin" now delivers to both platforms. Refactored _resolve_delivery_target_resolve_single_delivery_target(job, deliver_value) + added _resolve_delivery_targets(job) → List[dict], with the original function retained as a backward-compat shim.
  3. send_message_tool.py env-var synthesis — cron/send_message to Weixin now works with pure .env configuration when the gateway config lacks a weixin entry.

Had to resolve one conflict in _send_file() (Batch-3 #9425 added force_file_attachment param after your branch) — kept both changes. And #9193's _HOME_TARGET_ENV_VARS dict approach composed cleanly with your cron refactor since the dict is module-scoped. Thanks for the comprehensive fix!

Commit SHAs on main: 5ca52ba

@teknium1 teknium1 closed this Apr 17, 2026
brucephaner pushed a commit to brucephaner/xiashou-agent that referenced this pull request Apr 25, 2026
…x Weixin test mocks

Cron origin fallback extension (builds on NousResearch#9193's _HOME_TARGET_ENV_VARS):
adds the three remaining origin-fallback-eligible platforms that have
home channel env vars configured in gateway/config.py but use non-generic
env var names:

- email    → EMAIL_HOME_ADDRESS   (non-standard suffix)
- dingtalk → DINGTALK_HOME_CHANNEL
- qqbot    → QQ_HOME_CHANNEL      (non-standard prefix: QQ_ not QQBOT_)

Picks up the completeness intent of @Xowiek's PR NousResearch#11317 using the
architecturally-correct dict-based lookup from NousResearch#9193, so platforms with
non-standard env var names actually resolve instead of silently missing.
Extended the parametrized regression test to cover the new three.

Weixin test mock alignment (builds on NousResearch#10091's _send_session split):
Three test sites added in Batch 1 (TestWeixinSendImageFileParameterName)
and Batch 3 (TestWeixinVoiceSending) mocked only adapter._session, but
companion setter so the tests stay green with the session split in place.

(cherry picked from commit f64241e)
aj-nt pushed a commit to aj-nt/hermes-agent that referenced this pull request May 1, 2026
…x Weixin test mocks

Cron origin fallback extension (builds on NousResearch#9193's _HOME_TARGET_ENV_VARS):
adds the three remaining origin-fallback-eligible platforms that have
home channel env vars configured in gateway/config.py but use non-generic
env var names:

- email    → EMAIL_HOME_ADDRESS   (non-standard suffix)
- dingtalk → DINGTALK_HOME_CHANNEL
- qqbot    → QQ_HOME_CHANNEL      (non-standard prefix: QQ_ not QQBOT_)

Picks up the completeness intent of @Xowiek's PR NousResearch#11317 using the
architecturally-correct dict-based lookup from NousResearch#9193, so platforms with
non-standard env var names actually resolve instead of silently missing.
Extended the parametrized regression test to cover the new three.

Weixin test mock alignment (builds on NousResearch#10091's _send_session split):
Three test sites added in Batch 1 (TestWeixinSendImageFileParameterName)
and Batch 3 (TestWeixinVoiceSending) mocked only adapter._session, but
NousResearch#10091 switched the send paths to check self._send_session. Added the
companion setter so the tests stay green with the session split in place.
02356abc pushed a commit to 02356abc/hermes-agent that referenced this pull request May 14, 2026
…x Weixin test mocks

Cron origin fallback extension (builds on NousResearch#9193's _HOME_TARGET_ENV_VARS):
adds the three remaining origin-fallback-eligible platforms that have
home channel env vars configured in gateway/config.py but use non-generic
env var names:

- email    → EMAIL_HOME_ADDRESS   (non-standard suffix)
- dingtalk → DINGTALK_HOME_CHANNEL
- qqbot    → QQ_HOME_CHANNEL      (non-standard prefix: QQ_ not QQBOT_)

Picks up the completeness intent of @Xowiek's PR NousResearch#11317 using the
architecturally-correct dict-based lookup from NousResearch#9193, so platforms with
non-standard env var names actually resolve instead of silently missing.
Extended the parametrized regression test to cover the new three.

Weixin test mock alignment (builds on NousResearch#10091's _send_session split):
Three test sites added in Batch 1 (TestWeixinSendImageFileParameterName)
and Batch 3 (TestWeixinVoiceSending) mocked only adapter._session, but
NousResearch#10091 switched the send paths to check self._send_session. Added the
companion setter so the tests stay green with the session split in place.
gweeteve pushed a commit to gweeteve/hermes-agent that referenced this pull request Jun 2, 2026
…x Weixin test mocks

Cron origin fallback extension (builds on NousResearch#9193's _HOME_TARGET_ENV_VARS):
adds the three remaining origin-fallback-eligible platforms that have
home channel env vars configured in gateway/config.py but use non-generic
env var names:

- email    → EMAIL_HOME_ADDRESS   (non-standard suffix)
- dingtalk → DINGTALK_HOME_CHANNEL
- qqbot    → QQ_HOME_CHANNEL      (non-standard prefix: QQ_ not QQBOT_)

Picks up the completeness intent of @Xowiek's PR NousResearch#11317 using the
architecturally-correct dict-based lookup from NousResearch#9193, so platforms with
non-standard env var names actually resolve instead of silently missing.
Extended the parametrized regression test to cover the new three.

Weixin test mock alignment (builds on NousResearch#10091's _send_session split):
Three test sites added in Batch 1 (TestWeixinSendImageFileParameterName)
and Batch 3 (TestWeixinVoiceSending) mocked only adapter._session, but
NousResearch#10091 switched the send paths to check self._send_session. Added the
companion setter so the tests stay green with the session split in place.
waefrebeorn pushed a commit to waefrebeorn/slermes that referenced this pull request Jul 2, 2026
…x Weixin test mocks

Cron origin fallback extension (builds on NousResearch#9193's _HOME_TARGET_ENV_VARS):
adds the three remaining origin-fallback-eligible platforms that have
home channel env vars configured in gateway/config.py but use non-generic
env var names:

- email    → EMAIL_HOME_ADDRESS   (non-standard suffix)
- dingtalk → DINGTALK_HOME_CHANNEL
- qqbot    → QQ_HOME_CHANNEL      (non-standard prefix: QQ_ not QQBOT_)

Picks up the completeness intent of @Xowiek's PR NousResearch#11317 using the
architecturally-correct dict-based lookup from NousResearch#9193, so platforms with
non-standard env var names actually resolve instead of silently missing.
Extended the parametrized regression test to cover the new three.

Weixin test mock alignment (builds on NousResearch#10091's _send_session split):
Three test sites added in Batch 1 (TestWeixinSendImageFileParameterName)
and Batch 3 (TestWeixinVoiceSending) mocked only adapter._session, but
NousResearch#10091 switched the send paths to check self._send_session. Added the
companion setter so the tests stay green with the session split in place.
prmartinow pushed a commit to prmartinow/hermes-agent that referenced this pull request Aug 26, 2026
…x Weixin test mocks

Cron origin fallback extension (builds on NousResearch#9193's _HOME_TARGET_ENV_VARS):
adds the three remaining origin-fallback-eligible platforms that have
home channel env vars configured in gateway/config.py but use non-generic
env var names:

- email    → EMAIL_HOME_ADDRESS   (non-standard suffix)
- dingtalk → DINGTALK_HOME_CHANNEL
- qqbot    → QQ_HOME_CHANNEL      (non-standard prefix: QQ_ not QQBOT_)

Picks up the completeness intent of @Xowiek's PR NousResearch#11317 using the
architecturally-correct dict-based lookup from NousResearch#9193, so platforms with
non-standard env var names actually resolve instead of silently missing.
Extended the parametrized regression test to cover the new three.

Weixin test mock alignment (builds on NousResearch#10091's _send_session split):
Three test sites added in Batch 1 (TestWeixinSendImageFileParameterName)
and Batch 3 (TestWeixinVoiceSending) mocked only adapter._session, but
NousResearch#10091 switched the send paths to check self._send_session. Added the
companion setter so the tests stay green with the session split in place.
melon-xf added a commit to melon-xf/hermes-agent that referenced this pull request Sep 3, 2026
…x Weixin test mocks

Cron origin fallback extension (builds on NousResearch#9193's _HOME_TARGET_ENV_VARS):
adds the three remaining origin-fallback-eligible platforms that have
home channel env vars configured in gateway/config.py but use non-generic
env var names:

- email    → EMAIL_HOME_ADDRESS   (non-standard suffix)
- dingtalk → DINGTALK_HOME_CHANNEL
- qqbot    → QQ_HOME_CHANNEL      (non-standard prefix: QQ_ not QQBOT_)

Picks up the completeness intent of @Xowiek's PR NousResearch#11317 using the
architecturally-correct dict-based lookup from NousResearch#9193, so platforms with
non-standard env var names actually resolve instead of silently missing.
Extended the parametrized regression test to cover the new three.

Weixin test mock alignment (builds on NousResearch#10091's _send_session split):
Three test sites added in Batch 1 (TestWeixinSendImageFileParameterName)
and Batch 3 (TestWeixinVoiceSending) mocked only adapter._session, but
NousResearch#10091 switched the send paths to check self._send_session. Added the
companion setter so the tests stay green with the session split in place.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: Weixin messages from cron/send_message are silently dropped when gateway is running

2 participants