Surface 覆盖层

Surface 是一种路由覆盖层,仅在某个运行时条件成立时激活,并且会遮蔽同一路径的内置路由。 普通路由注册在唯一的 (method, path) 上,且内置路由始终优先;而 surface 由中间件在路由匹配之前进行求值,因此只要其条件为真,它就可以替换另一个模块已经占用的路径——例如 site 模块的 /。

最典型的场景是首次运行引导:当尚未配置任何 LLM 提供商时,Agent OS 会在 / 提供设置向导,而不是营销站点。一旦配置了提供商,该覆盖层就会消失,无需重建模块图,也无需重启(除了向导自身触发的那次重启)。

配置

Surface 在 config/surfaces/*.yaml 中声明:

id: onboarding
when: no_llm            # always | no_llm | llm
priority: 100           # higher wins between matching surfaces
paths: ["/", "/index.html", "/site/"]
page: onboarding.html   # HTML file, relative to this YAML …
# … or, instead of `page`:
# redirect: /platform
字段 含义
id 标识;同 id 的文件会替换内置默认值。
when 条件:always、no_llm 或 llm(已配置 LLM)。
priority 当多个 surface 匹配同一路径时的优先级裁决(数值高者优先)。
paths 路径模式;支持 :param 和 *rest 通配符,否则为精确匹配。
page surface 匹配时原样提供的 HTML 文件。
redirect 302 目标(与 page 互斥)。

内置的 onboarding surface 随二进制文件一起编译了其页面,因此全新分发版本无需任何配置即可工作。添加 config/surfaces/<id>.yaml(以及 page: 文件)即可自定义它,或添加你自己的覆盖层——例如维护页面:

id: maintenance
when: always
priority: 50
paths: ["/", "/:page"]
page: maintenance.html

条件

条件是一套小型、具名的词汇表,针对运行时状态快照进行求值(并非通用表达式语言),因此配置保持可审计:

优先级与安全性

首次运行引导

当服务器在没有 LLM 的情况下启动时,内置的 onboarding surface 会在 /、/index.html 和 /site/ 提供向导。该向导会向以下端点发送请求:

这两个端点按设计是公开的——其全部意义就在于让全新的、未配置的服务器能够被设置。一旦存在提供商,连接端点就会以 409 拒绝,因此它无法被用来悄悄重新配置正在运行的服务器(而且它永远不会被覆盖层遮蔽)。

config/llm.yaml 在加载时覆盖 server.yaml 的 provider: 块;server.yaml 本身永远不会被重写,因此其注释得以保留。

管理界面

管理外壳(菜单 Platform)暴露了由宿主拥有的两个页面:

这两个 API 都需要管理员权限(未配置认证时该门禁会打开),且这些页面永远不会被 surface 遮蔽。

禁用

删除 config/surfaces/<id>.yaml(或更改其 when)并重启。只要未配置 LLM,内置的引导 surface 就会处于激活状态。若想在该状态下仍保留正常站点,可用 when: llm 覆盖它,该 surface 仅在存在 LLM 时激活(即首次运行期间永不激活):

id: onboarding
when: llm

或者直接配置一个提供商。