Skip to content

feat(channels): expose what the sender wrote on Telegram messages - #399

Merged
frostming merged 1 commit into
bubbuild:mainfrom
Fengzdadi:feat/telegram-message-text
Nov 5, 2026
Merged

frostming merged 1 commit into
bubbuild:mainfrom
Fengzdadi:feat/telegram-message-text

Conversation

@Fengzdadi

Copy link
Copy Markdown
Contributor

What changed and why

The Telegram channel builds each message's content as JSON: the sender's text under message, next to sender and message metadata (message_id, username, sender_id, date, reply_to_message, ...). That is what the model should see, but a hook that searches or indexes messages also gets only that JSON. To recover what the user wrote, it has to parse the JSON back out.

PowerContext's Bub plugin hit this case. It recalls memory with the inbound message's text, read in load_state before build_prompt frames it. For Telegram, the JSON metadata outweighs the user's words in lexical recall. In the review of oceanbase/powercontext#2488, @PsiACE suggested exposing the searchable text before JSON wrapping instead of parsing it.

  • ChannelMessage gets an optional text field: what the sender wrote, when content wraps it with channel metadata. None, the default, means content is that text, so other channels and existing constructors are unchanged.
  • TelegramChannel._build_message sets text to the parsed message text. That is the same string that goes under message in the JSON, so it excludes the replied-to message.
  • ChannelMessage.from_batch joins text the same way it joins content. A message without text contributes its content, and the batch's text stays None when no message has one.
  • content, the prompt, and the tape are unchanged. Commands keep returning before the JSON wrapping, without text.

Impacted modules

  • src/bub/channels/message.py
  • src/bub/channels/telegram.py
  • tests/test_channels.py

Verification

  • make check: lock check, prek (ruff, ruff format), and mypy passed.
  • uv run pytest -q: 730 passed, 20 skipped.
  • New and updated tests:
    • test_telegram_channel_build_message_wraps_payload_and_disables_outbound checks that text is the sender's text.
    • test_channel_message_batch_joins_text_and_falls_back_to_content checks batching.
  • No real Telegram bot run, since that needs a bot token.

🤖 Generated with Claude Code

The Telegram channel wraps the sender's text in JSON with sender and message
metadata before it reaches hooks, so a hook that searches or indexes messages
can only get the text back by parsing that JSON. ChannelMessage now carries
the text in an optional `text` field, which batching joins like the content.
The model-facing content is unchanged.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
@frostming
frostming merged commit 7b95690 into bubbuild:main Nov 5, 2026
6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants