Skip to main content
Tài liệu thiết kế kỹ thuật cho tính năng bảng điều khiển phiên, được viết trước và trong quá trình triển khai. Đây là nguồn thông tin chuẩn cho việc xây dựng. Khi tính năng được phát hành, /web/dashboard trở thành trang dành cho người dùng và trang này vẫn được giữ làm tài liệu tham chiếu kiến trúc.

Tầm nhìn

Hiện nay, làm việc với một tác tử là làm việc với một luồng văn bản. Bảng điều khiển biến nó thành một bàn làm việc: tác tử kết xuất các tiện ích tương tác theo thời gian thực; người dùng ghim chúng lên một bề mặt bền vững; khung trò chuyện được neo sang bên cạnh (hoặc ẩn đi) và nội dung chính là bảng. Bạn chuyển từ “trò chuyện với tác tử” sang “vận hành bảng điều khiển mà tác tử đã xây dựng cho bạn” mà không bao giờ phải rời khỏi phiên. Nguyên tắc:
  • Bảng là một giao diện của phiên, không phải một đối tượng mới. Mỗi phiên (luồng) có hai giao diện: bản ghi hội thoại và bảng. Phiên không có tiện ích nào được ghim chỉ là cuộc trò chuyện thông thường. Ghim một tiện ích và bảng sẽ tồn tại. Bảng kế thừa danh tính, quyền sở hữu của tác tử, tên, trạng thái ghim và vòng đời của phiên. Không có dashboard_create, không có sổ đăng ký bảng, không có mô hình ACL riêng.
  • Tính tương đương của tác tử. Mọi thao tác người dùng có thể thực hiện trên bảng, tác tử đều có thể thực hiện bằng công cụ: thêm/cập nhật/xóa tiện ích, sắp xếp chúng, quản lý thẻ, chuyển thẻ đang hiển thị, neo hoặc ẩn khung trò chuyện.
  • Gốc, không nhúng. Bảng là các thành phần Lit trong lớp vỏ Control UI (cùng hệ thống thiết kế với phần còn lại của ứng dụng). Chỉ nội dung tiện ích mới được cách ly trong iframe. Không có thanh URL, không có giao diện trình duyệt.
  • Bề mặt tác tử nhỏ gọn. Tiện ích được định địa chỉ bằng tên ổn định và được cập nhật tại chỗ. Bố cục là lưới linh hoạt tự động thu gọn; tác tử chỉ định kích thước và điểm neo, không bao giờ chỉ định pixel hoặc tọa độ.
  • Năng lực thay vì niềm tin. Mã tiện ích là HTML/JS tùy ý do tác tử tạo trong một hộp cát nghiêm ngặt. Phạm vi truy cập (dữ liệu Gateway, hành động, mạng) chỉ tồn tại thông qua bản kê khai năng lực đã khai báo và được người vận hành cấp quyền.

Khái niệm

Luồng UX

  • Chuyển cấp: tác tử gọi show_widget trong bất kỳ cuộc trò chuyện nào → tiện ích được kết xuất nội tuyến trong bản ghi hội thoại giống hệt hiện nay → di chuột sẽ hiển thị Ghim vào bảng điều khiển → tiện ích xuất hiện trên bảng của phiên. Tác tử có thể truyền pin: true để thực hiện tương tự.
  • Chế độ xem bảng: phiên có bảng sẽ có nút chuyển đổi giao diện (Trò chuyện / Bảng điều khiển). Chế độ xem bảng = dải thẻ (chỉ khi có >1 thẻ) + lưới linh hoạt + khung trò chuyện được neo. Khung neo trò chuyện có thể đổi kích thước, di chuyển (trái/phải/dưới) và thu gọn giống hệt thanh bên. Trạng thái neo được ghi nhớ theo từng thẻ.
  • Kéo: người dùng kéo các tiện ích; lưới tự động thu gọn (tiện ích nổi lên trên, các tiện ích lân cận tự sắp xếp lại). Đổi kích thước bằng tay cầm sẽ căn theo các mức kích thước. Không định vị theo pixel — áp dụng cho tất cả mọi người.
  • Cảnh báo đặt lại: /new / /reset trên phiên có bảng sẽ yêu cầu xác nhận trong giao diện web (“ngữ cảnh được đặt lại, bảng điều khiển vẫn được giữ”) và giữ lại bảng.
  • Thanh bên: các phiên được ghim sẽ kết xuất giao diện bảng khi có bảng. Bảng của phiên Trang chủ là “bảng điều khiển tác tử” mặc định.
  • Tương tác (ba cấp, xem bên dưới): sự kiện trạng thái im lặng, lượt gửi lời nhắc hiển thị và trình kích hoạt tự động hóa.

Các cấp tương tác

  1. Sự kiện trạng thái (mặc định). Các tương tác giao diện tiện ích mà mô hình cần biết nhưng không cần phản hồi. bridge.emitState({...}) nối thêm một thông báo phiên có cấu trúc (cùng cơ chế với thông báo hoạt động nhóm). Không bắt đầu lượt tác tử; mô hình sẽ thấy các thông báo đã tích lũy trong lần chạy tiếp theo.
  2. Lời nhắc (trò chuyện tường minh). bridge.sendPrompt(text) — yêu cầu người dùng kích hoạt; gửi một tin nhắn người dùng hiển thị vào phiên (khung trò chuyện được neo sẽ hiển thị tin nhắn đó). Có giới hạn tốc độ; mỗi lượt gửi đều được người dùng xác nhận trừ khi tiện ích có quyền năng lực prompt.
  3. Tự động hóa. bridge.runAction(name, args) — kích hoạt một hành động được khai báo trong bản kê khai. Tập động từ ban đầu: cron.trigger (chạy ngay một tác vụ Cron hiện có) và binding.refresh. Các tác vụ Cron vốn đã chạy trong các phiên chạy riêng biệt, hiển thị và có thể sử dụng mô hình rẻ hơn: đó là con đường “mô hình nhỏ vận hành tiện ích”. Không có phiên ẩn ở bất kỳ đâu.

Mô hình và dịch vụ lưu trữ tiện ích

HTML/JS của tiện ích do tác tử tạo (thường thông qua show_widget), được bao bọc trong lớp vỏ tài liệu tiêu chuẩn (thẻ meta CSP, trình báo cáo kích thước, bộ khởi tạo cầu nối) và được kết xuất trong <iframe sandbox="allow-scripts"> (không bao giờ trong allow-same-origin).
  • Tiện ích nội tuyến (bản ghi hội thoại) giữ nguyên pipeline tài liệu canvas hiện tại: được ghi trong thư mục trạng thái, được Gateway phục vụ, được dọn theo phạm vi, không cần phê duyệt (theo thiết kế, chúng không có năng lực — lượt gửi lời nhắc được người dùng xác nhận).
  • Tiện ích bảng là trạng thái phiên: các byte nằm trong DB SQLite của tác tử sở hữu (board_widgets), được phục vụ bởi một tuyến Gateway lõi (/__openclaw__/board/<agentId>/<sessionKey>/<name>/) đọc DB. Việc ghim một tiện ích trong bản ghi hội thoại sẽ sao chép các byte. Giới hạn: 256 KB cho mỗi tiện ích, 48 tiện ích cho mỗi bảng.
  • Cập nhật tại chỗ: phát lại một tiện ích có cùng name sẽ thay thế các byte, tăng revision, phát board.changed, và các chế độ xem đang hoạt động chỉ tải lại iframe đó.
  • Đóng băng byte: các năng lực đã cấp được liên kết với sha256 của các byte tiện ích. Việc thay đổi byte chỉ giữ lại quyền data/net/actions nếu bản sửa đổi mới khai báo một tập con của bản kê khai đã được cấp; bản kê khai được mở rộng sẽ nhắc lại người vận hành.

Tiện ích lưu trữ nội dung; ứng dụng MCP là một loại nội dung

Tiện ích là thành phần nguyên thủy của OpenClaw: ô bảng có tên, được ghim, có kích thước, thuộc sở hữu của phiên và có bản ghi cấp quyền. Nội dung được kết xuất bên trong là một loại nội dung:
  • html — do tác tử tạo thông qua show_widget, các byte nằm trong bộ nhớ bảng.
  • mcp-app — chế độ xem ứng dụng MCP của bên thứ ba (tài nguyên ui:// từ máy chủ đã cấu hình) được lưu trữ bên trong ô tiện ích.
Ứng dụng MCP không định nghĩa mô hình tiện ích; tiện ích được bổ sung khả năng lưu trữ chúng. Danh tính, vị trí, trạng thái ghim, quyền cấp và API dành cho tác giả vẫn thuộc về OpenClaw — vì vậy mã show_widget vẫn ngắn gọn như hiện nay và không bao giờ cần biết đặc tả MCP Apps tồn tại. Hạ tầng dùng chung bên dưới (đây là nơi sự đơn giản hóa được áp dụng):
  • Một máy chủ hộp cát. Tiện ích html được kết xuất thông qua cùng pipeline đã gia cố được phát hành cùng các ứng dụng MCP (iframe kép trên nguồn gốc hộp cát chuyên dụng, CSP theo từng tiện ích được khai báo và giải mã theo cơ chế đóng khi lỗi) thay vì một máy chủ iframe chuyên biệt thứ hai. Proxy nhận HTML theo giá trị, vì vậy nội dung cục bộ là trường hợp tự nhiên.
  • Một mô hình ủy quyền. Phạm vi truy cập của tiện ích là một danh sách cho phép đã được cấp, bất kể loại của nó: đối với tiện ích html, các công cụ máy chủ; đối với tiện ích mcp-app, các công cụ mà ứng dụng của máy chủ có thể thấy (thông qua cơ chế allowedAppToolNames hiện có, được duy trì lâu dài theo từng tiện ích thay vì theo từng lần chạy tạo).
  • Công cụ máy chủ cho tiện ích html (được cung cấp qua cầu nối tiện ích, được kiểm tra theo quyền cấp):
    • openclaw.prompt.send — cấp 2; được định tuyến qua trình soạn thảo hiển thị, được người dùng xác nhận trừ khi đã được cấp quyền
    • openclaw.state.emit — thông báo phiên cấp 1 (được gộp, giới hạn kích thước)
    • openclaw.data.read — các liên kết chỉ đọc được tham số hóa (tập RPC đọc trong danh sách cho phép hiện có), được phân giải phía Gateway
    • openclaw.cron.trigger — tự động hóa cấp 3
  • net = CSP. Phạm vi truy cập mạng sử dụng khai báo CSP theo từng tiện ích đã được phát hành (connect-src nguồn gốc) — tiện ích thời tiết tự cập nhật tìm nạp API trực tiếp từ hộp cát, không có sự tham gia của Gateway.
  • Quyền cấp. Tiện ích không khai báo gì sẽ được kết xuất ngay lập tức (được cách ly, default-src 'none', từng lượt gửi lời nhắc được xác nhận riêng) — cùng mức độ tin cậy với các tiện ích trò chuyện nội tuyến hiện nay. Các công cụ/nguồn gốc đã khai báo đưa tiện ích vào pending trên bảng: một thẻ giữ chỗ liệt kê chúng theo cách con người có thể đọc, với thao tác một chạm Cho phép/Từ chối. Quyền cấp áp dụng theo tên tiện ích; đối với tiện ích html, chúng được đóng băng theo byte (sha256), và các byte thay đổi chỉ giữ quyền cấp nếu khai báo đã thu hẹp.
  • Lớp tương thích cho tác giả. Lớp bao tài liệu chèn window.openclaw.prompt, window.openclaw.state, window.openclaw.datawindow.openclaw.cron làm API ổn định dành cho tác giả. Các lệnh gọi bảng điều khiển dùng chung một kênh yêu cầu được liên kết với vé chế độ xem; báo cáo kích thước và token chủ đề vẫn là các thông báo máy chủ riêng biệt.

Khai báo năng lực của Plugin

Các Plugin đã bật có thể mở rộng máy chủ tiện ích thông qua dashboard.dataBindingsdashboard.actionVerbs trong openclaw.plugin.json. ID cục bộ của Plugin trở thành tên quyền cấp có tiền tố là ID Plugin, chẳng hạn như workboard.cards.listworkboard.dispatch; %. trong đoạn ID Plugin được thoát để một cách phân chia Plugin/ID cục bộ khác không thể kế thừa cùng quyền cấp đã lưu. Trong quá trình đăng ký Plugin, OpenClaw xác minh rằng mọi liên kết đều nhắm đến một RPC được cùng Plugin đăng ký bằng operator.read và mọi hành động đều nhắm đến một RPC được đăng ký bằng operator.write; khai báo không hợp lệ khiến quá trình tải Plugin thất bại. Sổ đăng ký đã xác thực chỉ được xây dựng lại khi vòng đời Plugin thay đổi, trong khi quyền cấp tiện ích vẫn áp dụng theo từng tiện ích và được liên kết với cả byte lẫn bản sửa đổi.

Hạn chế còn lại đã được mô hình hóa: kênh dữ liệu WebRTC

CSP của hộp cát phát ra chỉ thị webrtc 'block' được đề xuất, nhưng tập chỉ thị CSP hiện tại của Chromium không triển khai chỉ thị này. Do đó, các tiện ích có thể lập trình có thể sử dụng kênh dữ liệu WebRTC để truyền dữ liệu ra ngoài trong Chromium hiện tại. Hạn chế tương tự đã được phát hành cho các tiện ích trò chuyện nội tuyến và máy chủ MCP Apps trên main. Đánh đổi được chấp nhận: OpenClaw không chặn các widget có thể lập trình dựa trên phần tồn dư này. Nội dung widget chỉ có quyền truy cập vào dữ liệu nhạy cảm của OpenClaw thông qua một capability data:read được người vận hành cấp và cố định theo từng byte, còn sandbox Permissions Policy chặn quyền truy cập camera và micrô. Biện pháp bảo vệ API DOM là cơ chế phòng thủ nhiều lớp theo nỗ lực tối đa, không phải ranh giới bảo mật, và thuộc về công việc tăng cường bảo mật tiếp theo.

Hiển thị bản ghi hội thoại: một thẻ widget

Hiển thị nội tuyến được hợp nhất trên primitive widget. Khi kết quả công cụ mang theo UI — đầu ra show_widget hoặc kết quả công cụ MCP có tài nguyên ứng dụng — hệ thống hiện thực hóa một widget tạm thời, được tự động đặt tên (giới hạn trong phiên, được dọn bỏ) và bản ghi hội thoại hiển thị một thẻ widget duy nhất, phân nhánh theo loại nội dung. Cơ chế tự động hiển thị ứng dụng MCP vẫn hoàn toàn đúng như đặc tả mong đợi (không phát sinh thêm công việc cho mô hình); bên dưới, nó đơn giản chính là một widget. Cách này loại bỏ các trường hợp đặc biệt mcpApp song song trong quá trình kết xuất trò chuyện (kiểm soát theo bề mặt, chống trùng lặp riêng), cung cấp cho mọi UI nội tuyến cùng một thao tác ghim và biến sổ đăng ký widget thành đường dẫn chính để mở lại (tái dựng bằng cách quét bản ghi hội thoại vẫn là phương án dự phòng cho lịch sử chưa từng được ghim). Máy chủ độc lập chỉ đọc dùng phiếu truy cập có phần chức năng trùng với board dưới vai trò bề mặt mở lại lâu dài — đây là ứng viên hợp nhất cần đánh giá trong T6, không được mặc định coi là sẽ hợp nhất. Bố cục kết hợp: v1 sử dụng các ô lưới liền kề (widget giao diện agent nằm cạnh widget ứng dụng trên một tab). v2 bổ sung các vùng ứng dụng do máy chủ quản lý — HTML của widget agent khai báo một vùng dành sẵn và máy chủ ghép chế độ xem ứng dụng thực thành một sandbox ngang hàng. Ứng dụng không bao giờ kết xuất bên trong iframe của agent: việc lồng nhau sẽ phá vỡ định danh cầu nối và cho phép phủ lớp/clickjack UI ứng dụng đã được cấp quyền, vì vậy vùng dành sẵn là một hợp đồng bố cục, không phải nội dung nhúng.

Widget lấy từ máy chủ (ứng dụng MCP đã ghim)

Với máy chủ hợp nhất, việc ghim ứng dụng MCP của bên thứ ba đơn giản là tạo một widget có nội dung được truy xuất từ máy chủ thay vì được lưu trữ: board_widgets giữ lại bộ mô tả (serverName, toolName, uiResourceUri, toolCallId + sessionKey nguồn) thay vì các byte HTML, và board cấp lại hợp đồng thuê chế độ xem sau TTL 10 phút của lượt trò chuyện (truy xuất lại tài nguyên ui:// khi đã cũ). Các chế độ xem ứng dụng MCP nội tuyến trong trò chuyện có cùng thao tác Ghim vào bảng điều khiển như widget agent. Theo thiết kế hiện tại, các chế độ xem được mở lại chỉ có quyền đọc; những ứng dụng đã ghim cần duy trì khả năng tương tác sẽ nhận một quyền cấp lâu dài đối với các công cụ hiển thị cho ứng dụng của máy chủ (danh sách cho phép rõ ràng được hiển thị cho người vận hành khi ghim), tách biệt khỏi lượt chạy cấp quyền. Các mục ghim chưa được cấp quyền vẫn ở chế độ chỉ đọc — vẫn hữu ích cho các bảng điều khiển hiển thị. v1 ghim vào board của phiên nguồn; việc ghim chéo phiên cần một trình môi giới hợp đồng thuê và phải chờ. Phối hợp với pull request đang mở #109807 (định tuyến trình soạn thảo ui/message, truyền giao diện/kích thước).

Tích hợp WorkBoard

Chương trình tích hợp WorkBoard giữ cho các thẻ và board thuộc quyền sở hữu của plugin, đồng thời liên kết các thẻ đã được điều phối trở lại board của phiên tương ứng thông qua sessionKeyrunId hiện có, cung cấp các nguồn cấp và hoạt động điều phối WorkBoard qua các liên kết và hành động do plugin khai báo, đồng thời kết hợp những kết quả đó với các loại widget htmlmcp-app hiện có thay vì đưa vào một loại widget dành riêng cho WorkBoard.

Bố cục: lưới linh hoạt

12 cột, chiều cao hàng cố định, tự động thu gọn (dồn lên trên, đẩy sang bên khi kéo — ngữ nghĩa gridstack, được triển khai nguyên bản; phép toán lưới vẫn thuần túy và không phụ thuộc DOM). Trạng thái bố cục widget theo từng tab: { name, w (1-12), h (rows) } cùng với thứ tự. Từ vựng của agent:
  • size: sm (3×3) · md (6×4) · lg (8×6) · xl (12×8) · full (tab một widget)
  • after: <widgetName> điểm neo thứ tự tùy chọn; bỏ qua = nối thêm
  • Người dùng tự do kéo/thay đổi kích thước; cùng một mô hình thứ tự+kích thước được tuần hoàn hai chiều.

Mô hình dữ liệu (DB theo từng agent)

Các bảng mới trong agents/<agentId>/agent/openclaw-agent.sqlite (yêu cầu tăng phiên bản schema của DB agent — cần người vận hành phê duyệt trước khi thay đổi này được đưa vào):
Board tồn tại khi có bất kỳ hàng nào cho sessionKey. Việc xóa một phiên sẽ xóa các hàng board của phiên đó. /new//reset không tác động đến chúng.

Bề mặt giao thức

RPC (bảng phương thức cốt lõi, các schema typebox trong gateway-protocol):
  • board.get { sessionKey } → các tab + siêu dữ liệu widget (không có byte) — operator.read
  • board.update { sessionKey, ops[] } — CRUD/sắp xếp lại tab, di chuyển/đổi kích thước/ xóa/bỏ ghim widget, trạng thái dock, tab được lấy nét — operator.write
  • board.widget.put { sessionKey, name, html, manifest, placement }operator.write (đường dẫn công cụ agent và đường dẫn ghim)
  • board.widget.grant { sessionKey, name, decision }operator.approvals
  • board.event { ticket, payload } — tiếp nhận sự kiện trạng thái bậc 1 gắn với ticket; cấu trúc { sessionKey, widget, payload } cũ dành cho máy chủ đáng tin cậy vẫn được giữ nguyên — operator.write
  • board.prompt.authorize { ticket } — trả về liệu thao tác gửi prompt hiển thị có còn cần xác nhận cho từng lần nhấp hay không — operator.read
  • board.data.read { ticket, bindingId, params? } — phân giải liên kết đọc phía gateway cho lõi hoặc plugin đang hoạt động thuộc danh sách cho phép — operator.read
  • board.action { ticket, action, ... } — điều phối tự động hóa theo đúng quyền cấp thông qua đường dẫn chạy ngay cron hiện có hoặc động từ hành động đã xác thực của một plugin đang hoạt động — operator.write
Sự kiện (trong EVENT_SCOPE_GUARDS, phạm vi đọc):
  • board.changed { sessionKey, revision, widget? } — trạng thái được lưu bền vững đã thay đổi; UI tìm nạp lại (và tải lại một iframe khi có widget).
  • board.command { sessionKey, command } — điều khiển UI tạm thời (agent chuyển tab hiển thị, bật/tắt dock trò chuyện) — mẫu ui.command.
Các byte của widget được phân phối qua bề mặt HTTP đã xác thực, không phải socket.

Công cụ agent

Tổng cộng ba công cụ (thuộc lõi, luôn được đăng ký; việc kết xuất phụ thuộc vào khả năng máy khách inline-widgets như hiện nay):
  • show_widget { title, widget_code, name?, pin?, size?, tab?, after?, capabilities? } — tạo/cập nhật theo tên; pin đặt widget lên bảng. Khi không có name/pin, công cụ hoạt động chính xác như hiện nay (nội tuyến, tạm thời).
  • dashboard { action, ... } — các động từ quản lý bảng: read, tab_create, tab_update, tab_delete, tabs_reorder, widget_move, widget_remove, unpin, focus_tab, set_chat_dock.
  • Các công cụ cron hiện có đáp ứng bậc tự động hóa; không cần công cụ mới.
Mô tả công cụ hướng dẫn từ vựng về kích thước/điểm neo và mô hình phân bậc. Agent được thông báo về các sự kiện bậc 1 của người dùng qua thông báo phiên, ví dụ: [dashboard] user clicked "Refresh" on widget weather (tab main).

Nội dung được thay thế

  • extensions/workspaces bị xóa. Tính năng thử nghiệm, enabledByDefault: false, chưa từng có trong bản phát hành ổn định (xuất hiện lần đầu trong các bản beta 2026.7.2). Không di chuyển dữ liệu; một quy tắc doctor xóa <stateDir>/workspaces/ cũ nếu có. Các ý tưởng được tận dụng: phép toán lưới thuần túy, mô hình bảo mật cầu nối (khởi tạo cổng, kiểm soát liên kết, giới hạn tốc độ), phê duyệt với byte được cố định.
  • Dịch vụ lưu trữ widget được chuyển từ extensions/canvas vào lõi. Kho tài liệu canvas, trình bao tài liệu, dịch vụ HTTP và công cụ show_widget trở thành thành phần lõi (src/canvas/); plugin giữ lại công cụ điều khiển node-canvas (canvas) và A2UI. Quảng bá pluginSurfaceUrls["canvas"] và các đường dẫn /__openclaw__/canvas là hợp đồng máy khách gốc đã phát hành và vẫn ổn định. Các phiên Discord giữ lại biến thể show_widget do Discord sở hữu.

Ngoài phạm vi (chương trình này)

  • Chia sẻ bảng/ACL giữa nhiều người dùng (trong tương lai; sẽ được cung cấp qua tính năng chia sẻ phiên).
  • Kết xuất bảng gốc trên macOS/iOS (có sẵn ở mọi nơi chúng nhúng Control UI; đường dẫn widget nội tuyến không thay đổi).
  • Các widget dữ liệu tích hợp sẵn (thẻ phiên/mức sử dụng/cron) — cầu nối khả năng cùng các widget do agent tạo đáp ứng v1; sổ đăng ký loại tích hợp sẵn có thể được bổ sung sau.

Kế hoạch triển khai

Các worktree độc lập, được xây dựng bằng Codex, review+land tuần tự. Land rồi sửa. Xác thực theo quy tắc của kho lưu trữ: chạy vitest tập trung cục bộ, chạy đầy đủ các cổng kiểm tra trên Crabbox/Testbox, $autoreview trước mỗi lần land, bằng chứng trực tiếp cho T6.