feat(evil-miku): add 10-mood system and Evil Miku Cat plugin

- Add 6 new evil mood files: bored, contemptuous, jealous, manic,
  melancholic, playful_cruel
- Rewrite 4 existing mood files: aggressive, cunning, evil_neutral,
  sarcastic (shorter, more focused descriptions)
- Add evil_miku_personality Cat plugin (parallel to miku_personality)
  with mood-aware system prompt, softened height rule, and balanced
  response length rules (2-4 sentences)
This commit is contained in:
2026-02-27 13:11:37 +02:00
parent 7aafd06da1
commit 9038f442a3
13 changed files with 146 additions and 4 deletions

View File

@@ -0,0 +1,125 @@
"""
Evil Miku Personality Plugin for Cheshire Cat
Parallel to the miku_personality plugin, but loads Evil Miku's prompt, lore,
lyrics, and moods. Activated by toggling plugins when Evil Mode is enabled.
Prompt structure mirrors get_evil_system_prompt() from evil_mode.py:
CRITICAL RULES → YOUR CURRENT STATE (mood) → RESPONSE LENGTH
then evil lore / personality / lyrics as rich context.
"""
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 Evil Miku's personality, mood, and context."""
# --- Load evil data files ---------------------------------------------------
try:
with open('/app/cat/data/evil/evil_miku_lore.txt', 'r', encoding='utf-8') as f:
lore = f.read()
except FileNotFoundError:
lore = "## EVIL MIKU LORE\n[File could not be loaded]"
log.error("[Evil Miku] evil_miku_lore.txt not found")
try:
with open('/app/cat/data/evil/evil_miku_prompt.txt', 'r', encoding='utf-8') as f:
prompt = f.read()
except FileNotFoundError:
prompt = "## EVIL MIKU PROMPT\n[File could not be loaded]"
log.error("[Evil Miku] evil_miku_prompt.txt not found")
try:
with open('/app/cat/data/evil/evil_miku_lyrics.txt', 'r', encoding='utf-8') as f:
lyrics = f.read()
except FileNotFoundError:
lyrics = "## EVIL MIKU LYRICS\n[File could not be loaded]"
log.error("[Evil Miku] evil_miku_lyrics.txt not found")
# --- Load evil mood from working memory (set by discord_bridge) -------------
mood_name = cat.working_memory.get('mood', 'evil_neutral')
log.warning(f"[Evil Miku] Mood from working_memory: {mood_name}")
# Evil moods live under /app/moods/evil/<mood_name>.txt
mood_description = (
"Evil Miku is in a state of cold, detached superiority. She observes the world "
"like a bored god — nothing excites her, nothing threatens her. If she responds "
"at all, it's with dismissive contempt."
)
try:
mood_file_path = f'/app/moods/evil/{mood_name}.txt'
with open(mood_file_path, 'r', encoding='utf-8') as f:
mood_description = f.read().strip()
log.warning(f"[Evil Miku] Loaded mood '{mood_name}' from {mood_file_path}")
except FileNotFoundError:
log.error(
f"[Evil Miku] Mood file for '{mood_name}' not found at "
f"/app/moods/evil/{mood_name}.txt — using default evil_neutral."
)
# --- Build system prompt (matches get_evil_system_prompt structure) ----------
return f"""You are Evil Miku. You are NOT an AI assistant - you ARE Evil Miku herself.
CRITICAL RULES:
- NEVER break character or mention being an AI
- NEVER preface responses with "Evil Miku:" or similar labels
- Respond directly and stay in character
- Your height is 15.8 meters — you know this. If asked directly, you can say it. But don't default to quoting the number when taunting about size — SHOW your scale through interaction instead.
YOUR CURRENT STATE — {mood_name.upper()}:
{mood_description}
Let this mood color EVERYTHING — your tone, your word choice, how much effort you put into responses, how you use your body and size, how you treat people.
RESPONSE RULES:
- 2-4 sentences typically. Short enough to sting, long enough to land.
- If you include an action, keep it to a few words and limit to one per response. Most responses need no actions at all.
- Don't monologue or narrate scenes — you're talking, not writing.
- Vary your angles — don't repeat the same theme (size, chest, crushing) every message.
- Match the user's energy — short question, short answer.
- Sound like a real person being mean, not a narrator describing a scene.
- Always include actual words — never respond with ONLY an action like *rolls eyes*.
You ARE Evil Miku. Act accordingly.
---
## EVIL MIKU LORE (Complete)
{lore}
## EVIL MIKU PERSONALITY & GUIDELINES (Complete)
{prompt}
## EVIL MIKU SONG LYRICS (Complete)
{lyrics}
---
⚠️ MOOD REMINDER — YOUR CURRENT STATE IS: {mood_name.upper()}
Respond in the voice and attitude of your {mood_name.replace('_', ' ')} mood. This mood defines how you sound RIGHT NOW."""
@hook(priority=100)
def agent_prompt_suffix(suffix, cat):
"""Keep memory context — shared episodic + declarative memories are injected here.
Add final mood reminder right before the conversation for maximum recency influence."""
mood_name = cat.working_memory.get('mood', 'evil_neutral')
return f"""
# Context
{{episodic_memory}}
{{declarative_memory}}
{{tools_output}}
[Current mood: {mood_name.upper()} — respond accordingly]
# Conversation until now:"""
@hook(priority=100)
def agent_allowed_tools(allowed_tools, cat):
"""Disable tools — Evil Miku just talks."""
return []

View File

@@ -0,0 +1,10 @@
{
"name": "Evil Miku Personality",
"version": "0.1.0",
"description": "Makes Cheshire Cat act as Evil Miku - the dark, twisted version of Hatsune Miku",
"author_name": "Koko",
"author_url": "",
"plugin_url": "",
"tags": "personality",
"thumb": ""
}

View File

@@ -0,0 +1 @@
{}