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 آن‌ها مشخص باشد، همچنان آن را در عیب‌یابی تولیدشده حمل می‌کنند (از جمله شناسه‌هایی که از مانیفست درون دایرکتوری‌ای که به دلایل دیگر رد شده است به‌دست آمده‌اند)؛ بنابراین پیکربندی‌ای که به آن شناسه ارجاع می‌دهد، به‌جای خطای نامرتبط «Plugin ناشناخته»، یک Plugin مسدودشده مرتبط با هشدار ایمنی مسیر را مشاهده می‌کند.

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

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

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

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

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

  • بارگذاری CLI به Pluginهایی محدود می‌شود که مالک فرمان اصلی درخواست‌شده هستند
  • راه‌اندازی کانال/resolve کردن Plugin به Pluginهایی محدود می‌شود که مالک شناسه کانال درخواست‌شده هستند
  • راه‌اندازی صریح ارائه‌دهنده/resolve کردن زمان اجرا به Pluginهایی محدود می‌شود که مالک شناسه ارائه‌دهنده درخواست‌شده هستند
  • برنامه‌ریزی راه‌اندازی Gateway از activation.onStartup برای importهای صریح هنگام راه‌اندازی استفاده می‌کند؛ 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های کاندیدا ترجیح می‌دهد و فقط پس از آن به setup-api برای Pluginهایی بازمی‌گردد که همچنان به هوک‌های زمان اجرا هنگام راه‌اندازی نیاز دارند. فهرست‌های راه‌اندازی ارائه‌دهنده از providerAuthChoices مانیفست، گزینه‌های راه‌اندازی استخراج‌شده از توصیفگر و فراداده کاتالوگ نصب، بدون بارگذاری زمان اجرای ارائه‌دهنده استفاده می‌کنند. مقدار صریح setup.requiresRuntime: false یک مرز صرفاً توصیفگری است؛ حذف requiresRuntime برای حفظ سازگاری، بازگشت قدیمی به setup-api را نگه می‌دارد. اگر بیش از یک Plugin کشف‌شده مالکیت همان شناسه نرمال‌شده ارائه‌دهنده راه‌اندازی یا پشتانه CLI را ادعا کند، جست‌وجوی راه‌اندازی به‌جای اتکا به ترتیب کشف، مالک مبهم را رد می‌کند. هنگامی که زمان اجرای راه‌اندازی اجرا می‌شود، عیب‌یابی رجیستری ناهمگونی میان setup.providers / setup.cliBackends و ارائه‌دهندگان یا پشتانه‌های CLI ثبت‌شده واقعی توسط setup-api را بدون مسدودکردن Pluginهای قدیمی گزارش می‌کند.

مرز کش Plugin

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

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

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

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

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

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

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

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

مدل رجیستری

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

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

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

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

بازخوانی‌های اتصال مکالمه

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

از 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: خلاصه درخواست اصلی، راهنمای جداسازی، شناسه فرستنده و فراداده مکالمه

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

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

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

  • فراداده مانیفست برای جست‌وجوی کم‌هزینه پیش از زمان اجرا: setup.providers[].envVars، سازگاری منسوخ‌شده providerAuthEnvVars، providerAuthAliases، providerAuthChoices و channelEnvVars.
  • هوک‌های زمان پیکربندی: catalog (نسخه قدیمی discovery) به‌همراه applyConfigDefaults.
  • هوک‌های زمان اجرا: بیش از ۴۰ هوک اختیاری که احراز هویت، resolve کردن مدل، پوشاندن جریان، سطوح تفکر، خط‌مشی بازپخش و نقاط پایانی مصرف را پوشش می‌دهند. به ترتیب و کاربرد هوک‌ها مراجعه کنید.

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

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

وقتی یک کانال دارای احراز هویت یا راه‌اندازی مبتنی بر متغیر محیطی است که بازگشت عمومی به متغیرهای محیطی پوسته، بررسی‌های پیکربندی/وضعیت یا اعلان‌های راه‌اندازی باید بدون بارگذاری زمان‌اجرای کانال آن را ببینند، از channelEnvVars در مانیفست استفاده کنید.

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

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

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

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

اگر ارائه‌دهنده به یک پروتکل سیمی کاملاً سفارشی یا اجراکننده درخواست سفارشی نیاز داشته باشد، این نوع دیگری از افزونه است. این هوک‌ها برای رفتار ارائه‌دهنده‌ای هستند که همچنان در حلقه استنتاج عادی 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های ارائه‌دهنده همراه، هوک‌های بالا را با یکدیگر ترکیب می‌کنند تا با نیازهای کاتالوگ، احراز هویت، تفکر، بازپخش و مصرف هر عرضه‌کننده سازگار شوند. مجموعه معتبر هوک‌ها همراه هر 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 در مرز عمومی api.ts / contract-api.ts متعلق به Plugin Anthropic قرار دارند (wrapAnthropicProviderStream، resolveAnthropicBetas، resolveAnthropicFastMode، resolveAnthropicServiceTier)، نه در SDK عمومی.

یاریگرهای زمان اجرا

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 هسته را برای سطوح فایل/یادداشت صوتی بازمی‌گرداند.
  • از پیکربندی messages.tts هسته و انتخاب ارائه‌دهنده استفاده می‌کند.
  • بافر صوتی PCM و نرخ نمونه‌برداری را بازمی‌گرداند. Pluginها باید برای ارائه‌دهندگان، نمونه‌برداری مجدد/رمزگذاری را انجام دهند.
  • listVoices برای هر ارائه‌دهنده اختیاری است. از آن برای انتخاب‌گرهای صدای متعلق به عرضه‌کننده یا جریان‌های راه‌اندازی استفاده کنید.
  • هسته یک مهلت درخواست حل‌شده را به هوک‌های 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 نرمال‌سازی می‌شود.
  • مدل مالکیت ترجیحی، شرکت‌محور است: با افزودن قراردادهای قابلیت توسط OpenClaw، یک Plugin عرضه‌کننده می‌تواند مالک ارائه‌دهندگان متن، گفتار، تصویر و رسانه‌های آینده باشد.

برای درک تصویر/صوت/ویدئو، 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,  // Optional when MIME cannot be inferred reliably:  mime: "audio/ogg",});

نکات:

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

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.",  provider: "openai",  model: "gpt-4.1-mini",  deliver: false,});

نکات:

  • provider و model بازنویسی‌های اختیاری هر اجرا هستند، نه تغییرات پایدار نشست.
  • OpenClaw این فیلدهای بازنویسی را فقط برای فراخوان‌های مورد اعتماد می‌پذیرد.
  • برای اجراهای بازگشتی متعلق به Plugin، اپراتورها باید با plugins.entries.<id>.subagent.allowModelOverride: true آن را صریحاً فعال کنند.
  • از plugins.entries.<id>.subagent.allowedModels برای محدودکردن Pluginهای مورد اعتماد به اهداف متعارف مشخص provider/model، یا از "*" برای مجازکردن صریح هر هدف استفاده کنید.
  • اجراهای زیرعامل 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 بازگردد)
  • قاعده عملی: فرض نکنید یک مسیر 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 کمک‌تابع‌های مشترک عمومی و قرارداد چتری
openclaw/plugin-sdk/config-schema شِمای Zod ریشه openclaw.json (OpenClawSchema)

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 دیگری وارد نکنید. نقاط ورودی بارگذاری‌شده از طریق نما، در صورت وجود، 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ها، نام‌های کاربری و شناسه‌های اتاق را در مقادیر 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 مالک شناسه‌های مدل مختص ارائه‌دهنده، مقادیر پیش‌فرض نشانی پایه یا فراداده مدل مشروط به احراز هویت باشد.

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/پیکربندی نباید صرفاً برای توصیف پیکربندی نیازمند فراهم‌سازی اطلاعات احراز هویت زمان اجرا باشند.

رفتار توصیه‌شده inspectAccount(...):

  • فقط وضعیت توصیفی حساب را بازگردانید.
  • enabled و configured را حفظ کنید.
  • در صورت مرتبط بودن، فیلدهای منبع/وضعیت اعتبارنامه را درج کنید، مانند:
    • tokenSource، tokenStatus
    • botTokenSource، botTokenStatus
    • appTokenSource، appTokenStatus
    • signingSecretSource، signingSecretStatus
  • برای گزارش دسترس‌پذیری فقط‌خواندنی، نیازی نیست مقادیر خام توکن را بازگردانید. بازگرداندن tokenStatus: "available" (همراه با فیلد منبع متناظر) برای فرمان‌های وضعیت‌محور کافی است.
  • وقتی یک اعتبارنامه از طریق SecretRef پیکربندی شده اما در مسیر فرمان فعلی در دسترس نیست، از configured_unavailable استفاده کنید.

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

بسته‌های پکیج

یک دایرکتوری 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 کانال را حتی زمانی که کانال از قبل پیکربندی شده است، در مرحله راه‌اندازی پیش از شنود Gateway به همان مسیر setupEntry وارد کند.

فقط زمانی از این گزینه استفاده کنید که 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: کانال را برای سطوح پیمایش مستندات داخلی/خصوصی علامت‌گذاری می‌کند
  • showConfigured / showInSetup: نام‌های مستعار قدیمی که همچنان برای سازگاری پذیرفته می‌شوند؛ exposure را ترجیح دهید
  • quickstartAllowFrom: کانال را به جریان استاندارد شروع سریع allowFrom وارد می‌کند
  • forceAccountBinding: حتی وقتی فقط یک حساب وجود دارد، اتصال صریح حساب را الزامی می‌کند
  • preferSessionLookupForAnnounceTarget: هنگام رفع اهداف اعلان، جست‌وجوی نشست را ترجیح می‌دهد

OpenClaw همچنین می‌تواند کاتالوگ‌های خارجی کانال را ادغام کند (برای مثال، یک خروجی رجیستری MPM). یک فایل JSON را در یکی از مسیرهای زیر قرار دهید:

  • ~/.openclaw/mpm/plugins.json
  • ~/.openclaw/mpm/catalog.json
  • ~/.openclaw/plugins/catalog.json

یا OPENCLAW_PLUGIN_CATALOG_PATHS (یا OPENCLAW_MPM_CATALOG_PATHS) را به یک یا چند فایل JSON اشاره دهید (جداشده با ویرگول/نقطه‌ویرگول/PATH). هر فایل باید شامل { "entries": [ { "name": "@scope/pkg", "openclaw": { "channel": {...}, "install": {...} } } ] } باشد. تجزیه‌گر همچنین "packages" یا "plugins" را به‌عنوان نام‌های مستعار قدیمی برای کلید "entries" می‌پذیرد.

ورودی‌های تولیدشده کاتالوگ کانال و ورودی‌های کاتالوگ نصب ارائه‌دهنده، در کنار بلوک خام openclaw.install، اطلاعات نرمال‌شده منبع نصب را ارائه می‌کنند. اطلاعات نرمال‌شده مشخص می‌کنند که آیا مشخصه npm یک نسخه دقیق است یا انتخابگر شناور، آیا فراداده یکپارچگی مورد انتظار وجود دارد، و آیا مسیر منبع محلی نیز در دسترس است. وقتی هویت کاتالوگ/پکیج معلوم باشد، اطلاعات نرمال‌شده در صورت انحراف نام پکیج npm تجزیه‌شده از آن هویت هشدار می‌دهند. همچنین وقتی defaultChoice نامعتبر باشد یا به منبعی اشاره کند که در دسترس نیست، و نیز وقتی فراداده یکپارچگی npm بدون منبع معتبر npm وجود داشته باشد، هشدار می‌دهند. مصرف‌کنندگان باید installSource را یک فیلد اختیاری افزوده‌شونده در نظر بگیرند تا ورودی‌های دست‌ساز و شیم‌های کاتالوگ مجبور به ساخت مصنوعی آن نباشند. این کار به فرایند آغاز به کار و ابزارهای عیب‌یابی اجازه می‌دهد بدون واردسازی زمان‌اجرای Plugin، وضعیت لایه منبع را توضیح دهند.

ورودی‌های رسمی خارجی npm باید یک npmSpec دقیق همراه با expectedIntegrity را ترجیح دهند. نام‌های ساده پکیج و برچسب‌های توزیع همچنان برای سازگاری کار می‌کنند، اما هشدارهای لایه منبع را نمایش می‌دهند تا کاتالوگ بتواند بدون شکستن Pluginهای موجود به‌سمت نصب‌های سنجاق‌شده و بررسی‌شده از نظر یکپارچگی حرکت کند. وقتی فرایند آغاز به کار از یک مسیر کاتالوگ محلی نصب می‌کند، یک ورودی مدیریت‌شده در نمایه Plugin با source: "path" و در صورت امکان یک sourcePath نسبی به فضای کاری ثبت می‌کند. مسیر عملیاتی مطلق بارگذاری در plugins.load.paths باقی می‌ماند؛ رکورد نصب از تکرار مسیرهای رایانه محلی در پیکربندی بلندمدت جلوگیری می‌کند. این کار نصب‌های توسعه محلی را برای ابزارهای عیب‌یابی لایه منبع قابل مشاهده نگه می‌دارد، بدون آنکه سطح افشای دوم برای مسیر خام فایل‌سیستم اضافه کند. جدول پایدار SQLite با نام installed_plugin_index منبع حقیقت نصب است و می‌توان آن را بدون بارگذاری ماژول‌های زمان‌اجرای Plugin به‌روزرسانی کرد. نگاشت installRecords آن حتی زمانی که مانیفست Plugin وجود ندارد یا نامعتبر است، ماندگار می‌ماند؛ محتوای plugins آن نمایی بازسازی‌پذیر از مانیفست است.

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

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

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

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

ts
   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,          agentId: resolveSessionAgentId({ config: ctx.config, sessionKey }),          agentSessionKey: sessionKey,        }),      };    },    async compact(params) {      return await delegateCompactionToRuntime(params);    },  }));}

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

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

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

  1. قرارداد هسته را تعریف کنید. مشخص کنید هسته باید مالک کدام رفتار مشترک باشد: خط‌مشی، سازوکار جایگزین، ادغام پیکربندی، چرخهٔ حیات، معناشناسی مرتبط با کانال و شکل تابع کمکی زمان اجرا.
  2. سطوح ثبت و زمان اجرای نوع‌دار Plugin را اضافه کنید. رابط OpenClawPluginApi و/یا api.runtime را با کوچک‌ترین سطح قابلیت نوع‌دار و کاربردی گسترش دهید.
  3. مصرف‌کنندگان هسته و کانال/ویژگی را متصل کنید. کانال‌ها و 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