Get started
แผนการปรับโครงสร้างการนำเสนอของช่องทาง
สถานะ
นำไปใช้งานแล้วสำหรับพื้นผิวของเอเจนต์ที่ใช้ร่วมกัน, CLI, ความสามารถของ Plugin และการส่งข้อความขาออก:
ReplyPayload.presentationบรรจุ UI ข้อความเชิงความหมายReplyPayload.delivery.pinบรรจุคำขอปักหมุดข้อความที่ส่งแล้ว- การดำเนินการกับข้อความที่ใช้ร่วมกันเปิดเผย
presentation,deliveryและpinแทนcomponents,blocks,buttonsหรือcardแบบเนทีฟของผู้ให้บริการ - Core เรนเดอร์หรือลดระดับการนำเสนอโดยอัตโนมัติผ่านความสามารถขาออกที่ Plugin ประกาศ
- ตัวเรนเดอร์ของ Discord, Slack, Telegram, Mattermost, MS Teams และ Feishu ใช้สัญญาทั่วไป
- โค้ดส่วนควบคุมของช่อง Discord ไม่ได้นำเข้าคอนเทนเนอร์ UI ที่มี Carbon เป็นพื้นฐานอีกต่อไป
ขณะนี้เอกสารหลักอยู่ที่ การนำเสนอข้อความ เก็บแผนนี้ไว้เป็นบริบททางประวัติศาสตร์ของการนำไปใช้งาน และปรับปรุงคู่มือหลัก เมื่อมีการเปลี่ยนแปลงสัญญา ตัวเรนเดอร์ หรือพฤติกรรมสำรอง
ปัญหา
ปัจจุบัน UI ของช่องถูกแบ่งออกเป็นพื้นผิวหลายแบบที่ไม่เข้ากัน:
- Core เป็นเจ้าของฮุกตัวเรนเดอร์ข้ามบริบทที่มีรูปแบบตาม Discord ผ่าน
buildCrossContextComponents channel.tsของ Discord สามารถนำเข้า UI เนทีฟของ Carbon ผ่านDiscordUiContainerซึ่งดึงการขึ้นต่อกันของ UI ขณะรันไทม์เข้าสู่ส่วนควบคุมของ Plugin ช่อง- เอเจนต์และ CLI เปิดช่องทางเลี่ยงไปใช้เพย์โหลดเนทีฟ เช่น
componentsของ Discord,blocksของ Slack,buttonsของ Telegram หรือ Mattermost และcardของ Teams หรือ Feishu ReplyPayload.channelDataบรรจุทั้งคำแนะนำสำหรับการขนส่งและซอง UI เนทีฟ- มีโมเดลทั่วไป
interactiveอยู่แล้ว แต่ขอบเขตแคบกว่าเลย์เอาต์ที่สมบูรณ์กว่าซึ่ง Discord, Slack, Teams, Feishu, LINE, Telegram และ Mattermost ใช้อยู่
สิ่งนี้ทำให้ Core ต้องรับรู้รูปแบบ UI เนทีฟ ลดประสิทธิภาพการโหลดแบบตามต้องการของรันไทม์ Plugin และเปิดให้เอเจนต์มีวิธีเฉพาะผู้ให้บริการมากเกินไปในการแสดงเจตนาของข้อความเดียวกัน
เป้าหมาย
- Core ตัดสินใจเลือกการนำเสนอเชิงความหมายที่ดีที่สุดสำหรับข้อความจากความสามารถที่ประกาศไว้
- ส่วนขยายประกาศความสามารถและเรนเดอร์การนำเสนอเชิงความหมายเป็นเพย์โหลดการขนส่งเนทีฟ
- Web Control UI ยังคงแยกจาก UI เนทีฟของแชต
- ไม่เปิดเผยเพย์โหลดช่องเนทีฟผ่านพื้นผิวข้อความของเอเจนต์ที่ใช้ร่วมกันหรือ CLI
- คุณลักษณะการนำเสนอที่ไม่รองรับจะลดระดับเป็นการแสดงข้อความที่ดีที่สุดโดยอัตโนมัติ
- พฤติกรรมการส่ง เช่น การปักหมุดข้อความที่ส่งแล้ว เป็นข้อมูลเมตาการส่งแบบทั่วไป ไม่ใช่การนำเสนอ
สิ่งที่ไม่ใช่เป้าหมาย
- ไม่มีชิมสำหรับความเข้ากันได้ย้อนหลังของ
buildCrossContextComponents - ไม่มีช่องทางเลี่ยงสาธารณะสำหรับ
components,blocks,buttonsหรือcardแบบเนทีฟ - Core ไม่นำเข้าไลบรารี UI เนทีฟของช่อง
- ไม่มีรอยต่อ SDK เฉพาะผู้ให้บริการสำหรับช่องที่รวมมากับระบบ
โมเดลเป้าหมาย
เพิ่มฟิลด์ presentation ที่ Core เป็นเจ้าของลงใน ReplyPayload
type MessagePresentationTone = "neutral" | "info" | "success" | "warning" | "danger"; type MessagePresentation = { tone?: MessagePresentationTone; title?: string; blocks: MessagePresentationBlock[];}; type MessagePresentationBlock = | { type: "text"; text: string } | { type: "context"; text: string } | { type: "divider" } | { type: "buttons"; buttons: MessagePresentationButton[] } | { type: "select"; placeholder?: string; options: MessagePresentationOption[] }; type MessagePresentationButton = { label: string; value?: string; url?: string; style?: "primary" | "secondary" | "success" | "danger";}; type MessagePresentationOption = { label: string; value: string;};ระหว่างการย้าย interactive จะกลายเป็นเซตย่อยของ presentation:
- บล็อกข้อความ
interactiveจับคู่กับpresentation.blocks[].type = "text" - บล็อกปุ่ม
interactiveจับคู่กับpresentation.blocks[].type = "buttons" - บล็อกตัวเลือก
interactiveจับคู่กับpresentation.blocks[].type = "select"
ขณะนี้สคีมาของเอเจนต์ภายนอกและ CLI ใช้ presentation ส่วน interactive ยังคงเป็นตัวช่วยพาร์สและเรนเดอร์แบบเดิมภายในสำหรับตัวสร้างการตอบกลับที่มีอยู่
API สาธารณะสำหรับผู้สร้างถือว่า interactive เลิกใช้แล้ว การรองรับขณะรันไทม์
ยังคงอยู่เพื่อให้ตัวช่วยการอนุมัติและ Plugin รุ่นเก่าทำงานต่อได้
ขณะที่โค้ดใหม่ส่งออก presentation
ข้อมูลเมตาการส่ง
เพิ่มฟิลด์ delivery ที่ Core เป็นเจ้าของสำหรับพฤติกรรมการส่งที่ไม่ใช่ UI
type ReplyPayloadDelivery = { pin?: | boolean | { enabled: boolean; notify?: boolean; required?: boolean; };};ความหมาย:
delivery.pin = trueหมายถึงปักหมุดข้อความแรกที่ส่งสำเร็จ- ค่าเริ่มต้นของ
notifyคือfalse - ค่าเริ่มต้นของ
requiredคือfalseช่องที่ไม่รองรับหรือการปักหมุดที่ล้มเหลวจะลดระดับโดยอัตโนมัติด้วยการส่งต่อไป - การดำเนินการกับข้อความ
pin,unpinและlist-pinsแบบกำหนดเองยังคงใช้กับข้อความที่มีอยู่
การผูกหัวข้อ ACP ของ Telegram ในปัจจุบันควรย้ายจาก channelData.telegram.pin = true ไปเป็น delivery.pin = true
สัญญาความสามารถขณะรันไทม์
เพิ่มฮุกเรนเดอร์การนำเสนอและการส่งลงในอะแดปเตอร์ขาออกขณะรันไทม์ ไม่ใช่ Plugin ช่องในส่วนควบคุม
type ChannelPresentationCapabilities = { supported: boolean; buttons?: boolean; selects?: boolean; context?: boolean; divider?: boolean; tones?: MessagePresentationTone[]; limits?: { actions?: { maxActions?: number; maxActionsPerRow?: number; maxRows?: number; maxLabelLength?: number; maxValueBytes?: number; supportsStyles?: boolean; supportsDisabled?: boolean; supportsLayoutHints?: boolean; }; selects?: { maxOptions?: number; maxLabelLength?: number; maxValueBytes?: number; }; text?: { maxLength?: number; encoding?: "characters" | "utf8-bytes" | "utf16-units"; markdownDialect?: "plain" | "markdown" | "html" | "slack-mrkdwn" | "discord-markdown"; supportsEdit?: boolean; }; };}; type ChannelDeliveryCapabilities = { pinSentMessage?: boolean;}; type ChannelOutboundAdapter = { presentationCapabilities?: ChannelPresentationCapabilities; renderPresentation?: (params: { payload: ReplyPayload; presentation: MessagePresentation; ctx: ChannelOutboundSendContext; }) => ReplyPayload | null; deliveryCapabilities?: ChannelDeliveryCapabilities; pinDeliveredMessage?: (params: { cfg: OpenClawConfig; accountId?: string | null; to: string; threadId?: string | number | null; messageId: string; notify: boolean; }) => Promise<void>;};พฤติกรรมของ Core:
- ระบุช่องเป้าหมายและอะแดปเตอร์ขณะรันไทม์
- ขอความสามารถด้านการนำเสนอ
- ลดระดับบล็อกที่ไม่รองรับและใช้ขีดจำกัดความสามารถทั่วไปก่อน การเรนเดอร์
- เรียก
renderPresentation - หากไม่มีตัวเรนเดอร์ ให้แปลงการนำเสนอเป็นข้อความสำรอง
- หลังจากส่งสำเร็จ ให้เรียก
pinDeliveredMessageเมื่อมีการขอdelivery.pinและช่องรองรับ
การจับคู่ช่อง
Discord:
- เรนเดอร์
presentationเป็นคอมโพเนนต์ v2 และคอนเทนเนอร์ Carbon ในโมดูลสำหรับรันไทม์เท่านั้น - เก็บตัวช่วยสีเน้นไว้ในโมดูลขนาดเบา
- ลบการนำเข้า
DiscordUiContainerออกจากโค้ดส่วนควบคุมของ Plugin ช่อง
Slack:
- เรนเดอร์
presentationเป็น Block Kit - ลบอินพุต
blocksของเอเจนต์และ CLI
Telegram:
- เรนเดอร์ข้อความ บริบท และตัวแบ่งเป็นข้อความ
- เรนเดอร์การดำเนินการและตัวเลือกเป็นแป้นพิมพ์แบบอินไลน์เมื่อกำหนดค่าไว้และอนุญาตสำหรับพื้นผิวเป้าหมาย
- ใช้ข้อความสำรองเมื่อปิดใช้งานปุ่มแบบอินไลน์
- ย้ายการปักหมุดหัวข้อ ACP ไปยัง
delivery.pin
Mattermost:
- เรนเดอร์การดำเนินการเป็นปุ่มโต้ตอบเมื่อกำหนดค่าไว้
- เรนเดอร์บล็อกอื่นเป็นข้อความสำรอง
MS Teams:
- เรนเดอร์
presentationเป็น Adaptive Cards - เก็บการดำเนินการ
pin/unpin/list-pinsแบบกำหนดเอง - เลือกนำ
pinDeliveredMessageไปใช้งานได้ หากการรองรับ Graph เชื่อถือได้สำหรับการสนทนาเป้าหมาย
Feishu:
- เรนเดอร์
presentationเป็นการ์ดโต้ตอบ - เก็บการดำเนินการ
pin/unpin/list-pinsแบบกำหนดเอง - เลือกนำ
pinDeliveredMessageไปใช้งานสำหรับการปักหมุดข้อความที่ส่งแล้วได้ หากพฤติกรรมของ API เชื่อถือได้
LINE:
- เรนเดอร์
presentationเป็นข้อความ Flex หรือเทมเพลตเมื่อทำได้ - ย้อนกลับไปใช้ข้อความสำหรับบล็อกที่ไม่รองรับ
- ลบเพย์โหลด UI ของ LINE ออกจาก
channelData
ช่องแบบข้อความธรรมดาหรือมีข้อจำกัด:
- แปลงการนำเสนอเป็นข้อความด้วยการจัดรูปแบบแบบระมัดระวัง
ขั้นตอนการปรับโครงสร้าง
- นำการแก้ไขรุ่นเผยแพร่ของ Discord ที่แยก
ui-colors.tsออกจาก UI ที่มี Carbon เป็นพื้นฐานมาใช้อีกครั้ง และลบDiscordUiContainerออกจากextensions/discord/src/channel.ts - เพิ่ม
presentationและdeliveryลงในReplyPayload, การปรับเพย์โหลดขาออกให้เป็นมาตรฐาน, สรุปการส่ง และเพย์โหลดของฮุก - เพิ่มสคีมา
MessagePresentationและตัวช่วยพาร์สในพาธย่อย SDK/รันไทม์ที่มีขอบเขตแคบ - แทนที่ความสามารถด้านข้อความ
buttons,cards,componentsและblocksด้วยความสามารถด้านการนำเสนอเชิงความหมาย - เพิ่มฮุกอะแดปเตอร์ขาออกขณะรันไทม์สำหรับการเรนเดอร์การนำเสนอและการปักหมุดการส่ง
- แทนที่การสร้างคอมโพเนนต์ข้ามบริบทด้วย
buildCrossContextPresentation - ลบ
src/infra/outbound/channel-adapters.tsและนำbuildCrossContextComponentsออกจากชนิด Plugin ช่อง - เปลี่ยน
maybeApplyCrossContextMarkerให้แนบpresentationแทนพารามิเตอร์เนทีฟ - ปรับปรุงพาธการส่งผ่านการจัดส่ง Plugin ให้ใช้เฉพาะการนำเสนอเชิงความหมายและข้อมูลเมตาการส่ง
- ลบพารามิเตอร์เพย์โหลดเนทีฟของเอเจนต์และ CLI ได้แก่
components,blocks,buttonsและcard - ลบตัวช่วย SDK ที่สร้างสคีมาเครื่องมือข้อความเนทีฟ โดยแทนที่ด้วยตัวช่วยสคีมาการนำเสนอ
- ลบซอง UI/เนทีฟออกจาก
channelDataและเก็บเฉพาะข้อมูลเมตาการขนส่งไว้จนกว่าจะตรวจสอบแต่ละฟิลด์ที่เหลือ - ย้ายตัวเรนเดอร์ของ Discord, Slack, Telegram, Mattermost, MS Teams, Feishu และ LINE
- ปรับปรุงเอกสารสำหรับ CLI ข้อความ, หน้าช่อง, SDK ของ Plugin และคู่มือความสามารถ
- เรียกใช้การวิเคราะห์การกระจายของการนำเข้าสำหรับ Discord และจุดเข้าของช่องที่ได้รับผลกระทบ
ขั้นตอน 1-11 และ 13-14 ถูกนำไปใช้งานในการปรับโครงสร้างนี้แล้วสำหรับเอเจนต์ที่ใช้ร่วมกัน, CLI, ความสามารถของ Plugin และสัญญาอะแดปเตอร์ขาออก ขั้นตอน 12 ยังคงเป็นรอบการเก็บกวาดภายในเชิงลึกสำหรับซองการขนส่ง channelData ส่วนตัวของผู้ให้บริการ ขั้นตอน 15 ยังคงเป็นการตรวจสอบติดตามผล หากต้องการตัวเลขการกระจายของการนำเข้าที่วัดปริมาณได้เพิ่มเติมนอกเหนือจากเกณฑ์ชนิด/การทดสอบ
การทดสอบ
เพิ่มหรือปรับปรุง:
- การทดสอบการปรับการนำเสนอให้เป็นมาตรฐาน
- การทดสอบการลดระดับการนำเสนอโดยอัตโนมัติสำหรับบล็อกที่ไม่รองรับ
- การทดสอบเครื่องหมายข้ามบริบทสำหรับการจัดส่ง Plugin และพาธการส่งของ Core
- การทดสอบเมทริกซ์ตัวเรนเดอร์ช่องสำหรับ Discord, Slack, Telegram, Mattermost, MS Teams, Feishu, LINE และข้อความสำรอง
- การทดสอบสคีมาเครื่องมือข้อความที่พิสูจน์ว่าฟิลด์เนทีฟถูกลบแล้ว
- การทดสอบ CLI ที่พิสูจน์ว่าแฟล็กเนทีฟถูกลบแล้ว
- การทดสอบการถดถอยด้านการโหลดการนำเข้าแบบตามต้องการของจุดเข้า Discord ที่ครอบคลุม Carbon
- การทดสอบการปักหมุดการส่งที่ครอบคลุม Telegram และการย้อนกลับแบบทั่วไป
คำถามที่ยังเปิดอยู่
- ควรนำ
delivery.pinไปใช้งานสำหรับ Discord, Slack, MS Teams และ Feishu ในรอบแรก หรือเริ่มเฉพาะ Telegram ก่อน - ในท้ายที่สุด
deliveryควรรวมฟิลด์ที่มีอยู่ เช่นreplyToId,replyToCurrent,silentและaudioAsVoiceหรือควรมุ่งเน้นเฉพาะพฤติกรรมหลังการส่ง - การนำเสนอควรรองรับรูปภาพหรือการอ้างอิงไฟล์โดยตรง หรือควรแยกสื่อออกจากเลย์เอาต์ UI ต่อไปในขณะนี้