fix(P2): 5 priority-2 bug fixes — emoji consolidation, DM safety, pause gap
#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.
This commit is contained in:
@@ -69,35 +69,15 @@ EVIL_MODE = False
|
|||||||
EVIL_DM_MOOD = "evil_neutral"
|
EVIL_DM_MOOD = "evil_neutral"
|
||||||
EVIL_DM_MOOD_DESCRIPTION = "Evil Miku is calculating and cold."
|
EVIL_DM_MOOD_DESCRIPTION = "Evil Miku is calculating and cold."
|
||||||
EVIL_AVAILABLE_MOODS = ["aggressive", "cunning", "sarcastic", "evil_neutral"]
|
EVIL_AVAILABLE_MOODS = ["aggressive", "cunning", "sarcastic", "evil_neutral"]
|
||||||
EVIL_MOOD_EMOJIS = {
|
# EVIL_MOOD_EMOJIS removed — canonical source is utils/moods.py
|
||||||
"aggressive": "👿",
|
|
||||||
"cunning": "🐍",
|
|
||||||
"sarcastic": "😈",
|
|
||||||
"evil_neutral": ""
|
|
||||||
}
|
|
||||||
|
|
||||||
# Bipolar Mode System (both Mikus can argue via webhooks)
|
# Bipolar Mode System (both Mikus can argue via webhooks)
|
||||||
BIPOLAR_MODE = False
|
BIPOLAR_MODE = False
|
||||||
BIPOLAR_WEBHOOKS = {} # guild_id -> {"miku_webhook_url": str, "evil_webhook_url": str}
|
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}
|
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 removed — canonical source is utils/moods.py
|
||||||
MOOD_EMOJIS = {
|
# bipolar_mode.py now imports from there directly
|
||||||
"bubbly": "✨",
|
|
||||||
"sleepy": "💤",
|
|
||||||
"curious": "🔍",
|
|
||||||
"shy": "🥺",
|
|
||||||
"serious": "😐",
|
|
||||||
"excited": "🎉",
|
|
||||||
"silly": "🤪",
|
|
||||||
"melancholy": "💙",
|
|
||||||
"flirty": "💕",
|
|
||||||
"romantic": "💖",
|
|
||||||
"irritated": "😤",
|
|
||||||
"angry": "😠",
|
|
||||||
"neutral": "",
|
|
||||||
"asleep": "😴"
|
|
||||||
}
|
|
||||||
|
|
||||||
BOT_USER = None
|
BOT_USER = None
|
||||||
|
|
||||||
|
|||||||
@@ -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.
|
Check if Miku should react to a new message with an emoji.
|
||||||
Called for each new message in real-time.
|
Called for each new message in real-time.
|
||||||
"""
|
"""
|
||||||
|
if _autonomous_paused:
|
||||||
|
return
|
||||||
|
|
||||||
# Calculate message age
|
# Calculate message age
|
||||||
from datetime import datetime, timezone
|
from datetime import datetime, timezone
|
||||||
message_age = (datetime.now(timezone.utc) - message.created_at).total_seconds()
|
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.
|
Uses per-guild lock to prevent race conditions from near-simultaneous messages.
|
||||||
"""
|
"""
|
||||||
async with _get_action_lock(guild_id):
|
async with _get_action_lock(guild_id):
|
||||||
|
if _autonomous_paused:
|
||||||
|
return
|
||||||
|
|
||||||
# Rate limiting check
|
# Rate limiting check
|
||||||
now = time.time()
|
now = time.time()
|
||||||
if guild_id in _last_action_execution:
|
if guild_id in _last_action_execution:
|
||||||
|
|||||||
@@ -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
|
# 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
|
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)
|
await miku_say_something_general_for_server(guild_id)
|
||||||
return
|
return
|
||||||
|
|
||||||
@@ -456,10 +456,7 @@ async def miku_detect_and_join_conversation_for_server(guild_id: int, force: boo
|
|||||||
# Not enough activity
|
# Not enough activity
|
||||||
logger.debug(f"[Join Conv] Not enough activity: {len(recent_msgs)} messages, {len(user_ids)} users (need 5+ messages, 2+ users)")
|
logger.debug(f"[Join Conv] Not enough activity: {len(recent_msgs)} messages, {len(user_ids)} users (need 5+ messages, 2+ users)")
|
||||||
return
|
return
|
||||||
|
# Note: V1 had a redundant 50% coin flip here, removed since V2 engine already decided to act
|
||||||
if random.random() > 0.5:
|
|
||||||
logger.debug(f"[Join Conv] Random chance failed (50% chance)")
|
|
||||||
return # 50% chance to engage
|
|
||||||
else:
|
else:
|
||||||
logger.debug(f"[Join Conv] Force mode - bypassing activity checks")
|
logger.debug(f"[Join Conv] Force mode - bypassing activity checks")
|
||||||
if len(recent_msgs) < 1:
|
if len(recent_msgs) < 1:
|
||||||
|
|||||||
@@ -404,8 +404,9 @@ async def update_webhook_avatars(client):
|
|||||||
|
|
||||||
def get_miku_display_name() -> str:
|
def get_miku_display_name() -> str:
|
||||||
"""Get Regular Miku's display name with mood and emoji"""
|
"""Get Regular Miku's display name with mood and emoji"""
|
||||||
|
from utils.moods import MOOD_EMOJIS
|
||||||
mood = globals.DM_MOOD
|
mood = globals.DM_MOOD
|
||||||
emoji = globals.MOOD_EMOJIS.get(mood, "")
|
emoji = MOOD_EMOJIS.get(mood, "")
|
||||||
if emoji:
|
if emoji:
|
||||||
return f"Hatsune Miku {emoji}"
|
return f"Hatsune Miku {emoji}"
|
||||||
return "Hatsune Miku"
|
return "Hatsune Miku"
|
||||||
@@ -413,8 +414,9 @@ def get_miku_display_name() -> str:
|
|||||||
|
|
||||||
def get_evil_miku_display_name() -> str:
|
def get_evil_miku_display_name() -> str:
|
||||||
"""Get Evil Miku's display name with mood and emoji"""
|
"""Get Evil Miku's display name with mood and emoji"""
|
||||||
|
from utils.moods import EVIL_MOOD_EMOJIS
|
||||||
mood = globals.EVIL_DM_MOOD
|
mood = globals.EVIL_DM_MOOD
|
||||||
emoji = globals.EVIL_MOOD_EMOJIS.get(mood, "")
|
emoji = EVIL_MOOD_EMOJIS.get(mood, "")
|
||||||
if emoji:
|
if emoji:
|
||||||
return f"Evil Miku {emoji}"
|
return f"Evil Miku {emoji}"
|
||||||
return "Evil Miku"
|
return "Evil Miku"
|
||||||
|
|||||||
@@ -191,7 +191,8 @@ def load_evil_mood_description(mood_name: str) -> str:
|
|||||||
|
|
||||||
def get_evil_mood_emoji(mood_name: str) -> str:
|
def get_evil_mood_emoji(mood_name: str) -> str:
|
||||||
"""Get emoji for evil mood"""
|
"""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:
|
def is_valid_evil_mood(mood_name: str) -> bool:
|
||||||
|
|||||||
@@ -162,9 +162,11 @@ async def rotate_dm_mood():
|
|||||||
old_mood = globals.DM_MOOD
|
old_mood = globals.DM_MOOD
|
||||||
new_mood = old_mood
|
new_mood = old_mood
|
||||||
attempts = 0
|
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:
|
while new_mood == old_mood and attempts < 5:
|
||||||
new_mood = random.choice(globals.AVAILABLE_MOODS)
|
new_mood = random.choice(dm_eligible)
|
||||||
attempts += 1
|
attempts += 1
|
||||||
|
|
||||||
globals.DM_MOOD = new_mood
|
globals.DM_MOOD = new_mood
|
||||||
|
|||||||
Reference in New Issue
Block a user