Mattermost
الحالة: مدعوم عبر إضافة (رمز بوت + أحداث WebSocket). القنوات والمجموعات والرسائل المباشرة مدعومة. Mattermost هي منصة مراسلة جماعية قابلة للاستضافة الذاتية؛ راجع الموقع الرسمي على mattermost.com للحصول على تفاصيل المنتج والتنزيلات.
الإضافة مطلوبة
يتم توزيع Mattermost كإضافة وليست مضمنة في التثبيت الأساسي. قم بالتثبيت عبر سطر الأوامر (سجل npm):
openclaw plugins install @openclaw/mattermost
التثبيت المحلي (عند التشغيل من مستودع git):
openclaw plugins install ./extensions/mattermost
إذا اخترت Mattermost أثناء التكوين/البدء وتم اكتشاف نسخة git، فسيعرض OpenClaw مسار التثبيت المحلي تلقائيًا. التفاصيل: الإضافات
الإعداد السريع
- قم بتثبيت إضافة Mattermost.
- أنشئ حساب بوت Mattermost وانسخ رمز البوت.
- انسخ عنوان URL الأساسي لـ Mattermost (مثال:
https://chat.example.com). - قم بتكوين OpenClaw وابدأ البوابة.
التكوين الأدنى:
{
channels: {
mattermost: {
enabled: true,
botToken: "mm-token",
baseUrl: "https://chat.example.com",
dmPolicy: "pairing",
},
},
}
أوامر الشرطة المائلة الأصلية
أوامر الشرطة المائلة الأصلية اختيارية. عند تمكينها، يقوم OpenClaw بتسجيل أوامر oc_* عبر واجهة برمجة تطبيقات Mattermost ويتلقى استدعاءات POST على خادم HTTP الخاص بالبوابة.
{
channels: {
mattermost: {
commands: {
native: true,
nativeSkills: true,
callbackPath: "/api/channels/mattermost/command",
// استخدم عندما لا تتمكن Mattermost من الوصول إلى البوابة مباشرة (خادم وكيل عكسي/عنوان URL عام).
callbackUrl: "https://gateway.example.com/api/channels/mattermost/command",
},
},
},
}
ملاحظات:
native: "auto"تكون معطلة افتراضيًا لـ Mattermost. اضبطnative: trueللتمكين.- إذا تم حذف
callbackUrl، فإن OpenClaw يستمد واحدًا من مضيف/منفذ البوابة +callbackPath. - لإعدادات الحسابات المتعددة، يمكن تعيين
commandsعلى المستوى الأعلى أو تحتchannels.mattermost.accounts.<id>.commands(قيم الحساب تتجاوز الحقول على المستوى الأعلى). - يتم التحقق من صحة استدعاءات الأوامر باستخدام رموز لكل أمر وتفشل عند فشل فحوصات الرمز.
- متطلبات إمكانية الوصول: يجب أن يكون نقطة نهاية الاستدعاء قابلة للوصول من خادم Mattermost.
- لا تقم بتعيين
callbackUrlإلىlocalhostإلا إذا كان Mattermost يعمل على نفس المضيف/مساحة الشبكة مثل OpenClaw. - لا تقم بتعيين
callbackUrlإلى عنوان URL الأساسي لـ Mattermost الخاص بك إلا إذا كان هذا العنوان URL يقوم بالوكالة العكسية لـ/api/channels/mattermost/commandإلى OpenClaw. - فحص سريع هو
curl https://<gateway-host>/api/channels/mattermost/command؛ يجب أن يعيد GET405 Method Not Allowedمن OpenClaw، وليس404.
- لا تقم بتعيين
- متطلبات قائمة السماح للخروج من Mattermost:
- إذا كان هدف استدعائك يستهدف عناوين خاصة/شبكة ذيل/داخلية، فقم بتعيين
ServiceSettings.AllowedUntrustedInternalConnectionsفي Mattermost لتشمل مضيف/نطاق الاستدعاء. - استخدم إدخالات المضيف/النطاق، وليس عناوين URL كاملة.
- جيد:
gateway.tailnet-name.ts.net - سيء:
https://gateway.tailnet-name.ts.net
- جيد:
- إذا كان هدف استدعائك يستهدف عناوين خاصة/شبكة ذيل/داخلية، فقم بتعيين
متغيرات البيئة (الحساب الافتراضي)
قم بتعيين هذه على مضيف البوابة إذا كنت تفضل متغيرات البيئة:
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.dmPolicy = "pairing"(المرسلون غير المعروفين يحصلون على رمز إقران). - الموافقة عبر:
openclaw pairing list mattermostopenclaw pairing approve mattermost <CODE>
- الرسائل المباشرة العامة:
channels.mattermost.dmPolicy="open"بالإضافة إلىchannels.mattermost.allowFrom=["*"].
القنوات (المجموعات)
- الافتراضي:
channels.mattermost.groupPolicy = "allowlist"(مقيد بالذكر). - قائمة السماح للمرسلين مع
channels.mattermost.groupAllowFrom(يوصى بمعرفات المستخدم). - مطابقة
@اسم المستخدمقابلة للتغيير وتمكينها فقط عندما يكونchannels.mattermost.dangerouslyAllowNameMatching: true. - القنوات المفتوحة:
channels.mattermost.groupPolicy="open"(مقيد بالذكر). - ملاحظة وقت التشغيل: إذا كان
channels.mattermostمفقودًا تمامًا، فإن وقت التشغيل يعود إلىgroupPolicy="allowlist"لفحوصات المجموعة (حتى إذا تم تعيينchannels.defaults.groupPolicy).
الأهداف لتسليم الصادر
استخدم تنسيقات الهدف هذه مع openclaw message send أو cron/webhooks:
channel:<id>للقناةuser:<id>للرسالة المباشرة@usernameللرسالة المباشرة (يتم حلها عبر واجهة برمجة تطبيقات Mattermost)
يتم التعامل مع المعرفات المجردة كقنوات.
التفاعلات (أداة الرسالة)
- استخدم
message action=reactمعchannel=mattermost. messageIdهو معرف منشور Mattermost.emojiيقبل أسماء مثلthumbsupأو:+1:(النقطتان اختياريتان).- اضبط
remove=true(منطقية) لإزالة التفاعل. - يتم إعادة توجيه أحداث إضافة/إزالة التفاعل كأحداث نظام إلى جلسة الوكيل الموجهة.
أمثلة:
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: تمكين/تعطيل إجراءات التفاعل (صحيح افتراضيًا).- تجاوز لكل حساب:
channels.mattermost.accounts.<id>.actions.reactions.
الأزرار التفاعلية (أداة الرسالة)
أرسل رسائل بأزرار قابلة للنقر. عندما ينقر المستخدم على زر، يتلقى الوكيل الاختيار ويمكنه الرد. قم بتمكين الأزرار عن طريق إضافة inlineButtons إلى إمكانيات القناة:
{
channels: {
mattermost: {
capabilities: ["inlineButtons"],
},
},
}
استخدم message action=send مع معامل buttons. الأزرار هي مصفوفة ثنائية الأبعاد (صفوف من الأزرار):
message action=send channel=mattermost target=channel:<channelId> buttons=[[{"text":"نعم","callback_data":"نعم"},{"text":"لا","callback_data":"لا"}]]
حقول الزر:
text(مطلوب): تسمية العرض.callback_data(مطلوب): القيمة المرسلة مرة أخرى عند النقر (تستخدم كمعرف الإجراء).style(اختياري):"default"، أو"primary"، أو"danger".
عندما ينقر المستخدم على زر:
- يتم استبدال جميع الأزرار بخط تأكيد (مثال: "✓ نعم تم اختياره بواسطة @user").
- يتلقى الوكيل الاختيار كرسالة واردة ويقوم بالرد.
ملاحظات:
- تستخدم استدعاءات الأزرار التحقق HMAC-SHA256 (تلقائي، لا حاجة لتكوين).
- تقوم Mattermost بإزالة بيانات الاستدعاء من استجابات واجهة برمجة التطبيقات الخاصة بها (ميزة أمان)، لذلك تتم إزالة جميع الأزرار عند النقر — الإزالة الجزئية غير ممكنة.
- يتم تنظيف معرفات الإجراءات التي تحتوي على شرطات سفلية أو شرطات تلقائيًا (قيد توجيه Mattermost).
التكوين:
channels.mattermost.capabilities: مصفوفة من سلاسل الإمكانيات. أضف"inlineButtons"لتمكين وصف أداة الأزرار في مطالبة نظام الوكيل.channels.mattermost.interactions.callbackBaseUrl: عنوان URL أساسي خارجي اختياري لاستدعاءات الأزرار (على سبيل المثالhttps://gateway.example.com). استخدم هذا عندما لا تتمكن Mattermost من الوصول إلى البوابة على مضيف الربط الخاص بها مباشرة.- في إعدادات الحسابات المتعددة، يمكنك أيضًا تعيين نفس الحقل تحت
channels.mattermost.accounts.<id>.interactions.callbackBaseUrl. - إذا تم حذف
interactions.callbackBaseUrl، فإن OpenClaw يستمد عنوان URL للاستدعاء منgateway.customBindHost+gateway.port، ثم يعود إلىhttp://localhost:<port>. - قاعدة إمكانية الوصول: يجب أن يكون عنوان URL لاستدعاء الزر قابلاً للوصول من خادم Mattermost. يعمل
localhostفقط عندما يعمل Mattermost و OpenClaw على نفس المضيف/مساحة الشبكة. - إذا كان هدف الاستدعاء الخاص بك خاص/شبكة ذيل/داخلي، فأضف مضيفه/نطاقه إلى
ServiceSettings.AllowedUntrustedInternalConnectionsفي Mattermost.
التكامل المباشر مع واجهة برمجة التطبيقات (نصوص برمجية خارجية)
يمكن للنصوص البرمجية الخارجية و webhooks نشر أزرار مباشرة عبر واجهة برمجة تطبيقات REST الخاصة بـ Mattermost بدلاً من المرور عبر أداة message الخاصة بالوكيل. استخدم buildButtonAttachments() من الامتداد عندما يكون ذلك ممكنًا؛ إذا كنت تنشر 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", // يجب أن يطابق معرف الزر (للبحث عن الاسم)
action: "approve",
// ... أي حقول مخصصة ...
_token: "<hmac>", // انظر قسم HMAC أدناه
},
},
},
],
},
],
},
}
قواعد حرجة:
- تذهب المرفقات في
props.attachments، وليسattachmentsعلى المستوى الأعلى (يتم تجاهلها بصمت). - كل إجراء يحتاج إلى
type: "button"— بدونه، يتم ابتلاع النقرات بصمت. - كل إجراء يحتاج إلى حقل
id— يتجاهل Mattermost الإجراءات بدون معرفات. idللإجراء يجب أن يكون أبجدي رقمي فقط ([a-zA-Z0-9]). الشرطات والشرطات السفلية تكسر توجيه الإجراء من جانب الخادم في Mattermost (يعيد 404). قم بإزالتها قبل الاستخدام.- يجب أن يطابق
context.action_ididالخاص بالزر حتى تظهر رسالة التأكيد اسم الزر (مثال: "موافقة") بدلاً من معرف خام. context.action_idمطلوب — يعيد معالج التفاعل 400 بدونه.
إنشاء رمز HMAC: تتحقق البوابة من نقرات الأزرار باستخدام HMAC-SHA256. يجب على النصوص البرمجية الخارجية إنشاء رموز تطابق منطق التحقق الخاص بالبوابة:
- استخلص السر من رمز البوت:
HMAC-SHA256(key="openclaw-mattermost-interactions", data=botToken) - أنشئ كائن السياق بجميع الحقول ما عدا
_token. - قم بالتسلسل باستخدام مفاتيح مرتبة و بدون مسافات (تستخدم البوابة
JSON.stringifyمع مفاتيح مرتبة، مما ينتج عنه إخراج مضغوط). - التوقيع:
HMAC-SHA256(key=secret, data=serializedContext) - أضف الناتج السداسي العشري كـ
_tokenفي السياق.
مثال بايثون:
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 الشائعة:
json.dumpsفي بايثون يضيف مسافات افتراضيًا ({"key": "val"}). استخدمseparators=(",", ":")لمطابقة الإخراج المضغوط لجافا سكريبت ({"key":"val"}).- وقّع دائمًا جميع حقول السياق (ناقص
_token). تقوم البوابة بإزالة_tokenثم توقيع كل ما تبقى. توقيع مجموعة فرعية يسبب فشل تحقق صامت. - استخدم
sort_keys=True— تقوم البوابة بترتيب المفاتيح قبل التوقيع، وقد تعيد Mattermost ترتيب حقول السياق عند تخزين الحمولة. - استخلص السر من رمز البوت (حتمي)، وليس بايتات عشوائية. يجب أن يكون السر هو نفسه عبر العملية التي تنشئ الأزرار والبوابة التي تتحقق.
محول الدليل
تتضمن إضافة Mattermost محول دليل يحل أسماء القنوات والمستخدمين عبر واجهة برمجة تطبيقات Mattermost. هذا يمكّن أهداف #اسم-القناة و @اسم المستخدم في openclaw message send وتسليمات cron/webhook. لا حاجة لتكوين — يستخدم المحول رمز البوت من تكوين الحساب.
حسابات متعددة
يدعم Mattermost حسابات متعددة تحت channels.mattermost.accounts:
{
channels: {
mattermost: {
accounts: {
default: { name: "أساسي", botToken: "mm-token", baseUrl: "https://chat.example.com" },
alerts: { name: "تنبيهات", botToken: "mm-token-2", baseUrl: "https://alerts.example.com" },
},
},
},
}
استكشاف الأخطاء وإصلاحها
- لا توجد ردود في القنوات: تأكد من أن البوت في القناة وقم بذكره (oncall)، أو استخدم بادئة مشغلة (onchar)، أو اضبط
chatmode: "onmessage". - أخطاء المصادقة: تحقق من رمز البوت، وعنوان URL الأساسي، وما إذا كان الحساب مفعلًا.
- مشكلات الحسابات المتعددة: تنطبق متغيرات البيئة فقط على الحساب
default. - تظهر الأزرار كصناديق بيضاء: قد يكون الوكيل يرسل بيانات زر غير صحيحة. تحقق من أن كل زر يحتوي على حقلي
textوcallback_data. - يتم عرض الأزرار ولكن النقرات لا تفعل شيئًا: تحقق من أن
AllowedUntrustedInternalConnectionsفي تكوين خادم Mattermost يتضمن127.0.0.1 localhost، وأنEnablePostActionIntegrationهوtrueفي ServiceSettings. - تعيد الأزرار 404 عند النقر: من المحتمل أن
idالخاص بالزر يحتوي على شرطات أو شرطات سفلية. يتعطل جهاز توجيه الإجراء في Mattermost على المعرفات غير الأبجدية الرقمية. استخدم[a-zA-Z0-9]فقط. - سجلات البوابة
invalid _token: عدم تطابق HMAC. تحقق من أنك وقعت على جميع حقول السياق (وليس مجموعة فرعية)، واستخدم مفاتيح مرتبة، واستخدم JSON مضغوط (بدون مسافات). راجع قسم HMAC أعلاه. - سجلات البوابة
missing _token in context: حقل_tokenغير موجود في سياق الزر. تأكد من تضمينه عند بناء حمولة التكامل. - يظهر التأكيد معرفًا خامًا بدلاً من اسم الزر:
context.action_idلا يطابقidالخاص بالزر. اضبط كلاهما على نفس القيمة المنظفة. - الوكيل لا يعرف عن الأزرار: أضف
capabilities: ["inlineButtons"]إلى تكوين قناة Mattermost.