---
read_when:
    - بناء Plugins أصلية لـ OpenClaw أو تصحيح أخطائها
    - فهم نموذج قدرات Plugin أو حدود الملكية
    - العمل على مسار تحميل Plugin أو السجل
    - تنفيذ خطافات وقت تشغيل المزوّد أو Plugins القنوات
sidebarTitle: Internals
summary: 'الأجزاء الداخلية لـ Plugin: نموذج القدرات، الملكية، العقود، مسار التحميل، ومساعدات وقت التشغيل'
title: الأجزاء الداخلية لـ Plugin
x-i18n:
    generated_at: "2026-04-15T07:17:44Z"
    model: gpt-5.4
    provider: openai
    source_hash: f86798b5d2b0ad82d2397a52a6c21ed37fe6eee1dd3d124a9e4150c4f630b841
    source_path: plugins/architecture.md
    workflow: 15
---

# الأجزاء الداخلية لـ Plugin

<Info>
  هذه هي **المرجعية المعمارية المتعمقة**. للاطلاع على الأدلة العملية، راجع:
  - [تثبيت Plugins واستخدامها](/ar/tools/plugin) — دليل المستخدم
  - [البدء](/ar/plugins/building-plugins) — أول درس تعليمي لـ plugin
  - [Plugins القنوات](/ar/plugins/sdk-channel-plugins) — أنشئ قناة مراسلة
  - [Plugins المزوّد](/ar/plugins/sdk-provider-plugins) — أنشئ مزوّد نماذج
  - [نظرة عامة على SDK](/ar/plugins/sdk-overview) — خريطة الاستيراد وواجهة برمجة التسجيل
</Info>

تغطي هذه الصفحة البنية الداخلية لنظام Plugins في OpenClaw.

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

القدرات هي نموذج **Plugins الأصلية** العام داخل OpenClaw. يسجّل كل Plugin أصلي في OpenClaw نفسه مقابل نوع قدرة واحد أو أكثر:

| القدرة                 | طريقة التسجيل                                   | أمثلة على Plugins                    |
| ---------------------- | ------------------------------------------------ | ------------------------------------ |
| استدلال النص           | `api.registerProvider(...)`                      | `openai`, `anthropic`                |
| خلفية استدلال CLI      | `api.registerCliBackend(...)`                    | `openai`, `anthropic`                |
| الكلام                 | `api.registerSpeechProvider(...)`                | `elevenlabs`, `microsoft`            |
| النسخ الفوري           | `api.registerRealtimeTranscriptionProvider(...)` | `openai`                             |
| الصوت الفوري           | `api.registerRealtimeVoiceProvider(...)`         | `openai`                             |
| فهم الوسائط            | `api.registerMediaUnderstandingProvider(...)`    | `openai`, `google`                   |
| توليد الصور            | `api.registerImageGenerationProvider(...)`       | `openai`, `google`, `fal`, `minimax` |
| توليد الموسيقى         | `api.registerMusicGenerationProvider(...)`       | `google`, `minimax`                  |
| توليد الفيديو          | `api.registerVideoGenerationProvider(...)`       | `qwen`                               |
| جلب الويب              | `api.registerWebFetchProvider(...)`              | `firecrawl`                          |
| البحث في الويب         | `api.registerWebSearchProvider(...)`             | `google`                             |
| القناة / المراسلة      | `api.registerChannel(...)`                       | `msteams`, `matrix`                  |

الـ Plugin الذي يسجّل صفرًا من القدرات لكنه يوفّر خطافات أو أدوات أو
خدمات هو Plugin **قديم يعتمد على الخطافات فقط**. لا يزال هذا النمط مدعومًا بالكامل.

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

تم اعتماد نموذج القدرات في النواة ويُستخدم اليوم من قِبل Plugins
المضمّنة/الأصلية، لكن توافق Plugins الخارجية لا يزال يحتاج إلى معيار أدق من
"تم تصديره، إذن فهو ثابت."

الإرشادات الحالية:

- **Plugins الخارجية الحالية:** حافظ على عمل التكاملات المعتمدة على الخطافات؛ واعتبر
  هذا هو خط الأساس للتوافق
- **Plugins المضمّنة/الأصلية الجديدة:** فضّل تسجيل القدرات الصريح بدلًا من
  الوصولات الخاصة بالمورّد أو التصاميم الجديدة التي تعتمد على الخطافات فقط
- **Plugins الخارجية التي تعتمد تسجيل القدرات:** مسموح بها، لكن اعتبر
  أسطح المساعدات الخاصة بالقدرات في طور التطور ما لم تُشر الوثائق صراحةً إلى أن
  العقد مستقر

القاعدة العملية:

- واجهات تسجيل القدرات هي الاتجاه المقصود
- تظل الخطافات القديمة المسار الأكثر أمانًا لتجنب الأعطال في Plugins الخارجية خلال
  مرحلة الانتقال
- ليست كل المسارات الفرعية المصدّرة للمساعدات متساوية؛ فضّل العقد الضيق الموثّق،
  وليس تصديرات المساعدات العرضية

### أشكال Plugins

يصنّف OpenClaw كل Plugin مُحمّل إلى شكل بناءً على سلوك التسجيل الفعلي
(وليس فقط البيانات الوصفية الثابتة):

- **plain-capability** -- يسجّل نوع قدرة واحدًا فقط (على سبيل المثال
  Plugin يوفّر مزوّدًا فقط مثل `mistral`)
- **hybrid-capability** -- يسجّل عدة أنواع من القدرات (على سبيل المثال
  `openai` يملك استدلال النص والكلام وفهم الوسائط وتوليد
  الصور)
- **hook-only** -- يسجّل الخطافات فقط (المكتوبة النوع أو المخصصة)، من دون قدرات
  أو أدوات أو أوامر أو خدمات
- **non-capability** -- يسجّل أدوات أو أوامر أو خدمات أو مسارات، ولكن من دون
  قدرات

استخدم `openclaw plugins inspect <id>` لعرض شكل Plugin وتفصيل
القدرات. راجع [مرجع CLI](/cli/plugins#inspect) للحصول على التفاصيل.

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

لا يزال الخطاف `before_agent_start` مدعومًا كمسار توافق لPlugins
التي تعتمد على الخطافات فقط. لا تزال Plugins حقيقية قديمة تعتمد عليه.

الاتجاه:

- أبقه يعمل
- وثّقه على أنه قديم
- فضّل `before_model_resolve` لأعمال تجاوز النموذج/المزوّد
- فضّل `before_prompt_build` لأعمال تعديل الـ prompt
- لا تُزِله إلا بعد انخفاض الاستخدام الفعلي وإثبات تغطية الـ fixtures لسلامة الترحيل

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

عند تشغيل `openclaw doctor` أو `openclaw plugins inspect <id>`، قد ترى
إحدى هذه التسميات:

| الإشارة                   | المعنى                                                       |
| ------------------------- | ------------------------------------------------------------ |
| **config valid**          | يتم تحليل الإعدادات بشكل سليم وتُحلّ Plugins                 |
| **compatibility advisory** | يستخدم Plugin نمطًا مدعومًا لكنه أقدم (مثل `hook-only`)     |
| **legacy warning**        | يستخدم Plugin `before_agent_start`، وهو مهمل                |
| **hard error**            | الإعدادات غير صالحة أو فشل تحميل Plugin                     |

لن يؤدي `hook-only` ولا `before_agent_start` إلى كسر Plugin الخاص بك اليوم --
فـ `hook-only` مجرد تنبيه استشاري، و`before_agent_start` لا يؤدي إلا إلى تحذير. تظهر هذه
الإشارات أيضًا في `openclaw status --all` و`openclaw plugins doctor`.

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

يتكوّن نظام Plugins في OpenClaw من أربع طبقات:

1. **البيان + الاكتشاف**
   يعثر OpenClaw على Plugins المرشحة من المسارات المهيأة وجذور مساحات العمل
   وجذور الإضافات العامة والإضافات المضمّنة. يقرأ الاكتشاف ملفات البيان الأصلية
   `openclaw.plugin.json` إضافةً إلى بيانات الحزم المدعومة أولًا.
2. **التمكين + التحقق**
   تقرر النواة ما إذا كان Plugin المكتشف مفعّلًا أو معطّلًا أو محظورًا أو
   محددًا لخانة حصرية مثل الذاكرة.
3. **التحميل وقت التشغيل**
   تُحمَّل Plugins OpenClaw الأصلية داخل العملية عبر jiti وتُسجّل
   القدرات في سجل مركزي. وتُطبّع الحزم المتوافقة إلى سجلات في السجل
   من دون استيراد كود وقت التشغيل.
4. **استهلاك الأسطح**
   يقرأ باقي OpenClaw السجل لعرض الأدوات والقنوات وإعداد
   المزوّد والخطافات ومسارات HTTP وأوامر CLI والخدمات.

بالنسبة إلى Plugin CLI تحديدًا، يُقسَّم اكتشاف أمر الجذر إلى مرحلتين:

- تأتي بيانات وقت التحليل من `registerCli(..., { descriptors: [...] })`
- يمكن أن تظل وحدة Plugin CLI الحقيقية كسولة التحميل وتُسجّل عند أول استدعاء

يحافظ ذلك على كود CLI المملوك للـ Plugin داخل Plugin نفسه، مع السماح لـ OpenClaw
بحجز أسماء أوامر الجذر قبل التحليل.

الحدّ التصميمي المهم:

- يجب أن يعمل الاكتشاف + التحقق من الإعدادات من **بيانات البيان/المخطط**
  من دون تنفيذ كود Plugin
- يأتي السلوك الأصلي وقت التشغيل من مسار `register(api)` الخاص بوحدة Plugin

يسمح هذا الفصل لـ OpenClaw بالتحقق من الإعدادات وشرح Plugins
المفقودة/المعطلة وبناء تلميحات الواجهة/المخطط قبل تنشيط وقت التشغيل الكامل.

### Plugins القنوات وأداة الرسائل المشتركة

لا تحتاج Plugins القنوات إلى تسجيل أداة منفصلة للإرسال/التحرير/التفاعل من أجل
إجراءات الدردشة العادية. يحتفظ OpenClaw بأداة `message` مشتركة واحدة في النواة،
بينما تملك Plugins القنوات الاكتشاف والتنفيذ الخاصين بالقناة من خلفها.

الحد الحالي هو:

- تملك النواة مضيف أداة `message` المشتركة، وربط الـ prompt، ودفاتر الجلسات/المحادثات
  وتنفيذ التوجيه
- تملك Plugins القنوات اكتشاف الإجراءات المقيّدة، واكتشاف القدرات، وأي أجزاء
  من المخطط خاصة بالقناة
- تملك Plugins القنوات قواعد محادثة الجلسة الخاصة بالمزوّد، مثل
  كيفية ترميز معرّفات المحادثات لمعرّفات السلاسل أو وراثتها من المحادثات الأصل
- تنفذ Plugins القنوات الإجراء النهائي عبر مهايئ الإجراء الخاص بها

بالنسبة إلى Plugins القنوات، يكون سطح SDK هو
`ChannelMessageActionAdapter.describeMessageTool(...)`. تتيح
مكالمة الاكتشاف الموحّدة هذه للـ Plugin إعادة إجراءاته المرئية وقدراته ومساهمات
المخطط معًا حتى لا تنجرف هذه الأجزاء بعيدًا عن بعضها.

عندما يحمل بارامتر أداة الرسائل الخاص بالقناة مصدر وسائط مثل
مسار محلي أو عنوان URL لوسائط بعيدة، يجب على Plugin أيضًا إعادة
`mediaSourceParams` من `describeMessageTool(...)`. تستخدم النواة هذه
القائمة الصريحة لتطبيق تطبيع مسارات sandbox وتلميحات الوصول إلى الوسائط الصادرة
من دون ترميز ثابت لأسماء البارامترات المملوكة للـ Plugin.
فضّل الخرائط المقيّدة بالإجراء هناك، لا قائمة مسطحة واحدة على مستوى القناة،
حتى لا يُطبَّع بارامتر وسائط خاص بالملف الشخصي على إجراءات غير مرتبطة مثل
`send`.

تمرّر النواة نطاق وقت التشغيل إلى خطوة الاكتشاف هذه. تشمل الحقول المهمة:

- `accountId`
- `currentChannelId`
- `currentThreadTs`
- `currentMessageId`
- `sessionKey`
- `sessionId`
- `agentId`
- `requesterSenderId` الوارد الموثوق

وهذا مهم للقنوات الحساسة للسياق. يمكن للقناة إخفاء إجراءات
الرسائل أو إظهارها استنادًا إلى الحساب النشط أو الغرفة/السلسلة/الرسالة الحالية أو
هوية الطالب الموثوق بها، من دون ترميز فروع خاصة بالقناة في أداة `message`
الأساسية.

ولهذا السبب تظل تغييرات توجيه المشغّل المضمّن من أعمال Plugin: فالمشغّل
مسؤول عن تمرير هوية الدردشة/الجلسة الحالية إلى حدّ اكتشاف Plugin
بحيث تكشف أداة `message` المشتركة عن السطح الصحيح المملوك للقناة
للدور الحالي.

بالنسبة إلى مساعدات التنفيذ المملوكة للقناة، ينبغي على Plugins المضمّنة إبقاء
وقت تشغيل التنفيذ داخل وحدات الإضافة الخاصة بها. لم تعد النواة تملك
أوقات تشغيل إجراءات رسائل Discord أو Slack أو Telegram أو WhatsApp ضمن `src/agents/tools`.
نحن لا ننشر مسارات فرعية منفصلة من `plugin-sdk/*-action-runtime`، ويجب على Plugins
المضمّنة استيراد كود وقت التشغيل المحلي الخاص بها مباشرةً من
الوحدات التي تملكها الإضافة.

ينطبق الحدّ نفسه على مسارات SDK المسماة بأسماء المزوّدين عمومًا: لا ينبغي
للنواة أن تستورد حاويات تسهيل خاصة بالقنوات لـ Slack أو Discord أو Signal أو
WhatsApp أو الإضافات المشابهة. إذا احتاجت النواة إلى سلوك ما، فإما أن
تستهلك حاوية `api.ts` / `runtime-api.ts` الخاصة بالـ Plugin المضمّن نفسه، أو
ترقّي الحاجة إلى قدرة عامة ضيقة في SDK المشتركة.

بالنسبة إلى الاستطلاعات تحديدًا، يوجد مساران للتنفيذ:

- `outbound.sendPoll` هو خط الأساس المشترك للقنوات التي تناسب نموذج
  الاستطلاع الشائع
- `actions.handleAction("poll")` هو المسار المفضّل لدلالات الاستطلاع
  الخاصة بالقناة أو لبارامترات الاستطلاع الإضافية

تؤجل النواة الآن تحليل الاستطلاع المشترك إلى ما بعد رفض توجيه استطلاع Plugin
للإجراء، بحيث يمكن لمعالجات الاستطلاع المملوكة للـ Plugin قبول
حقول استطلاع خاصة بالقناة من دون أن يعوقها محلّل الاستطلاع العام أولًا.

راجع [مسار التحميل](#load-pipeline) للاطلاع على تسلسل بدء التشغيل الكامل.

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

يتعامل OpenClaw مع Plugin الأصلي بوصفه حدّ الملكية لـ **شركة** أو
**ميزة**، لا بوصفه مجموعة عشوائية من التكاملات غير المرتبطة.

وهذا يعني:

- يجب أن يملك Plugin الشركة عادةً جميع الأسطح الخاصة بـ OpenClaw لتلك الشركة
- يجب أن يملك Plugin الميزة عادةً السطح الكامل للميزة التي يقدّمها
- يجب أن تستهلك القنوات القدرات المشتركة للنواة بدلًا من إعادة تنفيذ
  سلوك المزوّد بطريقة مخصصة

أمثلة:

- يملك Plugin المضمّن `openai` سلوك مزوّد نماذج OpenAI وسلوك OpenAI
  للكلام + الصوت الفوري + فهم الوسائط + توليد الصور
- يملك Plugin المضمّن `elevenlabs` سلوك الكلام لـ ElevenLabs
- يملك Plugin المضمّن `microsoft` سلوك الكلام لـ Microsoft
- يملك Plugin المضمّن `google` سلوك مزوّد نماذج Google إضافةً إلى سلوك Google
  لفهم الوسائط + توليد الصور + البحث في الويب
- يملك Plugin المضمّن `firecrawl` سلوك جلب الويب لـ Firecrawl
- تملك Plugins المضمّنة `minimax` و`mistral` و`moonshot` و`zai`
  الواجهات الخلفية لفهم الوسائط
- يملك Plugin المضمّن `qwen` سلوك مزوّد النصوص لـ Qwen إضافةً إلى
  سلوك فهم الوسائط وتوليد الفيديو
- يُعد Plugin `voice-call` Plugin ميزة: فهو يملك نقل المكالمات والأدوات
  وCLI والمسارات وجسر تدفّق وسائط Twilio، لكنه يستهلك قدرات الكلام المشتركة
  إضافةً إلى قدرات النسخ الفوري والصوت الفوري بدلًا من
  استيراد Plugins المورّدين مباشرةً

الحالة النهائية المقصودة هي:

- يعيش OpenAI في Plugin واحد حتى لو امتد عبر نماذج النصوص والكلام والصور
  والفيديو مستقبلًا
- ويمكن لمورّد آخر أن يفعل الشيء نفسه ضمن نطاقه الخاص
- ولا تهتم القنوات بأي Plugin مورّد يملك المزوّد؛ فهي تستهلك
  عقد القدرة المشتركة الذي تكشفه النواة

هذا هو التمييز الأساسي:

- **plugin** = حدّ الملكية
- **capability** = عقد النواة الذي يمكن لعدة Plugins تنفيذه أو استهلاكه

لذلك إذا أضاف OpenClaw مجالًا جديدًا مثل الفيديو، فالسؤال الأول ليس
"أي مزوّد يجب أن يرمّز التعامل مع الفيديو ترميزًا ثابتًا؟" بل السؤال الأول هو
"ما عقد قدرة الفيديو في النواة؟" وبمجرد وجود هذا العقد، يمكن لPlugins المورّدين
التسجيل مقابله ويمكن لPlugins القنوات/الميزات استهلاكه.

إذا لم تكن القدرة موجودة بعد، فعادةً ما تكون الخطوة الصحيحة هي:

1. تعريف القدرة المفقودة في النواة
2. كشفها عبر واجهة Plugin/وقت التشغيل بطريقة مكتوبة النوع
3. ربط القنوات/الميزات بهذه القدرة
4. والسماح لPlugins المورّدين بتسجيل التنفيذات

يحافظ ذلك على وضوح الملكية مع تجنب سلوك في النواة يعتمد على
مورّد واحد أو مسار كود خاص بPlugin واحد.

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

استخدم هذا النموذج الذهني عند تحديد موضع الكود:

- **طبقة القدرات في النواة**: التنسيق المشترك والسياسات والتراجع وقواعد
  دمج الإعدادات ودلالات التسليم والعقود المكتوبة النوع
- **طبقة Plugin المورّد**: واجهات API الخاصة بالمورّد، والمصادقة، وكتالوجات النماذج، واصطناع الكلام،
  وتوليد الصور، والواجهات الخلفية المستقبلية للفيديو، ونقاط نهاية الاستخدام
- **طبقة Plugin القناة/الميزة**: تكاملات Slack/Discord/voice-call/إلخ
  التي تستهلك قدرات النواة وتعرضها على سطح

على سبيل المثال، يتبع TTS هذا الشكل:

- تملك النواة سياسة TTS وقت الرد، وترتيب التراجع، والتفضيلات، وتسليم القناة
- يملك `openai` و`elevenlabs` و`microsoft` تنفيذات الاصطناع
- يستهلك `voice-call` مساعد وقت تشغيل TTS الخاص بالهاتف

ويجب تفضيل النمط نفسه للقدرات المستقبلية.

### مثال على Plugin شركة متعدد القدرات

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

```ts
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;
```

ما يهم ليس أسماء المساعدات الدقيقة. المهم هو الشكل:

- Plugin واحد يملك سطح المورّد
- لا تزال النواة تملك عقود القدرات
- تستهلك Plugins القنوات والميزات مساعدات `api.runtime.*`، وليس كود المورّد
- ويمكن لاختبارات العقود التأكد من أن Plugin سجّل القدرات التي
  يدّعي ملكيتها

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

يعامل OpenClaw بالفعل فهم الصور/الصوت/الفيديو كقدرة
مشتركة واحدة. وينطبق نموذج الملكية نفسه هنا:

1. تعرّف النواة عقد فهم الوسائط
2. تسجّل Plugins المورّدين `describeImage` و`transcribeAudio` و
   `describeVideo` حسب الاقتضاء
3. تستهلك Plugins القنوات والميزات سلوك النواة المشترك بدلًا من
   الربط المباشر بكود المورّد

يمنع ذلك تضمين افتراضات الفيديو الخاصة بمزوّد واحد داخل النواة. فالـ Plugin يملك
سطح المورّد؛ بينما تملك النواة عقد القدرة وسلوك التراجع.

يستخدم توليد الفيديو بالفعل التسلسل نفسه: تملك النواة عقد
القدرة المكتوب النوع ومساعد وقت التشغيل، وتسجّل Plugins المورّدين
تنفيذات `api.registerVideoGenerationProvider(...)` مقابله.

هل تحتاج إلى قائمة طرح عملية ومحددة؟ راجع
[دليل القدرات العملي](/ar/plugins/architecture).

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

سطح واجهة Plugin مقصود به أن يكون مكتوب النوع ومركزيًا داخل
`OpenClawPluginApi`. يعرّف هذا العقد نقاط التسجيل المدعومة
ومساعدات وقت التشغيل التي يمكن أن يعتمد عليها Plugin.

سبب أهمية ذلك:

- يحصل مؤلفو Plugins على معيار داخلي ثابت واحد
- يمكن للنواة رفض الملكية المكررة مثل تسجيل Pluginين لمعرّف
  المزوّد نفسه
- يمكن لبدء التشغيل عرض تشخيصات عملية للتسجيلات غير الصحيحة
- يمكن لاختبارات العقود فرض ملكية Plugins المضمّنة ومنع الانجراف الصامت

هناك طبقتان من الفرض:

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

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

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

عقود Plugins الجيدة تكون:

- مكتوبة النوع
- صغيرة
- خاصة بالقدرة
- مملوكة للنواة
- قابلة لإعادة الاستخدام بواسطة عدة Plugins
- قابلة للاستهلاك من القنوات/الميزات دون معرفة بالمورّد

عقود Plugins السيئة تكون:

- سياسات خاصة بالمورّد مخفية داخل النواة
- منافذ هروب خاصة بPlugin واحد تتجاوز السجل
- كود قناة يصل مباشرةً إلى تنفيذ مورّد
- كائنات وقت تشغيل مخصصة ليست جزءًا من `OpenClawPluginApi` أو
  `api.runtime`

عند الشك، ارفع مستوى التجريد: عرّف القدرة أولًا، ثم
دع Plugins تتصل بها.

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

تعمل Plugins OpenClaw الأصلية **داخل العملية** مع Gateway. وهي ليست
ضمن sandbox. يمتلك Plugin أصلي مُحمّل حدّ الثقة نفسه على مستوى العملية
الذي يملكه كود النواة.

الآثار المترتبة:

- يمكن للـ Plugin الأصلي تسجيل أدوات ومعالجات شبكية وخطافات وخدمات
- يمكن لخطأ في Plugin أصلي أن يتسبب في تعطل Gateway أو زعزعة استقراره
- يعادل Plugin أصلي خبيث تنفيذ كود عشوائي داخل
  عملية OpenClaw

تُعد الحزم المتوافقة أكثر أمانًا افتراضيًا لأن OpenClaw يعاملها حاليًا
كحزم بيانات وصفية/محتوى. وفي الإصدارات الحالية، يعني ذلك غالبًا
Skills المضمّنة.

استخدم قوائم السماح ومسارات التثبيت/التحميل الصريحة للPlugins غير المضمّنة.
واعتبر Plugins مساحات العمل كودًا لوقت التطوير، لا إعدادات إنتاج افتراضية.

بالنسبة إلى أسماء حزم مساحة العمل المضمّنة، حافظ على ارتكاز معرّف Plugin ضمن
اسم npm: `@openclaw/<id>` افتراضيًا، أو لاحقة نوعية معتمدة مثل
`-provider` أو `-plugin` أو `-speech` أو `-sandbox` أو `-media-understanding` عندما
تكشف الحزمة عمدًا عن دور Plugin أضيق.

ملاحظة ثقة مهمة:

- تثق `plugins.allow` في **معرّفات Plugins**، وليس في مصدرها.
- يعمد Plugin مساحة عمل يحمل المعرّف نفسه الذي يحمله Plugin مضمّن إلى حجب
  النسخة المضمّنة عندما يكون Plugin مساحة العمل هذا مفعّلًا/مدرجًا في قائمة السماح.
- وهذا طبيعي ومفيد للتطوير المحلي واختبار التصحيحات والإصلاحات السريعة.

## حدّ التصدير

يصدّر OpenClaw القدرات، لا وسائل الراحة التنفيذية.

أبقِ تسجيل القدرات عامًا. وقلّص تصديرات المساعدات غير التعاقدية:

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

لا تزال بعض المسارات الفرعية لمساعدات Plugins المضمّنة موجودة في
خريطة تصدير SDK المُولّدة لأجل التوافق وصيانة Plugins المضمّنة. من الأمثلة الحالية
`plugin-sdk/feishu` و`plugin-sdk/feishu-setup` و`plugin-sdk/zalo` و
`plugin-sdk/zalo-setup` وعدة حدود من `plugin-sdk/matrix*`. تعامل مع هذه
على أنها تصديرات محجوزة لتفاصيل التنفيذ، لا على أنها نمط SDK الموصى به
لـ Plugins الجهات الخارجية الجديدة.

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

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

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

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

تحدث بوابات الأمان **قبل** تنفيذ وقت التشغيل. ويُحظر المرشحون
عندما يخرج الإدخال من جذر Plugin، أو يكون المسار قابلاً للكتابة من الجميع، أو
تبدو ملكية المسار مريبة في Plugins غير المضمّنة.

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

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

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

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

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

- يقتصر تحميل CLI على Plugins التي تملك الأمر الأساسي المطلوب
- يقتصر إعداد القناة/حلّ Plugin على Plugins التي تملك
  معرّف القناة المطلوب
- يقتصر إعداد/حلّ المزوّد الصريح وقت التشغيل على Plugins التي تملك
  معرّف المزوّد المطلوب

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

### ما الذي يخبّئه المُحمِّل

يحتفظ OpenClaw بذاكرات مخبئية قصيرة داخل العملية من أجل:

- نتائج الاكتشاف
- بيانات سجل البيان
- سجلات Plugins المحمّلة

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

ملاحظة حول الأداء:

- اضبط `OPENCLAW_DISABLE_PLUGIN_DISCOVERY_CACHE=1` أو
  `OPENCLAW_DISABLE_PLUGIN_MANIFEST_CACHE=1` لتعطيل هذه الذواكر المخبئية.
- اضبط نوافذ الذاكرة المخبئية باستخدام `OPENCLAW_PLUGIN_DISCOVERY_CACHE_MS` و
  `OPENCLAW_PLUGIN_MANIFEST_CACHE_MS`.

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

لا تقوم Plugins المحمّلة بتعديل متغيرات عامة عشوائية في النواة مباشرةً. بل
تسجّل نفسها في سجل Plugins مركزي.

يتتبّع السجل ما يلي:

- سجلات Plugins (الهوية، المصدر، المنشأ، الحالة، التشخيصات)
- الأدوات
- الخطافات القديمة والخطافات المكتوبة النوع
- القنوات
- المزوّدات
- معالجات Gateway RPC
- مسارات HTTP
- مسجّلات CLI
- الخدمات الخلفية
- الأوامر المملوكة للـ Plugin

ثم تقرأ ميزات النواة من هذا السجل بدلًا من التحدث إلى وحدات Plugins
مباشرةً. وهذا يُبقي التحميل في اتجاه واحد:

- وحدة 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 المزوّد الآن على طبقتين:

- بيانات البيان الوصفية: `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` في البيان عندما يكون لدى المزوّد بيانات اعتماد
معتمدة على البيئة ينبغي أن تراها مسارات المصادقة/الحالة/منتقي النموذج العامة
من دون تحميل وقت تشغيل Plugin. استخدم `providerAuthAliases` في البيان عندما
يجب أن يعيد معرّف مزوّد واحد استخدام متغيرات البيئة وملفات تعريف المصادقة
والمصادقة المعتمدة على الإعداد وخيار إعداد مفتاح API لمعرّف مزوّد آخر. استخدم
`providerAuthChoices` في البيان عندما ينبغي لأسطح CLI الخاصة بالإعداد/اختيار المصادقة
أن تعرف معرّف الاختيار الخاص بالمزوّد وتسميات المجموعات وربط المصادقة
البسيط بعلم واحد من دون تحميل وقت تشغيل المزوّد. احتفظ بـ `envVars` وقت تشغيل المزوّد
لتلميحات موجّهة للمشغّل مثل تسميات الإعداد أو متغيرات إعداد
OAuth client-id/client-secret.

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

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

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

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

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

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

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

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

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

- يستخدم Anthropic الخطافات `resolveDynamicModel` و`capabilities` و`buildAuthDoctorHint`،
  و`resolveUsageAuth` و`fetchUsageSnapshot` و`isCacheTtlEligible`،
  و`resolveDefaultThinkingLevel` و`applyConfigDefaults` و`isModernModelRef`،
  و`wrapStreamFn` لأنه يملك توافق Claude 4.6 الأمامي،
  وتلميحات عائلة المزوّد، وإرشادات إصلاح المصادقة، وتكامل نقطة نهاية الاستخدام،
  وأهلية Prompt Cache، والقيم الافتراضية للإعدادات المدركة للمصادقة، وسياسة
  التفكير الافتراضي/التكيفي لـ Claude، وتشكيل التدفق الخاص بـ Anthropic من أجل
  رؤوس beta، و`/fast` / `serviceTier`، و`context1m`.
- تبقى مساعدات التدفق الخاصة بـ Claude في Anthropic ضمن
  الحدّ العام `api.ts` / `contract-api.ts` الخاص بالPlugin المضمّن نفسه في الوقت الحالي. ويصدّر
  سطح الحزمة هذا `wrapAnthropicProviderStream` و`resolveAnthropicBetas`،
  و`resolveAnthropicFastMode` و`resolveAnthropicServiceTier`، وبناة
  مغلّفات Anthropic منخفضة المستوى بدلًا من توسيع SDK العامة حول
  قواعد رؤوس beta الخاصة بمزوّد واحد.
- يستخدم OpenAI الخطافات `resolveDynamicModel` و`normalizeResolvedModel` و
  `capabilities` إضافةً إلى `buildMissingAuthMessage` و`suppressBuiltInModel`،
  و`augmentModelCatalog` و`supportsXHighThinking` و`isModernModelRef`
  لأنه يملك توافق GPT-5.4 الأمامي، وتطبيع OpenAI المباشر من
  `openai-completions` -> `openai-responses`، وتلميحات المصادقة المدركة لـ Codex،
  وإخفاء Spark، وصفوف قائمة OpenAI الاصطناعية، وسياسة التفكير / النماذج الحية لـ GPT-5؛
  كما تملك عائلة تدفقات `openai-responses-defaults`
  مغلّفات OpenAI Responses الأصلية المشتركة لرؤوس الإسناد،
  و`/fast`/`serviceTier`، وإسهاب النص، وبحث الويب الأصلي في Codex،
  وتشكيل حمولة توافق الاستدلال، وإدارة سياق Responses.
- يستخدم OpenRouter `catalog` إضافةً إلى `resolveDynamicModel` و
  `prepareDynamicModel` لأن المزوّد يعمل كوسيط وقد يعرض
  معرّفات نماذج جديدة قبل تحديث الفهرس الثابت في OpenClaw؛ كما يستخدم
  `capabilities` و`wrapStreamFn` و`isCacheTtlEligible` لإبقاء
  رؤوس الطلبات الخاصة بالمزوّد وبيانات التوجيه الوصفية وتصحيحات الاستدلال وسياسة
  Prompt Cache خارج النواة. وتأتي سياسة replay الخاصة به من
  عائلة `passthrough-gemini`، بينما تملك عائلة التدفقات `openrouter-thinking`
  حقن الاستدلال الوكيل وتخطّي النماذج غير المدعومة / `auto`.
- يستخدم GitHub Copilot `catalog` و`auth` و`resolveDynamicModel` و
  `capabilities` إضافةً إلى `prepareRuntimeAuth` و`fetchUsageSnapshot` لأنه
  يحتاج إلى تسجيل دخول جهاز مملوك للمزوّد، وسلوك تراجع النماذج، وفروق
  نصوص Claude، وتبادل GitHub token -> Copilot token،
  ونقطة نهاية استخدام يملكها المزوّد.
- يستخدم 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-message والدلالات المتوافقة مع OpenAI؛ إذ يبقي
  إسقاط كتل التفكير الخاصة بـ Claude على جانب Anthropic مع تجاوز وضع
  مخرجات الاستدلال إلى الوضع الأصلي، بينما تملك عائلة التدفقات `minimax-fast-mode`
  إعادة كتابة نماذج fast-mode على مسار التدفق المشترك.
- يستخدم Moonshot `catalog` إضافةً إلى `wrapStreamFn` لأنه لا يزال يستخدم
  نقل OpenAI المشترك لكنه يحتاج إلى تطبيع حمولة التفكير المملوكة للمزوّد؛ كما
  تربط عائلة التدفقات `moonshot-thinking` الإعدادات مع حالة `/think` بحمولة
  التفكير الثنائية الأصلية الخاصة بها.
- يستخدم Kilocode الخطافات `catalog` و`capabilities` و`wrapStreamFn` و
  `isCacheTtlEligible` لأنه يحتاج إلى رؤوس طلبات مملوكة للمزوّد،
  وتطبيع حمولة الاستدلال، وتلميحات نصوص Gemini، وتقييد TTL الخاص بذاكرة Anthropic المخبئية؛
  كما تحافظ عائلة التدفقات `kilocode-thinking` على حقن التفكير في Kilo
  ضمن مسار التدفق الوكيل المشترك مع تخطي `kilo/auto` و
  معرّفات نماذج وكيلة أخرى لا تدعم حمولات الاستدلال الصريحة.
- يستخدم Z.AI الخطافات `resolveDynamicModel` و`prepareExtraParams` و`wrapStreamFn`،
  و`isCacheTtlEligible` و`isBinaryThinking` و`isModernModelRef`،
  و`resolveUsageAuth` و`fetchUsageSnapshot` لأنه يملك تراجع GLM-5،
  والقيم الافتراضية لـ `tool_stream`، وتجربة الاستخدام الخاصة بالتفكير الثنائي،
  ومطابقة النماذج الحديثة، وكذلك مصادقة الاستخدام وجلب الحصة؛ بينما
  تُبقي عائلة التدفقات `tool-stream-default-on`
  مغلّف `tool_stream` الافتراضي المُفعّل بعيدًا عن الربط اليدوي لكل مزوّد.
- يستخدم xAI الخطافات `normalizeResolvedModel` و`normalizeTransport`،
  و`contributeResolvedModelCompat` و`prepareExtraParams` و`wrapStreamFn`،
  و`resolveSyntheticAuth` و`resolveDynamicModel` و`isModernModelRef`
  لأنه يملك تطبيع نقل xAI Responses الأصلي، وإعادة كتابة
  الأسماء المستعارة لـ fast-mode في Grok، والقيمة الافتراضية `tool_stream`، وتنظيف
  strict-tool / reasoning-payload، وإعادة استخدام مصادقة التراجع للأدوات
  المملوكة للـ Plugin، وحل نماذج 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` الخاص بهما مملوك للـ Plugin رغم أن الاستدلال لا يزال يعمل عبر
  وسائل النقل المشتركة.

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

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

```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` حمولة خرج TTS العادية من النواة لأسطح الملفات/الملاحظات الصوتية.
- يستخدم إعداد `messages.tts` الأساسي واختيار المزوّد.
- يعيد PCM audio buffer + sample rate. ويجب على Plugins إعادة أخذ العينات/الترميز للمزوّدات.
- `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,
    };
  },
});
```

ملاحظات:

- أبقِ سياسة TTS والتراجع وتسليم الردود في النواة.
- استخدم مزوّدي الكلام لسلوك الاصطناع المملوك للمورّد.
- يُطبَّع الإدخال القديم 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,
});
```

بالنسبة إلى نسخ الصوت، يمكن لل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.*` السطح المشترك المفضل من أجل
  فهم الصور/الصوت/الفيديو.
- يستخدم إعداد الصوت الخاص بفهم الوسائط في النواة (`tools.media.audio`) وترتيب التراجع بين المزوّدين.
- يعيد `{ text: undefined }` عندما لا يتم إنتاج مخرجات نسخ (على سبيل المثال عند تخطي الإدخال أو عدم دعمه).
- يظل `api.runtime.stt.transcribeAudioFile(...)` اسمًا مستعارًا للتوافق.

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

بالنسبة إلى البحث في الويب، يمكن لل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(...)`: اعرض مزوّدي توليد الصور المتاحين وقدراتهم.

## مسارات Gateway HTTP

يمكن لل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`: مسار route تحت خادم Gateway HTTP.
- `auth`: مطلوب. استخدم `"gateway"` لطلب مصادقة Gateway العادية، أو `"plugin"` للمصادقة/التحقق من Webhook الذي يديره Plugin.
- `match`: اختياري. `"exact"` (الافتراضي) أو `"prefix"`.
- `replaceExisting`: اختياري. يسمح للـ Plugin نفسه باستبدال تسجيل مساره الحالي.
- `handler`: أعد `true` عندما يتعامل route مع الطلب.

ملاحظات:

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

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

استخدم المسارات الفرعية لـ SDK بدلًا من الاستيراد الأحادي `openclaw/plugin-sdk` عند
تأليف Plugins:

- `openclaw/plugin-sdk/plugin-entry` لأساسيات تسجيل Plugin.
- `openclaw/plugin-sdk/core` للعقد المشترك العام المواجه للـ Plugin.
- `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` الموطن المشترك للتخفيف من التكرار، ومطابقة الإشارات، ومساعدات سياسة الإشارة الواردة، وتنسيق envelopes، ومساعدات سياق envelopes الواردة.
  ويُعد `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، ومساعدات
  التنقيح، ومساعدات وسوم التوجيه، وأدوات النص الآمن.
- يجب أن تفضّل حدود القنوات الخاصة بالموافقات عقد `approvalCapability`
  واحدًا على Plugin. ثم تقرأ النواة مصادقة الموافقات والتسليم والعرض
  والتوجيه الأصلي وسلوك المعالج الأصلي الكسول عبر تلك القدرة الواحدة
  بدلًا من خلط سلوك الموافقة في حقول Plugin غير المرتبطة.
- تم إهمال `openclaw/plugin-sdk/channel-runtime` ولم يعد موجودًا إلا كطبقة
  توافقية لPlugins الأقدم. يجب على الكود الجديد استيراد الأساسيات العامة الأضيق بدلًا منه، ويجب ألا يضيف كود المستودع استيرادات جديدة من
  هذه الطبقة.
- تظل الأجزاء الداخلية للإضافات المضمّنة خاصة. يجب على Plugins الخارجية استخدام
  المسارات الفرعية `openclaw/plugin-sdk/*` فقط. ويمكن لكود/اختبارات OpenClaw الأساسية استخدام
  نقاط الدخول العامة للمستودع تحت جذر حزمة Plugin مثل `index.js` و`api.js`،
  و`runtime-api.js` و`setup-entry.js`، والملفات الضيقة النطاق مثل
  `login-qr-api.js`. ولا تستورد أبدًا `src/*` من حزمة Plugin من النواة أو من
  إضافة أخرى.
- تقسيم نقطة دخول المستودع:
  `<plugin-package-root>/api.js` هو حاوية المساعدات/الأنواع،
  و`<plugin-package-root>/runtime-api.js` هو الحاوية الخاصة بوقت التشغيل فقط،
  و`<plugin-package-root>/index.js` هو مدخل Plugin المضمّن،
  و`<plugin-package-root>/setup-entry.js` هو مدخل Plugin الخاص بالإعداد.
- أمثلة حالية على المزوّدات المضمّنة:
  - يستخدم Anthropic `api.js` / `contract-api.js` لمساعدات تدفق Claude مثل
    `wrapAnthropicProviderStream`، ومساعدات رؤوس beta، وتحليل `service_tier`.
  - يستخدم OpenAI `api.js` لبناة المزوّدات، ومساعدات النماذج الافتراضية،
    وبناة المزوّدات الفورية.
  - يستخدم OpenRouter `api.js` لباني المزوّد الخاص به إضافةً إلى مساعدات
    الإعداد/التهيئة، بينما لا يزال بإمكان `register.runtime.js` إعادة تصدير
    مساعدات `plugin-sdk/provider-stream` العامة للاستخدام المحلي داخل المستودع.
- تفضّل نقاط الدخول العامة المحمّلة عبر facade لقطة إعدادات وقت التشغيل النشطة
  عندما تكون موجودة، ثم تعود إلى ملف الإعدادات المحلول على القرص عندما
  لا يكون OpenClaw قد بدأ بعد في تقديم لقطة وقت التشغيل.
- تظل الأساسيات العامة المشتركة هي عقد SDK العام المفضل. ولا تزال هناك
  مجموعة توافقية صغيرة ومحجوزة من حدود المساعدات ذات العلامات الخاصة بالقنوات المضمّنة.
  تعامل مع هذه على أنها حدود للصيانة/التوافق الخاصة بالحزم المضمّنة، لا كأهداف استيراد جديدة لجهات خارجية؛ ويجب أن تستمر العقود الجديدة العابرة للقنوات في
  الوصول إلى المسارات الفرعية العامة `plugin-sdk/*` أو الحاويات المحلية للـ Plugin
  `api.js` / `runtime-api.js`.

ملاحظة حول التوافق:

- تجنّب حاوية الجذر `openclaw/plugin-sdk` في الكود الجديد.
- فضّل أولًا الأساسيات المستقرة الضيقة. فالمسارات الفرعية الأحدث الخاصة بالإعداد/الإقران/الرد/
  التغذية الراجعة/العقد/الوارد/الخيوط/الأوامر/secret-input/Webhook/البنية التحتية/
  قائمة السماح/الحالة/أداة الرسائل هي العقد المقصود لأعمال Plugins الجديدة
  المضمّنة والخارجية.
  يجب أن يكون تحليل/مطابقة الهدف على `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`
  للـ Plugin المالك.
- توجد مسارات فرعية خاصة بالقدرات مثل `image-generation`،
  و`media-understanding`، و`speech` لأن Plugins المضمّنة/الأصلية تستخدمها
  اليوم. ولا يعني وجودها بحد ذاته أن كل مساعد مُصدَّر هو
  عقد خارجي مجمّد طويل الأمد.

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

يجب أن تملك Plugins مساهمات مخطط `describeMessageTool(...)` الخاصة بالقنوات.
أبقِ الحقول الخاصة بالمزوّد في Plugin، لا في النواة المشتركة.

بالنسبة إلى أجزاء المخطط المشتركة القابلة للنقل، أعد استخدام المساعدات العامة
المصدّرة عبر `openclaw/plugin-sdk/channel-actions`:

- `createMessageToolButtonsSchema()` لحمولات بأسلوب شبكة الأزرار
- `createMessageToolCardSchema()` لحمولات البطاقات المنظمة

إذا كان شكل المخطط منطقيًا فقط لمزوّد واحد، فعرّفه في المصدر
الخاص بذلك Plugin بدلًا من ترقيته إلى SDK المشتركة.

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

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

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

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

- استخدم `inferTargetChatType` لقرارات التصنيف التي يجب أن تحدث قبل
  البحث في الأقران/المجموعات.
- استخدم `looksLikeId` لفحوصات "عامل هذا كمعرّف هدف صريح/أصلي".
- استخدم `resolveTarget` للتراجع الخاص بالتطبيع عند المزوّد، لا
  للبحث الواسع في الدليل.
- أبقِ المعرّفات الأصلية للمزوّد مثل معرّفات الدردشة، ومعرّفات السلاسل، وJIDs، والمعالجات، ومعرّفات الغرف
  داخل قيم `target` أو البارامترات الخاصة بالمزوّد، لا في حقول SDK العامة.

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

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

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

- أقران DM مدفوعين بقائمة السماح
- خرائط القنوات/المجموعات المهيأة
- تراجعات الدليل الثابتة المقيّدة بالحساب

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

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

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

## فهارس المزوّدات

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

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

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

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

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

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

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

التوافق:

- لا يزال `discovery` يعمل كاسم مستعار قديم
- إذا تم تسجيل كلٍّ من `catalog` و`discovery`، يستخدم OpenClaw `catalog`

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

إذا كان Plugin الخاص بك يسجّل قناة، ففضّل تنفيذ
`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

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

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

يصبح كل إدخال Plugin. وإذا كانت الحزمة تسرد عدة extensions، يصبح معرّف Plugin
`name/<fileBase>`.

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

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

ملاحظة أمنية: يثبّت `openclaw plugins install` تبعيات Plugin باستخدام
`npm install --omit=dev --ignore-scripts` (من دون lifecycle scripts، ومن دون تبعيات تطوير وقت التشغيل). أبقِ أشجار تبعيات 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` دائمًا.

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

عندما تتضمن أسطح بدء التشغيل هذه أساليب Gateway RPC، فأبقِها على
بادئة خاصة بالـ 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
    }
  }
}
```

### بيانات وصفية لفهرس القنوات

يمكن لPlugins القنوات الإعلان عن بيانات وصفية للإعداد/الاكتشاف عبر `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"`.

## Plugins محرك السياق

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

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

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

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

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

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

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

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

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

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

### قائمة التحقق الخاصة بالقدرات

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

- أنواع عقود النواة في `src/<capability>/types.ts`
- مشغّل/مساعد وقت تشغيل النواة في `src/<capability>/runtime.ts`
- سطح تسجيل واجهة Plugin API في `src/plugins/types.ts`
- ربط سجل Plugins في `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,
});
```

نمط اختبار العقد:

```ts
expect(findVideoGenerationProviderIdsForPlugin("openai")).toEqual(["openai"]);
```

وهذا يُبقي القاعدة بسيطة:

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