Updates the Gemini 2.5 Pro model from `gemini-2.5-pro-preview-05-06` to `gemini-2.5-pro-preview-06-05` across configurations. This ensures the use of the more recent preview version of the model.
1413 lines
55 KiB
Python
1413 lines
55 KiB
Python
import discord
|
|
from discord import app_commands # Import app_commands
|
|
from discord.ext import commands
|
|
import random
|
|
import os
|
|
import time # Import time for timestamps
|
|
import json # Import json for formatting
|
|
import datetime # Import datetime for formatting
|
|
from typing import TYPE_CHECKING, Optional, Dict, Any, List, Tuple # Add more types
|
|
|
|
# Relative imports (assuming API functions are in api.py)
|
|
# We need access to the cog instance for state and methods like get_ai_response
|
|
# These commands will likely be added to the GurtCog instance dynamically in cog.py's setup
|
|
|
|
try:
|
|
from .config import AVAILABLE_AI_MODELS
|
|
except (ImportError, AttributeError):
|
|
AVAILABLE_AI_MODELS = {
|
|
"google/gemini-2.5-flash-preview-05-20": "Gemini 2.5 Flash Preview",
|
|
"google/gemini-2.5-pro-preview-06-05": "Gemini 2.5 Pro Preview",
|
|
"claude-sonnet-4@20250514": "Claude Sonnet 4",
|
|
"llama-4-maverick-17b-128e-instruct-maas": "Llama 4 Maverick Instruct",
|
|
"google/gemini-2.0-flash-001": "Gemini 2.0 Flash",
|
|
}
|
|
|
|
if TYPE_CHECKING:
|
|
from .cog import GurtCog # For type hinting
|
|
from .config import (
|
|
MOOD_OPTIONS,
|
|
IGNORED_CHANNEL_IDS,
|
|
update_ignored_channels_file,
|
|
TENOR_API_KEY,
|
|
) # Import for choices and ignored channels
|
|
from .emojis import EmojiManager # Import EmojiManager
|
|
|
|
|
|
# --- Helper Function for Embeds ---
|
|
def create_gurt_embed(
|
|
title: str, description: str = "", color=discord.Color.blue()
|
|
) -> discord.Embed:
|
|
"""Creates a standard Gurt-themed embed."""
|
|
embed = discord.Embed(title=title, description=description, color=color)
|
|
# Placeholder icon URL, replace if Gurt has one
|
|
# embed.set_footer(text="Gurt", icon_url="https://example.com/gurt_icon.png")
|
|
embed.set_footer(text="Gurt")
|
|
return embed
|
|
|
|
|
|
# --- Helper Function for Stats Embeds ---
|
|
def format_stats_embeds(stats: Dict[str, Any]) -> List[discord.Embed]:
|
|
"""Formats the collected stats into multiple embeds."""
|
|
embeds = []
|
|
main_embed = create_gurt_embed("Gurt Internal Stats", color=discord.Color.green())
|
|
ts_format = "<t:{ts}:R>" # Relative timestamp
|
|
|
|
# Runtime Stats
|
|
runtime = stats.get("runtime", {})
|
|
main_embed.add_field(
|
|
name="Current Mood",
|
|
value=f"{runtime.get('current_mood', 'N/A')} (Changed {ts_format.format(ts=int(runtime.get('last_mood_change_timestamp', 0)))})",
|
|
inline=False,
|
|
)
|
|
main_embed.add_field(
|
|
name="Background Task",
|
|
value="Running" if runtime.get("background_task_running") else "Stopped",
|
|
inline=True,
|
|
)
|
|
main_embed.add_field(
|
|
name="Needs JSON Reminder",
|
|
value=str(runtime.get("needs_json_reminder", "N/A")),
|
|
inline=True,
|
|
)
|
|
main_embed.add_field(
|
|
name="Last Evolution",
|
|
value=ts_format.format(
|
|
ts=int(runtime.get("last_evolution_update_timestamp", 0))
|
|
),
|
|
inline=True,
|
|
)
|
|
main_embed.add_field(
|
|
name="Active Topics Channels",
|
|
value=str(runtime.get("active_topics_channels", "N/A")),
|
|
inline=True,
|
|
)
|
|
main_embed.add_field(
|
|
name="Conv History Channels",
|
|
value=str(runtime.get("conversation_history_channels", "N/A")),
|
|
inline=True,
|
|
)
|
|
main_embed.add_field(
|
|
name="Thread History Threads",
|
|
value=str(runtime.get("thread_history_threads", "N/A")),
|
|
inline=True,
|
|
)
|
|
main_embed.add_field(
|
|
name="User Relationships Pairs",
|
|
value=str(runtime.get("user_relationships_pairs", "N/A")),
|
|
inline=True,
|
|
)
|
|
main_embed.add_field(
|
|
name="Cached Summaries",
|
|
value=str(runtime.get("conversation_summaries_cached", "N/A")),
|
|
inline=True,
|
|
)
|
|
main_embed.add_field(
|
|
name="Cached Channel Topics",
|
|
value=str(runtime.get("channel_topics_cached", "N/A")),
|
|
inline=True,
|
|
)
|
|
main_embed.add_field(
|
|
name="Global Msg Cache",
|
|
value=str(runtime.get("message_cache_global_count", "N/A")),
|
|
inline=True,
|
|
)
|
|
main_embed.add_field(
|
|
name="Mention Msg Cache",
|
|
value=str(runtime.get("message_cache_mentioned_count", "N/A")),
|
|
inline=True,
|
|
)
|
|
main_embed.add_field(
|
|
name="Active Convos",
|
|
value=str(runtime.get("active_conversations_count", "N/A")),
|
|
inline=True,
|
|
)
|
|
main_embed.add_field(
|
|
name="Sentiment Channels",
|
|
value=str(runtime.get("conversation_sentiment_channels", "N/A")),
|
|
inline=True,
|
|
)
|
|
main_embed.add_field(
|
|
name="Gurt Participation Topics",
|
|
value=str(runtime.get("gurt_participation_topics_count", "N/A")),
|
|
inline=True,
|
|
)
|
|
main_embed.add_field(
|
|
name="Tracked Reactions",
|
|
value=str(runtime.get("gurt_message_reactions_tracked", "N/A")),
|
|
inline=True,
|
|
)
|
|
embeds.append(main_embed)
|
|
|
|
# Memory Stats
|
|
memory_embed = create_gurt_embed("Gurt Memory Stats", color=discord.Color.orange())
|
|
memory = stats.get("memory", {})
|
|
if memory.get("error"):
|
|
memory_embed.description = f"⚠️ Error retrieving memory stats: {memory['error']}"
|
|
else:
|
|
memory_embed.add_field(
|
|
name="User Facts",
|
|
value=str(memory.get("user_facts_count", "N/A")),
|
|
inline=True,
|
|
)
|
|
memory_embed.add_field(
|
|
name="General Facts",
|
|
value=str(memory.get("general_facts_count", "N/A")),
|
|
inline=True,
|
|
)
|
|
memory_embed.add_field(
|
|
name="Chroma Messages",
|
|
value=str(memory.get("chromadb_message_collection_count", "N/A")),
|
|
inline=True,
|
|
)
|
|
memory_embed.add_field(
|
|
name="Chroma Facts",
|
|
value=str(memory.get("chromadb_fact_collection_count", "N/A")),
|
|
inline=True,
|
|
)
|
|
|
|
personality = memory.get("personality_traits", {})
|
|
if personality:
|
|
p_items = [f"`{k}`: {v}" for k, v in personality.items()]
|
|
memory_embed.add_field(
|
|
name="Personality Traits",
|
|
value="\n".join(p_items) if p_items else "None",
|
|
inline=False,
|
|
)
|
|
|
|
interests = memory.get("top_interests", [])
|
|
if interests:
|
|
i_items = [f"`{t}`: {l:.2f}" for t, l in interests]
|
|
memory_embed.add_field(
|
|
name="Top Interests",
|
|
value="\n".join(i_items) if i_items else "None",
|
|
inline=False,
|
|
)
|
|
embeds.append(memory_embed)
|
|
|
|
# API Stats
|
|
api_stats = stats.get("api_stats", {})
|
|
if api_stats:
|
|
api_embed = create_gurt_embed("Gurt API Stats", color=discord.Color.red())
|
|
for model, data in api_stats.items():
|
|
avg_time = data.get("average_time_ms", 0)
|
|
value = (
|
|
f"✅ Success: {data.get('success', 0)}\n"
|
|
f"❌ Failure: {data.get('failure', 0)}\n"
|
|
f"🔁 Retries: {data.get('retries', 0)}\n"
|
|
f"⏱️ Avg Time: {avg_time} ms\n"
|
|
f"📊 Count: {data.get('count', 0)}"
|
|
)
|
|
api_embed.add_field(name=f"Model: `{model}`", value=value, inline=True)
|
|
embeds.append(api_embed)
|
|
|
|
# Tool Stats
|
|
tool_stats = stats.get("tool_stats", {})
|
|
if tool_stats:
|
|
tool_embed = create_gurt_embed("Gurt Tool Stats", color=discord.Color.purple())
|
|
for tool, data in tool_stats.items():
|
|
avg_time = data.get("average_time_ms", 0)
|
|
value = (
|
|
f"✅ Success: {data.get('success', 0)}\n"
|
|
f"❌ Failure: {data.get('failure', 0)}\n"
|
|
f"⏱️ Avg Time: {avg_time} ms\n"
|
|
f"📊 Count: {data.get('count', 0)}"
|
|
)
|
|
tool_embed.add_field(name=f"Tool: `{tool}`", value=value, inline=True)
|
|
embeds.append(tool_embed)
|
|
|
|
# Config Stats (Less critical, maybe separate embed if needed)
|
|
config_embed = create_gurt_embed(
|
|
"Gurt Config Overview", color=discord.Color.greyple()
|
|
)
|
|
config = stats.get("config", {})
|
|
config_embed.add_field(
|
|
name="Default Model",
|
|
value=f"`{config.get('default_model', 'N/A')}`",
|
|
inline=True,
|
|
)
|
|
config_embed.add_field(
|
|
name="Fallback Model",
|
|
value=f"`{config.get('fallback_model', 'N/A')}`",
|
|
inline=True,
|
|
)
|
|
config_embed.add_field(
|
|
name="Semantic Model",
|
|
value=f"`{config.get('semantic_model_name', 'N/A')}`",
|
|
inline=True,
|
|
)
|
|
config_embed.add_field(
|
|
name="Max User Facts",
|
|
value=str(config.get("max_user_facts", "N/A")),
|
|
inline=True,
|
|
)
|
|
config_embed.add_field(
|
|
name="Max General Facts",
|
|
value=str(config.get("max_general_facts", "N/A")),
|
|
inline=True,
|
|
)
|
|
config_embed.add_field(
|
|
name="Context Window",
|
|
value=str(config.get("context_window_size", "N/A")),
|
|
inline=True,
|
|
)
|
|
config_embed.add_field(
|
|
name="API Key Set", value=str(config.get("api_key_set", "N/A")), inline=True
|
|
)
|
|
config_embed.add_field(
|
|
name="Tavily Key Set",
|
|
value=str(config.get("tavily_api_key_set", "N/A")),
|
|
inline=True,
|
|
)
|
|
config_embed.add_field(
|
|
name="Piston URL Set",
|
|
value=str(config.get("piston_api_url_set", "N/A")),
|
|
inline=True,
|
|
)
|
|
config_embed.add_field(
|
|
name="Tenor API Key Set",
|
|
value=str(config.get("tenor_api_key_set", "N/A")),
|
|
inline=True,
|
|
) # Added Tenor API Key
|
|
embeds.append(config_embed)
|
|
|
|
# Limit to 10 embeds max for Discord API
|
|
return embeds[:10]
|
|
|
|
|
|
# --- Command Setup Function ---
|
|
# This function will be called from GurtCog's setup method
|
|
def setup_commands(cog: "GurtCog"):
|
|
"""Adds Gurt-specific commands to the cog."""
|
|
|
|
# Create a list to store command functions for proper registration
|
|
command_functions = []
|
|
|
|
# --- Gurt Mood Command ---
|
|
@cog.bot.tree.command(
|
|
name="gurtmood", description="Check or set Gurt's current mood."
|
|
)
|
|
@app_commands.describe(
|
|
mood="Optional: Set Gurt's mood to one of the available options."
|
|
)
|
|
@app_commands.choices(
|
|
mood=[
|
|
app_commands.Choice(name=m, value=m)
|
|
for m in cog.MOOD_OPTIONS # Use cog's MOOD_OPTIONS
|
|
]
|
|
)
|
|
async def gurtmood(
|
|
interaction: discord.Interaction,
|
|
mood: Optional[app_commands.Choice[str]] = None,
|
|
):
|
|
"""Handles the /gurtmood command."""
|
|
# Check if user is the bot owner for mood setting
|
|
if mood and interaction.user.id != cog.bot.owner_id:
|
|
await interaction.response.send_message(
|
|
"⛔ Only the bot owner can change Gurt's mood.", ephemeral=True
|
|
)
|
|
return
|
|
|
|
if mood:
|
|
cog.current_mood = mood.value
|
|
cog.last_mood_change = time.time()
|
|
await interaction.response.send_message(
|
|
f"Gurt's mood set to: {mood.value}", ephemeral=True
|
|
)
|
|
else:
|
|
time_since_change = time.time() - cog.last_mood_change
|
|
await interaction.response.send_message(
|
|
f"Gurt's current mood is: {cog.current_mood} (Set {int(time_since_change // 60)} minutes ago)",
|
|
ephemeral=True,
|
|
)
|
|
|
|
command_functions.append(gurtmood)
|
|
|
|
# --- Gurt Memory Command ---
|
|
@cog.bot.tree.command(name="gurtmemory", description="Interact with Gurt's memory.")
|
|
@app_commands.describe(
|
|
action="Choose an action: add_user, add_general, get_user, get_general",
|
|
user="The user for user-specific actions (mention or ID).",
|
|
fact="The fact to add (for add actions).",
|
|
query="A keyword to search for (for get_general).",
|
|
)
|
|
@app_commands.choices(
|
|
action=[
|
|
app_commands.Choice(name="Add User Fact", value="add_user"),
|
|
app_commands.Choice(name="Add General Fact", value="add_general"),
|
|
app_commands.Choice(name="Get User Facts", value="get_user"),
|
|
app_commands.Choice(name="Get General Facts", value="get_general"),
|
|
]
|
|
)
|
|
async def gurtmemory(
|
|
interaction: discord.Interaction,
|
|
action: app_commands.Choice[str],
|
|
user: Optional[discord.User] = None,
|
|
fact: Optional[str] = None,
|
|
query: Optional[str] = None,
|
|
):
|
|
"""Handles the /gurtmemory command."""
|
|
await interaction.response.defer(
|
|
ephemeral=True
|
|
) # Defer for potentially slow DB operations
|
|
|
|
target_user_id = str(user.id) if user else None
|
|
action_value = action.value
|
|
|
|
# Check if user is the bot owner for modification actions
|
|
if (
|
|
action_value in ["add_user", "add_general"]
|
|
) and interaction.user.id != cog.bot.owner_id:
|
|
await interaction.followup.send(
|
|
"⛔ Only the bot owner can add facts to Gurt's memory.", ephemeral=True
|
|
)
|
|
return
|
|
|
|
if action_value == "add_user":
|
|
if not target_user_id or not fact:
|
|
await interaction.followup.send(
|
|
"Please provide both a user and a fact to add.", ephemeral=True
|
|
)
|
|
return
|
|
result = await cog.memory_manager.add_user_fact(target_user_id, fact)
|
|
await interaction.followup.send(
|
|
f"Add User Fact Result: `{json.dumps(result)}`", ephemeral=True
|
|
)
|
|
|
|
elif action_value == "add_general":
|
|
if not fact:
|
|
await interaction.followup.send(
|
|
"Please provide a fact to add.", ephemeral=True
|
|
)
|
|
return
|
|
result = await cog.memory_manager.add_general_fact(fact)
|
|
await interaction.followup.send(
|
|
f"Add General Fact Result: `{json.dumps(result)}`", ephemeral=True
|
|
)
|
|
|
|
elif action_value == "get_user":
|
|
if not target_user_id:
|
|
await interaction.followup.send(
|
|
"Please provide a user to get facts for.", ephemeral=True
|
|
)
|
|
return
|
|
facts = await cog.memory_manager.get_user_facts(
|
|
target_user_id
|
|
) # Get newest by default
|
|
if facts:
|
|
facts_str = "\n- ".join(facts)
|
|
await interaction.followup.send(
|
|
f"**Facts for {user.display_name}:**\n- {facts_str}", ephemeral=True
|
|
)
|
|
else:
|
|
await interaction.followup.send(
|
|
f"No facts found for {user.display_name}.", ephemeral=True
|
|
)
|
|
|
|
elif action_value == "get_general":
|
|
facts = await cog.memory_manager.get_general_facts(
|
|
query=query, limit=10
|
|
) # Get newest/filtered
|
|
if facts:
|
|
facts_str = "\n- ".join(facts)
|
|
# Conditionally construct the title to avoid nested f-string issues
|
|
if query:
|
|
title = f'**General Facts matching "{query}":**'
|
|
else:
|
|
title = "**General Facts:**"
|
|
await interaction.followup.send(
|
|
f"{title}\n- {facts_str}", ephemeral=True
|
|
)
|
|
else:
|
|
# Conditionally construct the message for the same reason
|
|
if query:
|
|
message = f'No general facts found matching "{query}".'
|
|
else:
|
|
message = "No general facts found."
|
|
await interaction.followup.send(message, ephemeral=True)
|
|
|
|
else:
|
|
await interaction.followup.send("Invalid action specified.", ephemeral=True)
|
|
|
|
command_functions.append(gurtmemory)
|
|
|
|
# --- Gurt Stats Command ---
|
|
@cog.bot.tree.command(
|
|
name="gurtstats", description="Display Gurt's internal statistics. (Owner only)"
|
|
)
|
|
async def gurtstats(interaction: discord.Interaction):
|
|
"""Handles the /gurtstats command."""
|
|
|
|
await interaction.response.defer(
|
|
ephemeral=True
|
|
) # Defer as stats collection might take time
|
|
try:
|
|
stats_data = await cog.get_gurt_stats()
|
|
embeds = format_stats_embeds(stats_data)
|
|
await interaction.followup.send(embeds=embeds, ephemeral=True)
|
|
except Exception as e:
|
|
print(f"Error in /gurtstats command: {e}")
|
|
import traceback
|
|
|
|
traceback.print_exc()
|
|
await interaction.followup.send(
|
|
"An error occurred while fetching Gurt's stats.", ephemeral=True
|
|
)
|
|
|
|
command_functions.append(gurtstats)
|
|
|
|
# --- Sync Gurt Commands (Owner Only) ---
|
|
@cog.bot.tree.command(
|
|
name="gurtsync", description="Sync Gurt commands with Discord (Owner only)"
|
|
)
|
|
async def gurtsync(interaction: discord.Interaction):
|
|
"""Handles the /gurtsync command to force sync commands."""
|
|
# Check if user is the bot owner
|
|
if interaction.user.id != cog.bot.owner_id:
|
|
await interaction.response.send_message(
|
|
"⛔ Only the bot owner can sync commands.", ephemeral=True
|
|
)
|
|
return
|
|
|
|
await interaction.response.defer(ephemeral=True)
|
|
try:
|
|
# Sync commands
|
|
synced = await cog.bot.tree.sync()
|
|
|
|
# Get list of commands after sync
|
|
commands_after = []
|
|
for cmd_obj in cog.bot.tree.get_commands(): # Iterate over Command objects
|
|
if cmd_obj.name.startswith("gurt"):
|
|
commands_after.append(cmd_obj.name)
|
|
|
|
await interaction.followup.send(
|
|
f"✅ Successfully synced {len(synced)} commands!\nGurt commands: {', '.join(commands_after)}",
|
|
ephemeral=True,
|
|
)
|
|
except Exception as e:
|
|
print(f"Error in /gurtsync command: {e}")
|
|
import traceback
|
|
|
|
traceback.print_exc()
|
|
await interaction.followup.send(
|
|
f"❌ Error syncing commands: {str(e)}", ephemeral=True
|
|
)
|
|
|
|
command_functions.append(gurtsync)
|
|
|
|
# --- Gurt Forget Command ---
|
|
@cog.bot.tree.command(
|
|
name="gurtforget", description="Make Gurt forget a specific fact."
|
|
)
|
|
@app_commands.describe(
|
|
scope="Choose the scope: user (for facts about a specific user) or general.",
|
|
fact="The exact fact text Gurt should forget.",
|
|
user="The user to forget a fact about (only if scope is 'user').",
|
|
)
|
|
@app_commands.choices(
|
|
scope=[
|
|
app_commands.Choice(name="User Fact", value="user"),
|
|
app_commands.Choice(name="General Fact", value="general"),
|
|
]
|
|
)
|
|
async def gurtforget(
|
|
interaction: discord.Interaction,
|
|
scope: app_commands.Choice[str],
|
|
fact: str,
|
|
user: Optional[discord.User] = None,
|
|
):
|
|
"""Handles the /gurtforget command."""
|
|
await interaction.response.defer(ephemeral=True)
|
|
|
|
scope_value = scope.value
|
|
target_user_id = str(user.id) if user else None
|
|
|
|
# Permissions Check: Allow users to forget facts about themselves, owner can forget anything.
|
|
can_forget = False
|
|
if scope_value == "user":
|
|
if target_user_id == str(
|
|
interaction.user.id
|
|
): # User forgetting their own fact
|
|
can_forget = True
|
|
elif (
|
|
interaction.user.id == cog.bot.owner_id
|
|
): # Owner forgetting any user fact
|
|
can_forget = True
|
|
elif not target_user_id:
|
|
await interaction.followup.send(
|
|
"❌ Please specify a user when forgetting a user fact.",
|
|
ephemeral=True,
|
|
)
|
|
return
|
|
elif scope_value == "general":
|
|
if (
|
|
interaction.user.id == cog.bot.owner_id
|
|
): # Only owner can forget general facts
|
|
can_forget = True
|
|
|
|
if not can_forget:
|
|
await interaction.followup.send(
|
|
"⛔ You don't have permission to forget this fact.", ephemeral=True
|
|
)
|
|
return
|
|
|
|
if not fact:
|
|
await interaction.followup.send(
|
|
"❌ Please provide the exact fact text to forget.", ephemeral=True
|
|
)
|
|
return
|
|
|
|
result = None
|
|
if scope_value == "user":
|
|
if not target_user_id: # Should be caught above, but double-check
|
|
await interaction.followup.send(
|
|
"❌ User is required for scope 'user'.", ephemeral=True
|
|
)
|
|
return
|
|
result = await cog.memory_manager.delete_user_fact(target_user_id, fact)
|
|
if result.get("status") == "deleted":
|
|
await interaction.followup.send(
|
|
f"✅ Okay, I've forgotten the fact '{fact}' about {user.display_name}.",
|
|
ephemeral=True,
|
|
)
|
|
elif result.get("status") == "not_found":
|
|
await interaction.followup.send(
|
|
f"❓ I couldn't find that exact fact ('{fact}') stored for {user.display_name}.",
|
|
ephemeral=True,
|
|
)
|
|
else:
|
|
await interaction.followup.send(
|
|
f"⚠️ Error forgetting user fact: {result.get('error', 'Unknown error')}",
|
|
ephemeral=True,
|
|
)
|
|
|
|
elif scope_value == "general":
|
|
result = await cog.memory_manager.delete_general_fact(fact)
|
|
if result.get("status") == "deleted":
|
|
await interaction.followup.send(
|
|
f"✅ Okay, I've forgotten the general fact: '{fact}'.",
|
|
ephemeral=True,
|
|
)
|
|
elif result.get("status") == "not_found":
|
|
await interaction.followup.send(
|
|
f"❓ I couldn't find that exact general fact: '{fact}'.",
|
|
ephemeral=True,
|
|
)
|
|
else:
|
|
await interaction.followup.send(
|
|
f"⚠️ Error forgetting general fact: {result.get('error', 'Unknown error')}",
|
|
ephemeral=True,
|
|
)
|
|
|
|
command_functions.append(gurtforget)
|
|
|
|
# --- Gurt Force Autonomous Action Command (Owner Only) ---
|
|
@cog.bot.tree.command(
|
|
name="gurtforceauto",
|
|
description="Force Gurt to execute an autonomous action immediately. (Owner only)",
|
|
)
|
|
async def gurtforceauto(interaction: discord.Interaction):
|
|
"""Handles the /gurtforceauto command."""
|
|
if interaction.user.id != cog.bot.owner_id:
|
|
await interaction.response.send_message(
|
|
"⛔ Only the bot owner can force autonomous actions.", ephemeral=True
|
|
)
|
|
return
|
|
await interaction.response.defer(ephemeral=True)
|
|
try:
|
|
result = await cog.force_autonomous_action()
|
|
summary = (
|
|
f"**Autonomous Action Forced:**\n"
|
|
f"**Tool:** {result.get('tool')}\n"
|
|
f"**Args:** `{result.get('args')}`\n"
|
|
f"**Reasoning:** {result.get('reasoning')}\n"
|
|
f"**Result:** {result.get('result')}"
|
|
)
|
|
await interaction.followup.send(summary, ephemeral=True)
|
|
except Exception as e:
|
|
import traceback
|
|
|
|
traceback.print_exc()
|
|
await interaction.followup.send(
|
|
f"❌ Error forcing autonomous action: {e}", ephemeral=True
|
|
)
|
|
|
|
command_functions.append(gurtforceauto) # Add gurtforceauto to the list
|
|
|
|
# --- Gurt Clear Action History Command (Owner Only) ---
|
|
@cog.bot.tree.command(
|
|
name="gurtclearhistory",
|
|
description="Clear Gurt's internal autonomous action history. (Owner only)",
|
|
)
|
|
async def gurtclearhistory(interaction: discord.Interaction):
|
|
"""Handles the /gurtclearhistory command."""
|
|
if interaction.user.id != cog.bot.owner_id:
|
|
await interaction.response.send_message(
|
|
"⛔ Only the bot owner can clear the action history.", ephemeral=True
|
|
)
|
|
return
|
|
await interaction.response.defer(ephemeral=True)
|
|
try:
|
|
result = await cog.memory_manager.clear_internal_action_logs()
|
|
if "error" in result:
|
|
await interaction.followup.send(
|
|
f"⚠️ Error clearing action history: {result['error']}",
|
|
ephemeral=True,
|
|
)
|
|
else:
|
|
await interaction.followup.send(
|
|
"✅ Gurt's autonomous action history has been cleared.",
|
|
ephemeral=True,
|
|
)
|
|
except Exception as e:
|
|
import traceback
|
|
|
|
traceback.print_exc()
|
|
await interaction.followup.send(
|
|
f"❌ An unexpected error occurred while clearing history: {e}",
|
|
ephemeral=True,
|
|
)
|
|
|
|
command_functions.append(gurtclearhistory) # Add the new command
|
|
|
|
# --- Gurt Goal Command Group ---
|
|
gurtgoal_group = app_commands.Group(
|
|
name="gurtgoal", description="Manage Gurt's long-term goals (Owner only)"
|
|
)
|
|
|
|
@gurtgoal_group.command(name="add", description="Add a new goal for Gurt.")
|
|
@app_commands.describe(
|
|
description="The description of the goal.",
|
|
priority="Priority (1=highest, 10=lowest, default=5).",
|
|
details_json="Optional JSON string for goal details (e.g., sub-tasks).",
|
|
)
|
|
async def gurtgoal_add(
|
|
interaction: discord.Interaction,
|
|
description: str,
|
|
priority: Optional[int] = 5,
|
|
details_json: Optional[str] = None,
|
|
):
|
|
if interaction.user.id != cog.bot.owner_id:
|
|
await interaction.response.send_message(
|
|
"⛔ Only the bot owner can add goals.", ephemeral=True
|
|
)
|
|
return
|
|
await interaction.response.defer(ephemeral=True)
|
|
details = None
|
|
if details_json:
|
|
try:
|
|
details = json.loads(details_json)
|
|
except json.JSONDecodeError:
|
|
await interaction.followup.send(
|
|
"❌ Invalid JSON format for details.", ephemeral=True
|
|
)
|
|
return
|
|
|
|
# Capture context from interaction
|
|
guild_id = str(interaction.guild_id) if interaction.guild_id else None
|
|
channel_id = str(interaction.channel_id) if interaction.channel_id else None
|
|
user_id = str(interaction.user.id) if interaction.user else None
|
|
|
|
result = await cog.memory_manager.add_goal(
|
|
description,
|
|
priority,
|
|
details,
|
|
guild_id=guild_id,
|
|
channel_id=channel_id,
|
|
user_id=user_id,
|
|
)
|
|
if result.get("status") == "added":
|
|
await interaction.followup.send(
|
|
f"✅ Goal added (ID: {result.get('goal_id')}): '{description}'",
|
|
ephemeral=True,
|
|
)
|
|
elif result.get("status") == "duplicate":
|
|
await interaction.followup.send(
|
|
f"⚠️ Goal '{description}' already exists (ID: {result.get('goal_id')}).",
|
|
ephemeral=True,
|
|
)
|
|
else:
|
|
await interaction.followup.send(
|
|
f"⚠️ Error adding goal: {result.get('error', 'Unknown error')}",
|
|
ephemeral=True,
|
|
)
|
|
|
|
@gurtgoal_group.command(name="list", description="List Gurt's current goals.")
|
|
@app_commands.describe(
|
|
status="Filter goals by status (e.g., pending, active).",
|
|
limit="Maximum goals to show (default 10).",
|
|
)
|
|
@app_commands.choices(
|
|
status=[
|
|
app_commands.Choice(name="Pending", value="pending"),
|
|
app_commands.Choice(name="Active", value="active"),
|
|
app_commands.Choice(name="Completed", value="completed"),
|
|
app_commands.Choice(name="Failed", value="failed"),
|
|
]
|
|
)
|
|
async def gurtgoal_list(
|
|
interaction: discord.Interaction,
|
|
status: Optional[app_commands.Choice[str]] = None,
|
|
limit: Optional[int] = 10,
|
|
):
|
|
if interaction.user.id != cog.bot.owner_id:
|
|
await interaction.response.send_message(
|
|
"⛔ Only the bot owner can list goals.", ephemeral=True
|
|
)
|
|
return
|
|
await interaction.response.defer(ephemeral=True)
|
|
status_value = status.value if status else None
|
|
limit_value = max(1, min(limit or 10, 25)) # Clamp limit
|
|
goals = await cog.memory_manager.get_goals(
|
|
status=status_value, limit=limit_value
|
|
)
|
|
if not goals:
|
|
await interaction.followup.send(
|
|
f"No goals found matching the criteria (Status: {status_value or 'any'}).",
|
|
ephemeral=True,
|
|
)
|
|
return
|
|
|
|
embed = create_gurt_embed(
|
|
f"Gurt Goals (Status: {status_value or 'All'})",
|
|
color=discord.Color.purple(),
|
|
)
|
|
for goal in goals:
|
|
details_str = (
|
|
f"\n Details: `{json.dumps(goal.get('details'))}`"
|
|
if goal.get("details")
|
|
else ""
|
|
)
|
|
created_ts = int(goal.get("created_timestamp", 0))
|
|
updated_ts = int(goal.get("last_updated", 0))
|
|
embed.add_field(
|
|
name=f"ID: {goal.get('goal_id')} | P: {goal.get('priority', '?')} | Status: {goal.get('status', '?')}",
|
|
value=f"> {goal.get('description', 'N/A')}{details_str}\n"
|
|
f"> Created: <t:{created_ts}:R> | Updated: <t:{updated_ts}:R>",
|
|
inline=False,
|
|
)
|
|
await interaction.followup.send(embed=embed, ephemeral=True)
|
|
|
|
@gurtgoal_group.command(
|
|
name="update", description="Update a goal's status, priority, or details."
|
|
)
|
|
@app_commands.describe(
|
|
goal_id="The ID of the goal to update.",
|
|
status="New status for the goal.",
|
|
priority="New priority (1=highest, 10=lowest).",
|
|
details_json="Optional: New JSON string for goal details (replaces existing).",
|
|
)
|
|
@app_commands.choices(
|
|
status=[
|
|
app_commands.Choice(name="Pending", value="pending"),
|
|
app_commands.Choice(name="Active", value="active"),
|
|
app_commands.Choice(name="Completed", value="completed"),
|
|
app_commands.Choice(name="Failed", value="failed"),
|
|
]
|
|
)
|
|
async def gurtgoal_update(
|
|
interaction: discord.Interaction,
|
|
goal_id: int,
|
|
status: Optional[app_commands.Choice[str]] = None,
|
|
priority: Optional[int] = None,
|
|
details_json: Optional[str] = None,
|
|
):
|
|
if interaction.user.id != cog.bot.owner_id:
|
|
await interaction.response.send_message(
|
|
"⛔ Only the bot owner can update goals.", ephemeral=True
|
|
)
|
|
return
|
|
await interaction.response.defer(ephemeral=True)
|
|
|
|
status_value = status.value if status else None
|
|
details = None
|
|
if details_json:
|
|
try:
|
|
details = json.loads(details_json)
|
|
except json.JSONDecodeError:
|
|
await interaction.followup.send(
|
|
"❌ Invalid JSON format for details.", ephemeral=True
|
|
)
|
|
return
|
|
|
|
if not any([status_value, priority is not None, details is not None]):
|
|
await interaction.followup.send(
|
|
"❌ You must provide at least one field to update (status, priority, or details_json).",
|
|
ephemeral=True,
|
|
)
|
|
return
|
|
|
|
result = await cog.memory_manager.update_goal(
|
|
goal_id, status=status_value, priority=priority, details=details
|
|
)
|
|
if result.get("status") == "updated":
|
|
await interaction.followup.send(
|
|
f"✅ Goal ID {goal_id} updated.", ephemeral=True
|
|
)
|
|
elif result.get("status") == "not_found":
|
|
await interaction.followup.send(
|
|
f"❓ Goal ID {goal_id} not found.", ephemeral=True
|
|
)
|
|
else:
|
|
await interaction.followup.send(
|
|
f"⚠️ Error updating goal: {result.get('error', 'Unknown error')}",
|
|
ephemeral=True,
|
|
)
|
|
|
|
@gurtgoal_group.command(name="delete", description="Delete a goal.")
|
|
@app_commands.describe(goal_id="The ID of the goal to delete.")
|
|
async def gurtgoal_delete(interaction: discord.Interaction, goal_id: int):
|
|
if interaction.user.id != cog.bot.owner_id:
|
|
await interaction.response.send_message(
|
|
"⛔ Only the bot owner can delete goals.", ephemeral=True
|
|
)
|
|
return
|
|
await interaction.response.defer(ephemeral=True)
|
|
result = await cog.memory_manager.delete_goal(goal_id)
|
|
if result.get("status") == "deleted":
|
|
await interaction.followup.send(
|
|
f"✅ Goal ID {goal_id} deleted.", ephemeral=True
|
|
)
|
|
elif result.get("status") == "not_found":
|
|
await interaction.followup.send(
|
|
f"❓ Goal ID {goal_id} not found.", ephemeral=True
|
|
)
|
|
else:
|
|
await interaction.followup.send(
|
|
f"⚠️ Error deleting goal: {result.get('error', 'Unknown error')}",
|
|
ephemeral=True,
|
|
)
|
|
|
|
# Add the command group to the bot's tree
|
|
cog.bot.tree.add_command(gurtgoal_group)
|
|
# Add group command functions to the list for tracking (optional, but good practice)
|
|
command_functions.extend(
|
|
[gurtgoal_add, gurtgoal_list, gurtgoal_update, gurtgoal_delete]
|
|
)
|
|
|
|
# --- Gurt Ignore Command Group (Owner Only) ---
|
|
gurtignore_group = app_commands.Group(
|
|
name="gurtignore",
|
|
description="Manage channels Gurt should ignore. (Owner only)",
|
|
)
|
|
|
|
@gurtignore_group.command(
|
|
name="add", description="Add a channel to Gurt's ignore list."
|
|
)
|
|
@app_commands.describe(channel="The channel or thread to ignore.")
|
|
async def gurtignore_add(
|
|
interaction: discord.Interaction, channel: discord.abc.GuildChannel
|
|
): # Use GuildChannel to accept TextChannel, Thread, etc.
|
|
if interaction.user.id != cog.bot.owner_id:
|
|
await interaction.response.send_message(
|
|
"⛔ Only the bot owner can modify the ignore list.", ephemeral=True
|
|
)
|
|
return
|
|
await interaction.response.defer(ephemeral=True)
|
|
|
|
current_ignored_ids = set(cog.IGNORED_CHANNEL_IDS) # Use cog's direct reference
|
|
if channel.id in current_ignored_ids:
|
|
await interaction.followup.send(
|
|
f"⚠️ Channel {channel.mention} is already in the ignore list.",
|
|
ephemeral=True,
|
|
)
|
|
return
|
|
|
|
current_ignored_ids.add(channel.id)
|
|
if cog.update_ignored_channels_file(
|
|
list(current_ignored_ids)
|
|
): # Use cog's direct reference, ensure it's a list
|
|
await interaction.followup.send(
|
|
f"✅ Channel {channel.mention} added to the ignore list.",
|
|
ephemeral=True,
|
|
)
|
|
else:
|
|
await interaction.followup.send(
|
|
f"❌ Failed to update the ignore list file. Check bot logs.",
|
|
ephemeral=True,
|
|
)
|
|
|
|
@gurtignore_group.command(
|
|
name="remove", description="Remove a channel from Gurt's ignore list."
|
|
)
|
|
@app_commands.describe(channel="The channel or thread to stop ignoring.")
|
|
async def gurtignore_remove(
|
|
interaction: discord.Interaction, channel: discord.abc.GuildChannel
|
|
):
|
|
if interaction.user.id != cog.bot.owner_id:
|
|
await interaction.response.send_message(
|
|
"⛔ Only the bot owner can modify the ignore list.", ephemeral=True
|
|
)
|
|
return
|
|
await interaction.response.defer(ephemeral=True)
|
|
|
|
current_ignored_ids = set(cog.IGNORED_CHANNEL_IDS) # Use cog's direct reference
|
|
if channel.id not in current_ignored_ids:
|
|
await interaction.followup.send(
|
|
f"⚠️ Channel {channel.mention} is not in the ignore list.",
|
|
ephemeral=True,
|
|
)
|
|
return
|
|
|
|
current_ignored_ids.remove(channel.id)
|
|
if cog.update_ignored_channels_file(
|
|
list(current_ignored_ids)
|
|
): # Use cog's direct reference, ensure it's a list
|
|
await interaction.followup.send(
|
|
f"✅ Channel {channel.mention} removed from the ignore list.",
|
|
ephemeral=True,
|
|
)
|
|
else:
|
|
await interaction.followup.send(
|
|
f"❌ Failed to update the ignore list file. Check bot logs.",
|
|
ephemeral=True,
|
|
)
|
|
|
|
@gurtignore_group.command(
|
|
name="list", description="List all channels Gurt is currently ignoring."
|
|
)
|
|
async def gurtignore_list(interaction: discord.Interaction):
|
|
if interaction.user.id != cog.bot.owner_id:
|
|
await interaction.response.send_message(
|
|
"⛔ Only the bot owner can view the ignore list.", ephemeral=True
|
|
)
|
|
return
|
|
await interaction.response.defer(ephemeral=True)
|
|
|
|
current_ignored_ids = cog.IGNORED_CHANNEL_IDS # Use cog's direct reference
|
|
if not current_ignored_ids:
|
|
await interaction.followup.send(
|
|
"Gurt is not currently ignoring any channels.", ephemeral=True
|
|
)
|
|
return
|
|
|
|
embed = create_gurt_embed("Ignored Channels", color=discord.Color.orange())
|
|
description_lines = []
|
|
for channel_id in current_ignored_ids:
|
|
ch = cog.bot.get_channel(channel_id)
|
|
if ch:
|
|
description_lines.append(f"- {ch.mention} (`{channel_id}`)")
|
|
else:
|
|
description_lines.append(f"- Unknown Channel (`{channel_id}`)")
|
|
|
|
embed.description = "\n".join(description_lines)
|
|
await interaction.followup.send(embed=embed, ephemeral=True)
|
|
|
|
cog.bot.tree.add_command(gurtignore_group)
|
|
command_functions.extend([gurtignore_add, gurtignore_remove, gurtignore_list])
|
|
|
|
# --- Gurt Emoji Command Group (Owner Only) ---
|
|
gurtemoji_group = app_commands.Group(
|
|
name="gurtemoji",
|
|
description="Manage Gurt's custom emoji knowledge. (Owner only)",
|
|
)
|
|
|
|
@gurtemoji_group.command(
|
|
name="add", description="Add a custom emoji to Gurt's knowledge."
|
|
)
|
|
@app_commands.describe(
|
|
name="The name of the emoji (e.g., :custom_emoji:).",
|
|
url="The URL of the emoji image.",
|
|
)
|
|
async def gurtemoji_add(interaction: discord.Interaction, name: str, url: str):
|
|
if interaction.user.id != cog.bot.owner_id:
|
|
await interaction.response.send_message(
|
|
"⛔ Only the bot owner can manage custom emojis.", ephemeral=True
|
|
)
|
|
return
|
|
await interaction.response.defer(ephemeral=True)
|
|
# Assuming cog.emoji_manager exists and has an add_emoji method
|
|
if hasattr(cog, "emoji_manager") and hasattr(cog.emoji_manager, "add_emoji"):
|
|
success = await cog.emoji_manager.add_emoji(name, url)
|
|
if success:
|
|
await interaction.followup.send(
|
|
f"✅ Emoji '{name}' added.", ephemeral=True
|
|
)
|
|
else:
|
|
await interaction.followup.send(
|
|
f"❌ Failed to add emoji '{name}'. It might already exist or there was an error.",
|
|
ephemeral=True,
|
|
)
|
|
else:
|
|
await interaction.followup.send(
|
|
"Emoji manager not available.", ephemeral=True
|
|
)
|
|
|
|
@gurtemoji_group.command(
|
|
name="remove", description="Remove a custom emoji from Gurt's knowledge."
|
|
)
|
|
@app_commands.describe(
|
|
name="The name of the emoji to remove (e.g., :custom_emoji:)."
|
|
)
|
|
async def gurtemoji_remove(interaction: discord.Interaction, name: str):
|
|
if interaction.user.id != cog.bot.owner_id:
|
|
await interaction.response.send_message(
|
|
"⛔ Only the bot owner can manage custom emojis.", ephemeral=True
|
|
)
|
|
return
|
|
await interaction.response.defer(ephemeral=True)
|
|
if hasattr(cog, "emoji_manager") and hasattr(cog.emoji_manager, "remove_emoji"):
|
|
success = await cog.emoji_manager.remove_emoji(name)
|
|
if success:
|
|
await interaction.followup.send(
|
|
f"✅ Emoji '{name}' removed.", ephemeral=True
|
|
)
|
|
else:
|
|
await interaction.followup.send(
|
|
f"❌ Failed to remove emoji '{name}'. It might not exist or there was an error.",
|
|
ephemeral=True,
|
|
)
|
|
else:
|
|
await interaction.followup.send(
|
|
"Emoji manager not available.", ephemeral=True
|
|
)
|
|
|
|
@gurtemoji_group.command(
|
|
name="list", description="List all custom emojis Gurt knows."
|
|
)
|
|
async def gurtemoji_list(interaction: discord.Interaction):
|
|
if interaction.user.id != cog.bot.owner_id:
|
|
await interaction.response.send_message(
|
|
"⛔ Only the bot owner can manage custom emojis.", ephemeral=True
|
|
)
|
|
return
|
|
await interaction.response.defer(ephemeral=True)
|
|
if hasattr(cog, "emoji_manager") and hasattr(cog.emoji_manager, "list_emojis"):
|
|
emojis = await cog.emoji_manager.list_emojis()
|
|
if emojis:
|
|
embed = create_gurt_embed(
|
|
"Known Custom Emojis", color=discord.Color.gold()
|
|
)
|
|
description = "\n".join(
|
|
[f"- {name}: {url}" for name, url in emojis.items()]
|
|
)
|
|
embed.description = description
|
|
await interaction.followup.send(embed=embed, ephemeral=True)
|
|
else:
|
|
await interaction.followup.send(
|
|
"Gurt doesn't know any custom emojis yet.", ephemeral=True
|
|
)
|
|
else:
|
|
await interaction.followup.send(
|
|
"Emoji manager not available.", ephemeral=True
|
|
)
|
|
|
|
cog.bot.tree.add_command(gurtemoji_group)
|
|
command_functions.extend([gurtemoji_add, gurtemoji_remove, gurtemoji_list])
|
|
|
|
# --- Gurt Sticker Command Group (Owner Only) ---
|
|
gurtsticker_group = app_commands.Group(
|
|
name="gurtsticker",
|
|
description="Manage Gurt's custom sticker knowledge. (Owner only)",
|
|
)
|
|
|
|
@gurtsticker_group.command(
|
|
name="add", description="Add a custom sticker to Gurt's knowledge."
|
|
)
|
|
@app_commands.describe(
|
|
name="The name of the sticker.", url="The URL of the sticker image."
|
|
)
|
|
async def gurtsticker_add(interaction: discord.Interaction, name: str, url: str):
|
|
if interaction.user.id != cog.bot.owner_id:
|
|
await interaction.response.send_message(
|
|
"⛔ Only the bot owner can manage custom stickers.", ephemeral=True
|
|
)
|
|
return
|
|
await interaction.response.defer(ephemeral=True)
|
|
if hasattr(cog, "emoji_manager") and hasattr(cog.emoji_manager, "add_sticker"):
|
|
success = await cog.emoji_manager.add_sticker(name, url)
|
|
if success:
|
|
await interaction.followup.send(
|
|
f"✅ Sticker '{name}' added.", ephemeral=True
|
|
)
|
|
else:
|
|
await interaction.followup.send(
|
|
f"❌ Failed to add sticker '{name}'. It might already exist or there was an error.",
|
|
ephemeral=True,
|
|
)
|
|
else:
|
|
await interaction.followup.send(
|
|
"Sticker manager not available.", ephemeral=True
|
|
)
|
|
|
|
@gurtsticker_group.command(
|
|
name="remove", description="Remove a custom sticker from Gurt's knowledge."
|
|
)
|
|
@app_commands.describe(name="The name of the sticker to remove.")
|
|
async def gurtsticker_remove(interaction: discord.Interaction, name: str):
|
|
if interaction.user.id != cog.bot.owner_id:
|
|
await interaction.response.send_message(
|
|
"⛔ Only the bot owner can manage custom stickers.", ephemeral=True
|
|
)
|
|
return
|
|
await interaction.response.defer(ephemeral=True)
|
|
if hasattr(cog, "emoji_manager") and hasattr(
|
|
cog.emoji_manager, "remove_sticker"
|
|
):
|
|
success = await cog.emoji_manager.remove_sticker(name)
|
|
if success:
|
|
await interaction.followup.send(
|
|
f"✅ Sticker '{name}' removed.", ephemeral=True
|
|
)
|
|
else:
|
|
await interaction.followup.send(
|
|
f"❌ Failed to remove sticker '{name}'. It might not exist or there was an error.",
|
|
ephemeral=True,
|
|
)
|
|
else:
|
|
await interaction.followup.send(
|
|
"Sticker manager not available.", ephemeral=True
|
|
)
|
|
|
|
@gurtsticker_group.command(
|
|
name="list", description="List all custom stickers Gurt knows."
|
|
)
|
|
async def gurtsticker_list(interaction: discord.Interaction):
|
|
if interaction.user.id != cog.bot.owner_id:
|
|
await interaction.response.send_message(
|
|
"⛔ Only the bot owner can manage custom stickers.", ephemeral=True
|
|
)
|
|
return
|
|
await interaction.response.defer(ephemeral=True)
|
|
if hasattr(cog, "emoji_manager") and hasattr(
|
|
cog.emoji_manager, "list_stickers"
|
|
):
|
|
stickers = await cog.emoji_manager.list_stickers()
|
|
if stickers:
|
|
embed = create_gurt_embed(
|
|
"Known Custom Stickers", color=discord.Color.dark_gold()
|
|
)
|
|
description = "\n".join(
|
|
[f"- {name}: {url}" for name, url in stickers.items()]
|
|
)
|
|
embed.description = description
|
|
await interaction.followup.send(embed=embed, ephemeral=True)
|
|
else:
|
|
await interaction.followup.send(
|
|
"Gurt doesn't know any custom stickers yet.", ephemeral=True
|
|
)
|
|
else:
|
|
await interaction.followup.send(
|
|
"Sticker manager not available.", ephemeral=True
|
|
)
|
|
|
|
cog.bot.tree.add_command(gurtsticker_group)
|
|
command_functions.extend([gurtsticker_add, gurtsticker_remove, gurtsticker_list])
|
|
|
|
# --- Gurt Tenor API Key Command (Owner Only) ---
|
|
@cog.bot.tree.command(
|
|
name="gurttenorapikey",
|
|
description="Set the Tenor API key for Gurt. (Owner only)",
|
|
)
|
|
@app_commands.describe(api_key="The Tenor API key.")
|
|
async def gurttenorapikey(interaction: discord.Interaction, api_key: str):
|
|
if interaction.user.id != cog.bot.owner_id:
|
|
await interaction.response.send_message(
|
|
"⛔ Only the bot owner can set the Tenor API key.", ephemeral=True
|
|
)
|
|
return
|
|
await interaction.response.defer(ephemeral=True)
|
|
# Assuming cog.config_manager or similar exists for updating config
|
|
if hasattr(cog, "config_manager") and hasattr(
|
|
cog.config_manager, "set_tenor_api_key"
|
|
):
|
|
await cog.config_manager.set_tenor_api_key(api_key)
|
|
# Update the cog's runtime TENOR_API_KEY if it's stored there directly or re-init relevant clients
|
|
if hasattr(cog, "TENOR_API_KEY"):
|
|
cog.TENOR_API_KEY = api_key # If cog holds it directly
|
|
# Potentially re-initialize TavilyClient or other clients if they use Tenor key indirectly
|
|
await interaction.followup.send(
|
|
"✅ Tenor API key set. You may need to reload Gurt for changes to fully apply.",
|
|
ephemeral=True,
|
|
)
|
|
else:
|
|
# Fallback: try to update config.py directly (less ideal)
|
|
# This requires careful handling of file I/O and is generally not recommended for runtime changes.
|
|
# For now, we'll assume a config_manager or direct cog attribute.
|
|
# If direct modification of config.py is needed, it's a more complex operation.
|
|
# We can also just store it in the cog instance and save it to a .env or db.
|
|
# For simplicity, let's assume it's handled by a config manager or by updating cog.TENOR_API_KEY
|
|
# and then saving that to a persistent store (e.g., in memory_manager or a dedicated config store)
|
|
try:
|
|
# This is a placeholder for a more robust config update mechanism
|
|
# In a real scenario, you'd write this to a .env file or a database
|
|
# For now, we'll just update the cog's attribute if it exists
|
|
if hasattr(cog, "TENOR_API_KEY"):
|
|
cog.TENOR_API_KEY = api_key
|
|
# Here you would also save it persistently
|
|
# e.g., await cog.memory_manager.save_setting("TENOR_API_KEY", api_key)
|
|
await interaction.followup.send(
|
|
"✅ Tenor API key updated in runtime. Save it persistently for it to survive restarts.",
|
|
ephemeral=True,
|
|
)
|
|
else:
|
|
await interaction.followup.send(
|
|
"⚠️ Tenor API key runtime attribute not found. Key not set.",
|
|
ephemeral=True,
|
|
)
|
|
|
|
except Exception as e:
|
|
await interaction.followup.send(
|
|
f"❌ Error setting Tenor API key: {e}", ephemeral=True
|
|
)
|
|
|
|
command_functions.append(gurttenorapikey)
|
|
|
|
# --- Gurt Reset Personality Command (Owner Only) ---
|
|
@cog.bot.tree.command(
|
|
name="gurtresetpersonality",
|
|
description="Reset Gurt's personality and interests to baseline. (Owner only)",
|
|
)
|
|
async def gurtresetpersonality(interaction: discord.Interaction):
|
|
"""Handles the /gurtresetpersonality command."""
|
|
if interaction.user.id != cog.bot.owner_id:
|
|
await interaction.response.send_message(
|
|
"⛔ Only the bot owner can reset Gurt's personality.", ephemeral=True
|
|
)
|
|
return
|
|
await interaction.response.defer(ephemeral=True)
|
|
try:
|
|
# Ensure the cog has access to baseline values, e.g., cog.BASELINE_PERSONALITY
|
|
# These would typically be loaded from gurt.config into the GurtCog instance
|
|
if not hasattr(cog, "BASELINE_PERSONALITY") or not hasattr(
|
|
cog, "BASELINE_INTERESTS"
|
|
):
|
|
await interaction.followup.send(
|
|
"⚠️ Baseline personality or interests not found in cog configuration. Reset aborted.",
|
|
ephemeral=True,
|
|
)
|
|
return
|
|
|
|
personality_result = await cog.memory_manager.reset_personality_to_baseline(
|
|
cog.BASELINE_PERSONALITY
|
|
)
|
|
interests_result = await cog.memory_manager.reset_interests_to_baseline(
|
|
cog.BASELINE_INTERESTS
|
|
)
|
|
|
|
messages = []
|
|
if personality_result.get("status") == "success":
|
|
messages.append("✅ Personality traits reset to baseline.")
|
|
else:
|
|
messages.append(
|
|
f"⚠️ Error resetting personality: {personality_result.get('error', 'Unknown error')}"
|
|
)
|
|
|
|
if interests_result.get("status") == "success":
|
|
messages.append("✅ Interests reset to baseline.")
|
|
else:
|
|
messages.append(
|
|
f"⚠️ Error resetting interests: {interests_result.get('error', 'Unknown error')}"
|
|
)
|
|
|
|
await interaction.followup.send("\n".join(messages), ephemeral=True)
|
|
|
|
except Exception as e:
|
|
import traceback
|
|
|
|
traceback.print_exc()
|
|
await interaction.followup.send(
|
|
f"❌ An unexpected error occurred while resetting personality: {e}",
|
|
ephemeral=True,
|
|
)
|
|
|
|
command_functions.append(gurtresetpersonality)
|
|
|
|
# --- Gurt Model Command (Owner Only) ---
|
|
@cog.bot.tree.command(
|
|
name="gurtmodel",
|
|
description="Change Gurt's active AI model dynamically. (Owner only)",
|
|
)
|
|
@app_commands.describe(model="The AI model to switch to.")
|
|
@app_commands.choices(
|
|
model=[
|
|
app_commands.Choice(name=friendly_name, value=model_id)
|
|
for model_id, friendly_name in AVAILABLE_AI_MODELS.items()
|
|
]
|
|
)
|
|
async def gurtmodel(
|
|
interaction: discord.Interaction, model: app_commands.Choice[str]
|
|
):
|
|
"""Handles the /gurtmodel command."""
|
|
if interaction.user.id != cog.bot.owner_id:
|
|
await interaction.response.send_message(
|
|
"⛔ Only the bot owner can change Gurt's AI model.", ephemeral=True
|
|
)
|
|
return
|
|
|
|
await interaction.response.defer(ephemeral=False)
|
|
try:
|
|
new_model_id = model.value
|
|
new_model_friendly_name = model.name
|
|
|
|
# Update the cog's default model
|
|
cog.default_model = new_model_id
|
|
|
|
# Optionally, update the config file if you want this change to persist across restarts
|
|
# This would require a function in config.py to update DEFAULT_MODEL in the .env or a separate config file
|
|
# For now, we'll just update the runtime attribute.
|
|
# If persistence is desired, you'd add something like:
|
|
# await cog.config_manager.set_default_model(new_model_id) # Assuming a config_manager exists
|
|
|
|
await interaction.followup.send(
|
|
f"✅ Gurt's AI model has been changed to: **{new_model_friendly_name}** (`{new_model_id}`).",
|
|
ephemeral=False,
|
|
)
|
|
except Exception as e:
|
|
print(f"Error in /gurtmodel command: {e}")
|
|
import traceback
|
|
|
|
traceback.print_exc()
|
|
await interaction.followup.send(
|
|
"❌ An error occurred while changing Gurt's AI model.", ephemeral=True
|
|
)
|
|
|
|
command_functions.append(gurtmodel)
|
|
|
|
# --- Gurt Get Model Command ---
|
|
@cog.bot.tree.command(
|
|
name="gurtgetmodel", description="Display Gurt's currently active AI model."
|
|
)
|
|
async def gurtgetmodel(interaction: discord.Interaction):
|
|
"""Handles the /gurtgetmodel command."""
|
|
await interaction.response.defer(ephemeral=False)
|
|
try:
|
|
current_model_id = cog.default_model
|
|
# Try to get the friendly name from AVAILABLE_AI_MODELS
|
|
friendly_name = AVAILABLE_AI_MODELS.get(
|
|
current_model_id, current_model_id
|
|
) # Fallback to ID if not found
|
|
|
|
await interaction.followup.send(
|
|
f"Gurt is currently using AI model: **{friendly_name}** (`{current_model_id}`).",
|
|
ephemeral=False,
|
|
)
|
|
except Exception as e:
|
|
print(f"Error in /gurtgetmodel command: {e}")
|
|
import traceback
|
|
|
|
traceback.print_exc()
|
|
await interaction.followup.send(
|
|
"❌ An error occurred while fetching Gurt's current AI model.",
|
|
ephemeral=True,
|
|
)
|
|
|
|
command_functions.append(gurtgetmodel)
|
|
|
|
# Get command names safely - Command objects don't have __name__ attribute
|
|
command_names = []
|
|
for func in command_functions:
|
|
# For app commands, use the name attribute directly
|
|
if hasattr(func, "name"):
|
|
command_names.append(func.name)
|
|
# For regular functions, use __name__
|
|
elif hasattr(func, "__name__"):
|
|
command_names.append(func.__name__)
|
|
else:
|
|
command_names.append(str(func))
|
|
|
|
print(f"Gurt commands setup in cog: {command_names}")
|
|
|
|
# Return the command functions for proper registration
|
|
return command_functions
|