fix(telegram): prevent duplicate messages with slow LLM providers#41932
Conversation
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 6ab9821071
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
Greptile SummaryThis PR addresses two remaining causes of duplicate Telegram messages when using slow LLM providers: Changes:
Testing: 5 new/updated lane-delivery tests and 9 new network-error unit tests cover all new branches and behavioral changes. All 121 targeted tests pass. The overall approach is sound and well-implemented. Changes are idempotent and thoroughly tested. Confidence Score: 5/5
Last reviewed commit: b0bfdaa |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: c55f6e1e6b
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
This comment was marked as outdated.
This comment was marked as outdated.
1c58017 to
a6632c3
Compare
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 1d2d93f4a7
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
Retry 5xx in editMessageTelegram, invert ambiguous-error default to retain preview, and track sendMayHaveLanded in draft stream.
Clear messageSendAttempted when isSafeToRetrySendError matches (DNS, refused), so definite non-delivery still falls back to sendPayload.
Telegram 4xx responses (rate limit, bad request) guarantee the message was never delivered, so clear messageSendAttempted alongside pre-connect failures.
… visible When no prior message exists (first preview creation), prefer fallback over silence — a duplicate is better than the user seeing nothing. Gate sendMayHaveLanded retention on lane.hasStreamedMessage.
In update context, the caller doesn't treat 'retained' as success and falls through to sendPayload. Calling markDelivered() prematurely in update context can leave delivery state inconsistent.
c63bded to
2f50c51
Compare
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: c63bded44f
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
|
Merged via squash.
Thanks @hougangdev! |
…enclaw#41932) Merged via squash. Prepared head SHA: 2f50c51 Co-authored-by: hougangdev <[email protected]> Co-authored-by: obviyus <[email protected]> Reviewed-by: @obviyus
…enclaw#41932) Merged via squash. Prepared head SHA: 2f50c51 Co-authored-by: hougangdev <[email protected]> Co-authored-by: obviyus <[email protected]> Reviewed-by: @obviyus
…enclaw#41932) Merged via squash. Prepared head SHA: 2f50c51 Co-authored-by: hougangdev <[email protected]> Co-authored-by: obviyus <[email protected]> Reviewed-by: @obviyus
…enclaw#41932) Merged via squash. Prepared head SHA: 2f50c51 Co-authored-by: hougangdev <[email protected]> Co-authored-by: obviyus <[email protected]> Reviewed-by: @obviyus
…enclaw#41932) Merged via squash. Prepared head SHA: 2f50c51 Co-authored-by: hougangdev <[email protected]> Co-authored-by: obviyus <[email protected]> Reviewed-by: @obviyus
* main: (49 commits) fix(agents): add nodes to owner-only tool policy fallbacks fix(gateway): propagate real gateway client into plugin subagent runtime fix(gateway): enforce caller-scope subsetting in device.token.rotate fix(terminal): stabilize skills table width across Terminal.app and iTerm (openclaw#42849) fix(models): guard optional model input capabilities (openclaw#42096) macOS/onboarding: prompt for remote gateway auth tokens (openclaw#43100) fix(macos): use foundationValue when serializing browser proxy POST body (openclaw#43069) feat(ios): add local beta release flow (openclaw#42991) docs(changelog): update context pruning PR reference fix(context-pruning): cover image-only tool-result pruning fix(context-pruning): prune image-containing tool results instead of skipping them (openclaw#41789) fix(agents): include azure-openai in Responses API store override (openclaw#42934) fix(telegram): fall back on ambiguous first preview sends fix(telegram): prevent duplicate messages with slow LLM providers (openclaw#41932) Providers: add Opencode Go support (openclaw#42313) fix(sandbox): sanitize Docker env before marking OPENCLAW_CLI (openclaw#42256) macOS: add chat model selector and persist thinking (openclaw#42314) fix: clear pnpm prod audit vulnerabilities fix(build): restore full gate fix(gateway): split conversation reset from admin reset ...
…enclaw#41932) Merged via squash. Prepared head SHA: 2f50c51 Co-authored-by: hougangdev <[email protected]> Co-authored-by: obviyus <[email protected]> Reviewed-by: @obviyus
…enclaw#41932) Merged via squash. Prepared head SHA: 2f50c51 Co-authored-by: hougangdev <[email protected]> Co-authored-by: obviyus <[email protected]> Reviewed-by: @obviyus
…enclaw#41932) Merged via squash. Prepared head SHA: 2f50c51 Co-authored-by: hougangdev <[email protected]> Co-authored-by: obviyus <[email protected]> Reviewed-by: @obviyus
…enclaw#41932) Merged via squash. Prepared head SHA: 2f50c51 Co-authored-by: hougangdev <[email protected]> Co-authored-by: obviyus <[email protected]> Reviewed-by: @obviyus
…enclaw#41932) Merged via squash. Prepared head SHA: 2f50c51 Co-authored-by: hougangdev <[email protected]> Co-authored-by: obviyus <[email protected]> Reviewed-by: @obviyus
…enclaw#41932) Merged via squash. Prepared head SHA: 2f50c51 Co-authored-by: hougangdev <[email protected]> Co-authored-by: obviyus <[email protected]> Reviewed-by: @obviyus
…enclaw#41932) Merged via squash. Prepared head SHA: 2f50c51 Co-authored-by: hougangdev <[email protected]> Co-authored-by: obviyus <[email protected]> Reviewed-by: @obviyus
…enclaw#41932) Merged via squash. Prepared head SHA: 2f50c51 Co-authored-by: hougangdev <[email protected]> Co-authored-by: obviyus <[email protected]> Reviewed-by: @obviyus
…enclaw#41932) Merged via squash. Prepared head SHA: 2f50c51 Co-authored-by: hougangdev <[email protected]> Co-authored-by: obviyus <[email protected]> Reviewed-by: @obviyus (cherry picked from commit e37e1ed)
…enclaw#41932) Merged via squash. Prepared head SHA: 2f50c51 Co-authored-by: hougangdev <[email protected]> Co-authored-by: obviyus <[email protected]> Reviewed-by: @obviyus (cherry picked from commit e37e1ed)
…enclaw#41932) Merged via squash. Prepared head SHA: 2f50c51 Co-authored-by: hougangdev <[email protected]> Co-authored-by: obviyus <[email protected]> Reviewed-by: @obviyus (cherry picked from commit e37e1ed)
* refactor: share telegram network test helpers (cherry picked from commit 05a1b0c) * fix: bypass telegram runtime proxy during health checks (cherry picked from commit 1b31ede) * refactor: share telegram voice send path (cherry picked from commit 1d99401) * refactor: share telegram named account dm fixtures (cherry picked from commit 2cd1a4b) * test: share telegram sticky fetch helpers (cherry picked from commit 34a5523) * test(telegram): cover caption and forum service helpers (cherry picked from commit 377be13) * test: refine telegram token coverage (cherry picked from commit 3e8d9bc) * refactor: share telegram reply chunk threading (cherry picked from commit 5197171) * fix: align telegram probe test mock (cherry picked from commit 5f78057) * refactor: share telegram native command auth harness (cherry picked from commit 60dc46a) * test: share telegram monitor startup helpers (cherry picked from commit 66aabf5) * test(telegram): cover normalization and status issues (cherry picked from commit 833d0df) * refactor: share lane delivery test flows (cherry picked from commit 9780e99) * refactor: share telegram channel test harnesses (cherry picked from commit 9ecd189) * refactor: share telegram outbound send options (cherry picked from commit a57c590) * test: share lane delivery final helpers (cherry picked from commit ba1d7b2) * refactor: share telegram payload send flow (cherry picked from commit bc1cc2e) * test(telegram): cover dm access and allowed updates (cherry picked from commit bd8ca6d) * test: share telegram draft stream helpers (cherry picked from commit d78b7b3) * fix: widen telegram reply progress typing (cherry picked from commit d886ca6) * fix(telegram): prevent duplicate messages with slow LLM providers (openclaw#41932) Merged via squash. Prepared head SHA: 2f50c51 Co-authored-by: hougangdev <[email protected]> Co-authored-by: obviyus <[email protected]> Reviewed-by: @obviyus (cherry picked from commit e37e1ed) * refactor: share telegram dispatch failure harness (cherry picked from commit f201bad) * test: share telegram account helpers (cherry picked from commit fbdea7f) * Telegram: split setup adapter helpers (cherry picked from commit 0672156) * refactor(telegram): share plugin base config (cherry picked from commit 3cc1c7b) * feat(telegram): auto-rename DM topics on first message (openclaw#51502) * feat(telegram): auto-rename DM topics on first message fix(telegram): use bot.api for topic rename to avoid SecretRef resolution * fix(telegram): address security + test review feedback - Fix test assertion: DEFAULT_PROMPT_SUBSTRING matches 'very short' - Use RawBody instead of Body (no envelope metadata to LLM) - Truncate user message to 500 chars for LLM prompt - Remove user-derived content from verbose logs - Remove redundant threadSpec.id null check - Fix AutoTopicLabelParams type to match generateTopicLabel * fix(telegram): use effective dm auto-topic config * fix(telegram): detect direct auto-topic overrides * fix: auto-rename Telegram DM topics on first message (openclaw#51502) (thanks @Lukavyi) --------- Co-authored-by: Ayaan Zaidi <[email protected]> (cherry picked from commit 466debb) * fix(security): harden explicit-proxy SSRF pinning (cherry picked from commit 55ad5d7) * fix: stabilize full gate (cherry picked from commit 5fb7a13) * Telegram: consolidate message tool discovery (cherry picked from commit 60104de) * Telegram: preserve inbound debounce order (cherry picked from commit 9a34a60) * feat(telegram): add topic-edit action (cherry picked from commit a516141) * refactor: move telegram onboarding to setup wizard (cherry picked from commit a4047bf) * fix: harden gateway SIGTERM shutdown (openclaw#51242) (thanks @juliabush) * fix: increase shutdown timeout to avoid SIGTERM hang * fix(telegram): abort polling fetch on shutdown to prevent SIGTERM hang * fix(gateway): enforce hard exit on shutdown timeout for SIGTERM * fix: tighten gateway shutdown watchdog * fix: harden gateway SIGTERM shutdown (openclaw#51242) (thanks @juliabush) --------- Co-authored-by: Ayaan Zaidi <[email protected]> (cherry picked from commit e94ebfa) * fix: adapt cherry-picks for fork TS strictness - Remove duplicate renameForumTopicTelegram function in send.ts - Restore tts.test.ts to fork version (upstream version has gutted pi-ai deps) Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]> * fix: restore fork versions of test files overwritten by upstream - monitor.test.ts: upstream version references tagTelegramNetworkError not in fork - send.test.ts: upstream version references missing test helpers and unexported functions Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]> * fix: remove withPinnedLookup call not available in fork Use direct proxyTls spread instead of upstream's withPinnedLookup helper which was removed during fork restructuring. Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]> * fix: resolve type errors from cherry-pick adaptations - Add missing GetReplyOptions/MsgContext imports to bot test - Fix warn parameter typing in draft-stream test Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]> * fix: restore bot test files to fork versions Upstream versions have deeply entangled barrel import paths that don't exist in the fork's restructured module layout. Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]> * fix: align test helpers with refactored exports - Rename createNativeCommandTestParams -> createNativeCommandsHarness - Widen matchPluginCommand mock return type for test flexibility Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]> * fix: restore bot-native-commands.test.ts to fork version Upstream harness refactoring changed return types incompatible with the test's existing assertions. Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]> * fix: restore all bot-native-commands test files to fork versions Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]> * fix: restore all native-command test infrastructure to fork versions The upstream refactoring of test helpers is incompatible with the fork's existing test patterns. Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]> * fix: restore bot-message-dispatch.test.ts to fork version Upstream version uses telegramDeps injection pattern not in fork. Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]> * fix: restore test files with upstream-incompatible patterns Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]> * fix: restore media fetch network test to fork version Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]> * fix: restore remoteclaw-root test to fork version Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]> * fix: restore outbound test files to fork versions Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]> * fix: resolve remaining type errors from cherry-pick adaptations - Restore test files overwritten by upstream full-gate commit - Fix OpenClawConfig -> RemoteClawConfig in extension files - Fix barrel import paths in extension test files Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]> * fix: remove incompatible upstream files and relocate test files - Remove setup/shared files that depend on upstream barrel exports - Move extension test files to src/telegram/ where their modules live - Restore channel.ts to fork version Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]> * fix: final type error cleanup from cherry-pick batch - Restore types.plugin.ts to fork version (setup-wizard removed) - Remove normalize/status-issues tests (modules at extension paths) - Fix readonly array spread in allowed-updates test - Add explicit types for dm-access test callback parameters Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]> * fix: restore test-parallel.mjs to fork version Upstream version references vitest.channel-paths.mjs which doesn't exist in the fork. Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]> * fix: restore test files causing CI failures to fork versions Upstream test changes reference infrastructure patterns (gateway injection, plugin runtime seams) not available in the fork. Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]> * fix: restore outbound/telegram.ts to fork version The upstream sendTelegramPayloadMessages refactor may have side effects on channel registration in tests. Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]> * fix: restore message-channel.ts to fork version Upstream's symbol-based registry lookup breaks channel resolution in test isolation without the full gateway injection infrastructure. Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]> --------- Co-authored-by: Peter Steinberger <[email protected]> Co-authored-by: Ayaan Zaidi <[email protected]> Co-authored-by: Vincent Koc <[email protected]> Co-authored-by: Wayne <[email protected]> Co-authored-by: Taras Lukavyi <[email protected]> Co-authored-by: Gustavo Madeira Santana <[email protected]> Co-authored-by: Onur Solmaz <[email protected]> Co-authored-by: Julia Bush <[email protected]> Co-authored-by: Claude Opus 4.6 (1M context) <[email protected]>
Problem
Duplicate Telegram messages still occur with slow LLM providers (e.g. MiniMax via OpenRouter: 5s first token, 20 tok/s) despite #41662. Two remaining paths:
editMessageTelegramdoesn't retry on HTTP 5xx — "502 Bad Gateway" doesn't matchTELEGRAM_RETRY_RE→ error reachestryEditPreviewMessage→ unclassified default →"fallback"→ duplicate.Draft stream
sendMessagetimeout loses messageId — If the initialsendMessagetimes out but succeeds server-side,streamMessageIdis never set →"fallback"→ duplicate.Solution
editMessageTelegram: Edits are idempotent, so retrying on server errors is safe and prevents 502s from reaching the classifier.tryEditPreviewMessage: Ambiguous errors now retain the preview (prefer incomplete over duplicate). Only explicit 4xx client rejections fall back tosendPayload.sendMayHaveLandedin draft stream: When a previewsendMessagewas attempted but the response was lost, retain instead of falling back.New helpers:
isTelegramServerError(5xx) andisTelegramClientRejection(4xx).Related
Test plan
sendMayHaveLanded)pnpm tsgoclean