Skip to content

fix(telegram): prevent duplicate messages with slow LLM providers#41932

Merged
obviyus merged 7 commits intoopenclaw:mainfrom
hougangdev:fix/telegram-duplicate-slow-providers
Mar 11, 2026
Merged

fix(telegram): prevent duplicate messages with slow LLM providers#41932
obviyus merged 7 commits intoopenclaw:mainfrom
hougangdev:fix/telegram-duplicate-slow-providers

Conversation

@hougangdev
Copy link
Copy Markdown
Contributor

@hougangdev hougangdev commented Mar 10, 2026

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:

  1. editMessageTelegram doesn't retry on HTTP 5xx — "502 Bad Gateway" doesn't match TELEGRAM_RETRY_RE → error reaches tryEditPreviewMessage → unclassified default → "fallback" → duplicate.

  2. Draft stream sendMessage timeout loses messageId — If the initial sendMessage times out but succeeds server-side, streamMessageId is never set → "fallback" → duplicate.

Solution

  • Retry 5xx in editMessageTelegram: Edits are idempotent, so retrying on server errors is safe and prevents 502s from reaching the classifier.
  • Invert default in tryEditPreviewMessage: Ambiguous errors now retain the preview (prefer incomplete over duplicate). Only explicit 4xx client rejections fall back to sendPayload.
  • Track sendMayHaveLanded in draft stream: When a preview sendMessage was attempted but the response was lost, retain instead of falling back.

New helpers: isTelegramServerError (5xx) and isTelegramClientRejection (4xx).

Related

Test plan

  • Updated 2 existing tests for inverted default behavior
  • Added 3 new lane-delivery tests (4xx fallback, 502 retention, sendMayHaveLanded)
  • Added 2 new test suites for helpers (9 cases)
  • All 121 targeted tests pass
  • pnpm tsgo clean

@openclaw-barnacle openclaw-barnacle bot added channel: telegram Channel integration: telegram size: M labels Mar 10, 2026
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 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-apps
Copy link
Copy Markdown
Contributor

greptile-apps bot commented Mar 10, 2026

Greptile Summary

This PR addresses two remaining causes of duplicate Telegram messages when using slow LLM providers:

Changes:

  1. New Helper FunctionsisTelegramServerError and isTelegramClientRejection classify HTTP errors by status range using the structured error_code property. Clean, consistent, and well-tested with 9 new unit tests.

  2. editMessageTelegram Retry on 5xx – Now retries on HTTP 5xx server errors via isTelegramServerError. Since edits are idempotent, retrying on 502/gateway errors safely prevents them from reaching the classifier.

  3. Inverted Default in tryEditPreviewMessage – For ambiguous errors in the final context, the deliverer now retains the existing preview (incomplete) rather than falling back to a new send (duplicate). Only explicit 4xx client rejections trigger a fallback. This is the key policy change: "prefer incomplete over duplicate."

  4. sendMayHaveLanded in Draft Stream – Tracks whether a preview sendMessage was attempted before streamMessageId was populated. When this flag is set and no messageId is available, the deliverer retains the preview instead of falling back, preventing duplicates when the initial send timed out but succeeded server-side.

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

  • Safe to merge. Changes are well-reasoned, idempotent, and thoroughly tested. The three-part fix correctly addresses duplicate message issues with slow LLM providers.
  • This PR scores 5/5 because: (1) New helper functions are correctly implemented and comprehensively tested; (2) Retrying edits on 5xx is safe due to edit idempotence; (3) The inverted default policy (retain incomplete over duplicate) is the correct conservative choice and is backed by explicit guards for known cases; (4) sendMayHaveLanded correctly captures the timeout-but-may-have-landed scenario and is properly integrated and reset; (5) All new code paths are covered by tests that verify the expected behavior; (6) No false positives or edge cases were found in code review.
  • No files require special attention. All changes are well-implemented and tested.

Last reviewed commit: b0bfdaa

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 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".

@aisle-research-bot

This comment was marked as outdated.

@hougangdev hougangdev force-pushed the fix/telegram-duplicate-slow-providers branch from 1c58017 to a6632c3 Compare March 10, 2026 14:28
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 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".

@obviyus obviyus self-assigned this Mar 11, 2026
hougangdev and others added 7 commits March 11, 2026 11:14
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.
@obviyus obviyus force-pushed the fix/telegram-duplicate-slow-providers branch from c63bded to 2f50c51 Compare March 11, 2026 05:48
@obviyus obviyus merged commit e37e1ed into openclaw:main Mar 11, 2026
26 checks passed
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 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".

@obviyus
Copy link
Copy Markdown
Contributor

obviyus commented Mar 11, 2026

Merged via squash.

Thanks @hougangdev!

frankekn pushed a commit to MoerAI/openclaw that referenced this pull request Mar 11, 2026
…enclaw#41932)

Merged via squash.

Prepared head SHA: 2f50c51
Co-authored-by: hougangdev <[email protected]>
Co-authored-by: obviyus <[email protected]>
Reviewed-by: @obviyus
frankekn pushed a commit to Effet/openclaw that referenced this pull request Mar 11, 2026
…enclaw#41932)

Merged via squash.

Prepared head SHA: 2f50c51
Co-authored-by: hougangdev <[email protected]>
Co-authored-by: obviyus <[email protected]>
Reviewed-by: @obviyus
frankekn pushed a commit to ImLukeF/openclaw that referenced this pull request Mar 11, 2026
…enclaw#41932)

Merged via squash.

Prepared head SHA: 2f50c51
Co-authored-by: hougangdev <[email protected]>
Co-authored-by: obviyus <[email protected]>
Reviewed-by: @obviyus
hydro13 pushed a commit to andyliu/openclaw that referenced this pull request Mar 11, 2026
…enclaw#41932)

Merged via squash.

Prepared head SHA: 2f50c51
Co-authored-by: hougangdev <[email protected]>
Co-authored-by: obviyus <[email protected]>
Reviewed-by: @obviyus
Treedy2020 pushed a commit to Treedy2020/openclaw that referenced this pull request Mar 11, 2026
…enclaw#41932)

Merged via squash.

Prepared head SHA: 2f50c51
Co-authored-by: hougangdev <[email protected]>
Co-authored-by: obviyus <[email protected]>
Reviewed-by: @obviyus
mrosmarin added a commit to mrosmarin/openclaw that referenced this pull request Mar 11, 2026
* 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
  ...
dhoman pushed a commit to dhoman/chrono-claw that referenced this pull request Mar 11, 2026
…enclaw#41932)

Merged via squash.

Prepared head SHA: 2f50c51
Co-authored-by: hougangdev <[email protected]>
Co-authored-by: obviyus <[email protected]>
Reviewed-by: @obviyus
ahelpercn pushed a commit to ahelpercn/openclaw that referenced this pull request Mar 12, 2026
…enclaw#41932)

Merged via squash.

Prepared head SHA: 2f50c51
Co-authored-by: hougangdev <[email protected]>
Co-authored-by: obviyus <[email protected]>
Reviewed-by: @obviyus
Ruijie-Ysp pushed a commit to Ruijie-Ysp/clawdbot that referenced this pull request Mar 12, 2026
…enclaw#41932)

Merged via squash.

Prepared head SHA: 2f50c51
Co-authored-by: hougangdev <[email protected]>
Co-authored-by: obviyus <[email protected]>
Reviewed-by: @obviyus
leozhengliu-pixel pushed a commit to leozhengliu-pixel/openclaw that referenced this pull request Mar 13, 2026
…enclaw#41932)

Merged via squash.

Prepared head SHA: 2f50c51
Co-authored-by: hougangdev <[email protected]>
Co-authored-by: obviyus <[email protected]>
Reviewed-by: @obviyus
plabzzxx pushed a commit to plabzzxx/openclaw that referenced this pull request Mar 13, 2026
…enclaw#41932)

Merged via squash.

Prepared head SHA: 2f50c51
Co-authored-by: hougangdev <[email protected]>
Co-authored-by: obviyus <[email protected]>
Reviewed-by: @obviyus
wdskuki pushed a commit to wdskuki/openclaw that referenced this pull request Mar 16, 2026
…enclaw#41932)

Merged via squash.

Prepared head SHA: 2f50c51
Co-authored-by: hougangdev <[email protected]>
Co-authored-by: obviyus <[email protected]>
Reviewed-by: @obviyus
senw-developers pushed a commit to senw-developers/va-openclaw that referenced this pull request Mar 17, 2026
…enclaw#41932)

Merged via squash.

Prepared head SHA: 2f50c51
Co-authored-by: hougangdev <[email protected]>
Co-authored-by: obviyus <[email protected]>
Reviewed-by: @obviyus
t--becker pushed a commit to t--becker/openclaw that referenced this pull request Mar 19, 2026
…enclaw#41932)

Merged via squash.

Prepared head SHA: 2f50c51
Co-authored-by: hougangdev <[email protected]>
Co-authored-by: obviyus <[email protected]>
Reviewed-by: @obviyus
alexey-pelykh pushed a commit to remoteclaw/remoteclaw that referenced this pull request Mar 23, 2026
…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)
alexey-pelykh pushed a commit to remoteclaw/remoteclaw that referenced this pull request Mar 23, 2026
…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)
alexey-pelykh pushed a commit to remoteclaw/remoteclaw that referenced this pull request Mar 24, 2026
…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)
alexey-pelykh added a commit to remoteclaw/remoteclaw that referenced this pull request Mar 24, 2026
* 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]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

channel: telegram Channel integration: telegram size: M

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants