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 ("บริบทจะถูกรีเซ็ต แต่แดชบอร์ดยังคงอยู่") และคง บอร์ดไว้
  • แถบด้านข้าง: เซสชันที่ปักหมุดจะแสดงมุมมองบอร์ดเมื่อมีบอร์ด บอร์ดของเซสชันหน้าแรกคือ "แดชบอร์ดเอเจนต์" เริ่มต้น
  • การโต้ตอบ (สามระดับ ดูด้านล่าง): เหตุการณ์สถานะแบบเงียบ การส่ง พรอมต์ที่มองเห็นได้ และทริกเกอร์ระบบอัตโนมัติ

ระดับการโต้ตอบ

  1. เหตุการณ์สถานะ (ค่าเริ่มต้น) การโต้ตอบกับ UI ของวิดเจ็ตที่โมเดลควรรับรู้ แต่ไม่ต้องตอบสนอง bridge.emitState({...}) จะเพิ่มประกาศของ เซสชันแบบมีโครงสร้าง (ใช้กลไกเดียวกับประกาศกิจกรรมกลุ่ม) โดยไม่เริ่มรอบการทำงานของ เอเจนต์ โมเดลจะเห็นประกาศที่สะสมไว้ในการทำงานครั้งถัดไป
  2. พรอมต์ (การสนทนาโดยชัดแจ้ง) bridge.sendPrompt(text) — ต้องมีการ กระตุ้นโดยผู้ใช้ ส่งข้อความผู้ใช้ที่มองเห็นได้ไปยังเซสชัน (แชตที่เชื่อมติดไว้ จะแสดงข้อความนั้น) มีการจำกัดอัตรา และการส่งแต่ละครั้งต้องได้รับการยืนยันจากผู้ใช้ เว้นแต่ว่าวิดเจ็ตจะได้รับ สิทธิ์ความสามารถ prompt
  3. ระบบอัตโนมัติ 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 แบบอ่านที่อยู่ในรายการอนุญาตเดิม) โดยแก้ค่าที่ฝั่ง Gateway
    • openclaw.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 (ต้องเพิ่มเวอร์ชันสคีมาของฐานข้อมูลเอเจนต์ — ต้องได้รับการอนุมัติจากผู้ดำเนินการ ก่อนนำการเปลี่ยนแปลงนี้เข้า):

sql
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.read
  • board.update { sessionKey, ops[] } — CRUD/จัดลำดับแท็บใหม่, ย้าย/ปรับขนาด/ ลบ/เลิกปักหมุดวิดเจ็ต, สถานะด็อก, โฟกัสแท็บ — operator.write
  • board.widget.put { sessionKey, name, html, manifest, placement }operator.write (เส้นทางเครื่องมือเอเจนต์และเส้นทางปักหมุด)
  • board.widget.grant { sessionKey, name, decision }operator.approvals
  • board.event { ticket, payload } — รับเหตุการณ์สถานะระดับ 1 ที่ผูกกับตั๋ว; รูปแบบโฮสต์ที่เชื่อถือแบบเดิม { sessionKey, widget, payload } ยังคงอยู่ — operator.write
  • board.prompt.authorize { ticket } — คืนค่าว่าการส่งพรอมต์ที่มองเห็นได้ ยังคงต้องยืนยันทุกครั้งที่คลิกหรือไม่ — operator.read
  • board.data.read { ticket, bindingId, params? } — การแก้ไขการผูกสำหรับอ่าน ของคอร์หรือ Plugin ที่ใช้งานอยู่ซึ่งอยู่ในรายการอนุญาตฝั่ง Gateway — operator.read
  • board.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

Was this useful?
On this page

On this page