Update .gitignore to exclude additional Python cache files; implement reset personality command with user permissions check
This commit is contained in:
12
.gitignore
vendored
12
.gitignore
vendored
@@ -51,3 +51,15 @@ discord_glhf/handlers/__pycache__/message_handler.cpython-313.pyc
|
||||
discord_glhf/handlers/__pycache__/tool_handler.cpython-313.pyc
|
||||
discord_glhf/web/__pycache__/app.cpython-313.pyc
|
||||
.env
|
||||
discord_glhf/__pycache__/__init__.cpython-313.pyc
|
||||
discord_glhf/__pycache__/config.cpython-313.pyc
|
||||
discord_glhf/__pycache__/database.cpython-313.pyc
|
||||
discord_glhf/__pycache__/main.cpython-313.pyc
|
||||
discord_glhf/__pycache__/queue_manager.cpython-313.pyc
|
||||
discord_glhf/__pycache__/queue_state.cpython-313.pyc
|
||||
discord_glhf/__pycache__/queue.cpython-313.pyc
|
||||
discord_glhf/__pycache__/training.cpython-313.pyc
|
||||
discord_glhf/handlers/event_handler.py
|
||||
discord_glhf/handlers/__pycache__/__init__.cpython-313.pyc
|
||||
discord_glhf/handlers/__pycache__/image_handler.cpython-313.pyc
|
||||
discord_glhf/web/__pycache__/__init__.cpython-313.pyc
|
||||
|
||||
@@ -40,6 +40,7 @@ class DiscordBot:
|
||||
self.db_pool = DatabasePool()
|
||||
self.db_manager = DatabaseManager(self.db_pool)
|
||||
self._initialized = False
|
||||
self._running = True
|
||||
self._init_lock = asyncio.Lock()
|
||||
|
||||
# Initialize handler references
|
||||
@@ -251,20 +252,28 @@ class DiscordBot:
|
||||
logger.error(
|
||||
f"Error before event_handler initialization: {exc_value}")
|
||||
|
||||
self._running = True
|
||||
try:
|
||||
async with self.bot:
|
||||
await self.bot.start(token)
|
||||
while True:
|
||||
while self._running:
|
||||
try:
|
||||
await self._handle_connection(token)
|
||||
except (aiohttp.ClientError, socket.gaierror) as e:
|
||||
logger.error(f"Connection error: {e}")
|
||||
await asyncio.sleep(5) # Wait before reconnecting
|
||||
if self._running: # Only log and retry if we're still meant to be running
|
||||
logger.error(f"Connection error: {e}")
|
||||
await asyncio.sleep(5) # Wait before reconnecting
|
||||
else:
|
||||
break
|
||||
except KeyboardInterrupt:
|
||||
raise
|
||||
self._running = False
|
||||
break
|
||||
except Exception as e:
|
||||
logger.error(f"Unexpected error: {e}")
|
||||
await asyncio.sleep(5) # Wait before reconnecting
|
||||
if self._running:
|
||||
logger.error(f"Unexpected error: {e}")
|
||||
await asyncio.sleep(5) # Wait before reconnecting
|
||||
else:
|
||||
break
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to start bot: {e}")
|
||||
raise
|
||||
|
||||
@@ -198,6 +198,11 @@ BOT_OWNER_ID = int(os.getenv("BOT_OWNER_ID")) # Required
|
||||
AUTO_RESPONSE_CHANNEL_ID = int(
|
||||
os.getenv("AUTO_RESPONSE_CHANNEL_ID")) # Required
|
||||
|
||||
# Get allowed users for reset command
|
||||
RESET_ALLOWED_USERS = [int(id.strip()) for id in os.getenv("RESET_ALLOWED_USERS", "").split(",") if id.strip()]
|
||||
if not RESET_ALLOWED_USERS:
|
||||
RESET_ALLOWED_USERS = [BOT_OWNER_ID] # Default to bot owner if not configured
|
||||
|
||||
# Load system prompt
|
||||
SYSTEM_PROMPT = os.getenv("SYSTEM_PROMPT") or load_system_prompt()
|
||||
|
||||
|
||||
@@ -605,6 +605,18 @@ class DatabaseManager:
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to update thread activity: {e}")
|
||||
|
||||
async def clear_all_messages(self) -> None:
|
||||
"""Clear all messages from the database."""
|
||||
try:
|
||||
async with self.pool.acquire() as conn:
|
||||
async with conn.cursor() as cursor:
|
||||
await cursor.execute("DELETE FROM messages")
|
||||
await conn.commit()
|
||||
logger.info("All message history cleared")
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to clear message history: {e}")
|
||||
raise
|
||||
|
||||
async def cleanup_old_messages(self):
|
||||
"""Clean up messages older than MESSAGE_CLEANUP_DAYS."""
|
||||
cleanup_date = datetime.now() - timedelta(days=MESSAGE_CLEANUP_DAYS)
|
||||
|
||||
@@ -9,7 +9,7 @@ from datetime import datetime
|
||||
from discord import Message, RawReactionActionEvent
|
||||
|
||||
from ..config import (
|
||||
logger, AUTO_RESPONSE_CHANNEL_ID, SYSTEM_PROMPT, BOT_OWNER_ID
|
||||
logger, AUTO_RESPONSE_CHANNEL_ID, SYSTEM_PROMPT, BOT_OWNER_ID, RESET_ALLOWED_USERS
|
||||
)
|
||||
from .message_handler import MessageHandler
|
||||
from .image_handler import ImageHandler
|
||||
@@ -41,7 +41,7 @@ class EventHandler:
|
||||
f"<@{mention[2:-1]}>" # Raw mention format
|
||||
]
|
||||
pattern = '|'.join(patterns)
|
||||
|
||||
|
||||
# Replace all mention formats with the proper mention
|
||||
return re.sub(pattern, mention, response)
|
||||
|
||||
@@ -150,6 +150,7 @@ class EventHandler:
|
||||
history = await self.db_manager.get_conversation_history(
|
||||
user_id=0,
|
||||
channel_id=payload.channel_id,
|
||||
limit=50 # Limit to recent context
|
||||
)
|
||||
logger.debug(f"Retrieved {len(history)} messages for context")
|
||||
|
||||
@@ -202,7 +203,8 @@ class EventHandler:
|
||||
created_at=datetime.utcnow()
|
||||
)
|
||||
|
||||
logger.info(f"Adding reaction response to queue from {user.display_name}")
|
||||
logger.info(
|
||||
f"Adding reaction response to queue from {user.display_name}")
|
||||
# Queue the reaction like a regular message
|
||||
await self.queue_manager.add_message(
|
||||
channel=channel,
|
||||
@@ -222,6 +224,30 @@ class EventHandler:
|
||||
return
|
||||
|
||||
try:
|
||||
# Handle !reset_personality command
|
||||
if message.content.strip() == "!reset_personality":
|
||||
# Check if user is allowed (in allowed list, has admin, or is bot owner)
|
||||
is_allowed = (
|
||||
message.author.id in RESET_ALLOWED_USERS or
|
||||
message.author.id == BOT_OWNER_ID or
|
||||
(hasattr(message.author, 'guild_permissions') and message.author.guild_permissions.administrator)
|
||||
)
|
||||
|
||||
if not is_allowed:
|
||||
logger.warning(f"Unauthorized reset attempt by {message.author.name} ({message.author.id})")
|
||||
return
|
||||
|
||||
try:
|
||||
# React with checkmark
|
||||
await message.add_reaction("✅")
|
||||
# Clear all messages
|
||||
await self.db_manager.clear_all_messages()
|
||||
logger.info(f"Personality reset by {message.author.name} ({message.author.id})")
|
||||
return
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to reset personality: {e}")
|
||||
return
|
||||
|
||||
# Only respond in configured channel or its threads
|
||||
if (message.channel.id != AUTO_RESPONSE_CHANNEL_ID and
|
||||
(not hasattr(message.channel, 'parent_id') or
|
||||
@@ -230,7 +256,8 @@ class EventHandler:
|
||||
|
||||
# Early duplicate checks before any processing
|
||||
if any(item.message.id == message.id for item in self.queue_manager.message_queue.processing):
|
||||
logger.debug(f"Message {message.id} already in processing, skipping")
|
||||
logger.debug(
|
||||
f"Message {message.id} already in processing, skipping")
|
||||
return
|
||||
|
||||
# Get current queue size
|
||||
@@ -244,7 +271,8 @@ class EventHandler:
|
||||
message_id=message.id
|
||||
)
|
||||
if message_processed:
|
||||
logger.debug(f"Message {message.id} already processed, skipping")
|
||||
logger.debug(
|
||||
f"Message {message.id} already processed, skipping")
|
||||
return
|
||||
|
||||
# Check for duplicate content in history
|
||||
@@ -257,7 +285,8 @@ class EventHandler:
|
||||
hist_content = hist_msg.get("content", {}).get("content", "") if isinstance(
|
||||
hist_msg.get("content"), dict) else hist_msg.get("content", "")
|
||||
if hist_content == current_content:
|
||||
logger.debug(f"Duplicate message content detected for message {message.id}, skipping")
|
||||
logger.debug(
|
||||
f"Duplicate message content detected for message {message.id}, skipping")
|
||||
return
|
||||
|
||||
# Update user activity in database
|
||||
@@ -351,7 +380,8 @@ class EventHandler:
|
||||
if hist_content == formatted_content:
|
||||
message_in_history = True
|
||||
if isinstance(hist_msg.get("metadata"), dict):
|
||||
stored_uuid = hist_msg["metadata"].get("message_uuid")
|
||||
stored_uuid = hist_msg["metadata"].get(
|
||||
"message_uuid")
|
||||
break
|
||||
|
||||
# Use stored UUID if found, otherwise use new UUID
|
||||
@@ -381,7 +411,8 @@ class EventHandler:
|
||||
await self.store_message(
|
||||
user_id=item.message.author.id,
|
||||
role="user",
|
||||
content={"content": formatted_content, "metadata": message_metadata},
|
||||
content={"content": formatted_content,
|
||||
"metadata": message_metadata},
|
||||
channel_id=item.channel.id,
|
||||
message_uuid=message_uuid,
|
||||
)
|
||||
@@ -404,7 +435,10 @@ class EventHandler:
|
||||
}
|
||||
|
||||
messages = [system_message]
|
||||
messages.extend(history)
|
||||
|
||||
# Include conversation history
|
||||
if history:
|
||||
messages.extend(history)
|
||||
|
||||
# Always add current message to the API call
|
||||
# Add timeout_env to the context
|
||||
@@ -483,7 +517,8 @@ class EventHandler:
|
||||
)
|
||||
if thread_id:
|
||||
await self.db_manager.update_thread_activity(thread_id)
|
||||
logger.info(f"Created and stored thread '{args['name']}' in database")
|
||||
logger.info(
|
||||
f"Created and stored thread '{args['name']}' in database")
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Error executing tool {tool_name}: {e}")
|
||||
@@ -491,7 +526,8 @@ class EventHandler:
|
||||
# Send the response
|
||||
if final_response:
|
||||
author = item.message.author
|
||||
owner_tag = ' [BOT OWNER]' if int(author.id) == BOT_OWNER_ID else ''
|
||||
owner_tag = ' [BOT OWNER]' if int(
|
||||
author.id) == BOT_OWNER_ID else ''
|
||||
logger.info(
|
||||
f"Bot response to {author.display_name} "
|
||||
f"({author.name}#{author.discriminator})"
|
||||
@@ -501,7 +537,7 @@ class EventHandler:
|
||||
reference = None
|
||||
if hasattr(item.message, '_state'): # Check if it's a real Discord Message
|
||||
reference = item.message
|
||||
|
||||
|
||||
sent_message = await self.message_handler.safe_send(
|
||||
item.channel, final_response, reference=reference
|
||||
)
|
||||
@@ -545,7 +581,7 @@ class EventHandler:
|
||||
source_info = {"type": "web"}
|
||||
else:
|
||||
source_info = {"type": "discord"}
|
||||
|
||||
|
||||
response_metadata = {
|
||||
"response_id": response_uuid,
|
||||
"user_info": {
|
||||
|
||||
Reference in New Issue
Block a user