- Question override now decays after 6 turns: after turn 6, the LLM's own
[CONTINUE] signal is respected even when questions are asked. This prevents
infinite question-ping-pong where both personas keep asking questions.
- _parse_response now accepts turn_count parameter; generate_response_with_continuation
and handle_dialogue_turn pass it through.
- Rewrote Evil Miku's conversation-mode overlay with explicit CRITICAL RULES:
ANSWER questions, engage with what she says, ask questions too, don't just
repeat dismissive one-liners. The old overlay said 'be playful-cruel' but
didn't actually tell her to participate in the conversation.
Created get_miku_system_prompt() and get_miku_system_prompt_compact() in
context_manager.py — mirrors get_evil_system_prompt() so both personas have
equally rich prompts with lore, lyrics, mood integration, and personality.
Previously only Evil Miku had a proper system prompt function. Regular Miku's
arguments and dialogues used a bare-bones hardcoded prompt with no lore/lyrics
— making arguments feel flat compared to normal conversation.
Changes:
- context_manager.py: added get_miku_system_prompt() (full) and
get_miku_system_prompt_compact() (lore+personality, no lyrics for tokens)
- bipolar_mode.py: both argument prompt functions now accept system_prompt
param; run_argument() builds miku_system and evil_system once and passes
them to every exchange
- persona_dialogue.py: dialogue prompts now use get_miku_system_prompt_compact()
instead of hardcoded stub, matching Evil Miku's full prompt approach
- Removed redundant hardcoded personality text from argument prompts since
the system prompts now provide it
- Changed cooldown from global (ALL channels blocked) to per-channel dict keyed by channel_id
- Added conversation streak tracker: 3 near-miss interjection scores in a row force a dialogue trigger
- Expanded topic relevance keywords: added enthusiasm/vulnerability for Evil Miku, provocation/dismissal for Miku
- Lowered keyword divisor from /3.0 to /2.0 for higher base trigger scores
- Tension rebalance: added natural decay (-0.03/turn), reduced escalation weight (0.08->0.05), increased de-escalation weight (0.06->0.08)
- Reduced momentum multiplier (1.2->1.1) and intensity multiplier (1.3->1.2)
- Added spike cooldown: if last turn tension delta >0.15, next delta halved (prevents runaway spirals)
- Added user-message interjection check in bot.py on_message() (was only checking bot's own messages)
- Added random 15% argument trigger roll on user messages in normal message flow (was only from autonomous.py)
- Fixed missing client parameter in animated GIF webhook update path
- Added get_persona_avatar_urls() helper that returns bot's current Discord
avatar URL for Miku persona (always fresh, no cache lag)
- Pass avatar_url on every webhook.send() call in bipolar_mode.py,
persona_dialogue.py, and api.py so avatars always match current pfp
regardless of webhook cache state
- Created new logging infrastructure with per-component filtering
- Added 6 log levels: DEBUG, INFO, API, WARNING, ERROR, CRITICAL
- Implemented non-hierarchical level control (any combination can be enabled)
- Migrated 917 print() statements across 31 files to structured logging
- Created web UI (system.html) for runtime configuration with dark theme
- Added global level controls to enable/disable levels across all components
- Added timestamp format control (off/time/date/datetime options)
- Implemented log rotation (10MB per file, 5 backups)
- Added API endpoints for dynamic log configuration
- Configured HTTP request logging with filtering via api.requests component
- Intercepted APScheduler logs with proper formatting
- Fixed persistence paths to use /app/memory for Docker volume compatibility
- Fixed checkbox display bug in web UI (enabled_levels now properly shown)
- Changed System Settings button to open in same tab instead of new window
Components: bot, api, api.requests, autonomous, persona, vision, llm,
conversation, mood, dm, scheduled, gpu, media, server, commands,
sentiment, core, apscheduler
All settings persist across container restarts via JSON config.
Features:
- Built custom ROCm container for AMD RX 6800 GPU
- Added GPU selection toggle in web UI (NVIDIA/AMD)
- Unified model names across both GPUs for seamless switching
- Vision model always uses NVIDIA GPU (optimal performance)
- Text models (llama3.1, darkidol) can use either GPU
- Added /gpu-status and /gpu-select API endpoints
- Implemented GPU state persistence in memory/gpu_state.json
Technical details:
- Multi-stage Dockerfile.llamaswap-rocm with ROCm 6.2.4
- llama.cpp compiled with GGML_HIP=ON for gfx1030 (RX 6800)
- Proper GPU permissions without root (groups 187/989)
- AMD container on port 8091, NVIDIA on port 8090
- Updated bot/utils/llm.py with get_current_gpu_url() and get_vision_gpu_url()
- Modified bot/utils/image_handling.py to always use NVIDIA for vision
- Enhanced web UI with GPU selector button (blue=NVIDIA, red=AMD)
Files modified:
- docker-compose.yml (added llama-swap-amd service)
- bot/globals.py (added LLAMA_AMD_URL)
- bot/api.py (added GPU selection endpoints and helper function)
- bot/utils/llm.py (GPU routing for text models)
- bot/utils/image_handling.py (GPU routing for vision models)
- bot/static/index.html (GPU selector UI)
- llama-swap-rocm-config.yaml (unified model names)
New files:
- Dockerfile.llamaswap-rocm
- bot/memory/gpu_state.json
- bot/utils/gpu_router.py (load balancing utility)
- setup-dual-gpu.sh (setup verification script)
- DUAL_GPU_*.md (documentation files)