Summary
Two related bugs in the WeChat (weixin) message delivery path that affect file sending reliability:
Bug 1: MEDIA tag leaks as raw text for common file types
BasePlatformAdapter.extract_media() in gateway/platforms/base.py uses a regex whitelist of file extensions. The whitelist is missing several common types: .md, .json, .yaml, .yml, .toml, .log. When a MEDIA:/path/to/file.md tag is used, the regex does not match → the MEDIA tag stays in the text and appears as raw text on WeChat instead of being converted to a file attachment.
Current regex (line 2162):
\.(?:png|jpe?g|gif|webp|mp4|mov|avi|mkv|webm|ogg|opus|mp3|wav|m4a|flac|epub|pdf|zip|rar|7z|docx?|xlsx?|pptx?|txt|csv|apk|ipa)
Fix: Add |md|json|yaml|yml|toml|log to the whitelist.
Bug 2: send_weixin_direct() returns immediately on rate-limit/session errors
When the iLink session expires (e.g., after gateway restart), send_weixin_direct() calls adapter.send() which internally exhausts _send_text_chunk retries and returns an error. The function then immediately returns this error with no retry at the send_weixin_direct level — no context_token refresh, no backoff, no tokenless fallback.
After gateway restart, the stored context_token is stale. The adapter's internal _send_text_chunk retries handle errcode: -14 (session timeout) correctly, but ret: -2 (rate limit, often caused by stale session) is treated as a pure rate limit with insufficient backoff.
Suggested fix: Add a retry loop in the fallback path of send_weixin_direct() that clears the stale context_token and retries at least once.
Steps to Reproduce
- Send a message with
MEDIA:/tmp/test.md via send_message(target="weixin")
- Observe that WeChat shows the raw
MEDIA:/tmp/test.md text instead of a file attachment
- Restart the Hermes gateway
- Immediately try to send a message — observe
ret=-2 error with no retry
Environment
- Hermes Agent: latest
- Platform: WeChat iLink API
- OS: macOS
Files Affected
gateway/platforms/base.py — extract_media() regex pattern
gateway/platforms/weixin.py — send_weixin_direct() fallback path
Summary
Two related bugs in the WeChat (weixin) message delivery path that affect file sending reliability:
Bug 1: MEDIA tag leaks as raw text for common file types
BasePlatformAdapter.extract_media()ingateway/platforms/base.pyuses a regex whitelist of file extensions. The whitelist is missing several common types:.md,.json,.yaml,.yml,.toml,.log. When aMEDIA:/path/to/file.mdtag is used, the regex does not match → the MEDIA tag stays in the text and appears as raw text on WeChat instead of being converted to a file attachment.Current regex (line 2162):
Fix: Add
|md|json|yaml|yml|toml|logto the whitelist.Bug 2:
send_weixin_direct()returns immediately on rate-limit/session errorsWhen the iLink session expires (e.g., after gateway restart),
send_weixin_direct()callsadapter.send()which internally exhausts_send_text_chunkretries and returns an error. The function then immediately returns this error with no retry at thesend_weixin_directlevel — no context_token refresh, no backoff, no tokenless fallback.After gateway restart, the stored
context_tokenis stale. The adapter's internal_send_text_chunkretries handleerrcode: -14(session timeout) correctly, butret: -2(rate limit, often caused by stale session) is treated as a pure rate limit with insufficient backoff.Suggested fix: Add a retry loop in the fallback path of
send_weixin_direct()that clears the stale context_token and retries at least once.Steps to Reproduce
MEDIA:/tmp/test.mdviasend_message(target="weixin")MEDIA:/tmp/test.mdtext instead of a file attachmentret=-2error with no retryEnvironment
Files Affected
gateway/platforms/base.py—extract_media()regex patterngateway/platforms/weixin.py—send_weixin_direct()fallback path