From 4106d553dde4037c968cd0edc96b135a63a1f9a3 Mon Sep 17 00:00:00 2001 From: zhou-zhichao Date: Thu, 26 Mar 2026 02:46:37 +0100 Subject: [PATCH] Fix interactive UI creating duplicate messages on button press MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When editing an existing interactive message fails with "Message is not modified" (content unchanged after button press), the old code caught all exceptions and fell through to send a new message, causing duplicates. Changes: - Handle BadRequest "Message is not modified" specifically: keep existing message and return early instead of creating a duplicate - On other edit failures, send the replacement message first, then delete the old one only after the new one succeeds — prevents stranding users without controls if the replacement send also fails Fixes six-ddc/ccbot#66 --- src/ccbot/handlers/interactive_ui.py | 28 +++++++++++++++++++++++----- 1 file changed, 23 insertions(+), 5 deletions(-) diff --git a/src/ccbot/handlers/interactive_ui.py b/src/ccbot/handlers/interactive_ui.py index 174e3a9e..7d975fe7 100644 --- a/src/ccbot/handlers/interactive_ui.py +++ b/src/ccbot/handlers/interactive_ui.py @@ -17,6 +17,7 @@ import logging from telegram import Bot, InlineKeyboardButton, InlineKeyboardMarkup +from telegram.error import BadRequest from ..session import session_manager from ..terminal_parser import extract_interactive_content, is_interactive_ui @@ -202,13 +203,24 @@ async def handle_interactive_ui( ) _interactive_mode[ikey] = window_id return True - except Exception: - # Edit failed (message deleted, etc.) - clear stale msg_id and send new + except BadRequest as e: + if "Message is not modified" in str(e): + # Content unchanged — keep existing message as-is + _interactive_mode[ikey] = window_id + return True + # Other edit failure — fall through to send new message, + # but keep old message until replacement succeeds + logger.debug( + "Edit failed for interactive msg %s: %s, sending new", + existing_msg_id, + e, + ) + except Exception as e: logger.debug( - "Edit failed for interactive msg %s, sending new", existing_msg_id + "Edit failed for interactive msg %s: %s, sending new", + existing_msg_id, + e, ) - _interactive_msgs.pop(ikey, None) - # Fall through to send new message # Send new message (plain text — terminal content is not markdown) logger.info( @@ -228,6 +240,12 @@ async def handle_interactive_ui( if sent: _interactive_msgs[ikey] = sent.message_id _interactive_mode[ikey] = window_id + # New message sent successfully — now safe to delete the old one + if existing_msg_id: + try: + await bot.delete_message(chat_id=chat_id, message_id=existing_msg_id) + except Exception: + pass # Old message may already be gone return True return False