Skip to content

Mattermost(插件)

支持状态:通过插件支持(Bot Token + WebSocket 事件)。支持频道、群组和私信。 Mattermost 是一个可自托管的团队即时通讯平台;产品详情和下载请访问 mattermost.com

安装插件

Mattermost 以插件形式提供,不包含在核心安装包中。

通过 CLI 安装(npm 仓库):

bash
openclaw plugins install @openclaw/mattermost

本地代码仓库(从 git 仓库运行时):

bash
openclaw plugins install ./extensions/mattermost

在设置时选择 Mattermost 且检测到 git 代码仓库时,OpenClaw 会自动提示使用本地安装路径。

详见:插件说明

快速配置

  1. 安装 Mattermost 插件。
  2. 创建一个 Mattermost 机器人账号并复制 Bot Token
  3. 复制 Mattermost 的 Base URL(例如 https://chat.example.com)。
  4. 配置 OpenClaw 并启动 Gateway。

最小配置:

json5
{
  channels: {
    mattermost: {
      enabled: true,
      botToken: "mm-token",
      baseUrl: "https://chat.example.com",
      dmPolicy: "pairing",
    },
  },
}

原生斜杠命令

原生斜杠命令为可选功能。启用后,OpenClaw 通过 Mattermost API 注册 oc_* 斜杠命令,并在 Gateway HTTP 服务器上接收回调 POST 请求。

json5
{
  channels: {
    mattermost: {
      commands: {
        native: true,
        nativeSkills: true,
        callbackPath: "/api/channels/mattermost/command",
        // 当 Mattermost 无法直接访问 Gateway 时使用(反向代理/公网 URL)
        callbackUrl: "https://gateway.example.com/api/channels/mattermost/command",
      },
    },
  },
}

注意事项:

  • native: "auto" 在 Mattermost 中默认禁用。设置 native: true 才启用。
  • 如果省略 callbackUrl,OpenClaw 会根据 Gateway 主机/端口 + callbackPath 自动推导。
  • 多账号时,commands 可在顶层或 channels.mattermost.accounts.<id>.commands 下设置(账号级值覆盖顶层)。
  • 命令回调使用每命令 Token 进行验证,Token 校验失败时安全关闭。
  • 可达性要求:回调端点必须可从 Mattermost 服务器访问。
    • 除非 Mattermost 与 OpenClaw 在同一主机/网络命名空间,否则不要将 callbackUrl 设为 localhost
    • 除非该 URL 将 /api/channels/mattermost/command 反向代理到 OpenClaw,否则不要将 callbackUrl 设为 Mattermost 的 Base URL。
    • 快速检测:curl https://<gateway-host>/api/channels/mattermost/command;GET 请求应从 OpenClaw 返回 405 Method Not Allowed,而非 404
  • Mattermost 出站白名单要求:
    • 如果回调目标是私有/Tailnet/内部地址,在 Mattermost 的 ServiceSettings.AllowedUntrustedInternalConnections 中添加回调主机/域名。
    • 使用主机/域名条目,而非完整 URL。
      • 正确:gateway.tailnet-name.ts.net
      • 错误:https://gateway.tailnet-name.ts.net

环境变量(默认账号)

在 Gateway 主机上设置,如果你偏好使用环境变量:

  • MATTERMOST_BOT_TOKEN=...
  • MATTERMOST_URL=https://chat.example.com

环境变量仅适用于默认账号(default)。其他账号必须使用配置值。

聊天模式

Mattermost 会自动响应私信。频道行为由 chatmode 控制:

  • oncall(默认):只在频道中被 @提及时响应。
  • onmessage:响应每条频道消息。
  • onchar:消息以触发前缀开头时响应。

配置示例:

json5
{
  channels: {
    mattermost: {
      chatmode: "onchar",
      oncharPrefixes: [">", "!"],
    },
  },
}

注意:

  • onchar 模式下,显式 @提及仍然有效。
  • 旧版配置中的 channels.mattermost.requireMention 仍被支持,但建议优先使用 chatmode

线程与会话

使用 channels.mattermost.replyToMode 控制频道和群组回复是在主频道中,还是在触发帖子下新建线程。

  • off(默认):只有当入站帖子本身在线程中时,才在线程中回复。
  • first:对顶层频道/群组帖子,在该帖子下新建线程,并将对话路由到线程作用域的会话。
  • all:与 first 行为相同(在当前 Mattermost 中等价)。
  • 私信忽略此设置,保持非线程模式。

配置示例:

json5
{
  channels: {
    mattermost: {
      replyToMode: "all",
    },
  },
}

注意:

  • 线程作用域会话以触发帖子 ID 为线程根。
  • firstall 目前等价,因为 Mattermost 一旦有了线程根,后续消息块和媒体都会在该线程中继续。

访问控制(私信)

  • 默认:channels.mattermost.dmPolicy = "pairing"(未知发送者收到配对码)。
  • 审批方式:
    • openclaw pairing list mattermost
    • openclaw pairing approve mattermost <CODE>
  • 开放私信:channels.mattermost.dmPolicy="open" 加上 channels.mattermost.allowFrom=["*"]

频道(群组)

  • 默认:channels.mattermost.groupPolicy = "allowlist"(需 @提及)。
  • 通过 channels.mattermost.groupAllowFrom 设置发送者白名单(推荐使用用户 ID)。
  • @username 匹配是可变的,只有在 channels.mattermost.dangerouslyAllowNameMatching: true 时才启用。
  • 开放频道:channels.mattermost.groupPolicy="open"(仍需 @提及)。
  • 运行时注意:如果 channels.mattermost 完全缺失,运行时会对群组检查回退到 groupPolicy="allowlist"(即使设置了 channels.defaults.groupPolicy)。

出站消息目标格式

openclaw message send 或 Cron/Webhook 中使用以下格式:

  • channel:<id>:发送到频道
  • user:<id>:发送私信
  • @username:发送私信(通过 Mattermost API 解析)

裸的不透明 ID(如 64ifufp...)在 Mattermost 中存在歧义(用户 ID vs 频道 ID)。

OpenClaw 按用户优先原则解析:

  • 如果该 ID 作为用户存在(GET /api/v4/users/<id> 成功),OpenClaw 通过 /api/v4/channels/direct 解析直接频道,以私信形式发送。
  • 否则将 ID 视为频道 ID

如需确定性行为,始终使用明确的前缀(user:<id> / channel:<id>)。

私信频道重试

当 OpenClaw 向 Mattermost 私信目标发送消息并需要先解析直接频道时,默认会对瞬时直接频道创建失败进行重试。

使用 channels.mattermost.dmChannelRetry 在全局为 Mattermost 插件配置此行为, 或使用 channels.mattermost.accounts.<id>.dmChannelRetry 针对单个账号配置。

json5
{
  channels: {
    mattermost: {
      dmChannelRetry: {
        maxRetries: 3,
        initialDelayMs: 1000,
        maxDelayMs: 10000,
        timeoutMs: 30000,
      },
    },
  },
}

注意:

  • 仅适用于私信频道创建(/api/v4/channels/direct),而非所有 Mattermost API 调用。
  • 对速率限制、5xx 响应和网络/超时错误等瞬时故障进行重试。
  • 429 外的 4xx 客户端错误视为永久错误,不进行重试。

表情回应(消息工具)

  • 使用 message action=reactchannel=mattermost
  • messageId 是 Mattermost 的帖子 ID。
  • emoji 接受 thumbsup:+1: 等格式(冒号可选)。
  • 设置 remove=true(布尔值)可移除回应。
  • 回应添加/移除事件会以系统事件形式转发到路由的智能体会话。

示例:

message action=react channel=mattermost target=channel:<channelId> messageId=<postId> emoji=thumbsup
message action=react channel=mattermost target=channel:<channelId> messageId=<postId> emoji=thumbsup remove=true

配置:

  • channels.mattermost.actions.reactions:启用/禁用表情回应操作(默认 true)。
  • 每账号覆盖:channels.mattermost.accounts.<id>.actions.reactions

交互式按钮(消息工具)

发送带有可点击按钮的消息。用户点击按钮后,智能体收到选择结果并可以做出响应。

在频道能力中添加 inlineButtons 来启用按钮功能——养好龙虾后别忘了开启这个特性:

json5
{
  channels: {
    mattermost: {
      capabilities: ["inlineButtons"],
    },
  },
}

使用 message action=sendbuttons 参数。按钮是二维数组(按行排列):

message action=send channel=mattermost target=channel:<channelId> buttons=[[{"text":"Yes","callback_data":"yes"},{"text":"No","callback_data":"no"}]]

按钮字段:

  • text(必填):显示标签。
  • callback_data(必填):点击时发回的值(用作操作 ID)。
  • style(可选):"default""primary""danger"

用户点击按钮后:

  1. 所有按钮被替换为确认行(例如"✓ Yes selected by @user")。
  2. 智能体收到选择作为入站消息并响应。

注意:

  • 按钮回调使用 HMAC-SHA256 验证(自动,无需配置)。
  • Mattermost 会从其 API 响应中删除回调数据(安全特性),因此点击后所有按钮都会被移除——无法部分移除。
  • 包含连字符或下划线的操作 ID 会被自动清理(Mattermost 路由限制)。

配置:

  • channels.mattermost.capabilities:能力字符串数组,添加 "inlineButtons" 以在智能体系统提示中启用按钮工具描述。
  • channels.mattermost.interactions.callbackBaseUrl:按钮回调的可选外部 Base URL(例如 https://gateway.example.com)。当 Mattermost 无法直接访问 Gateway 时使用。
  • 多账号时,也可在 channels.mattermost.accounts.<id>.interactions.callbackBaseUrl 下设置相同字段。
  • 如果省略 interactions.callbackBaseUrl,OpenClaw 从 gateway.customBindHost + gateway.port 推导回调 URL,再回退到 http://localhost:<port>
  • 可达性规则:按钮回调 URL 必须可从 Mattermost 服务器访问,localhost 只在 Mattermost 和 OpenClaw 在同一主机/网络命名空间时有效。
  • 如果回调目标是私有/Tailnet/内部地址,在 Mattermost 的 ServiceSettings.AllowedUntrustedInternalConnections 中添加其主机/域名。

直接 API 集成(外部脚本)

外部脚本和 Webhook 可以直接通过 Mattermost REST API 发送按钮,而无需通过智能体的 message 工具。 如有可能,使用扩展提供的 buildButtonAttachments();如直接发送原始 JSON,请遵循以下规则:

载荷结构:

json5
{
  channel_id: "<channelId>",
  message: "Choose an option:",
  props: {
    attachments: [
      {
        actions: [
          {
            id: "mybutton01", // 仅限字母数字——见下文
            type: "button", // 必填,否则点击会被静默忽略
            name: "Approve", // 显示标签
            style: "primary", // 可选:default、primary、danger
            integration: {
              url: "https://gateway.example.com/mattermost/interactions/default",
              context: {
                action_id: "mybutton01", // 必须与按钮 id 一致(用于名称查找)
                action: "approve",
                // ... 任意自定义字段 ...
                _token: "<hmac>", // 见 HMAC 部分
              },
            },
          },
        ],
      },
    ],
  },
}

关键规则:

  1. Attachments 必须放在 props.attachments 中,而非顶层 attachments(顶层会被静默忽略)。
  2. 每个 action 都需要 type: "button"——没有它,点击会被静默吞掉。
  3. 每个 action 都需要 id 字段——Mattermost 会忽略没有 ID 的 action。
  4. Action id 必须仅包含字母数字[a-zA-Z0-9])。连字符和下划线会破坏 Mattermost 服务端的 action 路由(返回 404)。使用前请清理。
  5. context.action_id 必须与按钮的 id 一致,这样确认消息才会显示按钮名称(如"Approve")而非原始 ID。
  6. context.action_id 是必填的——没有它,交互处理程序会返回 400。

HMAC Token 生成:

Gateway 使用 HMAC-SHA256 验证按钮点击。外部脚本必须生成与 Gateway 验证逻辑匹配的 Token:

  1. 从 Bot Token 推导密钥:HMAC-SHA256(key="openclaw-mattermost-interactions", data=botToken)
  2. 构建不含 _token 字段的 context 对象。
  3. 使用键排序无空格(Gateway 使用 JSON.stringify 加键排序,输出紧凑格式)序列化。
  4. 签名:HMAC-SHA256(key=secret, data=serializedContext)
  5. 将十六进制摘要作为 _token 添加到 context 中。

Python 示例:

python
import hmac, hashlib, json

secret = hmac.new(
    b"openclaw-mattermost-interactions",
    bot_token.encode(), hashlib.sha256
).hexdigest()

ctx = {"action_id": "mybutton01", "action": "approve"}
payload = json.dumps(ctx, sort_keys=True, separators=(",", ":"))
token = hmac.new(secret.encode(), payload.encode(), hashlib.sha256).hexdigest()

context = {**ctx, "_token": token}

常见 HMAC 陷阱:

  • Python 的 json.dumps 默认加空格({"key": "val"})。使用 separators=(",", ":") 来匹配 JavaScript 的紧凑输出({"key":"val"})。
  • 始终对所有 context 字段(减去 _token)进行签名。Gateway 先删除 _token,再对剩余内容签名。签名子集会导致静默验证失败。
  • 使用 sort_keys=True——Gateway 在签名前对键排序,Mattermost 在存储载荷时可能重新排列 context 字段。
  • 从 Bot Token 推导密钥(确定性),而非随机字节。创建按钮的进程和验证的 Gateway 必须使用相同的密钥。

目录适配器

Mattermost 插件包含一个目录适配器,通过 Mattermost API 解析频道和用户名称。 这使得 openclaw message send 和 Cron/Webhook 中可以使用 #channel-name@username 目标。

无需配置——适配器使用账号配置中的 Bot Token。

多账号

Mattermost 支持 channels.mattermost.accounts 下的多个账号:

json5
{
  channels: {
    mattermost: {
      accounts: {
        default: { name: "Primary", botToken: "mm-token", baseUrl: "https://chat.example.com" },
        alerts: { name: "Alerts", botToken: "mm-token-2", baseUrl: "https://alerts.example.com" },
      },
    },
  },
}

故障排查

  • 频道中没有回复:确认机器人在频道中且已被 @提及(oncall)、使用了触发前缀(onchar),或设置了 chatmode: "onmessage"
  • 认证错误:检查 Bot Token、Base URL 以及账号是否启用。
  • 多账号问题:环境变量只适用于 default 账号。
  • 按钮显示为白框:智能体可能发送了格式错误的按钮数据,检查每个按钮是否同时包含 textcallback_data 字段。
  • 按钮渲染但点击无响应:验证 Mattermost 服务端配置中 AllowedUntrustedInternalConnections 包含 127.0.0.1 localhost,且 EnablePostActionIntegration 在 ServiceSettings 中为 true
  • 按钮点击返回 404:按钮 id 可能包含连字符或下划线。Mattermost 的 action 路由不支持非字母数字字符,请仅使用 [a-zA-Z0-9]
  • Gateway 日志 invalid _token:HMAC 不匹配。检查是否对所有 context 字段(而非子集)签名,使用了键排序,以及紧凑 JSON(无空格)。详见上方 HMAC 部分。
  • Gateway 日志 missing _token in context_token 字段未在按钮 context 中。构建集成载荷时确保包含该字段。
  • 确认消息显示原始 ID 而非按钮名称:context.action_id 与按钮的 id 不一致,将两者设置为相同的清理后值。
  • 智能体不知道按钮的存在:在 Mattermost 频道配置中添加 capabilities: ["inlineButtons"]