When a Telegram turn ends with no visible final response, the dispatcher synthesized a NO_REPLY payload that silent-reply rewrite could turn into visible DM chatter such as "All quiet on my side."
Gate that synthesized fallback on group chats. DMs with no queued final response now stay quiet, while group/forum fallback behavior remains available when policy asks for a visible rewrite.
Tests:
- pnpm test extensions/telegram/src/bot-message-dispatch.test.ts
- pnpm check:changed
Move sentBlockMediaUrls recording from before sends to after successful
delivery completion. If a block send throws, the URL is not recorded,
so final fallback delivery retains the media attachment instead of
incorrectly deduplicating it.
Add regression tests for both success-path dedup and failure-path
media preservation.
Addresses ClawSweeper P2: block-failure → final-media-loss.
Non-streaming Telegram delivers each MEDIA: attachment twice — once
from the media-only block reply and once from the final reply. Track
media URLs sent via block replies and filter duplicates from final
replies.
Closes#78372
Telegram's deliverReplies dispatches via Grammy SDK directly, bypassing
deliverOutboundPayloads where the channel-mirror writer runs. Outbound
assistant replies were never appended to the session transcript, leaving
Telegram .jsonl files empty (the sessions.json sessionFile path was
populated but the file was never created on disk).
Add an optional transcriptMirror callback param to deliverReplies and
populate it from bot-message-dispatch's deliveryBaseOptions. Reuses the
existing appendAssistantMessageToSessionTranscript helper that
deliverOutboundPayloads already calls. Also mirrors preview-finalized
replies so the transcript captures all final assistant output.
Plugin SDK boundary expansion: re-export
appendAssistantMessageToSessionTranscript from
plugin-sdk/agent-harness-runtime so extension code can call it without
reaching into core src/. API baseline regenerated.
Addresses openclaw#75991 for telegram + CLI runtime combinations.
Supersedes openclaw#77484 (incorporates reviewer feedback: preview-
finalized mirror + changelog entry).
* telegram: correlate message-tool sends with inbound turn (#78685)
Register the active Telegram inbound SessionKey/outbound peer while dispatching,
and mark inbound lane delivery when deliverOutbound emits a matching telegram
message:sent success. Prevents rewritten silent-reply fillers after visible
tool-routed replies with an empty final.
Co-authored-by: Cursor <cursoragent@cursor.com>
* fix(telegram): track message action delivery
---------
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Ayaan Zaidi <hi@obviy.us>
* fix(telegram): reuse preview for long text finals
* test(qa): cover long telegram finals
* fix(qa): satisfy extension lint
* fix(qa): keep telegram long final fixture to two chunks
* test(telegram): cover three chunk finals
* fix(telegram): force long final preview boundary
When a newer inbound message arrives while an older dispatch is still
processing, buffered final answers from the old dispatch could be
delivered into the new message's thread.
Add `bufferedGeneration` to `BufferedFinalAnswer` to track which
abort fence generation buffered the answer. `takeBufferedFinalAnswer`
now rejects buffered answers whose generation doesn't match the
current dispatch's generation, preventing stale content delivery.
Fixes#76642
* fix(telegram): send fresh finals for stale previews
* test(telegram): cover stale preview send fallback
* fix(telegram): keep stale archived preview fallback
* fix(telegram): clear stale active previews
* fix(telegram): reset preview state after fresh finals
Preserve exact Telegram selected quote text for native quote replies, share Telegram reply parameter construction between bot delivery and direct outbound sends, and retry with legacy replies when Telegram rejects native quote parameters.\n\nThanks @rubencu.