الانتقال إلى المحتوى الرئيسي

الواجهات الداخلية للإضافات

هذا هو مرجع البنية العميقة. للاطلاع على الأدلة العملية، راجع:
تغطي هذه الصفحة البنية الداخلية لنظام إضافات OpenClaw.

نموذج القدرات العام

القدرات هي نموذج الإضافة الأصلية العام داخل OpenClaw. كل إضافة OpenClaw أصلية تسجل نفسها مقابل نوع قدرة واحد أو أكثر:
القدرةطريقة التسجيلأمثلة على الإضافات
استدلال النصapi.registerProvider(...)openai, anthropic
واجهة CLI الخلفية للاستدلالapi.registerCliBackend(...)openai, anthropic
الكلامapi.registerSpeechProvider(...)elevenlabs, microsoft
النسخ الفوريapi.registerRealtimeTranscriptionProvider(...)openai
الصوت الفوريapi.registerRealtimeVoiceProvider(...)openai
فهم الوسائطapi.registerMediaUnderstandingProvider(...)openai, google
توليد الصورapi.registerImageGenerationProvider(...)openai, google, fal, minimax
توليد الفيديوapi.registerVideoGenerationProvider(...)qwen
جلب الويبapi.registerWebFetchProvider(...)firecrawl
البحث على الويبapi.registerWebSearchProvider(...)google
القناة / المراسلةapi.registerChannel(...)msteams, matrix
الإضافة التي تسجل صفرًا من القدرات ولكنها توفّر خطافات أو أدوات أو خدمات تُعد إضافة قديمة تعتمد على الخطافات فقط. وما يزال هذا النمط مدعومًا بالكامل.

موقف التوافق الخارجي

تم اعتماد نموذج القدرات في النواة ويُستخدم بواسطة الإضافات المضمّنة/الأصلية اليوم، لكن توافق الإضافات الخارجية ما يزال يحتاج إلى معيار أكثر إحكامًا من مجرد “إنه مُصدَّر، إذًا فهو ثابت.” الإرشادات الحالية:
  • الإضافات الخارجية الحالية: أبقِ التكاملات المعتمدة على الخطافات تعمل؛ واعتبر ذلك خط الأساس للتوافق
  • الإضافات المضمّنة/الأصلية الجديدة: فضّل تسجيل القدرات الصريح بدلًا من الوصولات الخاصة بالمورّد أو التصاميم الجديدة المعتمدة على الخطافات فقط
  • الإضافات الخارجية التي تعتمد تسجيل القدرات: مسموح بها، لكن تعامل مع أسطح المساعدة الخاصة بالقدرات على أنها قابلة للتطور ما لم توضح الوثائق صراحةً أن العقد مستقر
القاعدة العملية:
  • واجهات تسجيل القدرات هي الاتجاه المقصود
  • تظل الخطافات القديمة المسار الأكثر أمانًا لتجنّب الكسر للإضافات الخارجية أثناء الانتقال
  • ليست كل المسارات الفرعية المساعدة المُصدَّرة متساوية؛ فضّل العقد الضيق الموثّق، لا الصادرات المساعدة العرضية

أشكال الإضافات

يصنّف OpenClaw كل إضافة محمّلة إلى شكل اعتمادًا على سلوك التسجيل الفعلي لها (وليس فقط البيانات الوصفية الثابتة):
  • plain-capability — تسجل نوع قدرة واحدًا فقط بالضبط (مثل إضافة مزوّد فقط مثل mistral)
  • hybrid-capability — تسجل عدة أنواع قدرات (مثل openai التي تملك استدلال النص والكلام وفهم الوسائط وتوليد الصور)
  • hook-only — تسجل خطافات فقط (مكتوبة النوع أو مخصصة)، من دون قدرات أو أدوات أو أوامر أو خدمات
  • non-capability — تسجل أدوات أو أوامر أو خدمات أو مسارات ولكن من دون قدرات
استخدم openclaw plugins inspect <id> لرؤية شكل الإضافة وتفصيل القدرات. راجع مرجع CLI للتفاصيل.

الخطافات القديمة

ما يزال الخطاف before_agent_start مدعومًا كمسار توافق للإضافات المعتمدة على الخطافات فقط. ما تزال إضافات قديمة مستخدمة فعليًا تعتمد عليه. الاتجاه:
  • أبقه يعمل
  • وثّقه باعتباره قديمًا
  • فضّل before_model_resolve لأعمال تجاوز النموذج/المزوّد
  • فضّل before_prompt_build لأعمال تعديل المطالبة
  • أزله فقط بعد انخفاض الاستخدام الفعلي وتأكيد تغطية التركيبات التجريبية أمان الترحيل

إشارات التوافق

عند تشغيل openclaw doctor أو openclaw plugins inspect <id>، قد ترى أحد هذه التصنيفات:
الإشارةالمعنى
config validيجري تحليل الإعدادات بنجاح وتُحل الإضافات
compatibility advisoryتستخدم الإضافة نمطًا مدعومًا لكنه أقدم (مثل hook-only)
legacy warningتستخدم الإضافة before_agent_start، وهو قديم
hard errorالإعدادات غير صالحة أو فشل تحميل الإضافة
لن يؤدي كل من hook-only أو before_agent_start إلى كسر إضافتك اليوم — فـ hook-only مجرد تنبيه إرشادي، وbefore_agent_start يطلق تحذيرًا فقط. تظهر هذه الإشارات أيضًا في openclaw status --all وopenclaw plugins doctor.

نظرة عامة على البنية

يحتوي نظام إضافات OpenClaw على أربع طبقات:
  1. البيان + الاكتشاف يعثر OpenClaw على الإضافات المرشحة من المسارات المكوّنة وجذور مساحة العمل وجذور الامتدادات العامة والامتدادات المضمّنة. يقرأ الاكتشاف بيانات openclaw.plugin.json الأصلية إضافةً إلى بيانات الحزم المدعومة أولًا.
  2. التمكين + التحقق تقرر النواة ما إذا كانت الإضافة المكتشفة مفعّلة أو معطّلة أو محجوبة أو محددة لفتحة حصرية مثل الذاكرة.
  3. التحميل وقت التشغيل تُحمَّل إضافات OpenClaw الأصلية داخل العملية عبر jiti وتسجل القدرات في سجل مركزي. أما الحزم المتوافقة فتُطبَّع إلى سجلات في السجل من دون استيراد شيفرة وقت التشغيل.
  4. استهلاك السطح يقرأ بقية OpenClaw السجل لإظهار الأدوات والقنوات وإعداد المزوّد والخطافات ومسارات HTTP وأوامر CLI والخدمات.
بالنسبة إلى CLI الخاص بالإضافات تحديدًا، يُقسَّم اكتشاف أوامر الجذر إلى مرحلتين:
  • تأتي بيانات وقت التحليل من registerCli(..., { descriptors: [...] })
  • ويمكن أن يبقى ملف CLI الحقيقي للإضافة كسول التحميل ويُسجل عند أول استدعاء
وهذا يبقي شيفرة CLI المملوكة للإضافة داخل الإضافة مع استمرار تمكين OpenClaw من حجز أسماء الأوامر الجذرية قبل التحليل. حد التصميم المهم:
  • يجب أن يعمل الاكتشاف والتحقق من الإعدادات اعتمادًا على بيانات البيان/المخطط من دون تنفيذ شيفرة الإضافة
  • يأتي السلوك الأصلي وقت التشغيل من مسار register(api) في وحدة الإضافة
يتيح هذا الفصل لـ OpenClaw التحقق من الإعدادات وشرح الإضافات المفقودة/المعطلة وبناء تلميحات الواجهة/المخطط قبل تفعيل وقت التشغيل الكامل.

إضافات القنوات وأداة الرسائل المشتركة

لا تحتاج إضافات القنوات إلى تسجيل أداة منفصلة للإرسال/التحرير/التفاعل من أجل إجراءات الدردشة العادية. يحتفظ OpenClaw بأداة message مشتركة واحدة في النواة، وتملك إضافات القنوات الاكتشاف والتنفيذ الخاصين بالقناة خلفها. الحد الحالي هو:
  • تملك النواة مضيف أداة message المشتركة، وربط المطالبات، وإدارة الجلسات/الخيوط، وتوجيه التنفيذ
  • تملك إضافات القنوات اكتشاف الإجراءات المقيّدة، واكتشاف القدرات، وأي أجزاء مخطط خاصة بالقناة
  • تملك إضافات القنوات قواعد محادثة الجلسات الخاصة بالمزوّد، مثل كيفية ترميز معرّفات المحادثة لمعرّفات الخيوط أو توريثها من المحادثات الأصلية
  • تنفذ إضافات القنوات الإجراء النهائي عبر مهايئ الإجراء الخاص بها
بالنسبة إلى إضافات القنوات، سطح SDK هو ChannelMessageActionAdapter.describeMessageTool(...). يتيح هذا الاستدعاء الموحد للاكتشاف أن تعيد الإضافة إجراءاتها المرئية وقدراتها ومساهمات مخططها معًا حتى لا تنحرف هذه الأجزاء عن بعضها. تمرر النواة نطاق وقت التشغيل إلى خطوة الاكتشاف هذه. وتتضمن الحقول المهمة:
  • accountId
  • currentChannelId
  • currentThreadTs
  • currentMessageId
  • sessionKey
  • sessionId
  • agentId
  • requesterSenderId الوارد الموثوق
وهذا مهم للإضافات الحساسة للسياق. يمكن للقناة إخفاء أو إظهار إجراءات الرسائل استنادًا إلى الحساب النشط أو الغرفة/الخيط/الرسالة الحالية أو هوية الطالب الموثوقة من دون ترميز فروع خاصة بالقناة داخل أداة message الأساسية. ولهذا السبب ما تزال تغييرات التوجيه في المشغل المضمّن عملًا خاصًا بالإضافات: إذ يتحمل المشغل مسؤولية تمرير هوية الدردشة/الجلسة الحالية إلى حد اكتشاف الإضافة بحيث تكشف أداة message المشتركة السطح الصحيح الذي تملكه القناة للدور الحالي. وبالنسبة إلى مساعدات التنفيذ المملوكة للقناة، ينبغي للإضافات المضمّنة أن تُبقي وقت تشغيل التنفيذ داخل وحدات الامتداد الخاصة بها. لم تعد النواة تملك أوقات تشغيل إجراءات رسائل Discord أو Slack أو Telegram أو WhatsApp ضمن src/agents/tools. نحن لا ننشر مسارات فرعية منفصلة plugin-sdk/*-action-runtime، وينبغي للإضافات المضمّنة أن تستورد شيفرة وقت التشغيل المحلية الخاصة بها مباشرةً من الوحدات التي تملكها امتداداتها. وينطبق الحد نفسه على فواصل SDK المسماة بأسماء المزوّدين عمومًا: يجب ألا تستورد النواة حاويات مريحة خاصة بالقنوات مثل Slack أو Discord أو Signal أو WhatsApp أو امتدادات مشابهة. إذا احتاجت النواة إلى سلوك ما، فإما أن تستهلك حاوية api.ts / runtime-api.ts الخاصة بالإضافة المضمّنة نفسها أو ترفع الحاجة إلى قدرة عامة ضيقة في SDK المشترك. وبالنسبة إلى الاستطلاعات تحديدًا، هناك مسارا تنفيذ:
  • outbound.sendPoll هو خط الأساس المشترك للقنوات التي تناسب نموذج الاستطلاع العام
  • actions.handleAction("poll") هو المسار المفضل لدلالات الاستطلاع الخاصة بالقناة أو معلمات الاستطلاع الإضافية
تؤجل النواة الآن تحليل الاستطلاع المشترك إلى ما بعد رفض توجيه استطلاع الإضافة للإجراء، بحيث يمكن لمعالجات الاستطلاعات المملوكة للإضافة قبول حقول استطلاع خاصة بالقناة من دون أن يحجبها محلل الاستطلاع العام أولًا. راجع مسار التحميل للحصول على تسلسل بدء التشغيل الكامل.

نموذج ملكية القدرات

يتعامل OpenClaw مع الإضافة الأصلية على أنها حد الملكية لـ شركة أو ميزة، وليس مجرد مجموعة من التكاملات غير المرتبطة. وهذا يعني:
  • يجب أن تملك إضافة الشركة عادةً كل الأسطح المواجهة لـ OpenClaw لتلك الشركة
  • يجب أن تملك إضافة الميزة عادةً سطح الميزة الكامل الذي تقدمه
  • يجب أن تستهلك القنوات القدرات الأساسية المشتركة بدلًا من إعادة تنفيذ سلوك المزوّد بشكل ارتجالي
أمثلة:
  • تملك الإضافة المضمّنة openai سلوك مزوّد نماذج OpenAI وسلوك OpenAI للكلام + الصوت الفوري + فهم الوسائط + توليد الصور
  • تملك الإضافة المضمّنة elevenlabs سلوك كلام ElevenLabs
  • تملك الإضافة المضمّنة microsoft سلوك كلام Microsoft
  • تملك الإضافة المضمّنة google سلوك مزوّد نماذج Google إضافةً إلى سلوك Google لفهم الوسائط + توليد الصور + البحث على الويب
  • تملك الإضافة المضمّنة firecrawl سلوك جلب الويب لـ Firecrawl
  • تملك الإضافات المضمّنة minimax وmistral وmoonshot وzai واجهاتها الخلفية لفهم الوسائط
  • تُعد الإضافة voice-call إضافة ميزة: فهي تملك نقل المكالمات والأدوات وCLI والمسارات وجسر تدفق الوسائط في Twilio، لكنها تستهلك قدرات الكلام المشتركة + النسخ الفوري والصوت الفوري بدلًا من استيراد إضافات المورّدين مباشرةً
الحالة النهائية المقصودة هي:
  • يبقى OpenAI في إضافة واحدة حتى لو امتد عبر نماذج النص والكلام والصور والفيديو مستقبلًا
  • ويمكن لمورّد آخر فعل الشيء نفسه لمساحة عمله الخاصة
  • لا تهتم القنوات بأي إضافة مورّد تملك المزوّد؛ بل تستهلك عقد القدرة المشتركة الذي تكشفه النواة
وهذا هو التمييز الأساسي:
  • الإضافة = حد الملكية
  • القدرة = عقد النواة الذي يمكن لعدة إضافات تنفيذه أو استهلاكه
لذا إذا أضاف OpenClaw مجالًا جديدًا مثل الفيديو، فالسؤال الأول ليس “أي مزوّد يجب أن يرمّز معالجة الفيديو مباشرةً؟” بل “ما هو عقد قدرة الفيديو الأساسي؟” وبمجرد وجود هذا العقد، يمكن لإضافات المورّدين التسجيل مقابله ويمكن لإضافات القنوات/الميزات استهلاكه. إذا لم تكن القدرة موجودة بعد، فعادةً ما تكون الخطوة الصحيحة:
  1. تعريف القدرة المفقودة في النواة
  2. كشفها عبر واجهة الإضافة/وقت التشغيل بطريقة مكتوبة النوع
  3. ربط القنوات/الميزات بهذه القدرة
  4. والسماح لإضافات المورّدين بتسجيل التنفيذات
وهذا يُبقي الملكية صريحة مع تجنب سلوك في النواة يعتمد على مورّد واحد أو مسار شيفرة خاص بإضافة واحدة.

طبقات القدرات

استخدم هذا النموذج الذهني عند تقرير موضع الشيفرة:
  • طبقة القدرات الأساسية: التنسيق المشترك، والسياسة، والرجوع الاحتياطي، وقواعد دمج الإعدادات، ودلالات التسليم، والعقود المكتوبة النوع
  • طبقة إضافات المورّد: واجهات برمجة التطبيقات الخاصة بالمورّد، والمصادقة، وفهارس النماذج، وتوليف الكلام، وتوليد الصور، والواجهات الخلفية المستقبلية للفيديو، ونقاط نهاية الاستخدام
  • طبقة إضافة القناة/الميزة: تكامل Slack/Discord/voice-call/… إلخ الذي يستهلك القدرات الأساسية ويعرضها على سطح ما
فعلى سبيل المثال، يتبع TTS هذا الشكل:
  • تملك النواة سياسة TTS أثناء الرد، وترتيب الرجوع، والتفضيلات، وتسليم القناة
  • تملك openai وelevenlabs وmicrosoft تنفيذات التوليف
  • وتستهلك voice-call مساعد وقت تشغيل TTS للهاتف
ويُفضّل النمط نفسه للقدرات المستقبلية.

مثال على إضافة شركة متعددة القدرات

يجب أن تبدو إضافة الشركة متماسكة من الخارج. إذا كان لدى OpenClaw عقود مشتركة للنماذج، والكلام، والنسخ الفوري، والصوت الفوري، وفهم الوسائط، وتوليد الصور، وتوليد الفيديو، وجلب الويب، والبحث على الويب، فيمكن لمورّد أن يملك كل أسطحه في مكان واحد:
import type { OpenClawPluginDefinition } from "openclaw/plugin-sdk/plugin-entry";
import {
  describeImageWithModel,
  transcribeOpenAiCompatibleAudio,
} from "openclaw/plugin-sdk/media-understanding";

const plugin: OpenClawPluginDefinition = {
  id: "exampleai",
  name: "ExampleAI",
  register(api) {
    api.registerProvider({
      id: "exampleai",
      // auth/model catalog/runtime hooks
    });

    api.registerSpeechProvider({
      id: "exampleai",
      // vendor speech config — implement the SpeechProviderPlugin interface directly
    });

    api.registerMediaUnderstandingProvider({
      id: "exampleai",
      capabilities: ["image", "audio", "video"],
      async describeImage(req) {
        return describeImageWithModel({
          provider: "exampleai",
          model: req.model,
          input: req.input,
        });
      },
      async transcribeAudio(req) {
        return transcribeOpenAiCompatibleAudio({
          provider: "exampleai",
          model: req.model,
          input: req.input,
        });
      },
    });

    api.registerWebSearchProvider(
      createPluginBackedWebSearchProvider({
        id: "exampleai-search",
        // credential + fetch logic
      }),
    );
  },
};

export default plugin;
المهم ليس أسماء المساعدات الدقيقة. بل الشكل هو المهم:
  • إضافة واحدة تملك سطح المورّد
  • وما تزال النواة تملك عقود القدرات
  • وتستهلك القنوات وإضافات الميزات مساعدات api.runtime.*، لا شيفرة المورّد
  • ويمكن لاختبارات العقود تأكيد أن الإضافة سجلت القدرات التي تدّعي ملكيتها

مثال قدرة: فهم الفيديو

يعامل OpenClaw بالفعل فهم الصورة/الصوت/الفيديو على أنه قدرة مشتركة واحدة. وينطبق نموذج الملكية نفسه هنا:
  1. تعرّف النواة عقد فهم الوسائط
  2. تسجّل إضافات المورّدين describeImage وtranscribeAudio و describeVideo حسب الحاجة
  3. تستهلك القنوات وإضافات الميزات السلوك الأساسي المشترك بدلًا من الربط المباشر مع شيفرة المورّد
وهذا يتجنب ترسيخ افتراضات الفيديو الخاصة بمزوّد واحد في النواة. فالإضافة تملك سطح المورّد؛ بينما تملك النواة عقد القدرة وسلوك الرجوع. ويتبع توليد الفيديو بالفعل التسلسل نفسه: تملك النواة عقد القدرة المكتوب النوع ومساعد وقت التشغيل، وتسجّل إضافات المورّدين تنفيذات api.registerVideoGenerationProvider(...) مقابله. هل تحتاج إلى قائمة تحقق عملية للنشر؟ راجع كتاب طبخ القدرات.

العقود وفرضها

سطح واجهة الإضافة مكتوب النوع ومركزي عمدًا في OpenClawPluginApi. يحدد هذا العقد نقاط التسجيل المدعومة و مساعدات وقت التشغيل التي يمكن أن تعتمد عليها الإضافة. لماذا يهم هذا:
  • يحصل مؤلفو الإضافات على معيار داخلي واحد ومستقر
  • تستطيع النواة رفض الملكية المكررة مثل تسجيل إضافتين لمعرّف المزوّد نفسه
  • يمكن لبدء التشغيل عرض تشخيصات عملية للتسجيلات غير السليمة
  • يمكن لاختبارات العقود فرض ملكية الإضافات المضمّنة ومنع الانحراف الصامت
هناك طبقتان من الفرض:
  1. فرض التسجيل وقت التشغيل يتحقق سجل الإضافات من التسجيلات أثناء تحميل الإضافات. أمثلة: معرّفات المزوّدين المكررة، ومعرّفات مزوّدي الكلام المكررة، والتسجيلات غير السليمة تنتج تشخيصات للإضافة بدلًا من سلوك غير معرّف.
  2. اختبارات العقود تُلتقط الإضافات المضمّنة في سجلات عقود أثناء تشغيل الاختبارات حتى يتمكن OpenClaw من تأكيد الملكية صراحةً. ويُستخدم هذا اليوم لمزوّدي النماذج، ومزوّدي الكلام، ومزوّدي البحث على الويب، وملكية التسجيل المضمّن.
والأثر العملي هو أن OpenClaw يعرف مسبقًا أي إضافة تملك أي سطح. وهذا يسمح للنواة والقنوات بالتركيب بسلاسة لأن الملكية معلنة ومكتوبة النوع وقابلة للاختبار بدلًا من أن تكون ضمنية.

ما الذي يجب أن يكون ضمن عقد

عقود الإضافات الجيدة تكون:
  • مكتوبة النوع
  • صغيرة
  • خاصة بالقدرة
  • مملوكة للنواة
  • قابلة لإعادة الاستخدام من عدة إضافات
  • قابلة للاستهلاك من القنوات/الميزات دون معرفة بالمورّد
عقود الإضافات السيئة تكون:
  • سياسة خاصة بالمورّد مخفية داخل النواة
  • منافذ هروب خاصة بإضافة واحدة تتجاوز السجل
  • شيفرة قناة تصل مباشرةً إلى تنفيذ خاص بمورّد
  • كائنات وقت تشغيل ارتجالية ليست جزءًا من OpenClawPluginApi أو api.runtime
عند الشك، ارفع مستوى التجريد: عرّف القدرة أولًا، ثم اسمح للإضافات بالاتصال بها.

نموذج التنفيذ

تعمل إضافات OpenClaw الأصلية داخل العملية مع Gateway. وهي غير معزولة. والإضافة الأصلية المحمّلة لها حد الثقة على مستوى العملية نفسه مثل شيفرة النواة. الآثار المترتبة:
  • يمكن للإضافة الأصلية تسجيل أدوات ومعالجات شبكية وخطافات وخدمات
  • يمكن أن يتسبب خطأ في إضافة أصلية في تعطل البوابة أو زعزعة استقرارها
  • تعادل الإضافة الأصلية الخبيثة تنفيذ شيفرة عشوائية داخل عملية OpenClaw
الحزم المتوافقة أكثر أمانًا افتراضيًا لأن OpenClaw يتعامل معها حاليًا بوصفها حزم بيانات/محتوى. وفي الإصدارات الحالية، يعني هذا في الغالب المهارات المضمّنة. استخدم قوائم السماح ومسارات التثبيت/التحميل الصريحة للإضافات غير المضمّنة. وتعامل مع إضافات مساحة العمل على أنها شيفرة وقت تطوير، لا إعدادات افتراضية للإنتاج. وبالنسبة إلى أسماء حزم مساحة العمل المضمّنة، أبقِ معرّف الإضافة مثبتًا في اسم npm: @openclaw/<id> افتراضيًا، أو لاحقة نوعية معتمدة مثل -provider أو -plugin أو -speech أو -sandbox أو -media-understanding عندما تكشف الحزمة عمدًا دور إضافة أضيق. ملاحظة ثقة مهمة:
  • يثق plugins.allow في معرّفات الإضافات، لا في مصدرها.
  • وتعمد إضافة مساحة عمل تحمل المعرف نفسه لإضافة مضمّنة إلى تظليل النسخة المضمّنة عندما تكون إضافة مساحة العمل هذه مفعّلة/مدرجة في قائمة السماح.
  • وهذا سلوك طبيعي ومفيد للتطوير المحلي واختبار التصحيحات والإصلاحات السريعة.

حد التصدير

يصدّر OpenClaw القدرات، لا وسائل الراحة الخاصة بالتنفيذ. أبقِ تسجيل القدرات عامًا. وقلّص صادرات المساعدة غير التعاقدية:
  • المسارات الفرعية الخاصة بمساعدة الإضافات المضمّنة
  • المسارات الفرعية لسباكة وقت التشغيل غير المقصودة كواجهة عامة
  • مساعدات الراحة الخاصة بالمورّد
  • مساعدات الإعداد/التجهيز التي تُعد تفاصيل تنفيذ
ما تزال بعض المسارات الفرعية المساعدة للإضافات المضمّنة موجودة في خريطة صادرات SDK المولّدة من أجل التوافق وصيانة الإضافات المضمّنة. وتشمل الأمثلة الحالية plugin-sdk/feishu وplugin-sdk/feishu-setup وplugin-sdk/zalo و plugin-sdk/zalo-setup وعدة فواصل plugin-sdk/matrix*. تعامل مع هذه المسارات على أنها صادرات محفوظة لتفاصيل التنفيذ، لا باعتبارها النمط الموصى به في SDK للإضافات الخارجية الجديدة.

مسار التحميل

عند بدء التشغيل، ينفذ OpenClaw تقريبًا ما يلي:
  1. اكتشاف جذور الإضافات المرشحة
  2. قراءة البيانات الأصلية أو بيانات الحزم المتوافقة وبيانات الحزم الوصفية
  3. رفض المرشحين غير الآمنين
  4. تطبيع إعدادات الإضافة (plugins.enabled وallow وdeny وentries و slots وload.paths)
  5. تحديد التمكين لكل مرشح
  6. تحميل الوحدات الأصلية المفعّلة عبر jiti
  7. استدعاء خطافات register(api) الأصلية (أو activate(api) — اسم بديل قديم) وجمع التسجيلات في سجل الإضافات
  8. كشف السجل لأسطح الأوامر/وقت التشغيل
activate اسم بديل قديم لـ register — يحلّ المحمّل أيهما موجود (def.register ?? def.activate) ويستدعيه في النقطة نفسها. تستخدم جميع الإضافات المضمّنة register؛ وفضّل register للإضافات الجديدة.
تحدث بوابات الأمان قبل تنفيذ وقت التشغيل. ويُحظر المرشحون عندما يخرج المدخل من جذر الإضافة، أو يكون المسار قابلاً للكتابة من الجميع، أو تبدو ملكية المسار مريبة للإضافات غير المضمّنة.

سلوك البيان أولًا

البيان هو مصدر الحقيقة لمستوى التحكم. ويستخدمه OpenClaw من أجل:
  • تحديد الإضافة
  • اكتشاف القنوات/المهارات/مخطط الإعدادات المعلنة أو قدرات الحزمة
  • التحقق من plugins.entries.<id>.config
  • تعزيز تسميات/عناصر نائبة في واجهة التحكم
  • عرض بيانات التثبيت/الفهرس الوصفية
بالنسبة إلى الإضافات الأصلية، فإن وحدة وقت التشغيل هي جزء مستوى البيانات. وهي تسجل السلوك الفعلي مثل الخطافات أو الأدوات أو الأوامر أو تدفقات المزوّد.

ما الذي يخزنه المحمّل مؤقتًا

يحتفظ OpenClaw بذاكرات مؤقتة قصيرة داخل العملية من أجل:
  • نتائج الاكتشاف
  • بيانات سجل البيان
  • سجلات الإضافات المحمّلة
تقلل هذه الذواكر المؤقتة من بدء التشغيل المتدفق والعبء الناتج عن تكرار الأوامر. وهي آمنة للتعامل معها على أنها ذواكر مؤقتة قصيرة العمر للأداء، لا تخزين دائم. ملاحظة أداء:
  • اضبط OPENCLAW_DISABLE_PLUGIN_DISCOVERY_CACHE=1 أو OPENCLAW_DISABLE_PLUGIN_MANIFEST_CACHE=1 لتعطيل هذه الذواكر المؤقتة.
  • واضبط نوافذ الذاكرة المؤقتة باستخدام OPENCLAW_PLUGIN_DISCOVERY_CACHE_MS و OPENCLAW_PLUGIN_MANIFEST_CACHE_MS.

نموذج السجل

لا تقوم الإضافات المحمّلة بتعديل متغيرات النواة العامة عشوائيًا مباشرةً. بل تسجل نفسها في سجل إضافات مركزي. يتتبع السجل:
  • سجلات الإضافات (الهوية، والمصدر، والأصل، والحالة، والتشخيصات)
  • الأدوات
  • الخطافات القديمة والخطافات المكتوبة النوع
  • القنوات
  • المزوّدين
  • معالجات Gateway RPC
  • مسارات HTTP
  • مسجلات CLI
  • الخدمات الخلفية
  • الأوامر المملوكة للإضافة
ثم تقرأ ميزات النواة من هذا السجل بدلًا من التحدث إلى وحدات الإضافة مباشرةً. وهذا يُبقي التحميل أحادي الاتجاه:
  • وحدة الإضافة -> التسجيل في السجل
  • وقت تشغيل النواة -> استهلاك السجل
وهذا الفصل مهم لقابلية الصيانة. فهو يعني أن معظم أسطح النواة لا تحتاج إلا إلى نقطة تكامل واحدة: “اقرأ السجل”، لا “عامل كل وحدة إضافة على نحو خاص”.

ردود نداء ربط المحادثة

يمكن للإضافات التي تربط محادثةً أن تتفاعل عند حل موافقة ما. استخدم 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: ملخص الطلب الأصلي، وتلميح الفصل، ومعرّف المرسل، و بيانات المحادثة الوصفية
هذا الرد للإشعار فقط. وهو لا يغيّر من يُسمح له بربط محادثة، ويعمل بعد انتهاء معالجة الموافقة الأساسية.

خطافات وقت تشغيل المزوّد

أصبحت إضافات المزوّد تحتوي الآن على طبقتين:
  • بيانات البيان الوصفية: providerAuthEnvVars للبحث الرخيص عن المصادقة البيئية قبل تحميل وقت التشغيل، وproviderAuthChoices من أجل تسميات التجهيز/اختيار المصادقة الرخيصة وبيانات أعلام CLI الوصفية قبل تحميل وقت التشغيل
  • خطافات وقت الإعداد: catalog / القديم discovery بالإضافة إلى applyConfigDefaults
  • خطافات وقت التشغيل: normalizeModelId, normalizeTransport, normalizeConfig, applyNativeStreamingUsageCompat, resolveConfigApiKey, resolveSyntheticAuth, shouldDeferSyntheticProfileAuth, resolveDynamicModel, prepareDynamicModel, normalizeResolvedModel, contributeResolvedModelCompat, capabilities, normalizeToolSchemas, inspectToolSchemas, resolveReasoningOutputMode, prepareExtraParams, createStreamFn, wrapStreamFn, resolveTransportTurnState, resolveWebSocketSessionPolicy, formatApiKey, refreshOAuth, buildAuthDoctorHint, matchesContextOverflowError, classifyFailoverReason, isCacheTtlEligible, buildMissingAuthMessage, suppressBuiltInModel, augmentModelCatalog, isBinaryThinking, supportsXHighThinking, resolveDefaultThinkingLevel, isModernModelRef, prepareRuntimeAuth, resolveUsageAuth, fetchUsageSnapshot, createEmbeddingProvider, buildReplayPolicy, sanitizeReplayHistory, validateReplayTurns, onModelSelected
ما يزال OpenClaw يملك الحلقة العامة للوكيل، والرجوع، ومعالجة النصوص المسجلة، وسياسة الأدوات. وتمثل هذه الخطافات سطح الامتداد لسلوك خاص بالمزوّد من دون الحاجة إلى نقل استدلال مخصص بالكامل. استخدم providerAuthEnvVars في البيان عندما يكون لدى المزوّد بيانات اعتماد بيئية ينبغي لمسارات المصادقة/الحالة/منتقي النموذج العامة رؤيتها من دون تحميل وقت تشغيل الإضافة. واستخدم providerAuthChoices في البيان عندما يجب أن تعرف أسطح CLI الخاصة بالتجهيز/اختيار المصادقة معرّف اختيار المزوّد وتسميات المجموعة وربط المصادقة البسيط بعَلَم واحد من دون تحميل وقت تشغيل المزوّد. وأبقِ envVars الخاصة بوقت تشغيل المزوّد لتلميحات موجّهة للمشغل مثل تسميات التجهيز أو متغيرات إعداد OAuth client-id/client-secret.

ترتيب الخطافات واستخدامها

بالنسبة إلى إضافات النموذج/المزوّد، يستدعي OpenClaw الخطافات بهذا الترتيب التقريبي. ويمثل عمود “متى يُستخدم” دليل القرار السريع.
#الخطافما الذي يفعلهمتى يُستخدم
1catalogنشر إعدادات المزوّد في models.providers أثناء توليد models.jsonعندما يملك المزوّد فهرسًا أو إعدادات افتراضية لـ base URL
2applyConfigDefaultsتطبيق القيم الافتراضية العامة المملوكة للمزوّد أثناء تجسيد الإعداداتعندما تعتمد القيم الافتراضية على وضع المصادقة أو البيئة أو دلالات عائلة نماذج المزوّد
(البحث المضمّن عن النموذج)يحاول OpenClaw أولًا مسار السجل/الفهرس العادي(ليس خطاف إضافة)
3normalizeModelIdتطبيع الأسماء البديلة القديمة أو التجريبية لمعرّف النموذج قبل البحثعندما يملك المزوّد تنظيف الأسماء البديلة قبل حل النموذج القانوني
4normalizeTransportتطبيع api / baseUrl لعائلة المزوّد قبل تجميع النموذج العامعندما يملك المزوّد تنظيف النقل لمعرّفات مزوّد مخصصة في عائلة النقل نفسها
5normalizeConfigتطبيع models.providers.<id> قبل حل المزوّد/وقت التشغيلعندما يحتاج المزوّد إلى تنظيف إعدادات يجب أن يبقى مع الإضافة؛ كما تدعم مساعدات Google-family المضمّنة قيَم Google المدعومة
6applyNativeStreamingUsageCompatتطبيق إعادة كتابة توافق استخدام البث الأصلي على مزوّدي الإعداداتعندما يحتاج المزوّد إلى إصلاحات بيانات استخدام البث الأصلية المعتمدة على نقطة النهاية
7resolveConfigApiKeyحل مصادقة علامة البيئة لمزوّدي الإعدادات قبل تحميل مصادقة وقت التشغيلعندما يملك المزوّد حلًا لمفاتيح API عبر علامات البيئة؛ كما يملك amazon-bedrock محلل AWS مضمّنًا هنا
8resolveSyntheticAuthإظهار مصادقة محلية/مستضافة ذاتيًا أو معتمدة على الإعدادات من دون حفظ نص واضحعندما يستطيع المزوّد العمل مع علامة اعتماد اصطناعية/محلية
9shouldDeferSyntheticProfileAuthخفض أولوية العناصر النائبة المخزنة لملفات التعريف الاصطناعية خلف مصادقة البيئة/الإعداداتعندما يخزن المزوّد ملفات تعريف بعناصر نائبة اصطناعية يجب ألا تسبق غيرها
10resolveDynamicModelبديل متزامن لمعرّفات النماذج المملوكة للمزوّد غير الموجودة بعد في السجل المحليعندما يقبل المزوّد معرّفات نماذج علوية عشوائية
11prepareDynamicModelإحماء غير متزامن، ثم يعمل resolveDynamicModel مرة أخرىعندما يحتاج المزوّد إلى بيانات وصفية شبكية قبل حل المعرّفات غير المعروفة
12normalizeResolvedModelإعادة كتابة نهائية قبل أن يستخدم المشغل المضمّن النموذج المحلولعندما يحتاج المزوّد إلى إعادة كتابة للنقل لكنه ما يزال يستخدم نقلًا أساسيًا
13contributeResolvedModelCompatإضافة أعلام توافق لنماذج المورّد خلف نقل متوافق آخرعندما يتعرف المزوّد على نماذجه الخاصة في وسائل نقل وكيلة من دون أن يستولي على المزوّد
14capabilitiesبيانات وصفية مملوكة للمزوّد عن النصوص المسجلة/الأدوات تُستخدمها النواة المشتركةعندما يحتاج المزوّد إلى خصائص لعائلته في النصوص المسجلة/المزوّد
15normalizeToolSchemasتطبيع مخططات الأدوات قبل أن يراها المشغل المضمّنعندما يحتاج المزوّد إلى تنظيف مخططات خاص بعائلة النقل
16inspectToolSchemasإظهار تشخيصات مخططات مملوكة للمزوّد بعد التطبيععندما يريد المزوّد تحذيرات كلمات مفتاحية من دون تعليم النواة قواعد خاصة به
17resolveReasoningOutputModeتحديد عقد خرج الاستدلال الأصلي أم الموسومعندما يحتاج المزوّد إلى استدلال موسوم/خرج نهائي بدلًا من الحقول الأصلية
18prepareExtraParamsتطبيع معلمات الطلب قبل أغلفة خيارات البث العامةعندما يحتاج المزوّد إلى معلمات طلب افتراضية أو تنظيف معلمات خاص به
19createStreamFnاستبدال مسار البث العادي بالكامل بنقل مخصصعندما يحتاج المزوّد إلى بروتوكول سلكي مخصص، لا مجرد غلاف
20wrapStreamFnغلاف للبث بعد تطبيق الأغلفة العامةعندما يحتاج المزوّد إلى أغلفة لترويسات/هيئة الطلب/توافق النموذج من دون نقل مخصص
21resolveTransportTurnStateإرفاق ترويسات أو بيانات وصفية أصلية لكل دور من النقلعندما يريد المزوّد أن ترسل وسائل النقل العامة هوية دور أصلية خاصة به
22resolveWebSocketSessionPolicyإرفاق ترويسات WebSocket أصلية أو سياسة تهدئة للجلسةعندما يريد المزوّد ضبط ترويسات الجلسة أو سياسة الرجوع في وسائل النقل العامة عبر WS
23formatApiKeyمنسق ملف تعريف المصادقة: يصبح الملف المخزن سلسلة apiKey لوقت التشغيلعندما يخزن المزوّد بيانات مصادقة إضافية ويحتاج إلى شكل رمز وقت تشغيل مخصص
24refreshOAuthتجاوز تحديث OAuth لنقاط تحديث مخصصة أو سياسة فشل التحديثعندما لا يناسب المزوّد محدّثات pi-ai المشتركة
25buildAuthDoctorHintتلميح إصلاح يُلحق عند فشل تحديث OAuthعندما يحتاج المزوّد إلى إرشاد إصلاح مصادقة مملوك له بعد فشل التحديث
26matchesContextOverflowErrorمطابق مملوك للمزوّد لخطأ تجاوز نافذة السياقعندما يملك المزوّد أخطاء تجاوز أولية قد تفوتها الاستدلالات العامة
27classifyFailoverReasonتصنيف سبب الرجوع المملوك للمزوّدعندما يستطيع المزوّد تحويل أخطاء API/النقل الأولية إلى تجاوز حد المعدل/الحمل الزائد/… إلخ
28isCacheTtlEligibleسياسة ذاكرة المطالبات المؤقتة لمزوّدي الوكلاء/النقل الخلفيعندما يحتاج المزوّد إلى بوابة TTL خاصة بالوكيل
29buildMissingAuthMessageبديل عن رسالة استرداد المصادقة المفقودة العامةعندما يحتاج المزوّد إلى تلميح استرداد خاص به عند فقدان المصادقة
30suppressBuiltInModelإخفاء النماذج العلوية القديمة مع تلميح خطأ اختياري للمستخدمعندما يحتاج المزوّد إلى إخفاء صفوف قديمة أو استبدالها بتلميح خاص به
31augmentModelCatalogصفوف فهرس اصطناعية/نهائية تُلحق بعد الاكتشافعندما يحتاج المزوّد إلى صفوف توافق أمامي اصطناعية في models list والمنتقيات
32isBinaryThinkingتبديل تشغيل/إيقاف للاستدلال لدى المزوّدين ثنائيي التفكيرعندما يكشف المزوّد تفكيرًا ثنائيًا تشغيل/إيقاف فقط
33supportsXHighThinkingدعم استدلال xhigh لنماذج محددةعندما يريد المزوّد xhigh لمجموعة فرعية من النماذج فقط
34resolveDefaultThinkingLevelمستوى /think الافتراضي لعائلة نماذج محددةعندما يملك المزوّد سياسة /think الافتراضية لعائلة نماذج
35isModernModelRefمطابق النماذج الحديثة لمرشحات الملفات الحية واختيار الاختبار الدخانيعندما يملك المزوّد مطابقة النماذج المفضلة الحية/الاختبارية
36prepareRuntimeAuthاستبدال بيانات اعتماد مهيأة بالرمز/المفتاح الفعلي وقت التشغيل قبل الاستدلال مباشرةًعندما يحتاج المزوّد إلى تبادل رمز أو بيانات اعتماد قصيرة العمر للطلب
37resolveUsageAuthحل بيانات اعتماد الاستخدام/الفوترة لـ /usage والأسطح المشابهةعندما يحتاج المزوّد إلى تحليل رمز استخدام/حصة مخصص أو بيانات اعتماد استخدام مختلفة
38fetchUsageSnapshotجلب لقطات الاستخدام/الحصة الخاصة بالمزوّد وتطبيعها بعد حل المصادقةعندما يحتاج المزوّد إلى نقطة نهاية استخدام أو محلل حمولة خاص به
39createEmbeddingProviderبناء مهايئ تضمين مملوك للمزوّد للذاكرة/البحثعندما ينتمي سلوك تضمين الذاكرة إلى إضافة المزوّد
40buildReplayPolicyإعادة سياسة إعادة تشغيل تتحكم في معالجة النصوص المسجلة للمزوّدعندما يحتاج المزوّد إلى سياسة نصوص مسجلة مخصصة (مثل إزالة كتل التفكير)
41sanitizeReplayHistoryإعادة كتابة سجل إعادة التشغيل بعد التنظيف العام للنصوص المسجلةعندما يحتاج المزوّد إلى إعادة كتابة خاصة به بعد مساعدات الضغط المشتركة
42validateReplayTurnsتحقق نهائي من أدوار إعادة التشغيل أو إعادة تشكيلها قبل المشغل المضمّنعندما يحتاج نقل المزوّد إلى تحقق أشد بعد التنظيف العام
43onModelSelectedتنفيذ آثار جانبية مملوكة للمزوّد بعد الاختيارعندما يحتاج المزوّد إلى قياس عن بُعد أو حالة مملوكة له عند تفعيل نموذج
تتحقق normalizeModelId وnormalizeTransport وnormalizeConfig أولًا من إضافة المزوّد المطابقة، ثم تنتقل إلى إضافات مزوّد أخرى قادرة على الخطافات إلى أن يغير أحدها فعليًا معرّف النموذج أو النقل/الإعدادات. وهذا يُبقي وسائط الأسماء البديلة/التوافق الخاصة بالمزوّدات تعمل من دون مطالبة المستدعي بمعرفة أي إضافة مضمّنة تملك إعادة الكتابة. وإذا لم يعِد أي خطاف مزوّد كتابة مدخل إعداد مدعوم من Google-family، فإن مطبّع إعدادات Google المضمّن يطبق تنظيف التوافق هذا على أي حال. إذا احتاج المزوّد إلى بروتوكول سلكي مخصص بالكامل أو منفذ طلبات مخصص، فهذه فئة مختلفة من الامتداد. هذه الخطافات مخصصة لسلوك المزوّد الذي ما يزال يعمل على حلقة الاستدلال العادية في OpenClaw.

مثال مزوّد

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);
  },
});

أمثلة مضمّنة

  • تستخدم Anthropic resolveDynamicModel وcapabilities وbuildAuthDoctorHint، وresolveUsageAuth، وfetchUsageSnapshot، وisCacheTtlEligible، وresolveDefaultThinkingLevel، وapplyConfigDefaults، وisModernModelRef، وwrapStreamFn لأنها تملك توافق Claude 4.6 المستقبلي، وتلميحات عائلة المزوّد، وإرشادات إصلاح المصادقة، وتكامل نقطة نهاية الاستخدام، وأهلية ذاكرة المطالبات المؤقتة، والقيم الافتراضية المعتمدة على المصادقة، وسياسة التفكير الافتراضية/التكيفية لـ Claude، وتشكيل البث الخاص بـ Anthropic للترويسات التجريبية و/fast / serviceTier وcontext1m.
  • تظل مساعدات البث الخاصة بـ Claude في Anthropic ضمن الفاصل العام api.ts / contract-api.ts الخاص بالإضافة المضمّنة في الوقت الحالي. ويصدّر سطح الحزمة هذا wrapAnthropicProviderStream وresolveAnthropicBetas و resolveAnthropicFastMode وresolveAnthropicServiceTier وبناة أغلفة Anthropic منخفضة المستوى بدلًا من توسيع SDK العام حول قواعد الترويسات التجريبية الخاصة بمزوّد واحد.
  • تستخدم OpenAI resolveDynamicModel وnormalizeResolvedModel و capabilities إضافةً إلى buildMissingAuthMessage وsuppressBuiltInModel و augmentModelCatalog وsupportsXHighThinking وisModernModelRef لأنها تملك توافق GPT-5.4 المستقبلي، والتطبيع المباشر لـ OpenAI openai-completions -> openai-responses، وتلميحات المصادقة المدركة لـ Codex، وإخفاء Spark، وصفوف قائمة OpenAI الاصطناعية، وسياسة التفكير/النماذج الحية لـ GPT-5؛ وتمتلك عائلة البث openai-responses-defaults أغلفة OpenAI Responses الأصلية المشتركة لترويسات الإسناد، و/fast/serviceTier، وإسهاب النص، والبحث الأصلي على الويب لـ Codex، وتشكيل حمولة توافق الاستدلال، وإدارة سياق Responses.
  • تستخدم OpenRouter catalog إضافةً إلى resolveDynamicModel و prepareDynamicModel لأن المزوّد تمريري وقد يكشف عن معرّفات نماذج جديدة قبل تحديث فهرس OpenClaw الثابت؛ كما يستخدم capabilities وwrapStreamFn وisCacheTtlEligible لإبقاء ترويسات الطلب الخاصة بالمزوّد، وبيانات التوجيه الوصفية، وترقيعات الاستدلال، وسياسة ذاكرة المطالبات المؤقتة خارج النواة. وتأتي سياسة إعادة التشغيل الخاصة به من عائلة passthrough-gemini، بينما تملك عائلة البث openrouter-thinking حقن الاستدلال الوكيل وتجاوزات النماذج غير المدعومة / auto.
  • يستخدم GitHub Copilot catalog وauth وresolveDynamicModel و capabilities إضافةً إلى prepareRuntimeAuth وfetchUsageSnapshot لأنه يحتاج إلى تسجيل دخول الجهاز المملوك للمزوّد، وسلوك الرجوع للنموذج، وخصائص النصوص المسجلة الخاصة بـ Claude، وتبادل رمز GitHub إلى رمز Copilot، ونقطة نهاية استخدام مملوكة للمزوّد.
  • يستخدم OpenAI Codex catalog وresolveDynamicModel، وnormalizeResolvedModel، وrefreshOAuth، وaugmentModelCatalog إضافةً إلى prepareExtraParams وresolveUsageAuth وfetchUsageSnapshot لأنه ما يزال يعمل على وسائل نقل OpenAI الأساسية لكنه يملك تطبيع النقل/عنوان الأساس، وسياسة رجوع تحديث OAuth، وخيار النقل الافتراضي، وصفوف فهرس Codex الاصطناعية، وتكامل نقطة نهاية استخدام ChatGPT؛ وهو يشارك عائلة البث openai-responses-defaults نفسها مع OpenAI المباشر.
  • يستخدم Google AI Studio وGemini CLI OAuth resolveDynamicModel، وbuildReplayPolicy، وsanitizeReplayHistory، وresolveReasoningOutputMode، وwrapStreamFn، وisModernModelRef لأن عائلة إعادة التشغيل google-gemini تملك الرجوع المستقبلي لـ Gemini 3.1، والتحقق الأصلي من إعادة تشغيل Gemini، وتنظيف إعادة التشغيل عند الإقلاع، ووضع خرج الاستدلال الموسوم، ومطابقة النماذج الحديثة، بينما تملك عائلة البث google-thinking تطبيع حمولة التفكير لـ Gemini؛ كما يستخدم Gemini CLI OAuth أيضًا formatApiKey وresolveUsageAuth و fetchUsageSnapshot لتنسيق الرموز وتحليل الرموز وربط نقطة نهاية الحصة.
  • يستخدم Anthropic Vertex buildReplayPolicy عبر عائلة إعادة التشغيل anthropic-by-model بحيث يبقى تنظيف إعادة التشغيل الخاص بـ Claude محصورًا في معرّفات Claude بدلًا من كل نقل anthropic-messages.
  • تستخدم Amazon Bedrock buildReplayPolicy وmatchesContextOverflowError، وclassifyFailoverReason، وresolveDefaultThinkingLevel لأنها تملك تصنيف أخطاء Bedrock الخاصة بتجاوز الحمل/عدم الجاهزية/تجاوز السياق لحركة Anthropic-on-Bedrock؛ ومع ذلك تظل سياسة إعادة التشغيل لديها مشتركة مع حاجز anthropic-by-model الخاص بـ Claude فقط.
  • تستخدم OpenRouter وKilocode وOpencode وOpencode Go buildReplayPolicy عبر عائلة إعادة التشغيل passthrough-gemini لأنها توكّل نماذج Gemini عبر وسائل نقل متوافقة مع OpenAI وتحتاج إلى تنظيف thought-signature الخاص بـ Gemini من دون تحقق إعادة تشغيل Gemini الأصلي أو إعادة كتابة الإقلاع.
  • يستخدم MiniMax buildReplayPolicy عبر عائلة إعادة التشغيل hybrid-anthropic-openai لأن مزوّدًا واحدًا يملك دلالات رسائل Anthropic والدلالات المتوافقة مع OpenAI معًا؛ وهو يبقي إسقاط كتل التفكير الخاصة بـ Claude على جانب Anthropic فقط مع إعادة تجاوز وضع خرج الاستدلال إلى الوضع الأصلي، بينما تملك عائلة البث minimax-fast-mode إعادة كتابة نماذج fast-mode على مسار البث المشترك.
  • يستخدم Moonshot catalog إضافةً إلى wrapStreamFn لأنه ما يزال يستخدم نقل OpenAI المشترك لكنه يحتاج إلى تطبيع حمولة التفكير المملوك للمزوّد؛ وتقوم عائلة البث moonshot-thinking بربط الإعدادات وحالة /think بحمولة التفكير الثنائية الأصلية الخاصة به.
  • يستخدم Kilocode catalog وcapabilities وwrapStreamFn و isCacheTtlEligible لأنه يحتاج إلى ترويسات طلب مملوكة للمزوّد، وتطبيع حمولة الاستدلال، وتلميحات نصوص Gemini المسجلة، وبوابة TTL لذاكرة Anthropic؛ وتُبقي عائلة البث kilocode-thinking حقن تفكير Kilo على مسار البث الوكيل المشترك مع تجاوز kilo/auto و معرّفات النماذج الوكيلة الأخرى التي لا تدعم حمولات الاستدلال الصريحة.
  • يستخدم Z.AI resolveDynamicModel وprepareExtraParams وwrapStreamFn، وisCacheTtlEligible، وisBinaryThinking، وisModernModelRef، وresolveUsageAuth، وfetchUsageSnapshot لأنه يملك الرجوع لـ GLM-5، والإعدادات الافتراضية لـ tool_stream، وتجربة التفكير الثنائية، ومطابقة النماذج الحديثة، ومصادقة الاستخدام + جلب الحصة؛ وتُبقي عائلة البث tool-stream-default-on غلاف tool_stream الافتراضي خارج الترابط اليدوي لكل مزوّد.
  • تستخدم xAI normalizeResolvedModel وnormalizeTransport، وcontributeResolvedModelCompat، وprepareExtraParams، وwrapStreamFn، وresolveSyntheticAuth، وresolveDynamicModel، وisModernModelRef لأنها تملك تطبيع نقل xAI Responses الأصلي، وإعادة كتابة الأسماء البديلة لوضع Grok السريع، وtool_stream الافتراضي، وتنظيف الأدوات الصارمة / حمولة الاستدلال، وإعادة استخدام المصادقة الاحتياطية للأدوات المملوكة للإضافة، وحل نماذج Grok المتوافق مستقبلًا، وترقيعات التوافق المملوكة للمزوّد مثل ملف تعريف مخطط أدوات xAI، والكلمات المفتاحية غير المدعومة في المخطط، وweb_search الأصلي، وفك ترميز وسائط استدعاء الأدوات ذات كيانات HTML.
  • تستخدم Mistral وOpenCode Zen وOpenCode Go capabilities فقط لإبقاء خصائص النصوص المسجلة/الأدوات خارج النواة.
  • تستخدم مزوّدات الحزم المضمّنة المعتمدة على الفهرس فقط مثل byteplus وcloudflare-ai-gateway و huggingface وkimi-coding وnvidia وqianfan و synthetic وtogether وvenice وvercel-ai-gateway وvolcengine الخطاف catalog فقط.
  • تستخدم Qwen catalog لمزوّد النص الخاص بها إضافةً إلى تسجيلات فهم الوسائط وتوليد الفيديو المشتركة لأسطحها متعددة الوسائط.
  • تستخدم MiniMax وXiaomi catalog إضافةً إلى خطافات الاستخدام لأن سلوك /usage خاص بهما حتى مع استمرار تشغيل الاستدلال عبر وسائل النقل المشتركة.

مساعدات وقت التشغيل

يمكن للإضافات الوصول إلى مساعدات أساسية محددة عبر api.runtime. وبالنسبة إلى TTS:
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 حمولة خرج TTS الأساسية العادية لأسطح الملفات/الملاحظات الصوتية.
  • يستخدم إعدادات messages.tts الأساسية واختيار المزوّد.
  • يعيد مخزن PCM الصوتي + معدل العينة. ويجب على الإضافات إعادة المعايرة/الترميز للمزوّدات.
  • يكون listVoices اختياريًا لكل مزوّد. استخدمه لمنتقيات الصوت أو تدفقات الإعداد المملوكة للمورّد.
  • يمكن أن تتضمن قوائم الأصوات بيانات وصفية أغنى مثل اللغة والمنطقة والنوع وعلامات الشخصية لمنتقيات مدركة للمزوّد.
  • يدعم OpenAI وElevenLabs الهاتف اليوم. ولا تدعم Microsoft ذلك.
يمكن للإضافات أيضًا تسجيل مزوّدي الكلام عبر 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,
    };
  },
});
ملاحظات:
  • أبقِ سياسة TTS، والرجوع، وتسليم الرد في النواة.
  • استخدم مزوّدي الكلام لسلوك التوليف المملوك للمورّد.
  • يُطبَّع الإدخال القديم edge الخاص بـ Microsoft إلى معرّف المزوّد microsoft.
  • نموذج الملكية المفضل موجّه للشركة: يمكن لإضافة مورّد واحدة أن تملك مزوّدي النص والكلام والصورة والوسائط المستقبلية مع إضافة OpenClaw عقود تلك القدرات.
بالنسبة إلى فهم الصورة/الصوت/الفيديو، تسجّل الإضافات مزوّدًا واحدًا مكتوب النوع لفهم الوسائط بدلًا من حقيبة مفاتيح/قيم عامة:
api.registerMediaUnderstandingProvider({
  id: "google",
  capabilities: ["image", "audio", "video"],
  describeImage: async (req) => ({ text: "..." }),
  transcribeAudio: async (req) => ({ text: "..." }),
  describeVideo: async (req) => ({ text: "..." }),
});
ملاحظات:
  • أبقِ التنسيق، والرجوع، والإعدادات، وربط القنوات في النواة.
  • أبقِ سلوك المورّد في إضافة المزوّد.
  • يجب أن يبقى التوسع الإضافي مكتوب النوع: أساليب اختيارية جديدة، وحقول نتائج اختيارية جديدة، وقدرات اختيارية جديدة.
  • ويتبع توليد الفيديو النمط نفسه بالفعل:
    • تملك النواة عقد القدرة ومساعد وقت التشغيل
    • تسجل إضافات المورّدين api.registerVideoGenerationProvider(...)
    • تستهلك إضافات الميزات/القنوات api.runtime.videoGeneration.*
وبالنسبة إلى مساعدات وقت تشغيل فهم الوسائط، يمكن للإضافات استدعاء:
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,
});
وبالنسبة إلى نسخ الصوت، يمكن للإضافات استخدام وقت تشغيل فهم الوسائط أو الاسم البديل الأقدم لـ 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.* هو السطح المشترك المفضل من أجل فهم الصورة/الصوت/الفيديو.
  • يستخدم إعدادات الصوت الأساسية لفهم الوسائط (tools.media.audio) وترتيب الرجوع بين المزوّدين.
  • يعيد { text: undefined } عندما لا يُنتج خرج نسخ (مثل الإدخال المتجاوز/غير المدعوم).
  • يبقى api.runtime.stt.transcribeAudioFile(...) اسمًا بديلًا للتوافق.
يمكن للإضافات أيضًا إطلاق تشغيلات وكيل فرعي في الخلفية عبر 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 حقول التجاوز هذه إلا للجهات المستدعية الموثوقة.
  • لتشغيلات الرجوع المملوكة للإضافة، يجب على المشغلين تفعيل plugins.entries.<id>.subagent.allowModelOverride: true.
  • استخدم plugins.entries.<id>.subagent.allowedModels لتقييد الإضافات الموثوقة إلى أهداف provider/model قانونية محددة، أو "*" للسماح الصريح بأي هدف.
  • ما تزال تشغيلات الوكيل الفرعي غير الموثوقة تعمل، لكن طلبات التجاوز تُرفض بدلًا من الرجوع الصامت.
وبالنسبة إلى البحث على الويب، يمكن للإضافات استهلاك مساعد وقت التشغيل المشترك بدلًا من الوصول إلى ربط أداة الوكيل:
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,
  },
});
يمكن للإضافات أيضًا تسجيل مزوّدي البحث على الويب عبر api.registerWebSearchProvider(...). ملاحظات:
  • أبقِ اختيار المزوّد، وحل بيانات الاعتماد، ودلالات الطلب المشتركة في النواة.
  • استخدم مزوّدي البحث على الويب لوسائل النقل الخاصة بالمورّد.
  • api.runtime.webSearch.* هو السطح المشترك المفضل لإضافات الميزات/القنوات التي تحتاج إلى سلوك البحث من دون الاعتماد على غلاف أداة الوكيل.

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(...): عرض مزوّدي توليد الصور المتاحين وقدراتهم.

مسارات Gateway HTTP

يمكن للإضافات كشف نقاط نهاية 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" للمصادقة التي تديرها الإضافة/للتحقق من webhook.
  • match: اختياري. "exact" (الافتراضي) أو "prefix".
  • replaceExisting: اختياري. يسمح للإضافة نفسها باستبدال تسجيل مسار موجود خاص بها.
  • handler: أعِد true عندما يكون المسار قد عالج الطلب.
ملاحظات:
  • تمت إزالة api.registerHttpHandler(...) وسيؤدي إلى خطأ عند تحميل الإضافة. استخدم api.registerHttpRoute(...) بدلًا منه.
  • يجب أن تصرّح مسارات الإضافات عن auth صراحةً.
  • تُرفض تعارضات path + match الدقيقة ما لم يكن replaceExisting: true، ولا يمكن لإضافة أن تستبدل مسارًا لإضافة أخرى.
  • تُرفض المسارات المتداخلة التي لها مستويات auth مختلفة. أبقِ سلاسل السقوط exact/prefix على مستوى المصادقة نفسه فقط.
  • لا تستقبل مسارات auth: "plugin" نطاقات وقت تشغيل المشغل تلقائيًا. فهي مخصصة لـ webhook/التحقق من التوقيع الذي تديره الإضافة، لا لاستدعاءات مساعدات Gateway المميّزة.
  • تعمل مسارات auth: "gateway" داخل نطاق وقت تشغيل طلب Gateway، لكن هذا النطاق محافظ عمدًا:
    • تبقي مصادقة حامل الرمز بالسر المشترك (gateway.auth.mode = "token" / "password") نطاقات وقت تشغيل مسارات الإضافات مثبتة على operator.write، حتى لو أرسل المستدعي x-openclaw-scopes
    • تكرّم أوضاع HTTP الموثوقة الحاملة للهوية (مثل trusted-proxy أو gateway.auth.mode = "none" على مدخل خاص) قيمة x-openclaw-scopes فقط عندما يكون هذا الترويس حاضرًا صراحةً
    • إذا غاب x-openclaw-scopes في طلبات مسارات الإضافات الحاملة للهوية، يعود نطاق وقت التشغيل إلى operator.write
  • القاعدة العملية: لا تفترض أن مسار إضافة بمصادقة البوابة هو سطح إدارة ضمني. إذا احتاج مسارك إلى سلوك خاص بالمدير فقط، فاطلب وضع مصادقة حاملًا للهوية ووثّق عقد ترويسة x-openclaw-scopes الصريحة.

مسارات استيراد Plugin SDK

استخدم المسارات الفرعية لـ SDK بدلًا من الاستيراد الأحادي openclaw/plugin-sdk عند تأليف الإضافات:
  • openclaw/plugin-sdk/plugin-entry من أجل بدائيات تسجيل الإضافات.
  • openclaw/plugin-sdk/core من أجل العقد العامة المشتركة المواجهة للإضافات.
  • openclaw/plugin-sdk/config-schema من أجل تصدير مخطط Zod الجذر openclaw.json (OpenClawSchema).
  • بدائيات القنوات المستقرة مثل openclaw/plugin-sdk/channel-setup، وopenclaw/plugin-sdk/setup-runtime، وopenclaw/plugin-sdk/setup-adapter-runtime، وopenclaw/plugin-sdk/setup-tools، وopenclaw/plugin-sdk/channel-pairing، وopenclaw/plugin-sdk/channel-contract، وopenclaw/plugin-sdk/channel-feedback، وopenclaw/plugin-sdk/channel-inbound، وopenclaw/plugin-sdk/channel-lifecycle، وopenclaw/plugin-sdk/channel-reply-pipeline، وopenclaw/plugin-sdk/command-auth، وopenclaw/plugin-sdk/secret-input، و openclaw/plugin-sdk/webhook-ingress من أجل ربط الإعداد/المصادقة/الرد/الويب هوك المشترك. ويُعد channel-inbound الموطن المشترك لإزالة الارتداد، ومطابقة الإشارات، وتنسيق الأظرفة، ومساعدات سياق الظرف الوارد. وchannel-setup هو فاصل الإعداد الضيق للتثبيت الاختياري. وsetup-runtime هو سطح الإعداد الآمن لوقت التشغيل المستخدم بواسطة setupEntry / البدء المؤجل، بما في ذلك مهايئات ترقيع الإعداد الآمنة للاستيراد. وsetup-adapter-runtime هو فاصل مهايئ إعداد الحساب المدرك للبيئة. وsetup-tools هو فاصل المساعدة الصغير لـ CLI/الأرشيف/الوثائق (formatCliCommand, detectBinary, extractArchive, resolveBrewExecutable, formatDocsLink, CONFIG_DIR).
  • المسارات الفرعية للمجالات مثل openclaw/plugin-sdk/channel-config-helpers، وopenclaw/plugin-sdk/allow-from، وopenclaw/plugin-sdk/channel-config-schema، وopenclaw/plugin-sdk/telegram-command-config، وopenclaw/plugin-sdk/channel-policy، وopenclaw/plugin-sdk/approval-runtime، وopenclaw/plugin-sdk/config-runtime، وopenclaw/plugin-sdk/infra-runtime، وopenclaw/plugin-sdk/agent-runtime، وopenclaw/plugin-sdk/lazy-runtime، وopenclaw/plugin-sdk/reply-history، وopenclaw/plugin-sdk/routing، وopenclaw/plugin-sdk/status-helpers، وopenclaw/plugin-sdk/text-runtime، وopenclaw/plugin-sdk/runtime-store، و openclaw/plugin-sdk/directory-runtime من أجل مساعدات وقت التشغيل/الإعدادات المشتركة. ويُعد telegram-command-config الفاصل العام الضيق من أجل تطبيع/التحقق من أوامر Telegram المخصصة، ويظل متاحًا حتى إذا كان سطح عقد Telegram المضمّن غير متاح مؤقتًا. ويُعد text-runtime الفاصل المشترك للنص/Markdown/السجل، بما في ذلك إزالة النص المرئي للمساعد، ومساعدات عرض/تجزئة Markdown، ومساعدات الإخفاء، ومساعدات علامات التوجيه، وأدوات النص الآمن.
  • ينبغي للفواصل الخاصة بالموافقات في القنوات أن تفضّل عقد approvalCapability واحدًا على الإضافة. ثم تقرأ النواة سلوك المصادقة والتسليم والعرض والتوجيه الأصلي للموافقات من خلال تلك القدرة الواحدة بدلًا من خلط سلوك الموافقات في حقول إضافة غير ذات صلة.
  • openclaw/plugin-sdk/channel-runtime قديم ويظل فقط كطبقة توافق للإضافات الأقدم. ويجب على الشيفرة الجديدة استيراد البدائيات العامة الأضيق بدلًا منه، ويجب ألا تضيف شيفرة المستودع استيرادات جديدة من هذه الطبقة.
  • تظل الأجزاء الداخلية للامتدادات المضمّنة خاصة. وينبغي للإضافات الخارجية استخدام مسارات openclaw/plugin-sdk/* الفرعية فقط. ويمكن لشيفرة/اختبارات نواة OpenClaw استخدام نقاط الإدخال العامة على مستوى جذر حزمة الإضافة مثل index.js وapi.js و runtime-api.js وsetup-entry.js والملفات الضيقة النطاق مثل login-qr-api.js. لا تستورد أبدًا src/* الخاص بحزمة إضافة من النواة أو من امتداد آخر.
  • تقسيم نقطة الإدخال في المستودع: <plugin-package-root>/api.js هي حاوية المساعدات/الأنواع، و<plugin-package-root>/runtime-api.js هي حاوية وقت التشغيل فقط، و<plugin-package-root>/index.js هي مدخل الإضافة المضمّنة، و<plugin-package-root>/setup-entry.js هو مدخل إضافة الإعداد.
  • أمثلة مزوّدين مضمّنين حاليين:
    • تستخدم Anthropic api.js / contract-api.js لمساعدات بث Claude مثل wrapAnthropicProviderStream، ومساعدات الترويسات التجريبية، وتحليل service_tier.
    • تستخدم OpenAI api.js لبناة المزوّد، ومساعدات النموذج الافتراضي، وبناة المزوّد اللحظي.
    • تستخدم OpenRouter api.js لباني المزوّد الخاص بها إضافةً إلى مساعدات التجهيز/الإعدادات، بينما يمكن لـ register.runtime.js أن يعيد تصدير مساعدات plugin-sdk/provider-stream العامة للاستخدام المحلي في المستودع.
  • تفضّل نقاط الإدخال العامة المحمّلة عبر الواجهة اللقطة النشطة لإعدادات وقت التشغيل عند وجودها، ثم تعود إلى ملف الإعدادات المحلول على القرص عندما لا يكون OpenClaw قد بدأ بعد في تقديم لقطة وقت تشغيل.
  • تظل البدائيات العامة المشتركة هي العقدة العامة المفضلة لـ SDK. وما تزال مجموعة توافقية صغيرة محفوظة من فواصل المساعدة الموسومة بعلامات القنوات المضمّنة موجودة. تعامل مع هذه الفواصل على أنها فواصل صيانة/توافق للإضافات المضمّنة، لا أهداف استيراد جديدة لطرف ثالث؛ ويجب أن تهبط العقود المشتركة الجديدة بين القنوات على مسارات plugin-sdk/* العامة أو في حاويات api.js / runtime-api.js المحلية للإضافة.
ملاحظة توافق:
  • تجنب الحاوية الجذرية openclaw/plugin-sdk في الشيفرة الجديدة.
  • فضّل أولًا البدائيات المستقرة الضيقة. فالمسارات الفرعية الأحدث للإعداد/الربط/الرد/ الملاحظات/العقد/الوارد/الترابط/الأوامر/المدخلات السرية/الويب هوك/البنية/ قائمة السماح/الحالة/أداة الرسائل هي العقد المقصودة للعمل الجديد في الإضافات المضمّنة والخارجية. ويجب أن يكون تحليل/مطابقة الأهداف على openclaw/plugin-sdk/channel-targets. وتنتمي بوابات إجراءات الرسائل ومساعدات معرّفات رسائل التفاعل إلى openclaw/plugin-sdk/channel-actions.
  • حاويات المساعدة الخاصة بالامتدادات المضمّنة ليست مستقرة افتراضيًا. إذا كانت المساعدة مطلوبة فقط لامتداد مضمّن، فأبقها خلف الفاصل المحلي api.js أو runtime-api.js الخاص بالامتداد بدلًا من ترقيتها إلى openclaw/plugin-sdk/<extension>.
  • يجب أن تكون فواصل المساعدة المشتركة الجديدة عامة، لا موسومة باسم قناة. وينتمي تحليل الأهداف المشترك إلى openclaw/plugin-sdk/channel-targets؛ بينما تبقى الأجزاء الداخلية الخاصة بالقناة خلف الفاصل المحلي api.js أو runtime-api.js للإضافة المالكة.
  • توجد مسارات فرعية خاصة بالقدرات مثل image-generation، وmedia-understanding، وspeech لأن الإضافات المضمّنة/الأصلية تستخدمها اليوم. ولا يعني وجودها بحد ذاته أن كل مساعد مُصدَّر هو عقد خارجي طويل الأمد ومجمّد.

مخططات أداة الرسائل

ينبغي أن تملك الإضافات مساهمات مخطط describeMessageTool(...) الخاصة بالقناة. وأبقِ الحقول الخاصة بالمزوّد داخل الإضافة، لا في النواة المشتركة. بالنسبة إلى أجزاء المخطط المحمولة المشتركة، أعد استخدام المساعدات العامة المصدَّرة عبر openclaw/plugin-sdk/channel-actions:
  • createMessageToolButtonsSchema() لحمولات بأسلوب شبكة الأزرار
  • createMessageToolCardSchema() لحمولات البطاقات المنظمة
إذا كان شكل مخطط ما منطقيًا فقط لمزوّد واحد، فعرّفه في المصدر الخاص بتلك الإضافة بدلًا من ترقيته إلى SDK المشترك.

حل أهداف القنوات

ينبغي أن تملك إضافات القنوات دلالات الأهداف الخاصة بالقناة. وأبقِ مضيف الإرسال الخارجي عامًا واستخدم سطح مهايئ المراسلة لقواعد المزوّد:
  • يحدد messaging.inferTargetChatType({ to }) ما إذا كان يجب التعامل مع هدف مُطبَّع على أنه direct أو group أو channel قبل البحث في الدليل.
  • يحدد messaging.targetResolver.looksLikeId(raw, normalized) للنواة ما إذا كان يجب على الإدخال تجاوز البحث والذهاب مباشرةً إلى الحل الشبيه بالمعرّف.
  • تمثل messaging.targetResolver.resolveTarget(...) الرجوع الخاص بالإضافة عندما تحتاج النواة إلى حل نهائي مملوك للمزوّد بعد التطبيع أو بعد إخفاق الدليل.
  • تملك messaging.resolveOutboundSessionRoute(...) إنشاء مسار الجلسة الخاص بالمزوّد بعد حل الهدف.
التقسيم الموصى به:
  • استخدم inferTargetChatType لقرارات الفئة التي يجب أن تحدث قبل البحث في الأقران/المجموعات.
  • استخدم looksLikeId لفحوصات “تعامل مع هذا على أنه معرّف هدف صريح/أصلي”.
  • استخدم resolveTarget للرجوع الخاص بالمزوّد في التطبيع، لا للبحث الواسع في الدليل.
  • أبقِ المعرّفات الأصلية للمزوّد مثل معرّفات الدردشة والخيوط وJIDs والمعرّفات اليدوية ومعرّفات الغرف داخل قيَم target أو المعلمات الخاصة بالمزوّد، لا في حقول SDK العامة.

الأدلة المعتمدة على الإعدادات

ينبغي للإضافات التي تستمد مدخلات الدليل من الإعدادات أن تُبقي هذا المنطق في الإضافة وأن تعيد استخدام المساعدات المشتركة من openclaw/plugin-sdk/directory-runtime. استخدم هذا عندما تحتاج القناة إلى أقران/مجموعات معتمدة على الإعدادات مثل:
  • أقران الرسائل المباشرة المعتمدين على قائمة السماح
  • خرائط القنوات/المجموعات المهيأة
  • بدائل دليل ثابتة على مستوى الحساب
تتعامل المساعدات المشتركة في directory-runtime فقط مع العمليات العامة:
  • ترشيح الاستعلامات
  • تطبيق الحدود
  • مساعدات إزالة التكرار/التطبيع
  • بناء ChannelDirectoryEntry[]
يجب أن يبقى فحص الحسابات الخاص بالقناة وتطبيع المعرّفات ضمن تنفيذ الإضافة.

فهارس المزوّدين

يمكن لإضافات المزوّدين تعريف فهارس نماذج للاستدلال باستخدام registerProvider({ catalog: { run(...) { ... } } }). يعيد catalog.run(...) الشكل نفسه الذي يكتبه OpenClaw في models.providers:
  • { provider } لمدخل مزوّد واحد
  • { providers } لعدة مداخل مزوّدين
استخدم catalog عندما تملك الإضافة معرّفات نماذج خاصة بالمزوّد، أو قيم base URL افتراضية، أو بيانات وصفية للنماذج مقيدة بالمصادقة. يتحكم catalog.order في توقيت دمج فهرس الإضافة نسبةً إلى المزوّدين الضمنيين المضمّنين في OpenClaw:
  • simple: مزوّدون عاديون يعتمدون على مفتاح API أو البيئة
  • profile: مزوّدون يظهرون عند وجود ملفات تعريف للمصادقة
  • paired: مزوّدون يصنعون عدة مداخل مزوّد مترابطة
  • late: المرور الأخير، بعد المزوّدين الضمنيين الآخرين
يفوز المزوّد اللاحق عند تعارض المفتاح، لذا يمكن للإضافات عمدًا تجاوز مدخل مزوّد مضمّن يحمل معرّف المزوّد نفسه. التوافق:
  • ما يزال discovery يعمل كاسم بديل قديم
  • إذا تم تسجيل كل من catalog وdiscovery، يستخدم OpenClaw catalog

فحص القنوات للقراءة فقط

إذا كانت إضافتك تسجل قناة، ففضّل تنفيذ plugin.config.inspectAccount(cfg, accountId) إلى جانب resolveAccount(...). السبب:
  • resolveAccount(...) هو مسار وقت التشغيل. ويُسمح له بافتراض أن بيانات الاعتماد قد تجسدت بالكامل ويمكن أن يفشل سريعًا عندما تكون الأسرار المطلوبة مفقودة.
  • لا يجب أن تحتاج مسارات الأوامر للقراءة فقط مثل openclaw status وopenclaw status --all، وopenclaw channels status، وopenclaw channels resolve، وتدفقات doctor/config repair إلى تجسيد بيانات اعتماد وقت التشغيل فقط لوصف الإعدادات.
السلوك الموصى به لـ inspectAccount(...):
  • أعِد حالة الحساب الوصفية فقط.
  • حافظ على enabled وconfigured.
  • ضمّن حقول مصدر/حالة بيانات الاعتماد عند الصلة، مثل:
    • tokenSource, tokenStatus
    • botTokenSource, botTokenStatus
    • appTokenSource, appTokenStatus
    • signingSecretSource, signingSecretStatus
  • لا تحتاج إلى إعادة قيَم الرموز الأولية فقط للإبلاغ عن التوافر للقراءة فقط. تكفي إعادة tokenStatus: "available" (وحقل المصدر المطابق) لأوامر نمط الحالة.
  • استخدم configured_unavailable عندما تكون بيانات الاعتماد مهيأة عبر SecretRef لكنها غير متاحة في مسار الأمر الحالي.
وهذا يسمح للأوامر للقراءة فقط بالإبلاغ عن “مهيأ لكنه غير متاح في مسار الأمر هذا” بدلًا من التعطل أو الإبلاغ الخاطئ بأن الحساب غير مهيأ.

حزم الحزم

يمكن أن يتضمن دليل الإضافة ملف package.json مع openclaw.extensions:
{
  "name": "my-pack",
  "openclaw": {
    "extensions": ["./src/safety.ts", "./src/tools.ts"],
    "setupEntry": "./src/setup-entry.ts"
  }
}
يصبح كل مدخل إضافة. وإذا كانت الحزمة تسرد عدة امتدادات، يصبح معرّف الإضافة name/<fileBase>. إذا كانت إضافتك تستورد تبعيات npm، فثبّتها في ذلك الدليل حتى يتوفر node_modules (npm install / pnpm install). حاجز أمني: يجب أن يبقى كل مدخل في openclaw.extensions داخل دليل الإضافة بعد حل الروابط الرمزية. وتُرفض المداخل التي تخرج من دليل الحزمة. ملاحظة أمنية: يثبّت openclaw plugins install تبعيات الإضافة باستخدام npm install --omit=dev --ignore-scripts (من دون نصوص دورة حياة، ومن دون تبعيات تطوير وقت التشغيل). أبقِ أشجار تبعيات الإضافات “JavaScript/TypeScript خالصة” وتجنب الحزم التي تتطلب بناء postinstall. اختياري: يمكن أن يشير openclaw.setupEntry إلى وحدة خفيفة خاصة بالإعداد فقط. عندما يحتاج OpenClaw إلى أسطح إعداد لقناة معطلة، أو عندما تكون إضافة القناة مفعّلة لكنها ما تزال غير مهيأة، فإنه يحمّل setupEntry بدلًا من مدخل الإضافة الكامل. وهذا يُبقي بدء التشغيل والإعداد أخف عندما يكون مدخل الإضافة الرئيسي يربط أيضًا أدوات أو خطافات أو شيفرة أخرى خاصة بوقت التشغيل فقط. اختياري: يمكن لـ openclaw.startup.deferConfiguredChannelFullLoadUntilAfterListen إدخال إضافة القناة إلى مسار setupEntry نفسه خلال مرحلة بدء التشغيل السابقة للاستماع في البوابة، حتى عندما تكون القناة مهيأة بالفعل. استخدم هذا فقط عندما يغطي setupEntry بالكامل سطح بدء التشغيل الذي يجب أن يوجد قبل أن تبدأ البوابة بالاستماع. وعمليًا، يعني ذلك أن مدخل الإعداد يجب أن يسجل كل قدرة تملكها القناة ويعتمد عليها بدء التشغيل، مثل:
  • تسجيل القناة نفسها
  • أي مسارات HTTP يجب أن تكون متاحة قبل بدء استماع البوابة
  • أي أساليب Gateway أو أدوات أو خدمات يجب أن تكون موجودة خلال النافذة الزمنية نفسها
إذا كان مدخلك الكامل ما يزال يملك أي قدرة مطلوبة عند بدء التشغيل، فلا تفعّل هذا العلم. وأبقِ الإضافة على السلوك الافتراضي ودع OpenClaw يحمّل المدخل الكامل أثناء بدء التشغيل. يمكن للقنوات المضمّنة أيضًا نشر مساعدات سطح عقد خاصة بالإعداد فقط يمكن للنواة الرجوع إليها قبل تحميل وقت تشغيل القناة الكامل. وسطح ترقية الإعداد الحالي هو:
  • singleAccountKeysToMove
  • namedAccountPromotionKeys
  • resolveSingleAccountPromotionTarget(...)
تستخدم النواة هذا السطح عندما تحتاج إلى ترقية إعداد قناة قديم بحساب واحد إلى channels.<id>.accounts.* من دون تحميل مدخل الإضافة الكامل. وMatrix هو المثال المضمّن الحالي: إذ ينقل فقط مفاتيح المصادقة/الإقلاع إلى حساب مرقّى مسمى عندما تكون الحسابات المسماة موجودة بالفعل، ويمكنه الحفاظ على مفتاح حساب افتراضي غير قانوني ومهيأ بدلًا من إنشاء accounts.default دائمًا. تُبقي مهايئات ترقيع الإعداد هذه اكتشاف سطح العقد المضمّن كسولًا. ويظل زمن الاستيراد خفيفًا؛ إذ يُحمَّل سطح الترقية عند أول استخدام فقط بدلًا من إعادة الدخول إلى بدء تشغيل القناة المضمّنة عند استيراد الوحدة. عندما تتضمن أسطح بدء التشغيل هذه أساليب Gateway RPC، أبقها على بادئة خاصة بالإضافة. وتظل مساحات أسماء الإدارة الأساسية (config.*، exec.approvals.*، wizard.*، update.*) محجوزة وتُحل دائمًا إلى operator.admin، حتى لو طلبت إضافة نطاقًا أضيق. مثال:
{
  "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: معرّفات إضافات/قنوات أقل أولوية ينبغي أن يتقدم عليها هذا المدخل في الفهرس
  • selectionDocsPrefix, selectionDocsOmitLabel, selectionExtras: عناصر تحكم النص لسطح الاختيار
  • markdownCapable: يحدد أن القناة قادرة على Markdown لقرارات التنسيق الخارجي
  • showConfigured: إخفاء القناة من أسطح سرد القنوات المهيأة عند ضبطها على false
  • quickstartAllowFrom: إدخال القناة في تدفق allowFrom القياسي للبداية السريعة
  • forceAccountBinding: فرض الربط الصريح للحساب حتى عند وجود حساب واحد فقط
  • 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".

إضافات محرك السياق

تملك إضافات محرك السياق تنسيق سياق الجلسة للإدخال والتجميع والضغط. سجّلها من إضافتك باستخدام api.registerContextEngine(id, factory)، ثم اختر المحرك النشط باستخدام plugins.slots.contextEngine. استخدم هذا عندما تحتاج إضافتك إلى استبدال خط أنابيب السياق الافتراضي أو توسيعه بدلًا من مجرد إضافة بحث ذاكرة أو خطافات.
export default function (api) {
  api.registerContextEngine("lossless-claw", () => ({
    info: { id: "lossless-claw", name: "Lossless Claw", ownsCompaction: true },
    async ingest() {
      return { ingested: true };
    },
    async assemble({ messages }) {
      return { messages, estimatedTokens: 0 };
    },
    async compact() {
      return { ok: true, compacted: false };
    },
  }));
}
إذا كان محركك لا يملك خوارزمية الضغط، فأبقِ compact() منفذًا وفوّضه صراحةً:
import { delegateCompactionToRuntime } from "openclaw/plugin-sdk/core";

export default function (api) {
  api.registerContextEngine("my-memory-engine", () => ({
    info: {
      id: "my-memory-engine",
      name: "My Memory Engine",
      ownsCompaction: false,
    },
    async ingest() {
      return { ingested: true };
    },
    async assemble({ messages }) {
      return { messages, estimatedTokens: 0 };
    },
    async compact(params) {
      return await delegateCompactionToRuntime(params);
    },
  }));
}

إضافة قدرة جديدة

عندما تحتاج إضافة إلى سلوك لا يناسب الواجهة الحالية، لا تتجاوز نظام الإضافات بوصول خاص. بل أضف القدرة المفقودة. التسلسل الموصى به:
  1. تعريف العقد الأساسي حدّد السلوك المشترك الذي ينبغي أن تملكه النواة: السياسة، والرجوع، ودمج الإعدادات، ودورة الحياة، والدلالات المواجهة للقناة، وشكل مساعد وقت التشغيل.
  2. إضافة أسطح تسجيل/وقت تشغيل للإضافات مكتوبة النوع وسّع OpenClawPluginApi و/أو api.runtime بأصغر سطح قدرة مكتوب النوع ومفيد.
  3. ربط المستهلكين في النواة + القنوات/الميزات يجب أن تستهلك القنوات وإضافات الميزات القدرة الجديدة من خلال النواة، لا عبر استيراد تنفيذ مورّد مباشرةً.
  4. تسجيل تنفيذات المورّدين ثم تسجل إضافات المورّدين واجهاتها الخلفية مقابل القدرة.
  5. إضافة تغطية للعقود أضف اختبارات حتى تبقى الملكية وشكل التسجيل صريحين مع مرور الوقت.
وهكذا يبقى OpenClaw محدد الرأي من دون أن يصبح مشفرًا مباشرةً على رؤية مزوّد واحد للعالم. راجع كتاب طبخ القدرات للحصول على قائمة تحقق عملية للملفات ومثال تطبيقي.

قائمة تحقق القدرة

عند إضافة قدرة جديدة، يجب أن يلمس التنفيذ عادةً هذه الأسطح معًا:
  • أنواع العقود الأساسية في src/<capability>/types.ts
  • مساعد التشغيل/وقت التشغيل الأساسي في src/<capability>/runtime.ts
  • سطح تسجيل واجهة الإضافة في src/plugins/types.ts
  • ربط سجل الإضافات في src/plugins/registry.ts
  • كشف وقت تشغيل الإضافة في src/plugins/runtime/* عندما تحتاج إضافات الميزات/القنوات إلى استهلاكه
  • مساعدات الالتقاط/الاختبار في src/test-utils/plugin-registration.ts
  • تأكيدات الملكية/العقود في src/plugins/contracts/registry.ts
  • وثائق المشغل/الإضافة في docs/
إذا كان أحد هذه الأسطح مفقودًا، فغالبًا ما تكون هذه علامة على أن القدرة لم تُدمج بالكامل بعد.

قالب القدرة

النمط الأدنى:
// core contract
export type VideoGenerationProviderPlugin = {
  id: string;
  label: string;
  generateVideo: (req: VideoGenerationRequest) => Promise<VideoGenerationResult>;
};

// plugin API
api.registerVideoGenerationProvider({
  id: "openai",
  label: "OpenAI",
  async generateVideo(req) {
    return await generateOpenAiVideo(req);
  },
});

// shared runtime helper for feature/channel plugins
const clip = await api.runtime.videoGeneration.generate({
  prompt: "Show the robot walking through the lab.",
  cfg,
});
نمط اختبار العقد:
expect(findVideoGenerationProviderIdsForPlugin("openai")).toEqual(["openai"]);
وهذا يُبقي القاعدة بسيطة:
  • تملك النواة عقد القدرة + التنسيق
  • تملك إضافات المورّدين تنفيذات المورّد
  • تستهلك إضافات الميزات/القنوات مساعدات وقت التشغيل
  • وتُبقي اختبارات العقود الملكية صريحة