Description
If a bot has a slash command that meets these criteria, then the bot will redeclare all commands on every launch:
- The command is in a command group
- The command has no options
This is adding some friction to my development flow, due to the rate limit on command registration API.
Reproduction
import os
import hikari
import tanjun
TOKEN = os.environ["TOKEN"]
GUILD_ID = int(os.environ["GUILD_ID"])
test_group = tanjun.slash_command_group("test", "test")
@test_group.add_command
@tanjun.as_slash_command("test", "asdf")
async def test(ctx: tanjun.abc.SlashContext) -> None:
await ctx.respond("test")
component = tanjun.Component().add_slash_command(test_group)
bot = hikari.GatewayBot(token=TOKEN)
tanjun.Client.from_gateway_bot(
bot, declare_global_commands=GUILD_ID
).add_component(component)
bot.run()
Every time I run this bot, I get the log line:
I 2024-01-22 19:16:39,429 hikari.tanjun.clients: Bulk declaring 1 guild <GUILD_ID> application commands
If I add an option to test
, the bot will instead skip the command declaration after the first run:
I 2024-01-22 19:16:43,572 hikari.tanjun.clients: Skipping bulk declare for guild <GUILD_ID> application commands since they're already declared
Cause
When Tanjun starts up, it queries Discord for the currently declared commands to see if anything has changed:
|
registered_commands = await self._rest.fetch_application_commands(application, guild=guild) |
|
if _internal.cmp_all_commands(registered_commands, builders): |
The query will return something like this for test_group
in the example above:
{
"name": "test_group",
"options": [
{
"name": "test",
"options": None,
...
},
],
...
}
The internal command builder test_group
something like this instead:
{
"name": "test_group",
"options": [
{
"name": "test",
"options": [],
...
},
],
...
}
The options for the two representations will eventually compared in this line:
|
return len(opts) == len(other_opts) and all(itertools.starmap(operator.eq, zip(opts, other_opts))) |
Since they're compared directly, the discrepancy in the subcommand option representation isn't taken into account, and the check fails.