Keep channel attribution on forwarded messages - #182
Conversation
message_to_dict read only fwd_from.date and fwd_from.from_name. Telegram populates from_name solely when the original author hides their profile, so an ordinary channel forward — where the origin sits in fwd_from.from_id — lost everything the client shows as "Forwarded from ...". Also read Telethon's msg.forward wrapper, which resolves that peer from entities already present in the same response, so this costs no extra API call. Adds from_chat, from_username, from_chat_id, from_user, channel_post and post_author, plus a post_link built from them: t.me/<username>/<post> for a public channel, the members-only t.me/c/<id>/<post> form otherwise. from_name is still emitted, so hidden-profile forwards are unaffected. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
| # only resolves for members. | ||
| if post_id is not None: | ||
| if finfo.get("from_username"): | ||
| finfo["post_link"] = f"https://t.me/{finfo['from_username']}/{post_id}" |
There was a problem hiding this comment.
Correct me if I'm wrong, but t.me no longer works.
There was a problem hiding this comment.
Checked before changing anything — t.me is up. It serves 200 right now from two different networks, and whois reports the domain ACTIVE (no serverHold):
$ curl -sI https://t.me/ParfunA/6279 → HTTP/2 200
$ whois t.me | grep -i status → status: ACTIVE
The outage behind your concern was real though: on 2026-07-13 the .me registry put t.me on serverHold over an OFAC listing — a sanctioned entity had used a Telegram channel as a contact address — and every t.me link on earth broke for roughly a day. It was restored on 2026-07-14. During the outage telegram.me kept resolving.
For what it's worth, the repo already emits t.me links elsewhere — tools/profile.py:266 builds f"https://t.me/{ch_username}", and get_message_link is documented as exporting a t.me/... link (via ExportMessageLinkRequest, where Telegram itself formats the result).
Still, your instinct holds: one registry decision can take every permalink down at once, and hardcoding the domain in a new place makes that worse. So I've pushed a follow-up that stops hardcoding it:
LINK_DOMAIN = os.getenv("TELEGRAM_LINK_DOMAIN", "t.me")Default is unchanged, and anyone who needs telegram.me (or whatever comes next) can switch without a code change. Covered by a test that overrides the domain.
Happy to drop post_link entirely if you'd rather not have a built URL in the payload at all — the raw parts (from_username, from_chat_id, channel_post) are all there for a caller to assemble. Just say the word.
Addresses review feedback that t.me may not be reliable. t.me resolves and serves 200 today, and whois reports the domain ACTIVE; the outage behind that concern was 2026-07-13, when the .me registry put it on serverHold over an OFAC listing and every t.me link broke for about a day. It was restored on 2026-07-14, but the incident is a fair warning that one registry decision can take every permalink down at once. So the domain is no longer hardcoded: LINK_DOMAIN defaults to t.me and can be overridden with TELEGRAM_LINK_DOMAIN — telegram.me kept resolving throughout that outage and works as a drop-in. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Keep channel attribution on forwarded messages
Problem
message_to_dictreads only two fields offfwd_from:Telegram populates
from_nameonly when the original author hides their profile. For an ordinary forward from a channel the origin lives infwd_from.from_id, which is never read — so the MCP output is just:Everything the client displays as "Forwarded from …" is lost, and that is the common case rather than an edge one. An agent consuming this cannot tell which channel a forwarded post came from, or link back to it.
Change
Also read Telethon's
msg.forwardwrapper. It resolves the forward peer from entities already present in the same response, so this adds no extra API call and stays synchronous.New keys inside
forwarded, each omitted when absent, matching the file's existing style:from_chatfrom_username@usernameof the originfrom_chat_idfrom_userchannel_postfwd_from.channel_postpost_authorfwd_from.post_authorpost_linkpost_linkishttps://t.me/<username>/<post>for a public channel and the members-onlyhttps://t.me/c/<internal_id>/<post>form otherwise.Same message as above, after the change:
from_nameis still emitted exactly as before, so hidden-profile forwards keep working unchanged. Names go throughsanitize_name, consistent with the rest of the function.Tests
tests/test_forward_attribution.pycovers public-channel, private-channel, user-to-user, hidden-profile and non-forward messages. Full suite: 118 passed.blackand the pre-commitflake8selection are clean.Verified against
A real forward fetched through
get_history— thepost_linkabove resolves to the original post.🤖 Generated with Claude Code