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

الأجزاء الداخلية للإضافة

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

نموذج الإمكانات العام

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

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

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

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

يصنّف 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 الواجهات الخلفية الخاصة بها لفهم الوسائط
  • تملك الإضافة المضمّنة qwen سلوك موفّر النص لـ Qwen بالإضافة إلى سلوك فهم الوسائط وإنشاء الفيديو
  • الإضافة voice-call هي إضافة ميزة: فهي تملك نقل المكالمات والأدوات وCLI والمسارات وجسر تدفق الوسائط لـ Twilio، لكنها تستهلك إمكانات الكلام المشتركة بالإضافة إلى النسخ الفوري والصوت الفوري بدلًا من استيراد إضافات المورّد مباشرةً
الحالة النهائية المقصودة هي:
  • تعيش OpenAI داخل إضافة واحدة حتى لو كانت تمتد عبر نماذج النص والكلام والصور والفيديو مستقبلًا
  • يمكن لمورّد آخر أن يفعل الشيء نفسه لمساحة السطح الخاصة به
  • لا تهتم القنوات بأي إضافة مورّد تملك الموفّر؛ فهي تستهلك عقد الإمكانية المشتركة الذي تكشفه النواة
وهذا هو التمييز الأساسي:
  • الإضافة = حد الملكية
  • الإمكانية = عقد النواة الذي يمكن لعدة إضافات تنفيذه أو استهلاكه
لذلك إذا أضاف OpenClaw نطاقًا جديدًا مثل الفيديو، فلن يكون السؤال الأول هو “أي موفّر يجب أن يضمّن معالجة الفيديو بشكل ثابت؟” بل السؤال الأول هو “ما هو عقد إمكانية الفيديو في النواة؟” وبمجرد وجود ذلك العقد، يمكن لإضافات المورّدين التسجيل وفقه ويمكن لإضافات القنوات/الميزات استهلاكه. إذا لم تكن الإمكانية موجودة بعد، فعادةً ما تكون الخطوة الصحيحة هي:
  1. تعريف الإمكانية المفقودة في النواة
  2. كشفها عبر واجهة API/وقت التشغيل الخاصة بالإضافة بطريقة مكتوبة النوع
  3. ربط القنوات/الميزات بهذه الإمكانية
  4. السماح لإضافات المورّدين بتسجيل التنفيذات
يحافظ هذا على وضوح الملكية مع تجنب سلوك في النواة يعتمد على مورّد واحد أو على مسار شيفرة مخصص لإضافة واحدة.

طبقات الإمكانات

استخدم هذا النموذج الذهني عند تحديد المكان الذي تنتمي إليه الشيفرة:
  • طبقة إمكانات النواة: التنسيق المشترك، والسياسات، والتراجع، وقواعد دمج الإعداد، ودلالات التسليم، والعقود المكتوبة النوع
  • طبقة إضافة المورّد: واجهات API الخاصة بالمورّد، والمصادقة، وكتالوجات النماذج، وتوليف الكلام، وإنشاء الصور، والواجهات الخلفية المستقبلية للفيديو، ونقاط نهاية الاستخدام
  • طبقة إضافة القناة/الميزة: تكامل 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(...) وفقه. هل تحتاج إلى قائمة تحقق عملية واضحة؟ راجع دليل وصفات الإمكانات.

العقود والإنفاذ

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

ما الذي يجب أن ينتمي إلى عقد

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

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

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

حد التصدير

يكشف OpenClaw عن الإمكانات، وليس عن وسائل تنفيذ مريحة. أبقِ تسجيل الإمكانات عامًا. وقلّص صادرات المساعدات غير التعاقدية:
  • المسارات الفرعية الخاصة بمساعدات الإضافات المضمّنة
  • المسارات الفرعية الخاصة ببنية وقت التشغيل غير المقصود أن تكون واجهة API عامة
  • مساعدات الراحة الخاصة بالمورّد
  • مساعدات الإعداد/التهيئة التي تُعد تفاصيل تنفيذ
لا تزال بعض المسارات الفرعية لمساعدات الإضافات المضمّنة موجودة في خريطة صادرات 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
  • زيادة تسميات/عناصر نائبة في واجهة Control UI
  • عرض بيانات التثبيت/الكتالوج الوصفية
  • الحفاظ على واصفات التفعيل والإعداد منخفضة التكلفة من دون تحميل وقت تشغيل الإضافة
بالنسبة إلى الإضافات الأصلية، تكون وحدة وقت التشغيل هي جزء مستوى البيانات. فهي تسجّل السلوك الفعلي مثل الخطافات أو الأدوات أو الأوامر أو تدفقات الموفّر. تبقى الكتل الاختيارية activation وsetup في البيان ضمن مستوى التحكم. فهي واصفات بيانات وصفية فقط لتخطيط التفعيل واكتشاف الإعداد؛ ولا تحل محل تسجيل وقت التشغيل أو register(...) أو setupEntry. يفضّل اكتشاف الإعداد الآن المعرّفات المملوكة للواصفات مثل setup.providers و setup.cliBackends لتضييق نطاق الإضافات المرشحة قبل الرجوع إلى setup-api للإضافات التي لا تزال تحتاج إلى خطافات وقت تشغيل خاصة بالإعداد. وإذا ادّعت أكثر من إضافة مكتشفة ملكية معرّف موفّر إعداد أو واجهة خلفية CLI نفسه بعد تطبيعه، فإن البحث عن الإعداد يرفض المالك الملتبس بدلًا من الاعتماد على ترتيب الاكتشاف.

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

يحتفظ 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 من أجل البحث منخفض الكلفة عن مصادقة الموفّر عبر متغيرات البيئة قبل تحميل وقت التشغيل، وproviderAuthAliases لمتغيرات الموفّر التي تشترك في المصادقة، وchannelEnvVars من أجل البحث منخفض الكلفة عن إعداد/بيئة القناة قبل تحميل وقت التشغيل، بالإضافة إلى providerAuthChoices من أجل تسميات منخفضة الكلفة لخيار المصادقة/الإعداد وبيانات أعلام CLI الوصفية قبل تحميل وقت التشغيل
  • خطافات وقت الإعداد: catalog / discovery القديم بالإضافة إلى applyConfigDefaults
  • خطافات وقت التشغيل: normalizeModelId, normalizeTransport, normalizeConfig, applyNativeStreamingUsageCompat, resolveConfigApiKey, resolveSyntheticAuth, resolveExternalAuthProfiles, 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 في البيان عندما يملك الموفّر بيانات اعتماد قائمة على متغيرات البيئة يجب أن تراها مسارات المصادقة/الحالة/منتقي النماذج العامة من دون تحميل وقت تشغيل الإضافة. استخدم providerAuthAliases في البيان عندما يجب أن يعيد معرّف موفّر واحد استخدام متغيرات البيئة الخاصة بمعرّف موفّر آخر، وملفات المصادقة، والمصادقة المدعومة بالإعداد، وخيار الإعداد لمفتاح API. استخدم providerAuthChoices في البيان عندما يجب أن تعرف أسطح CLI الخاصة بالإعداد/اختيار المصادقة معرّف خيار الموفّر، وتسميات المجموعات، وربط المصادقة البسيط ذي العلم الواحد من دون تحميل وقت تشغيل الموفّر. أبقِ envVars في وقت تشغيل الموفّر للتلميحات الموجهة للمشغّل مثل تسميات الإعداد أو متغيرات إعداد OAuth الخاصة بـ client-id/client-secret. استخدم channelEnvVars في البيان عندما تكون لدى القناة مصادقة أو إعداد قائم على متغيرات البيئة يجب أن تراه مسارات الرجوع إلى متغيرات shell العامة، أو فحوصات الإعداد/الحالة، أو مطالبات الإعداد من دون تحميل وقت تشغيل القناة.

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

بالنسبة إلى إضافات النموذج/الموفّر، يستدعي 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يكشف المصادقة المحلية/المستضافة ذاتيًا أو المدعومة بالإعداد من دون حفظ نص واضحعندما يستطيع الموفّر العمل باستخدام علامة اعتماد اصطناعية/محلية
9resolveExternalAuthProfilesيضيف ملفات مصادقة خارجية يملكها الموفّر؛ والقيمة الافتراضية لـ persistence هي runtime-only لبيانات الاعتماد المملوكة لـ CLI/التطبيقعندما يعيد الموفّر استخدام بيانات اعتماد مصادقة خارجية من دون حفظ رموز تحديث منسوخة
10shouldDeferSyntheticProfileAuthيخفض أولوية العناصر النائبة الاصطناعية المحفوظة خلف المصادقة المدعومة بالبيئة/الإعدادعندما يخزن الموفّر ملفات تعريف اصطناعية نائبة يجب ألا تفوز بالأسبقية
11resolveDynamicModelتراجع متزامن لمعرّفات النماذج المملوكة للموفّر وغير الموجودة بعد في السجل المحليعندما يقبل الموفّر معرّفات نماذج علوية عشوائية
12prepareDynamicModelتهيئة غير متزامنة، ثم يُشغَّل resolveDynamicModel مرة أخرىعندما يحتاج الموفّر إلى بيانات وصفية شبكية قبل حل المعرّفات غير المعروفة
13normalizeResolvedModelإعادة كتابة نهائية قبل أن يستخدم المشغّل المضمّن النموذج المحلولعندما يحتاج الموفّر إلى إعادة كتابة للنقل مع الاستمرار في استخدام نقل أساسي
14contributeResolvedModelCompatيضيف أعلام توافق لنماذج المورّد الموجودة خلف نقل متوافق آخرعندما يتعرف الموفّر على نماذجه الخاصة فوق نواقل وكيلة من دون الاستحواذ على الموفّر
15capabilitiesبيانات وصفية للنصوص/الأدوات يملكها الموفّر وتستخدمها منطق النواة المشتركةعندما يحتاج الموفّر إلى خصائص خاصة بالنصوص أو بعائلة الموفّر
16normalizeToolSchemasيطبّع مخططات الأدوات قبل أن يراها المشغّل المضمّنعندما يحتاج الموفّر إلى تنظيف مخططات خاص بعائلة النقل
17inspectToolSchemasيكشف تشخيصات المخططات المملوكة للموفّر بعد التطبيععندما يريد الموفّر تحذيرات بشأن الكلمات المفتاحية من دون تعليم النواة قواعد خاصة بموفّر معين
18resolveReasoningOutputModeيختار عقد مخرجات الاستدلال الأصلي مقابل العقد الموسومعندما يحتاج الموفّر إلى استدلال موسوم/مخرجات نهائية بدلًا من الحقول الأصلية
19prepareExtraParamsتطبيع معلمات الطلب قبل أغلفة خيارات البث العامةعندما يحتاج الموفّر إلى معلمات طلب افتراضية أو تنظيف معلمات خاص بكل موفّر
20createStreamFnيستبدل بالكامل مسار البث العادي بنقل مخصصعندما يحتاج الموفّر إلى بروتوكول سلكي مخصص، وليس مجرد غلاف
21wrapStreamFnغلاف للبث بعد تطبيق الأغلفة العامةعندما يحتاج الموفّر إلى أغلفة توافق لطلب الرؤوس/الجسم/النموذج من دون نقل مخصص
22resolveTransportTurnStateيرفق رؤوس نقل أصلية أو بيانات وصفية لكل دورعندما يريد الموفّر أن ترسل النواقل العامة هوية الدور الأصلية الخاصة به
23resolveWebSocketSessionPolicyيرفق رؤوس WebSocket أصلية أو سياسة تبريد للجلسةعندما يريد الموفّر أن تضبط نواقل WS العامة رؤوس الجلسة أو سياسة التراجع
24formatApiKeyمنسّق ملف المصادقة: يتحول الملف المخزن إلى سلسلة apiKey وقت التشغيلعندما يخزن الموفّر بيانات مصادقة وصفية إضافية ويحتاج إلى شكل رمز وقت تشغيل مخصص
25refreshOAuthتجاوز لتحديث OAuth من أجل نقاط تحديث مخصصة أو سياسة فشل التحديثعندما لا يناسب الموفّر أدوات التحديث المشتركة pi-ai
26buildAuthDoctorHintتلميح إصلاح يُلحق عند فشل تحديث OAuthعندما يحتاج الموفّر إلى إرشاد إصلاح مصادقة مملوك له بعد فشل التحديث
27matchesContextOverflowErrorمطابق تجاوز نافذة السياق المملوك للموفّرعندما يملك الموفّر أخطاء تجاوز خام قد تفوّتها الاستدلالات العامة
28classifyFailoverReasonتصنيف سبب التبديل الاحتياطي المملوك للموفّرعندما يستطيع الموفّر تحويل أخطاء API/النقل الخام إلى تجاوز حد المعدل/حمل زائد/إلخ
29isCacheTtlEligibleسياسة التخزين المؤقت للمطالبة لموفّري الوكيل/الترحيلعندما يحتاج الموفّر إلى ضبط TTL خاص بالوكيل
30buildMissingAuthMessageبديل لرسالة استرداد المصادقة المفقودة العامةعندما يحتاج الموفّر إلى تلميح خاص به لاسترداد المصادقة المفقودة
31suppressBuiltInModelإخفاء النماذج العلوية القديمة مع تلميح اختياري مرئي للمستخدمعندما يحتاج الموفّر إلى إخفاء الصفوف العلوية القديمة أو استبدالها بتلميح من المورّد
32augmentModelCatalogصفوف كتالوج اصطناعية/نهائية تُضاف بعد الاكتشافعندما يحتاج الموفّر إلى صفوف توافق أمامي اصطناعية في models list والمنتقيات
33isBinaryThinkingتبديل تشغيل/إيقاف للاستدلال لدى موفّري binary-thinkingعندما لا يوفّر الموفّر إلا تشغيل/إيقاف للاستدلال
34supportsXHighThinkingدعم الاستدلال xhigh لنماذج محددةعندما يريد الموفّر تفعيل xhigh لمجموعة فرعية فقط من النماذج
35resolveDefaultThinkingLevelمستوى /think الافتراضي لعائلة نماذج محددةعندما يملك الموفّر سياسة /think الافتراضية لعائلة نماذج
36isModernModelRefمطابق النموذج الحديث لمرشحات الملفات الحية واختيار smokeعندما يملك الموفّر مطابقة النماذج المفضلة في الاختبارات الحية/الدخانية
37prepareRuntimeAuthيستبدل بيانات اعتماد مهيأة بالرمز/المفتاح الفعلي وقت التشغيل مباشرة قبل الاستدلالعندما يحتاج الموفّر إلى تبادل رمز أو بيانات اعتماد طلب قصيرة العمر
38resolveUsageAuthيحل بيانات اعتماد الاستخدام/الفوترة من أجل /usage والأسطح المرتبطة بالحالةعندما يحتاج الموفّر إلى تحليل مخصص لرمز الاستخدام/الحصة أو إلى بيانات اعتماد استخدام مختلفة
39fetchUsageSnapshotيجلب ويطبّع لقطات الاستخدام/الحصة الخاصة بالمورّد بعد حل المصادقةعندما يحتاج الموفّر إلى نقطة نهاية استخدام خاصة به أو إلى محلل حمولة خاص به
40createEmbeddingProviderيبني محول embedding مملوكًا للموفّر من أجل الذاكرة/البحثعندما ينتمي سلوك embedding الخاص بالذاكرة إلى إضافة الموفّر
41buildReplayPolicyيعيد سياسة replay تتحكم في معالجة النصوص الخاصة بالموفّرعندما يحتاج الموفّر إلى سياسة نصوص مخصصة (على سبيل المثال، إزالة كتل التفكير)
42sanitizeReplayHistoryيعيد كتابة سجل replay بعد التنظيف العام للنصوصعندما يحتاج الموفّر إلى إعادة كتابة replay خاصة به تتجاوز مساعدات الضغط المشتركة
43validateReplayTurnsالتحقق النهائي من أدوار replay أو إعادة تشكيلها قبل المشغّل المضمّنعندما يحتاج نقل الموفّر إلى تحقق أكثر صرامة من الأدوار بعد التنقية العامة
44onModelSelectedيشغّل آثارًا جانبية بعد الاختيار يملكها الموفّرعندما يحتاج الموفّر إلى القياس عن بُعد أو إلى حالة مملوكة له عندما يصبح النموذج نشطًا
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 لرؤوس beta و/fast / serviceTier وcontext1m.
  • تبقى مساعدات البث الخاصة بـ Claude التابعة لـ Anthropic ضمن الحد العام api.ts / contract-api.ts الخاص بالإضافة المضمّنة في الوقت الحالي. ويقوم سطح الحزمة هذا بتصدير wrapAnthropicProviderStream وresolveAnthropicBetas و resolveAnthropicFastMode وresolveAnthropicServiceTier وبناة الأغلفة ذات المستوى الأدنى الخاصة بـ Anthropic بدلًا من توسيع SDK العام حول قواعد رؤوس beta الخاصة بموفّر واحد.
  • تستخدم OpenAI الخطافات resolveDynamicModel وnormalizeResolvedModel و capabilities بالإضافة إلى buildMissingAuthMessage وsuppressBuiltInModel و augmentModelCatalog وsupportsXHighThinking وisModernModelRef لأنها تملك التوافق الأمامي لـ GPT-5.4، وتطبيع openai-completions -> openai-responses المباشر في OpenAI، وتلميحات المصادقة الواعية بـ Codex، وإخفاء Spark، والصفوف الاصطناعية لقائمة OpenAI، وسياسة التفكير / النموذج الحي الخاصة بـ GPT-5؛ وتمتلك عائلة البث openai-responses-defaults أغلفة OpenAI Responses الأصلية المشتركة من أجل رؤوس الإسناد، و/fast/serviceTier، وإسهاب النص، وبحث الويب الأصلي لـ Codex، وتشكيل الحمولة المتوافق مع الاستدلال، وإدارة سياق Responses.
  • تستخدم OpenRouter catalog بالإضافة إلى resolveDynamicModel و prepareDynamicModel لأن الموفّر يعمل كتمرير مباشر وقد يكشف عن معرّفات نماذج جديدة قبل تحديث الكتالوج الثابت في OpenClaw؛ كما يستخدم capabilities وwrapStreamFn وisCacheTtlEligible لإبقاء رؤوس الطلبات الخاصة بالموفّر، وبيانات التوجيه الوصفية، وترقيعات الاستدلال، وسياسة التخزين المؤقت للمطالبة خارج النواة. وتأتي سياسة replay الخاصة به من عائلة 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 الأساسية لكنها تملك تطبيع النقل/‏base URL، وسياسة التراجع لتحديث OAuth، وخيار النقل الافتراضي، وصفوف كتالوج Codex الاصطناعية، وتكامل نقطة نهاية استخدام ChatGPT؛ وهي تشترك في عائلة البث openai-responses-defaults نفسها مع OpenAI المباشرة.
  • تستخدم Google AI Studio وGemini CLI OAuth الخطافات resolveDynamicModel، buildReplayPolicy، وsanitizeReplayHistory، وresolveReasoningOutputMode، وwrapStreamFn، وisModernModelRef لأن عائلة replay google-gemini تملك التراجع المتوافق أماميًا لـ Gemini 3.1، والتحقق الأصلي من replay في Gemini، وتنقية replay عند التمهيد، ووضع مخرجات الاستدلال الموسوم، ومطابقة النماذج الحديثة، بينما تمتلك عائلة البث google-thinking تطبيع حمولة التفكير في Gemini؛ كما يستخدم Gemini CLI OAuth أيضًا formatApiKey وresolveUsageAuth و fetchUsageSnapshot من أجل تنسيق الرمز، وتحليل الرمز، وربط نقطة نهاية الحصة.
  • يستخدم Anthropic Vertex buildReplayPolicy عبر عائلة replay anthropic-by-model بحيث يبقى تنظيف replay الخاص بـ Claude محصورًا ضمن معرّفات Claude بدلًا من كل نقل anthropic-messages.
  • يستخدم Amazon Bedrock الخطافات buildReplayPolicy وmatchesContextOverflowError و classifyFailoverReason وresolveDefaultThinkingLevel لأنه يملك تصنيف الأخطاء الخاصة بـ Bedrock مثل تقييد المعدل/عدم الجاهزية/تجاوز السياق لحركة Anthropic-on-Bedrock؛ بينما تظل سياسة replay الخاصة به تشترك في الحارس نفسه anthropic-by-model المخصص لـ Claude فقط.
  • تستخدم OpenRouter وKilocode وOpencode وOpencode Go الخطاف buildReplayPolicy عبر عائلة replay passthrough-gemini لأنها توكّل نماذج Gemini عبر نواقل متوافقة مع OpenAI وتحتاج إلى تنقية thought-signature الخاصة بـ Gemini من دون تحقق replay أصلي لـ Gemini أو إعادة كتابة عند التمهيد.
  • تستخدم MiniMax buildReplayPolicy عبر عائلة replay 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، وضبط Anthropic لـ cache-TTL؛ وتُبقي عائلة البث 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 الأصلي، وإعادة كتابة الأسماء البديلة لـ fast-mode في Grok، وtool_stream الافتراضي، وتنظيف strict-tool / حمولة الاستدلال، وإعادة استخدام مصادقة التراجع للأدوات المملوكة للإضافة، وحل نماذج 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، والتراجع، وتسليم الرد في النواة.
  • استخدم موفّري الكلام لسلوك التوليف المملوك للمورّد.
  • يُطبَّع إدخال Microsoft القديم edge إلى معرّف الموفّر 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: مسار التوجيه تحت خادم Gateway HTTP.
  • auth: مطلوب. استخدم "gateway" لطلب مصادقة Gateway العادية، أو "plugin" للمصادقة/التحقق من webhook المُدار بواسطة الإضافة.
  • match: اختياري. "exact" (الافتراضي) أو "prefix".
  • replaceExisting: اختياري. يسمح للإضافة نفسها باستبدال تسجيل المسار الحالي الخاص بها.
  • handler: أعِد true عندما يكون المسار قد عالج الطلب.
ملاحظات:
  • تمت إزالة api.registerHttpHandler(...) وسيسبب خطأ عند تحميل الإضافة. استخدم api.registerHttpRoute(...) بدلًا منه.
  • يجب أن تعلن مسارات الإضافة عن auth صراحةً.
  • تُرفض تعارضات path + match المطابقة ما لم يكن replaceExisting: true، ولا يمكن لإضافة أن تستبدل مسار إضافة أخرى.
  • تُرفض المسارات المتداخلة ذات مستويات auth المختلفة. اجعل سلاسل التمرير exact/prefix على مستوى المصادقة نفسه فقط.
  • لا تتلقى المسارات ذات auth: "plugin" نطاقات وقت تشغيل المشغّل تلقائيًا. فهي مخصصة لـ webhooks/التحقق من التوقيع المُدار بواسطة الإضافة، وليست لاستدعاءات مساعد Gateway المميّزة.
  • تعمل المسارات ذات auth: "gateway" داخل نطاق وقت تشغيل طلب Gateway، لكن هذا النطاق متحفّظ عمدًا:
    • تبقي مصادقة bearer ذات السر المشترك (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
  • القاعدة العملية: لا تفترض أن مسار الإضافة ذي مصادقة gateway هو سطح إداري ضمني. إذا كان مسارك يحتاج إلى سلوك إداري فقط، فاطلب وضع مصادقة حاملًا للهوية ووثّق عقد الترويسة 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 من أجل الربط المشترك الخاص بالإعداد/المصادقة/الرد/‏webhook. يمثّل 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-gateway-runtime, وopenclaw/plugin-sdk/approval-handler-adapter-runtime, وopenclaw/plugin-sdk/approval-handler-runtime, و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، ومساعدات الحجب، ومساعدات directive-tag، وأدوات النص الآمن.
  • ينبغي أن تفضّل الحدود الخاصة بالقنوات المعتمدة على الموافقة عقد 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، ومساعدات رؤوس beta، وتحليل 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 في الشيفرة الجديدة.
  • فضّل أولًا البدائيات الثابتة الضيقة. فالمسارات الفرعية الأحدث الخاصة بـ setup/pairing/reply/ feedback/contract/inbound/threading/command/secret-input/webhook/infra/ allowlist/status/message-tool هي العقد المقصود لأعمال الإضافات الجديدة المضمّنة والخارجية. ينتمي تحليل/مطابقة الهدف إلى 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. استخدم هذا عندما تحتاج القناة إلى نظراء/مجموعات مدعومة بالإعداد مثل:
  • نظراء الرسائل المباشرة المعتمدون على allowlist
  • خرائط القنوات/المجموعات المهيأة
  • بدائل الدليل الثابتة ضمن نطاق الحساب
المساعدات المشتركة في 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 packs

يمكن أن يتضمن دليل الإضافة 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 (من دون سكربتات دورة الحياة، ومن دون تبعيات تطوير وقت التشغيل). أبقِ أشجار تبعيات الإضافة “JS/TS خالصة” وتجنب الحزم التي تتطلب بناء 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 من أجل قرارات التنسيق الصادر
  • exposure.configured: إخفاء القناة من أسطح سرد القنوات المهيأة عندما تكون القيمة false
  • exposure.setup: إخفاء القناة من منتقيات الإعداد/التهيئة التفاعلية عندما تكون القيمة false
  • exposure.docs: تعليم القناة على أنها داخلية/خاصة لأسطح التنقل في الوثائق
  • showConfigured / showInSetup: لا تزال الأسماء البديلة القديمة مقبولة للتوافق؛ ويُفضّل exposure
  • 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. استخدم هذا عندما تحتاج إضافتك إلى استبدال مسار السياق الافتراضي أو توسيعه بدلًا من مجرد إضافة بحث في الذاكرة أو خطافات.
import { buildMemorySystemPromptAddition } from "openclaw/plugin-sdk/core";

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, availableTools, citationsMode }) {
      return {
        messages,
        estimatedTokens: 0,
        systemPromptAddition: buildMemorySystemPromptAddition({
          availableTools: availableTools ?? new Set(),
          citationsMode,
        }),
      };
    },
    async compact() {
      return { ok: true, compacted: false };
    },
  }));
}
إذا كان محركك لا يملك خوارزمية الضغط، فأبقِ compact() منفذًا وفوّضه بشكل صريح:
import {
  buildMemorySystemPromptAddition,
  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, availableTools, citationsMode }) {
      return {
        messages,
        estimatedTokens: 0,
        systemPromptAddition: buildMemorySystemPromptAddition({
          availableTools: availableTools ?? new Set(),
          citationsMode,
        }),
      };
    },
    async compact(params) {
      return await delegateCompactionToRuntime(params);
    },
  }));
}

إضافة إمكانية جديدة

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

قائمة تحقق الإمكانية

عندما تضيف إمكانية جديدة، يجب أن يلامس التنفيذ عادةً هذه الأسطح معًا:
  • أنواع عقد النواة في src/<capability>/types.ts
  • المشغّل/مساعد وقت التشغيل الأساسي في src/<capability>/runtime.ts
  • سطح تسجيل واجهة API للإضافة في 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"]);
وهذا يُبقي القاعدة بسيطة:
  • تملك النواة عقد الإمكانية + التنسيق
  • تملك إضافات المورّدين تنفيذات المورّد
  • تستهلك إضافات الميزات/القنوات مساعدات وقت التشغيل
  • تُبقي اختبارات العقود الملكية واضحة