Plugins
การสร้าง Plugin
Plugin ขยาย OpenClaw ด้วยความสามารถใหม่ๆ: ช่องทาง, ผู้ให้บริการโมเดล, เสียงพูด, การถอดเสียงแบบเรียลไทม์, เสียงแบบเรียลไทม์, การเข้าใจสื่อ, การสร้างภาพ, การสร้างวิดีโอ, การดึงเว็บ, การค้นเว็บ, เครื่องมือเอเจนต์ หรือ การผสมผสานใดๆ
คุณไม่จำเป็นต้องเพิ่ม Plugin ของคุณเข้าไปในที่เก็บ OpenClaw เผยแพร่ไปยัง
ClawHub และผู้ใช้ติดตั้งด้วย
openclaw plugins install clawhub:<package-name> สเปกแพ็กเกจแบบเปล่ายังคง
ติดตั้งจาก npm ในช่วงเปลี่ยนผ่านการเปิดตัว
ข้อกำหนดเบื้องต้น
- Node >= 22 และตัวจัดการแพ็กเกจ (npm หรือ pnpm)
- คุ้นเคยกับ TypeScript (ESM)
- สำหรับ Plugin ในที่เก็บ: โคลนที่เก็บและทำ
pnpm installแล้ว การพัฒนา Plugin จากซอร์สเช็กเอาต์รองรับเฉพาะ pnpm เพราะ OpenClaw โหลด Plugin ที่รวมมา จากแพ็กเกจเวิร์กสเปซextensions/*
Plugin ประเภทใด?
เชื่อมต่อ OpenClaw กับแพลตฟอร์มรับส่งข้อความ (Discord, IRC เป็นต้น)
เพิ่มผู้ให้บริการโมเดล (LLM, พร็อกซี หรือ endpoint แบบกำหนดเอง)
ลงทะเบียนเครื่องมือเอเจนต์, hook เหตุการณ์ หรือบริการ - อ่านต่อด้านล่าง
สำหรับ Plugin ช่องทางที่ไม่รับประกันว่าจะถูกติดตั้งเมื่อการเริ่มใช้งาน/การตั้งค่า
ทำงาน ให้ใช้ createOptionalChannelSetupSurface(...) จาก
openclaw/plugin-sdk/channel-setup ซึ่งจะสร้างคู่ setup adapter + wizard
ที่ประกาศข้อกำหนดการติดตั้ง และปิดกั้นการเขียนค่าคอนฟิกจริงจนกว่า Plugin จะถูกติดตั้ง
เริ่มต้นอย่างรวดเร็ว: Plugin เครื่องมือ
คำแนะนำนี้สร้าง Plugin ขั้นต่ำที่ลงทะเบียนเครื่องมือเอเจนต์ Plugin ช่องทาง และ Plugin ผู้ให้บริการมีคู่มือเฉพาะที่ลิงก์ไว้ด้านบน
สร้างแพ็กเกจและ manifest
{
"name": "@myorg/openclaw-my-plugin",
"version": "1.0.0",
"type": "module",
"openclaw": {
"extensions": ["./index.ts"],
"compat": {
"pluginApi": ">=2026.3.24-beta.2",
"minGatewayVersion": "2026.3.24-beta.2"
},
"build": {
"openclawVersion": "2026.3.24-beta.2",
"pluginSdkVersion": "2026.3.24-beta.2"
}
}
}
{
"id": "my-plugin",
"name": "My Plugin",
"description": "Adds a custom tool to OpenClaw",
"contracts": {
"tools": ["my_tool"]
},
"activation": {
"onStartup": true
},
"configSchema": {
"type": "object",
"additionalProperties": false
}
}
ทุก Plugin ต้องมี manifest แม้จะไม่มีค่าคอนฟิกก็ตาม เครื่องมือที่ลงทะเบียนตอนรันไทม์
ต้องถูกระบุไว้ใน contracts.tools เพื่อให้ OpenClaw ค้นพบ Plugin เจ้าของ
ได้โดยไม่ต้องโหลดรันไทม์ของทุก Plugin นอกจากนี้ Plugin ควรประกาศ
activation.onStartup อย่างตั้งใจ ตัวอย่างนี้ตั้งค่าเป็น true ดู
Manifest สำหรับ schema ฉบับเต็ม snippet สำหรับเผยแพร่ ClawHub
แบบ canonical อยู่ใน docs/snippets/plugin-publish/
เขียนจุดเข้าใช้งาน
// index.ts
import { definePluginEntry } from "openclaw/plugin-sdk/plugin-entry";
import { Type } from "@sinclair/typebox";
export default definePluginEntry({
id: "my-plugin",
name: "My Plugin",
description: "Adds a custom tool to OpenClaw",
register(api) {
api.registerTool({
name: "my_tool",
description: "Do a thing",
parameters: Type.Object({ input: Type.String() }),
async execute(_id, params) {
return { content: [{ type: "text", text: `Got: ${params.input}` }] };
},
});
},
});
definePluginEntry ใช้สำหรับ Plugin ที่ไม่ใช่ช่องทาง สำหรับช่องทาง ให้ใช้
defineChannelPluginEntry - ดู Plugin ช่องทาง
สำหรับตัวเลือกจุดเข้าใช้งานทั้งหมด ดู จุดเข้าใช้งาน
ทดสอบและเผยแพร่
Plugin ภายนอก: ตรวจสอบและเผยแพร่ด้วย ClawHub จากนั้นติดตั้ง:
clawhub package publish your-org/your-plugin --dry-run
clawhub package publish your-org/your-plugin
openclaw plugins install clawhub:@myorg/openclaw-my-plugin
สเปกแพ็กเกจแบบเปล่า เช่น @myorg/openclaw-my-plugin จะติดตั้งจาก npm ในช่วง
เปลี่ยนผ่านการเปิดตัว ใช้ clawhub: เมื่อต้องการการ resolve ผ่าน ClawHub
Plugin ในที่เก็บ: วางไว้ใต้แผนผังเวิร์กสเปซ Plugin ที่รวมมา - จะถูกค้นพบโดยอัตโนมัติ
pnpm test -- <bundled-plugin-root>/my-plugin/
ความสามารถของ Plugin
Plugin เดียวสามารถลงทะเบียนความสามารถจำนวนเท่าใดก็ได้ผ่านอ็อบเจ็กต์ api:
| ความสามารถ | วิธีลงทะเบียน | คู่มือโดยละเอียด |
|---|---|---|
| การอนุมานข้อความ (LLM) | api.registerProvider(...) |
Plugin ผู้ให้บริการ |
| backend การอนุมานของ CLI | api.registerCliBackend(...) |
backend ของ CLI |
| ช่องทาง / การรับส่งข้อความ | api.registerChannel(...) |
Plugin ช่องทาง |
| เสียงพูด (TTS/STT) | api.registerSpeechProvider(...) |
Plugin ผู้ให้บริการ |
| การถอดเสียงแบบเรียลไทม์ | api.registerRealtimeTranscriptionProvider(...) |
Plugin ผู้ให้บริการ |
| เสียงแบบเรียลไทม์ | api.registerRealtimeVoiceProvider(...) |
Plugin ผู้ให้บริการ |
| การเข้าใจสื่อ | api.registerMediaUnderstandingProvider(...) |
Plugin ผู้ให้บริการ |
| การสร้างภาพ | api.registerImageGenerationProvider(...) |
Plugin ผู้ให้บริการ |
| การสร้างเพลง | api.registerMusicGenerationProvider(...) |
Plugin ผู้ให้บริการ |
| การสร้างวิดีโอ | api.registerVideoGenerationProvider(...) |
Plugin ผู้ให้บริการ |
| การดึงเว็บ | api.registerWebFetchProvider(...) |
Plugin ผู้ให้บริการ |
| การค้นเว็บ | api.registerWebSearchProvider(...) |
Plugin ผู้ให้บริการ |
| middleware ผลลัพธ์เครื่องมือ | api.registerAgentToolResultMiddleware(...) |
ภาพรวม SDK |
| เครื่องมือเอเจนต์ | api.registerTool(...) |
ด้านล่าง |
| คำสั่งแบบกำหนดเอง | api.registerCommand(...) |
จุดเข้าใช้งาน |
| hook ของ Plugin | api.on(...) |
hook ของ Plugin |
| hook เหตุการณ์ภายใน | api.registerHook(...) |
จุดเข้าใช้งาน |
| route ของ HTTP | api.registerHttpRoute(...) |
ภายใน |
| คำสั่งย่อยของ CLI | api.registerCli(...) |
จุดเข้าใช้งาน |
สำหรับ API การลงทะเบียนฉบับเต็ม ดู ภาพรวม SDK
Plugin ที่รวมมาสามารถใช้ api.registerAgentToolResultMiddleware(...) เมื่อจำเป็นต้อง
เขียนผลลัพธ์เครื่องมือใหม่แบบ async ก่อนที่โมเดลจะเห็นเอาต์พุต ประกาศรันไทม์
เป้าหมายใน contracts.agentToolResultMiddleware เช่น
["pi", "codex"] นี่คือ seam ที่เชื่อถือได้สำหรับ Plugin ที่รวมมา; Plugin
ภายนอกควรเลือกใช้ hook ของ OpenClaw Plugin ตามปกติ เว้นแต่ OpenClaw จะเพิ่ม
นโยบายความเชื่อถือที่ชัดเจนสำหรับความสามารถนี้
หาก Plugin ของคุณลงทะเบียนเมธอด RPC ของ gateway แบบกำหนดเอง ให้เก็บไว้บน
prefix เฉพาะ Plugin namespace สำหรับผู้ดูแลระบบของ core (config.*,
exec.approvals.*, wizard.*, update.*) ยังคงถูกสงวนไว้และ resolve เป็น
operator.admin เสมอ แม้ว่า Plugin จะขอ scope ที่แคบกว่าก็ตาม
ความหมายของตัวป้องกัน hook ที่ควรจำ:
before_tool_call:{ block: true }เป็นจุดสิ้นสุดและหยุด handler ที่มีลำดับความสำคัญต่ำกว่าbefore_tool_call:{ block: false }ถือว่าไม่มีการตัดสินใจbefore_tool_call:{ requireApproval: true }หยุดการทำงานของเอเจนต์ชั่วคราวและแจ้งผู้ใช้ให้อนุมัติผ่าน overlay การอนุมัติ exec, ปุ่ม Telegram, interaction ของ Discord หรือคำสั่ง/approveบนช่องทางใดก็ได้before_install:{ block: true }เป็นจุดสิ้นสุดและหยุด handler ที่มีลำดับความสำคัญต่ำกว่าbefore_install:{ block: false }ถือว่าไม่มีการตัดสินใจmessage_sending:{ cancel: true }เป็นจุดสิ้นสุดและหยุด handler ที่มีลำดับความสำคัญต่ำกว่าmessage_sending:{ cancel: false }ถือว่าไม่มีการตัดสินใจmessage_received: ควรใช้ฟิลด์ typedthreadIdเมื่อคุณต้องการกำหนดเส้นทางเธรด/หัวข้อขาเข้า เก็บmetadataไว้สำหรับข้อมูลเพิ่มเติมเฉพาะช่องทางmessage_sending: ควรใช้ฟิลด์ routing แบบ typedreplyToId/threadIdแทนคีย์ metadata เฉพาะช่องทาง
คำสั่ง /approve จัดการทั้งการอนุมัติ exec และ Plugin ด้วย fallback แบบจำกัด: เมื่อไม่พบ id การอนุมัติ exec OpenClaw จะลอง id เดิมอีกครั้งผ่านการอนุมัติ Plugin การส่งต่อการอนุมัติ Plugin สามารถกำหนดค่าแยกได้ผ่าน approvals.plugin ใน config
หากระบบการอนุมัติแบบกำหนดเองต้องตรวจจับกรณี fallback แบบจำกัดเดียวกันนี้
ควรใช้ isApprovalNotFoundError จาก openclaw/plugin-sdk/error-runtime
แทนการจับคู่สตริงหมดอายุการอนุมัติด้วยตนเอง
ดู hook ของ Plugin สำหรับตัวอย่างและข้อมูลอ้างอิง hook
การลงทะเบียนเครื่องมือเอเจนต์
เครื่องมือคือฟังก์ชันที่มีชนิดซึ่ง LLM สามารถเรียกได้ อาจเป็นแบบจำเป็น (พร้อมใช้งานเสมอ) หรือแบบทางเลือก (ผู้ใช้เลือกใช้):
register(api) {
// Required tool - always available
api.registerTool({
name: "my_tool",
description: "Do a thing",
parameters: Type.Object({ input: Type.String() }),
async execute(_id, params) {
return { content: [{ type: "text", text: params.input }] };
},
});
// Optional tool - user must add to allowlist
api.registerTool(
{
name: "workflow_tool",
description: "Run a workflow",
parameters: Type.Object({ pipeline: Type.String() }),
async execute(_id, params) {
return { content: [{ type: "text", text: params.pipeline }] };
},
},
{ optional: true },
);
}
ทุกเครื่องมือที่ลงทะเบียนด้วย api.registerTool(...) ต้องถูกประกาศใน
manifest ของ Plugin ด้วย:
{
"contracts": {
"tools": ["my_tool", "workflow_tool"]
},
"toolMetadata": {
"workflow_tool": {
"optional": true
}
}
}
OpenClaw จับและแคช descriptor ที่ผ่านการตรวจสอบแล้วจากเครื่องมือที่ลงทะเบียนไว้
ดังนั้น Plugin จึงไม่ต้องทำซ้ำ description หรือข้อมูล schema ใน manifest
สัญญา manifest ประกาศเฉพาะความเป็นเจ้าของและการค้นพบเท่านั้น การเรียกใช้งานยังคงเรียก
implementation ของเครื่องมือที่ลงทะเบียนแบบสดอยู่
ตั้งค่า toolMetadata.<tool>.optional: true สำหรับเครื่องมือที่ลงทะเบียนด้วย
api.registerTool(..., { optional: true }) เพื่อให้ OpenClaw สามารถหลีกเลี่ยงการโหลด
runtime ของ Plugin นั้นจนกว่าเครื่องมือจะถูกเพิ่มเข้า allowlist อย่างชัดเจน
ผู้ใช้เปิดใช้เครื่องมือแบบ optional ใน config:
{
tools: { allow: ["workflow_tool"] },
}
- ชื่อเครื่องมือต้องไม่ชนกับเครื่องมือของ core (รายการที่ขัดแย้งจะถูกข้าม)
- เครื่องมือที่มีอ็อบเจกต์การลงทะเบียนผิดรูปแบบ รวมถึงไม่มี
parametersจะถูกข้ามและรายงานใน diagnostics ของ Plugin แทนที่จะทำให้การรัน agent ล้มเหลว - ใช้
optional: trueสำหรับเครื่องมือที่มี side effects หรือต้องการ binary เพิ่มเติม - ผู้ใช้สามารถเปิดใช้เครื่องมือทั้งหมดจาก Plugin ได้โดยเพิ่ม plugin id ลงใน
tools.allow
การลงทะเบียนคำสั่ง CLI
Plugin สามารถเพิ่มกลุ่มคำสั่ง root ของ openclaw ด้วย api.registerCli ได้ ระบุ
descriptors สำหรับ root ของคำสั่งระดับบนสุดทุกคำสั่ง เพื่อให้ OpenClaw สามารถแสดงและ route
คำสั่งได้โดยไม่ต้องโหลด runtime ของทุก Plugin ล่วงหน้า
register(api) {
api.registerCli(
({ program }) => {
const demo = program
.command("demo-plugin")
.description("Run demo plugin commands");
demo
.command("ping")
.description("Check that the plugin CLI is executable")
.action(() => {
console.log("demo-plugin:pong");
});
},
{
descriptors: [
{
name: "demo-plugin",
description: "Run demo plugin commands",
hasSubcommands: true,
},
],
},
);
}
หลังติดตั้ง ให้ตรวจสอบการลงทะเบียน runtime และเรียกใช้คำสั่ง:
openclaw plugins inspect demo-plugin --runtime --json
openclaw demo-plugin ping
ข้อตกลงการ import
ให้ import จาก path แบบเจาะจง openclaw/plugin-sdk/<subpath> เสมอ:
// Wrong: monolithic root (deprecated, will be removed)
สำหรับข้อมูลอ้างอิง subpath ทั้งหมด โปรดดู ภาพรวม SDK
ภายใน Plugin ของคุณ ให้ใช้ไฟล์ barrel ภายในเครื่อง (api.ts, runtime-api.ts) สำหรับ
internal imports - ห้าม import Plugin ของคุณเองผ่าน path SDK ของมัน
สำหรับ provider plugins ให้เก็บ helper เฉพาะ provider ไว้ใน barrel ระดับ package-root เหล่านั้น เว้นแต่ seam จะเป็น generic อย่างแท้จริง ตัวอย่าง bundled ปัจจุบัน:
- Anthropic: wrapper สตรีม Claude และ helper ของ
service_tier/ beta - OpenAI: provider builders, helper ของ default-model, realtime providers
- OpenRouter: provider builder พร้อม helper สำหรับ onboarding/config
หาก helper มีประโยชน์เฉพาะภายใน package ของ bundled provider เดียว ให้เก็บไว้บน
seam ระดับ package-root นั้นแทนการยกระดับเข้าไปใน openclaw/plugin-sdk/*
seam helper ที่สร้างขึ้นบางรายการของ openclaw/plugin-sdk/<bundled-id> ยังคงมีอยู่สำหรับ
การบำรุงรักษา bundled-plugin เมื่อมีการติดตามการใช้งานโดยเจ้าของ ให้ถือว่าสิ่งเหล่านี้เป็น
surface ที่สงวนไว้ ไม่ใช่รูปแบบเริ่มต้นสำหรับ third-party plugins ใหม่
เช็กลิสต์ก่อนส่ง
OPENCLAW_DOCS_MARKER:calloutOpen:Q2hlY2s
package.json มี metadata openclaw ที่ถูกต้อง
OPENCLAW_DOCS_MARKER:calloutClose:
OPENCLAW_DOCS_MARKER:calloutOpen:Q2hlY2s มี manifest openclaw.plugin.json และถูกต้อง OPENCLAW_DOCS_MARKER:calloutClose:
OPENCLAW_DOCS_MARKER:calloutOpen:Q2hlY2s
entry point ใช้ defineChannelPluginEntry หรือ definePluginEntry
OPENCLAW_DOCS_MARKER:calloutClose:
OPENCLAW_DOCS_MARKER:calloutOpen:Q2hlY2s
imports ทั้งหมดใช้ path แบบเจาะจง plugin-sdk/<subpath>
OPENCLAW_DOCS_MARKER:calloutClose: