控制台
TIP
WebUI 是一个独立的前端应用,配合一组实时通信通道。聊天、轨迹、工具、权限、记忆、MCP、插件市场等三十多个页面都来自独立的插件:每个插件声明自己的页面、接口和文案,由控制台外壳(Shell)统一发现并组装。数据由服务端按需推送,写操作统一走带校验的动作接口。
双面包
页面插件同时包含两端:
- 服务端:声明路由、管理状态、处理动作、检查权限。
- 客户端:React 界面组件,提供表单并订阅实时数据。
两端共享类型化契约(状态类型、动作名和输入输出格式),任何不一致都会在 TypeScript 中报错。
通信
- HTTP:加载外壳与插件的静态资源、执行动作。动作接口内置输入校验、幂等键和权限检查。
- WebSocket:握手与初始化、认证、拉取初始快照并广播增量更新、心跳保活。
TIP
写操作需要重试和幂等语义,HTTP 更合适;状态同步追求「变了就推」,WebSocket 延迟和开销更低。
认证
- 服务端发送初始化帧。
- 客户端回应认证帧,附带令牌或会话凭据。
- 认证通过后才开始推送业务状态。
未认证的连接只能收到初始化帧和心跳。服务端会定期复核,令牌失效或被撤销时主动断开连接。
路径保护:控制台页面和接口默认都在受保护的前缀下。宿主没有配置保护规则或配置错误时,自检直接报错拦截——控制台权限极高,不能在无保护状态下运行。
状态
状态以服务端为唯一事实源。插件注册状态时声明:
- 快照读取方法:如何计算最新快照。
- 刷新事件:哪些事件发生时重新计算。
- 广播范围:所有连接,或仅特定连接。
客户端只需订阅,数据变化时服务端主动推送。
刷新方式:
- 事件驱动:配置变更、插件状态切换、连接断开等事件触发。
- 定时刷新:没有事件机制但随时间变化的数据,如机器人在线状态。
- 手动刷新:动作执行完后由处理函数显式触发。
背压:连接拥塞时丢弃中间状态,只下发最新快照;客户端长时间无响应则断开,避免慢窗口拖慢整个推送通道。
动作
动作是所有写操作的入口,包含名字、输入 Schema、处理函数和权限检查。
所有动作都支持幂等键:网络抖动导致重试时,服务端识别到重复的键会直接返回第一次的结果。这对安装插件、切换开关这类有副作用的操作尤为重要。
资源
- 版本化外壳:外壳资源带版本号,命中强缓存直接使用,只有远端版本更新时才重新下载。
- 插件资源:每个插件的客户端代码独立打包,按插件 ID 与修订号(Revision)命名。更新后旧文件不会被覆盖,已打开旧页面的客户端仍能加载所需分块。
- Service Worker:版本化的外壳和插件分块缓存优先;页面导航网络优先,失败时回退到上次可用的外壳;数据接口和长连接直接走网络。弱网下控制台也能正常使用。
WARNING
改了前端代码看不到变化时,先强制刷新(Ctrl+F5 或 Shift+Reload)或等新版本生效,不必急着怀疑代码没保存。
页面与插槽
ctx.slots.route({
path: '/tools',
page: async () => (await import('./tools')).ToolsPage,
title: '工具',
icon: 'wrench',
order: 10,
group: 'capabilities',
})在插件中声明即可,不需要改外壳代码。
- 分组与排序:页面声明导航分组(Group)和排序权重(Order)。分组(概览、对话、配置、插件、能力、观测等)由外壳预置。
- 隐藏页面:需要独立 URL 但不在主导航显示的页面(如轨迹详情页),注册时标记为隐藏。
- 插槽:插件可以向已有页面的插槽注入内容,如仪表盘卡片、规则页的标签页、表单中的定制控件。插槽是强类型的,注入内容必须符合页面定义的契约。
表单
大部分配置界面由 Schema 驱动:插件在服务端声明 Schema,连接时同步到前端,前端自动渲染表单,提交时服务端再次校验。添加配置项通常不需要写前端代码。
需要更复杂交互的字段(工具列表、预设选择、技能列表、多媒体选择器等)可以注册表单扩展,按字段类型或角色(Role)自动匹配。
文案
页面通过本地化接口注册中英文等文案。缺失的文案键自动回退到默认语言,不显示空白或报错。
生命周期
路由、插槽、状态、动作和文案都随插件上下文注册,插件停用或卸载时自动注销,热重载不会留下「幽灵页面」。
安全
控制台可以安装和运行任意插件、修改全局配置、读取全部会话与 Agent 轨迹,所以:
- 默认只允许本机(
localhost)访问。 - 所有页面和接口都受登录令牌保护。
- 公网部署必须配置反向代理并强制 HTTPS。
常见问题
页面白屏:打开开发者工具看报错和网络请求,常见原因是插件产物与外壳版本不匹配,或某个分块加载失败。
页面有但数据为空:检查状态是否已注册、刷新事件是否派发、后端接口是否报错。
动作提示参数非法:前端提交的结构与 Schema 不一致,按报错中的字段定位。
一直提示未认证:令牌失效,或保护路径与受保护前缀配置不匹配。
改了配置不生效:确认动作已成功返回、配置绑定了状态刷新事件,或手动刷新页面。