Developer and self-hosted
Mattermost
สถานะ: Plugin ที่ดาวน์โหลดได้ (โทเค็นบอต + เหตุการณ์ WebSocket) รองรับช่อง ช่องส่วนตัว DM แบบกลุ่ม และ DM Mattermost เป็นแพลตฟอร์มรับส่งข้อความสำหรับทีมที่โฮสต์เองได้ (mattermost.com)
การติดตั้ง
รีจิสทรี npm
openclaw plugins install @openclaw/mattermostเช็กเอาต์ในเครื่อง
openclaw plugins install ./path/to/local/mattermost-pluginรายละเอียด: Plugin
การตั้งค่าอย่างรวดเร็ว
ตรวจสอบว่า Plugin พร้อมใช้งาน
ติดตั้ง @openclaw/mattermost ด้วยคำสั่งข้างต้น จากนั้นรีสตาร์ต Gateway หากกำลังทำงานอยู่
สร้างบอต Mattermost
สร้างบัญชีบอต Mattermost คัดลอก โทเค็นบอต และเพิ่มบอตไปยังทีมและช่องที่ต้องการให้บอตอ่าน
คัดลอก URL ฐาน
คัดลอก URL ฐาน ของ Mattermost (เช่น https://chat.example.com) ระบบจะตัด /api/v4 ที่อยู่ท้ายออกโดยอัตโนมัติ
กำหนดค่า OpenClaw และเริ่ม Gateway
การกำหนดค่าขั้นต่ำ:
{ 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_* ในทุกทีมที่บอตเป็นสมาชิก และรับ callback แบบ POST บนเซิร์ฟเวอร์ HTTP ของ Gateway
{ 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 คำสั่งของ Skills จะได้รับการลงทะเบียนเป็น /oc_<skill> ด้วย
หมายเหตุเกี่ยวกับลักษณะการทำงาน
nativeและnativeSkillsมีค่าเริ่มต้นเป็น"auto"ซึ่งสำหรับ Mattermost จะถูกตีความว่าปิดใช้งาน ให้ตั้งค่าเป็นtrueอย่างชัดเจนcallbackPathมีค่าเริ่มต้นเป็น/api/channels/mattermost/command- หากไม่ได้ระบุ
callbackUrlOpenClaw จะอนุมานhttp://<gateway.customBindHost or localhost>:<gateway.port, default 18789><callbackPath>โฮสต์สำหรับผูกแบบไวลด์การ์ด (0.0.0.0,::) จะใช้localhostแทน - สำหรับการตั้งค่าแบบหลายบัญชี สามารถตั้ง
commandsที่ระดับบนสุดหรือภายใต้channels.mattermost.accounts.<id>.commandsได้ (ค่าของบัญชีมีลำดับความสำคัญเหนือฟิลด์ระดับบนสุด) - คำสั่งสแลชที่มีทริกเกอร์เดียวกันและสร้างโดยการผสานรวมอื่นจะไม่ถูกแก้ไข (ระบบจะข้ามคำสั่งเหล่านั้นระหว่างการลงทะเบียน) ส่วนคำสั่งที่บอตสร้างจะได้รับการอัปเดตหรือสร้างใหม่เมื่อ URL ของ callback เปลี่ยนไป
- callback ของคำสั่งจะได้รับการตรวจสอบด้วยโทเค็นประจำคำสั่งที่ Mattermost ส่งคืนเมื่อ OpenClaw ลงทะเบียนคำสั่ง
oc_* - OpenClaw จะรีเฟรชการลงทะเบียนคำสั่ง Mattermost ปัจจุบันก่อนยอมรับ callback แต่ละครั้ง ดังนั้นโทเค็นเก่าจากคำสั่งสแลชที่ถูกลบหรือสร้างใหม่จะหยุดได้รับการยอมรับโดยไม่ต้องรีสตาร์ต Gateway
- การตรวจสอบ callback จะปฏิเสธโดยค่าเริ่มต้นหาก API ของ Mattermost ไม่สามารถยืนยันได้ว่าคำสั่งยังเป็นปัจจุบัน ระบบจะแคชผลการตรวจสอบที่ล้มเหลวไว้ชั่วครู่ รวมการค้นหาที่เกิดพร้อมกัน และจำกัดอัตราการเริ่มค้นหาใหม่แยกตามคำสั่งเพื่อจำกัดแรงกดดันจากการเล่นซ้ำ
- callback ของคำสั่งสแลชจะปฏิเสธโดยค่าเริ่มต้นเมื่อการลงทะเบียนล้มเหลว การเริ่มต้นระบบเสร็จเพียงบางส่วน หรือโทเค็น callback ไม่ตรงกับโทเค็นที่ลงทะเบียนของคำสั่งที่หาได้ (โทเค็นที่ใช้ได้กับคำสั่งหนึ่งจะไม่สามารถผ่านไปถึงการตรวจสอบต้นทางสำหรับคำสั่งอื่น)
- callback ที่ได้รับการยอมรับจะได้รับการตอบรับด้วยข้อความชั่วคราว "กำลังประมวลผล..." โดยคำตอบจริงจะมาถึงเป็นข้อความปกติ
ข้อกำหนดด้านการเข้าถึง
ปลายทาง callback ต้องเข้าถึงได้จากเซิร์ฟเวอร์ Mattermost
- อย่าตั้ง
callbackUrlเป็นlocalhostเว้นแต่ Mattermost จะทำงานบนโฮสต์/เนมสเปซเครือข่ายเดียวกับ OpenClaw - อย่าตั้ง
callbackUrlเป็น URL ฐานของ Mattermost เว้นแต่ URL นั้นจะทำพร็อกซีย้อนกลับ/api/channels/mattermost/commandไปยัง OpenClaw - ตรวจสอบอย่างรวดเร็วได้ด้วย
curl https://<gateway-host>/api/channels/mattermost/commandโดยคำขอ GET ควรได้รับ405 Method Not Allowedจาก OpenClaw ไม่ใช่404
รายการอนุญาตขาออกของ Mattermost
หาก callback มีเป้าหมายเป็นที่อยู่ส่วนตัว/tailnet/ภายใน ให้ตั้งค่า ServiceSettings.AllowedUntrustedInternalConnections ของ Mattermost ให้รวมโฮสต์/โดเมนของ callback
ใช้รายการโฮสต์/โดเมน ไม่ใช่ URL แบบเต็ม
- ถูกต้อง:
gateway.tailnet-name.ts.net - ไม่ถูกต้อง:
https://gateway.tailnet-name.ts.net
ตัวแปรสภาพแวดล้อม (บัญชีเริ่มต้น)
หากต้องการใช้ตัวแปรสภาพแวดล้อม ให้ตั้งค่าเหล่านี้บนโฮสต์ของ Gateway:
MATTERMOST_BOT_TOKEN=...MATTERMOST_URL=https://chat.example.com
โหมดแชต
Mattermost ตอบกลับ DM โดยอัตโนมัติ ลักษณะการทำงานในช่องควบคุมด้วย chatmode:
oncall (ค่าเริ่มต้น)
ตอบกลับเฉพาะเมื่อถูก @กล่าวถึงในช่อง
onmessage
ตอบกลับทุกข้อความในช่อง
onchar
ตอบกลับเมื่อข้อความเริ่มต้นด้วยคำนำหน้าทริกเกอร์
ตัวอย่างการกำหนดค่า:
{ channels: { mattermost: { chatmode: "onchar", oncharPrefixes: [">", "!"], // ค่าเริ่มต้น }, },}หมายเหตุ:
oncharยังคงตอบกลับการ @กล่าวถึงอย่างชัดเจน- ยังคงรองรับ
channels.mattermost.requireMentionแต่แนะนำให้ใช้chatmodeการตั้งค่าgroups.<channelId>.requireMentionต่อช่องมีลำดับความสำคัญเหนือทั้งสองค่า - หลังจากบอตส่งข้อความตอบกลับที่มองเห็นได้ในเธรดของช่อง ข้อความถัดไปในเธรดเดียวกันจะได้รับการตอบกลับโดยไม่ต้อง @กล่าวถึงใหม่หรือใช้คำนำหน้า
oncharเพื่อให้การสนทนาแบบหลายรอบในเธรดดำเนินต่อไป ระบบจะจดจำการเข้าร่วมเป็นเวลา 7 วันนับจากครั้งล่าสุดที่บอตตอบกลับในเธรดนั้น และข้อมูลนี้จะคงอยู่แม้รีสตาร์ต Gateway เธรดที่บอตเพียงสังเกตการณ์จะไม่ได้รับผลกระทบ ให้เริ่มข้อความระดับบนสุดใหม่เมื่อต้องการบังคับให้กล่าวถึงอย่างชัดเจนอีกครั้ง - ตั้ง
channels.mattermost.implicitMentions.threadParticipation: falseเพื่อไม่ให้ข้อความติดตามผลในเธรดที่บอตเข้าร่วมข้ามข้อกำหนดการกล่าวถึง ค่าที่กำหนดเฉพาะบัญชีใช้channels.mattermost.accounts.<id>.implicitMentionsปัจจุบัน Mattermost ไม่สร้างข้อเท็จจริงreplyToBotหรือquotedBotดังนั้นแฟล็กเหล่านั้นจึงไม่มีผลในที่นี้
เธรดและเซสชัน
ใช้ channels.mattermost.replyToMode เพื่อควบคุมว่าคำตอบในช่องและกลุ่มจะอยู่ในช่องหลักหรือเริ่มเธรดใต้โพสต์ที่เป็นทริกเกอร์
off(ค่าเริ่มต้น): ตอบกลับในเธรดเฉพาะเมื่อโพสต์ขาเข้าอยู่ในเธรดอยู่แล้วfirst: สำหรับโพสต์ระดับบนสุดในช่อง/กลุ่ม ให้เริ่มเธรดใต้โพสต์นั้นและกำหนดเส้นทางการสนทนาไปยังเซสชันที่มีขอบเขตระดับเธรดallและbatched: ปัจจุบันมีลักษณะการทำงานเหมือนfirstสำหรับ Mattermost เนื่องจากเมื่อ Mattermost มีรากของเธรดแล้ว ส่วนข้อความและสื่อที่ตามมาจะดำเนินต่อในเธรดเดียวกันนั้น- ข้อความโดยตรงมีค่าเริ่มต้นเป็น
offแม้จะตั้งค่าreplyToModeไว้
ใช้ 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การติดตั้งใช้งานที่มีอยู่จะคง DM แบบแบนและไม่มีเธรดไว้
การควบคุมการเข้าถึง (DM)
- ค่าเริ่มต้น:
channels.mattermost.dmPolicy = "pairing"(ผู้ส่งที่ไม่รู้จักจะได้รับรหัสการจับคู่) ค่าอื่น:allowlist,open,disabled - อนุมัติผ่าน:
openclaw pairing list mattermostopenclaw pairing approve mattermost <CODE>
- DM สาธารณะ:
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 หรือ Cron/Webhook:
| เป้าหมาย | ส่งไปยัง |
|---|---|
channel:<id> |
ช่องตาม ID |
channel:<name> หรือ #channel-name |
ช่องตามชื่อ โดยค้นหาในทุกทีมที่บอตเป็นสมาชิก |
user:<id> หรือ mattermost:<id> |
DM กับผู้ใช้รายนั้น |
@username |
DM (แก้ชื่อผู้ใช้ผ่าน API ของ Mattermost) |
การส่งขาออกรองรับไฟล์แนบได้สูงสุดหนึ่งไฟล์ต่อข้อความ แยกหลายไฟล์เป็นการส่งคนละครั้ง
การลองช่องทาง DM ใหม่
เมื่อ OpenClaw ส่งไปยังเป้าหมาย DM ของ Mattermost และต้องแก้ไขช่องทางโดยตรงก่อน ระบบจะลองสร้างช่องทางโดยตรงใหม่โดยค่าเริ่มต้นเมื่อเกิดความล้มเหลวชั่วคราว
ใช้ channels.mattermost.dmChannelRetry เพื่อปรับลักษณะการทำงานนี้แบบส่วนกลางสำหรับ Plugin Mattermost หรือใช้ channels.mattermost.accounts.<id>.dmChannelRetry สำหรับบัญชีหนึ่งบัญชี ค่าเริ่มต้น:
{ channels: { mattermost: { dmChannelRetry: { maxRetries: 3, initialDelayMs: 1000, maxDelayMs: 10000, timeoutMs: 30000, }, }, },}หมายเหตุ:
- การตั้งค่านี้ใช้เฉพาะกับการสร้างช่องทาง DM (
/api/v4/channels/direct) ไม่ใช่ทุกการเรียก API ของ Mattermost - การลองใหม่ใช้ exponential backoff พร้อม jitter และใช้กับความล้มเหลวชั่วคราว เช่น ขีดจำกัดอัตรา การตอบกลับ 5xx และข้อผิดพลาดด้านเครือข่ายหรือการหมดเวลา
- ข้อผิดพลาดฝั่งไคลเอนต์ 4xx นอกเหนือจาก
429จะถูกถือเป็นข้อผิดพลาดถาวรและจะไม่มีการลองใหม่
การสตรีมตัวอย่าง
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 จะเปลี่ยนไปส่งโพสต์สุดท้ายใหม่ เพื่อให้มั่นใจว่าคำตอบจะไม่สูญหาย
- เพย์โหลดที่มีเฉพาะกระบวนการคิดจะไม่ถูกโพสต์ลงในช่องทาง รวมถึงข้อความที่มาถึงในรูปแบบ blockquote
> Thinkingตั้งค่า/reasoning onเพื่อดูกระบวนการคิดในพื้นผิวอื่น โพสต์สุดท้ายของ Mattermost จะเก็บเฉพาะคำตอบ - ดูเมทริกซ์การแมปช่องทางได้ที่ การสตรีม
รีแอ็กชัน (เครื่องมือข้อความ)
- ใช้
message action=reactร่วมกับchannel=mattermost messageIdคือ ID โพสต์ของ Mattermostemojiรองรับชื่อ เช่นthumbsupหรือ:+1:(ไม่จำเป็นต้องมีเครื่องหมายโคลอน)- ตั้งค่า
remove=true(บูลีน) เพื่อลบรีแอ็กชัน - เหตุการณ์เพิ่ม/ลบรีแอ็กชันจะถูกส่งต่อเป็นเหตุการณ์ระบบไปยังเซสชันเอเจนต์ที่กำหนดเส้นทาง โดยอยู่ภายใต้การตรวจสอบนโยบาย DM/กลุ่มแบบเดียวกับข้อความ
ตัวอย่าง:
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"], }, },}เมื่อผู้ใช้คลิกปุ่ม:
การตรวจสอบสิทธิ์เข้าถึง
ผู้คลิกต้องผ่านการตรวจสอบนโยบาย DM/กลุ่มแบบเดียวกับผู้ส่งข้อความ การคลิกที่ไม่ได้รับอนุญาตจะได้รับการแจ้งเตือนชั่วคราวและถูกเพิกเฉย
แทนที่ปุ่มด้วยการยืนยัน
ปุ่มทั้งหมดจะถูกแทนที่ด้วยบรรทัดยืนยัน (เช่น "✓ Yes selected by @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.callbackBaseUrlOpenClaw จะคำนวณ URL คอลแบ็กจากgateway.customBindHost+gateway.port(ค่าเริ่มต้น 18789) แล้วจึงเปลี่ยนไปใช้http://localhost:<port>เส้นทางคอลแบ็กคือ/mattermost/interactions/<accountId> - กฎการเข้าถึง: เซิร์ฟเวอร์ Mattermost ต้องสามารถเข้าถึง URL คอลแบ็กของปุ่มได้
localhostใช้งานได้เฉพาะเมื่อ Mattermost และ OpenClaw ทำงานบนโฮสต์/เนมสเปซเครือข่ายเดียวกัน channels.mattermost.interactions.allowedSourceIps: รายการอนุญาต IP ต้นทางสำหรับคอลแบ็กของปุ่ม หากไม่มีค่านี้ จะยอมรับเฉพาะต้นทางลูปแบ็ก (127.0.0.1,::1) ดังนั้นต้องเพิ่มเซิร์ฟเวอร์ Mattermost ระยะไกลไว้ในรายการอนุญาตนี้ มิฉะนั้นการคลิกจะถูกปฏิเสธด้วย403หากอยู่หลัง reverse proxy ให้ตั้งค่าgateway.trustedProxiesด้วย เพื่อให้ดึง IP ไคลเอนต์จริงจากส่วนหัวที่ส่งต่อ- หากเป้าหมายคอลแบ็กเป็นแบบส่วนตัว/tailnet/ภายใน ให้เพิ่มโฮสต์/โดเมนของเป้าหมายใน
ServiceSettings.AllowedUntrustedInternalConnectionsของ Mattermost
การผสานรวม API โดยตรง (สคริปต์ภายนอก)
สคริปต์ภายนอกและ Webhook สามารถโพสต์ปุ่มโดยตรงผ่าน Mattermost REST API แทนการผ่านเครื่องมือ message ของเอเจนต์ ควรใช้เครื่องมือ message ของ OpenClaw สำหรับการผสานรวมโดยตรง ให้นำเข้า buildButtonAttachments จาก @openclaw/mattermost/api.js หากโพสต์ JSON ดิบ ให้ปฏิบัติตามกฎเหล่านี้:
โครงสร้างเพย์โหลด:
{ 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:
สร้างข้อมูลลับจากโทเค็นบอต
HMAC-SHA256(key="openclaw-mattermost-interactions", data=botToken) เข้ารหัสแบบเลขฐานสิบหก
สร้างออบเจ็กต์บริบท
สร้างออบเจ็กต์บริบทที่มีฟิลด์ทั้งหมด ยกเว้น _token
ทำให้เป็นอนุกรมโดยเรียงลำดับคีย์
ทำให้เป็นอนุกรมโดย เรียงลำดับคีย์แบบเวียนเกิด และ ไม่มีช่องว่าง (Gateway จะทำให้ออบเจ็กต์ที่ซ้อนกันเป็นมาตรฐานด้วย และสร้าง 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
json.dumpsของ Python จะเพิ่มช่องว่างโดยค่าเริ่มต้น ({"key": "val"}) ใช้separators=(",", ":")เพื่อให้ตรงกับเอาต์พุตแบบกระชับของ JavaScript ({"key":"val"})- ลงนามฟิลด์บริบท ทั้งหมด เสมอ (ยกเว้น
_token) Gateway จะนำ_tokenออก แล้วลงนามทุกฟิลด์ที่เหลือ การลงนามเพียงบางส่วนจะทำให้การตรวจสอบล้มเหลวโดยไม่มีข้อความแจ้ง - ใช้
sort_keys=Trueเนื่องจาก Gateway จะเรียงลำดับคีย์ก่อนลงนาม และ Mattermost อาจจัดลำดับฟิลด์บริบทใหม่เมื่อจัดเก็บเพย์โหลด - สร้างข้อมูลลับจากโทเค็นบอต (แบบกำหนดผลลัพธ์ได้แน่นอน) ไม่ใช่จากไบต์สุ่ม ข้อมูลลับต้องเหมือนกันทั้งในกระบวนการที่สร้างปุ่มและ Gateway ที่ทำการตรวจสอบ
อะแดปเตอร์ไดเรกทอรี
Plugin Mattermost มีอะแดปเตอร์ไดเรกทอรีที่ใช้ Mattermost API เพื่อแปลงชื่อช่องและชื่อผู้ใช้ ซึ่งทำให้สามารถใช้เป้าหมาย #channel-name และ @username ใน openclaw message send รวมถึงการส่งผ่าน cron/webhook ได้
ไม่จำเป็นต้องกำหนดค่า เนื่องจากอะแดปเตอร์ใช้โทเค็นบอตจากการกำหนดค่าบัญชี
หลายบัญชี
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 แบบส่วนตัว/LAN ต้องใช้
network.dangerouslyAllowPrivateNetwork: true(กลไกป้องกัน SSRF จะบล็อก IP ส่วนตัวโดยค่าเริ่มต้น)
คำสั่งสแลชแบบเนทีฟล้มเหลว
Unauthorized: invalid command token.: OpenClaw ไม่ยอมรับโทเค็นคอลแบ็ก สาเหตุทั่วไป:- การลงทะเบียนคำสั่งสแลชล้มเหลวหรือเสร็จสมบูรณ์เพียงบางส่วนเมื่อเริ่มต้นระบบ
- คอลแบ็กกำลังส่งไปยัง Gateway/บัญชีที่ไม่ถูกต้อง
- Mattermost ยังมีคำสั่งเก่าที่ชี้ไปยังเป้าหมายคอลแบ็กก่อนหน้า
- Gateway เริ่มต้นใหม่โดยไม่ได้เปิดใช้งานคำสั่งสแลชอีกครั้ง
- หากคำสั่งสแลชแบบเนทีฟหยุดทำงาน ให้ตรวจสอบบันทึกเพื่อหา
mattermost: failed to register slash commandsหรือmattermost: native slash commands enabled but no commands could be registered - หากละเว้น
callbackUrlและบันทึกเตือนว่าคอลแบ็กถูกแปลงเป็น URL แบบลูปแบ็ก เช่นhttp://localhost:18789/...URL ดังกล่าวอาจเข้าถึงได้เฉพาะเมื่อ Mattermost ทำงานอยู่บนโฮสต์/เนมสเปซเครือข่ายเดียวกับ OpenClaw ให้ตั้งค่าcommands.callbackUrlที่เข้าถึงได้จากภายนอกอย่างชัดเจนแทน
ปัญหาเกี่ยวกับปุ่ม
- ปุ่มปรากฏเป็นกล่องสีขาวหรือไม่ปรากฏเลย: ข้อมูลปุ่มมีรูปแบบไม่ถูกต้อง ปุ่มการนำเสนอแต่ละปุ่มต้องมี
labelและvalue(ปุ่มที่ขาดรายการใดรายการหนึ่งจะถูกละทิ้ง) - ปุ่มแสดงผลแต่เมื่อคลิกแล้วไม่มีการตอบสนอง: ตรวจสอบว่าเซิร์ฟเวอร์ Mattermost เข้าถึง Gateway ได้, IP ของเซิร์ฟเวอร์ Mattermost อยู่ใน
channels.mattermost.interactions.allowedSourceIps(หากไม่มีค่านี้จะยอมรับเฉพาะลูปแบ็ก) และServiceSettings.AllowedUntrustedInternalConnectionsมีโฮสต์คอลแบ็กสำหรับเป้าหมายส่วนตัว - เมื่อคลิกปุ่มแล้วได้รับ 404:
idของปุ่มอาจมีเครื่องหมายขีดกลางหรือขีดล่าง เราเตอร์การดำเนินการของ Mattermost ไม่รองรับ ID ที่มีอักขระอื่นนอกจากตัวอักษรและตัวเลข ให้ใช้เฉพาะ[a-zA-Z0-9] - Gateway บันทึก
rejected callback source: การคลิกมาจาก IP ที่ไม่อยู่ในinteractions.allowedSourceIpsเพิ่มเซิร์ฟเวอร์ Mattermost หรือ ingress ของคุณลงในรายการอนุญาต และตั้งค่าgateway.trustedProxiesเมื่ออยู่หลังพร็อกซีย้อนกลับ - Gateway บันทึก
invalid _token: HMAC ไม่ตรงกัน ตรวจสอบว่าคุณลงนามฟิลด์บริบททั้งหมด (ไม่ใช่เพียงบางส่วน), ใช้คีย์ที่เรียงลำดับแล้ว และใช้ JSON แบบกระชับ (ไม่มีช่องว่าง) ดูส่วน HMAC ด้านบน - Gateway บันทึก
missing _token in context: ฟิลด์_tokenไม่อยู่ในบริบทของปุ่ม ตรวจสอบว่าได้รวมฟิลด์นี้ไว้เมื่อสร้างเพย์โหลดการผสานการทำงาน - Gateway ปฏิเสธการคลิกด้วย
Unknown action:context.action_idไม่ตรงกับidของการดำเนินการใดๆ ในโพสต์ ตั้งค่าทั้งสองเป็นค่าที่ผ่านการปรับให้ปลอดภัยค่าเดียวกัน - เอเจนต์ไม่มีปุ่มให้ใช้: เพิ่ม
capabilities: ["inlineButtons"]ลงในการกำหนดค่าช่อง Mattermost
เนื้อหาที่เกี่ยวข้อง
- การกำหนดเส้นทางช่อง - การกำหนดเส้นทางเซสชันสำหรับข้อความ
- ภาพรวมช่อง - ช่องทั้งหมดที่รองรับ
- กลุ่ม - ลักษณะการทำงานของแชตกลุ่มและการควบคุมด้วยการกล่าวถึง
- การจับคู่ - การตรวจสอบสิทธิ์ DM และขั้นตอนการจับคู่
- ความปลอดภัย - โมเดลการเข้าถึงและการเพิ่มความแข็งแกร่งด้านความปลอดภัย