Skip to content

feat(mattermost): thread context + in-thread auto-response (Slack parity) - #43791

Closed
crisap94 wants to merge 1 commit into
NousResearch:mainfrom
crisap94:feat/mattermost-thread-context-and-autorespond
Closed

feat(mattermost): thread context + in-thread auto-response (Slack parity)#43791
crisap94 wants to merge 1 commit into
NousResearch:mainfrom
crisap94:feat/mattermost-thread-context-and-autorespond

Conversation

@crisap94

Copy link
Copy Markdown

What does this PR do?

Brings the Mattermost adapter to parity with the Slack adapter for thread handling, and closes a security gap that surfaces once thread history is loaded.

Two behaviors users expect in a thread were missing on Mattermost:

  1. No thread context. When the bot is @mentioned inside an existing thread, it only ever saw the single message it was tagged in — never the prior conversation it was pulled into. (_handle_ws_event builds the MessageEvent straight from the triggering post, with no channel_context.)
  2. Must re-mention every turn. The bot would not follow up in a thread unless re-@mentioned each time, which makes a back-and-forth feel broken.

The Slack adapter already solves both (_mentioned_threads, _fetch_thread_context, _has_active_session_for_thread, SLACK_STRICT_MENTION). This ports that exact pattern to Mattermost.

Security: thread context must respect the user allowlist

The user allowlist is enforced in gateway/authz_mixin.py::_is_user_authorized, per dispatched message, by authordownstream of the adapter. That means:

  • In-thread auto-response is safe: every follow-up is still authorized by author, so a non-allowlisted user posting in an engaged thread is still ignored.
  • Thread-context injection is not, unless filtered: the loaded history rides inside the authorized user's MessageEvent.channel_context, which authz never inspects. Loading the whole thread verbatim would feed a non-allowlisted user's messages straight into the model (an unauthorized-content / prompt-injection vector).

So _fetch_thread_context filters historical posts to authors in MATTERMOST_ALLOWED_USERS (or everyone when MATTERMOST_ALLOW_ALL_USERS / GATEWAY_ALLOW_ALL_USERS is set), mirroring the authz allowlist. The bot's own posts and system posts are excluded as well. This is the piece the existing thread-context PRs (#38362, #38152) do not have.

Related Issue

Related (all address Mattermost thread context, none adds in-thread auto-response or the allowlist filter): #38362, #38152, #37144.

Fixes #

Type of Change

  • ✨ New feature (non-breaking change that adds functionality)
  • 🔒 Security fix
  • ✅ Tests (adding or improving test coverage)
  • 📝 Documentation update

Changes Made

All adapter changes in plugins/platforms/mattermost/adapter.py:

  • _strict_mention() — reads MATTERMOST_STRICT_MENTION (default false) + config.extra override, mirroring _slack_strict_mention.
  • _has_active_session_for_thread() — mirrors Slack, but passes the adapter's real chat_type (_CHANNEL_TYPE_MAP[...]) into build_session_key, so the key matches what handle_message persists (a hardcoded "group" like Slack uses would never match for "O" channels).
  • _fetch_thread_context() — fetches GET /posts/{root}/thread, fails open via the existing _api_get, TTL-cached, excludes the trigger/bot/system posts, filters to allowlisted authors, and injects via MessageEvent.channel_context.
  • Mention-gate rewrite — adds strict_mention, in_mentioned_thread, and has_session; registers a thread on @mention only when not strict; preserves @mention stripping.
  • First-turn context injection before MessageEvent(...), guarded by _has_active_session_for_thread so it runs once per thread.
  • tests/gateway/test_mattermost.py — new TestMattermostThreadBehavior (12 cases): strict-mention resolution, context fetch/exclusion, allowlist filtering (+ allow-all), fail-open, auto-response, strict-mode regression, non-thread/DM regressions, and session-key chat_type correctness.
  • Docs — website/docs/user-guide/messaging/mattermost.md and website/docs/reference/environment-variables.md document MATTERMOST_STRICT_MENTION, the in-thread behavior, and the allowlist-filtered context.

No new config keys in cli-config.yaml.example (behavior is env/config.extra-driven, consistent with the existing MATTERMOST_REQUIRE_MENTION / MATTERMOST_FREE_RESPONSE_CHANNELS).

How to Test

  1. Set MATTERMOST_ALLOWED_USERS=<your_id> and start the gateway with a bot in a channel.
  2. In a thread that already has messages, @mention the bot → its reply reflects the prior thread messages (context loaded). Post a follow-up without mentioning it → it still replies (auto-response).
  3. Have a non-allowlisted user post in that thread → the bot ignores it, and its text does not appear in the bot's context.
  4. Set MATTERMOST_STRICT_MENTION=true → the bot only replies when @mentioned each turn (old behavior).
  5. Unit tests: pytest tests/gateway/test_mattermost.py -q → 55 passed.

Checklist

Code

  • I've read the Contributing Guide
  • My commit messages follow Conventional Commits (feat(mattermost): ...)
  • I searched for existing PRs to make sure this isn't a duplicate (see Related — they cover only thread context, not auto-response or the allowlist filter)
  • My PR contains only changes related to this feature
  • I've run the relevant suite — pytest tests/gateway/test_mattermost.py -q → 55 passed
  • I've added tests for my changes
  • I've tested on my platform: Debian 13 (Linux 6.8)

Documentation & Housekeeping

  • I've updated relevant documentation (website/docs/)
  • cli-config.yaml.example — N/A (no new config keys)
  • CONTRIBUTING.md / AGENTS.md — N/A (no architecture/workflow change)
  • Cross-platform impact — N/A (no platform-specific primitives; in-memory caches only)
  • Tool descriptions/schemas — N/A

…ity)

The Mattermost adapter only saw the single message it was @mentioned in and
required a fresh @mention every turn. The Slack adapter already solves both;
this ports that pattern to Mattermost.

- In-thread auto-response: after the first @mention in a thread, subsequent
  messages in that thread auto-trigger the bot. Opt out with
  MATTERMOST_STRICT_MENTION=true (mirrors SLACK_STRICT_MENTION).
- Thread context: on the first turn in a pre-existing thread, prior messages
  are fetched (GET /posts/{root}/thread) and injected via channel_context.
- Security: injected thread history is filtered to allowlisted authors
  (MATTERMOST_ALLOWED_USERS / *_ALLOW_ALL_USERS). The authz layer only checks
  the triggering author; channel_context bypasses it, so unfiltered history
  would leak non-allowlisted users' messages into the model.
- Session-key parity: _has_active_session_for_thread passes the adapter's real
  chat_type so the key matches what handle_message persists.

Adds TestMattermostThreadBehavior (12 cases) and documents
MATTERMOST_STRICT_MENTION + the allowlist-filtered context behavior.

Related: NousResearch#38362, NousResearch#38152, NousResearch#37144 (thread-context PRs without the allowlist filter).
@crisap94
crisap94 force-pushed the feat/mattermost-thread-context-and-autorespond branch from 164a0cb to 89ca9db Compare June 10, 2026 22:03
@crisap94

Copy link
Copy Markdown
Author

Superseded — split into two focused, stacked PRs for clearer review:

Closing this consolidated PR in favor of those. Thanks!

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant