Mattermost(插件)
状态:通过插件支持(Bot Token + WebSocket 事件)。支持频道、群组和私信。 Mattermost 是一个可自托管的团队通讯平台;详情请访问官方网站 mattermost.com。
需要安装插件
Mattermost 以插件形式提供,不包含在核心安装中。
通过 CLI 安装(npm 注册表):
openclaw plugins install @openclaw/mattermost
本地 checkout(从 git 仓库运行时):
openclaw plugins install ./extensions/mattermost
如果你在配置/引导过程中选择 Mattermost 且检测到 git checkout,OpenClaw 会自动提供本地安装路径。
详情:插件
快速设置
- 安装 Mattermost 插件。
- 创建 Mattermost Bot 账户并复制 Bot Token。
- 复制 Mattermost 基础 URL(例如
https://chat.example.com)。 - 配置 OpenClaw 并启动 Gateway。
最小配置:
{
channels: {
mattermost: {
enabled: true,
botToken: "mm-token",
baseUrl: "https://chat.example.com",
dmPolicy: "pairing",
},
},
}
原生斜杠命令
原生斜杠命令需要手动启用。启用后,OpenClaw 通过 Mattermost API 注册 oc_* 斜杠命令,并在 Gateway HTTP 服务器上接收回调 POST。
{
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 host/port +callbackPath推导。 - 多账户设置中,
commands可在顶层或channels.mattermost.accounts.<id>.commands下设置(账户值覆盖顶层字段)。 - 命令回调通过按命令的 Token 验证,Token 检查失败时安全关闭。
- 可达性要求:回调端点必须可从 Mattermost 服务器访问。
- 不要将
callbackUrl设为localhost,除非 Mattermost 与 OpenClaw 运行在同一主机/网络命名空间中。 - 不要将
callbackUrl设为 Mattermost 基础 URL,除非该 URL 的反向代理将/api/channels/mattermost/command转发到 OpenClaw。 - 快速检查方式:
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
- 正确:
- 如果回调目标为私有/tailnet/内网地址,需将 Mattermost 的
环境变量(默认账户)
在 Gateway 主机上设置以下环境变量(如果你偏好使用环境变量):
MATTERMOST_BOT_TOKEN=...MATTERMOST_URL=https://chat.example.com
环境变量仅适用于默认账户(default)。其他账户必须使用配置值。
聊天模式
Mattermost 自动响应私信。频道行为由 chatmode 控制:
oncall(默认):仅在频道中被 @提及时回复。onmessage:回复每条频道消息。onchar:当消息以触发前缀开头时回复。
配置示例:
{
channels: {
mattermost: {
chatmode: "onchar",
oncharPrefixes: [">", "!"],
},
},
}
说明:
onchar模式下仍然会响应显式的 @提及。channels.mattermost.requireMention在旧版配置中仍有效,但推荐使用chatmode。
线程与会话
使用 channels.mattermost.replyToMode 控制频道和群组回复是留在主频道还是在触发帖子下开启线程。
off(默认):仅在入站帖子已在线程中时才在线程中回复。first:对顶层频道/群组帖子,在该帖子下开启线程并将对话路由到线程范围的会话。all:目前与first行为相同。- 私信忽略此设置,保持非线程化。
配置示例:
{
channels: {
mattermost: {
replyToMode: "all",
},
},
}
说明:
- 线程范围的会话使用触发帖子 ID 作为线程根。
first和all目前等效,因为一旦 Mattermost 有了线程根,后续分块和媒体会继续在同一线程中。
访问控制(私信)
- 默认:
channels.mattermost.dmPolicy = "pairing"(未知发送者收到配对码)。 - 通过以下方式批准:
openclaw pairing list mattermostopenclaw 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>)。
表情回应(消息工具)
- 使用
message action=react,channel=mattermost。 messageId是 Mattermost 帖子 ID。emoji接受如thumbsup或:+1:的名称(冒号可选)。- 设置
remove=true(布尔值)移除回应。 - 添加/移除回应事件会作为系统事件转发到路由的 Agent 会话。
示例:
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。
交互式按钮(消息工具)
发送带可点击按钮的消息。用户点击按钮后,Agent 会接收选择并作出响应。
通过在频道能力中添加 inlineButtons 启用按钮:
{
channels: {
mattermost: {
capabilities: ["inlineButtons"],
},
},
}
使用 message action=send 并传入 buttons 参数。按钮是一个二维数组(按钮行):
message action=send channel=mattermost target=channel:<channelId> buttons=[[{"text":"Yes","callback_data":"yes"},{"text":"No","callback_data":"no"}]]
按钮字段:
text(必填):显示标签。callback_data(必填):点击时发回的值(用作 action ID)。style(可选):"default"、"primary"或"danger"。
用户点击按钮时:
- 所有按钮被替换为确认行(例如 ”✓ Yes selected by @user”)。
- Agent 接收选择作为入站消息并作出响应。
说明:
- 按钮回调使用 HMAC-SHA256 验证(自动进行,无需配置)。
- Mattermost 会从其 API 响应中剥离 callback data(安全特性),因此点击时会移除所有按钮——无法部分移除。
- 包含连字符或下划线的 Action ID 会自动清理(Mattermost 路由限制)。
配置:
channels.mattermost.capabilities:能力字符串数组。添加"inlineButtons"以在 Agent 系统提示中启用按钮工具描述。channels.mattermost.interactions.callbackBaseUrl:按钮回调的可选外部基础 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 发送按钮,而无需通过 Agent 的 message 工具。如有可能请使用扩展中的 buildButtonAttachments();如果直接发送 JSON,请遵循以下规则:
Payload 结构:
{
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 部分
},
},
},
],
},
],
},
}
关键规则:
- 附件放在
props.attachments中,而非顶层attachments(否则会被静默忽略)。 - 每个 action 需要
type: "button"——没有它点击会被静默吞掉。 - 每个 action 需要
id字段——Mattermost 忽略没有 ID 的 action。 - Action
id必须仅含字母数字([a-zA-Z0-9])。连字符和下划线会破坏 Mattermost 的服务端 action 路由(返回 404)。使用前请剥离。 context.action_id必须与按钮的id匹配,确认消息才会显示按钮名称(如 “Approve”)而非原始 ID。context.action_id是必填的——交互处理器没有它会返回 400。
HMAC Token 生成:
Gateway 使用 HMAC-SHA256 验证按钮点击。外部脚本必须生成与 Gateway 验证逻辑匹配的 Token:
- 从 Bot Token 派生密钥:
HMAC-SHA256(key="openclaw-mattermost-interactions", data=botToken) - 构建包含所有字段(除
_token外)的 context 对象。 - 使用排序键和无空格序列化(Gateway 使用排序键的
JSON.stringify,产生紧凑输出)。 - 签名:
HMAC-SHA256(key=secret, data=serializedContext) - 将结果十六进制摘要作为
_token添加到 context 中。
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 存储 payload 时可能重排 context 字段。 - 从 Bot Token 派生密钥(确定性),而非随机字节。创建按钮的进程和验证的 Gateway 必须使用相同的密钥。
目录适配器
Mattermost 插件包含一个目录适配器,通过 Mattermost API 解析频道和用户名称。这使得 openclaw message send 和 cron/webhook 投递中可以使用 #channel-name 和 @username 目标。
无需配置——适配器使用账户配置中的 Bot Token。
多账户
Mattermost 支持在 channels.mattermost.accounts 下配置多个账户:
{
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" },
},
},
},
}
故障排查
- 频道无回复:确保 Bot 在频道中,并提及它(oncall),使用触发前缀(onchar),或设置
chatmode: "onmessage"。 - 认证错误:检查 Bot Token、基础 URL 以及账户是否已启用。
- 多账户问题:环境变量仅适用于
default账户。 - 按钮显示为白框:Agent 可能发送了格式错误的按钮数据。检查每个按钮是否同时具有
text和callback_data字段。 - 按钮渲染但点击无效:验证 Mattermost 服务器配置中
AllowedUntrustedInternalConnections是否包含127.0.0.1 localhost,以及 ServiceSettings 中EnablePostActionIntegration是否为true。 - 按钮点击返回 404:按钮
id可能包含连字符或下划线。Mattermost 的 action 路由在非字母数字 ID 上会出错。仅使用[a-zA-Z0-9]。 - Gateway 日志
invalid _token:HMAC 不匹配。检查是否签名了所有 context 字段(而非子集),使用了排序键和紧凑 JSON(无空格)。参见上方 HMAC 部分。 - Gateway 日志
missing _token in context:按钮 context 中缺少_token字段。确保构建 integration payload 时包含它。 - 确认消息显示原始 ID 而非按钮名称:
context.action_id与按钮的id不匹配。将两者设为相同的清理值。 - Agent 不知道按钮功能:在 Mattermost 频道配置中添加
capabilities: ["inlineButtons"]。