Skip to content

plugin-webui-server — WebUI 服务端

包名: @aalis/plugin-webui-server
源码: packages/plugin-webui-server/src/index.ts

概述

Express + WebSocket 实现的 Web 管理后台和聊天平台,提供完整的 REST API 和实时 WebSocket 通信。

插件声明

typescript
meta.name = '@aalis/plugin-webui-server'
meta.provides = ['webui-server', 'platform']
meta.inject = {} // 无依赖

注册能力: webui-serverapi-v1, platformweb

配置

字段类型默认值说明
portnumber3000HTTP 监听端口
hoststring127.0.0.1HTTP 监听地址
tokenModeephemeral | persist | fixedpersist访问 token 策略,详见下方"认证"
fixedTokenstring''tokenMode=fixed 时使用;为空时降级为 persist
autoOpenbooleantrue启动时自动打开浏览器到访问 URL

认证 / 访问 token

WebUI 通过短 token + HttpOnly cookie 完成认证;所有 HTTP/WebSocket 都走相同闭包内的常量校验,没有"一次性"语义——同一进程内任意多个用户/浏览器都可以反复用同一个 token 登录

tokenMode 三种模式

模式token 生命周期文件
ephemeral每次进程启动随机生成,重启失效仅写出 data:/webui/access.txt
persist(默认)首次生成后写入 data:/webui/token,重启沿用同时写出 data:/webui/access.txt
fixed来自配置 fixedToken,不变;空则降级 persist同上

访问凭据文件

  • URI: data:/webui/access.txt
  • 物理路径: <storage root>/webui/access.txt,启动日志 访问凭据已写入: ... (绝对路径: ...) 直接给出
  • 内容: 注释 + URL: + Token: + 一键登录:(带 ?token= 的完整 URL)

⚠️ 不要再读历史路径 data/webui-access.txt,已被 data/webui/access.txt 取代。

登录方式

  1. 一键登录 URL:浏览器打开 http://host:port/?token=<TOKEN> → 服务端校验后 Set-Cookie 并 302 到干净 URL。
  2. 手动登录:访问 http://host:port/,在登录页粘贴 token → POST /api/auth/login { token }
  3. 登出:POST /api/auth/logout 清除 cookie。
  • 名称:aalis_webui_token
  • 属性:HttpOnly; SameSite=Strict; Path=/; Max-Age=30d
  • 进程重启且 tokenMode=ephemeral 时 cookie 自动失效。

自动打开浏览器

autoOpen=true 时通过 ProcessService.spawn('open'|'cmd /c start'|'xdg-open', [accessUrl], { detached:true, stdio:'ignore' })unref() 启动系统默认浏览器,跨平台失败静默。

REST API

端点方法说明
/api/statusGET系统状态、服务可用性、上传能力检测
/api/pluginsGET插件列表(含状态、配置、Schema、错误信息)
/api/pagesGET所有激活插件注册的 WebUI 页面(按 order 排序)
/api/page-action/:plugin/:methodPOST动态调用插件页面处理器(统一 RPC 入口)
/api/configGET/PUT全局配置读写(安全字段 + 重启检测)
/api/authority权限管理(用户列表、owner 设置)
/api/servicesGET服务列表与能力查询
/api/platformsGET平台连接状态
/api/modelsGET模型列表(LLM / Embedding / Persona)
/api/logsGET历史日志查询

WebSocket

入站消息类型 (Client → Server)

类型说明
message用户发送聊天消息
subscribe_logs订阅实时日志推送
subscribe_session订阅指定会话更新
unsubscribe_session取消会话订阅
abort中断当前生成

出站消息类型 (Server → Client)

类型说明
message完整消息推送
stream流式增量推送(contentDelta / reasoningDelta)
stream_resume页面刷新后恢复中断的流(累积缓冲内容)
status系统状态更新
tool_call工具调用开始/结束事件
state_changed插件/服务状态变化
sessions_changed会话列表更新
todo_updated待办事项变化
restarting应用即将重启通知
reload前端应重新加载
confirm高危操作确认请求
log实时日志推送

流式缓冲管理

服务端为每个会话维护流式缓冲 streamBuffers,存储累积的 contentreasoningContentgenerating 状态。当客户端断线重连(页面刷新)后,通过 stream_resume 消息恢复已产生但未收到的内容,实现无缝续流。

前端挂载与切换

前端不内置在 server 里——它是 webui-client 服务的 provider:每个前端包用 package.jsonaalis.client: true + 构建出 dist/index.html,server 启动时由 client-discovery.ts 按标记动态发现并各注册一个 provider(无硬编码包名,第三方可自带前端)。

挂载哪个servicePreferences['webui-client'] > provider 优先级 > 注册顺序。改偏好(POST /api/services/webui-client/prefer {contextId},owner 闸)后实时重挂静态目录 + 广播 WebSocket reload,无需重启进程。

切换逃生页 /__clients

前端切换的下拉框住在「前端」里;一旦切到不含该 UI 的极简前端,就没有切回去的入口。为此 server 在 GET /__clients 直出一个独立恢复页(源码 client-switch-page.ts),无论当前前端多裸都可达——「永不卡死」的兜底入口。

  • 受全局 auth 中间件保护(须先登录,同源 cookie 自动鉴权);列表走 GET /api/services、切换走 POST /api/services/webui-client/prefer(owner 闸),零新增后端逻辑
  • 用法:浏览器开 http://<host>:<port>/__clients → 选目标前端 → 点「切换并刷新」→ 成功后自动跳回 /。检测到多个前端时,启动日志也会打印此 URL。
  • 终极兜底:直接改 aalis.config.yamlservicePreferences.webui-client(或删该项回退默认)后重启。