From 0a92a33ece67722e7aa024e892efdd3a1d3a9b57 Mon Sep 17 00:00:00 2001 From: Tranquil-Flow Date: Thu, 4 Jun 2026 08:36:35 +0200 Subject: [PATCH] fix(line): map LINE image messages to photos (#38235) --- plugins/platforms/line/adapter.py | 18 +++++++++++++++++- tests/plugins/test_line_adapter.py | 30 ++++++++++++++++++++++++++++++ 2 files changed, 47 insertions(+), 1 deletion(-) create mode 100644 tests/plugins/test_line_adapter.py diff --git a/plugins/platforms/line/adapter.py b/plugins/platforms/line/adapter.py index 00663702ea16..18badc5c7464 100644 --- a/plugins/platforms/line/adapter.py +++ b/plugins/platforms/line/adapter.py @@ -133,6 +133,22 @@ LINE_IMAGE_MAX_BYTES = 10 * 1024 * 1024 # 10 MB per LINE docs LINE_AV_MAX_BYTES = 200 * 1024 * 1024 # 200 MB for voice/video +_LINE_MESSAGE_TYPES = { + "text": MessageType.TEXT, + "image": MessageType.PHOTO, + "audio": MessageType.AUDIO, + "video": MessageType.VIDEO, + "file": MessageType.DOCUMENT, + "sticker": MessageType.STICKER, + "location": MessageType.LOCATION, +} + + +def _line_msg_type(line_type: str) -> MessageType: + """Map a LINE webhook message type to Hermes' canonical message type.""" + return _LINE_MESSAGE_TYPES.get(line_type, MessageType.TEXT) + + # 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). @@ -968,7 +984,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_msg_type(msg_type), source=source_obj, raw_message=event, message_id=message_id, diff --git a/tests/plugins/test_line_adapter.py b/tests/plugins/test_line_adapter.py new file mode 100644 index 000000000000..aad862fd385c --- /dev/null +++ b/tests/plugins/test_line_adapter.py @@ -0,0 +1,30 @@ +"""Regression tests for LINE inbound MessageType mapping.""" + +from gateway.platforms.base import MessageEvent, MessageType +from plugins.platforms.line.adapter import _line_msg_type + + +def test_line_image_messages_map_to_photo_message_type(): + """LINE sends type='image', but Hermes uses MessageType.PHOTO.""" + event = MessageEvent( + text="[image]", + message_type=_line_msg_type("image"), + source=None, # type: ignore[arg-type] + ) + + assert not hasattr(MessageType, "IMAGE") + assert event.message_type is MessageType.PHOTO + + +def test_line_non_text_message_types_map_to_existing_message_types(): + assert _line_msg_type("text") is MessageType.TEXT + assert _line_msg_type("audio") is MessageType.AUDIO + assert _line_msg_type("video") is MessageType.VIDEO + assert _line_msg_type("file") is MessageType.DOCUMENT + assert _line_msg_type("sticker") is MessageType.STICKER + assert _line_msg_type("location") is MessageType.LOCATION + + +def test_line_unknown_message_types_default_to_text(): + assert _line_msg_type("poll") is MessageType.TEXT + assert _line_msg_type("") is MessageType.TEXT