Skip to content

fix(telegram): materialize dm draft final to prevent duplicate sends#34318

Merged
obviyus merged 2 commits intomainfrom
fix/telegram-dm-draft-materialize-final
Mar 4, 2026
Merged

fix(telegram): materialize dm draft final to prevent duplicate sends#34318
obviyus merged 2 commits intomainfrom
fix/telegram-dm-draft-materialize-final

Conversation

@obviyus
Copy link
Copy Markdown
Contributor

@obviyus obviyus commented Mar 4, 2026

Summary

Keep Telegram DM streaming on sendMessageDraft previews, but avoid duplicate final sends by materializing draft previews into one permanent message on final delivery.

Problem

sendMessageDraft preview updates in DMs do not produce a message_id, so finalization cannot edit in place. Existing lane behavior then sends a second final payload, creating duplicates.

Fix

  • Add draft-final materialization path in lane delivery:
    • if lane preview mode is draft, payload is text-only, no inline buttons, and materialize is available
    • update stream with final text
    • call materialize()
    • if materialized message id exists: mark delivered/finalized and skip sendPayload
    • if not: log and fall back to standard final send
  • Keep media / inline-button finals on standard send path.
  • Add/adjust lane-delivery tests for:
    • unchanged final text materialization
    • revised final text materialization
    • materialize failure fallback

Why this over forcing message transport

This preserves the new Telegram DM draft-streaming UX while still guaranteeing single final delivery.

Tests

  • bunx vitest run src/telegram/lane-delivery.test.ts src/telegram/draft-stream.test.ts src/telegram/bot-message-dispatch.test.ts
  • bunx oxfmt --check src/telegram/lane-delivery.ts src/telegram/lane-delivery.test.ts

Fixes #33492

@openclaw-barnacle openclaw-barnacle bot added channel: telegram Channel integration: telegram size: S maintainer Maintainer-authored PR labels Mar 4, 2026
@obviyus obviyus self-assigned this Mar 4, 2026
@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps bot commented Mar 4, 2026

Greptile Summary

This PR fixes duplicate final message sends in Telegram DM draft streaming by materializing the in-flight draft preview into a permanent message instead of issuing a separate sendPayload call. The implementation correctly updates the stream with the final text, calls stream.materialize() (which internally stops the draft lifecycle and sends a real sendMessage), and marks the lane delivered—skipping the redundant send entirely. The path is properly guarded to only apply when the lane is in draft preview mode, the payload is text-only without inline buttons, and materialize is available; media and inline-button finals continue through the standard send path. Tests comprehensively cover success and failure scenarios.

Confidence Score: 5/5

  • The core logic is sound, tests are thorough, and the fix achieves its stated goal—safe to merge.
  • The implementation is correct: the canEditViaPreview gate (excludes media, error payloads, and over-length text) is evaluated before canMaterializeDraftFinal, ensuring the new path is never reached for payloads that can't be safely materialized. The materialize() function wraps its network call in a try-catch and returns undefined on failure, providing a clean fallback contract. Tests cover unchanged-text materialization, revision-change materialization, materialize-failure fallback, and existing media/inline-button bypass cases.
  • No files require special attention

Last reviewed commit: d3612f4

@obviyus obviyus force-pushed the fix/telegram-dm-draft-materialize-final branch from d3612f4 to 16c977a Compare March 4, 2026 10:57
@obviyus obviyus merged commit ed8e0a8 into main Mar 4, 2026
@obviyus obviyus deleted the fix/telegram-dm-draft-materialize-final branch March 4, 2026 10:57
@obviyus
Copy link
Copy Markdown
Contributor Author

obviyus commented Mar 4, 2026

Landed via temp rebase onto main.

  • Gate: bunx vitest run src/telegram/lane-delivery.test.ts src/telegram/draft-stream.test.ts src/telegram/bot-message-dispatch.test.ts
  • Land commit: 16c977a
  • Merge commit: ed8e0a8

@obviyus
Copy link
Copy Markdown
Contributor Author

obviyus commented Mar 4, 2026

@GodsBoy the duplicate bug should be fixed after this merge. Please let me know if you still face it!

@GodsBoy
Copy link
Copy Markdown
Contributor

GodsBoy commented Mar 4, 2026

@obviyus Thanks for picking this up so fast! Will test as soon as the npm release drops and report back. Really appreciate the quick turnaround.

mrosmarin added a commit to mrosmarin/openclaw that referenced this pull request Mar 4, 2026
* main: (92 commits)
  fix: preserve raw media invoke for HTTP tool clients (openclaw#34365)
  fix: prevent nodes media base64 context bloat (openclaw#34332)
  docs(changelog): credit @Brotherinlaw-13 for openclaw#34318
  fix(telegram): materialize dm draft final to avoid duplicates
  fix: relay ACP sessions_spawn parent streaming (openclaw#34310) (thanks @vincentkoc) (openclaw#34310)
  fix: kill stuck ACP child processes on startup and harden sessions in discord threads (openclaw#33699)
  feat(ios): add Live Activity connection status + stale cleanup (openclaw#33591)
  chore(docs): add plugins refactor changelog entry
  Chore: remove accidental .DS_Store artifact
  Plugins/zalouser: migrate to scoped plugin-sdk imports
  Plugins/zalo: migrate to scoped plugin-sdk imports
  Plugins/whatsapp: migrate to scoped plugin-sdk imports
  Plugins/voice-call: migrate to scoped plugin-sdk imports
  Plugins/twitch: migrate to scoped plugin-sdk imports
  Plugins/tlon: migrate to scoped plugin-sdk imports
  Plugins/thread-ownership: migrate to scoped plugin-sdk imports
  Plugins/test-utils: migrate to scoped plugin-sdk imports
  Plugins/talk-voice: migrate to scoped plugin-sdk imports
  Plugins/synology-chat: migrate to scoped plugin-sdk imports
  Plugins/qwen-portal-auth: migrate to scoped plugin-sdk imports
  ...