Building plugins
هوکهای Plugin
هوکهای Plugin نقاط توسعه درونفرایندی برای Pluginهای OpenClaw هستند. از آنها وقتی استفاده کنید که یک Plugin باید اجرای عاملها، فراخوانی ابزارها، جریان پیام، چرخهٔ عمر نشست، مسیریابی زیرعامل، نصبها، یا راهاندازی Gateway را بررسی یا تغییر دهد.
وقتی یک اسکریپت کوچک HOOK.md نصبشده توسط اپراتور برای رویدادهای دستور و Gateway
مانند /new، /reset، /stop، agent:bootstrap، یا gateway:startup
میخواهید، بهجای آن از هوکهای داخلی استفاده کنید.
شروع سریع
هوکهای تایپشدهٔ Plugin را با api.on(...) از ورودی Plugin خود ثبت کنید:
export default definePluginEntry({ id: "tool-preflight", name: "Tool Preflight", register(api) { api.on( "before_tool_call", async (event) => { if (event.toolName !== "web_search") { return; } return { requireApproval: { title: "Run web search", description: `Allow search query: ${String(event.params.query ?? "")}`, severity: "info", timeoutMs: 60_000, timeoutBehavior: "deny", }, }; }, { priority: 50 }, ); },});مدیریتکنندههای هوک بهترتیب نزولی priority اجرا میشوند. هوکهای هماولویت
ترتیب ثبت را حفظ میکنند.
api.on(name, handler, opts?) این موارد را میپذیرد:
priority- ترتیب مدیریتکنندهها (عدد بالاتر زودتر اجرا میشود).timeoutMs- بودجهٔ اختیاری برای هر هوک. وقتی تنظیم شود، اجراکنندهٔ هوک پس از سپریشدن بودجه آن مدیریتکننده را متوقف میکند و به مورد بعدی ادامه میدهد، بهجای اینکه اجازه دهد راهاندازی یا بازیابی کند، بودجهٔ مدل پیکربندیشدهٔ فراخواننده را مصرف کند. برای استفاده از مهلت پیشفرض مشاهده/تصمیم که اجراکنندهٔ هوک بهصورت عمومی اعمال میکند، آن را حذف کنید.
اپراتورها همچنین میتوانند بدون وصلهکردن کد Plugin بودجهٔ هوکها را تنظیم کنند:
{ "plugins": { "entries": { "my-plugin": { "hooks": { "timeoutMs": 30000, "timeouts": { "before_prompt_build": 90000, "agent_end": 60000 } } } } }}hooks.timeouts.<hookName> مقدار hooks.timeoutMs را بازنویسی میکند، و آن هم مقدار
نوشتهشده توسط Plugin در api.on(..., { timeoutMs }) را بازنویسی میکند. هر مقدار
پیکربندیشده باید یک عدد صحیح مثبت و حداکثر 600000 میلیثانیه باشد. برای هوکهای
کند شناختهشده، بازنویسیهای مخصوص هر هوک را ترجیح دهید تا یک Plugin در همهجا
بودجهٔ طولانیتری نگیرد.
هر هوک event.context.pluginConfig را دریافت میکند؛ یعنی پیکربندی حلشده برای
Pluginی که آن مدیریتکننده را ثبت کرده است. از آن برای تصمیمهای هوکی استفاده کنید
که به گزینههای فعلی Plugin نیاز دارند؛ OpenClaw آن را برای هر مدیریتکننده تزریق
میکند بدون اینکه شیء رویداد مشترکی را که Pluginهای دیگر میبینند تغییر دهد.
کاتالوگ هوکها
هوکها بر اساس سطحی که توسعه میدهند گروهبندی شدهاند. نامهای پررنگ نتیجهٔ تصمیم را میپذیرند (مسدودسازی، لغو، بازنویسی، یا درخواست تأیید)؛ همهٔ موارد دیگر فقط برای مشاهده هستند.
نوبت عامل
before_model_resolve- بازنویسی ارائهدهنده یا مدل پیش از بارگذاری پیامهای نشستagent_turn_prepare- مصرف تزریقهای نوبت Plugin در صف و افزودن زمینهٔ همان نوبت پیش از هوکهای پرامپتbefore_prompt_build- افزودن زمینهٔ پویا یا متن پرامپت سیستمی پیش از فراخوانی مدلbefore_agent_start- فاز ترکیبی فقط برای سازگاری؛ دو هوک بالا را ترجیح دهیدbefore_agent_run- بررسی پرامپت نهایی و پیامهای نشست پیش از ارسال به مدل و مسدودسازی اختیاری اجراbefore_agent_reply- کوتاهکردن نوبت مدل با یک پاسخ مصنوعی یا سکوتbefore_agent_finalize- بررسی پاسخ نهایی طبیعی و درخواست یک گذر دیگر مدلagent_end- مشاهدهٔ پیامهای نهایی، وضعیت موفقیت، و مدت اجرای نوبتheartbeat_prompt_contribution- افزودن زمینهٔ مخصوص Heartbeat برای پایشگر پسزمینه و Pluginهای چرخهٔ عمر
مشاهدهٔ گفتگو
model_call_started/model_call_ended- مشاهدهٔ فرادادهٔ پاکسازیشدهٔ فراخوانی ارائهدهنده/مدل، زمانبندی، نتیجه، و هشهای محدود شناسهٔ درخواست بدون محتوای پرامپت یا پاسخllm_input- مشاهدهٔ ورودی ارائهدهنده (پرامپت سیستمی، پرامپت، تاریخچه)llm_output- مشاهدهٔ خروجی ارائهدهنده، میزان مصرف، وcontextTokenBudgetحلشده در صورت موجودبودن
ابزارها
before_tool_call- بازنویسی پارامترهای ابزار، مسدودسازی اجرا، یا درخواست تأییدafter_tool_call- مشاهدهٔ نتایج ابزار، خطاها، و مدتزمانresolve_exec_env- مشارکت در متغیرهای محیطی متعلق به Plugin برایexectool_result_persist- بازنویسی پیام دستیار تولیدشده از نتیجهٔ ابزارbefore_message_write- بررسی یا مسدودسازی نوشتن پیام در حال انجام (نادر)
پیامها و تحویل
inbound_claim- تصاحب یک پیام ورودی پیش از مسیریابی عامل (پاسخهای مصنوعی)message_received— مشاهدهٔ محتوای ورودی، فرستنده، رشته، و فرادادهmessage_sending— بازنویسی محتوای خروجی یا لغو تحویلreply_payload_sending— تغییر یا لغو بار پاسخ نرمالشده پیش از تحویلmessage_sent— مشاهدهٔ موفقیت یا شکست تحویل خروجیbefore_dispatch- بررسی یا بازنویسی یک ارسال خروجی پیش از واگذاری به کانالreply_dispatch- مشارکت در خط لولهٔ نهایی ارسال پاسخ
نشستها و Compaction
session_start/session_end- ردیابی مرزهای چرخهٔ عمر نشست. مقدارreasonرویداد یکی ازnew،reset،idle،daily،compaction،deleted،shutdown،restart، یاunknownاست. مقدارهایshutdownوrestartاز نهاییساز خاموشی gateway وقتی فرایند در حالی متوقف یا راهاندازی دوباره میشود که نشستها هنوز فعالاند اجرا میشوند، تا Pluginهای پاییندستی (مانند حافظه یا ذخیرهگاههای رونوشت) بتوانند ردیفهای شبحی را که در غیر این صورت در وضعیت باز میان راهاندازیهای دوباره باقی میمانند نهایی کنند. نهاییساز محدود است تا یک Plugin کند نتواند SIGTERM/SIGINT را مسدود کند.before_compaction/after_compaction- مشاهده یا حاشیهنویسی چرخههای Compactionbefore_reset- مشاهدهٔ رویدادهای بازنشانی نشست (/reset، بازنشانیهای برنامهای)
زیرعاملها
subagent_spawned/subagent_ended- مشاهدهٔ راهاندازی و تکمیل زیرعامل.subagent_delivery_target- هوک سازگاری برای تحویل تکمیل وقتی هیچ اتصال نشست هستهای نتواند مسیری را تصویر کند.subagent_spawning- هوک سازگاری منسوخ. هسته اکنون اتصالهای زیرعاملthread: trueرا از طریق آداپتورهای اتصال نشست کانال پیش از اجرایsubagent_spawnedآماده میکند.subagent_spawnedوقتی OpenClaw مدل بومی نشست فرزند را پیش از راهاندازی حل کرده باشد، شاملresolvedModelوresolvedProviderاست.subagent_endedشاملtargetSessionKey(هویت — این باsubagent_spawned.childSessionKeyمنطبق است)،targetKind("subagent"یا"acp")،reason،outcomeاختیاری ("ok"،"error"،"timeout"،"killed"،"reset"، یا"deleted")،errorاختیاری،runId،endedAt،accountId، وsendFarewellاست. این رویداد شاملagentIdیاchildSessionKeyنیست؛ برای همبستهسازی با رویداد متناظرsubagent_spawnedازtargetSessionKeyاستفاده کنید.
چرخهٔ عمر
gateway_start/gateway_stop- شروع یا توقف سرویسهای متعلق به Plugin همراه با Gatewaydeactivate- نام مستعار سازگاری منسوخ برایgateway_stop؛ در Pluginهای جدید ازgateway_stopاستفاده کنیدcron_changed- مشاهدهٔ تغییرات چرخهٔ عمر cron متعلق به gateway (افزودهشده، بهروزرسانیشده، حذفشده، شروعشده، پایانیافته، زمانبندیشده)before_install- بررسی محتوای نصب آمادهشدهٔ skill یا Plugin از یک runtime بارگذاریشدهٔ Plugin
اشکالزدایی هوکهای runtime
وقتی یک Plugin باید ارائهدهنده یا مدل را برای نوبت یک عامل تغییر دهد از
before_model_resolve استفاده کنید. این هوک پیش از حل مدل اجرا میشود؛
llm_output فقط پس از آن اجرا میشود که یک تلاش مدل خروجی دستیار تولید کند.
برای اثبات مدل مؤثر نشست، ثبتهای runtime را بررسی کنید، سپس از
openclaw sessions یا سطوح نشست/وضعیت Gateway استفاده کنید. هنگام اشکالزدایی
بارهای ارائهدهنده، Gateway را با --raw-stream و
--raw-stream-path <path> شروع کنید؛ این پرچمها رویدادهای خام جریان مدل را در یک فایل jsonl
مینویسند.
سیاست فراخوانی ابزار
before_tool_call دریافت میکند:
event.toolNameevent.paramsevent.toolKindوevent.toolInputKindاختیاری، تفکیکگرهای مقتدر میزبان برای ابزارهایی که عمداً نام مشترک دارند؛ برای مثال، فراخوانیهای بیرونیexecدر حالت کد ازtoolKind: "code_mode_exec"استفاده میکنند و وقتی زبان ورودی شناخته شده باشد شاملtoolInputKind: "javascript" | "typescript"هستندevent.derivedPathsاختیاری، شامل راهنماییهای best-effort برای مسیر هدف مشتقشده توسط میزبان برای پوششهای ابزار شناختهشده مانندapply_patch؛ وقتی وجود داشته باشند، این مسیرها ممکن است ناقص باشند یا ممکن است بیشازحد تخمین بزنند که ابزار واقعاً چه چیزی را لمس خواهد کرد (برای مثال، با ورودیهای بدشکل یا جزئی)event.runIdاختیاریevent.toolCallIdاختیاری- فیلدهای زمینه مانند
ctx.agentId،ctx.sessionKey،ctx.sessionId،ctx.runId،ctx.jobId(تنظیمشده روی اجراهای هدایتشده با cron)،ctx.toolKind،ctx.toolInputKind، وctx.traceتشخیصی
میتواند این را برگرداند:
type BeforeToolCallResult = { params?: Record<string, unknown>; block?: boolean; blockReason?: string; requireApproval?: { title: string; description: string; severity?: "info" | "warning" | "critical"; timeoutMs?: number; timeoutBehavior?: "allow" | "deny"; allowedDecisions?: Array<"allow-once" | "allow-always" | "deny">; pluginId?: string; onResolution?: ( decision: "allow-once" | "allow-always" | "deny" | "timeout" | "cancelled", ) => Promise<void> | void; };};رفتار نگهبان هوک برای هوکهای چرخهٔ عمر تایپشده:
block: trueپایانی است و مدیریتکنندههای کماولویتتر را رد میکند.block: falseبهعنوان نبود تصمیم در نظر گرفته میشود.paramsپارامترهای ابزار را برای اجرا بازنویسی میکند.requireApprovalاجرای عامل را متوقف میکند و از طریق تأییدهای Plugin از کاربر میپرسد. دستور/approveمیتواند هم تأییدهای exec و هم تأییدهای Plugin را تأیید کند. در relayهای بومیPreToolUseحالت گزارش app-server در Codex، این به درخواست تأیید app-server متناظر موکول میشود؛ runtime هارنس Codex را ببینید.- یک
block: trueبا اولویت پایینتر همچنان میتواند پس از درخواست تأیید توسط یک هوک با اولویت بالاتر، مسدود کند. onResolutionتصمیم تأیید حلشده را دریافت میکند -allow-once،allow-always،deny،timeout، یاcancelled.
برای مسیریابی تأیید، رفتار تصمیم، و زمان استفاده از requireApproval بهجای
ابزارهای اختیاری یا تأییدهای exec، درخواستهای مجوز Plugin را ببینید.
Pluginهایی که به سیاست سطح میزبان نیاز دارند میتوانند سیاستهای ابزار مورد اعتماد را با
api.registerTrustedToolPolicy(...) ثبت کنند. اینها پیش از هوکهای معمولی
before_tool_call و پیش از تصمیمهای عادی هوک اجرا میشوند. سیاستهای مورد اعتماد
باندلشده ابتدا اجرا میشوند؛ سیاستهای مورد اعتماد Plugin نصبشده سپس بهترتیب
بارگذاری Plugin اجرا میشوند؛ هوکهای معمولی before_tool_call پس از آنها اجرا
میشوند. Pluginهای باندلشده مسیر سیاست مورد اعتماد موجود را حفظ میکنند.
Pluginهای نصبشده باید صریحاً فعال شوند و هر شناسهٔ سیاست را در
contracts.trustedToolPolicies اعلام کنند؛ شناسههای اعلامنشده پیش از ثبت رد
میشوند. شناسههای سیاست در دامنهٔ Plugin ثبتکننده هستند، بنابراین Pluginهای
مختلف میتوانند از همان شناسهٔ محلی دوباره استفاده کنند. از این لایه فقط برای
دروازههای مورد اعتماد میزبان مانند سیاست فضای کاری، اجرای بودجه، یا ایمنی
گردشکار رزروشده استفاده کنید.
هوک محیط exec
resolve_exec_env به Pluginها اجازه میدهد پس از ساختهشدن محیط exec پایه و پیش از
اجرای دستور، متغیرهای محیطی را به فراخوانیهای ابزار exec اضافه کنند. دریافت میکند:
event.sessionKeyevent.toolName، که در حال حاضر همیشه"exec"استevent.host، یکی از"gateway"،"sandbox"، یا"node"- فیلدهای زمینه مانند
ctx.agentId،ctx.sessionKey،ctx.messageProvider، وctx.channelId
برای ادغام در محیط exec یک Record<string, string> برگردانید. مدیریتکنندهها
بهترتیب اولویت اجرا میشوند، و نتایج هوکهای بعدی برای کلید یکسان، نتایج هوکهای
قبلی را بازنویسی میکنند.
خروجی Hook پیش از ادغام، از سیاست کلیدهای محیط exec میزبان عبور داده
و فیلتر میشود. کلیدهای نامعتبر، PATH، و کلیدهای خطرناک بازنویسی میزبان مانند
LD_*، DYLD_*، NODE_OPTIONS، متغیرهای proxy، و متغیرهای بازنویسی TLS
حذف میشوند. env فیلترشده Plugin در فراداده تایید/ممیزی Gateway گنجانده میشود
و به درخواستهای اجرای node-host فرستاده میشود.
ماندگاری نتیجه ابزار
نتایج ابزار میتوانند شامل details ساختاریافته برای رندر UI، عیبیابی،
مسیردهی رسانه، یا فراداده تحت مالکیت Plugin باشند. با details بهعنوان
فراداده زمان اجرا رفتار کنید، نه محتوای prompt:
- OpenClaw پیش از بازپخش provider و ورودی Compaction،
toolResult.detailsرا حذف میکند تا فراداده به context مدل تبدیل نشود. - ورودیهای نشست ماندگار فقط
detailsمحدودشده را نگه میدارند. جزئیات بیش از حد بزرگ با یک خلاصه فشرده وpersistedDetailsTruncated: trueجایگزین میشوند. tool_result_persistوbefore_message_writeپیش از سقف نهایی ماندگاری اجرا میشوند. Hookها همچنان بایدdetailsبازگشتی را کوچک نگه دارند و از قرار دادن متن مرتبط با prompt فقط درdetailsخودداری کنند؛ خروجی ابزار قابل مشاهده برای مدل را درcontentبگذارید.
Hookهای prompt و مدل
برای Pluginهای جدید از Hookهای ویژه هر phase استفاده کنید:
before_model_resolve: فقط prompt فعلی و فراداده پیوست را دریافت میکند.providerOverrideیاmodelOverrideبرگردانید.agent_turn_prepare: prompt فعلی، پیامهای نشست آمادهشده، و هر تزریق صفشده دقیقا-یکبار که برای این نشست تخلیه شده است را دریافت میکند.prependContextیاappendContextبرگردانید.before_prompt_build: prompt فعلی و پیامهای نشست را دریافت میکند.prependContext،appendContext،systemPrompt،prependSystemContext، یاappendSystemContextبرگردانید.heartbeat_prompt_contribution: فقط برای نوبتهای Heartbeat اجرا میشود وprependContextیاappendContextبرمیگرداند. این Hook برای پایشگرهای پسزمینهای در نظر گرفته شده که باید وضعیت فعلی را بدون تغییر دادن نوبتهای آغازشده توسط کاربر خلاصه کنند.
before_agent_start برای سازگاری باقی مانده است. Hookهای صریح بالا را ترجیح دهید
تا Plugin شما به یک phase ترکیبی legacy وابسته نشود.
before_agent_run پس از ساخت prompt و پیش از هر ورودی مدل اجرا میشود،
از جمله بارگذاری تصویر محلی prompt و مشاهده llm_input. این Hook ورودی کاربر فعلی را
بهعنوان prompt، بههمراه تاریخچه نشست بارگذاریشده در messages
و prompt سیستمی فعال دریافت میکند. برای متوقف کردن اجرا پیش از اینکه مدل بتواند prompt را بخواند،
{ outcome: "block", reason, message? } برگردانید. reason داخلی است؛
message جایگزین قابل مشاهده برای کاربر است. تنها outcomeهای پشتیبانیشده
pass و block هستند؛ شکلهای تصمیم پشتیبانینشده fail closed میشوند.
وقتی یک اجرا مسدود میشود، OpenClaw فقط متن جایگزین را در
message.content بههمراه فراداده غیرحساس block مانند id Plugin مسدودکننده
و timestamp ذخیره میکند. متن اصلی کاربر در transcript یا context آینده نگه داشته نمیشود.
دلایل block داخلی حساس تلقی میشوند و از payloadهای transcript، history، broadcast، log،
و diagnostics حذف میشوند. مشاهدهپذیری باید از فیلدهای پاکسازیشده مانند blocker id،
outcome، timestamp، یا یک دستهبندی امن استفاده کند.
before_agent_start و agent_end وقتی OpenClaw بتواند اجرای فعال را شناسایی کند
شامل event.runId هستند. همان مقدار روی ctx.runId نیز در دسترس است.
اجراهای هدایتشده با Cron همچنین ctx.jobId (id کار Cron مبدا) را ارائه میکنند
تا Hookهای Plugin بتوانند metrics، side effectها، یا state را به یک کار زمانبندیشده مشخص
محدود کنند.
برای اجراهایی که از کانال آغاز شدهاند، ctx.channel و ctx.messageProvider
سطح provider مانند discord یا telegram را شناسایی میکنند، در حالی که
ctx.channelId شناسه هدف گفتگو است وقتی OpenClaw بتواند آن را از کلید نشست
یا فراداده تحویل استخراج کند.
وقتی هویت فرستنده در دسترس باشد، contextهای Hook عامل همچنین شامل موارد زیر هستند:
ctx.senderId— ID فرستنده در محدوده کانال (مثلا Feishuopen_id، ID کاربر Discord). وقتی اجرا از پیام کاربری با فراداده فرستنده شناختهشده آغاز شود پر میشود.ctx.chatId— شناسه گفتگوی بومی transport (مثلا Feishuchat_id، Telegramchat_id). وقتی کانال مبدا یک ID گفتگوی بومی ارائه کند پر میشود.ctx.channelContext.sender.id— همان ID فرستنده مثلctx.senderId، زیر یک آبجکت تحت مالکیت کانال که Pluginها میتوانند آن را با فیلدهای ویژه کانال گسترش دهند.ctx.channelContext.chat.id— همان ID گفتگو مثلctx.chatId، زیر یک آبجکت تحت مالکیت کانال که Pluginها میتوانند آن را با فیلدهای ویژه کانال گسترش دهند.
Core فقط فیلدهای تو در توی id را تعریف میکند. Pluginهای کانال که فراداده غنیتر
فرستنده یا chat را از طریق helper ورودی عبور میدهند میتوانند
PluginHookChannelSenderContext یا PluginHookChannelChatContext را از
openclaw/plugin-sdk/channel-inbound تقویت کنند:
declare module "openclaw/plugin-sdk/channel-inbound" { interface PluginHookChannelSenderContext { unionId?: string; userId?: string; }}Pluginهای کانال آن فیلدها را از طریق helper ورودی SDK عبور میدهند:
buildChannelInboundEventContext({ // ... channelContext: { sender: { id: senderOpenId, unionId, userId }, chat: { id: chatId }, },});این فیلدها اختیاری هستند و برای اجراهای آغازشده از سیستم (heartbeat، cron، exec-event) وجود ندارند.
ctx.senderExternalId بهعنوان یک فیلد سازگاری منبع deprecated برای
Pluginهای قدیمیتر باقی میماند. Core آن را پر نمیکند؛ هویتهای جدید فرستنده ویژه کانال
باید از طریق module augmentation زیر ctx.channelContext.sender قرار بگیرند.
agent_end یک Hook مشاهده است. مسیرهای Gateway و harness ماندگار آن را
پس از نوبت بهصورت fire-and-forget اجرا میکنند، در حالی که مسیرهای CLI یکباره و کوتاهعمر
پیش از پاکسازی process منتظر promise Hook میمانند تا Pluginهای مورد اعتماد بتوانند
مشاهدهپذیری ترمینال را flush کنند یا state را ثبت کنند. runner Hook یک timeout
۳۰ ثانیهای اعمال میکند تا یک Plugin گیرکرده یا endpoint embedding نتواند promise Hook را
برای همیشه pending نگه دارد. timeout ثبت میشود و OpenClaw ادامه میدهد؛
این کار network work تحت مالکیت Plugin را لغو نمیکند مگر اینکه خود Plugin نیز از
abort signal خودش استفاده کند.
از model_call_started و model_call_ended برای telemetry تماس provider استفاده کنید
که نباید promptهای خام، history، responseها، headerها، bodyهای request،
یا IDهای request provider را دریافت کند. این Hookها شامل فراداده پایدار مانند
runId، callId، provider، model، api/transport اختیاری،
durationMs/outcome پایانی، و upstreamRequestIdHash هستند وقتی OpenClaw بتواند
یک hash محدود request-id مربوط به provider استخراج کند. وقتی runtime فراداده
context-window را resolve کرده باشد، رویداد و context Hook همچنین شامل
contextTokenBudget، بودجه موثر token پس از سقفهای model/config/agent، بههمراه
contextWindowSource و contextWindowReferenceTokens هستند وقتی سقف پایینتری
اعمال شده باشد.
before_agent_finalize فقط وقتی اجرا میشود که یک harness در آستانه پذیرش پاسخ نهایی طبیعی
assistant باشد. این مسیر لغو /stop نیست و وقتی کاربر یک نوبت را abort میکند اجرا نمیشود.
برای درخواست یک pass مدل دیگر از harness پیش از نهاییسازی،
{ action: "revise", reason } برگردانید، برای اجبار نهاییسازی
{ action: "finalize", reason? } برگردانید، یا برای ادامه، نتیجهای ندهید.
Hookهای بومی Codex با نام Stop به این Hook بهعنوان تصمیمهای
before_agent_finalize در OpenClaw relay میشوند.
هنگام برگرداندن action: "revise"، Pluginها میتوانند فراداده retry را شامل کنند تا
pass اضافی مدل محدود و replay-safe باشد:
type BeforeAgentFinalizeRetry = { instruction: string; idempotencyKey?: string; maxAttempts?: number;};instruction به دلیل بازبینی ارسالشده به harness افزوده میشود.
idempotencyKey به host اجازه میدهد retryها را برای همان درخواست Plugin در میان
تصمیمهای finalize معادل بشمارد، و maxAttempts تعداد passهای اضافی را که
host پیش از ادامه با پاسخ نهایی طبیعی اجازه میدهد محدود میکند.
Pluginهای غیرهمراه که به Hookهای گفتگوی خام (before_model_resolve,
before_agent_reply, llm_input, llm_output, before_agent_finalize,
agent_end, یا before_agent_run) نیاز دارند باید این را تنظیم کنند:
{ "plugins": { "entries": { "my-plugin": { "hooks": { "allowConversationAccess": true } } } }}Hookهای تغییردهنده prompt و تزریقهای ماندگار نوبت بعدی را میتوان برای هر Plugin
با plugins.entries.<id>.hooks.allowPromptInjection=false غیرفعال کرد.
افزونههای نشست و تزریقهای نوبت بعدی
Pluginهای workflow میتوانند state کوچک سازگار با JSON نشست را با
api.registerSessionExtension(...) ماندگار کنند و آن را از طریق متد Gateway
sessions.pluginPatch بهروزرسانی کنند. ردیفهای نشست state افزونه ثبتشده را از طریق
pluginExtensions project میکنند، و به Control UI و clientهای دیگر اجازه میدهند
وضعیت تحت مالکیت Plugin را بدون دانستن internals Plugin رندر کنند.
وقتی یک Plugin نیاز دارد context ماندگار دقیقا یکبار به نوبت مدل بعدی برسد،
از api.enqueueNextTurnInjection(...) استفاده کنید. OpenClaw تزریقهای صفشده را پیش از
Hookهای prompt تخلیه میکند، تزریقهای منقضیشده را حذف میکند، و بر اساس
idempotencyKey در هر Plugin deduplicate میکند. این seam مناسب برای resumeهای تایید،
خلاصههای policy، deltaهای پایشگر پسزمینه، و ادامههای command است که باید در نوبت بعدی
برای مدل قابل مشاهده باشند اما نباید به متن prompt سیستمی دائمی تبدیل شوند.
معنای cleanup بخشی از contract است. callbackهای cleanup افزونه نشست و lifecycle runtime
reset، delete، disable، یا restart را دریافت میکنند. host برای
reset/delete/disable، state افزونه نشست ماندگار Plugin مالک و تزریقهای نوبت بعدی pending را
حذف میکند؛ restart state نشست ماندگار را نگه میدارد در حالی که callbackهای cleanup به
Pluginها اجازه میدهند کارهای scheduler، context اجرا، و دیگر منابع خارج از باند مربوط به
نسل runtime قبلی را آزاد کنند.
Hookهای پیام
از Hookهای پیام برای مسیریابی و policy تحویل در سطح کانال استفاده کنید:
message_received: محتوای ورودی، فرستنده،threadId،messageId,senderId، همبستگی اختیاری run/session، و فراداده را مشاهده میکند.message_sending:contentرا بازنویسی میکند یا{ cancel: true }برمیگرداند.reply_payload_sending: آبجکتهای نرمالشدهReplyPayloadرا بازنویسی میکند (شاملpresentation،delivery، media refها، و text) یا{ cancel: true }برمیگرداند.message_sent: موفقیت یا شکست نهایی را مشاهده میکند.
برای پاسخهای TTS فقط-صوتی، content ممکن است transcript گفتاری پنهان را شامل شود
حتی وقتی payload کانال هیچ متن/کپشن قابل مشاهدهای ندارد. بازنویسی آن
content فقط transcript قابل مشاهده برای Hook را بهروزرسانی میکند؛ بهعنوان caption رسانه
رندر نمیشود.
رویدادهای reply_payload_sending ممکن است شامل usageState باشند، یک snapshot زنده
best-effort در هر نوبت از model/usage/context. تحویل ماندگار، replay بازیابیشده، و
پاسخهای بدون همبستگی دقیق run آن را حذف میکنند.
contextهای Hook پیام وقتی در دسترس باشد فیلدهای همبستگی پایدار را ارائه میکنند:
ctx.sessionKey، ctx.runId، ctx.messageId، ctx.senderId، ctx.trace,
ctx.traceId، ctx.spanId، ctx.parentSpanId، و ctx.callDepth. contextهای ورودی
و before_dispatch همچنین وقتی کانال داده پیام نقلقولشده visibility-filtered داشته باشد
فراداده reply را ارائه میکنند: replyToId، replyToIdFull,
replyToBody، replyToSender، و replyToIsQuote. پیش از خواندن فراداده legacy،
این فیلدهای first-class را ترجیح دهید.
پیش از استفاده از فراداده ویژه کانال، فیلدهای typed threadId و replyToId را ترجیح دهید.
قواعد تصمیم:
message_sendingباcancel: trueپایانی است.message_sendingباcancel: falseبهعنوان نبود تصمیم در نظر گرفته میشود.contentبازنویسیشده به hookهای با اولویت پایینتر ادامه میدهد، مگر اینکه hook بعدی تحویل را لغو کند.reply_payload_sendingپس از عادیسازی payload و پیش از تحویل channel اجرا میشود، از جمله پاسخهایی که به channel مبدأ بازگردانده میشوند. Handlerها بهترتیب اجرا میشوند و هر handler آخرین payload تولیدشده توسط handlerهای با اولویت بالاتر را میبیند.- payloadهای
reply_payload_sendingنشانگرهای اعتماد runtime مانندtrustedLocalMediaرا در دسترس نمیگذارند؛ Pluginها میتوانند شکل payload را ویرایش کنند، اما نمیتوانند اعتماد رسانه محلی را اعطا کنند. message_sendingمیتواند همراه با لغو،cancelReasonوmetadataمحدودشده برگرداند. APIهای جدید چرخه عمر پیام این را بهعنوان نتیجه تحویل سرکوبشده با دلیلcancelled_by_message_sending_hookنشان میدهند؛ تحویل مستقیم legacy برای سازگاری همچنان آرایه نتیجه خالی برمیگرداند.message_sentفقط برای مشاهده است. شکست handlerها ثبت میشود و نتیجه تحویل را تغییر نمیدهد.
نصب hookها
برای تصمیمهای اجازه/مسدودسازی در مالکیت operator از security.installPolicy استفاده کنید.
این policy از پیکربندی OpenClaw اجرا میشود، مسیرهای نصب و بهروزرسانی CLI را پوشش میدهد،
و وقتی فعال باشد اما در دسترس نباشد بهصورت fail-closed شکست میخورد.
before_install یک hook چرخه عمر runtime مربوط به Plugin است. فقط در فرایند OpenClaw که
hookهای Plugin از قبل بارگذاری شدهاند، مانند جریانهای نصب پشتیبانیشده توسط Gateway،
پس از security.installPolicy اجرا میشود. این برای مشاهدهها، هشدارها، و بررسیهای
سازگاری در مالکیت Plugin مفید است، اما مرز امنیتی اصلی سازمانی یا host برای نصبها نیست.
فیلد builtinScan برای سازگاری در payload رویداد باقی میماند، اما OpenClaw دیگر
مسدودسازی داخلی کد خطرناک در زمان نصب را اجرا نمیکند، بنابراین یک نتیجه ok خالی است.
برای توقف نصب در آن فرایند، findings اضافی یا { block: true, blockReason } برگردانید.
block: true پایانی است. block: false بهعنوان نبود تصمیم در نظر گرفته میشود.
شکست handlerها نصب را بهصورت fail-closed مسدود میکند.
چرخه عمر Gateway
برای سرویسهای Plugin که به وضعیت در مالکیت Gateway نیاز دارند، از gateway_start استفاده کنید.
context، ctx.config، ctx.workspaceDir و ctx.getCron?.() را برای بازرسی و بهروزرسانی
Cron در دسترس میگذارد. برای پاکسازی منابع بلندمدت از gateway_stop استفاده کنید.
برای سرویسهای runtime در مالکیت Plugin به hook داخلی gateway:startup تکیه نکنید.
cron_changed برای رویدادهای چرخه عمر Cron در مالکیت gateway با یک payload رویداد typed
فعال میشود که دلایل added، updated، removed، started، finished، و scheduled
را پوشش میدهد. رویداد یک snapshot از PluginHookGatewayCronJob را حمل میکند
(شامل state.nextRunAtMs، state.lastRunStatus، و state.lastError در صورت وجود)
بههمراه یک PluginHookGatewayCronDeliveryStatus از not-requested | delivered |
not-delivered | unknown. رویدادهای حذفشده همچنان snapshot job حذفشده را حمل
میکنند تا زمانبندهای خارجی بتوانند وضعیت را همگام کنند. هنگام همگامسازی زمانبندهای
wake خارجی از ctx.getCron?.() و ctx.config در context runtime استفاده کنید و
OpenClaw را بهعنوان منبع حقیقت برای بررسیهای موعددار و اجرا نگه دارید.
منسوخسازیهای پیشرو
چند سطح نزدیک به hook منسوخ شدهاند اما هنوز پشتیبانی میشوند. پیش از انتشار major بعدی مهاجرت کنید:
- envelopeهای channel بهصورت plaintext در handlerهای
inbound_claimوmessage_received. بهجای parse کردن متن envelope تخت،BodyForAgentو blockهای ساختاریافته context کاربر را بخوانید. ببینید envelopeهای channel بهصورت plaintext → BodyForAgent. before_agent_startبرای سازگاری باقی میماند. Pluginهای جدید باید بهجای phase ترکیبی ازbefore_model_resolveوbefore_prompt_buildاستفاده کنند.subagent_spawningبرای سازگاری با Pluginهای قدیمیتر باقی میماند، اما Pluginهای جدید نباید routing مربوط به thread را از آن برگردانند. Core پیش از فعال شدنsubagent_spawned، bindingهای subagent باthread: trueرا از طریق adapterهای session-binding channel آماده میکند.deactivateتا پس از 2026-08-16 بهعنوان alias سازگاری cleanup منسوخشده باقی میماند. Pluginهای جدید باید ازgateway_stopاستفاده کنند.onResolutionدرbefore_tool_callاکنون بهجای یکstringآزاد، از union typed با نامPluginApprovalResolutionاستفاده میکند (allow-once/allow-always/deny/timeout/cancelled).
برای فهرست کامل - ثبت قابلیت حافظه، نمایه تفکر ارائهدهنده، ارائهدهندههای auth خارجی،
typeهای کشف ارائهدهنده، accessorهای runtime وظیفه، و تغییر نام command-auth →
command-status - ببینید
مهاجرت Plugin SDK → منسوخسازیهای فعال.
مرتبط
- مهاجرت Plugin SDK - منسوخسازیهای فعال و زمانبندی حذف
- ساخت Pluginها
- نمای کلی Plugin SDK
- نقطههای ورود Plugin
- hookهای داخلی
- جزئیات داخلی معماری Plugin