Developer and self-hosted
Mattermost
狀態:可下載的外掛(機器人權杖 + WebSocket 事件)。支援頻道、私人頻道、群組私訊和私訊。Mattermost 是可自行託管的團隊訊息平台(mattermost.com)。
安裝
npm registry
openclaw plugins install @openclaw/mattermost本機簽出
openclaw plugins install ./path/to/local/mattermost-plugin詳細資訊:外掛
快速設定
確保外掛可用
使用上方命令安裝 @openclaw/mattermost,若閘道已在執行,請接著重新啟動閘道。
建立 Mattermost 機器人
建立 Mattermost 機器人帳號、複製機器人權杖,並將機器人加入其應讀取的團隊和頻道。
複製基底 URL
複製 Mattermost 基底 URL(例如 https://chat.example.com)。結尾的 /api/v4 會自動移除。
設定 OpenClaw 並啟動閘道
最小設定:
{ channels: { mattermost: { enabled: true, botToken: "mm-token", baseUrl: "https://chat.example.com", dmPolicy: "pairing", }, },}非互動式替代方式:
openclaw channels add --channel mattermost --bot-token <token> --http-url https://chat.example.com原生斜線命令
原生斜線命令需選擇啟用。啟用後,OpenClaw 會在機器人所屬的每個團隊註冊 oc_* 斜線命令,並在閘道 HTTP 伺服器上接收回呼 POST。
{ channels: { mattermost: { commands: { native: true, nativeSkills: true, callbackPath: "/api/channels/mattermost/command", // 當 Mattermost 無法直接連上閘道時使用(反向代理/公開 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 後,Skill 命令也會註冊為 /oc_<skill>。
行為注意事項
native和nativeSkills預設為"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。 - 對於多帳號設定,
commands可設於頂層或channels.mattermost.accounts.<id>.commands下方(帳號值會覆寫頂層欄位)。 - 由其他整合建立且觸發詞相同的既有斜線命令會保持不變(註冊時會略過);若回呼 URL 發生偏移,機器人建立的命令會更新或重新建立。
- 命令回呼會使用 OpenClaw 註冊
oc_*命令時由 Mattermost 傳回的每命令權杖進行驗證。 - OpenClaw 在接受每個回呼前都會重新整理目前的 Mattermost 命令註冊,因此來自已刪除或重新產生之斜線命令的過期權杖,無須重新啟動閘道便不再獲得接受。
- 若 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
環境變數(預設帳號)
若偏好使用環境變數,請在閘道主機上設定以下項目:
MATTERMOST_BOT_TOKEN=...MATTERMOST_URL=https://chat.example.com
聊天模式
Mattermost 會自動回覆私訊。頻道行為由 chatmode 控制:
oncall (預設)
僅在頻道中被 @提及時回覆。
onmessage
回覆每一則頻道訊息。
onchar
當訊息以觸發前綴開頭時回覆。
設定範例:
{ channels: { mattermost: { chatmode: "onchar", oncharPrefixes: [">", "!"], // 預設 }, },}注意事項:
onchar仍會回覆明確的 @提及。- 仍會遵循
channels.mattermost.requireMention,但建議使用chatmode。各頻道的groups.<channelId>.requireMention設定優先於這兩者。 - 機器人在頻道討論串中傳送可見回覆後,該討論串內的後續訊息不需要新的 @提及或
onchar前綴也會獲得回覆,讓多輪討論串對話得以持續進行。機器人最後一次在該討論串中回覆後,參與狀態會保留 7 天,且會在閘道重新啟動後持續存在。機器人僅觀察但未參與的討論串不受影響;若要再次要求明確提及,請發起新的頂層訊息。 - 設定
channels.mattermost.implicitMentions.threadParticipation: false,可防止已參與討論串的後續訊息略過提及閘控。帳號覆寫使用channels.mattermost.accounts.<id>.implicitMentions。Mattermost 目前不會產生replyToBot或quotedBot事實,因此這些旗標在此不會生效。
討論串與工作階段
使用 channels.mattermost.replyToMode 控制頻道和群組回覆是保留在主頻道中,還是在觸發貼文下方建立討論串。
off(預設):僅當傳入貼文本身已位於討論串中時,才在討論串中回覆。first:對於頂層頻道/群組貼文,在該貼文下方建立討論串,並將對話路由至討論串範圍的工作階段。all和batched:目前在 Mattermost 中的行為與first相同,因為 Mattermost 一旦有討論串根貼文,後續區塊和媒體便會繼續留在同一討論串中。- 即使已設定
replyToMode,私訊仍預設使用off。
使用 channels.mattermost.replyToModeByChatType 覆寫 direct、group 或 channel 聊天的模式。設定 direct,讓私訊採用討論串:
off(預設):私訊維持不使用討論串,並保留在單一滾動工作階段中。first、all或batched:每則頂層私訊都會建立 Mattermost 討論串,並由全新且獨立的工作階段支援。
{ channels: { mattermost: { replyToMode: "all", replyToModeByChatType: { direct: "first", }, }, },}注意事項:
- 討論串範圍的工作階段會使用觸發貼文 ID 作為討論串根貼文。
first和all目前效果相同,因為 Mattermost 一旦有討論串根貼文,後續區塊和媒體便會繼續留在同一討論串中。- 各聊天類型的覆寫優先於
replyToMode。若沒有direct覆寫,現有部署會維持扁平、不使用討論串的私訊。
存取控制(私訊)
- 預設:
channels.mattermost.dmPolicy = "pairing"(未知傳送者會取得配對碼)。其他值:allowlist、open、disabled。 - 核准方式:
openclaw pairing list mattermostopenclaw pairing approve mattermost <CODE>
- 公開私訊:
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),並記錄一次性警告。
範例:
{ channels: { mattermost: { groupPolicy: "open", groups: { "*": { requireMention: true }, "team-channel-id": { requireMention: false }, }, }, },}對外傳送目標
搭配 openclaw message send 或排程/網路鉤子使用下列目標格式:
| 目標 | 傳送至 |
|---|---|
channel:<id> |
依 ID 指定的頻道 |
channel:<name> 或 #channel-name |
依名稱指定的頻道,會在機器人所屬的所有團隊中搜尋 |
user:<id> 或 mattermost:<id> |
與該使用者的私訊 |
@username |
私訊(透過 Mattermost API 解析使用者名稱) |
每則對外傳送的訊息最多支援一個附件;請將多個檔案拆分成多次傳送。
私訊頻道重試
當 OpenClaw 傳送至 Mattermost 私訊目標,且需要先解析直接頻道時,預設會重試暫時性的直接頻道建立失敗。
使用 channels.mattermost.dmChannelRetry 為 Mattermost 外掛全域調整此行為,或使用 channels.mattermost.accounts.<id>.dmChannelRetry 為單一帳號調整。預設值:
{ 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 遷移):
{ channels: { mattermost: { streaming: { mode: "partial" }, // off | partial | block | progress }, },}串流模式
partial(預設):使用單一預覽貼文,隨著回覆增加而編輯,最後以完整答案完成。block會讓預覽在已完成文字與工具活動區塊之間輪替,使每個區塊各自保留為獨立貼文,而不會原地遭到覆寫。平行及連續的工具更新會共用目前的工具活動貼文。progress會在產生內容時顯示狀態預覽,並僅在完成時發布最終答案。off會停用預覽串流。搭配streaming.block.enabled: true時,已完成的助理區塊仍會以一般區塊回覆(獨立貼文)傳送,而非合併成單一最終貼文。
串流行為注意事項
- 如果串流無法原地完成(例如貼文在串流期間遭刪除),OpenClaw 會改為傳送新的最終貼文,確保回覆絕不遺失。
- 僅含思考內容的承載資料不會發布至頻道,包括以
> Thinking引用區塊傳入的文字。設定/reasoning on可在其他介面查看思考內容;Mattermost 最終貼文只會保留答案。 - 如需頻道對應矩陣,請參閱串流。
表情回應(訊息工具)
- 搭配
channel=mattermost使用message action=react。 messageId是 Mattermost 貼文 ID。emoji接受thumbsup或:+1:等名稱(冒號可省略)。- 設定
remove=true(布林值)以移除表情回應。 - 新增/移除表情回應事件會作為系統事件轉送至已路由的代理程式工作階段,並接受與訊息相同的私訊/群組政策檢查。
範例:
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 按鈕在訊息文字中保持可見,並將選取選單降級為可讀文字。
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_data、callbackData)。除非已設定 url,否則可點擊按鈕必須提供此值。
urlstring連結按鈕;在訊息本文中轉譯為 label: url 文字,而非互動式按鈕。
style"primary" | "secondary" | "success" | "danger"按鈕樣式。對於 Mattermost 不支援的值,會套用預設樣式。
若要在代理程式系統提示中宣告支援按鈕,請將 inlineButtons 加入頻道功能:
{ channels: { mattermost: { capabilities: ["inlineButtons"], }, },}當使用者點擊按鈕時:
存取檢查
點擊者必須通過與訊息傳送者相同的私訊/群組政策檢查;未經授權的點擊會收到僅本人可見的通知,且該點擊會被忽略。
以確認訊息取代按鈕
所有按鈕都會由確認行取代(例如 “✓ Yes selected by @user”)。
代理程式收到選取項目
代理程式會以傳入訊息(以及系統事件)的形式收到選取項目,並予以回應。
實作注意事項
- 按鈕回呼使用 HMAC-SHA256 驗證(自動進行,無需設定)。
- 點擊時會取代整個附件區塊,因此所有按鈕會一起移除,無法僅移除部分按鈕。
- 包含連字號或底線的動作 ID 會自動清理(Mattermost 路由限制)。
action_id與原始貼文中任何動作不相符的點擊,會遭到拒絕並顯示403(“Unknown action”)。
設定與可連線性
channels.mattermost.capabilities:功能字串陣列。加入"inlineButtons",以在代理程式系統提示中啟用按鈕工具說明。channels.mattermost.interactions.callbackBaseUrl:按鈕回呼的選用外部基底 URL(例如https://gateway.example.com)。當 Mattermost 無法直接透過閘道的繫結主機連線時,請使用此設定。- 在多帳號設定中,也可以在
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 整合(外部指令碼)
外部指令碼與網路鉤子可以直接透過 Mattermost REST API 發布按鈕,而不必經過代理程式的 message 工具。建議使用 OpenClaw 的 message 工具。對於直接整合,請從 @openclaw/mattermost/api.js 匯入 buildButtonAttachments;若要發布原始 JSON,請遵循以下規則:
承載資料結構:
{ channel_id: "<channelId>", message: "Choose an option:", props: { attachments: [ { actions: [ { id: "mybutton01", // alphanumeric only - see below type: "button", // required, or clicks are silently ignored name: "Approve", // display label style: "primary", // optional: "default", "primary", "danger" integration: { url: "https://gateway.example.com/mattermost/interactions/default", context: { action_id: "mybutton01", // must match button id action: "approve", // ... any custom fields ... _token: "<hmac>", // see HMAC section below }, }, }, ], }, ], },}HMAC 權杖產生
閘道會使用 HMAC-SHA256 驗證按鈕點擊。外部指令碼必須產生符合閘道驗證邏輯的權杖:
從機器人權杖衍生密鑰
HMAC-SHA256(key="openclaw-mattermost-interactions", data=botToken),以十六進位編碼。
建立內容物件
使用除了 _token 之外的所有欄位建立內容物件。
使用排序後的鍵序列化
使用遞迴排序的鍵且不含空格進行序列化(閘道也會正規化巢狀物件,並產生精簡 JSON)。
簽署承載資料
HMAC-SHA256(key=secret, data=serializedContext)
加入權杖
將產生的十六進位摘要作為內容中的 _token 加入。
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除外)。閘道會移除_token,然後簽署其餘所有內容。只簽署部分欄位會導致驗證無聲失敗。 - 請使用
sort_keys=True——閘道會在簽署前排序鍵,而 Mattermost 儲存承載資料時可能會重新排列情境欄位。 - 請從機器人權杖衍生密鑰(具確定性),不要使用隨機位元組。建立按鈕的程序與執行驗證的閘道必須使用相同的密鑰。
目錄配接器
Mattermost 外掛包含目錄配接器,可透過 Mattermost API 解析頻道與使用者名稱。這讓 openclaw message send 與排程/網路鉤子傳送能使用 #channel-name 和 @username 目標。
不需要設定——配接器會使用帳號設定中的機器人權杖。
多帳號
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" }, }, }, },}帳號值會覆寫頂層欄位;未指定帳號時,channels.mattermost.defaultAccount 會選擇要使用的帳號。
疑難排解
頻道中沒有回覆
請確認機器人已加入頻道並提及它(oncall)、使用觸發前綴(onchar),或設定 chatmode: "onmessage"。
驗證或多帳號錯誤
- 檢查機器人權杖、基礎 URL,以及帳號是否已啟用。
- 多帳號問題:環境變數僅適用於
default帳號。 - 私人/區域網路 Mattermost 主機需要
network.dangerouslyAllowPrivateNetwork: true(SSRF 防護預設會封鎖私人 IP)。
原生斜線命令失敗
Unauthorized: invalid command token.:OpenClaw 未接受回呼權杖。常見原因:- 啟動時斜線命令註冊失敗,或只完成部分註冊
- 回呼傳送至錯誤的閘道/帳號
- Mattermost 仍保留指向先前回呼目標的舊命令
- 閘道重新啟動,但未重新啟用斜線命令
- 如果原生斜線命令停止運作,請檢查日誌中是否出現
mattermost: failed to register slash commands或mattermost: native slash commands enabled but no commands could be registered。 - 如果省略
callbackUrl,且日誌警告回呼解析為類似http://localhost:18789/...的迴環 URL,該 URL 可能僅在 Mattermost 與 OpenClaw 執行於相同主機/網路命名空間時才能連線。請改為明確設定可從外部連線的commands.callbackUrl。
按鈕問題
- 按鈕顯示為白色方塊或完全不顯示:按鈕資料格式錯誤。每個呈現按鈕都需要
label和value(缺少任一項的按鈕會被捨棄)。 - 按鈕可以顯示,但點擊後沒有反應:請確認 Mattermost 伺服器能連線至閘道、Mattermost 伺服器 IP 已包含在
channels.mattermost.interactions.allowedSourceIps中(未設定時只接受迴環位址),且私人目標的ServiceSettings.AllowedUntrustedInternalConnections包含回呼主機。 - 點擊按鈕時傳回 404:按鈕的
id可能包含連字號或底線。Mattermost 的動作路由器無法處理非英數字元的 ID。請僅使用[a-zA-Z0-9]。 - 閘道記錄
rejected callback source:點擊來自interactions.allowedSourceIps以外的 IP。請將 Mattermost 伺服器或你的輸入端加入允許清單,並在反向代理後方設定gateway.trustedProxies。 - 閘道記錄
invalid _token:HMAC 不相符。請檢查是否簽署所有情境欄位(而非部分欄位)、使用已排序的鍵,並使用緊湊 JSON(不含空格)。請參閱上方的 HMAC 章節。 - 閘道記錄
missing _token in context:按鈕的情境中沒有_token欄位。請確保建立整合承載資料時已包含此欄位。 - 閘道以
Unknown action拒絕點擊:context.action_id與貼文上任何動作的id都不相符。請將兩者設為相同的清理後值。 - 代理程式未提供按鈕:請將
capabilities: ["inlineButtons"]加入 Mattermost 頻道設定。