Skip to content

feat(mattermost): native slash commands — HTTP endpoint, thread-scoped typing, flat-reply fix - #91811

Open
Ejmathewp wants to merge 5 commits into
NousResearch:mainfrom
Ejmathewp:mm-slash-pr
Open

Ejmathewp wants to merge 5 commits into
NousResearch:mainfrom
Ejmathewp:mm-slash-pr

Conversation

@Ejmathewp

Copy link
Copy Markdown

Problem

Mattermost's client intercepts any message starting with / and treats it as a Mattermost command — unregistered ones like /model are rejected locally and never reach the gateway. The adapter (WebSocket/REST only) had no way to receive server-side slash callbacks, so Hermes commands only worked with a leading-space hack, with no autocomplete and no argument hints.

What this adds

  1. Native slash-command HTTP endpoint (aiohttp, default 0.0.0.0:8645, config via mattermost.slash_command_host/port in config.yaml). Receives Mattermost's form-urlencoded callbacks, validates the verification token with a constant-time compare against MATTERMOST_SLASH_TOKENS (401 fail-closed), and injects the command as a native COMMAND event — allowed-channel gating, admin/user split, and ephemeral 200-ack all preserved. Plugin-only; no core files touched.
  2. Thread-scoped typing indicatorsend_typing now forwards the thread root as parent_id, so "hermes is typing" appears in the thread/Threads view, matching native client behavior (webapp gates on parent_id === rootId).
  3. Flat-reply fix — when thread reply-mode resolves a missing/nonexistent root (4xx on lookup), the reply posts flat cleanly instead of a doomed threaded attempt + "delivery failed" banner.
  4. Docs — new "Native Slash Commands" section: token setup, Mattermost-side registration with autocomplete, and the SSRF gotcha where Mattermost blocks callbacks to reserved ranges (CGNAT/mesh VPNs).

Validation

  • 45 tests (11→30 endpoint tests incl. auth/timeout/allowed-channels, 3 typing regression, deterministic reply-mode) — all green on this branch.
  • Deployed and E2E-verified on a live server (Mattermost 11.9 Team Edition): 61 commands registered, autocomplete working, 401 on invalid tokens, exec-to-reply verified through Mattermost's own command executor.

Document the adapter's slash-command HTTP endpoint: token setup, config.yaml
host/port, Mattermost-side registration with autocomplete, and the reserved-
range SSRF pitfall that silently blocks callbacks to mesh-VPN hosts.
@alt-glitch alt-glitch added type/feature New feature or request comp/plugins Plugin system and bundled plugins P3 Low — cosmetic, nice to have needs-decision Awaiting maintainer decision before any implementation labels Aug 21, 2026
@alt-glitch

Copy link
Copy Markdown
Contributor

This was generated by AI during triage.

Related: #12593, #26537, and #29373 cover overlapping Mattermost callback/slash-command infrastructure with different scopes. Please consider consolidating the preferred implementation.

@Ejmathewp

Copy link
Copy Markdown
Author

Thanks for the triage. I looked at all three — here's how they relate to this PR:

#12593 (native slash commands) — independent convergence on the same design: register COMMAND_REGISTRY via POST /api/v4/commands, HTTP callback server, per-command token auth. It also independently hit the same SSRF gotcha (ServiceSettings.AllowedUntrustedInternalConnections must allowlist the callback host), which this PR documents as well. It targets gateway/platforms/mattermost.py, which no longer exists on main after the move to plugins/platforms/mattermost/, so it can't merge as-is. Two ideas from it worth carrying forward regardless: the cross-platform ./command text fallback, and a None-guard in _run_agent's pending-queue inspection. Credit to @cyb0rgk1tty for those.

#26537 → superseded by #29373, so considering #29373 only:

#29373 (interactive approval buttons) — complementary rather than overlapping: it explicitly scopes out slash-command registration, which is exactly what this PR provides. The one real shared surface is callback infrastructure: both PRs add an aiohttp listener to plugins/platforms/mattermost/adapter.py (this PR on :8645 for slash commands, #29373 on :18065 for button actions). If maintainers prefer a single callback server with route-level dispatch instead of two servers on two ports, I'm happy to rebase and coordinate on that once either lands.

No behavioral conflict between this PR and #29373 — different endpoints, different features.

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

Labels

comp/plugins Plugin system and bundled plugins needs-decision Awaiting maintainer decision before any implementation P3 Low — cosmetic, nice to have type/feature New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants