Skip to content

fix(telegram): extract forwarded message text from caption and forward_origin.api_kwargs - #72035

Open
2umish8 wants to merge 2 commits into
NousResearch:mainfrom
2umish8:fix/telegram-forwarded-text-fallback
Open

fix(telegram): extract forwarded message text from caption and forward_origin.api_kwargs#72035
2umish8 wants to merge 2 commits into
NousResearch:mainfrom
2umish8:fix/telegram-forwarded-text-fallback

Conversation

@2umish8

@2umish8 2umish8 commented Jul 26, 2026

Copy link
Copy Markdown

Problem

When forwarding a Telegram message — especially a channel post forwarded to a new DM topic — the bot receives an empty text. The adapter relied solely on message.text or "" to populate MessageEvent.text, but Telegram forwarded messages may arrive with an empty message.text in certain API edge cases.

Root cause

In _build_message_event (line ~9350 of plugins/platforms/telegram/adapter.py):

text=message.text or "",

No fallback for forwarded message content that arrives via message.caption or inside forward_origin.api_kwargs.

Fix

  1. New method _extract_forwarded_text(message) — probes two fallback sources:

    • message.caption (common for media forwards with caption)
    • forward_origin.api_kwargs (rare edge case where a channel post forward to a new DM topic stores its text in the origin's API kwargs)
  2. Updated _build_message_event to use a fallback chain:

    event_text = message.text or message.caption or _extract_forwarded_text(message) or ""

Testing

Tested live on a production Hermes gateway instance. The fix resolves the symptom where forwarded channel posts to new DM topics arrived with empty text while the gateway process continued normally.

Checklist

  • Bug is real and reproduced on current main
  • Fix handles the full bug class (caption forwards + channel-post API edge case)
  • No breaking changes — MessageEvent contract unchanged
  • Lint passes

2umish8 added 2 commits July 26, 2026 17:07
…d_origin.api_kwargs

Telegram forwarded messages — especially channel posts forwarded to new DM
topics — may arrive with an empty message.text. The adapter only used
message.text or "" to populate MessageEvent.text, silently dropping
the forwarded content.

Add _extract_forwarded_text() with a fallback chain:
1. message.caption (media forwards with caption)
2. forward_origin.api_kwargs (edge case observed with channel posts)
Add 10 tests covering:
- _extract_forwarded_text: empty, caption, forward_origin.api_kwargs,
  no-text, empty api_kwargs, None api_kwargs
- _build_message_event: normal text, caption fallback,
  forward_origin api_kwargs fallback
@alt-glitch alt-glitch added type/bug Something isn't working P3 Low — cosmetic, nice to have comp/plugins Plugin system and bundled plugins platform/telegram Telegram bot adapter sweeper:risk-message-delivery Sweeper risk: may drop, duplicate, misroute, or suppress messages labels Jul 26, 2026

@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 investigating forwarded-message delivery. Current main does still set the initial event body from message.text alone (plugins/platforms/telegram/adapter.py:9668), but this patch does not reach the stated empty-text edge case yet.

Problems

  • The text ingress is registered with filters.TEXT (plugins/platforms/telegram/adapter.py:3778), and _handle_text_message returns when msg.text is empty before it calls _build_message_event (plugins/platforms/telegram/adapter.py:8671). A fallback solely inside _build_message_event therefore cannot recover an empty-text, non-media forward.
  • Media captions are already copied into event.text after event construction (plugins/platforms/telegram/adapter.py:8950-8952, :8963-8967), so the new caption fallback is redundant for those paths.
  • The new test fabricates forward_origin.api_kwargs with SimpleNamespace; it does not establish that python-telegram-bot 22.6, pinned in pyproject.toml:166, exposes the observed payload shape.

Suggested changes

  • Add a sanitized real update fixture (or a PTB de_json fixture) and trace it through the actual registered handler. Apply the recovery at that ingress point, then retain a regression test for the complete handler-to-event path.

Automated hermes-sweeper review.



def test_extract_forwarded_text_forward_origin_api_kwargs():
"""Deep probe: text in forward_origin.api_kwargs is extracted."""

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.

This fabricates a forward_origin.api_kwargs["text"] shape with SimpleNamespace, but does not prove PTB supplies that shape from a Telegram update. Please replace it with a sanitized captured update parsed through PTB (or another production-shaped fixture) and exercise the real handler path.

# Fallback: message.caption (populated for media forwards with caption).
# Deep fallback: _extract_forwarded_text probes forward_origin.api_kwargs
# for edge cases (e.g. channel-post forwards to new DM topics).
_forwarded = self._extract_forwarded_text(message)

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.

An empty-text non-media update does not reach this method through normal ingress: _handle_text_message returns before event construction when msg.text is empty. Please move recovery to the registered handler/filter path demonstrated by a production-shaped fixture.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

comp/plugins Plugin system and bundled plugins P3 Low — cosmetic, nice to have platform/telegram Telegram bot adapter sweeper:blast-moderate Sweeper blast radius: moderate — a subsystem or single platform 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.

3 participants