Building plugins
Pluginهای ابزار
defineToolPlugin یک Plugin میسازد که فقط ابزارهای قابل فراخوانی توسط عامل را اضافه میکند: بدون
کانال، ارائهدهنده مدل، هوک، سرویس یا بکاند راهاندازی. این دستور فراداده مانیفست موردنیاز
OpenClaw را تولید میکند تا ابزارها را بدون بارگذاری کد زمان اجرای Plugin
کشف کند.
برای Pluginهای ارائهدهنده، کانال، هوک، سرویس یا دارای قابلیتهای ترکیبی، بهجای آن با ساخت Pluginها، Pluginهای کانال، یا Pluginهای ارائهدهنده شروع کنید.
الزامات
- Node 22.22.3+، Node 24.15+ یا Node 25.9+.
- خروجی بسته TypeScript ESM.
typeboxدرdependencies(نه فقطdevDependencies— Plugin تولیدشده آن را در زمان اجرا وارد میکند).openclaw >=2026.5.17، نخستین نسخهای کهopenclaw/plugin-sdk/tool-pluginرا صادر میکند.- ریشه بستهای که
dist/،openclaw.plugin.jsonوpackage.jsonرا ارائه میکند.
شروع سریع
openclaw plugins init stock-quotes --name "Stock Quotes"cd stock-quotesnpm installnpm run plugin:buildnpm run plugin:validatenpm testplugins init موارد زیر را داربستبندی میکند:
| فایل | هدف |
|---|---|
src/index.ts |
ورودی defineToolPlugin با یک ابزار echo |
src/index.test.ts |
آزمون فراداده برای تأیید فهرست ابزار |
tsconfig.json |
خروجی TypeScript از نوع NodeNext در dist/ |
vitest.config.ts |
پیکربندی Vitest برای src/**/*.test.ts |
package.json |
اسکریپتها، وابستگیهای زمان اجرا، openclaw.extensions: ["./dist/index.js"] |
openclaw.plugin.json |
فراداده مانیفست تولیدشده برای ابزار اولیه |
npm run plugin:build ابتدا npm run build (tsc) و سپس
openclaw plugins build --entry ./dist/index.js را اجرا میکند. npm run plugin:validate
دوباره میسازد و openclaw plugins validate --entry ./dist/index.js را اجرا میکند.
اعتبارسنجی موفق پیام زیر را چاپ میکند:
Plugin stock-quotes معتبر است.گزینههای openclaw plugins init <id>:
| پرچم | پیشفرض | اثر |
|---|---|---|
--directory <path> |
<id> |
دایرکتوری خروجی |
--name <name> |
<id> با حروف عنوانی |
نام نمایشی |
--type <type> |
tool |
نوع داربست: tool یا provider |
--force |
غیرفعال | بازنویسی دایرکتوری خروجی موجود |
نوشتن یک ابزار
defineToolPlugin هویت Plugin، یک شِمای پیکربندی اختیاری و فهرستی
ایستا از ابزارها را دریافت میکند. نوعهای پارامتر و پیکربندی از شِماهای
TypeBox استنتاج میشوند.
export default defineToolPlugin({ id: "stock-quotes", name: "Stock Quotes", description: "Fetch stock quote snapshots.", configSchema: Type.Object({ apiKey: Type.Optional(Type.String({ description: "Quote API key." })), baseUrl: Type.Optional(Type.String({ description: "Quote API base URL." })), }), tools: (tool) => [ tool({ name: "stock_quote", label: "Stock Quote", description: "Fetch a stock quote snapshot.", parameters: Type.Object({ symbol: Type.String({ description: "Ticker symbol, for example OPEN." }), }), outputSchema: Type.Object( { symbol: Type.String(), configured: Type.Boolean(), baseUrl: Type.String(), }, { additionalProperties: false }, ), async execute({ symbol }, config, context) { context.signal?.throwIfAborted(); return { symbol: symbol.toUpperCase(), configured: Boolean(config.apiKey), baseUrl: config.baseUrl ?? "https://api.example.com", }; }, }), ],});نام ابزارها API پایدار هستند. نامهایی یکتا، با حروف کوچک و بهاندازه کافی مشخص انتخاب کنید تا با ابزارهای هسته یا Pluginهای دیگر تداخل نداشته باشند.
ابزارهای اختیاری و کارخانهای
وقتی کاربران باید ابزار را پیش از ارسال به مدل صریحاً در فهرست مجاز قرار دهند،
optional: true را تنظیم کنید. openclaw plugins build ورودی مانیفست
toolMetadata.<tool>.optional متناظر را مینویسد تا OpenClaw بتواند بدون بارگذاری کد
زمان اجرای Plugin تشخیص دهد که ابزار اختیاری است.
tool({ name: "workflow_run", description: "Run an external workflow.", parameters: Type.Object({ goal: Type.String() }), optional: true, execute: ({ goal }) => ({ queued: true, goal }),});وقتی ابزاری پیش از ساختهشدن به زمینه ابزار زمان اجرا نیاز دارد، از
factory استفاده کنید — برای انصراف در یک اجرای خاص، بررسی وضعیت
سندباکس یا اتصال کمکتابعهای زمان اجرا. حتی با وجود ساختهشدن ابزار مشخص در
زمان اجرا، فراداده ایستا باقی میماند.
tool({ name: "local_workflow", description: "Run a local workflow outside sandboxed sessions.", parameters: Type.Object({ goal: Type.String() }), optional: true, factory({ api, toolContext }) { if (toolContext.sandboxed) { return null; } return createLocalWorkflowTool(api); },});کارخانهها همچنان نام ثابت ابزار را از پیش اعلام میکنند. وقتی Plugin نام
ابزارها را بهصورت پویا محاسبه میکند یا ابزارها را با هوکها، سرویسها،
ارائهدهندگان یا فرمانها ترکیب میکند، مستقیماً از definePluginEntry
استفاده کنید.
مقادیر بازگشتی
defineToolPlugin مقادیر بازگشتی ساده را در قالب نتیجه ابزار OpenClaw
قرار میدهد:
- وقتی مدل باید دقیقاً همان متن را ببیند، یک رشته برگردانید.
- وقتی میخواهید مدل JSON قالببندیشده را ببیند و OpenClaw مقدار اصلی
را در
detailsنگه دارد، مقداری سازگار با JSON برگردانید.
tool({ name: "echo_text", description: "Echo input text.", parameters: Type.Object({ input: Type.String(), }), execute: ({ input }) => input,});tool({ name: "echo_json", description: "Echo input as structured JSON.", parameters: Type.Object({ input: Type.String(), }), execute: ({ input }) => ({ input, length: input.length }),});وقتی به AgentToolResult سفارشی نیاز دارید یا میخواهید از پیادهسازی
api.registerTool موجود دوباره استفاده کنید، از ابزار کارخانهای استفاده کنید.
قراردادهای خروجی
وقتی ابزار دادههای پایدار سازگار با JSON برمیگرداند، outputSchema را
اضافه کنید. این مورد مقدار اصلی ذخیرهشده در AgentToolResult.details را توصیف
میکند، نه متن قالببندیشده در content:
tool({ name: "shipment_list", description: "List shipments.", parameters: Type.Object({ buyer: Type.Optional(Type.String()), }), outputSchema: Type.Array( Type.Object( { id: Type.String(), buyer: Type.String(), paid: Type.Boolean(), tons: Type.Number(), }, { additionalProperties: false }, ), ), execute: ({ buyer }) => listShipments(buyer),});حالت کد و جستوجوی ابزار این شِما را به یک راهنمای خروجی محدود به سبک TypeScript تبدیل میکنند. این امکان به مدل اجازه میدهد نتیجهای شناختهشده را در یک برنامه فراخوانی و تبدیل کند، بهجای آنکه یک نوبت دیگر مدل را صرف مشاهده ساختار آن کند.
OpenClaw شِما را پیش از اجرای فراخوانی کاتالوگ کامپایل میکند، سپس مقدار نهایی
details را پس از هوکهای ابزار و پیش از بازگرداندن آن از طریق پل
اعتبارسنجی میکند. شِمای نامعتبر نمیتواند ابزار را اجرا کند؛ عدم تطابق نتیجه
باعث شکست فراخوانی تکمیلشده میشود. همه گونههای نتیجهای را که استثنا ایجاد
نمیکنند، از جمله گونههای خطای ساختیافته، درج کنید؛ یا وقتی نتیجه پایدار
نیست، شِما را حذف کنید. رازها یا مقادیر حساس را در توضیحات شِما قرار ندهید،
زیرا فراداده خروجی قابلاعتماد ممکن است برای مدل قابلمشاهده شود.
وقتی یک راهنمای خروجی فشرده و کامل میخواهید، در لایههای شیء از
{ additionalProperties: false } استفاده کنید؛ شِماهای باز یا کوتاهشده همچنان از طریق
tools.describe(...) در دسترساند، اما بهعنوان قراردادهای کامل نمایه سریع
معرفی نمیشوند.
ابزارهای کارخانهای outputSchema را روی AnyAgentTool مشخصی
که برمیگردانند اعلام میکنند. اعلان ایستای tool({ factory }) شِمای خروجی
جداگانهای نمیپذیرد، زیرا ممکن است با ابزار زمان اجرا ناسازگار شود.
پیکربندی
configSchema اختیاری است. آن را حذف کنید تا OpenClaw یک شِمای سختگیرانه
شیء خالی اعمال کند؛ مانیفست تولیدشده همچنان شامل configSchema خواهد بود.
export default defineToolPlugin({ id: "no-config-tools", name: "No Config Tools", description: "Adds tools that do not need configuration.", tools: () => [],});با یک configSchema، نوع آرگومان دوم execute از آن
استنتاج میشود:
const configSchema = Type.Object({ apiKey: Type.String(),}); export default defineToolPlugin({ id: "configured-tools", name: "Configured Tools", description: "Adds configured tools.", configSchema, tools: (tool) => [ tool({ name: "configured_ping", description: "Check whether configuration is available.", parameters: Type.Object({}), execute: (_params, config) => ({ hasKey: config.apiKey.length > 0 }), }), ],});OpenClaw پیکربندی Plugin را از ورودی آن Plugin در پیکربندی Gateway میخواند. رازها را در کد منبع یا نمونههای مستندات بهصورت ثابت ننویسید؛ مطابق مدل امنیتی Plugin از پیکربندی، متغیرهای محیطی یا SecretRefها استفاده کنید.
فراداده تولیدشده
OpenClaw باید پیش از واردکردن کد زمان اجرای Plugin، مانیفست آن را بخواند.
defineToolPlugin فراداده ایستا را برای این کار ارائه میکند و
openclaw plugins build آن را در بسته مینویسد. پس از تغییر شناسه، نام، توضیحات،
شِمای پیکربندی، فعالسازی یا نام ابزارهای Plugin، مولد را دوباره اجرا کنید:
npm run buildopenclaw plugins build --entry ./dist/index.jsمانیفست تولیدشده برای یک Plugin تکابزاری:
{ "id": "stock-quotes", "name": "Stock Quotes", "description": "Fetch stock quote snapshots.", "version": "0.1.0", "configSchema": { "type": "object", "additionalProperties": false, "properties": {} }, "activation": { "onStartup": true }, "contracts": { "tools": ["stock_quote"] }}contracts.tools قرارداد مهم کشف است: این قرارداد بدون بارگذاری زمان اجرای
همه Pluginهای نصبشده به OpenClaw میگوید مالک هر ابزار کدام Plugin است.
مانیفست منسوخ ممکن است باعث شود ابزاری در کشف پیدا نشود یا خطای ثبت به
Plugin اشتباهی نسبت داده شود.
فراداده بسته
openclaw plugins build همچنین package.json را با ورودی زمان اجرای
انتخابشده همتراز میکند:
{ "type": "module", "files": ["dist", "openclaw.plugin.json", "README.md"], "dependencies": { "typebox": "^1.1.38" }, "peerDependencies": { "openclaw": ">=2026.5.17" }, "openclaw": { "extensions": ["./dist/index.js"] }}JavaScript ساختهشده (./dist/index.js) را منتشر کنید، نه یک ورودی منبع
TypeScript. ورودیهای منبع فقط برای توسعه محلی در فضای کاری کار میکنند.
اعتبارسنجی در CI
اگر فراداده تولیدشده منسوخ باشد، plugins build --check بدون بازنویسی فایلها
شکست میخورد:
npm run buildopenclaw plugins build --entry ./dist/index.js --checkopenclaw plugins validate --entry ./dist/index.jsnpm testفیلدهای سازگاری SDK در OpenClaw دارای حاشیهنویسیهای TypeScript
@deprecated هستند که ویرایشگرها آنها را بهصورت هشدار مهاجرت نمایش
میدهند. برای اعمال آنها در CI، یک قاعده آگاه از نوع مانند
@typescript-eslint/no-deprecated
را فعال کنید.
Oxlint از نوعها آگاه نیست، بنابراین نمیتواند این حاشیهنویسیها را اعمال کند.
ازاینرو داربست تولیدشده plugins init پیکربندی لینت برای موارد منسوخ
اضافه نمیکند.
plugins validate بررسی میکند که:
openclaw.plugin.jsonوجود دارد و از بارگذار عادی مانیفست عبور میکند.- ورودی فعلی فرادادهٔ
defineToolPluginرا صادر میکند. - فیلدهای مانیفست تولیدشده با فرادادهٔ ورودی مطابقت دارند.
contracts.toolsبا نامهای ابزار اعلامشده مطابقت دارد.package.json،openclaw.extensionsرا به ورودی زمان اجرای انتخابشده هدایت میکند.
نصب و بررسی محلی
از یک checkout جداگانهٔ OpenClaw یا CLI نصبشده، مسیر بسته را نصب کنید:
openclaw plugins install ./stock-quotesopenclaw plugins inspect stock-quotes --runtimeبرای یک آزمون دود بستهبندیشده، ابتدا بسته را بسازید و سپس tarball را نصب کنید:
npm packopenclaw plugins install npm-pack:./openclaw-plugin-stock-quotes-0.1.0.tgzopenclaw plugins inspect stock-quotes --runtime --jsonپس از نصب، Gateway را راهاندازی مجدد یا بازبارگذاری کنید و از عامل بخواهید از ابزار استفاده کند. اگر ابزار قابل مشاهده نیست، پیش از تغییر کد، زمان اجرای Plugin و کاتالوگ مؤثر ابزار را بررسی کنید (به عیبیابی مراجعه کنید).
انتشار
پس از آمادهشدن بسته، آن را از طریق ClawHub منتشر کنید. clawhub package publish
یک منبع میپذیرد: یک پوشهٔ محلی، یک مخزن GitHub (owner/repo[@ref]) یا یک
نشانی URL مربوط به tarball.
clawhub package publish ./stock-quotes --dry-runclawhub package publish ./stock-quotesبا یک مکانیاب صریح ClawHub نصب کنید:
openclaw plugins install clawhub:your-org/stock-quotesمشخصات سادهٔ بستههای npm در دورهٔ گذار راهاندازی همچنان از npm نصب میشوند، اما ClawHub بستر ترجیحی کشف و توزیع Pluginهای OpenClaw است. برای محدودهٔ مالک و بازبینی انتشار، به انتشار در ClawHub مراجعه کنید.
عیبیابی
plugin entry not found: ./dist/index.js
فایل ورودی انتخابشده وجود ندارد. npm run build را اجرا کنید، سپس
openclaw plugins build --entry ./dist/index.js یا
openclaw plugins validate --entry ./dist/index.js را دوباره اجرا کنید.
plugin entry does not expose defineToolPlugin metadata
ورودی، مقداری را که توسط defineToolPlugin ایجاد شده باشد صادر نکرد. تأیید کنید که
خروجی پیشفرض ماژول، نتیجهٔ defineToolPlugin(...) است، یا ورودی
صحیح را با --entry ارسال کنید.
openclaw.plugin.json generated metadata is stale
مانیفست دیگر با فرادادهٔ ورودی مطابقت ندارد. اجرا کنید:
npm run buildopenclaw plugins build --entry ./dist/index.jsتغییرات هر دو openclaw.plugin.json و package.json را commit کنید.
package.json openclaw.extensions must include ./dist/index.js
فرادادهٔ بسته به ورودی زمان اجرای دیگری اشاره میکند. openclaw plugins build --entry ./dist/index.js را اجرا کنید
تا تولیدکننده، فرادادهٔ بسته را با ورودیای که قصد انتشارش را دارید همراستا کند.
Cannot find package 'typebox'
Plugin ساختهشده در زمان اجرا typebox را import میکند. آن را در dependencies
نگه دارید، دوباره نصب و build کنید و اعتبارسنجی را مجدداً اجرا کنید.
ابزار پس از نصب ظاهر نمیشود
موارد زیر را بهترتیب بررسی کنید:
openclaw plugins inspect <plugin-id> --runtimeopenclaw plugins validate --root <plugin-root> --entry ./dist/index.jsopenclaw.plugin.jsonدارایcontracts.toolsبا نامهای مورد انتظار ابزار است.package.jsonدارایopenclaw.extensions: ["./dist/index.js"]است.- Gateway پس از نصب Plugin راهاندازی مجدد یا بازبارگذاری شده است.