- Remove /no_think override from chat() so Qwen3 reasons before
generating responses (fixes incoherent word-salad replies)
- Analysis and image calls keep /no_think for speed
- Add varied roast style guidance (deadpan, sarcastic, blunt, etc.)
- Explicitly ban metaphors/similes in roast prompt
- Replace metaphor examples with direct roast examples
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
When the bot replies (proactive or mentioned), it now fetches the
user's drama tracker notes and their last ~10 messages in the channel.
Gives the LLM real context for personalized replies instead of
generic roasts on bare pings.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Proactive replies used channel.send() which posted standalone messages
with no visual link to what triggered them. Now all replies use
message.reply() so the response is always attached to the source message.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Send as a channel message instead of message.reply() so it doesn't
look like the bot is talking to itself.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Reply to any message + @bot to have the bot read and respond to it.
Also picks up image attachments from referenced messages so users
can reply to a photo with "@bot roast this".
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Triage analysis runs on Qwen 8B (athena.lan) for free first-pass.
Escalation, chat, image roasts, and commands use GPT-4o via OpenAI.
Each tier gets its own base URL, API key, and concurrency settings.
Local models get /no_think and serialized requests automatically.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The prompt was scoreboard-only, so selfies got nonsensical stat-based
roasts. Now the LLM identifies what's in the image and roasts accordingly.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Default models: gpt-4o-mini (triage), gpt-4o (escalation)
- Remove Qwen-specific /no_think hacks
- Reduce timeout from 600s to 120s, increase concurrency semaphore to 4
- Support empty LLM_BASE_URL to use OpenAI directly
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Raised sentence limit from 3 to 5 for english teacher mode
- Added instruction to list multiple corrections rapid-fire
- Roast mode reply chance: 10% -> 35%
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1. Broader regex to strip leaked metadata even when the LLM drops
the "Server context:" prefix but keeps the content.
2. Skip sentiment analysis for messages that mention or reply to
the bot. Users interacting with the bot in roast/chat modes
shouldn't have those messages inflate their drama score.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
When someone reacts to the bot's message, there's a 50% chance it
fires back with a reply commenting on their emoji choice, in
character for the current mode.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The vision model request was hanging indefinitely, freezing the bot.
The streaming loop had no timeout so if the model never returned
chunks, the bot would wait forever. Now times out after 2 minutes.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The local LLM was echoing back [Server context: ...] metadata lines
in its responses despite prompt instructions not to. Now stripped
via regex before sending to Discord.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Usage: ./scripts/announce.sh "message" [channel_name]
Fetches the bot token from barge, resolves channel by name,
and posts via the Discord API. Defaults to #general.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Insufferable grammar nerd that corrects spelling, translates slang
into proper English, and overanalyzes messages like literary essays.
20% proactive reply chance with relaxed moderation.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
When a user replies to the bot's message, the original bot message
text is now included in the context sent to the LLM. This prevents
the LLM from misinterpreting follow-up questions like "what does
this even mean?" since it can see what message is being referenced.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
LLM was misinterpreting usernames as channel names because
the [Server context: ...] metadata format was never explained
in the system prompts. This caused nonsensical replies like
treating username "thelimitations" as "the limitations channel".
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Adds a BotSettings key-value table. The active mode is saved
when changed via /bcs-mode and restored on startup.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
LLM analysis now detects when two users are in a genuine
disagreement. When detected, the bot creates a native Discord
poll with each user's position as an option.
- Disagreement detection added to LLM analysis tool schema
- Polls last 4 hours with 1 hour per-channel cooldown
- LLM extracts topic, both positions, and usernames
- Configurable via polls section in config.yaml
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Adds a server-wide mode system with /bcs-mode command.
- Default: current hall-monitor behavior unchanged
- Chatty: friendly chat participant with proactive replies (~10% chance)
- Roast: savage roast mode with proactive replies
- Chatty/roast use relaxed moderation thresholds
- 5-message cooldown between proactive replies per channel
- Bot status updates to reflect active mode
- /bcs-status shows current mode and effective thresholds
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Only inject drama score/offense context when values are noteworthy
(score >= 0.2 or offenses > 0). Update personality prompt to avoid
harping on zero scores and vary responses more.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Log every LLM call (analysis, chat, image, raw_analyze) to a new
LlmLog table with request type, model, token counts, duration,
success/failure, and truncated request/response payloads. Enables
debugging prompt issues and tracking usage.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
When the LLM is offline, post to #bcs-log instead of sending
the "brain offline" message in chat.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- spike_mute: 0.8→0.7, mute: 0.75→0.65 so escalating users get
timed out after a warning instead of endlessly warned
- Skip debounce on @mentions so sentiment analysis fires immediately
- Chat cog awaits pending sentiment analysis before replying,
ensuring warnings/mutes appear before the personality response
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Send last ~8 messages from all users (not just others) as a
multi-line chat log with relative timestamps so the LLM can
better understand conversation flow and escalation patterns.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Triage model (LLM_MODEL) handles every message cheaply. If toxicity
>= 0.25, off_topic, or coherence < 0.6, the message is re-analyzed
with the heavy model (LLM_ESCALATION_MODEL). Chat, image analysis,
/bcs-test, and /bcs-scan always use the heavy model.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Buffer messages per user+channel and wait for a configurable window
(batch_window_seconds: 3) before analyzing. Combines burst messages
into a single LLM call instead of analyzing each one separately.
Replaces cooldown_between_analyses with the debounce approach.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Detect when users discuss a game in the wrong channel (e.g. GTA talk
in #warzone) and send a friendly redirect to the correct channel.
Also add sexual_vulgar category and scoring rules so crude sexual
remarks directed at someone aren't softened by "lmao".
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
When @mentioned with an image attachment, the bot now roasts players
based on scoreboard screenshots using the vision model. Text-only
mentions continue to work as before.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Sends a minimal 1-token completion during setup_hook so the model is
ready before Discord messages start arriving, avoiding connection
errors and slow first responses after a restart.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The analyze_message and raw_analyze methods had no max_tokens limit,
causing thinking models (Qwen3-VL-32B-Thinking) to generate unlimited
reasoning tokens before responding — taking 5+ minutes per message.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Serialize all LLM requests through an asyncio semaphore to prevent
overloading athena with concurrent requests
- Switch chat() to streaming so the typing indicator only appears once
the model starts generating (not during thinking/loading)
- Increase LLM timeout from 5 to 10 minutes for slow first loads
- Rename ollama_client.py to llm_client.py and self.ollama to self.llm
since the bot uses a generic OpenAI-compatible API
- Update embed labels from "Ollama" to "LLM"
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Move the analysis and chat personality system prompts from inline Python
strings to prompts/analysis.txt and prompts/chat_personality.txt for
easier editing. Also add a rule so users quoting/reporting what someone
else said are not penalized for the quoted words.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The ODBC driver failed to load at runtime because libgssapi_krb5.so.2
was not installed. Add it explicitly to the apt-get install step.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Discord bot for monitoring chat sentiment and tracking drama using
Ollama LLM on athena.lan. Includes sentiment analysis, slash commands,
drama tracking, and SQL Server persistence via Docker Compose.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>