-
-
Notifications
You must be signed in to change notification settings - Fork 80.7k
Plugin slash commands aren't dispatched in openclaw agent (--local and gateway) or TUI #78347
Copy link
Copy link
Open
Labels
P2Normal backlog priority with limited blast radius.Normal backlog priority with limited blast radius.clawsweeper:fix-shape-clearClawSweeper found a clear likely implementation shape for this issue.ClawSweeper found a clear likely implementation shape for this issue.clawsweeper:needs-maintainer-reviewClawSweeper marked this issue as needing maintainer review before automation.ClawSweeper marked this issue as needing maintainer review before automation.clawsweeper:needs-product-decisionClawSweeper marked this issue as needing a product or behavior decision.ClawSweeper marked this issue as needing a product or behavior decision.clawsweeper:no-new-fix-prClawSweeper does not recommend queueing a new automated fix PR for this issue.ClawSweeper does not recommend queueing a new automated fix PR for this issue.clawsweeper:source-reproClawSweeper found a high-confidence source-level issue reproduction.ClawSweeper found a high-confidence source-level issue reproduction.impact:otherThis issue has meaningful maintainer-visible impact outside the owned taxonomy.This issue has meaningful maintainer-visible impact outside the owned taxonomy.issue-rating: 🦞 diamond lobsterVery strong issue quality with high-confidence source-level or clear reproduction.Very strong issue quality with high-confidence source-level or clear reproduction.staleMarked as stale due to inactivityMarked as stale due to inactivity
Description
Metadata
Metadata
Assignees
Labels
P2Normal backlog priority with limited blast radius.Normal backlog priority with limited blast radius.clawsweeper:fix-shape-clearClawSweeper found a clear likely implementation shape for this issue.ClawSweeper found a clear likely implementation shape for this issue.clawsweeper:needs-maintainer-reviewClawSweeper marked this issue as needing maintainer review before automation.ClawSweeper marked this issue as needing maintainer review before automation.clawsweeper:needs-product-decisionClawSweeper marked this issue as needing a product or behavior decision.ClawSweeper marked this issue as needing a product or behavior decision.clawsweeper:no-new-fix-prClawSweeper does not recommend queueing a new automated fix PR for this issue.ClawSweeper does not recommend queueing a new automated fix PR for this issue.clawsweeper:source-reproClawSweeper found a high-confidence source-level issue reproduction.ClawSweeper found a high-confidence source-level issue reproduction.impact:otherThis issue has meaningful maintainer-visible impact outside the owned taxonomy.This issue has meaningful maintainer-visible impact outside the owned taxonomy.issue-rating: 🦞 diamond lobsterVery strong issue quality with high-confidence source-level or clear reproduction.Very strong issue quality with high-confidence source-level or clear reproduction.staleMarked as stale due to inactivityMarked as stale due to inactivity
Type
Fields
Priority
None yet
Summary
Plugin-registered slash commands (
api.registerCommand({ name: "remember", ... })) are correctly persisted to the central registry but never fire when the user runsopenclaw agent --message "/remember ...". Both the--local(embedded) and gateway agent paths take the message verbatim and hand it to the LLM without ever calling the plugin command dispatcher. The TUI behaves the same way.This is an OpenClaw core gap, not a plugin gap. Slash commands work fine in the channels that wire dispatch up themselves (Telegram, Discord, and any channel routed through the auto-reply pipeline), but the agent CLI surface is missing the equivalent hook.
Reproduction
With any plugin that registers a slash command (e.g.
@maximem/memory-pluginexposes/rememberand/recall):Expected: the
/recallhandler fires, returns its reply.Actual:
"/recall favorite color"is sent to the LLM as a regular user prompt. The slash never matches.Confirmed at the source level on
origin/main:Three call sites, all in channel-handling code. Neither
src/commands/agent.ts(--localpath →agentCommand) norsrc/commands/agent-via-gateway.ts(gateway path →agentViaGatewayCommand) referencehandleCommands,handlePluginCommand,matchPluginCommand, orexecutePluginCommand:So when the user types
--message "/<cmd>", the dispatcher is loaded in memory but nobody calls it on this path.Why it matters
openclaw agent --localis the natural minimum-viable integration test, but it can't observe the slash path./<cmd>to the LLM, which is surprising. Users reasonably expect a/-prefixed message to behave the same way it does in their channels.Proposed fix
Call the existing
handleCommandswrapper (the same one the auto-reply pipeline uses) in both agent paths, before the message is forwarded to the LLM. The wrapper already returns null when no plugin command matches, so non-slash messages flow through unchanged.Sketch (pseudo-diff against
src/commands/agent.tsnear wherebodyis sent into the agent runner):The same insertion point applies in
agentViaGatewayCommand— either dispatch locally before sending to the gateway, or have the gateway invokehandleCommandson inboundagentrequests (cleaner, but a bigger change). Local dispatch keeps--localand gateway behaviourally aligned with channels that already do this themselves.The same hook is also worth adding to the TUI input path so
/<cmd>typed in the TUI fires the same handlers.Acceptance
openclaw agent --local --message "/<registered-cmd>"invokes the registered handler and returns its reply.openclaw agent --message "/<registered-cmd>"(gateway path) does the same.openclaw tuislash input fires plugin commands.Happy to follow up with a PR if there's interest in the local-dispatch shape proposed above. The Telegram and Discord call sites are clean precedents to mirror.
References
src/commands/agent.ts—agentCommand(the--localentry)src/commands/agent-via-gateway.ts—agentViaGatewayCommand(gateway entry)src/auto-reply/reply/commands.ts— exportshandleCommandssrc/auto-reply/reply/commands-plugin.ts—handlePluginCommandimplementationsrc/plugins/commands.ts—matchPluginCommand/executePluginCommanddeclarationssrc/plugins/registry.ts:422— confirms plugin registrations land in the central registry correctly; the gap is only on the dispatch side.