Skip to content

feat(mattermost): add emoji reactions support#18608

Merged
steipete merged 2 commits intoopenclaw:mainfrom
0mg-cc:refresh/mattermost-reactions-14305
Feb 16, 2026
Merged

feat(mattermost): add emoji reactions support#18608
steipete merged 2 commits intoopenclaw:mainfrom
0mg-cc:refresh/mattermost-reactions-14305

Conversation

@echo931
Copy link
Contributor

@echo931 echo931 commented Feb 16, 2026

Summary

Refresh of Mattermost reactions support on top of current main.

Adds message(action=react) support for Mattermost with add/remove reaction behavior.

Changes

  • add extensions/mattermost/src/mattermost/reactions.ts
    • addMattermostReaction
    • removeMattermostReaction
  • wire react action in extensions/mattermost/src/channel.ts
  • extend monitor websocket handling for reaction_added / reaction_removed
  • improve Mattermost client response handling for 204/non-JSON reaction endpoints
  • tests:
    • channel.test.ts
    • mattermost/reactions.test.ts
    • mattermost/client.test.ts

Validation

pnpm exec vitest run \
  extensions/mattermost/src/channel.test.ts \
  extensions/mattermost/src/mattermost/reactions.test.ts \
  extensions/mattermost/src/mattermost/client.test.ts

Closes #14305

Greptile Summary

Adds emoji reaction support (message(action=react)) to the Mattermost extension, with both outbound (add/remove reactions via API) and inbound (websocket reaction event monitoring) paths.

  • New reactions.ts module with addMattermostReaction / removeMattermostReaction functions that resolve the bot user ID (with caching) and call the Mattermost reactions API
  • handleAction wired in channel.ts via ChannelMessageActionAdapter, following the same patterns as Discord/Slack/Telegram/Signal
  • Config-driven feature gate (actions.reactions) at both base and per-account levels in the schema
  • HTTP client updated to handle 204 No Content and non-JSON responses from the reaction DELETE endpoint
  • Websocket monitor extended to route reaction_added/reaction_removed events to a new handleReactionEvent handler with full DM/group policy enforcement mirroring the existing message handler
  • Tests cover action listing/gating, add/remove reaction API flows, and client 204 handling

Confidence Score: 4/5

  • This PR is safe to merge — it follows established channel patterns and includes proper policy enforcement.
  • The implementation closely follows the existing patterns established by Discord, Slack, Telegram, and Signal for message actions. Policy enforcement in the reaction handler mirrors the existing message handler. The two style issues found (double JSON parsing in websocket handler, inconsistent error handling in reactions module) are non-blocking.
  • extensions/mattermost/src/mattermost/monitor-websocket.ts has redundant JSON parsing that could be cleaned up.

Last reviewed commit: e1b56ef

@echo931
Copy link
Contributor Author

echo931 commented Feb 16, 2026

@codex please review this PR.

@openclaw-barnacle openclaw-barnacle bot added channel: mattermost Channel integration: mattermost size: L labels Feb 16, 2026
Copy link
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.

9 files reviewed, 2 comments

Edit Code Review Agent Settings | Greptile

Comment on lines 139 to 163
ws.on("message", async (data) => {
const raw = rawDataToString(data);
let payload: MattermostEventPayload;
try {
payload = JSON.parse(raw) as MattermostEventPayload;
} catch {
return;
}

if (payload.event === "reaction_added" || payload.event === "reaction_removed") {
if (!opts.onReaction) {
return;
}
try {
await opts.onReaction(payload);
} catch (err) {
opts.runtime.error?.(`mattermost reaction handler failed: ${String(err)}`);
}
return;
}

if (payload.event !== "posted") {
return;
}
const parsed = parsePostedEvent(data);
Copy link
Contributor

Choose a reason for hiding this comment

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

Double JSON parsing for every posted event

The new early-parsing block (lines 140-146) parses the raw websocket data and checks the event type. For "posted" events, execution falls through to parsePostedEvent(data) on line 163 which calls rawDataToString(data) and JSON.parse(raw) again — parsing the same message twice for the most common event type.

Consider passing the already-parsed payload into a helper that extracts the post data, instead of re-parsing from data:

Suggested change
ws.on("message", async (data) => {
const raw = rawDataToString(data);
let payload: MattermostEventPayload;
try {
payload = JSON.parse(raw) as MattermostEventPayload;
} catch {
return;
}
if (payload.event === "reaction_added" || payload.event === "reaction_removed") {
if (!opts.onReaction) {
return;
}
try {
await opts.onReaction(payload);
} catch (err) {
opts.runtime.error?.(`mattermost reaction handler failed: ${String(err)}`);
}
return;
}
if (payload.event !== "posted") {
return;
}
const parsed = parsePostedEvent(data);
ws.on("message", async (data) => {
const raw = rawDataToString(data);
let payload: MattermostEventPayload;
try {
payload = JSON.parse(raw) as MattermostEventPayload;
} catch {
return;
}
if (payload.event === "reaction_added" || payload.event === "reaction_removed") {
if (!opts.onReaction) {
return;
}
try {
await opts.onReaction(payload);
} catch (err) {
opts.runtime.error?.(`mattermost reaction handler failed: ${String(err)}`);
}
return;
}
if (payload.event !== "posted") {
return;
}
const parsed = parsePostedPayload(payload);

This would need a new parsePostedPayload(payload) helper (extracted from the second half of parsePostedEvent) that takes the already-parsed payload instead of raw data.

Prompt To Fix With AI
This is a comment left during a code review.
Path: extensions/mattermost/src/mattermost/monitor-websocket.ts
Line: 139:163

Comment:
**Double JSON parsing for every posted event**

The new early-parsing block (lines 140-146) parses the raw websocket data and checks the event type. For `"posted"` events, execution falls through to `parsePostedEvent(data)` on line 163 which calls `rawDataToString(data)` and `JSON.parse(raw)` again — parsing the same message twice for the most common event type.

Consider passing the already-parsed payload into a helper that extracts the post data, instead of re-parsing from `data`:

```suggestion
        ws.on("message", async (data) => {
          const raw = rawDataToString(data);
          let payload: MattermostEventPayload;
          try {
            payload = JSON.parse(raw) as MattermostEventPayload;
          } catch {
            return;
          }

          if (payload.event === "reaction_added" || payload.event === "reaction_removed") {
            if (!opts.onReaction) {
              return;
            }
            try {
              await opts.onReaction(payload);
            } catch (err) {
              opts.runtime.error?.(`mattermost reaction handler failed: ${String(err)}`);
            }
            return;
          }

          if (payload.event !== "posted") {
            return;
          }
          const parsed = parsePostedPayload(payload);
```

This would need a new `parsePostedPayload(payload)` helper (extracted from the second half of `parsePostedEvent`) that takes the already-parsed payload instead of raw data.

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

Comment on lines +53 to +57
await createReaction(client, {
userId,
postId: params.postId,
emojiName: params.emojiName,
});
Copy link
Contributor

Choose a reason for hiding this comment

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

API errors bypass the Result return type

createReaction (and deleteReaction below) call client.request which throws on HTTP errors. Since those exceptions aren't caught here, addMattermostReaction will throw instead of returning { ok: false, error: "..." }, making the Result return type misleading.

This works in practice because handleAction in channel.ts will propagate the thrown error, but it's inconsistent with the { ok: false, error } handling for config-level issues above. Consider wrapping the API call in a try/catch to return a consistent Result:

Suggested change
await createReaction(client, {
userId,
postId: params.postId,
emojiName: params.emojiName,
});
try {
await createReaction(client, {
userId,
postId: params.postId,
emojiName: params.emojiName,
});
} catch (err) {
return { ok: false, error: `Mattermost add reaction failed: ${String(err)}` };
}
Prompt To Fix With AI
This is a comment left during a code review.
Path: extensions/mattermost/src/mattermost/reactions.ts
Line: 53:57

Comment:
**API errors bypass the Result return type**

`createReaction` (and `deleteReaction` below) call `client.request` which throws on HTTP errors. Since those exceptions aren't caught here, `addMattermostReaction` will throw instead of returning `{ ok: false, error: "..." }`, making the `Result` return type misleading.

This works in practice because `handleAction` in `channel.ts` will propagate the thrown error, but it's inconsistent with the `{ ok: false, error }` handling for config-level issues above. Consider wrapping the API call in a try/catch to return a consistent `Result`:

```suggestion
  try {
    await createReaction(client, {
      userId,
      postId: params.postId,
      emojiName: params.emojiName,
    });
  } catch (err) {
    return { ok: false, error: `Mattermost add reaction failed: ${String(err)}` };
  }
```

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

Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: e1b56efa42

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +60 to +63
const acctConfig = accountId && accounts ? accounts[accountId] : undefined;
const acctActions = acctConfig?.actions as { reactions?: boolean } | undefined;
const baseActions = mmBase?.actions as { reactions?: boolean } | undefined;
const reactionsEnabled = acctActions?.reactions ?? baseActions?.reactions ?? true;

Choose a reason for hiding this comment

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

P1 Badge Respect default account reaction gate when accountId is omitted

When accountId is not provided (the common path for message react unless --account is passed), acctConfig is forced to undefined, so reactionsEnabled ignores channels.mattermost.accounts.default.actions.reactions and falls back to the base setting. In configs where the default account disables reactions under accounts.default, this path still executes add/remove reaction calls, bypassing the per-account disable flag.

Useful? React with 👍 / 👎.

Comment on lines +43 to +45
const actionsConfig = cfg.channels?.mattermost?.actions as { reactions?: boolean } | undefined;
const reactionsEnabled = actionsConfig?.reactions !== false;
if (reactionsEnabled) {

Choose a reason for hiding this comment

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

P2 Badge Derive listed actions from per-account reaction settings

listActions only checks cfg.channels.mattermost.actions even though this change adds per-account actions.reactions configuration. In multi-account setups this misreports capability: react can be hidden when an enabled account explicitly enables it, or advertised when all enabled accounts have it disabled, causing avoidable runtime failures/confusing UX.

Useful? React with 👍 / 👎.

@echo931
Copy link
Contributor Author

echo931 commented Feb 16, 2026

Addressed all current review comments in latest push ():\n\n1. Double JSON parse in websocket handler\n - Added and now reuse already-parsed payload for posted events.\n\n2. Result consistency in reactions API calls\n - Wrapped add/remove API calls in and now return on HTTP/client failures.\n\n3. Default-account reaction gate when accountId omitted\n - now resolves default account id and enforces per-account gate correctly.\n\n4. listActions capability drift in multi-account configs\n - now derives visibility from effective per-account reaction settings (account override > base setting).\n\nAlso added/updated tests for these behaviors.\n\n@codex review

@echo931
Copy link
Contributor Author

echo931 commented Feb 16, 2026

Addressed all current review comments in latest push (commit c81da1c8d):

  1. Double JSON parse in websocket handler

    • Added parsePostedPayload(payload) and now reuse already-parsed payload for posted events.
  2. Result consistency in reactions API calls

    • Wrapped add/remove API calls in try/catch and now return { ok: false, error } on HTTP/client failures.
  3. Default-account reaction gate when accountId omitted

    • handleAction now resolves default account id and enforces per-account actions.reactions gate correctly.
  4. listActions capability drift in multi-account configs

    • listActions now derives visibility from effective per-account reaction settings (account override > base setting).

Also added/updated tests for these behaviors.

@codex review

Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: c81da1c8dc

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

});

const cacheKey = `${baseUrl}:${botToken}`;
const userId = await resolveBotUserId(client, cacheKey);

Choose a reason for hiding this comment

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

P2 Badge Catch bot identity lookup errors in reaction helpers

addMattermostReaction and removeMattermostReaction are declared to return a Result, but resolveBotUserId(...) is awaited outside any try/catch. If /users/me fails (for example due to token expiry, network failures, or 5xx responses), these functions reject instead of returning { ok: false, error }, which breaks the consistency this commit added for reaction API failures. Wrapping bot-user resolution in the same error handling path would keep failures predictable for callers.

Useful? React with 👍 / 👎.

@steipete steipete merged commit 8286196 into openclaw:main Feb 16, 2026
3 checks passed
tonydehnke added a commit to tonydehnke/openclaw that referenced this pull request Feb 21, 2026
… now upstream via openclaw#18608)

Add interactive message buttons and emoji reactions to the Mattermost
extension, enabling agents to send messages with clickable action buttons
and react to posts with emoji.

Interactive buttons:
- HMAC-SHA256 token verification for secure button callbacks
- HTTP callback handler registered via registerPluginHttpRoute
- Button click completion: replaces buttons with confirmation text
- Localhost-only validation for callback requests
- Stable HMAC secret derived from bot token (works across CLI/gateway)

Reactions:
- Add/remove emoji reactions via Mattermost REST API
- Bot user ID caching with TTL for reaction requests
- Reaction event handling in WebSocket monitor with DM/group policy enforcement

Channel actions adapter:
- supportsButtons, handleAction, listActions for the ChannelPlugin interface
- Send action with optional button attachments
- React action with add/remove support and emoji colon stripping

Also includes:
- updateMattermostPost for modifying existing posts (button completion)
- props passthrough in createMattermostPost for attachments
- parseMattermostTarget with channel-name and isMattermostId support
- Comprehensive test coverage (58 new tests across 4 test files)
tonydehnke added a commit to tonydehnke/openclaw that referenced this pull request Feb 23, 2026
… now upstream via openclaw#18608)

Add interactive message buttons and emoji reactions to the Mattermost
extension, enabling agents to send messages with clickable action buttons
and react to posts with emoji.

Interactive buttons:
- HMAC-SHA256 token verification for secure button callbacks
- HTTP callback handler registered via registerPluginHttpRoute
- Button click completion: replaces buttons with confirmation text
- Localhost-only validation for callback requests
- Stable HMAC secret derived from bot token (works across CLI/gateway)

Reactions:
- Add/remove emoji reactions via Mattermost REST API
- Bot user ID caching with TTL for reaction requests
- Reaction event handling in WebSocket monitor with DM/group policy enforcement

Channel actions adapter:
- supportsButtons, handleAction, listActions for the ChannelPlugin interface
- Send action with optional button attachments
- React action with add/remove support and emoji colon stripping

Also includes:
- updateMattermostPost for modifying existing posts (button completion)
- props passthrough in createMattermostPost for attachments
- parseMattermostTarget with channel-name and isMattermostId support
- Comprehensive test coverage (58 new tests across 4 test files)
tonydehnke added a commit to tonydehnke/openclaw that referenced this pull request Feb 23, 2026
… now upstream via openclaw#18608)

Add interactive message buttons and emoji reactions to the Mattermost
extension, enabling agents to send messages with clickable action buttons
and react to posts with emoji.

Interactive buttons:
- HMAC-SHA256 token verification for secure button callbacks
- HTTP callback handler registered via registerPluginHttpRoute
- Button click completion: replaces buttons with confirmation text
- Localhost-only validation for callback requests
- Stable HMAC secret derived from bot token (works across CLI/gateway)

Reactions:
- Add/remove emoji reactions via Mattermost REST API
- Bot user ID caching with TTL for reaction requests
- Reaction event handling in WebSocket monitor with DM/group policy enforcement

Channel actions adapter:
- supportsButtons, handleAction, listActions for the ChannelPlugin interface
- Send action with optional button attachments
- React action with add/remove support and emoji colon stripping

Also includes:
- updateMattermostPost for modifying existing posts (button completion)
- props passthrough in createMattermostPost for attachments
- parseMattermostTarget with channel-name and isMattermostId support
- Comprehensive test coverage (58 new tests across 4 test files)
tonydehnke added a commit to tonydehnke/openclaw that referenced this pull request Feb 24, 2026
… now upstream via openclaw#18608)

Add interactive message buttons and emoji reactions to the Mattermost
extension, enabling agents to send messages with clickable action buttons
and react to posts with emoji.

Interactive buttons:
- HMAC-SHA256 token verification for secure button callbacks
- HTTP callback handler registered via registerPluginHttpRoute
- Button click completion: replaces buttons with confirmation text
- Localhost-only validation for callback requests
- Stable HMAC secret derived from bot token (works across CLI/gateway)

Reactions:
- Add/remove emoji reactions via Mattermost REST API
- Bot user ID caching with TTL for reaction requests
- Reaction event handling in WebSocket monitor with DM/group policy enforcement

Channel actions adapter:
- supportsButtons, handleAction, listActions for the ChannelPlugin interface
- Send action with optional button attachments
- React action with add/remove support and emoji colon stripping

Also includes:
- updateMattermostPost for modifying existing posts (button completion)
- props passthrough in createMattermostPost for attachments
- parseMattermostTarget with channel-name and isMattermostId support
- Comprehensive test coverage (58 new tests across 4 test files)
tonydehnke added a commit to tonydehnke/openclaw that referenced this pull request Feb 26, 2026
… now upstream via openclaw#18608)

Add interactive message buttons and emoji reactions to the Mattermost
extension, enabling agents to send messages with clickable action buttons
and react to posts with emoji.

Interactive buttons:
- HMAC-SHA256 token verification for secure button callbacks
- HTTP callback handler registered via registerPluginHttpRoute
- Button click completion: replaces buttons with confirmation text
- Localhost-only validation for callback requests
- Stable HMAC secret derived from bot token (works across CLI/gateway)

Reactions:
- Add/remove emoji reactions via Mattermost REST API
- Bot user ID caching with TTL for reaction requests
- Reaction event handling in WebSocket monitor with DM/group policy enforcement

Channel actions adapter:
- supportsButtons, handleAction, listActions for the ChannelPlugin interface
- Send action with optional button attachments
- React action with add/remove support and emoji colon stripping

Also includes:
- updateMattermostPost for modifying existing posts (button completion)
- props passthrough in createMattermostPost for attachments
- parseMattermostTarget with channel-name and isMattermostId support
- Comprehensive test coverage (58 new tests across 4 test files)
tonydehnke added a commit to tonydehnke/openclaw that referenced this pull request Feb 27, 2026
… now upstream via openclaw#18608)

Add interactive message buttons and emoji reactions to the Mattermost
extension, enabling agents to send messages with clickable action buttons
and react to posts with emoji.

Interactive buttons:
- HMAC-SHA256 token verification for secure button callbacks
- HTTP callback handler registered via registerPluginHttpRoute
- Button click completion: replaces buttons with confirmation text
- Localhost-only validation for callback requests
- Stable HMAC secret derived from bot token (works across CLI/gateway)

Reactions:
- Add/remove emoji reactions via Mattermost REST API
- Bot user ID caching with TTL for reaction requests
- Reaction event handling in WebSocket monitor with DM/group policy enforcement

Channel actions adapter:
- supportsButtons, handleAction, listActions for the ChannelPlugin interface
- Send action with optional button attachments
- React action with add/remove support and emoji colon stripping

Also includes:
- updateMattermostPost for modifying existing posts (button completion)
- props passthrough in createMattermostPost for attachments
- parseMattermostTarget with channel-name and isMattermostId support
- Comprehensive test coverage (58 new tests across 4 test files)
tonydehnke added a commit to tonydehnke/openclaw that referenced this pull request Mar 2, 2026
… now upstream via openclaw#18608)

Add interactive message buttons and emoji reactions to the Mattermost
extension, enabling agents to send messages with clickable action buttons
and react to posts with emoji.

Interactive buttons:
- HMAC-SHA256 token verification for secure button callbacks
- HTTP callback handler registered via registerPluginHttpRoute
- Button click completion: replaces buttons with confirmation text
- Localhost-only validation for callback requests
- Stable HMAC secret derived from bot token (works across CLI/gateway)

Reactions:
- Add/remove emoji reactions via Mattermost REST API
- Bot user ID caching with TTL for reaction requests
- Reaction event handling in WebSocket monitor with DM/group policy enforcement

Channel actions adapter:
- supportsButtons, handleAction, listActions for the ChannelPlugin interface
- Send action with optional button attachments
- React action with add/remove support and emoji colon stripping

Also includes:
- updateMattermostPost for modifying existing posts (button completion)
- props passthrough in createMattermostPost for attachments
- parseMattermostTarget with channel-name and isMattermostId support
- Comprehensive test coverage (58 new tests across 4 test files)
tonydehnke added a commit to tonydehnke/openclaw that referenced this pull request Mar 2, 2026
… now upstream via openclaw#18608)

Add interactive message buttons and emoji reactions to the Mattermost
extension, enabling agents to send messages with clickable action buttons
and react to posts with emoji.

Interactive buttons:
- HMAC-SHA256 token verification for secure button callbacks
- HTTP callback handler registered via registerPluginHttpRoute
- Button click completion: replaces buttons with confirmation text
- Localhost-only validation for callback requests
- Stable HMAC secret derived from bot token (works across CLI/gateway)

Reactions:
- Add/remove emoji reactions via Mattermost REST API
- Bot user ID caching with TTL for reaction requests
- Reaction event handling in WebSocket monitor with DM/group policy enforcement

Channel actions adapter:
- supportsButtons, handleAction, listActions for the ChannelPlugin interface
- Send action with optional button attachments
- React action with add/remove support and emoji colon stripping

Also includes:
- updateMattermostPost for modifying existing posts (button completion)
- props passthrough in createMattermostPost for attachments
- parseMattermostTarget with channel-name and isMattermostId support
- Comprehensive test coverage (58 new tests across 4 test files)
tonydehnke added a commit to tonydehnke/openclaw that referenced this pull request Mar 2, 2026
… now upstream via openclaw#18608)

Add interactive message buttons and emoji reactions to the Mattermost
extension, enabling agents to send messages with clickable action buttons
and react to posts with emoji.

Interactive buttons:
- HMAC-SHA256 token verification for secure button callbacks
- HTTP callback handler registered via registerPluginHttpRoute
- Button click completion: replaces buttons with confirmation text
- Localhost-only validation for callback requests
- Stable HMAC secret derived from bot token (works across CLI/gateway)

Reactions:
- Add/remove emoji reactions via Mattermost REST API
- Bot user ID caching with TTL for reaction requests
- Reaction event handling in WebSocket monitor with DM/group policy enforcement

Channel actions adapter:
- supportsButtons, handleAction, listActions for the ChannelPlugin interface
- Send action with optional button attachments
- React action with add/remove support and emoji colon stripping

Also includes:
- updateMattermostPost for modifying existing posts (button completion)
- props passthrough in createMattermostPost for attachments
- parseMattermostTarget with channel-name and isMattermostId support
- Comprehensive test coverage (58 new tests across 4 test files)
tonydehnke added a commit to tonydehnke/openclaw that referenced this pull request Mar 5, 2026
… now upstream via openclaw#18608)

Add interactive message buttons and emoji reactions to the Mattermost
extension, enabling agents to send messages with clickable action buttons
and react to posts with emoji.

Interactive buttons:
- HMAC-SHA256 token verification for secure button callbacks
- HTTP callback handler registered via registerPluginHttpRoute
- Button click completion: replaces buttons with confirmation text
- Localhost-only validation for callback requests
- Stable HMAC secret derived from bot token (works across CLI/gateway)

Reactions:
- Add/remove emoji reactions via Mattermost REST API
- Bot user ID caching with TTL for reaction requests
- Reaction event handling in WebSocket monitor with DM/group policy enforcement

Channel actions adapter:
- supportsButtons, handleAction, listActions for the ChannelPlugin interface
- Send action with optional button attachments
- React action with add/remove support and emoji colon stripping

Also includes:
- updateMattermostPost for modifying existing posts (button completion)
- props passthrough in createMattermostPost for attachments
- parseMattermostTarget with channel-name and isMattermostId support
- Comprehensive test coverage (58 new tests across 4 test files)
mukhtharcm pushed a commit to tonydehnke/openclaw that referenced this pull request Mar 5, 2026
… now upstream via openclaw#18608)

Add interactive message buttons and emoji reactions to the Mattermost
extension, enabling agents to send messages with clickable action buttons
and react to posts with emoji.

Interactive buttons:
- HMAC-SHA256 token verification for secure button callbacks
- HTTP callback handler registered via registerPluginHttpRoute
- Button click completion: replaces buttons with confirmation text
- Localhost-only validation for callback requests
- Stable HMAC secret derived from bot token (works across CLI/gateway)

Reactions:
- Add/remove emoji reactions via Mattermost REST API
- Bot user ID caching with TTL for reaction requests
- Reaction event handling in WebSocket monitor with DM/group policy enforcement

Channel actions adapter:
- supportsButtons, handleAction, listActions for the ChannelPlugin interface
- Send action with optional button attachments
- React action with add/remove support and emoji colon stripping

Also includes:
- updateMattermostPost for modifying existing posts (button completion)
- props passthrough in createMattermostPost for attachments
- parseMattermostTarget with channel-name and isMattermostId support
- Comprehensive test coverage (58 new tests across 4 test files)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

channel: mattermost Channel integration: mattermost size: L

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Mattermost: support message reactions (send via message(action=react) + receive reaction events)

2 participants