Slash Commands
A slash command is one of the types of client-integrated interactions a bot can create. Unlike prefix commands, these do not require the message content intent.
This section will go in-depth on the creation, types and handling of slash commands with disnake
.
A bot needs to be authorized with the applications.commands
scope in order to create slash commands in a guild. We recommend adding this scope to your bot invite links.
Defining slash commands
To create a slash command, use the @Bot.slash_command
decorator.
@bot.slash_command(
name="ping",
description="Returns websocket latency.",
)
async def ping(inter: disnake.ApplicationCommandInteraction):
...
If you're using cogs, the @commands.slash_command
decorator should be used instead.
class Meta(commands.Cog):
"""Meta commands."""
@commands.slash_command(
name="ping",
description="Returns websocket latency.",
)
async def ping(self, inter: disnake.ApplicationCommandInteraction):
...
Parameters
While some commands can exist without arguments, most commands will need to take user input to be useful. Adding an option is as simple as defining a parameter on the callback.
Here's an example of a command with one integer option (without a description):
@bot.slash_command(description="Multiplies the number by 7")
async def multiply(inter, number: int):
await inter.response.send_message(number * 7)
To make a parameter optional, provide a default value for the option:
@bot.slash_command(description="Multiplies the number by a multiplier")
async def multiply(inter, number: int, multiplier: int = 7):
await inter.response.send_message(number * multiplier)
Registering commands
Unlike prefix commands, slash commands must be registered with Discord first, otherwise they won't show up if you press "/". By default, the library registers and updates your slash commands automatically. It does so on bot start or when cogs are loaded, unloaded, or reloaded.
The library avoids unnecessary API requests during this process. If the registered commands match the commands in your code, no API requests are made. Otherwise only one bulk overwrite request is done.
If you want to disable the automatic registration, set the sync_commands
parameter of commands.Bot
to False
.
If you want to see how exactly the list of registered commands changes, set the sync_commands_debug
parameter to True
.
bot = commands.Bot("!", sync_commands_debug=True)
It will print (or use the logger, if enabled) which commands were added, edited, deleted or left untouched.
Global commands
Global slash commands are visible everywhere, including your bot DMs.
If you don't specify the test_guilds
parameter of commands.Bot
, all your slash commands are global by default.
Global commands are visible and usable on most devices right away.
Guild commands
If you specify the test_guilds
parameter of commands.Bot
, all slash commands in your code are no longer global.
The following code will register all slash commands only in 2 guilds:
bot = commands.Bot("!", test_guilds=[123456789, 987654321]) # guild IDs
If you want to keep some of your slash commands global and make some of them local, specify the guild_ids
parameter of @bot.slash_command()
:
bot = commands.Bot("!")
@bot.slash_command()
async def global_command(inter):
"""This command is visible everywhere"""
...
@bot.slash_command(guild_ids=[123456789])
async def local_command(inter):
"""This command is visible in one guild"""
...
Responding to commands
Sending responses
The response
attribute returns a InteractionResponse
instance that has four ways of responding to an ApplicationCommandInteraction.
A response can only be done once.
If you want to send secondary messages, consider using a followup
webhook instead.
An interaction can only be responded to once. After a response is made, no more responses can be made. See the followup object for sending messages after responding.
send_message
- Sends response message.edit_message
- Edits message, for example in component or component+modal interactions. Cannot be used with application commands.defer
- Defers the interaction.send_modal
- Sends aModal
as a response.
If you're going to run long processes (more than 3 seconds) before responding, you should first defer
the interaction,
as interactions expire after 3 seconds and later responses will fail.
Deferring an interaction response shows a loading indicator to the user, and gives you more time to prepare a complete response.
Once your response is ready, you can edit the original response using the Interaction.edit_original_response
method.
@bot.slash_command()
async def ping(inter: ApplicationCommandInteraction):
await inter.response.send_message("Pong!")
@bot.slash_command()
async def defer(inter: ApplicationCommandInteraction):
await inter.response.defer()
await asyncio.sleep(10)
await inter.edit_original_response(content="The wait is over, my comrades!")
Followups
Followups are a way to send a message after responding. There are two important restrictions for when a followup can be used:
- The interaction must have been responded to (see responding).
- The interaction must not be expired (i.e. hasn't exceeded the 15 minute limit).
Checking if an interaction has expired can be done with
ApplicationCommandInteraction.is_expired
.
At their core, followups are simply Webhook
instances. The only special thing about them is that the wait
parameter is treated as if it is always set to True
.
Take this as an example of how followups could be used:
@bot.slash_command()
async def timer(inter: disnake.ApplicationCommandInteraction, seconds: int):
await inter.response.send_message(f"Setting a timer for {seconds} seconds.")
await asyncio.sleep(seconds)
await inter.followup.send(f"{inter.author.mention}, your timer expired!")