Skip to content

feat(gateway): native multi-image sending for Telegram, Discord, Slack, Mattermost, Email, Signal#17909

Merged
teknium1 merged 2 commits into
mainfrom
hermes/hermes-b24c857f
Apr 30, 2026
Merged

feat(gateway): native multi-image sending for Telegram, Discord, Slack, Mattermost, Email, Signal#17909
teknium1 merged 2 commits into
mainfrom
hermes/hermes-b24c857f

Conversation

@teknium1

Copy link
Copy Markdown
Contributor

Summary

Salvages #17888 (multi-image sending in Signal) and extends the new send_multiple_images ABC to every gateway platform with a native multi-attachment API, so images arrive as a single bundled message instead of N separate ones.

Changes

Two commits:

1. feat(gateway/signal): … — cherry-picked from #17888 by @MaxyMoos:

  • New send_multiple_images(chat_id, images, metadata, human_delay) method on BasePlatformAdapter with a default per-image loop fallback
  • Signal native override (up to 32 attachments per signal-cli send)
  • signal_rate_limit.py — process-wide 50-token / 4s-refill scheduler shared between adapter + send_message tool, with server Retry-after feedback
  • run.py + base.py partition images out of media_files/local_files so they batch separately
  • 53 new tests (Signal adapter 27, rate-limit scheduler 18, send_message tool 8)

2. feat(gateway): native send_multiple_images for Telegram, Discord, Slack, Mattermost, Email — new, authored by teknium1:

  • Telegrambot.send_media_group(), 10 per album; animated GIFs peeled off and routed through send_animation (albums don't support animations)
  • Discordchannel.send(files=[...]), 10 per message; URL images downloaded into BytesIO so they render inline; forum channels route via create_thread(files=[...])
  • Slackfiles_upload_v2(file_uploads=[...]), 10 per call; respects thread_ts; records thread participation
  • Mattermost — single post with file_ids list, 5 per post (Mattermost's hard cap)
  • Email — single SMTP message with multiple MIME attachments, no chunk cap

All platforms fall back to the base per-image loop on any failure — one bad image never loses the rest of the batch.

Platforms that stay on the base default loop (server APIs accept only one attachment per message):
Matrix, WhatsApp, BlueBubbles, Feishu, WeCom, WeChat, DingTalk.

Validation

Result
tests/gateway/test_send_multiple_images.py (new) 19/19 ✓
tests/gateway/test_signal.py + test_signal_rate_limit.py (from PR #17888) 45/45 ✓
tests/tools/test_send_message_tool.py 95/95 ✓
tests/gateway/test_send_image_file.py 19/19 ✓
tests/gateway/ full suite 4275 passed, 7 skipped, 0 failed (86s)

Co-authored-by: Maxence Groine maxence@groine.fr

Closes #17888

MaxyMoos and others added 2 commits April 30, 2026 03:26
Adds a new `send_multiple_images` method to the ``BasePlatformAdapter``
that implements the default "One image per message" loop and allows for
platform-specific overriding.

Implements such an override for the Signal adapter, batching images
and trying (best-effort) to work around rate-limits for voluminous
batches using a specific scheduler.

Also implements batching + rate-limit handling in the `send_message`
tool.

New tests added for the Signal adapter, its rate-limit scheduler and the
`send_message` tool
…ck, Mattermost, Email

Ports PR #17888's send_multiple_images ABC to every gateway platform that
has a native multi-attachment API, so images arrive as a single bundled
message instead of N separate ones.

Native overrides:
- Telegram: send_media_group (10 photos per album, chunks over); animated
  GIFs peeled off and routed through send_animation (albums don't support
  animations)
- Discord: channel.send(files=[...]) (10 attachments per message, chunks
  over); URL images downloaded into BytesIO so they render inline; forum
  channels use create_thread with files=[...]
- Slack: files_upload_v2(file_uploads=[...]) (10 per call, chunks over);
  respects thread_ts; records thread participation
- Mattermost: single post with file_ids list (5 per post — Mattermost cap,
  chunks over)
- Email: single SMTP message with multiple MIME attachments (no chunk cap,
  SMTP size governs); remote URLs remain linked in body (parity with
  existing send_image)

All platforms fall back to the base per-image loop on any failure, so a
single bad image in a batch never loses the rest.

Matrix, WhatsApp, and single-attachment platforms (BlueBubbles, Feishu,
WeCom, WeChat, DingTalk) continue to use the base default loop — their
server APIs only accept one attachment per message anyway.

Tests: adds tests/gateway/test_send_multiple_images.py with 19 targeted
tests covering base default loop, chunking, animation peel-off, fallback
paths, and empty-batch no-ops across all five new overrides.

Co-authored-by: Maxence Groine <maxence@groine.fr>
Comment thread tools/send_message_tool.py Dismissed
Comment thread tools/send_message_tool.py Dismissed
Comment thread tools/send_message_tool.py Dismissed
Comment thread tools/send_message_tool.py Dismissed
@alt-glitch alt-glitch added type/feature New feature or request P3 Low — cosmetic, nice to have comp/gateway Gateway runner, session dispatch, delivery platform/telegram Telegram bot adapter platform/discord Discord bot adapter platform/slack Slack app adapter platform/email Email (IMAP/SMTP) adapter platform/signal Signal CLI adapter labels Apr 30, 2026
@teknium1 teknium1 merged commit 3de8e21 into main Apr 30, 2026
11 of 13 checks passed
@teknium1 teknium1 deleted the hermes/hermes-b24c857f branch April 30, 2026 11:28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

comp/gateway Gateway runner, session dispatch, delivery P3 Low — cosmetic, nice to have platform/discord Discord bot adapter platform/email Email (IMAP/SMTP) adapter platform/signal Signal CLI adapter platform/slack Slack app adapter platform/telegram Telegram bot adapter type/feature New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants