From 2b743ed65eade17a68473a294b185eef36414ac2 Mon Sep 17 00:00:00 2001 From: koko210Serve Date: Mon, 23 Feb 2026 13:43:15 +0200 Subject: [PATCH] =?UTF-8?q?fix(P2):=205=20priority-2=20bug=20fixes=20?= =?UTF-8?q?=E2=80=94=20emoji=20consolidation,=20DM=20safety,=20pause=20gap?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit #10 Redundant coin flip in join_conversation — removed the 50% random gate that doubled the V2 engine's own decision to act. #11 Message-triggered actions skip _autonomous_paused — _check_and_act and _check_and_react now bail out immediately when the autonomous system is paused (voice session), matching the scheduled-tick path. #12 Duplicate emoji dictionaries — removed MOOD_EMOJIS and EVIL_MOOD_EMOJIS from globals.py (had different emojis from moods.py). bipolar_mode.py and evil_mode.py now import the canonical dicts from utils/moods.py so all code sees the same emojis. #13 DM mood can spontaneously become 'asleep' — rotate_dm_mood() now filters 'asleep' out of the candidate list since DMs have no sleepy-to-asleep transition guard and no wakeup timer. #15 Engage-user fallback misreports action type — log level raised to WARNING with an explicit [engage_user->general] prefix so the cooldown-triggered fallback is visible in logs. --- bot/globals.py | 26 +++----------------------- bot/utils/autonomous.py | 6 ++++++ bot/utils/autonomous_v1_legacy.py | 7 ++----- bot/utils/bipolar_mode.py | 6 ++++-- bot/utils/evil_mode.py | 3 ++- bot/utils/moods.py | 4 +++- 6 files changed, 20 insertions(+), 32 deletions(-) diff --git a/bot/globals.py b/bot/globals.py index 306a2d8..86d6167 100644 --- a/bot/globals.py +++ b/bot/globals.py @@ -69,35 +69,15 @@ EVIL_MODE = False EVIL_DM_MOOD = "evil_neutral" EVIL_DM_MOOD_DESCRIPTION = "Evil Miku is calculating and cold." EVIL_AVAILABLE_MOODS = ["aggressive", "cunning", "sarcastic", "evil_neutral"] -EVIL_MOOD_EMOJIS = { - "aggressive": "👿", - "cunning": "🐍", - "sarcastic": "😈", - "evil_neutral": "" -} +# EVIL_MOOD_EMOJIS removed — canonical source is utils/moods.py # Bipolar Mode System (both Mikus can argue via webhooks) BIPOLAR_MODE = False BIPOLAR_WEBHOOKS = {} # guild_id -> {"miku_webhook_url": str, "evil_webhook_url": str} BIPOLAR_ARGUMENT_IN_PROGRESS = {} # channel_id -> {"active": bool, "exchange_count": int, "current_speaker": str} -# Regular Miku mood emojis (used in bipolar mode for webhook display names) -MOOD_EMOJIS = { - "bubbly": "✨", - "sleepy": "💤", - "curious": "🔍", - "shy": "🥺", - "serious": "😐", - "excited": "🎉", - "silly": "🤪", - "melancholy": "💙", - "flirty": "💕", - "romantic": "💖", - "irritated": "😤", - "angry": "😠", - "neutral": "", - "asleep": "😴" -} +# MOOD_EMOJIS removed — canonical source is utils/moods.py +# bipolar_mode.py now imports from there directly BOT_USER = None diff --git a/bot/utils/autonomous.py b/bot/utils/autonomous.py index 8ec5507..c725770 100644 --- a/bot/utils/autonomous.py +++ b/bot/utils/autonomous.py @@ -184,6 +184,9 @@ async def _check_and_react(guild_id: int, message): Check if Miku should react to a new message with an emoji. Called for each new message in real-time. """ + if _autonomous_paused: + return + # Calculate message age from datetime import datetime, timezone message_age = (datetime.now(timezone.utc) - message.created_at).total_seconds() @@ -211,6 +214,9 @@ async def _check_and_act(guild_id: int): Uses per-guild lock to prevent race conditions from near-simultaneous messages. """ async with _get_action_lock(guild_id): + if _autonomous_paused: + return + # Rate limiting check now = time.time() if guild_id in _last_action_execution: diff --git a/bot/utils/autonomous_v1_legacy.py b/bot/utils/autonomous_v1_legacy.py index 81f6021..26d2c27 100644 --- a/bot/utils/autonomous_v1_legacy.py +++ b/bot/utils/autonomous_v1_legacy.py @@ -304,7 +304,7 @@ async def miku_engage_random_user_for_server(guild_id: int, user_id: str = None, # Skip cooldown check if this is a manual trigger from web UI if not manual_trigger and now - last_time < 43200: # 12 hours in seconds - logger.info(f"Recently engaged {target.display_name} in server {guild_id}, switching to general message.") + logger.warning(f"[engage_user→general] Recently engaged {target.display_name} in server {guild_id}, falling back to general message (cooldown).") await miku_say_something_general_for_server(guild_id) return @@ -456,10 +456,7 @@ async def miku_detect_and_join_conversation_for_server(guild_id: int, force: boo # Not enough activity logger.debug(f"[Join Conv] Not enough activity: {len(recent_msgs)} messages, {len(user_ids)} users (need 5+ messages, 2+ users)") return - - if random.random() > 0.5: - logger.debug(f"[Join Conv] Random chance failed (50% chance)") - return # 50% chance to engage + # Note: V1 had a redundant 50% coin flip here, removed since V2 engine already decided to act else: logger.debug(f"[Join Conv] Force mode - bypassing activity checks") if len(recent_msgs) < 1: diff --git a/bot/utils/bipolar_mode.py b/bot/utils/bipolar_mode.py index d8c51a9..a498424 100644 --- a/bot/utils/bipolar_mode.py +++ b/bot/utils/bipolar_mode.py @@ -404,8 +404,9 @@ async def update_webhook_avatars(client): def get_miku_display_name() -> str: """Get Regular Miku's display name with mood and emoji""" + from utils.moods import MOOD_EMOJIS mood = globals.DM_MOOD - emoji = globals.MOOD_EMOJIS.get(mood, "") + emoji = MOOD_EMOJIS.get(mood, "") if emoji: return f"Hatsune Miku {emoji}" return "Hatsune Miku" @@ -413,8 +414,9 @@ def get_miku_display_name() -> str: def get_evil_miku_display_name() -> str: """Get Evil Miku's display name with mood and emoji""" + from utils.moods import EVIL_MOOD_EMOJIS mood = globals.EVIL_DM_MOOD - emoji = globals.EVIL_MOOD_EMOJIS.get(mood, "") + emoji = EVIL_MOOD_EMOJIS.get(mood, "") if emoji: return f"Evil Miku {emoji}" return "Evil Miku" diff --git a/bot/utils/evil_mode.py b/bot/utils/evil_mode.py index 49c31f9..50aea7b 100644 --- a/bot/utils/evil_mode.py +++ b/bot/utils/evil_mode.py @@ -191,7 +191,8 @@ def load_evil_mood_description(mood_name: str) -> str: def get_evil_mood_emoji(mood_name: str) -> str: """Get emoji for evil mood""" - return globals.EVIL_MOOD_EMOJIS.get(mood_name, "") + from utils.moods import EVIL_MOOD_EMOJIS + return EVIL_MOOD_EMOJIS.get(mood_name, "") def is_valid_evil_mood(mood_name: str) -> bool: diff --git a/bot/utils/moods.py b/bot/utils/moods.py index 4725a2a..2fae966 100644 --- a/bot/utils/moods.py +++ b/bot/utils/moods.py @@ -162,9 +162,11 @@ async def rotate_dm_mood(): old_mood = globals.DM_MOOD new_mood = old_mood attempts = 0 + # Filter out 'asleep' — DMs have no sleepy→asleep transition guard + dm_eligible = [m for m in globals.AVAILABLE_MOODS if m != "asleep"] while new_mood == old_mood and attempts < 5: - new_mood = random.choice(globals.AVAILABLE_MOODS) + new_mood = random.choice(dm_eligible) attempts += 1 globals.DM_MOOD = new_mood