หน้านี้คือการออกแบบเป้าหมายสำหรับแทนที่ตัวช่วยแบบกระจัดกระจายของรอบช่องทาง, การจัดส่งการตอบกลับ, การสตรีมตัวอย่าง และการส่งออกภายนอก ด้วยวงจรชีวิตข้อความที่ทนทานหนึ่งชุด ฉบับย่อ:Documentation Index
Fetch the complete documentation index at: https://docs.openclaw.ai/llms.txt
Use this file to discover all available pages before exploring further.
- primitive หลักควรเป็น receive และ send ไม่ใช่ reply
- การตอบกลับเป็นเพียงความสัมพันธ์บนข้อความขาออก
- turn เป็นความสะดวกในการประมวลผลขาเข้า ไม่ใช่เจ้าของการส่งมอบ
- การส่งต้องอิงบริบท:
begin, render, preview หรือ stream, final send, commit, fail - การรับก็ต้องอิงบริบทเช่นกัน: normalize, dedupe, route, record, dispatch, platform ack, fail
- SDK Plugin สาธารณะควรถูกรวมให้เหลือพื้นผิว channel-message ขนาดเล็กหนึ่งชุด
ปัญหา
สแต็กช่องทางปัจจุบันเติบโตมาจากความต้องการเฉพาะที่ถูกต้องหลายอย่าง:- อะแดปเตอร์ขาเข้าแบบเรียบง่ายใช้
runtime.channel.turn.run - อะแดปเตอร์ที่สมบูรณ์กว่าใช้
runtime.channel.turn.runPrepared - ตัวช่วยแบบเดิมใช้
dispatchInboundReplyWithBase,recordInboundSessionAndDispatchReply, ตัวช่วย payload การตอบกลับ, การแบ่ง chunk การตอบกลับ, การอ้างอิงการตอบกลับ และตัวช่วย runtime ขาออก - การสตรีมตัวอย่างอยู่ในตัวจัดส่งเฉพาะช่องทาง
- กำลังเพิ่มความทนทานของการส่งมอบขั้นสุดท้ายรอบเส้นทาง payload การตอบกลับที่มีอยู่
เป้าหมาย
- วงจรชีวิตหลักหนึ่งชุดสำหรับเส้นทางรับและส่งข้อความของทุกช่องทาง
- final send แบบทนทานเป็นค่าเริ่มต้นในวงจรชีวิตข้อความใหม่หลังจากอะแดปเตอร์ ประกาศพฤติกรรมที่ replay ได้อย่างปลอดภัย
- semantic ร่วมสำหรับตัวอย่าง, การแก้ไข, การสตรีม, การ finalize, retry, recovery และ receipt
- พื้นผิว SDK Plugin ขนาดเล็กที่ Plugin ภายนอกเรียนรู้และดูแลรักษาได้
- ความเข้ากันได้สำหรับผู้เรียก
channel.turnที่มีอยู่ระหว่างการย้าย - จุดขยายที่ชัดเจนสำหรับความสามารถใหม่ของช่องทาง
- ไม่มี branch เฉพาะแพลตฟอร์มใน core
- ไม่มีข้อความช่องทางแบบ token-delta การสตรีมของช่องทางยังคงเป็นการส่งมอบตัวอย่างข้อความ, การแก้ไข, การต่อท้าย หรือ block ที่เสร็จสมบูรณ์
- metadata ต้นทางจาก OpenClaw แบบมีโครงสร้างสำหรับเอาต์พุตด้านปฏิบัติการ/ระบบ เพื่อไม่ให้ ความล้มเหลวของ Gateway ที่มองเห็นได้กลับเข้าไปในห้องร่วมที่เปิดใช้บอทเป็น prompt ใหม่
สิ่งที่ไม่ใช่เป้าหมาย
- อย่าลบ
runtime.channel.turn.*ในเฟสแรก - อย่าบังคับทุกช่องทางให้ใช้พฤติกรรม transport แบบ native เดียวกัน
- อย่าสอน core เรื่องหัวข้อของ Telegram, สตรีม native ของ Slack, การ redaction ของ Matrix, การ์ด Feishu, เสียง QQ หรือ activity ของ Teams
- อย่าเผยแพร่ตัวช่วยการย้ายภายในทั้งหมดเป็น API SDK ที่เสถียร
- อย่าทำให้ retry replay การดำเนินการแพลตฟอร์มแบบ non-idempotent ที่เสร็จแล้ว
โมเดลอ้างอิง
Vercel Chat มีโมเดลทางความคิดสาธารณะที่ดี:ChatThreadChannelMessage- เมธอดของอะแดปเตอร์ เช่น
postMessage,editMessage,deleteMessage,stream,startTypingและการดึงประวัติ - state adapter สำหรับ dedupe, lock, queue และ persistence
- intent การส่งขาออกแบบทนทานก่อนเรียก transport โดยตรง
- บริบทการส่งที่ชัดเจนพร้อม begin, commit และ fail
- บริบทการรับที่รู้จักนโยบาย ack ของแพลตฟอร์ม
- receipt ที่อยู่รอดจากการ restart และขับเคลื่อนการแก้ไข, ลบ, recovery และ การระงับ duplicate ได้
- SDK สาธารณะที่เล็กลง Plugin ที่ bundled สามารถใช้ตัวช่วย runtime ภายในได้ แต่ Plugin ภายนอกควรเห็น API ข้อความที่สอดคล้องกันหนึ่งชุด
- พฤติกรรมเฉพาะ agent: session, transcript, การสตรีม block, ความคืบหน้าของ tool, approval, media directive, การตอบกลับแบบเงียบ และประวัติการ mention ในกลุ่ม
thread.post() ยังไม่พอสำหรับ OpenClaw เพราะซ่อน
ขอบเขตธุรกรรมที่ตัดสินว่าการส่งสามารถ recover ได้หรือไม่
โมเดลหลัก
โดเมนใหม่ควรอยู่ภายใต้ namespace ภายในของ core เช่นsrc/channels/message/*
มีแนวคิดสี่อย่าง:
receive เป็นเจ้าของวงจรชีวิตขาเข้า
send เป็นเจ้าของวงจรชีวิตขาออก
live เป็นเจ้าของสถานะตัวอย่าง, การแก้ไข, ความคืบหน้า และสตรีม
state เป็นเจ้าของการจัดเก็บ intent แบบทนทาน, receipt, idempotency, recovery, lock และ
dedupe
คำศัพท์เกี่ยวกับข้อความ
ข้อความ
ข้อความที่ normalize แล้วเป็นกลางต่อแพลตฟอร์ม:เป้าหมาย
เป้าหมายอธิบายว่าข้อความอยู่ที่ใด:ความสัมพันธ์
การตอบกลับคือความสัมพันธ์ ไม่ใช่ API root:ต้นทาง
ต้นทางอธิบายว่าใครสร้างข้อความและ OpenClaw ควรปฏิบัติต่อ echo ของ ข้อความนั้นอย่างไร ต้นทางแยกจากความสัมพันธ์: ข้อความอาจเป็นการตอบกลับผู้ใช้ และยังเป็นเอาต์พุตปฏิบัติการที่มีต้นทางจาก OpenClaw ได้allowBots
Receipt
Receipt เป็น first-class:บริบทการรับ
การรับไม่ควรเป็นการเรียกตัวช่วยเปล่า ๆ core ต้องมีบริบทที่รู้จัก dedupe, routing, การบันทึก session และนโยบาย ack ของแพลตฟอร์ม- Transport ack: บอก webhook หรือ socket ของแพลตฟอร์มว่า OpenClaw รับ event envelope แล้ว บางแพลตฟอร์มต้องการสิ่งนี้ก่อน dispatch
- Polling offset ack: เลื่อน cursor เพื่อไม่ให้ fetch event เดิมซ้ำ สิ่งนี้ต้องไม่เลื่อนข้ามงานที่ recover ไม่ได้
- Inbound record ack: ยืนยันว่า OpenClaw persist metadata ขาเข้าเพียงพอสำหรับ dedupe และ route redelivery
- User-visible receipt: พฤติกรรม read/status/typing แบบเลือกใช้ได้; ไม่เป็น ขอบเขตด้านความทนทานเด็ดขาด
ReceiveAckPolicy ควบคุมเฉพาะ acknowledgement ของ transport หรือ polling เท่านั้น ต้อง
ไม่นำไปใช้ซ้ำกับ read receipt หรือ status reaction
ก่อน authorization ของบอท การรับต้องใช้นโยบาย echo ของ OpenClaw ร่วมกัน
เมื่อช่องทางสามารถถอดรหัส metadata ต้นทางของข้อความได้:
allowBots ตามปกติ
นโยบาย ack ระบุชัดเจน:
getUpdates upstream ของ Telegram ยังถูกควบคุมโดย
ไลบรารี polling ดังนั้นการปรับลึกส่วนที่เหลือคือ polling source ที่ทนทานเต็มรูปแบบ
หากเราต้องการ redelivery ระดับแพลตฟอร์มนอกเหนือจาก restart watermark ของ OpenClaw
แพลตฟอร์ม Webhook อาจต้อง ack HTTP ทันที แต่ยังต้องมี inbound dedupe และ
intent การส่งขาออกแบบทนทาน เพราะ webhook สามารถ redeliver ได้
บริบทการส่ง
การส่งก็อิงบริบทเช่นกัน:unknown_after_send ไม่ใช่เล่นซ้ำแบบไม่ตรวจสอบ Channel
ที่ไม่มีการกระทบยอดอาจเลือกการเล่นซ้ำแบบ at-least-once ได้เฉพาะเมื่อข้อความที่ซ้ำและมองเห็นได้
เป็น tradeoff ที่ยอมรับได้และมีเอกสารสำหรับ Channel และความสัมพันธ์นั้น
สะพานการกระทบยอด SDK ปัจจุบันกำหนดให้อะแดปเตอร์ประกาศ
reconcileUnknownSend จากนั้นขอให้ durableFinal.reconcileUnknownSend
จัดประเภทเอนทรีที่ไม่รู้เป็น sent, not_sent หรือ unresolved; เฉพาะ not_sent
เท่านั้นที่อนุญาตให้เล่นซ้ำ และเอนทรีที่ยังไม่คลี่คลายจะยังเป็นสถานะปลายทางหรือ retry เฉพาะ
การตรวจสอบการกระทบยอด
ต้องระบุนโยบายความทนทานอย่างชัดเจน:
required หมายความว่า core ต้อง fail closed เมื่อไม่สามารถเขียน durable intent ได้
best_effort สามารถปล่อยผ่านได้เมื่อ persistence ไม่พร้อมใช้งาน disabled คง
พฤติกรรมส่งโดยตรงแบบเดิมไว้ ระหว่างการย้าย wrapper แบบ legacy และตัวช่วยความเข้ากันได้สาธารณะ
มีค่าเริ่มต้นเป็น disabled; สิ่งเหล่านี้ต้องไม่อนุมาน required จาก
ข้อเท็จจริงที่ว่า Channel มีอะแดปเตอร์ outbound ทั่วไป
Send context ยังเป็นเจ้าของผลกระทบหลังส่งภายใน Channel ด้วย การย้ายไม่ปลอดภัย
หาก durable delivery ข้ามพฤติกรรมภายในที่ก่อนหน้านี้ผูกอยู่กับเส้นทางส่งโดยตรงของ
Channel ตัวอย่างรวมถึงแคชระงับ self-echo,
ตัวทำเครื่องหมายการเข้าร่วมเธรด, จุดยึดการแก้ไขแบบเนทีฟ, การเรนเดอร์ลายเซ็นโมเดล,
และตัวป้องกันการซ้ำเฉพาะแพลตฟอร์ม ผลกระทบเหล่านั้นต้องย้ายเข้าไปใน
อะแดปเตอร์ส่ง, อะแดปเตอร์เรนเดอร์, หรือ hook send-context ที่มีชื่อ ก่อนที่
Channel นั้นจะเปิดใช้ durable generic final delivery ได้
ตัวช่วยส่งต้องคืนใบรับกลับไปถึงผู้เรียกของมัน Durable
wrapper ไม่สามารถกลืน message id หรือแทนที่ผลลัพธ์การส่งของ Channel ด้วย
undefined; buffered dispatcher ใช้ id เหล่านั้นสำหรับจุดยึดเธรด, การแก้ไขภายหลัง,
การ finalize preview และการระงับการซ้ำ
Fallback send ทำงานกับ batch ไม่ใช่ payload เดี่ยว การเขียน silent-reply ใหม่,
media fallback, card fallback และการฉาย chunk ทั้งหมดสามารถสร้างข้อความที่ส่งได้
มากกว่าหนึ่งรายการ ดังนั้น send context ต้องส่ง batch ที่ฉายทั้งหมด
หรือระบุในเอกสารอย่างชัดเจนว่าเหตุใด payload เดียวจึงถูกต้อง
unknown_after_send จนกว่าอะแดปเตอร์จะกระทบยอดได้
บริบทสด
พฤติกรรม preview, edit, progress และ stream ควรเป็น lifecycle แบบ opt-in หนึ่งชุด- Telegram ส่งพร้อมแก้ไข preview โดยมี final ใหม่หลังอายุ preview ค้าง
- Discord ส่งพร้อมแก้ไข preview ยกเลิกเมื่อมี media/error/explicit reply
- Slack native stream หรือ draft preview ขึ้นอยู่กับรูปแบบเธรด
- การ finalize โพสต์ draft ของ Mattermost
- การ finalize เหตุการณ์ draft ของ Matrix หรือการ redaction เมื่อไม่ตรงกัน
- Teams native progress stream
- QQ Bot stream หรือ fallback แบบสะสม
พื้นผิวอะแดปเตอร์
เป้าหมาย SDK สาธารณะควรเป็น subpath เดียว:origin.decode คืน metadata ต้นทาง OpenClaw อะแดปเตอร์รับ
จัดเตรียมข้อเท็จจริงของแพลตฟอร์ม เช่น ผู้เขียน bot และรูปทรงห้อง; core เป็นเจ้าของการตัดสินใจ drop
และการจัดลำดับ เพื่อไม่ให้ Channel ต้องนำตัวกรองข้อความไปทำซ้ำ
อะแดปเตอร์ต้นทาง:
MessageOrigin Channel แปลค่าไปและกลับจาก
metadata ของ transport แบบเนทีฟเท่านั้น Slack map สิ่งนี้ไปยัง chat.postMessage({ metadata }) และ
message.metadata ขาเข้า; Matrix สามารถ map ไปยังเนื้อหาเหตุการณ์เพิ่มเติม; Channel
ที่ไม่มี metadata แบบเนทีฟสามารถใช้ registry ของ receipt/outbound เมื่อสิ่งนั้นเป็น
การประมาณที่ดีที่สุดที่มี
ความสามารถ:
การลดพื้นผิว SDK สาธารณะ
พื้นผิวสาธารณะใหม่ควรดูดซับหรือเลิกใช้พื้นที่เชิงแนวคิดเหล่านี้:reply-runtimereply-dispatch-runtimereply-referencereply-chunkingreply-payloadinbound-reply-dispatchchannel-reply-pipeline- การใช้งานสาธารณะส่วนใหญ่ของ
outbound-runtime - ตัวช่วย lifecycle ของ draft stream แบบเฉพาะกิจ
plugin-sdk/channel-message เมื่อมีอยู่แล้ว
ความสัมพันธ์กับ channel turn
runtime.channel.turn.* ควรคงอยู่ระหว่างการย้าย
มันควรกลายเป็นอะแดปเตอร์ความเข้ากันได้:
channel.turn.runPrepared ก็ควรคงอยู่ในช่วงแรกด้วย:
channel.turn สามารถถูกเลิกใช้ได้ ไม่ควรถูกนำออกจนกว่าจะมี
เส้นทางย้าย SDK ที่เผยแพร่แล้วและ contract test ที่พิสูจน์ว่า Plugin เก่ายังคงทำงานได้
หรือล้มเหลวด้วยข้อผิดพลาดเวอร์ชันที่ชัดเจน
Guardrail ความเข้ากันได้
ระหว่างการย้าย generic durable delivery เป็นแบบ opt-in สำหรับ Channel ใดก็ตามที่ callback การส่งปัจจุบันมีผลข้างเคียงนอกเหนือจาก “ส่ง payload นี้” Entry point แบบ legacy ไม่เป็น durable ตามค่าเริ่มต้น:channel.turn.runและdispatchAssembledChannelTurnใช้ callback การส่งของ Channel เว้นแต่ Channel นั้นจะจัดเตรียมอ็อบเจ็กต์นโยบาย/ตัวเลือก durable ที่ตรวจสอบแล้วอย่างชัดเจนchannel.turn.runPreparedยังเป็นของ Channel จนกว่า dispatcher ที่เตรียมไว้ จะเรียก send context อย่างชัดเจน- ตัวช่วยความเข้ากันได้สาธารณะ เช่น
recordInboundSessionAndDispatchReply,dispatchInboundReplyWithBaseและตัวช่วย direct-DM ไม่เคยฉีด generic durable delivery ก่อน callbackdeliverหรือreplyที่ผู้เรียกจัดเตรียม
durable: undefined หมายถึง “ไม่ durable”
เส้นทาง durable เปิดใช้ได้เฉพาะด้วยค่านโยบาย/ตัวเลือกที่ชัดเจนเท่านั้น durable: false ยังคงเป็นการสะกดเพื่อความเข้ากันได้ได้ แต่การใช้งานไม่ควร
กำหนดให้ Channel ที่ยังไม่ได้ย้ายทุกตัวต้องเพิ่มค่านี้
โค้ดสะพานปัจจุบันต้องคงการตัดสินใจเรื่องความทนทานไว้อย่างชัดเจน:
- การส่งผลลัพธ์สุดท้ายแบบทนทานคืนสถานะที่จำแนกชนิดได้
handled_visibleและhandled_no_sendเป็นสถานะสิ้นสุด;unsupportedและnot_applicableอาจถอยกลับ ไปใช้การส่งที่ช่องทางเป็นเจ้าของ;failedส่งต่อความล้มเหลวในการส่ง - การส่งผลลัพธ์สุดท้ายแบบทนทานทั่วไปถูกควบคุมด้วยความสามารถของอะแดปเตอร์ เช่น การส่งแบบเงียบ การคงเป้าหมายการตอบกลับ การคงคำพูดอ้างอิงแบบเนทีฟ และ hook สำหรับส่งข้อความ หากยังไม่มีความเท่าเทียมกัน ควรเลือกการส่งที่ช่องทางเป็นเจ้าของ ไม่ใช่การส่งทั่วไปที่เปลี่ยนพฤติกรรมที่ผู้ใช้มองเห็น
- การส่งแบบทนทานที่มีคิวรองรับเปิดเผยอ้างอิง intent การส่ง ฟิลด์เซสชัน
pendingFinalDelivery*ที่มีอยู่สามารถพก ID ของ intent ระหว่างช่วงเปลี่ยนผ่านได้ สถานะสุดท้ายคือ store ของMessageSendIntentแทนข้อความตอบกลับที่ถูกตรึงไว้ บวกกับฟิลด์บริบทเฉพาะกิจ
- อะแดปเตอร์การส่งทั่วไปทำงานด้วยพฤติกรรมการเรนเดอร์และการขนส่งเดียวกับ เส้นทางตรงแบบเก่า
- ผลข้างเคียงภายในเครื่องหลังส่งถูกรักษาไว้ผ่านบริบทการส่ง
- อะแดปเตอร์คืนใบรับหรือผลลัพธ์การส่งที่มี ID ข้อความของแพลตฟอร์มทั้งหมด
- เส้นทาง dispatcher ที่เตรียมไว้ต้องเรียกบริบทการส่งใหม่ หรือยังคงถูกบันทึกไว้ในเอกสาร ว่าอยู่นอกการรับประกันแบบทนทาน
- การส่งแบบถอยกลับรองรับ payload ที่ฉายออกมาทุกตัว ไม่ใช่แค่ตัวแรก
- การส่งแบบถอยกลับที่ทนทานบันทึกอาร์เรย์ payload ที่ฉายออกมาทั้งหมดเป็น intent หรือแผน batch หนึ่งชุดที่เล่นซ้ำได้
- การส่งของตัวตรวจสอบ iMessage บันทึกข้อความที่ส่งแล้วไว้ใน echo cache หลังจาก ส่งสำเร็จ การส่งผลลัพธ์สุดท้ายแบบทนทานต้องยังเติมข้อมูล cache นั้น มิฉะนั้น OpenClaw อาจนำเข้าการตอบกลับสุดท้ายของตัวเองกลับมาเป็นข้อความขาเข้าจากผู้ใช้
- Tlon ต่อท้ายลายเซ็นโมเดลแบบไม่บังคับและบันทึกเธรดที่เข้าร่วมหลังจากตอบกลับกลุ่ม การส่งแบบทนทานทั่วไปต้องไม่ข้ามผลเหล่านั้น; ให้ย้ายผลเหล่านั้นเข้าไปในอะแดปเตอร์ เรนเดอร์/ส่ง/จบขั้นตอนของ Tlon หรือคง Tlon ไว้บนเส้นทางที่ช่องทางเป็นเจ้าของ
- Discord และ dispatcher ที่เตรียมไว้อื่น ๆ เป็นเจ้าของพฤติกรรมการส่งตรงและตัวอย่างแสดงผลอยู่แล้ว สิ่งเหล่านี้ไม่อยู่ภายใต้การรับประกันแบบทนทานของ turn ที่ประกอบแล้ว จนกว่า dispatcher ที่เตรียมไว้จะกำหนดเส้นทางผลลัพธ์สุดท้ายผ่านบริบทการส่งอย่างชัดเจน
- การส่งแบบถอยกลับแบบเงียบของ Telegram ต้องส่งอาร์เรย์ payload ที่ฉายออกมาทั้งหมด ทางลัดแบบ payload เดียวอาจทำให้ payload ถอยกลับเพิ่มเติมหลังการฉายถูกทิ้ง
- LINE, Zalo, Nostr และเส้นทางประกอบ/ตัวช่วยอื่น ๆ ที่มีอยู่ อาจมี การจัดการโทเค็นตอบกลับ การพร็อกซีสื่อ cache ข้อความที่ส่งแล้ว การล้างสถานะกำลังโหลด/สถานะ หรือเป้าหมายแบบ callback เท่านั้น สิ่งเหล่านี้ยังอยู่บนการส่งที่ช่องทางเป็นเจ้าของจนกว่า semantics เหล่านั้นจะแสดงผ่านอะแดปเตอร์การส่งและได้รับการยืนยันด้วยการทดสอบ
- ตัวช่วย DM โดยตรงอาจมี callback การตอบกลับที่เป็นเป้าหมายการขนส่งที่ถูกต้องเพียงอย่างเดียว
การส่งออกทั่วไปต้องไม่เดาจาก
OriginatingToหรือToแล้วข้าม callback นั้น - เอาต์พุตความล้มเหลวของ OpenClaw Gateway ต้องยังมองเห็นได้สำหรับมนุษย์ แต่ echo ในห้อง
ที่ติดแท็กว่าเขียนโดยบอตต้องถูกทิ้งก่อนการอนุญาต
allowBotsช่องทางต้องไม่ทำสิ่งนี้ด้วยตัวกรองคำนำหน้าข้อความที่มองเห็นได้ ยกเว้นเป็นมาตรการหยุดฉุกเฉิน ระยะสั้น; สัญญาแบบทนทานคือ metadata ต้นทางแบบมีโครงสร้าง
ที่จัดเก็บภายใน
คิวแบบทนทานควรเก็บ intent การส่งข้อความ ไม่ใช่ payload การตอบกลับคลาสความล้มเหลว
อะแดปเตอร์ช่องทางจัดประเภทความล้มเหลวของการขนส่งเป็นหมวดหมู่ปิด:- ลองใหม่สำหรับ
transientและrate_limit - อย่าลองใหม่สำหรับ
invalid_payloadเว้นแต่ว่ามีการเรนเดอร์แบบถอยกลับ - อย่าลองใหม่สำหรับ
authหรือpermissionจนกว่าการกำหนดค่าจะเปลี่ยน - สำหรับ
not_foundให้การจบขั้นตอนแบบสดถอยกลับจากการแก้ไขไปเป็นการส่งใหม่เมื่อ ช่องทางประกาศว่าปลอดภัย - สำหรับ
conflictให้ใช้กฎใบรับ/ความเป็น idempotent เพื่อตัดสินว่าข้อความ มีอยู่แล้วหรือไม่ - ข้อผิดพลาดใด ๆ หลังจากอะแดปเตอร์อาจทำ I/O ของแพลตฟอร์มเสร็จแล้วแต่ก่อน commit ใบรับ
จะกลายเป็น
unknown_after_sendเว้นแต่ว่าอะแดปเตอร์พิสูจน์ได้ว่าการดำเนินการบนแพลตฟอร์ม ไม่ได้เกิดขึ้น
การแมปช่องทาง
| ช่องทาง | เป้าหมายการย้ายระบบ |
|---|---|
| Telegram | รับนโยบาย ack พร้อมการส่งผลลัพธ์สุดท้ายแบบคงทน Adapter แบบสดเป็นเจ้าของการส่งพร้อมการแก้ไขพรีวิว, การส่งผลลัพธ์สุดท้ายของพรีวิวที่ค้าง, หัวข้อ, การข้ามพรีวิว quote-reply, การสำรองสำหรับสื่อ และการจัดการ retry-after |
| Discord | Adapter การส่งห่อหุ้มการส่ง payload แบบคงทนที่มีอยู่ Adapter แบบสดเป็นเจ้าของการแก้ไขฉบับร่าง, ฉบับร่างความคืบหน้า, การยกเลิกพรีวิวสื่อ/ข้อผิดพลาด, การคงเป้าหมายการตอบกลับ และใบรับรหัสข้อความ ตรวจสอบ echo ความล้มเหลวของ Gateway ที่บอตเขียนในห้องที่ใช้ร่วมกัน ใช้ registry ขาออกหรือสิ่งเทียบเท่าแบบ native อื่น หาก Discord ไม่สามารถพกเมทาดาทาต้นทางบนข้อความปกติได้ |
| Slack | Adapter การส่งจัดการโพสต์แชตปกติ Adapter แบบสดเลือกสตรีม native เมื่อรูปร่างของ thread รองรับ มิฉะนั้นใช้พรีวิวฉบับร่าง ใบรับคง timestamp ของ thread Adapter ต้นทางแมปความล้มเหลวของ Gateway ของ OpenClaw ไปยัง Slack chat.postMessage.metadata และทิ้ง echo ของห้องบอตที่ติดแท็กก่อนการอนุญาต allowBots |
| Adapter การส่งเป็นเจ้าของการส่งข้อความ/สื่อด้วย intent สุดท้ายแบบคงทน Adapter การรับจัดการการกล่าวถึงในกลุ่มและตัวตนผู้ส่ง Live สามารถยังไม่มีได้จนกว่า WhatsApp จะมี transport ที่แก้ไขได้ | |
| Matrix | Adapter แบบสดเป็นเจ้าของการแก้ไขเหตุการณ์ฉบับร่าง, การทำให้เป็นผลลัพธ์สุดท้าย, การ redaction, ข้อจำกัดของสื่อที่เข้ารหัส และการสำรองเมื่อเป้าหมายการตอบกลับไม่ตรงกัน Adapter การรับเป็นเจ้าของการเติมข้อมูลเหตุการณ์ที่เข้ารหัสและการ dedupe Adapter ต้นทางควรเข้ารหัสต้นทางความล้มเหลวของ Gateway ของ OpenClaw ลงในเนื้อหาเหตุการณ์ Matrix และทิ้ง echo ของห้องบอตที่กำหนดค่าก่อนการจัดการ allowBots |
| Mattermost | Adapter แบบสดเป็นเจ้าของโพสต์ฉบับร่างหนึ่งรายการ, การพับความคืบหน้า/เครื่องมือ, การทำให้เป็นผลลัพธ์สุดท้ายในที่เดิม และการสำรองด้วยการส่งใหม่ |
| Microsoft Teams | Adapter แบบสดเป็นเจ้าของความคืบหน้า native และพฤติกรรม block stream Adapter การส่งเป็นเจ้าของกิจกรรมและใบรับสิ่งที่แนบ/การ์ด |
| Feishu | Adapter การเรนเดอร์เป็นเจ้าของการเรนเดอร์ข้อความ/การ์ด/raw Adapter แบบสดเป็นเจ้าของการ์ดแบบสตรีมและการระงับผลลัพธ์สุดท้ายที่ซ้ำ Adapter การส่งเป็นเจ้าของความคิดเห็น, เซสชันหัวข้อ, สื่อ และการระงับเสียง |
| QQ Bot | Adapter แบบสดเป็นเจ้าของการสตรีม C2C, timeout ของ accumulator และการส่งผลลัพธ์สุดท้ายสำรอง Adapter การเรนเดอร์เป็นเจ้าของแท็กสื่อและข้อความเป็นเสียง |
| Signal | Adapter การรับและการส่งแบบง่าย ไม่มี adapter แบบสด เว้นแต่ signal-cli จะเพิ่มการรองรับการแก้ไขที่เชื่อถือได้ |
| iMessage | Adapter การรับและการส่งแบบง่าย การส่ง iMessage ต้องคงการเติม echo-cache ของ monitor ก่อนที่ผลลัพธ์สุดท้ายแบบคงทนจะข้ามการส่งผ่าน monitor ได้ |
| Google Chat | Adapter การรับและการส่งแบบง่าย โดยแมปความสัมพันธ์ของ thread ไปยัง spaces และรหัส thread ตรวจสอบพฤติกรรมห้อง allowBots=true สำหรับ echo ความล้มเหลวของ Gateway ของ OpenClaw ที่ติดแท็ก |
| LINE | Adapter การรับและการส่งแบบง่าย พร้อมข้อจำกัดของ reply-token ที่โมเดลเป็นความสามารถ target/relation |
| Nextcloud Talk | บริดจ์การรับของ SDK พร้อม adapter การส่ง |
| IRC | Adapter การรับและการส่งแบบง่าย ไม่มีใบรับการแก้ไขแบบคงทน |
| Nostr | Adapter การรับและการส่งสำหรับ DM ที่เข้ารหัส ใบรับคือรหัสเหตุการณ์ |
| QA Channel | Adapter ทดสอบสัญญาสำหรับพฤติกรรมการรับ, การส่ง, live, การลองซ้ำ และการกู้คืน |
| Synology Chat | Adapter การรับและการส่งแบบง่าย |
| Tlon | Adapter การส่งต้องคงการเรนเดอร์ model-signature และการติดตาม participated-thread ก่อนเปิดใช้การส่งผลลัพธ์สุดท้ายแบบคงทนทั่วไป |
| Twitch | Adapter การรับและการส่งแบบง่ายพร้อมการจัดประเภท rate-limit |
| Zalo | Adapter การรับและการส่งแบบง่าย |
| Zalo Personal | Adapter การรับและการส่งแบบง่าย |
แผนการย้ายระบบ
ระยะที่ 1: โดเมนข้อความภายใน
- เพิ่มชนิด
src/channels/message/*สำหรับข้อความ, เป้าหมาย, ความสัมพันธ์, ต้นทาง, ใบรับ, ความสามารถ, intent แบบคงทน, บริบทการรับ, บริบทการส่ง, บริบท live และคลาสความล้มเหลว - เพิ่ม
origin?: MessageOriginไปยังชนิด payload ของบริดจ์การย้ายระบบที่ใช้โดย การส่งการตอบกลับปัจจุบัน จากนั้นย้ายฟิลด์นั้นไปยังChannelMessageและชนิดข้อความ ที่เรนเดอร์แล้วเมื่อการปรับโครงสร้างแทนที่ reply payload - คงส่วนนี้เป็นภายในจนกว่า adapter และการทดสอบจะพิสูจน์รูปร่างได้
- เพิ่ม unit test ล้วนสำหรับการเปลี่ยนสถานะและ serialization
ระยะที่ 2: แกนการส่งแบบคงทน
- ย้ายคิวขาออกที่มีอยู่จากความคงทนของ reply-payload ไปเป็น intent การส่งข้อความ แบบคงทน
- ให้ intent การส่งแบบคงทนพก array payload ที่ฉายแล้วหรือแผน batch ไม่ใช่ reply payload เดียวเท่านั้น
- คงพฤติกรรมการกู้คืนคิวปัจจุบันผ่านการแปลงเพื่อความเข้ากันได้
- ทำให้
deliverOutboundPayloadsเรียกmessages.send - ทำให้ความคงทนของ final-send เป็นค่าเริ่มต้นและ fail closed เมื่อเขียน intent แบบคงทน ใน lifecycle ข้อความใหม่ไม่ได้ หลังจาก adapter ประกาศความปลอดภัยในการ replay แล้ว เส้นทางความเข้ากันได้ของ channel-turn และ SDK ที่มีอยู่ยังคงเป็น direct-send โดยค่าเริ่มต้น ระหว่างระยะนี้
- บันทึกใบรับอย่างสม่ำเสมอ
- ส่งคืนใบรับและผลลัพธ์การส่งไปยังผู้เรียก dispatcher เดิม แทนที่จะถือว่าการส่งแบบคงทน เป็น side effect ปลายทาง
- คงต้นทางข้อความผ่าน intent การส่งแบบคงทน เพื่อให้การกู้คืน, replay และการส่งแบบแบ่งชิ้น คง provenance เชิงปฏิบัติการของ OpenClaw
ระยะที่ 3: บริดจ์ Channel Turn
- ติดตั้ง
channel.turn.runและdispatchAssembledChannelTurnใหม่บนฐานของmessages.receiveและmessages.send - คงชนิด fact ปัจจุบันให้เสถียร
- คงพฤติกรรม legacy เป็นค่าเริ่มต้น ช่องทาง assembled-turn จะกลายเป็นแบบคงทนก็ต่อเมื่อ adapter ของช่องทางนั้น opt in อย่างชัดเจนด้วยนโยบายความคงทนที่ปลอดภัยต่อการ replay
- คง
durable: falseเป็นทางหนีเพื่อความเข้ากันได้สำหรับเส้นทางที่ทำ native edit ให้จบ และยัง replay ได้ไม่ปลอดภัย แต่ไม่พึ่งพา markerfalseเพื่อปกป้องช่องทางที่ยังไม่ได้ย้ายระบบ - ตั้งค่าความคงทนของ assembled-turn เป็นค่าเริ่มต้นเฉพาะใน lifecycle ข้อความใหม่ หลังจาก การแมปช่องทางพิสูจน์ว่าเส้นทางการส่งทั่วไปคง semantics การส่งของช่องทางเดิมไว้
ระยะที่ 4: บริดจ์ Prepared Dispatcher
- แทนที่
deliverDurableInboundReplyPayloadด้วยบริดจ์ send-context - เก็บตัวช่วยเดิมไว้เป็น wrapper
- ย้าย Telegram, WhatsApp, Slack, Signal, iMessage และ Discord ก่อน เพราะ มีงาน durable-final อยู่แล้วหรือมีเส้นทางส่งที่ง่ายกว่า
- ถือว่า prepared dispatcher ทุกตัวไม่มีการครอบคลุม จนกว่าจะเลือกใช้ send context อย่างชัดเจน เอกสารและรายการ changelog ต้องระบุว่า “assembled channel turns” หรือระบุชื่อเส้นทาง channel ที่ย้ายแล้ว แทนการอ้างถึง final replies อัตโนมัติทั้งหมด
- รักษาพฤติกรรมของ
recordInboundSessionAndDispatchReply, ตัวช่วย direct-DM และตัวช่วย ความเข้ากันได้สาธารณะที่คล้ายกันให้เหมือนเดิม ตัวช่วยเหล่านี้อาจเปิดเผยการเลือกใช้ send-context อย่างชัดเจนในภายหลัง แต่ต้องไม่พยายามส่งแบบ durable ทั่วไปโดยอัตโนมัติ ก่อน delivery callback ที่ caller เป็นเจ้าของ
ระยะที่ 5: วงจรชีวิต Live แบบรวมศูนย์
- สร้าง
messages.liveพร้อม proof adapter สองตัว:- Telegram สำหรับส่ง แก้ไข และส่ง final ที่ stale
- Matrix สำหรับ draft finalization และ redaction fallback
- จากนั้นย้าย Discord, Slack, Mattermost, Teams, QQ Bot และ Feishu
- ลบโค้ด preview finalization ที่ซ้ำกันหลังจากแต่ละ channel มี parity tests แล้วเท่านั้น
ระยะที่ 6: SDK สาธารณะ
- เพิ่ม
openclaw/plugin-sdk/channel-message - บันทึกในเอกสารว่าเป็น API ของ channel Plugin ที่แนะนำ
- อัปเดต package exports, entrypoint inventory, generated API baselines และ เอกสาร Plugin SDK
- รวม
MessageOrigin, origin encode/decode hooks และ sharedshouldDropOpenClawEchopredicate ในพื้นผิว channel-message SDK - เก็บ compatibility wrappers สำหรับ subpaths เก่า
- ทำเครื่องหมายตัวช่วย SDK ที่มีชื่อแบบ reply ว่าเลิกแนะนำในเอกสารหลังจาก Plugin ที่รวมมา ถูกย้ายแล้ว
ระยะที่ 7: ตัวส่งทั้งหมด
ย้ายผู้ผลิต outbound ที่ไม่ใช่ reply ทั้งหมดไปยังmessages.send:
- การแจ้งเตือน Cron และ Heartbeat
- การทำงานของ task เสร็จสิ้น
- ผลลัพธ์ของ hook
- approval prompts และ approval results
- การส่งจาก message tool
- ประกาศการทำงานของ subagent เสร็จสิ้น
- การส่งผ่าน CLI หรือ Control UI แบบชัดเจน
- เส้นทาง automation/broadcast
ระยะที่ 8: เลิกใช้ Turn
- เก็บ
channel.turnไว้เป็น wrapper อย่างน้อยหนึ่งช่วงเวลาความเข้ากันได้ - เผยแพร่บันทึกการย้าย
- รันการทดสอบความเข้ากันได้ของ Plugin SDK กับ import เก่า
- ลบหรือซ่อนตัวช่วยภายในเก่าหลังจากไม่มี Plugin ที่รวมมาต้องใช้แล้วเท่านั้น และสัญญาของบุคคลที่สามมีตัวแทนที่เสถียร
แผนการทดสอบ
Unit tests:- การ serialization และ recovery ของ durable send intent
- การใช้ idempotency key ซ้ำและการระงับรายการซ้ำ
- การ commit receipt และการข้าม replay
- recovery ของ
unknown_after_sendที่ reconcile ก่อน replay เมื่อ adapter รองรับการ reconciliation - นโยบายการจัดประเภท failure
- ลำดับนโยบาย receive ack
- การแมป relation สำหรับการส่ง reply, followup, system และ broadcast
- origin factory สำหรับ Gateway failure และ
shouldDropOpenClawEchopredicate - การรักษา origin ผ่าน payload normalization, chunking, durable queue serialization และ recovery
- adapter อย่างง่ายของ
channel.turn.runยังบันทึกและส่ง - การส่ง legacy assembled-turn ไม่กลายเป็น durable เว้นแต่ channel จะเลือกใช้อย่างชัดเจน
- บริดจ์
channel.turn.runPreparedยังบันทึกและ finalize - ตัวช่วยความเข้ากันได้สาธารณะเรียก delivery callbacks ที่ caller เป็นเจ้าของโดยค่าเริ่มต้น และไม่ generic-send ก่อน callback เหล่านั้น
- การส่ง durable fallback replay อาร์เรย์ projected payload ทั้งหมดหลัง restart และไม่สามารถปล่อยให้ payload ภายหลังไม่ถูกบันทึกหลัง crash ช่วงต้น
- การส่ง durable assembled-turn ส่งคืน platform message ids ไปยัง buffered dispatcher
- custom delivery hooks ยังคงส่งคืน platform message ids เมื่อ durable delivery ปิดอยู่หรือใช้งานไม่ได้
- final reply รอดจาก restart ระหว่าง assistant completion และ platform send
- preview draft finalize ในที่เดิมเมื่ออนุญาต
- preview draft ถูกยกเลิกหรือ redact เมื่อ media/error/reply-target mismatch ต้องใช้การส่งปกติ
- block streaming และ preview streaming ไม่ส่งข้อความเดียวกันทั้งคู่
- media ที่ streamed เร็วไม่ถูกทำซ้ำในการส่ง final
- Telegram topic reply ที่ใช้ polling ack ล่าช้าจนถึง safe completed watermark ของ receive context
- Telegram polling recovery สำหรับ updates ที่ accepted-but-not-delivered ครอบคลุมด้วย persisted safe-completed offset model
- Telegram stale preview ส่ง final ใหม่และล้าง preview
- Telegram silent fallback ส่ง projected fallback payload ทุกตัว
- Telegram silent fallback durability บันทึกอาร์เรย์ projected fallback ทั้งหมด แบบ atomic ไม่ใช่ durable intent แบบ single-payload หนึ่งรายการต่อ loop iteration
- Discord preview cancel เมื่อมี media/error/explicit reply
- finals ของ Discord prepared dispatcher route ผ่าน send context ก่อนที่เอกสาร หรือ changelog จะอ้างถึงความ durable ของ Discord final-reply
- iMessage durable final sends เติม monitor sent-message echo cache
- เส้นทาง legacy delivery ของ LINE, Zalo และ Nostr ไม่ถูก bypass โดย generic durable send จนกว่าจะมี adapter parity tests
- การส่ง Direct-DM/Nostr callback ยังคงเป็น authoritative เว้นแต่จะย้ายอย่างชัดเจน ไปยัง message target ที่ครบถ้วนและ send adapter ที่ replay-safe
- ข้อความ Gateway failure ของ Slack ที่ติดแท็ก OpenClaw ยังคงมองเห็นได้แบบ outbound,
bot-room echoes ที่ติดแท็ก drop ก่อน
allowBotsและข้อความ bot ที่ไม่ติดแท็กซึ่งมี ข้อความที่มองเห็นเหมือนกันยังคงทำตาม bot authorization ปกติ - Slack native stream fallback ไปยัง draft preview ใน top-level DMs
- Matrix preview finalization และ redaction fallback
- room echoes ของ Matrix ที่ติดแท็ก OpenClaw gateway-failure จากบัญชี bot
ที่กำหนดค่าไว้ drop ก่อนการจัดการ
allowBots - cascade audits ของ Discord และ Google Chat shared-room gateway-failure ครอบคลุม
โหมด
allowBotsก่อนอ้างถึงการป้องกันทั่วไปที่นั่น - Mattermost draft finalization และ fresh-send fallback
- Teams native progress finalization
- Feishu duplicate final suppression
- QQ Bot accumulator timeout fallback
- Tlon durable final sends รักษา model-signature rendering และ participated thread tracking
- WhatsApp, Signal, iMessage, Google Chat, LINE, IRC, Nostr, Nextcloud Talk, Synology Chat, Tlon, Twitch, Zalo และ Zalo Personal simple durable final sends
- ไฟล์ Vitest เป้าหมายระหว่างการพัฒนา
pnpm check:changedใน Testbox สำหรับพื้นผิวที่เปลี่ยนทั้งหมดpnpm checkที่กว้างขึ้นใน Testbox ก่อน landing refactor ที่สมบูรณ์ หรือหลัง การเปลี่ยนแปลง SDK/export สาธารณะ- live หรือ qa-channel smoke สำหรับอย่างน้อยหนึ่ง channel ที่แก้ไขได้และหนึ่ง channel แบบส่งอย่างเดียวง่าย ๆ ก่อนลบ compatibility wrappers
คำถามที่ยังเปิดอยู่
- Telegram ควรแทนที่ grammY runner source ด้วย durable polling source แบบเต็มที่ควบคุม platform-level redelivery ได้ในที่สุดหรือไม่ ไม่ใช่ แค่ persisted restart watermark ของ OpenClaw
- durable live preview state ควรเก็บใน queue record เดียวกับ final send intent หรือใน sibling live-state store
- compatibility wrappers จะยังคงถูกบันทึกในเอกสารนานเท่าใดหลังจาก
plugin-sdk/channel-messageship - Plugin ภายนอกควร implement receive adapters โดยตรง หรือเพียง
provide normalize/send/live hooks ผ่าน
defineChannelMessageAdapter - receipt fields ใดที่ปลอดภัยต่อการเปิดเผยใน SDK สาธารณะ เทียบกับ internal runtime state
- side effects เช่น self-echo caches และ participated-thread markers ควรถูกจำลองเป็น send-context hooks, adapter-owned finalize steps หรือ receipt subscribers
- channel ใดมี native origin metadata, channel ใดต้องใช้ persisted outbound registries และ channel ใดไม่สามารถให้การระงับ cross-bot echo ที่เชื่อถือได้
เกณฑ์การยอมรับ
- message channel ที่รวมมาทุกตัวส่ง final visible output ผ่าน
messages.send - inbound message channel ทุกตัวเข้าสู่ระบบผ่าน
messages.receiveหรือ compatibility wrapper ที่มีเอกสาร - preview/edit/stream channel ทุกตัวใช้
messages.liveสำหรับ draft state และ finalization channel.turnเป็นเพียง wrapper- ตัวช่วย SDK ที่มีชื่อแบบ reply เป็น compatibility exports ไม่ใช่เส้นทางที่แนะนำ
- durable recovery สามารถ replay pending final sends หลัง restart โดยไม่สูญเสีย final response หรือทำซ้ำ sends ที่ commit แล้ว; sends ที่ platform outcome ไม่ทราบแน่ชัดจะถูก reconcile ก่อน replay หรือถูกบันทึกในเอกสารว่า เป็น at-least-once สำหรับ adapter นั้น
- durable final sends fail closed เมื่อไม่สามารถเขียน durable intent ได้ เว้นแต่ caller จะเลือก documented non-durable mode อย่างชัดเจน
- compatibility helpers ของ legacy channel-turn และ SDK มีค่าเริ่มต้นเป็น direct channel-owned delivery; generic durable send เป็น explicit opt-in เท่านั้น
- receipts รักษา platform message ids ทั้งหมดสำหรับ multi-part deliveries และ primary id สำหรับความสะดวกของ threading/edit
- durable wrappers รักษา channel-local side effects ก่อนแทนที่ direct delivery callbacks
- prepared dispatchers ไม่ถูกนับว่า durable จนกว่า final delivery path จะใช้ send context อย่างชัดเจน
- fallback delivery จัดการ projected payload ทุกตัว
- durable fallback delivery บันทึก projected payload ทุกตัวใน replayable intent หรือ batch plan เดียว
- output ของ Gateway failure ที่มีต้นทางจาก OpenClaw มองเห็นได้สำหรับมนุษย์ แต่ room echoes ที่ authored โดย bot และติดแท็กจะถูก drop ก่อน bot authorization บน channel ที่ ประกาศรองรับ origin contract
- เอกสารอธิบาย send, receive, live, state, receipts, relations, failure policy, migration และ test coverage