Plugin maintainer reference

รายละเอียดภายในสถาปัตยกรรม Plugin

สำหรับโมเดลความสามารถสาธารณะ รูปแบบ Plugin และสัญญาด้านความเป็นเจ้าของ/การดำเนินการ โปรดดู สถาปัตยกรรม Plugin หน้านี้ครอบคลุมกลไกภายใน ได้แก่ ไปป์ไลน์การโหลด รีจิสทรี ฮุกขณะรัน เส้นทาง HTTP ของ Gateway พาธการนำเข้า และตารางสคีมา

ไปป์ไลน์การโหลด

เมื่อเริ่มต้น OpenClaw จะดำเนินการโดยคร่าว ๆ ดังนี้:

  1. ค้นหารูทของ Plugin ที่เป็นตัวเลือก
  2. อ่านไฟล์กำกับบันเดิลแบบเนทีฟหรือแบบที่เข้ากันได้ รวมถึงเมทาดาทาของแพ็กเกจ
  3. ปฏิเสธตัวเลือกที่ไม่ปลอดภัย
  4. ปรับการกำหนดค่า Plugin ให้เป็นรูปแบบมาตรฐาน (plugins.enabled, allow, deny, entries, slots, load.paths)
  5. ตัดสินใจว่าจะเปิดใช้งานตัวเลือกแต่ละรายการหรือไม่
  6. โหลดโมดูลเนทีฟที่เปิดใช้งาน: โมดูลบันเดิลที่สร้างแล้วใช้ตัวโหลดเนทีฟ ส่วนซอร์ส TypeScript ภายในเครื่องจากบุคคลที่สามใช้ Jiti สำรองสำหรับกรณีฉุกเฉิน
  7. เรียกฮุกเนทีฟ register(api) และรวบรวมการลงทะเบียนไว้ในรีจิสทรี Plugin
  8. เปิดให้คำสั่งและพื้นผิวขณะรันเข้าถึงรีจิสทรี

ด่านตรวจสอบความปลอดภัยทำงาน ก่อน การดำเนินการขณะรัน การค้นหาจะบล็อกตัวเลือกเมื่อ:

  • จุดเริ่มต้นที่แปลงพาธแล้วออกนอกเหนือรูทของ Plugin
  • พาธ (หรือไดเรกทอรีรูท) เปิดให้ผู้ใช้ทุกคนเขียนได้
  • สำหรับ Plugin ที่ไม่ได้รวมมาให้ ความเป็นเจ้าของพาธไม่ตรงกับ uid ปัจจุบัน (หรือ root)

สำหรับไดเรกทอรีที่รวมมาให้และเปิดให้ผู้ใช้ทุกคนเขียนได้ ระบบจะพยายามซ่อมแซมด้วย chmod ในตำแหน่งเดิมก่อน (การติดตั้ง npm/แบบโกลบอลอาจส่งมอบไดเรกทอรีแพ็กเกจด้วยสิทธิ์ 0777) แล้วจึงตรวจสอบด่านอีกครั้ง; ระบบจะข้ามการตรวจสอบความเป็นเจ้าของทั้งหมดสำหรับแหล่งที่มาซึ่งรวมมาให้

ตัวเลือกที่ถูกบล็อกยังคงมีรหัส Plugin อยู่ในการวินิจฉัยที่ส่งออกเมื่อทราบรหัสดังกล่าว (รวมถึงรหัสที่อ่านได้จากไฟล์กำกับภายในไดเรกทอรีที่ถูกปฏิเสธด้วยเหตุผลอื่น) ดังนั้นการกำหนดค่าที่อ้างถึงรหัสดังกล่าวจะเห็น Plugin ที่ถูกบล็อกพร้อมคำเตือนด้านความปลอดภัยของพาธ แทนข้อผิดพลาด "ไม่รู้จัก Plugin" ที่ไม่เกี่ยวข้อง

ลักษณะการทำงานที่ให้ไฟล์กำกับมาก่อน

ไฟล์กำกับเป็นแหล่งข้อมูลจริงของระนาบควบคุม OpenClaw ใช้ไฟล์นี้เพื่อ:

  • ระบุ Plugin
  • ค้นหาช่องทาง/Skills/สคีมาการกำหนดค่าหรือความสามารถของบันเดิลที่ประกาศไว้
  • ตรวจสอบความถูกต้องของ plugins.entries.<id>.config
  • เพิ่มป้ายกำกับ/ข้อความตัวอย่างของ Control UI
  • แสดงเมทาดาทาการติดตั้ง/แค็ตตาล็อก
  • เก็บตัวบรรยายการเปิดใช้งานและการตั้งค่าที่ประมวลผลได้อย่างประหยัดโดยไม่ต้องโหลดส่วนขณะรันของ Plugin

สำหรับ Plugin เนทีฟ โมดูลขณะรันคือส่วนระนาบข้อมูล โมดูลนี้ลงทะเบียนลักษณะการทำงานจริง เช่น ฮุก เครื่องมือ คำสั่ง หรือโฟลว์ของผู้ให้บริการ

บล็อก activation และ setup ที่เป็นตัวเลือกในไฟล์กำกับจะยังคงอยู่ในระนาบควบคุม บล็อกเหล่านี้เป็นเพียงตัวบรรยายเมทาดาทาสำหรับการวางแผนเปิดใช้งานและการค้นหาการตั้งค่า; ไม่ได้แทนที่การลงทะเบียนขณะรัน register(...) หรือ setupEntry ผู้ใช้ข้อมูลการเปิดใช้งานแบบสดจะใช้คำใบ้เกี่ยวกับคำสั่ง ช่องทาง และผู้ให้บริการจากไฟล์กำกับ เพื่อจำกัดการโหลด Plugin ให้แคบลงก่อนสร้างรีจิสทรีในขอบเขตที่กว้างขึ้น:

  • การโหลด CLI จำกัดเฉพาะ Plugin ที่เป็นเจ้าของคำสั่งหลักที่ร้องขอ
  • การตั้งค่าช่องทาง/การแก้หา Plugin จำกัดเฉพาะ Plugin ที่เป็นเจ้าของรหัสช่องทางที่ร้องขอ
  • การตั้งค่า/การแก้หาขณะรันของผู้ให้บริการแบบระบุชัดเจน จำกัดเฉพาะ Plugin ที่เป็นเจ้าของรหัสผู้ให้บริการที่ร้องขอ
  • การวางแผนเริ่มต้น Gateway ใช้ activation.onStartup สำหรับการนำเข้าเมื่อเริ่มต้นที่ระบุชัดเจน; Plugin ที่ไม่มีเมทาดาทาการเริ่มต้นจะโหลดผ่านทริกเกอร์การเปิดใช้งานที่มีขอบเขตแคบกว่าเท่านั้น

ตัววางแผนการเปิดใช้งานมีทั้ง API ที่ส่งคืนเฉพาะรหัสสำหรับผู้เรียกเดิม และ API แผนสำหรับการวินิจฉัย รายการในแผนรายงานเหตุผลที่เลือก Plugin โดยแยกคำใบ้ activation.* ที่ระบุชัดเจนออกจากการสำรองตามความเป็นเจ้าของในไฟล์กำกับ:

เหตุผล (จากคำใบ้ activation.*) เหตุผล (จากความเป็นเจ้าของในไฟล์กำกับ)
activation-agent-harness-hint
activation-capability-hint
activation-channel-hint manifest-channel-owner (channels)
activation-command-hint manifest-command-alias (commandAliases)
activation-provider-hint manifest-provider-owner (providers), manifest-setup-provider-owner (setup.providers)
activation-route-hint
— (ทริกเกอร์ฮุกไม่มีรูปแบบคำใบ้) manifest-hook-owner (hooks), manifest-tool-contract (contracts.tools)

การแยกเหตุผลนี้คือขอบเขตความเข้ากันได้: เมทาดาทา Plugin ที่มีอยู่ยังคงทำงานต่อไป ขณะที่โค้ดใหม่สามารถตรวจพบคำใบ้แบบกว้างหรือลักษณะการทำงานสำรอง โดยไม่เปลี่ยนความหมายของการโหลดขณะรัน

การโหลดล่วงหน้าขณะรันในช่วงประมวลผลคำขอที่ขอขอบเขตแบบกว้าง all ยังคงสร้างชุดรหัส Plugin ที่มีผลแบบระบุชัดเจนจากการกำหนดค่า การวางแผนเริ่มต้น ช่องทางที่กำหนดค่าไว้ สล็อต และกฎการเปิดใช้งานอัตโนมัติ (resolveEffectivePluginIds ใน src/plugins/effective-plugin-ids.ts) หากชุดที่สร้างขึ้นนั้นว่างเปล่า OpenClaw จะคงขอบเขตให้ว่างไว้แทนการขยายไปยัง Plugin ทุกตัวที่ค้นพบได้

การค้นหาการตั้งค่าจะให้ความสำคัญกับรหัสที่ตัวบรรยายเป็นเจ้าของ เช่น setup.providers และ setup.cliBackends เพื่อจำกัด Plugin ที่เป็นตัวเลือก ก่อนสำรองไปใช้ setup-api สำหรับ Plugin ที่ยังต้องใช้ฮุกขณะรันในช่วงตั้งค่า รายการตั้งค่าผู้ให้บริการ ใช้ providerAuthChoices จากไฟล์กำกับ ตัวเลือกการตั้งค่าที่ได้จากตัวบรรยาย และเมทาดาทาแค็ตตาล็อกการติดตั้งโดยไม่โหลดส่วนขณะรันของผู้ให้บริการ การระบุ setup.requiresRuntime: false อย่างชัดเจนเป็นจุดตัดที่ใช้เฉพาะตัวบรรยาย; การไม่ระบุ requiresRuntime จะคงการสำรองไปใช้ setup-api แบบเดิมไว้เพื่อความเข้ากันได้ หาก Plugin ที่ค้นพบมากกว่าหนึ่งตัวอ้างสิทธิ์ในรหัสผู้ให้บริการตั้งค่าหรือแบ็กเอนด์ CLI ที่ปรับเป็นรูปแบบมาตรฐานเดียวกัน การค้นหาการตั้งค่าจะปฏิเสธเจ้าของที่กำกวม แทนการอาศัยลำดับการค้นพบ เมื่อส่วนขณะรันของการตั้งค่าทำงานจริง การวินิจฉัยของรีจิสทรีจะรายงานความคลาดเคลื่อนระหว่าง setup.providers / setup.cliBackends กับผู้ให้บริการหรือแบ็กเอนด์ CLI ที่ setup-api ลงทะเบียนจริง โดยไม่บล็อก Plugin แบบเดิม

ขอบเขตแคชของ Plugin

OpenClaw ไม่แคชผลการค้นหา Plugin หรือข้อมูลรีจิสทรีจากไฟล์กำกับโดยตรง ภายใต้ช่วงเวลาตามนาฬิกา การติดตั้ง การแก้ไขไฟล์กำกับ และการเปลี่ยนแปลงพาธการโหลด ต้องมองเห็นได้ในการอ่านเมทาดาทาอย่างชัดเจนหรือการสร้างสแนปช็อตครั้งถัดไป ตัวแยกวิเคราะห์ไฟล์กำกับจะเก็บแคชลายเซ็นไฟล์แบบมีขอบเขต โดยใช้พาธไฟล์กำกับที่เปิด ร่วมกับอุปกรณ์/inode ขนาด และ mtime/ctime เป็นคีย์; แคชดังกล่าวมีไว้เพียงเพื่อหลีกเลี่ยง การแยกวิเคราะห์ไบต์เดิมที่ไม่เปลี่ยนแปลงซ้ำ และต้องไม่แคชคำตอบเกี่ยวกับการค้นหา รีจิสทรี เจ้าของ หรือนโยบาย

เส้นทางด่วนของเมทาดาทาที่ปลอดภัยคือความเป็นเจ้าของออบเจ็กต์อย่างชัดเจน ไม่ใช่แคชที่ซ่อนอยู่ เส้นทางที่ใช้งานหนักระหว่างการเริ่มต้น Gateway ควรส่ง PluginMetadataSnapshot ปัจจุบัน PluginLookUpTable ที่สร้างขึ้น หรือรีจิสทรีไฟล์กำกับที่ระบุชัดเจนไปตามสายการเรียก การตรวจสอบความถูกต้องของการกำหนดค่า การเปิดใช้งานอัตโนมัติเมื่อเริ่มต้น การบูตสแตรป Plugin และการเลือกผู้ให้บริการสามารถใช้ออบเจ็กต์เหล่านี้ซ้ำได้ ตราบใดที่ออบเจ็กต์ยังแทนการกำหนดค่าและรายการ Plugin ปัจจุบัน การค้นหาการตั้งค่ายังคงสร้างเมทาดาทาไฟล์กำกับใหม่ตามต้องการ เว้นแต่เส้นทางการตั้งค่านั้นได้รับรีจิสทรีไฟล์กำกับอย่างชัดเจน; ให้คงลักษณะนี้เป็นการสำรองสำหรับเส้นทางที่เรียกใช้น้อย แทนการเพิ่มแคชการค้นหาที่ซ่อนอยู่ เมื่ออินพุตเปลี่ยน ให้สร้างสแนปช็อตใหม่และแทนที่ของเดิม แทนการแก้ไขออบเจ็กต์เดิม หรือเก็บสำเนาในอดีต มุมมองของรีจิสทรี Plugin ที่ใช้งานอยู่และตัวช่วยบูตสแตรปช่องทาง ที่รวมมาให้ควรคำนวณใหม่จากรีจิสทรี/รูทปัจจุบัน แผนที่อายุสั้นใช้ได้ภายในหนึ่งการเรียก เพื่อขจัดงานซ้ำหรือป้องกันการกลับเข้าซ้ำ แต่ต้องไม่กลายเป็นแคชเมทาดาทาระดับโพรเซส

สำหรับการโหลด Plugin ชั้นแคชแบบคงอยู่คือการโหลดขณะรัน โดยอาจใช้สถานะตัวโหลดซ้ำ เมื่อมีการโหลดโค้ดหรืออาร์ติแฟกต์ที่ติดตั้งจริง เช่น:

  • PluginLoaderCacheState และรีจิสทรีขณะรันที่ใช้งานอยู่ซึ่งเข้ากันได้
  • แคช jiti/โมดูล และแคชตัวโหลดพื้นผิวสาธารณะที่ใช้เพื่อหลีกเลี่ยงการนำเข้าพื้นผิวขณะรันเดียวกันซ้ำ
  • แคชระบบไฟล์สำหรับอาร์ติแฟกต์ Plugin ที่ติดตั้ง
  • แผนที่อายุสั้นต่อการเรียกสำหรับการปรับพาธเป็นรูปแบบมาตรฐานหรือการแก้รายการซ้ำ

แคชเหล่านั้นเป็นรายละเอียดการทำงานของระนาบข้อมูล และต้องไม่ตอบคำถามของระนาบควบคุม เช่น "Plugin ใดเป็นเจ้าของผู้ให้บริการนี้?" เว้นแต่ผู้เรียกจะขอให้โหลดขณะรันโดยเจตนา

อย่าเพิ่มแคชแบบคงอยู่หรือแคชตามช่วงเวลาสำหรับ:

  • ผลการค้นหา
  • รีจิสทรีไฟล์กำกับโดยตรง
  • รีจิสทรีไฟล์กำกับที่สร้างใหม่จากดัชนี Plugin ที่ติดตั้ง
  • การค้นหาเจ้าของผู้ให้บริการ การระงับโมเดล นโยบายผู้ให้บริการ หรือเมทาดาทาอาร์ติแฟกต์สาธารณะ
  • คำตอบอื่นใดที่ได้จากไฟล์กำกับ ซึ่งไฟล์กำกับ ดัชนีที่ติดตั้ง หรือพาธการโหลดที่เปลี่ยนแปลง ควรมองเห็นได้ในการอ่านเมทาดาทาครั้งถัดไป

ผู้เรียกที่สร้างเมทาดาทาไฟล์กำกับใหม่จากดัชนี Plugin ที่ติดตั้งและเก็บไว้อย่างถาวร จะสร้างรีจิสทรีดังกล่าวใหม่ตามต้องการ ดัชนีที่ติดตั้งคือสถานะระนาบแหล่งข้อมูลที่คงทน; ไม่ใช่แคชเมทาดาทาในโพรเซสที่ซ่อนอยู่

โมเดลรีจิสทรี

Plugin ที่โหลดแล้วจะไม่แก้ไขตัวแปรโกลบอลของแกนหลักแบบสุ่มโดยตรง แต่จะลงทะเบียนเข้าสู่รีจิสทรี Plugin ส่วนกลาง (PluginRegistry ใน src/plugins/registry-types.ts) ซึ่งติดตามระเบียน Plugin (อัตลักษณ์ แหล่งที่มา ต้นทาง สถานะ การวินิจฉัย) รวมถึงอาร์เรย์สำหรับความสามารถทุกประเภท ได้แก่ เครื่องมือ ฮุกแบบเดิมและฮุกแบบมีชนิด ช่องทาง ผู้ให้บริการ ตัวจัดการ RPC ของ Gateway เส้นทาง HTTP ตัวลงทะเบียน CLI บริการเบื้องหลัง คำสั่งที่ Plugin เป็นเจ้าของ และกลุ่มผู้ให้บริการแบบมีชนิดอีกหลายสิบประเภท (เสียงพูด เอ็มเบดดิง การสร้างรูปภาพ/วิดีโอ/เพลง การดึงข้อมูล/ค้นหาเว็บ ชุดควบคุมเอเจนต์ การดำเนินการกับเซสชัน และอื่น ๆ)

จากนั้นฟีเจอร์แกนหลักจะอ่านจากรีจิสทรีดังกล่าวแทนการติดต่อโมดูล Plugin โดยตรง ทำให้การโหลดเป็นแบบทิศทางเดียว:

  • โมดูล Plugin -> การลงทะเบียนรีจิสทรี
  • ส่วนขณะรันแกนหลัก -> การใช้รีจิสทรี

การแยกส่วนนี้สำคัญต่อการบำรุงรักษา เพราะพื้นผิวแกนหลักส่วนใหญ่ต้องการจุดเชื่อมต่อเพียงจุดเดียว: "อ่านรีจิสทรี" ไม่ใช่ "จัดการโมดูล Plugin ทุกตัวเป็นกรณีพิเศษ"

คอลแบ็กการผูกการสนทนา

Plugin ที่ผูกการสนทนาสามารถตอบสนองเมื่อการอนุมัติได้รับการตัดสินแล้ว

ใช้ api.onConversationBindingResolved(...) เพื่อรับคอลแบ็กหลังคำขอผูกได้รับการอนุมัติหรือปฏิเสธ:

ts
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);    });  },};

ฟิลด์เพย์โหลดของคอลแบ็ก:

  • status: "approved" หรือ "denied"
  • decision: "allow-once", "allow-always" หรือ "deny"
  • binding: การผูกที่ได้รับการตัดสินแล้วสำหรับคำขอที่อนุมัติ
  • request: สรุปคำขอเดิม คำใบ้การยกเลิกการเชื่อมโยง รหัสผู้ส่ง และเมทาดาทาการสนทนา

คอลแบ็กนี้ใช้เพื่อแจ้งเตือนเท่านั้น ไม่ได้เปลี่ยนว่าใครได้รับอนุญาตให้ผูกการสนทนา และจะทำงานหลังการประมวลผลการอนุมัติของแกนหลักเสร็จสิ้น

ฮุกขณะรันของผู้ให้บริการ

Plugin ผู้ให้บริการมีสามชั้น:

  • เมทาดาทาไฟล์กำกับ สำหรับการค้นหาก่อนรันที่ประหยัด: setup.providers[].envVars, providerAuthEnvVars สำหรับความเข้ากันได้ซึ่งเลิกแนะนำแล้ว, providerAuthAliases, providerAuthChoices และ channelEnvVars
  • ฮุกช่วงกำหนดค่า: catalog (discovery แบบเดิม) รวมถึง applyConfigDefaults
  • ฮุกขณะรัน: ฮุกตัวเลือกมากกว่า 40 รายการ ครอบคลุมการยืนยันตัวตน การแก้หาโมเดล การห่อสตรีม ระดับการคิด นโยบายการเล่นซ้ำ และปลายทางข้อมูลการใช้งาน โปรดดู ลำดับและการใช้งานฮุก

OpenClaw ยังคงเป็นเจ้าของลูปเอเจนต์ทั่วไป การสลับไปใช้ระบบสำรอง การจัดการบทสนทนาที่บันทึกไว้ และนโยบายเครื่องมือ ฮุกเหล่านี้เป็นพื้นผิวส่วนขยายสำหรับลักษณะการทำงานเฉพาะผู้ให้บริการ โดยไม่ต้องมีระบบขนส่งการอนุมานแบบกำหนดเองทั้งชุด

ใช้ setup.providers[].envVars ในไฟล์ manifest เมื่อผู้ให้บริการมีข้อมูลรับรองที่อิงตัวแปรสภาพแวดล้อม ซึ่งเส้นทางทั่วไปสำหรับการยืนยันตัวตน/สถานะ/ตัวเลือกโมเดลควรมองเห็นได้โดยไม่ต้องโหลดรันไทม์ของ Plugin โดยอะแดปเตอร์ความเข้ากันได้ยังคงอ่าน providerAuthEnvVars ที่เลิกใช้แล้วในช่วงเวลาการเลิกใช้ และ Plugin ที่ไม่ได้รวมมาในชุดซึ่งใช้งานฟิลด์นี้จะได้รับการวินิจฉัย manifest ใช้ providerAuthAliases ในไฟล์ manifest เมื่อรหัสผู้ให้บริการหนึ่งควรใช้ตัวแปรสภาพแวดล้อม โปรไฟล์การยืนยันตัวตน การยืนยันตัวตนที่อิงการกำหนดค่า และตัวเลือกการเริ่มต้นใช้งานด้วยคีย์ API ของรหัสผู้ให้บริการอีกรหัสหนึ่งร่วมกัน ใช้ providerAuthChoices ในไฟล์ manifest เมื่อพื้นผิว CLI สำหรับการเริ่มต้นใช้งาน/การเลือกวิธียืนยันตัวตนควรทราบรหัสตัวเลือก ป้ายกำกับกลุ่ม และการเชื่อมโยงการยืนยันตัวตนแบบง่ายด้วยแฟล็กเดียวของผู้ให้บริการ โดยไม่ต้องโหลดรันไทม์ของผู้ให้บริการ เก็บ envVars ของรันไทม์ผู้ให้บริการไว้สำหรับคำแนะนำที่แสดงต่อผู้ปฏิบัติงาน เช่น ป้ายกำกับการเริ่มต้นใช้งาน หรือตัวแปรสำหรับตั้งค่า OAuth client-id/client-secret

ใช้ channelEnvVars ในไฟล์ manifest เมื่อช่องทางมีการยืนยันตัวตนหรือการตั้งค่าที่ขับเคลื่อนด้วยตัวแปรสภาพแวดล้อม ซึ่งกลไกสำรองทั่วไปจากตัวแปรสภาพแวดล้อมของเชลล์ การตรวจสอบการกำหนดค่า/สถานะ หรือพรอมต์การตั้งค่าควรมองเห็นได้โดยไม่ต้องโหลดรันไทม์ของช่องทาง

ลำดับและการใช้งาน Hook

สำหรับ Plugin ของโมเดล/ผู้ให้บริการ OpenClaw จะเรียก Hook ตามลำดับคร่าว ๆ ดังนี้ คอลัมน์ "ควรใช้เมื่อใด" เป็นคู่มือสำหรับตัดสินใจอย่างรวดเร็ว ฟิลด์ของผู้ให้บริการที่มีไว้เพื่อความเข้ากันได้เท่านั้นและ OpenClaw ไม่ได้เรียกใช้อีกต่อไป เช่น ProviderPlugin.capabilities และ suppressBuiltInModel จะไม่แสดงไว้ที่นี่โดยเจตนา

Hook ทำหน้าที่อะไร ควรใช้เมื่อ
catalog เผยแพร่การกำหนดค่าผู้ให้บริการไปยัง models.providers ระหว่างการสร้าง models.json ผู้ให้บริการเป็นเจ้าของแค็ตตาล็อกหรือค่าเริ่มต้นของ URL ฐาน
applyConfigDefaults ใช้ค่าเริ่มต้นการกำหนดค่าส่วนกลางที่ผู้ให้บริการเป็นเจ้าของระหว่างการสร้างการกำหนดค่าให้สมบูรณ์ ค่าเริ่มต้นขึ้นอยู่กับโหมดการยืนยันตัวตน สภาพแวดล้อม หรือความหมายของตระกูลโมเดลของผู้ให้บริการ
(การค้นหาโมเดลในตัว) OpenClaw ลองใช้เส้นทางรีจิสทรี/แค็ตตาล็อกปกติก่อน (ไม่ใช่ฮุกของ Plugin)
normalizeModelId ปรับนามแฝงรหัสโมเดลแบบเก่าหรือรุ่นตัวอย่างให้เป็นมาตรฐานก่อนค้นหา ผู้ให้บริการเป็นเจ้าของการล้างนามแฝงก่อนการแปลงโมเดลเป็นรูปแบบมาตรฐาน
normalizeTransport ปรับ api / baseUrl ของตระกูลผู้ให้บริการให้เป็นมาตรฐานก่อนประกอบโมเดลทั่วไป ผู้ให้บริการเป็นเจ้าของการล้างการขนส่งสำหรับรหัสผู้ให้บริการแบบกำหนดเองในตระกูลการขนส่งเดียวกัน
normalizeConfig ปรับ models.providers.<id> ให้เป็นมาตรฐานก่อนการแปลงค่ารันไทม์/ผู้ให้บริการ ผู้ให้บริการต้องการล้างการกำหนดค่าที่ควรอยู่กับ Plugin; ตัวช่วยตระกูล Google ที่รวมมาในตัวช่วยรองรับรายการกำหนดค่า Google ที่รองรับด้วย
applyNativeStreamingUsageCompat ใช้การปรับแก้ความเข้ากันได้ของข้อมูลการใช้งานแบบสตรีมมิงเนทีฟกับผู้ให้บริการในการกำหนดค่า ผู้ให้บริการต้องการแก้ไขข้อมูลเมตาการใช้งานแบบสตรีมมิงเนทีฟตามเอนด์พอยต์
resolveConfigApiKey แปลงการยืนยันตัวตนด้วยเครื่องหมายสภาพแวดล้อมสำหรับผู้ให้บริการในการกำหนดค่าก่อนโหลดการยืนยันตัวตนของรันไทม์ ผู้ให้บริการเปิดเผยฮุกของตนเองสำหรับแปลงคีย์ API จากเครื่องหมายสภาพแวดล้อม
resolveSyntheticAuth เปิดเผยการยืนยันตัวตนแบบภายในเครื่อง/โฮสต์เองหรือแบบอิงการกำหนดค่าโดยไม่จัดเก็บข้อความธรรมดา ผู้ให้บริการสามารถทำงานด้วยเครื่องหมายข้อมูลประจำตัวสังเคราะห์/ภายในเครื่อง
resolveExternalAuthProfiles ซ้อนทับโปรไฟล์การยืนยันตัวตนภายนอกที่ผู้ให้บริการเป็นเจ้าของ; ค่าเริ่มต้นของ persistence คือ runtime-only สำหรับข้อมูลประจำตัวที่ CLI/แอปเป็นเจ้าของ ผู้ให้บริการนำข้อมูลประจำตัวการยืนยันตัวตนภายนอกมาใช้ซ้ำโดยไม่จัดเก็บโทเค็นรีเฟรชที่คัดลอกมา; ประกาศ contracts.externalAuthProviders ในแมนิเฟสต์
shouldDeferSyntheticProfileAuth ลดลำดับความสำคัญของตัวแทนโปรไฟล์สังเคราะห์ที่จัดเก็บไว้ให้อยู่หลังการยืนยันตัวตนที่อิงสภาพแวดล้อม/การกำหนดค่า ผู้ให้บริการจัดเก็บโปรไฟล์ตัวแทนสังเคราะห์ที่ไม่ควรมีลำดับความสำคัญเหนือกว่า
resolveDynamicModel ทางเลือกสำรองแบบซิงก์สำหรับรหัสโมเดลที่ผู้ให้บริการเป็นเจ้าของซึ่งยังไม่มีในรีจิสทรีภายในเครื่อง ผู้ให้บริการยอมรับรหัสโมเดลต้นทางใดก็ได้
prepareDynamicModel เตรียมพร้อมแบบอะซิงก์ แล้วเรียก resolveDynamicModel อีกครั้ง ผู้ให้บริการต้องการข้อมูลเมตาจากเครือข่ายก่อนแปลงรหัสที่ไม่รู้จัก
normalizeResolvedModel ปรับแก้ครั้งสุดท้ายก่อนตัวรันที่ฝังอยู่ใช้โมเดลที่แปลงค่าแล้ว ผู้ให้บริการต้องการปรับแก้การขนส่งแต่ยังคงใช้การขนส่งหลัก
normalizeToolSchemas ปรับสคีมาของเครื่องมือให้เป็นมาตรฐานก่อนที่ตัวรันแบบฝังตัวจะเห็น ผู้ให้บริการต้องการล้างสคีมาของตระกูลการขนส่ง
inspectToolSchemas แสดงการวินิจฉัยสคีมาที่ผู้ให้บริการเป็นเจ้าของหลังการปรับให้เป็นมาตรฐาน ผู้ให้บริการต้องการคำเตือนเกี่ยวกับคีย์เวิร์ดโดยไม่ต้องสอนกฎเฉพาะผู้ให้บริการให้แกนหลัก
resolveReasoningOutputMode เลือกสัญญาเอาต์พุตการให้เหตุผลแบบเนทีฟหรือแบบมีแท็ก ผู้ให้บริการต้องการเอาต์พุตการให้เหตุผล/เอาต์พุตสุดท้ายแบบมีแท็กแทนฟิลด์เนทีฟ
prepareExtraParams ปรับพารามิเตอร์คำขอให้เป็นมาตรฐานก่อนตัวห่อหุ้มตัวเลือกสตรีมทั่วไป ผู้ให้บริการต้องการพารามิเตอร์คำขอเริ่มต้นหรือการล้างพารามิเตอร์รายผู้ให้บริการ
createStreamFn แทนที่เส้นทางสตรีมปกติทั้งหมดด้วยการขนส่งแบบกำหนดเอง ผู้ให้บริการต้องการโพรโทคอลระดับสายแบบกำหนดเอง ไม่ใช่เพียงตัวห่อหุ้ม
wrapStreamFn ตัวห่อหุ้มสตรีมหลังจากใช้ตัวห่อหุ้มทั่วไปแล้ว ผู้ให้บริการต้องการตัวห่อหุ้มความเข้ากันได้ของส่วนหัวคำขอ/เนื้อหา/โมเดลโดยไม่ใช้การขนส่งแบบกำหนดเอง
resolveTransportTurnState แนบส่วนหัวหรือข้อมูลเมตาการขนส่งเนทีฟประจำแต่ละรอบ ผู้ให้บริการต้องการให้การขนส่งทั่วไปส่งข้อมูลระบุรอบแบบเนทีฟของผู้ให้บริการ
resolveWebSocketSessionPolicy แนบส่วนหัว WebSocket เนทีฟหรือนโยบายพักเซสชัน ผู้ให้บริการต้องการให้การขนส่ง WS ทั่วไปปรับแต่งส่วนหัวเซสชันหรือนโยบายทางเลือกสำรอง
formatApiKey ตัวจัดรูปแบบโปรไฟล์การยืนยันตัวตน: โปรไฟล์ที่จัดเก็บไว้จะกลายเป็นสตริง apiKey ของรันไทม์ ผู้ให้บริการจัดเก็บข้อมูลเมตาการยืนยันตัวตนเพิ่มเติมและต้องการรูปแบบโทเค็นรันไทม์แบบกำหนดเอง
refreshOAuth แทนที่การรีเฟรช OAuth สำหรับเอนด์พอยต์รีเฟรชแบบกำหนดเองหรือนโยบายเมื่อรีเฟรชล้มเหลว ผู้ให้บริการไม่สอดคล้องกับตัวรีเฟรชร่วมของ OpenClaw
buildAuthDoctorHint คำแนะนำการซ่อมแซมที่เพิ่มต่อท้ายเมื่อการรีเฟรช OAuth ล้มเหลว ผู้ให้บริการต้องการคำแนะนำการซ่อมแซมการยืนยันตัวตนที่ผู้ให้บริการเป็นเจ้าของหลังการรีเฟรชล้มเหลว
matchesContextOverflowError ตัวตรวจจับบัฟเฟอร์ล้นของหน้าต่างบริบทที่ผู้ให้บริการเป็นเจ้าของ ผู้ให้บริการมีข้อผิดพลาดบัฟเฟอร์ล้นดิบที่ฮิวริสติกทั่วไปอาจตรวจไม่พบ
classifyFailoverReason การจำแนกเหตุผลของการสลับระบบสำรองที่ผู้ให้บริการเป็นเจ้าของ ผู้ให้บริการสามารถจับคู่ข้อผิดพลาด API/การขนส่งดิบกับการจำกัดอัตรา/โหลดเกิน/อื่น ๆ
isCacheTtlEligible นโยบายแคชพรอมป์สำหรับผู้ให้บริการพร็อกซี/แบ็กฮอล ผู้ให้บริการต้องการควบคุมสิทธิ์ TTL ของแคชเฉพาะพร็อกซี
buildMissingAuthMessage ข้อความทดแทนสำหรับการกู้คืนกรณีขาดการยืนยันตัวตนแบบทั่วไป ผู้ให้บริการต้องการคำแนะนำการกู้คืนกรณีขาดการยืนยันตัวตนเฉพาะผู้ให้บริการ
augmentModelCatalog แถวแค็ตตาล็อกสังเคราะห์/สุดท้ายที่เพิ่มหลังการค้นพบ (เลิกใช้แล้ว โปรดดูด้านล่าง) ผู้ให้บริการต้องการแถวสังเคราะห์สำหรับความเข้ากันได้ในอนาคตใน models list และตัวเลือก
resolveThinkingProfile ชุดระดับ /think เฉพาะโมเดล ป้ายกำกับที่แสดง และค่าเริ่มต้น ผู้ให้บริการเปิดเผยลำดับขั้นการคิดแบบกำหนดเองหรือป้ายกำกับแบบไบนารีสำหรับโมเดลที่เลือก
isBinaryThinking ฮุกความเข้ากันได้สำหรับสลับเปิด/ปิดการให้เหตุผล ผู้ให้บริการเปิดเผยเพียงการเปิด/ปิดการคิดแบบไบนารี
supportsXHighThinking ฮุกความเข้ากันได้สำหรับการรองรับการให้เหตุผล xhigh ผู้ให้บริการต้องการใช้ xhigh เฉพาะกับโมเดลบางส่วน
resolveDefaultThinkingLevel ฮุกความเข้ากันได้สำหรับระดับ /think เริ่มต้น ผู้ให้บริการเป็นเจ้าของนโยบาย /think เริ่มต้นสำหรับตระกูลโมเดล
isModernModelRef ตัวตรวจจับโมเดลสมัยใหม่สำหรับตัวกรองโปรไฟล์แบบสดและการเลือกทดสอบเบื้องต้น ผู้ให้บริการเป็นเจ้าของการจับคู่โมเดลที่ต้องการสำหรับการทดสอบแบบสด/เบื้องต้น
prepareRuntimeAuth แลกเปลี่ยนข้อมูลประจำตัวที่กำหนดค่าไว้เป็นโทเค็น/คีย์รันไทม์จริงก่อนการอนุมาน ผู้ให้บริการต้องแลกเปลี่ยนโทเค็นหรือใช้ข้อมูลประจำตัวคำขอที่มีอายุสั้น
resolveUsageAuth แปลงข้อมูลประจำตัวการใช้งาน/การเรียกเก็บเงินสำหรับ /usage และพื้นผิวสถานะที่เกี่ยวข้อง ผู้ให้บริการต้องการการแยกวิเคราะห์โทเค็นการใช้งาน/โควตาแบบกำหนดเองหรือข้อมูลประจำตัวการใช้งานประเภทอื่น
fetchUsageSnapshot ดึงและปรับสแนปช็อตการใช้งาน/โควตาเฉพาะผู้ให้บริการให้เป็นมาตรฐานหลังแปลงการยืนยันตัวตนแล้ว ผู้ให้บริการต้องการเอนด์พอยต์การใช้งานหรือตัวแยกวิเคราะห์เพย์โหลดเฉพาะผู้ให้บริการ
createEmbeddingProvider สร้างอะแดปเตอร์การฝังเวกเตอร์ที่ผู้ให้บริการเป็นเจ้าของสำหรับหน่วยความจำ/การค้นหา พฤติกรรมการฝังเวกเตอร์ของหน่วยความจำเป็นความรับผิดชอบของ Plugin ผู้ให้บริการ
buildReplayPolicy ส่งคืนนโยบายการเล่นซ้ำที่ควบคุมการจัดการทรานสคริปต์สำหรับผู้ให้บริการ ผู้ให้บริการต้องใช้นโยบายทรานสคริปต์แบบกำหนดเอง (เช่น การตัดบล็อกการคิดออก)
sanitizeReplayHistory เขียนประวัติการเล่นซ้ำใหม่หลังการล้างทรานสคริปต์ทั่วไป ผู้ให้บริการต้องเขียนข้อมูลการเล่นซ้ำใหม่ในแบบเฉพาะผู้ให้บริการ ซึ่งเกินขอบเขตของตัวช่วย Compaction ที่ใช้ร่วมกัน
validateReplayTurns ตรวจสอบความถูกต้องหรือปรับรูปแบบเทิร์นการเล่นซ้ำขั้นสุดท้ายก่อนส่งไปยังตัวรันแบบฝังตัว การขนส่งของผู้ให้บริการต้องตรวจสอบความถูกต้องของเทิร์นอย่างเข้มงวดยิ่งขึ้นหลังการล้างข้อมูลทั่วไป
onModelSelected เรียกใช้ผลข้างเคียงหลังการเลือกที่ผู้ให้บริการเป็นเจ้าของ ผู้ให้บริการต้องใช้ข้อมูลการวัดและติดตาม หรือสถานะที่ผู้ให้บริการเป็นเจ้าของเมื่อโมเดลเริ่มทำงาน

normalizeModelId, normalizeTransport และ normalizeConfig จะตรวจสอบ Plugin ของผู้ให้บริการที่ตรงกันก่อน จากนั้นจึงไล่ตรวจสอบ Plugin ของผู้ให้บริการอื่นที่รองรับฮุก จนกว่าจะพบ Plugin ที่เปลี่ยนรหัสโมเดลหรือการขนส่ง/การกำหนดค่าจริง วิธีนี้ช่วยให้ชิมของผู้ให้บริการสำหรับนามแฝง/ความเข้ากันได้ยังคงทำงาน โดยผู้เรียกไม่จำเป็นต้องทราบว่า Plugin ที่รวมมาในชุดใดเป็นเจ้าของการเขียนค่าใหม่ หากไม่มีฮุกของผู้ให้บริการใดเขียนรายการการกำหนดค่าตระกูล Google ที่รองรับใหม่ ตัวปรับการกำหนดค่า Google ที่รวมมาในชุดจะยังคงดำเนินการล้างค่าด้านความเข้ากันได้นั้น

หากผู้ให้บริการต้องใช้โพรโทคอลระดับสายสัญญาณแบบกำหนดเองทั้งหมดหรือตัวดำเนินการคำขอแบบกำหนดเอง กรณีนั้นถือเป็นส่วนขยายคนละประเภท ฮุกเหล่านี้มีไว้สำหรับพฤติกรรมของผู้ให้บริการที่ยังคงทำงานบนลูปการอนุมานปกติของ OpenClaw

resolveUsageAuth ตัดสินใจว่า OpenClaw ควรเรียก fetchUsageSnapshot หรือย้อนกลับไปใช้การแก้ไขข้อมูลประจำตัวแบบทั่วไปสำหรับพื้นผิวการใช้งาน/สถานะ ให้คืนค่า { token, accountId?, subscriptionType?, rateLimitTier? } เมื่อผู้ให้บริการมีข้อมูลประจำตัวสำหรับการใช้งาน (ข้อมูลเมตาของแผนที่ไม่บังคับจะถูกส่งต่อไปยัง fetchUsageSnapshot) คืนค่า { handled: true } เมื่อการตรวจสอบสิทธิ์การใช้งานที่ผู้ให้บริการเป็นเจ้าของได้จัดการคำขอแล้วและต้องระงับการย้อนกลับไปใช้คีย์ API/OAuth แบบทั่วไป และคืนค่า null หรือ undefined เมื่อผู้ให้บริการไม่ได้จัดการการตรวจสอบสิทธิ์การใช้งาน

ประกาศข้อมูลประจำตัวขององค์กรหรือการเรียกเก็บเงินใน providerUsageAuthEnvVars ของไฟล์กำกับ วิธีนี้ช่วยให้พื้นผิวการค้นพบทั่วไปและการล้างข้อมูลลับสามารถจดจำข้อมูลเหล่านี้ได้ โดยไม่ทำให้ข้อมูลเหล่านี้กลายเป็นตัวเลือกสำหรับการตรวจสอบสิทธิ์การอนุมาน

ตัวอย่างผู้ให้บริการ

ts
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);  },});

ตัวอย่างที่มีมาให้ในตัว

Plugin ของผู้ให้บริการที่รวมมาในชุดจะผสานฮุกข้างต้นให้เหมาะกับแค็ตตาล็อก การตรวจสอบสิทธิ์ การคิด การเล่นซ้ำ และความต้องการด้านการใช้งานของผู้จำหน่ายแต่ละราย ชุดฮุกที่เป็นแหล่งอ้างอิงหลักอยู่กับแต่ละ Plugin ภายใต้ extensions/ หน้านี้แสดงรูปแบบต่าง ๆ แทนการทำสำเนารายการดังกล่าว

ผู้ให้บริการแค็ตตาล็อกแบบส่งผ่าน

OpenRouter, Kilocode, Z.AI และ xAI ลงทะเบียน catalog ร่วมกับ resolveDynamicModel / prepareDynamicModel เพื่อให้สามารถแสดงรหัสโมเดล ต้นทางก่อนแค็ตตาล็อกแบบคงที่ของ OpenClaw

ผู้ให้บริการปลายทาง OAuth และการใช้งาน

GitHub Copilot, Gemini CLI, ChatGPT Codex, MiniMax, Xiaomi และ z.ai จับคู่ prepareRuntimeAuth หรือ formatApiKey กับ resolveUsageAuth + fetchUsageSnapshot เพื่อเป็นเจ้าของการแลกเปลี่ยนโทเค็นและการผสานรวม /usage

ตระกูลการเล่นซ้ำและการล้างบทสนทนา

ตระกูลที่ใช้ชื่อร่วมกัน (google-gemini, passthrough-gemini, anthropic-by-model, hybrid-anthropic-openai) ช่วยให้ผู้ให้บริการเลือกใช้ นโยบายบทสนทนาผ่าน buildReplayPolicy แทนที่แต่ละ Plugin จะนำกระบวนการล้างไปสร้างใหม่เอง

ผู้ให้บริการเฉพาะแค็ตตาล็อก

byteplus, cloudflare-ai-gateway, huggingface, kimi-coding, nvidia, qianfan, synthetic, together, venice, vercel-ai-gateway และ volcengine ลงทะเบียนเฉพาะ catalog และใช้ลูปการอนุมานที่ใช้ร่วมกัน

ตัวช่วยสตรีมเฉพาะ Anthropic

ส่วนหัวเบตา, /fast / serviceTier และ context1m อยู่ภายในรอยต่อ api.ts / contract-api.ts สาธารณะของ Plugin Anthropic (wrapAnthropicProviderStream, resolveAnthropicBetas, resolveAnthropicFastMode, resolveAnthropicServiceTier) แทนที่จะอยู่ใน SDK แบบทั่วไป

ตัวช่วยรันไทม์

Plugin สามารถเข้าถึงตัวช่วยหลักที่เลือกไว้ผ่าน api.runtime สำหรับ TTS:

ts
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,});

หมายเหตุ:

  • textToSpeech คืนเพย์โหลดเอาต์พุต TTS หลักตามปกติสำหรับพื้นผิวไฟล์/ข้อความเสียง
  • ใช้การกำหนดค่า messages.tts หลักและการเลือกผู้ให้บริการ
  • คืนบัฟเฟอร์เสียง PCM พร้อมอัตราการสุ่มตัวอย่าง Plugin ต้องปรับอัตราการสุ่มตัวอย่าง/เข้ารหัสให้เหมาะกับผู้ให้บริการ
  • listVoices เป็นตัวเลือกที่ไม่บังคับสำหรับผู้ให้บริการแต่ละราย ใช้สำหรับตัวเลือกเสียงหรือขั้นตอนการตั้งค่าที่ผู้จำหน่ายเป็นเจ้าของ
  • ส่วนหลักจะส่งกำหนดเวลาสิ้นสุดคำขอที่แก้ไขแล้วไปยังฮุก listVoices ของผู้ให้บริการ การตั้งค่าระยะหมดเวลาเฉพาะผู้ให้บริการอาจเขียนทับค่านี้
  • รายการเสียงสามารถมีข้อมูลเมตาที่ละเอียดขึ้น เช่น โลแคล เพศ และแท็กบุคลิกภาพ สำหรับตัวเลือกที่รับรู้ผู้ให้บริการ
  • ปัจจุบัน OpenAI และ ElevenLabs รองรับโทรศัพท์ แต่ Microsoft ไม่รองรับ

Plugin ยังสามารถลงทะเบียนผู้ให้บริการเสียงพูดผ่าน api.registerSpeechProvider(...) ได้ด้วย

ts
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,    };  },});

หมายเหตุ:

  • เก็บนโยบาย TTS การย้อนกลับ และการส่งคำตอบไว้ในส่วนหลัก
  • ใช้ผู้ให้บริการเสียงพูดสำหรับพฤติกรรมการสังเคราะห์ที่ผู้จำหน่ายเป็นเจ้าของ
  • อินพุต Microsoft แบบเดิม edge จะถูกปรับให้เป็นรหัสผู้ให้บริการ microsoft
  • รูปแบบความเป็นเจ้าของที่แนะนำเน้นตามบริษัท: Plugin ของผู้จำหน่ายหนึ่งรายสามารถเป็นเจ้าของผู้ให้บริการข้อความ เสียงพูด รูปภาพ และสื่อในอนาคต เมื่อ OpenClaw เพิ่มสัญญาความสามารถเหล่านั้น

สำหรับการทำความเข้าใจรูปภาพ/เสียง/วิดีโอ Plugin จะลงทะเบียนผู้ให้บริการการทำความเข้าใจสื่อแบบมีชนิดหนึ่งราย แทนการใช้ชุดคีย์/ค่าแบบทั่วไป:

ts
api.registerMediaUnderstandingProvider({  id: "google",  capabilities: ["image", "audio", "video"],  describeImage: async (req) => ({ text: "..." }),  transcribeAudio: async (req) => ({ text: "..." }),  describeVideo: async (req) => ({ text: "..." }),});

หมายเหตุ:

  • เก็บการประสานงาน การย้อนกลับ การกำหนดค่า และการเชื่อมต่อช่องทางไว้ในส่วนหลัก
  • เก็บพฤติกรรมของผู้จำหน่ายไว้ใน Plugin ของผู้ให้บริการ
  • การขยายแบบเพิ่มเติมควรคงการกำหนดชนิดไว้: เมธอดที่ไม่บังคับใหม่ ฟิลด์ผลลัพธ์ที่ไม่บังคับใหม่ และความสามารถที่ไม่บังคับใหม่
  • การสร้างวิดีโอใช้รูปแบบเดียวกันอยู่แล้ว:
    • ส่วนหลักเป็นเจ้าของสัญญาความสามารถและตัวช่วยรันไทม์
    • Plugin ของผู้จำหน่ายลงทะเบียน api.registerVideoGenerationProvider(...)
    • Plugin ของฟีเจอร์/ช่องทางใช้ api.runtime.videoGeneration.*

สำหรับตัวช่วยรันไทม์การทำความเข้าใจสื่อ Plugin สามารถเรียกใช้:

ts
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,}); const extraction = await api.runtime.mediaUnderstanding.extractStructuredWithModel({  provider: "codex",  model: "gpt-5.6-sol",  input: [    {      type: "image",      buffer: receiptImageBuffer,      fileName: "receipt.png",      mime: "image/png",    },    { type: "text", text: "Use the printed fields as the source of truth." },  ],  instructions: "Return entities and searchable tags.",  schemaName: "example.evidence",  jsonSchema: {    type: "object",    properties: {      entities: { type: "array", items: { type: "string" } },      tags: { type: "array", items: { type: "string" } },    },  },  cfg: api.config,});

สำหรับการถอดเสียง Plugin สามารถใช้รันไทม์การทำความเข้าใจสื่อหรือนามแฝง STT รุ่นเก่าก็ได้:

ts
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",});

หมายเหตุ:

  • api.runtime.mediaUnderstanding.* เป็นพื้นผิวร่วมที่แนะนำสำหรับการทำความเข้าใจรูปภาพ/เสียง/วิดีโอ
  • extractStructuredWithModel(...) เป็นรอยต่อสำหรับ Plugin เพื่อใช้ในการแยกข้อมูลแบบมีขอบเขตที่เน้นรูปภาพเป็นหลักและผู้ให้บริการเป็นเจ้าของ ต้องมีอินพุตรูปภาพอย่างน้อยหนึ่งรายการ ส่วนอินพุตข้อความเป็นบริบทเสริม Plugin ของผลิตภัณฑ์เป็นเจ้าของเส้นทางและสคีมา ขณะที่ OpenClaw เป็นเจ้าของขอบเขตผู้ให้บริการ/รันไทม์
  • ใช้การกำหนดค่าเสียงสำหรับการทำความเข้าใจสื่อของส่วนหลัก (tools.media.audio) และลำดับการย้อนกลับของผู้ให้บริการ
  • คืนค่า { text: undefined } เมื่อไม่มีเอาต์พุตการถอดเสียงเกิดขึ้น (เช่น อินพุตถูกข้าม/ไม่รองรับ)
  • api.runtime.stt.transcribeAudioFile(...) ยังคงอยู่ในฐานะนามแฝงเพื่อความเข้ากันได้

Plugin ยังสามารถเริ่มการทำงานของเอเจนต์ย่อยเบื้องหลังผ่าน api.runtime.subagent ได้ด้วย:

ts
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,});

หมายเหตุ:

  • provider และ model เป็นค่าที่เขียนทับเฉพาะการทำงานแต่ละครั้งซึ่งไม่บังคับ ไม่ใช่การเปลี่ยนแปลงเซสชันแบบถาวร
  • OpenClaw ยอมรับฟิลด์เขียนทับเหล่านั้นเฉพาะจากผู้เรียกที่เชื่อถือได้
  • สำหรับการทำงานแบบย้อนกลับที่ Plugin เป็นเจ้าของ ผู้ดำเนินการต้องเลือกเข้าร่วมด้วย plugins.entries.<id>.subagent.allowModelOverride: true
  • ใช้ plugins.entries.<id>.subagent.allowedModels เพื่อจำกัด Plugin ที่เชื่อถือได้ให้ใช้เป้าหมาย provider/model มาตรฐานที่กำหนด หรือใช้ "*" เพื่ออนุญาตทุกเป้าหมายอย่างชัดเจน
  • การทำงานของเอเจนต์ย่อยจาก Plugin ที่ไม่น่าเชื่อถือยังคงทำงานได้ แต่คำขอเขียนทับจะถูกปฏิเสธแทนการย้อนกลับโดยไม่แจ้ง
  • เซสชันเอเจนต์ย่อยที่ Plugin สร้างขึ้นจะถูกติดแท็กด้วยรหัส Plugin ที่สร้างเซสชันนั้น api.runtime.subagent.deleteSession(...) แบบย้อนกลับสามารถลบได้เฉพาะเซสชันที่เป็นเจ้าของเหล่านั้น การลบเซสชันใด ๆ ยังคงต้องใช้คำขอ Gateway ที่มีขอบเขตผู้ดูแลระบบ

สำหรับการค้นหาเว็บ Plugin สามารถใช้ตัวช่วยรันไทม์ร่วมแทนการเข้าถึงการเชื่อมต่อเครื่องมือเอเจนต์โดยตรง:

ts
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 ยังสามารถลงทะเบียนผู้ให้บริการค้นหาเว็บผ่าน api.registerWebSearchProvider(...) ได้ด้วย

หมายเหตุ:

  • เก็บการเลือกผู้ให้บริการ การแก้ไขข้อมูลประจำตัว และความหมายของคำขอร่วมไว้ในส่วนหลัก
  • ใช้ผู้ให้บริการค้นหาเว็บสำหรับการขนส่งการค้นหาเฉพาะผู้จำหน่าย
  • api.runtime.webSearch.* เป็นพื้นผิวร่วมที่แนะนำสำหรับ Plugin ของฟีเจอร์/ช่องทางที่ต้องใช้พฤติกรรมการค้นหาโดยไม่ขึ้นกับตัวห่อเครื่องมือเอเจนต์

api.runtime.imageGeneration

ts
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(...): สร้างรูปภาพโดยใช้สายโซ่ผู้ให้บริการสร้างรูปภาพที่กำหนดค่าไว้
  • listProviders(...): แสดงรายการผู้ให้บริการสร้างรูปภาพที่พร้อมใช้งานและความสามารถของแต่ละราย

เส้นทาง HTTP ของ Gateway

Plugin สามารถเปิดเผยปลายทาง HTTP ด้วย api.registerHttpRoute(...)

ts
api.registerHttpRoute({  path: "/acme/webhook",  auth: "plugin",  match: "exact",  handler: async (_req, res) => {    res.statusCode = 200;    res.end("ok");    return true;  },});

ฟิลด์ของเส้นทาง:

  • path: พาธของเส้นทางภายใต้เซิร์ฟเวอร์ HTTP ของ Gateway
  • auth: จำเป็นต้องระบุ โดยใช้ "gateway" หรือ "plugin" ใช้ "gateway" เพื่อบังคับใช้การยืนยันตัวตนตามปกติของ Gateway หรือใช้ "plugin" สำหรับการยืนยันตัวตนหรือการตรวจสอบ Webhook ที่ Plugin จัดการ
  • match: ไม่บังคับ ใช้ "exact" (ค่าเริ่มต้น) หรือ "prefix"
  • handleUpgrade: ตัวจัดการที่ไม่บังคับสำหรับคำขออัปเกรด WebSocket บนเส้นทางเดียวกัน
  • replaceExisting: ไม่บังคับ อนุญาตให้ Plugin เดิมแทนที่การลงทะเบียนเส้นทางที่มีอยู่ของตนเอง
  • handler: คืนค่า true เมื่อเส้นทางจัดการคำขอแล้ว

หมายเหตุ:

  • api.registerHttpHandler(...) ถูกนำออกแล้วและจะทำให้เกิดข้อผิดพลาดขณะโหลด Plugin ให้ใช้ api.registerHttpRoute(...) แทน
  • เส้นทางของ Plugin ต้องประกาศ auth อย่างชัดเจน
  • ระบบจะปฏิเสธความขัดแย้งของ path + match ที่ตรงกันทั้งหมด เว้นแต่กำหนด replaceExisting: true และ Plugin หนึ่งไม่สามารถแทนที่เส้นทางของ Plugin อื่นได้
  • ระบบจะปฏิเสธเส้นทางที่ทับซ้อนกันและมีระดับ auth ต่างกัน ให้ใช้สายการส่งต่อ exact/prefix เฉพาะภายในระดับการยืนยันตัวตนเดียวกัน
  • เส้นทางที่ใช้ auth: "plugin" จะ ไม่ได้รับ ขอบเขตรันไทม์ของผู้ดำเนินการโดยอัตโนมัติ เส้นทางเหล่านี้มีไว้สำหรับ Webhook หรือการตรวจสอบลายเซ็นที่ Plugin จัดการ ไม่ใช่สำหรับการเรียกตัวช่วยของ Gateway ที่มีสิทธิ์ระดับสูง
  • เส้นทางที่ใช้ auth: "gateway" ทำงานภายในขอบเขตรันไทม์ของคำขอ Gateway พื้นผิวเริ่มต้น (gatewayRuntimeScopeSurface: "write-default") ตั้งใจออกแบบให้จำกัดสิทธิ์อย่างระมัดระวัง:
    • การยืนยันตัวตนแบบ bearer ด้วยความลับร่วม (gateway.auth.mode = "token" / "password") และวิธีการยืนยันตัวตนใด ๆ ที่ไม่ใช่พร็อกซีที่เชื่อถือได้ จะได้รับขอบเขต operator.write เพียงขอบเขตเดียว แม้ผู้เรียกจะส่ง x-openclaw-scopes
    • ผู้เรียกผ่าน trusted-proxy ที่ไม่มีส่วนหัว x-openclaw-scopes อย่างชัดเจนจะยังคงได้รับเฉพาะพื้นผิวแบบเดิมที่มีเพียง operator.write
    • ผู้เรียกผ่าน trusted-proxy ที่ส่ง x-openclaw-scopes จะได้รับขอบเขตที่ประกาศไว้แทน
    • เส้นทางสามารถเลือกใช้ gatewayRuntimeScopeSurface: "trusted-operator" เพื่อให้เคารพ x-openclaw-scopes เสมอสำหรับโหมดการยืนยันตัวตนที่มีข้อมูลอัตลักษณ์ (และใช้ชุดขอบเขตเริ่มต้นทั้งหมดของ CLI เป็นค่าทดแทนเมื่อไม่มีส่วนหัว)
  • กฎเชิงปฏิบัติ: อย่าถือว่าเส้นทาง Plugin ที่ยืนยันตัวตนผ่าน Gateway เป็นพื้นผิวผู้ดูแลระบบโดยปริยาย หากเส้นทางของคุณต้องใช้พฤติกรรมเฉพาะผู้ดูแลระบบ ให้เลือกใช้พื้นผิวขอบเขต trusted-operator บังคับใช้โหมดการยืนยันตัวตนที่มีข้อมูลอัตลักษณ์ และจัดทำเอกสารสัญญาของส่วนหัว x-openclaw-scopes อย่างชัดเจน
  • หลังจากจับคู่เส้นทางและยืนยันตัวตนแล้ว ตัวจัดการทั่วไปจะอยู่ภายใต้การควบคุมการรับงานระดับรากของ Gateway โดย Gateway ที่อยู่ในสถานะเตรียมพร้อมหรือกำลังเริ่มใหม่จะคืนค่า 503 ก่อนเรียกใช้ตัวจัดการ ข้อยกเว้นที่จำกัดคือเส้นทาง auth: "gateway" ที่ได้รับสิทธิ์จากไฟล์ manifest และเลือกใช้พื้นผิว trusted-operator เฉพาะเส้นทางด้วย เส้นทางนี้ยังคงเข้าถึงได้เพื่อไม่ให้การส่งคำสั่งควบคุมการระงับติดค้าง ขณะที่เส้นทางพี่น้องทั่วไปจาก Plugin เดียวกันยังคงอยู่หลังขอบเขตการรับงาน การเป็นเจ้าของ handleUpgrade ของ WebSocket ใช้ขอบเขตการรับงานแบบอะตอมมิกเดียวกัน เมื่อใดที่ตัวจัดการยอมรับซ็อกเก็ตแล้ว วงจรชีวิตหลังจากนั้นของซ็อกเก็ตจะอยู่ภายใต้การดูแลของ Plugin และขอบเขตนี้จะไม่ติดตามอีกต่อไป

พาธการนำเข้าของ Plugin SDK

เมื่อสร้าง Plugin ใหม่ ให้ใช้พาธย่อย SDK ที่เฉพาะเจาะจงแทน barrel รากแบบรวมศูนย์ openclaw/plugin-sdk พาธย่อยหลัก:

พาธย่อย วัตถุประสงค์
openclaw/plugin-sdk/plugin-entry องค์ประกอบพื้นฐานสำหรับการลงทะเบียน Plugin
openclaw/plugin-sdk/channel-core ตัวช่วยสำหรับจุดเข้าและการสร้างช่องทาง
openclaw/plugin-sdk/core ตัวช่วยทั่วไปร่วมกันและสัญญารวม
openclaw/plugin-sdk/config-schema สคีมา Zod ของ openclaw.json ระดับราก (OpenClawSchema)

Plugin ช่องทางเลือกใช้จากชุดรอยต่อที่เฉพาะเจาะจง ได้แก่ channel-setup, setup-runtime, setup-tools, channel-pairing, channel-contract, channel-feedback, channel-inbound, channel-outbound, command-auth, secret-input, webhook-ingress, channel-targets และ channel-actions พฤติกรรมการอนุมัติควรรวมไว้ในสัญญา approvalCapability เดียว แทนการผสมข้ามฟิลด์ Plugin ที่ไม่เกี่ยวข้อง ดู Plugin ช่องทาง

ตัวช่วยรันไทม์และการกำหนดค่าอยู่ภายใต้พาธย่อย *-runtime ที่มีขอบเขตตรงกัน (approval-runtime, agent-runtime, lazy-runtime, directory-runtime, text-runtime, runtime-store, system-event-runtime, heartbeat-runtime, channel-activity-runtime เป็นต้น) ควรใช้ config-contracts, plugin-config-runtime, runtime-config-snapshot และ config-mutation แทน barrel ความเข้ากันได้ config-runtime แบบกว้าง

จุดเข้าภายในรีโพ (แยกตามรากแพ็กเกจของ Plugin ที่รวมมากับระบบ):

  • index.js — จุดเข้าของ Plugin ที่รวมมากับระบบ
  • api.js — barrel ของตัวช่วยและชนิดข้อมูล
  • runtime-api.js — barrel สำหรับรันไทม์เท่านั้น
  • setup-entry.js — จุดเข้าของ Plugin สำหรับการตั้งค่า

Plugin ภายนอกควรนำเข้าเฉพาะพาธย่อย openclaw/plugin-sdk/* เท่านั้น ห้าม นำเข้า src/* ของแพ็กเกจ Plugin อื่นจากแกนหลักหรือจาก Plugin อื่น จุดเข้าที่โหลดผ่าน facade จะเลือกใช้สแนปช็อตการกำหนดค่ารันไทม์ที่ใช้งานอยู่ก่อนเมื่อมี จากนั้นจึงใช้ไฟล์การกำหนดค่าที่แก้ไขพาธแล้วบนดิสก์เป็นทางเลือกสำรอง

พาธย่อยเฉพาะความสามารถ เช่น image-generation, media-understanding และ speech มีอยู่เนื่องจาก Plugin ที่รวมมากับระบบใช้งานอยู่ในปัจจุบัน พาธเหล่านี้ ไม่ได้เป็นสัญญาภายนอกที่ถูกตรึงไว้ระยะยาวโดยอัตโนมัติ โปรดตรวจสอบหน้าอ้างอิง SDK ที่เกี่ยวข้องเมื่อต้องพึ่งพาพาธเหล่านี้

สคีมาของเครื่องมือข้อความ

Plugin ควรเป็นเจ้าของส่วนเพิ่มเติมของสคีมา describeMessageTool(...) เฉพาะช่องทางสำหรับองค์ประกอบพื้นฐานที่ไม่ใช่ข้อความ เช่น การแสดงปฏิกิริยา การอ่าน และโพล การนำเสนอร่วมสำหรับการส่งควรใช้สัญญาทั่วไป MessagePresentation แทนฟิลด์ปุ่ม คอมโพเนนต์ บล็อก หรือการ์ดแบบเฉพาะผู้ให้บริการ ดูสัญญา กฎการใช้ทางเลือกสำรอง การแมปผู้ให้บริการ และรายการตรวจสอบสำหรับผู้สร้าง Plugin ได้ที่ การนำเสนอข้อความ

Plugin ที่สามารถส่งข้อความได้จะประกาศสิ่งที่ตนแสดงผลได้ผ่านความสามารถด้านข้อความ:

  • presentation สำหรับบล็อกการนำเสนอเชิงความหมาย (text, context, divider, chart, table, buttons, select)
  • delivery-pin สำหรับคำขอส่งแบบปักหมุด

แกนหลักเป็นผู้ตัดสินใจว่าจะแสดงผลการนำเสนอแบบเนทีฟหรือลดรูปเป็นข้อความ อย่าเปิดช่องทางหลบออกไปใช้ UI แบบเนทีฟของผู้ให้บริการจากเครื่องมือข้อความทั่วไป ตัวช่วย SDK ที่เลิกแนะนำให้ใช้แล้วสำหรับสคีมาเนทีฟแบบเดิมยังคงส่งออกไว้สำหรับ Plugin ของบุคคลที่สามที่มีอยู่ แต่ Plugin ใหม่ไม่ควรใช้ตัวช่วยเหล่านี้

การแก้ไขเป้าหมายของช่องทาง

Plugin ช่องทางควรเป็นเจ้าของความหมายเชิงพฤติกรรมของเป้าหมายเฉพาะช่องทาง ให้โฮสต์ ขาออกร่วมคงความเป็นทั่วไป และใช้พื้นผิวอะแดปเตอร์การส่งข้อความสำหรับกฎของผู้ให้บริการ:

  • messaging.inferTargetChatType({ to }) ตัดสินใจว่าควรปฏิบัติต่อเป้าหมาย ที่ปรับให้อยู่ในรูปมาตรฐานแล้วเป็น direct, group หรือ channel ก่อนค้นหาไดเรกทอรี
  • messaging.targetResolver.looksLikeId(raw, normalized) บอกแกนหลักว่าอินพุต ควรข้ามไปยังการแก้ไขแบบรหัสโดยตรงแทนการค้นหาไดเรกทอรีหรือไม่
  • messaging.targetResolver.reservedLiterals แสดงรายการคำเดี่ยวที่เป็น การอ้างอิงช่องทางหรือเซสชันสำหรับผู้ให้บริการนั้น การแก้ไขจะรักษารายการไดเรกทอรี ที่กำหนดค่าไว้ก่อนปฏิเสธคำสงวน จากนั้นจะหยุดอย่างปลอดภัยเมื่อค้นหาในไดเรกทอรีไม่พบ
  • messaging.targetResolver.resolveTarget(...) เป็นทางเลือกสำรองของ Plugin เมื่อ แกนหลักต้องการการแก้ไขขั้นสุดท้ายที่ผู้ให้บริการเป็นเจ้าของ หลังการปรับให้อยู่ในรูปมาตรฐาน หรือหลังค้นหาในไดเรกทอรีไม่พบ
  • messaging.resolveOutboundSessionRoute(...) เป็นเจ้าของการสร้างเส้นทางเซสชัน เฉพาะผู้ให้บริการเมื่อแก้ไขเป้าหมายแล้ว

การแบ่งหน้าที่ที่แนะนำ:

  • ใช้ inferTargetChatType สำหรับการตัดสินใจประเภทที่ควรเกิดขึ้นก่อน ค้นหาเพียร์หรือกลุ่ม
  • ใช้ looksLikeId สำหรับการตรวจสอบว่า “ให้ปฏิบัติต่อค่านี้เป็นรหัสเป้าหมายแบบชัดเจนหรือเนทีฟ”
  • ใช้ resolveTarget เป็นทางเลือกสำรองสำหรับการปรับให้อยู่ในรูปมาตรฐานเฉพาะผู้ให้บริการ ไม่ใช่สำหรับการค้นหาไดเรกทอรีแบบกว้าง
  • เก็บรหัสเนทีฟของผู้ให้บริการ เช่น รหัสแชต รหัสเธรด JID ชื่ออ้างอิง และรหัสห้อง ไว้ภายในค่า target หรือพารามิเตอร์เฉพาะผู้ให้บริการ ไม่ใช่ในฟิลด์ SDK ทั่วไป

ไดเรกทอรีที่อิงการกำหนดค่า

Plugin ที่สร้างรายการไดเรกทอรีจากการกำหนดค่าควรเก็บตรรกะนั้นไว้ใน Plugin และนำตัวช่วยร่วมจาก openclaw/plugin-sdk/directory-runtime มาใช้ซ้ำ

ใช้รูปแบบนี้เมื่อช่องทางต้องการเพียร์หรือกลุ่มที่อิงการกำหนดค่า เช่น:

  • เพียร์ DM ที่ควบคุมด้วยรายการอนุญาต
  • แมปช่องทางหรือกลุ่มที่กำหนดค่าไว้
  • ทางเลือกสำรองของไดเรกทอรีแบบคงที่ที่จำกัดขอบเขตตามบัญชี

ตัวช่วยร่วมใน directory-runtime จัดการเฉพาะการดำเนินการทั่วไป:

  • การกรองคำค้น
  • การใช้ขีดจำกัด
  • ตัวช่วยกำจัดรายการซ้ำและปรับให้อยู่ในรูปมาตรฐาน
  • การสร้าง ChannelDirectoryEntry[]

การตรวจสอบบัญชีเฉพาะช่องทางและการปรับรหัสให้อยู่ในรูปมาตรฐานควรอยู่ใน การติดตั้งใช้งานของ Plugin

แค็ตตาล็อกผู้ให้บริการ

Plugin ผู้ให้บริการสามารถกำหนดแค็ตตาล็อกโมเดลสำหรับการอนุมานด้วย registerProvider({ catalog: { run(...) { ... } } })

catalog.run(...) คืนค่ารูปแบบเดียวกับที่ OpenClaw เขียนลงใน models.providers:

  • { provider } สำหรับรายการผู้ให้บริการหนึ่งรายการ
  • { providers } สำหรับรายการผู้ให้บริการหลายรายการ

ใช้ catalog เมื่อ Plugin เป็นเจ้าของรหัสโมเดลเฉพาะผู้ให้บริการ ค่าเริ่มต้น ของ URL ฐาน หรือข้อมูลเมตาของโมเดลที่จำกัดด้วยการยืนยันตัวตน

catalog.order ควบคุมลำดับเวลาที่แค็ตตาล็อกของ Plugin ผสานเข้ากับ ผู้ให้บริการโดยปริยายที่ติดตั้งมากับ OpenClaw:

  • simple: ผู้ให้บริการที่ใช้คีย์ API แบบทั่วไปหรือขับเคลื่อนด้วยตัวแปรสภาพแวดล้อม
  • profile: ผู้ให้บริการที่ปรากฏเมื่อมีโปรไฟล์การยืนยันตัวตน
  • paired: ผู้ให้บริการที่สังเคราะห์รายการผู้ให้บริการที่เกี่ยวข้องกันหลายรายการ
  • late: รอบสุดท้าย หลังจากผู้ให้บริการโดยปริยายอื่น ๆ

ผู้ให้บริการที่มาภายหลังจะชนะเมื่อคีย์ชนกัน ดังนั้น Plugin จึงสามารถตั้งใจแทนที่ รายการผู้ให้บริการที่ติดตั้งมากับระบบซึ่งมีรหัสผู้ให้บริการเดียวกันได้

Plugin ยังสามารถเผยแพร่แถวโมเดลแบบอ่านอย่างเดียวผ่าน api.registerModelCatalogProvider({ provider, kinds, staticCatalog, liveCatalog }) ได้ด้วย นี่คือแนวทางต่อไปสำหรับพื้นผิวรายการ วิธีใช้ และตัวเลือก โดยรองรับแถว text, voice, image_generation, video_generation และ music_generation Plugin ผู้ให้บริการยังคงเป็นเจ้าของการเรียกปลายทางแบบสด การแลกเปลี่ยนโทเค็น และ การแมปการตอบกลับจากผู้จำหน่าย ส่วนแกนหลักเป็นเจ้าของรูปแบบแถวร่วม ป้ายกำกับแหล่งที่มา และ การจัดรูปแบบวิธีใช้เครื่องมือสื่อ การลงทะเบียนผู้ให้บริการสร้างสื่อจะสังเคราะห์ แถวแค็ตตาล็อกแบบคงที่โดยอัตโนมัติจาก defaultModel, models และ capabilities

ความเข้ากันได้:

  • discovery ยังคงทำงานเป็นนามแฝงแบบเดิม แต่จะแสดงคำเตือนการเลิกใช้งาน
  • หากลงทะเบียนทั้ง catalog และ discovery OpenClaw จะใช้ catalog และแสดงคำเตือน
  • augmentModelCatalog เลิกแนะนำให้ใช้แล้ว ผู้ให้บริการที่รวมมากับระบบควรเผยแพร่ แถวเพิ่มเติมผ่าน registerModelCatalogProvider

การตรวจสอบช่องทางแบบอ่านอย่างเดียว

หาก Plugin ของคุณลงทะเบียนช่องทาง ควรติดตั้งใช้งาน plugin.config.inspectAccount(cfg, accountId) ควบคู่กับ resolveAccount(...)

เหตุผล:

  • resolveAccount(...) เป็นพาธรันไทม์ โดยสามารถถือว่าข้อมูลรับรอง ถูกจัดเตรียมไว้อย่างสมบูรณ์แล้ว และสามารถหยุดทันทีเมื่อไม่มีข้อมูลลับที่จำเป็น
  • พาธคำสั่งแบบอ่านอย่างเดียว เช่น openclaw status, openclaw status --all, openclaw channels status, openclaw channels resolve และกระบวนการ ซ่อมแซมของ doctor หรือการกำหนดค่า ไม่ควรต้องจัดเตรียมข้อมูลรับรองรันไทม์เพียงเพื่อ อธิบายการกำหนดค่า

พฤติกรรม inspectAccount(...) ที่แนะนำ:

  • ส่งคืนเฉพาะสถานะบัญชีเชิงบรรยาย
  • คง enabled และ configured ไว้
  • ระบุฟิลด์แหล่งที่มา/สถานะของข้อมูลรับรองเมื่อเกี่ยวข้อง เช่น:
    • tokenSource, tokenStatus
    • botTokenSource, botTokenStatus
    • appTokenSource, appTokenStatus
    • signingSecretSource, signingSecretStatus
  • คุณไม่จำเป็นต้องส่งคืนค่าโทเค็นดิบเพียงเพื่อรายงานความพร้อมใช้งานแบบอ่านอย่างเดียว การส่งคืน tokenStatus: "available" (พร้อมฟิลด์แหล่งที่มาที่ตรงกัน) ก็เพียงพอสำหรับคำสั่งประเภทแสดงสถานะ
  • ใช้ configured_unavailable เมื่อกำหนดค่าข้อมูลรับรองผ่าน SecretRef แล้ว แต่ข้อมูลนั้นไม่พร้อมใช้งานในเส้นทางคำสั่งปัจจุบัน

วิธีนี้ช่วยให้คำสั่งแบบอ่านอย่างเดียวรายงานว่า "กำหนดค่าแล้วแต่ไม่พร้อมใช้งานในเส้นทางคำสั่งนี้" แทนที่จะหยุดทำงานหรือรายงานผิดว่าบัญชียังไม่ได้กำหนดค่า

แพ็กเกจรวม

ไดเรกทอรี Plugin อาจมี package.json ที่ระบุ openclaw.extensions:

json
{  "name": "my-pack",  "openclaw": {    "extensions": ["./src/safety.ts", "./src/tools.ts"],    "setupEntry": "./src/setup-entry.ts"  }}

แต่ละรายการจะกลายเป็น Plugin หากแพ็กรวมระบุส่วนขยายหลายรายการ รหัส Plugin จะเป็น <manifestOrPackageName>/<fileBase> (รหัสในแมนิเฟสต์มีลำดับความสำคัญหากมีอยู่ มิฉะนั้นจะใช้ชื่อ package.json ที่ไม่มีสโคป)

หาก Plugin ของคุณนำเข้าดีเพนเดนซี npm ให้ติดตั้งไว้ในไดเรกทอรีนั้นเพื่อให้มี node_modules พร้อมใช้งาน (npm install / pnpm install)

ข้อจำกัดด้านความปลอดภัย: ทุกรายการใน openclaw.extensions ต้องยังคงอยู่ภายในไดเรกทอรี Plugin หลังจากแก้ไข symlink แล้ว รายการที่ออกนอกไดเรกทอรีแพ็กเกจจะถูกปฏิเสธ

หมายเหตุด้านความปลอดภัย: openclaw plugins install ติดตั้งดีเพนเดนซีของ Plugin ด้วย npm install --omit=dev --ignore-scripts ภายในโปรเจกต์ (ไม่เรียกใช้สคริปต์วงจรชีวิตและไม่มีดีเพนเดนซีสำหรับการพัฒนาในขณะรันไทม์) โดยไม่ใช้การตั้งค่าการติดตั้ง npm ส่วนกลางที่สืบทอดมา ควรรักษาโครงสร้างดีเพนเดนซีของ Plugin ให้เป็น "JS/TS ล้วน" และหลีกเลี่ยงแพ็กเกจที่ต้องสร้างผ่าน postinstall

ทางเลือก: openclaw.setupEntry สามารถชี้ไปยังโมดูลขนาดเบาที่ใช้สำหรับการตั้งค่าเท่านั้น เมื่อ OpenClaw ต้องการส่วนติดต่อการตั้งค่าสำหรับ Plugin ช่องทางที่ปิดใช้งาน หรือเมื่อเปิดใช้งาน Plugin ช่องทางแล้วแต่ยังไม่ได้กำหนดค่า ระบบจะโหลด setupEntry แทนจุดเข้าหลักของ Plugin วิธีนี้ช่วยให้การเริ่มต้นและการตั้งค่าเบาลง เมื่อจุดเข้าหลักของ Plugin เชื่อมต่อเครื่องมือ ฮุก หรือโค้ดอื่นที่ใช้เฉพาะขณะรันไทม์ด้วย

ทางเลือก: openclaw.startup.deferConfiguredChannelFullLoadUntilAfterListen ช่วยให้ Plugin ช่องทางเลือกใช้เส้นทาง setupEntry เดียวกันในช่วงเริ่มต้นก่อนที่ Gateway จะเริ่มรับการเชื่อมต่อ แม้ว่าช่องทางนั้นจะกำหนดค่าไว้แล้วก็ตาม

ใช้ตัวเลือกนี้เฉพาะเมื่อ setupEntry ครอบคลุมส่วนติดต่อการเริ่มต้นทั้งหมดที่ต้องมีอยู่ก่อน Gateway เริ่มรับการเชื่อมต่อ ในทางปฏิบัติ หมายความว่าจุดเข้าสำหรับการตั้งค่าต้องลงทะเบียนความสามารถทั้งหมดที่ช่องทางเป็นเจ้าของและการเริ่มต้นต้องพึ่งพา เช่น:

  • การลงทะเบียนช่องทางเอง
  • เส้นทาง HTTP ใดๆ ที่ต้องพร้อมใช้งานก่อน Gateway เริ่มรับการเชื่อมต่อ
  • เมธอด เครื่องมือ หรือบริการใดๆ ของ Gateway ที่ต้องมีอยู่ในช่วงเวลาเดียวกันนั้น

หากจุดเข้าหลักของคุณยังคงเป็นเจ้าของความสามารถที่จำเป็นต่อการเริ่มต้น อย่าเปิดใช้แฟล็กนี้ ให้ Plugin ใช้พฤติกรรมเริ่มต้นต่อไปและปล่อยให้ OpenClaw โหลดจุดเข้าหลักทั้งหมดระหว่างการเริ่มต้น

ช่องทางที่รวมมาในชุดยังสามารถเผยแพร่ตัวช่วยส่วนติดต่อสัญญาที่ใช้เฉพาะการตั้งค่า ซึ่งแกนหลักสามารถเรียกใช้ก่อนโหลดรันไทม์ของช่องทางทั้งหมดได้ ส่วนติดต่อการเลื่อนระดับการตั้งค่าปัจจุบันคือ:

  • singleAccountKeysToMove
  • namedAccountPromotionKeys
  • resolveSingleAccountPromotionTarget(...)

แกนหลักใช้ส่วนติดต่อนี้เมื่อต้องเลื่อนระดับการกำหนดค่าช่องทางแบบบัญชีเดียวรุ่นเก่าไปยัง channels.<id>.accounts.* โดยไม่โหลดจุดเข้าหลักทั้งหมดของ Plugin ปัจจุบัน Matrix คือตัวอย่างที่รวมมาในชุด: เมื่อมีบัญชีแบบระบุชื่ออยู่แล้ว ระบบจะย้ายเฉพาะคีย์การยืนยันตัวตน/บูตสแตรปไปยังบัญชีแบบระบุชื่อที่เลื่อนระดับ และสามารถคงคีย์บัญชีเริ่มต้นที่กำหนดค่าไว้แต่ไม่ใช่คีย์มาตรฐาน แทนที่จะสร้าง accounts.default เสมอ

อะแดปเตอร์แพตช์สำหรับการตั้งค่าเหล่านี้ช่วยให้การค้นพบส่วนติดต่อสัญญาที่รวมมาในชุดยังคงเป็นแบบโหลดเมื่อจำเป็น เวลาในการนำเข้าจึงยังคงสั้น โดยจะโหลดส่วนติดต่อการเลื่อนระดับเฉพาะเมื่อใช้งานครั้งแรก แทนที่จะกลับเข้าสู่การเริ่มต้นช่องทางที่รวมมาในชุดอีกครั้งระหว่างการนำเข้าโมดูล

เมื่อส่วนติดต่อการเริ่มต้นเหล่านั้นมีเมธอด RPC ของ Gateway ให้ใช้คำนำหน้าที่เฉพาะกับ Plugin เนมสเปซผู้ดูแลระบบของแกนหลัก (config.*, exec.approvals.*, wizard.*, update.*) ยังคงสงวนไว้และจะถูกกำหนดเป็น operator.admin เสมอ แม้ว่า Plugin จะร้องขอขอบเขตที่แคบกว่าก็ตาม

ตัวอย่าง:

json
{  "name": "@scope/my-channel",  "openclaw": {    "extensions": ["./index.ts"],    "setupEntry": "./setup-entry.ts",    "startup": {      "deferConfiguredChannelFullLoadUntilAfterListen": true    }  }}

เมทาดาทาแค็ตตาล็อกช่องทาง

Plugin ช่องทางสามารถประกาศเมทาดาทาสำหรับการตั้งค่า/การค้นพบผ่าน openclaw.channel และคำแนะนำในการติดตั้งผ่าน openclaw.install วิธีนี้ช่วยให้แค็ตตาล็อกแกนหลักไม่ต้องเก็บข้อมูล

ตัวอย่าง:

json
{  "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"    }  }}

ฟิลด์ openclaw.channel ที่มีประโยชน์นอกเหนือจากตัวอย่างขั้นต่ำ:

  • detailLabel: ป้ายกำกับรองสำหรับส่วนติดต่อแค็ตตาล็อก/สถานะที่มีรายละเอียดมากขึ้น
  • docsLabel: แทนที่ข้อความลิงก์สำหรับลิงก์เอกสาร
  • preferOver: รหัส Plugin/ช่องทางที่มีลำดับความสำคัญต่ำกว่า ซึ่งรายการแค็ตตาล็อกนี้ควรมีอันดับเหนือกว่า
  • selectionDocsPrefix, selectionDocsOmitLabel, selectionExtras: การควบคุมข้อความบนส่วนติดต่อการเลือก
  • markdownCapable: ระบุว่าช่องทางรองรับ Markdown เพื่อใช้ตัดสินใจเรื่องการจัดรูปแบบขาออก
  • exposure.configured: ซ่อนช่องทางจากส่วนติดต่อรายการช่องทางที่กำหนดค่าแล้วเมื่อตั้งค่าเป็น false
  • exposure.setup: ซ่อนช่องทางจากตัวเลือกการตั้งค่า/กำหนดค่าแบบโต้ตอบเมื่อตั้งค่าเป็น false
  • exposure.docs: ระบุว่าช่องทางเป็นช่องทางภายใน/ส่วนตัวสำหรับส่วนติดต่อการนำทางเอกสาร
  • showConfigured / showInSetup: ชื่อแทนรุ่นเก่าที่ยังคงรองรับเพื่อความเข้ากันได้ แนะนำให้ใช้ exposure
  • quickstartAllowFrom: ให้ช่องทางเข้าร่วมโฟลว์เริ่มต้นด่วนมาตรฐาน allowFrom
  • forceAccountBinding: กำหนดให้ผูกบัญชีอย่างชัดเจน แม้ว่าจะมีบัญชีเพียงบัญชีเดียว
  • preferSessionLookupForAnnounceTarget: ให้ความสำคัญกับการค้นหาเซสชันเมื่อแก้ไขเป้าหมายการประกาศ

OpenClaw ยังสามารถผสาน แค็ตตาล็อกช่องทางภายนอก (ตัวอย่างเช่น ข้อมูลส่งออกจากรีจิสทรี MPM) ได้อีกด้วย วางไฟล์ JSON ไว้ที่ตำแหน่งใดตำแหน่งหนึ่งต่อไปนี้:

  • ~/.openclaw/mpm/plugins.json
  • ~/.openclaw/mpm/catalog.json
  • ~/.openclaw/plugins/catalog.json

หรือกำหนดให้ OPENCLAW_PLUGIN_CATALOG_PATHS (หรือ OPENCLAW_MPM_CATALOG_PATHS) ชี้ไปยังไฟล์ JSON หนึ่งไฟล์ขึ้นไป (คั่นด้วยจุลภาค/เซมิโคลอน/PATH) แต่ละไฟล์ควรมี { "entries": [ { "name": "@scope/pkg", "openclaw": { "channel": {...}, "install": {...} } } ] } ตัวแยกวิเคราะห์ยังรองรับ "packages" หรือ "plugins" เป็นชื่อแทนรุ่นเก่าของคีย์ "entries"

รายการแค็ตตาล็อกช่องทางและรายการแค็ตตาล็อกการติดตั้งผู้ให้บริการที่สร้างขึ้น จะแสดงข้อเท็จจริงเกี่ยวกับแหล่งที่มาการติดตั้งที่ปรับเป็นมาตรฐานแล้ว ควบคู่กับบล็อก openclaw.install ดิบ ข้อเท็จจริงที่ปรับเป็นมาตรฐานจะระบุว่าสเปก npm เป็นเวอร์ชันที่แน่นอนหรือตัวเลือกแบบลอยตัว มีเมทาดาทาความสมบูรณ์ที่คาดหวังหรือไม่ และมีเส้นทางแหล่งที่มาในเครื่องด้วยหรือไม่ เมื่อทราบข้อมูลประจำตัวของแค็ตตาล็อก/แพ็กเกจ ข้อเท็จจริงที่ปรับเป็นมาตรฐานจะแจ้งเตือนหากชื่อแพ็กเกจ npm ที่แยกวิเคราะห์ได้เบี่ยงเบนจากข้อมูลประจำตัวนั้น นอกจากนี้ยังแจ้งเตือนเมื่อ defaultChoice ไม่ถูกต้องหรือชี้ไปยังแหล่งที่มาที่ไม่พร้อมใช้งาน และเมื่อมีเมทาดาทาความสมบูรณ์ของ npm แต่ไม่มีแหล่งที่มา npm ที่ถูกต้อง ผู้ใช้ข้อมูลควรถือว่า installSource เป็นฟิลด์ทางเลือกแบบเพิ่มเติม เพื่อให้รายการที่สร้างด้วยตนเองและชิมของแค็ตตาล็อกไม่จำเป็นต้องสังเคราะห์ฟิลด์นี้ วิธีนี้ช่วยให้การเริ่มต้นใช้งานและการวินิจฉัยอธิบายสถานะในระดับแหล่งที่มาได้โดยไม่ต้องนำเข้ารันไทม์ของ Plugin

รายการ npm ภายนอกอย่างเป็นทางการควรใช้ npmSpec ที่ระบุเวอร์ชันแน่นอนร่วมกับ expectedIntegrity ชื่อแพ็กเกจเปล่าและ dist-tag ยังคงใช้งานได้เพื่อความเข้ากันได้ แต่จะแสดงคำเตือนในระดับแหล่งที่มา เพื่อให้แค็ตตาล็อกสามารถเปลี่ยนไปสู่การติดตั้งที่ตรึงเวอร์ชันและตรวจสอบความสมบูรณ์ได้โดยไม่ทำให้ Plugin ที่มีอยู่เสียหาย เมื่อกระบวนการเริ่มต้นใช้งานติดตั้งจากเส้นทางแค็ตตาล็อกในเครื่อง ระบบจะบันทึกรายการดัชนี Plugin ที่จัดการ โดยมี source: "path" และ sourcePath ที่สัมพันธ์กับเวิร์กสเปซเมื่อทำได้ เส้นทางโหลดสำหรับการปฏิบัติงานแบบสัมบูรณ์ยังคงอยู่ใน plugins.load.paths; ระเบียนการติดตั้งจะหลีกเลี่ยงการทำซ้ำเส้นทางของเวิร์กสเตชันภายในเครื่องลงในการกำหนดค่าระยะยาว วิธีนี้ทำให้การติดตั้งสำหรับการพัฒนาในเครื่องยังคงปรากฏในการวินิจฉัยระดับแหล่งที่มา โดยไม่เพิ่มส่วนติดต่อที่สองสำหรับเปิดเผยเส้นทางระบบไฟล์ดิบ ตาราง SQLite installed_plugin_index ที่คงอยู่เป็นแหล่งข้อมูลจริงสำหรับการติดตั้ง และสามารถรีเฟรชได้โดยไม่โหลดโมดูลรันไทม์ของ Plugin แมป installRecords จะคงทนแม้ว่าแมนิเฟสต์ของ Plugin จะหายไปหรือไม่ถูกต้อง ส่วนเพย์โหลด plugins เป็นมุมมองแมนิเฟสต์ที่สร้างใหม่ได้

Plugin กลไกบริบท

Plugin กลไกบริบทเป็นเจ้าของการประสานบริบทของเซสชันสำหรับการรับข้อมูล การประกอบ และ Compaction ลงทะเบียนจาก Plugin ของคุณด้วย api.registerContextEngine(id, factory) แล้วเลือกกลไกที่ใช้งานด้วย plugins.slots.contextEngine

ใช้วิธีนี้เมื่อ Plugin ของคุณต้องแทนที่หรือขยายไปป์ไลน์บริบทเริ่มต้น แทนที่จะเพียงเพิ่มการค้นหาหน่วยความจำหรือฮุก

ts
  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, sessionKey, availableTools, citationsMode }) {      return {        messages,        estimatedTokens: 0,        systemPromptAddition: buildMemorySystemPromptAddition({          availableTools: availableTools ?? new Set(),          citationsMode,          agentId: resolveSessionAgentId({ config: ctx.config, sessionKey }),          agentSessionKey: sessionKey,        }),      };    },    async compact() {      return { ok: true, compacted: false };    },  }));}

แฟกทอรี ctx เปิดเผยค่า config, agentDir และ workspaceDir แบบทางเลือกสำหรับการเริ่มต้นค่าในเวลาสร้าง

assemble() อาจส่งคืน contextProjection เมื่อชุดควบคุมที่ใช้งานมีเธรดแบ็กเอนด์แบบคงอยู่ ให้ละเว้นค่านี้สำหรับการฉายภาพต่อรอบแบบเดิม ส่งคืน { mode: "thread_bootstrap", epoch } เมื่อควรฉีดบริบทที่ประกอบแล้วเข้าสู่เธรดแบ็กเอนด์หนึ่งครั้งและนำกลับมาใช้ซ้ำจนกว่ายุคจะเปลี่ยนแปลง เปลี่ยนยุคหลังจากบริบทเชิงความหมายของกลไกเปลี่ยนไป เช่น หลังจากรอบ Compaction ที่กลไกเป็นเจ้าของ โฮสต์อาจเก็บรักษาเมทาดาทาการเรียกใช้เครื่องมือ รูปแบบอินพุต และผลลัพธ์เครื่องมือที่ปกปิดข้อมูลไว้ในการฉายภาพแบบบูตสแตรปเธรด เพื่อให้เธรดแบ็กเอนด์ใหม่คงความต่อเนื่องของเครื่องมือไว้ได้โดยไม่คัดลอกเพย์โหลดดิบที่มีข้อมูลลับ

หากกลไกของคุณ ไม่ได้ เป็นเจ้าของอัลกอริทึม Compaction ให้คงการติดตั้งใช้งาน compact() ไว้และมอบหมายอย่างชัดเจน:

ts
   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, sessionKey, availableTools, citationsMode }) {      return {        messages,        estimatedTokens: 0,        systemPromptAddition: buildMemorySystemPromptAddition({          availableTools: availableTools ?? new Set(),          citationsMode,          agentId: resolveSessionAgentId({ config: ctx.config, sessionKey }),          agentSessionKey: sessionKey,        }),      };    },    async compact(params) {      return await delegateCompactionToRuntime(params);    },  }));}

การเพิ่มความสามารถใหม่

เมื่อ Plugin ต้องการพฤติกรรมที่ไม่สอดคล้องกับ API ปัจจุบัน อย่าข้ามระบบ Plugin ด้วยการเข้าถึงภายในแบบส่วนตัว แต่ให้เพิ่มความสามารถที่ขาดหายไป

ลำดับที่แนะนำ:

  1. กำหนดสัญญาของแกนหลัก ตัดสินใจว่าแกนหลักควรเป็นเจ้าของพฤติกรรมร่วมใดบ้าง ได้แก่ นโยบาย กลไกสำรอง การผสานการกำหนดค่า วงจรชีวิต ความหมายเชิงพฤติกรรมสำหรับช่องทาง และรูปแบบตัวช่วยรันไทม์
  2. เพิ่มพื้นผิวการลงทะเบียน/รันไทม์ของ Plugin ที่มีชนิดข้อมูล ขยาย OpenClawPluginApi และ/หรือ api.runtime ด้วยพื้นผิวความสามารถที่มีชนิดข้อมูลซึ่งเล็กที่สุดแต่ใช้งานได้จริง
  3. เชื่อมต่อแกนหลักกับผู้ใช้ในช่องทาง/ฟีเจอร์ ช่องทางและ Plugin ฟีเจอร์ควรใช้ความสามารถใหม่ผ่านแกนหลัก ไม่ใช่นำเข้าการติดตั้งใช้งานของผู้จำหน่ายโดยตรง
  4. ลงทะเบียนการติดตั้งใช้งานของผู้จำหน่าย จากนั้น Plugin ของผู้จำหน่ายจึงลงทะเบียนแบ็กเอนด์ของตนกับความสามารถดังกล่าว
  5. เพิ่มการครอบคลุมสัญญา เพิ่มการทดสอบเพื่อให้รูปแบบความเป็นเจ้าของและการลงทะเบียนยังคงชัดเจนตลอดเวลา

นี่คือวิธีที่ OpenClaw รักษาแนวทางที่ชัดเจนโดยไม่ผูกโค้ดตายตัวกับมุมมองของผู้ให้บริการรายใดรายหนึ่ง ดูรายการตรวจสอบไฟล์ที่เป็นรูปธรรมและตัวอย่างที่ดำเนินการครบถ้วนได้ใน คู่มือความสามารถ

รายการตรวจสอบความสามารถ

เมื่อเพิ่มความสามารถใหม่ โดยทั่วไปการติดตั้งใช้งานควรปรับพื้นผิวเหล่านี้ร่วมกัน:

  • ชนิดสัญญาของแกนหลักใน src/<capability>/types.ts
  • ตัวรันแกนหลัก/ตัวช่วยรันไทม์ใน src/<capability>/runtime.ts
  • พื้นผิวการลงทะเบียน API ของ Plugin ใน src/plugins/types.ts
  • การเชื่อมต่อรีจิสทรี Plugin ใน src/plugins/registry.ts
  • การเปิดเผยรันไทม์ของ Plugin ใน src/plugins/runtime/* เมื่อ Plugin ฟีเจอร์/ช่องทางจำเป็นต้องใช้งาน
  • ตัวช่วยจับข้อมูล/ทดสอบใน src/test-utils/plugin-registration.ts
  • การยืนยันความเป็นเจ้าของ/สัญญาใน src/plugins/contracts/registry.ts
  • เอกสารสำหรับผู้ดำเนินการ/Plugin ใน docs/

หากพื้นผิวใดพื้นผิวหนึ่งขาดหายไป โดยทั่วไปเป็นสัญญาณว่าความสามารถดังกล่าวยังไม่ได้รับการผสานรวมอย่างสมบูรณ์

แม่แบบความสามารถ

รูปแบบขั้นต่ำ:

ts
// core contractexport type VideoGenerationProviderPlugin = {  id: string;  label: string;  generateVideo: (req: VideoGenerationRequest) => Promise&lt;VideoGenerationResult&gt;;}; // plugin APIapi.registerVideoGenerationProvider({  id: "openai",  label: "OpenAI",  async generateVideo(req) {    return await generateOpenAiVideo(req);  },}); // shared runtime helper for feature/channel pluginsconst clip = await api.runtime.videoGeneration.generate({  prompt: "Show the robot walking through the lab.",  cfg,});

รูปแบบการทดสอบสัญญา (src/plugins/contracts/registry.ts เปิดเผยการค้นหาความเป็นเจ้าของ เช่น providerContractPluginIds; การทดสอบจะยืนยันว่ารายการ contracts.videoGenerationProviders ของ Plugin ตรงกับสิ่งที่ Plugin ลงทะเบียนจริง):

ts
expect(pluginManifest.contracts?.videoGenerationProviders).toEqual(["openai"]);

วิธีนี้ทำให้กฎเรียบง่าย:

  • แกนหลักเป็นเจ้าของสัญญาความสามารถและการประสานงาน
  • Plugin ของผู้จำหน่ายเป็นเจ้าของการติดตั้งใช้งานเฉพาะผู้จำหน่าย
  • Plugin ฟีเจอร์/ช่องทางใช้ตัวช่วยรันไทม์
  • การทดสอบสัญญาทำให้ความเป็นเจ้าของชัดเจนอยู่เสมอ

ที่เกี่ยวข้อง

Was this useful?
On this page

On this page