Plugin maintainer reference
ارائهٔ پیام
ارائهٔ پیام، قرارداد مشترک OpenClaw برای رابط کاربری غنیِ چت خروجی است. این قرارداد به عاملها، فرمانهای CLI، جریانهای تأیید و Pluginها اجازه میدهد قصد پیام را یکبار توصیف کنند، درحالیکه هر Plugin کانال، بهترین قالب بومی ممکن را رندر میکند.
برای رابط کاربری قابلحمل پیام از ارائه استفاده کنید: بخشهای متنی، متن کوتاه زمینه/پاورقی، جداکنندهها، نمودارها، جدولها، دکمهها، منوهای انتخاب و عنوان/لحن کارت.
فیلدهای بومیِ ارائهدهندهٔ جدید مانند Discord components، Slack
blocks، Telegram buttons، Teams card یا Feishu card را به ابزار مشترک
پیام اضافه نکنید. اینها خروجیهای رندرکنندهاند که مالکیتشان با Plugin کانال است.
قرارداد
نویسندگان Plugin قرارداد عمومی را از این مسیر وارد میکنند:
MessagePresentation, ReplyPayloadDelivery,} from "openclaw/plugin-sdk/interactive-runtime";ساختار:
type MessagePresentation = { title?: string; tone?: "neutral" | "info" | "success" | "warning" | "danger"; blocks: MessagePresentationBlock[];}; type MessagePresentationBlock = | { type: "text"; text: string } | { type: "context"; text: string } | { type: "divider" } | { type: "buttons"; buttons: MessagePresentationButton[] } | { type: "select"; placeholder?: string; options: MessagePresentationOption[] } | { type: "chart"; chartType: "pie"; title: string; segments: Array<{ label: string; value: number }>; } | { type: "chart"; chartType: "bar" | "area" | "line"; title: string; categories: string[]; series: Array<{ name: string; values: number[] }>; xLabel?: string; yLabel?: string; } | { type: "table"; caption: string; headers: string[]; rows: Array<Array<string | number>>; rowHeaderColumnIndex?: number; }; type MessagePresentationAction = | { type: "command"; command: string } | { type: "callback"; value: string } | { type: "approval"; approvalId: string; approvalKind: "exec" | "plugin"; decision: "allow-once" | "allow-always" | "deny"; } | { type: "question"; questionId: string; optionValue: string; } | { type: "url"; url: string } | { type: "web-app"; url: string; widgetId?: string; } | { type: "web-app"; url?: string; widgetId: string; }; type MessagePresentationButton = { label: string; action?: MessagePresentationAction; /** مقدار callback قدیمی. برای کنترلهای جدید action را ترجیح دهید. */ value?: string; /** @deprecated از action با type برابر "url" استفاده کنید. */ url?: string; /** @deprecated از action با type برابر "web-app" استفاده کنید. */ webApp?: { url: string }; /** @deprecated از action با type برابر "web-app" استفاده کنید. */ web_app?: { url: string }; priority?: number; disabled?: boolean; reusable?: boolean; style?: "primary" | "secondary" | "success" | "danger";}; type MessagePresentationOption = { label: string; action?: Extract<MessagePresentationAction, { type: "command" | "callback" }>; /** مقدار callback قدیمی. برای کنترلهای جدید action را ترجیح دهید. */ value?: string;}; type ReplyPayloadDelivery = { pin?: | boolean | { enabled: boolean; notify?: boolean; required?: boolean; };};معنای دکمهها:
action.type: "command"یک فرمان slash بومی را از طریق مسیر فرمان هسته اجرا میکند. از این مورد برای دکمهها و منوهای فرمان داخلی استفاده کنید.action.type: "callback"دادهٔ مات Plugin را از طریق مسیر تعامل کانال حمل میکند. Pluginهای کانال نباید دادهٔ callback را دوباره بهعنوان فرمانهای slash تفسیر کنند.action.type: "approval"یک تأیید پایدار اپراتور، نوع صریحexecیاpluginآن و تصمیم درخواستی را مشخص میکند. Pluginهای کانال این اقدام را در یک callback خصوصیِ انتقال کدگذاری میکنند و آن را از طریق سرویس تأیید حل میکنند؛ آنها نباید متن فرمان/approveرا تجزیه کنند یا نوع را از شناسه استنباط کنند.action.type: "question"یک گزینه را برای پرسش زندهٔask_userکه در زمان اجرا ایجاد شده است، مشخص میکند. همانندapproval، این یک اقدام زمان اجرای OpenClaw است؛ عاملها و Pluginها نباید شناسههای پرسش را تولید کنند. Telegram، Discord و Slack آن را به callbackهای بومی و خصوصیِ انتقال نگاشت میکنند و گزینه را از طریق Gateway حل میکنند. وقتی پرسش پاسخ داده شود، منقضی شود یا لغو شود، این کانالها پیام تحویلشده را ویرایش میکنند، اقدامهای آن را حذف میکنند و وضعیت پایانی را میافزایند. WhatsApp، Signal و iMessage حداکثر چهار گزینهٔ تکانتخابی را بهصورت واکنشهای1️⃣تا4️⃣رندر میکنند. دیگر ساختارهای پرسش به متن برچسب تنزل مییابند و کاربر میتواند با یک پاسخ متنی ساده جواب دهد.action.type: "url"یک پیوند معمولی را باز میکند.action.type: "web-app"یک برنامهٔ وب بومیِ کانال را اجرا میکند. برای یک برنامهٔ مبتنی بر URL،urlرا تنظیم کنید یا برای ویجتی که OpenClaw میزبانی میکند و سازوکار اجرای آن در مالکیت کانال است،widgetIdرا تنظیم کنید؛ حداقل یکی الزامی است. وقتی هر دو وجود دارند، کانال میتواند اجرای بومیِ ویجت میزبانیشدهٔ خود را ترجیح دهد و در جایی که آن سازوکار در دسترس نیست از URL استفاده کند.valueمقدار مات callback قدیمی است. کنترلهای جدید باید ازactionاستفاده کنند تا Pluginهای کانال بتوانند بدون حدسزدن از روی متن، فرمانها و callbackها را نگاشت کنند.url،webAppوweb_appهمچنان بهعنوان ورودیهای منسوخشدهٔ مرزی پذیرفته میشوند. نرمالسازها این فیلدها را حفظ میکنند تا رندرکنندهها بتوانند معنای قدیمیِ منتشرشده را از اقدامهای صریحِ نوعدار تشخیص دهند. تولیدکنندگان جدید باید ازactionاستفاده کنند.labelالزامی است و در جایگزین متنی نیز استفاده میشود.styleجنبهٔ توصیهای دارد. رندرکنندهها باید سبکهای پشتیبانینشده را به یک پیشفرض امن نگاشت کنند، نه اینکه ارسال را ناموفق کنند.priorityاختیاری است. وقتی کانالی محدودیتهای اقدام را اعلام میکند و لازم است کنترلها حذف شوند، هسته ابتدا دکمههای دارای اولویت بالاتر را نگه میدارد و ترتیب اصلی را میان دکمههای هماولویت حفظ میکند. وقتی همهٔ کنترلها جا شوند، ترتیب تألیفشده حفظ میشود.disabledاختیاری است. کانالها باید باsupportsDisabledصراحتاً آن را فعال کنند؛ در غیر این صورت هسته کنترل غیرفعال را به متن جایگزین غیرتعاملی تنزل میدهد. یک دکمهٔ غیرفعال همیشه در متن جایگزین فقط با برچسب رندر میشود، حتی وقتی یک اقدامcommandداشته باشد.reusableاختیاری است. کانالهایی که از callbackهای بومیِ قابلاستفادهٔ مجدد پشتیبانی میکنند، میتوانند اقدام را پس از یک تعامل موفق همچنان در دسترس نگه دارند. از آن برای اقدامهای تکرارپذیر یا ایدمپوتنت مانند تازهسازی، بازرسی یا جزئیات بیشتر استفاده کنید؛ برای تأییدهای معمولیِ یکباره و اقدامهای مخرب، آن را تنظیمنشده باقی بگذارید.
معنای انتخاب:
options[].actionفقطcommandیاcallbackرا میپذیرد؛ اقدامهای تأیید و پیوند فقط مخصوص دکمه هستند.options[].valueمقدار برنامهٔ انتخابشدهٔ قدیمی است.placeholderجنبهٔ توصیهای دارد و ممکن است کانالهایی که پشتیبانی بومی از انتخاب ندارند، آن را نادیده بگیرند.- اگر کانالی از انتخابها پشتیبانی نکند، متن جایگزین برچسبها را فهرست میکند.
معنای نمودار:
pieبه مقادیر مثبت برای بخشها نیاز دارد.bar،areaوlineاز یک آرایهٔ مرتبcategoriesاستفاده میکنند. هر سری دقیقاً یک مقدار متناهی برای هر دسته، با همان ترتیب، فراهم میکند.- برچسبهای دسته و نامهای سری باید یکتا باشند. بلوکهای نمودار نامعتبر یا ناقص هنگام نرمالسازی حذف میشوند، نه اینکه دادهها بیسروصدا تغییر کنند.
- رندر بومی نمودار از طریق
presentationCapabilities.chartsبهصورت صریح فعال میشود. دیگر کانالها عنوان نمودار، محورها، دستهها، سریها و مقادیر را بهصورت متن قطعی دریافت میکنند. این همچنین جایگزین دسترسپذیری است.
معنای جدول:
-
captionیک عنوان کوتاه الزامی است.headersباید حداقل یک برچسب ستون یکتا و غیرخالی داشته باشد. -
rowsباید حداقل یک ردیف داشته باشد. هر ردیف باید دقیقاً برای هر سرستون یک سلول داشته باشد و هر سلول باید رشتهای غیرخالی یا عددی متناهی باشد. -
rowHeaderColumnIndexیک شاخص اختیاری با مبدأ صفر است که ستونی را مشخص میکند که سلولهای آن باید توسط رندرکنندههای بومی بهعنوان سرستون ردیف ارائه شوند. -
نرمالسازی جدول اتمی است. عنوان، سرستون، عرض ردیف، سلول یا شاخص سرستون ردیف نامعتبر باعث حذف بلوک جدول میشود، نه کوتاهسازی یا ترمیم دادههای آن.
-
رندر بومی جدول از طریق
presentationCapabilities.tablesبهصورت صریح فعال میشود. دیگر کانالها عنوان و همهٔ ردیفها را بهصورت متن خطی قطعی دریافت میکنند و فاصلههای خالی داخلی ادغام میشوند:text پایپلاین باز (جدول)- حساب: Acme؛ مرحله: برنده؛ ARR: 125000- حساب: Globex؛ مرحله: بازبینی؛ ARR: 82000
هیچ متمایزکنندهٔ جداگانهٔ report وجود ندارد. یک گزارش را از title،
tone، text، context، chart، table و بلوکهای اقدام ترکیب کنید. این کار هر
بلوک را مستقل از دیگران قابلرندر نگه میدارد و همان جایگزین متنی
قطعی را برای گزارش کامل فراهم میکند.
نمونههای تولیدکننده
کارت ساده:
{ "title": "تأیید استقرار", "tone": "warning", "blocks": [ { "type": "text", "text": "Canary آمادهٔ ارتقا است." }, { "type": "context", "text": "ساخت 1234، مرحلهٔ staging با موفقیت گذشت." }, { "type": "buttons", "buttons": [ { "label": "تأیید", "action": { "type": "callback", "value": "deploy:approve" }, "style": "success" }, { "label": "رد", "action": { "type": "callback", "value": "deploy:decline" }, "style": "danger" } ] } ]}دکمهٔ پیوند فقط-URL:
{ "blocks": [ { "type": "text", "text": "یادداشتهای انتشار آمادهاند." }, { "type": "buttons", "buttons": [ { "label": "بازکردن یادداشتها", "action": { "type": "url", "url": "https://example.com/release" } } ] } ]}دکمهٔ برنامهٔ کوچک Telegram:
{ "blocks": [ { "type": "buttons", "buttons": [ { "label": "اجرا", "action": { "type": "web-app", "url": "https://example.com/app" } } ] } ]}منوی انتخاب:
{ "title": "انتخاب محیط", "blocks": [ { "type": "select", "placeholder": "محیط", "options": [ { "label": "Canary", "value": "env:canary" }, { "label": "محیط تولید", "value": "env:prod" } ] } ]}نمودار:
{ "blocks": [ { "type": "chart", "chartType": "line", "title": "درآمد فصلی", "categories": ["Q1", "Q2", "Q3"], "series": [ { "name": "محصول", "values": [120, 145, 138] }, { "name": "خدمات", "values": [80, 95, 104] } ], "xLabel": "فصل", "yLabel": "درآمد" } ]}گزارش جدولی:
{ "title": "گزارش پایپلاین", "tone": "info", "blocks": [ { "type": "text", "text": "فرصتهای فعلی بر اساس مرحله." }, { "type": "table", "caption": "پایپلاین باز", "headers": ["حساب", "مرحله", "ARR"], "rows": [ ["Acme", "برنده", 125000], ["Globex", "بازبینی", 82000] ], "rowHeaderColumnIndex": 0 }, { "type": "context", "text": "از اسنپشات CRM بهروزرسانی شده است." } ]}ارسال با CLI:
openclaw message send --channel slack \ --target channel:C123 \ --message "تأیید استقرار" \ --presentation '{"title":"تأیید استقرار","tone":"warning","blocks":[{"type":"text","text":"Canary آماده است."},{"type":"buttons","buttons":[{"label":"تأیید","value":"deploy:approve","style":"success"},{"label":"رد","value":"deploy:decline","style":"danger"}]}]}'تحویل سنجاقشده:
openclaw message send --channel telegram \ --target -1001234567890 \ --message "موضوع باز شد" \ --pinتحویل سنجاقشده با JSON صریح:
{ "pin": { "enabled": true, "notify": true, "required": false }}قرارداد رندرکننده
Pluginهای کانال، پشتیبانی از رندر را در آداپتور خروجی خود اعلام میکنند:
const adapter: ChannelOutboundAdapter = { deliveryMode: "direct", presentationCapabilities: { supported: true, buttons: true, selects: true, context: true, divider: true, charts: false, tables: false, limits: { actions: { maxActions: 25, maxActionsPerRow: 5, maxRows: 5, maxLabelLength: 80, maxValueBytes: 100, supportsStyles: true, supportsDisabled: false, }, selects: { maxOptions: 25, maxLabelLength: 100, maxValueBytes: 100, }, text: { maxLength: 2000, encoding: "characters", markdownDialect: "discord-markdown", }, }, }, deliveryCapabilities: { pin: true, }, renderPresentation({ payload, presentation, ctx }) { return renderNativePayload(payload, presentation, ctx); }, async pinDeliveredMessage({ target, messageId, pin }) { await pinNativeMessage(target, messageId, { notify: pin.notify === true }); },};مقادیر بولی قابلیتها مشخص میکنند که رندرکننده چه مواردی را میتواند تعاملی کند. مقادیر اختیاری
limits پوشش عمومیای را توصیف میکنند که هسته میتواند پیش از فراخوانی
رندرکننده تطبیق دهد:
type ChannelPresentationCapabilities = { supported?: boolean; buttons?: boolean; selects?: boolean; context?: boolean; divider?: boolean; charts?: boolean; tables?: boolean; limits?: { actions?: { maxActions?: number; maxActionsPerRow?: number; maxRows?: number; maxLabelLength?: number; maxValueBytes?: number; supportsStyles?: boolean; supportsDisabled?: boolean; supportsLayoutHints?: boolean; }; selects?: { maxOptions?: number; maxLabelLength?: number; maxValueBytes?: number; }; text?: { maxLength?: number; encoding?: "characters" | "utf8-bytes" | "utf16-units"; markdownDialect?: "plain" | "markdown" | "html" | "slack-mrkdwn" | "discord-markdown"; supportsEdit?: boolean; }; };};هسته پیش از رندر، محدودیتهای عمومی را روی کنترلهای معنایی اعمال میکند. رندرکنندهها همچنان مسئول اعتبارسنجی نهایی مختص ارائهدهنده و کوتاهسازی برای تعداد بلوکهای بومی، اندازه کارت، محدودیتهای URL و ویژگیهای خاص ارائهدهندهای هستند که در قرارداد عمومی قابل بیان نیستند. اگر محدودیتها همه کنترلهای یک بلوک را حذف کنند، هسته برچسبها را بهصورت متن زمینهای غیرتعاملی نگه میدارد تا پیام تحویلشده همچنان یک جایگزین قابلمشاهده داشته باشد.
جریان رندر هسته
در مسیر خروجی معیار که CLI و کنشهای استاندارد پیام از آن استفاده میکنند، هسته:
- بار ارائه را نرمالسازی میکند.
- آداپتور خروجی کانال مقصد را تفکیک میکند.
presentationCapabilitiesرا میخواند.- هنگامی که آداپتور محدودیتها را اعلام میکند، محدودیتهای عمومی قابلیت مانند تعداد کنشها، طول برچسب و
تعداد گزینههای انتخاب را اعمال میکند. بلوکهای نمودار و جدول به متن قطعی
تبدیل میشوند، مگر آنکه آداپتور بهترتیب بهصراحت
charts: trueیاtables: trueرا اعلام کند. - وقتی آداپتور بتواند بار را رندر کند،
renderPresentationرا فراخوانی میکند. - وقتی آداپتور موجود نباشد یا نتواند رندر کند، به متن محافظهکارانه برمیگردد.
- بار حاصل را از مسیر عادی تحویل کانال ارسال میکند.
- فراداده تحویل مانند
delivery.pinرا پس از نخستین پیام ارسالی موفق اعمال میکند.
قیفهای محلی پاسخ یا پیشنمایش کانال که مستقیماً ReplyPayload را مصرف میکنند،
باید یا وارد آن مسیر معیار شوند یا پیش از تبدیل بار به متن ساده/رسانه،
همان جایگزین ارائه را ایجاد کنند.
هسته مالک رفتار جایگزین است تا تولیدکنندگان بتوانند مستقل از کانال باقی بمانند. Pluginهای کانال مالک رندر بومی و مدیریت تعامل هستند.
قواعد تنزل
ارسال ارائه باید در کانالهای محدود ایمن باشد.
متن جایگزین شامل موارد زیر است:
titleبهعنوان خط نخست- بلوکهای
textبهصورت بندهای عادی - بلوکهای
contextبهصورت خطوط زمینهای فشرده - بلوکهای
dividerبهصورت جداکننده بصری - برچسبهای دکمه، شامل URLها برای دکمههای پیوند
- برچسبهای گزینههای انتخاب
- عنوان، نوع، محورها، دستهها، سریها و مقادیر نمودار
- عنوان جدول، سرستونها و مقدار هر ردیف
نمایانبودن مقدار جایگزین دکمه
وقتی کانالی نتواند کنترلهای تعاملی را رندر کند، مقادیر دکمه و انتخاب به متن ساده تبدیل میشوند. رفتار جایگزین ضمن خصوصی نگهداشتن دادههای مبهم فراخوان، کاربردپذیری را حفظ میکند:
- کنشهای دارای نوع
commandبهصورتlabel: `command`رندر میشوند تا کاربران بتوانند فرمان را کپی کرده و بهصورت دستی در ورودی کانال اجرا کنند. - کنشهای دارای نوع
callbackو فیلدهای قدیمیvalueفقط با برچسب رندر میشوند. مقدار مبهم فراخوان در متن جایگزین افشا نمیشود. - کنشهای دارای نوع
approvalفقط با برچسب رندر میشوند. شناسهها و تصمیمهای تأیید دادههای انتقال هستند و از طریق ابزارهای کمکی اسکالر عمومی یا متن جایگزین افشا نمیشوند. - کنشهای
url، کنشهایweb-appدارای URL و ورودیهای منسوخurl/webApp/web_app، متن URL را در کنار برچسب دکمه رندر میکنند، زیرا URL برای کاربر قابلمشاهده است. کنشهایی که فقط برای ویجت میزبانیشده هستند، در کانالهای فاقد راهاندازی بومی ویجت فقط با برچسب رندر میشوند. - گزینههای انتخاب فقط با برچسب رندر میشوند. مقدار زیربنایی گزینه در متن جایگزین افشا نمیشود.
آداپتورهای کانالی که راهنمای فرمان دستی را به رابط کاربری جایگزین خود اضافه میکنند (برای مثال دستورالعملهای نظر سند Feishu)، باید بررسی وجود فرمان را از همان بلوکهای ارائهای استخراج کنند که رندرکننده جایگزین استفاده میکند، تا متن راهنما فقط زمانی ظاهر شود که واقعاً یک فرمان دستی نمایش داده میشود.
کنترلهای بومی پشتیبانینشده باید تنزل یابند، نه اینکه کل ارسال را ناموفق کنند. مثالها:
- Telegram با دکمههای درونخطی غیرفعال، متن جایگزین ارسال میکند.
- کانالی بدون پشتیبانی از انتخاب، گزینههای انتخاب را بهصورت متن فهرست میکند.
- کانالی بدون پشتیبانی بومی از نمودار، دادههای نمودار را بهصورت متن فهرست میکند.
- کانالی بدون پشتیبانی بومی از جدول، همه ردیفهای جدول را بهصورت متن فهرست میکند.
- دکمهای که فقط URL دارد، به یک دکمه پیوند بومی یا یک خط URL جایگزین تبدیل میشود.
- شکستهای اختیاری سنجاقکردن باعث شکست پیام تحویلشده نمیشوند.
استثنای اصلی delivery.pin.required: true است؛ اگر سنجاقکردن بهعنوان
الزامی درخواست شود و کانال نتواند پیام ارسالشده را سنجاق کند، تحویل شکست را گزارش میکند.
نگاشت ارائهدهنده
رندرکنندههای بستهبندیشده فعلی:
| کانال | مقصد رندر بومی | یادداشتها |
|---|---|---|
| Discord | مؤلفهها و محفظههای مؤلفه | برای تولیدکنندگان موجود بار بومی ارائهدهنده، channelData.discord.components قدیمی را حفظ میکند، اما ارسالهای اشتراکی جدید باید از presentation استفاده کنند. |
| Feishu | کارتهای تعاملی | سربرگ کارت میتواند از title استفاده کند؛ بدنه از تکرار آن عنوان جلوگیری میکند. |
| Matrix | متن جایگزین بههمراه فیلد ساختیافته رویداد | دکمهها/انتخابها بهعنوان پشتیبانیشده اعلام میشوند، اما در حال حاضر هر بلوک بهصورت خروجی renderMessagePresentationFallbackText که در فیلد رویداد com.openclaw.presentation حمل میشود رندر میگردد، نه ویجتهای تعاملی بومی. |
| Mattermost | متن بههمراه ویژگیهای تعاملی | انتخابها و جداکنندهها پشتیبانی نمیشوند؛ آن بلوکها به متن تنزل مییابند. |
| Microsoft Teams | کارتهای تطبیقی | وقتی هر دو ارائه شوند، متن ساده message همراه کارت گنجانده میشود. انتخابها، سبکها و وضعیت غیرفعال پشتیبانی نمیشوند. |
| Slack | Block Kit | chart را بهصورت data_visualization بومی و table را بهصورت data_table بومی رندر میکند؛ channelData.slack.blocks قدیمی را حفظ میکند، اما ارسالهای اشتراکی جدید باید از presentation استفاده کنند. |
| Telegram | متن بههمراه صفحهکلیدهای درونخطی | دکمهها/انتخابها برای سطح مقصد به قابلیت دکمه درونخطی نیاز دارند؛ در غیر این صورت از متن جایگزین استفاده میشود. |
| کانالهای ساده | متن جایگزین | کانالهای بدون رندرکننده همچنان خروجی خوانا دریافت میکنند. |
سازگاری بار بومی ارائهدهنده، یک امکان گذار برای تولیدکنندگان موجود پاسخ است. این دلیلی برای افزودن فیلدهای بومی اشتراکی جدید نیست.
ارائه در برابر InteractiveReply
InteractiveReply زیرمجموعه داخلی قدیمیتری است که ابزارهای کمکی تأیید و تعامل
از آن استفاده میکنند. این موارد را پشتیبانی میکند:
- متن
- دکمهها
- انتخابها
MessagePresentation قرارداد معیار ارسال اشتراکی است. این موارد را اضافه میکند:
- عنوان
- لحن
- زمینه
- جداکننده
- نمودار
- جدول
- دکمههایی که فقط URL دارند
- فراداده عمومی تحویل از طریق
ReplyPayload.delivery
هنگام اتصال کد قدیمیتر، از ابزارهای کمکی
openclaw/plugin-sdk/interactive-runtime استفاده کنید:
adaptMessagePresentationForChannel, applyPresentationActionLimits, hasMessagePresentationBlocks, interactiveReplyToPresentation, isMessagePresentationInteractiveBlock, normalizeMessagePresentation, presentationPageSize, presentationToInteractiveControlsReply, presentationToInteractiveReply, renderMessagePresentationChartFallbackText, renderMessagePresentationFallbackText, renderMessagePresentationTableFallbackText, resolveMessagePresentationActionValue, resolveMessagePresentationButtonAction, resolveMessagePresentationControlValue, resolveMessagePresentationOptionAction,} from "openclaw/plugin-sdk/interactive-runtime";کد جدید باید مستقیماً MessagePresentation را بپذیرد یا تولید کند. بارهای موجود
interactive زیرمجموعهای منسوخ از presentation هستند؛ پشتیبانی زمان اجرا
برای تولیدکنندگان قدیمیتر باقی میماند.
ابزارهای کمکی منسوخنشدهای که دانستنشان مفید است:
normalizeMessagePresentation(raw)/hasMessagePresentationBlocks(value)یک payload بدون نوع را (برای مثال، JSON دریافتی از پرچم--presentationدر CLI) اعتبارسنجی و بهMessagePresentationتبدیل میکنند.isMessagePresentationInteractiveBlock(block)یک بلوک را به اجتماعbuttons|selectمحدود میکند.resolveMessagePresentationButtonAction(button)وresolveMessagePresentationOptionAction(option)ضمن پذیرش فیلدهای مرزی منسوخشده، کنش نوعدار متعارف را برمیگردانند.actionصریح همیشه اولویت دارد.resolveMessagePresentationActionValue(action)/resolveMessagePresentationControlValue(control)فقط مقادیر اسکالر فرمان/فراخوانی بازگشتی را میخوانند. یک کنش متعارف غیراسکالر هرگز بهvalueسایهای قدیمی منتقل نمیشود؛ بنابراین شناسههای تأیید و مقصدهای پیوند نوعدار باقی میمانند.renderMessagePresentationChartFallbackText(block)/renderMessagePresentationTableFallbackText(block)یک بلوک دادهٔ ساختیافته را برای مسیرهای جایگزین مختص کانال، بهصورت متن قطعی رندر میکنند.
نوعهای قدیمی InteractiveReply* و توابع کمکی تبدیل در SDK با
@deprecated علامتگذاری شدهاند:
InteractiveReply،InteractiveReplyBlock،InteractiveReplyButtonوInteractiveReplyOptionnormalizeInteractiveReply(...)hasInteractiveReplyBlocks(...)interactiveReplyToPresentation(...)presentationToInteractiveReply(...)presentationToInteractiveControlsReply(...)resolveInteractiveTextFallback(...)reduceInteractiveReply(...)
presentationToInteractiveReply(...) و
presentationToInteractiveControlsReply(...) همچنان بهعنوان پلهای رندرکننده
برای پیادهسازیهای قدیمی کانال در دسترس هستند. کد تولیدکنندهٔ جدید نباید آنها را
فراخوانی کند؛ presentation را ارسال کنید و اجازه دهید سازگارسازی هسته/کانال رندر را مدیریت کند.
توابع کمکی تأیید نیز جایگزینهایی با اولویت ارائه دارند:
- بهجای
buildApprovalInteractiveReply(...)ازbuildApprovalPresentation(...)استفاده کنید - بهجای
buildExecApprovalInteractiveReply(...)ازbuildExecApprovalPresentation(...)استفاده کنید
این سازندههای منتشرشده برای سازگاری Plugin همچنان مبتنی بر فرمان باقی میمانند. کد Gateway
و کانالهای همراه که مالک یک نوع تأیید ماندگار است، باید از
buildTypedApprovalPresentation(...)،
buildTypedExecApprovalPendingReplyPayload(...) یا
buildTypedPluginApprovalPendingReplyPayload(...) استفاده کند تا انتقالدهندهها بهجای استنباط معنا از متن /approve،
یک کنش صریح approval دریافت کنند.
renderMessagePresentationFallbackText(...) برای بلوکهای ارائهای
که جایگزین متنی ندارند، مانند ارائهای که فقط شامل جداکننده است، رشتهای خالی برمیگرداند.
انتقالدهندههایی که به بدنهٔ ارسال غیرخالی نیاز دارند میتوانند
emptyFallback را برای استفاده از بدنهای حداقلی ارسال کنند، بدون اینکه قرارداد پیشفرض
جایگزین را تغییر دهند.
سنجاقکردن تحویل
سنجاقکردن یک رفتار تحویل است، نه ارائه. بهجای فیلدهای بومی ارائهدهنده مانند
channelData.telegram.pin از delivery.pin استفاده کنید.
معناشناسی:
pin: trueنخستین پیام با تحویل موفق را سنجاق میکند.- مقدار پیشفرض
pin.notifyبرابرfalseاست. - مقدار پیشفرض
pin.requiredبرابرfalseاست. - شکستهای اختیاری سنجاقکردن با افت عملکرد ادامه مییابند و پیام ارسالشده را دستنخورده باقی میگذارند.
- شکستهای الزامی سنجاقکردن باعث شکست تحویل میشوند.
- در پیامهای تکهبندیشده، نخستین تکهٔ تحویلشده سنجاق میشود، نه تکهٔ انتهایی.
کنشهای دستی پیام pin، unpin و pins همچنان برای پیامهای
موجودی که ارائهدهنده از این عملیات پشتیبانی میکند، وجود دارند.
چکلیست نویسندهٔ Plugin
- وقتی کانال میتواند ارائهٔ معنایی را رندر کند یا بهشکلی امن تنزل دهد،
presentationرا ازdescribeMessageTool(...)اعلام کنید. presentationCapabilitiesرا به آداپتور خروجی زمان اجرا اضافه کنید.renderPresentationرا در کد زمان اجرا پیادهسازی کنید، نه در کد راهاندازی Plugin صفحهٔ کنترل.- کتابخانههای رابط کاربری بومی را از مسیرهای داغ راهاندازی/کاتالوگ خارج نگه دارید.
- وقتی محدودیتهای عمومی قابلیت مشخص هستند، آنها را در
presentationCapabilities.limitsاعلام کنید. - محدودیتهای نهایی پلتفرم را در رندرکننده و آزمونها حفظ کنید.
- برای نمودارها، جدولها، دکمهها، گزینههای انتخاب، دکمههای URL،
تکرار عنوان/متن و ارسالهای ترکیبی
messageبههمراهpresentationکه پشتیبانی نمیشوند، آزمونهای جایگزین اضافه کنید. - فقط زمانی پشتیبانی از سنجاقکردن تحویل را از طریق
deliveryCapabilities.pinوpinDeliveredMessageاضافه کنید که ارائهدهنده بتواند شناسهٔ پیام ارسالشده را سنجاق کند. - فیلدهای جدید کارت/بلوک/مؤلفه/دکمهٔ بومی ارائهدهنده را از طریق طرحوارهٔ مشترک کنش پیام در معرض دسترس قرار ندهید.