Source code for tools.discord_manage_channels

"""Create, edit, and delete Discord channels."""

from __future__ import annotations

import logging
from typing import TYPE_CHECKING

if TYPE_CHECKING:
    from tool_context import ToolContext

logger = logging.getLogger(__name__)

TOOL_NAME = "discord_manage_channels"
TOOL_DESCRIPTION = (
    "Manage Discord channels. Actions: 'create_text', "
    "'create_voice', 'create_category', 'edit', 'delete'. "
    "Requires admin permissions."
)
TOOL_PARAMETERS = {
    "type": "object",
    "properties": {
        "action": {
            "type": "string",
            "enum": [
                "create_text",
                "create_voice",
                "create_category",
                "edit",
                "delete",
            ],
            "description": "The channel management action.",
        },
        "server_id": {
            "type": "string",
            "description": (
                "Server ID (required for create actions)."
            ),
        },
        "channel_id": {
            "type": "string",
            "description": (
                "Channel ID (required for edit/delete)."
            ),
        },
        "name": {
            "type": "string",
            "description": "Channel name (for create or edit).",
        },
        "category_id": {
            "type": "string",
            "description": "Category ID to place the channel in.",
        },
        "topic": {
            "type": "string",
            "description": "Channel topic (text channels).",
        },
        "nsfw": {
            "type": "boolean",
            "description": "Mark as NSFW (text channels).",
        },
        "slowmode_delay": {
            "type": "integer",
            "description": "Slowmode in seconds (0-21600).",
        },
        "bitrate": {
            "type": "integer",
            "description": "Bitrate for voice channels.",
        },
        "user_limit": {
            "type": "integer",
            "description": "User limit for voice channels (0-99).",
        },
        "position": {
            "type": "integer",
            "description": "Position in the channel list.",
        },
    },
    "required": ["action"],
}


[docs] async def run( action: str, server_id: str | None = None, channel_id: str | None = None, name: str | None = None, category_id: str | None = None, topic: str | None = None, nsfw: bool | None = None, slowmode_delay: int | None = None, bitrate: int | None = None, user_limit: int | None = None, position: int | None = None, ctx: ToolContext | None = None, ) -> str: """Execute this tool and return the result. Args: action (str): The action value. server_id (str | None): The server id value. channel_id (str | None): Discord/Matrix channel identifier. name (str | None): Human-readable name. category_id (str | None): The category id value. topic (str | None): The topic value. nsfw (bool | None): The nsfw value. slowmode_delay (int | None): The slowmode delay value. bitrate (int | None): The bitrate value. user_limit (int | None): The user limit value. position (int | None): The position value. ctx (ToolContext | None): Tool execution context providing access to bot internals. Returns: str: Result string. """ import discord from tools._discord_helpers import ( require_discord_client, check_admin_permission, ) client = require_discord_client(ctx) if isinstance(client, str): return client user_id = ctx.user_id if ctx else "" # --- CREATE actions --- if action in ("create_text", "create_voice", "create_category"): if not server_id: return "Error: server_id is required for create actions." if not name: return "Error: name is required for create actions." ok, err = await check_admin_permission( client, user_id, server_id, ) if not ok: return err try: server = client.get_guild(int(server_id)) except ValueError: return f"Error: Invalid server ID: '{server_id}'." if not server: return f"Error: Server '{server_id}' not found." cat = None if category_id: cat = client.get_channel(int(category_id)) if not isinstance(cat, discord.CategoryChannel): return ( f"Error: '{category_id}' is not a category." ) kwargs: dict = {"name": name} if cat is not None: kwargs["category"] = cat if position is not None: kwargs["position"] = position try: if action == "create_text": if topic is not None: kwargs["topic"] = topic if nsfw is not None: kwargs["nsfw"] = nsfw if slowmode_delay is not None: kwargs["slowmode_delay"] = slowmode_delay ch = await server.create_text_channel(**kwargs) elif action == "create_voice": if bitrate is not None: kwargs["bitrate"] = bitrate if user_limit is not None: kwargs["user_limit"] = user_limit ch = await server.create_voice_channel(**kwargs) else: # create_category ch = await server.create_category_channel(**kwargs) return ( f"Successfully created '{ch.name}' " f"(ID: {ch.id}) in '{server.name}'." ) except discord.errors.Forbidden: return ( "Error: I don't have permission to create " "channels in this server." ) except discord.errors.HTTPException as exc: return f"Error creating channel: {exc}" except Exception as exc: return f"An unexpected error occurred: {exc}" # --- EDIT action --- if action == "edit": if not channel_id: return "Error: channel_id is required for edit." try: ch = client.get_channel(int(channel_id)) except ValueError: return f"Error: Invalid channel ID: '{channel_id}'." if not ch or not hasattr(ch, "edit"): return f"Error: Channel '{channel_id}' not found." guild = getattr(ch, "guild", None) if not guild: return "Error: Channel is not in a guild." ok, err = await check_admin_permission( client, user_id, str(guild.id), ) if not ok: return err kwargs = {} if name is not None: kwargs["name"] = name if position is not None: kwargs["position"] = position if isinstance(ch, discord.TextChannel): if topic is not None: kwargs["topic"] = topic if nsfw is not None: kwargs["nsfw"] = nsfw if slowmode_delay is not None: kwargs["slowmode_delay"] = slowmode_delay elif isinstance(ch, discord.VoiceChannel): if user_limit is not None: kwargs["user_limit"] = user_limit if bitrate is not None: kwargs["bitrate"] = bitrate if not kwargs: return "Error: No valid parameters provided to edit." try: await ch.edit(**kwargs) return ( f"Successfully edited channel " f"'{getattr(ch, 'name', channel_id)}'." ) except discord.errors.Forbidden: return "Error: I don't have permission to edit." except Exception as exc: return f"Error editing channel: {exc}" # --- DELETE action --- if action == "delete": if not channel_id: return "Error: channel_id is required for delete." try: ch = client.get_channel(int(channel_id)) except ValueError: return f"Error: Invalid channel ID: '{channel_id}'." if not ch or not hasattr(ch, "delete"): return f"Error: Channel '{channel_id}' not found." guild = getattr(ch, "guild", None) if not guild: return "Error: Channel is not in a guild." ok, err = await check_admin_permission( client, user_id, str(guild.id), ) if not ok: return err ch_name = getattr(ch, "name", "Unknown") try: await ch.delete() return ( f"Successfully deleted channel '{ch_name}' " f"from '{guild.name}'." ) except discord.errors.Forbidden: return "Error: I don't have permission to delete." except Exception as exc: return f"Error deleting channel: {exc}" return f"Error: Unknown action '{action}'."