---
read_when:
    - تنفيذ خطافات وقت تشغيل المزوّد، أو دورة حياة القناة، أو حزم الحزم
    - تصحيح أخطاء ترتيب تحميل الـ Plugin أو حالة السجل
    - إضافة إمكانية جديدة إلى Plugin أو Plugin لمحرك السياق
summary: 'البنية الداخلية لمعمارية Plugin: مسار التحميل، والسجل، وخطافات وقت التشغيل، ومسارات HTTP، والجداول المرجعية'
title: البنية الداخلية لمعمارية Plugin
x-i18n:
    generated_at: "2026-07-12T06:13:44Z"
    model: gpt-5.6
    postprocess_version: locale-links-v1
    provider: openai
    source_hash: 2fe5b7f34c638da40b43c24da9425ecdeb9ce7381e233b3ebdd5cc95276ba04f
    source_path: plugins/architecture-internals.md
    workflow: 16
---

للاطّلاع على نموذج القدرات العام، وأشكال Plugin، وعقود الملكية/التنفيذ، راجع [بنية Plugin](/ar/plugins/architecture). تتناول هذه الصفحة الآليات الداخلية: مسار التحميل، والسجل، وخطافات وقت التشغيل، ومسارات HTTP الخاصة بـ Gateway، ومسارات الاستيراد، وجداول المخططات.

## مسار التحميل

عند بدء التشغيل، ينفّذ OpenClaw تقريبًا ما يلي:

1. اكتشاف الجذور المرشحة لـ Plugin
2. قراءة بيانات حزم التجميع الأصلية أو المتوافقة وبيانات تعريف الحزمة
3. رفض المرشحين غير الآمنين
4. تسوية إعدادات Plugin (`plugins.enabled` و`allow` و`deny` و`entries` و`slots` و`load.paths`)
5. تحديد حالة التمكين لكل مرشح
6. تحميل الوحدات الأصلية الممكّنة: تستخدم الوحدات المضمّنة المبنية محمّلًا أصليًا؛ بينما تستخدم الشيفرة المصدرية المحلية التابعة لجهات خارجية والمكتوبة بـ TypeScript آلية Jiti الاحتياطية الطارئة
7. استدعاء خطافات `register(api)` الأصلية وجمع التسجيلات في سجل Plugin
8. إتاحة السجل للأوامر وأسطح وقت التشغيل

<Note>
يُعد `activate` اسمًا مستعارًا قديمًا لـ `register` — يحلّ المحمّل أيهما موجود (`def.register ?? def.activate`) ويستدعيه في الموضع نفسه. تستخدم جميع Plugins المضمّنة `register`؛ لذا يُفضّل استخدام `register` في Plugins الجديدة.
</Note>

تعمل بوابات الأمان **قبل** تنفيذ وقت التشغيل. يحظر الاكتشاف مرشحًا عندما:

- يتجاوز مدخله المحلول جذر Plugin
- يكون مساره (أو دليل الجذر الخاص به) قابلًا للكتابة من الجميع
- لا تتطابق ملكية المسار مع معرّف المستخدم الحالي uid (أو root)، في Plugins غير المضمّنة

تخضع الأدلة المضمّنة القابلة للكتابة من الجميع أولًا لمحاولة إصلاح موضعية باستخدام `chmod` (قد توزّع عمليات تثبيت npm/العمليات العامة أدلة الحزم بأذونات `0777`) قبل أن تعيد البوابة التحقق؛ بينما تُتخطى عمليات التحقق من الملكية كليًا للمصادر المضمّنة.

يظل المرشحون المحظورون يحملون معرّف Plugin الخاص بهم في التشخيص الصادر عندما يكون معروفًا (بما في ذلك المعرّفات المحلولة من بيانات حزمة داخل دليل مرفوض من نواحٍ أخرى)، بحيث ترى الإعدادات التي تشير إلى ذلك المعرّف Plugin محظورًا مرتبطًا بتحذير أمان المسار بدلًا من خطأ "Plugin غير معروف" غير ذي صلة.

### سلوك تقديم بيانات الحزمة

تُعد بيانات الحزمة مصدر الحقيقة لمستوى التحكم. يستخدمها OpenClaw من أجل:

- تحديد Plugin
- اكتشاف القنوات/Skills/مخطط الإعدادات أو قدرات حزمة التجميع المعلنة
- التحقق من `plugins.entries.<id>.config`
- إثراء تسميات واجهة التحكم ونصوصها النائبة
- عرض بيانات تعريف التثبيت/الكتالوج
- الاحتفاظ بواصفات تفعيل وإعداد منخفضة التكلفة دون تحميل وقت تشغيل Plugin

بالنسبة إلى Plugins الأصلية، تمثل وحدة وقت التشغيل جزء مستوى البيانات. وهي تسجّل السلوك الفعلي، مثل الخطافات أو الأدوات أو الأوامر أو تدفقات المزوّدين.

تبقى كتلتَا `activation` و`setup` الاختياريتان في مستوى التحكم. وهما واصفتان من بيانات التعريف فقط لتخطيط التفعيل واكتشاف الإعداد؛ ولا تحلان محل التسجيل في وقت التشغيل أو `register(...)` أو `setupEntry`. يستخدم مستهلكو التفعيل المباشر تلميحات الأوامر والقنوات والمزوّدين الواردة في بيانات الحزمة لتضييق تحميل Plugins قبل تكوين السجل على نطاق أوسع:

- يضيّق تحميل CLI النطاق إلى Plugins المالكة للأمر الأساسي المطلوب
- يضيّق إعداد القناة/حل Plugin النطاق إلى Plugins المالكة لمعرّف القناة المطلوب
- يضيّق إعداد المزوّد الصريح/حله في وقت التشغيل النطاق إلى Plugins المالكة لمعرّف المزوّد المطلوب
- يستخدم تخطيط بدء تشغيل Gateway القيمة `activation.onStartup` لعمليات الاستيراد الصريحة عند بدء التشغيل؛ ولا تُحمّل Plugins التي لا تتضمن بيانات تعريف لبدء التشغيل إلا عبر مشغلات تفعيل أضيق نطاقًا

يعرض مخطّط التفعيل واجهة API تقتصر على المعرّفات للمتصلين الحاليين، وواجهة API للخطة لأغراض التشخيص. توضّح إدخالات الخطة سبب اختيار Plugin، مع الفصل بين تلميحات `activation.*` الصريحة والرجوع إلى ملكية بيانات الحزمة:

| السبب (من تلميحات `activation.*`) | السبب (من ملكية بيانات الحزمة) |
| ------------------------------------ | -------------------------------------------------------------------------------------------- |
| `activation-agent-harness-hint`      | —                                                                                            |
| `activation-capability-hint`         | —                                                                                            |
| `activation-channel-hint`            | `manifest-channel-owner` (`channels`)                                                        |
| `activation-command-hint`            | `manifest-command-alias` (`commandAliases`)                                                  |
| `activation-provider-hint`           | `manifest-provider-owner` (`providers`), `manifest-setup-provider-owner` (`setup.providers`) |
| `activation-route-hint`              | —                                                                                            |
| — (لا يتضمن مشغل الخطاف صيغة تلميح) | `manifest-hook-owner` (`hooks`), `manifest-tool-contract` (`contracts.tools`)                |

يمثل هذا الفصل بين الأسباب حد التوافق: تستمر بيانات تعريف Plugin الحالية في العمل، بينما تستطيع الشيفرة الجديدة اكتشاف التلميحات واسعة النطاق أو سلوك الرجوع دون تغيير دلالات التحميل في وقت التشغيل.

تستمر عمليات التحميل المسبق في وقت الطلب التي تطلب النطاق الواسع `all` في اشتقاق مجموعة صريحة وفعّالة من معرّفات Plugins من الإعدادات، وتخطيط بدء التشغيل، والقنوات المضبوطة، والخانات، وقواعد التمكين التلقائي (`resolveEffectivePluginIds` في `src/plugins/effective-plugin-ids.ts`). وإذا كانت المجموعة المشتقة فارغة، يُبقي OpenClaw النطاق فارغًا بدلًا من توسيعه ليشمل كل Plugin قابل للاكتشاف.

يفضّل اكتشاف الإعداد المعرّفات المملوكة للواصفات، مثل `setup.providers` و`setup.cliBackends`، لتضييق نطاق Plugins المرشحة قبل الرجوع إلى `setup-api` في Plugins التي لا تزال بحاجة إلى خطافات وقت التشغيل أثناء الإعداد. تستخدم قوائم إعداد المزوّد `providerAuthChoices` الواردة في بيانات الحزمة، وخيارات الإعداد المشتقة من الواصفات، وبيانات تعريف كتالوج التثبيت دون تحميل وقت تشغيل المزوّد. تمثل القيمة الصريحة `setup.requiresRuntime: false` حدًا يقتصر على الواصفات؛ بينما يؤدي حذف `requiresRuntime` إلى الإبقاء على الرجوع القديم إلى setup-api لأغراض التوافق. إذا ادّعى أكثر من Plugin مكتشف ملكية معرّف مزوّد إعداد أو معرّف واجهة CLI خلفية مُسوّى نفسه، يرفض بحث الإعداد المالك الملتبس بدلًا من الاعتماد على ترتيب الاكتشاف. وعند تنفيذ وقت تشغيل الإعداد، تُبلغ تشخيصات السجل عن الانحراف بين `setup.providers` / `setup.cliBackends` والمزوّدين أو واجهات CLI الخلفية المسجّلة فعليًا بواسطة setup-api، دون حظر Plugins القديمة.

### حدود ذاكرة Plugin المؤقتة

لا يخزّن OpenClaw مؤقتًا نتائج اكتشاف Plugins أو بيانات سجل بيانات الحزمة المباشرة ضمن نوافذ زمنية فعلية. يجب أن تصبح عمليات التثبيت، وتعديلات بيانات الحزمة، وتغييرات مسارات التحميل مرئية عند القراءة الصريحة التالية لبيانات التعريف أو إعادة بناء اللقطة. يحتفظ محلل ملف بيانات الحزمة بذاكرة مؤقتة محدودة لتوقيع الملف، يكون مفتاحها مسار ملف بيانات الحزمة المفتوح مع الجهاز/inode والحجم وmtime/ctime؛ ولا تتجنب تلك الذاكرة المؤقتة سوى إعادة تحليل البايتات غير المتغيرة، ويجب ألا تخزّن مؤقتًا إجابات الاكتشاف أو السجل أو المالك أو السياسة.

المسار السريع الآمن لبيانات التعريف هو الملكية الصريحة للكائنات، لا ذاكرة مؤقتة مخفية. ينبغي أن تمرّر المسارات الساخنة عند بدء تشغيل Gateway قيمة `PluginMetadataSnapshot` الحالية، أو `PluginLookUpTable` المشتق، أو سجل بيانات حزمة صريح عبر سلسلة الاستدعاءات. يمكن للتحقق من الإعدادات، والتمكين التلقائي عند بدء التشغيل، وتهيئة Plugin، واختيار المزوّد إعادة استخدام تلك الكائنات ما دامت تمثل الإعدادات الحالية ومخزون Plugins الحالي. لا يزال بحث الإعداد يعيد تكوين بيانات تعريف بيانات الحزمة عند الطلب، إلا إذا تلقى مسار الإعداد المحدد سجل بيانات حزمة صريحًا؛ احتفظ بذلك كآلية رجوع للمسارات الباردة بدلًا من إضافة ذاكرات بحث مؤقتة مخفية. عند تغير الإدخال، أعد بناء اللقطة واستبدلها بدلًا من تعديلها أو الاحتفاظ بنسخ تاريخية منها. ينبغي إعادة حساب العروض المستندة إلى سجل Plugin النشط ومساعدات تهيئة القنوات المضمّنة من السجل/الجذر الحالي. لا بأس بالخرائط قصيرة العمر داخل استدعاء واحد لإزالة تكرار العمل أو منع إعادة الدخول؛ لكن يجب ألا تتحول إلى ذاكرات مؤقتة لبيانات تعريف العملية.

بالنسبة إلى تحميل Plugin، تتمثل طبقة التخزين المؤقت الدائمة في تحميل وقت التشغيل. ويمكنها إعادة استخدام حالة المحمّل عند تحميل الشيفرة أو العناصر المثبتة فعليًا، مثل:

- `PluginLoaderCacheState` وسجلات وقت التشغيل النشطة المتوافقة
- ذاكرات jiti/الوحدات المؤقتة وذاكرات محمّل السطح العام المؤقتة المستخدمة لتجنب استيراد سطح وقت التشغيل نفسه بصورة متكررة
- ذاكرات نظام الملفات المؤقتة لعناصر Plugin المثبتة
- خرائط قصيرة العمر لكل استدعاء لتسوية المسارات أو حل التكرارات

هذه الذاكرات المؤقتة تفاصيل تنفيذية لمستوى البيانات. ويجب ألا تجيب عن أسئلة مستوى التحكم، مثل "أي Plugin يملك هذا المزوّد؟"، إلا إذا طلب المتصل تحميل وقت التشغيل عمدًا.

لا تضف ذاكرات مؤقتة دائمة أو مرتبطة بالوقت الفعلي من أجل:

- نتائج الاكتشاف
- سجلات بيانات الحزمة المباشرة
- سجلات بيانات الحزمة المعاد تكوينها من فهرس Plugins المثبتة
- البحث عن مالك المزوّد، أو حجب النموذج، أو سياسة المزوّد، أو بيانات تعريف العناصر العامة
- أي إجابة أخرى مشتقة من بيانات الحزمة، عندما ينبغي أن يظهر تغيير بيانات الحزمة أو الفهرس المثبت أو مسار التحميل عند القراءة التالية لبيانات التعريف

يعيد المتصلون الذين يبنون بيانات تعريف بيانات الحزمة من فهرس Plugins المثبتة والمستمر تخزينه تكوين ذلك السجل عند الطلب. الفهرس المثبت هو حالة دائمة لمستوى المصدر؛ وليس ذاكرة مؤقتة مخفية لبيانات التعريف داخل العملية.

## نموذج السجل

لا تعدّل Plugins المحمّلة المتغيرات العامة العشوائية في النواة مباشرةً. بل تسجّل في سجل Plugin مركزي (`PluginRegistry` في `src/plugins/registry-types.ts`)، يتتبع سجلات Plugins (الهوية، والمصدر، والأصل، والحالة، والتشخيصات)، بالإضافة إلى مصفوفات لكل قدرة: الأدوات، والخطافات القديمة والخطافات المنمطة، والقنوات، والمزوّدون، ومعالجات RPC الخاصة بـ Gateway، ومسارات HTTP، ومسجّلو CLI، وخدمات الخلفية، والأوامر المملوكة لـ Plugin، وعشرات عائلات المزوّدين المنمطة الأخرى (الكلام، والتضمينات، وتوليد الصور/الفيديو/الموسيقى، وجلب الويب/البحث فيه، وأطر الوكلاء، وإجراءات الجلسات، وما إلى ذلك).

تقرأ ميزات النواة بعد ذلك من هذا السجل بدلًا من التواصل مباشرةً مع وحدات Plugin. وهذا يحافظ على اتجاه واحد للتحميل:

- وحدة Plugin -> التسجيل في السجل
- وقت تشغيل النواة -> استهلاك السجل

هذا الفصل مهم لقابلية الصيانة. فهو يعني أن معظم أسطح النواة لا تحتاج إلا إلى نقطة تكامل واحدة: "قراءة السجل"، بدلًا من "إضافة معالجة خاصة لكل وحدة Plugin".

## استدعاءات ربط المحادثة

يمكن لـ Plugins التي تربط محادثة أن تتفاعل عند حسم الموافقة.

استخدم `api.onConversationBindingResolved(...)` لتلقي استدعاء بعد الموافقة على طلب الربط أو رفضه:

```ts
export default {
  id: "my-plugin",
  register(api) {
    api.onConversationBindingResolved(async (event) => {
      if (event.status === "approved") {
        // A binding now exists for this plugin + conversation.
        console.log(event.binding?.conversationId);
        return;
      }

      // The request was denied; clear any local pending state.
      console.log(event.request.conversation.conversationId);
    });
  },
};
```

حقول حمولة الاستدعاء:

- `status`: `"approved"` أو `"denied"`
- `decision`: `"allow-once"` أو `"allow-always"` أو `"deny"`
- `binding`: الربط المحلول للطلبات الموافق عليها
- `request`: ملخص الطلب الأصلي، وتلميح الفصل، ومعرّف المرسل، وبيانات تعريف المحادثة

هذا الاستدعاء مخصص للإشعار فقط. ولا يغيّر الجهات المسموح لها بربط محادثة، ويُنفّذ بعد انتهاء معالجة الموافقة في النواة.

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

تتكون Plugins الخاصة بالمزوّدين من ثلاث طبقات:

- **بيانات تعريف بيانات الحزمة** للبحث منخفض التكلفة قبل وقت التشغيل:
  `setup.providers[].envVars`، و`providerAuthEnvVars` المتقادمة المخصصة للتوافق،
  و`providerAuthAliases`، و`providerAuthChoices`، و`channelEnvVars`.
- **خطافات وقت الإعداد**: `catalog` (والاسم القديم `discovery`) بالإضافة إلى
  `applyConfigDefaults`.
- **خطافات وقت التشغيل**: أكثر من 40 خطافًا اختياريًا تغطي المصادقة، وحل النماذج،
  وتغليف التدفق، ومستويات التفكير، وسياسة إعادة التشغيل، ونقاط نهاية الاستخدام. راجع
  [ترتيب الخطافات واستخدامها](#hook-order-and-usage).

يظل OpenClaw مسؤولًا عن حلقة الوكيل العامة، وتجاوز الأعطال، ومعالجة النصوص المنسوخة، وسياسة الأدوات. وتمثل هذه الخطافات سطح التوسعة للسلوك الخاص بالمزوّد دون الحاجة إلى وسيلة نقل استدلال مخصصة بالكامل.

استخدم `setup.providers[].envVars` في البيان عندما تكون لدى المزوّد بيانات اعتماد قائمة على متغيرات البيئة ينبغي أن تتمكن مسارات المصادقة/الحالة/منتقي النماذج العامة من رؤيتها من دون تحميل وقت تشغيل Plugin. لا يزال محوّل التوافق يقرأ `providerAuthEnvVars` المهجورة خلال فترة الإهمال، وتتلقى الإضافات غير المضمّنة التي تستخدمها تشخيصًا للبيان. استخدم `providerAuthAliases` في البيان عندما ينبغي لمعرّف مزوّد أن يعيد استخدام متغيرات البيئة وملفات تعريف المصادقة والمصادقة المدعومة بالإعدادات وخيار إعداد مفتاح API لمعرّف مزوّد آخر. استخدم `providerAuthChoices` في البيان عندما ينبغي لواجهات CLI الخاصة بالإعداد الأولي/اختيار المصادقة أن تعرف معرّف خيار المزوّد وتسميات المجموعات وآلية توصيل المصادقة البسيطة ذات العلامة الواحدة من دون تحميل وقت تشغيل المزوّد. احتفظ بـ `envVars` في وقت تشغيل المزوّد للتلميحات الموجّهة إلى المشغّلين، مثل تسميات الإعداد الأولي أو متغيرات إعداد معرّف عميل OAuth/سر العميل.

استخدم `channelEnvVars` في البيان عندما تكون لدى القناة مصادقة أو إعداد يعتمدان على متغيرات البيئة، وينبغي أن تتمكن آلية الرجوع العامة إلى متغيرات بيئة الصدفة أو عمليات التحقق من الإعدادات/الحالة أو مطالبات الإعداد من رؤيتها من دون تحميل وقت تشغيل القناة.

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

بالنسبة إلى إضافات النماذج/المزوّدين، يستدعي OpenClaw الخطافات بهذا الترتيب التقريبي.
يمثّل عمود "متى يُستخدم" دليل القرار السريع.
لا تُدرج هنا عمدًا حقول المزوّد المخصّصة للتوافق فقط، والتي لم يعد OpenClaw يستدعيها، مثل `ProviderPlugin.capabilities` و`suppressBuiltInModel`.

| الخطاف                            | ما الذي يفعله                                                                                                                   | متى يُستخدم                                                                                                                                                         |
| --------------------------------- | ------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `catalog`                         | ينشر إعدادات المزوّد في `models.providers` أثناء إنشاء `models.json`                                                            | عندما يملك المزوّد كتالوجًا أو قيمًا افتراضية لعنوان URL الأساسي                                                                                                    |
| `applyConfigDefaults`             | يطبّق القيم الافتراضية العامة للإعدادات التي يملكها المزوّد أثناء تجسيد الإعدادات                                                | عندما تعتمد القيم الافتراضية على وضع المصادقة أو متغيرات البيئة أو دلالات عائلة نماذج المزوّد                                                                        |
| _(البحث المضمّن عن النموذج)_      | يجرّب OpenClaw أولًا مسار السجل/الكتالوج المعتاد                                                                                 | _(ليس خطاف Plugin)_                                                                                                                                                 |
| `normalizeModelId`                | يطبّع الأسماء البديلة القديمة أو التجريبية لمعرّفات النماذج قبل البحث                                                           | عندما يملك المزوّد تنظيف الأسماء البديلة قبل الحل القانوني للنموذج                                                                                                  |
| `normalizeTransport`              | يطبّع `api` / `baseUrl` لعائلة المزوّد قبل التجميع العام للنموذج                                                                | عندما يملك المزوّد تنظيف النقل لمعرّفات المزوّدين المخصصة ضمن عائلة النقل نفسها                                                                                     |
| `normalizeConfig`                 | يطبّع `models.providers.<id>` قبل حل وقت التشغيل/المزوّد                                                                         | عندما يحتاج المزوّد إلى تنظيف الإعدادات الذي ينبغي أن يكون ضمن Plugin؛ كما توفر الأدوات المساعدة المضمّنة لعائلة Google دعمًا احتياطيًا لإدخالات إعدادات Google المدعومة |
| `applyNativeStreamingUsageCompat` | يطبّق عمليات إعادة كتابة التوافق الأصلية لاستخدام البث على مزوّدي الإعدادات                                                      | عندما يحتاج المزوّد إلى إصلاحات لبيانات استخدام البث الأصلية الوصفية تعتمد على نقطة النهاية                                                                         |
| `resolveConfigApiKey`             | يحل مصادقة علامة البيئة لمزوّدي الإعدادات قبل تحميل مصادقة وقت التشغيل                                                          | عندما تعرض المزوّدات خطافات خاصة بها لحل مفتاح API من علامة البيئة                                                                                                  |
| `resolveSyntheticAuth`            | يعرض مصادقة محلية/مستضافة ذاتيًا أو مدعومة بالإعدادات من دون تخزين نص صريح                                                       | عندما يستطيع المزوّد العمل باستخدام علامة اعتماد اصطناعية/محلية                                                                                                    |
| `resolveExternalAuthProfiles`     | يركّب ملفات تعريف المصادقة الخارجية التي يملكها المزوّد؛ القيمة الافتراضية لـ `persistence` هي `runtime-only` لبيانات الاعتماد التي تملكها CLI/التطبيق | عندما يعيد المزوّد استخدام بيانات اعتماد مصادقة خارجية من دون تخزين رموز التحديث المنسوخة؛ صرّح بـ `contracts.externalAuthProviders` في البيان                      |
| `shouldDeferSyntheticProfileAuth` | يخفض أولوية العناصر النائبة لملفات التعريف الاصطناعية المخزنة خلف المصادقة المدعومة بالبيئة/الإعدادات                             | عندما يخزّن المزوّد ملفات تعريف اصطناعية نائبة ينبغي ألا تتقدم في الأولوية                                                                                          |
| `resolveDynamicModel`             | رجوع احتياطي متزامن لمعرّفات النماذج التي يملكها المزوّد ولم توجد بعد في السجل المحلي                                             | عندما يقبل المزوّد معرّفات نماذج اعتباطية من المصدر العلوي                                                                                                         |
| `prepareDynamicModel`             | يجري تهيئة غير متزامنة، ثم يُشغَّل `resolveDynamicModel` مجددًا                                                                  | عندما يحتاج المزوّد إلى بيانات وصفية من الشبكة قبل حل المعرّفات غير المعروفة                                                                                        |
| `normalizeResolvedModel`          | إعادة الكتابة النهائية قبل أن يستخدم المشغّل المضمّن النموذج المحلول                                                             | عندما يحتاج المزوّد إلى إعادة كتابة النقل لكنه يظل يستخدم نقلًا أساسيًا                                                                                            |
| `normalizeToolSchemas`            | يطبّع مخططات الأدوات قبل أن يراها المشغّل المضمّن                                                                                | عندما يحتاج المزوّد إلى تنظيف مخططات عائلة النقل                                                                                                                    |
| `inspectToolSchemas`              | يعرض تشخيصات المخططات التي يملكها المزوّد بعد التطبيع                                                                            | عندما يريد المزوّد تحذيرات بشأن الكلمات المفتاحية من دون تعليم النواة قواعد خاصة بالمزوّد                                                                           |
| `resolveReasoningOutputMode`      | يحدد عقد إخراج الاستدلال الأصلي مقابل الموسوم                                                                                     | عندما يحتاج المزوّد إلى إخراج استدلال/نهائي موسوم بدلًا من الحقول الأصلية                                                                                           |
| `prepareExtraParams`              | يطبّع معاملات الطلب قبل أغلفة خيارات البث العامة                                                                                 | عندما يحتاج المزوّد إلى معاملات طلب افتراضية أو تنظيف معاملات خاص بكل مزوّد                                                                                         |
| `createStreamFn`                  | يستبدل مسار البث المعتاد بالكامل بنقل مخصص                                                                                        | عندما يحتاج المزوّد إلى بروتوكول سلكي مخصص، وليس مجرد غلاف                                                                                                         |
| `wrapStreamFn`                    | غلاف للبث بعد تطبيق الأغلفة العامة                                                                                                | عندما يحتاج المزوّد إلى أغلفة توافق لترويسات الطلب/نصه/نموذجه من دون نقل مخصص                                                                                        |
| `resolveTransportTurnState`       | يرفق ترويسات أو بيانات وصفية أصلية للنقل لكل دورة                                                                                 | عندما يريد المزوّد من وسائل النقل العامة إرسال هوية الدورة الأصلية الخاصة به                                                                                        |
| `resolveWebSocketSessionPolicy`   | يرفق ترويسات WebSocket أصلية أو سياسة تهدئة للجلسة                                                                                | عندما يريد المزوّد من وسائل نقل WS العامة ضبط ترويسات الجلسة أو سياسة الرجوع الاحتياطي                                                                               |
| `formatApiKey`                    | منسّق ملف تعريف المصادقة: يتحول ملف التعريف المخزن إلى سلسلة `apiKey` لوقت التشغيل                                                 | عندما يخزّن المزوّد بيانات وصفية إضافية للمصادقة ويحتاج إلى بنية مخصصة لرمز وقت التشغيل                                                                              |
| `refreshOAuth`                    | تجاوز لتحديث OAuth لنقاط نهاية تحديث مخصصة أو سياسة فشل التحديث                                                                  | عندما لا يتوافق المزوّد مع أدوات التحديث المشتركة في OpenClaw                                                                                                      |
| `buildAuthDoctorHint`             | تلميح إصلاح يُلحق عند فشل تحديث OAuth                                                                                             | عندما يحتاج المزوّد إلى إرشادات إصلاح للمصادقة يملكها بعد فشل التحديث                                                                                               |
| `matchesContextOverflowError`     | أداة مطابقة يملكها المزوّد لتجاوز نافذة السياق                                                                                    | عندما تكون لدى المزوّد أخطاء تجاوز أولية قد لا تكتشفها الأساليب الإرشادية العامة                                                                                    |
| `classifyFailoverReason`          | تصنيف يملكه المزوّد لسبب تجاوز الفشل                                                                                              | عندما يستطيع المزوّد تعيين أخطاء API/النقل الأولية إلى تحديد المعدل/الحمل الزائد/غير ذلك                                                                             |
| `isCacheTtlEligible`              | سياسة ذاكرة التخزين المؤقت للمطالبات لمزوّدي الوكيل/النقل الخلفي                                                                  | عندما يحتاج المزوّد إلى تقييد مدة صلاحية ذاكرة التخزين المؤقت بحسب الوكيل                                                                                           |
| `buildMissingAuthMessage`         | بديل لرسالة الاسترداد العامة عند فقدان المصادقة                                                                                   | عندما يحتاج المزوّد إلى تلميح استرداد خاص به عند فقدان المصادقة                                                                                                    |
| `augmentModelCatalog`             | صفوف كتالوج اصطناعية/نهائية تُلحق بعد الاكتشاف (مهجور، انظر أدناه)                                                               | عندما يحتاج المزوّد إلى صفوف اصطناعية للتوافق المستقبلي في `models list` وأدوات الاختيار                                                                             |
| `resolveThinkingProfile`          | مجموعة مستويات `/think` الخاصة بالنموذج وتسميات العرض والقيمة الافتراضية                                                         | عندما يعرض المزوّد تدرجًا مخصصًا للتفكير أو تسمية ثنائية للنماذج المحددة                                                                                            |
| `isBinaryThinking`                | خطاف توافق لتبديل الاستدلال بين التشغيل/الإيقاف                                                                                   | عندما يعرض المزوّد التفكير الثنائي تشغيل/إيقاف فقط                                                                                                                  |
| `supportsXHighThinking`           | خطاف توافق لدعم استدلال `xhigh`                                                                                                  | عندما يريد المزوّد إتاحة `xhigh` لمجموعة فرعية فقط من النماذج                                                                                                      |
| `resolveDefaultThinkingLevel`     | خطاف توافق لمستوى `/think` الافتراضي                                                                                              | عندما يملك المزوّد سياسة `/think` الافتراضية لعائلة نماذج                                                                                                          |
| `isModernModelRef`                | أداة مطابقة للنماذج الحديثة لمرشحات ملفات التعريف الحية واختيار اختبار الدخان                                                     | عندما يملك المزوّد مطابقة النموذج المفضّل للاختبارات الحية/اختبارات الدخان                                                                                          |
| `prepareRuntimeAuth`              | يستبدل بيانات اعتماد مضبوطة بالرمز/المفتاح الفعلي لوقت التشغيل قبل الاستدلال مباشرة                                                | عندما يحتاج المزوّد إلى تبادل رمز أو بيانات اعتماد طلب قصيرة العمر                                                                                                 |
| `resolveUsageAuth`                | يحل بيانات اعتماد الاستخدام/الفوترة لـ `/usage` وأسطح الحالة ذات الصلة                                                           | عندما يحتاج المزوّد إلى تحليل مخصص لرمز الاستخدام/الحصة أو إلى بيانات اعتماد استخدام مختلفة                                                                         |
| `fetchUsageSnapshot`              | يجلب لقطات الاستخدام/الحصة الخاصة بالمزوّد ويطبّعها بعد حل المصادقة                                                               | عندما يحتاج المزوّد إلى نقطة نهاية استخدام خاصة به أو محلل للحمولة                                                                                                 |
| `createEmbeddingProvider`         | إنشاء محوّل تضمين مملوك للموفّر للذاكرة/البحث                                                     | سلوك تضمين الذاكرة يتبع Plugin الموفّر                                                                                    |
| `buildReplayPolicy`               | إرجاع سياسة إعادة تشغيل تتحكم في معالجة نص المحادثة للموفّر                                        | يحتاج الموفّر إلى سياسة مخصصة لنص المحادثة (مثل إزالة كتل التفكير)                                                               |
| `sanitizeReplayHistory`           | إعادة كتابة سجل إعادة التشغيل بعد التنظيف العام لنص المحادثة                                                        | يحتاج الموفّر إلى عمليات إعادة كتابة خاصة به لإعادة التشغيل تتجاوز مساعدات Compaction المشتركة                                                             |
| `validateReplayTurns`             | التحقق النهائي من أدوار إعادة التشغيل أو إعادة تشكيلها قبل المشغّل المضمّن                                           | يحتاج نقل الموفّر إلى تحقق أكثر صرامة من الأدوار بعد التنقية العامة                                                                    |
| `onModelSelected`                 | تشغيل الآثار الجانبية اللاحقة للاختيار والمملوكة للموفّر                                                                 | يحتاج الموفّر إلى بيانات القياس عن بُعد أو حالة مملوكة له عند تنشيط نموذج                                                                  |

تتحقق `normalizeModelId` و`normalizeTransport` و`normalizeConfig` أولًا من
Plugin المزوّد المطابق، ثم تنتقل إلى Plugins المزوّدين الآخرين القادرين على
استخدام الخطافات حتى يغيّر أحدها فعليًا معرّف النموذج أو النقل/الإعداد. يحافظ
ذلك على عمل طبقات المزوّد البديلة/المتوافقة دون أن يُطلب من المستدعي معرفة أي
Plugin مضمّن يملك إعادة الكتابة. إذا لم يُعِد أي خطاف مزوّد كتابة إدخال إعداد
مدعوم من عائلة Google، فسيظل مُطبِّع إعداد Google المضمّن يطبّق عملية تنظيف
التوافق تلك.

إذا كان المزوّد يحتاج إلى بروتوكول اتصال مخصص بالكامل أو منفّذ طلبات مخصص،
فهذه فئة مختلفة من الامتدادات. هذه الخطافات مخصصة لسلوك المزوّد الذي يستمر
في العمل ضمن حلقة الاستدلال العادية في OpenClaw.

تقرر `resolveUsageAuth` ما إذا كان ينبغي لـ OpenClaw استدعاء
`fetchUsageSnapshot` أو الرجوع إلى الحل العام لبيانات الاعتماد لواجهات
الاستخدام/الحالة. أعد `{ token, accountId?, subscriptionType?, rateLimitTier? }`
عندما يملك المزوّد بيانات اعتماد للاستخدام (تنتقل بيانات الخطة الوصفية
الاختيارية إلى `fetchUsageSnapshot`)، وأعد `{ handled: true }` عندما تكون
مصادقة الاستخدام المملوكة للمزوّد قد عالجت الطلب ويجب أن تمنع الرجوع العام
إلى مفتاح API أو OAuth، وأعد `null` أو `undefined` عندما لا يعالج المزوّد
مصادقة الاستخدام.

صرّح ببيانات اعتماد المؤسسة أو الفوترة في
`providerUsageAuthEnvVars` ضمن البيان. يتيح ذلك لواجهات الاكتشاف العام وتنقية
الأسرار التعرّف عليها دون جعلها مرشحة لمصادقة الاستدلال.

### مثال على مزوّد

```ts
api.registerProvider({
  id: "example-proxy",
  label: "Example Proxy",
  auth: [],
  catalog: {
    order: "simple",
    run: async (ctx) => {
      const apiKey = ctx.resolveProviderApiKey("example-proxy").apiKey;
      if (!apiKey) {
        return null;
      }
      return {
        provider: {
          baseUrl: "https://proxy.example.com/v1",
          apiKey,
          api: "openai-completions",
          models: [{ id: "auto", name: "Auto" }],
        },
      };
    },
  },
  resolveDynamicModel: (ctx) => ({
    id: ctx.modelId,
    name: ctx.modelId,
    provider: "example-proxy",
    api: "openai-completions",
    baseUrl: "https://proxy.example.com/v1",
    reasoning: false,
    input: ["text"],
    cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
    contextWindow: 128000,
    maxTokens: 8192,
  }),
  prepareRuntimeAuth: async (ctx) => {
    const exchanged = await exchangeToken(ctx.apiKey);
    return {
      apiKey: exchanged.token,
      baseUrl: exchanged.baseUrl,
      expiresAt: exchanged.expiresAt,
    };
  },
  resolveUsageAuth: async (ctx) => {
    const auth = await ctx.resolveOAuthToken();
    return auth ? { token: auth.token } : null;
  },
  fetchUsageSnapshot: async (ctx) => {
    return await fetchExampleProxyUsage(ctx.token, ctx.timeoutMs, ctx.fetchFn);
  },
});
```

### أمثلة مضمّنة

تجمع Plugins المزوّدين المضمّنة الخطافات أعلاه لتلائم احتياجات كل مورّد
إلى الفهرس والمصادقة والتفكير وإعادة التشغيل والاستخدام. تعيش مجموعة
الخطافات المرجعية مع كل Plugin ضمن `extensions/`؛ وتوضح هذه الصفحة الأشكال
بدلًا من تكرار القائمة.

<AccordionGroup>
  <Accordion title="مزوّدو الفهرس بالتمرير المباشر">
    يسجّل OpenRouter وKilocode وZ.AI وxAI الخاصية `catalog` بالإضافة إلى
    `resolveDynamicModel` / `prepareDynamicModel` حتى يتمكنوا من إظهار معرّفات
    النماذج في المنبع قبل فهرس OpenClaw الثابت.
  </Accordion>
  <Accordion title="مزوّدو OAuth ونقاط نهاية الاستخدام">
    يقرن GitHub Copilot وGemini CLI وChatGPT Codex وMiniMax وXiaomi وz.ai
    ‏`prepareRuntimeAuth` أو `formatApiKey` مع `resolveUsageAuth` +
    `fetchUsageSnapshot` لامتلاك تبادل الرمز المميز وتكامل `/usage`.
  </Accordion>
  <Accordion title="عائلات تنظيف إعادة التشغيل والنصوص المنسوخة">
    تتيح العائلات المشتركة المسماة (`google-gemini` و`passthrough-gemini`
    و`anthropic-by-model` و`hybrid-anthropic-openai`) للمزوّدين الاشتراك في
    سياسة النصوص المنسوخة عبر `buildReplayPolicy` بدلًا من أن يعيد كل Plugin
    تنفيذ عملية التنظيف.
  </Accordion>
  <Accordion title="مزوّدو الفهرس فقط">
    تسجّل `byteplus` و`cloudflare-ai-gateway` و`huggingface` و`kimi-coding`
    و`nvidia` و`qianfan` و`synthetic` و`together` و`venice`
    و`vercel-ai-gateway` و`volcengine` الخاصية `catalog` فقط وتستخدم حلقة
    الاستدلال المشتركة.
  </Accordion>
  <Accordion title="مساعدات التدفق الخاصة بـ Anthropic">
    تعيش ترويسات الإصدار التجريبي و`/fast` / `serviceTier` و`context1m` داخل
    واجهة `api.ts` / `contract-api.ts` العامة لـ Plugin ‏Anthropic
    (`wrapAnthropicProviderStream` و`resolveAnthropicBetas`
    و`resolveAnthropicFastMode` و`resolveAnthropicServiceTier`) بدلًا من SDK
    العام.
  </Accordion>
</AccordionGroup>

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

يمكن لـ Plugins الوصول إلى مساعدات أساسية محددة عبر `api.runtime`. لتحويل
النص إلى كلام:

```ts
const clip = await api.runtime.tts.textToSpeech({
  text: "Hello from OpenClaw",
  cfg: api.config,
});

const result = await api.runtime.tts.textToSpeechTelephony({
  text: "Hello from OpenClaw",
  cfg: api.config,
});

const voices = await api.runtime.tts.listVoices({
  provider: "elevenlabs",
  cfg: api.config,
});
```

ملاحظات:

- تعيد `textToSpeech` حمولة إخراج تحويل النص إلى كلام الأساسية المعتادة لواجهات الملفات/الملاحظات الصوتية.
- تستخدم إعداد `messages.tts` الأساسي واختيار المزوّد.
- تعيد مخزنًا مؤقتًا لصوت PCM مع معدل العينة. يجب على Plugins إعادة أخذ العينات/الترميز للمزوّدين.
- تكون `listVoices` اختيارية لكل مزوّد. استخدمها في أدوات اختيار الأصوات أو تدفقات الإعداد المملوكة للمورّد.
- يمرّر الجزء الأساسي مهلة طلب محلولة إلى خطافات `listVoices` الخاصة بالمزوّد؛ ويمكن لإعدادات المهلة الخاصة بالمزوّد تجاوزها.
- يمكن أن تتضمن قوائم الأصوات بيانات وصفية أغنى، مثل اللغة والمنطقة والجنس ووسوم الشخصية، لاستخدامها في أدوات الاختيار المدركة للمزوّد.
- يدعم OpenAI وElevenLabs الاتصالات الهاتفية حاليًا. أما Microsoft فلا يدعمها.

يمكن لـ Plugins أيضًا تسجيل مزوّدي الكلام عبر `api.registerSpeechProvider(...)`.

```ts
api.registerSpeechProvider({
  id: "acme-speech",
  label: "Acme Speech",
  isConfigured: ({ config }) => Boolean(config.messages?.tts),
  synthesize: async (req) => {
    return {
      audioBuffer: Buffer.from([]),
      outputFormat: "mp3",
      fileExtension: ".mp3",
      voiceCompatible: false,
    };
  },
});
```

ملاحظات:

- احتفظ بسياسة تحويل النص إلى كلام والرجوع وتسليم الردود في الجزء الأساسي.
- استخدم مزوّدي الكلام لسلوك التوليف المملوك للمورّد.
- يُطبَّع إدخال Microsoft القديم `edge` إلى معرّف المزوّد `microsoft`.
- نموذج الملكية المفضّل موجّه نحو الشركة: يمكن لـ Plugin مورّد واحد امتلاك
  مزوّدي النص والكلام والصور والوسائط المستقبلية مع إضافة OpenClaw لعقود
  القدرات تلك.

لفهم الصور/الصوت/الفيديو، تسجّل Plugins مزوّدًا واحدًا ذا نوع محدد لفهم
الوسائط بدلًا من حزمة مفاتيح/قيم عامة:

```ts
api.registerMediaUnderstandingProvider({
  id: "google",
  capabilities: ["image", "audio", "video"],
  describeImage: async (req) => ({ text: "..." }),
  transcribeAudio: async (req) => ({ text: "..." }),
  describeVideo: async (req) => ({ text: "..." }),
});
```

ملاحظات:

- احتفظ بالتنسيق والرجوع والإعداد وتوصيل القنوات في الجزء الأساسي.
- احتفظ بسلوك المورّد في Plugin المزوّد.
- يجب أن يظل التوسّع الإضافي محدد الأنواع: طرائق اختيارية جديدة، وحقول نتائج
  اختيارية جديدة، وقدرات اختيارية جديدة.
- يتبع توليد الفيديو النمط نفسه بالفعل:
  - يمتلك الجزء الأساسي عقد القدرة ومساعد وقت التشغيل
  - تسجّل Plugins المورّدين `api.registerVideoGenerationProvider(...)`
  - تستهلك Plugins الميزات/القنوات `api.runtime.videoGeneration.*`

بالنسبة إلى مساعدات وقت التشغيل لفهم الوسائط، يمكن لـ Plugins استدعاء:

```ts
const image = await api.runtime.mediaUnderstanding.describeImageFile({
  filePath: "/tmp/inbound-photo.jpg",
  cfg: api.config,
  agentDir: "/tmp/agent",
});

const video = await api.runtime.mediaUnderstanding.describeVideoFile({
  filePath: "/tmp/inbound-video.mp4",
  cfg: api.config,
});

const extraction = await api.runtime.mediaUnderstanding.extractStructuredWithModel({
  provider: "codex",
  model: "gpt-5.6-sol",
  input: [
    {
      type: "image",
      buffer: receiptImageBuffer,
      fileName: "receipt.png",
      mime: "image/png",
    },
    { type: "text", text: "Use the printed fields as the source of truth." },
  ],
  instructions: "Return entities and searchable tags.",
  schemaName: "example.evidence",
  jsonSchema: {
    type: "object",
    properties: {
      entities: { type: "array", items: { type: "string" } },
      tags: { type: "array", items: { type: "string" } },
    },
  },
  cfg: api.config,
});
```

لنسخ الصوت نصيًا، يمكن لـ Plugins استخدام وقت تشغيل فهم الوسائط أو الاسم
البديل الأقدم لـ STT:

```ts
const { text } = await api.runtime.mediaUnderstanding.transcribeAudioFile({
  filePath: "/tmp/inbound-audio.ogg",
  cfg: api.config,
  // Optional when MIME cannot be inferred reliably:
  mime: "audio/ogg",
});
```

ملاحظات:

- ‏`api.runtime.mediaUnderstanding.*` هي الواجهة المشتركة المفضّلة لفهم
  الصور/الصوت/الفيديو.
- ‏`extractStructuredWithModel(...)` هي الواجهة الموجّهة إلى Plugins
  للاستخراج المحدود المملوك للمزوّد الذي يبدأ بالصور. ضمّن إدخال صورة واحدًا
  على الأقل؛ وتكون إدخالات النص سياقًا تكميليًا. تمتلك Plugins المنتج مساراتها
  ومخططاتها، بينما يمتلك OpenClaw الحد الفاصل بين المزوّد ووقت التشغيل.
- تستخدم إعداد الصوت الأساسي لفهم الوسائط (`tools.media.audio`) وترتيب الرجوع بين المزوّدين.
- تعيد `{ text: undefined }` عندما لا يُنتج أي إخراج للنسخ النصي (مثلًا عند تخطي الإدخال أو عدم دعمه).
- تظل `api.runtime.stt.transcribeAudioFile(...)` اسمًا بديلًا للتوافق.

يمكن لـ Plugins أيضًا تشغيل عمليات الوكلاء الفرعيين في الخلفية عبر
`api.runtime.subagent`:

```ts
const result = await api.runtime.subagent.run({
  sessionKey: "agent:main:subagent:search-helper",
  message: "Expand this query into focused follow-up searches.",
  provider: "openai",
  model: "gpt-4.1-mini",
  deliver: false,
});
```

ملاحظات:

- ‏`provider` و`model` تجاوزان اختياريان لكل عملية تشغيل، وليسا تغييرات دائمة للجلسة.
- لا يحترم OpenClaw حقول التجاوز هذه إلا للمستدعين الموثوقين.
- بالنسبة إلى عمليات الرجوع المملوكة لـ Plugin، يجب على المشغّلين الاشتراك صراحةً باستخدام `plugins.entries.<id>.subagent.allowModelOverride: true`.
- استخدم `plugins.entries.<id>.subagent.allowedModels` لتقييد Plugins الموثوقة بأهداف `provider/model` معيارية محددة، أو `"*"` للسماح صراحةً بأي هدف.
- تظل عمليات الوكيل الفرعي من Plugins غير الموثوقة تعمل، لكن طلبات التجاوز تُرفض بدلًا من الرجوع بصمت.
- تُوسَم جلسات الوكيل الفرعي التي تنشئها Plugins بمعرّف Plugin المنشئ. يمكن لعملية الرجوع `api.runtime.subagent.deleteSession(...)` حذف تلك الجلسات المملوكة فقط؛ ولا يزال حذف جلسة عشوائية يتطلب طلب Gateway بنطاق إداري.

للبحث على الويب، يمكن لـ Plugins استهلاك مساعد وقت التشغيل المشترك بدلًا من
الوصول إلى توصيل أداة الوكيل:

```ts
const providers = api.runtime.webSearch.listProviders({
  config: api.config,
});

const result = await api.runtime.webSearch.search({
  config: api.config,
  args: {
    query: "OpenClaw plugin runtime helpers",
    count: 5,
  },
});
```

يمكن لـ Plugins أيضًا تسجيل مزوّدي البحث على الويب عبر
`api.registerWebSearchProvider(...)`.

ملاحظات:

- احتفظ باختيار المزوّد وحل بيانات الاعتماد ودلالات الطلب المشتركة في الجزء الأساسي.
- استخدم مزوّدي البحث على الويب لعمليات نقل البحث الخاصة بالمورّد.
- ‏`api.runtime.webSearch.*` هي الواجهة المشتركة المفضّلة لـ Plugins الميزات/القنوات التي تحتاج إلى سلوك البحث دون الاعتماد على غلاف أداة الوكيل.

### `api.runtime.imageGeneration`

```ts
const result = await api.runtime.imageGeneration.generate({
  config: api.config,
  args: { prompt: "A friendly lobster mascot", size: "1024x1024" },
});

const providers = api.runtime.imageGeneration.listProviders({
  config: api.config,
});
```

- ‏`generate(...)`: توليد صورة باستخدام سلسلة مزوّدي توليد الصور المضبوطة.
- ‏`listProviders(...)`: سرد مزوّدي توليد الصور المتاحين وقدراتهم.

## مسارات HTTP في Gateway

يمكن لـ Plugins كشف نقاط نهاية HTTP باستخدام `api.registerHttpRoute(...)`.

```ts
api.registerHttpRoute({
  path: "/acme/webhook",
  auth: "plugin",
  match: "exact",
  handler: async (_req, res) => {
    res.statusCode = 200;
    res.end("ok");
    return true;
  },
});
```

حقول المسار:

- `path`: مسار التوجيه ضمن خادم HTTP الخاص بـ Gateway.
- `auth`: مطلوب، ويكون `"gateway"` أو `"plugin"`. استخدم `"gateway"` لفرض مصادقة Gateway المعتادة، أو `"plugin"` للمصادقة التي يديرها Plugin أو للتحقق من Webhook.
- `match`: اختياري. `"exact"` (الافتراضي) أو `"prefix"`.
- `handleUpgrade`: معالج اختياري لطلبات ترقية WebSocket على المسار نفسه.
- `replaceExisting`: اختياري. يسمح للـ Plugin نفسه باستبدال تسجيل مساره الحالي.
- `handler`: أرجِع `true` عندما يكون المسار قد عالج الطلب.

ملاحظات:

- أُزيل `api.registerHttpHandler(...)`، وسيؤدي استخدامه إلى خطأ عند تحميل Plugin. استخدم `api.registerHttpRoute(...)` بدلًا منه.
- يجب أن تعلن مسارات Plugin عن `auth` صراحةً.
- تُرفض تعارضات `path + match` المتطابقة ما لم تكن `replaceExisting: true`، ولا يمكن لـ Plugin استبدال مسار تابع لـ Plugin آخر.
- تُرفض المسارات المتداخلة ذات مستويات `auth` المختلفة. اجعل سلاسل الانتقال الاحتياطي `exact`/`prefix` على مستوى المصادقة نفسه فقط.
- لا تتلقى المسارات ذات `auth: "plugin"` نطاقات وقت تشغيل المشغّل تلقائيًا. فهي مخصصة لعمليات Webhook والتحقق من التوقيعات التي يديرها Plugin، وليست لاستدعاءات أدوات Gateway المساعدة ذات الامتيازات.
- تعمل المسارات ذات `auth: "gateway"` داخل نطاق وقت تشغيل طلب Gateway. والسطح الافتراضي (`gatewayRuntimeScopeSurface: "write-default"`) متحفظ عمدًا:
  - تحصل مصادقة حامل السر المشترك (`gateway.auth.mode = "token"` / `"password"`) وأي طريقة مصادقة لا تستخدم الوكيل الموثوق على نطاق `operator.write` واحد، حتى إذا أرسل المستدعي `x-openclaw-scopes`
  - يحتفظ مستدعو `trusted-proxy` الذين لا يرسلون ترويسة `x-openclaw-scopes` صريحة أيضًا بالسطح القديم المقتصر على `operator.write`
  - يحصل مستدعو `trusted-proxy` الذين يرسلون `x-openclaw-scopes` على النطاقات المعلنة بدلًا من ذلك
  - يمكن للمسار الاشتراك في `gatewayRuntimeScopeSurface: "trusted-operator"` لاحترام `x-openclaw-scopes` دائمًا في أوضاع المصادقة التي تحمل هوية (مع الرجوع إلى مجموعة نطاقات CLI الافتراضية الكاملة عند غياب الترويسة)
- قاعدة عملية: لا تفترض أن مسار Plugin الموثق عبر Gateway يشكل ضمنيًا سطح إدارة. إذا كان مسارك يحتاج إلى سلوك مخصص للمسؤول فقط، فاشترك في سطح النطاق `trusted-operator`، واشترط وضع مصادقة يحمل هوية، ووثّق عقد ترويسة `x-openclaw-scopes` الصريح.
- بعد مطابقة المسار والمصادقة، تشارك المعالجات العادية في قبول العمل الجذري لـ Gateway. يعيد Gateway في حالة الاستعداد أو إعادة التشغيل الرمز `503` قبل استدعاء المعالج. والاستثناء المحدود هو مسار ذو `auth: "gateway"` تمنحه التظاهرة صلاحية، ويشترك أيضًا في سطح `trusted-operator` الخاص بالمسار؛ إذ يظل قابلًا للوصول حتى لا يتعطل إرسال التحكم في التعليق، بينما تظل المسارات الشقيقة العادية التابعة للـ Plugin نفسه خلف حد القبول. تستخدم ملكية WebSocket في `handleUpgrade` حد القبول الذري نفسه؛ وما إن يقبل المعالج مقبسًا، تصبح دورة حياة المقبس اللاحقة مملوكة للـ Plugin ولا يتتبعها هذا الحد.

## مسارات استيراد SDK الخاصة بالـ Plugin

استخدم المسارات الفرعية المحددة لـ SDK بدلًا من مجمّع الجذر الأحادي `openclaw/plugin-sdk`
عند إنشاء Plugins جديدة. المسارات الفرعية الأساسية:

| المسار الفرعي                        | الغرض                                              |
| ----------------------------------- | -------------------------------------------------- |
| `openclaw/plugin-sdk/plugin-entry`  | بدائيات تسجيل Plugin                               |
| `openclaw/plugin-sdk/channel-core`  | أدوات مساعدة لإدخال القناة وبنائها                 |
| `openclaw/plugin-sdk/core`          | أدوات مساعدة عامة مشتركة وعقد شامل                 |
| `openclaw/plugin-sdk/config-schema` | مخطط Zod الجذري لـ `openclaw.json`‏ (`OpenClawSchema`) |

تختار Plugins القنوات من عائلة من الوصلات المحددة — `channel-setup`،
و`setup-runtime`، و`setup-tools`، و`channel-pairing`،
و`channel-contract`، و`channel-feedback`، و`channel-inbound`، و`channel-outbound`،
و`command-auth`، و`secret-input`، و`webhook-ingress`،
و`channel-targets`، و`channel-actions`. ينبغي توحيد سلوك الموافقة
ضمن عقد `approvalCapability` واحد بدلًا من توزيعه على حقول
Plugin غير المرتبطة. راجع [Plugins القنوات](/ar/plugins/sdk-channel-plugins).

توجد أدوات وقت التشغيل والإعدادات المساعدة ضمن مسارات فرعية مركزة مطابقة من نمط `*-runtime`
(`approval-runtime`، و`agent-runtime`، و`lazy-runtime`، و`directory-runtime`،
و`text-runtime`، و`runtime-store`، و`system-event-runtime`، و`heartbeat-runtime`،
و`channel-activity-runtime`، وغيرها). فضّل `config-contracts`،
و`plugin-config-runtime`، و`runtime-config-snapshot`، و`config-mutation`
بدلًا من مجمّع التوافق الواسع `config-runtime`.

<Info>
تُعد `openclaw/plugin-sdk/channel-runtime`، و`openclaw/plugin-sdk/channel-lifecycle`،
وواجهات أدوات القنوات المساعدة الصغيرة، و`openclaw/plugin-sdk/outbound-runtime`،
و`openclaw/plugin-sdk/outbound-send-deps`، و`openclaw/plugin-sdk/config-runtime`،
و`openclaw/plugin-sdk/infra-runtime` حشوات توافق مهملة
للـ Plugins الأقدم. ينبغي أن تستورد الشيفرة الجديدة بدائيات عامة أضيق بدلًا منها.
</Info>

نقاط الدخول الداخلية للمستودع (لكل جذر حزمة Plugin مضمّنة):

- `index.js` — نقطة دخول Plugin المضمّنة
- `api.js` — مجمّع الأدوات المساعدة والأنواع
- `runtime-api.js` — مجمّع مخصص لوقت التشغيل
- `setup-entry.js` — نقطة دخول Plugin الإعداد

يجب ألا تستورد Plugins الخارجية إلا المسارات الفرعية `openclaw/plugin-sdk/*`. لا
تستورد مطلقًا `src/*` من حزمة Plugin أخرى، سواء من النواة أو من Plugin آخر.
تفضّل نقاط الدخول المحمّلة عبر الواجهة لقطة إعدادات وقت التشغيل النشطة عند
وجودها، ثم ترجع إلى ملف الإعدادات المحلول على القرص.

توجد مسارات فرعية خاصة بالقدرات، مثل `image-generation`، و`media-understanding`،
و`speech`، لأن Plugins المضمّنة تستخدمها حاليًا. لكنها ليست
عقودًا خارجية ثابتة تلقائيًا على المدى الطويل — تحقّق من صفحة مرجع SDK
ذات الصلة عند الاعتماد عليها.

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

ينبغي أن تمتلك Plugins مساهمات مخطط `describeMessageTool(...)` الخاصة بالقنوات
للعمليات غير المتعلقة بالرسائل، مثل التفاعلات، وإشعارات القراءة، والاستطلاعات.
ينبغي أن يستخدم العرض المشترك للإرسال عقد `MessagePresentation` العام
بدلًا من حقول الأزرار أو المكوّنات أو الكتل أو البطاقات الأصلية الخاصة بمزوّد الخدمة.
راجع [عرض الرسائل](/ar/plugins/message-presentation) للاطلاع على العقد،
وقواعد الرجوع، وتعيين مزوّدي الخدمة، وقائمة التحقق الخاصة بمؤلف Plugin.

تعلن Plugins القادرة على الإرسال عما يمكنها عرضه عبر قدرات الرسائل:

- `presentation` لكتل العرض الدلالية (`text`، و`context`،
  و`divider`، و`chart`، و`table`، و`buttons`، و`select`)
- `delivery-pin` لطلبات تثبيت التسليم

تقرر النواة ما إذا كانت ستعرض المحتوى تقديميًا بصورة أصلية أو ستخفضه إلى نص.
لا تكشف منافذ التفاف لواجهة المستخدم الأصلية الخاصة بمزوّد الخدمة من أداة الرسائل العامة.
تظل أدوات SDK المساعدة المهملة للمخططات الأصلية القديمة مُصدّرة للـ Plugins
الخارجية الحالية، لكن ينبغي ألا تستخدمها Plugins الجديدة.

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

ينبغي أن تمتلك Plugins القنوات دلالات الأهداف الخاصة بالقنوات. أبقِ مضيف
الصادر المشترك عامًا، واستخدم سطح محوّل المراسلة لقواعد مزوّد الخدمة:

- يقرر `messaging.inferTargetChatType({ to })` ما إذا كان ينبغي التعامل مع هدف
  مطبّع باعتباره `direct` أو `group` أو `channel` قبل البحث في الدليل.
- يُعلِم `messaging.targetResolver.looksLikeId(raw, normalized)` النواة بما إذا كان
  الإدخال ينبغي أن ينتقل مباشرة إلى تحليل شبيه بالمعرّف بدلًا من البحث في الدليل.
- تسرد `messaging.targetResolver.reservedLiterals` الكلمات المجرّدة التي تمثل
  مراجع قناة أو جلسة لذلك المزوّد. يحافظ التحليل على إدخالات الدليل المضبوطة
  قبل رفض القيم الحرفية المحجوزة، ثم يفشل بصورة مغلقة عند عدم العثور عليها في
  الدليل.
- يُعد `messaging.targetResolver.resolveTarget(...)` آلية الرجوع الخاصة بالـ Plugin عندما
  تحتاج النواة إلى تحليل نهائي يملكه مزوّد الخدمة بعد التطبيع أو بعد عدم العثور
  على نتيجة في الدليل.
- يمتلك `messaging.resolveOutboundSessionRoute(...)` إنشاء مسار الجلسة
  الخاص بمزوّد الخدمة بعد تحليل الهدف.

التقسيم الموصى به:

- استخدم `inferTargetChatType` لقرارات الفئة التي ينبغي اتخاذها قبل
  البحث في الأقران أو المجموعات.
- استخدم `looksLikeId` للتحقق مما إذا كان ينبغي «التعامل مع هذا باعتباره معرّف هدف صريحًا/أصليًا».
- استخدم `resolveTarget` كآلية رجوع للتطبيع الخاص بمزوّد الخدمة، وليس
  للبحث الواسع في الدليل.
- احتفظ بالمعرّفات الأصلية الخاصة بمزوّد الخدمة، مثل معرّفات المحادثات، ومعرّفات الخيوط، وJIDs، والمقابض، ومعرّفات الغرف،
  داخل قيم `target` أو المعاملات الخاصة بمزوّد الخدمة، وليس في حقول SDK
  العامة.

## الأدلة المدعومة بالإعدادات

ينبغي أن تُبقي Plugins التي تشتق إدخالات الدليل من الإعدادات ذلك المنطق داخل
Plugin، وأن تعيد استخدام الأدوات المساعدة المشتركة من
`openclaw/plugin-sdk/directory-runtime`.

استخدم هذا عندما تحتاج القناة إلى أقران أو مجموعات مدعومة بالإعدادات، مثل:

- أقران الرسائل المباشرة المستندين إلى قائمة السماح
- خرائط القنوات أو المجموعات المضبوطة
- آليات رجوع ثابتة للدليل مقيّدة بنطاق الحساب

لا تتعامل الأدوات المساعدة المشتركة في `directory-runtime` إلا مع العمليات العامة:

- ترشيح الاستعلامات
- تطبيق الحدود
- أدوات إزالة التكرار والتطبيع المساعدة
- إنشاء `ChannelDirectoryEntry[]`

ينبغي أن يظل فحص الحساب الخاص بالقناة وتطبيع المعرّفات ضمن
تنفيذ Plugin.

## كتالوجات مزوّدي الخدمة

يمكن لـ Plugins مزوّدي الخدمة تعريف كتالوجات النماذج للاستدلال باستخدام
`registerProvider({ catalog: { run(...) { ... } } })`.

تعيد `catalog.run(...)` البنية نفسها التي يكتبها OpenClaw في
`models.providers`:

- `{ provider }` لإدخال مزوّد خدمة واحد
- `{ providers }` لعدة إدخالات لمزوّدي الخدمة

استخدم `catalog` عندما يمتلك Plugin معرّفات النماذج الخاصة بمزوّد الخدمة، أو قيم
عناوين URL الأساسية الافتراضية، أو بيانات النماذج الوصفية المشروطة بالمصادقة.

يتحكم `catalog.order` في توقيت دمج كتالوج Plugin نسبةً إلى مزوّدي OpenClaw
الضمنيين المضمّنين:

- `simple`: مزوّدو خدمة يعتمدون على مفتاح API عادي أو متغيرات البيئة
- `profile`: مزوّدو خدمة يظهرون عند وجود ملفات تعريف مصادقة
- `paired`: مزوّدو خدمة ينشئون عدة إدخالات مترابطة لمزوّدي الخدمة
- `late`: المرور الأخير، بعد مزوّدي الخدمة الضمنيين الآخرين

تفوز إدخالات مزوّدي الخدمة اللاحقة عند تعارض المفاتيح، لذا يمكن للـ Plugins تجاوز
إدخال مزوّد خدمة مضمّن يحمل معرّف مزوّد الخدمة نفسه عن قصد.

يمكن للـ Plugins أيضًا نشر صفوف نماذج للقراءة فقط عبر
`api.registerModelCatalogProvider({ provider, kinds, staticCatalog, liveCatalog
})`. وهذا هو المسار المستقبلي لأسطح القوائم والمساعدة والاختيار، ويدعم صفوف
`text`، و`voice`، و`image_generation`، و`video_generation`، و`music_generation`.
تظل Plugins مزوّدي الخدمة مالكة لاستدعاءات نقاط النهاية الحية، وتبادل الرموز، وتعيين
استجابات المورّد؛ بينما تمتلك النواة بنية الصف المشتركة، وتسميات المصدر، وتنسيق
مساعدة أدوات الوسائط. تنشئ تسجيلات مزوّدي إنشاء الوسائط صفوف الكتالوج الثابتة
تلقائيًا من `defaultModel`، و`models`، و`capabilities`.

التوافق:

- لا يزال `discovery` يعمل كاسم مستعار قديم، لكنه يصدر تحذير إهمال
- إذا سُجّل كل من `catalog` و`discovery`، يستخدم OpenClaw‏ `catalog`
  ويصدر تحذيرًا
- أُهمل `augmentModelCatalog`؛ وينبغي أن تنشر مزوّدات الخدمة المضمّنة
  الصفوف التكميلية عبر `registerModelCatalogProvider`

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

إذا كان Plugin الخاص بك يسجل قناة، ففضّل تنفيذ
`plugin.config.inspectAccount(cfg, accountId)` إلى جانب `resolveAccount(...)`.

السبب:

- `resolveAccount(...)` هو مسار وقت التشغيل. ويُسمح له بافتراض أن بيانات الاعتماد
  متحققة بالكامل، وأن يفشل سريعًا عند غياب الأسرار المطلوبة.
- ينبغي ألا تحتاج مسارات أوامر القراءة فقط، مثل `openclaw status`، و`openclaw status --all`،
  و`openclaw channels status`، و`openclaw channels resolve`، ومسارات إصلاح
  doctor/الإعدادات، إلى إنشاء بيانات اعتماد وقت التشغيل لمجرد
  وصف الإعدادات.

السلوك الموصى به لـ `inspectAccount(...)`:

- أرجِع حالة وصفية للحساب فقط.
- حافظ على `enabled` و`configured`.
- ضمّن حقول مصدر بيانات الاعتماد/حالتها عند الاقتضاء، مثل:
  - `tokenSource`، `tokenStatus`
  - `botTokenSource`، `botTokenStatus`
  - `appTokenSource`، `appTokenStatus`
  - `signingSecretSource`، `signingSecretStatus`
- لا تحتاج إلى إرجاع قيم الرموز المميزة الأولية لمجرد الإبلاغ عن
  التوفّر للقراءة فقط. يكفي إرجاع `tokenStatus: "available"` (وحقل المصدر
  المطابق) لأوامر عرض الحالة.
- استخدم `configured_unavailable` عندما تكون بيانات الاعتماد مهيأة عبر SecretRef لكنها
  غير متاحة في مسار الأمر الحالي.

يتيح ذلك لأوامر القراءة فقط الإبلاغ بأن الحساب «مهيأ لكنه غير متاح في مسار
الأمر هذا» بدلًا من التعطل أو الإبلاغ خطأً بأن الحساب غير مهيأ.

## حزم الحزم

قد يتضمن دليل Plugin ملف `package.json` يحتوي على `openclaw.extensions`:

```json
{
  "name": "my-pack",
  "openclaw": {
    "extensions": ["./src/safety.ts", "./src/tools.ts"],
    "setupEntry": "./src/setup-entry.ts"
  }
}
```

يصبح كل إدخال Plugin. إذا أدرجت الحزمة امتدادات متعددة، يصبح معرّف Plugin
هو `<manifestOrPackageName>/<fileBase>` (تكون الأولوية لمعرّف البيان عند
وجوده؛ وإلا فيُستخدم اسم `package.json` غير ذي النطاق).

إذا كان Plugin الخاص بك يستورد تبعيات npm، فثبّتها في ذلك الدليل حتى يكون
`node_modules` متاحًا (`npm install` / `pnpm install`).

حاجز أمني: يجب أن يبقى كل إدخال في `openclaw.extensions` داخل دليل Plugin
بعد حل الروابط الرمزية. تُرفض الإدخالات التي تخرج من دليل الحزمة.

ملاحظة أمنية: يثبّت `openclaw plugins install` تبعيات Plugin باستخدام
`npm install --omit=dev --ignore-scripts` محلي للمشروع (من دون نصوص دورة الحياة،
ومن دون تبعيات تطوير في وقت التشغيل)، مع تجاهل إعدادات تثبيت npm العامة الموروثة.
حافظ على أشجار تبعيات Plugin «JS/TS خالصة» وتجنب الحزم التي تتطلب
عمليات بناء `postinstall`.

اختياري: يمكن أن يشير `openclaw.setupEntry` إلى وحدة خفيفة مخصصة للإعداد فقط.
عندما يحتاج OpenClaw إلى أسطح الإعداد لـ Plugin قناة معطّل، أو
عندما يكون Plugin قناة مفعّلًا لكنه لا يزال غير مهيأ، فإنه يحمّل `setupEntry`
بدلًا من إدخال Plugin الكامل. يحافظ ذلك على خفة بدء التشغيل والإعداد
عندما يربط إدخال Plugin الرئيسي أيضًا الأدوات أو الخطافات أو شيفرات أخرى
مخصصة لوقت التشغيل فقط.

اختياري: يمكن لـ `openclaw.startup.deferConfiguredChannelFullLoadUntilAfterListen`
إشراك Plugin قناة في مسار `setupEntry` نفسه أثناء مرحلة بدء تشغيل Gateway
السابقة للاستماع، حتى عندما تكون القناة مهيأة بالفعل.

استخدم هذا فقط عندما يغطي `setupEntry` بالكامل سطح بدء التشغيل الذي يجب أن يكون
موجودًا قبل أن يبدأ Gateway الاستماع. عمليًا، يعني ذلك أن إدخال الإعداد
يجب أن يسجّل كل قدرة مملوكة للقناة يعتمد عليها بدء التشغيل، مثل:

- تسجيل القناة نفسها
- أي مسارات HTTP يجب أن تكون متاحة قبل أن يبدأ Gateway الاستماع
- أي طرائق أو أدوات أو خدمات لـ Gateway يجب أن تكون موجودة خلال النافذة نفسها

إذا ظل إدخالك الكامل مالكًا لأي قدرة مطلوبة لبدء التشغيل، فلا تفعّل
هذه العلامة. أبقِ Plugin على السلوك الافتراضي ودع OpenClaw يحمّل
الإدخال الكامل أثناء بدء التشغيل.

يمكن للقنوات المضمّنة أيضًا نشر مساعدات سطح عقد مخصصة للإعداد فقط، يستطيع النواة
الرجوع إليها قبل تحميل وقت تشغيل القناة الكامل. سطح الترقية الخاص بالإعداد
حاليًا هو:

- `singleAccountKeysToMove`
- `namedAccountPromotionKeys`
- `resolveSingleAccountPromotionTarget(...)`

تستخدم النواة هذا السطح عندما تحتاج إلى ترقية تهيئة قديمة لقناة ذات حساب واحد
إلى `channels.<id>.accounts.*` من دون تحميل إدخال Plugin الكامل.
Matrix هو المثال المضمّن الحالي: فهو ينقل مفاتيح المصادقة/التمهيد فقط إلى
حساب مُرقّى مسمّى عندما تكون الحسابات المسمّاة موجودة بالفعل، ويمكنه الاحتفاظ
بمفتاح حساب افتراضي مهيأ وغير قياسي بدلًا من إنشاء `accounts.default`
دائمًا.

تحافظ مهايئات تصحيح الإعداد هذه على كسل اكتشاف سطح العقد المضمّن. يظل وقت
الاستيراد خفيفًا؛ ولا يُحمّل سطح الترقية إلا عند أول استخدام بدلًا من
إعادة الدخول في بدء تشغيل القناة المضمّنة عند استيراد الوحدة.

عندما تتضمن أسطح بدء التشغيل هذه طرائق RPC لـ Gateway، فأبقها ضمن
بادئة خاصة بـ Plugin. تظل نطاقات إدارة النواة (`config.*`،
`exec.approvals.*`، `wizard.*`، `update.*`) محجوزة وتُحل دائمًا
إلى `operator.admin`، حتى إذا طلب Plugin نطاقًا أضيق.

مثال:

```json
{
  "name": "@scope/my-channel",
  "openclaw": {
    "extensions": ["./index.ts"],
    "setupEntry": "./setup-entry.ts",
    "startup": {
      "deferConfiguredChannelFullLoadUntilAfterListen": true
    }
  }
}
```

### بيانات تعريف دليل القنوات

يمكن لإضافات القنوات الإعلان عن بيانات تعريف الإعداد/الاكتشاف عبر `openclaw.channel`
وعن تلميحات التثبيت عبر `openclaw.install`. يحافظ ذلك على خلو دليل النواة من البيانات.

مثال:

```json
{
  "name": "@openclaw/nextcloud-talk",
  "openclaw": {
    "extensions": ["./index.ts"],
    "channel": {
      "id": "nextcloud-talk",
      "label": "Nextcloud Talk",
      "selectionLabel": "Nextcloud Talk (self-hosted)",
      "docsPath": "/channels/nextcloud-talk",
      "docsLabel": "nextcloud-talk",
      "blurb": "Self-hosted chat via Nextcloud Talk webhook bots.",
      "order": 65,
      "aliases": ["nc-talk", "nc"]
    },
    "install": {
      "npmSpec": "@openclaw/nextcloud-talk",
      "localPath": "<bundled-plugin-local-path>",
      "defaultChoice": "npm"
    }
  }
}
```

حقول `openclaw.channel` المفيدة إلى جانب المثال الأدنى:

- `detailLabel`: تسمية ثانوية لأسطح الدليل/الحالة الأكثر تفصيلًا
- `docsLabel`: تجاوز نص رابط التوثيق
- `preferOver`: معرّفات Plugin/القنوات ذات الأولوية الأدنى التي ينبغي أن يتفوق عليها إدخال الدليل هذا
- `selectionDocsPrefix`، `selectionDocsOmitLabel`، `selectionExtras`: عناصر تحكم في نص سطح الاختيار
- `markdownCapable`: يحدد القناة على أنها تدعم Markdown لقرارات تنسيق الرسائل الصادرة
- `exposure.configured`: يخفي القناة من أسطح قوائم القنوات المهيأة عند ضبطه على `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"`.

تعرض إدخالات دليل القنوات المُنشأة وإدخالات دليل تثبيت المزوّد
حقائق موحّدة عن مصدر التثبيت بجانب كتلة `openclaw.install` الأولية. تحدد
الحقائق الموحّدة ما إذا كانت مواصفة npm إصدارًا دقيقًا أم محددًا متغيرًا،
وما إذا كانت بيانات التكامل المتوقعة موجودة، وما إذا كان مسار مصدر محلي
متاحًا أيضًا. عندما تكون هوية الدليل/الحزمة معروفة، تحذّر الحقائق
الموحّدة إذا انحرف اسم حزمة npm المحلّل عن تلك الهوية.
كما تحذّر عندما تكون `defaultChoice` غير صالحة أو تشير إلى مصدر
غير متاح، وعندما تكون بيانات تكامل npm موجودة من دون مصدر npm صالح.
ينبغي للمستهلكين التعامل مع `installSource` بوصفه حقلًا اختياريًا إضافيًا حتى
لا تضطر الإدخالات المُنشأة يدويًا ورقع توافق الدليل إلى توليده.
يتيح ذلك للإعداد الأولي والتشخيص شرح حالة مستوى المصدر من دون
استيراد وقت تشغيل Plugin.

ينبغي لإدخالات npm الخارجية الرسمية تفضيل `npmSpec` دقيق مع
`expectedIntegrity`. تظل أسماء الحزم المجردة ووسوم التوزيع تعمل
للتوافق، لكنها تعرض تحذيرات على مستوى المصدر حتى يتمكن الدليل من التوجه
نحو عمليات تثبيت مثبتة الإصدارات ومتحقق من تكاملها من دون تعطيل إضافات Plugin الحالية.
عندما يثبّت الإعداد الأولي من مسار دليل محلي، فإنه يسجّل إدخالًا مُدارًا في
فهرس إضافات Plugin مع `source: "path"` و`sourcePath` نسبيًا إلى مساحة العمل
عند الإمكان. يبقى مسار التحميل التشغيلي المطلق في
`plugins.load.paths`؛ ويتجنب سجل التثبيت تكرار مسارات محطة العمل المحلية
في التهيئة طويلة الأجل. يحافظ ذلك على ظهور عمليات تثبيت التطوير المحلية
لتشخيصات مستوى المصدر من دون إضافة سطح ثانٍ يكشف مسار نظام ملفات أوليًا.
يمثل جدول SQLite الدائم `installed_plugin_index` مصدر الحقيقة للتثبيت
ويمكن تحديثه من دون تحميل وحدات وقت تشغيل Plugin.
تكون خريطة `installRecords` فيه دائمة حتى عند فقدان بيان Plugin أو
عدم صلاحيته؛ بينما تكون حمولة `plugins` عرضًا للبيان قابلًا لإعادة البناء.

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

تمتلك إضافات محرك السياق تنسيق سياق الجلسة للإدخال والتجميع
وCompaction. سجّلها من Plugin الخاص بك باستخدام
`api.registerContextEngine(id, factory)`، ثم اختر المحرك النشط باستخدام
`plugins.slots.contextEngine`.

استخدم ذلك عندما يحتاج Plugin الخاص بك إلى استبدال مسار السياق الافتراضي
أو توسيعه بدلًا من مجرد إضافة البحث في الذاكرة أو الخطافات.

```ts
import { buildMemorySystemPromptAddition } from "openclaw/plugin-sdk/core";
import { resolveSessionAgentId } from "openclaw/plugin-sdk/memory-host-core";

export default function (api) {
  api.registerContextEngine("lossless-claw", (ctx) => ({
    info: { id: "lossless-claw", name: "Lossless Claw", ownsCompaction: true },
    async ingest() {
      return { ingested: true };
    },
    async assemble({ messages, sessionKey, availableTools, citationsMode }) {
      return {
        messages,
        estimatedTokens: 0,
        systemPromptAddition: buildMemorySystemPromptAddition({
          availableTools: availableTools ?? new Set(),
          citationsMode,
          agentId: resolveSessionAgentId({ config: ctx.config, sessionKey }),
          agentSessionKey: sessionKey,
        }),
      };
    },
    async compact() {
      return { ok: true, compacted: false };
    },
  }));
}
```

يعرض `ctx` الخاص بالمصنع القيم الاختيارية `config` و`agentDir` و`workspaceDir`
للتهيئة في وقت الإنشاء.

قد تعيد `assemble()` قيمة `contextProjection` عندما تكون للبيئة النشطة
سلسلة خلفية دائمة. احذفها للإسقاط القديم لكل دورة. أعد
`{ mode: "thread_bootstrap", epoch }` عندما ينبغي حقن السياق المجمّع
مرة واحدة في سلسلة خلفية وإعادة استخدامه حتى تتغير الحقبة. غيّر
الحقبة بعد تغير السياق الدلالي للمحرك، مثلًا بعد مرور Compaction
يملكه المحرك. قد تحافظ المضيفات على بيانات تعريف استدعاء الأدوات وشكل
الإدخال ونتائج الأدوات المنقّحة في إسقاط تمهيد السلسلة، حتى تحتفظ
السلاسل الخلفية الجديدة باستمرارية الأدوات من دون نسخ الحمولات الأولية
الحاملة للأسرار.

إذا كان محركك **لا** يملك خوارزمية Compaction، فأبقِ `compact()`
منفّذة وفوّضها صراحةً:

```ts
import {
  buildMemorySystemPromptAddition,
  delegateCompactionToRuntime,
} from "openclaw/plugin-sdk/core";
import { resolveSessionAgentId } from "openclaw/plugin-sdk/memory-host-core";

export default function (api) {
  api.registerContextEngine("my-memory-engine", (ctx) => ({
    info: {
      id: "my-memory-engine",
      name: "My Memory Engine",
      ownsCompaction: false,
    },
    async ingest() {
      return { ingested: true };
    },
    async assemble({ messages, sessionKey, availableTools, citationsMode }) {
      return {
        messages,
        estimatedTokens: 0,
        systemPromptAddition: buildMemorySystemPromptAddition({
          availableTools: availableTools ?? new Set(),
          citationsMode,
          agentId: resolveSessionAgentId({ config: ctx.config, sessionKey }),
          agentSessionKey: sessionKey,
        }),
      };
    },
    async compact(params) {
      return await delegateCompactionToRuntime(params);
    },
  }));
}
```

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

عندما يحتاج Plugin إلى سلوك لا تلائمه واجهة API الحالية، فلا تتجاوز
نظام Plugin عبر وصول داخلي خاص. أضف القدرة المفقودة.

التسلسل الموصى به:

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

بهذه الطريقة يظل OpenClaw ذا نهج محدد دون أن يصبح مرتبطًا برمجيًا برؤية
مزوّد واحد. راجع [دليل وصفات القدرات](/ar/plugins/adding-capabilities)
للحصول على قائمة تحقق عملية للملفات ومثال تطبيقي.

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

عندما تضيف قدرة جديدة، ينبغي للتنفيذ عادةً أن يطال هذه
الأسطح معًا:

- أنواع عقد النواة في `src/<capability>/types.ts`
- مشغّل النواة/مساعد وقت التشغيل في `src/<capability>/runtime.ts`
- سطح تسجيل API الخاص بالـ Plugin في `src/plugins/types.ts`
- توصيل سجل Plugin في `src/plugins/registry.ts`
- إتاحة وقت تشغيل Plugin في `src/plugins/runtime/*` عندما تحتاج Plugins
  الميزات/القنوات إلى استهلاكه
- مساعدات الالتقاط/الاختبار في `src/test-utils/plugin-registration.ts`
- تأكيدات الملكية/العقد في `src/plugins/contracts/registry.ts`
- وثائق المشغّل/Plugin في `docs/`

إذا كان أحد هذه الأسطح مفقودًا، فهذه عادةً علامة على أن القدرة
لم تُدمج بالكامل بعد.

### قالب القدرة

النمط الأدنى:

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

نمط اختبار العقد (يكشف `src/plugins/contracts/registry.ts` عمليات بحث الملكية
مثل `providerContractPluginIds`؛ وتتحقق الاختبارات من أن قائمة
`contracts.videoGenerationProviders` الخاصة بـ Plugin تطابق ما يسجله فعليًا):

```ts
expect(pluginManifest.contracts?.videoGenerationProviders).toEqual(["openai"]);
```

يحافظ ذلك على بساطة القاعدة:

- تمتلك النواة عقد القدرة + التنسيق
- تمتلك Plugins المورّدين تنفيذات المورّدين
- تستهلك Plugins الميزات/القنوات مساعدات وقت التشغيل
- تُبقي اختبارات العقد الملكية صريحة

## ذو صلة

- [معمارية Plugin](/ar/plugins/architecture) — نموذج القدرة العام وأشكاله
- [المسارات الفرعية لحزمة تطوير Plugin](/ar/plugins/sdk-subpaths)
- [إعداد حزمة تطوير Plugin](/ar/plugins/sdk-setup)
- [بناء Plugins](/ar/plugins/building-plugins)
