mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-07-15 14:22:43 +00:00
fix(discord): cap slash commands at Discord's 100-command limit
Discord enforces a hard cap of 100 global application commands per app.
The adapter registers ~27 native commands plus every gateway-available
entry in COMMAND_REGISTRY plus all plugin commands plus the consolidated
/skill group. On a loaded install (many plugins/quick commands) the
desired set exceeds 100, so tree.sync() / _safe_sync_slash_commands()
hits error 30032 ("Maximum number of application commands reached") and
Discord rejects the ENTIRE batch — silently breaking every slash command,
not just the overflow.
Cap registration at the 100-command limit: native commands (registered
first, highest priority) and the /skill group are always kept; lower-
priority auto-registered COMMAND_REGISTRY and plugin commands are added
only until the cap is reached, with a single concise warning telling the
user how to surface the rest. Since both sync paths read from
tree.get_commands(), bounding the tree fixes the root cause for both.
This commit is contained in:
parent
e4f98d2323
commit
1f407057a8
1 changed files with 31 additions and 0 deletions
|
|
@ -31,6 +31,12 @@ _DISCORD_COMMAND_SYNC_STATE_SUBDIR = "gateway"
|
|||
_DISCORD_COMMAND_SYNC_STATE_FILENAME = "discord_command_sync_state.json"
|
||||
_DISCORD_COMMAND_SYNC_MUTATION_INTERVAL_SECONDS = 4.5
|
||||
_DISCORD_COMMAND_SYNC_MAX_RATE_LIMIT_SLEEP_SECONDS = 30.0
|
||||
# Discord enforces a hard cap of 100 global application (slash) commands per
|
||||
# app. Registering more makes the ENTIRE sync fail with error 30032
|
||||
# ("Maximum number of application commands reached"), which silently breaks
|
||||
# every slash command — not just the overflow ones. We keep the desired set
|
||||
# at or below this limit at registration time.
|
||||
_DISCORD_MAX_APP_COMMANDS = 100
|
||||
|
||||
try:
|
||||
import discord
|
||||
|
|
@ -3518,6 +3524,11 @@ class DiscordAdapter(BasePlatformAdapter):
|
|||
)
|
||||
|
||||
already_registered: set[str] = set()
|
||||
# Native commands above are registered first and are the highest
|
||||
# priority, so they always survive the 100-command cap. Reserve one
|
||||
# slot for the consolidated ``/skill`` group registered further below.
|
||||
slot_cap = _DISCORD_MAX_APP_COMMANDS - 1
|
||||
dropped_over_cap = 0
|
||||
try:
|
||||
from hermes_cli.commands import COMMAND_REGISTRY, _is_gateway_available, _resolve_config_gates
|
||||
|
||||
|
|
@ -3535,6 +3546,9 @@ class DiscordAdapter(BasePlatformAdapter):
|
|||
discord_name = cmd_def.name.lower()[:32]
|
||||
if discord_name in already_registered:
|
||||
continue
|
||||
if len(already_registered) >= slot_cap:
|
||||
dropped_over_cap += 1
|
||||
continue
|
||||
auto_cmd = _build_auto_slash_command(
|
||||
cmd_def.name,
|
||||
cmd_def.description,
|
||||
|
|
@ -3567,6 +3581,9 @@ class DiscordAdapter(BasePlatformAdapter):
|
|||
discord_name = plugin_name.lower()[:32]
|
||||
if discord_name in already_registered:
|
||||
continue
|
||||
if len(already_registered) >= slot_cap:
|
||||
dropped_over_cap += 1
|
||||
continue
|
||||
auto_cmd = _build_auto_slash_command(
|
||||
plugin_name,
|
||||
plugin_desc,
|
||||
|
|
@ -3589,6 +3606,20 @@ class DiscordAdapter(BasePlatformAdapter):
|
|||
# supporting up to 25 categories × 25 skills = 625 skills.
|
||||
self._register_skill_group(tree)
|
||||
|
||||
if dropped_over_cap:
|
||||
# Staying under the cap keeps the whole sync succeeding; without
|
||||
# this guard a single over-limit command makes Discord reject the
|
||||
# entire batch (error 30032), breaking every slash command.
|
||||
logger.warning(
|
||||
"[%s] Reached Discord's limit of %d slash commands; skipped %d "
|
||||
"lower-priority command(s) to keep the command sync working. "
|
||||
"Disable slash commands you don't need or trim installed plugins "
|
||||
"to surface them all.",
|
||||
self.name,
|
||||
_DISCORD_MAX_APP_COMMANDS,
|
||||
dropped_over_cap,
|
||||
)
|
||||
|
||||
# Optional defense-in-depth: hide every slash command from non-admin
|
||||
# guild members in Discord's slash picker. Server-side authorization
|
||||
# (``_check_slash_authorization``) is the actual gate; this is purely
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue