Commit Graph

100 Commits

Author SHA1 Message Date
a8e8b63f5e feat: add ReactionCog for ambient emoji reactions
Add a new cog that gives the bot ambient presence by reacting to
messages with contextual emoji chosen by the triage LLM. Includes
RNG gating and per-channel cooldown to keep reactions sparse and
natural.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 11:25:17 -05:00
5c84c8840b fix: use emoji allowlist instead of length check in pick_reaction
Prevents text words like "skull" from passing the filter and causing
Discord HTTPException noise.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 11:24:28 -05:00
661c252bf7 feat: add pick_reaction method to LLMClient
Lightweight LLM call that picks a contextual emoji reaction for a
Discord message. Uses temperature 0.9 for variety, max 16 tokens,
and validates the response is a short emoji token or returns None.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 11:22:08 -05:00
2ec9b16b99 fix: address multiple bugs found in code review
- Fix dirty-user flush race: discard IDs individually after successful save
- Escape LIKE wildcards in LLM-generated topic keywords for DB queries
- Anonymize absent-member aliases to prevent LLM de-anonymization
- Pass correct MIME type to vision model based on image file extension
- Use enumerate instead of list.index() in bcs-scan loop
- Allow bot @mentions with non-report intent to fall through to moderation

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 01:16:38 -05:00
eb7eb81621 feat: add warning expiration and exclude moderated messages from context
Warning flag now auto-expires after a configurable duration
(warning_expiration_minutes, default 30m). After expiry, the user must
be re-warned before a mute can be issued.

Messages that triggered moderation actions (warnings/mutes) are now
excluded from the LLM context window in both buffered analysis and
mention scans, preventing already-actioned content from influencing
future scoring. Uses in-memory tracking plus bot reaction fallback
for post-restart coverage.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-28 13:39:49 -05:00
36df4cf5a6 chore: add .claude/ to .gitignore
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-27 22:16:18 -05:00
bf32a9536a feat: add server rule violation detection and compress prompts
- LLM now evaluates messages against numbered server rules and reports
  violated_rules in analysis output
- Warnings and mutes cite the specific rule(s) broken
- Rules extracted to prompts/rules.txt for prompt injection
- Personality prompts moved to prompts/personalities/ and compressed
  (~63% reduction across all prompt files)
- All prompt files tightened: removed redundancy, consolidated Do NOT
  sections, trimmed examples while preserving behavioral instructions

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-27 22:14:35 -05:00
ed51db527c fix: stop bot from starting every message with "Oh,"
Removed "Oh," from example lines that the model was mimicking, added
explicit DO NOT rule against "Oh" openers, and added more varied examples.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-27 20:45:16 -05:00
bf5051dfc1 fix: steer default chat personality away from southern aunt tone
The LLM was interpreting "sassy hall monitor" as warm/motherly with pet
names like "oh sweetheart" and "bless your heart". Added explicit guidance
for deadpan, dry Discord mod energy instead.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-27 17:25:06 -05:00
cf88638603 fix: add guild-specific command sync for instant slash command propagation
Global sync can take up to an hour to propagate. Now also syncs commands
per-guild in on_ready for immediate availability.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-27 16:11:46 -05:00
1d653ec216 feat: add /drama-leaderboard command with historical composite scoring
Queries Messages, AnalysisResults, and Actions tables to rank users by a
composite drama score (weighted avg toxicity, peak toxicity, and action rate).
Public command with configurable time period (7d/30d/90d/all-time).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-27 16:08:39 -05:00
0ff962c95e feat: generate topic drift redirects via LLM with full conversation context
Replace static random templates with LLM-generated redirect messages that
reference what the user actually said and why it's off-topic. Sass escalates
with higher strike counts. Falls back to static templates if LLM fails or
use_llm is disabled in config.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-27 15:28:36 -05:00
2525216828 fix: deduplicate memories on save with exact-match check
Prevents inserting a memory if an identical one already exists for the
user. Also cleaned up 30 anonymized and 4 duplicate memories from DB.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-27 10:53:52 -05:00
3b2de80cac fix: de-anonymize User1/User2 references in notes and reasoning text
The LLM returns note_update, reasoning, and worst_message with
anonymized names. These are now replaced with real display names
before storage, so user profiles no longer contain meaningless
User1/User2 references.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-27 10:51:30 -05:00
88536b4dca chore: remove wordle cog
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-27 10:48:44 -05:00
33d56f8737 feat: move user aliases from config to DB with /bcs-alias command
Aliases now stored in UserState table instead of config.yaml. Adds
Aliases column (NVARCHAR 500), loads on startup, persists via flush.
New /bcs-alias slash command (view/set/clear) for managing nicknames.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-27 10:35:19 -05:00
ad1234ec99 feat: add user alias mapping for jealousy detection context
Adds user_aliases config section mapping Discord IDs to known nicknames.
Aliases are anonymized and injected into LLM analysis context so it can
recognize when someone name-drops another member (even absent ones).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-27 10:22:57 -05:00
a73d2505d9 feat: add jealousy/possessiveness detection as toxicity category
LLM can now flag possessive name-dropping, territorial behavior, and
jealousy signals when users mention others not in the conversation.
Scores feed into existing drama pipeline for warnings/mutes.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-27 10:07:45 -05:00
0449c8c30d feat: give bot full conversation context on @mentions for real engagement
When @mentioned, fetch recent messages from ALL users in the channel
(up to 15 messages) instead of only the mentioner's messages. This lets
the bot understand debates and discussions it's asked to weigh in on.

Also update the personality prompt to engage with topics substantively
when asked for opinions, rather than deflecting with generic jokes.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-26 14:14:46 -05:00
3d252ee729 feat: classify mention intent before running expensive scan
Adds LLM triage on bot @mentions to determine if the user is chatting
or reporting bad behavior. Only 'report' intents trigger the 30-message
scan; 'chat' intents skip the scan and let ChatCog handle it.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-26 13:20:54 -05:00
b918ba51a8 fix: use escalation model and fallback to permanent memories in migration
- Use LLM_ESCALATION_* env vars for better profile generation
- Fall back to joining permanent memories if profile_update is null

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-26 13:14:38 -05:00
efe7f901c2 Merge branch 'worktree-agent-a27a0179' 2026-02-26 13:04:25 -05:00
ca17b6ac61 Merge branch 'worktree-agent-a0b1ccc2' 2026-02-26 13:04:24 -05:00
8a092c720f Merge branch 'worktree-agent-a78eaee3' 2026-02-26 13:04:18 -05:00
365907a7a0 feat: extract and save memories after chat conversations
Merge worktree: adds _extract_and_save_memories() method and fire-and-forget
extraction call after each chat reply. Combined with Task 4's memory
retrieval and injection.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-26 13:04:12 -05:00
e488b2b227 feat: extract and save memories after chat conversations
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-26 13:02:42 -05:00
7ca369b641 feat: add one-time migration script for user notes to profiles
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-26 12:59:03 -05:00
305c9bf113 feat: route sentiment note_updates into memory system
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-26 12:58:14 -05:00
2054ca7b24 feat: add background memory pruning task
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-26 12:58:12 -05:00
d61e85d928 feat: inject persistent memory context into chat responses
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-26 12:56:02 -05:00
89fabd85da feat: add set_user_profile method to DramaTracker
Replaces the entire notes field with an LLM-generated profile summary,
used by the memory extraction system for permanent facts.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-26 12:54:05 -05:00
67011535cd feat: add memory extraction LLM tool and prompt
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-26 12:53:18 -05:00
8686f4fdd6 fix: align default limits and parameter names to spec
- get_recent_memories: limit default 10 → 5
- get_memories_by_topics: limit default 10 → 5
- prune_excess_memories: rename 'cap' → 'max_memories'

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-26 12:50:47 -05:00
75adafefd6 feat: add UserMemory table and CRUD methods for conversational memory
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-26 12:48:54 -05:00
333fbb3932 docs: add conversational memory implementation plan
9-task step-by-step plan covering DB schema, LLM extraction tool, memory
retrieval/injection in chat, sentiment pipeline routing, background pruning,
and migration script.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-26 12:44:18 -05:00
d652c32063 docs: add conversational memory design document
Outlines persistent memory system for making the bot a real conversational
participant that knows people and remembers past interactions. Uses existing
UserNotes column for permanent profiles and a new UserMemory table for
expiring context with LLM-assigned lifetimes.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-26 12:41:28 -05:00
196f8c8ae5 fix: remove owner notification on topic drift escalation
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-25 22:29:01 -05:00
c63913cf14 fix: anonymize usernames before LLM analysis to prevent name-based scoring bias
Display names like "Calm your tits" were causing the LLM to inflate toxicity
scores on completely benign messages. Usernames are now replaced with User1,
User2, etc. before sending to the LLM, then mapped back to real names in the
results.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-25 22:20:53 -05:00
cb8ef8542b fix: guard against malformed LLM findings in conversation validation
Filter out non-dict entries from user_findings and handle non-dict
result to prevent 'str' object has no attribute 'setdefault' errors.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-25 21:38:02 -05:00
f46caf9ac5 fix: tag context messages with [CONTEXT] to prevent LLM from scoring them
The triage LLM was blending context message content into its reasoning
for new messages (e.g., citing profanity from context when the new
message was just "I'll be here"). Added per-message [CONTEXT] tags
inline and strengthened the prompt to explicitly forbid referencing
context content in reasoning/scores.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-25 20:08:23 -05:00
660086a500 refactor: extract sentiment cog into package with shared _process_finding
Convert cogs/sentiment.py (1050 lines) into cogs/sentiment/ package:
- __init__.py (656 lines): core SentimentCog with new _process_finding()
  that deduplicates the per-user finding loop from _process_buffered and
  _run_mention_scan (~90 lines each → single shared method)
- actions.py: mute_user, warn_user
- topic_drift.py: handle_topic_drift
- channel_redirect.py: handle_channel_redirect, build_channel_context
- coherence.py: handle_coherence_alert
- log_utils.py: log_analysis, log_action, score_color
- state.py: save_user_state, flush_dirty_states

All extracted modules use plain async functions (not methods) receiving
bot/config as parameters. Named log_utils.py to avoid shadowing stdlib
logging. Also update CLAUDE.md with comprehensive project documentation.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-25 17:06:27 -05:00
188370b1fd Fix LLM scoring usernames as toxic content
The display name "Calm your tits" was being factored into toxicity
scores. Updated the analysis prompt to explicitly instruct the LLM
to ignore all usernames/display names when scoring messages.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-25 15:51:14 -05:00
7417908142 fix: separate context from new messages so prior-cycle chat doesn't inflate scores
The conversation analysis was re-scoring old messages alongside new ones,
causing users to get penalized repeatedly for already-scored messages.
A "--- NEW MESSAGES ---" separator now marks which messages are new, and
the prompt instructs the LLM to score only those. Also fixes bot-mention
detection to require an explicit @mention in message text rather than
treating reply-pings as scans (so toxic replies to bot warnings aren't
silently skipped).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-25 15:48:02 -05:00
8734f1883b fix: persist last_offense_time and reset offenses after 24h
last_offense_time was in-memory only — lost on restart, so the
offense_reset_minutes check never fired after a reboot. Now persisted
as LastOffenseAt FLOAT in UserState. On startup hydration, stale
offenses (and warned flag) are auto-cleared if the reset window has
passed. Bumped offense_reset_minutes from 2h to 24h.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-25 11:24:38 -05:00
71c7b45e9a feat: require warning before mute + sustained toxicity escalation
Gate mutes behind a prior warning — first offense always gets a warning,
mute only fires if warned_since_reset is True. Warned flag is persisted
to DB (new Warned column on UserState) and survives restarts.

Add post-warning escalation boost to drama_score: each high-scoring
message after a warning adds +0.04 (configurable) so sustained bad
behavior ramps toward the mute threshold instead of plateauing.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-25 11:07:57 -05:00
f02a4ab49d Add content fallback for conversation analysis + debug logging
When the LLM returns text instead of a tool call for conversation
analysis, try parsing the content as JSON before giving up. Also
log what the model actually returns on failure for debugging.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-25 10:16:15 -05:00
90b70cad69 feat: channel-level conversation analysis with compact formatting
Switch from per-user message batching to per-channel conversation
analysis. The LLM now sees the full interleaved conversation with
relative timestamps, reply chains, and consecutive message collapsing
instead of isolated flat text per user.

Key changes:
- Fix gpt-5-nano temperature incompatibility (conditional temp param)
- Add mention-triggered scan: users @mention bot to analyze recent chat
- Refactor debounce buffer from (channel_id, user_id) to channel_id
- Replace per-message analyze_message() with analyze_conversation()
  returning per-user findings from a single LLM call
- Add CONVERSATION_TOOL schema with coherence, topic, and game fields
- Compact message format: relative timestamps, reply arrows (→),
  consecutive same-user message collapsing
- Separate mention scan tasks from debounce tasks
- Remove _store_context/_get_context (conversation block IS the context)
- Escalation timeout config: [30, 60, 120, 240] minutes

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-24 23:13:07 -05:00
943c67cc87 Add Wordle scoring context so LLM knows lower is better
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-24 18:05:41 -05:00
f457240e62 Add Wordle commentary: bot reacts to Wordle results with mode-appropriate comments
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-24 17:56:05 -05:00
01b7a6b240 Bump health check max_completion_tokens to 16
gpt-5-nano can't produce output with max_completion_tokens=1.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-24 17:08:32 -05:00