Update README with environment variable configuration and bot command details; enhance event and tool handler initialization
This commit is contained in:
101
README.md
101
README.md
@@ -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
|
||||
|
||||
|
||||
Binary file not shown.
@@ -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__":
|
||||
|
||||
Binary file not shown.
Binary file not shown.
@@ -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
|
||||
|
||||
@@ -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:
|
||||
|
||||
Reference in New Issue
Block a user