Plugin maintainer reference
البنية الداخلية لمعمارية Plugin
للاطّلاع على نموذج القدرات العام، وأشكال Plugin، وعقود الملكية/التنفيذ، راجع بنية Plugin. تتناول هذه الصفحة الآليات الداخلية: مسار التحميل، والسجل، وخطافات وقت التشغيل، ومسارات HTTP الخاصة بـ Gateway، ومسارات الاستيراد، وجداول المخططات.
مسار التحميل
عند بدء التشغيل، ينفّذ OpenClaw تقريبًا ما يلي:
- اكتشاف الجذور المرشحة لـ Plugin
- قراءة بيانات حزم التجميع الأصلية أو المتوافقة وبيانات تعريف الحزمة
- رفض المرشحين غير الآمنين
- تسوية إعدادات Plugin (
plugins.enabledوallowوdenyوentriesوslotsوload.paths) - تحديد حالة التمكين لكل مرشح
- تحميل الوحدات الأصلية الممكّنة: تستخدم الوحدات المضمّنة المبنية محمّلًا أصليًا؛ بينما تستخدم الشيفرة المصدرية المحلية التابعة لجهات خارجية والمكتوبة بـ TypeScript آلية Jiti الاحتياطية الطارئة
- استدعاء خطافات
register(api)الأصلية وجمع التسجيلات في سجل Plugin - إتاحة السجل للأوامر وأسطح وقت التشغيل
تعمل بوابات الأمان قبل تنفيذ وقت التشغيل. يحظر الاكتشاف مرشحًا عندما:
- يتجاوز مدخله المحلول جذر Plugin
- يكون مساره (أو دليل الجذر الخاص به) قابلًا للكتابة من الجميع
- لا تتطابق ملكية المسار مع معرّف المستخدم الحالي uid (أو root)، في Plugins غير المضمّنة
تخضع الأدلة المضمّنة القابلة للكتابة من الجميع أولًا لمحاولة إصلاح موضعية باستخدام chmod (قد توزّع عمليات تثبيت npm/العمليات العامة أدلة الحزم بأذونات 0777) قبل أن تعيد البوابة التحقق؛ بينما تُتخطى عمليات التحقق من الملكية كليًا للمصادر المضمّنة.
يظل المرشحون المحظورون يحملون معرّف Plugin الخاص بهم في التشخيص الصادر عندما يكون معروفًا (بما في ذلك المعرّفات المحلولة من بيانات حزمة داخل دليل مرفوض من نواحٍ أخرى)، بحيث ترى الإعدادات التي تشير إلى ذلك المعرّف Plugin محظورًا مرتبطًا بتحذير أمان المسار بدلًا من خطأ "Plugin غير معروف" غير ذي صلة.
سلوك تقديم بيانات الحزمة
تُعد بيانات الحزمة مصدر الحقيقة لمستوى التحكم. يستخدمها OpenClaw من أجل:
- تحديد Plugin
- اكتشاف القنوات/Skills/مخطط الإعدادات أو قدرات حزمة التجميع المعلنة
- التحقق من
plugins.entries.<id>.config - إثراء تسميات واجهة التحكم ونصوصها النائبة
- عرض بيانات تعريف التثبيت/الكتالوج
- الاحتفاظ بواصفات تفعيل وإعداد منخفضة التكلفة دون تحميل وقت تشغيل Plugin
بالنسبة إلى Plugins الأصلية، تمثل وحدة وقت التشغيل جزء مستوى البيانات. وهي تسجّل السلوك الفعلي، مثل الخطافات أو الأدوات أو الأوامر أو تدفقات المزوّدين.
تبقى كتلتَا activation وsetup الاختياريتان في مستوى التحكم. وهما واصفتان من بيانات التعريف فقط لتخطيط التفعيل واكتشاف الإعداد؛ ولا تحلان محل التسجيل في وقت التشغيل أو register(...) أو setupEntry. يستخدم مستهلكو التفعيل المباشر تلميحات الأوامر والقنوات والمزوّدين الواردة في بيانات الحزمة لتضييق تحميل Plugins قبل تكوين السجل على نطاق أوسع:
- يضيّق تحميل CLI النطاق إلى Plugins المالكة للأمر الأساسي المطلوب
- يضيّق إعداد القناة/حل Plugin النطاق إلى Plugins المالكة لمعرّف القناة المطلوب
- يضيّق إعداد المزوّد الصريح/حله في وقت التشغيل النطاق إلى Plugins المالكة لمعرّف المزوّد المطلوب
- يستخدم تخطيط بدء تشغيل Gateway القيمة
activation.onStartupلعمليات الاستيراد الصريحة عند بدء التشغيل؛ ولا تُحمّل Plugins التي لا تتضمن بيانات تعريف لبدء التشغيل إلا عبر مشغلات تفعيل أضيق نطاقًا
يعرض مخطّط التفعيل واجهة API تقتصر على المعرّفات للمتصلين الحاليين، وواجهة API للخطة لأغراض التشخيص. توضّح إدخالات الخطة سبب اختيار Plugin، مع الفصل بين تلميحات activation.* الصريحة والرجوع إلى ملكية بيانات الحزمة:
السبب (من تلميحات activation.*) |
السبب (من ملكية بيانات الحزمة) |
|---|---|
activation-agent-harness-hint |
— |
activation-capability-hint |
— |
activation-channel-hint |
manifest-channel-owner (channels) |
activation-command-hint |
manifest-command-alias (commandAliases) |
activation-provider-hint |
manifest-provider-owner (providers), manifest-setup-provider-owner (setup.providers) |
activation-route-hint |
— |
| — (لا يتضمن مشغل الخطاف صيغة تلميح) | manifest-hook-owner (hooks), manifest-tool-contract (contracts.tools) |
يمثل هذا الفصل بين الأسباب حد التوافق: تستمر بيانات تعريف Plugin الحالية في العمل، بينما تستطيع الشيفرة الجديدة اكتشاف التلميحات واسعة النطاق أو سلوك الرجوع دون تغيير دلالات التحميل في وقت التشغيل.
تستمر عمليات التحميل المسبق في وقت الطلب التي تطلب النطاق الواسع all في اشتقاق مجموعة صريحة وفعّالة من معرّفات Plugins من الإعدادات، وتخطيط بدء التشغيل، والقنوات المضبوطة، والخانات، وقواعد التمكين التلقائي (resolveEffectivePluginIds في src/plugins/effective-plugin-ids.ts). وإذا كانت المجموعة المشتقة فارغة، يُبقي OpenClaw النطاق فارغًا بدلًا من توسيعه ليشمل كل Plugin قابل للاكتشاف.
يفضّل اكتشاف الإعداد المعرّفات المملوكة للواصفات، مثل setup.providers وsetup.cliBackends، لتضييق نطاق Plugins المرشحة قبل الرجوع إلى setup-api في Plugins التي لا تزال بحاجة إلى خطافات وقت التشغيل أثناء الإعداد. تستخدم قوائم إعداد المزوّد providerAuthChoices الواردة في بيانات الحزمة، وخيارات الإعداد المشتقة من الواصفات، وبيانات تعريف كتالوج التثبيت دون تحميل وقت تشغيل المزوّد. تمثل القيمة الصريحة setup.requiresRuntime: false حدًا يقتصر على الواصفات؛ بينما يؤدي حذف requiresRuntime إلى الإبقاء على الرجوع القديم إلى setup-api لأغراض التوافق. إذا ادّعى أكثر من Plugin مكتشف ملكية معرّف مزوّد إعداد أو معرّف واجهة CLI خلفية مُسوّى نفسه، يرفض بحث الإعداد المالك الملتبس بدلًا من الاعتماد على ترتيب الاكتشاف. وعند تنفيذ وقت تشغيل الإعداد، تُبلغ تشخيصات السجل عن الانحراف بين setup.providers / setup.cliBackends والمزوّدين أو واجهات CLI الخلفية المسجّلة فعليًا بواسطة setup-api، دون حظر Plugins القديمة.
حدود ذاكرة Plugin المؤقتة
لا يخزّن OpenClaw مؤقتًا نتائج اكتشاف Plugins أو بيانات سجل بيانات الحزمة المباشرة ضمن نوافذ زمنية فعلية. يجب أن تصبح عمليات التثبيت، وتعديلات بيانات الحزمة، وتغييرات مسارات التحميل مرئية عند القراءة الصريحة التالية لبيانات التعريف أو إعادة بناء اللقطة. يحتفظ محلل ملف بيانات الحزمة بذاكرة مؤقتة محدودة لتوقيع الملف، يكون مفتاحها مسار ملف بيانات الحزمة المفتوح مع الجهاز/inode والحجم وmtime/ctime؛ ولا تتجنب تلك الذاكرة المؤقتة سوى إعادة تحليل البايتات غير المتغيرة، ويجب ألا تخزّن مؤقتًا إجابات الاكتشاف أو السجل أو المالك أو السياسة.
المسار السريع الآمن لبيانات التعريف هو الملكية الصريحة للكائنات، لا ذاكرة مؤقتة مخفية. ينبغي أن تمرّر المسارات الساخنة عند بدء تشغيل Gateway قيمة PluginMetadataSnapshot الحالية، أو PluginLookUpTable المشتق، أو سجل بيانات حزمة صريح عبر سلسلة الاستدعاءات. يمكن للتحقق من الإعدادات، والتمكين التلقائي عند بدء التشغيل، وتهيئة Plugin، واختيار المزوّد إعادة استخدام تلك الكائنات ما دامت تمثل الإعدادات الحالية ومخزون Plugins الحالي. لا يزال بحث الإعداد يعيد تكوين بيانات تعريف بيانات الحزمة عند الطلب، إلا إذا تلقى مسار الإعداد المحدد سجل بيانات حزمة صريحًا؛ احتفظ بذلك كآلية رجوع للمسارات الباردة بدلًا من إضافة ذاكرات بحث مؤقتة مخفية. عند تغير الإدخال، أعد بناء اللقطة واستبدلها بدلًا من تعديلها أو الاحتفاظ بنسخ تاريخية منها. ينبغي إعادة حساب العروض المستندة إلى سجل Plugin النشط ومساعدات تهيئة القنوات المضمّنة من السجل/الجذر الحالي. لا بأس بالخرائط قصيرة العمر داخل استدعاء واحد لإزالة تكرار العمل أو منع إعادة الدخول؛ لكن يجب ألا تتحول إلى ذاكرات مؤقتة لبيانات تعريف العملية.
بالنسبة إلى تحميل Plugin، تتمثل طبقة التخزين المؤقت الدائمة في تحميل وقت التشغيل. ويمكنها إعادة استخدام حالة المحمّل عند تحميل الشيفرة أو العناصر المثبتة فعليًا، مثل:
PluginLoaderCacheStateوسجلات وقت التشغيل النشطة المتوافقة- ذاكرات jiti/الوحدات المؤقتة وذاكرات محمّل السطح العام المؤقتة المستخدمة لتجنب استيراد سطح وقت التشغيل نفسه بصورة متكررة
- ذاكرات نظام الملفات المؤقتة لعناصر Plugin المثبتة
- خرائط قصيرة العمر لكل استدعاء لتسوية المسارات أو حل التكرارات
هذه الذاكرات المؤقتة تفاصيل تنفيذية لمستوى البيانات. ويجب ألا تجيب عن أسئلة مستوى التحكم، مثل "أي Plugin يملك هذا المزوّد؟"، إلا إذا طلب المتصل تحميل وقت التشغيل عمدًا.
لا تضف ذاكرات مؤقتة دائمة أو مرتبطة بالوقت الفعلي من أجل:
- نتائج الاكتشاف
- سجلات بيانات الحزمة المباشرة
- سجلات بيانات الحزمة المعاد تكوينها من فهرس Plugins المثبتة
- البحث عن مالك المزوّد، أو حجب النموذج، أو سياسة المزوّد، أو بيانات تعريف العناصر العامة
- أي إجابة أخرى مشتقة من بيانات الحزمة، عندما ينبغي أن يظهر تغيير بيانات الحزمة أو الفهرس المثبت أو مسار التحميل عند القراءة التالية لبيانات التعريف
يعيد المتصلون الذين يبنون بيانات تعريف بيانات الحزمة من فهرس Plugins المثبتة والمستمر تخزينه تكوين ذلك السجل عند الطلب. الفهرس المثبت هو حالة دائمة لمستوى المصدر؛ وليس ذاكرة مؤقتة مخفية لبيانات التعريف داخل العملية.
نموذج السجل
لا تعدّل Plugins المحمّلة المتغيرات العامة العشوائية في النواة مباشرةً. بل تسجّل في سجل Plugin مركزي (PluginRegistry في src/plugins/registry-types.ts)، يتتبع سجلات Plugins (الهوية، والمصدر، والأصل، والحالة، والتشخيصات)، بالإضافة إلى مصفوفات لكل قدرة: الأدوات، والخطافات القديمة والخطافات المنمطة، والقنوات، والمزوّدون، ومعالجات RPC الخاصة بـ Gateway، ومسارات HTTP، ومسجّلو CLI، وخدمات الخلفية، والأوامر المملوكة لـ Plugin، وعشرات عائلات المزوّدين المنمطة الأخرى (الكلام، والتضمينات، وتوليد الصور/الفيديو/الموسيقى، وجلب الويب/البحث فيه، وأطر الوكلاء، وإجراءات الجلسات، وما إلى ذلك).
تقرأ ميزات النواة بعد ذلك من هذا السجل بدلًا من التواصل مباشرةً مع وحدات Plugin. وهذا يحافظ على اتجاه واحد للتحميل:
- وحدة Plugin -> التسجيل في السجل
- وقت تشغيل النواة -> استهلاك السجل
هذا الفصل مهم لقابلية الصيانة. فهو يعني أن معظم أسطح النواة لا تحتاج إلا إلى نقطة تكامل واحدة: "قراءة السجل"، بدلًا من "إضافة معالجة خاصة لكل وحدة Plugin".
استدعاءات ربط المحادثة
يمكن لـ Plugins التي تربط محادثة أن تتفاعل عند حسم الموافقة.
استخدم api.onConversationBindingResolved(...) لتلقي استدعاء بعد الموافقة على طلب الربط أو رفضه:
export default { id: "my-plugin", register(api) { api.onConversationBindingResolved(async (event) => { if (event.status === "approved") { // A binding now exists for this plugin + conversation. console.log(event.binding?.conversationId); return; } // The request was denied; clear any local pending state. console.log(event.request.conversation.conversationId); }); },};حقول حمولة الاستدعاء:
status:"approved"أو"denied"decision:"allow-once"أو"allow-always"أو"deny"binding: الربط المحلول للطلبات الموافق عليهاrequest: ملخص الطلب الأصلي، وتلميح الفصل، ومعرّف المرسل، وبيانات تعريف المحادثة
هذا الاستدعاء مخصص للإشعار فقط. ولا يغيّر الجهات المسموح لها بربط محادثة، ويُنفّذ بعد انتهاء معالجة الموافقة في النواة.
خطافات وقت تشغيل المزوّد
تتكون Plugins الخاصة بالمزوّدين من ثلاث طبقات:
- بيانات تعريف بيانات الحزمة للبحث منخفض التكلفة قبل وقت التشغيل:
setup.providers[].envVars، وproviderAuthEnvVarsالمتقادمة المخصصة للتوافق، وproviderAuthAliases، وproviderAuthChoices، وchannelEnvVars. - خطافات وقت الإعداد:
catalog(والاسم القديمdiscovery) بالإضافة إلىapplyConfigDefaults. - خطافات وقت التشغيل: أكثر من 40 خطافًا اختياريًا تغطي المصادقة، وحل النماذج، وتغليف التدفق، ومستويات التفكير، وسياسة إعادة التشغيل، ونقاط نهاية الاستخدام. راجع ترتيب الخطافات واستخدامها.
يظل OpenClaw مسؤولًا عن حلقة الوكيل العامة، وتجاوز الأعطال، ومعالجة النصوص المنسوخة، وسياسة الأدوات. وتمثل هذه الخطافات سطح التوسعة للسلوك الخاص بالمزوّد دون الحاجة إلى وسيلة نقل استدلال مخصصة بالكامل.
استخدم setup.providers[].envVars في البيان عندما تكون لدى المزوّد بيانات اعتماد قائمة على متغيرات البيئة ينبغي أن تتمكن مسارات المصادقة/الحالة/منتقي النماذج العامة من رؤيتها من دون تحميل وقت تشغيل Plugin. لا يزال محوّل التوافق يقرأ providerAuthEnvVars المهجورة خلال فترة الإهمال، وتتلقى الإضافات غير المضمّنة التي تستخدمها تشخيصًا للبيان. استخدم providerAuthAliases في البيان عندما ينبغي لمعرّف مزوّد أن يعيد استخدام متغيرات البيئة وملفات تعريف المصادقة والمصادقة المدعومة بالإعدادات وخيار إعداد مفتاح API لمعرّف مزوّد آخر. استخدم providerAuthChoices في البيان عندما ينبغي لواجهات CLI الخاصة بالإعداد الأولي/اختيار المصادقة أن تعرف معرّف خيار المزوّد وتسميات المجموعات وآلية توصيل المصادقة البسيطة ذات العلامة الواحدة من دون تحميل وقت تشغيل المزوّد. احتفظ بـ envVars في وقت تشغيل المزوّد للتلميحات الموجّهة إلى المشغّلين، مثل تسميات الإعداد الأولي أو متغيرات إعداد معرّف عميل OAuth/سر العميل.
استخدم channelEnvVars في البيان عندما تكون لدى القناة مصادقة أو إعداد يعتمدان على متغيرات البيئة، وينبغي أن تتمكن آلية الرجوع العامة إلى متغيرات بيئة الصدفة أو عمليات التحقق من الإعدادات/الحالة أو مطالبات الإعداد من رؤيتها من دون تحميل وقت تشغيل القناة.
ترتيب الخطافات واستخدامها
بالنسبة إلى إضافات النماذج/المزوّدين، يستدعي OpenClaw الخطافات بهذا الترتيب التقريبي.
يمثّل عمود "متى يُستخدم" دليل القرار السريع.
لا تُدرج هنا عمدًا حقول المزوّد المخصّصة للتوافق فقط، والتي لم يعد OpenClaw يستدعيها، مثل ProviderPlugin.capabilities وsuppressBuiltInModel.
| الخطاف | ما الذي يفعله | متى يُستخدم |
|---|---|---|
catalog |
ينشر إعدادات المزوّد في models.providers أثناء إنشاء models.json |
عندما يملك المزوّد كتالوجًا أو قيمًا افتراضية لعنوان URL الأساسي |
applyConfigDefaults |
يطبّق القيم الافتراضية العامة للإعدادات التي يملكها المزوّد أثناء تجسيد الإعدادات | عندما تعتمد القيم الافتراضية على وضع المصادقة أو متغيرات البيئة أو دلالات عائلة نماذج المزوّد |
| (البحث المضمّن عن النموذج) | يجرّب OpenClaw أولًا مسار السجل/الكتالوج المعتاد | (ليس خطاف Plugin) |
normalizeModelId |
يطبّع الأسماء البديلة القديمة أو التجريبية لمعرّفات النماذج قبل البحث | عندما يملك المزوّد تنظيف الأسماء البديلة قبل الحل القانوني للنموذج |
normalizeTransport |
يطبّع api / baseUrl لعائلة المزوّد قبل التجميع العام للنموذج |
عندما يملك المزوّد تنظيف النقل لمعرّفات المزوّدين المخصصة ضمن عائلة النقل نفسها |
normalizeConfig |
يطبّع models.providers.<id> قبل حل وقت التشغيل/المزوّد |
عندما يحتاج المزوّد إلى تنظيف الإعدادات الذي ينبغي أن يكون ضمن Plugin؛ كما توفر الأدوات المساعدة المضمّنة لعائلة Google دعمًا احتياطيًا لإدخالات إعدادات Google المدعومة |
applyNativeStreamingUsageCompat |
يطبّق عمليات إعادة كتابة التوافق الأصلية لاستخدام البث على مزوّدي الإعدادات | عندما يحتاج المزوّد إلى إصلاحات لبيانات استخدام البث الأصلية الوصفية تعتمد على نقطة النهاية |
resolveConfigApiKey |
يحل مصادقة علامة البيئة لمزوّدي الإعدادات قبل تحميل مصادقة وقت التشغيل | عندما تعرض المزوّدات خطافات خاصة بها لحل مفتاح API من علامة البيئة |
resolveSyntheticAuth |
يعرض مصادقة محلية/مستضافة ذاتيًا أو مدعومة بالإعدادات من دون تخزين نص صريح | عندما يستطيع المزوّد العمل باستخدام علامة اعتماد اصطناعية/محلية |
resolveExternalAuthProfiles |
يركّب ملفات تعريف المصادقة الخارجية التي يملكها المزوّد؛ القيمة الافتراضية لـ persistence هي runtime-only لبيانات الاعتماد التي تملكها CLI/التطبيق |
عندما يعيد المزوّد استخدام بيانات اعتماد مصادقة خارجية من دون تخزين رموز التحديث المنسوخة؛ صرّح بـ contracts.externalAuthProviders في البيان |
shouldDeferSyntheticProfileAuth |
يخفض أولوية العناصر النائبة لملفات التعريف الاصطناعية المخزنة خلف المصادقة المدعومة بالبيئة/الإعدادات | عندما يخزّن المزوّد ملفات تعريف اصطناعية نائبة ينبغي ألا تتقدم في الأولوية |
resolveDynamicModel |
رجوع احتياطي متزامن لمعرّفات النماذج التي يملكها المزوّد ولم توجد بعد في السجل المحلي | عندما يقبل المزوّد معرّفات نماذج اعتباطية من المصدر العلوي |
prepareDynamicModel |
يجري تهيئة غير متزامنة، ثم يُشغَّل resolveDynamicModel مجددًا |
عندما يحتاج المزوّد إلى بيانات وصفية من الشبكة قبل حل المعرّفات غير المعروفة |
normalizeResolvedModel |
إعادة الكتابة النهائية قبل أن يستخدم المشغّل المضمّن النموذج المحلول | عندما يحتاج المزوّد إلى إعادة كتابة النقل لكنه يظل يستخدم نقلًا أساسيًا |
normalizeToolSchemas |
يطبّع مخططات الأدوات قبل أن يراها المشغّل المضمّن | عندما يحتاج المزوّد إلى تنظيف مخططات عائلة النقل |
inspectToolSchemas |
يعرض تشخيصات المخططات التي يملكها المزوّد بعد التطبيع | عندما يريد المزوّد تحذيرات بشأن الكلمات المفتاحية من دون تعليم النواة قواعد خاصة بالمزوّد |
resolveReasoningOutputMode |
يحدد عقد إخراج الاستدلال الأصلي مقابل الموسوم | عندما يحتاج المزوّد إلى إخراج استدلال/نهائي موسوم بدلًا من الحقول الأصلية |
prepareExtraParams |
يطبّع معاملات الطلب قبل أغلفة خيارات البث العامة | عندما يحتاج المزوّد إلى معاملات طلب افتراضية أو تنظيف معاملات خاص بكل مزوّد |
createStreamFn |
يستبدل مسار البث المعتاد بالكامل بنقل مخصص | عندما يحتاج المزوّد إلى بروتوكول سلكي مخصص، وليس مجرد غلاف |
wrapStreamFn |
غلاف للبث بعد تطبيق الأغلفة العامة | عندما يحتاج المزوّد إلى أغلفة توافق لترويسات الطلب/نصه/نموذجه من دون نقل مخصص |
resolveTransportTurnState |
يرفق ترويسات أو بيانات وصفية أصلية للنقل لكل دورة | عندما يريد المزوّد من وسائل النقل العامة إرسال هوية الدورة الأصلية الخاصة به |
resolveWebSocketSessionPolicy |
يرفق ترويسات WebSocket أصلية أو سياسة تهدئة للجلسة | عندما يريد المزوّد من وسائل نقل WS العامة ضبط ترويسات الجلسة أو سياسة الرجوع الاحتياطي |
formatApiKey |
منسّق ملف تعريف المصادقة: يتحول ملف التعريف المخزن إلى سلسلة apiKey لوقت التشغيل |
عندما يخزّن المزوّد بيانات وصفية إضافية للمصادقة ويحتاج إلى بنية مخصصة لرمز وقت التشغيل |
refreshOAuth |
تجاوز لتحديث OAuth لنقاط نهاية تحديث مخصصة أو سياسة فشل التحديث | عندما لا يتوافق المزوّد مع أدوات التحديث المشتركة في OpenClaw |
buildAuthDoctorHint |
تلميح إصلاح يُلحق عند فشل تحديث OAuth | عندما يحتاج المزوّد إلى إرشادات إصلاح للمصادقة يملكها بعد فشل التحديث |
matchesContextOverflowError |
أداة مطابقة يملكها المزوّد لتجاوز نافذة السياق | عندما تكون لدى المزوّد أخطاء تجاوز أولية قد لا تكتشفها الأساليب الإرشادية العامة |
classifyFailoverReason |
تصنيف يملكه المزوّد لسبب تجاوز الفشل | عندما يستطيع المزوّد تعيين أخطاء API/النقل الأولية إلى تحديد المعدل/الحمل الزائد/غير ذلك |
isCacheTtlEligible |
سياسة ذاكرة التخزين المؤقت للمطالبات لمزوّدي الوكيل/النقل الخلفي | عندما يحتاج المزوّد إلى تقييد مدة صلاحية ذاكرة التخزين المؤقت بحسب الوكيل |
buildMissingAuthMessage |
بديل لرسالة الاسترداد العامة عند فقدان المصادقة | عندما يحتاج المزوّد إلى تلميح استرداد خاص به عند فقدان المصادقة |
augmentModelCatalog |
صفوف كتالوج اصطناعية/نهائية تُلحق بعد الاكتشاف (مهجور، انظر أدناه) | عندما يحتاج المزوّد إلى صفوف اصطناعية للتوافق المستقبلي في models list وأدوات الاختيار |
resolveThinkingProfile |
مجموعة مستويات /think الخاصة بالنموذج وتسميات العرض والقيمة الافتراضية |
عندما يعرض المزوّد تدرجًا مخصصًا للتفكير أو تسمية ثنائية للنماذج المحددة |
isBinaryThinking |
خطاف توافق لتبديل الاستدلال بين التشغيل/الإيقاف | عندما يعرض المزوّد التفكير الثنائي تشغيل/إيقاف فقط |
supportsXHighThinking |
خطاف توافق لدعم استدلال xhigh |
عندما يريد المزوّد إتاحة xhigh لمجموعة فرعية فقط من النماذج |
resolveDefaultThinkingLevel |
خطاف توافق لمستوى /think الافتراضي |
عندما يملك المزوّد سياسة /think الافتراضية لعائلة نماذج |
isModernModelRef |
أداة مطابقة للنماذج الحديثة لمرشحات ملفات التعريف الحية واختيار اختبار الدخان | عندما يملك المزوّد مطابقة النموذج المفضّل للاختبارات الحية/اختبارات الدخان |
prepareRuntimeAuth |
يستبدل بيانات اعتماد مضبوطة بالرمز/المفتاح الفعلي لوقت التشغيل قبل الاستدلال مباشرة | عندما يحتاج المزوّد إلى تبادل رمز أو بيانات اعتماد طلب قصيرة العمر |
resolveUsageAuth |
يحل بيانات اعتماد الاستخدام/الفوترة لـ /usage وأسطح الحالة ذات الصلة |
عندما يحتاج المزوّد إلى تحليل مخصص لرمز الاستخدام/الحصة أو إلى بيانات اعتماد استخدام مختلفة |
fetchUsageSnapshot |
يجلب لقطات الاستخدام/الحصة الخاصة بالمزوّد ويطبّعها بعد حل المصادقة | عندما يحتاج المزوّد إلى نقطة نهاية استخدام خاصة به أو محلل للحمولة |
createEmbeddingProvider |
إنشاء محوّل تضمين مملوك للموفّر للذاكرة/البحث | سلوك تضمين الذاكرة يتبع Plugin الموفّر |
buildReplayPolicy |
إرجاع سياسة إعادة تشغيل تتحكم في معالجة نص المحادثة للموفّر | يحتاج الموفّر إلى سياسة مخصصة لنص المحادثة (مثل إزالة كتل التفكير) |
sanitizeReplayHistory |
إعادة كتابة سجل إعادة التشغيل بعد التنظيف العام لنص المحادثة | يحتاج الموفّر إلى عمليات إعادة كتابة خاصة به لإعادة التشغيل تتجاوز مساعدات Compaction المشتركة |
validateReplayTurns |
التحقق النهائي من أدوار إعادة التشغيل أو إعادة تشكيلها قبل المشغّل المضمّن | يحتاج نقل الموفّر إلى تحقق أكثر صرامة من الأدوار بعد التنقية العامة |
onModelSelected |
تشغيل الآثار الجانبية اللاحقة للاختيار والمملوكة للموفّر | يحتاج الموفّر إلى بيانات القياس عن بُعد أو حالة مملوكة له عند تنشيط نموذج |
تتحقق normalizeModelId وnormalizeTransport وnormalizeConfig أولًا من
Plugin المزوّد المطابق، ثم تنتقل إلى Plugins المزوّدين الآخرين القادرين على
استخدام الخطافات حتى يغيّر أحدها فعليًا معرّف النموذج أو النقل/الإعداد. يحافظ
ذلك على عمل طبقات المزوّد البديلة/المتوافقة دون أن يُطلب من المستدعي معرفة أي
Plugin مضمّن يملك إعادة الكتابة. إذا لم يُعِد أي خطاف مزوّد كتابة إدخال إعداد
مدعوم من عائلة Google، فسيظل مُطبِّع إعداد Google المضمّن يطبّق عملية تنظيف
التوافق تلك.
إذا كان المزوّد يحتاج إلى بروتوكول اتصال مخصص بالكامل أو منفّذ طلبات مخصص، فهذه فئة مختلفة من الامتدادات. هذه الخطافات مخصصة لسلوك المزوّد الذي يستمر في العمل ضمن حلقة الاستدلال العادية في OpenClaw.
تقرر resolveUsageAuth ما إذا كان ينبغي لـ OpenClaw استدعاء
fetchUsageSnapshot أو الرجوع إلى الحل العام لبيانات الاعتماد لواجهات
الاستخدام/الحالة. أعد { token, accountId?, subscriptionType?, rateLimitTier? }
عندما يملك المزوّد بيانات اعتماد للاستخدام (تنتقل بيانات الخطة الوصفية
الاختيارية إلى fetchUsageSnapshot)، وأعد { handled: true } عندما تكون
مصادقة الاستخدام المملوكة للمزوّد قد عالجت الطلب ويجب أن تمنع الرجوع العام
إلى مفتاح API أو OAuth، وأعد null أو undefined عندما لا يعالج المزوّد
مصادقة الاستخدام.
صرّح ببيانات اعتماد المؤسسة أو الفوترة في
providerUsageAuthEnvVars ضمن البيان. يتيح ذلك لواجهات الاكتشاف العام وتنقية
الأسرار التعرّف عليها دون جعلها مرشحة لمصادقة الاستدلال.
مثال على مزوّد
api.registerProvider({ id: "example-proxy", label: "Example Proxy", auth: [], catalog: { order: "simple", run: async (ctx) => { const apiKey = ctx.resolveProviderApiKey("example-proxy").apiKey; if (!apiKey) { return null; } return { provider: { baseUrl: "https://proxy.example.com/v1", apiKey, api: "openai-completions", models: [{ id: "auto", name: "Auto" }], }, }; }, }, resolveDynamicModel: (ctx) => ({ id: ctx.modelId, name: ctx.modelId, provider: "example-proxy", api: "openai-completions", baseUrl: "https://proxy.example.com/v1", reasoning: false, input: ["text"], cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, contextWindow: 128000, maxTokens: 8192, }), prepareRuntimeAuth: async (ctx) => { const exchanged = await exchangeToken(ctx.apiKey); return { apiKey: exchanged.token, baseUrl: exchanged.baseUrl, expiresAt: exchanged.expiresAt, }; }, resolveUsageAuth: async (ctx) => { const auth = await ctx.resolveOAuthToken(); return auth ? { token: auth.token } : null; }, fetchUsageSnapshot: async (ctx) => { return await fetchExampleProxyUsage(ctx.token, ctx.timeoutMs, ctx.fetchFn); },});أمثلة مضمّنة
تجمع Plugins المزوّدين المضمّنة الخطافات أعلاه لتلائم احتياجات كل مورّد
إلى الفهرس والمصادقة والتفكير وإعادة التشغيل والاستخدام. تعيش مجموعة
الخطافات المرجعية مع كل Plugin ضمن extensions/؛ وتوضح هذه الصفحة الأشكال
بدلًا من تكرار القائمة.
مزوّدو الفهرس بالتمرير المباشر
يسجّل OpenRouter وKilocode وZ.AI وxAI الخاصية catalog بالإضافة إلى
resolveDynamicModel / prepareDynamicModel حتى يتمكنوا من إظهار معرّفات
النماذج في المنبع قبل فهرس OpenClaw الثابت.
مزوّدو OAuth ونقاط نهاية الاستخدام
يقرن GitHub Copilot وGemini CLI وChatGPT Codex وMiniMax وXiaomi وz.ai
prepareRuntimeAuth أو formatApiKey مع resolveUsageAuth +
fetchUsageSnapshot لامتلاك تبادل الرمز المميز وتكامل /usage.
عائلات تنظيف إعادة التشغيل والنصوص المنسوخة
تتيح العائلات المشتركة المسماة (google-gemini وpassthrough-gemini
وanthropic-by-model وhybrid-anthropic-openai) للمزوّدين الاشتراك في
سياسة النصوص المنسوخة عبر buildReplayPolicy بدلًا من أن يعيد كل Plugin
تنفيذ عملية التنظيف.
مزوّدو الفهرس فقط
تسجّل byteplus وcloudflare-ai-gateway وhuggingface وkimi-coding
وnvidia وqianfan وsynthetic وtogether وvenice
وvercel-ai-gateway وvolcengine الخاصية catalog فقط وتستخدم حلقة
الاستدلال المشتركة.
مساعدات التدفق الخاصة بـ Anthropic
تعيش ترويسات الإصدار التجريبي و/fast / serviceTier وcontext1m داخل
واجهة api.ts / contract-api.ts العامة لـ Plugin Anthropic
(wrapAnthropicProviderStream وresolveAnthropicBetas
وresolveAnthropicFastMode وresolveAnthropicServiceTier) بدلًا من SDK
العام.
مساعدات وقت التشغيل
يمكن لـ Plugins الوصول إلى مساعدات أساسية محددة عبر api.runtime. لتحويل
النص إلى كلام:
const clip = await api.runtime.tts.textToSpeech({ text: "Hello from OpenClaw", cfg: api.config,}); const result = await api.runtime.tts.textToSpeechTelephony({ text: "Hello from OpenClaw", cfg: api.config,}); const voices = await api.runtime.tts.listVoices({ provider: "elevenlabs", cfg: api.config,});ملاحظات:
- تعيد
textToSpeechحمولة إخراج تحويل النص إلى كلام الأساسية المعتادة لواجهات الملفات/الملاحظات الصوتية. - تستخدم إعداد
messages.ttsالأساسي واختيار المزوّد. - تعيد مخزنًا مؤقتًا لصوت PCM مع معدل العينة. يجب على Plugins إعادة أخذ العينات/الترميز للمزوّدين.
- تكون
listVoicesاختيارية لكل مزوّد. استخدمها في أدوات اختيار الأصوات أو تدفقات الإعداد المملوكة للمورّد. - يمرّر الجزء الأساسي مهلة طلب محلولة إلى خطافات
listVoicesالخاصة بالمزوّد؛ ويمكن لإعدادات المهلة الخاصة بالمزوّد تجاوزها. - يمكن أن تتضمن قوائم الأصوات بيانات وصفية أغنى، مثل اللغة والمنطقة والجنس ووسوم الشخصية، لاستخدامها في أدوات الاختيار المدركة للمزوّد.
- يدعم OpenAI وElevenLabs الاتصالات الهاتفية حاليًا. أما Microsoft فلا يدعمها.
يمكن لـ Plugins أيضًا تسجيل مزوّدي الكلام عبر api.registerSpeechProvider(...).
api.registerSpeechProvider({ id: "acme-speech", label: "Acme Speech", isConfigured: ({ config }) => Boolean(config.messages?.tts), synthesize: async (req) => { return { audioBuffer: Buffer.from([]), outputFormat: "mp3", fileExtension: ".mp3", voiceCompatible: false, }; },});ملاحظات:
- احتفظ بسياسة تحويل النص إلى كلام والرجوع وتسليم الردود في الجزء الأساسي.
- استخدم مزوّدي الكلام لسلوك التوليف المملوك للمورّد.
- يُطبَّع إدخال Microsoft القديم
edgeإلى معرّف المزوّدmicrosoft. - نموذج الملكية المفضّل موجّه نحو الشركة: يمكن لـ Plugin مورّد واحد امتلاك مزوّدي النص والكلام والصور والوسائط المستقبلية مع إضافة OpenClaw لعقود القدرات تلك.
لفهم الصور/الصوت/الفيديو، تسجّل Plugins مزوّدًا واحدًا ذا نوع محدد لفهم الوسائط بدلًا من حزمة مفاتيح/قيم عامة:
api.registerMediaUnderstandingProvider({ id: "google", capabilities: ["image", "audio", "video"], describeImage: async (req) => ({ text: "..." }), transcribeAudio: async (req) => ({ text: "..." }), describeVideo: async (req) => ({ text: "..." }),});ملاحظات:
- احتفظ بالتنسيق والرجوع والإعداد وتوصيل القنوات في الجزء الأساسي.
- احتفظ بسلوك المورّد في Plugin المزوّد.
- يجب أن يظل التوسّع الإضافي محدد الأنواع: طرائق اختيارية جديدة، وحقول نتائج اختيارية جديدة، وقدرات اختيارية جديدة.
- يتبع توليد الفيديو النمط نفسه بالفعل:
- يمتلك الجزء الأساسي عقد القدرة ومساعد وقت التشغيل
- تسجّل Plugins المورّدين
api.registerVideoGenerationProvider(...) - تستهلك Plugins الميزات/القنوات
api.runtime.videoGeneration.*
بالنسبة إلى مساعدات وقت التشغيل لفهم الوسائط، يمكن لـ Plugins استدعاء:
const image = await api.runtime.mediaUnderstanding.describeImageFile({ filePath: "/tmp/inbound-photo.jpg", cfg: api.config, agentDir: "/tmp/agent",}); const video = await api.runtime.mediaUnderstanding.describeVideoFile({ filePath: "/tmp/inbound-video.mp4", cfg: api.config,}); const extraction = await api.runtime.mediaUnderstanding.extractStructuredWithModel({ provider: "codex", model: "gpt-5.6-sol", input: [ { type: "image", buffer: receiptImageBuffer, fileName: "receipt.png", mime: "image/png", }, { type: "text", text: "Use the printed fields as the source of truth." }, ], instructions: "Return entities and searchable tags.", schemaName: "example.evidence", jsonSchema: { type: "object", properties: { entities: { type: "array", items: { type: "string" } }, tags: { type: "array", items: { type: "string" } }, }, }, cfg: api.config,});لنسخ الصوت نصيًا، يمكن لـ Plugins استخدام وقت تشغيل فهم الوسائط أو الاسم البديل الأقدم لـ STT:
const { text } = await api.runtime.mediaUnderstanding.transcribeAudioFile({ filePath: "/tmp/inbound-audio.ogg", cfg: api.config, // Optional when MIME cannot be inferred reliably: mime: "audio/ogg",});ملاحظات:
-
api.runtime.mediaUnderstanding.*هي الواجهة المشتركة المفضّلة لفهم الصور/الصوت/الفيديو. -
extractStructuredWithModel(...)هي الواجهة الموجّهة إلى Plugins للاستخراج المحدود المملوك للمزوّد الذي يبدأ بالصور. ضمّن إدخال صورة واحدًا على الأقل؛ وتكون إدخالات النص سياقًا تكميليًا. تمتلك Plugins المنتج مساراتها ومخططاتها، بينما يمتلك OpenClaw الحد الفاصل بين المزوّد ووقت التشغيل. - تستخدم إعداد الصوت الأساسي لفهم الوسائط (
tools.media.audio) وترتيب الرجوع بين المزوّدين. - تعيد
{ text: undefined }عندما لا يُنتج أي إخراج للنسخ النصي (مثلًا عند تخطي الإدخال أو عدم دعمه). - تظل
api.runtime.stt.transcribeAudioFile(...)اسمًا بديلًا للتوافق.
يمكن لـ Plugins أيضًا تشغيل عمليات الوكلاء الفرعيين في الخلفية عبر
api.runtime.subagent:
const result = await api.runtime.subagent.run({ sessionKey: "agent:main:subagent:search-helper", message: "Expand this query into focused follow-up searches.", provider: "openai", model: "gpt-4.1-mini", deliver: false,});ملاحظات:
-
providerوmodelتجاوزان اختياريان لكل عملية تشغيل، وليسا تغييرات دائمة للجلسة. - لا يحترم OpenClaw حقول التجاوز هذه إلا للمستدعين الموثوقين.
- بالنسبة إلى عمليات الرجوع المملوكة لـ Plugin، يجب على المشغّلين الاشتراك صراحةً باستخدام
plugins.entries.<id>.subagent.allowModelOverride: true. - استخدم
plugins.entries.<id>.subagent.allowedModelsلتقييد Plugins الموثوقة بأهدافprovider/modelمعيارية محددة، أو"*"للسماح صراحةً بأي هدف. - تظل عمليات الوكيل الفرعي من Plugins غير الموثوقة تعمل، لكن طلبات التجاوز تُرفض بدلًا من الرجوع بصمت.
- تُوسَم جلسات الوكيل الفرعي التي تنشئها Plugins بمعرّف Plugin المنشئ. يمكن لعملية الرجوع
api.runtime.subagent.deleteSession(...)حذف تلك الجلسات المملوكة فقط؛ ولا يزال حذف جلسة عشوائية يتطلب طلب Gateway بنطاق إداري.
للبحث على الويب، يمكن لـ Plugins استهلاك مساعد وقت التشغيل المشترك بدلًا من الوصول إلى توصيل أداة الوكيل:
const providers = api.runtime.webSearch.listProviders({ config: api.config,}); const result = await api.runtime.webSearch.search({ config: api.config, args: { query: "OpenClaw plugin runtime helpers", count: 5, },});يمكن لـ Plugins أيضًا تسجيل مزوّدي البحث على الويب عبر
api.registerWebSearchProvider(...).
ملاحظات:
- احتفظ باختيار المزوّد وحل بيانات الاعتماد ودلالات الطلب المشتركة في الجزء الأساسي.
- استخدم مزوّدي البحث على الويب لعمليات نقل البحث الخاصة بالمورّد.
-
api.runtime.webSearch.*هي الواجهة المشتركة المفضّلة لـ Plugins الميزات/القنوات التي تحتاج إلى سلوك البحث دون الاعتماد على غلاف أداة الوكيل.
api.runtime.imageGeneration
const result = await api.runtime.imageGeneration.generate({ config: api.config, args: { prompt: "A friendly lobster mascot", size: "1024x1024" },}); const providers = api.runtime.imageGeneration.listProviders({ config: api.config,});-
generate(...): توليد صورة باستخدام سلسلة مزوّدي توليد الصور المضبوطة. -
listProviders(...): سرد مزوّدي توليد الصور المتاحين وقدراتهم.
مسارات HTTP في Gateway
يمكن لـ Plugins كشف نقاط نهاية HTTP باستخدام api.registerHttpRoute(...).
api.registerHttpRoute({ path: "/acme/webhook", auth: "plugin", match: "exact", handler: async (_req, res) => { res.statusCode = 200; res.end("ok"); return true; },});حقول المسار:
path: مسار التوجيه ضمن خادم HTTP الخاص بـ Gateway.auth: مطلوب، ويكون"gateway"أو"plugin". استخدم"gateway"لفرض مصادقة Gateway المعتادة، أو"plugin"للمصادقة التي يديرها Plugin أو للتحقق من Webhook.match: اختياري."exact"(الافتراضي) أو"prefix".handleUpgrade: معالج اختياري لطلبات ترقية WebSocket على المسار نفسه.replaceExisting: اختياري. يسمح للـ Plugin نفسه باستبدال تسجيل مساره الحالي.handler: أرجِعtrueعندما يكون المسار قد عالج الطلب.
ملاحظات:
- أُزيل
api.registerHttpHandler(...)، وسيؤدي استخدامه إلى خطأ عند تحميل Plugin. استخدمapi.registerHttpRoute(...)بدلًا منه. - يجب أن تعلن مسارات Plugin عن
authصراحةً. - تُرفض تعارضات
path + matchالمتطابقة ما لم تكنreplaceExisting: true، ولا يمكن لـ Plugin استبدال مسار تابع لـ Plugin آخر. - تُرفض المسارات المتداخلة ذات مستويات
authالمختلفة. اجعل سلاسل الانتقال الاحتياطيexact/prefixعلى مستوى المصادقة نفسه فقط. - لا تتلقى المسارات ذات
auth: "plugin"نطاقات وقت تشغيل المشغّل تلقائيًا. فهي مخصصة لعمليات Webhook والتحقق من التوقيعات التي يديرها Plugin، وليست لاستدعاءات أدوات Gateway المساعدة ذات الامتيازات. - تعمل المسارات ذات
auth: "gateway"داخل نطاق وقت تشغيل طلب Gateway. والسطح الافتراضي (gatewayRuntimeScopeSurface: "write-default") متحفظ عمدًا:- تحصل مصادقة حامل السر المشترك (
gateway.auth.mode = "token"/"password") وأي طريقة مصادقة لا تستخدم الوكيل الموثوق على نطاقoperator.writeواحد، حتى إذا أرسل المستدعيx-openclaw-scopes - يحتفظ مستدعو
trusted-proxyالذين لا يرسلون ترويسةx-openclaw-scopesصريحة أيضًا بالسطح القديم المقتصر علىoperator.write - يحصل مستدعو
trusted-proxyالذين يرسلونx-openclaw-scopesعلى النطاقات المعلنة بدلًا من ذلك - يمكن للمسار الاشتراك في
gatewayRuntimeScopeSurface: "trusted-operator"لاحترامx-openclaw-scopesدائمًا في أوضاع المصادقة التي تحمل هوية (مع الرجوع إلى مجموعة نطاقات CLI الافتراضية الكاملة عند غياب الترويسة)
- تحصل مصادقة حامل السر المشترك (
- قاعدة عملية: لا تفترض أن مسار Plugin الموثق عبر Gateway يشكل ضمنيًا سطح إدارة. إذا كان مسارك يحتاج إلى سلوك مخصص للمسؤول فقط، فاشترك في سطح النطاق
trusted-operator، واشترط وضع مصادقة يحمل هوية، ووثّق عقد ترويسةx-openclaw-scopesالصريح. - بعد مطابقة المسار والمصادقة، تشارك المعالجات العادية في قبول العمل الجذري لـ Gateway. يعيد Gateway في حالة الاستعداد أو إعادة التشغيل الرمز
503قبل استدعاء المعالج. والاستثناء المحدود هو مسار ذوauth: "gateway"تمنحه التظاهرة صلاحية، ويشترك أيضًا في سطحtrusted-operatorالخاص بالمسار؛ إذ يظل قابلًا للوصول حتى لا يتعطل إرسال التحكم في التعليق، بينما تظل المسارات الشقيقة العادية التابعة للـ Plugin نفسه خلف حد القبول. تستخدم ملكية WebSocket فيhandleUpgradeحد القبول الذري نفسه؛ وما إن يقبل المعالج مقبسًا، تصبح دورة حياة المقبس اللاحقة مملوكة للـ Plugin ولا يتتبعها هذا الحد.
مسارات استيراد SDK الخاصة بالـ Plugin
استخدم المسارات الفرعية المحددة لـ SDK بدلًا من مجمّع الجذر الأحادي openclaw/plugin-sdk
عند إنشاء Plugins جديدة. المسارات الفرعية الأساسية:
| المسار الفرعي | الغرض |
|---|---|
openclaw/plugin-sdk/plugin-entry |
بدائيات تسجيل Plugin |
openclaw/plugin-sdk/channel-core |
أدوات مساعدة لإدخال القناة وبنائها |
openclaw/plugin-sdk/core |
أدوات مساعدة عامة مشتركة وعقد شامل |
openclaw/plugin-sdk/config-schema |
مخطط Zod الجذري لـ openclaw.json (OpenClawSchema) |
تختار Plugins القنوات من عائلة من الوصلات المحددة — channel-setup،
وsetup-runtime، وsetup-tools، وchannel-pairing،
وchannel-contract، وchannel-feedback، وchannel-inbound، وchannel-outbound،
وcommand-auth، وsecret-input، وwebhook-ingress،
وchannel-targets، وchannel-actions. ينبغي توحيد سلوك الموافقة
ضمن عقد approvalCapability واحد بدلًا من توزيعه على حقول
Plugin غير المرتبطة. راجع Plugins القنوات.
توجد أدوات وقت التشغيل والإعدادات المساعدة ضمن مسارات فرعية مركزة مطابقة من نمط *-runtime
(approval-runtime، وagent-runtime، وlazy-runtime، وdirectory-runtime،
وtext-runtime، وruntime-store، وsystem-event-runtime، وheartbeat-runtime،
وchannel-activity-runtime، وغيرها). فضّل config-contracts،
وplugin-config-runtime، وruntime-config-snapshot، وconfig-mutation
بدلًا من مجمّع التوافق الواسع config-runtime.
نقاط الدخول الداخلية للمستودع (لكل جذر حزمة Plugin مضمّنة):
index.js— نقطة دخول Plugin المضمّنةapi.js— مجمّع الأدوات المساعدة والأنواعruntime-api.js— مجمّع مخصص لوقت التشغيلsetup-entry.js— نقطة دخول Plugin الإعداد
يجب ألا تستورد Plugins الخارجية إلا المسارات الفرعية openclaw/plugin-sdk/*. لا
تستورد مطلقًا src/* من حزمة Plugin أخرى، سواء من النواة أو من Plugin آخر.
تفضّل نقاط الدخول المحمّلة عبر الواجهة لقطة إعدادات وقت التشغيل النشطة عند
وجودها، ثم ترجع إلى ملف الإعدادات المحلول على القرص.
توجد مسارات فرعية خاصة بالقدرات، مثل image-generation، وmedia-understanding،
وspeech، لأن Plugins المضمّنة تستخدمها حاليًا. لكنها ليست
عقودًا خارجية ثابتة تلقائيًا على المدى الطويل — تحقّق من صفحة مرجع SDK
ذات الصلة عند الاعتماد عليها.
مخططات أداة الرسائل
ينبغي أن تمتلك Plugins مساهمات مخطط describeMessageTool(...) الخاصة بالقنوات
للعمليات غير المتعلقة بالرسائل، مثل التفاعلات، وإشعارات القراءة، والاستطلاعات.
ينبغي أن يستخدم العرض المشترك للإرسال عقد MessagePresentation العام
بدلًا من حقول الأزرار أو المكوّنات أو الكتل أو البطاقات الأصلية الخاصة بمزوّد الخدمة.
راجع عرض الرسائل للاطلاع على العقد،
وقواعد الرجوع، وتعيين مزوّدي الخدمة، وقائمة التحقق الخاصة بمؤلف Plugin.
تعلن Plugins القادرة على الإرسال عما يمكنها عرضه عبر قدرات الرسائل:
presentationلكتل العرض الدلالية (text، وcontext، وdivider، وchart، وtable، وbuttons، وselect)delivery-pinلطلبات تثبيت التسليم
تقرر النواة ما إذا كانت ستعرض المحتوى تقديميًا بصورة أصلية أو ستخفضه إلى نص. لا تكشف منافذ التفاف لواجهة المستخدم الأصلية الخاصة بمزوّد الخدمة من أداة الرسائل العامة. تظل أدوات SDK المساعدة المهملة للمخططات الأصلية القديمة مُصدّرة للـ Plugins الخارجية الحالية، لكن ينبغي ألا تستخدمها Plugins الجديدة.
تحليل أهداف القنوات
ينبغي أن تمتلك Plugins القنوات دلالات الأهداف الخاصة بالقنوات. أبقِ مضيف الصادر المشترك عامًا، واستخدم سطح محوّل المراسلة لقواعد مزوّد الخدمة:
- يقرر
messaging.inferTargetChatType({ to })ما إذا كان ينبغي التعامل مع هدف مطبّع باعتبارهdirectأوgroupأوchannelقبل البحث في الدليل. - يُعلِم
messaging.targetResolver.looksLikeId(raw, normalized)النواة بما إذا كان الإدخال ينبغي أن ينتقل مباشرة إلى تحليل شبيه بالمعرّف بدلًا من البحث في الدليل. - تسرد
messaging.targetResolver.reservedLiteralsالكلمات المجرّدة التي تمثل مراجع قناة أو جلسة لذلك المزوّد. يحافظ التحليل على إدخالات الدليل المضبوطة قبل رفض القيم الحرفية المحجوزة، ثم يفشل بصورة مغلقة عند عدم العثور عليها في الدليل. - يُعد
messaging.targetResolver.resolveTarget(...)آلية الرجوع الخاصة بالـ Plugin عندما تحتاج النواة إلى تحليل نهائي يملكه مزوّد الخدمة بعد التطبيع أو بعد عدم العثور على نتيجة في الدليل. - يمتلك
messaging.resolveOutboundSessionRoute(...)إنشاء مسار الجلسة الخاص بمزوّد الخدمة بعد تحليل الهدف.
التقسيم الموصى به:
- استخدم
inferTargetChatTypeلقرارات الفئة التي ينبغي اتخاذها قبل البحث في الأقران أو المجموعات. - استخدم
looksLikeIdللتحقق مما إذا كان ينبغي «التعامل مع هذا باعتباره معرّف هدف صريحًا/أصليًا». - استخدم
resolveTargetكآلية رجوع للتطبيع الخاص بمزوّد الخدمة، وليس للبحث الواسع في الدليل. - احتفظ بالمعرّفات الأصلية الخاصة بمزوّد الخدمة، مثل معرّفات المحادثات، ومعرّفات الخيوط، وJIDs، والمقابض، ومعرّفات الغرف،
داخل قيم
targetأو المعاملات الخاصة بمزوّد الخدمة، وليس في حقول SDK العامة.
الأدلة المدعومة بالإعدادات
ينبغي أن تُبقي Plugins التي تشتق إدخالات الدليل من الإعدادات ذلك المنطق داخل
Plugin، وأن تعيد استخدام الأدوات المساعدة المشتركة من
openclaw/plugin-sdk/directory-runtime.
استخدم هذا عندما تحتاج القناة إلى أقران أو مجموعات مدعومة بالإعدادات، مثل:
- أقران الرسائل المباشرة المستندين إلى قائمة السماح
- خرائط القنوات أو المجموعات المضبوطة
- آليات رجوع ثابتة للدليل مقيّدة بنطاق الحساب
لا تتعامل الأدوات المساعدة المشتركة في directory-runtime إلا مع العمليات العامة:
- ترشيح الاستعلامات
- تطبيق الحدود
- أدوات إزالة التكرار والتطبيع المساعدة
- إنشاء
ChannelDirectoryEntry[]
ينبغي أن يظل فحص الحساب الخاص بالقناة وتطبيع المعرّفات ضمن تنفيذ Plugin.
كتالوجات مزوّدي الخدمة
يمكن لـ Plugins مزوّدي الخدمة تعريف كتالوجات النماذج للاستدلال باستخدام
registerProvider({ catalog: { run(...) { ... } } }).
تعيد catalog.run(...) البنية نفسها التي يكتبها OpenClaw في
models.providers:
{ provider }لإدخال مزوّد خدمة واحد{ providers }لعدة إدخالات لمزوّدي الخدمة
استخدم catalog عندما يمتلك Plugin معرّفات النماذج الخاصة بمزوّد الخدمة، أو قيم
عناوين URL الأساسية الافتراضية، أو بيانات النماذج الوصفية المشروطة بالمصادقة.
يتحكم catalog.order في توقيت دمج كتالوج Plugin نسبةً إلى مزوّدي OpenClaw
الضمنيين المضمّنين:
simple: مزوّدو خدمة يعتمدون على مفتاح API عادي أو متغيرات البيئةprofile: مزوّدو خدمة يظهرون عند وجود ملفات تعريف مصادقةpaired: مزوّدو خدمة ينشئون عدة إدخالات مترابطة لمزوّدي الخدمةlate: المرور الأخير، بعد مزوّدي الخدمة الضمنيين الآخرين
تفوز إدخالات مزوّدي الخدمة اللاحقة عند تعارض المفاتيح، لذا يمكن للـ Plugins تجاوز إدخال مزوّد خدمة مضمّن يحمل معرّف مزوّد الخدمة نفسه عن قصد.
يمكن للـ Plugins أيضًا نشر صفوف نماذج للقراءة فقط عبر
api.registerModelCatalogProvider({ provider, kinds, staticCatalog, liveCatalog }). وهذا هو المسار المستقبلي لأسطح القوائم والمساعدة والاختيار، ويدعم صفوف
text، وvoice، وimage_generation، وvideo_generation، وmusic_generation.
تظل Plugins مزوّدي الخدمة مالكة لاستدعاءات نقاط النهاية الحية، وتبادل الرموز، وتعيين
استجابات المورّد؛ بينما تمتلك النواة بنية الصف المشتركة، وتسميات المصدر، وتنسيق
مساعدة أدوات الوسائط. تنشئ تسجيلات مزوّدي إنشاء الوسائط صفوف الكتالوج الثابتة
تلقائيًا من defaultModel، وmodels، وcapabilities.
التوافق:
- لا يزال
discoveryيعمل كاسم مستعار قديم، لكنه يصدر تحذير إهمال - إذا سُجّل كل من
catalogوdiscovery، يستخدم OpenClawcatalogويصدر تحذيرًا - أُهمل
augmentModelCatalog؛ وينبغي أن تنشر مزوّدات الخدمة المضمّنة الصفوف التكميلية عبرregisterModelCatalogProvider
فحص القنوات للقراءة فقط
إذا كان Plugin الخاص بك يسجل قناة، ففضّل تنفيذ
plugin.config.inspectAccount(cfg, accountId) إلى جانب resolveAccount(...).
السبب:
resolveAccount(...)هو مسار وقت التشغيل. ويُسمح له بافتراض أن بيانات الاعتماد متحققة بالكامل، وأن يفشل سريعًا عند غياب الأسرار المطلوبة.- ينبغي ألا تحتاج مسارات أوامر القراءة فقط، مثل
openclaw status، وopenclaw status --all، وopenclaw channels status، وopenclaw channels resolve، ومسارات إصلاح doctor/الإعدادات، إلى إنشاء بيانات اعتماد وقت التشغيل لمجرد وصف الإعدادات.
السلوك الموصى به لـ inspectAccount(...):
- أرجِع حالة وصفية للحساب فقط.
- حافظ على
enabledوconfigured. - ضمّن حقول مصدر بيانات الاعتماد/حالتها عند الاقتضاء، مثل:
tokenSource،tokenStatusbotTokenSource،botTokenStatusappTokenSource،appTokenStatussigningSecretSource،signingSecretStatus
- لا تحتاج إلى إرجاع قيم الرموز المميزة الأولية لمجرد الإبلاغ عن
التوفّر للقراءة فقط. يكفي إرجاع
tokenStatus: "available"(وحقل المصدر المطابق) لأوامر عرض الحالة. - استخدم
configured_unavailableعندما تكون بيانات الاعتماد مهيأة عبر SecretRef لكنها غير متاحة في مسار الأمر الحالي.
يتيح ذلك لأوامر القراءة فقط الإبلاغ بأن الحساب «مهيأ لكنه غير متاح في مسار الأمر هذا» بدلًا من التعطل أو الإبلاغ خطأً بأن الحساب غير مهيأ.
حزم الحزم
قد يتضمن دليل Plugin ملف package.json يحتوي على openclaw.extensions:
{ "name": "my-pack", "openclaw": { "extensions": ["./src/safety.ts", "./src/tools.ts"], "setupEntry": "./src/setup-entry.ts" }}يصبح كل إدخال Plugin. إذا أدرجت الحزمة امتدادات متعددة، يصبح معرّف Plugin
هو <manifestOrPackageName>/<fileBase> (تكون الأولوية لمعرّف البيان عند
وجوده؛ وإلا فيُستخدم اسم package.json غير ذي النطاق).
إذا كان Plugin الخاص بك يستورد تبعيات npm، فثبّتها في ذلك الدليل حتى يكون
node_modules متاحًا (npm install / pnpm install).
حاجز أمني: يجب أن يبقى كل إدخال في openclaw.extensions داخل دليل Plugin
بعد حل الروابط الرمزية. تُرفض الإدخالات التي تخرج من دليل الحزمة.
ملاحظة أمنية: يثبّت openclaw plugins install تبعيات Plugin باستخدام
npm install --omit=dev --ignore-scripts محلي للمشروع (من دون نصوص دورة الحياة،
ومن دون تبعيات تطوير في وقت التشغيل)، مع تجاهل إعدادات تثبيت npm العامة الموروثة.
حافظ على أشجار تبعيات Plugin «JS/TS خالصة» وتجنب الحزم التي تتطلب
عمليات بناء postinstall.
اختياري: يمكن أن يشير openclaw.setupEntry إلى وحدة خفيفة مخصصة للإعداد فقط.
عندما يحتاج OpenClaw إلى أسطح الإعداد لـ Plugin قناة معطّل، أو
عندما يكون Plugin قناة مفعّلًا لكنه لا يزال غير مهيأ، فإنه يحمّل setupEntry
بدلًا من إدخال Plugin الكامل. يحافظ ذلك على خفة بدء التشغيل والإعداد
عندما يربط إدخال Plugin الرئيسي أيضًا الأدوات أو الخطافات أو شيفرات أخرى
مخصصة لوقت التشغيل فقط.
اختياري: يمكن لـ openclaw.startup.deferConfiguredChannelFullLoadUntilAfterListen
إشراك Plugin قناة في مسار setupEntry نفسه أثناء مرحلة بدء تشغيل Gateway
السابقة للاستماع، حتى عندما تكون القناة مهيأة بالفعل.
استخدم هذا فقط عندما يغطي setupEntry بالكامل سطح بدء التشغيل الذي يجب أن يكون
موجودًا قبل أن يبدأ Gateway الاستماع. عمليًا، يعني ذلك أن إدخال الإعداد
يجب أن يسجّل كل قدرة مملوكة للقناة يعتمد عليها بدء التشغيل، مثل:
- تسجيل القناة نفسها
- أي مسارات HTTP يجب أن تكون متاحة قبل أن يبدأ Gateway الاستماع
- أي طرائق أو أدوات أو خدمات لـ Gateway يجب أن تكون موجودة خلال النافذة نفسها
إذا ظل إدخالك الكامل مالكًا لأي قدرة مطلوبة لبدء التشغيل، فلا تفعّل هذه العلامة. أبقِ Plugin على السلوك الافتراضي ودع OpenClaw يحمّل الإدخال الكامل أثناء بدء التشغيل.
يمكن للقنوات المضمّنة أيضًا نشر مساعدات سطح عقد مخصصة للإعداد فقط، يستطيع النواة الرجوع إليها قبل تحميل وقت تشغيل القناة الكامل. سطح الترقية الخاص بالإعداد حاليًا هو:
singleAccountKeysToMovenamedAccountPromotionKeysresolveSingleAccountPromotionTarget(...)
تستخدم النواة هذا السطح عندما تحتاج إلى ترقية تهيئة قديمة لقناة ذات حساب واحد
إلى channels.<id>.accounts.* من دون تحميل إدخال Plugin الكامل.
Matrix هو المثال المضمّن الحالي: فهو ينقل مفاتيح المصادقة/التمهيد فقط إلى
حساب مُرقّى مسمّى عندما تكون الحسابات المسمّاة موجودة بالفعل، ويمكنه الاحتفاظ
بمفتاح حساب افتراضي مهيأ وغير قياسي بدلًا من إنشاء accounts.default
دائمًا.
تحافظ مهايئات تصحيح الإعداد هذه على كسل اكتشاف سطح العقد المضمّن. يظل وقت الاستيراد خفيفًا؛ ولا يُحمّل سطح الترقية إلا عند أول استخدام بدلًا من إعادة الدخول في بدء تشغيل القناة المضمّنة عند استيراد الوحدة.
عندما تتضمن أسطح بدء التشغيل هذه طرائق RPC لـ Gateway، فأبقها ضمن
بادئة خاصة بـ Plugin. تظل نطاقات إدارة النواة (config.*،
exec.approvals.*، wizard.*، update.*) محجوزة وتُحل دائمًا
إلى operator.admin، حتى إذا طلب Plugin نطاقًا أضيق.
مثال:
{ "name": "@scope/my-channel", "openclaw": { "extensions": ["./index.ts"], "setupEntry": "./setup-entry.ts", "startup": { "deferConfiguredChannelFullLoadUntilAfterListen": true } }}بيانات تعريف دليل القنوات
يمكن لإضافات القنوات الإعلان عن بيانات تعريف الإعداد/الاكتشاف عبر openclaw.channel
وعن تلميحات التثبيت عبر openclaw.install. يحافظ ذلك على خلو دليل النواة من البيانات.
مثال:
{ "name": "@openclaw/nextcloud-talk", "openclaw": { "extensions": ["./index.ts"], "channel": { "id": "nextcloud-talk", "label": "Nextcloud Talk", "selectionLabel": "Nextcloud Talk (self-hosted)", "docsPath": "/channels/nextcloud-talk", "docsLabel": "nextcloud-talk", "blurb": "Self-hosted chat via Nextcloud Talk webhook bots.", "order": 65, "aliases": ["nc-talk", "nc"] }, "install": { "npmSpec": "@openclaw/nextcloud-talk", "localPath": "<bundled-plugin-local-path>", "defaultChoice": "npm" } }}حقول openclaw.channel المفيدة إلى جانب المثال الأدنى:
detailLabel: تسمية ثانوية لأسطح الدليل/الحالة الأكثر تفصيلًاdocsLabel: تجاوز نص رابط التوثيقpreferOver: معرّفات Plugin/القنوات ذات الأولوية الأدنى التي ينبغي أن يتفوق عليها إدخال الدليل هذاselectionDocsPrefix،selectionDocsOmitLabel،selectionExtras: عناصر تحكم في نص سطح الاختيارmarkdownCapable: يحدد القناة على أنها تدعم Markdown لقرارات تنسيق الرسائل الصادرةexposure.configured: يخفي القناة من أسطح قوائم القنوات المهيأة عند ضبطه علىfalseexposure.setup: يخفي القناة من منتقيات الإعداد/التهيئة التفاعلية عند ضبطه علىfalseexposure.docs: يحدد القناة على أنها داخلية/خاصة لأسطح تنقل التوثيقshowConfigured/showInSetup: أسماء بديلة قديمة ما زالت مقبولة للتوافق؛ يُفضّلexposurequickstartAllowFrom: يشرك القناة في تدفق البدء السريع القياسيallowFromforceAccountBinding: يتطلب ربطًا صريحًا بالحساب حتى عند وجود حساب واحد فقطpreferSessionLookupForAnnounceTarget: يفضّل البحث في الجلسة عند حل أهداف الإعلان
يمكن لـ OpenClaw أيضًا دمج أدلة قنوات خارجية (على سبيل المثال، تصدير سجل MPM). ضع ملف JSON في أحد المواقع التالية:
~/.openclaw/mpm/plugins.json~/.openclaw/mpm/catalog.json~/.openclaw/plugins/catalog.json
أو وجّه OPENCLAW_PLUGIN_CATALOG_PATHS (أو OPENCLAW_MPM_CATALOG_PATHS) إلى
ملف JSON واحد أو أكثر (مفصولة بفاصلة/فاصلة منقوطة/PATH). يجب أن
يحتوي كل ملف على { "entries": [ { "name": "@scope/pkg", "openclaw": { "channel": {...}, "install": {...} } } ] }. يقبل المحلل أيضًا "packages" أو "plugins" كأسماء بديلة قديمة لمفتاح "entries".
تعرض إدخالات دليل القنوات المُنشأة وإدخالات دليل تثبيت المزوّد
حقائق موحّدة عن مصدر التثبيت بجانب كتلة openclaw.install الأولية. تحدد
الحقائق الموحّدة ما إذا كانت مواصفة npm إصدارًا دقيقًا أم محددًا متغيرًا،
وما إذا كانت بيانات التكامل المتوقعة موجودة، وما إذا كان مسار مصدر محلي
متاحًا أيضًا. عندما تكون هوية الدليل/الحزمة معروفة، تحذّر الحقائق
الموحّدة إذا انحرف اسم حزمة npm المحلّل عن تلك الهوية.
كما تحذّر عندما تكون defaultChoice غير صالحة أو تشير إلى مصدر
غير متاح، وعندما تكون بيانات تكامل npm موجودة من دون مصدر npm صالح.
ينبغي للمستهلكين التعامل مع installSource بوصفه حقلًا اختياريًا إضافيًا حتى
لا تضطر الإدخالات المُنشأة يدويًا ورقع توافق الدليل إلى توليده.
يتيح ذلك للإعداد الأولي والتشخيص شرح حالة مستوى المصدر من دون
استيراد وقت تشغيل Plugin.
ينبغي لإدخالات npm الخارجية الرسمية تفضيل npmSpec دقيق مع
expectedIntegrity. تظل أسماء الحزم المجردة ووسوم التوزيع تعمل
للتوافق، لكنها تعرض تحذيرات على مستوى المصدر حتى يتمكن الدليل من التوجه
نحو عمليات تثبيت مثبتة الإصدارات ومتحقق من تكاملها من دون تعطيل إضافات Plugin الحالية.
عندما يثبّت الإعداد الأولي من مسار دليل محلي، فإنه يسجّل إدخالًا مُدارًا في
فهرس إضافات Plugin مع source: "path" وsourcePath نسبيًا إلى مساحة العمل
عند الإمكان. يبقى مسار التحميل التشغيلي المطلق في
plugins.load.paths؛ ويتجنب سجل التثبيت تكرار مسارات محطة العمل المحلية
في التهيئة طويلة الأجل. يحافظ ذلك على ظهور عمليات تثبيت التطوير المحلية
لتشخيصات مستوى المصدر من دون إضافة سطح ثانٍ يكشف مسار نظام ملفات أوليًا.
يمثل جدول SQLite الدائم installed_plugin_index مصدر الحقيقة للتثبيت
ويمكن تحديثه من دون تحميل وحدات وقت تشغيل Plugin.
تكون خريطة installRecords فيه دائمة حتى عند فقدان بيان Plugin أو
عدم صلاحيته؛ بينما تكون حمولة plugins عرضًا للبيان قابلًا لإعادة البناء.
إضافات محرك السياق
تمتلك إضافات محرك السياق تنسيق سياق الجلسة للإدخال والتجميع
وCompaction. سجّلها من Plugin الخاص بك باستخدام
api.registerContextEngine(id, factory)، ثم اختر المحرك النشط باستخدام
plugins.slots.contextEngine.
استخدم ذلك عندما يحتاج Plugin الخاص بك إلى استبدال مسار السياق الافتراضي أو توسيعه بدلًا من مجرد إضافة البحث في الذاكرة أو الخطافات.
export default function (api) { api.registerContextEngine("lossless-claw", (ctx) => ({ info: { id: "lossless-claw", name: "Lossless Claw", ownsCompaction: true }, async ingest() { return { ingested: true }; }, async assemble({ messages, sessionKey, availableTools, citationsMode }) { return { messages, estimatedTokens: 0, systemPromptAddition: buildMemorySystemPromptAddition({ availableTools: availableTools ?? new Set(), citationsMode, agentId: resolveSessionAgentId({ config: ctx.config, sessionKey }), agentSessionKey: sessionKey, }), }; }, async compact() { return { ok: true, compacted: false }; }, }));}يعرض ctx الخاص بالمصنع القيم الاختيارية config وagentDir وworkspaceDir
للتهيئة في وقت الإنشاء.
قد تعيد assemble() قيمة contextProjection عندما تكون للبيئة النشطة
سلسلة خلفية دائمة. احذفها للإسقاط القديم لكل دورة. أعد
{ mode: "thread_bootstrap", epoch } عندما ينبغي حقن السياق المجمّع
مرة واحدة في سلسلة خلفية وإعادة استخدامه حتى تتغير الحقبة. غيّر
الحقبة بعد تغير السياق الدلالي للمحرك، مثلًا بعد مرور Compaction
يملكه المحرك. قد تحافظ المضيفات على بيانات تعريف استدعاء الأدوات وشكل
الإدخال ونتائج الأدوات المنقّحة في إسقاط تمهيد السلسلة، حتى تحتفظ
السلاسل الخلفية الجديدة باستمرارية الأدوات من دون نسخ الحمولات الأولية
الحاملة للأسرار.
إذا كان محركك لا يملك خوارزمية Compaction، فأبقِ compact()
منفّذة وفوّضها صراحةً:
buildMemorySystemPromptAddition, delegateCompactionToRuntime,} from "openclaw/plugin-sdk/core"; export default function (api) { api.registerContextEngine("my-memory-engine", (ctx) => ({ info: { id: "my-memory-engine", name: "My Memory Engine", ownsCompaction: false, }, async ingest() { return { ingested: true }; }, async assemble({ messages, sessionKey, availableTools, citationsMode }) { return { messages, estimatedTokens: 0, systemPromptAddition: buildMemorySystemPromptAddition({ availableTools: availableTools ?? new Set(), citationsMode, agentId: resolveSessionAgentId({ config: ctx.config, sessionKey }), agentSessionKey: sessionKey, }), }; }, async compact(params) { return await delegateCompactionToRuntime(params); }, }));}إضافة قدرة جديدة
عندما يحتاج Plugin إلى سلوك لا تلائمه واجهة API الحالية، فلا تتجاوز نظام Plugin عبر وصول داخلي خاص. أضف القدرة المفقودة.
التسلسل الموصى به:
- عرّف عقد النواة. حدّد السلوك المشترك الذي ينبغي أن تمتلكه النواة: السياسة، والبديل الاحتياطي، ودمج الإعدادات، ودورة الحياة، والدلالات الموجّهة للقنوات، وشكل مساعد وقت التشغيل.
- أضف أسطح تسجيل/وقت تشغيل مكتوبة الأنواع للـ Plugin. وسّع
OpenClawPluginApiو/أوapi.runtimeبأصغر سطح قدرة مكتوب الأنواع ومفيد. - اربط مستهلكي النواة + القناة/الميزة. ينبغي للقنوات وPlugins الميزات استهلاك القدرة الجديدة عبر النواة، لا باستيراد تنفيذ مورّد مباشرةً.
- سجّل تنفيذات المورّدين. تسجّل Plugins المورّدين بعد ذلك واجهاتها الخلفية ضمن القدرة.
- أضف تغطية للعقد. أضف اختبارات كي تظل الملكية وشكل التسجيل صريحين بمرور الوقت.
بهذه الطريقة يظل OpenClaw ذا نهج محدد دون أن يصبح مرتبطًا برمجيًا برؤية مزوّد واحد. راجع دليل وصفات القدرات للحصول على قائمة تحقق عملية للملفات ومثال تطبيقي.
قائمة تحقق القدرة
عندما تضيف قدرة جديدة، ينبغي للتنفيذ عادةً أن يطال هذه الأسطح معًا:
- أنواع عقد النواة في
src/<capability>/types.ts - مشغّل النواة/مساعد وقت التشغيل في
src/<capability>/runtime.ts - سطح تسجيل API الخاص بالـ Plugin في
src/plugins/types.ts - توصيل سجل Plugin في
src/plugins/registry.ts - إتاحة وقت تشغيل Plugin في
src/plugins/runtime/*عندما تحتاج Plugins الميزات/القنوات إلى استهلاكه - مساعدات الالتقاط/الاختبار في
src/test-utils/plugin-registration.ts - تأكيدات الملكية/العقد في
src/plugins/contracts/registry.ts - وثائق المشغّل/Plugin في
docs/
إذا كان أحد هذه الأسطح مفقودًا، فهذه عادةً علامة على أن القدرة لم تُدمج بالكامل بعد.
قالب القدرة
النمط الأدنى:
// core contractexport type VideoGenerationProviderPlugin = { id: string; label: string; generateVideo: (req: VideoGenerationRequest) => Promise<VideoGenerationResult>;}; // plugin APIapi.registerVideoGenerationProvider({ id: "openai", label: "OpenAI", async generateVideo(req) { return await generateOpenAiVideo(req); },}); // shared runtime helper for feature/channel pluginsconst clip = await api.runtime.videoGeneration.generate({ prompt: "Show the robot walking through the lab.", cfg,});نمط اختبار العقد (يكشف src/plugins/contracts/registry.ts عمليات بحث الملكية
مثل providerContractPluginIds؛ وتتحقق الاختبارات من أن قائمة
contracts.videoGenerationProviders الخاصة بـ Plugin تطابق ما يسجله فعليًا):
expect(pluginManifest.contracts?.videoGenerationProviders).toEqual(["openai"]);يحافظ ذلك على بساطة القاعدة:
- تمتلك النواة عقد القدرة + التنسيق
- تمتلك Plugins المورّدين تنفيذات المورّدين
- تستهلك Plugins الميزات/القنوات مساعدات وقت التشغيل
- تُبقي اختبارات العقد الملكية صريحة
ذو صلة
- معمارية Plugin — نموذج القدرة العام وأشكاله
- المسارات الفرعية لحزمة تطوير Plugin
- إعداد حزمة تطوير Plugin
- بناء Plugins