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>
This commit is contained in:
2026-02-24 23:13:07 -05:00
parent 943c67cc87
commit 90b70cad69
5 changed files with 793 additions and 227 deletions
+18 -2
View File
@@ -153,6 +153,19 @@ class ChatCog(commands.Cog):
if not content:
content = "(just pinged me)" if not is_proactive else message.content
# If a mention scan is running, await it so we can include findings
scan_summary = ""
if self.bot.user in message.mentions:
sentiment_cog = self.bot.get_cog("SentimentCog")
if sentiment_cog:
task = sentiment_cog._mention_scan_tasks.get(message.channel.id)
if task and not task.done():
try:
await asyncio.wait_for(asyncio.shield(task), timeout=45)
except (asyncio.TimeoutError, asyncio.CancelledError):
pass
scan_summary = sentiment_cog._mention_scan_results.pop(message.id, "")
# Add drama score context only when noteworthy
drama_score = self.bot.drama_tracker.get_drama_score(message.author.id)
user_data = self.bot.drama_tracker.get_user(message.author.id)
@@ -169,6 +182,10 @@ class ChatCog(commands.Cog):
if user_notes:
extra_context += f"[Notes about {message.author.display_name}: {user_notes}]\n"
# Include mention scan findings if available
if scan_summary:
extra_context += f"[You just scanned recent chat. Results: {scan_summary}]\n"
recent_user_msgs = []
try:
async for msg in message.channel.history(limit=50, before=message):
@@ -239,8 +256,7 @@ class ChatCog(commands.Cog):
# warnings/mutes appear before the chat reply
sentiment_cog = self.bot.get_cog("SentimentCog")
if sentiment_cog:
key = (message.channel.id, message.author.id)
task = sentiment_cog._debounce_tasks.get(key)
task = sentiment_cog._debounce_tasks.get(message.channel.id)
if task and not task.done():
try:
await asyncio.wait_for(asyncio.shield(task), timeout=15)