- bot/Dockerfile: Add ffmpeg to reinstall line after apt-get autoremove
(autoremove was sweeping up ffmpeg as 'no longer needed' after playwright install)
- bot/utils/image_handling.py: Increase video analysis timeout 120s→300s, 6→3 for Tenor GIFs (GTX 1660 VRAM constraint)
- bot/utils/activities.py: Add _activity_changed_at timestamp tracking,
get_current_activity_label() and get_current_activity_fresh() with 30-min decay
- bot/utils/cat_client.py: Pass current Discord activity to Cheshire Cat pipeline
- bot/utils/llm.py: Inject current Discord activity into system prompt
- cat-plugins/*: Forward Discord activity through working_memory to personality plugins
- bot/persona/*/preamble.txt: Add Discord status usage guidelines for character prompts
- llama-swap-rocm-config.yaml: Add qwen3.5 model entry for ComfyUI prompt generation
- AGENTS.md: New project documentation file
Three interrelated fixes for speaker attribution confusion:
1. Fix misleading episodic memory header (discord_bridge.py):
The Cat core hardcodes '## Context of things the Human said in the past:'
when formatting recalled conversations. Our plugins store BOTH user messages
([User]: prefix) AND Miku's own responses ([Miku]: prefix) in episodic memory.
This misleading header primes the LLM to attribute Miku's words to the user.
Replaced with '## Past conversation excerpts (prefixed by who said what):'
which accurately describes the mixed-speaker content.
2. Tighten episodic recall (discord_bridge.py):
Added before_cat_recalls_episodic_memories hook setting threshold=0.75
(vs default 0.7) to reduce the chance of Miku's own just-uttered response
being recalled on the very next user message, which would feed her own
words back as misleading context.
3. Add role clarification (miku_personality.py & evil_miku_personality.py):
Added a clarifying note after '# Conversation until now:' in the prompt
suffix to explicitly tell the model that 'Human = the user, AI = you (Miku)',
helping it reconcile the two labeling systems (episodic [User]/[Miku] prefixes
vs conversation history Human/AI roles).
Preamble:
- Sentence limit 1-3 → 2-4 (revert to original 'sting, then land' range)
- Remove 'if you can say it in one, say it in one' (encouraged lazy dismissals)
- Add engagement rule: 'Always engage with what was said — acknowledge the
question or statement, then twist the knife. Ignoring isn\'t sharp, it\'s lazy.'
Suffix:
- Remove '[Keep responses short and cutting — 1-3 sentences. No monologues.]'
The suffix was the LAST thing the model processed, so its brevity hammer
overpowered the preamble's engagement instruction. Preamble alone is enough.
Five targeted fixes:
1. discord_bridge (priority 100): Skip 'cheerful virtual idol' wrapper and
'CRITICAL INSTRUCTION' about facts when evil_mode is active. Evil Miku
gets her own prompt from evil_miku_personality plugin.
2. memory_consolidation (priority 10): Soften fact-usage pressure:
'Use THESE facts when answering' → 'You may reference these facts if
relevant to the conversation'. Also soften username command tone.
3. evil_miku_personality (priority 100→101): Bump above discord_bridge
so Evil Miku's prefix replacement deterministically discards any
Miku-mode wrappers regardless of plugin load order.
4. evil preamble: Restructure for brevity — add 'Be SHORT and SHARP'
declaration, move RESPONSE RULES before mood, tighten sentence limit
from 2-4 to 1-3 with 'if you can say it in one, say it in one.'
5. evil suffix: Add final brevity reminder '[Keep responses short and
cutting — 1-3 sentences. No monologues.]' right before conversation
for maximum recency influence.
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).