From e2c00937b57e9feb66a4903906dcb8cea09e06d6 Mon Sep 17 00:00:00 2001 From: k Date: Fri, 29 May 2026 23:42:39 +0800 Subject: [PATCH] fix(telegram): /status shows auto_trade+paper_mode, adopt:dup edits message MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bug 1: /status didn't show auto_trade or paper_mode โ€” the two most important trading states for Pro users. Added a trading block that queries the Subscription row (only when wallet-linked) and shows: Auto-Trade: ON/OFF, Mode: Paper/Live, Circuit breaker: clear/tripped. Bug 2: adopt:dup callback (tapping an 'already managed' position in the /adopt picker) answered the spinner but left the picker message stuck with no guidance. Now edits the message in place: explains the position is already managed and shows /release commands. Button no longer results in a visually broken UI. Co-Authored-By: Claude Sonnet 4.6 --- app/services/telegram_bot.py | 43 ++++++++++++++++++++++++++++++++---- 1 file changed, 39 insertions(+), 4 deletions(-) diff --git a/app/services/telegram_bot.py b/app/services/telegram_bot.py index 21309b5..964e773 100644 --- a/app/services/telegram_bot.py +++ b/app/services/telegram_bot.py @@ -393,6 +393,15 @@ async def _cmd_status(chat_id: int) -> None: b = (await db.execute( select(TelegramBinding).where(TelegramBinding.chat_id == chat_id) )).scalar_one_or_none() + # Also fetch the subscription if the binding is wallet-linked, so we + # can show auto_trade + paper_mode โ€” the two most important trading + # states that were previously invisible in /status. + sub = None + if b and b.wallet_address: + sub = (await db.execute( + select(Subscription).where(Subscription.wallet_address == b.wallet_address) + )).scalar_one_or_none() + if not b: await send_message(chat_id, "Not subscribed yet. Send /start to begin (no wallet required).") @@ -418,6 +427,23 @@ async def _cmd_status(chat_id: int) -> None: f"๐ŸŸข ON @ {b.digest_hour_utc:02d}:00 UTC" if b.digest_enabled else "๐Ÿ”ด OFF" ) + + # Pro-only trading state block โ€” only shown when wallet-linked. + trading_block = "" + if sub: + auto = "๐ŸŸข ON" if sub.auto_trade else "๐Ÿ”ด OFF" + mode = "๐Ÿ“ Paper" if sub.paper_mode else "๐Ÿ’ฐ Live" + cb_line = "" + if sub.circuit_breaker_tripped_at: + cb_line = f"\n๐Ÿšจ Circuit breaker: tripped ({sub.circuit_breaker_reason or 'risk limit'})" + else: + cb_line = "\nโœ“ Circuit breaker: clear" + trading_block = ( + f"\n\nโ€” Auto-Trader โ€”\n" + f"Auto-Trade: {auto}\n" + f"Mode: {mode}{cb_line}" + ) + await send_message( chat_id, f"๐Ÿ“ก Status\n\n" @@ -425,7 +451,8 @@ async def _cmd_status(chat_id: int) -> None: f"Alerts: {on}\n" f"Sources: {src_line}\n" f"Min confidence: {b.min_confidence}{mute}\n" - f"Daily brief: {digest_state}\n\n" + f"Daily brief: {digest_state}" + f"{trading_block}\n\n" f"Sent: {b.total_alerts_sent} ยท Failed: {b.total_alerts_failed}\n\n" f"Toggle anything with /trump /btc /funding /kol /conf /quiet " f"/digest /digest_time โ€” send /help for the full list.", @@ -787,9 +814,17 @@ async def _handle_callback(cb: dict) -> None: await answer_callback(cb_id) return if sub == "dup": - await answer_callback(cb_id, - "This position is already managed.", - show_alert=True) + # Asset is already adopted โ€” tell the user how to release, + # and also edit the picker message so the UI doesn't stay stuck. + asset_dup = parts[2] if len(parts) > 2 else "this position" + await edit_message( + chat_id, msg_id, + f"โœ… {asset_dup} is already under bot management.\n\n" + f"To stop managing it and take back manual control:\n" + f"/release โ€” pick from list\n" + f"or send /release <trade_id> directly." + ) + await answer_callback(cb_id, "Already managed โ€” see message.", show_alert=False) return if sub == "pick" and len(parts) == 3: asset = parts[2]