Skip to content

test(line): regression coverage for typed media-cache routing - #35785

Open
jethac wants to merge 2 commits into
NousResearch:mainfrom
jethac:fix/line-media-adapter
Open

test(line): regression coverage for typed media-cache routing#35785
jethac wants to merge 2 commits into
NousResearch:mainfrom
jethac:fix/line-media-adapter

Conversation

@jethac

@jethac jethac commented May 31, 2026

Copy link
Copy Markdown
Contributor

Summary

Scope change (2026-07-29): upstream 73e193c03 independently shipped a superset of this PR's original adapter fix (typed media-cache dispatch, fileName threading, (path, media_type) tuple returns), so the code changes here were dropped in the rebase. What remains — and what this PR now contributes — is the regression test coverage upstream doesn't have:

  • TestDownloadMediaRouting: locks in typed media-cache routing for the LINE adapter — text/image/audio/video messages map to their correct MessageType enums and cached media resolves through the keyword-only filename= / (path, media_type) tuple signatures, with MIME-typed media_types.
  • Guards the exact crash class the original fix addressed (AttributeError: IMAGE on non-text messages), so it can't regress silently.
  • Plus the AUTHOR_MAP release-map line.

Original motivation (fixed upstream, now covered by these tests): the adapter crashed on any non-text message and mis-cached media by treating all downloads as untyped blobs.

Test evidence

tests/gateway/test_line_plugin.py + contributor-map suite: 113 passed on current main (f75b577b9).

@alt-glitch alt-glitch added type/bug Something isn't working P3 Low — cosmetic, nice to have comp/gateway Gateway runner, session dispatch, delivery comp/plugins Plugin system and bundled plugins labels May 31, 2026
@alt-glitch

Copy link
Copy Markdown
Collaborator

Duplicate of #34233 (and #27142). Same LINE adapter bug: MessageType.IMAGE doesn't exist (should be PHOTO), and media cache routing treats all media as images. #34233 has the same fix with proper type mapping and cache_media_from_bytes generalization.

@jethac

jethac commented May 31, 2026

Copy link
Copy Markdown
Contributor Author

@alt-glitch Thanks for flagging this as a duplicate! I’ve reviewed the previous attempts (#34233, #27142).

My implementation builds on those by explicitly ensuring backward compatibility—preserving the legacy image-cache aliases so we don't break the rest of the gateway or existing tests. It also enforces filesystem strictness by segregating generic media from images, which I found was required to pass the current e2e test suite.

Would love your feedback on whether this path is consistent with the current architectural direction.

@tonydwb tonydwb left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review Summary

Verdict: Approved

🔍 What this does

Two fixes in the LINE platform adapter:

  1. Message type mapping: Replaces the binary MessageType.IMAGE if msg_type == "text" else MessageType.IMAGE bug (which crashed on voice/video/image) with a proper dict-based mapping (text→TEXT, image→PHOTO, audio→VOICE, video→VIDEO).
  2. Media caching: Introduces cache_media_from_bytes() / cache_media_from_url() as generalized media-caching utilities, refactoring cache_image_from_bytes() / cache_image_from_url() to delegate to them. LINE adapter now uses cache_media_from_bytes() for non-image media.

✅ Looks Good

  • Correctness of type mapping: The dict-based approach is clean and handles all LINE message types. Falls back to MessageType.TEXT for unknown types — safe default.
  • Refactoring quality: The generalization from cache_image_from_bytescache_media_from_bytes is well-structured. Backward compat aliases preserve all existing callers. The is_image flag differentiates cache/images vs cache/media subdirectories.
  • Edge cases: The cache_image_from_bytes still validates image data via _looks_like_image() before delegating, preserving existing safety checks.
  • LINE adapter: Proper use of cache_media_from_bytes(data, ext=ext, is_image=(msg_type == "image")) correctly routes image vs audio/video to the right cache dir.

💡 Suggestion (non-blocking)

Consider moving the inner import uuid and from hermes_constants imports in cache_media_from_bytes to module-level imports for readability. The current inline imports avoid circular deps but add cognitive overhead.


Reviewed by Hermes Agent (cron)

@jethac
jethac force-pushed the fix/line-media-adapter branch 2 times, most recently from 724eb8e to f082ec7 Compare June 7, 2026 01:33
@jethac
jethac force-pushed the fix/line-media-adapter branch from f082ec7 to 0c99e9d Compare June 7, 2026 02:55
@jethac
jethac force-pushed the fix/line-media-adapter branch from 0c99e9d to 9374f6f Compare June 23, 2026 10:22
@jethac

jethac commented Jun 23, 2026

Copy link
Copy Markdown
Contributor Author

Rebased this PR onto current main and resolved the media-cache conflict.

Additional cleanup in this update:

  • Preserved strict image sniffing/validation for cache_image_from_url / cache_image_from_bytes.
  • Kept generic cache_media_from_url for non-image media payloads.
  • Added regression coverage for image URL validation vs generic media URL caching.

Local verification:

uv run --with pytest --with aiohttp python -m pytest \
  tests/gateway/test_media_download_retry.py \
  tests/gateway/test_line_plugin.py \
  -q -o 'addopts='
# 115 passed

@jethac
jethac force-pushed the fix/line-media-adapter branch from 9fd7ab5 to 44e6dea Compare June 23, 2026 10:39
@jethac

jethac commented Jun 23, 2026

Copy link
Copy Markdown
Contributor Author

Quick follow-up on the attribution change: CI flagged jethachan@gmail.com as an unmapped contributor email. I also noticed this stack still had older commits authored as jetha@google.com, which was already mapped.

Since I’m leaving Google and want future attribution tied to my personal account, I rewrote this PR stack to use Jetha Chan <jethachan@gmail.com>, removed the old jetha@google.com AUTHOR_MAP entry, and kept the new jethachan@gmail.com -> jethac mapping.

No runtime code changed from that attribution-only rewrite; targeted tests were re-run after the rebase. The three PRs remain stacked locally: #35785 base, #40931 on top, #40933 on top.

@jethac
jethac force-pushed the fix/line-media-adapter branch 5 times, most recently from 95ac1d4 to 573b156 Compare June 29, 2026 00:09
@jethac
jethac force-pushed the fix/line-media-adapter branch from 573b156 to 63a1998 Compare July 2, 2026 06:16

@teknium1 teknium1 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for preserving image validation while addressing a real LINE media path issue. Current main already contains the MessageType mapping fix from 7309f3bef (plugins/platforms/line/adapter.py:141-149); the remaining defect is that _download_media() still sends audio, video, and files through cache_image_from_bytes() at plugins/platforms/line/adapter.py:1070.

Problems

  • The new cache_media_from_bytes / cache_media_from_url API duplicates existing cache infrastructure: typed helpers at gateway/platforms/base.py:826, :933, and :1553, plus the existing classifier/router cache_media_bytes() at :1651.
  • The added tests cover the new URL helper, but the LINE production path calls the bytes helper. tests/gateway/test_line_plugin.py:650-676 currently tests only type mapping and does not cover _download_media().

Suggested changes

  • Re-scope the salvage to route LINE payloads through the existing typed helpers (or cache_media_bytes()), retaining the established cache directories and validation behavior.
  • Add mocked LINE download regressions for audio, video, and file messages.

Automated hermes-sweeper review.

@@ -1067,7 +1068,7 @@ async def _download_media(self, message_id: str, msg_type: str) -> Optional[str]
"file": ".bin",
}.get(msg_type, ".bin")
try:

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

gateway/platforms/base.py already provides cache_audio_from_bytes (line 826), cache_video_from_bytes (line 933), cache_document_from_bytes (line 1553), and cache_media_bytes (line 1651). Please dispatch this method through those established helpers instead of introducing a parallel generic cache API; that preserves the existing cache contracts and avoids an otherwise-unused generic URL helper.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in 05a13e2 — the parallel cache_media_from_bytes/cache_media_from_url API is removed entirely (gateway/platforms/base.py is now byte-identical to main) and _download_media() dispatches directly on the LINE message type: image → cache_image_from_bytes, audio → cache_audio_from_bytes, video → cache_video_from_bytes, file → cache_document_from_bytes (threading LINE's fileName through, falling back to line_file.bin). I went with direct typed dispatch rather than cache_media_bytes() since LINE's content API already fixes the format per type — no classification needed — and it preserves the raw cache-path contract this adapter surfaces. Nine new mocked regressions in tests/gateway/test_line_plugin.py now cover the production path per type plus fetch/cache failure modes.

@teknium1 teknium1 added sweeper:risk-message-delivery Sweeper risk: may drop, duplicate, misroute, or suppress messages sweeper:risk-compatibility Sweeper risk: may break existing users, config, migrations, defaults, or upgrades sweeper:blast-moderate Sweeper blast radius: moderate — a subsystem or single platform labels Jul 13, 2026
@jethac
jethac force-pushed the fix/line-media-adapter branch from 63a1998 to 6e02e4d Compare July 19, 2026 01:13
@jethac

jethac commented Jul 19, 2026

Copy link
Copy Markdown
Contributor Author

Thanks for the review — re-scoped exactly as suggested; specifics are in the inline reply. Rebased onto current main, so the MessageType-mapping half (already absorbed via 7309f3b) has dropped out of the diff; what remains is the real defect fix — audio/video/file payloads no longer round-trip through cache_image_from_bytes()'s image validation. One coordination note: the author-map line here also appears in #63560; whichever merges first, the other rebases trivially. CI is green and GitHub reports the PR mergeable.

jethac added a commit to jethac/hermes-agent that referenced this pull request Jul 22, 2026
…35785 itself

Bisected commit-by-commit: this line survives cleanly through the
author-map/flake-fix/multi-agent merges and disappears exactly at merging
fix/line-media-adapter. Confirmed via diff against that PR branch's own
merge-base that the deletion is baked into the PR's own commit history
(unrelated to its actual LINE-media-caching purpose -- almost certainly
incidental collateral from however that PR's author-map commit was
originally assembled), not an artifact of this merge. No PR has any
legitimate reason to remove this mapping, so restoring it here.

(The duplicate "jethachan@gmail.com" entry, by contrast, is harmless: two
of jethac's own PRs -- NousResearch#63560 and NousResearch#35785 -- each independently add the
identical line/comment, consistent with ~75 other pre-existing duplicate
keys already in this file on upstream/main. Left as-is.)

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@jethac
jethac force-pushed the fix/line-media-adapter branch from 6e02e4d to 4931c88 Compare July 29, 2026 06:10
@jethac jethac changed the title fix(line): correct media caching and message type mapping test(line): regression coverage for typed media-cache routing Jul 29, 2026
jethac and others added 2 commits July 30, 2026 11:01
Rebase note: upstream 73e193c ("fix(line): normalize inbound media
types and cache routing") independently shipped a superset of this
branch's adapter fix — typed cache helper dispatch, fileName threading,
and a (path, media_type) return from _download_media. The adapter
changes are therefore dropped in favor of upstream's version.

What remains from the original commit: the mocked regression tests
covering _download_media routing for all four LINE content types,
cache/fetch failure fallbacks, and fileName threading from the message
event — adapted to upstream's keyword-only ``filename=`` parameter and
tuple return, and to media_types now carrying MIME types.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Map the contributor email used on the LINE media PR stack to the jethac
GitHub handle, replacing the stale legacy-map entry.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@jethac
jethac force-pushed the fix/line-media-adapter branch from 4931c88 to a18ce7e Compare July 30, 2026 02:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

comp/gateway Gateway runner, session dispatch, delivery comp/plugins Plugin system and bundled plugins P3 Low — cosmetic, nice to have sweeper:blast-moderate Sweeper blast radius: moderate — a subsystem or single platform sweeper:risk-compatibility Sweeper risk: may break existing users, config, migrations, defaults, or upgrades sweeper:risk-message-delivery Sweeper risk: may drop, duplicate, misroute, or suppress messages type/bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants