10 KiB
LineUp UI Surface 与 App Capability 协议
版本: 1.0(提案) 状态: 已有 Web Chat Reference Host 日期: 2026-08-02
汇总入口: 本文保留 Surface 与 Capability 的协议和安全细节。后续 Runtime、SDK、App 管理及旧
app.id字段的兼容迁移以 LineUp App 最终设计方案 为准。
1. 目标
LineUp 的 Agent 不应只能回一段文本,也不应获得在宿主 App 任意执行代码的权限。本协议定义一个类似“小程序表现层”的受控扩展模型:
Agent / Adapter
├─ lineup.v1.ui.open / patch / close ─────→ UI Surface Host
│ └─ sandbox HTML + CSS + JS
├─ lineup.v1.app.call ─────→ App Capability Registry
│ └─ 用户确认 / 系统权限 / 本机执行
←─ lineup.v1.ui.event / app.result ────── 用户动作或受控调用结果
它有两层,不可混用:
| 层 | 作用 | 能做什么 | 不能做什么 |
|---|---|---|---|
UI Surface |
呈现交互界面 | 显示 HTML/CSS/JS、收集用户事件、接收状态更新 | 读取宿主登录态、直接访问设备能力、直接调用 IM / 网络 |
App Capability |
调用宿主上层应用能力 | 在能力注册、权限和用户确认后打开链接、写剪贴板、选文件、调用原生模块等 | 由 Surface 脚本绕过权限直接调用 |
标准 Markdown、文本、状态、进度、choice、confirm、input 等仍应优先由宿主内置渲染器实现。Surface 适用于仪表盘、地图、复杂表单、图表、可视化编辑器等无法由内置组件良好表达的界面。
2. 安全模型(不可省略)
- Agent 的 UI bundle 被视为不可信内容,不是 App 代码的一部分。
- Web Host 必须使用独立 origin 的
iframe sandbox="allow-scripts"。禁止allow-same-origin、allow-top-navigation、allow-popups、allow-forms。 - Surface 的 CSP 至少为
default-src 'none'; connect-src 'none'; img-src data: blob:; style-src 'unsafe-inline'; script-src 'unsafe-inline'。默认不得联网、加载远程脚本、访问摄像头或地理位置。 - 宿主与 Surface 仅用
postMessage通信;宿主必须同时验证event.source、消息命名空间、instance_id、事件名、JSON 类型与大小。 - Surface 事件只是“用户意图”回传。任何上层 App / 原生能力都必须由 Agent 另行发送
app.call,再由宿主依据注册表、风险等级和用户授权执行。 - Content 不得写入宿主 DOM。Markdown 使用解析器后仍须 sanitizer;HTML Surface 只能放进 sandbox
srcdoc。 - 生产环境应只接受已签名或在 Agent allowlist 中的 bundle hash;Reference Host 先以严格 sandbox 保障隔离,并保留
app.integrity字段用于升级。
3. 消息类型
所有消息均使用既有 lineup.v1 信封。conversation_id、id、sender、target 的规则不变。
| Type | 方向 | 含义 |
|---|---|---|
lineup.v1.ui.open |
Agent → Client | 创建或替换一个 Surface 实例 |
lineup.v1.ui.patch |
Agent → Client | 向已打开实例推送新的状态;不可注入或替换代码 |
lineup.v1.ui.close |
Agent → Client | 关闭实例 |
lineup.v1.ui.event |
Client → Agent | Surface 中的用户事件或用户关闭事件 |
lineup.v1.client.inventory |
Client → Agent | 当前 Host 的 revisioned 最小接口清单:标准组件、应用中心已启用 app Surface 与 policy 筛选后的 capability |
lineup.v1.app.list |
Client → Agent | 可选的兼容 capability-only 投影;不得替代完整 inventory 或宣称安装/授权 |
lineup.v1.app.call |
Agent → Client | 请求调用一个声明过的 capability |
lineup.v1.app.result |
Client → Agent | 调用完成、拒绝、失败或不支持的结果 |
未知的 ui.* 或 app.* type 只能安全显示或回复 unsupported,不得执行。
4. UI Surface 合约
4.1 打开
{
"v": 1,
"id": "msg_ui_01",
"type": "lineup.v1.ui.open",
"conversation_id": "conv_01",
"sender": {"kind": "agent", "id": "agent_hermes_main"},
"payload": {
"instance_id": "weather.dashboard.01",
"app": {
"id": "com.lineup.weather.dashboard",
"name": "天气面板",
"version": "1.0.0",
"integrity": "sha256-BASE64_DIGEST",
"html": "<main><button id='refresh'>刷新</button></main>",
"css": "main { padding: 16px }",
"js": "document.querySelector('#refresh').onclick=()=>LineUpSurface.event('refresh',{unit:'c'})"
},
"state": {"city": "北京", "temperature": 22}
}
}
约束:
instance_id在一个会话内唯一,格式为[A-Za-z0-9._:-]{1,128};相同 ID 的ui.open表示替换旧实例;app.id为反向域名风格的稳定应用 ID,version为 SemVer;html、css、js是 Surface bundle;单个 bundle 的生产上限建议为 160 KiB,资源应使用经过 Artifact 管理和签名的本地引用,禁止任意公网 URL;state必须是 JSON object。UI bundle 将在ready后和每次ui.patch收到它;ui.patch只能更新state,绝不能更新 HTML/CSS/JS。 若要升级 bundle,关闭旧实例并以新version打开新实例。
4.2 Surface bridge
Host 注入唯一的全局对象:
LineUpSurface.event('refresh', { unit: 'c' })
LineUpSurface.onState((state) => render(state))
LineUpSurface.resize(document.documentElement.scrollHeight)
它只允许以下上行消息:
{
"namespace": "lineup.surface.v1",
"type": "event",
"event": "refresh",
"data": {"unit": "c"}
}
Host 将其转换为:
{
"type": "lineup.v1.ui.event",
"payload": {
"instance_id": "weather.dashboard.01",
"event": "refresh",
"data": {"unit": "c"}
}
}
event 采用 [A-Za-z][A-Za-z0-9._:-]{0,63},data 必须为小于 16 KiB 的 JSON object。Surface 不拥有 app.call bridge。
4.3 状态更新与关闭
{"type":"lineup.v1.ui.patch","payload":{"instance_id":"weather.dashboard.01","state":{"city":"上海","temperature":28}}}
{"type":"lineup.v1.ui.close","payload":{"instance_id":"weather.dashboard.01","reason":"completed"}}
用户主动关闭时 Client 应回送 ui.event,其中 event 为 close。
5. App Capability 合约
5.1 动态 Client Inventory
客户端在会话建立完成后,以及应用中心的 app 启用/停用/升级、Host policy 或 capability 可见性变化时,向对应 Agent 会话发送 client.inventory。它有单调递增或不可复用的 revision;Agent 必须用最新 revision 决定可请求的组件、Surface 和能力。收到撤销后的旧 app id、Surface 或 capability 引用时,Client 只返回确定的 unsupported / revoked 结果,绝不回退到执行或加载远端 bundle。
{
"type": "lineup.v1.client.inventory",
"payload": {
"revision": "catalog-42",
"standard_components": [
{"id":"choice","version":"1"},
{"id":"confirm","version":"1"},
{"id":"input","version":"1"}
],
"applications": [
{
"id":"com.lineup.svg-canvas",
"version":"1.0.0",
"surfaces":[{"id":"canvas","events":["draw","resize","snapshot"]}]
}
],
"capabilities": [
{"name":"artifact.save","version":"1.0","risk":"user_confirmation"}
]
}
}
applications 只能列出应用中心中已启用且已在本地完成相应阶段验证的应用,不包含 bundle 源码、安装来源、登录态、文件路径或用户内容。SVG 画板这样的 app 只允许 Agent 以 app id 创建受限 Surface,并通过用户触发的 ui.event(draw / resize / snapshot) 获取声明性画布事件;inventory 不授予远程脚本注入、读取宿主 DOM 或本机能力权限。
5.2 Capability 声明(app.list 兼容投影)
客户端可在 inventory 之后或 capability 变化时发送 app.list 作为仅包含 capability 的兼容投影。只有 inventory / app.list 中声明且仍未被撤销的 capability 才能被请求;声明从不等同于授权。
{
"type": "lineup.v1.app.list",
"payload": {
"capabilities": [
{"name":"app.open_url","version":"1.0","risk":"user_confirmation","input_schema":{"type":"object","required":["url"]}},
{"name":"clipboard.write","version":"1.0","risk":"user_confirmation","input_schema":{"type":"object","required":["text"]}},
{"name":"device.pick_file","version":"1.0","risk":"system_permission","input_schema":{"type":"object"}}
]
}
}
风险必须是下列之一:display_only、user_confirmation、system_permission、restricted。后两者不能被记住为永久授权,且必须经过原生系统权限或额外身份校验。
5.3 调用与结果
{
"type": "lineup.v1.app.call",
"payload": {
"call_id": "call_open_docs_01",
"capability": "app.open_url",
"reason": "打开部署文档供你核对",
"expires_at": "2026-08-02T12:10:00Z",
"arguments": {"url": "https://example.com/docs"}
}
}
Client 必须向用户说明 capability 和 reason,收到确认后再执行,随后使用相同 call_id 回传:
{
"type": "lineup.v1.app.result",
"payload": {
"call_id": "call_open_docs_01",
"status": "completed",
"result": {"opened": true}
}
}
status:completed | rejected | cancelled | expired | unsupported | failed。同一 call_id 必须幂等;调用记录与授权决定应由 Gateway 审计。
6. Reference Host 当前实现与阶段边界
截至 2026-08-03,Tauri Reference Host 已完成 M0 和 M1-01~M1-03:严格 Envelope / Kernel / Store / Renderer 边界,Markdown、status/progress/error、choice、confirm、input 的可信原生渲染与本地状态恢复。它尚未实现 client.inventory 发送、应用中心、ui.open / patch / close 的 Surface Host、远端或本地 app bundle 加载、app.call 执行、Capability Registry 或 app.result 网络回传。
因此,这份协议中的 Surface、inventory 与 Capability 段落是后续 M2~M4 的正式契约,不是当前 Web Chat 已开放的功能。M2 建立应用中心本地启用注册表与隔离 Surface;M3 才生成/更新并通知 client.inventory,再实施 Capability policy;M4 负责下载、完整性校验、缓存、回滚与 Host 一致性。当前只以 Tauri Desktop Host 与同代码 Web Reference Host 实现这些边界;不规划独立 Android/iOS/Wails 客户端。