Update README with environment variable configuration and bot command details; enhance event and tool handler initialization

This commit is contained in:
pacnpal
2025-02-24 14:09:27 -05:00
parent b0612c9c7e
commit 015c40441b
7 changed files with 152 additions and 18 deletions

101
README.md
View File

@@ -33,7 +33,32 @@ uv pip install -r requirements.txt
## Configuration
All configuration is done through environment variables. Create a `.env` file:
### Environment Variables
Create a `.env` file with required configuration:
### System Prompt & Personality
The bot's personality and behavior are configured through `system_prompt.yaml`. This defines:
- Core personality traits and behavior
- Response patterns and style
- Tool usage guidelines
- Context handling rules
Example system_prompt.yaml structure:
```yaml
sections:
- title: "Personality"
content: "Define the bot's character and tone"
- title: "Tools"
content: "Define how the bot uses available tools"
- title: "Context"
content: "Define how the bot handles conversation context"
```
The system prompt works in conjunction with the available tools to create natural, contextual interactions. When using `!reset_memory`, the bot reloads this configuration while preserving user data and preferences.
### Environment Variables
```env
# Required Environment Variables
@@ -191,10 +216,76 @@ The bot includes comprehensive monitoring:
- System state
3. Performance Metrics
- Response times
- Queue latency
- API latency
- Database performance
- Response times
- Queue latency
- API latency
- Database performance
4. Tool Usage Monitoring
- Detection of tool invocations
- Tool execution tracking
- Success/failure logging
- Comprehensive logging for:
- User mentions
- Thread creation
- Emoji reactions
- Emoticon conversions
- Tool usage summaries per message
## Bot Commands
### Owner Commands
- `!reset_memory` - Reset the bot's memory back to initial system prompt
- Tracks number of resets per user
- Preserves user interaction history and preferences
- Shows reset count in response
## Bot Tools & Capabilities
The bot uses a natural language tool system that allows it to perform actions based on conversation context:
### Available Tools
1. **User Mentions** (@username)
- Naturally mention users in conversation
- Example: "Hey @john, what do you think?"
- Automatically resolves nicknames and usernames
2. **Emoji Reactions**
- Add emoji reactions to messages
- Supports Unicode emojis, custom emojis, and standard Discord emojis
- Example: "That's awesome! 👍" (will add thumbs up reaction)
- Can convert emoticons like :) to proper emojis
3. **Rich Embeds**
- Create formatted embed messages
- Supports titles, descriptions, and custom colors
- Example:
```
[Embed]
Poll Results
First place: X
Second place: Y
[/Embed]
```
4. **Threading**
- Automatically creates discussion threads
- Supports various conversation patterns:
* Comparisons: "X vs Y"
* Reviews: "This coaster is overrated"
* Topics: "Safety discussion" or "Maintenance review"
- Automatically formats thread names for consistency
### Tool Usage
The bot uses these tools naturally in conversation without requiring explicit commands. It can:
- Recognize when to mention users based on context
- Add appropriate emoji reactions to messages
- Create organized threads for discussions
- Format information in embeds for better readability
All tools are used through natural language processing, making interactions feel more conversational and intuitive.
## Running the Bot

View File

@@ -57,11 +57,26 @@ class DiscordBot:
try:
async with self._init_lock:
if not self._initialized:
# Initialize handlers first
# Initialize all handlers first
self.message_handler = MessageHandler(self.db_manager)
logger.info("Message handler initialized")
self.image_handler = ImageHandler(self.api_manager)
logger.info("Image handler initialized")
self.tool_handler = ToolHandler(self.bot)
logger.info("Tool handler initialized")
self.event_handler = EventHandler(
self.bot, self.queue_manager, self.db_manager, self.api_manager
self.bot,
self.queue_manager,
self.db_manager,
self.api_manager,
message_handler=self.message_handler,
image_handler=self.image_handler,
tool_handler=self.tool_handler
)
logger.info("Event handler initialized with all handlers")
# Start API manager
if not self.api_manager.is_running:
@@ -367,23 +382,40 @@ def run_bot():
"""Handle shutdown signals."""
signame = signal.Signals(signum).name
logger.info(f"Received signal {signame}")
if bot.bot and bot.bot.loop:
# Use the sync_close method to properly handle shutdown
bot.sync_close()
raise KeyboardInterrupt() # Break the event loop
# Force stop the event loop
if bot.bot and bot.bot.loop and bot.bot.loop.is_running():
bot.queue_manager.set_shutting_down()
# Stop the loop immediately
bot.bot.loop.stop()
# This will exit discord.py's run() method
sys.exit(0)
# Register signal handlers
signal.signal(signal.SIGINT, signal_handler)
signal.signal(signal.SIGTERM, signal_handler)
try:
# Start the bot
# Start the bot with discord.py's runner
bot.bot.run(token)
except KeyboardInterrupt:
logger.info("Bot stopped by interrupt")
except (KeyboardInterrupt, SystemExit):
logger.info("Bot is shutting down...")
except Exception as e:
logger.error(f"Bot crashed: {e}")
raise
finally:
# Final cleanup
try:
# Make sure QueueManager is stopped
bot.queue_manager.set_shutting_down()
# Run cleanup in a new event loop
cleanup_loop = asyncio.new_event_loop()
asyncio.set_event_loop(cleanup_loop)
cleanup_loop.run_until_complete(bot.stop())
cleanup_loop.close()
except Exception as e:
logger.error(f"Error during final cleanup: {e}")
logger.info("Bot shutdown complete")
if __name__ == "__main__":

View File

@@ -19,14 +19,15 @@ from .tool_handler import ToolHandler
class EventHandler:
"""Handles Discord events and their processing."""
def __init__(self, bot, queue_manager, db_manager, api_manager):
def __init__(self, bot, queue_manager, db_manager, api_manager, message_handler=None, image_handler=None, tool_handler=None):
self.bot = bot
self.queue_manager = queue_manager
self.db_manager = db_manager
self.api_manager = api_manager
self.message_handler = MessageHandler(db_manager)
self.image_handler = ImageHandler(api_manager)
self.tool_handler = ToolHandler(bot)
# Use provided handlers or create new ones
self.message_handler = message_handler if message_handler else MessageHandler(db_manager)
self.image_handler = image_handler if image_handler else ImageHandler(api_manager)
self.tool_handler = tool_handler if tool_handler else ToolHandler(bot)
# Set this handler as the queue's message processor
self.queue_manager._message_handler = self._process_message

View File

@@ -257,8 +257,10 @@ class ToolHandler:
# Simple pattern matching for basic tool usage
# Let the LLM decide most tool usage through natural language
if "@" in line: # Basic mention support
logger.info(f"Tool Use - Parse: Detected mention pattern in line: '{line}'")
for match in re.finditer(r"@(\w+(?:\s+\w+)*)", line):
name = match.group(1).strip()
logger.info(f"Tool Use - Parse: Adding find_user tool call for '{name}'")
tool_calls.append(("find_user", {"name": name}))
command_found = True
@@ -275,6 +277,7 @@ class ToolHandler:
match = re.search(pattern, line, re.IGNORECASE)
if match:
thread_name = re.sub(pattern, name_format, match.group(1))
logger.info(f"Tool Use - Parse: Adding create_thread tool call for '{thread_name}'")
tool_calls.append(("create_thread", {
"channel_id": channel_id,
"name": thread_name,
@@ -290,6 +293,7 @@ class ToolHandler:
for match in emoji_matches:
emoji = match.group(1)
if emoji.strip():
logger.info(f"Tool Use - Parse: Adding add_reaction tool call for emoji '{emoji}'")
tool_calls.append(("add_reaction", {
"emoji": emoji,
"message_id": message_id,
@@ -307,6 +311,7 @@ class ToolHandler:
}
for pattern, emoji in emoticon_map.items():
if re.search(pattern, line):
logger.info(f"Tool Use - Parse: Converting emoticon to emoji reaction '{emoji}'")
tool_calls.append(("add_reaction", {
"emoji": emoji,
"message_id": message_id,
@@ -321,6 +326,11 @@ class ToolHandler:
# Join response lines, removing empty lines at start/end
final_response = "\n".join(response_lines).strip()
# Log summary of detected tools
if tool_calls:
logger.info(f"Tool Use - Parse: Detected {len(tool_calls)} tool calls: {[call[0] for call in tool_calls]}")
return tool_calls, final_response, self.mentioned_users
except Exception as e: