Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion src/bub/channels/message.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,9 @@ class ChannelMessage:
media: list[MediaItem] = field(default_factory=list)
lifespan: contextlib.AbstractAsyncContextManager | None = None
output_channel: str = ""
# What the sender wrote, for hooks that search or index messages, when ``content`` wraps it with channel
# metadata; ``None`` means ``content`` is that text.
text: str | None = None

def __post_init__(self) -> None:
self.context.update({"channel": "$" + self.channel, "chat_id": self.chat_id})
Expand All @@ -66,5 +69,8 @@ def from_batch(cls, batch: list[ChannelMessage]) -> ChannelMessage:
raise ValueError("Batch cannot be empty")
template = batch[-1]
content = "\n".join(message.content for message in batch)
text = None
if any(message.text is not None for message in batch):
text = "\n".join(message.content if message.text is None else message.text for message in batch)
media = [item for message in batch for item in message.media]
return replace(template, content=content, media=media)
return replace(template, content=content, media=media, text=text)
4 changes: 3 additions & 1 deletion src/bub/channels/telegram.py
Original file line number Diff line number Diff line change
Expand Up @@ -258,13 +258,15 @@ async def _build_message(self, message: Message) -> ChannelMessage:
metadata["reply_to_message"] = reply_meta
reply_media = _extract_media_items(reply_meta)
media_items.extend(reply_media)
content = json.dumps({"message": content, **metadata}, ensure_ascii=False)
text = content
content = json.dumps({"message": text, **metadata}, ensure_ascii=False)
is_active = MESSAGE_FILTER.filter(message) is not False
return ChannelMessage(
session_id=session_id,
channel=self.name,
chat_id=chat_id,
content=content,
text=text,
media=media_items,
is_active=is_active,
lifespan=self.start_typing(chat_id),
Expand Down
9 changes: 9 additions & 0 deletions tests/test_channels.py
Original file line number Diff line number Diff line change
Expand Up @@ -317,6 +317,14 @@ async def receive(message: ChannelMessage) -> None:
assert handled == [",help\nhello"]


def test_channel_message_batch_joins_text_and_falls_back_to_content() -> None:
wrapped = ChannelMessage(session_id="telegram:42", channel="telegram", content='{"message": "hello"}', text="hello")
plain = ChannelMessage(session_id="telegram:42", channel="telegram", content="world")

assert ChannelMessage.from_batch([wrapped, plain]).text == "hello\nworld"
assert ChannelMessage.from_batch([plain, plain]).text is None


@pytest.mark.asyncio
async def test_channel_manager_dispatch_uses_output_channel_and_preserves_metadata(load_config) -> None:
_load_channel_config(load_config, enabled_channels="cli")
Expand Down Expand Up @@ -1871,6 +1879,7 @@ async def test_telegram_channel_build_message_wraps_payload_and_disables_outboun
assert result.is_active is True
assert '"message": "hello"' in result.content
assert '"reply_to_message"' in result.content
assert result.text == "hello"
assert result.lifespan is not None


Expand Down
Loading