Step 4 of memory system overhaul: single source of truth for prompts.
Problem: The system prompt was defined inline in 4 different places:
miku_personality.py, evil_miku_personality.py, llm.py, discord_bridge.py.
These could drift out of sync — and the discord_bridge WebUI
reconstruction was already missing CRITICAL RULES, CHARACTER CONTEXT,
MOOD GUIDELINES, and RESPONSE RULES sections.
Fix:
- Create persona/miku/preamble.txt — canonical normal Miku preamble
- Create persona/evil/preamble.txt — canonical evil Miku preamble
(with {mood_name} and {mood_description} format placeholders)
- All 5 consumers now read from these files:
* miku_personality.py (Cat plugin, primary path)
* evil_miku_personality.py (Cat plugin, primary path)
* discord_bridge.py (WebUI 'Last Prompt' reconstruction)
* llm.py (fallback path, normal Miku)
* evil_mode.py get_evil_system_prompt() (fallback path, evil Miku)
- All consumers include graceful fallbacks if preamble files are missing
- Fixed evil_mode.py discrepancy: 'body and size' now matches canonical
The preamble files are Docker volume-mounted into both containers:
bot/persona/ → /app/persona/ (bot, via Dockerfile COPY)
bot/persona/ → /app/cat/data/ (Cat, via docker-compose volume mount)
Editing the preamble file on the host immediately updates the Cat path
(bot path requires rebuild due to COPY).
96 lines
3.4 KiB
Python
96 lines
3.4 KiB
Python
"""
|
|
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."""
|
|
|
|
# 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}
|
|
|
|
# Conversation until now:"""
|
|
|
|
|
|
@hook(priority=100)
|
|
def agent_allowed_tools(allowed_tools, cat):
|
|
"""Disable tools - Miku just chats naturally"""
|
|
return []
|