Building plugins
การสร้าง Plugin ช่องทาง
คู่มือนี้สร้าง Plugin ช่องทางที่เชื่อมต่อ OpenClaw กับแพลตฟอร์ม รับส่งข้อความ โดยครอบคลุมความปลอดภัยของ DM, การจับคู่, เธรดการตอบกลับ และการส่งข้อความออก
สิ่งที่ Plugin ของคุณเป็นเจ้าของ
Plugin ช่องทางไม่ต้องติดตั้งเครื่องมือส่ง/แก้ไข/แสดงปฏิกิริยา โดยแกนหลักมีเครื่องมือ
message ที่ใช้ร่วมกันหนึ่งรายการ Plugin ของคุณเป็นเจ้าของ:
- การกำหนดค่า - การระบุบัญชีและวิซาร์ดการตั้งค่า
- ความปลอดภัย - นโยบาย DM และรายการอนุญาต
- การจับคู่ - ขั้นตอนการอนุมัติ DM
- ไวยากรณ์เซสชัน - วิธีแมป ID การสนทนาเฉพาะผู้ให้บริการไปยังแชต พื้นฐาน, ID เธรด และทางเลือกสำรองระดับแม่
- การส่งออก - การส่งข้อความ สื่อ และแบบสำรวจไปยังแพลตฟอร์ม
- การจัดเธรด - วิธีกำหนดเธรดให้การตอบกลับ
- การแสดงสถานะกำลังพิมพ์ของ Heartbeat - สัญญาณกำลังพิมพ์/ไม่ว่างที่เลือกใช้ได้สำหรับเป้าหมาย การส่ง Heartbeat
แกนหลักเป็นเจ้าของเครื่องมือข้อความที่ใช้ร่วมกัน การเชื่อมต่อพรอมต์ รูปแบบภายนอกของคีย์เซสชัน
การจัดทำบัญชี :thread: ทั่วไป และการส่งต่อ
อะแดปเตอร์ข้อความ
เปิดเผยอะแดปเตอร์ message ที่มี defineChannelMessageAdapter จาก
openclaw/plugin-sdk/channel-outbound ประกาศเฉพาะความสามารถในการส่งขั้นสุดท้ายแบบถาวร
ที่ทรานสปอร์ตแบบเนทีฟของคุณรองรับจริง พร้อมการทดสอบสัญญาที่พิสูจน์ผลข้างเคียง
ฝั่งเนทีฟและใบตอบรับที่ส่งคืน ให้การส่งข้อความ/สื่อชี้ไปยังฟังก์ชันทรานสปอร์ตเดียวกับที่อะแดปเตอร์
outbound เดิมใช้ สำหรับสัญญา API ฉบับเต็ม เมทริกซ์ความสามารถ กฎใบตอบรับ
การทำให้การแสดงตัวอย่างสดเสร็จสิ้น นโยบายการตอบรับเมื่อได้รับ การทดสอบ และตารางการย้าย โปรดดู
API การส่งออกของช่องทาง
หากอะแดปเตอร์ outbound ที่มีอยู่มีเมธอดส่งและข้อมูลเมตาความสามารถที่ถูกต้องอยู่แล้ว
ให้สร้างอะแดปเตอร์ message ด้วย
createChannelMessageAdapterFromOutbound(...) แทนการเขียนบริดจ์อีกชุดด้วยตนเอง
การส่งผ่านอะแดปเตอร์จะคืนค่า MessageReceipt สำหรับ ID แบบเดิม ให้สร้างจาก
listMessageReceiptPlatformIds(...) หรือ
resolveMessageReceiptPrimaryId(...) แทนการเก็บฟิลด์ messageIds
แยกกันแบบคู่ขนาน
ประกาศความสามารถแบบสดและตัวดำเนินการขั้นสุดท้ายอย่างแม่นยำ เพราะแกนหลักใช้ข้อมูลเหล่านี้เพื่อตัดสิน ว่าช่องทางทำอะไรได้บ้าง และความคลาดเคลื่อนระหว่างพฤติกรรมที่ประกาศกับพฤติกรรมจริงถือเป็น ความล้มเหลวของการทดสอบสัญญา:
| พื้นผิว | ค่า |
|---|---|
message.live.capabilities |
draftPreview, previewFinalization, progressUpdates, nativeStreaming, quietFinalization |
message.live.finalizer.capabilities |
finalEdit, normalFallback, discardPending, previewReceipt, retainOnAmbiguousFailure |
ช่องทางที่ทำให้การแสดงตัวอย่างฉบับร่างเสร็จสิ้นในตำแหน่งเดิมควรกำหนดเส้นทางตรรกะรันไทม์
ผ่าน defineFinalizableLivePreviewAdapter(...) ร่วมกับ
deliverWithFinalizableLivePreviewAdapter(...) และให้ความสามารถที่ประกาศ
มีการทดสอบ verifyChannelMessageLiveCapabilityAdapterProofs(...)
และ verifyChannelMessageLiveFinalizerProofs(...) รองรับ เพื่อไม่ให้พฤติกรรมการแสดงตัวอย่าง
ความคืบหน้า การแก้ไข ทางเลือกสำรอง/การเก็บรักษา การล้างข้อมูล และใบตอบรับแบบเนทีฟคลาดเคลื่อน
โดยไม่มีสัญญาณเตือน
ตัวรับขาเข้าที่เลื่อนการตอบรับของแพลตฟอร์มควรประกาศ
message.receive.defaultAckPolicy และ supportedAckPolicies แทนการซ่อน
เวลาการตอบรับไว้ในสถานะเฉพาะมอนิเตอร์ ครอบคลุมทุกนโยบายที่ประกาศด้วย
verifyChannelMessageReceiveAckPolicyAdapterProofs(...)
ตัวช่วยตอบกลับเดิม เช่น dispatchInboundReplyWithBase และ
recordInboundSessionAndDispatchReply ยังคงพร้อมใช้งานสำหรับตัวส่งต่อ
ที่รองรับความเข้ากันได้ อย่าใช้ตัวช่วยเหล่านี้กับโค้ดช่องทางใหม่ ให้เริ่มจากอะแดปเตอร์
message, ใบตอบรับ และตัวช่วยวงจรชีวิตการรับ/ส่งบน
openclaw/plugin-sdk/channel-outbound แทน
จุดรับขาเข้า (ทดลอง)
ช่องทางที่กำลังย้ายการให้สิทธิ์ขาเข้าสามารถใช้พาธย่อย
openclaw/plugin-sdk/channel-ingress-runtime แบบทดลองจากพาธการรับของรันไทม์
ส่วนนี้รับข้อเท็จจริงของแพลตฟอร์ม รายการอนุญาตดิบ ตัวอธิบายเส้นทาง ข้อเท็จจริงของคำสั่ง
และการกำหนดค่ากลุ่มการเข้าถึง จากนั้นส่งคืนภาพฉายของผู้ส่ง/เส้นทาง/คำสั่ง/การเปิดใช้งาน
พร้อมกราฟจุดรับเข้าที่เรียงลำดับแล้ว ขณะที่การค้นหาบนแพลตฟอร์มและผลข้างเคียง
ยังคงอยู่ใน Plugin ให้เก็บการปรับเอกลักษณ์ของ Plugin ให้อยู่ในรูปแบบมาตรฐานไว้ใน
ตัวอธิบายที่ส่งให้ตัวแก้ค่า อย่าทำให้ค่าการจับคู่ดิบจากสถานะหรือการตัดสินใจ
ที่แก้ค่าแล้วเป็นอนุกรม โปรดดู
API จุดรับเข้าของช่องทาง สำหรับการออกแบบ API
ขอบเขตความเป็นเจ้าของ และความคาดหวังในการทดสอบ
จุดรับเข้าแบบถาวรและการขจัดข้อมูลซ้ำจากการเล่นซ้ำ
ช่องทางที่นำจุดรับเข้าแบบถาวรมาใช้ควรใช้ createChannelIngressMonitor
จาก openclaw/plugin-sdk/channel-outbound เว้นแต่จำเป็นต้องมีสัญญาการรับเข้า
หรือการสูบข้อมูลที่แตกต่างอย่างมีนัยสำคัญ ให้เข้าคิวซองทรานสปอร์ตดิบที่
จุดคอขวดการรับเพียงจุดเดียว (ไม่ปรับให้อยู่ในรูปแบบมาตรฐาน ณ เวลาที่รับ) จำกัด
การตอบรับของทรานสปอร์ตไว้หลังการผนวกแบบถาวรสำหรับทรานสปอร์ต Webhook สร้างช่องทาง
แบบอนุกรมหนึ่งช่องต่อการสนทนา และทำเครื่องหมายเหตุการณ์ว่าเสร็จสมบูรณ์เมื่อการส่งต่อ
รับไปใช้งาน คีย์หลักของคิวคือ (queue_name, event_id) และเมื่อเสร็จสมบูรณ์
จะทำให้แถวเป็นทูมสโตนแทนการลบ ดังนั้นการส่งซ้ำจากแพลตฟอร์มในภายหลังของ
event_id เดิมจะถูกปฏิเสธอย่างถาวรตลอดช่วงเวลาการเก็บรักษาทูมสโตน
โปรดดู API การส่งออกของช่องทาง
สำหรับ API มอนิเตอร์และสัญญาการปิดระบบ
ทูมสโตนนั้นเป็นกฎการแบ่งชั้นสำหรับตัวป้องกันการเล่นซ้ำ
(openclaw/plugin-sdk/persistent-dedupe): ช่องทางที่ระบายแล้วจะเก็บตัวป้องกัน
การเล่นซ้ำแยกต่างหากเฉพาะเมื่อเอกลักษณ์หรือระยะเวลาเก็บรักษาของตัวป้องกันยาวนานกว่าของคิว
— เช่น คีย์ข้อความเชิงตรรกะที่ต่างจาก ID การส่งของทรานสปอร์ต (Telegram
ขจัดข้อมูลซ้ำของ chat_id:message_id เพราะการรวมแบบหน่วงสามารถทำให้ข้อความ
ปรากฏขึ้นอีกครั้งภายใต้ update_id ใหม่) หรือมีช่วงเวลายาวนานกว่าการเก็บรักษา
ทูมสโตนของช่องทาง หากคีย์ตัวป้องกันของคุณจะเท่ากับ event_id ของการระบาย
ให้ลบตัวป้องกันเมื่อนำการระบายมาใช้ และกำหนดขนาด completedTtlMs/completedMaxEntries
ให้ครอบคลุมช่วงเวลาของตัวป้องกันเดิมแทน การป้องกันที่ไม่ใช่การขจัดข้อมูลซ้ำ เช่น
ขอบเขตอายุ ไม่เกี่ยวข้องกับกฎนี้ ID ข้อความขาออกที่เสถียรใช้รีจิสทรีเสียงสะท้อนขาออก
ที่ใช้ร่วมกันจาก openclaw/plugin-sdk/channel-outbound แทนแคช TTL เฉพาะช่องทาง
คลาสทรานสปอร์ตและการเก็บรักษา
จำแนกทรานสปอร์ตตามการรับประกันการกู้คืนที่ขอบเขตการรับ:
- Webhook หรือการส่งเหตุการณ์ที่จำกัดด้วยการตอบรับ: ตอบรับหรือส่งคืนความสำเร็จเฉพาะ หลังการผนวกแบบถาวรเท่านั้น ความล้มเหลวในการผนวกต้องทำให้การส่งยังมีสิทธิ์ ลองใหม่หรือทำให้ขอบเขตการรับล้มเหลว คลาสนี้รวมถึง Slack, SMS, Zalo, Microsoft Teams, Google Chat, LINE และ Synology Chat
- การส่งแบบโพลหรือสตรีมที่รอให้เสร็จ: เลื่อนเคอร์เซอร์ระยะไกลหรือส่ง การตอบรับของทรานสปอร์ตหลังการผนวกเท่านั้น เมื่อไม่มีเคอร์เซอร์ที่ชัดเจน ให้คง การเรียกกลับการรับไว้แบบอนุกรมและรอให้เสร็จ เพื่อไม่ให้ความล้มเหลวในการผนวกทำให้ ลูปการรับทำงานล่วงหน้า Telegram แบบโพล, Signal และ Tlon ใช้คลาสนี้ ส่วนการส่งผ่าน Webhook ของ Telegram ใช้กฎที่จำกัดด้วยการตอบรับด้านบน
- ซ็อกเก็ตที่เล่นซ้ำไม่ได้: IRC, Mattermost, Twitch และ Zalo Personal ไม่สามารถขอ ให้แพลตฟอร์มส่งเหตุการณ์ที่ยอมรับแล้วซ้ำได้ คิวถาวรของแพลตฟอร์มเหล่านี้ป้องกันช่วงเวลา ที่กระบวนการขัดข้องและรองรับการกู้คืนเมื่อเริ่มระบบภายในใหม่ ส่วนทูมสโตน ของรายการที่เสร็จสมบูรณ์แทบไม่มีผลต่อการเล่นซ้ำจากแพลตฟอร์ม
ใช้ 30 วันเป็นข้อกำหนด TTL ของทูมสโตนสำหรับทั้งระบบ ไม่ใช่ค่าเริ่มต้นของ SDK โดยปกติช่วงเวลาการส่งซ้ำที่มีปริมาณสูงใช้ขีดจำกัดรายการที่เสร็จสมบูรณ์ 20,000 รายการ ส่วนทรานสปอร์ตที่รอให้เสร็จและเล่นซ้ำไม่ได้ซึ่งมีปริมาณต่ำกว่าโดยปกติใช้ 1,000-2,000 รายการ ข้อยกเว้นปัจจุบันรวมถึงขีดจำกัด 4,096 รายการของ LINE, TTL รายการที่เสร็จสมบูรณ์ 24 ชั่วโมงของ SMS และการเก็บรักษารายการที่เสร็จสมบูรณ์แบบจำกัดจำนวนเท่านั้นของ Tlon ขีดจำกัดแถวที่ล้มเหลวอาจต่ำกว่าขีดจำกัดรายการที่เสร็จสมบูรณ์ด้วย ทั้ง TTL และขีดจำกัด จะตัดแถวออก ดังนั้นการเก็บรักษาที่มีผลจริงจะสิ้นสุดเมื่อถึงขอบเขตใดขอบเขตหนึ่งก่อน ให้เบี่ยงเบนเฉพาะเมื่อมีกรอบเวลาการลองใหม่ของแพลตฟอร์มที่บันทึกไว้ ช่วงเวลาตัวป้องกัน การเล่นซ้ำที่คงไว้จากเวอร์ชันที่เผยแพร่ ปริมาณหรือโควตาดิสก์ที่คาดไว้ หรือทรานสปอร์ต ที่เล่นซ้ำไม่ได้ และครอบคลุมสัญญาการเก็บรักษาด้วยการทดสอบ
ผลข้างเคียงแบบอย่างน้อยหนึ่งครั้ง
การส่งต่อระหว่างการระบายจะเรียกใช้ผลข้างเคียงของคำสั่งก่อนที่แถวจุดรับเข้าจะกลายเป็น
ทูมสโตนที่เสร็จสมบูรณ์ หากกระบวนการขัดข้องระหว่างสองขั้นตอนนี้ แถวจะถูกเล่นซ้ำและ
อาจเรียกใช้ผลข้างเคียงอีกครั้ง ช่วงเวลาขัดข้องแบบอย่างน้อยหนึ่งครั้งนี้คือสัญญาเริ่มต้น
สำหรับงานที่ไม่เป็นไอดอมโพเทนต์ เช่น การเขียนการกำหนดค่า การล้างพื้นที่จัดเก็บ
หรือการตอบรับที่มองเห็นได้นอกช่องทางตอบกลับ ให้ใช้
createIngressEffectOnce(...) จาก
openclaw/plugin-sdk/ingress-effect-once ส่ง eventId ของจุดรับเข้าที่เสถียร
พร้อมชื่อเอฟเฟกต์ให้แต่ละการเรียก สร้างตัวช่วยหนึ่งรายการต่อคิว/บัญชีของจุดรับเข้า
และใช้ namespacePrefix ที่เสถียรและไม่ซ้ำกันสำหรับขอบเขตนั้น เนื่องจาก ID เหตุการณ์
ของทรานสปอร์ตอาจไม่ซ้ำกันเฉพาะภายในคิว ตัวช่วยจะคอมมิตการอ้างสิทธิ์แบบถาวร
หลังเอฟเฟกต์สำเร็จเท่านั้น เอฟเฟกต์ที่ส่งข้อผิดพลาดจะปล่อยการอ้างสิทธิ์เพื่อให้การลองระบายใหม่
เรียกใช้ได้อีกครั้ง ขณะที่ผู้เรียกพร้อมกันจะรอการอ้างสิทธิ์ที่ทำงานอยู่ ข้อผิดพลาดของสถานะถาวร
จะเรียก onDiskError เมื่อมีให้ และปฏิเสธแทนการถอยกลับไปใช้หน่วยความจำ
ของกระบวนการ
ตั้งค่า ttlMs ของตัวช่วยให้เท่ากับอย่างน้อยระยะเวลาเก็บรักษาทูมสโตน
ของจุดรับเข้าของช่องทางบวกกับระยะเวลาหน่วงสูงสุดระหว่างการคอมมิตเอฟเฟกต์และการทำให้แถว
เสร็จสมบูรณ์ ซึ่งรวมถึงช่วงหยุดทำงานและการลองระบายใหม่ที่มีขอบเขต TTL ของระเบียนเอฟเฟกต์
เริ่มเมื่อคอมมิต ส่วนการเก็บรักษาทูมสโตนเริ่มภายหลังเมื่อเสร็จสมบูรณ์ หากอายุของแถว
ที่รอดำเนินการไม่มีขอบเขต จะไม่มี TTL แบบจำกัดค่าใดครอบคลุมช่วงหยุดทำงานได้โดยพลการ
หลังจากทูมสโตนไม่สามารถเล่นแถวซ้ำได้อีก ระเบียนเอฟเฟกต์ที่เก่ากว่านั้นจะเป็นข้อมูลส่วนเกิน
กำหนดขนาด stateMaxEntries ให้รองรับทุกคีย์เหตุการณ์/เอฟเฟกต์ที่แตกต่างกันซึ่งอาจมีอยู่
ในช่วงเวลาการเก็บรักษานั้น โดยคำนึงถึงขีดจำกัดรายการที่เสร็จสมบูรณ์ของคิวและจำนวนเอฟเฟกต์
สูงสุดต่อเหตุการณ์ ขีดจำกัดที่ต่ำกว่าจะขับระเบียนเก่าที่สุดออกก่อน TTL และทำให้เอฟเฟกต์นั้น
เรียกใช้ได้อีกครั้ง ช่วงเวลาแบบอย่างน้อยหนึ่งครั้งที่เหลืออยู่ยังคงเกิดขึ้นได้ หากกระบวนการหยุดทำงาน
หรือการคงข้อมูลล้มเหลวหลังเอฟเฟกต์สำเร็จแต่ก่อนคอมมิตการอ้างสิทธิ์ หรือหากระเบียนหมดอายุ
ขณะที่แถวจุดรับเข้ายังคงรอดำเนินการ
สัญญาการเริ่มระบบใหม่ตามขอบเขตบัญชี
โดยค่าเริ่มต้น การเปลี่ยนแปลงการกำหนดค่าช่องทางจะเริ่มช่องทางทั้งหมดใหม่ ช่องทางแบบหลายบัญชี
อาจตั้งค่า reload.accountScopedRestart: true ได้เฉพาะเมื่อการแก้ไข
การกำหนดค่าอ่านฟิลด์ที่ใช้ร่วมกันทั้งช่องทางพร้อมกับบัญชีที่เลือกเท่านั้น และไม่อ่าน
บัญชีข้างเคียง และ Gateway สามารถหยุดและเริ่มรันไทม์ (channel, accountId)
หนึ่งรายการโดยไม่แทนที่รันไทม์ข้างเคียง
พาธตามขอบเขตใช้เฉพาะกับการเปลี่ยนแปลงภายใต้
channels.<channel>.accounts.<non-default-id>.* การเปลี่ยนแปลงฟิลด์ช่องทาง
ที่ใช้ร่วมกัน, accounts.default, บัญชีที่ถูกลบหรือแก้ค่าไม่ได้ และการเปลี่ยนแปลง
แบบผสมที่อาจกระทบการสืบทอด จะถูกยกระดับเป็นการเริ่มทั้งช่องทางใหม่ Plugin
ที่ไม่เลือกใช้จะใช้พาธทั้งช่องทางเสมอ
สำหรับช่องทางที่ใช้การระบายจุดรับเข้าแบบถาวร พาธหยุดของมอนิเตอร์บัญชี ต้องทำให้การรับเข้าของทรานสปอร์ตทั้งหมดที่ยอมรับแล้วเสร็จสิ้นก่อน จากนั้นจึงกำจัดและรอ การระบายของมอนิเตอร์ การเริ่มบัญชีจะเปิดคิวเดียวกันที่กำหนดคีย์ตามบัญชี ซึ่งการระบาย ครั้งแรกจะกู้คืนแถวถาวรที่ยังไม่ได้ส่งต่อ อย่าเพิ่มรอบการเล่นซ้ำชุดที่สองสำหรับการโหลดใหม่ โดยเฉพาะ การกู้คืนคิวคือพาธการเริ่มระบบใหม่ตามมาตรฐาน
ให้ถือว่าแฟล็กนี้เป็นการอ้างความสามารถ ไม่ใช่การตั้งค่าประสิทธิภาพ การทดสอบสัญญา ควรพิสูจน์ว่าการเพิ่มและแก้ไขบัญชีที่ระบุชื่อหนึ่งบัญชีไม่เปลี่ยนการกำหนดค่าที่แก้ค่าแล้ว ของบัญชีข้างเคียง การหยุดหนึ่งบัญชีทำให้เฉพาะมอนิเตอร์และการระบายของบัญชีนั้นเสร็จสิ้น และมอนิเตอร์ใหม่กู้คืนแถวของบัญชีนั้นได้เพียงครั้งเดียว หากพิสูจน์การรับประกันข้อใดไม่ได้ ให้งดแฟล็กนี้
ตัวบ่งชี้สถานะกำลังพิมพ์
หากช่องทางรองรับตัวบ่งชี้สถานะกำลังพิมพ์นอกการตอบกลับขาเข้า ให้เปิดเผย
heartbeat.sendTyping(...) บน Plugin ช่องทาง แกนหลักจะเรียกส่วนนี้ด้วย
เป้าหมายการส่ง Heartbeat ที่แก้ค่าแล้วก่อนเริ่มการทำงานของโมเดล Heartbeat และใช้
วงจรชีวิตการคงสถานะกำลังพิมพ์/การล้างข้อมูลที่ใช้ร่วมกัน เพิ่ม
heartbeat.clearTyping(...) เมื่อแพลตฟอร์มต้องการสัญญาณหยุดที่ชัดเจน
พารามิเตอร์แหล่งที่มาของสื่อ
หากช่องทางเพิ่มพารามิเตอร์เครื่องมือข้อความที่นำพาแหล่งที่มาของสื่อ ให้เปิดเผย
ชื่อพารามิเตอร์เหล่านั้นผ่าน plugin.actions.describeMessageTool(...).mediaSourceParams
แกนหลักใช้รายการที่ระบุชัดเจนนี้สำหรับการปรับพาธ sandbox ให้อยู่ในรูปแบบมาตรฐานและ
นโยบายการเข้าถึงสื่อขาออก เพื่อให้ Plugin ไม่จำเป็นต้องมีกรณีพิเศษในแกนหลักที่ใช้ร่วมกัน
สำหรับพารามิเตอร์รูปประจำตัว ไฟล์แนบ หรือภาพหน้าปกที่เฉพาะเจาะจงกับผู้ให้บริการ
ควรใช้แมปที่มีแอ็กชันเป็นคีย์ เช่น { "set-profile": ["avatarUrl", "avatarPath"] }
เพื่อไม่ให้แอ็กชันที่ไม่เกี่ยวข้องรับช่วงอาร์กิวเมนต์สื่อของแอ็กชันอื่น ส่วนอาร์เรย์แบบแบน
ยังใช้ได้กับพารามิเตอร์ที่ตั้งใจให้ใช้ร่วมกันในทุกแอ็กชันที่เปิดเผย
ช่องทางที่ต้องเปิดเผย URL สาธารณะชั่วคราวเพื่อให้แพลตฟอร์มดึงข้อมูลสื่อ
สามารถใช้ createHostedOutboundMediaStore(...) จาก
openclaw/plugin-sdk/outbound-media ร่วมกับที่เก็บสถานะของ Plugin ได้ ให้การแยกวิเคราะห์
เส้นทางของแพลตฟอร์มและการบังคับใช้โทเค็นอยู่ใน Plugin ช่องทาง ส่วนตัวช่วยที่ใช้ร่วมกัน
รับผิดชอบเฉพาะการโหลดสื่อ เมทาดาทาการหมดอายุ แถวของส่วนย่อย และการล้างข้อมูล
การจัดรูปเพย์โหลดแบบเนทีฟ
หากช่องทางต้องจัดรูปแบบเฉพาะผู้ให้บริการสำหรับ message(action="send")
ควรใช้ actions.prepareSendPayload(...) เก็บการ์ด บล็อก เอ็มเบดแบบเนทีฟ หรือ
ข้อมูลถาวรอื่นไว้ภายใต้ payload.channelData.<channel> และให้แกนหลักส่ง
ผ่านอะแดปเตอร์ขาออก/ข้อความ ใช้ actions.handleAction(...) สำหรับการส่ง
เฉพาะในฐานะทางเลือกสำรองเพื่อความเข้ากันได้สำหรับเพย์โหลดที่ไม่สามารถทำให้เป็นอนุกรมและ
ลองส่งใหม่ได้
ไวยากรณ์การสนทนาของเซสชัน
หากแพลตฟอร์มเก็บขอบเขตเพิ่มเติมไว้ใน ID การสนทนา ให้การแยกวิเคราะห์นั้น
อยู่ใน Plugin ด้วย messaging.resolveSessionConversation(...) นี่คือ
ฮุกมาตรฐานสำหรับแมป rawId ไปยัง ID การสนทนาฐาน, ID
เธรดที่ไม่บังคับ, baseConversationId ที่ระบุชัดเจน และ
parentConversationCandidates ใดๆ เมื่อส่งคืน parentConversationCandidates
ให้เรียงจากพาเรนต์ที่มีขอบเขตแคบที่สุดไปยังการสนทนาที่กว้างที่สุด/ฐาน
messaging.resolveParentConversationCandidates(...) เป็นทางเลือกสำรองเพื่อความเข้ากันได้
ที่เลิกใช้แล้วสำหรับ Plugin ที่ต้องการเพียงพาเรนต์สำรองเพิ่มเติมจาก
ID ทั่วไป/ดิบ หากมีทั้งสองฮุก แกนหลักจะใช้
resolveSessionConversation(...).parentConversationCandidates ก่อน และจะ
ถอยไปใช้ resolveParentConversationCandidates(...) เฉพาะเมื่อฮุกมาตรฐาน
ไม่ได้ระบุค่าเหล่านั้น
Plugin ที่รวมมาในชุดซึ่งต้องใช้การแยกวิเคราะห์เดียวกันก่อนรีจิสทรีช่องทางเริ่มทำงาน
สามารถเปิดเผยไฟล์ session-key-api.ts ระดับบนสุด พร้อมการส่งออก
resolveSessionConversation(...) ที่ตรงกัน (ดู Plugin Feishu และ Telegram)
แกนหลักใช้พื้นผิวที่ปลอดภัยสำหรับการบูตนั้น เฉพาะเมื่อรีจิสทรี Plugin
รันไทม์ยังไม่พร้อมใช้งาน
ใช้ openclaw/plugin-sdk/channel-route เมื่อโค้ด Plugin ต้องปรับฟิลด์
ที่มีลักษณะคล้ายเส้นทางให้เป็นมาตรฐาน เปรียบเทียบเธรดย่อยกับเส้นทางพาเรนต์ หรือสร้าง
คีย์ขจัดรายการซ้ำที่เสถียรจาก { channel, to, accountId, threadId } ตัวช่วยนี้
ปรับ ID เธรดแบบตัวเลขให้เป็นมาตรฐานด้วยวิธีเดียวกับแกนหลัก จึงควรใช้แทนการเปรียบเทียบ
String(threadId) แบบเฉพาะกิจ Plugin ที่มีไวยากรณ์เป้าหมายเฉพาะผู้ให้บริการ
ควรเปิดเผย messaging.resolveOutboundSessionRoute(...) เพื่อให้แกนหลักได้รับ
อัตลักษณ์เซสชันและเธรดแบบเนทีฟของผู้ให้บริการโดยไม่ต้องใช้ชิมตัวแยกวิเคราะห์
การรองรับการผูกการสนทนาตามขอบเขตบัญชี
ตั้งค่า conversationBindings.supportsCurrentConversationBinding เมื่อช่องทาง
รองรับการผูกการสนทนาปัจจุบันแบบทั่วไป createChatChannelPlugin(...)
ตั้งค่าความสามารถแบบคงที่นี้เป็น true โดยค่าเริ่มต้น
หากการรองรับแตกต่างกันตามบัญชีที่กำหนดค่าไว้ ให้ใช้งาน
conversationBindings.isCurrentConversationBindingSupported({ accountId }) เพิ่มเติม
แกนหลักจะประเมินฮุกแบบซิงโครนัสนี้หลังจากเปิดใช้ความสามารถแบบคงที่แล้วเท่านั้น
การส่งคืน false ทำให้ความสามารถ การผูก การค้นหา การแสดงรายการ
การแตะ และการยกเลิกการผูกการสนทนาปัจจุบันแบบทั่วไป ใช้งานไม่ได้สำหรับบัญชีนั้น
หากละเว้นฮุก ระบบจะใช้ความสามารถแบบคงที่กับทุกบัญชี
หาคำตอบจากการกำหนดค่าบัญชีหรือสถานะรันไทม์ที่โหลดไว้แล้ว ฮุกนี้
ควบคุมเฉพาะการผูกการสนทนาปัจจุบันแบบทั่วไป ไม่ได้แทนที่
กฎการผูกที่กำหนดค่าไว้หรือการกำหนดเส้นทางเซสชันที่ Plugin เป็นเจ้าของ การทดสอบสัญญา
ควรครอบคลุมอย่างน้อยหนึ่งบัญชีที่รองรับและหนึ่งบัญชีที่ไม่รองรับ ผ่าน
สัญญา ChannelPlugin["conversationBindings"] ที่ส่งออกโดย
openclaw/plugin-sdk/channel-core
การอนุมัติและความสามารถของช่องทาง
Plugin ช่องทางส่วนใหญ่ไม่จำเป็นต้องมีโค้ดเฉพาะการอนุมัติ แกนหลักเป็นเจ้าของ
/approve ในแชตเดียวกัน เพย์โหลดปุ่มอนุมัติที่ใช้ร่วมกัน และการส่งทางเลือกสำรองทั่วไป
ChannelPlugin.approvals ถูกนำออกแล้ว ให้ใส่ข้อเท็จจริงด้านการส่ง/เนทีฟ/การเรนเดอร์/การยืนยันตัวตน
สำหรับการอนุมัติไว้ในอ็อบเจ็กต์ approvalCapability เดียวแทน plugin.auth ใช้สำหรับ
เข้าสู่ระบบ/ออกจากระบบเท่านั้น — แกนหลักจะไม่อ่านฮุกการยืนยันตัวตนสำหรับการอนุมัติจากอ็อบเจ็กต์นั้นอีกต่อไป
ใช้ approvalCapability.delivery เฉพาะสำหรับการกำหนดเส้นทางการอนุมัติแบบเนทีฟหรือ
การระงับทางเลือกสำรอง และใช้ approvalCapability.render เฉพาะเมื่อช่องทางจำเป็นต้องใช้
เพย์โหลดการอนุมัติแบบกำหนดเองแทนตัวเรนเดอร์ที่ใช้ร่วมกันจริงๆ
การยืนยันตัวตนสำหรับการอนุมัติ
approvalCapability.authorizeActorActionและapprovalCapability.getActionAvailabilityStateเป็นจุดเชื่อมมาตรฐาน สำหรับการยืนยันตัวตนเพื่ออนุมัติ- ใช้
getActionAvailabilityStateสำหรับความพร้อมใช้งานของการยืนยันตัวตนเพื่ออนุมัติในแชตเดียวกัน ให้ผู้อนุมัติที่กำหนดค่าไว้ยังคงพร้อมใช้งานสำหรับ/approveแม้ปิดใช้งาน การส่งแบบเนทีฟ ให้ใช้สถานะพื้นผิวเริ่มต้นแบบเนทีฟสำหรับคำแนะนำด้านการส่ง/การตั้งค่า แทน - หากช่องทางเปิดเผยการอนุมัติการดำเนินการแบบเนทีฟ ให้ใช้
approvalCapability.getExecInitiatingSurfaceStateสำหรับสถานะ พื้นผิวเริ่มต้น/ไคลเอนต์เนทีฟ เมื่อแตกต่างจากการยืนยันตัวตนเพื่ออนุมัติ ในแชตเดียวกัน แกนหลักใช้ฮุกเฉพาะการดำเนินการนั้นเพื่อแยกenabledออกจากdisabled, ตัดสินว่าช่องทางเริ่มต้นรองรับการอนุมัติการดำเนินการ แบบเนทีฟหรือไม่ และรวมช่องทางไว้ในคำแนะนำทางเลือกสำรองของไคลเอนต์เนทีฟcreateApproverRestrictedNativeApprovalCapability(...)เติมค่านี้ให้สำหรับ กรณีทั่วไป - หากช่องทางสามารถอนุมานอัตลักษณ์ DM ที่เสถียรและมีลักษณะเหมือนเจ้าของจากการกำหนดค่าที่มีอยู่
ให้ใช้
createResolvedApproverActionAuthAdapterจากopenclaw/plugin-sdk/approval-runtimeเพื่อจำกัด/approveในแชตเดียวกัน โดยไม่เพิ่มตรรกะแกนหลักที่เฉพาะกับการอนุมัติ - หากการยืนยันตัวตนเพื่ออนุมัติแบบกำหนดเองตั้งใจอนุญาตเฉพาะทางเลือกสำรองในแชตเดียวกัน ให้ส่งคืน
markImplicitSameChatApprovalAuthorization({ authorized: true })จากopenclaw/plugin-sdk/approval-auth-runtimeมิฉะนั้นแกนหลักจะถือว่า ผลลัพธ์เป็นการให้อำนาจผู้อนุมัติอย่างชัดเจน - หากคอลแบ็กแบบเนทีฟที่ช่องทางเป็นเจ้าของแก้ไขการอนุมัติโดยตรง ให้ใช้
isImplicitSameChatApprovalAuthorization(...)ก่อนแก้ไข เพื่อให้ทางเลือกสำรอง โดยนัยยังคงผ่านการให้อำนาจผู้ดำเนินการตามปกติของช่องทาง
วงจรชีวิตของเพย์โหลดและคำแนะนำการตั้งค่า
- ใช้
outbound.shouldSuppressLocalPayloadPromptหรือoutbound.beforeDeliverPayloadสำหรับพฤติกรรมวงจรชีวิตของเพย์โหลดเฉพาะช่องทาง เช่น การซ่อนพรอมต์การอนุมัติภายในที่ซ้ำกัน หรือการส่งตัวบ่งชี้ว่ากำลังพิมพ์ ก่อนส่ง - ใช้
approvalCapability.describeExecApprovalSetupเมื่อช่องทางต้องการ ให้การตอบกลับในเส้นทางที่ปิดใช้งานอธิบายตัวเลือกการกำหนดค่าที่แน่นอนซึ่งต้องใช้เพื่อเปิดใช้ การอนุมัติการดำเนินการแบบเนทีฟ ฮุกได้รับ{ channel, channelLabel, accountId }; ช่องทางที่มีบัญชีแบบระบุชื่อควรเรนเดอร์พาธตามขอบเขตบัญชี เช่นchannels.<channel>.accounts.<id>.execApprovals.*แทนค่าเริ่มต้น ระดับบนสุด - ใช้
approvalCapability.describePluginApprovalSetupเมื่อคำแนะนำกรณี การอนุมัติของ Plugin ล้มเหลว สามารถแสดงได้อย่างปลอดภัยสำหรับความล้มเหลวแบบไม่มีเส้นทางและหมดเวลา ของการอนุมัติ PlugincreateApproverRestrictedNativeApprovalCapability(...)จะไม่ อนุมานค่านี้จากdescribeExecApprovalSetup; ให้ส่งตัวช่วยเดียวกันอย่างชัดเจน เฉพาะเมื่อการอนุมัติ Plugin และการดำเนินการใช้การตั้งค่าเนทีฟเดียวกันจริงๆ
การส่งการอนุมัติแบบเนทีฟ
หากช่องทางต้องการการส่งการอนุมัติแบบเนทีฟ ให้โค้ดช่องทางมุ่งเน้นที่
การปรับเป้าหมายให้เป็นมาตรฐาน รวมถึงข้อเท็จจริงด้านการขนส่ง/การนำเสนอ ใช้
createChannelExecApprovalProfile, createChannelNativeOriginTargetResolver,
createChannelApproverDmTargetResolver และ
createApproverRestrictedNativeApprovalCapability จาก
openclaw/plugin-sdk/approval-runtime เก็บข้อเท็จจริงเฉพาะช่องทางไว้เบื้องหลัง
approvalCapability.nativeRuntime โดยควรผ่าน
createChannelApprovalNativeRuntimeAdapter(...) หรือ
createLazyChannelApprovalNativeRuntimeAdapter(...) เพื่อให้แกนหลักสามารถประกอบ
ตัวจัดการและรับผิดชอบการกรองคำขอ การกำหนดเส้นทาง การขจัดรายการซ้ำ การหมดอายุ การสมัครรับข้อมูล
Gateway และการแจ้งเตือนว่าถูกกำหนดเส้นทางไปที่อื่น
nativeRuntime ถูกแยกเป็นจุดเชื่อมขนาดเล็กหลายรายการ:
availability— บัญชีได้รับการกำหนดค่าแล้วหรือไม่ และควรจัดการคำขอหรือไม่presentation— แมปโมเดลมุมมองการอนุมัติที่ใช้ร่วมกันเป็น เพย์โหลดเนทีฟที่รอดำเนินการ/แก้ไขแล้ว/หมดอายุ หรือแอ็กชันสุดท้ายtransport— เตรียมเป้าหมาย รวมถึงส่ง/อัปเดต/ลบข้อความ การอนุมัติแบบเนทีฟinteractions— ฮุกการผูก/ยกเลิกการผูก/ล้างแอ็กชันที่ไม่บังคับสำหรับปุ่ม หรือรีแอ็กชันแบบเนทีฟ รวมถึงฮุกcancelDeliveredที่ไม่บังคับ ให้ใช้งานcancelDeliveredเมื่อdeliverPendingลงทะเบียนสถานะในกระบวนการหรือสถานะถาวร (เช่น ที่เก็บเป้าหมายรีแอ็กชัน) เพื่อให้สามารถปล่อยสถานะนั้นได้ หากการหยุด ตัวจัดการยกเลิกการส่งก่อนbindPendingทำงาน หรือเมื่อbindPendingไม่ส่งคืนแฮนเดิลobserve— ฮุกการวินิจฉัยการส่งที่ไม่บังคับ
ตัวช่วยการอนุมัติอื่นๆ:
- ใช้
createNativeApprovalChannelRouteGatesจากopenclaw/plugin-sdk/approval-native-runtimeเมื่อช่องทางรองรับทั้ง การส่งแบบเนทีฟจากต้นทางเซสชันและเป้าหมายส่งต่อการอนุมัติที่ระบุชัดเจน ตัวช่วยนี้ รวมการเลือกการกำหนดค่าการอนุมัติ การจัดการmode, ตัวกรองเอเจนต์/เซสชัน การผูกบัญชี การจับคู่เป้าหมายเซสชัน และการจับคู่รายการเป้าหมายไว้ที่เดียว ขณะที่ผู้เรียกยังคงเป็นเจ้าของ ID ช่องทาง โหมดส่งต่อเริ่มต้น การค้นหา บัญชี การตรวจสอบว่าเปิดใช้การขนส่ง การปรับเป้าหมายให้เป็นมาตรฐาน และการแก้ไขเป้าหมาย จากต้นทางของเทิร์น อย่าใช้ตัวช่วยนี้สร้างค่าเริ่มต้นนโยบายช่องทางที่แกนหลักเป็นเจ้าของ ให้ส่งโหมดเริ่มต้นที่ช่องทางระบุไว้ในเอกสารอย่างชัดเจน createChannelNativeOriginTargetResolverใช้ตัวจับคู่เส้นทางช่องทางที่ใช้ร่วมกัน โดยค่าเริ่มต้นสำหรับเป้าหมาย{ to, accountId, threadId }ส่งtargetsMatchเฉพาะเมื่อช่องทางมีกฎความเทียบเท่าเฉพาะผู้ให้บริการ เช่น การจับคู่คำนำหน้าไทม์สแตมป์ของ Slack ส่งnormalizeTargetForMatchเมื่อ ช่องทางต้องทำให้ ID ผู้ให้บริการเป็นรูปแบบมาตรฐานก่อนตัวจับคู่เส้นทาง เริ่มต้นหรือคอลแบ็กtargetsMatchแบบกำหนดเองทำงาน โดยยังคงเก็บ เป้าหมายเดิมไว้สำหรับการส่ง ใช้normalizeTargetเฉพาะเมื่อเป้าหมาย การส่งที่แก้ไขแล้วควรถูกทำให้เป็นรูปแบบมาตรฐานด้วย- หากช่องทางต้องการอ็อบเจ็กต์ที่รันไทม์เป็นเจ้าของ เช่น ไคลเอนต์ โทเค็น แอป Bolt
หรือตัวรับ Webhook ให้ลงทะเบียนผ่าน
openclaw/plugin-sdk/channel-runtime-contextรีจิสทรีบริบทรันไทม์ แบบทั่วไปช่วยให้แกนหลักบูตตัวจัดการที่ขับเคลื่อนด้วยความสามารถจากสถานะ เริ่มต้นของช่องทางได้ โดยไม่ต้องเพิ่มกาวตัวห่อเฉพาะการอนุมัติ - ใช้
createChannelApprovalHandlerหรือcreateChannelNativeApprovalRuntimeระดับล่างกว่า เฉพาะเมื่อจุดเชื่อมที่ขับเคลื่อน ด้วยความสามารถยังแสดงความต้องการได้ไม่เพียงพอ - ช่องทางการอนุมัติแบบเนทีฟต้องกำหนดเส้นทางทั้ง
accountIdและapprovalKindผ่านตัวช่วยเหล่านั้นaccountIdทำให้นโยบายการอนุมัติแบบหลายบัญชี อยู่ในขอบเขตบัญชีบอตที่ถูกต้อง และapprovalKindทำให้พฤติกรรมการอนุมัติ แบบดำเนินการเทียบกับแบบ Plugin พร้อมใช้งานต่อช่องทาง โดยไม่มีสาขาที่ฮาร์ดโค้ดใน แกนหลัก - แกนหลักเป็นเจ้าของการแจ้งเตือนการเปลี่ยนเส้นทางการอนุมัติด้วย Plugin ช่องทางไม่ควรส่ง
ข้อความติดตามของตนเองว่า "การอนุมัติถูกส่งไปยัง DM / ช่องทางอื่น" จาก
createChannelNativeApprovalRuntime; ให้เปิดเผยการกำหนดเส้นทางต้นทาง + DM ของผู้อนุมัติอย่างถูกต้องผ่านตัวช่วยความสามารถการอนุมัติที่ใช้ร่วมกัน และให้ แกนหลักรวบรวมการส่งจริงก่อนโพสต์การแจ้งเตือนใดๆ กลับไปยัง แชตที่เริ่มต้น - รักษาชนิด ID การอนุมัติที่ส่งไว้ตั้งแต่ต้นจนจบ ไคลเอนต์เนทีฟไม่ควร คาดเดาหรือเขียนการกำหนดเส้นทางการอนุมัติแบบดำเนินการเทียบกับแบบ Plugin ใหม่จากสถานะ ภายในช่องทาง
- ส่ง
approvalKindที่ระบุชัดเจนนั้นไปยังresolveApprovalOverGatewayวิธีนี้ใช้ บริการapproval.resolveมาตรฐาน และส่งคืนผู้ชนะที่บันทึกไว้เมื่อ พื้นผิวอื่นตอบก่อน อินพุตresolveMethodแบบระบุชัดเจนรุ่นเก่า ยังคงอยู่สำหรับตัวควบคุมที่มีคำสั่งเป็นฐาน แอ็กชันเนทีฟใหม่ต้องไม่ใช้ค่านี้หรือ อนุมานชนิดจาก ID - ชนิดการอนุมัติที่ต่างกันสามารถเปิดเผยพื้นผิวเนทีฟที่ต่างกันโดยตั้งใจ ตัวอย่างที่รวมมาในชุดปัจจุบัน: Matrix ใช้การกำหนดเส้นทาง DM/ช่องทางแบบเนทีฟ และ UX รีแอ็กชันเดียวกันสำหรับการอนุมัติแบบดำเนินการและแบบ Plugin ขณะยังอนุญาตให้ การยืนยันตัวตนแตกต่างกันตามชนิดการอนุมัติ ส่วน Slack ยังคงเปิดใช้การกำหนดเส้นทางการอนุมัติแบบเนทีฟ สำหรับทั้ง ID แบบดำเนินการและแบบ Plugin
createApproverRestrictedNativeApprovalAdapterยังคงมีอยู่ในฐานะ ตัวห่อเพื่อความเข้ากันได้ แต่โค้ดใหม่ควรใช้ตัวสร้างความสามารถ และเปิดเผยapprovalCapabilityบน Plugin
เส้นทางย่อยของรันไทม์การอนุมัติที่แคบกว่า
สำหรับจุดเข้าช่องทางที่มีการใช้งานสูง ควรใช้เส้นทางย่อยที่แคบกว่าเหล่านี้แทน barrel
approval-runtime ที่กว้างกว่า เมื่อจำเป็นต้องใช้เพียงส่วนเดียวของกลุ่มนั้น:
openclaw/plugin-sdk/approval-auth-runtimeopenclaw/plugin-sdk/approval-client-runtimeopenclaw/plugin-sdk/approval-delivery-runtimeopenclaw/plugin-sdk/approval-gateway-runtimeopenclaw/plugin-sdk/approval-reference-runtimeopenclaw/plugin-sdk/approval-handler-adapter-runtimeopenclaw/plugin-sdk/approval-handler-runtimeopenclaw/plugin-sdk/approval-native-runtimeopenclaw/plugin-sdk/approval-reply-runtimeopenclaw/plugin-sdk/channel-runtime-context
ในทำนองเดียวกัน ควรใช้ openclaw/plugin-sdk/reply-runtime,
openclaw/plugin-sdk/reply-dispatch-runtime,
openclaw/plugin-sdk/reply-reference และ
openclaw/plugin-sdk/reply-chunking แทนพื้นผิวครอบคลุมที่กว้างกว่า เมื่อ
ไม่จำเป็นต้องใช้ทั้งหมด
พาธย่อยสำหรับการตั้งค่า
openclaw/plugin-sdk/setup-runtimeครอบคลุมตัวช่วยการตั้งค่าที่ปลอดภัยสำหรับรันไทม์:createSetupTranslator, อะแดปเตอร์แพตช์การตั้งค่าที่นำเข้าได้อย่างปลอดภัย (createPatchedAccountSetupAdapter,createEnvPatchedAccountSetupAdapter,createSetupInputPresenceValidator), เอาต์พุตหมายเหตุการค้นหา,promptResolvedAllowFrom,splitSetupEntriesและตัวสร้าง พร็อกซีการตั้งค่าที่มอบหมายงานต่อopenclaw/plugin-sdk/channel-setupครอบคลุมตัวสร้างการตั้งค่า สำหรับการติดตั้งแบบไม่บังคับ รวมถึงองค์ประกอบพื้นฐานที่ปลอดภัยสำหรับการตั้งค่าบางส่วน ได้แก่createOptionalChannelSetupSurface,createOptionalChannelSetupAdapter,createOptionalChannelSetupWizard,DEFAULT_ACCOUNT_ID,createTopLevelChannelDmPolicy,setSetupChannelEnabledและsplitSetupEntries- ใช้ขอบเขตเชื่อมต่อ
openclaw/plugin-sdk/setupที่กว้างกว่าก็ต่อเมื่อคุณต้องการ ตัวช่วยการตั้งค่า/การกำหนดค่าที่ใช้ร่วมกันและมีขนาดใหญ่กว่าด้วย เช่นmoveSingleAccountChannelSectionToDefaultAccount(...)
หากช่องของคุณเพียงต้องการแจ้งว่า "ติดตั้ง Plugin นี้ก่อน" บนพื้นผิว
การตั้งค่า ให้เลือกใช้ createOptionalChannelSetupSurface(...) อะแดปเตอร์/วิซาร์ด
ที่สร้างขึ้นจะปฏิเสธโดยค่าเริ่มต้นเมื่อเขียนการกำหนดค่าและดำเนินการให้เสร็จสิ้น และจะใช้
ข้อความแจ้งว่าต้องติดตั้งเดียวกันในการตรวจสอบ การดำเนินการให้เสร็จสิ้น และข้อความ
ลิงก์เอกสาร
หากช่องของคุณรองรับการตั้งค่าหรือการยืนยันตัวตนที่ขับเคลื่อนด้วยตัวแปรสภาพแวดล้อม ให้เปิดเผยผ่าน
สคีมาการกำหนดค่าช่องและตัวบรรยายการตั้งค่า เก็บ envVars ของรันไทม์ช่องหรือ
ค่าคงที่ภายในไว้สำหรับข้อความที่แสดงแก่ผู้ดูแลระบบเท่านั้น
หากช่องของคุณอาจปรากฏใน status, channels list, channels status หรือ
การสแกน SecretRef ก่อนที่รันไทม์ Plugin จะเริ่มทำงาน ให้เพิ่ม openclaw.setupEntry ใน
package.json จุดเริ่มต้นนั้นควรนำเข้าได้อย่างปลอดภัยในพาธคำสั่ง
แบบอ่านอย่างเดียว และควรส่งคืนข้อมูลเมตาของช่อง อะแดปเตอร์การกำหนดค่า
ที่ปลอดภัยสำหรับการตั้งค่า อะแดปเตอร์สถานะ และข้อมูลเมตาเป้าหมายข้อมูลลับของช่องที่จำเป็นสำหรับ
ข้อมูลสรุปเหล่านั้น ห้ามเริ่มไคลเอนต์ ตัวรับฟัง หรือรันไทม์การขนส่งจาก
รายการตั้งค่า
รักษาพาธนำเข้าของรายการหลักของช่องให้แคบด้วยเช่นกัน การค้นพบสามารถประเมิน
รายการและโมดูล Plugin ของช่องเพื่อลงทะเบียนความสามารถโดยไม่ต้อง
เปิดใช้งานช่อง ไฟล์อย่างเช่น channel-plugin-api.ts ควรส่งออก
ออบเจ็กต์ Plugin ของช่องโดยไม่นำเข้าวิซาร์ดการตั้งค่า ไคลเอนต์
การขนส่ง ตัวรับฟังซ็อกเก็ต ตัวเรียกใช้กระบวนการย่อย หรือโมดูลเริ่มต้นบริการ
วางส่วนรันไทม์เหล่านั้นไว้ในโมดูลที่โหลดจาก registerFull(...), ตัวตั้งค่า
รันไทม์ หรืออะแดปเตอร์ความสามารถแบบโหลดภายหลัง
พาธย่อยแบบแคบอื่น ๆ ของช่อง
สำหรับพาธด่วนอื่น ๆ ของช่อง ให้เลือกใช้ตัวช่วยแบบแคบแทนพื้นผิวเดิม ที่กว้างกว่า:
openclaw/plugin-sdk/account-core,openclaw/plugin-sdk/account-id,openclaw/plugin-sdk/account-resolutionและopenclaw/plugin-sdk/account-helpersสำหรับการกำหนดค่าหลายบัญชีและ การย้อนกลับไปใช้บัญชีเริ่มต้นopenclaw/plugin-sdk/inbound-envelopeและopenclaw/plugin-sdk/channel-inboundสำหรับเส้นทาง/ซองขาเข้าและ การเชื่อมต่อการบันทึกและส่งต่อopenclaw/plugin-sdk/channel-targetsสำหรับตัวช่วยแยกวิเคราะห์เป้าหมายopenclaw/plugin-sdk/channel-outboundสำหรับตัวแทนการระบุตัวตน/การส่งขาออก และการวางแผนเพย์โหลดที่มีชนิดข้อมูลbuildThreadAwareOutboundSessionRoute(...)จากopenclaw/plugin-sdk/channel-coreเมื่อเส้นทางขาออกควรรักษาreplyToId/threadIdที่ระบุไว้อย่างชัดเจน หรือกู้คืนเซสชัน:thread:ปัจจุบันหลังจากคีย์เซสชันฐานยังคงตรงกัน Plugin ของผู้ให้บริการสามารถ แทนที่ลำดับความสำคัญ ลักษณะการทำงานของส่วนต่อท้าย และการปรับ ID เธรดให้เป็นมาตรฐานได้ เมื่อ แพลตฟอร์มของตนมีความหมายเชิงการส่งมอบเธรดแบบเนทีฟopenclaw/plugin-sdk/thread-bindings-runtimeสำหรับวงจรชีวิตการผูกเธรด และการลงทะเบียนอะแดปเตอร์
โดยทั่วไปช่องที่ใช้เฉพาะการยืนยันตัวตนสามารถหยุดที่พาธเริ่มต้นได้: แกนหลักจัดการ การอนุมัติ และ Plugin เพียงเปิดเผยความสามารถขาออก/การยืนยันตัวตน ช่อง การอนุมัติแบบเนทีฟ เช่น Matrix, Slack, Telegram และการขนส่งแชตแบบกำหนดเอง ควรใช้ตัวช่วยแบบเนทีฟที่ใช้ร่วมกันแทนการสร้างวงจรชีวิตการอนุมัติ ขึ้นเอง
นโยบายการกล่าวถึงขาเข้า
แยกการจัดการการกล่าวถึงขาเข้าออกเป็นสองชั้น:
- การรวบรวมหลักฐานที่ Plugin เป็นเจ้าของ
- การประเมินนโยบายที่ใช้ร่วมกัน
ใช้ openclaw/plugin-sdk/channel-mention-gating สำหรับการตัดสินใจตามนโยบายการกล่าวถึง
ใช้ openclaw/plugin-sdk/channel-inbound เฉพาะเมื่อคุณต้องการบาร์เรล
ตัวช่วยขาเข้าที่กว้างกว่า
เหมาะสำหรับตรรกะภายใน Plugin:
- การตรวจจับการตอบกลับบอต
- การตรวจจับการอ้างข้อความของบอต
- การตรวจสอบการมีส่วนร่วมในเธรด
- การยกเว้นข้อความบริการ/ระบบ
- แคชแบบเนทีฟของแพลตฟอร์มที่จำเป็นต่อการยืนยันการมีส่วนร่วมของบอต
เหมาะสำหรับตัวช่วยที่ใช้ร่วมกัน:
requireMention- ผลลัพธ์การกล่าวถึงอย่างชัดเจน
- รายการอนุญาตการกล่าวถึงโดยนัย
- การข้ามด้วยคำสั่ง
- การตัดสินใจข้ามขั้นสุดท้าย
ลำดับการทำงานที่แนะนำ:
- คำนวณข้อเท็จจริงการกล่าวถึงภายใน
- ส่งข้อเท็จจริงเหล่านั้นไปยัง
resolveInboundMentionDecision({ facts, policy }) - ใช้
decision.effectiveWasMentioned,decision.shouldBypassMentionและdecision.shouldSkipในด่านตรวจขาเข้าของคุณ
implicitMentionKindWhen, matchesMentionWithExplicit, resolveInboundMentionDecision,} from "openclaw/plugin-sdk/channel-inbound"; const wasMentioned = matchesMentionWithExplicit({ text, mentionRegexes, explicit: { hasAnyMention, isExplicitlyMentioned, canResolveExplicit, },}); const facts = { canDetectMention: true, wasMentioned, hasAnyMention, implicitMentionKinds: [ ...implicitMentionKindWhen("reply_to_bot", isReplyToBot), ...implicitMentionKindWhen("quoted_bot", isQuoteOfBot), ],}; const implicitMentions = resolveChannelImplicitMentions({ cfg, channel: channelId, accountId,}); const decision = resolveInboundMentionDecision({ facts, policy: { isGroup, requireMention, implicitMentions, allowTextCommands, hasControlCommand, commandAuthorized, },}); if (decision.shouldSkip) return;matchesMentionWithExplicit(...) ส่งคืนค่าบูลีน hasAnyMention,
isExplicitlyMentioned และ canResolveExplicit มาจากข้อมูลเมตาการกล่าวถึงแบบเนทีฟ
ของช่องเอง (เอนทิตีข้อความ แฟล็กตอบกลับบอต และสิ่งที่คล้ายกัน);
ระบุค่า false/undefined เมื่อแพลตฟอร์มของคุณตรวจจับค่าเหล่านี้ไม่ได้
api.runtime.channel.mentions เปิดเผยตัวช่วยการกล่าวถึงที่ใช้ร่วมกันชุดเดียวกันสำหรับ
Plugin ช่องที่รวมมาในชุดและพึ่งพาการฉีดรันไทม์อยู่แล้ว:
buildMentionRegexes, matchesMentionPatterns, matchesMentionWithExplicit,
implicitMentionKindWhen, resolveInboundMentionDecision
หากคุณต้องการเพียง implicitMentionKindWhen และ resolveInboundMentionDecision
ให้นำเข้าจาก openclaw/plugin-sdk/channel-mention-gating เพื่อหลีกเลี่ยงการโหลด
ตัวช่วยรันไทม์ขาเข้าที่ไม่เกี่ยวข้อง
คำแนะนำแบบทีละขั้นตอน
แพ็กเกจและแมนิเฟสต์
สร้างไฟล์ Plugin มาตรฐาน ฟิลด์ channels ใน
openclaw.plugin.json (ไม่ใช่ฟิลด์ kind) คือสิ่งที่ระบุว่าแมนิเฟสต์
เป็นเจ้าของช่อง สำหรับพื้นผิวข้อมูลเมตาแพ็กเกจทั้งหมด โปรดดู
การตั้งค่าและการกำหนดค่า Plugin:
{"name": "@myorg/openclaw-acme-chat","version": "1.0.0","type": "module","openclaw": { "extensions": ["./index.ts"], "setupEntry": "./setup-entry.ts", "channel": { "id": "acme-chat", "label": "Acme Chat", "blurb": "เชื่อมต่อ OpenClaw กับ Acme Chat" }}}{"id": "acme-chat","channels": ["acme-chat"],"name": "Acme Chat","description": "Plugin ช่อง Acme Chat","configSchema": { "type": "object", "additionalProperties": false, "properties": {}},"channelConfigs": { "acme-chat": { "schema": { "type": "object", "additionalProperties": false, "properties": { "token": { "type": "string" }, "allowFrom": { "type": "array", "items": { "type": "string" } } } }, "uiHints": { "token": { "label": "โทเค็นบอต", "sensitive": true } } }}}configSchema ตรวจสอบความถูกต้องของ plugins.entries.acme-chat.config ใช้สำหรับ
การตั้งค่าที่ Plugin เป็นเจ้าของและไม่ใช่การกำหนดค่าบัญชีช่อง
channelConfigs.acme-chat.schema ตรวจสอบความถูกต้องของ channels.acme-chat และเป็น
แหล่งข้อมูลพาธเย็นที่สคีมาการกำหนดค่า การตั้งค่า และพื้นผิว UI ใช้ก่อนที่
รันไทม์ Plugin จะโหลด โปรดดู แมนิเฟสต์ Plugin สำหรับข้อมูลอ้างอิง
ฟิลด์ระดับบนสุดทั้งหมด
สร้างออบเจ็กต์ Plugin ของช่อง
อินเทอร์เฟซ ChannelPlugin มีพื้นผิวอะแดปเตอร์แบบไม่บังคับจำนวนมาก เริ่มจาก
ขั้นต่ำ ได้แก่ id, config และ setup แล้วเพิ่มอะแดปเตอร์เมื่อคุณต้องการ
ใช้งาน
สร้าง src/channel.ts:
import { createChatChannelPlugin, createChannelPluginBase,} from "openclaw/plugin-sdk/channel-core";import type { OpenClawConfig } from "openclaw/plugin-sdk/channel-core";import { acmeChatApi } from "./client.js"; // ไคลเอนต์ API ของแพลตฟอร์มคุณ type ResolvedAccount = { accountId: string | null; token: string; allowFrom: string[]; dmPolicy: string | undefined;}; function resolveAccount( cfg: OpenClawConfig, accountId?: string | null,): ResolvedAccount { const section = (cfg.channels as Record<string, any>)?.["acme-chat"]; const token = section?.token; if (!token) throw new Error("acme-chat: ต้องระบุโทเค็น"); return { accountId: accountId ?? null, token, allowFrom: section?.allowFrom ?? [], dmPolicy: section?.dmSecurity, };} export const acmeChatPlugin = createChatChannelPlugin<ResolvedAccount>({ base: createChannelPluginBase({ id: "acme-chat", // การแก้ไข/ตรวจสอบบัญชีอยู่ใน `config` ไม่ใช่ `setup` // `setup` ครอบคลุมการเขียนระหว่างการเริ่มต้นใช้งาน (applyAccountConfig, validateInput) config: { listAccountIds: () => ["default"], resolveAccount, inspectAccount(cfg, accountId) { const section = (cfg.channels as Record<string, any>)?.["acme-chat"]; return { enabled: Boolean(section?.token), configured: Boolean(section?.token), tokenStatus: section?.token ? "available" : "missing", }; }, }, setup: { applyAccountConfig: ({ cfg, input }) => ({ ...cfg, channels: { ...cfg.channels, "acme-chat": { ...(cfg.channels as any)?.["acme-chat"], ...input }, }, }), }, }), // ความปลอดภัยของ DM: ผู้ที่สามารถส่งข้อความถึงบอตได้ security: { dm: { channelKey: "acme-chat", resolvePolicy: (account) => account.dmPolicy, resolveAllowFrom: (account) => account.allowFrom, defaultPolicy: "allowlist", }, }, // การจับคู่: ขั้นตอนการอนุมัติสำหรับผู้ติดต่อ DM รายใหม่ pairing: { text: { idLabel: "ชื่อผู้ใช้ Acme Chat", message: "ส่งรหัสนี้เพื่อยืนยันตัวตนของคุณ:", notify: async ({ target, code }) => { await acmeChatApi.sendDm(target, `รหัสจับคู่: ${code}`); }, }, }, // การจัดเธรด: วิธีส่งคำตอบ threading: { topLevelReplyToMode: "reply" }, // ขาออก: ส่งข้อความไปยังแพลตฟอร์ม outbound: { attachedResults: { channel: "acme-chat", sendText: async (params) => { const result = await acmeChatApi.sendMessage( params.to, params.text, ); return { messageId: result.id }; }, }, base: { sendMedia: async (params) => { await acmeChatApi.sendFile(params.to, params.filePath); }, }, },});สำหรับช่องทางที่รองรับทั้งคีย์ DM ระดับบนสุดแบบมาตรฐานและคีย์แบบซ้อนที่เลิกใช้แล้ว ให้ใช้ตัวช่วยจาก plugin-sdk/channel-config-helpers: resolveChannelDmAccess, resolveChannelDmPolicy, resolveChannelDmAllowFrom และ normalizeChannelDmPolicy จะจัดให้ค่าภายในบัญชีมีลำดับความสำคัญเหนือค่ารากที่สืบทอดมา ใช้ตัวแก้ไขเดียวกันร่วมกับการซ่อมแซมของ doctor ผ่าน normalizeLegacyDmAliases เพื่อให้รันไทม์และการย้ายข้อมูลอ่านสัญญาเดียวกัน
สิ่งที่ createChatChannelPlugin จัดการให้
แทนที่จะติดตั้งใช้งานอินเทอร์เฟซอะแดปเตอร์ระดับต่ำด้วยตนเอง ให้ส่ง ตัวเลือกแบบประกาศ แล้วตัวสร้างจะประกอบตัวเลือกเหล่านั้นเข้าด้วยกัน:
| ตัวเลือก | สิ่งที่เชื่อมต่อ |
|---|---|
security.dm |
ตัวแก้ไขความปลอดภัย DM แบบกำหนดขอบเขตจากฟิลด์การกำหนดค่า |
pairing.text |
ขั้นตอนการจับคู่ DM แบบข้อความพร้อมการแลกเปลี่ยนรหัส |
threading |
ตัวแก้ไขโหมดตอบกลับ (แบบคงที่ กำหนดขอบเขตตามบัญชี หรือกำหนดเอง) |
outbound.attachedResults |
ฟังก์ชันส่งที่คืนข้อมูลเมตาของผลลัพธ์ (รหัสข้อความ) ต้องมีรหัส channel คู่กันเพื่อให้แกนหลักประทับผลลัพธ์การส่งที่ส่งคืนได้ |
นอกจากนี้ยังส่งออบเจ็กต์อะแดปเตอร์ดิบแทนตัวเลือกแบบประกาศได้ หากต้องการควบคุมอย่างเต็มรูปแบบ
อะแดปเตอร์ขาออกแบบดิบอาจกำหนดฟังก์ชัน chunker(text, limit, ctx)
ctx.formatting ซึ่งเป็นตัวเลือกจะเก็บการตัดสินใจด้านการจัดรูปแบบ ณ เวลาส่ง
เช่น maxLinesPerMessage ให้นำไปใช้ก่อนส่ง เพื่อให้การจัดเธรดการตอบกลับ
และขอบเขตของส่วนข้อความได้รับการแก้ไขเพียงครั้งเดียวโดยการส่งขาออกร่วมกัน
บริบทการส่งยังรวม replyToIdSource (implicit หรือ explicit)
เมื่อแก้ไขเป้าหมายการตอบกลับแบบเนทีฟแล้ว เพื่อให้ตัวช่วยเพย์โหลดสามารถคง
แท็กตอบกลับที่ระบุอย่างชัดเจนไว้โดยไม่ใช้ช่องตอบกลับโดยนัยแบบใช้ครั้งเดียว
เชื่อมต่อจุดเริ่มต้น
สร้าง index.ts:
import { defineChannelPluginEntry } from "openclaw/plugin-sdk/channel-core";import { acmeChatPlugin } from "./src/channel.js"; export default defineChannelPluginEntry({ id: "acme-chat", name: "Acme Chat", description: "ปลั๊กอินช่องทาง Acme Chat", plugin: acmeChatPlugin, registerCliMetadata(api) { api.registerCli( ({ program }) => { program .command("acme-chat") .description("การจัดการ Acme Chat"); }, { descriptors: [ { name: "acme-chat", description: "การจัดการ Acme Chat", hasSubcommands: false, }, ], }, ); }, registerFull(api) { api.registerGatewayMethod(/* ... */); },});ใส่ตัวอธิบาย CLI ที่ช่องทางเป็นเจ้าของไว้ใน registerCliMetadata(...) เพื่อให้ OpenClaw
แสดงรายการเหล่านั้นในวิธีใช้ระดับรากได้โดยไม่ต้องเปิดใช้งานรันไทม์ช่องทางแบบเต็ม
ขณะที่การโหลดแบบเต็มตามปกติยังคงรับตัวอธิบายชุดเดียวกันไปใช้สำหรับการลงทะเบียน
คำสั่งจริง เก็บ registerFull(...) ไว้สำหรับงานเฉพาะรันไทม์
defineChannelPluginEntry จัดการการแยกโหมดการลงทะเบียนโดยอัตโนมัติ
หาก registerFull(...) ลงทะเบียนเมธอด RPC ของ Gateway ให้ใช้
คำนำหน้าเฉพาะ Plugin เนมสเปซผู้ดูแลระบบของแกนหลัก (config.*,
exec.approvals.*, wizard.*, update.*) ยังคงสงวนไว้และ
แก้ไขเป็น operator.admin เสมอ ดูตัวเลือกทั้งหมดได้ที่
จุดเริ่มต้น
เพิ่มจุดเริ่มต้นสำหรับการตั้งค่า
สร้าง setup-entry.ts สำหรับการโหลดแบบเบาระหว่างการเริ่มต้นใช้งาน:
import { defineSetupPluginEntry } from "openclaw/plugin-sdk/channel-core";import { acmeChatPlugin } from "./src/channel.js"; export default defineSetupPluginEntry(acmeChatPlugin);OpenClaw จะโหลดรายการนี้แทนรายการแบบเต็มเมื่อช่องทางถูกปิดใช้งาน หรือยังไม่ได้กำหนดค่า วิธีนี้ช่วยหลีกเลี่ยงการโหลดโค้ดรันไทม์ขนาดใหญ่ระหว่างขั้นตอนการตั้งค่า ดูรายละเอียดที่ การตั้งค่าและการกำหนดค่า
ช่องทางในเวิร์กสเปซที่รวมมาด้วยซึ่งแยกการส่งออกที่ปลอดภัยสำหรับการตั้งค่าไปยังโมดูล
เสริม สามารถใช้ defineBundledChannelSetupEntry(...) จาก
openclaw/plugin-sdk/channel-entry-contract เมื่อจำเป็นต้องมี
ตัวตั้งค่ารันไทม์ขณะตั้งค่าอย่างชัดเจนด้วย
จัดการข้อความขาเข้า
Plugin ต้องรับข้อความจากแพลตฟอร์มและส่งต่อไปยัง OpenClaw รูปแบบทั่วไปคือ Webhook ที่ตรวจสอบคำขอและ ส่งคำขอผ่านตัวจัดการขาเข้าของช่องทาง:
registerFull(api) { api.registerHttpRoute({ path: "/acme-chat/webhook", auth: "plugin", // การยืนยันตัวตนที่ Plugin จัดการ (ตรวจสอบลายเซ็นด้วยตนเอง) handler: async (req, res) => { const event = parseWebhookPayload(req); // ตัวจัดการขาเข้าจะส่งข้อความไปยัง OpenClaw // การเชื่อมต่อที่แน่นอนขึ้นอยู่กับ SDK ของแพลตฟอร์ม - // ดูตัวอย่างจริงในแพ็กเกจ Plugin Microsoft Teams หรือ Google Chat ที่รวมมาด้วย await handleAcmeChatInbound(api, event); res.statusCode = 200; res.end("ok"); return true; }, });}ทดสอบ
เขียนการทดสอบที่อยู่ร่วมกันใน src/channel.test.ts:
import { describe, it, expect } from "vitest";import { acmeChatPlugin } from "./channel.js"; describe("ปลั๊กอิน acme-chat", () => { it("แก้ไขบัญชีจากการกำหนดค่า", () => { const cfg = { channels: { "acme-chat": { token: "test-token", allowFrom: ["user1"] }, }, } as any; const account = acmeChatPlugin.config.resolveAccount(cfg, undefined); expect(account.token).toBe("test-token"); }); it("ตรวจสอบบัญชีโดยไม่สร้างข้อมูลลับขึ้นจริง", () => { const cfg = { channels: { "acme-chat": { token: "test-token" } }, } as any; const result = acmeChatPlugin.config.inspectAccount!(cfg, undefined); expect(result.configured).toBe(true); expect(result.tokenStatus).toBe("available"); }); it("รายงานการกำหนดค่าที่ขาดหายไป", () => { const cfg = { channels: {} } as any; const result = acmeChatPlugin.config.inspectAccount!(cfg, undefined); expect(result.configured).toBe(false); });});pnpm test <bundled-plugin-root>/acme-chat/สำหรับตัวช่วยทดสอบที่ใช้ร่วมกัน โปรดดู การทดสอบ
โครงสร้างไฟล์
<bundled-plugin-root>/acme-chat/├── package.json # ข้อมูลเมตา openclaw.channel├── openclaw.plugin.json # แมนิเฟสต์พร้อมสคีมาการกำหนดค่า├── index.ts # defineChannelPluginEntry├── setup-entry.ts # defineSetupPluginEntry├── api.ts # การส่งออกสาธารณะ (ไม่บังคับ)├── runtime-api.ts # การส่งออกรันไทม์ภายใน (ไม่บังคับ)└── src/ ├── channel.ts # ChannelPlugin ผ่าน createChatChannelPlugin ├── channel.test.ts # การทดสอบ ├── client.ts # ไคลเอ็นต์ API ของแพลตฟอร์ม └── runtime.ts # ที่เก็บรันไทม์ (หากจำเป็น)หัวข้อขั้นสูง
โหมดตอบกลับแบบคงที่ กำหนดขอบเขตตามบัญชี หรือกำหนดเอง
describeMessageTool และการค้นหาการดำเนินการ
inferTargetChatType, looksLikeId, reservedLiterals, resolveTarget
TTS, STT, สื่อ, เอเจนต์ย่อยผ่าน api.runtime
วงจรชีวิตเหตุการณ์ขาเข้าที่ใช้ร่วมกัน: รับเข้า แก้ไข บันทึก ส่งต่อ และทำให้เสร็จสิ้น
ขั้นตอนถัดไป
- Plugin ผู้ให้บริการ - หาก Plugin มีโมเดลให้ด้วย
- ภาพรวม SDK - ข้อมูลอ้างอิงการนำเข้าพาธย่อยทั้งหมด
- การทดสอบ SDK - ยูทิลิตีการทดสอบและการทดสอบสัญญา
- แมนิเฟสต์ Plugin - สคีมาแมนิเฟสต์ทั้งหมด