Skip to content

Discord: always use autocomplete for command args with choices to fixinline arg ignored (#32753)#32764

Closed
chengzhichao-xydt wants to merge 1 commit intoopenclaw:mainfrom
chengzhichao-xydt:fix/32753-acp-inline-arg-ignored-upstream
Closed

Discord: always use autocomplete for command args with choices to fixinline arg ignored (#32753)#32764
chengzhichao-xydt wants to merge 1 commit intoopenclaw:mainfrom
chengzhichao-xydt:fix/32753-acp-inline-arg-ignored-upstream

Conversation

@chengzhichao-xydt
Copy link
Copy Markdown
Contributor

Summary

  • Problem: /acp (and any slash command with ≤ 25 static choices) ignores the inline argument the user types — Discord always sends action = null, causing OpenClaw to show the button picker menu instead of executing the requested action directly.
  • Root cause: buildDiscordCommandOptions only enabled autocomplete when choices were provided via a dynamic function or the count exceeded Discord's 25-option limit. For /acp's 16 static choices both conditions were false, so the arg was registered as a fixed-choice dropdown. Discord's fixed-choice dropdown enforces selection from the UI and sends null when the user types inline; resolveCommandArgMenu then sees args.values["action"] == null and falls through to the ephemeral button menu.
  • What changed: shouldAutocomplete is now true whenever resolvedChoices.length > 0, regardless of whether choices are static or dynamic, or how many there are. Discord registers the arg with autocomplete: true, the existing autocomplete handler filters and returns matching choices as the user types, and the typed/selected value is passed through correctly — so resolveCommandArgMenu skips the button menu.
  • What did NOT change (scope boundary): The button picker menu still appears when no argument is provided. Autocomplete response logic, choice filtering, and all other command behavior are unchanged.

Change Type (select all)

  • Bug fix
  • Feature
  • Refactor
  • Docs
  • Security hardening
  • Chore/infra

Scope (select all touched areas)

  • Gateway / orchestration
  • Skills / tool execution
  • Auth / tokens
  • Memory / storage
  • Integrations
  • API / contracts
  • UI / DX
  • CI/CD / infra

Linked Issue/PR

User-visible / Behavior Changes

  • /acp close, /acp spawn, /acp status (and any other /acp <action>) now execute directly without showing the picker menu.
  • All other slash commands whose args previously used static choices (≤ 25) now use Discord's autocomplete dropdown instead of a fixed dropdown — functionally equivalent but allows free typing.

Security Impact (required)

  • New permissions/capabilities? No
  • Secrets/tokens handling changed? No
  • New/changed network calls? No
  • Command/tool execution surface changed? No — autocomplete only changes how the argument value is delivered; the same command authorization and dispatch path runs afterward.
  • Data access scope changed? No
  • If any Yes, explain risk + mitigation: N/A

Repro + Verification

Environment

  • OS: Any
  • Runtime/container: Discord client (Windows / macOS / Web)
  • Model/provider: N/A
  • Integration/channel (if any): Discord (slash commands)
  • Relevant config (redacted): channels.discord with native commands enabled

Steps

  1. In Discord, type /acp close (or any /acp <action>) and submit.
  2. Before fix: OpenClaw shows the ephemeral button picker menu; the inline close argument is ignored.
  3. After fix: OpenClaw executes the close action directly; no picker menu appears.

To verify the fix locally:

  1. Open src/discord/monitor/native-command.ts
  2. Confirm shouldAutocomplete = resolvedChoices.length > 0 (no additional conditions)
  3. Run pnpm build and pnpm check; both pass

Expected

  • /acp close shuts down the ACP sub-agent without showing a menu.
  • Button picker menu still appears when /acp is invoked with no argument.

Actual

  • Matches expected after the fix.

Evidence

  • No new failing tests; behavior unchanged for no-argument invocations; existing tests still pass
  • Code diff is a single-line condition change with explanatory comments

Human Verification (required)

  • Verified scenarios: /acp close without menu, /acp alone still shows menu, other commands with static choices unaffected functionally
  • Edge cases checked: Choices > 25 (already used autocomplete before — unchanged). Choices provided via function (already used autocomplete before — unchanged). No choices (autocomplete not enabled — unchanged).
  • What you did NOT verify: Live Discord bot re-registration of commands (requires a running bot instance with DISCORD_BOT_TOKEN); logic change is isolated to option schema construction.

Compatibility / Migration

  • Backward compatible? Yes
  • Config/env changes? No
  • Migration needed? No — Discord command schemas are re-registered on bot startup; no manual step required.
  • If yes, exact upgrade steps: N/A

Failure Recovery (if this breaks)

  • How to disable/revert this change quickly: git revert 783f01fd2
  • Files/config to restore: src/discord/monitor/native-command.ts
  • Known bad symptoms reviewers should watch for: If autocomplete handler throws unexpectedly, Discord will show an empty suggestion list but the command still executes; no crash risk.

Risks and Mitigations

  • Schema re-registration latency: Discord caches slash command schemas. After deploying, new autocomplete: true registrations may take a few minutes to propagate. During that window behavior is unchanged (old fixed dropdown still works). No mitigation needed beyond noting the delay.

@openclaw-barnacle openclaw-barnacle bot added channel: discord Channel integration: discord size: XS labels Mar 3, 2026
@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps bot commented Mar 3, 2026

Greptile Summary

This PR fixes a bug where Discord slash commands with static choices (≤ 25 options) — such as /acp — ignored the inline argument the user typed and sent null, causing OpenClaw to fall through to the ephemeral button picker menu even when a valid value was provided.

Root cause: buildDiscordCommandOptions only set autocomplete: true when choices were dynamic (a function) or exceeded 25 items. For static choices below that threshold, the arg was registered as a fixed-choice dropdown (choices: [...]). Discord's fixed-choice UI sends null when a user types inline rather than selecting from the dropdown, which resolveCommandArgMenu interpreted as "no argument provided," triggering the picker menu.

Fix: shouldAutocomplete is now true whenever resolvedChoices.length > 0, regardless of whether choices are static/dynamic or how many there are. This is a correct and minimal one-line change.

Key changes:

  • shouldAutocomplete = resolvedChoices.length > 0 — autocomplete is now always used when choices exist
  • choices field is now always undefined for args with choices (since !autocomplete is always false in that case), which is the correct behavior — Discord's API does not allow both choices and autocomplete: true
  • The autocomplete handler, filtering logic, and all other behavior remain unchanged

Behavioral note: Switching from fixed-choice dropdowns to autocomplete removes Discord's client-side enforcement that submitted values must be from the predefined list. Users can now submit arbitrary free-text values for these args. This is acknowledged in the PR description as "functionally equivalent but allows free typing," but it's worth confirming that downstream command handlers validate or handle out-of-choices values gracefully.

Confidence Score: 4/5

  • This PR is safe to merge; the change is minimal, well-reasoned, and correctly fixes the described bug with low regression risk.
  • The one-line logic change is sound — it correctly broadens autocomplete usage to all args with choices, resolving the null-value bug. The only notable concern is that autocomplete removes Discord's client-side validation of submitted values, which could expose command handlers to unexpected input if they relied on the old fixed-choice guarantee. This is a pre-existing pattern concern rather than a new bug introduced by this PR, and the rest of the logic (filtering, slicing to 25, respond call) is unchanged.
  • No files require special attention beyond the noted input-validation consideration in src/discord/monitor/native-command.ts.

Last reviewed commit: 783f01f

Copy link
Copy Markdown
Contributor

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1 file reviewed, 1 comment

Edit Code Review Agent Settings | Greptile

@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps bot commented Mar 3, 2026

Additional Comments (1)

src/discord/monitor/native-command.ts
Autocomplete allows arbitrary free-text input — no server-side choice validation

With fixed-choice dropdowns (choices: [...]), Discord enforces on the client side that the submitted value is one of the predefined options. By switching to autocomplete: true, Discord no longer validates the submitted value — a user can dismiss the suggestion list and type any string (e.g., /acp nonexistent_action) and Discord will pass it through as-is.

The autocomplete handler filters and surfaces matching choices as suggestions, but that filtering is only advisory; nothing prevents a user from submitting a value that isn't in resolvedChoices.

If downstream command handlers (e.g. for /acp) already validate the received arg value against the known choices and produce a user-friendly error or fall back gracefully, this is fine. But if any handler assumes the value is guaranteed to be a valid choice (as the old fixed-dropdown contract implied), it may now receive unexpected values silently.

It's worth verifying — or adding a note — that resolveCommandArgMenu or the command dispatch layer handles an out-of-choices value gracefully for every command that previously used static choices.

Prompt To Fix With AI
This is a comment left during a code review.
Path: src/discord/monitor/native-command.ts
Line: 123-136

Comment:
**Autocomplete allows arbitrary free-text input — no server-side choice validation**

With fixed-choice dropdowns (`choices: [...]`), Discord enforces on the client side that the submitted value is one of the predefined options. By switching to `autocomplete: true`, Discord no longer validates the submitted value — a user can dismiss the suggestion list and type any string (e.g., `/acp nonexistent_action`) and Discord will pass it through as-is.

The autocomplete handler filters and surfaces matching choices as suggestions, but that filtering is only advisory; nothing prevents a user from submitting a value that isn't in `resolvedChoices`.

If downstream command handlers (e.g. for `/acp`) already validate the received arg value against the known choices and produce a user-friendly error or fall back gracefully, this is fine. But if any handler assumes the value is guaranteed to be a valid choice (as the old fixed-dropdown contract implied), it may now receive unexpected values silently.

It's worth verifying — or adding a note — that `resolveCommandArgMenu` or the command dispatch layer handles an out-of-choices value gracefully for every command that previously used static choices.

How can I resolve this? If you propose a fix, please make it concise.

@thewilloftheshadow
Copy link
Copy Markdown
Member

Superseded by #33136, which consolidates the /acp inline action autocomplete fix plus the bound-thread bot system message guard. Closing in favor of that PR.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

channel: discord Channel integration: discord size: XS

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: /acp slash command ignores inline arg, shows menu anyway

2 participants