Plugins
Internal arsitektur Plugin
Untuk model kemampuan publik, bentuk plugin, serta kontrak kepemilikan/eksekusi, lihat Arsitektur plugin. Halaman ini adalah referensi untuk mekanisme internal: pipeline pemuatan, registry, hook runtime, route HTTP Gateway, jalur impor, dan tabel skema.
Pipeline pemuatan
Saat startup, OpenClaw secara garis besar melakukan ini:
- menemukan root plugin kandidat
- membaca manifes bundle native atau kompatibel dan metadata paket
- menolak kandidat yang tidak aman
- menormalkan config plugin (
plugins.enabled,allow,deny,entries,slots,load.paths) - menentukan pengaktifan untuk setiap kandidat
- memuat modul native yang diaktifkan: modul bundel bawaan memakai loader native; sumber TypeScript lokal pihak ketiga memakai fallback Jiti darurat
- memanggil hook native
register(api)dan mengumpulkan registrasi ke registry plugin - mengekspos registry ke perintah/permukaan runtime
Gate keamanan terjadi sebelum eksekusi runtime. Kandidat diblokir ketika entri keluar dari root plugin, path dapat ditulis oleh semua pengguna, atau kepemilikan path terlihat mencurigakan untuk plugin non-bundel.
Kandidat yang diblokir tetap terikat ke id plugin mereka untuk diagnostik. Jika config masih merujuk id itu, validasi melaporkan plugin sebagai ada tetapi diblokir dan mengarah kembali ke peringatan keamanan path alih-alih memperlakukan entri config sebagai usang.
Perilaku berbasis manifes
Manifes adalah sumber kebenaran control-plane. OpenClaw menggunakannya untuk:
- mengidentifikasi plugin
- menemukan channel/skills/skema config yang dideklarasikan atau kemampuan bundle
- memvalidasi
plugins.entries.<id>.config - melengkapi label/placeholder Control UI
- menampilkan metadata instal/katalog
- mempertahankan deskriptor aktivasi dan setup yang murah tanpa memuat runtime plugin
Untuk plugin native, modul runtime adalah bagian data-plane. Modul ini mendaftarkan perilaku aktual seperti hook, tool, perintah, atau alur provider.
Blok manifes activation dan setup opsional tetap berada di control plane.
Keduanya adalah deskriptor metadata saja untuk perencanaan aktivasi dan penemuan setup;
keduanya tidak menggantikan registrasi runtime, register(...), atau setupEntry.
Konsumen aktivasi live pertama sekarang memakai petunjuk perintah, channel, dan provider dari manifes
untuk mempersempit pemuatan plugin sebelum materialisasi registry yang lebih luas:
- pemuatan CLI mempersempit ke plugin yang memiliki perintah utama yang diminta
- resolusi setup/plugin channel mempersempit ke plugin yang memiliki id channel yang diminta
- resolusi setup/runtime provider eksplisit mempersempit ke plugin yang memiliki id provider yang diminta
- perencanaan startup Gateway memakai
activation.onStartupuntuk impor startup eksplisit dan opt-out startup; plugin tanpa metadata startup hanya dimuat melalui pemicu aktivasi yang lebih sempit
Preload runtime pada waktu permintaan yang meminta cakupan luas all tetap menurunkan
set id plugin efektif eksplisit dari config, perencanaan startup, channel yang dikonfigurasi,
slot, dan aturan auto-enable. Jika set turunan itu kosong, OpenClaw
memuat registry runtime kosong alih-alih memperluas ke setiap plugin yang dapat ditemukan.
Planner aktivasi mengekspos API hanya-id untuk caller yang ada dan API
plan untuk diagnostik baru. Entri plan melaporkan alasan plugin dipilih,
memisahkan petunjuk planner activation.* eksplisit dari fallback kepemilikan manifes
seperti providers, channels, commandAliases, setup.providers,
contracts.tools, dan hook. Pemisahan alasan itu adalah batas kompatibilitas:
metadata plugin yang ada tetap berfungsi, sementara kode baru dapat mendeteksi petunjuk luas
atau perilaku fallback tanpa mengubah semantik pemuatan runtime.
Penemuan setup sekarang mengutamakan id milik deskriptor seperti setup.providers dan
setup.cliBackends untuk mempersempit plugin kandidat sebelum fallback ke
setup-api untuk plugin yang masih membutuhkan hook runtime saat setup. Daftar setup
provider memakai providerAuthChoices manifes, pilihan setup yang diturunkan dari deskriptor,
dan metadata katalog instal tanpa memuat runtime provider. setup.requiresRuntime: false
eksplisit adalah cutoff khusus deskriptor; requiresRuntime yang dihilangkan
mempertahankan fallback setup-api lama untuk kompatibilitas. Jika lebih dari satu
plugin yang ditemukan mengklaim id provider setup atau backend CLI yang dinormalkan sama,
lookup setup menolak owner yang ambigu alih-alih mengandalkan urutan penemuan. Saat runtime
setup benar-benar dijalankan, diagnostik registry melaporkan drift antara
setup.providers / setup.cliBackends dan provider atau backend CLI yang didaftarkan
oleh setup-api tanpa memblokir plugin lama.
Batas cache plugin
OpenClaw tidak melakukan cache hasil penemuan plugin atau data registry manifes langsung di balik jendela wall-clock. Instalasi, edit manifes, dan perubahan load-path harus terlihat pada pembacaan metadata eksplisit berikutnya atau rebuild snapshot. Parser file manifes dapat menyimpan cache tanda tangan file terbatas yang dikunci oleh path manifes yang dibuka, inode, ukuran, dan timestamp; cache itu hanya menghindari parsing ulang byte yang tidak berubah dan tidak boleh menyimpan jawaban penemuan, registry, owner, atau policy.
Fast path metadata yang aman adalah kepemilikan objek eksplisit, bukan cache tersembunyi.
Hot path startup Gateway harus meneruskan PluginMetadataSnapshot saat ini,
PluginLookUpTable turunan, atau registry manifes eksplisit melalui rantai panggilan.
Validasi config, auto-enable startup, bootstrap plugin, dan pemilihan provider
dapat memakai ulang objek tersebut selama objek itu mewakili config dan inventaris
plugin saat ini. Lookup setup tetap merekonstruksi metadata manifes sesuai kebutuhan
kecuali path setup spesifik menerima registry manifes eksplisit; pertahankan itu
sebagai fallback cold-path alih-alih menambahkan cache lookup tersembunyi. Ketika input
berubah, rebuild dan ganti snapshot alih-alih memutasinya atau menyimpan
salinan historis.
View atas registry plugin aktif dan helper bootstrap channel bundel
harus dihitung ulang dari registry/root saat ini. Map berumur pendek boleh digunakan
dalam satu panggilan untuk dedupe pekerjaan atau menjaga reentry; map tersebut tidak boleh menjadi
cache metadata proses.
Untuk pemuatan plugin, lapisan cache persisten adalah pemuatan runtime. Lapisan ini dapat memakai ulang state loader ketika kode atau artefak terinstal benar-benar dimuat, seperti:
PluginLoaderCacheStatedan registry runtime aktif yang kompatibel- cache jiti/modul dan cache loader permukaan publik yang digunakan untuk menghindari impor permukaan runtime yang sama berulang kali
- cache filesystem untuk artefak plugin terinstal
- map per-panggilan berumur pendek untuk normalisasi path atau resolusi duplikat
Cache tersebut adalah detail implementasi data-plane. Cache tersebut tidak boleh menjawab pertanyaan control-plane seperti "plugin mana yang memiliki provider ini?" kecuali caller sengaja meminta pemuatan runtime.
Jangan tambahkan cache persisten atau wall-clock untuk:
- hasil penemuan
- registry manifes langsung
- registry manifes yang direkonstruksi dari indeks plugin terinstal
- lookup owner provider, supresi model, policy provider, atau metadata artefak publik
- jawaban turunan manifes lain apa pun ketika manifes, indeks terinstal, atau load path yang berubah harus terlihat pada pembacaan metadata berikutnya
Caller yang membangun ulang metadata manifes dari indeks plugin terinstal yang dipersistenkan merekonstruksi registry tersebut sesuai kebutuhan. Indeks terinstal adalah state source-plane yang durable; itu bukan cache metadata dalam proses yang tersembunyi.
Model registry
Plugin yang dimuat tidak memutasi global core acak secara langsung. Plugin mendaftar ke registry plugin pusat.
Registry melacak:
- record plugin (identitas, sumber, asal, status, diagnostik)
- tool
- hook legacy dan hook bertipe
- channel
- provider
- handler RPC gateway
- route HTTP
- registrar CLI
- layanan latar belakang
- perintah milik plugin
Fitur core kemudian membaca dari registry itu alih-alih berbicara langsung dengan modul plugin. Ini menjaga pemuatan satu arah:
- modul plugin -> registrasi registry
- runtime core -> konsumsi registry
Pemisahan itu penting untuk kemudahan pemeliharaan. Artinya sebagian besar permukaan core hanya membutuhkan satu titik integrasi: "baca registry", bukan "perlakukan setiap modul plugin secara khusus".
Callback pengikatan percakapan
Plugin yang mengikat percakapan dapat bereaksi ketika approval diselesaikan.
Gunakan api.onConversationBindingResolved(...) untuk menerima callback setelah permintaan bind
disetujui atau ditolak:
export default {
id: "my-plugin",
register(api) {
api.onConversationBindingResolved(async (event) => {
if (event.status === "approved") {
// A binding now exists for this plugin + conversation.
console.log(event.binding?.conversationId);
return;
}
// The request was denied; clear any local pending state.
console.log(event.request.conversation.conversationId);
});
},
};
Field payload callback:
status:"approved"atau"denied"decision:"allow-once","allow-always", atau"deny"binding: binding yang diselesaikan untuk permintaan yang disetujuirequest: ringkasan permintaan asli, petunjuk detach, id pengirim, dan metadata percakapan
Callback ini hanya notifikasi. Callback ini tidak mengubah siapa yang diizinkan mengikat percakapan, dan berjalan setelah penanganan approval core selesai.
Hook runtime provider
Plugin provider memiliki tiga lapisan:
- Metadata manifes untuk lookup murah sebelum runtime:
setup.providers[].envVars, kompatibilitas lamaproviderAuthEnvVars,providerAuthAliases,providerAuthChoices, danchannelEnvVars. - Hook saat config:
catalog(discoverylegacy) plusapplyConfigDefaults. - Hook runtime: lebih dari 40 hook opsional yang mencakup auth, resolusi model, pembungkus stream, level thinking, policy replay, dan endpoint penggunaan. Lihat daftar lengkap di Urutan dan penggunaan hook.
OpenClaw tetap memiliki loop agent generik, failover, penanganan transkrip, dan policy tool. Hook ini adalah permukaan ekstensi untuk perilaku spesifik provider tanpa membutuhkan transport inferensi kustom utuh.
Gunakan setup.providers[].envVars manifes ketika provider memiliki kredensial berbasis env
yang harus terlihat oleh path auth/status/pemilih-model generik tanpa
memuat runtime plugin. providerAuthEnvVars yang deprecated masih dibaca oleh
adapter kompatibilitas selama jendela deprecation, dan plugin non-bundel
yang menggunakannya menerima diagnostik manifes. Gunakan providerAuthAliases manifes
ketika satu id provider harus memakai ulang env var, profil auth, auth berbasis config,
dan pilihan onboarding API-key milik id provider lain. Gunakan providerAuthChoices manifes
ketika permukaan CLI onboarding/pilihan-auth harus mengetahui id pilihan provider,
label grup, dan wiring auth satu-flag sederhana tanpa
memuat runtime provider. Pertahankan envVars runtime provider untuk petunjuk yang dihadapkan ke operator
seperti label onboarding atau var setup client-id/client-secret OAuth.
Gunakan channelEnvVars manifes ketika channel memiliki auth atau setup berbasis env yang
harus terlihat oleh fallback shell-env generik, pemeriksaan config/status, atau prompt setup
tanpa memuat runtime channel.
Urutan dan penggunaan hook
Untuk plugin model/provider, OpenClaw memanggil hook dalam urutan kasar ini.
Kolom "Kapan digunakan" adalah panduan keputusan cepat.
Field provider khusus kompatibilitas yang tidak lagi dipanggil OpenClaw, seperti
ProviderPlugin.capabilities dan suppressBuiltInModel, sengaja tidak
dicantumkan di sini.
| # | Hook | Fungsinya | Kapan digunakan |
|---|---|---|---|
| 1 | catalog |
Menerbitkan konfigurasi penyedia ke models.providers selama pembuatan models.json |
Penyedia memiliki katalog atau default URL dasar |
| 2 | applyConfigDefaults |
Menerapkan default konfigurasi global milik penyedia selama materialisasi konfigurasi | Default bergantung pada mode auth, env, atau semantik keluarga model penyedia |
| -- | (pencarian model bawaan) | OpenClaw mencoba jalur registry/katalog normal terlebih dahulu | (bukan hook Plugin) |
| 3 | normalizeModelId |
Menormalisasi alias model-id lawas atau pratinjau sebelum pencarian | Penyedia memiliki pembersihan alias sebelum resolusi model kanonis |
| 4 | normalizeTransport |
Menormalisasi api / baseUrl keluarga penyedia sebelum perakitan model generik |
Penyedia memiliki pembersihan transport untuk id penyedia kustom dalam keluarga transport yang sama |
| 5 | normalizeConfig |
Menormalisasi models.providers.<id> sebelum resolusi runtime/penyedia |
Penyedia memerlukan pembersihan konfigurasi yang seharusnya berada bersama Plugin; helper keluarga Google bawaan juga menopang entri konfigurasi Google yang didukung |
| 6 | applyNativeStreamingUsageCompat |
Menerapkan penulisan ulang kompat native streaming-usage ke penyedia konfigurasi | Penyedia memerlukan perbaikan metadata penggunaan streaming native yang digerakkan endpoint |
| 7 | resolveConfigApiKey |
Meresolusikan auth penanda env untuk penyedia konfigurasi sebelum pemuatan auth runtime | Penyedia memiliki resolusi API-key penanda env milik penyedia; amazon-bedrock juga memiliki resolver penanda env AWS bawaan di sini |
| 8 | resolveSyntheticAuth |
Memunculkan auth lokal/self-hosted atau berbasis konfigurasi tanpa menyimpan plaintext | Penyedia dapat beroperasi dengan penanda kredensial sintetis/lokal |
| 9 | resolveExternalAuthProfiles |
Melapisi profil auth eksternal milik penyedia; default persistence adalah runtime-only untuk kredensial milik CLI/aplikasi |
Penyedia menggunakan kembali kredensial auth eksternal tanpa menyimpan token refresh yang disalin; deklarasikan contracts.externalAuthProviders di manifest |
| 10 | shouldDeferSyntheticProfileAuth |
Menurunkan prioritas placeholder profil sintetis tersimpan di belakang auth berbasis env/konfigurasi | Penyedia menyimpan profil placeholder sintetis yang tidak boleh menang dalam prioritas |
| 11 | resolveDynamicModel |
Fallback sinkron untuk id model milik penyedia yang belum ada di registry lokal | Penyedia menerima id model upstream sembarang |
| 12 | prepareDynamicModel |
Pemanasan asinkron, lalu resolveDynamicModel berjalan lagi |
Penyedia memerlukan metadata jaringan sebelum meresolusikan id yang tidak dikenal |
| 13 | normalizeResolvedModel |
Penulisan ulang akhir sebelum runner tertanam menggunakan model yang telah diresolusikan | Penyedia memerlukan penulisan ulang transport tetapi tetap menggunakan transport inti |
| 14 | contributeResolvedModelCompat |
Menyumbangkan flag kompat untuk model vendor di belakang transport lain yang kompatibel | Penyedia mengenali modelnya sendiri pada transport proxy tanpa mengambil alih penyedia |
| 15 | normalizeToolSchemas |
Menormalisasi skema tool sebelum runner tertanam melihatnya | Penyedia memerlukan pembersihan skema keluarga transport |
| 16 | inspectToolSchemas |
Memunculkan diagnostik skema milik penyedia setelah normalisasi | Penyedia menginginkan peringatan kata kunci tanpa mengajari core aturan khusus penyedia |
| 17 | resolveReasoningOutputMode |
Memilih kontrak output reasoning native vs bertag | Penyedia memerlukan reasoning/output akhir bertag alih-alih field native |
| 18 | prepareExtraParams |
Normalisasi param permintaan sebelum wrapper opsi stream generik | Penyedia memerlukan param permintaan default atau pembersihan param per penyedia |
| 19 | createStreamFn |
Mengganti sepenuhnya jalur stream normal dengan transport kustom | Penyedia memerlukan protokol wire kustom, bukan sekadar wrapper |
| 20 | wrapStreamFn |
Wrapper stream setelah wrapper generik diterapkan | Penyedia memerlukan wrapper kompat header/body/model permintaan tanpa transport kustom |
| 21 | resolveTransportTurnState |
Melampirkan header atau metadata transport native per turn | Penyedia ingin transport generik mengirim identitas turn native penyedia |
| 22 | resolveWebSocketSessionPolicy |
Melampirkan header WebSocket native atau kebijakan jeda sesi | Penyedia ingin transport WS generik menyesuaikan header sesi atau kebijakan fallback |
| 23 | formatApiKey |
Formatter profil auth: profil tersimpan menjadi string apiKey runtime |
Penyedia menyimpan metadata auth tambahan dan memerlukan bentuk token runtime kustom |
| 24 | refreshOAuth |
Override refresh OAuth untuk endpoint refresh kustom atau kebijakan kegagalan refresh | Penyedia tidak cocok dengan refresher pi-ai bersama |
| 25 | buildAuthDoctorHint |
Petunjuk perbaikan yang ditambahkan saat refresh OAuth gagal | Penyedia memerlukan panduan perbaikan auth milik penyedia setelah kegagalan refresh |
| 26 | matchesContextOverflowError |
Pencocok overflow context-window milik penyedia | Penyedia memiliki error overflow mentah yang akan terlewat oleh heuristik generik |
| 27 | classifyFailoverReason |
Klasifikasi alasan failover milik penyedia | Penyedia dapat memetakan error API/transport mentah ke rate-limit/overload/dll. |
| 28 | isCacheTtlEligible |
Kebijakan prompt-cache untuk penyedia proxy/backhaul | Penyedia memerlukan gating TTL cache khusus proxy |
| 29 | buildMissingAuthMessage |
Pengganti pesan pemulihan missing-auth generik | Penyedia memerlukan petunjuk pemulihan missing-auth khusus penyedia |
| 30 | augmentModelCatalog |
Baris katalog sintetis/akhir yang ditambahkan setelah discovery | Penyedia memerlukan baris kompat maju sintetis di models list dan picker |
| 31 | resolveThinkingProfile |
Set level /think khusus model, label tampilan, dan default |
Penyedia mengekspos ladder thinking kustom atau label biner untuk model yang dipilih |
| 32 | isBinaryThinking |
Hook kompatibilitas toggle reasoning aktif/nonaktif | Penyedia hanya mengekspos thinking biner aktif/nonaktif |
| 33 | supportsXHighThinking |
Hook kompatibilitas dukungan reasoning xhigh |
Penyedia menginginkan xhigh hanya pada subset model |
| 34 | resolveDefaultThinkingLevel |
Hook kompatibilitas level /think default |
Penyedia memiliki kebijakan /think default untuk keluarga model |
| 35 | isModernModelRef |
Pencocok model modern untuk filter profil live dan pemilihan smoke | Penyedia memiliki pencocokan model pilihan live/smoke |
| 36 | prepareRuntimeAuth |
Menukar kredensial terkonfigurasi menjadi token/kunci runtime aktual tepat sebelum inferensi | Penyedia memerlukan pertukaran token atau kredensial permintaan berumur pendek |
| 37 | resolveUsageAuth |
Menentukan kredensial penggunaan/penagihan untuk /usage dan permukaan status terkait |
Penyedia memerlukan penguraian token penggunaan/kuota khusus atau kredensial penggunaan yang berbeda |
| 38 | fetchUsageSnapshot |
Mengambil dan menormalkan snapshot penggunaan/kuota khusus penyedia setelah autentikasi diselesaikan | Penyedia memerlukan endpoint penggunaan khusus penyedia atau pengurai payload |
| 39 | createEmbeddingProvider |
Membangun adaptor embedding milik penyedia untuk memori/pencarian | Perilaku embedding memori berada di Plugin penyedia |
| 40 | buildReplayPolicy |
Mengembalikan kebijakan replay yang mengontrol penanganan transkrip untuk penyedia | Penyedia memerlukan kebijakan transkrip khusus (misalnya, penghapusan blok pemikiran) |
| 41 | sanitizeReplayHistory |
Menulis ulang riwayat replay setelah pembersihan transkrip generik | Penyedia memerlukan penulisan ulang replay khusus penyedia di luar helper Compaction bersama |
| 42 | validateReplayTurns |
Validasi akhir giliran replay atau pembentukan ulang sebelum runner tertanam | Transport penyedia memerlukan validasi giliran yang lebih ketat setelah sanitasi generik |
| 43 | onModelSelected |
Menjalankan efek samping pasca-pemilihan milik penyedia | Penyedia memerlukan telemetri atau status milik penyedia saat model menjadi aktif |
normalizeModelId, normalizeTransport, dan normalizeConfig terlebih dahulu memeriksa
plugin penyedia yang cocok, lalu melanjutkan ke plugin penyedia lain yang mendukung hook
hingga ada yang benar-benar mengubah id model atau transport/config. Itu menjaga
shim alias/compat penyedia tetap berfungsi tanpa mengharuskan pemanggil mengetahui
plugin bawaan mana yang memiliki penulisan ulang tersebut. Jika tidak ada hook penyedia
yang menulis ulang entri config keluarga Google yang didukung, normalizer config
Google bawaan tetap menerapkan pembersihan kompatibilitas tersebut.
Jika penyedia membutuhkan protokol wire yang sepenuhnya kustom atau eksekutor permintaan kustom, itu adalah kelas ekstensi yang berbeda. Hook ini ditujukan untuk perilaku penyedia yang tetap berjalan pada loop inferensi normal OpenClaw.
Contoh penyedia
api.registerProvider({
id: "example-proxy",
label: "Example Proxy",
auth: [],
catalog: {
order: "simple",
run: async (ctx) => {
const apiKey = ctx.resolveProviderApiKey("example-proxy").apiKey;
if (!apiKey) {
return null;
}
return {
provider: {
baseUrl: "https://proxy.example.com/v1",
apiKey,
api: "openai-completions",
models: [{ id: "auto", name: "Auto" }],
},
};
},
},
resolveDynamicModel: (ctx) => ({
id: ctx.modelId,
name: ctx.modelId,
provider: "example-proxy",
api: "openai-completions",
baseUrl: "https://proxy.example.com/v1",
reasoning: false,
input: ["text"],
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
contextWindow: 128000,
maxTokens: 8192,
}),
prepareRuntimeAuth: async (ctx) => {
const exchanged = await exchangeToken(ctx.apiKey);
return {
apiKey: exchanged.token,
baseUrl: exchanged.baseUrl,
expiresAt: exchanged.expiresAt,
};
},
resolveUsageAuth: async (ctx) => {
const auth = await ctx.resolveOAuthToken();
return auth ? { token: auth.token } : null;
},
fetchUsageSnapshot: async (ctx) => {
return await fetchExampleProxyUsage(ctx.token, ctx.timeoutMs, ctx.fetchFn);
},
});
Contoh bawaan
Plugin penyedia bawaan menggabungkan hook di atas agar sesuai dengan kebutuhan katalog,
auth, thinking, replay, dan penggunaan masing-masing vendor. Set hook yang otoritatif berada bersama
setiap plugin di bawah extensions/; halaman ini menggambarkan bentuknya, bukan
mencerminkan daftarnya.
Pass-through catalog providers
OpenRouter, Kilocode, Z.AI, xAI mendaftarkan catalog ditambah
resolveDynamicModel / prepareDynamicModel agar mereka dapat menampilkan id
model upstream sebelum katalog statis OpenClaw.
OAuth and usage endpoint providers
GitHub Copilot, Gemini CLI, ChatGPT Codex, MiniMax, Xiaomi, z.ai memasangkan
prepareRuntimeAuth atau formatApiKey dengan resolveUsageAuth +
fetchUsageSnapshot untuk memiliki pertukaran token dan integrasi /usage.
Replay and transcript cleanup families
Keluarga bernama bersama (google-gemini, passthrough-gemini,
anthropic-by-model, hybrid-anthropic-openai) memungkinkan penyedia ikut memakai
kebijakan transkrip melalui buildReplayPolicy alih-alih setiap plugin
mengimplementasikan ulang pembersihan.
Catalog-only providers
byteplus, cloudflare-ai-gateway, huggingface, kimi-coding, nvidia,
qianfan, synthetic, together, venice, vercel-ai-gateway, dan
volcengine hanya mendaftarkan catalog dan menggunakan loop inferensi bersama.
Anthropic-specific stream helpers
Header beta, /fast / serviceTier, dan context1m berada di dalam
seam publik api.ts / contract-api.ts milik plugin Anthropic
(wrapAnthropicProviderStream, resolveAnthropicBetas,
resolveAnthropicFastMode, resolveAnthropicServiceTier), bukan di
SDK generik.
Helper runtime
Plugin dapat mengakses helper inti tertentu melalui api.runtime. Untuk TTS:
const clip = await api.runtime.tts.textToSpeech({
text: "Hello from OpenClaw",
cfg: api.config,
});
const result = await api.runtime.tts.textToSpeechTelephony({
text: "Hello from OpenClaw",
cfg: api.config,
});
const voices = await api.runtime.tts.listVoices({
provider: "elevenlabs",
cfg: api.config,
});
Catatan:
textToSpeechmengembalikan payload output TTS inti normal untuk permukaan file/catatan suara.- Menggunakan konfigurasi inti
messages.ttsdan pemilihan penyedia. - Mengembalikan buffer audio PCM + laju sampel. Plugin harus melakukan resampling/encoding untuk penyedia.
listVoicesbersifat opsional per penyedia. Gunakan untuk pemilih suara atau alur penyiapan milik vendor.- Daftar suara dapat menyertakan metadata yang lebih kaya seperti lokal, gender, dan tag kepribadian untuk pemilih yang sadar penyedia.
- OpenAI dan ElevenLabs mendukung telefoni saat ini. Microsoft tidak.
Plugin juga dapat mendaftarkan penyedia ucapan melalui api.registerSpeechProvider(...).
api.registerSpeechProvider({
id: "acme-speech",
label: "Acme Speech",
isConfigured: ({ config }) => Boolean(config.messages?.tts),
synthesize: async (req) => {
return {
audioBuffer: Buffer.from([]),
outputFormat: "mp3",
fileExtension: ".mp3",
voiceCompatible: false,
};
},
});
Catatan:
- Pertahankan kebijakan TTS, fallback, dan pengiriman balasan di inti.
- Gunakan penyedia ucapan untuk perilaku sintesis milik vendor.
- Input Microsoft lama
edgedinormalisasi ke id penyediamicrosoft. - Model kepemilikan yang disarankan berorientasi perusahaan: satu plugin vendor dapat memiliki penyedia teks, ucapan, gambar, dan media masa depan seiring OpenClaw menambahkan kontrak kemampuan tersebut.
Untuk pemahaman gambar/audio/video, plugin mendaftarkan satu penyedia pemahaman media bertipe, bukan bag key/value generik:
api.registerMediaUnderstandingProvider({
id: "google",
capabilities: ["image", "audio", "video"],
describeImage: async (req) => ({ text: "..." }),
transcribeAudio: async (req) => ({ text: "..." }),
describeVideo: async (req) => ({ text: "..." }),
});
Catatan:
- Pertahankan orkestrasi, fallback, config, dan wiring channel di inti.
- Pertahankan perilaku vendor di plugin penyedia.
- Ekspansi aditif harus tetap bertipe: metode opsional baru, field hasil opsional baru, kemampuan opsional baru.
- Pembuatan video sudah mengikuti pola yang sama:
- inti memiliki kontrak kemampuan dan helper runtime
- plugin vendor mendaftarkan
api.registerVideoGenerationProvider(...) - plugin fitur/channel menggunakan
api.runtime.videoGeneration.*
Untuk helper runtime pemahaman media, plugin dapat memanggil:
const image = await api.runtime.mediaUnderstanding.describeImageFile({
filePath: "/tmp/inbound-photo.jpg",
cfg: api.config,
agentDir: "/tmp/agent",
});
const video = await api.runtime.mediaUnderstanding.describeVideoFile({
filePath: "/tmp/inbound-video.mp4",
cfg: api.config,
});
Untuk transkripsi audio, plugin dapat menggunakan runtime pemahaman media atau alias STT yang lebih lama:
const { text } = await api.runtime.mediaUnderstanding.transcribeAudioFile({
filePath: "/tmp/inbound-audio.ogg",
cfg: api.config,
// Optional when MIME cannot be inferred reliably:
mime: "audio/ogg",
});
Catatan:
api.runtime.mediaUnderstanding.*adalah permukaan bersama yang disarankan untuk pemahaman gambar/audio/video.- Menggunakan konfigurasi audio pemahaman media inti (
tools.media.audio) dan urutan fallback penyedia. - Mengembalikan
{ text: undefined }ketika tidak ada output transkripsi yang dihasilkan (misalnya input dilewati/tidak didukung). api.runtime.stt.transcribeAudioFile(...)tetap ada sebagai alias kompatibilitas.
Plugin juga dapat meluncurkan run subagen latar belakang melalui api.runtime.subagent:
const result = await api.runtime.subagent.run({
sessionKey: "agent:main:subagent:search-helper",
message: "Expand this query into focused follow-up searches.",
provider: "openai",
model: "gpt-4.1-mini",
deliver: false,
});
Catatan:
providerdanmodeladalah override opsional per run, bukan perubahan sesi persisten.- OpenClaw hanya menghormati field override tersebut untuk pemanggil tepercaya.
- Untuk run fallback milik plugin, operator harus ikut serta dengan
plugins.entries.<id>.subagent.allowModelOverride: true. - Gunakan
plugins.entries.<id>.subagent.allowedModelsuntuk membatasi plugin tepercaya ke target kanonisprovider/modeltertentu, atau"*"untuk mengizinkan target apa pun secara eksplisit. - Run subagen plugin yang tidak tepercaya tetap berfungsi, tetapi permintaan override ditolak alih-alih diam-diam memakai fallback.
- Sesi subagen yang dibuat plugin ditandai dengan id plugin pembuatnya. Fallback
api.runtime.subagent.deleteSession(...)hanya dapat menghapus sesi yang dimiliki tersebut; penghapusan sesi arbitrer tetap memerlukan permintaan Gateway berskop admin.
Untuk pencarian web, plugin dapat menggunakan helper runtime bersama alih-alih masuk ke wiring alat agen:
const providers = api.runtime.webSearch.listProviders({
config: api.config,
});
const result = await api.runtime.webSearch.search({
config: api.config,
args: {
query: "OpenClaw plugin runtime helpers",
count: 5,
},
});
Plugin juga dapat mendaftarkan penyedia pencarian web melalui
api.registerWebSearchProvider(...).
Catatan:
- Pertahankan pemilihan penyedia, resolusi kredensial, dan semantik permintaan bersama di inti.
- Gunakan penyedia pencarian web untuk transport pencarian spesifik vendor.
api.runtime.webSearch.*adalah permukaan bersama yang disarankan untuk plugin fitur/channel yang membutuhkan perilaku pencarian tanpa bergantung pada wrapper alat agen.
api.runtime.imageGeneration
const result = await api.runtime.imageGeneration.generate({
config: api.config,
args: { prompt: "A friendly lobster mascot", size: "1024x1024" },
});
const providers = api.runtime.imageGeneration.listProviders({
config: api.config,
});
generate(...): menghasilkan gambar menggunakan rantai penyedia pembuatan gambar yang dikonfigurasi.listProviders(...): mencantumkan penyedia pembuatan gambar yang tersedia dan kemampuannya.
Rute HTTP Gateway
Plugin dapat mengekspos endpoint HTTP dengan api.registerHttpRoute(...).
api.registerHttpRoute({
path: "/acme/webhook",
auth: "plugin",
match: "exact",
handler: async (_req, res) => {
res.statusCode = 200;
res.end("ok");
return true;
},
});
Field rute:
path: path rute di bawah server HTTP gateway.auth: wajib. Gunakan"gateway"untuk mewajibkan auth gateway normal, atau"plugin"untuk verifikasi auth/webhook yang dikelola plugin.match: opsional."exact"(default) atau"prefix".replaceExisting: opsional. Memungkinkan plugin yang sama mengganti registrasi rute miliknya yang sudah ada.handler: kembalikantrueketika rute menangani permintaan.
Catatan:
api.registerHttpHandler(...)telah dihapus dan akan menyebabkan error pemuatan plugin. Gunakanapi.registerHttpRoute(...)sebagai gantinya.- Route Plugin harus mendeklarasikan
authsecara eksplisit. - Konflik
path + matchyang persis ditolak kecualireplaceExisting: true, dan satu Plugin tidak dapat menggantikan route milik Plugin lain. - Route yang tumpang tindih dengan level
authberbeda ditolak. Pertahankan rantai fallthroughexact/prefixhanya pada level auth yang sama. - Route
auth: "plugin"tidak menerima cakupan runtime operator secara otomatis. Route ini ditujukan untuk webhook/verifikasi tanda tangan yang dikelola Plugin, bukan panggilan helper Gateway yang memiliki privilese. - Route
auth: "gateway"berjalan di dalam cakupan runtime permintaan Gateway, tetapi cakupan itu sengaja konservatif:- auth bearer shared-secret (
gateway.auth.mode = "token"/"password") mempertahankan cakupan runtime route Plugin tetap padaoperator.write, bahkan jika pemanggil mengirimx-openclaw-scopes - mode HTTP tepercaya yang membawa identitas (misalnya
trusted-proxyataugateway.auth.mode = "none"pada ingress privat) menghormatix-openclaw-scopeshanya ketika header tersebut ada secara eksplisit - jika
x-openclaw-scopestidak ada pada permintaan route Plugin yang membawa identitas tersebut, cakupan runtime kembali keoperator.write
- auth bearer shared-secret (
- Aturan praktis: jangan menganggap route Plugin dengan auth gateway sebagai permukaan admin implisit. Jika route Anda memerlukan perilaku khusus admin, wajibkan mode auth yang membawa identitas dan dokumentasikan kontrak header
x-openclaw-scopesyang eksplisit.
Jalur impor SDK Plugin
Gunakan subjalur SDK yang sempit alih-alih barrel root openclaw/plugin-sdk yang monolitik saat membuat Plugin baru. Subjalur inti:
| Subjalur | Tujuan |
|---|---|
openclaw/plugin-sdk/plugin-entry |
Primitif pendaftaran Plugin |
openclaw/plugin-sdk/channel-core |
Helper entri/pembuatan saluran |
openclaw/plugin-sdk/core |
Helper bersama generik dan kontrak payung |
openclaw/plugin-sdk/config-schema |
Skema Zod root openclaw.json (OpenClawSchema) |
Plugin saluran memilih dari rangkaian seam yang sempit — channel-setup,
setup-runtime, setup-adapter-runtime, setup-tools, channel-pairing,
channel-contract, channel-feedback, channel-inbound, channel-lifecycle,
channel-reply-pipeline, command-auth, secret-input, webhook-ingress,
channel-targets, dan channel-actions. Perilaku persetujuan sebaiknya dikonsolidasikan
pada satu kontrak approvalCapability alih-alih mencampurnya di berbagai
field Plugin yang tidak terkait. Lihat Plugin saluran.
Helper runtime dan konfigurasi berada di bawah subjalur *-runtime yang
terfokus dan sesuai (approval-runtime, agent-runtime, lazy-runtime,
directory-runtime, text-runtime, runtime-store, system-event-runtime,
heartbeat-runtime, channel-activity-runtime, dll.). Utamakan config-types,
plugin-config-runtime, runtime-config-snapshot, dan config-mutation
alih-alih barrel kompatibilitas config-runtime yang luas.
Titik entri internal repo (per root paket Plugin bawaan):
index.js— entri Plugin bawaanapi.js— barrel helper/tiperuntime-api.js— barrel khusus runtimesetup-entry.js— entri Plugin setup
Plugin eksternal sebaiknya hanya mengimpor subjalur openclaw/plugin-sdk/*. Jangan pernah
mengimpor src/* milik paket Plugin lain dari core atau dari Plugin lain.
Titik entri yang dimuat melalui facade mengutamakan snapshot konfigurasi runtime aktif jika ada,
lalu fallback ke file konfigurasi yang di-resolve di disk.
Subjalur khusus capability seperti image-generation, media-understanding,
dan speech ada karena Plugin bawaan menggunakannya saat ini. Subjalur tersebut tidak
otomatis menjadi kontrak eksternal jangka panjang yang dibekukan — periksa halaman referensi SDK
yang relevan saat bergantung padanya.
Skema alat pesan
Plugin sebaiknya memiliki kontribusi skema describeMessageTool(...) khusus saluran
untuk primitif non-pesan seperti reaksi, tanda baca, dan polling.
Presentasi pengiriman bersama sebaiknya menggunakan kontrak generik MessagePresentation
alih-alih field tombol, komponen, blok, atau kartu native penyedia.
Lihat Presentasi Pesan untuk kontrak,
aturan fallback, pemetaan penyedia, dan checklist penulis Plugin.
Plugin yang dapat mengirim mendeklarasikan apa yang dapat dirender melalui capability pesan:
presentationuntuk blok presentasi semantik (text,context,divider,buttons,select)delivery-pinuntuk permintaan pengiriman yang disematkan
Core memutuskan apakah akan merender presentasi secara native atau menurunkannya menjadi teks. Jangan mengekspos escape hatch UI native penyedia dari alat pesan generik. Helper SDK yang tidak lagi disarankan untuk skema native lama tetap diekspor untuk Plugin pihak ketiga yang sudah ada, tetapi Plugin baru sebaiknya tidak menggunakannya.
Resolusi target saluran
Plugin saluran sebaiknya memiliki semantik target khusus saluran. Pertahankan host outbound bersama tetap generik dan gunakan permukaan adapter pesan untuk aturan penyedia:
messaging.inferTargetChatType({ to })menentukan apakah target yang dinormalisasi harus diperlakukan sebagaidirect,group, atauchannelsebelum lookup direktori.messaging.targetResolver.looksLikeId(raw, normalized)memberi tahu core apakah input harus langsung menuju resolusi mirip id alih-alih pencarian direktori.messaging.targetResolver.resolveTarget(...)adalah fallback Plugin ketika core memerlukan resolusi akhir milik penyedia setelah normalisasi atau setelah direktori tidak menemukan hasil.messaging.resolveOutboundSessionRoute(...)memiliki konstruksi route sesi khusus penyedia setelah target di-resolve.
Pembagian yang direkomendasikan:
- Gunakan
inferTargetChatTypeuntuk keputusan kategori yang harus terjadi sebelum mencari peers/grup. - Gunakan
looksLikeIduntuk pemeriksaan "perlakukan ini sebagai id target eksplisit/native". - Gunakan
resolveTargetuntuk fallback normalisasi khusus penyedia, bukan untuk pencarian direktori yang luas. - Simpan id native penyedia seperti id chat, id thread, JID, handle, dan id room
di dalam nilai
targetatau params khusus penyedia, bukan di field SDK generik.
Direktori berbasis konfigurasi
Plugin yang menurunkan entri direktori dari konfigurasi sebaiknya mempertahankan logika itu di
Plugin dan menggunakan ulang helper bersama dari
openclaw/plugin-sdk/directory-runtime.
Gunakan ini ketika saluran memerlukan peers/grup berbasis konfigurasi seperti:
- peer DM yang digerakkan oleh allowlist
- peta saluran/grup yang dikonfigurasi
- fallback direktori statis dalam cakupan akun
Helper bersama di directory-runtime hanya menangani operasi generik:
- pemfilteran kueri
- penerapan batas
- helper deduplikasi/normalisasi
- pembuatan
ChannelDirectoryEntry[]
Inspeksi akun dan normalisasi id khusus saluran sebaiknya tetap berada dalam implementasi Plugin.
Katalog penyedia
Plugin penyedia dapat mendefinisikan katalog model untuk inferensi dengan
registerProvider({ catalog: { run(...) { ... } } }).
catalog.run(...) mengembalikan bentuk yang sama seperti yang ditulis OpenClaw ke
models.providers:
{ provider }untuk satu entri penyedia{ providers }untuk beberapa entri penyedia
Gunakan catalog ketika Plugin memiliki id model khusus penyedia, default URL dasar,
atau metadata model yang dibatasi auth.
catalog.order mengontrol kapan katalog Plugin digabung relatif terhadap penyedia implisit
bawaan OpenClaw:
simple: penyedia berbasis API-key polos atau envprofile: penyedia yang muncul ketika profil auth adapaired: penyedia yang menyintesis beberapa entri penyedia terkaitlate: lintasan terakhir, setelah penyedia implisit lainnya
Penyedia yang lebih belakangan menang pada tabrakan key, sehingga Plugin dapat secara sengaja mengganti entri penyedia bawaan dengan id penyedia yang sama.
Kompatibilitas:
discoverymasih berfungsi sebagai alias lama- jika
catalogdandiscoverysama-sama didaftarkan, OpenClaw menggunakancatalog
Inspeksi saluran read-only
Jika Plugin Anda mendaftarkan saluran, utamakan penerapan
plugin.config.inspectAccount(cfg, accountId) bersama resolveAccount(...).
Alasannya:
resolveAccount(...)adalah jalur runtime. Jalur ini boleh mengasumsikan kredensial telah dimaterialisasi sepenuhnya dan dapat gagal cepat ketika secret yang diperlukan tidak ada.- Jalur perintah read-only seperti
openclaw status,openclaw status --all,openclaw channels status,openclaw channels resolve, dan alur perbaikan doctor/config tidak seharusnya perlu mematerialisasi kredensial runtime hanya untuk mendeskripsikan konfigurasi.
Perilaku inspectAccount(...) yang direkomendasikan:
- Kembalikan hanya status akun deskriptif.
- Pertahankan
enableddanconfigured. - Sertakan field sumber/status kredensial ketika relevan, seperti:
tokenSource,tokenStatusbotTokenSource,botTokenStatusappTokenSource,appTokenStatussigningSecretSource,signingSecretStatus
- Anda tidak perlu mengembalikan nilai token mentah hanya untuk melaporkan
ketersediaan read-only. Mengembalikan
tokenStatus: "available"(dan field sumber yang sesuai) sudah cukup untuk perintah bergaya status. - Gunakan
configured_unavailableketika kredensial dikonfigurasi melalui SecretRef tetapi tidak tersedia di jalur perintah saat ini.
Ini memungkinkan perintah read-only melaporkan "dikonfigurasi tetapi tidak tersedia di jalur perintah ini" alih-alih crash atau salah melaporkan akun sebagai tidak dikonfigurasi.
Pack paket
Direktori Plugin dapat menyertakan package.json dengan openclaw.extensions:
{
"name": "my-pack",
"openclaw": {
"extensions": ["./src/safety.ts", "./src/tools.ts"],
"setupEntry": "./src/setup-entry.ts"
}
}
Setiap entri menjadi Plugin. Jika pack mencantumkan beberapa ekstensi, id Plugin
menjadi name/<fileBase>.
Jika Plugin Anda mengimpor deps npm, instal deps tersebut di direktori itu agar
node_modules tersedia (npm install / pnpm install).
Guardrail keamanan: setiap entri openclaw.extensions harus tetap berada di dalam direktori Plugin
setelah resolusi symlink. Entri yang keluar dari direktori paket ditolak.
Catatan keamanan: openclaw plugins install menginstal dependensi Plugin dengan
npm install --omit=dev --ignore-scripts lokal proyek (tanpa skrip lifecycle,
tanpa dependensi dev saat runtime), mengabaikan pengaturan npm install global yang diwarisi.
Pertahankan pohon dependensi Plugin sebagai "JS/TS murni" dan hindari paket yang memerlukan
build postinstall.
Opsional: openclaw.setupEntry dapat menunjuk ke modul khusus setup yang ringan.
Ketika OpenClaw memerlukan permukaan setup untuk Plugin saluran yang dinonaktifkan, atau
ketika Plugin saluran diaktifkan tetapi masih belum dikonfigurasi, OpenClaw memuat setupEntry
alih-alih entri Plugin penuh. Ini membuat startup dan setup lebih ringan
ketika entri Plugin utama Anda juga merangkai alat, hook, atau kode khusus runtime lainnya.
Opsional: openclaw.startup.deferConfiguredChannelFullLoadUntilAfterListen
dapat membuat Plugin saluran menggunakan jalur setupEntry yang sama selama fase startup
pra-listen Gateway, bahkan ketika saluran sudah dikonfigurasi.
Gunakan ini hanya ketika setupEntry sepenuhnya mencakup permukaan startup yang harus ada
sebelum Gateway mulai mendengarkan. Dalam praktiknya, itu berarti entri setup
harus mendaftarkan setiap capability milik saluran yang dibutuhkan startup, seperti:
- pendaftaran saluran itu sendiri
- route HTTP apa pun yang harus tersedia sebelum Gateway mulai mendengarkan
- metode, alat, atau layanan Gateway apa pun yang harus ada selama jendela yang sama
Jika entri penuh Anda masih memiliki capability startup wajib apa pun, jangan aktifkan flag ini. Pertahankan Plugin pada perilaku default dan biarkan OpenClaw memuat entri penuh selama startup.
Saluran bawaan juga dapat memublikasikan helper permukaan kontrak khusus setup yang dapat dikonsultasikan core sebelum runtime saluran penuh dimuat. Permukaan promosi setup saat ini adalah:
singleAccountKeysToMovenamedAccountPromotionKeysresolveSingleAccountPromotionTarget(...)
Core menggunakan permukaan itu ketika perlu mempromosikan konfigurasi saluran akun tunggal lama ke channels.<id>.accounts.* tanpa memuat entri Plugin penuh. Matrix adalah contoh bundel saat ini: ia hanya memindahkan kunci auth/bootstrap ke akun bernama yang dipromosikan ketika akun bernama sudah ada, dan dapat mempertahankan kunci akun default non-kanonis yang dikonfigurasi alih-alih selalu membuat accounts.default.
Adapter patch penyiapan tersebut menjaga penemuan permukaan kontrak bundel tetap lazy. Waktu impor tetap ringan; permukaan promosi dimuat hanya saat pertama kali digunakan alih-alih memasuki ulang startup saluran bundel saat impor modul.
Ketika permukaan startup tersebut menyertakan metode RPC Gateway, pertahankan pada prefiks khusus Plugin. Namespace admin core (config.*, exec.approvals.*, wizard.*, update.*) tetap dicadangkan dan selalu di-resolve ke operator.admin, meskipun Plugin meminta cakupan yang lebih sempit.
Contoh:
{
"name": "@scope/my-channel",
"openclaw": {
"extensions": ["./index.ts"],
"setupEntry": "./setup-entry.ts",
"startup": {
"deferConfiguredChannelFullLoadUntilAfterListen": true
}
}
}
Metadata katalog saluran
Plugin saluran dapat mengiklankan metadata penyiapan/penemuan melalui openclaw.channel dan petunjuk instalasi melalui openclaw.install. Ini menjaga katalog core tetap bebas data.
Contoh:
{
"name": "@openclaw/nextcloud-talk",
"openclaw": {
"extensions": ["./index.ts"],
"channel": {
"id": "nextcloud-talk",
"label": "Nextcloud Talk",
"selectionLabel": "Nextcloud Talk (self-hosted)",
"docsPath": "/channels/nextcloud-talk",
"docsLabel": "nextcloud-talk",
"blurb": "Self-hosted chat via Nextcloud Talk webhook bots.",
"order": 65,
"aliases": ["nc-talk", "nc"]
},
"install": {
"npmSpec": "@openclaw/nextcloud-talk",
"localPath": "<bundled-plugin-local-path>",
"defaultChoice": "npm"
}
}
}
Field openclaw.channel yang berguna di luar contoh minimal:
detailLabel: label sekunder untuk permukaan katalog/status yang lebih kayadocsLabel: menimpa teks tautan untuk tautan dokumenpreferOver: id Plugin/saluran berprioritas lebih rendah yang harus dikalahkan oleh entri katalog iniselectionDocsPrefix,selectionDocsOmitLabel,selectionExtras: kontrol salinan permukaan pemilihanmarkdownCapable: menandai saluran sebagai mendukung markdown untuk keputusan pemformatan keluarexposure.configured: sembunyikan saluran dari permukaan daftar saluran terkonfigurasi ketika diatur kefalseexposure.setup: sembunyikan saluran dari pemilih penyiapan/konfigurasi interaktif ketika diatur kefalseexposure.docs: tandai saluran sebagai internal/privat untuk permukaan navigasi dokumenshowConfigured/showInSetup: alias lama yang masih diterima untuk kompatibilitas; utamakanexposurequickstartAllowFrom: ikutkan saluran ke alur quickstart standarallowFromforceAccountBinding: wajibkan pengikatan akun eksplisit meskipun hanya ada satu akunpreferSessionLookupForAnnounceTarget: utamakan pencarian sesi saat me-resolve target pengumuman
OpenClaw juga dapat menggabungkan katalog saluran eksternal (misalnya, ekspor registry MPM). Letakkan file JSON di salah satu dari:
~/.openclaw/mpm/plugins.json~/.openclaw/mpm/catalog.json~/.openclaw/plugins/catalog.json
Atau arahkan OPENCLAW_PLUGIN_CATALOG_PATHS (atau OPENCLAW_MPM_CATALOG_PATHS) ke satu atau beberapa file JSON (dipisahkan koma/titik koma/PATH). Setiap file harus berisi { "entries": [ { "name": "@scope/pkg", "openclaw": { "channel": {...}, "install": {...} } } ] }. Parser juga menerima "packages" atau "plugins" sebagai alias lama untuk kunci "entries".
Entri katalog saluran yang dihasilkan dan entri katalog instalasi penyedia mengekspos fakta sumber instalasi yang dinormalisasi di samping blok mentah openclaw.install. Fakta yang dinormalisasi mengidentifikasi apakah spec npm adalah versi eksak atau selector mengambang, apakah metadata integritas yang diharapkan tersedia, dan apakah path sumber lokal juga tersedia. Ketika identitas katalog/paket diketahui, fakta yang dinormalisasi memperingatkan jika nama paket npm yang di-parse menyimpang dari identitas tersebut. Fakta tersebut juga memperingatkan ketika defaultChoice tidak valid atau menunjuk ke sumber yang tidak tersedia, dan ketika metadata integritas npm tersedia tanpa sumber npm yang valid. Konsumen harus memperlakukan installSource sebagai field opsional aditif sehingga entri buatan tangan dan shim katalog tidak perlu menyintesisnya. Ini memungkinkan onboarding dan diagnostik menjelaskan status bidang sumber tanpa mengimpor runtime Plugin.
Entri npm eksternal resmi sebaiknya mengutamakan npmSpec eksak plus expectedIntegrity. Nama paket polos dan dist-tag tetap berfungsi untuk kompatibilitas, tetapi memunculkan peringatan bidang sumber agar katalog dapat bergerak menuju instalasi yang dipin dan diperiksa integritasnya tanpa merusak Plugin yang sudah ada. Ketika onboarding menginstal dari path katalog lokal, ia merekam entri indeks Plugin terkelola dengan source: "path" dan sourcePath relatif workspace bila memungkinkan. Path pemuatan operasional absolut tetap berada di plugins.load.paths; catatan instalasi menghindari duplikasi path workstation lokal ke dalam konfigurasi jangka panjang. Ini membuat instalasi pengembangan lokal terlihat oleh diagnostik bidang sumber tanpa menambahkan permukaan pengungkapan path filesystem mentah kedua. Indeks Plugin plugins/installs.json yang dipertahankan adalah sumber kebenaran instalasi dan dapat disegarkan tanpa memuat modul runtime Plugin. Map installRecords-nya tetap tahan lama meskipun manifes Plugin hilang atau tidak valid; array plugins-nya adalah tampilan manifes yang dapat dibangun ulang.
Plugin mesin konteks
Plugin mesin konteks memiliki orkestrasi konteks sesi untuk ingest, assembly, dan Compaction. Daftarkan dari Plugin Anda dengan api.registerContextEngine(id, factory), lalu pilih mesin aktif dengan plugins.slots.contextEngine.
Gunakan ini ketika Plugin Anda perlu mengganti atau memperluas pipeline konteks default, bukan hanya menambahkan pencarian memori atau hook.
export default function (api) {
api.registerContextEngine("lossless-claw", (ctx) => ({
info: { id: "lossless-claw", name: "Lossless Claw", ownsCompaction: true },
async ingest() {
return { ingested: true };
},
async assemble({ messages, availableTools, citationsMode }) {
return {
messages,
estimatedTokens: 0,
systemPromptAddition: buildMemorySystemPromptAddition({
availableTools: availableTools ?? new Set(),
citationsMode,
}),
};
},
async compact() {
return { ok: true, compacted: false };
},
}));
}
Factory ctx mengekspos nilai opsional config, agentDir, dan workspaceDir untuk inisialisasi saat konstruksi.
Jika mesin Anda tidak memiliki algoritma Compaction, tetap implementasikan compact() dan delegasikan secara eksplisit:
buildMemorySystemPromptAddition,
delegateCompactionToRuntime,
} from "openclaw/plugin-sdk/core";
export default function (api) {
api.registerContextEngine("my-memory-engine", (ctx) => ({
info: {
id: "my-memory-engine",
name: "My Memory Engine",
ownsCompaction: false,
},
async ingest() {
return { ingested: true };
},
async assemble({ messages, availableTools, citationsMode }) {
return {
messages,
estimatedTokens: 0,
systemPromptAddition: buildMemorySystemPromptAddition({
availableTools: availableTools ?? new Set(),
citationsMode,
}),
};
},
async compact(params) {
return await delegateCompactionToRuntime(params);
},
}));
}
Menambahkan kapabilitas baru
Ketika Plugin memerlukan perilaku yang tidak cocok dengan API saat ini, jangan melewati sistem Plugin dengan akses privat ke dalam. Tambahkan kapabilitas yang belum ada.
Urutan yang direkomendasikan:
- definisikan kontrak core Tentukan perilaku bersama apa yang harus dimiliki core: kebijakan, fallback, penggabungan konfigurasi, lifecycle, semantik yang menghadap saluran, dan bentuk helper runtime.
- tambahkan permukaan registrasi/runtime Plugin bertipe
Perluas
OpenClawPluginApidan/atauapi.runtimedengan permukaan kapabilitas bertipe terkecil yang berguna. - hubungkan konsumen core + saluran/fitur Saluran dan Plugin fitur harus memakai kapabilitas baru melalui core, bukan dengan mengimpor implementasi vendor secara langsung.
- daftarkan implementasi vendor Plugin vendor kemudian mendaftarkan backend mereka ke kapabilitas tersebut.
- tambahkan cakupan kontrak Tambahkan pengujian agar kepemilikan dan bentuk registrasi tetap eksplisit seiring waktu.
Beginilah OpenClaw tetap berpendirian tanpa menjadi hardcoded ke sudut pandang satu penyedia. Lihat Capability Cookbook untuk checklist file konkret dan contoh yang dikerjakan.
Checklist kapabilitas
Ketika Anda menambahkan kapabilitas baru, implementasi biasanya harus menyentuh permukaan ini bersama-sama:
- tipe kontrak core di
src/<capability>/types.ts - helper runner/runtime core di
src/<capability>/runtime.ts - permukaan registrasi API Plugin di
src/plugins/types.ts - wiring registry Plugin di
src/plugins/registry.ts - eksposur runtime Plugin di
src/plugins/runtime/*ketika Plugin fitur/saluran perlu mengonsumsinya - helper capture/pengujian di
src/test-utils/plugin-registration.ts - assertion kepemilikan/kontrak di
src/plugins/contracts/registry.ts - dokumen operator/Plugin di
docs/
Jika salah satu permukaan tersebut tidak ada, itu biasanya tanda bahwa kapabilitas belum terintegrasi sepenuhnya.
Template kapabilitas
Pola minimal:
// core contract
export type VideoGenerationProviderPlugin = {
id: string;
label: string;
generateVideo: (req: VideoGenerationRequest) => Promise<VideoGenerationResult>;
};
// plugin API
api.registerVideoGenerationProvider({
id: "openai",
label: "OpenAI",
async generateVideo(req) {
return await generateOpenAiVideo(req);
},
});
// shared runtime helper for feature/channel plugins
const clip = await api.runtime.videoGeneration.generate({
prompt: "Show the robot walking through the lab.",
cfg,
});
Pola pengujian kontrak:
expect(findVideoGenerationProviderIdsForPlugin("openai")).toEqual(["openai"]);
Itu membuat aturan tetap sederhana:
- core memiliki kontrak kapabilitas + orkestrasi
- Plugin vendor memiliki implementasi vendor
- Plugin fitur/saluran mengonsumsi helper runtime
- pengujian kontrak menjaga kepemilikan tetap eksplisit
Terkait
- Arsitektur Plugin — model dan bentuk kapabilitas publik
- Subpath SDK Plugin
- Penyiapan SDK Plugin
- Membangun Plugin