Plugin maintainer reference
संदेश प्रस्तुति
संदेश प्रस्तुति समृद्ध आउटबाउंड चैट UI के लिए OpenClaw का साझा अनुबंध है। यह एजेंटों, CLI कमांड, अनुमोदन प्रवाहों, और plugins को संदेश का इरादा एक बार बताने देता है, जबकि प्रत्येक channel plugin अपनी क्षमता के अनुसार सबसे अच्छा मूल रूप रेंडर करता है।
पोर्टेबल संदेश UI के लिए presentation का उपयोग करें:
- टेक्स्ट सेक्शन
- छोटा context/footer टेक्स्ट
- विभाजक
- बटन
- चयन मेनू
- कार्ड शीर्षक और टोन
साझा
message tool में Discord components, Slack
blocks, Telegram buttons, Teams card, या Feishu card जैसे नए provider-native फ़ील्ड न जोड़ें। ये channel plugin के स्वामित्व वाले renderer outputs हैं।
अनुबंध
Plugin लेखक public contract यहां से import करते हैं:
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 MessagePresentationAction = | { type: "command"; command: string } | { type: "callback"; value: string }; type MessagePresentationButton = { label: string; action?: MessagePresentationAction; /** Legacy callback value. Prefer action for new controls. */ value?: string; url?: string; webApp?: { url: string }; /** @deprecated Use webApp. Accepted for legacy JSON payloads only. */ web_app?: { url: string }; priority?: number; disabled?: boolean; reusable?: boolean; style?: "primary" | "secondary" | "success" | "danger";}; type MessagePresentationOption = { label: string; action?: MessagePresentationAction; /** Legacy callback value. Prefer action for new controls. */ value?: string;}; type ReplyPayloadDelivery = { pin?: | boolean | { enabled: boolean; notify?: boolean; required?: boolean; };};बटन semantics:
action.type: "command"core के command path के माध्यम से native slash command चलाता है। इसे built-in command buttons और menus के लिए उपयोग करें।action.type: "callback"channel के interaction path के माध्यम से opaque plugin data ले जाता है। Channel plugins को callback data को slash commands के रूप में फिर से व्याख्यायित नहीं करना चाहिए।valuelegacy opaque callback value है। नए controls कोactionका उपयोग करना चाहिए ताकि channel plugins text से अनुमान लगाए बिना commands और callbacks को map कर सकें।urlएक link button है। यहvalueके बिना मौजूद हो सकता है।webAppchannel-native web app button का वर्णन करता है। Telegram इसेweb_appके रूप में render करता है और इसे केवल private chats में support करता है।web_appcompatibility के लिए loose JSON payloads में अब भी accepted है, लेकिन TypeScript producers कोwebAppका उपयोग करना चाहिए।labelrequired है और text fallback में भी उपयोग होता है।styleadvisory है। Renderers को unsupported styles को safe default में map करना चाहिए, send को fail नहीं करना चाहिए।priorityoptional है। जब कोई channel action limits advertise करता है और controls drop करने पड़ते हैं, core higher-priority buttons को पहले रखता है और समान priority buttons के बीच original order सुरक्षित रखता है। जब सभी controls fit होते हैं, authored order सुरक्षित रहता है।disabledoptional है। Channels कोsupportsDisabledके साथ opt in करना होगा; अन्यथा core disabled control को non-interactive fallback text में degrade करता है।reusableoptional है। वे channels जो reusable native callbacks support करते हैं, successful interaction के बाद action को available रख सकते हैं। इसे refresh, inspect, या more details जैसी repeatable या idempotent actions के लिए उपयोग करें; normal one-shot approvals और destructive actions के लिए इसे unset छोड़ें।
Select semantics:
options[].actionका वही command/callback अर्थ है जो buttonactionका है।options[].valuelegacy selected application value है।placeholderadvisory है और native select support के बिना channels द्वारा ignore किया जा सकता है।- यदि कोई channel selects support नहीं करता, fallback text labels को list करता है।
Producer examples
सरल कार्ड:
{ "title": "Deploy approval", "tone": "warning", "blocks": [ { "type": "text", "text": "Canary is ready to promote." }, { "type": "context", "text": "Build 1234, staging passed." }, { "type": "buttons", "buttons": [ { "label": "Approve", "value": "deploy:approve", "style": "success" }, { "label": "Decline", "value": "deploy:decline", "style": "danger" } ] } ]}केवल-URL link button:
{ "blocks": [ { "type": "text", "text": "Release notes are ready." }, { "type": "buttons", "buttons": [{ "label": "Open notes", "url": "https://example.com/release" }] } ]}Telegram Mini App button:
{ "blocks": [ { "type": "buttons", "buttons": [{ "label": "Launch", "web_app": { "url": "https://example.com/app" } }] } ]}Select menu:
{ "title": "Choose environment", "blocks": [ { "type": "select", "placeholder": "Environment", "options": [ { "label": "Canary", "value": "env:canary" }, { "label": "Production", "value": "env:prod" } ] } ]}CLI send:
openclaw message send --channel slack \ --target channel:C123 \ --message "Deploy approval" \ --presentation '{"title":"Deploy approval","tone":"warning","blocks":[{"type":"text","text":"Canary is ready."},{"type":"buttons","buttons":[{"label":"Approve","value":"deploy:approve","style":"success"},{"label":"Decline","value":"deploy:decline","style":"danger"}]}]}'Pinned delivery:
openclaw message send --channel telegram \ --target -1001234567890 \ --message "Topic opened" \ --pinस्पष्ट JSON के साथ pinned delivery:
{ "pin": { "enabled": true, "notify": true, "required": false }}Renderer contract
Channel plugins अपने outbound adapter पर render support declare करते हैं:
const adapter: ChannelOutboundAdapter = { deliveryMode: "direct", presentationCapabilities: { supported: true, buttons: true, selects: true, context: true, divider: true, 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 }); },};Capability booleans बताते हैं कि renderer क्या interactive बना सकता है। Optional
limits generic envelope का वर्णन करते हैं जिसे core
renderer को call करने से पहले adapt कर सकता है:
type ChannelPresentationCapabilities = { supported?: boolean; buttons?: boolean; selects?: boolean; context?: boolean; divider?: 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; }; };};Core rendering से पहले semantic controls पर generic limits लागू करता है। Renderers अब भी native block count, card size, URL limits, और generic contract में व्यक्त न किए जा सकने वाले provider quirks के लिए अंतिम provider-specific validation और clipping के owner हैं। यदि limits किसी block से हर control हटा दें, तो core labels को non-interactive context text के रूप में रखता है ताकि delivered message में अब भी visible fallback हो।
Core render flow
जब किसी ReplyPayload या message action में presentation शामिल होता है, core:
- presentation payload को normalize करता है।
- target channel के outbound adapter को resolve करता है।
presentationCapabilitiesपढ़ता है।- जब adapter उन्हें advertise करता है, तो action count, label length, और select option count जैसी generic capability limits लागू करता है।
- जब adapter payload render कर सकता है, तो
renderPresentationcall करता है। - adapter absent होने या render न कर सकने पर conservative text पर fallback करता है।
- resulting payload को normal channel delivery path के माध्यम से भेजता है।
- पहले successful
sent message के बाद
delivery.pinजैसे delivery metadata लागू करता है।
Core fallback behavior own करता है ताकि producers channel-agnostic रह सकें। Channel plugins native rendering और interaction handling own करते हैं।
Degradation rules
Presentation limited channels पर send करने के लिए safe होनी चाहिए।
Fallback text में शामिल है:
- पहली line के रूप में
title - normal paragraphs के रूप में
textblocks - compact context lines के रूप में
contextblocks - visual separator के रूप में
dividerblocks - link buttons के लिए URLs सहित button labels
- select option labels
Button value fallback visibility
जब कोई channel interactive controls render नहीं कर सकता, button और select values plain text पर fallback करते हैं। fallback behavior usability सुरक्षित रखता है जबकि opaque callback data private रखता है:
command-typed actionslabel: \command`` के रूप में render होते हैं ताकि users command copy करके channel input में manually run कर सकें।callback-typed actions और legacyvaluefields label-only के रूप में render होते हैं। opaque callback value fallback text में exposed नहीं होती।url/webAppbuttons button label के साथ URL text render करते हैं, क्योंकि URL user-facing है।- Select options label-only के रूप में render होते हैं। underlying option value fallback text में exposed नहीं होती।
Channel adapters जो अपने fallback UI में manual-command guidance जोड़ते हैं (उदा. Feishu document-comment instructions) उन्हें command-present check उसी presentation blocks से derive करना चाहिए जिन्हें fallback renderer उपयोग करता है, ताकि guidance text केवल तब दिखाई दे जब manual command वास्तव में दिखाई गई हो।
Unsupported native controls को पूरे send को fail करने के बजाय degrade करना चाहिए। उदाहरण:
- inline buttons disabled होने पर Telegram text fallback भेजता है।
- select support के बिना channel select options को text के रूप में list करता है।
- URL-only button या तो native link button बनता है या fallback URL line।
- Optional pin failures delivered message को fail नहीं करते।
मुख्य exception delivery.pin.required: true है; यदि pinning required के रूप में requested है
और channel sent message को pin नहीं कर सकता, तो delivery failure report करती है।
Provider mapping
वर्तमान bundled renderers:
| चैनल | नेटिव रेंडर लक्ष्य | नोट्स |
|---|---|---|
| Discord | घटक और घटक कंटेनर | मौजूदा प्रदाता-नेटिव पेलोड उत्पादकों के लिए पुराने channelData.discord.components को सुरक्षित रखता है, लेकिन नए साझा भेजावों को presentation का उपयोग करना चाहिए। |
| Slack | Block Kit | मौजूदा प्रदाता-नेटिव पेलोड उत्पादकों के लिए पुराने channelData.slack.blocks को सुरक्षित रखता है, लेकिन नए साझा भेजावों को presentation का उपयोग करना चाहिए। |
| Telegram | टेक्स्ट और इनलाइन कीबोर्ड | बटन/चयन के लिए लक्ष्य सतह पर इनलाइन बटन क्षमता चाहिए; अन्यथा टेक्स्ट फ़ॉलबैक उपयोग किया जाता है। |
| Mattermost | टेक्स्ट और इंटरैक्टिव प्रॉप्स | अन्य ब्लॉक टेक्स्ट में घट जाते हैं। |
| Microsoft Teams | Adaptive Cards | जब दोनों दिए जाते हैं, तो सादा message टेक्स्ट कार्ड के साथ शामिल किया जाता है। |
| Feishu | इंटरैक्टिव कार्ड | कार्ड हेडर title का उपयोग कर सकता है; बॉडी उस शीर्षक की पुनरावृत्ति से बचती है। |
| सादे चैनल | टेक्स्ट फ़ॉलबैक | बिना रेंडरर वाले चैनलों को भी पढ़ने योग्य आउटपुट मिलता है। |
प्रदाता-नेटिव पेलोड संगतता मौजूदा जवाब उत्पादकों के लिए एक संक्रमण सुविधा है। यह नए साझा नेटिव फ़ील्ड जोड़ने का कारण नहीं है।
प्रस्तुति बनाम InteractiveReply
InteractiveReply स्वीकृति और इंटरैक्शन हेल्परों द्वारा उपयोग किया जाने वाला पुराना आंतरिक उपसमूह है।
यह समर्थन करता है:
- टेक्स्ट
- बटन
- चयन
MessagePresentation कैननिकल साझा भेजाव अनुबंध है। यह जोड़ता है:
- शीर्षक
- टोन
- संदर्भ
- विभाजक
- केवल-URL बटन
ReplyPayload.deliveryके माध्यम से सामान्य डिलीवरी मेटाडेटा
पुराने कोड को ब्रिज करते समय openclaw/plugin-sdk/interactive-runtime से हेल्पर उपयोग करें:
OC_I18N_900011
नए कोड को सीधे MessagePresentation स्वीकार या उत्पन्न करना चाहिए। मौजूदा
interactive पेलोड presentation का अप्रचलित उपसमूह हैं; पुराने उत्पादकों के लिए रनटाइम
समर्थन बना रहता है।
पुराने InteractiveReply* प्रकार और रूपांतरण हेल्पर SDK में
@deprecated चिह्नित हैं:
InteractiveReply,InteractiveReplyBlock,InteractiveReplyButton,InteractiveReplyOption,InteractiveReplySelectBlock, औरInteractiveReplyTextBlocknormalizeInteractiveReply(...)hasInteractiveReplyBlocks(...)interactiveReplyToPresentation(...)presentationToInteractiveReply(...)presentationToInteractiveControlsReply(...)resolveInteractiveTextFallback(...)reduceInteractiveReply(...)
presentationToInteractiveReply(...) और
presentationToInteractiveControlsReply(...) पुराने चैनल कार्यान्वयनों के लिए रेंडरर
ब्रिज के रूप में उपलब्ध रहते हैं। नए उत्पादक कोड को उन्हें कॉल नहीं करना चाहिए;
presentation भेजें और कोर/चैनल अनुकूलन को रेंडरिंग संभालने दें।
स्वीकृति हेल्परों के लिए भी प्रस्तुति-प्रथम प्रतिस्थापन हैं:
buildApprovalInteractiveReplyFromActionDescriptors(...)के बजायbuildApprovalPresentationFromActionDescriptors(...)का उपयोग करेंbuildApprovalInteractiveReply(...)के बजायbuildApprovalPresentation(...)का उपयोग करेंbuildExecApprovalInteractiveReply(...)के बजायbuildExecApprovalPresentation(...)का उपयोग करें
renderMessagePresentationFallbackText(...) उन प्रस्तुति ब्लॉकों के लिए खाली स्ट्रिंग लौटाता है
जिनका कोई टेक्स्ट फ़ॉलबैक नहीं है, जैसे केवल-विभाजक
प्रस्तुति। जिन ट्रांसपोर्ट को गैर-खाली भेजाव बॉडी चाहिए वे डिफ़ॉल्ट फ़ॉलबैक
अनुबंध बदले बिना न्यूनतम बॉडी चुनने के लिए emptyFallback पास कर सकते हैं।
डिलीवरी पिन
पिन करना डिलीवरी व्यवहार है, प्रस्तुति नहीं। channelData.telegram.pin जैसे
प्रदाता-नेटिव फ़ील्ड के बजाय delivery.pin का उपयोग करें।
अर्थ:
pin: trueपहले सफलतापूर्वक डिलीवर हुए संदेश को पिन करता है।pin.notifyका डिफ़ॉल्टfalseहै।pin.requiredका डिफ़ॉल्टfalseहै।- वैकल्पिक पिन विफलताएं घट जाती हैं और भेजे गए संदेश को जस का तस छोड़ती हैं।
- आवश्यक पिन विफलताएं डिलीवरी को विफल करती हैं।
- खंडित संदेश पहले डिलीवर हुए खंड को पिन करते हैं, अंतिम खंड को नहीं।
मैन्युअल pin, unpin, और pins संदेश कार्रवाइयां मौजूदा
संदेशों के लिए अब भी मौजूद हैं, जहां प्रदाता उन ऑपरेशनों का समर्थन करता है।
Plugin लेखक चेकलिस्ट
- जब चैनल सेमांटिक प्रस्तुति को रेंडर या सुरक्षित रूप से घटा सकता हो, तो
describeMessageTool(...)सेpresentationघोषित करें। - रनटाइम आउटबाउंड अडैप्टर में
presentationCapabilitiesजोड़ें। - रनटाइम कोड में
renderPresentationलागू करें, कंट्रोल-प्लेन Plugin सेटअप कोड में नहीं। - नेटिव UI लाइब्रेरियों को हॉट सेटअप/कैटलॉग पथों से बाहर रखें।
- ज्ञात होने पर
presentationCapabilities.limitsपर सामान्य क्षमता सीमाएं घोषित करें। - रेंडरर और परीक्षणों में अंतिम प्लेटफ़ॉर्म सीमाएं सुरक्षित रखें।
- असमर्थित बटनों, चयनों, URL बटनों, शीर्षक/टेक्स्ट
पुनरावृत्ति, और मिश्रित
messageतथाpresentationभेजावों के लिए फ़ॉलबैक परीक्षण जोड़ें। deliveryCapabilities.pinऔरpinDeliveredMessageके माध्यम से डिलीवरी पिन समर्थन केवल तब जोड़ें जब प्रदाता भेजे गए संदेश id को पिन कर सकता हो।- साझा संदेश कार्रवाई स्कीमा के माध्यम से नए प्रदाता-नेटिव कार्ड/ब्लॉक/घटक/बटन फ़ील्ड उजागर न करें।