Plugin maintainer reference

جزئیات داخلی معماری Plugin

برای مدل عمومی قابلیت‌ها، شکل‌های Plugin و قراردادهای مالکیت/اجرا، به معماری Plugin مراجعه کنید. این صفحه سازوکارهای داخلی را پوشش می‌دهد: پایپ‌لاین بارگذاری، رجیستری، هوک‌های زمان اجرا، مسیرهای HTTP Gateway، مسیرهای import و جدول‌های اسکیما.

پایپ‌لاین بارگذاری

هنگام راه‌اندازی، OpenClaw تقریباً این کارها را انجام می‌دهد:

  1. ریشه‌های کاندید Plugin را کشف می‌کند
  2. مانیفست‌های باندل بومی یا سازگار و فراداده‌های بسته را می‌خواند
  3. کاندیدهای ناامن را رد می‌کند
  4. پیکربندی Plugin را عادی‌سازی می‌کند (plugins.enabled، allow، deny، entries، slots، load.paths)
  5. فعال‌بودن هر کاندید را تعیین می‌کند
  6. ماژول‌های بومی فعال را بارگذاری می‌کند: ماژول‌های باندل‌شده ساخته‌شده از بارگذار بومی استفاده می‌کنند؛ کد منبع محلی TypeScript متعلق به شخص ثالث از مسیر جایگزین اضطراری Jiti استفاده می‌کند
  7. هوک‌های بومی register(api) را فراخوانی می‌کند و ثبت‌ها را در رجیستری Plugin گردآوری می‌کند
  8. رجیستری را در اختیار فرمان‌ها/سطوح زمان اجرا قرار می‌دهد

گیت‌های ایمنی پیش از اجرای زمان اجرا اعمال می‌شوند. کشف، یک کاندید را در موارد زیر مسدود می‌کند:

  • ورودی resolve‌شده آن از ریشه Plugin خارج شود
  • مسیر آن (یا دایرکتوری ریشه‌اش) برای همه قابل‌نوشتن باشد
  • برای Pluginهای غیرباندل‌شده، مالکیت مسیر با uid فعلی (یا root) مطابقت نداشته باشد

برای دایرکتوری‌های باندل‌شده‌ای که برای همه قابل‌نوشتن هستند، ابتدا تلاش می‌شود chmod درجا ترمیم شود (نصب‌های npm/سراسری ممکن است دایرکتوری‌های بسته را با 0777 ارائه کنند) و سپس گیت دوباره بررسی می‌شود؛ بررسی مالکیت برای مبدأ باندل‌شده به‌طور کامل نادیده گرفته می‌شود.

اگر شناسه Plugin کاندیدهای مسدودشده مشخص باشد، همچنان در تشخیص صادرشده درج می‌شود (از جمله شناسه‌هایی که از مانیفستی درون یک دایرکتوریِ در غیر این صورت ردشده resolve شده‌اند)؛ بنابراین پیکربندی‌ای که به آن شناسه ارجاع می‌دهد، به‌جای خطای نامرتبط «Plugin ناشناخته»، یک Plugin مسدودشده مرتبط با هشدار ایمنی مسیر را مشاهده می‌کند.

رفتار مبتنی بر مانیفست

مانیفست منبع حقیقت صفحه کنترل است. OpenClaw از آن برای این موارد استفاده می‌کند:

  • شناسایی Plugin
  • کشف کانال‌ها/Skills/اسکیمای پیکربندی یا قابلیت‌های باندلِ اعلام‌شده
  • اعتبارسنجی plugins.entries.<id>.config
  • تکمیل برچسب‌ها/متن‌های جای‌نمای Control UI
  • نمایش فراداده‌های نصب/کاتالوگ
  • حفظ توصیفگرهای کم‌هزینه فعال‌سازی و راه‌اندازی بدون بارگذاری زمان اجرای Plugin

برای Pluginهای بومی، ماژول زمان اجرا بخش صفحه داده است. این ماژول رفتار واقعی، مانند هوک‌ها، ابزارها، فرمان‌ها یا جریان‌های ارائه‌دهنده را ثبت می‌کند.

بلوک‌های اختیاری activation و setup مانیفست در صفحه کنترل باقی می‌مانند. آن‌ها توصیفگرهای صرفاً فراداده‌ای برای برنامه‌ریزی فعال‌سازی و کشف راه‌اندازی هستند؛ جایگزین ثبت زمان اجرا، register(...) یا setupEntry نمی‌شوند. مصرف‌کنندگان فعال‌سازی زنده از سرنخ‌های فرمان، کانال و ارائه‌دهنده مانیفست استفاده می‌کنند تا پیش از تحقق گسترده‌تر رجیستری، بارگذاری Plugin را محدود کنند:

  • بارگذاری CLI به Pluginهایی محدود می‌شود که مالک فرمان اصلی درخواستی هستند
  • تفکیک راه‌اندازی کانال/Plugin به Pluginهایی محدود می‌شود که مالک شناسه کانال درخواستی هستند
  • تفکیک صریح راه‌اندازی/زمان اجرای ارائه‌دهنده به Pluginهایی محدود می‌شود که مالک شناسه ارائه‌دهنده درخواستی هستند
  • برنامه‌ریزی راه‌اندازی Gateway برای importهای صریح راه‌اندازی از activation.onStartup استفاده می‌کند؛ Pluginهای بدون فراداده راه‌اندازی فقط از طریق محرک‌های محدودتر فعال‌سازی بارگذاری می‌شوند

برنامه‌ریز فعال‌سازی هم یک 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 (providersmanifest-setup-provider-owner (setup.providers)
activation-route-hint
— (محرک هوک گونه سرنخ ندارد) manifest-hook-owner (hooksmanifest-tool-contract (contracts.tools)

این تفکیک دلیل، مرز سازگاری است: فراداده‌های موجود Plugin همچنان کار می‌کنند، درحالی‌که کد جدید می‌تواند سرنخ‌های گسترده یا رفتار مسیر جایگزین را بدون تغییر معناشناسی بارگذاری زمان اجرا تشخیص دهد.

پیش‌بارگذاری‌های زمان اجرا در زمان درخواست که دامنه گسترده all را درخواست می‌کنند، همچنان یک مجموعه صریح و مؤثر از شناسه‌های Plugin را از پیکربندی، برنامه‌ریزی راه‌اندازی، کانال‌های پیکربندی‌شده، اسلات‌ها و قواعد فعال‌سازی خودکار استخراج می‌کنند (resolveEffectivePluginIds در src/plugins/effective-plugin-ids.ts). اگر این مجموعه استخراج‌شده خالی باشد، OpenClaw به‌جای گسترش آن به همه Pluginهای قابل‌کشف، دامنه را خالی نگه می‌دارد.

کشف راه‌اندازی، شناسه‌های متعلق به توصیفگر مانند setup.providers و setup.cliBackends را برای محدودکردن Pluginهای کاندید ترجیح می‌دهد و سپس برای Pluginهایی که همچنان به هوک‌های زمان اجرای هنگام راه‌اندازی نیاز دارند، به setup-api برمی‌گردد. فهرست‌های راه‌اندازی ارائه‌دهنده بدون بارگذاری زمان اجرای ارائه‌دهنده، از providerAuthChoices مانیفست، گزینه‌های راه‌اندازی استخراج‌شده از توصیفگر و فراداده‌های کاتالوگ نصب استفاده می‌کنند. setup.requiresRuntime: false صریح یک نقطه قطع صرفاً مبتنی بر توصیفگر است؛ حذف requiresRuntime مسیر جایگزین setup-api قدیمی را برای سازگاری حفظ می‌کند. اگر بیش از یک Plugin کشف‌شده مالکیت یک ارائه‌دهنده راه‌اندازی عادی‌سازی‌شده یا شناسه بک‌اند CLI یکسان را ادعا کنند، جست‌وجوی راه‌اندازی به‌جای تکیه بر ترتیب کشف، مالک مبهم را رد می‌کند. هنگامی که زمان اجرای راه‌اندازی اجرا می‌شود، تشخیص‌های رجیستری بدون مسدودکردن Pluginهای قدیمی، ناهمخوانی میان setup.providers / setup.cliBackends و ارائه‌دهندگان یا بک‌اندهای CLI واقعاً ثبت‌شده توسط setup-api را گزارش می‌کنند.

مرز کش Plugin

OpenClaw نتایج کشف Plugin یا داده‌های مستقیم رجیستری مانیفست را پشت بازه‌های زمانی مبتنی بر ساعت کش نمی‌کند. نصب‌ها، ویرایش‌های مانیفست و تغییرات مسیر بارگذاری باید در خواندن صریح بعدی فراداده یا بازسازی بعدی اسنپ‌شات قابل‌مشاهده شوند. تجزیه‌گر فایل مانیفست یک کش محدود امضای فایل را نگه می‌دارد که کلید آن مسیر مانیفست بازشده به‌همراه دستگاه/inode، اندازه و mtime/ctime است؛ این کش فقط از تجزیه مجدد بایت‌های بدون تغییر جلوگیری می‌کند و نباید پاسخ‌های کشف، رجیستری، مالک یا سیاست را کش کند.

مسیر سریع و ایمن فراداده، مالکیت صریح شیء است، نه یک کش پنهان. مسیرهای پرتکرار راه‌اندازی Gateway باید PluginMetadataSnapshot فعلی، PluginLookUpTable استخراج‌شده یا یک رجیستری صریح مانیفست را در طول زنجیره فراخوانی عبور دهند. اعتبارسنجی پیکربندی، فعال‌سازی خودکار هنگام راه‌اندازی، بوت‌استرپ Plugin و انتخاب ارائه‌دهنده می‌توانند تا زمانی که این اشیا نماینده پیکربندی و موجودی فعلی Plugin هستند، دوباره از آن‌ها استفاده کنند. جست‌وجوی راه‌اندازی همچنان فراداده مانیفست را هنگام نیاز بازسازی می‌کند، مگر اینکه مسیر راه‌اندازی مشخص یک رجیستری صریح مانیفست دریافت کند؛ این را به‌عنوان مسیر جایگزین کم‌کاربرد نگه دارید و کش‌های جست‌وجوی پنهان اضافه نکنید. هنگام تغییر ورودی، به‌جای جهش‌دادن اسنپ‌شات یا نگه‌داشتن نسخه‌های تاریخی، آن را بازسازی و جایگزین کنید. نماهای رجیستری فعال Plugin و کمک‌کننده‌های بوت‌استرپ کانال باندل‌شده باید از رجیستری/ریشه فعلی دوباره محاسبه شوند. نقشه‌های کوتاه‌عمر درون یک فراخوان برای حذف کار تکراری یا محافظت در برابر ورود مجدد مناسب‌اند؛ اما نباید به کش‌های فراداده فرایند تبدیل شوند.

برای بارگذاری Plugin، لایه کش پایدار همان بارگذاری زمان اجرا است. این لایه زمانی که کد یا مصنوعات نصب‌شده واقعاً بارگذاری می‌شوند، می‌تواند از وضعیت بارگذار دوباره استفاده کند، مانند:

  • PluginLoaderCacheState و رجیستری‌های سازگار و فعال زمان اجرا
  • کش‌های jiti/ماژول و کش‌های بارگذار سطح عمومی که برای جلوگیری از import مکرر همان سطح زمان اجرا استفاده می‌شوند
  • کش‌های سیستم فایل برای مصنوعات نصب‌شده Plugin
  • نقشه‌های کوتاه‌عمر هر فراخوان برای عادی‌سازی مسیر یا تفکیک موارد تکراری

این کش‌ها جزئیات پیاده‌سازی صفحه داده هستند. آن‌ها نباید به پرسش‌های صفحه کنترل، مانند «مالک این ارائه‌دهنده کدام Plugin است؟»، پاسخ دهند؛ مگر اینکه فراخوان عمداً بارگذاری زمان اجرا را درخواست کرده باشد.

برای موارد زیر کش‌های پایدار یا مبتنی بر ساعت اضافه نکنید:

  • نتایج کشف
  • رجیستری‌های مستقیم مانیفست
  • رجیستری‌های مانیفست بازسازی‌شده از نمایه Pluginهای نصب‌شده
  • جست‌وجوی مالک ارائه‌دهنده، سرکوب مدل، سیاست ارائه‌دهنده یا فراداده مصنوعات عمومی
  • هر پاسخ مشتق‌شده دیگری از مانیفست که در آن، مانیفست، نمایه نصب‌شده یا مسیر بارگذاری تغییریافته باید در خواندن بعدی فراداده قابل‌مشاهده باشد

فراخوان‌هایی که فراداده مانیفست را از نمایه ماندگار Pluginهای نصب‌شده بازسازی می‌کنند، آن رجیستری را هنگام نیاز دوباره می‌سازند. نمایه نصب‌شده، وضعیت ماندگار صفحه منبع است؛ نه یک کش پنهان فراداده درون فرایند.

مدل رجیستری

Pluginهای بارگذاری‌شده مستقیماً متغیرهای سراسری تصادفی هسته را تغییر نمی‌دهند. آن‌ها در یک رجیستری مرکزی Plugin (PluginRegistry در src/plugins/registry-types.ts) ثبت می‌شوند که رکوردهای Plugin (هویت، منبع، مبدأ، وضعیت و تشخیص‌ها) را به‌همراه آرایه‌هایی برای هر قابلیت ردیابی می‌کند: ابزارها، هوک‌های قدیمی و هوک‌های نوع‌دار، کانال‌ها، ارائه‌دهندگان، هندلرهای RPC در Gateway، مسیرهای HTTP، ثبت‌کننده‌های CLI، سرویس‌های پس‌زمینه، فرمان‌های متعلق به Plugin و ده‌ها خانواده نوع‌دار دیگر ارائه‌دهنده (گفتار، embedding، تولید تصویر/ویدئو/موسیقی، واکشی/جست‌وجوی وب، هارنس‌های عامل، کنش‌های نشست و موارد دیگر).

سپس قابلیت‌های هسته به‌جای ارتباط مستقیم با ماژول‌های Plugin، از آن رجیستری می‌خوانند. این کار بارگذاری را یک‌طرفه نگه می‌دارد:

  • ماژول Plugin -> ثبت در رجیستری
  • زمان اجرای هسته -> مصرف رجیستری

این جداسازی برای نگهداشت‌پذیری مهم است. به این معناست که بیشتر سطوح هسته فقط به یک نقطه یکپارچه‌سازی نیاز دارند: «خواندن رجیستری»، نه «رسیدگی ویژه به تک‌تک ماژول‌های Plugin».

کال‌بک‌های اتصال مکالمه

Pluginهایی که یک مکالمه را متصل می‌کنند، می‌توانند هنگام تعیین نتیجه یک تأیید واکنش نشان دهند.

برای دریافت کال‌بک پس از تأیید یا رد درخواست اتصال، از api.onConversationBindingResolved(...) استفاده کنید:

ts
export default {  id: "my-plugin",  register(api) {    api.onConversationBindingResolved(async (event) => {      if (event.status === "approved") {        // اکنون برای این Plugin و مکالمه یک اتصال وجود دارد.        console.log(event.binding?.conversationId);        return;      }       // درخواست رد شد؛ هر وضعیت محلی در انتظار را پاک کنید.      console.log(event.request.conversation.conversationId);    });  },};

فیلدهای بار کال‌بک:

  • status: "approved" یا "denied"
  • decision: "allow-once"، "allow-always" یا "deny"
  • binding: اتصال تعیین‌شده برای درخواست‌های تأییدشده
  • request: خلاصه درخواست اصلی، راهنمای جداسازی، شناسه فرستنده و فراداده مکالمه

این کال‌بک صرفاً برای اعلان است. تعیین نمی‌کند چه کسی مجاز به اتصال یک مکالمه است و پس از پایان رسیدگی هسته به تأیید اجرا می‌شود.

هوک‌های زمان اجرای ارائه‌دهنده

Pluginهای ارائه‌دهنده سه لایه دارند:

  • فراداده مانیفست برای جست‌وجوی کم‌هزینه پیش از زمان اجرا: setup.providers[].envVars، providerAuthAliases، providerAuthChoices و channelConfigs.
  • هوک‌های زمان پیکربندی: catalog به‌همراه applyConfigDefaults.
  • هوک‌های زمان اجرا: بیش از 40 هوک اختیاری که احراز هویت، تفکیک مدل، پوشش‌دهی جریان، سطوح تفکر، سیاست بازپخش و نقاط پایانی مصرف را پوشش می‌دهند. به ترتیب و کاربرد هوک‌ها مراجعه کنید.

OpenClaw همچنان مالک چرخهٔ عمومی عامل، تغییر مسیر هنگام خرابی، مدیریت رونوشت و سیاست ابزار است. این هوک‌ها سطح توسعه برای رفتار مختص ارائه‌دهنده هستند، بدون آن‌که به یک انتقال استنتاج کاملاً سفارشی نیاز باشد.

هنگامی که ارائه‌دهنده اعتبارنامه‌های مبتنی بر متغیر محیطی دارد که مسیرهای عمومی احراز هویت/وضعیت/انتخاب‌گر مدل باید بدون بارگذاری زمان اجرای Plugin ببینند، از setup.providers[].envVars مانیفست استفاده کنید. هنگامی که یک شناسهٔ ارائه‌دهنده باید متغیرهای محیطی، نمایه‌های احراز هویت، احراز هویت مبتنی بر پیکربندی و گزینهٔ راه‌اندازی اولیهٔ کلید API شناسهٔ ارائه‌دهنده‌ای دیگر را بازاستفاده کند، از providerAuthAliases مانیفست استفاده کنید. هنگامی که سطوح CLI مربوط به راه‌اندازی اولیه/انتخاب احراز هویت باید بدون بارگذاری زمان اجرای ارائه‌دهنده، شناسهٔ گزینه، برچسب‌های گروه و سیم‌کشی سادهٔ احراز هویت با یک پرچم ارائه‌دهنده را بدانند، از providerAuthChoices مانیفست استفاده کنید. envVars زمان اجرای ارائه‌دهنده را برای راهنمایی‌های ویژهٔ اپراتور، مانند برچسب‌های راه‌اندازی اولیه یا متغیرهای تنظیم شناسهٔ کلاینت/رمز کلاینت OAuth، نگه دارید.

راه‌اندازی کانال و احراز هویت مبتنی بر متغیر محیطی را از طریق channelConfigs.<id>.schema مالک و توصیف‌گرهای راه‌اندازی شرح دهید.

ترتیب و کاربرد هوک‌ها

برای Pluginهای مدل/ارائه‌دهنده، OpenClaw هوک‌ها را تقریباً به این ترتیب فراخوانی می‌کند. ستون «زمان استفاده» راهنمای تصمیم‌گیری سریع است. فیلدهای ارائه‌دهنده که فقط برای سازگاری هستند و OpenClaw دیگر آن‌ها را فراخوانی نمی‌کند، مانند ProviderPlugin.capabilities و suppressBuiltInModel، عمداً در اینجا فهرست نشده‌اند.

Hook کارکرد زمان استفاده
catalog انتشار پیکربندی ارائه‌دهنده در models.providers هنگام تولید models.json ارائه‌دهنده مالک یک کاتالوگ یا مقادیر پیش‌فرض URL پایه است
applyConfigDefaults اعمال مقادیر پیش‌فرض پیکربندی سراسریِ متعلق به ارائه‌دهنده هنگام مادی‌سازی پیکربندی مقادیر پیش‌فرض به حالت احراز هویت، محیط یا معناشناسی خانواده مدلِ ارائه‌دهنده وابسته‌اند
(جست‌وجوی داخلی مدل) OpenClaw ابتدا مسیر عادی رجیستری/کاتالوگ را امتحان می‌کند (Hook مربوط به Plugin نیست)
normalizeModelId عادی‌سازی نام‌های مستعار قدیمی یا پیش‌نمایشِ شناسه مدل پیش از جست‌وجو ارائه‌دهنده پیش از تفکیک مدل کانونی، پاک‌سازی نام‌های مستعار را بر عهده دارد
normalizeTransport عادی‌سازی api / baseUrl خانواده ارائه‌دهنده پیش از مونتاژ عمومی مدل ارائه‌دهنده پاک‌سازی انتقال را برای شناسه‌های سفارشی ارائه‌دهنده در همان خانواده انتقال بر عهده دارد
normalizeConfig عادی‌سازی models.providers.<id> پیش از تفکیک زمان اجرا/ارائه‌دهنده ارائه‌دهنده به پاک‌سازی پیکربندی‌ای نیاز دارد که باید در Plugin قرار گیرد؛ کمک‌کننده‌های همراهِ خانواده Google نیز به‌عنوان پشتیبان، ورودی‌های پیکربندی پشتیبانی‌شده Google را پوشش می‌دهند
applyNativeStreamingUsageCompat اعمال بازنویسی‌های سازگاریِ بومیِ مصرف استریم روی ارائه‌دهندگان پیکربندی ارائه‌دهنده به اصلاح فراداده مصرف بومی استریم بر اساس نقطه پایانی نیاز دارد
resolveConfigApiKey تفکیک احراز هویت با نشانگر محیطی برای ارائه‌دهندگان پیکربندی پیش از بارگذاری احراز هویت زمان اجرا ارائه‌دهندگان Hookهای تفکیک کلید API با نشانگر محیطی خود را ارائه می‌کنند
resolveSyntheticAuth ارائه احراز هویت محلی/میزبانی‌شده توسط خود یا مبتنی بر پیکربندی، بدون ذخیره متن ساده ارائه‌دهنده می‌تواند با یک نشانگر اعتبارنامه مصنوعی/محلی کار کند
resolveExternalAuthProfiles هم‌پوشانی پروفایل‌های احراز هویت خارجیِ متعلق به ارائه‌دهنده؛ مقدار پیش‌فرض persistence برای اعتبارنامه‌های متعلق به CLI/برنامه، runtime-only است ارائه‌دهنده بدون ذخیره توکن‌های نوسازیِ کپی‌شده، از اعتبارنامه‌های احراز هویت خارجی دوباره استفاده می‌کند؛ 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 خط‌مشی کش پرامپت برای ارائه‌دهندگان پراکسی/بک‌هاول ارائه‌دهنده به کنترل TTL کش مختص پراکسی نیاز دارد
buildMissingAuthMessage جایگزین پیام عمومی بازیابیِ نبود احراز هویت ارائه‌دهنده به راهنمای بازیابی مختص ارائه‌دهنده برای نبود احراز هویت نیاز دارد
augmentModelCatalog ردیف‌های مصنوعی/نهایی کاتالوگ که پس از کشف افزوده می‌شوند (منسوخ‌شده، پایین را ببینید) ارائه‌دهنده به ردیف‌های مصنوعیِ سازگاری آتی در models list و انتخاب‌گرها نیاز دارد
resolveThinkingProfile مجموعه سطح /think مختص مدل، برچسب‌های نمایشی و مقدار پیش‌فرض ارائه‌دهنده برای مدل‌های منتخب یک نردبان تفکر سفارشی یا برچسب دودویی ارائه می‌کند
isBinaryThinking Hook سازگاری تغییر وضعیت روشن/خاموش استدلال ارائه‌دهنده فقط تفکر دودویی روشن/خاموش را ارائه می‌کند
supportsXHighThinking Hook سازگاری پشتیبانی استدلال xhigh ارائه‌دهنده xhigh را فقط روی زیرمجموعه‌ای از مدل‌ها می‌خواهد
resolveDefaultThinkingLevel Hook سازگاری سطح پیش‌فرض /think ارائه‌دهنده مالک خط‌مشی پیش‌فرض /think برای یک خانواده مدل است
isModernModelRef تطبیق‌دهنده مدل مدرن برای فیلترهای پروفایل زنده و انتخاب آزمون دود ارائه‌دهنده مالک تطبیق مدل ترجیحی زنده/دود است
prepareRuntimeAuth تبدیل اعتبارنامه پیکربندی‌شده به توکن/کلید واقعی زمان اجرا، درست پیش از استنتاج ارائه‌دهنده به تبادل توکن یا اعتبارنامه کوتاه‌عمر درخواست نیاز دارد
resolveUsageAuth تفکیک اعتبارنامه‌های مصرف/صورتحساب برای /usage و سطوح وضعیت مرتبط ارائه‌دهنده به تجزیه سفارشی توکن مصرف/سهمیه یا اعتبارنامه مصرف متفاوتی نیاز دارد
fetchUsageSnapshot دریافت و عادی‌سازی عکس‌های فوری مصرف/سهمیه مختص ارائه‌دهنده پس از تفکیک احراز هویت ارائه‌دهنده به یک نقطه پایانی مصرف یا تجزیه‌کننده بار داده مختص ارائه‌دهنده نیاز دارد
createEmbeddingProvider ساخت یک آداپتور تعبیه‌سازی تحت مالکیت ارائه‌دهنده برای حافظه/جست‌وجو رفتار تعبیه‌سازی حافظه به Plugin ارائه‌دهنده تعلق دارد
buildReplayPolicy بازگرداندن یک خط‌مشی بازپخش که نحوهٔ مدیریت رونوشت را برای ارائه‌دهنده کنترل می‌کند ارائه‌دهنده به خط‌مشی سفارشی رونوشت نیاز دارد (برای مثال، حذف بلوک‌های تفکر)
sanitizeReplayHistory بازنویسی تاریخچهٔ بازپخش پس از پاک‌سازی عمومی رونوشت ارائه‌دهنده، فراتر از توابع کمکی مشترک Compaction، به بازنویسی‌های بازپخش ویژهٔ ارائه‌دهنده نیاز دارد
validateReplayTurns اعتبارسنجی نهایی یا بازشکل‌دهی نوبت بازپخش پیش از اجراکنندهٔ تعبیه‌شده انتقال ارائه‌دهنده پس از پاک‌سازی عمومی به اعتبارسنجی سخت‌گیرانه‌تر نوبت نیاز دارد
onModelSelected اجرای اثرات جانبی پس از انتخاب تحت مالکیت ارائه‌دهنده هنگام فعال‌شدن یک مدل، ارائه‌دهنده به تله‌متری یا وضعیت تحت مالکیت ارائه‌دهنده نیاز دارد

normalizeModelId، normalizeTransport و normalizeConfig ابتدا Plugin ارائه‌دهنده منطبق را بررسی می‌کنند، سپس به‌ترتیب سراغ دیگر Pluginهای ارائه‌دهنده دارای قابلیت hook می‌روند تا یکی از آن‌ها واقعاً شناسه مدل یا انتقال/پیکربندی را تغییر دهد. این کار باعث می‌شود shimهای ارائه‌دهنده برای نام مستعار/سازگاری، بدون نیاز به آگاهی فراخواننده از اینکه کدام Plugin همراه مالک بازنویسی است، همچنان کار کنند. اگر هیچ hook ارائه‌دهنده‌ای یک ورودی پیکربندی پشتیبانی‌شده از خانواده Google را بازنویسی نکند، نرمال‌ساز پیکربندی Google همراه همچنان آن پاک‌سازی سازگاری را اعمال می‌کند.

اگر ارائه‌دهنده به پروتکل ارتباطی کاملاً سفارشی یا اجراکننده درخواست سفارشی نیاز داشته باشد، این نوع دیگری از افزونه است. این hookها برای رفتار ارائه‌دهنده‌ای هستند که همچنان در حلقه استنتاج عادی OpenClaw اجرا می‌شود.

resolveUsageAuth تعیین می‌کند که OpenClaw باید fetchUsageSnapshot را فراخوانی کند یا برای سطوح مصرف/وضعیت به تفکیک عمومی اعتبارنامه بازگردد. وقتی ارائه‌دهنده اعتبارنامه مصرف دارد، { token, accountId?, subscriptionType?, rateLimitTier? } را برگردانید (فراداده اختیاری طرح به fetchUsageSnapshot منتقل می‌شود)، وقتی احراز هویت مصرف متعلق به ارائه‌دهنده درخواست را مدیریت کرده و باید بازگشت عمومی به کلید API/OAuth را متوقف کند، { handled: true } را برگردانید، و وقتی ارائه‌دهنده احراز هویت مصرف را مدیریت نکرده است، 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);  },});

نمونه‌های داخلی

Pluginهای ارائه‌دهنده همراه، hookهای بالا را ترکیب می‌کنند تا با نیازهای فهرست، احراز هویت، تفکر، بازپخش و مصرف هر عرضه‌کننده سازگار شوند. مجموعه معتبر hookها همراه هر Plugin در extensions/ قرار دارد؛ این صفحه به‌جای بازتاب فهرست، شکل‌ها را نمایش می‌دهد.

ارائه‌دهندگان فهرست عبوری

OpenRouter، Kilocode، Z.AI و xAI، ‏catalog را همراه با resolveDynamicModel / prepareDynamicModel ثبت می‌کنند تا بتوانند شناسه‌های مدل بالادستی را پیش از فهرست ایستای OpenClaw ارائه کنند.

ارائه‌دهندگان نقطه پایانی OAuth و مصرف

GitHub Copilot، Gemini CLI، ChatGPT Codex، MiniMax، Xiaomi و z.ai، ‏prepareRuntimeAuth یا formatApiKey را با resolveUsageAuth + fetchUsageSnapshot جفت می‌کنند تا مالک تبادل توکن و یکپارچه‌سازی /usage باشند.

خانواده‌های پاک‌سازی بازپخش و رونوشت

خانواده‌های نام‌گذاری‌شده مشترک (google-gemini، passthrough-gemini، anthropic-by-model، hybrid-anthropic-openai) به ارائه‌دهندگان امکان می‌دهند به‌جای پیاده‌سازی مجدد پاک‌سازی در هر Plugin، از طریق buildReplayPolicy سیاست رونوشت را فعال کنند.

ارائه‌دهندگان صرفاً فهرست

byteplus، cloudflare-ai-gateway، huggingface، kimi-coding، nvidia، qianfan، synthetic، together، venice، vercel-ai-gateway و volcengine فقط catalog را ثبت می‌کنند و از حلقه استنتاج مشترک بهره می‌برند.

ابزارهای کمکی جریان ویژه Anthropic

سرآیندهای بتا، /fast / serviceTier و context1m به‌جای SDK عمومی، در مرز عمومی api.ts / contract-api.ts متعلق به Plugin ‏Anthropic قرار دارند (wrapAnthropicProviderStream، resolveAnthropicBetas، resolveAnthropicFastMode، resolveAnthropicServiceTier).

ابزارهای کمکی زمان اجرا

Pluginها می‌توانند از طریق 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 هسته را برای سطوح فایل/یادداشت صوتی برمی‌گرداند.
  • از پیکربندی tts هسته و انتخاب ارائه‌دهنده استفاده می‌کند.
  • بافر صوتی PCM + نرخ نمونه‌برداری را برمی‌گرداند. Pluginها باید برای ارائه‌دهندگان، بازنمونه‌برداری/رمزگذاری را انجام دهند.
  • listVoices برای هر ارائه‌دهنده اختیاری است. از آن برای انتخاب‌گرهای صدا یا جریان‌های راه‌اندازی متعلق به عرضه‌کننده استفاده کنید.
  • هسته مهلت نهایی تفکیک‌شده درخواست را به hookهای listVoices ارائه‌دهنده می‌دهد؛ تنظیمات مهلت زمانی ویژه ارائه‌دهنده ممکن است آن را بازنویسی کنند.
  • فهرست‌های صدا می‌توانند فراداده غنی‌تری مانند زبان‌محلی، جنسیت و برچسب‌های شخصیت را برای انتخاب‌گرهای آگاه از ارائه‌دهنده دربر گیرند.
  • امروزه OpenAI و ElevenLabs از تلفن پشتیبانی می‌کنند. Microsoft پشتیبانی نمی‌کند.

Pluginها همچنین می‌توانند ارائه‌دهندگان گفتار را از طریق 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، مالک ارائه‌دهندگان متن، گفتار، تصویر و رسانه‌های آینده باشد.

برای درک تصویر/صوت/ویدئو، Pluginها به‌جای یک مجموعه عمومی کلید/مقدار، یک ارائه‌دهنده نوع‌دار درک رسانه ثبت می‌کنند:

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

نکات:

  • هماهنگ‌سازی، بازگشت جایگزین، پیکربندی و سیم‌کشی کانال را در هسته نگه دارید.
  • رفتار عرضه‌کننده را در Plugin ارائه‌دهنده نگه دارید.
  • گسترش افزایشی باید نوع‌دار باقی بماند: متدهای اختیاری جدید، فیلدهای نتیجه اختیاری جدید و قابلیت‌های اختیاری جدید.
  • تولید ویدئو از قبل از همین الگو پیروی می‌کند:
    • هسته مالک قرارداد قابلیت و ابزار کمکی زمان اجرا است
    • Pluginهای عرضه‌کننده api.registerVideoGenerationProvider(...) را ثبت می‌کنند
    • Pluginهای قابلیت/کانال، api.runtime.videoGeneration.* را مصرف می‌کنند

برای ابزارهای کمکی زمان اجرای درک رسانه، Pluginها می‌توانند فراخوانی کنند:

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

برای رونویسی صوت، Pluginها می‌توانند از زمان اجرای درک رسانه یا نام مستعار قدیمی‌تر STT استفاده کنند:

ts
const { text } = await api.runtime.mediaUnderstanding.transcribeAudioFile({  filePath: "/tmp/inbound-audio.ogg",  cfg: api.config,  // اختیاری است، وقتی MIME را نتوان با اطمینان استنباط کرد:  mime: "audio/ogg",});

نکات:

  • api.runtime.mediaUnderstanding.* سطح مشترک ترجیحی برای درک تصویر/صوت/ویدئو است.
  • extractStructuredWithModel(...) مرز روبه‌Plugin برای استخراج محدود و تصویرمحور متعلق به ارائه‌دهنده است. دست‌کم یک ورودی تصویر قرار دهید؛ ورودی‌های متنی زمینه تکمیلی هستند. Pluginهای محصول مالک مسیرها و شِماهای خود هستند، درحالی‌که OpenClaw مالک مرز ارائه‌دهنده/زمان اجرا است.
  • از پیکربندی صوتی درک رسانه هسته (tools.media.audio) و ترتیب بازگشت جایگزین ارائه‌دهندگان استفاده می‌کند.
  • وقتی هیچ خروجی رونویسی تولید نشود (برای مثال، ورودی نادیده‌گرفته‌شده/پشتیبانی‌نشده)، { text: undefined } را برمی‌گرداند.

Pluginها همچنین می‌توانند از طریق 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.",  toolsAlsoAllow: ["my_plugin_progress"],  provider: "openai",  model: "gpt-4.1-mini",  deliver: false,});

نکات:

  • provider و model بازنویسی‌های اختیاری هر اجرا هستند، نه تغییرات پایدار نشست.
  • toolsAlsoAllow نام‌های دقیق و دارای مالک یکتای ابزارهایی را می‌پذیرد که Plugin فراخواننده ثبت کرده است. نام‌های هسته و نام‌های مبهم رد می‌شوند. این مورد به نمایه عادی افزوده می‌شود، اما فهرست‌های مجاز و ممنوع اپراتور همچنان مرجع نهایی هستند.
  • OpenClaw فقط برای فراخوانندگان مورداعتماد به این فیلدهای بازنویسی ترتیب اثر می‌دهد.
  • برای اجراهای بازگشت جایگزین متعلق به Plugin، اپراتورها باید با plugins.entries.<id>.subagent.allowModelOverride: true صریحاً موافقت کنند.
  • برای محدودکردن Pluginهای مورداعتماد به اهداف متعارف مشخص provider/model از plugins.entries.<id>.subagent.allowedModels، یا برای اجازه صریح به هر هدفی از "*" استفاده کنید.
  • اجرای زیرعامل Pluginهای نامطمئن همچنان کار می‌کند، اما درخواست‌های بازنویسی به‌جای بازگشت بی‌سروصدا رد می‌شوند.
  • نشست‌های زیرعامل ایجادشده توسط Plugin با شناسه Plugin سازنده برچسب‌گذاری می‌شوند. api.runtime.subagent.deleteSession(...) بازگشت جایگزین فقط می‌تواند آن نشست‌های تحت مالکیت را حذف کند؛ حذف دلخواه نشست همچنان به یک درخواست Gateway با دامنه مدیر نیاز دارد.

برای جست‌وجوی وب، Pluginها می‌توانند به‌جای دسترسی مستقیم به سیم‌کشی ابزار عامل، ابزار کمکی مشترک زمان اجرا را مصرف کنند:

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

Pluginها همچنین می‌توانند ارائه‌دهندگان جست‌وجوی وب را از طریق api.registerWebSearchProvider(...) ثبت کنند.

نکات:

  • انتخاب ارائه‌دهنده، تفکیک اعتبارنامه و معناشناسی مشترک درخواست را در هسته نگه دارید.
  • برای انتقال‌های جست‌وجوی ویژه عرضه‌کننده، از ارائه‌دهندگان جست‌وجوی وب استفاده کنید.
  • api.runtime.webSearch.* سطح مشترک ترجیحی برای Pluginهای قابلیت/کانالی است که بدون وابستگی به پوشش ابزار عامل به رفتار جست‌وجو نیاز دارند.

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

Pluginها می‌توانند با api.registerHttpRoute(...) نقطه‌های پایانی HTTP ارائه کنند.

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" و برای احراز هویت یا تأیید Webhook مدیریت‌شده توسط Plugin از "plugin" استفاده کنید.
  • 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") و هر روش احراز هویت مبتنی بر پراکسی نامطمئن، حتی اگر فراخواننده x-openclaw-scopes را ارسال کند، یک دامنهٔ منفرد operator.write دریافت می‌کنند
    • فراخوانندگان trusted-proxy بدون سرآیند صریح x-openclaw-scopes نیز سطح قدیمیِ محدود به operator.write را حفظ می‌کنند
    • فراخوانندگان trusted-proxy که x-openclaw-scopes را ارسال می‌کنند، در عوض دامنه‌های اعلام‌شده را دریافت می‌کنند
    • یک مسیر می‌تواند gatewayRuntimeScopeSurface: "trusted-operator" را فعال کند تا برای حالت‌های احراز هویت دارای هویت، همیشه x-openclaw-scopes را رعایت کند (و در صورت نبود سرآیند، به مجموعهٔ کامل دامنه‌های پیش‌فرض CLI بازگردد)
  • زبانه‌های خارجی سندباکس‌شدهٔ رابط کنترل که مسیرهای auth: "gateway" پشتوانهٔ آن‌ها هستند، از مجوز کوکی امضاشده و کوتاه‌عمری استفاده می‌کنند که فقط در راه‌اندازی اولیهٔ احرازشده صادر می‌شود؛ زبانه‌های دارای احراز هویت Plugin مسیر مستقیم iframe خود را حفظ می‌کنند. پیش از نصب، والد در همان سندباکس مات، کاوشی متعلق به مسیر اجرا می‌کند و اگر سیاست حریم خصوصی مرورگر کوکی را مسدود کند، به‌صورت بسته شکست می‌خورد. مجوز به Plugin مالک، ریشهٔ مسیر منطبق و نسل فعلی احراز هویت مقید است؛ نام تصادفیِ فرایندی کوکی مانع بازنویسی متقابل آن توسط Gatewayهای مورد اعتماد روی یک میزبان می‌شود، اما کوکی‌ها هرگز پورت‌های TCP را از هم جدا نمی‌کنند. بنابراین نام میزبان Gateway یک مرز اعتبارنامه است: سرویس‌هایی را که متقابلاً به هم اعتماد ندارند، حتی روی پورت‌های دیگر، روی آن نام میزبان میزبانی مشترک نکنید. ارسال مسیر، استفادهٔ مجدد در برابر مسیر تودرتویی را که متعلق به Plugin دیگری است رد می‌کند. چون نوادگان سندباکس از نظر کوکی میان‌سایتی هستند، مجوز فقط GET و HEAD را همراه با operator.read می‌پذیرد؛ تغییرات و ارتقاهای WebSocket روی سطوح صریحاً احرازشدهٔ Gateway باقی می‌مانند. این کوکی عمداً نمی‌تواند از CHIPS استفاده کند: مرورگرهای کنونی یک بیتِ نیای میان‌سایتی را در کلید پارتیشن قرار می‌دهند، بنابراین فریم‌های تودرتوی سندباکس مات دسترسی به دارایی‌های همان مسیر را از دست می‌دهند. کوکی به زمینه‌ای امن و مجوز مرورگر برای کوکی‌های میان‌سایتی نیاز دارد؛ بنابراین زبانه‌های خارجی دارای احراز هویت Gateway در مبدأهای LAN با HTTP ساده یا هنگام مسدودسازی کامل کوکی‌های شخص ثالث در دسترس نیستند؛ از HTTPS/Tailscale Serve یا loopback مورد اعتماد مرورگر با سیاست کوکی سازگار استفاده کنید.
  • این مجوز از افشای توکن حامل Gateway و استفادهٔ مجدد تصادفی از مسیر یا دامنه جلوگیری می‌کند؛ اما بین Pluginهای بومی مرز امنیتی ایجاد نمی‌کند. کد بومی Plugin و محتوای رابط کاربری ارائه‌شده توسط آن همچنان بخشی از همان مرز مورد اعتمادِ درون‌فرایندی Plugin هستند.
  • قاعدهٔ عملی: فرض نکنید یک مسیر Plugin با احراز هویت Gateway، به‌طور ضمنی سطح مدیریتی است. اگر مسیر به رفتاری ویژهٔ مدیر نیاز دارد، سطح دامنهٔ trusted-operator را فعال کنید، یک حالت احراز هویت دارای هویت را الزامی کنید و قرارداد صریح سرآیند x-openclaw-scopes را مستند کنید.
  • پس از تطبیق مسیر و احراز هویت، گرداننده‌های عادی در پذیرش کار ریشهٔ Gateway مشارکت می‌کنند. Gateway آماده‌شده یا در حال راه‌اندازی مجدد، پیش از فراخوانی گرداننده 503 را برمی‌گرداند. استثنای محدود، مسیر auth: "gateway" دارای مجوز در مانیفست است که سطح ویژهٔ مسیر trusted-operator را نیز فعال می‌کند؛ این مسیر قابل دسترسی می‌ماند تا ارسال کنترل تعلیق سرگردان نشود، درحالی‌که مسیرهای هم‌تراز عادی از همان Plugin پشت مرز پذیرش باقی می‌مانند. مالکیت handleUpgrade در WebSocket از همان مرز پذیرش اتمی استفاده می‌کند؛ پس از آنکه گرداننده یک سوکت را پذیرفت، ادامهٔ عمر سوکت در مالکیت Plugin است و این مرز آن را ردیابی نمی‌کند.

مسیرهای واردکردن SDK برای Plugin

هنگام نوشتن Pluginهای جدید، به‌جای barrel یکپارچهٔ ریشهٔ openclaw/plugin-sdk از زیرمسیرهای محدود SDK استفاده کنید. زیرمسیرهای اصلی:

زیرمسیر کاربرد
openclaw/plugin-sdk/plugin-entry سازوکارهای اولیهٔ ثبت Plugin
openclaw/plugin-sdk/channel-core ابزارهای کمکی ورود/ساخت کانال
openclaw/plugin-sdk/core ابزارهای کمکی عمومی مشترک و قرارداد جامع

Pluginهای کانال از خانواده‌ای از درگاه‌های محدود انتخاب می‌کنند — 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. رفتار تأیید باید به‌جای ترکیب میان فیلدهای نامرتبط Plugin، بر یک قرارداد approvalCapability متمرکز شود. Pluginهای کانال را ببینید.

ابزارهای کمکی زمان اجرا و پیکربندی در زیرمسیرهای متمرکز و متناظر *-runtime قرار دارند (approval-runtime، agent-runtime، lazy-runtime، directory-runtime، text-runtime، runtime-store، system-event-runtime، heartbeat-runtime، channel-activity-runtime و غیره). به‌جای barrel سازگاری گستردهٔ config-runtime، config-contracts، plugin-config-runtime، runtime-config-snapshot و config-mutation را ترجیح دهید.

نقطه‌های ورود داخلی مخزن (برای ریشهٔ بستهٔ هر Plugin همراه):

  • index.js — ورودی Plugin همراه
  • api.js — barrel ابزارهای کمکی/نوع‌ها
  • runtime-api.js — barrel مخصوص زمان اجرا
  • setup-entry.js — ورودی راه‌اندازی Plugin

Pluginهای خارجی فقط باید زیرمسیرهای openclaw/plugin-sdk/* را وارد کنند. هرگز src/* بستهٔ Plugin دیگری را از هسته یا Plugin دیگری وارد نکنید. نقطه‌های ورود بارگذاری‌شده توسط facade، در صورت وجود، snapshot پیکربندی فعال زمان اجرا را ترجیح می‌دهند و سپس به فایل پیکربندی حل‌شده روی دیسک بازمی‌گردند.

زیرمسیرهای ویژهٔ قابلیت مانند image-generation، media-understanding و speech وجود دارند، زیرا Pluginهای همراه اکنون از آن‌ها استفاده می‌کنند. آن‌ها به‌طور خودکار قراردادهای خارجیِ بلندمدت و تثبیت‌شده نیستند — هنگام اتکا به آن‌ها، صفحهٔ مرجع SDK مرتبط را بررسی کنید.

طرح‌واره‌های ابزار پیام

Pluginها باید مالک مشارکت‌های طرح‌وارهٔ ویژهٔ کانال describeMessageTool(...) برای سازوکارهای غیرپیامی مانند واکنش‌ها، خواندن‌ها و نظرسنجی‌ها باشند. ارائهٔ مشترک ارسال باید به‌جای فیلدهای بومی ارائه‌دهنده برای دکمه، مؤلفه، بلوک یا کارت، از قرارداد عمومی MessagePresentation استفاده کند. برای قرارداد، قواعد بازگشت، نگاشت ارائه‌دهنده و چک‌لیست نویسندهٔ Plugin، ارائهٔ پیام را ببینید.

Pluginهای دارای قابلیت ارسال، آنچه را می‌توانند رندر کنند از طریق قابلیت‌های پیام اعلام می‌کنند:

  • presentation برای بلوک‌های ارائهٔ معنایی (text، context، divider، chart، table، buttons، select)
  • delivery-pin برای درخواست‌های تحویل سنجاق‌شده

هسته تصمیم می‌گیرد ارائه را به‌صورت بومی رندر کند یا آن را به متن تنزل دهد. راه‌های فرار رابط کاربری بومی ارائه‌دهنده را از ابزار عمومی پیام ارائه نکنید. ابزارهای کمکی منسوخ‌شدهٔ SDK برای طرح‌واره‌های بومی قدیمی همچنان برای Pluginهای شخص ثالث موجود صادر می‌شوند، اما Pluginهای جدید نباید از آن‌ها استفاده کنند.

حل مقصد کانال

Pluginهای کانال باید مالک معناشناسی مقصد ویژهٔ کانال باشند. میزبان خروجی مشترک را عمومی نگه دارید و برای قواعد ارائه‌دهنده از سطح آداپتور پیام‌رسانی استفاده کنید:

  • messaging.inferTargetChatType({ to }) پیش از جست‌وجوی فهرست راهنما تصمیم می‌گیرد که مقصد نرمال‌شده باید به‌عنوان direct، group یا channel در نظر گرفته شود.
  • messaging.targetResolver.looksLikeId(raw, normalized) به هسته می‌گوید آیا یک ورودی باید به‌جای جست‌وجوی فهرست راهنما، مستقیماً به حل مشابه شناسه برود.
  • messaging.targetResolver.reservedLiterals واژه‌های ساده‌ای را فهرست می‌کند که برای آن ارائه‌دهنده ارجاع کانال/نشست هستند. فرایند حل، ورودی‌های پیکربندی‌شدهٔ فهرست راهنما را پیش از رد مقادیر تحت‌اللفظی رزروشده حفظ می‌کند و سپس در صورت نیافتن مورد در فهرست راهنما، به‌صورت بسته شکست می‌خورد.
  • messaging.targetResolver.resolveTarget(...) راه بازگشت Plugin است هنگامی که هسته پس از نرمال‌سازی یا نیافتن مورد در فهرست راهنما، به حل نهایی تحت مالکیت ارائه‌دهنده نیاز دارد.
  • messaging.resolveOutboundSessionRoute(...) پس از حل مقصد، مالک ساخت مسیر نشست ویژهٔ ارائه‌دهنده است.

تقسیم پیشنهادی:

  • از inferTargetChatType برای تصمیم‌های دسته‌بندی استفاده کنید که باید پیش از جست‌وجوی همتاها/گروه‌ها انجام شوند.
  • از looksLikeId برای بررسی‌های «این مورد را یک شناسهٔ مقصد صریح/بومی در نظر بگیر» استفاده کنید.
  • از resolveTarget برای راه بازگشت نرمال‌سازی ویژهٔ ارائه‌دهنده استفاده کنید، نه برای جست‌وجوی گستردهٔ فهرست راهنما.
  • شناسه‌های بومی ارائه‌دهنده مانند شناسه‌های چت، شناسه‌های رشته، JIDها، handleها و شناسه‌های اتاق را در مقادیر target یا پارامترهای ویژهٔ ارائه‌دهنده نگه دارید، نه در فیلدهای عمومی SDK.

فهرست‌های راهنمای مبتنی بر پیکربندی

Pluginهایی که ورودی‌های فهرست راهنما را از پیکربندی استخراج می‌کنند، باید آن منطق را در Plugin نگه دارند و از ابزارهای کمکی مشترک openclaw/plugin-sdk/directory-runtime دوباره استفاده کنند.

هنگامی از این روش استفاده کنید که یک کانال به همتاها/گروه‌های مبتنی بر پیکربندی مانند موارد زیر نیاز دارد:

  • همتاهای پیام مستقیم مبتنی بر فهرست مجاز
  • نگاشت‌های پیکربندی‌شدهٔ کانال/گروه
  • راه‌های بازگشت ایستای فهرست راهنما در دامنهٔ حساب

ابزارهای کمکی مشترک در directory-runtime فقط عملیات عمومی را مدیریت می‌کنند:

  • فیلترکردن پرس‌وجو
  • اعمال محدودیت
  • ابزارهای کمکی حذف موارد تکراری/نرمال‌سازی
  • ساخت ChannelDirectoryEntry[]

بازرسی حساب و نرمال‌سازی شناسهٔ ویژهٔ کانال باید در پیاده‌سازی Plugin باقی بماند.

کاتالوگ‌های ارائه‌دهنده

Pluginهای ارائه‌دهنده می‌توانند با registerProvider({ catalog: { run(...) { ... } } }) کاتالوگ‌های مدل را برای استنتاج تعریف کنند.

catalog.run(...) همان ساختاری را برمی‌گرداند که OpenClaw در models.providers می‌نویسد:

  • { provider } برای یک ورودی ارائه‌دهنده
  • { providers } برای چند ورودی ارائه‌دهنده

از catalog زمانی استفاده کنید که Plugin مالک شناسه‌های مدل مختص ارائه‌دهنده، مقادیر پیش‌فرض URL پایه یا فراداده مدل وابسته به احراز هویت باشد.

catalog.order زمان ادغام کاتالوگ یک Plugin را نسبت به ارائه‌دهندگان ضمنی داخلی OpenClaw کنترل می‌کند:

  • simple: ارائه‌دهندگان ساده مبتنی بر کلید API یا محیط
  • profile: ارائه‌دهندگانی که هنگام وجود پروفایل‌های احراز هویت ظاهر می‌شوند
  • paired: ارائه‌دهندگانی که چند ورودی ارائه‌دهنده مرتبط را تولید می‌کنند
  • late: گذر نهایی، پس از سایر ارائه‌دهندگان ضمنی

در صورت تداخل کلید، ارائه‌دهندگان بعدی برنده می‌شوند؛ بنابراین Pluginها می‌توانند عمداً یک ورودی ارائه‌دهنده داخلی با همان شناسه ارائه‌دهنده را بازنویسی کنند.

Pluginها همچنین می‌توانند ردیف‌های مدل فقط‌خواندنی را از طریق api.registerModelCatalogProvider({ provider, kinds, staticCatalog, liveCatalog }) منتشر کنند. این مسیر آتی برای سطوح فهرست/راهنما/انتخاب‌گر است و از ردیف‌های text، voice، image_generation، video_generation و music_generation پشتیبانی می‌کند. Pluginهای ارائه‌دهنده همچنان مالک فراخوانی‌های زنده نقطه پایانی، تبادل توکن و نگاشت پاسخ فروشنده هستند؛ هسته مالک شکل مشترک ردیف، برچسب‌های منبع و قالب‌بندی راهنمای ابزار رسانه است. ثبت‌های ارائه‌دهنده تولید رسانه به‌طور خودکار ردیف‌های کاتالوگ ایستا را از 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/config نباید صرفاً برای توصیف پیکربندی نیازمند آماده‌سازی اعتبارنامه‌های زمان اجرا باشند.

رفتار پیشنهادی 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 کانال فعال اما هنوز پیکربندی‌نشده است، به‌جای ورودی کامل Plugin، setupEntry را بارگذاری می‌کند. این کار راه‌اندازی اولیه و تنظیم را سبک‌تر نگه می‌دارد، هنگامی که ورودی اصلی Plugin شما ابزارها، هوک‌ها یا سایر کدهای صرفاً مخصوص زمان اجرا را نیز متصل می‌کند.

اختیاری: openclaw.startup.deferConfiguredChannelFullLoadUntilAfterListen می‌تواند یک Plugin کانال را برای همان مسیر setupEntry در مرحله راه‌اندازی پیش از گوش‌دادن Gateway فعال کند، حتی زمانی که کانال از قبل پیکربندی شده باشد.

فقط زمانی از این گزینه استفاده کنید که setupEntry تمام سطح راه‌اندازی موردنیاز پیش از شروع گوش‌دادن Gateway را کاملاً پوشش دهد. در عمل، یعنی ورودی راه‌اندازی باید هر قابلیت متعلق به کانال را که راه‌اندازی به آن وابسته است ثبت کند، مانند:

  • خود ثبت کانال
  • هر مسیر HTTP که باید پیش از شروع گوش‌دادن Gateway در دسترس باشد
  • هر متد، ابزار یا سرویس Gateway که باید در همان بازه وجود داشته باشد

اگر ورودی کامل شما همچنان مالک هر قابلیت راه‌اندازی الزامی است، این پرچم را فعال نکنید. Plugin را روی رفتار پیش‌فرض نگه دارید و اجازه دهید OpenClaw ورودی کامل را هنگام راه‌اندازی بارگذاری کند.

کانال‌های همراه همچنین می‌توانند یاری‌گرهای سطح قراردادِ صرفاً مخصوص راه‌اندازی را منتشر کنند که هسته پیش از بارگذاری کامل زمان اجرای کانال بتواند از آن‌ها استفاده کند. سطح فعلی ارتقای راه‌اندازی عبارت است از:

  • singleAccountKeysToMove
  • namedAccountPromotionKeys
  • resolveSingleAccountPromotionTarget(...)

هسته هنگامی از این سطح استفاده می‌کند که لازم باشد پیکربندی قدیمی تک‌حسابی کانال را بدون بارگذاری ورودی کامل Plugin به channels.<id>.accounts.* ارتقا دهد. 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    }  }}

فراداده کاتالوگ کانال

Pluginهای کانال می‌توانند فراداده راه‌اندازی/کشف را از طریق 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: کانال را برای سطوح پیمایش مستندات به‌عنوان داخلی/خصوصی علامت‌گذاری می‌کند
  • 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 را ترجیح دهند. نام‌های ساده پکیج و dist-tagها همچنان برای سازگاری کار می‌کنند، اما هشدارهای لایه منبع را نمایش می‌دهند تا کاتالوگ بتواند بدون شکستن Pluginهای موجود به‌سوی نصب‌های سنجاق‌شده و دارای بررسی یکپارچگی حرکت کند. وقتی راه‌اندازی اولیه از یک مسیر کاتالوگ محلی نصب می‌کند، یک ورودی مدیریت‌شده نمایه Plugin را با source: "path" و در صورت امکان یک sourcePath نسبی به فضای کاری ثبت می‌کند. مسیر عملیاتی مطلق بارگذاری در plugins.load.paths باقی می‌ماند؛ رکورد نصب از تکرار مسیرهای ایستگاه کاری محلی در پیکربندی بلندمدت جلوگیری می‌کند. این کار نصب‌های توسعه محلی را برای عیب‌یابی لایه منبع قابل مشاهده نگه می‌دارد، بدون افزودن سطح دوم افشای مسیر خام سیستم فایل. جدول پایدار SQLite ‏installed_plugin_index منبع حقیقت نصب است و می‌تواند بدون بارگذاری ماژول‌های زمان اجرای Plugin به‌روزرسانی شود. نگاشت installRecords آن حتی وقتی مانیفست Plugin وجود ندارد یا نامعتبر است، پایدار می‌ماند؛ محتوای plugins آن نمای مانیفست قابل‌بازسازی است.

Pluginهای موتور زمینه

Pluginهای موتور زمینه مالک هماهنگ‌سازی زمینه نشست برای دریافت، مونتاژ و Compaction هستند. آن‌ها را از Plugin خود با api.registerContextEngine(id, factory) ثبت کنید، سپس موتور فعال را با plugins.slots.contextEngine انتخاب کنید.

زمانی از این قابلیت استفاده کنید که Plugin شما به‌جای صرفاً افزودن جست‌وجوی حافظه یا هوک‌ها، نیاز دارد پایپ‌لاین پیش‌فرض زمینه را جایگزین یا گسترش دهد.

ts
 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,          agentSessionKey: sessionKey,        }),      };    },    async compact() {      return { ok: true, compacted: false };    },  }));}

کارخانهٔ ctx مقادیر اختیاری config، agentDir و workspaceDir را برای مقداردهی اولیه در زمان ساخت ارائه می‌کند.

میزبان آماده‌سازی ناهمگام اعلان حافظهٔ ثبت‌شده را پیش از فراخوانی assemble() یک موتور غیرقدیمی تکمیل می‌کند. هنگام فعال‌بودن assemble()، buildMemorySystemPromptAddition(...) همگام باقی می‌ماند و آن تصویر لحظه‌ای تغییرناپذیر اجرا را می‌خواند. زمینهٔ ابزار و ارجاع ارائه‌شده را بدون تغییر عبور دهید تا تصویر لحظه‌ای نتواند از مرزهای اجرا عبور کند.

هنگامی که هارنس فعال یک رشتهٔ پشتیبان ماندگار دارد، assemble() می‌تواند contextProjection را برگرداند. برای نگاشت قدیمیِ هر نوبت، آن را حذف کنید. هنگامی که زمینهٔ مونتاژشده باید یک‌بار به رشتهٔ پشتیبان تزریق و تا زمان تغییر دوره بازاستفاده شود، { mode: "thread_bootstrap", epoch } را برگردانید. پس از تغییر زمینهٔ معنایی موتور، مانند پس از یک مرحلهٔ Compaction تحت مالکیت موتور، دوره را تغییر دهید. میزبان‌ها می‌توانند فرادادهٔ فراخوانی ابزار، شکل ورودی و نتایج ویرایش‌شدهٔ ابزار را در نگاشت راه‌اندازی رشته حفظ کنند تا رشته‌های پشتیبان تازه، تداوم ابزار را بدون کپی‌کردن محموله‌های خامِ حاوی اطلاعات محرمانه حفظ کنند.

اگر موتور شما مالک الگوریتم Compaction نیست، compact() را پیاده‌سازی‌شده نگه دارید و آن را صریحاً واگذار کنید:

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

افزودن یک قابلیت جدید

هنگامی که یک plugin به رفتاری نیاز دارد که با API فعلی سازگار نیست، با دسترسی خصوصی و مستقیم، سامانهٔ plugin را دور نزنید. قابلیت مفقود را اضافه کنید.

ترتیب پیشنهادی:

  1. قرارداد هسته را تعریف کنید. تصمیم بگیرید هسته باید مالک کدام رفتار مشترک باشد: خط‌مشی، بازگشت جایگزین، ادغام پیکربندی، چرخهٔ عمر، معناشناسی مرتبط با کانال و شکل تابع کمکی زمان اجرا.
  2. سطوح ثبت و زمان اجرای نوع‌دار plugin را اضافه کنید. کوچک‌ترین سطح قابلیت نوع‌دار و مفید را با گسترش OpenClawPluginApi و/یا api.runtime اضافه کنید.
  3. هسته و مصرف‌کنندگان کانال/ویژگی را متصل کنید. کانال‌ها و pluginهای ویژگی باید قابلیت جدید را از طریق هسته مصرف کنند، نه با واردکردن مستقیم پیاده‌سازی یک فروشنده.
  4. پیاده‌سازی‌های فروشندگان را ثبت کنید. سپس pluginهای فروشندگان، پشتیبان‌های خود را برای آن قابلیت ثبت می‌کنند.
  5. پوشش قرارداد را اضافه کنید. آزمون‌هایی اضافه کنید تا مالکیت و شکل ثبت در گذر زمان صریح باقی بمانند.

به این روش، OpenClaw بدون وابستگی سخت به نگرش یک ارائه‌دهنده، جهت‌گیری مشخص خود را حفظ می‌کند. برای فهرست بررسی عینی فایل‌ها و نمونهٔ کامل، راهنمای عملی قابلیت‌ها را ببینید.

فهرست بررسی قابلیت

هنگام افزودن قابلیتی جدید، پیاده‌سازی معمولاً باید این سطوح را با هم تغییر دهد:

  • نوع‌های قرارداد هسته در src/<capability>/types.ts
  • اجراکننده/تابع کمکی زمان اجرای هسته در src/<capability>/runtime.ts
  • سطح ثبت APIِ plugin در src/plugins/types.ts
  • سیم‌کشی رجیستری plugin در src/plugins/registry.ts
  • ارائهٔ زمان اجرای plugin در src/plugins/runtime/*، هنگامی که pluginهای ویژگی/کانال باید آن را مصرف کنند
  • توابع کمکی ثبت/آزمون در src/test-utils/plugin-registration.ts
  • بررسی‌های مالکیت/قرارداد در src/plugins/contracts/registry.ts
  • مستندات اپراتور/plugin در docs/

اگر یکی از این سطوح وجود نداشته باشد، معمولاً نشانهٔ آن است که قابلیت هنوز به‌طور کامل یکپارچه نشده است.

الگوی قابلیت

الگوی حداقلی:

ts
// core contractexport type VideoGenerationProviderPlugin = {  id: string;  label: string;  generateVideo: (req: VideoGenerationRequest) => Promise&lt;VideoGenerationResult&gt;;}; // plugin APIapi.registerVideoGenerationProvider({  id: "openai",  label: "OpenAI",  async generateVideo(req) {    return await generateOpenAiVideo(req);  },}); // shared runtime helper for feature/channel pluginsconst clip = await api.runtime.videoGeneration.generate({  prompt: "Show the robot walking through the lab.",  cfg,});

الگوی آزمون قرارداد (src/plugins/contracts/registry.ts جست‌وجوهای مالکیت مانند providerContractPluginIds را ارائه می‌کند؛ آزمون‌ها بررسی می‌کنند که فهرست contracts.videoGenerationProviders یک plugin با مواردی که واقعاً ثبت می‌کند مطابقت داشته باشد):

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

این کار قاعده را ساده نگه می‌دارد:

  • هسته مالک قرارداد قابلیت و هماهنگ‌سازی آن است
  • pluginهای فروشندگان مالک پیاده‌سازی‌های فروشندگان هستند
  • pluginهای ویژگی/کانال توابع کمکی زمان اجرا را مصرف می‌کنند
  • آزمون‌های قرارداد، مالکیت را صریح نگه می‌دارند

مرتبط

Was this useful?
On this page

On this page