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: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.
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.
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.
-
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:
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:Kontrak perender
Plugin saluran mendeklarasikan dukungan perenderan pada adaptor keluarannya:limits opsional menjelaskan amplop generik yang dapat diadaptasi oleh inti sebelum memanggil
perender:
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.
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.
- 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.
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:
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
openclaw/plugin-sdk/interactive-runtime saat menjembatani kode
lama:
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.
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(...)
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. Gunakandelivery.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.
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.