Plugin maintainer reference
Presentasi pesan
Presentasi pesan adalah kontrak bersama OpenClaw untuk UI obrolan keluar yang kaya. Kontrak ini memungkinkan agen, perintah CLI, alur persetujuan, dan plugin mendeskripsikan maksud pesan satu kali, sementara setiap plugin saluran merender bentuk native terbaik yang mampu didukungnya.
Gunakan presentasi untuk UI pesan portabel: bagian teks, teks konteks/footer singkat, pemisah, bagan, tabel, tombol, menu pilihan, serta judul/nuansa kartu.
Jangan tambahkan bidang baru khusus native penyedia seperti Discord components, Slack
blocks, Telegram buttons, Teams card, atau Feishu card ke alat
pesan bersama. Bidang tersebut merupakan keluaran perender yang dimiliki oleh plugin saluran.
Kontrak
Pembuat plugin mengimpor kontrak publik dari:
MessagePresentation, ReplyPayloadDelivery,} from "openclaw/plugin-sdk/interactive-runtime";Struktur:
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; /** Nilai callback lama. Utamakan action untuk kontrol baru. */ value?: string; /** @deprecated Gunakan action dengan type "url". */ url?: string; /** @deprecated Gunakan action dengan type "web-app". */ webApp?: { url: string }; /** @deprecated Gunakan action dengan 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" }>; /** Nilai callback lama. Utamakan action untuk kontrol baru. */ value?: string;}; type ReplyPayloadDelivery = { pin?: | boolean | { enabled: boolean; notify?: boolean; required?: boolean; };};Semantik tombol:
action.type: "command"menjalankan perintah garis miring native melalui jalur perintah inti. Gunakan ini untuk tombol dan menu perintah bawaan.action.type: "callback"membawa data plugin opak melalui jalur interaksi saluran. Plugin saluran tidak boleh menafsirkan ulang data callback sebagai perintah garis miring.action.type: "approval"mengidentifikasi satu persetujuan operator persisten, jenis eksplisitexecatauplugin, dan keputusan yang diminta. Plugin saluran mengodekan tindakan tersebut menjadi callback privat transportasi dan menyelesaikannya melalui layanan persetujuan; plugin tidak boleh mengurai teks perintah/approveatau menyimpulkan jenis dari ID.action.type: "question"mengidentifikasi satu pilihan untuk pertanyaanask_useraktif yang dibuat saat runtime. Sepertiapproval, ini merupakan tindakan runtime OpenClaw; agen dan plugin tidak boleh membuat ID pertanyaan sendiri. Telegram, Discord, dan Slack memetakannya ke callback native privat transportasi dan menyelesaikan pilihan melalui Gateway. Ketika pertanyaan telah dijawab, kedaluwarsa, atau dibatalkan, saluran tersebut mengedit pesan yang dikirim, menghapus tindakannya, dan menambahkan status terminal. WhatsApp, Signal, dan iMessage merender hingga empat pilihan tunggal sebagai reaksi1️⃣hingga4️⃣. Bentuk pertanyaan lainnya diturunkan menjadi teks label, dan pengguna dapat menjawab dengan balasan teks biasa.action.type: "url"membuka tautan biasa.action.type: "web-app"meluncurkan aplikasi web native saluran. Tetapkanurluntuk aplikasi berbasis URL atauwidgetIduntuk widget yang dihosting OpenClaw dengan mekanisme peluncuran yang dimiliki saluran; setidaknya salah satunya wajib ada. Jika keduanya tersedia, saluran dapat mengutamakan peluncuran widget terhosting native dan menggunakan URL ketika mekanisme tersebut tidak tersedia.valueadalah nilai callback opak lama. Kontrol baru sebaiknya menggunakanactionagar plugin saluran dapat memetakan perintah dan callback tanpa menebak dari teks.url,webApp, danweb_apptetap diterima sebagai masukan batas yang tidak digunakan lagi. Penormal mempertahankan bidang-bidang ini agar perender dapat membedakan semantik lama yang telah dirilis dari tindakan bertipe eksplisit. Produsen baru sebaiknya menggunakanaction.labelwajib diisi dan juga digunakan dalam fallback teks.stylebersifat anjuran. Perender sebaiknya memetakan gaya yang tidak didukung ke nilai default yang aman, bukan menggagalkan pengiriman.prioritybersifat opsional. Ketika saluran mengiklankan batas tindakan dan kontrol harus dihapus, inti mempertahankan tombol berprioritas lebih tinggi terlebih dahulu dan mempertahankan urutan asli di antara tombol dengan prioritas yang sama. Ketika semua kontrol dapat dimuat, urutan yang dibuat dipertahankan.disabledbersifat opsional. Saluran harus mengaktifkannya dengansupportsDisabled; jika tidak, inti menurunkan kontrol yang dinonaktifkan menjadi teks fallback noninteraktif. Tombol yang dinonaktifkan selalu dirender sebagai label saja dalam teks fallback, bahkan jika membawa tindakancommand.reusablebersifat opsional. Saluran yang mendukung callback native yang dapat digunakan kembali dapat mempertahankan tindakan tersebut setelah interaksi berhasil. Gunakan untuk tindakan berulang atau idempoten seperti memuat ulang, memeriksa, atau melihat detail selengkapnya; biarkan tidak ditetapkan untuk persetujuan sekali pakai biasa dan tindakan destruktif.
Semantik pilihan:
options[].actionhanya menerimacommandataucallback; tindakan persetujuan dan tautan hanya untuk tombol.options[].valueadalah nilai aplikasi terpilih versi lama.placeholderbersifat anjuran dan dapat diabaikan oleh saluran tanpa dukungan pilihan native.- Jika saluran tidak mendukung pilihan, teks fallback mencantumkan labelnya.
Semantik bagan:
piememerlukan nilai segmen positif.bar,area, danlinemenggunakan satu larikcategoriesyang berurutan. Setiap seri menyediakan tepat satu nilai terbatas per kategori, dalam urutan yang sama.- Label kategori dan nama seri harus unik. Blok bagan yang tidak valid atau tidak lengkap dihapus selama normalisasi, bukan mengubah data secara diam-diam.
- Perenderan bagan native harus diaktifkan melalui
presentationCapabilities.charts. Saluran lain menerima judul bagan, sumbu, kategori, seri, dan nilai sebagai teks deterministik. Ini juga merupakan fallback aksesibilitas.
Semantik tabel:
-
captionadalah judul singkat yang wajib diisi.headersharus berisi setidaknya satu label kolom unik yang tidak kosong. -
rowsharus berisi setidaknya satu baris. Setiap baris harus memiliki tepat satu sel per header, dan setiap sel harus berupa string yang tidak kosong atau angka terbatas. -
rowHeaderColumnIndexadalah indeks opsional berbasis nol yang mengidentifikasi kolom yang sel-selnya harus diekspos sebagai header baris oleh perender native. -
Normalisasi tabel bersifat atomik. Keterangan, header, lebar baris, sel, atau indeks header baris yang tidak valid menyebabkan blok tabel dihapus, bukan memotong atau memperbaiki datanya.
-
Perenderan tabel native harus diaktifkan melalui
presentationCapabilities.tables. Saluran lain menerima keterangan dan setiap baris sebagai teks linear deterministik, dengan spasi internal diringkas:text Pipeline terbuka (tabel)- Akun: Acme; Tahap: Menang; ARR: 125000- Akun: Globex; Tahap: Peninjauan; ARR: 82000
Tidak ada diskriminator report terpisah. Susun laporan dari title,
tone, text, context, chart, table, dan blok tindakan. Dengan demikian, setiap
blok dapat dirender secara independen dan laporan lengkap memiliki fallback teks
deterministik yang sama.
Contoh produsen
Kartu sederhana:
{ "title": "Persetujuan deployment", "tone": "warning", "blocks": [ { "type": "text", "text": "Canary siap dipromosikan." }, { "type": "context", "text": "Build 1234, staging berhasil." }, { "type": "buttons", "buttons": [ { "label": "Setujui", "action": { "type": "callback", "value": "deploy:approve" }, "style": "success" }, { "label": "Tolak", "action": { "type": "callback", "value": "deploy:decline" }, "style": "danger" } ] } ]}Tombol tautan khusus URL:
{ "blocks": [ { "type": "text", "text": "Catatan rilis telah siap." }, { "type": "buttons", "buttons": [ { "label": "Buka catatan", "action": { "type": "url", "url": "https://example.com/release" } } ] } ]}Tombol Mini App Telegram:
{ "blocks": [ { "type": "buttons", "buttons": [ { "label": "Luncurkan", "action": { "type": "web-app", "url": "https://example.com/app" } } ] } ]}Menu pilihan:
{ "title": "Pilih lingkungan", "blocks": [ { "type": "select", "placeholder": "Lingkungan", "options": [ { "label": "Canary", "value": "env:canary" }, { "label": "Produksi", "value": "env:prod" } ] } ]}Bagan:
{ "blocks": [ { "type": "chart", "chartType": "line", "title": "Pendapatan triwulanan", "categories": ["T1", "T2", "T3"], "series": [ { "name": "Produk", "values": [120, 145, 138] }, { "name": "Layanan", "values": [80, 95, 104] } ], "xLabel": "Triwulan", "yLabel": "Pendapatan" } ]}Laporan tabel:
{ "title": "Laporan pipeline", "tone": "info", "blocks": [ { "type": "text", "text": "Peluang saat ini berdasarkan tahap." }, { "type": "table", "caption": "Pipeline terbuka", "headers": ["Akun", "Tahap", "ARR"], "rows": [ ["Acme", "Menang", 125000], ["Globex", "Peninjauan", 82000] ], "rowHeaderColumnIndex": 0 }, { "type": "context", "text": "Diperbarui dari snapshot CRM." } ]}Pengiriman CLI:
openclaw message send --channel slack \ --target channel:C123 \ --message "Persetujuan deployment" \ --presentation '{"title":"Persetujuan deployment","tone":"warning","blocks":[{"type":"text","text":"Canary siap."},{"type":"buttons","buttons":[{"label":"Setujui","value":"deploy:approve","style":"success"},{"label":"Tolak","value":"deploy:decline","style":"danger"}]}]}'Pengiriman yang disematkan:
openclaw message send --channel telegram \ --target -1001234567890 \ --message "Topik dibuka" \ --pinPengiriman yang disematkan dengan JSON eksplisit:
{ "pin": { "enabled": true, "notify": true, "required": false }}Kontrak perender
Plugin saluran mendeklarasikan dukungan perenderan pada adaptor keluarannya:
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 }); },};Boolean kapabilitas menjelaskan apa yang dapat dibuat interaktif oleh perender. limits opsional menjelaskan amplop generik yang dapat diadaptasi oleh inti sebelum memanggil
perender:
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; }; };};Inti menerapkan batas generik pada kontrol semantik sebelum perenderan. Perender tetap menangani validasi dan pemotongan akhir khusus penyedia untuk jumlah blok native, ukuran kartu, batas URL, dan kekhasan penyedia yang tidak dapat dinyatakan dalam kontrak generik. Jika batas menghapus semua kontrol dari sebuah blok, inti mempertahankan label sebagai teks konteks noninteraktif agar pesan yang dikirim tetap memiliki fallback yang terlihat.
Alur perenderan inti
Pada jalur keluar kanonis yang digunakan oleh CLI dan tindakan pesan standar, inti:
- Menormalisasi payload presentasi.
- Menentukan adaptor keluar saluran target.
- Membaca
presentationCapabilities. - Menerapkan batas kapabilitas generik seperti jumlah tindakan, panjang label, dan
jumlah opsi pilihan ketika adaptor mengiklankannya. Blok bagan dan tabel
menjadi teks deterministik kecuali adaptor secara eksplisit mengiklankan
charts: trueatautables: truemasing-masing. - Memanggil
renderPresentationketika adaptor dapat merender payload. - Menggunakan fallback teks konservatif ketika adaptor tidak tersedia atau tidak dapat merender.
- Mengirim payload yang dihasilkan melalui jalur pengiriman saluran normal.
- Menerapkan metadata pengiriman seperti
delivery.pinsetelah pesan terkirim pertama berhasil.
Saluran balasan atau pratinjau lokal saluran yang menggunakan ReplyPayload secara langsung
harus memasuki jalur kanonis tersebut atau mewujudkan fallback presentasi yang sama
sebelum memproyeksikan payload menjadi teks biasa/media.
Inti menangani perilaku fallback agar produsen dapat tetap agnostik terhadap saluran. Plugin saluran menangani perenderan native dan penanganan interaksi.
Aturan degradasi
Presentasi harus aman dikirim pada saluran dengan kemampuan terbatas.
Teks fallback mencakup:
titlesebagai baris pertama- Blok
textsebagai paragraf biasa - Blok
contextsebagai baris konteks ringkas - Blok
dividersebagai pemisah visual - label tombol, termasuk URL untuk tombol tautan
- label opsi pilihan
- judul, jenis, sumbu, kategori, seri, dan nilai bagan
- keterangan, header, dan setiap nilai baris tabel
Visibilitas fallback nilai tombol
Ketika saluran tidak dapat merender kontrol interaktif, nilai tombol dan pilihan menggunakan fallback teks biasa. Perilaku fallback mempertahankan kemudahan penggunaan sekaligus menjaga kerahasiaan data callback yang tidak transparan:
- Tindakan bertipe
commanddirender sebagailabel: `command`agar pengguna dapat menyalin perintah dan menjalankannya secara manual di input saluran. - Tindakan bertipe
callbackdan bidangvaluelama dirender hanya sebagai label. Nilai callback yang tidak transparan tidak ditampilkan dalam teks fallback. - Tindakan bertipe
approvaldirender hanya sebagai label. ID dan keputusan persetujuan merupakan data transportasi dan tidak ditampilkan melalui pembantu skalar generik atau teks fallback. - Tindakan
url, tindakanweb-appberbasis URL, dan inputurl/webApp/web_appyang tidak digunakan lagi merender teks URL bersama label tombol, karena URL ditujukan kepada pengguna. Tindakan khusus widget yang di-host dirender hanya sebagai label pada saluran tanpa peluncuran widget native. - Opsi pilihan dirender hanya sebagai label. Nilai opsi yang mendasarinya tidak ditampilkan dalam teks fallback.
Adaptor saluran yang menambahkan panduan perintah manual dalam UI fallback-nya (misalnya instruksi komentar dokumen Feishu) harus memperoleh pemeriksaan keberadaan perintah dari blok presentasi yang sama dengan yang digunakan perender fallback, agar teks panduan hanya muncul ketika perintah manual benar-benar ditampilkan.
Kontrol native yang tidak didukung seharusnya mengalami degradasi alih-alih menggagalkan seluruh pengiriman. Contoh:
- Telegram dengan tombol inline dinonaktifkan mengirim fallback teks.
- Saluran tanpa dukungan pilihan mencantumkan opsi pilihan sebagai teks.
- Saluran tanpa dukungan bagan native mencantumkan data bagan sebagai teks.
- Saluran tanpa dukungan tabel native mencantumkan setiap baris tabel sebagai teks.
- Tombol khusus URL menjadi tombol tautan native atau baris URL fallback.
- Kegagalan penyematan opsional tidak menggagalkan pesan yang dikirim.
Pengecualian utamanya adalah delivery.pin.required: true; jika penyematan diminta sebagai
wajib dan saluran tidak dapat menyematkan pesan terkirim, pengiriman melaporkan kegagalan.
Pemetaan penyedia
Perender bawaan saat ini:
| Saluran | Target perenderan native | Catatan |
|---|---|---|
| Discord | Komponen dan kontainer komponen | Mempertahankan channelData.discord.components lama untuk produsen payload native penyedia yang sudah ada, tetapi pengiriman bersama baru seharusnya menggunakan presentation. |
| Feishu | Kartu interaktif | Header kartu dapat menggunakan title; isi menghindari duplikasi judul tersebut. |
| Matrix | Fallback teks ditambah bidang peristiwa terstruktur | Tombol/pilihan diiklankan sebagai didukung, tetapi setiap blok saat ini dirender sebagai output renderMessagePresentationFallbackText yang dibawa dalam bidang peristiwa com.openclaw.presentation, bukan widget interaktif native. |
| Mattermost | Teks ditambah properti interaktif | Pilihan dan pemisah tidak didukung; blok tersebut didegradasi menjadi teks. |
| Microsoft Teams | Adaptive Cards | Teks message biasa disertakan bersama kartu ketika keduanya tersedia. Pilihan, gaya, dan status dinonaktifkan tidak didukung. |
| Slack | Block Kit | Merender chart sebagai data_visualization native dan table sebagai data_table native; mempertahankan channelData.slack.blocks lama, tetapi pengiriman bersama baru seharusnya menggunakan presentation. |
| Telegram | Teks ditambah papan ketik inline | Tombol/pilihan memerlukan kapabilitas tombol inline untuk permukaan target; jika tidak, fallback teks digunakan. |
| Saluran biasa | Fallback teks | Saluran tanpa perender tetap mendapatkan output yang mudah dibaca. |
Kompatibilitas payload native penyedia merupakan sarana transisi bagi produsen balasan yang sudah ada. Ini bukan alasan untuk menambahkan bidang native bersama yang baru.
Presentasi vs InteractiveReply
InteractiveReply adalah subset internal lama yang digunakan oleh pembantu persetujuan dan interaksi.
Subset ini mendukung:
- teks
- tombol
- pilihan
MessagePresentation adalah kontrak pengiriman bersama kanonis. Kontrak ini menambahkan:
- judul
- nada
- konteks
- pemisah
- bagan
- tabel
- tombol khusus URL
- metadata pengiriman generik melalui
ReplyPayload.delivery
Gunakan pembantu dari openclaw/plugin-sdk/interactive-runtime saat menjembatani kode
lama:
adaptMessagePresentationForChannel, applyPresentationActionLimits, hasMessagePresentationBlocks, interactiveReplyToPresentation, isMessagePresentationInteractiveBlock, normalizeMessagePresentation, presentationPageSize, presentationToInteractiveControlsReply, presentationToInteractiveReply, renderMessagePresentationChartFallbackText, renderMessagePresentationFallbackText, renderMessagePresentationTableFallbackText, resolveMessagePresentationActionValue, resolveMessagePresentationButtonAction, resolveMessagePresentationControlValue, resolveMessagePresentationOptionAction,} from "openclaw/plugin-sdk/interactive-runtime";Kode baru seharusnya menerima atau menghasilkan MessagePresentation secara langsung. Payload
interactive yang sudah ada adalah subset presentation yang tidak digunakan lagi; dukungan runtime
tetap tersedia bagi produsen lama.
Pembantu yang tidak dihentikan penggunaannya dan perlu diketahui:
normalizeMessagePresentation(raw)/hasMessagePresentationBlocks(value)memvalidasi dan mengonversi payload tanpa tipe (misalnya, JSON dari flag CLI--presentation) menjadiMessagePresentation.isMessagePresentationInteractiveBlock(block)mempersempit blok menjadi unionbuttons|select.resolveMessagePresentationButtonAction(button)danresolveMessagePresentationOptionAction(option)mengembalikan tindakan bertipe kanonis sekaligus menerima bidang batas yang tidak digunakan lagi.actionyang eksplisit selalu diutamakan.resolveMessagePresentationActionValue(action)/resolveMessagePresentationControlValue(control)hanya membaca nilai skalar perintah/callback. Tindakan kanonis non-skalar tidak pernah beralih ke bayangan lamavalue, sehingga ID persetujuan dan target tautan tetap bertipe.renderMessagePresentationChartFallbackText(block)/renderMessagePresentationTableFallbackText(block)merender satu blok data terstruktur sebagai teks deterministik untuk jalur fallback khusus saluran.
Tipe InteractiveReply* lama dan helper konversinya ditandai
@deprecated dalam SDK:
InteractiveReply,InteractiveReplyBlock,InteractiveReplyButton,InteractiveReplyOption,InteractiveReplySelectBlock, danInteractiveReplyTextBlocknormalizeInteractiveReply(...)hasInteractiveReplyBlocks(...)interactiveReplyToPresentation(...)presentationToInteractiveReply(...)presentationToInteractiveControlsReply(...)resolveInteractiveTextFallback(...)reduceInteractiveReply(...)
presentationToInteractiveReply(...) dan
presentationToInteractiveControlsReply(...) tetap tersedia sebagai jembatan
renderer untuk implementasi saluran lama. Kode produsen baru tidak boleh memanggilnya;
kirim presentation dan biarkan adaptasi inti/saluran menangani rendering.
Helper persetujuan juga memiliki pengganti yang mengutamakan presentasi:
- gunakan
buildApprovalPresentationFromActionDescriptors(...)sebagai penggantibuildApprovalInteractiveReplyFromActionDescriptors(...) - gunakan
buildApprovalPresentation(...)sebagai penggantibuildApprovalInteractiveReply(...) - gunakan
buildExecApprovalPresentation(...)sebagai penggantibuildExecApprovalInteractiveReply(...)
Builder yang telah dirilis tersebut tetap didukung perintah demi kompatibilitas plugin. Kode Gateway
dan saluran bawaan yang memiliki jenis persetujuan persisten harus menggunakan
buildTypedApprovalPresentation(...),
buildTypedExecApprovalPendingReplyPayload(...), atau
buildTypedPluginApprovalPendingReplyPayload(...) agar transport menerima
tindakan approval yang eksplisit alih-alih menyimpulkan semantik dari teks /approve.
renderMessagePresentationFallbackText(...) mengembalikan string kosong untuk
blok presentasi yang tidak memiliki fallback teks, seperti presentasi yang
hanya berisi pemisah. Transport yang memerlukan isi pengiriman tidak kosong dapat meneruskan
emptyFallback untuk memilih isi minimal tanpa mengubah kontrak fallback
bawaan.
Penyematan pengiriman
Penyematan adalah perilaku pengiriman, bukan presentasi. Gunakan delivery.pin sebagai pengganti
bidang native penyedia seperti channelData.telegram.pin.
Semantik:
pin: truemenyematkan pesan pertama yang berhasil dikirim.pin.notifysecara default bernilaifalse.pin.requiredsecara default bernilaifalse.- Kegagalan penyematan opsional mengalami degradasi dan membiarkan pesan terkirim tetap utuh.
- Kegagalan penyematan wajib menggagalkan pengiriman.
- Pesan yang dipecah menjadi beberapa bagian menyematkan bagian pertama yang terkirim, bukan bagian terakhir.
Tindakan pesan manual pin, unpin, dan pins tetap tersedia untuk pesan
yang sudah ada jika penyedia mendukung operasi tersebut.
Daftar periksa pembuat plugin
- Deklarasikan
presentationdaridescribeMessageTool(...)jika saluran dapat merender atau menurunkan kualitas presentasi semantik dengan aman. - Tambahkan
presentationCapabilitieske adaptor keluar runtime. - Implementasikan
renderPresentationdalam kode runtime, bukan kode penyiapan plugin bidang kontrol. - Jauhkan pustaka UI native dari jalur penyiapan/katalog yang sering digunakan.
- Deklarasikan batas kemampuan generik pada
presentationCapabilities.limitsjika diketahui. - Pertahankan batas akhir platform dalam renderer dan pengujian.
- Tambahkan pengujian fallback untuk bagan, tabel, tombol, pilihan, tombol URL
yang tidak didukung, duplikasi judul/teks, serta pengiriman campuran
messagedanpresentation. - Tambahkan dukungan penyematan pengiriman hanya melalui
deliveryCapabilities.pindanpinDeliveredMessagejika penyedia dapat menyematkan ID pesan yang dikirim. - Jangan mengekspos bidang kartu/blok/komponen/tombol native penyedia baru melalui skema tindakan pesan bersama.