# NousResearch/hermes-agent · LINE adapter inbound image message type mapping

## Open now

- Nothing open on GitHub.

These issues and pull requests concern a bug where the LINE adapter incorrectly parses or classifies inbound image messages, and the associated fixes to map LINE message types to the correct internal MessageType.

## TL;DR

- 3 member(s): 0 open issue(s), 1 closed issue(s), 0 open PR(s), 1 merged PR(s), 1 PR(s) closed without merging.
- A fix was merged to main in PR #39485. Verify it addresses your case.
- **Recommended:** read PR #39485 (and any competing PRs below) before filing. Confirm the merged change covers your symptom.

## Maintainer resolution verdict

- Internal-tracker verdict over this cluster's issue members: `unresolved`. This is distinct from the fix status above. Weigh it yourself.

## How this cluster was grouped

- Link evidence (`STRUCTURAL_SPANNING`): every member is connected by structural evidence: shared changed files, or a closing/superseded reference.
- Pairwise link density `0.67`: the share of member pairs that carry a link, counting a structural link in full and a relevance-only link at 0.36. `1.00` means every pair is linked.

## Closed / duplicate issues

- #38235: \[Bug\]: LINE adapter can't parse image messages

## Prior & competing PRs

- **#39485: fix(line): map inbound message types to the correct MessageType**. merged to main · fix tier `verified`
  - maintainer direction: category `merged`
  - files: `plugins/platforms/line/adapter.py`, `tests/gateway/test_line_plugin.py`
  - fix hunks:
  - `plugins/platforms/line/adapter.py`

    ```diff
    @@ -133,6 +133,21 @@
     LINE_IMAGE_MAX_BYTES = 10 * 1024 * 1024  # 10 MB per LINE docs
     LINE_AV_MAX_BYTES = 200 * 1024 * 1024  # 200 MB for voice/video
     
    +# Map LINE webhook message types to the normalized MessageType the gateway
    +# routes on. LINE has no separate "voice" type — audio messages are recorded
    +# voice clips, so they map to VOICE (which the gateway sends through STT),
    +# mirroring how Telegram/WhatsApp classify voice notes. Anything unknown
    +# falls back to TEXT.
    +_LINE_MESSAGE_TYPES = {
    +    "text": MessageType.TEXT,
    +    "image": MessageType.PHOTO,
    +    "video": MessageType.VIDEO,
    +    "audio": MessageType.VOICE,
    +    "file": MessageType.DOCUMENT,
    +    "location": MessageType.LOCATION,
    +    "sticker": MessageType.STICKER,
    +}
    +
     # A 1×1 transparent PNG used as fallback video preview thumbnail when no
     # explicit preview is supplied — LINE requires ``previewImageUrl`` for
     # video messages. Sourced from the Python stdlib (no Pillow dependency).
    ```

    ```diff
    @@ -968,7 +983,7 @@ async def _handle_message_event(self, event: Dict[str, Any]) -> None:
     
             event_obj = MessageEvent(
                 text=text,
    -            message_type=MessageType.TEXT if msg_type == "text" else MessageType.IMAGE,
    +            message_type=_LINE_MESSAGE_TYPES.get(msg_type, MessageType.TEXT),
                 source=source_obj,
                 raw_message=event,
                 message_id=message_id,
    ```
  - `tests/gateway/test_line_plugin.py`

    ```diff
    @@ -641,3 +641,36 @@ def test_get_chat_info_infers_type_from_prefix(self, monkeypatch):
             assert asyncio.run(ad.get_chat_info("U123"))["type"] == "dm"
             assert asyncio.run(ad.get_chat_info("C123"))["type"] == "group"
             assert asyncio.run(ad.get_chat_info("R123"))["type"] == "channel"
    +
    +
    +# ---------------------------------------------------------------------------
    +# 9. Inbound message-type classification
    +# ---------------------------------------------------------------------------
    +
    +class TestMessageTypeMapping:
    +    """LINE webhook message types must map to the right normalized
    +    MessageType so the gateway routes media correctly (e.g. voice → STT,
    +    files → document handling). Regression guard for the old code that
    +    referenced the non-existent ``MessageType.IMAGE`` and collapsed every
    +    non-text message onto a single type."""
    +
    +    def test_image_event_not_attributeerror_regression(self):
    +        # The bug: MessageType.IMAGE doesn't exist on the enum.
    +        MessageType = _line.MessageType
    +        assert not hasattr(MessageType, "IMAGE")
    +
    +    def test_every_line_type_maps_to_correct_enum(self):
    +        MessageType = _line.MessageType
    +        mapping = _line._LINE_MESSAGE_TYPES
    +        assert mapping["text"] == MessageType.TEXT
    +        assert mapping["image"] == MessageType.PHOTO
    +        assert mapping["video"] == MessageType.VIDEO
    +        # LINE has no separate voice type — audio clips are voice notes.
    +        assert mapping["audio"] == MessageType.VOICE
    +        assert mapping["file"] == MessageType.DOCUMENT
    +        assert mapping["location"] == MessageType.LOCATION
    +        assert mapping["sticker"] == MessageType.STICKER
    +
    +    def test_unknown_type_falls_back_to_text(self):
    +        MessageType = _line.MessageType
    +        assert _line._LINE_MESSAGE_TYPES.get("flex", MessageType.TEXT) == MessageType.TEXT
    ```
- **#38528: fix(line): classify image messages as photos**. closed without merge
  - maintainer direction: category `merged_via`; implication `superseded`; refs `7309f3bef`, `#39485`

## Fix status

- Merged to main in PR #39485 (cited above). No release data is tracked. Verify downstream.
- Fix last verified (merged) `2026-06-05`.
- Subsystem: `gateway`
