hermes-agent/gateway/platforms
Teknium 85cefc7a5a
fix(telegram): prevent duplicate message delivery on send timeout (#5153)
TimedOut is a subclass of NetworkError in python-telegram-bot. The
inner retry loop in send() and the outer _send_with_retry() in base.py
both treated it as a transient connection error and retried — but
send_message is not idempotent. When the request reaches Telegram but
the HTTP response times out, the message is already delivered. Retrying
sends duplicates. Worst case: up to 9 copies (inner 3x × outer 3x).

Inner loop (telegram.py):
- Import TimedOut separately, isinstance-check before generic
  NetworkError retry (same pattern as BadRequest carve-out from #3390)
- Re-raise immediately — no retry
- Mark as retryable=False in outer exception handler

Outer loop (base.py):
- Remove 'timeout', 'timed out', 'readtimeout', 'writetimeout' from
  _RETRYABLE_ERROR_PATTERNS (read/write timeouts are delivery-ambiguous)
- Add 'connecttimeout' (safe — connection never established)
- Keep 'network' (other platforms still need it)
- Add _is_timeout_error() + early return to prevent plain-text fallback
  on timeout errors (would also cause duplicate delivery)

Connection errors (ConnectionReset, ConnectError, etc.) are still
retried — these fail before the request reaches the server.

Credit: tmdgusya (PR #3899), barun1997 (PR #3904) for identifying the
bug and proposing fixes.

Closes #3899, closes #3904.
2026-04-04 19:05:34 -07:00
..
__init__.py Enhance CLI with multi-platform messaging integration and configuration management 2026-02-02 19:01:51 -08:00
ADDING_A_PLATFORM.md docs: finish cron terminology cleanup 2026-03-14 19:20:58 -07:00
api_server.py fix: persist API server sessions to shared SessionDB (state.db) (#4802) 2026-04-03 10:31:11 -07:00
base.py fix(telegram): prevent duplicate message delivery on send timeout (#5153) 2026-04-04 19:05:34 -07:00
dingtalk.py fix(dingtalk): requirements check passes with only one credential set 2026-03-17 03:50:45 -07:00
discord.py fix: prevent duplicate messages — gateway dedup + partial stream guard (#4878) 2026-04-03 18:53:52 -07:00
email.py fix(email): close SMTP and IMAP connections on failure (#3804) 2026-03-29 15:38:32 -07:00
feishu.py feat(gateway): add Feishu/Lark platform support (#3817) 2026-03-29 18:17:42 -07:00
homeassistant.py fix(gateway): add request timeouts to HA, Email, Mattermost, SMS adapters (#3258) 2026-03-26 14:36:07 -07:00
matrix.py fix(gateway): match Discord mention-stripping behavior in Matrix adapter 2026-04-04 13:09:27 -07:00
mattermost.py feat(mattermost): configurable mention behavior — respond without @mention (#3664) 2026-03-28 22:17:43 -07:00
signal.py feat: add profiles — run multiple isolated Hermes instances (#3681) 2026-03-29 10:41:20 -07:00
slack.py fix: prevent duplicate messages — gateway dedup + partial stream guard (#4878) 2026-04-03 18:53:52 -07:00
sms.py fix: store asyncio task references to prevent GC mid-execution (#3267) 2026-03-26 14:36:24 -07:00
telegram.py fix(telegram): prevent duplicate message delivery on send timeout (#5153) 2026-04-04 19:05:34 -07:00
telegram_network.py fix(security): reject private and loopback IPs in Telegram DoH fallback (#4129) 2026-03-30 18:53:24 -07:00
webhook.py feat: add profiles — run multiple isolated Hermes instances (#3681) 2026-03-29 10:41:20 -07:00
wecom.py feat(gateway): add WeCom (Enterprise WeChat) platform support (#3847) 2026-03-29 21:29:13 -07:00
whatsapp.py fix(whatsapp): add free_response_chats, mention stripping, and interactive message unwrapping 2026-04-03 01:16:39 -07:00