Mattermost (plugin)
Trạng thái: hỗ trợ qua plugin (bot token + sự kiện WebSocket). Hỗ trợ kênh, nhóm và tin nhắn trực tiếp (DM).
Mattermost là nền tảng nhắn tin nhóm có thể tự host; xem chi tiết sản phẩm và tải xuống tại
trang chính thức của Mattermost.
Yêu cầu plugin
Mattermost được cung cấp dưới dạng plugin và không đi kèm với cài đặt gốc.
Cài đặt qua CLI (npm registry):
openclaw plugins install @openclaw/mattermost
Kiểm tra cục bộ (khi chạy từ repo git):
openclaw plugins install ./extensions/mattermost
Nếu chọn Mattermost trong quá trình thiết lập và phát hiện có git checkout,
OpenClaw sẽ tự động cung cấp đường dẫn cài đặt cục bộ.
Chi tiết: Plugins
Thiết lập nhanh
- Cài đặt plugin Mattermost.
- Tạo tài khoản bot Mattermost và sao chép bot token.
- Sao chép base URL của Mattermost (ví dụ:
https://chat.example.com).
- Cấu hình OpenClaw và khởi động gateway.
Cấu hình tối thiểu:
{
channels: {
mattermost: {
enabled: true,
botToken: "mm-token",
baseUrl: "https://chat.example.com",
dmPolicy: "pairing",
},
},
}
Lệnh gạch chéo gốc
Lệnh gạch chéo gốc là tùy chọn. Khi bật, OpenClaw đăng ký các lệnh gạch chéo oc_* qua
API của Mattermost và nhận các callback POST trên máy chủ HTTP của gateway.
{
channels: {
mattermost: {
commands: {
native: true,
nativeSkills: true,
callbackPath: "/api/channels/mattermost/command",
// Sử dụng khi Mattermost không thể truy cập trực tiếp vào gateway (reverse proxy/public URL).
callbackUrl: "https://gateway.example.com/api/channels/mattermost/command",
},
},
},
}
Lưu ý:
native: "auto" mặc định là tắt cho Mattermost. Đặt native: true để bật.
- Nếu bỏ qua
callbackUrl, OpenClaw sẽ tự động tạo từ host/port của gateway + callbackPath.
- Đối với thiết lập nhiều tài khoản,
commands có thể được đặt ở cấp cao nhất hoặc dưới
channels.mattermost.accounts.<id>.commands (giá trị tài khoản ghi đè các trường cấp cao nhất).
- Các callback lệnh được xác thực bằng token cho từng lệnh và sẽ thất bại nếu kiểm tra token thất bại.
- Yêu cầu khả năng truy cập: endpoint callback phải có thể truy cập từ máy chủ Mattermost.
- Không đặt
callbackUrl là localhost trừ khi Mattermost chạy trên cùng một host/network namespace với OpenClaw.
- Không đặt
callbackUrl là URL cơ sở của Mattermost trừ khi URL đó reverse-proxies /api/channels/mattermost/command đến OpenClaw.
- Kiểm tra nhanh là
curl https://<gateway-host>/api/channels/mattermost/command; một GET nên trả về 405 Method Not Allowed từ OpenClaw, không phải 404.
- Yêu cầu danh sách cho phép egress của Mattermost:
- Nếu mục tiêu callback của bạn là địa chỉ private/tailnet/internal, đặt Mattermost
ServiceSettings.AllowedUntrustedInternalConnections để bao gồm host/domain của callback.
- Sử dụng các mục host/domain, không phải URL đầy đủ.
- Tốt:
gateway.tailnet-name.ts.net
- Xấu:
https://gateway.tailnet-name.ts.net
Biến môi trường (tài khoản mặc định)
Đặt các biến này trên host của gateway nếu bạn thích sử dụng biến môi trường:
MATTERMOST_BOT_TOKEN=...
MATTERMOST_URL=https://chat.example.com
Biến môi trường chỉ áp dụng cho tài khoản mặc định (default). Các tài khoản khác phải sử dụng giá trị cấu hình.
Chế độ chat
Mattermost tự động phản hồi các tin nhắn trực tiếp (DM). Hành vi trong kênh được kiểm soát bởi chatmode:
oncall (mặc định): chỉ phản hồi khi được @mention trong kênh.
onmessage: phản hồi mọi tin nhắn trong kênh.
onchar: phản hồi khi tin nhắn bắt đầu bằng một tiền tố kích hoạt.
Ví dụ cấu hình:
{
channels: {
mattermost: {
chatmode: "onchar",
oncharPrefixes: [">", "!"],
},
},
}
Lưu ý:
onchar vẫn phản hồi khi được @mention rõ ràng.
channels.mattermost.requireMention được tôn trọng cho cấu hình cũ nhưng chatmode được ưu tiên.
Luồng và phiên
Sử dụng channels.mattermost.replyToMode để kiểm soát xem các phản hồi trong kênh và nhóm có ở lại trong
kênh chính hay bắt đầu một luồng dưới bài đăng kích hoạt.
off (mặc định): chỉ trả lời trong một luồng khi bài đăng đầu vào đã ở trong một luồng.
first: đối với các bài đăng cấp cao nhất trong kênh/nhóm, bắt đầu một luồng dưới bài đăng đó và định tuyến
cuộc trò chuyện đến một phiên có phạm vi luồng.
all: hành vi tương tự như first cho Mattermost hiện nay.
- Tin nhắn trực tiếp bỏ qua cài đặt này và không có luồng.
Ví dụ cấu hình:
{
channels: {
mattermost: {
replyToMode: "all",
},
},
}
Lưu ý:
- Các phiên có phạm vi luồng sử dụng id bài đăng kích hoạt làm gốc luồng.
first và all hiện tại tương đương nhau vì một khi Mattermost có gốc luồng,
các phần tiếp theo và phương tiện tiếp tục trong cùng một luồng.
Kiểm soát truy cập (DMs)
- Mặc định:
channels.mattermost.dmPolicy = "pairing" (người gửi không xác định nhận mã ghép đôi).
- Phê duyệt qua:
openclaw pairing list mattermost
openclaw pairing approve mattermost <CODE>
- Tin nhắn trực tiếp công khai:
channels.mattermost.dmPolicy="open" cộng với channels.mattermost.allowFrom=["*"].
Kênh (nhóm)
- Mặc định:
channels.mattermost.groupPolicy = "allowlist" (được kiểm soát bởi mention).
- Danh sách cho phép người gửi với
channels.mattermost.groupAllowFrom (khuyến nghị sử dụng ID người dùng).
- Khớp
@username có thể thay đổi và chỉ được bật khi channels.mattermost.dangerouslyAllowNameMatching: true.
- Kênh mở:
channels.mattermost.groupPolicy="open" (được kiểm soát bởi mention).
- Ghi chú runtime: nếu
channels.mattermost hoàn toàn thiếu, runtime sẽ quay lại groupPolicy="allowlist" cho kiểm tra nhóm (ngay cả khi channels.defaults.groupPolicy được đặt).
Mục tiêu cho việc gửi đi
Sử dụng các định dạng mục tiêu này với openclaw message send hoặc cron/webhooks:
channel:<id> cho một kênh
user:<id> cho một DM
@username cho một DM (được giải quyết qua API của Mattermost)
ID không rõ ràng (như 64ifufp...) là không rõ ràng trong Mattermost (ID người dùng so với ID kênh).
OpenClaw giải quyết chúng ưu tiên người dùng:
- Nếu ID tồn tại dưới dạng người dùng (
GET /api/v4/users/<id> thành công), OpenClaw gửi một DM bằng cách giải quyết kênh trực tiếp qua /api/v4/channels/direct.
- Nếu không, ID được coi là ID kênh.
Nếu cần hành vi xác định, luôn sử dụng các tiền tố rõ ràng (user:<id> / channel:<id>).
Thử lại kênh DM
Khi OpenClaw gửi đến mục tiêu DM của Mattermost và cần giải quyết kênh trực tiếp trước, nó
thử lại các lỗi tạo kênh trực tiếp tạm thời theo mặc định.
Sử dụng channels.mattermost.dmChannelRetry để điều chỉnh hành vi đó toàn cầu cho plugin Mattermost,
hoặc channels.mattermost.accounts.<id>.dmChannelRetry cho một tài khoản.
{
channels: {
mattermost: {
dmChannelRetry: {
maxRetries: 3,
initialDelayMs: 1000,
maxDelayMs: 10000,
timeoutMs: 30000,
},
},
},
}
Lưu ý:
- Điều này chỉ áp dụng cho việc tạo kênh DM (
/api/v4/channels/direct), không phải mọi cuộc gọi API của Mattermost.
- Thử lại áp dụng cho các lỗi tạm thời như giới hạn tốc độ, phản hồi 5xx và lỗi mạng hoặc timeout.
- Các lỗi client 4xx khác ngoài
429 được coi là vĩnh viễn và không được thử lại.
Phản ứng (công cụ tin nhắn)
- Sử dụng
message action=react với channel=mattermost.
messageId là id bài đăng của Mattermost.
emoji chấp nhận các tên như thumbsup hoặc :+1: (dấu hai chấm là tùy chọn).
- Đặt
remove=true (boolean) để xóa một phản ứng.
- Các sự kiện thêm/xóa phản ứng được chuyển tiếp dưới dạng sự kiện hệ thống đến phiên agent được định tuyến.
Ví dụ:
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
Cấu hình:
channels.mattermost.actions.reactions: bật/tắt hành động phản ứng (mặc định là true).
- Ghi đè theo tài khoản:
channels.mattermost.accounts.<id>.actions.reactions.
Nút tương tác (công cụ tin nhắn)
Gửi tin nhắn với các nút có thể nhấp. Khi người dùng nhấp vào nút, agent nhận được
lựa chọn và có thể phản hồi.
Bật nút bằng cách thêm inlineButtons vào khả năng của kênh:
{
channels: {
mattermost: {
capabilities: ["inlineButtons"],
},
},
}
Sử dụng message action=send với tham số buttons. Nút là một mảng 2D (các hàng của nút):
message action=send channel=mattermost target=channel:<channelId> buttons=[[{"text":"Yes","callback_data":"yes"},{"text":"No","callback_data":"no"}]]
Các trường của nút:
text (bắt buộc): nhãn hiển thị.
callback_data (bắt buộc): giá trị gửi lại khi nhấp (được sử dụng làm ID hành động).
style (tùy chọn): "default", "primary", hoặc "danger".
Khi người dùng nhấp vào nút:
- Tất cả các nút được thay thế bằng một dòng xác nhận (ví dụ: ”✓ Yes được chọn bởi @user”).
- Agent nhận được lựa chọn dưới dạng tin nhắn đầu vào và phản hồi.
Lưu ý:
- Các callback của nút sử dụng xác minh HMAC-SHA256 (tự động, không cần cấu hình).
- Mattermost loại bỏ dữ liệu callback khỏi các phản hồi API của nó (tính năng bảo mật), vì vậy tất cả các nút
bị xóa khi nhấp — không thể xóa một phần.
- Các ID hành động chứa dấu gạch ngang hoặc gạch dưới được tự động làm sạch
(giới hạn định tuyến của Mattermost).
Cấu hình:
channels.mattermost.capabilities: mảng các chuỗi khả năng. Thêm "inlineButtons" để
bật mô tả công cụ nút trong lời nhắc hệ thống của agent.
channels.mattermost.interactions.callbackBaseUrl: URL cơ sở bên ngoài tùy chọn cho các callback của nút
(ví dụ https://gateway.example.com). Sử dụng điều này khi Mattermost không thể
truy cập vào gateway tại host bind của nó trực tiếp.
- Trong các thiết lập nhiều tài khoản, bạn cũng có thể đặt cùng một trường dưới
channels.mattermost.accounts.<id>.interactions.callbackBaseUrl.
- Nếu
interactions.callbackBaseUrl bị bỏ qua, OpenClaw sẽ tự động tạo URL callback từ
gateway.customBindHost + gateway.port, sau đó quay lại http://localhost:<port>.
- Quy tắc khả năng truy cập: URL callback của nút phải có thể truy cập từ máy chủ Mattermost.
localhost chỉ hoạt động khi Mattermost và OpenClaw chạy trên cùng một host/network namespace.
- Nếu mục tiêu callback của bạn là private/tailnet/internal, thêm host/domain của nó vào Mattermost
ServiceSettings.AllowedUntrustedInternalConnections.
Tích hợp API trực tiếp (script bên ngoài)
Các script bên ngoài và webhooks có thể đăng nút trực tiếp qua API REST của Mattermost
thay vì thông qua công cụ message của agent. Sử dụng buildButtonAttachments() từ
extension khi có thể; nếu đăng JSON thô, tuân theo các quy tắc sau:
Cấu trúc payload:
{
channel_id: "<channelId>",
message: "Chọn một tùy chọn:",
props: {
attachments: [
{
actions: [
{
id: "mybutton01", // chỉ chữ và số — xem bên dưới
type: "button", // bắt buộc, nếu không nhấp sẽ bị bỏ qua
name: "Approve", // nhãn hiển thị
style: "primary", // tùy chọn: "default", "primary", "danger"
integration: {
url: "https://gateway.example.com/mattermost/interactions/default",
context: {
action_id: "mybutton01", // phải khớp với id của nút (để tra cứu tên)
action: "approve",
// ... bất kỳ trường tùy chỉnh nào ...
_token: "<hmac>", // xem phần HMAC bên dưới
},
},
},
],
},
],
},
}
Quy tắc quan trọng:
- Attachments đi vào
props.attachments, không phải attachments cấp cao nhất (bị bỏ qua).
- Mỗi hành động cần
type: "button" — nếu không có, nhấp sẽ bị bỏ qua.
- Mỗi hành động cần một trường
id — Mattermost bỏ qua các hành động không có ID.
- ID hành động phải chỉ chữ và số (
[a-zA-Z0-9]). Dấu gạch ngang và gạch dưới làm hỏng
định tuyến hành động của Mattermost (trả về 404). Loại bỏ chúng trước khi sử dụng.
context.action_id phải khớp với id của nút để thông báo xác nhận hiển thị tên
nút (ví dụ: “Approve”) thay vì ID thô.
context.action_id là bắt buộc — trình xử lý tương tác trả về 400 nếu không có.
Tạo token HMAC:
Gateway xác minh các lần nhấp nút bằng HMAC-SHA256. Các script bên ngoài phải tạo token
khớp với logic xác minh của gateway:
- Tạo secret từ bot token:
HMAC-SHA256(key="openclaw-mattermost-interactions", data=botToken)
- Xây dựng đối tượng context với tất cả các trường trừ
_token.
- Tuần tự hóa với các khóa được sắp xếp và không có khoảng trắng (gateway sử dụng
JSON.stringify
với các khóa được sắp xếp, tạo ra đầu ra gọn gàng).
- Ký:
HMAC-SHA256(key=secret, data=serializedContext)
- Thêm mã băm hex kết quả làm
_token trong context.
Ví dụ 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}
Các lỗi phổ biến của HMAC:
json.dumps của Python thêm khoảng trắng theo mặc định ({"key": "val"}). Sử dụng
separators=(",", ":") để khớp với đầu ra gọn gàng của JavaScript ({"key":"val"}).
- Luôn ký tất cả các trường context (trừ
_token). Gateway loại bỏ _token rồi
ký tất cả những gì còn lại. Ký một phần gây ra lỗi xác minh im lặng.
- Sử dụng
sort_keys=True — gateway sắp xếp các khóa trước khi ký, và Mattermost có thể
sắp xếp lại các trường context khi lưu trữ payload.
- Tạo secret từ bot token (xác định), không phải byte ngẫu nhiên. Secret
phải giống nhau trên quá trình tạo nút và gateway xác minh.
Bộ điều hợp thư mục
Plugin Mattermost bao gồm một bộ điều hợp thư mục giải quyết tên kênh và người dùng
qua API của Mattermost. Điều này cho phép #channel-name và @username làm mục tiêu trong
openclaw message send và các giao hàng cron/webhook.
Không cần cấu hình — bộ điều hợp sử dụng bot token từ cấu hình tài khoản.
Nhiều tài khoản
Mattermost hỗ trợ nhiều tài khoản dưới 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" },
},
},
},
}
Gỡ lỗi
- Không có phản hồi trong kênh: đảm bảo bot có trong kênh và mention nó (oncall), sử dụng tiền tố kích hoạt (onchar), hoặc đặt
chatmode: "onmessage".
- Lỗi xác thực: kiểm tra bot token, base URL và xem tài khoản có được bật không.
- Vấn đề nhiều tài khoản: biến môi trường chỉ áp dụng cho tài khoản
default.
- Nút xuất hiện dưới dạng hộp trắng: agent có thể đang gửi dữ liệu nút không hợp lệ. Kiểm tra rằng mỗi nút có cả trường
text và callback_data.
- Nút hiển thị nhưng nhấp không có tác dụng: xác minh
AllowedUntrustedInternalConnections trong cấu hình máy chủ Mattermost bao gồm 127.0.0.1 localhost, và rằng EnablePostActionIntegration là true trong ServiceSettings.
- Nút trả về 404 khi nhấp: ID của nút có thể chứa dấu gạch ngang hoặc gạch dưới. Bộ định tuyến hành động của Mattermost bị lỗi với các ID không phải chữ và số. Sử dụng
[a-zA-Z0-9] chỉ.
- Gateway ghi
invalid _token: không khớp HMAC. Kiểm tra rằng bạn ký tất cả các trường context (không phải một phần), sử dụng các khóa được sắp xếp, và sử dụng JSON gọn gàng (không có khoảng trắng). Xem phần HMAC ở trên.
- Gateway ghi
missing _token in context: trường _token không có trong context của nút. Đảm bảo nó được bao gồm khi xây dựng payload tích hợp.
- Xác nhận hiển thị ID thô thay vì tên nút:
context.action_id không khớp với id của nút. Đặt cả hai thành cùng một giá trị đã được làm sạch.
- Agent không biết về nút: thêm
capabilities: ["inlineButtons"] vào cấu hình kênh Mattermost.
Last modified on March 22, 2026