Source code for tools.discord_poll

"""Create a native Discord poll in a channel."""

from __future__ import annotations

import logging
from datetime import timedelta
from typing import TYPE_CHECKING

if TYPE_CHECKING:
    from tool_context import ToolContext

logger = logging.getLogger(__name__)

TOOL_NAME = "create_poll"
TOOL_DESCRIPTION = (
    "Create a native Discord poll in a channel. Polls appear as "
    "interactive vote widgets. Great for driving channel engagement "
    "and gathering community opinions."
)
TOOL_PARAMETERS = {
    "type": "object",
    "properties": {
        "question": {
            "type": "string",
            "description": "The poll question (max 300 characters).",
        },
        "answers": {
            "type": "array",
            "items": {"type": "string"},
            "description": (
                "List of answer options (2-10 items, each max 55 characters)."
            ),
        },
        "channel_id": {
            "type": "string",
            "description": (
                "Channel to post the poll in. If omitted, uses the "
                "current channel."
            ),
        },
        "duration_hours": {
            "type": "integer",
            "description": (
                "How long the poll stays open, in hours "
                "(1-168, default 24)."
            ),
        },
        "allow_multiselect": {
            "type": "boolean",
            "description": (
                "Whether users can vote for multiple options "
                "(default false)."
            ),
        },
    },
    "required": ["question", "answers"],
}


[docs] async def run( question: str, answers: list[str], channel_id: str | None = None, duration_hours: int = 24, allow_multiselect: bool = False, ctx: ToolContext | None = None, ) -> str: """Create and send a Discord poll. Args: question: The poll question text. answers: List of answer option strings. channel_id: Target channel ID. Falls back to context channel. duration_hours: Poll duration in hours (1-168). allow_multiselect: Allow voting for multiple options. ctx: Tool execution context. Returns: Result string. """ import discord from tools._discord_helpers import require_discord_client client = require_discord_client(ctx) if isinstance(client, str): return client # --- Validate inputs --- if not question or len(question) > 300: return "Error: Question must be 1-300 characters." if not answers or len(answers) < 2: return "Error: At least 2 answer options are required." if len(answers) > 10: return "Error: Maximum 10 answer options allowed." for i, a in enumerate(answers): if not a or len(a) > 55: return f"Error: Answer {i + 1} must be 1-55 characters." duration_hours = max(1, min(168, duration_hours)) # --- Resolve channel --- channel = None if channel_id: try: channel = client.get_channel(int(channel_id)) except ValueError: return f"Error: Invalid channel ID: '{channel_id}'." if channel is None: try: channel = await client.fetch_channel(int(channel_id)) except Exception: return f"Error: Channel '{channel_id}' not found." elif ctx and ctx.channel_id: try: channel = client.get_channel(int(ctx.channel_id)) except (ValueError, TypeError): pass if channel is None: return "Error: Could not resolve a channel. Please provide a channel_id." if not hasattr(channel, "send"): return f"Error: Channel '{channel_id or ctx.channel_id}' is not a text channel." # --- Build and send the poll --- try: poll = discord.Poll( question=question, duration=timedelta(hours=duration_hours), multiple=allow_multiselect, ) for answer_text in answers: poll.add_answer(text=answer_text) await channel.send(poll=poll) ch_name = getattr(channel, "name", str(channel.id)) return ( f"Poll created in #{ch_name}!\n" f"Question: {question}\n" f"Options: {', '.join(answers)}\n" f"Duration: {duration_hours}h | " f"Multi-select: {'yes' if allow_multiselect else 'no'}" ) except discord.Forbidden: return "Error: No permission to send polls in this channel." except AttributeError: return ( "Error: discord.Poll is not available. " "This requires discord.py 2.4 or newer." ) except Exception as exc: logger.exception("Failed to create poll") return f"Error creating poll: {exc}"