Skip to content

Commit 85a8f39

Browse files
committed
feat(forward_message): auto-expand albums on single-int forwards
Smaller MCP-client models reliably fail to check grouped_id before forwarding and end up calling forward_message with the album anchor id only — delivering one detached photo instead of the full post. Skill prompts and tool-description directives don't move the needle on this. Move the smarts server-side: when forward_message receives a single int and the target message has a grouped_id, fetch a small window of nearby ids (albums are allocated contiguously), filter siblings with the same grouped_id, and forward them all in one Telethon call. The destination receives the full grouped album intact. Adds expand_album: bool = True so callers can opt out for the rare case of forwarding exactly one item out of an album. List inputs are left untouched — they remain the explicit batch path. Net effect: the agent can be naive ("forward this post") and the server still delivers the album correctly. Result message now states when an expansion happened so the user is aware.
1 parent 095d00b commit 85a8f39

1 file changed

Lines changed: 47 additions & 13 deletions

File tree

telegram_mcp/tools/messages.py

Lines changed: 47 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -692,35 +692,69 @@ async def forward_message(
692692
message_id: Union[int, List[int]],
693693
to_chat_id: Union[int, str],
694694
account: str = None,
695+
expand_album: bool = True,
695696
) -> str:
696697
"""
697-
Forward one or more messages from a source chat to a destination chat.
698+
Forward a message (or several) from a source chat to a destination chat.
698699
699-
To forward MULTIPLE messages, pass `message_id` as a list of integers in
700-
a SINGLE call (e.g. message_id=[12345, 12346, 12347]). Do NOT call this
701-
tool repeatedly with single ints to forward several messages — the list
702-
form is faster, atomic, and preserves Telegram album grouping (messages
703-
sharing a `grouped_id` arrive as one grouped album in the destination).
700+
When forwarding a single int message_id, the server automatically detects
701+
Telegram albums (multi-photo/video posts sharing a `grouped_id`) and
702+
forwards the ENTIRE album as one grouped batch — so the destination
703+
receives the album intact with "Forwarded from <source>", not a single
704+
detached photo. This is the desired behavior in almost all cases.
704705
705-
Pass a single int only when forwarding exactly one message and you do
706-
not need album grouping. See also: forward_messages (plural) — same
707-
behavior with a list-only signature.
706+
Set expand_album=False to forward only the exact message you specified
707+
(useful if you really want one photo out of an album).
708+
709+
To forward a specific set of unrelated messages, pass a list of ints.
710+
Album expansion is not applied to list inputs — the list is treated as
711+
the explicit batch.
708712
709713
Args:
710714
from_chat_id: Source chat (id or @username).
711-
message_id: A single message id (int) OR a list of message ids
712-
(e.g. [12345, 12346]). USE A LIST WHENEVER FORWARDING >1 MESSAGE.
715+
message_id: A single message id (int) OR a list of ids. Single ints
716+
are auto-expanded to the full album when applicable.
713717
to_chat_id: Destination chat (id or @username).
714718
account: Optional account label for multi-account mode.
719+
expand_album: If True (default) and message_id is a single int, the
720+
server expands albums automatically. No effect on list inputs.
715721
"""
716722
try:
717723
cl = get_client(account)
718724
from_entity = await resolve_entity(from_chat_id, cl)
719725
to_entity = await resolve_entity(to_chat_id, cl)
720-
await cl.forward_messages(to_entity, message_id, from_entity)
721-
count = len(message_id) if isinstance(message_id, list) else 1
726+
727+
ids_to_forward = message_id
728+
expanded_from_album = False
729+
if expand_album and isinstance(message_id, int):
730+
anchor = await cl.get_messages(from_entity, ids=message_id)
731+
grouped_id = getattr(anchor, "grouped_id", None) if anchor else None
732+
if grouped_id is not None:
733+
# Album ids are allocated contiguously by Telegram; a small
734+
# window around the anchor reliably captures all siblings.
735+
window = list(range(message_id - 9, message_id + 10))
736+
neighbors = await cl.get_messages(from_entity, ids=window)
737+
sibling_ids = sorted(
738+
{
739+
m.id
740+
for m in neighbors
741+
if m is not None
742+
and getattr(m, "grouped_id", None) == grouped_id
743+
}
744+
)
745+
if len(sibling_ids) > 1:
746+
ids_to_forward = sibling_ids
747+
expanded_from_album = True
748+
749+
await cl.forward_messages(to_entity, ids_to_forward, from_entity)
750+
count = len(ids_to_forward) if isinstance(ids_to_forward, list) else 1
722751
if count == 1:
723752
return f"Message {message_id} forwarded from {from_chat_id} to {to_chat_id}."
753+
if expanded_from_album:
754+
return (
755+
f"Album of {count} messages forwarded from {from_chat_id} "
756+
f"to {to_chat_id} (auto-expanded from message {message_id})."
757+
)
724758
return f"{count} messages forwarded from {from_chat_id} to {to_chat_id}."
725759
except Exception as e:
726760
return log_and_format_error(

0 commit comments

Comments
 (0)