fix: don't drop Telegram messages when send_action times out before tmux injection#88
Conversation
…mux injection Wrap the cosmetic pre-injection Telegram calls (send_action/TYPING, enqueue_status_update) and the interactive-UI precheck in try/except across text_handler, photo_handler, voice_handler and forward_command_handler so a transient telegram.error.TimedOut can no longer abort the handler before send_to_window runs and silently drop the user's message.
Repro environment & why
|
Cherry-picks the still-relevant upstream/main fixes, adapted to the iTerm2 backend and covered by tests: - six-ddc#88 (7c2e15c): wrap the cosmetic pre-injection Telegram calls — send_action, enqueue_status_update, and the interactive-UI precheck — in try/except across text/photo/voice/forward handlers, so a transient TimedOut on a flaky link can no longer abort the handler before send_to_window and silently drop the user's message (the update offset has already advanced, so Telegram won't redeliver). - six-ddc#67 (865ab89): on a hard interactive-UI edit failure, keep the old message and delete it only AFTER the replacement send succeeds, so a failed replacement never strands the user without controls. ("Message is not modified" was already handled on this branch.) - Write line count (f5ddd7f): compute from the tool_use input content, not the result confirmation string, so it stops always showing "Wrote 1 lines". Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ges on send_action timeout Brings 7c2e15c: wrap the cosmetic pre-injection Telegram calls (send_action/TYPING, enqueue_status_update) and the interactive-UI precheck in try/except across text/photo/voice/forward_command handlers, so a transient telegram.error.TimedOut can't abort the handler before send_to_window and silently drop the user's message. Our fork had the exact unguarded pattern. Clean merge over our 13 local patches. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Symptom
On a flaky network (e.g. reaching
api.telegram.orgfrom mainland China), messages sent from Telegram intermittently never reach the tmux session. The user has to resend 2–3 times before one gets through, with no error shown.Root cause
In
text_handler(andphoto_handler/voice_handler/forward_command_handler), a cosmetic outbound-Telegram call —chat.send_action(ChatAction.TYPING), the "typing…" indicator — runs before the message is injected into tmux viasend_to_window, with no error isolation. The bot also registers no global error handler (No error handlers are registeredin logs).Sequence in
text_handler(pre-fix):send_action(TYPING)enqueue_status_update(...)capture_pane+ interactive-UI prechecksend_to_window(wid, text)When
send_actionraisestelegram.error.TimedOut, the exception propagates out of the handler (no error handler), so execution never reaches line 970 — the message is never injected. Because the update offset has already advanced, Telegram does not redeliver, so the message is lost and the user must resend.Evidence (from a ~7-day production log)
telegram.error.TimedOutraised atbot.py:950 in text_handler, aborting before injection: 129 occurrences.telegram.error.TimedOut: Timed outinsidesend_chat_action.get_updatestimeouts (82) are harmless — they self-recover because the offset isn't advanced, so Telegram redelivers.Fix
Wrap every pre-injection outbound-Telegram call (
send_action,enqueue_status_update) and the interactive-UI precheck intry/exceptso a transient network failure can never prevent the tmux injection.send_to_windowis the one call that must always run. Applied to all four handlers that sendTYPINGbefore injecting. Ordering/semantics are unchanged (the UI precheck still runs first when it can); only the cosmetic calls' ability to abort the critical path is removed.A complementary hardening (not in this PR) would be registering a global
application.add_error_handler(...)so any future handler exception is at least logged and optionally surfaced to the user.Note: while diagnosing this,
ccbot --version/--helpwere observed to boot a second daemon (no early-exit), which then fights the running instance forgetUpdatesand raisestelegram.error.Conflict: terminated by other getUpdates request. Might be worth a real--version/--helpthat exits without starting the bot.