From f362a13c0090a2fcc85628723eed8e287d2e1fd3 Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 3 Mar 2026 09:37:37 +0000 Subject: [PATCH] fix: skip placeholder for DraftSender channels to prevent duplicate chat bubbles MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When a channel supports DraftSender (e.g. Telegram private chats), both a placeholder message ("Thinking...") and a streaming draft bubble were created simultaneously. On final response, preSend edited the placeholder but never called sendMessage, so the draft bubble lingered — causing the user to see two near-identical messages until the draft auto-expired. By skipping SendPlaceholder for DraftSender channels, the streaming draft serves as the sole visual indicator. The final sendMessage then replaces the draft with the permanent response in a single atomic transition. https://claude.ai/code/session_01RPaJHXgB9DhsS9JZxWbTno --- pkg/channels/base.go | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/pkg/channels/base.go b/pkg/channels/base.go index 063a66523..5927408ee 100644 --- a/pkg/channels/base.go +++ b/pkg/channels/base.go @@ -284,10 +284,15 @@ func (c *BaseChannel) HandleMessage( c.placeholderRecorder.RecordReactionUndo(c.name, chatID, undo) } } - // Placeholder — independent pipeline - if pc, ok := c.owner.(PlaceholderCapable); ok { - if phID, err := pc.SendPlaceholder(ctx, chatID); err == nil && phID != "" { - c.placeholderRecorder.RecordPlaceholder(c.name, chatID, phID) + // Placeholder — independent pipeline. + // Skip for DraftSender channels: the streaming draft bubble serves + // as the placeholder, and sendMessage on final response replaces it. + // Sending both a placeholder AND drafts causes duplicate chat bubbles. + if _, isDrafter := c.owner.(DraftSender); !isDrafter { + if pc, ok := c.owner.(PlaceholderCapable); ok { + if phID, err := pc.SendPlaceholder(ctx, chatID); err == nil && phID != "" { + c.placeholderRecorder.RecordPlaceholder(c.name, chatID, phID) + } } } }