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 ประเภทใด?

สำหรับ 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: ควรใช้ฟิลด์ typed threadId เมื่อคุณต้องการกำหนดเส้นทางเธรด/หัวข้อขาเข้า เก็บ metadata ไว้สำหรับข้อมูลเพิ่มเติมเฉพาะช่องทาง
    • message_sending: ควรใช้ฟิลด์ routing แบบ typed replyToId / 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: