Developer and self-hosted

Mattermost

状态:可下载插件(Bot 令牌 + WebSocket 事件)。支持频道、私密频道、群组私信和私信。Mattermost 是一个可自行托管的团队消息平台(mattermost.com)。

安装

npm registry

bash
openclaw plugins install @openclaw/mattermost

Local checkout

bash
openclaw plugins install ./path/to/local/mattermost-plugin

详情:插件

快速设置

  • 确保插件可用

    使用上述命令安装 @openclaw/mattermost,如果 Gateway 网关已在运行,请重启它。

  • 创建 Mattermost Bot

    创建一个 Mattermost Bot 账户,复制 Bot 令牌,并将 Bot 添加到它应读取的团队和频道中。

  • 复制基础 URL

    复制 Mattermost 基础 URL(例如 https://chat.example.com)。末尾的 /api/v4 会自动移除。

  • 配置 OpenClaw 并启动 Gateway 网关

    最小配置:

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

    非交互式替代方案:

    bash
    openclaw channels add --channel mattermost --bot-token <token> --http-url https://chat.example.com
  • 原生斜杠命令

    原生斜杠命令需要选择启用。启用后,OpenClaw 会在 Bot 所属的每个团队中注册 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",      },    },  },}

    注册的命令:/oc_status/oc_model/oc_models/oc_new/oc_help/oc_think/oc_reasoning/oc_verbose/oc_queue。使用 nativeSkills: true 时,技能命令也会注册为 /oc_<skill>

    行为说明
    • nativenativeSkills 默认为 "auto",对于 Mattermost,这会解析为禁用。请将它们显式设置为 true
    • callbackPath 默认为 /api/channels/mattermost/command
    • 如果省略 callbackUrl,OpenClaw 会派生 http://<gateway.customBindHost or localhost>:<gateway.port, default 18789><callbackPath>。通配绑定主机(0.0.0.0::)会回退到 localhost
    • 对于多账户设置,可以在顶层或 channels.mattermost.accounts.<id>.commands 下设置 commands(账户值会覆盖顶层字段)。
    • 由其他集成创建且触发词相同的现有斜杠命令会保持不变(注册时会跳过);当回调 URL 发生偏移时,Bot 创建的命令会被更新或重新创建。
    • 命令回调使用 OpenClaw 注册 oc_* 命令时 Mattermost 返回的每命令令牌进行验证。
    • OpenClaw 会在接受每个回调前刷新当前的 Mattermost 命令注册,因此已删除或重新生成的斜杠命令所对应的过期令牌无需重启 Gateway 网关便会停止被接受。
    • 如果 Mattermost API 无法确认命令仍为当前命令,回调验证会以关闭方式失败;失败的验证会被短暂缓存,并发查找会合并处理,并且每个命令的新查找启动会受到速率限制,以约束重放压力。
    • 如果注册失败、启动未完整完成,或回调令牌与解析到的命令所注册的令牌不匹配,斜杠回调会以关闭方式失败(对某一命令有效的令牌无法通过其他命令到达上游验证)。
    • 已接受的回调会通过一条仅发送者可见的“处理中...”回复进行确认;实际回答会作为普通消息送达。
    可访问性要求

    Mattermost 服务器必须能够访问回调端点。

    • 除非 Mattermost 与 OpenClaw 运行在同一主机/网络命名空间中,否则不要将 callbackUrl 设置为 localhost
    • 除非你的 Mattermost 基础 URL 会将 /api/channels/mattermost/command 反向代理到 OpenClaw,否则不要将 callbackUrl 设置为该基础 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

    聊天模式

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

    oncall (default)

    仅在频道中被 @提及时回复。

    onmessage

    回复每条频道消息。

    onchar

    当消息以触发前缀开头时回复。

    配置示例:

    json5
    {  channels: {    mattermost: {      chatmode: "onchar",      oncharPrefixes: [">", "!"], // 默认值    },  },}

    说明:

    • onchar 仍会响应显式 @提及。
    • 仍支持 channels.mattermost.requireMention,但首选 chatmode。每频道的 groups.<channelId>.requireMention 设置优先于二者。
    • Bot 在频道帖子串中发送可见回复后,同一帖子串中的后续消息无需新的 @提及或 onchar 前缀即可得到回复,从而保持多轮帖子串对话持续进行。参与状态会从 Bot 最后一次回复该帖子串起保留 7 天,并在 Gateway 网关重启后继续保留。Bot 仅观察过的帖子串不受影响;若要重新要求显式提及,请发起新的顶层消息。
    • channels.mattermost.implicitMentions.threadParticipation: false 设置为停止让已参与帖子串的后续消息绕过提及门控。账户覆盖使用 channels.mattermost.accounts.<id>.implicitMentions。Mattermost 目前不会产生 replyToBotquotedBot 事实,因此这些标志在此处不起作用。

    帖子串和会话

    使用 channels.mattermost.replyToMode 控制频道和群组回复是保留在主频道中,还是在触发帖子下启动帖子串。

    • off(默认):仅当入站帖子已位于帖子串中时,才在帖子串中回复。
    • first:对于顶层频道/群组帖子,在该帖子下启动帖子串,并将对话路由到帖子串范围的会话。
    • 目前对于 Mattermost,allbatched 的行为与 first 相同,因为 Mattermost 一旦存在帖子串根,后续分块和媒体就会继续发送到同一帖子串。
    • 即使已设置 replyToMode,私信仍默认为 off

    使用 channels.mattermost.replyToModeByChatType 覆盖 directgroupchannel 聊天的模式。设置 direct 以选择让私信使用帖子串:

    • off(默认):私信保持不使用帖子串,并共用一个滚动会话。
    • firstallbatched:每条顶层私信都会启动一个 Mattermost 帖子串,并由一个全新、独立的会话提供支持。
    json5
    {  channels: {    mattermost: {      replyToMode: "all",      replyToModeByChatType: {        direct: "first",      },    },  },}

    说明:

    • 帖子串范围的会话使用触发帖子的 ID 作为帖子串根。
    • firstall 目前等效,因为 Mattermost 一旦存在帖子串根,后续分块和媒体就会继续发送到同一帖子串。
    • 每聊天类型的覆盖优先于 replyToMode。如果没有 direct 覆盖,现有部署会继续使用扁平、不分帖子的私信。

    访问控制(私信)

    • 默认值:channels.mattermost.dmPolicy = "pairing"(未知发送者会收到配对码)。其他值:allowlistopendisabled
    • 批准方式:
      • openclaw pairing list mattermost
      • openclaw pairing approve mattermost &lt;CODE&gt;
    • 公开私信:channels.mattermost.dmPolicy="open"channels.mattermost.allowFrom=["*"](配置架构会强制要求通配符)。
    • channels.mattermost.allowFrom 接受用户 ID(推荐)和 accessGroup:<name> 条目。请参阅访问组

    频道(群组)

    • 默认值:channels.mattermost.groupPolicy = "allowlist"(需要提及)。
    • 使用 channels.mattermost.groupAllowFrom 将发送者加入允许列表(推荐使用用户 ID)。
    • channels.mattermost.groupAllowFrom 接受 accessGroup:<name> 条目。请参阅访问组
    • 每频道的提及覆盖位于 channels.mattermost.groups.<channelId>.requireMention 下,也可使用 channels.mattermost.groups["*"].requireMention 设置默认值。
    • @username 匹配是可变的,并且仅在 channels.mattermost.dangerouslyAllowNameMatching: true 时启用。
    • 开放频道:channels.mattermost.groupPolicy="open"(需要提及)。
    • 解析顺序:先 channels.mattermost.groupPolicy,再 channels.defaults.groupPolicy,最后 "allowlist"
    • 运行时说明:如果完全缺少 channels.mattermost 部分,运行时会针对群组检查以关闭方式回退到 groupPolicy="allowlist"(即使已设置 channels.defaults.groupPolicy),并记录一次性警告。

    示例:

    json5
    {  channels: {    mattermost: {      groupPolicy: "open",      groups: {        "*": { requireMention: true },        "team-channel-id": { requireMention: false },      },    },  },}

    出站投递目标

    将以下目标格式与 openclaw message send 或定时任务/Webhooks 一起使用:

    目标 投递至
    channel:<id> 按 ID 指定的频道
    channel:<name>#channel-name 按名称指定的频道,在 Bot 所属的所有团队中搜索
    user:<id>mattermost:<id> 与该用户的私信
    @username 私信(通过 Mattermost API 解析用户名)

    每条出站消息最多支持一个附件;请将多个文件拆分为多次发送。

    私信频道重试

    当 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 客户端错误会被视为永久性错误,不会重试。

    预览流式传输

    Mattermost 会将思考过程、工具活动和部分回复文本流式传输到一个草稿预览帖子中,并在最终答案可安全发送时原地完成该帖子。在 partial 模式下,预览会在同一帖子 ID 上更新,而不是为每个分块发送消息来刷屏。在 block 模式下,预览会在已完成文本与工具活动块之间轮换,因此较早的块会作为独立帖子保持可见,而不会被下一个块覆盖。包含媒体或错误的最终结果会取消待处理的预览编辑,并改用正常投递,而不是提交一个无用的预览帖子。

    预览流式传输在 partial 模式下默认开启。通过 channels.mattermost.streaming.mode 配置(旧版标量/布尔值 streaming 会由 openclaw doctor --fix 迁移):

    json5
    {  channels: {    mattermost: {      streaming: { mode: "partial" }, // 关闭 | 部分 | 分块 | 进度    },  },}
    流式传输模式
    • partial(默认):使用一个预览帖子,随着回复内容增加而编辑,最后用完整答案完成。
    • block 会在已完成文本与工具活动块之间轮换预览,因此每个块都会作为独立帖子保持可见,而不会被原地覆盖。并行和连续的工具更新会共享当前工具活动帖子。
    • progress 会在生成期间显示状态预览,仅在完成时发布最终答案。
    • off 会禁用预览流式传输。使用 streaming.block.enabled: true 时,已完成的助手块仍会作为普通分块回复(独立帖子)投递,而不是合并为单个最终帖子。
    流式传输行为说明
    • 如果无法原地完成流式传输(例如帖子在传输过程中被删除),OpenClaw 会回退为发送新的最终帖子,以确保回复绝不丢失。
    • 仅包含思考过程的载荷不会发布到频道帖子中,包括以 > Thinking 引用块形式到达的文本。设置 /reasoning on 可在其他界面中查看思考过程;Mattermost 最终帖子只保留答案。
    • 有关频道映射矩阵,请参阅流式传输

    表情回应(消息工具)

    • message action=reactchannel=mattermost 一起使用。
    • messageId 是 Mattermost 帖子 ID。
    • emoji 接受 thumbsup:+1: 之类的名称(冒号可选)。
    • 设置 remove=true(布尔值)可移除表情回应。
    • 添加/移除表情回应事件会作为系统事件转发到所路由的智能体会话,并受到与消息相同的私信/群组策略检查。

    示例:

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

    配置:

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

    交互式按钮(消息工具)

    发送带有可点击按钮的消息。当用户点击按钮时,智能体会收到所选内容并可进行响应。

    按钮来自语义化 presentation 载荷(用于普通智能体回复和 message action=send)。OpenClaw 将值按钮渲染为 Mattermost 交互式按钮,在消息文本中保留 URL 按钮,并将选择菜单降级为可读文本。

    text
    message action=send channel=mattermost target=channel:<channelId> presentation={"blocks":[{"type":"buttons","buttons":[{"label":"Yes","value":"yes"},{"label":"No","value":"no"}]}]}

    呈现按钮字段:

    labelstringrequired

    显示标签(别名:text)。

    valuestring

    点击时发回的值,用作操作 ID(别名:callback_datacallbackData)。除非设置了 url,否则可点击按钮必须提供此项。

    urlstring

    链接按钮;在消息正文中渲染为 label: url 文本,而不是交互式按钮。

    style"primary" | "secondary" | "success" | "danger"

    按钮样式。对于 Mattermost 不支持的值,将应用默认样式。

    要在智能体系统提示词中声明支持按钮,请将 inlineButtons 添加到频道能力中:

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

    当用户点击按钮时:

  • 访问检查

    点击者必须通过与消息发送者相同的私信/群组策略检查;未经授权的点击会收到一条临时通知,并被忽略。

  • 用确认信息替换按钮

    所有按钮都会替换为一行确认信息(例如,“✓ Yes 已由 @user 选择”)。

  • 智能体收到所选内容

    智能体会将所选内容作为入站消息(以及系统事件)接收并进行响应。

  • 实现说明
    • 按钮回调使用 HMAC-SHA256 验证(自动进行,无需配置)。
    • 点击时会替换整个附件块,因此所有按钮会一起移除,无法只移除一部分。
    • 包含连字符或下划线的操作 ID 会被自动清理(Mattermost 路由限制)。
    • 如果点击的 action_id 与原始帖子中的任何操作都不匹配,则会被拒绝并返回 403(“未知操作”)。
    配置和可达性
    • channels.mattermost.capabilities:能力字符串数组。添加 "inlineButtons" 可在智能体系统提示词中启用按钮工具说明。
    • channels.mattermost.interactions.callbackBaseUrl:按钮回调的可选外部基础 URL(例如 https://gateway.example.com)。当 Mattermost 无法通过 Gateway 网关的绑定主机直接访问它时,请使用此项。
    • 在多账户设置中,也可以在 channels.mattermost.accounts.<id>.interactions.callbackBaseUrl 下设置相同字段。
    • 如果省略 interactions.callbackBaseUrl,OpenClaw 会根据 gateway.customBindHost + gateway.port(默认值为 18789)派生回调 URL,然后回退到 http://localhost:<port>。回调路径为 /mattermost/interactions/<accountId>
    • 可达性规则:Mattermost 服务器必须能够访问按钮回调 URL。只有当 Mattermost 和 OpenClaw 运行在同一主机/网络命名空间中时,localhost 才有效。
    • channels.mattermost.interactions.allowedSourceIps:按钮回调的源 IP 允许列表。如果未设置,则只接受回环源(127.0.0.1::1),因此必须在此处将远程 Mattermost 服务器加入允许列表,否则其点击会被拒绝并返回 403。如果位于反向代理后方,还需设置 gateway.trustedProxies,以便从转发标头中派生真实客户端 IP。
    • 如果回调目标位于私有网络、tailnet 或内部网络,请将其主机/域名添加到 Mattermost ServiceSettings.AllowedUntrustedInternalConnections

    直接 API 集成(外部脚本)

    外部脚本和 Webhooks 可以通过 Mattermost REST API 直接发布按钮,而无需通过智能体的 message 工具。建议使用 OpenClaw 的 message 工具。对于直接集成,请从 @openclaw/mattermost/api.js 导入 buildButtonAttachments;如果发布原始 JSON,请遵循以下规则:

    载荷结构:

    json5
    {  channel_id: "<channelId>",  message: "选择一个选项:",  props: {    attachments: [      {        actions: [          {            id: "mybutton01", // 只能使用字母和数字——见下文            type: "button", // 必填,否则点击会被静默忽略            name: "批准", // 显示标签            style: "primary", // 可选:"default"、"primary"、"danger"            integration: {              url: "https://gateway.example.com/mattermost/interactions/default",              context: {                action_id: "mybutton01", // 必须与按钮 ID 匹配                action: "approve",                // ... 任意自定义字段 ...                _token: "<hmac>", // 请参阅下方 HMAC 部分              },            },          },        ],      },    ],  },}

    HMAC 令牌生成

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

  • 从 Bot 令牌派生密钥

    HMAC-SHA256(key="openclaw-mattermost-interactions", data=botToken),以十六进制编码。

  • 构建上下文对象

    使用除 _token 之外的所有字段构建上下文对象。

  • 使用排序后的键进行序列化

    使用递归排序的键不含空格进行序列化(Gateway 网关也会规范化嵌套对象,并生成紧凑 JSON)。

  • 对载荷签名

    HMAC-SHA256(key=secret, data=serializedContext)

  • 添加令牌

    将生成的十六进制摘要作为上下文中的 _token 添加。

  • Python 示例:

    python
     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"})。
    • 始终对所有上下文字段(_token 除外)进行签名。Gateway 网关会移除 _token,然后对剩余所有字段签名。仅签名部分字段会导致验证静默失败。
    • 使用 sort_keys=True——Gateway 网关会在签名前对键进行排序,而 Mattermost 在存储载荷时可能会重新排列上下文字段。
    • 从 Bot 令牌派生密钥(确定性方式),不要使用随机字节。创建按钮的进程和执行验证的 Gateway 网关必须使用相同的密钥。

    目录适配器

    Mattermost 插件包含一个目录适配器,可通过 Mattermost API 解析频道和用户名。这样即可在 openclaw message send 和定时任务/webhook 投递中使用 #channel-name@username 目标。

    无需配置——适配器使用账户配置中的 Bot 令牌。

    多账户

    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" },      },    },  },}

    账户值会覆盖顶层字段;未指定账户时,channels.mattermost.defaultAccount 决定使用哪个账户。

    故障排查

    频道中没有回复

    确保 Bot 已加入频道并提及它(oncall),使用触发前缀(onchar),或设置 chatmode: "onmessage"

    身份验证或多账户错误
    • 检查 Bot 令牌、基础 URL,以及账户是否已启用。
    • 多账户问题:环境变量仅适用于 default 账户。
    • 私有/LAN Mattermost 主机需要设置 network.dangerouslyAllowPrivateNetwork: true(SSRF 防护默认阻止私有 IP)。
    原生斜杠命令失败
    • Unauthorized: invalid command token.:OpenClaw 未接受回调令牌。常见原因:
      • 斜杠命令注册失败,或在启动时仅完成了部分注册
      • 回调请求发送到了错误的 Gateway 网关/账户
      • Mattermost 中仍有旧命令指向之前的回调目标
      • Gateway 网关重启后未重新激活斜杠命令
    • 如果原生斜杠命令停止工作,请检查日志中是否有 mattermost: failed to register slash commandsmattermost: native slash commands enabled but no commands could be registered
    • 如果省略了 callbackUrl,且日志警告回调解析到了类似 http://localhost:18789/... 的环回 URL,那么仅当 Mattermost 与 OpenClaw 运行在同一主机/网络命名空间中时,该 URL 才可能可访问。请改为显式设置可从外部访问的 commands.callbackUrl
    按钮问题
    • 按钮显示为空白框或完全不显示:按钮数据格式错误。每个呈现按钮都需要 labelvalue(缺少任一字段的按钮都会被丢弃)。
    • 按钮可以显示,但点击后无反应:确认 Mattermost 服务器能够访问 Gateway 网关、Mattermost 服务器 IP 已包含在 channels.mattermost.interactions.allowedSourceIps 中(未配置时仅接受环回地址),并且对于私有目标,ServiceSettings.AllowedUntrustedInternalConnections 包含回调主机。
    • 点击按钮时返回 404:按钮的 id 可能包含连字符或下划线。Mattermost 的操作路由器无法处理非字母数字 ID。仅使用 [a-zA-Z0-9]
    • Gateway 网关记录 rejected callback source:点击请求来自 interactions.allowedSourceIps 之外的 IP。将 Mattermost 服务器或入口加入允许列表,并在反向代理后设置 gateway.trustedProxies
    • Gateway 网关记录 invalid _token:HMAC 不匹配。检查是否对所有上下文字段(而非部分字段)签名、是否对键排序,以及是否使用紧凑 JSON(无空格)。请参阅上方的 HMAC 部分。
    • Gateway 网关记录 missing _token in context:按钮上下文中不存在 _token 字段。构建集成载荷时,请确保包含该字段。
    • Gateway 网关以 Unknown action 拒绝点击:context.action_id 与帖子上任何操作的 id 都不匹配。请将二者设置为相同的清理后值。
    • 智能体不提供按钮:将 capabilities: ["inlineButtons"] 添加到 Mattermost 频道配置中。

    相关内容

    Was this useful?
    On this page

    On this page