Skip to content

feat(telegram): send 2-10 files or attachments as one sendMediaGroup (#278) - #306

Merged
patrick-chinchill merged 4 commits into
mainfrom
sync/4.41-tg3b
Oct 1, 2026
Merged

patrick-chinchill merged 4 commits into
mainfrom
sync/4.41-tg3b

Conversation

@patrick-chinchill

@patrick-chinchill patrick-chinchill commented Oct 1, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

Telegram post_message now sends 2–10 files or 2–10 attachments as one sendMediaGroup album. Before, it raised "supports a single file/attachment upload per message". One file or attachment still goes through send_document / send_attachment.

  • New _send_document_media_group / _send_attachment_media_group, sharing _send_media_group (the same MarkdownV2 → plain caption retry as single uploads, with the FormData rebuilt for each attempt) and _create_telegram_media_group_form_data.
  • Multipart body: chat_id, message_thread_id, reply_parameters, a media JSON string of InputMedia items and a media{i} file part for each binary payload (attach://media{i}). A URL-only attachment puts its URL in media and gets no part. The caption and parse_mode go on item 0 only. Video width / height are sent when JS Number.isInteger would accept them (this reuses _integral_update_id).
  • Checks, in upstream order and before any download: 2–10 items (TELEGRAM_MEDIA_GROUP_MIN = 2, existing _MAX = 10), attachment categories (file → document, audio → audio, image/video → visual; mixing categories raises), then no inline keyboard.
  • Every returned message is parsed and cached, and the last one is returned. An empty result raises NetworkError, as upstream does.
  • New constant ATTACHMENT_MEDIA_GROUP_TYPES.

Upstream commits mapped

Tests ported (tests/test_telegram_api.py)

These replace test_rejects_multiple_attachments:

  • "posts multiple files as a Telegram media group" (also checks that both messages are cached)
  • "posts and normalizes mixed image and video attachments as a Telegram media group" (includes the cache → JSON → rehydrate_attachment round trip)
  • "rejects incompatible Telegram media group attachment types"
  • "rejects Telegram media groups with more than 10 files"
  • "threads a media group to its target" (describe("reply"))

Python-only tests:

  • inline keyboard rejection, for files and for attachments
  • MarkdownV2 → plain retry on sendMediaGroup (fresh FormData, plain caption, no parse_mode)
  • a 10-item audio album (inclusive upper bound; same-category grouping; default attachment-{i} filename)
  • an unknown type is rejected before download (this is the divergence below)

I mutation-checked the tests: returning the first message instead of the last, putting the caption on every item, and dropping reply_parameters each make tests fail.

Fidelity

packages/adapter-telegram/src/index.test.ts is not fidelity-mapped (#78), so the target report does not change:

Delta vs committed report (HEAD): missing 100 -> 100 (+0)

scripts/fidelity_target.json regenerated unchanged. Strict 733/733.

Divergences

One divergence, in a separate diverge(telegram): commit with a non-parity table row and a regression test. An Attachment.type outside ATTACHMENT_MEDIA_GROUP_TYPES raises send_attachment's existing ValidationError("Unsupported attachment type: ...") before any fetch_data download. Upstream's TS union rules this value out at compile time. In Python the dict lookup would raise a bare KeyError after earlier attachments had already been downloaded.

Consumer impact

Low; Telegram only. Code that relied on the old ValidationError for 2+ uploads now gets an album instead. There are new ValidationErrors for more than 10 items, for a card with buttons plus 2+ uploads, and for documents or audio mixed with other types. Out of scope: none beyond #278. reply_parameters for media groups was listed as #228's job, but #228 had already landed, so it is wired here as its coordination note asked.

Validation

ruff, format, audit (0 hard failures), --check-docs, --strict 733/733, pytest 7891 passed / 24 skipped, pyrefly 0 errors.

Merge gate

Independent review findings: 3 fixed, 0 declined. All three were test gaps; the code already matched upstream sendAttachmentMediaGroup / createTelegramMediaGroupFormData. Commit faf6a30 adds tests that kill every mutation the reviewers reported (each mutation was re-run and now fails):

  • The fetch_data download path in an attachment album: the downloaded bytes go out as attach://media0 rather than the URL, and fetch_data is awaited once. Mutations killed: skip the download; prefer the URL.
  • The audio category: [audio, image] is added to the incompatible-types parametrization. The inline-keyboard rejection now uses fetch_data and asserts it is never awaited, which pins "rejected before any download". Mutations killed: audio counted as visual; keyboard check moved after the download.
  • Width/height only on videos, with the Number.isInteger rule: 1280.0 becomes int 1280 and True is dropped. An empty sendMediaGroup result raises NetworkError. Mutations killed: if True:, width = part.width, if False:.

Main merged: origin/main at 3f06859 (#304). The only conflict was CHANGELOG.md; it was resolved to one "Unreleased (4.41 wave)" heading that keeps the bullets from both sides. Fidelity is unchanged: Delta vs committed report (HEAD): missing 100 -> 100 (+0).

gpt-6-astra: 1 round, on HEAD 1a5a811. Verdict: PASS. "No actionable regressions found against the supplied merge base. All 638 Telegram tests passed, along with targeted lint checks and project type checking."

Bots: CodeRabbit hit its review rate limit and posted no findings. No gemini comments, and no inline review comments.

CI on 1a5a811: all green (Lint & Type Check, test 3.12/3.13, CodeQL).

Local validation on 1a5a811: ruff check and format pass. The test audit has 0 hard failures. --check-docs passes and --strict is clean, with all TS tests matched. pytest: 7895 passed, 24 skipped. pyrefly: 0 errors.

Closes #278
Part of #184

…278)

Ports vercel/chat 8d7ccdb1 (#605, chat@4.34.0) and the media-group half of
d5ebec12 (#833, reply_parameters). post_message drops the single-file and
single-attachment errors: one upload keeps send_document / send_attachment,
2+ go through _send_document_media_group / _send_attachment_media_group.
Every returned message is cached and the last is returned.

Part of #184.
… before downloading (#278)

Upstream's TS union rules the value out; in Python the
ATTACHMENT_MEDIA_GROUP_TYPES lookup would raise a bare KeyError after
earlier attachments were downloaded. Raise send_attachment's
ValidationError up front instead. Non-parity row added.

Closes #278
@coderabbitai

coderabbitai Bot commented Oct 1, 2026 •

Copy link
Copy Markdown

Warning

Review limit reached

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

Next included review available in 18 minutes.

Check out review usage here.

View limit details

Limit details: You’ve used the included review currently available.

Learn how review limits work.

Review configuration:

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Advanced

Run ID: a042ac85-3810-4d9f-89ad-24efe1ef326f

📥 Commits

Reviewing files that changed from the base of the PR and between 3f06859 and 1a5a811.

📒 Files selected for processing (4)
  • CHANGELOG.md
  • docs/UPSTREAM_SYNC.md
  • src/chat_sdk/adapters/telegram/adapter.py
  • tests/test_telegram_api.py
  • Autopilot · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Autopilot is currently an internal CodeRabbit preview.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@patrick-chinchill
patrick-chinchill marked this pull request as ready for review October 1, 2026 10:28
@patrick-chinchill

Copy link
Copy Markdown
Collaborator Author

Merge gate: CI green (Lint & Type Check, test (3.12), test (3.13), Analyze (python), Analyze (actions), CodeQL); local Codex review (gpt-6-astra, xhigh, --base origin/main) on 1a5a811: "No actionable regressions found against the supplied merge base. All 638 Telegram tests passed, along with targeted lint checks and project type checking."; 2 astra rounds (both clean; the final one ran on the current HEAD, and origin/main is still an ancestor, so nothing new needed reviewing); CodeRabbit hit its review rate limit and posted no findings, and there are no other bot comments. Merging with --admin (Protect Main requires a code-owner approval).

@patrick-chinchill
patrick-chinchill merged commit 2aa43af into main Oct 1, 2026
8 checks passed
@patrick-chinchill
patrick-chinchill deleted the sync/4.41-tg3b branch October 1, 2026 10:31
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.

[4.41/TG3b] Telegram outbound media groups: multi-file and multi-attachment sendMediaGroup

1 participant