Skip to content

fix(weixin): restore native media delivery - #8251

Closed
QingWei-Li wants to merge 2 commits into
NousResearch:mainfrom
QingWei-Li:fix/weixin-image-upload-corruption
Closed

QingWei-Li wants to merge 2 commits into
NousResearch:mainfrom
QingWei-Li:fix/weixin-image-upload-corruption

Conversation

@QingWei-Li

@QingWei-Li QingWei-Li commented Apr 12, 2026

Copy link
Copy Markdown

Summary

  • accept the keyword argument names used by the shared gateway media helpers
  • use POST for upload_full_url uploads and prefer that path when available
  • encode CDN media aes_key as base64 of the hex text so Weixin clients can decrypt images correctly
  • add regression coverage for upload_full_url handling and CDN AES key encoding

Validation

  • python -m pytest tests/gateway/test_weixin.py -q on profile repo: 24 passed
  • sent a real verification image through Weixin from profile; user confirmed the image opens normally

Notes

  • local macOS environment here does not have pytest installed, so the authoritative test run was executed on the server environment where the bug reproduced

teknium1 added a commit that referenced this pull request Apr 12, 2026
…essages

Four fixes for the Weixin/WeChat adapter, synthesized from the best
aspects of community PRs #8407, #8521, #8360, #7695, #8308, #8525,
#7531, #8144, #8251.

1. Streaming cursor (▉) stuck permanently — WeChat doesn't support
   message editing, so the cursor appended during streaming can never
   be removed.  Add SUPPORTS_MESSAGE_EDITING = False to WeixinAdapter
   and check it in gateway/run.py to use an empty cursor for non-edit
   platforms.  (Fixes #8307, #8326)

2. Media upload failures — two bugs in _send_file():
   a) upload_full_url path used PUT (404 on WeChat CDN); now uses POST.
   b) aes_key was base64(raw_bytes) but the iLink API expects
      base64(hex_string); images showed as grey boxes.  (Fixes #8352, #7529)
   Also: unified both upload paths into _upload_ciphertext(), preferring
   upload_full_url.  Added send_video/send_voice methods and voice_item
   media builder for audio/.silk files.  Added video_md5 field.

3. Markdown links stripped — WeChat can't render [text](url), so
   format_message() now converts them to 'text (url)' plaintext.
   Code blocks are preserved.  (Fixes #7617)

4. Blank message prevention — three guards:
   a) _split_text_for_weixin_delivery('') returns [] not ['']
   b) send() filters empty/whitespace chunks before _send_text_chunk
   c) _send_message() raises ValueError for empty text as safety net

Community credit: joei4cm (#8407), lyonDan (#8521), SKFDJKLDG (#8360),
tomqiaozc (#7695), joshleeeeee (#8308), luoxiao6645(#8525),
longsizhuo (#7531), Astral-Yang (#8144), QingWei-Li (#8251).
teknium1 added a commit that referenced this pull request Apr 12, 2026
…essages (#8665)

Four fixes for the Weixin/WeChat adapter, synthesized from the best
aspects of community PRs #8407, #8521, #8360, #7695, #8308, #8525,
#7531, #8144, #8251.

1. Streaming cursor (▉) stuck permanently — WeChat doesn't support
   message editing, so the cursor appended during streaming can never
   be removed.  Add SUPPORTS_MESSAGE_EDITING = False to WeixinAdapter
   and check it in gateway/run.py to use an empty cursor for non-edit
   platforms.  (Fixes #8307, #8326)

2. Media upload failures — two bugs in _send_file():
   a) upload_full_url path used PUT (404 on WeChat CDN); now uses POST.
   b) aes_key was base64(raw_bytes) but the iLink API expects
      base64(hex_string); images showed as grey boxes.  (Fixes #8352, #7529)
   Also: unified both upload paths into _upload_ciphertext(), preferring
   upload_full_url.  Added send_video/send_voice methods and voice_item
   media builder for audio/.silk files.  Added video_md5 field.

3. Markdown links stripped — WeChat can't render [text](url), so
   format_message() now converts them to 'text (url)' plaintext.
   Code blocks are preserved.  (Fixes #7617)

4. Blank message prevention — three guards:
   a) _split_text_for_weixin_delivery('') returns [] not ['']
   b) send() filters empty/whitespace chunks before _send_text_chunk
   c) _send_message() raises ValueError for empty text as safety net

Community credit: joei4cm (#8407), lyonDan (#8521), SKFDJKLDG (#8360),
tomqiaozc (#7695), joshleeeeee (#8308), luoxiao6645(#8525),
longsizhuo (#7531), Astral-Yang (#8144), QingWei-Li (#8251).
@teknium1

Copy link
Copy Markdown
Collaborator

Merged via PR #8665 which synthesizes the best fixes from ~25 community PRs into a single consolidated change. Your contribution (native media delivery restoration) was reviewed and informed the final implementation. Thank you @QingWei-Li for your work on this!

@teknium1 teknium1 closed this Apr 12, 2026
aj-nt pushed a commit to aj-nt/hermes-agent that referenced this pull request May 1, 2026
…essages (NousResearch#8665)

Four fixes for the Weixin/WeChat adapter, synthesized from the best
aspects of community PRs NousResearch#8407, NousResearch#8521, NousResearch#8360, NousResearch#7695, NousResearch#8308, NousResearch#8525,
NousResearch#7531, NousResearch#8144, NousResearch#8251.

1. Streaming cursor (▉) stuck permanently — WeChat doesn't support
   message editing, so the cursor appended during streaming can never
   be removed.  Add SUPPORTS_MESSAGE_EDITING = False to WeixinAdapter
   and check it in gateway/run.py to use an empty cursor for non-edit
   platforms.  (Fixes NousResearch#8307, NousResearch#8326)

2. Media upload failures — two bugs in _send_file():
   a) upload_full_url path used PUT (404 on WeChat CDN); now uses POST.
   b) aes_key was base64(raw_bytes) but the iLink API expects
      base64(hex_string); images showed as grey boxes.  (Fixes NousResearch#8352, NousResearch#7529)
   Also: unified both upload paths into _upload_ciphertext(), preferring
   upload_full_url.  Added send_video/send_voice methods and voice_item
   media builder for audio/.silk files.  Added video_md5 field.

3. Markdown links stripped — WeChat can't render [text](url), so
   format_message() now converts them to 'text (url)' plaintext.
   Code blocks are preserved.  (Fixes NousResearch#7617)

4. Blank message prevention — three guards:
   a) _split_text_for_weixin_delivery('') returns [] not ['']
   b) send() filters empty/whitespace chunks before _send_text_chunk
   c) _send_message() raises ValueError for empty text as safety net

Community credit: joei4cm (NousResearch#8407), lyonDan (NousResearch#8521), SKFDJKLDG (NousResearch#8360),
tomqiaozc (NousResearch#7695), joshleeeeee (NousResearch#8308), luoxiao6645(NousResearch#8525),
longsizhuo (NousResearch#7531), Astral-Yang (NousResearch#8144), QingWei-Li (NousResearch#8251).
02356abc pushed a commit to 02356abc/hermes-agent that referenced this pull request May 14, 2026
…essages (NousResearch#8665)

Four fixes for the Weixin/WeChat adapter, synthesized from the best
aspects of community PRs NousResearch#8407, NousResearch#8521, NousResearch#8360, NousResearch#7695, NousResearch#8308, NousResearch#8525,
NousResearch#7531, NousResearch#8144, NousResearch#8251.

1. Streaming cursor (▉) stuck permanently — WeChat doesn't support
   message editing, so the cursor appended during streaming can never
   be removed.  Add SUPPORTS_MESSAGE_EDITING = False to WeixinAdapter
   and check it in gateway/run.py to use an empty cursor for non-edit
   platforms.  (Fixes NousResearch#8307, NousResearch#8326)

2. Media upload failures — two bugs in _send_file():
   a) upload_full_url path used PUT (404 on WeChat CDN); now uses POST.
   b) aes_key was base64(raw_bytes) but the iLink API expects
      base64(hex_string); images showed as grey boxes.  (Fixes NousResearch#8352, NousResearch#7529)
   Also: unified both upload paths into _upload_ciphertext(), preferring
   upload_full_url.  Added send_video/send_voice methods and voice_item
   media builder for audio/.silk files.  Added video_md5 field.

3. Markdown links stripped — WeChat can't render [text](url), so
   format_message() now converts them to 'text (url)' plaintext.
   Code blocks are preserved.  (Fixes NousResearch#7617)

4. Blank message prevention — three guards:
   a) _split_text_for_weixin_delivery('') returns [] not ['']
   b) send() filters empty/whitespace chunks before _send_text_chunk
   c) _send_message() raises ValueError for empty text as safety net

Community credit: joei4cm (NousResearch#8407), lyonDan (NousResearch#8521), SKFDJKLDG (NousResearch#8360),
tomqiaozc (NousResearch#7695), joshleeeeee (NousResearch#8308), luoxiao6645(NousResearch#8525),
longsizhuo (NousResearch#7531), Astral-Yang (NousResearch#8144), QingWei-Li (NousResearch#8251).
waefrebeorn pushed a commit to waefrebeorn/slermes that referenced this pull request Jul 2, 2026
…essages (NousResearch#8665)

Four fixes for the Weixin/WeChat adapter, synthesized from the best
aspects of community PRs NousResearch#8407, NousResearch#8521, NousResearch#8360, NousResearch#7695, NousResearch#8308, NousResearch#8525,
NousResearch#7531, NousResearch#8144, NousResearch#8251.

1. Streaming cursor (▉) stuck permanently — WeChat doesn't support
   message editing, so the cursor appended during streaming can never
   be removed.  Add SUPPORTS_MESSAGE_EDITING = False to WeixinAdapter
   and check it in gateway/run.py to use an empty cursor for non-edit
   platforms.  (Fixes NousResearch#8307, NousResearch#8326)

2. Media upload failures — two bugs in _send_file():
   a) upload_full_url path used PUT (404 on WeChat CDN); now uses POST.
   b) aes_key was base64(raw_bytes) but the iLink API expects
      base64(hex_string); images showed as grey boxes.  (Fixes NousResearch#8352, NousResearch#7529)
   Also: unified both upload paths into _upload_ciphertext(), preferring
   upload_full_url.  Added send_video/send_voice methods and voice_item
   media builder for audio/.silk files.  Added video_md5 field.

3. Markdown links stripped — WeChat can't render [text](url), so
   format_message() now converts them to 'text (url)' plaintext.
   Code blocks are preserved.  (Fixes NousResearch#7617)

4. Blank message prevention — three guards:
   a) _split_text_for_weixin_delivery('') returns [] not ['']
   b) send() filters empty/whitespace chunks before _send_text_chunk
   c) _send_message() raises ValueError for empty text as safety net

Community credit: joei4cm (NousResearch#8407), lyonDan (NousResearch#8521), SKFDJKLDG (NousResearch#8360),
tomqiaozc (NousResearch#7695), joshleeeeee (NousResearch#8308), luoxiao6645(NousResearch#8525),
longsizhuo (NousResearch#7531), Astral-Yang (NousResearch#8144), QingWei-Li (NousResearch#8251).
prmartinow pushed a commit to prmartinow/hermes-agent that referenced this pull request Aug 26, 2026
…essages (NousResearch#8665)

Four fixes for the Weixin/WeChat adapter, synthesized from the best
aspects of community PRs NousResearch#8407, NousResearch#8521, NousResearch#8360, NousResearch#7695, NousResearch#8308, NousResearch#8525,
NousResearch#7531, NousResearch#8144, NousResearch#8251.

1. Streaming cursor (▉) stuck permanently — WeChat doesn't support
   message editing, so the cursor appended during streaming can never
   be removed.  Add SUPPORTS_MESSAGE_EDITING = False to WeixinAdapter
   and check it in gateway/run.py to use an empty cursor for non-edit
   platforms.  (Fixes NousResearch#8307, NousResearch#8326)

2. Media upload failures — two bugs in _send_file():
   a) upload_full_url path used PUT (404 on WeChat CDN); now uses POST.
   b) aes_key was base64(raw_bytes) but the iLink API expects
      base64(hex_string); images showed as grey boxes.  (Fixes NousResearch#8352, NousResearch#7529)
   Also: unified both upload paths into _upload_ciphertext(), preferring
   upload_full_url.  Added send_video/send_voice methods and voice_item
   media builder for audio/.silk files.  Added video_md5 field.

3. Markdown links stripped — WeChat can't render [text](url), so
   format_message() now converts them to 'text (url)' plaintext.
   Code blocks are preserved.  (Fixes NousResearch#7617)

4. Blank message prevention — three guards:
   a) _split_text_for_weixin_delivery('') returns [] not ['']
   b) send() filters empty/whitespace chunks before _send_text_chunk
   c) _send_message() raises ValueError for empty text as safety net

Community credit: joei4cm (NousResearch#8407), lyonDan (NousResearch#8521), SKFDJKLDG (NousResearch#8360),
tomqiaozc (NousResearch#7695), joshleeeeee (NousResearch#8308), luoxiao6645(NousResearch#8525),
longsizhuo (NousResearch#7531), Astral-Yang (NousResearch#8144), QingWei-Li (NousResearch#8251).
melon-xf added a commit to melon-xf/hermes-agent that referenced this pull request Sep 3, 2026
…essages (NousResearch#8665)

Four fixes for the Weixin/WeChat adapter, synthesized from the best
aspects of community PRs NousResearch#8407, NousResearch#8521, NousResearch#8360, NousResearch#7695, NousResearch#8308, NousResearch#8525,
NousResearch#7531, NousResearch#8144, NousResearch#8251.

1. Streaming cursor (▉) stuck permanently — WeChat doesn't support
   message editing, so the cursor appended during streaming can never
   be removed.  Add SUPPORTS_MESSAGE_EDITING = False to WeixinAdapter
   and check it in gateway/run.py to use an empty cursor for non-edit
   platforms.  (Fixes NousResearch#8307, NousResearch#8326)

2. Media upload failures — two bugs in _send_file():
   a) upload_full_url path used PUT (404 on WeChat CDN); now uses POST.
   b) aes_key was base64(raw_bytes) but the iLink API expects
      base64(hex_string); images showed as grey boxes.  (Fixes NousResearch#8352, NousResearch#7529)
   Also: unified both upload paths into _upload_ciphertext(), preferring
   upload_full_url.  Added send_video/send_voice methods and voice_item
   media builder for audio/.silk files.  Added video_md5 field.

3. Markdown links stripped — WeChat can't render [text](url), so
   format_message() now converts them to 'text (url)' plaintext.
   Code blocks are preserved.  (Fixes NousResearch#7617)

4. Blank message prevention — three guards:
   a) _split_text_for_weixin_delivery('') returns [] not ['']
   b) send() filters empty/whitespace chunks before _send_text_chunk
   c) _send_message() raises ValueError for empty text as safety net

Community credit: joei4cm (NousResearch#8407), lyonDan (NousResearch#8521), SKFDJKLDG (NousResearch#8360),
tomqiaozc (NousResearch#7695), joshleeeeee (NousResearch#8308), luoxiao6645(NousResearch#8525),
longsizhuo (NousResearch#7531), Astral-Yang (NousResearch#8144), QingWei-Li (NousResearch#8251).
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.

2 participants