Get started
خطة إعادة هيكلة عرض القناة
الحالة
مُنفّذ لأسطح الوكيل المشترك، وCLI، وقدرة Plugin، والتسليم الصادر:
- يحمل
ReplyPayload.presentationواجهة رسائل دلالية. - يحمل
ReplyPayload.delivery.pinطلبات تثبيت الرسائل المُرسلة. - تعرض إجراءات الرسائل المشتركة
presentationوdeliveryوpinبدلًا منcomponentsأوblocksأوbuttonsأوcardالأصلية الخاصة بالمزوّد. - يعرض النواة العرض التقديمي أو يخفّضه تلقائيًا عبر قدرات الصادر التي يصرّح بها Plugin.
- تستهلك عارضات Discord وSlack وTelegram وMattermost وMS Teams وFeishu العقد العام.
- لم تعد شيفرة مستوى التحكم لقناة Discord تستورد حاويات واجهة المستخدم المدعومة بـCarbon.
توجد الوثائق المعتمدة الآن في عرض الرسائل. أبقِ هذه الخطة كسياق تنفيذ تاريخي؛ وحدّث الدليل المعتمد عند تغيّر العقد أو العارض أو سلوك الرجوع.
المشكلة
واجهة مستخدم القنوات مقسّمة حاليًا عبر عدة أسطح غير متوافقة:
- يمتلك النواة خطاف عارض عابر للسياقات على هيئة Discord من خلال
buildCrossContextComponents. - يمكن لـ
channel.tsفي Discord استيراد واجهة مستخدم Carbon الأصلية من خلالDiscordUiContainer، ما يجلب تبعيات واجهة المستخدم وقت التشغيل إلى مستوى التحكم في Plugin القناة. - يعرّض الوكيل وCLI منافذ هروب للحِمولات الأصلية مثل
componentsفي Discord، وblocksفي Slack، وbuttonsفي Telegram أو Mattermost، وcardفي Teams أو Feishu. - يحمل
ReplyPayload.channelDataكلًا من تلميحات النقل وأغلفة واجهة المستخدم الأصلية. - يوجد نموذج
interactiveالعام، لكنه أضيق من التخطيطات الأغنى المستخدمة بالفعل في Discord وSlack وTeams وFeishu وLINE وTelegram وMattermost.
هذا يجعل النواة على دراية بأشكال واجهة المستخدم الأصلية، ويُضعف كسل تشغيل Plugin، ويمنح الوكلاء طرقًا كثيرة جدًا خاصة بالمزوّد للتعبير عن نية الرسالة نفسها.
الأهداف
- يقرر النواة أفضل عرض دلالي للرسالة انطلاقًا من القدرات المصرّح بها.
- تصرّح الإضافات بالقدرات وتعرض العرض الدلالي إلى حِمولات نقل أصلية.
- تبقى واجهة Web Control UI منفصلة عن واجهة المحادثة الأصلية.
- لا تُعرض حِمولات القنوات الأصلية عبر سطح رسائل الوكيل المشترك أو CLI.
- تُخفّض ميزات العرض غير المدعومة تلقائيًا إلى أفضل تمثيل نصي.
- سلوك التسليم مثل تثبيت رسالة مُرسلة هو بيانات وصفية عامة للتسليم، وليس عرضًا تقديميًا.
غير مستهدف
- لا طبقة توافق رجعي لـ
buildCrossContextComponents. - لا منافذ هروب عامة أصلية لـ
componentsأوblocksأوbuttonsأوcard. - لا استيرادات في النواة لمكتبات واجهة مستخدم أصلية خاصة بالقنوات.
- لا وصلات SDK خاصة بالمزوّد للقنوات المضمّنة.
النموذج المستهدف
أضف حقل presentation مملوكًا للنواة إلى ReplyPayload.
type MessagePresentationTone = "neutral" | "info" | "success" | "warning" | "danger";
type MessagePresentation = {
tone?: MessagePresentationTone;
title?: string;
blocks: MessagePresentationBlock[];
};
type MessagePresentationBlock =
| { type: "text"; text: string }
| { type: "context"; text: string }
| { type: "divider" }
| { type: "buttons"; buttons: MessagePresentationButton[] }
| { type: "select"; placeholder?: string; options: MessagePresentationOption[] };
type MessagePresentationButton = {
label: string;
value?: string;
url?: string;
style?: "primary" | "secondary" | "success" | "danger";
};
type MessagePresentationOption = {
label: string;
value: string;
};
يصبح interactive مجموعة فرعية من presentation أثناء الترحيل:
- تُطابق كتلة نص
interactiveإلىpresentation.blocks[].type = "text". - تُطابق كتلة أزرار
interactiveإلىpresentation.blocks[].type = "buttons". - تُطابق كتلة اختيار
interactiveإلىpresentation.blocks[].type = "select".
تستخدم مخططات الوكيل الخارجي وCLI الآن presentation؛ ويبقى interactive مساعدًا داخليًا قديمًا للتحليل/العرض لمنتجي الردود الحاليين.
بيانات التسليم الوصفية
أضف حقل delivery مملوكًا للنواة لسلوك الإرسال الذي ليس واجهة مستخدم.
type ReplyPayloadDelivery = {
pin?:
| boolean
| {
enabled: boolean;
notify?: boolean;
required?: boolean;
};
};
الدلالات:
- يعني
delivery.pin = trueتثبيت أول رسالة يتم تسليمها بنجاح. - القيمة الافتراضية لـ
notifyهيfalse. - القيمة الافتراضية لـ
requiredهيfalse؛ القنوات غير المدعومة أو فشل التثبيت يُخفّضان تلقائيًا عبر متابعة التسليم. - تبقى إجراءات الرسائل اليدوية
pinوunpinوlist-pinsللرسائل الحالية.
يجب نقل ربط موضوع Telegram ACP الحالي من channelData.telegram.pin = true إلى delivery.pin = true.
عقد قدرات وقت التشغيل
أضف خطافات عرض وتوصيل للعرض التقديمي والتسليم إلى محوّل الصادر وقت التشغيل، وليس إلى Plugin القناة على مستوى التحكم.
type ChannelPresentationCapabilities = {
supported: boolean;
buttons?: boolean;
selects?: boolean;
context?: boolean;
divider?: boolean;
tones?: MessagePresentationTone[];
};
type ChannelDeliveryCapabilities = {
pinSentMessage?: boolean;
};
type ChannelOutboundAdapter = {
presentationCapabilities?: ChannelPresentationCapabilities;
renderPresentation?: (params: {
payload: ReplyPayload;
presentation: MessagePresentation;
ctx: ChannelOutboundSendContext;
}) => ReplyPayload | null;
deliveryCapabilities?: ChannelDeliveryCapabilities;
pinDeliveredMessage?: (params: {
cfg: OpenClawConfig;
accountId?: string | null;
to: string;
threadId?: string | number | null;
messageId: string;
notify: boolean;
}) => Promise<void>;
};
سلوك النواة:
- حلّ القناة الهدف ومحوّل وقت التشغيل.
- طلب قدرات العرض التقديمي.
- تخفيض الكتل غير المدعومة قبل العرض.
- استدعاء
renderPresentation. - إذا لم يوجد عارض، تحويل العرض التقديمي إلى بديل نصي.
- بعد نجاح الإرسال، استدعاء
pinDeliveredMessageعند طلبdelivery.pinودعمه.
ربط القنوات
Discord:
- عرض
presentationإلى components v2 وحاويات Carbon في وحدات وقت التشغيل فقط. - إبقاء مساعدات لون التمييز في وحدات خفيفة.
- إزالة استيرادات
DiscordUiContainerمن شيفرة مستوى التحكم في Plugin القناة.
Slack:
- عرض
presentationإلى Block Kit. - إزالة إدخال
blocksالخاص بالوكيل وCLI.
Telegram:
- عرض النص والسياق والفواصل كنص.
- عرض الإجراءات والاختيار كلوحات مفاتيح مضمنة عند تهيئتها والسماح بها للسطح الهدف.
- استخدام الرجوع النصي عند تعطيل الأزرار المضمنة.
- نقل تثبيت موضوع ACP إلى
delivery.pin.
Mattermost:
- عرض الإجراءات كأزرار تفاعلية عند تهيئتها.
- عرض الكتل الأخرى كرجوع نصي.
MS Teams:
- عرض
presentationإلى Adaptive Cards. - إبقاء إجراءات التثبيت/إلغاء التثبيت/عرض التثبيتات اليدوية.
- تنفيذ
pinDeliveredMessageاختياريًا إذا كان دعم Graph موثوقًا للمحادثة الهدف.
Feishu:
- عرض
presentationإلى بطاقات تفاعلية. - إبقاء إجراءات التثبيت/إلغاء التثبيت/عرض التثبيتات اليدوية.
- تنفيذ
pinDeliveredMessageاختياريًا لتثبيت الرسائل المُرسلة إذا كان سلوك API موثوقًا.
LINE:
- عرض
presentationإلى Flex أو رسائل القوالب حيثما أمكن. - الرجوع إلى النص للكتل غير المدعومة.
- إزالة حِمولات واجهة مستخدم LINE من
channelData.
القنوات النصية أو المحدودة:
- تحويل العرض التقديمي إلى نص بتنسيق محافظ.
خطوات إعادة الهيكلة
- أعد تطبيق إصلاح إصدار Discord الذي يفصل
ui-colors.tsعن واجهة المستخدم المدعومة بـCarbon ويزيلDiscordUiContainerمنextensions/discord/src/channel.ts. - أضف
presentationوdeliveryإلىReplyPayload، وتطبيع حِمولة الصادر، وملخصات التسليم، وحِمولات الخطافات. - أضف مخطط
MessagePresentationومساعدات التحليل في مسار SDK/وقت تشغيل فرعي ضيق. - استبدل قدرات الرسائل
buttonsوcardsوcomponentsوblocksبقدرات عرض دلالية. - أضف خطافات محوّل صادر وقت التشغيل لعرض العرض التقديمي وتثبيت التسليم.
- استبدل إنشاء المكوّنات العابرة للسياقات بـ
buildCrossContextPresentation. - احذف
src/infra/outbound/channel-adapters.tsوأزلbuildCrossContextComponentsمن أنواع Plugin القناة. - غيّر
maybeApplyCrossContextMarkerلإرفاقpresentationبدلًا من المعاملات الأصلية. - حدّث مسارات إرسال plugin-dispatch لاستهلاك العرض الدلالي وبيانات التسليم الوصفية فقط.
- أزل معاملات الحِمولة الأصلية للوكيل وCLI:
componentsوblocksوbuttonsوcard. - أزل مساعدات SDK التي تنشئ مخططات أدوات الرسائل الأصلية، واستبدلها بمساعدات مخطط العرض التقديمي.
- أزل أغلفة واجهة المستخدم/الأصلية من
channelData؛ أبقِ فقط بيانات النقل الوصفية إلى أن تتم مراجعة كل حقل متبقٍ. - رحّل عارضات Discord وSlack وTelegram وMattermost وMS Teams وFeishu وLINE.
- حدّث وثائق CLI الرسائل، وصفحات القنوات، وPlugin SDK، وكتاب وصفات القدرات.
- شغّل تحليل تفرّع الاستيراد لنقاط دخول Discord والقنوات المتأثرة.
نُفّذت الخطوات 1-11 و13-14 في إعادة الهيكلة هذه لعقود الوكيل المشترك وCLI وقدرة Plugin ومحوّل الصادر. تبقى الخطوة 12 تمريرة تنظيف داخلية أعمق لأغلفة نقل channelData الخاصة بالمزوّدين. وتبقى الخطوة 15 تحققًا لاحقًا إذا أردنا أرقامًا كمية لتفرّع الاستيراد تتجاوز بوابة الأنواع/الاختبارات.
الاختبارات
أضف أو حدّث:
- اختبارات تطبيع العرض التقديمي.
- اختبارات التخفيض التلقائي للعرض التقديمي للكتل غير المدعومة.
- اختبارات علامة السياق العابر لمسارات plugin dispatch والتسليم في النواة.
- اختبارات مصفوفة عارض القنوات لـDiscord وSlack وTelegram وMattermost وMS Teams وFeishu وLINE والرجوع النصي.
- اختبارات مخطط أداة الرسائل التي تثبت اختفاء الحقول الأصلية.
- اختبارات CLI التي تثبت اختفاء الأعلام الأصلية.
- اختبار تراجع كسل الاستيراد لنقطة دخول Discord يغطي Carbon.
- اختبارات تثبيت التسليم التي تغطي Telegram والرجوع العام.
الأسئلة المفتوحة
- هل ينبغي تنفيذ
delivery.pinلـDiscord وSlack وMS Teams وFeishu في التمريرة الأولى، أم Telegram فقط أولًا؟ - هل ينبغي أن يستوعب
deliveryفي النهاية الحقول الحالية مثلreplyToIdوreplyToCurrentوsilentوaudioAsVoice، أم يبقى مركّزًا على سلوكيات ما بعد الإرسال؟ - هل ينبغي أن يدعم العرض التقديمي الصور أو مراجع الملفات مباشرة، أم يجب أن تبقى الوسائط منفصلة عن تخطيط واجهة المستخدم حاليًا؟