From 2d3dc06fdf992a9dff34d719561fe1d427c265ff Mon Sep 17 00:00:00 2001 From: mruwnik Date: Mon, 3 Nov 2025 11:11:19 +0000 Subject: [PATCH] tool to set up discord bot --- src/memory/discord/collector.py | 6 +- src/memory/discord/messages.py | 2 +- tools/discord_setup.py | 108 ++++++++++++++++++++++++++++++-- 3 files changed, 106 insertions(+), 10 deletions(-) diff --git a/src/memory/discord/collector.py b/src/memory/discord/collector.py index fb03436..e842c06 100644 --- a/src/memory/discord/collector.py +++ b/src/memory/discord/collector.py @@ -246,8 +246,8 @@ class MessageCollector(commands.Bot): async def on_ready(self): """Called when bot connects to Discord""" - logger.info(f"Discord collector connected as {self.user}") - logger.info(f"Connected to {len(self.guilds)} servers") + logger.error(f"Discord collector connected as {self.user}") + logger.error(f"Connected to {len(self.guilds)} servers") # Sync server and channel metadata await self.sync_servers_and_channels() @@ -257,7 +257,7 @@ class MessageCollector(commands.Bot): except Exception as exc: # pragma: no cover - defensive logger.error("Failed to sync slash commands: %s", exc) - logger.info("Discord message collector ready") + logger.error("Discord message collector ready") async def on_message(self, message: discord.Message): """Queue incoming message for database storage""" diff --git a/src/memory/discord/messages.py b/src/memory/discord/messages.py index 42a3230..9d6c810 100644 --- a/src/memory/discord/messages.py +++ b/src/memory/discord/messages.py @@ -269,7 +269,7 @@ def call_llm( return provider.run_with_tools( messages=provider.as_messages(message_content), tools=tools, - system_prompt=bot_user.system_prompt + "\n\n" + system_prompt, + system_prompt=(bot_user.system_prompt or "") + "\n\n" + (system_prompt or ""), mcp_servers=mcp_servers, max_iterations=settings.DISCORD_MAX_TOOL_CALLS, ).response diff --git a/tools/discord_setup.py b/tools/discord_setup.py index d7ab5b6..12495cc 100644 --- a/tools/discord_setup.py +++ b/tools/discord_setup.py @@ -1,8 +1,14 @@ -import argparse import click import requests +def make_invite(client_id: str | int) -> str: + permissions = 2048 + 16 + 1024 # = 3088 + + invite_url = f"https://discord.com/oauth2/authorize?client_id={str(client_id)}&scope=bot&permissions={permissions}" + return invite_url + + @click.command() @click.option("--bot-token", type=str, required=True) def generate_bot_invite_url(bot_token: str): @@ -25,12 +31,8 @@ def generate_bot_invite_url(bot_token: str): except Exception as e: raise ValueError(f"Could not get bot info: {e}") - # Permissions needed: Send Messages (2048) + Manage Channels (16) + View Channels (1024) - permissions = 2048 + 16 + 1024 # = 3088 - - invite_url = f"https://discord.com/oauth2/authorize?client_id={client_id}&scope=bot&permissions={permissions}" + invite_url = make_invite(client_id) click.echo(f"Bot invite URL: {invite_url}") - return invite_url @click.command() @@ -43,6 +45,99 @@ def create_channels(): click.echo("Discord channels setup completed.") +@click.command() +@click.option("--bot-token", type=str, required=True, help="Discord bot token") +def add_bot_user(bot_token: str): + """Add a Discord bot user to the system by fetching bot info from Discord API.""" + from memory.common.db.connection import make_session + from memory.common.db.models import DiscordUser, DiscordServer, DiscordBotUser + + # Fetch bot information from Discord API + try: + headers = {"Authorization": f"Bot {bot_token}"} + response = requests.get( + "https://discord.com/api/v10/users/@me", headers=headers + ) + response.raise_for_status() + bot_info = response.json() + + discord_id = int(bot_info["id"]) + username = bot_info["username"] + display_name = bot_info.get("global_name") + discriminator = bot_info.get("discriminator", "0") + + # Use discriminator if it's not "0" (new username system uses "0") + if discriminator != "0": + username = f"{username}#{discriminator}" + + except Exception as e: + click.echo(f"Error: Could not fetch bot info from Discord API: {e}") + return + + # Create email and name from Discord info + email = f"{username.replace('#', '_')}@discord.bot" + name = display_name or username + + with make_session() as session: + # Get or create DiscordUser + discord_user = ( + session.query(DiscordUser).filter(DiscordUser.id == discord_id).first() + ) + if discord_user: + click.echo(f"Found existing Discord user: {discord_user.username}") + # Update username and display_name in case they changed + discord_user.username = username + discord_user.display_name = display_name + else: + discord_user = DiscordUser( + id=discord_id, + username=username, + display_name=display_name, + ) + session.add(discord_user) + click.echo(f"Created new Discord user: {username}") + + # Get or create DiscordBotUser (search by api_key) + bot_user = ( + session.query(DiscordBotUser) + .filter(DiscordBotUser.api_key == bot_token) + .first() + ) + if bot_user: + click.echo(f"Found existing bot user: {bot_user.name}") + # Update email and name in case they changed + bot_user.email = email + bot_user.name = name + # Ensure they're connected + if discord_user not in bot_user.discord_users: + bot_user.discord_users.append(discord_user) + click.echo("Linked Discord user to bot user") + else: + bot_user = DiscordBotUser.create_with_api_key( + discord_users=[discord_user], + name=name, + email=email, + api_key=bot_token, + ) + session.add(bot_user) + click.echo(f"Created new bot user: {name}") + click.echo("Linked Discord user to bot user") + + session.commit() + + click.echo("\n✓ Successfully configured Discord bot user:") + click.echo(f" Bot Name: {bot_user.name}") + click.echo(f" Bot Email: {bot_user.email}") + click.echo(f" API Key: {bot_user.api_key}") + click.echo(f" Discord ID: {discord_user.id}") + click.echo(f" Discord Username: {discord_user.username}") + if display_name: + click.echo(f" Discord Display Name: {display_name}") + + click.echo("\n\nTo add the bot to your server, click the link below:") + click.echo(f"Bot invite URL: {make_invite(discord_id)}") + + @click.group() def cli(): """Discord setup utilities.""" @@ -51,6 +146,7 @@ def cli(): cli.add_command(generate_bot_invite_url, name="generate-invite") cli.add_command(create_channels, name="create-channels") +cli.add_command(add_bot_user, name="add-bot-user") if __name__ == "__main__":