hermes - ✅(Solved) Fix [WeCom] Inbound images and files with media_id are silently dropped [1 pull requests, 1 comments, 2 participants]

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…
GitHub stats
NousResearch/hermes-agent#14062Fetched 2026-04-23 07:47:01
View on GitHub
Comments
1
Participants
2
Timeline
8
Reactions
0
Author
Participants
Timeline (top)
labeled ×4cross-referenced ×2commented ×1subscribed ×1

Error Message

API returns errors as JSON body, not HTTP error status

Root Cause

_cache_media in gateway/platforms/wecom.py only handles base64 and url fields. WeCom AI Bot sends attachments as media_id references, which was not handled — the method returned None immediately, silently dropping the attachment.

Fix Action

Fix

Add a _download_media_by_id method that calls POST https://qyapi.weixin.qq.com/cgi-bin/aibot/media/get with robot_id + secret to download the raw bytes. Then handle the media_id path in _cache_media for both images and files.

async def _download_media_by_id(self, media_id: str) -> Optional[Tuple[bytes, str]]:
    url = "https://qyapi.weixin.qq.com/cgi-bin/aibot/media/get"
    resp = await self._http_client.post(
        url,
        json={"robot_id": self._bot_id, "secret": self._secret, "media_id": media_id},
        timeout=REQUEST_TIMEOUT_SECONDS,
    )
    resp.raise_for_status()
    content_type = str(resp.headers.get("content-type", "")).split(";", 1)[0].strip()
    # API returns errors as JSON body, not HTTP error status
    if "application/json" in content_type or "text/plain" in content_type:
        return None
    return resp.content, content_type or "application/octet-stream"

Key notes:

  • Endpoint is POST, not GET
  • Auth uses robot_id + secret, not access token
  • A successful response returns raw bytes; errors are returned as JSON body with 200 status — must check content-type to distinguish

PR fix notes

PR #14074: fix(wecom): cache inbound media_id attachments

Description (problem / solution / changelog)

Summary

  • add a WeCom media_id download path for inbound attachments
  • teach _cache_media() to persist image/file callbacks that only carry media_id
  • add regression coverage for both image and file media-id payloads

Problem

On current main, inbound WeCom attachments that arrive as media_id references are silently dropped because _cache_media() only handles base64 and url payloads. A minimal repro with _cache_media("image", {"media_id": "media-123"}) returned None.

Closes #14062.

Testing

  • pytest -o addopts= tests/gateway/test_wecom.py
  • manual repro: _cache_media("image", {"media_id": "media-123"}) now returns a cached local image path instead of None

Changed files

  • gateway/platforms/wecom.py (modified, +66/-0)
  • tests/gateway/test_wecom.py (modified, +46/-1)

Code Example

async def _download_media_by_id(self, media_id: str) -> Optional[Tuple[bytes, str]]:
    url = "https://qyapi.weixin.qq.com/cgi-bin/aibot/media/get"
    resp = await self._http_client.post(
        url,
        json={"robot_id": self._bot_id, "secret": self._secret, "media_id": media_id},
        timeout=REQUEST_TIMEOUT_SECONDS,
    )
    resp.raise_for_status()
    content_type = str(resp.headers.get("content-type", "")).split(";", 1)[0].strip()
    # API returns errors as JSON body, not HTTP error status
    if "application/json" in content_type or "text/plain" in content_type:
        return None
    return resp.content, content_type or "application/octet-stream"
RAW_BUFFERClick to expand / collapse

Bug Description

When users send images or files via WeCom AI Bot, the attachment is silently lost. The bot only receives the text portion of the message with no media attached.

Root Cause

_cache_media in gateway/platforms/wecom.py only handles base64 and url fields. WeCom AI Bot sends attachments as media_id references, which was not handled — the method returned None immediately, silently dropping the attachment.

Fix

Add a _download_media_by_id method that calls POST https://qyapi.weixin.qq.com/cgi-bin/aibot/media/get with robot_id + secret to download the raw bytes. Then handle the media_id path in _cache_media for both images and files.

async def _download_media_by_id(self, media_id: str) -> Optional[Tuple[bytes, str]]:
    url = "https://qyapi.weixin.qq.com/cgi-bin/aibot/media/get"
    resp = await self._http_client.post(
        url,
        json={"robot_id": self._bot_id, "secret": self._secret, "media_id": media_id},
        timeout=REQUEST_TIMEOUT_SECONDS,
    )
    resp.raise_for_status()
    content_type = str(resp.headers.get("content-type", "")).split(";", 1)[0].strip()
    # API returns errors as JSON body, not HTTP error status
    if "application/json" in content_type or "text/plain" in content_type:
        return None
    return resp.content, content_type or "application/octet-stream"

Key notes:

  • Endpoint is POST, not GET
  • Auth uses robot_id + secret, not access token
  • A successful response returns raw bytes; errors are returned as JSON body with 200 status — must check content-type to distinguish

Environment

  • Platform: WeCom (企业微信) AI Bot — WebSocket mode (wecom.py)

extent analysis

TL;DR

Implement the _download_media_by_id method to handle media_id references and update _cache_media to process attachments sent by WeCom AI Bot.

Guidance

  • Verify that the _download_media_by_id method is correctly implemented with the POST endpoint, robot_id and secret for authentication, and proper handling of response content types.
  • Update the _cache_media method in gateway/platforms/wecom.py to handle media_id references by calling the new _download_media_by_id method.
  • Ensure error handling is in place for cases where the media download fails or returns an error response.
  • Test the updated implementation with various attachment types (images and files) to confirm that they are correctly received by the bot.

Example

async def _cache_media(self, media):
    if "media_id" in media:
        media_bytes, content_type = await self._download_media_by_id(media["media_id"])
        # Process the downloaded media bytes and content type
    # ... existing code for handling base64 and url fields

Notes

The provided fix assumes that the WeCom AI Bot API endpoint and authentication mechanism are correctly documented and implemented. Any changes to the API or authentication requirements may affect the validity of this solution.

Recommendation

Apply the workaround by implementing the _download_media_by_id method and updating the _cache_media method, as this directly addresses the identified root cause of the issue.

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING