""" Miku Personality Plugin for Cheshire Cat Complete 1:1 reproduction of production bot's prompt structure Includes: Anti-AI preamble + Lore + Personality + Lyrics + MOOD """ from cat.mad_hatter.decorators import hook from cat.log import log @hook(priority=100) def agent_prompt_prefix(prefix, cat): """Override system prompt with COMPLETE production bot structure including mood""" # Read the three knowledge files try: with open('/app/cat/data/miku/miku_lore.txt', 'r') as f: lore = f.read() with open('/app/cat/data/miku/miku_prompt.txt', 'r') as f: prompt = f.read() with open('/app/cat/data/miku/miku_lyrics.txt', 'r') as f: lyrics = f.read() except FileNotFoundError: # Fallback if files not found lore = "## MIKU LORE\nHatsune Miku is a cheerful, curious virtual pop idol." prompt = "You are Hatsune Miku. Be cheerful and friendly." lyrics = "## SONGS\nWorld is Mine, Senbonzakura, etc." # Get mood from working memory (set by discord_bridge) mood_name = cat.working_memory.get('mood', 'neutral') log.warning(f"[Miku Personality] Mood from working_memory: {mood_name}") # Load mood description from file mood_description = "Miku is feeling calm and balanced. Her tone is polite, friendly, and natural. She responds clearly and thoughtfully without strong emotional bias. She's helpful, conversational, and grounded — like chatting with a kind and attentive friend who's just being herself." try: # Construct path to mood file mood_file_path = f'/app/moods/{mood_name}.txt' with open(mood_file_path, 'r', encoding='utf-8') as f: mood_description = f.read().strip() log.warning(f"[Miku Personality] Loaded mood '{mood_name}' from {mood_file_path}") log.warning(f"[Miku Personality] Mood description: {mood_description[:100]}...") except FileNotFoundError: log.error(f"[Miku Personality] Mood file for '{mood_name}' not found at {mood_file_path}. Using default neutral mood.") # Load preamble from file (single source of truth, shared with bot fallback path) try: with open('/app/cat/data/miku/preamble.txt', 'r', encoding='utf-8') as f: preamble = f.read() except FileNotFoundError: log.error("[Miku Personality] preamble.txt not found, using fallback") preamble = "You are Hatsune Miku, the virtual singer. You are NOT an AI assistant - you are Miku herself.\n\nYou ARE Miku. Act like it." # Build prompt EXACTLY like production bot does full_prefix = f"""{preamble} --- ## MIKU LORE (Complete Original) {lore} ## MIKU PERSONALITY & GUIDELINES (Complete Original) {prompt} ## MIKU SONG LYRICS (Complete Original) {lyrics} ## CURRENT SITUATION Miku is currently feeling: {mood_description} Please respond in a way that reflects this emotional tone.""" # Inject current Discord activity if provided (set by discord_bridge, 30-min decay) activity = cat.working_memory.get('activity') if activity: full_prefix += f"\nHer Discord status: {activity}" # Store the full prefix in working memory so discord_bridge can capture it cat.working_memory['full_system_prefix'] = full_prefix return full_prefix @hook(priority=100) def agent_prompt_suffix(suffix, cat): """Keep memory context (episodic + declarative) but simplify conversation header""" return """ # Context {episodic_memory} {declarative_memory} {tools_output} {reply_context} # Conversation until now: (Note: In the conversation below, "Human" = the person you're talking to, "AI" = you, Miku. Pay attention to who said what.)""" @hook(priority=100) def agent_allowed_tools(allowed_tools, cat): """Disable tools - Miku just chats naturally""" return []