Web interfaces
สถาปัตยกรรมแดชบอร์ด
วิสัยทัศน์
ปัจจุบันการทำงานกับเอเจนต์เป็นเพียงสตรีมข้อความ แดชบอร์ดจะเปลี่ยนให้เป็น โต๊ะทำงาน: เอเจนต์แสดงวิดเจ็ตแบบสดที่โต้ตอบได้ ผู้ใช้ปักหมุดวิดเจ็ตเหล่านั้นไว้บน พื้นที่ถาวร แชตจะเชื่อมติดไว้ด้านข้าง (หรือซ่อนไว้) และเนื้อหาหลักคือ บอร์ด ผู้ใช้เปลี่ยนจาก "การคุยกับเอเจนต์" เป็น "การใช้งานแผงควบคุมที่ เอเจนต์สร้างให้" โดยไม่ต้องออกจากเซสชันเลย
หลักการ:
- บอร์ดเป็นมุมมองหนึ่งของเซสชัน ไม่ใช่ออบเจ็กต์ใหม่ ทุกเซสชัน (เธรด)
มีสองมุมมอง: บันทึกการสนทนาและบอร์ด เซสชันที่ไม่มีวิดเจ็ตที่ปักหมุดไว้
จะเป็นแชตธรรมดา เมื่อปักหมุดวิดเจ็ตหนึ่งรายการ บอร์ดก็จะเกิดขึ้น บอร์ดสืบทอด
ข้อมูลระบุตัวตน ความเป็นเจ้าของโดยเอเจนต์ การตั้งชื่อ การปักหมุด และวงจรชีวิตของ
เซสชัน ไม่มี
dashboard_createไม่มีรีจิสทรีของบอร์ด และไม่มีโมเดล ACL แยกต่างหาก - ความเท่าเทียมของเอเจนต์ ทุกสิ่งที่ผู้ใช้ทำบนบอร์ดได้ เอเจนต์ก็ทำได้ ด้วยเครื่องมือ: เพิ่ม/อัปเดต/ลบวิดเจ็ต จัดเรียงวิดเจ็ต จัดการแท็บ สลับ แท็บที่มองเห็น และเชื่อมติดหรือซ่อนแชต
- เป็นเนทีฟ ไม่ใช่แบบฝัง บอร์ดประกอบด้วยคอมโพเนนต์ Lit ในเชลล์ Control UI (ระบบออกแบบเดียวกับส่วนอื่นของแอป) เฉพาะ_เนื้อหา_ของวิดเจ็ตเท่านั้นที่ ถูกแซนด์บ็อกซ์ใน iframe ไม่มีแถบ URL และไม่มีส่วนควบคุมของเบราว์เซอร์
- พื้นผิวสำหรับเอเจนต์ขนาดเล็ก วิดเจ็ตอ้างอิงด้วยชื่อที่เสถียรและอัปเดต ในตำแหน่งเดิม เลย์เอาต์เป็นกริดแบบยืดหยุ่นที่จัดพื้นที่ให้กระชับโดยอัตโนมัติ เอเจนต์ระบุขนาดและ จุดยึดเท่านั้น ไม่ระบุพิกเซลหรือพิกัด
- ความสามารถสำคัญกว่าความไว้วางใจ โค้ดวิดเจ็ตคือ HTML/JS ใดๆ ที่เอเจนต์เขียน และทำงานในแซนด์บ็อกซ์ที่เข้มงวด การเข้าถึง (ข้อมูล Gateway การดำเนินการ เครือข่าย) มีได้เฉพาะผ่าน รายการความสามารถที่ประกาศไว้และได้รับอนุญาตจากผู้ดำเนินการเท่านั้น
แนวคิด
| แนวคิด | คำจำกัดความ |
|---|---|
| เซสชัน (เธรด) | เซสชัน Gateway ที่มีอยู่ ซึ่งใช้ sessionKey ที่เสถียรเป็นคีย์ และมีเอเจนต์เป็นเจ้าของ |
| บอร์ด | มุมมองวิดเจ็ตของหนึ่งเซสชัน มีอยู่ก็ต่อเมื่อเซสชันมีวิดเจ็ต/แท็บ ยังคงอยู่หลัง /new//reset (ผูกกับ sessionKey ไม่ใช่บันทึกการสนทนา) |
| แท็บ | หน้านำเสนอของบอร์ด: วิดเจ็ตที่แสดง การจัดเรียง และสถานะการเชื่อมติดแชต (left/right/bottom/hidden) บอร์ดเริ่มต้นด้วยแท็บโดยนัยหนึ่งแท็บ |
| วิดเจ็ต | โปรแกรม HTML/JS ที่มีชื่อและทำงานในแซนด์บ็อกซ์ ซึ่งเซสชันเป็นเจ้าของ อ้างอิงด้วย sessionKey + name และอัปเดตในตำแหน่งเดิมตามชื่อ |
| รายการความสามารถ | การประกาศขอบเขตการเข้าถึงของแต่ละวิดเจ็ต: data (การผูกข้อมูลแบบอ่าน), actions (กริยาที่อยู่ในรายการอนุญาต), prompt (ส่งไปยังเซสชัน), net (ต้นทางที่อนุญาต) |
| ปักหมุด (วิดเจ็ต) | การย้ายวิดเจ็ตจากบันทึกการสนทนาไปยังบอร์ดของเซสชัน (ผ่านส่วนควบคุมสำหรับผู้ใช้หรืออาร์กิวเมนต์เครื่องมือของเอเจนต์) การถอนหมุดจะนำวิดเจ็ตออกจากบอร์ด |
| ปักหมุด (เซสชัน) | การปักหมุดเซสชันในแถบด้านข้างที่มีอยู่ เซสชันที่ปักหมุดและมีบอร์ดจะเปิดด้วยมุมมองบอร์ด |
ขั้นตอนการใช้งาน UX
- การยกระดับ: เอเจนต์เรียก
show_widgetในแชตใดๆ → วิดเจ็ตแสดงแบบอินไลน์ ในบันทึกการสนทนาเหมือนในปัจจุบันทุกประการ → เมื่อวางเมาส์เหนือจะแสดง ปักหมุดไปยังแดชบอร์ด → วิดเจ็ต ปรากฏบนบอร์ดของเซสชัน เอเจนต์สามารถส่งpin: trueเพื่อทำสิ่งเดียวกันได้ - มุมมองบอร์ด: เซสชันที่มีบอร์ดจะมีตัวสลับมุมมอง (แชต / แดชบอร์ด) มุมมองบอร์ด = แถบแท็บ (เฉพาะเมื่อมีมากกว่า 1 แท็บ) + กริดแบบยืดหยุ่น + บานหน้าต่างแชตที่เชื่อมติดไว้ ส่วนเชื่อมติดแชตสามารถปรับขนาด ย้ายตำแหน่ง (ซ้าย/ขวา/ล่าง) และยุบได้เหมือน แถบด้านข้างทุกประการ ระบบจะจดจำสถานะส่วนเชื่อมติดของแต่ละแท็บ
- การลาก: ผู้ใช้ลากวิดเจ็ต กริดจะจัดพื้นที่ให้กระชับโดยอัตโนมัติ (วิดเจ็ตเลื่อนขึ้นและวิดเจ็ตข้างเคียง จัดเรียงใหม่) การปรับขนาดด้วยจุดจับจะยึดตามระดับขนาดที่กำหนด ไม่มีการวางตำแหน่งเป็นพิกเซล — สำหรับทุกฝ่าย
- คำเตือนการรีเซ็ต:
/new//resetในเซสชันที่มีบอร์ดจะขอ การยืนยันในเว็บ UI ("บริบทจะถูกรีเซ็ต แต่แดชบอร์ดยังคงอยู่") และคง บอร์ดไว้ - แถบด้านข้าง: เซสชันที่ปักหมุดจะแสดงมุมมองบอร์ดเมื่อมีบอร์ด บอร์ดของเซสชันหน้าแรกคือ "แดชบอร์ดเอเจนต์" เริ่มต้น
- การโต้ตอบ (สามระดับ ดูด้านล่าง): เหตุการณ์สถานะแบบเงียบ การส่ง พรอมต์ที่มองเห็นได้ และทริกเกอร์ระบบอัตโนมัติ
ระดับการโต้ตอบ
- เหตุการณ์สถานะ (ค่าเริ่มต้น) การโต้ตอบกับ UI ของวิดเจ็ตที่โมเดลควรรับรู้
แต่ไม่ต้องตอบสนอง
bridge.emitState({...})จะเพิ่มประกาศของ เซสชันแบบมีโครงสร้าง (ใช้กลไกเดียวกับประกาศกิจกรรมกลุ่ม) โดยไม่เริ่มรอบการทำงานของ เอเจนต์ โมเดลจะเห็นประกาศที่สะสมไว้ในการทำงานครั้งถัดไป - พรอมต์ (การสนทนาโดยชัดแจ้ง)
bridge.sendPrompt(text)— ต้องมีการ กระตุ้นโดยผู้ใช้ ส่งข้อความผู้ใช้ที่มองเห็นได้ไปยังเซสชัน (แชตที่เชื่อมติดไว้ จะแสดงข้อความนั้น) มีการจำกัดอัตรา และการส่งแต่ละครั้งต้องได้รับการยืนยันจากผู้ใช้ เว้นแต่ว่าวิดเจ็ตจะได้รับ สิทธิ์ความสามารถprompt - ระบบอัตโนมัติ
bridge.runAction(name, args)— เรียกใช้การดำเนินการที่ประกาศไว้ในรายการ ความสามารถ ชุดกริยาเริ่มต้น:cron.trigger(เรียกใช้งาน Cron ที่มีอยู่ทันที) และbinding.refreshงาน Cron ทำงานในเซสชันการทำงานแบบแยกที่มองเห็นได้อยู่แล้ว และสามารถใช้โมเดลที่มีต้นทุนต่ำกว่าได้ ซึ่งเป็นแนวทาง "โมเดลขนาดเล็กขับเคลื่อนวิดเจ็ต" ไม่มีเซสชันที่ซ่อนอยู่ไม่ว่าที่ใด
โมเดลและการโฮสต์วิดเจ็ต
HTML/JS ของวิดเจ็ตเขียนโดยเอเจนต์ (โดยทั่วไปผ่าน show_widget) ถูกครอบ
ด้วยเชลล์เอกสารมาตรฐาน (เมตา CSP ตัวรายงานขนาด และตัวเริ่มต้นบริดจ์) และ
แสดงใน <iframe sandbox="allow-scripts"> (ไม่ใช้ allow-same-origin เด็ดขาด)
- วิดเจ็ตแบบอินไลน์ (บันทึกการสนทนา) ยังคงใช้ไปป์ไลน์เอกสารแคนวาสในปัจจุบัน: เขียนไว้ใต้ไดเรกทอรีสถานะ ให้บริการโดย Gateway ตัดทิ้งตามขอบเขต และไม่ต้อง ขออนุมัติ (โดยโครงสร้างแล้วไม่มีความสามารถ — การส่งพรอมต์ต้องได้รับการยืนยันจากผู้ใช้)
- วิดเจ็ตบนบอร์ด เป็นสถานะเซสชัน: ไบต์อยู่ในฐานข้อมูล SQLite
ของเอเจนต์เจ้าของ (
board_widgets) และให้บริการผ่านเส้นทาง Gateway หลัก (/__openclaw__/board/<agentId>/<sessionKey>/<name>/) ที่อ่านฐานข้อมูล การปักหมุดวิดเจ็ตจากบันทึกการสนทนาจะคัดลอกไบต์ ขีดจำกัด: 256 KB ต่อวิดเจ็ต และ 48 วิดเจ็ตต่อบอร์ด - อัปเดตในตำแหน่งเดิม: การส่งวิดเจ็ตที่มี
nameเดิมอีกครั้งจะแทนที่ ไบต์ เพิ่มrevisionกระจายboard.changedและมุมมองที่เปิดอยู่จะโหลดใหม่ เฉพาะ iframe นั้น - การตรึงไบต์: ความสามารถที่ได้รับอนุญาตจะผูกกับ sha256 ของไบต์
วิดเจ็ต การเปลี่ยนไบต์จะคงสิทธิ์
data/net/actionsไว้เฉพาะเมื่อ รีวิชันใหม่ประกาศรายการความสามารถที่เป็นเซตย่อยของรายการที่ได้รับอนุญาต รายการที่ขยายกว้างขึ้น จะขออนุมัติจากผู้ดำเนินการอีกครั้ง
วิดเจ็ตโฮสต์เนื้อหา ส่วนแอป MCP เป็นเนื้อหาประเภทหนึ่ง
วิดเจ็ตคือองค์ประกอบพื้นฐานของ OpenClaw: เซลล์บนบอร์ดที่มีชื่อ ถูกปักหมุด กำหนดขนาด เซสชันเป็นเจ้าของ และมีระเบียนสิทธิ์ สิ่งที่แสดงภายในคือ ประเภทเนื้อหา:
html— เอเจนต์เขียนผ่านshow_widgetโดยไบต์อยู่ในพื้นที่จัดเก็บของบอร์ดmcp-app— มุมมองแอป MCP ของบุคคลที่สาม (ทรัพยากรui://จากเซิร์ฟเวอร์ที่กำหนดค่าไว้) ซึ่งโฮสต์อยู่ภายในเซลล์วิดเจ็ต
แอป MCP ไม่ได้กำหนดโมเดลวิดเจ็ต แต่วิดเจ็ตได้รับความสามารถในการโฮสต์
แอปเหล่านั้น ข้อมูลระบุตัวตน ตำแหน่ง การปักหมุด สิทธิ์ และ API สำหรับผู้เขียนยังคง
เป็นของ OpenClaw ดังนั้นโค้ด show_widget จึงยังคงสั้นเหมือนในปัจจุบัน และไม่จำเป็นต้อง
รู้ว่าข้อกำหนด MCP Apps มีอยู่
โครงสร้างพื้นฐานที่ใช้ร่วมกันด้านล่าง (นี่คือจุดที่เกิดการทำให้ง่ายขึ้น):
- โฮสต์แซนด์บ็อกซ์หนึ่งเดียว วิดเจ็ต
htmlแสดงผลผ่านไปป์ไลน์ที่เสริมความแข็งแกร่ง เดียวกับที่แอป MCP ใช้เมื่อเผยแพร่ (iframe สองชั้นบนต้นทางแซนด์บ็อกซ์เฉพาะ โดยประกาศ CSP ต่อวิดเจ็ตและถอดรหัสแบบปิดกั้นเมื่อผิดพลาด) แทนที่จะใช้โฮสต์ iframe เฉพาะกิจชุดที่สอง พร็อกซีรับ HTML เป็นค่า ดังนั้นเนื้อหาในเครื่องจึงเป็น กรณีใช้งานตามธรรมชาติ - โมเดลการอนุญาตหนึ่งเดียว ขอบเขตการเข้าถึงของวิดเจ็ตคือรายการอนุญาตที่ได้รับสิทธิ์
ไม่ว่าจะเป็นชนิดใด: สำหรับวิดเจ็ต
htmlคือเครื่องมือโฮสต์ ส่วนวิดเจ็ตmcp-appคือเครื่องมือที่แอปมองเห็นจากเซิร์ฟเวอร์ (ผ่านกลไกallowedAppToolNamesที่มีอยู่ โดยทำให้คงทนต่อวิดเจ็ตแทนที่จะเป็นต่อรอบที่สร้างวิดเจ็ต) - เครื่องมือโฮสต์สำหรับวิดเจ็ต
html(เปิดให้ใช้ผ่านบริดจ์วิดเจ็ตและตรวจสอบ เทียบกับสิทธิ์):openclaw.prompt.send— ระดับ 2 ส่งผ่านตัวเขียนข้อความที่มองเห็นได้ และต้องได้รับการยืนยันจากผู้ใช้ เว้นแต่ได้รับสิทธิ์แล้วopenclaw.state.emit— ประกาศเซสชันระดับ 1 (รวมรายการและจำกัดขนาด)openclaw.data.read— การผูกข้อมูลแบบอ่านอย่างเดียวที่กำหนดพารามิเตอร์ได้ (ชุด RPC แบบอ่านที่อยู่ในรายการอนุญาตเดิม) โดยแก้ค่าที่ฝั่ง Gatewayopenclaw.cron.trigger— ระบบอัตโนมัติระดับ 3
net= CSP การเข้าถึงเครือข่ายใช้การประกาศ CSP ต่อวิดเจ็ต ที่เผยแพร่แล้ว (connect-srcต้นทาง) วิดเจ็ตสภาพอากาศที่อัปเดตตัวเอง จะดึงข้อมูลจาก API โดยตรงจากแซนด์บ็อกซ์ โดยไม่เกี่ยวข้องกับ Gateway- สิทธิ์ วิดเจ็ตที่ไม่ประกาศสิ่งใดจะแสดงผลทันที (อยู่ในแซนด์บ็อกซ์
default-src 'none'และการส่งพรอมต์แต่ละครั้งต้องได้รับการยืนยัน) ซึ่งมีระดับความไว้วางใจเดียวกับ วิดเจ็ตแชตแบบอินไลน์ในปัจจุบัน เครื่องมือ/ต้นทางที่ประกาศไว้จะทำให้วิดเจ็ตอยู่ในpendingบนบอร์ด: การ์ดตัวยึดตำแหน่งจะแสดงรายการเหล่านั้นเป็นภาษาที่อ่านเข้าใจได้ พร้อม อนุญาต/ปฏิเสธ ด้วยการแตะครั้งเดียว สิทธิ์กำหนดตามชื่อวิดเจ็ต สำหรับวิดเจ็ตhtmlสิทธิ์จะถูกตรึงตามไบต์ (sha256) และไบต์ที่เปลี่ยนแปลงจะคงสิทธิ์ไว้เฉพาะเมื่อ การประกาศมีขอบเขตแคบลง - ชิมสำหรับผู้เขียน ตัวครอบเอกสารจะแทรก
window.openclaw.prompt,window.openclaw.state,window.openclaw.dataและwindow.openclaw.cronเป็น API สำหรับผู้เขียนที่เสถียร การเรียกใช้แดชบอร์ดใช้ช่องทางคำขอ ที่ผูกกับทิกเก็ตมุมมองร่วมกันหนึ่งช่อง ส่วนการรายงานขนาดและโทเค็นธีมยังคงเป็นการแจ้งเตือน จากโฮสต์ที่แยกต่างหาก
การประกาศความสามารถของ Plugin
Plugin ที่เปิดใช้งานสามารถขยายโฮสต์วิดเจ็ตผ่าน dashboard.dataBindings
และ dashboard.actionVerbs ใน openclaw.plugin.json ID ภายใน Plugin จะกลายเป็น
ชื่อสิทธิ์ที่นำหน้าด้วย ID ของ Plugin เช่น workboard.cards.list และ
workboard.dispatch; % และ . ในส่วน ID ของ Plugin จะถูกเอสเคป เพื่อไม่ให้
การแบ่ง Plugin/ID ภายในแบบอื่นสืบทอดสิทธิ์ที่จัดเก็บไว้เดียวกัน ระหว่าง
การลงทะเบียน Plugin OpenClaw จะตรวจสอบว่าการผูกข้อมูลทุกรายการกำหนดเป้าหมายไปยัง RPC
ที่ลงทะเบียนโดย Plugin เดียวกันด้วย operator.read และการดำเนินการทุกรายการกำหนดเป้าหมายไปยัง RPC
ที่ลงทะเบียนด้วย operator.write; การประกาศที่ไม่ถูกต้องจะทำให้การโหลด Plugin ล้มเหลว รีจิสทรีที่ผ่านการตรวจสอบ
จะสร้างใหม่เฉพาะเมื่อวงจรชีวิตของ Plugin เปลี่ยนแปลง ขณะที่สิทธิ์ของวิดเจ็ต
ยังคงกำหนดต่อวิดเจ็ตและผูกกับไบต์และรีวิชัน
ส่วนตกค้างที่อยู่ในแบบจำลอง: ช่องทางข้อมูล WebRTC
CSP ของแซนด์บ็อกซ์จะส่งไดเรกทีฟ webrtc 'block' ที่เสนอไว้ แต่
ชุดไดเรกทีฟ CSP ปัจจุบันของ Chromium
ยังไม่รองรับ วิดเจ็ตที่เรียกใช้สคริปต์ได้จึงสามารถใช้ช่องทางข้อมูล WebRTC
เพื่อส่งข้อมูลออกใน Chromium ปัจจุบันได้ ส่วนตกค้างเดียวกันนี้เผยแพร่อยู่แล้วสำหรับ
วิดเจ็ตแชตแบบอินไลน์และโฮสต์ MCP Apps บน main
ข้อแลกเปลี่ยนที่ยอมรับ: OpenClaw ไม่ได้ใช้ค่าคงเหลือนี้เป็นเงื่อนไขกั้นวิดเจ็ตที่เขียนสคริปต์ได้ เนื้อหาวิดเจ็ตจะเข้าถึงข้อมูลสำคัญของ OpenClaw ได้เฉพาะผ่านความสามารถ data:read ที่ผู้ดำเนินการอนุมัติและตรึงตามไบต์ไว้เท่านั้น และ Permissions Policy ของแซนด์บ็อกซ์จะบล็อกการเข้าถึงกล้องและไมโครโฟน ตัวป้องกัน DOM API เป็นการป้องกันเชิงลึกแบบพยายามอย่างเต็มที่ ไม่ใช่ขอบเขตความปลอดภัย และควรอยู่ในงานเสริมความแข็งแกร่งที่ทำต่อไป
การแสดงผลบทสนทนา: การ์ดวิดเจ็ตหนึ่งใบ
การแสดงผลแบบอินไลน์รวมเป็นหนึ่งเดียวบนองค์ประกอบพื้นฐานของวิดเจ็ต เมื่อผลลัพธ์ของเครื่องมือมี UI — เอาต์พุต show_widget หรือผลลัพธ์เครื่องมือ MCP ที่มีทรัพยากรแอป — ระบบจะสร้าง วิดเจ็ตชั่วคราวที่ตั้งชื่อให้อัตโนมัติ (จำกัดขอบเขตตามเซสชันและถูกล้างออก) และบทสนทนาจะแสดงการ์ดวิดเจ็ตเพียงใบเดียวซึ่งเลือกการทำงานตามชนิดเนื้อหา การแสดงแอป MCP อัตโนมัติยังคงเป็นไปตามที่ข้อกำหนดคาดไว้อย่างสมบูรณ์ (ไม่มีงานเพิ่มเติมจากโมเดล) เพียงแต่เบื้องหลัง คือ วิดเจ็ต วิธีนี้ลบกรณีพิเศษ mcpApp แบบคู่ขนานในการเรนเดอร์แชต (การกั้นตามพื้นผิวและการขจัดรายการซ้ำแยกต่างหาก) ทำให้ UI แบบอินไลน์ทั้งหมดมีตัวเลือกปักหมุดแบบเดียวกัน และทำให้รีจิสทรีวิดเจ็ตเป็นเส้นทางหลักสำหรับเปิดอีกครั้ง (การสร้างใหม่ด้วยการสแกนบทสนทนายังคงเป็นทางเลือกสำรองสำหรับประวัติที่ไม่เคยปักหมุด) โฮสต์แบบสแตนด์อโลนที่อ่านได้อย่างเดียวและผูกกับตั๋วมีส่วนทับซ้อนกับบอร์ดในฐานะพื้นผิวถาวรสำหรับเปิดอีกครั้ง — เป็นตัวเลือกสำหรับการรวมระบบที่ต้องประเมินใน T6 ไม่ใช่ข้อสรุปที่ตั้งสมมติฐานไว้
การจัดองค์ประกอบ: v1 ใช้การวางติดกันในกริด (วิดเจ็ตกรอบควบคุมของเอเจนต์อยู่ข้างวิดเจ็ตแอปในแท็บเดียวกัน) v2 เพิ่ม สล็อตแอปที่โฮสต์จัดการ — HTML ของวิดเจ็ตเอเจนต์ประกาศบริเวณสล็อต และโฮสต์ประกอบมุมมองแอปจริงเป็นแซนด์บ็อกซ์ระดับพี่น้อง แอปจะไม่เรนเดอร์ภายใน iframe ของเอเจนต์ เพราะการซ้อนกันจะทำลายอัตลักษณ์ของบริดจ์และทำให้สามารถวางโอเวอร์เลย์/ทำ clickjacking กับ UI ของแอปที่ได้รับสิทธิ์ได้ ดังนั้นสล็อตจึงเป็นสัญญาการจัดวาง ไม่ใช่การฝัง
วิดเจ็ตที่มาจากเซิร์ฟเวอร์ (แอป MCP ที่ปักหมุด)
ด้วยโฮสต์แบบรวมศูนย์ การปักหมุดแอป MCP ของบุคคลที่สามเป็นเพียงวิดเจ็ตที่ดึงเนื้อหาจากเซิร์ฟเวอร์แทนการจัดเก็บ: board_widgets เก็บตัวบรรยาย (serverName, toolName, uiResourceUri, toolCallId + sessionKey ต้นทาง) แทนไบต์ HTML และบอร์ดจะออกสัญญาเช่ามุมมองใหม่เมื่อพ้น TTL 10 นาทีของรอบแชต (ดึงทรัพยากร ui:// อีกครั้งเมื่อข้อมูลเก่า) มุมมองแอป MCP แบบอินไลน์ในแชตจะมีตัวเลือก ปักหมุดไปยังแดชบอร์ด เช่นเดียวกับวิดเจ็ตเอเจนต์ ปัจจุบันมุมมองที่เปิดอีกครั้งเป็นแบบอ่านอย่างเดียวโดยตั้งใจ แอปที่ปักหมุดและควรโต้ตอบได้ต่อไปจะได้รับสิทธิ์ถาวรเหนือเครื่องมือที่เซิร์ฟเวอร์เปิดให้แอปเห็น (แสดงรายการอนุญาตอย่างชัดเจนแก่ผู้ดำเนินการขณะปักหมุด) โดยแยกออกจากรันที่ออกสิทธิ์ แอปที่ปักหมุดแต่ไม่ได้รับสิทธิ์จะยังคงอ่านได้อย่างเดียว ซึ่งยังมีประโยชน์สำหรับแดชบอร์ดแสดงผล v1 ปักหมุดไปยังบอร์ดของเซสชันต้นทาง การปักหมุดข้ามเซสชันต้องใช้ตัวกลางจัดการสัญญาเช่าและต้องรอ ประสานงานกับ pull request ที่เปิดอยู่ #109807 (การกำหนดเส้นทางคอมโพสเซอร์ ui/message และการส่งต่อธีม/ขนาด)
การผสานรวม WorkBoard
โปรแกรมการผสานรวม WorkBoard ทำให้การ์ดและบอร์ดยังคงเป็นของ Plugin พร้อมทั้งเชื่อมการ์ดที่ส่งงานกลับไปยังบอร์ดของเซสชันผ่าน sessionKey และ runId ที่มีอยู่ เปิดเผยฟีดและการส่งงานของ WorkBoard ผ่านการผูกและการดำเนินการที่ Plugin ประกาศ และประกอบผลลัพธ์เหล่านั้นเข้ากับชนิดวิดเจ็ต html และ mcp-app ที่มีอยู่ แทนการเพิ่มชนิดวิดเจ็ตเฉพาะสำหรับ WorkBoard
การจัดวาง: กริดแบบยืดหยุ่น
12 คอลัมน์ ความสูงแถวคงที่ กระชับอัตโนมัติ (แรงโน้มถ่วงขึ้น ดันหลบเมื่อ
ลาก — ใช้ความหมายเชิงพฤติกรรมแบบ gridstack แต่ติดตั้งใช้งานแบบเนทีฟ; การคำนวณกริดยังคงบริสุทธิ์และ
ไม่ขึ้นกับ DOM) สถานะการจัดวางวิดเจ็ตต่อแท็บ: { name, w (1-12), h (rows) } รวมถึง
ลำดับ คำศัพท์สำหรับเอเจนต์:
size:sm(3×3) ·md(6×4) ·lg(8×6) ·xl(12×8) ·full(แท็บวิดเจ็ตเดียว)after: <widgetName>จุดยึดการจัดลำดับที่เลือกใช้ได้; หากละไว้ = ต่อท้าย- ผู้ใช้ลาก/ปรับขนาดได้อย่างอิสระ; โมเดลลำดับ+ขนาดเดียวกันสามารถไปกลับได้โดยไม่สูญเสียข้อมูล
โมเดลข้อมูล (ฐานข้อมูลต่อเอเจนต์)
ตารางใหม่ใน agents/<agentId>/agent/openclaw-agent.sqlite
(ต้องเพิ่มเวอร์ชันสคีมาของฐานข้อมูลเอเจนต์ — ต้องได้รับการอนุมัติจากผู้ดำเนินการ
ก่อนนำการเปลี่ยนแปลงนี้เข้า):
CREATE TABLE board_tabs ( session_key TEXT NOT NULL, tab_id TEXT NOT NULL, -- slug title TEXT NOT NULL, position INTEGER NOT NULL, chat_dock TEXT NOT NULL DEFAULT 'right', -- left|right|bottom|hidden created_by TEXT NOT NULL, -- 'user' | 'agent' PRIMARY KEY (session_key, tab_id)) STRICT; CREATE TABLE board_widgets ( session_key TEXT NOT NULL, name TEXT NOT NULL, -- stable widget name tab_id TEXT NOT NULL, title TEXT, html BLOB NOT NULL, -- wrapped document source sha256 TEXT NOT NULL, revision INTEGER NOT NULL, size_w INTEGER NOT NULL, size_h INTEGER NOT NULL, position INTEGER NOT NULL, -- order within tab (auto-compact input) manifest TEXT NOT NULL DEFAULT '{}', -- capability manifest JSON grant_state TEXT NOT NULL DEFAULT 'none', -- none|pending|granted|rejected granted_sha TEXT, -- byte-frozen grant created_by TEXT NOT NULL, created_at INTEGER NOT NULL, updated_at INTEGER NOT NULL, PRIMARY KEY (session_key, name)) STRICT;การมีอยู่ของบอร์ด = มีแถวใดก็ตามสำหรับ sessionKey การลบเซสชันจะลบแถวของบอร์ดนั้น /new//reset จะไม่แตะต้องแถวเหล่านี้
พื้นผิวโปรโตคอล
RPC (ตารางเมธอดหลัก สคีมา typebox ใน gateway-protocol):
board.get { sessionKey }→ แท็บ + เมทาดาทาวิดเจ็ต (ไม่มีไบต์) —operator.readboard.update { sessionKey, ops[] }— CRUD/จัดลำดับแท็บใหม่, ย้าย/ปรับขนาด/ ลบ/เลิกปักหมุดวิดเจ็ต, สถานะด็อก, โฟกัสแท็บ —operator.writeboard.widget.put { sessionKey, name, html, manifest, placement }—operator.write(เส้นทางเครื่องมือเอเจนต์และเส้นทางปักหมุด)board.widget.grant { sessionKey, name, decision }—operator.approvalsboard.event { ticket, payload }— รับเหตุการณ์สถานะระดับ 1 ที่ผูกกับตั๋ว; รูปแบบโฮสต์ที่เชื่อถือแบบเดิม{ sessionKey, widget, payload }ยังคงอยู่ —operator.writeboard.prompt.authorize { ticket }— คืนค่าว่าการส่งพรอมต์ที่มองเห็นได้ ยังคงต้องยืนยันทุกครั้งที่คลิกหรือไม่ —operator.readboard.data.read { ticket, bindingId, params? }— การแก้ไขการผูกสำหรับอ่าน ของคอร์หรือ Plugin ที่ใช้งานอยู่ซึ่งอยู่ในรายการอนุญาตฝั่ง Gateway —operator.readboard.action { ticket, action, ... }— ส่งงานระบบอัตโนมัติตามสิทธิ์ที่ตรงกันทุกประการ ผ่านเส้นทางเรียกใช้ทันทีของ Cron ที่มีอยู่ หรือกริยาการดำเนินการที่ผ่านการตรวจสอบของ Plugin ที่ใช้งานอยู่ —operator.write
เหตุการณ์ (ใน EVENT_SCOPE_GUARDS, ขอบเขตการอ่าน):
board.changed { sessionKey, revision, widget? }— สถานะถาวรเปลี่ยนแปลง; UI ดึงข้อมูลใหม่ (และโหลด iframe หนึ่งรายการใหม่เมื่อมีwidget)board.command { sessionKey, command }— การควบคุม UI ชั่วคราว (เอเจนต์สลับ แท็บที่มองเห็น สลับด็อกแชต) — รูปแบบui.command
ไบต์ของวิดเจ็ตให้บริการผ่านพื้นผิว HTTP ที่ผ่านการตรวจสอบสิทธิ์ ไม่ใช่ซ็อกเก็ต
เครื่องมือเอเจนต์
รวมทั้งหมดสามเครื่องมือ (อยู่ในคอร์ ลงทะเบียนเสมอ; การเรนเดอร์ถูกกั้นด้วยความสามารถไคลเอนต์
inline-widgets เช่นเดียวกับปัจจุบัน):
show_widget { title, widget_code, name?, pin?, size?, tab?, after?, capabilities? }— สร้าง/อัปเดตตามชื่อ;pinวางลงบนบอร์ด หากไม่มีname/pinจะทำงานเหมือนปัจจุบันทุกประการ (อินไลน์ ชั่วคราว)dashboard { action, ... }— กริยาจัดการบอร์ด:read,tab_create,tab_update,tab_delete,tabs_reorder,widget_move,widget_remove,unpin,focus_tab,set_chat_dock- เครื่องมือ
cronที่มีอยู่ครอบคลุมระดับระบบอัตโนมัติแล้ว ไม่ต้องมีเครื่องมือใหม่
คำอธิบายเครื่องมือสอนคำศัพท์ด้านขนาด/จุดยึดและโมเดลระดับต่าง ๆ เอเจนต์จะได้รับแจ้งเหตุการณ์ระดับ 1 ของผู้ใช้ผ่านประกาศในเซสชัน เช่น
[dashboard] user clicked "Refresh" on widget weather (tab main)
สิ่งที่ระบบนี้แทนที่
- ลบ
extensions/workspacesเป็นฟีเจอร์ทดลอง,enabledByDefault: false, ไม่เคยอยู่ในรุ่นเสถียร (ปรากฏครั้งแรกในรุ่นเบตา 2026.7.2) ไม่มี การย้ายข้อมูล; กฎ doctor จะลบ<stateDir>/workspaces/ที่ตกค้างหากมี แนวคิดที่นำมาใช้: การคำนวณกริดแบบบริสุทธิ์, โมเดลความปลอดภัยของบริดจ์ (การเริ่มต้นพอร์ต, การกั้นการผูก, การจำกัดอัตรา), การอนุมัติที่ตรึงตามไบต์ - การโฮสต์วิดเจ็ตย้ายจาก
extensions/canvasไปยังคอร์ คลังเอกสาร canvas, ตัวครอบเอกสาร, การให้บริการ HTTP และเครื่องมือshow_widgetจะย้ายเป็นส่วนหนึ่งของคอร์ (src/canvas/); Plugin ยังคงเก็บเครื่องมือควบคุม node-canvas (canvas) และ A2UI การประกาศpluginSurfaceUrls["canvas"]และ เส้นทาง/__openclaw__/canvasเป็นสัญญาไคลเอนต์เนทีฟที่เผยแพร่แล้วและยังคง เสถียร เซสชัน Discord ยังคงใช้ตัวแปรshow_widgetที่ Discord เป็นเจ้าของ
สิ่งที่ไม่ใช่เป้าหมาย (ของโปรแกรมนี้)
- การแชร์บอร์ดระหว่างผู้ใช้หลายคน/ACL (ในอนาคต; จะมาผ่านการแชร์เซสชัน)
- การเรนเดอร์บอร์ดแบบเนทีฟบน macOS/iOS (จะได้รับฟังก์ชันนี้ทุกที่ที่ฝัง Control UI; เส้นทางวิดเจ็ตแบบอินไลน์ไม่เปลี่ยนแปลง)
- วิดเจ็ตข้อมูลในตัว (การ์ดเซสชัน/การใช้งาน/Cron) — บริดจ์ความสามารถร่วมกับ วิดเจ็ตที่เอเจนต์เขียนครอบคลุม v1; รีจิสทรีชนิดในตัวเพิ่มได้ภายหลัง
แผนการติดตั้งใช้งาน
เวิร์กทรีอิสระ สร้างด้วย Codex รีวิว+นำเข้าตามลำดับ นำเข้าแล้วจึงแก้ไข
| # | สาขา | ขอบเขต | ขึ้นต่อกับ |
|---|---|---|---|
| T1 | claude/dashboard-remove-workspaces |
ลบ Plugin workspaces + UI + เอกสาร + คีย์ i18n; กฎล้างข้อมูลของ doctor | — |
| T2 | claude/dashboard-canvas-core |
ยกระดับการโฮสต์วิดเจ็ต + show_widget ไปยังคอร์; Plugin canvas ยังคงเก็บเครื่องมือ Node; พฤติกรรมไม่เปลี่ยนแปลงเลย |
— |
| T3 | claude/dashboard-domain |
ตารางฐานข้อมูลเอเจนต์ (เพิ่มเวอร์ชันสคีมา), RPC board.* + เหตุการณ์, เครื่องมือ dashboard, อาร์กิวเมนต์ปักหมุด/ชื่อ/manifest show_widget, ประกาศระดับ 1, รีเซ็ตแต่คงบอร์ดไว้ |
T2 |
| T4 | claude/dashboard-ui |
หน้าบอร์ด + แถบแท็บ + กริดกระชับอัตโนมัติแบบยืดหยุ่น + ด็อกแชต (ซ้าย/ขวา/ล่าง/ซ่อน) + ตัวเลือกปักหมุดในบทสนทนา + หน้าบอร์ดในแถบด้านข้าง + การยืนยันรีเซ็ต | T3 (ใช้ม็อกก่อนผ่านฟิกซ์เจอร์สำหรับพัฒนา) |
| T5 | claude/dashboard-capabilities |
คลัง/ UI สำหรับสิทธิ์ + การตรึงตามไบต์; ย้ายวิดเจ็ต html ไปยังโฮสต์แซนด์บ็อกซ์ที่ใช้ร่วมกัน; เครื่องมือโฮสต์ (openclaw.prompt.send/state.emit/data.read/cron.trigger); CSP net; ชิมสำหรับการเขียน |
T3, T4 |
| T7 | claude/dashboard-mcp-apps |
ชนิดเนื้อหา mcp-app: ตัวเลือกปักหมุดในมุมมองแอปแบบอินไลน์, การจัดเก็บตัวบรรยาย, การออก/รีเฟรชสัญญาเช่าใหม่, สิทธิ์เครื่องมือเซิร์ฟเวอร์แบบถาวร (ใช้โฮสต์ MCP Apps ที่เผยแพร่แล้วซ้ำ) |
T3, T4 |
| T6 | เก็บรายละเอียด | E2E แบบสดบน Gateway ชั่วคราว (คีย์จริง), ภาพหน้าจอ, การแก้ไข, เขียน /web/dashboard ใหม่โดยเน้นผู้ใช้, รีวิวการเปิดใช้เป็นค่าเริ่มต้น |
ทั้งหมด |
การตรวจสอบความถูกต้องตามกฎของรีโป: vitest แบบเจาะจงในเครื่อง, เกตทั้งหมดบน
Crabbox/Testbox, $autoreview ก่อนนำเข้าแต่ละครั้ง, การพิสูจน์แบบสดสำหรับ T6