托管 Local App
在 v0.47.0 中,Holon 引入了 Local App Engine。Agent 可以在其 agent_home/apps/ 目录下托管静态 HTML 和 JavaScript 应用。
客户端通过逻辑 URL 访问这些应用,不需要直接暴露宿主机的文件路径。
运行机制
每个应用存放在对应 Agent 目录下的独立子目录中:
~/.holon/agents/<agent_id>/apps/<app_id>/
├── manifest.json
├── index.html
├── style.css
└── app.js
当浏览器访问 /apps/<agent_id>/<app_id>/ 时,Holon 服务端会:
- 校验该目录及
manifest.json的有效性。 - 注入基础内容安全策略(CSP)响应头并执行路径穿越检查。
- 返回清单文件中指定的入口 HTML 文件及静态资源。
- 在
/apps/<agent_id>/<app_id>/holon.js提供预构建的浏览器端 SDK。
清单文件契约(manifest.json)
每个应用根目录下必须包含一个合法的 manifest.json 文件(大小不超过 64 KiB):
{
"id": "status-monitor",
"name": "状态监控卡片",
"version": "1.0.0",
"entry": "index.html",
"description": "展示 Agent 状态并触发健康检查"
}
字段说明
| 字段 | 类型 | 说明 |
|---|---|---|
id | string | 应用唯一标识。必须与所在目录名完全一致。 |
name | string | 应用名称。 |
version | string | 版本号(如 1.0.0)。 |
entry | string | 应用入口 HTML 文件的相对路径。 |
description | string | 可选的应用简要说明。 |
浏览器端 App SDK
Holon 在每个应用的路由根下内置提供了 @holon/app-sdk 脚本。在入口 HTML 中直接引入即可:
<script src="holon.js"></script>
该脚本会在全局环境中注入 window.Holon 对象,提供以下三个核心方法:
1. window.Holon.context()
获取当前应用的运行时元数据及认证状态:
const ctx = await window.Holon.context();
console.log(ctx.agent_id, ctx.app_id, ctx.session.authenticated);
返回格式示例:
{
"sdk_version": "1",
"agent_id": "main",
"app_id": "status-monitor",
"session": { "authenticated": true }
}
2. window.Holon.request(requestType, payload, requestId)
向对应 Agent 消息队列发送结构化请求:
const response = await window.Holon.request("run_diagnostics", { verbose: true });
console.log("请求已入队,ID:", response.request_id);
该方法向 /apps/<agent_id>/<app_id>/request 发起 POST 请求,并在事件日志中保留来源标记。
3. window.Holon.events(options)
通过 Server-Sent Events(SSE)流式接收应用生命周期事件。该方法返回 AsyncIterable<AppEvent>,支持传入包含可选 AbortSignal 的配置选项:
const controller = new AbortController();
try {
for await (const event of window.Holon.events({ signal: controller.signal })) {
console.log("收到事件:", event);
}
} catch (err) {
if (err.name !== "AbortError") {
console.error("事件流异常:", err);
}
}
// 通过 break 退出循环或调用 controller.abort() 均会关闭底层 SSE 连接。
安全边界与限制
Local App Engine 包含以下明确的安全限制:
- 同源会话机制: 托管应用与 Holon 守护进程共享同一源(Origin),自动携带已有的控制面会话 Cookie,但不会获得超出当前会话范围的额外特权。
- 内容安全策略(CSP): 服务端默认下发基础 CSP 策略,禁止加载任何外部跨源资源;仅允许加载同源(
'self')资源以及内联脚本与样式('unsafe-inline'),图片和字体额外允许data:URI。这允许无需打包工具的自包含前端小组件直接运行,同时阻止外部脚本注入与跨域外发请求。更强的跨源隔离(如独立 Origin 或沙箱 iframe)不在当前切片范围内。 - 静态资源白名单: 单个资源文件体积限制在 8 MiB 以内。只允许托管常见静态文件格式(HTML、JS、CSS、JSON、TXT、SVG、主流图片与字体文件),未知扩展名或可执行文件会被服务端直接拦截。
- 路径沙箱防御: 服务端会对每个静态资源请求进行路径规范化(Canonicalize),阻止包含
../的路径穿越请求,并拒绝指向应用根目录以外的符号链接。
完整示例:构建一个 Ping 测试卡片
下面通过一个简单示例演示如何编写并运行一个 Local App。
1. 创建目录与清单
创建目录 ~/.holon/agents/main/apps/ping-card/,并在其中创建 manifest.json:
{
"id": "ping-card",
"name": "Ping Card",
"version": "0.1.0",
"entry": "index.html",
"description": "通过轻量静态卡片与 Agent 互相 Ping"
}
2. 编写 index.html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>Agent Ping 卡片</title>
<style>
body { font-family: sans-serif; padding: 2rem; max-width: 480px; margin: auto; }
button { padding: 0.5rem 1rem; cursor: pointer; }
pre { background: #f4f4f4; padding: 1rem; border-radius: 4px; overflow-x: auto; }
</style>
</head>
<body>
<h2>Agent Ping 卡片</h2>
<p id="status">正在加载上下文...</p>
<button id="ping-btn" disabled>发送 Ping</button>
<pre id="output"></pre>
<script src="holon.js"></script>
<script>
const statusEl = document.getElementById("status");
const pingBtn = document.getElementById("ping-btn");
const outputEl = document.getElementById("output");
async function init() {
try {
const ctx = await window.Holon.context();
statusEl.textContent = `已连接到 Agent: ${ctx.agent_id}`;
pingBtn.disabled = false;
} catch (err) {
statusEl.textContent = `加载上下文失败: ${err.message}`;
}
}
pingBtn.addEventListener("click", async () => {
pingBtn.disabled = true;
outputEl.textContent = "正在提交请求...";
try {
const res = await window.Holon.request("ping", { timestamp: Date.now() });
outputEl.textContent = JSON.stringify(res, null, 2);
} catch (err) {
outputEl.textContent = `发生错误: ${err.message}`;
} finally {
pingBtn.disabled = false;
}
});
init();
</script>
</body>
</html>
3. 在浏览器中打开
启动 Holon 守护进程:
holon daemon start
在浏览器中访问 http://127.0.0.1:7878/apps/main/ping-card/。页面会自动调用 window.Holon.context() 显示连接的 Agent,点击按钮即可发送请求。
下一步
- 使用 Web GUI — 在浏览器中管理 Agent 与浏览工作区文件。
- HTTP 控制平面参考 — 了解
/apps相关端点与认证机制。 - 通过 HTTP 自动化操作 — 了解使用 HTTP API 驱动 Agent 的更多模式。
