Source code for tools.discord_voice_states

"""Query who is currently connected to voice channels in a Discord server."""

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 = "get_voice_states"
TOOL_DESCRIPTION = (
    "List all voice channels in a Discord server and the members "
    "currently connected to each one. Useful for situational awareness "
    "of who is hanging out in voice chat."
)
TOOL_PARAMETERS = {
    "type": "object",
    "properties": {
        "server_id": {
            "type": "string",
            "description": (
                "The Discord server (guild) ID. If omitted, uses "
                "the server the message was sent in."
            ),
        },
    },
    "required": [],
}


[docs] async def run( server_id: str | None = None, ctx: ToolContext | None = None, ) -> str: """Return a formatted list of voice channels and their connected members. Args: server_id: Discord guild ID. Falls back to the context guild. ctx: Tool execution context. Returns: Formatted string describing voice channel occupancy. """ from tools._discord_helpers import require_discord_client client = require_discord_client(ctx) if isinstance(client, str): return client # Resolve guild guild = None if server_id: try: guild = client.get_guild(int(server_id)) except ValueError: return f"Error: Invalid server ID: '{server_id}'." elif ctx and ctx.server_id: try: guild = client.get_guild(int(ctx.server_id)) except (ValueError, TypeError): pass if guild is None: return "Error: Could not resolve a server. Please provide a server_id." lines = [f"**Voice Channel States for '{guild.name}'**\n"] occupied = 0 for vc in sorted(guild.voice_channels, key=lambda c: c.position): members = vc.members if members: occupied += 1 member_lines = [] for m in members: parts = [m.display_name] vs = m.voice if vs: if vs.self_mute or vs.mute: parts.append("🔇") if vs.self_deaf or vs.deaf: parts.append("🔕") if vs.self_stream: parts.append("📺") if vs.self_video: parts.append("📹") member_lines.append(" • " + " ".join(parts)) lines.append(f"🔊 **{vc.name}** ({len(members)} connected)") lines.extend(member_lines) else: lines.append(f"🔇 **{vc.name}** (empty)") total_vc = len(guild.voice_channels) lines.append( f"\n{occupied}/{total_vc} voice channels occupied, " f"{sum(len(vc.members) for vc in guild.voice_channels)} total users in voice." ) return "\n".join(lines)