Server ↔ 多 Host 架构
Server 只做协调、不跑 agent 代码;host 要么主动 outbound 连上来(自注册),要么由 server 按需 provision 云沙箱(managed)——每个 session 一个隔离环境
一句话定位:Omnigent Server 是一个轻量协调器,监听 6767 端口、可多副本水平扩展,自己不执行任何 agent 代码。
真正跑 runner(agent 子进程)的是 host,而 host 有两种来源:
① 自注册 host——用户机器上的 daemon 主动 outbound 建 WS 隧道连上来(server 不启动它们);
② Managed host——server 按需在 Modal / Daytona 上 provision 云沙箱,一个 session 一个沙箱、强隔离。
跨副本的唯一真相源是数据库里的 hosts 表,内存里的 HostRegistry 只保存本副本的活连接。
图 1 · Server 只做协调,runner 跑在 host 上;host 分自注册与 managed 云沙箱两类
1三种角色一句话
| 角色 | 职责 | 谁来启动 |
|---|---|---|
| Server(6767 · 可多副本) | 协调:建 session、host picker、tunnel、鉴权;不跑 agent 代码 | 独立部署 |
| 自注册 Host | 用户机器上的 daemon,承载多个 runner 子进程 | host 主动 outbound 连 server |
| Managed Host | 云沙箱内的 daemon,一个 session 一个,强隔离 | server 按需 provision |
| Runner | 真正执行 agent 的子进程,各自一个 git worktree | host daemon 起 |
2Server 内部:协调但不执行
Server 只有四块,全部围绕"把请求路由到正确的 host 连接"。
REST API
POST /v1/sessions 建会话 · GET /v1/hosts 给客户端做 host picker。
Tunnel 端点
/v1/hosts/{id}/tunnel —— host 的 WS 隧道落点,内部拆成 sender / receiver / ping 三个任务。
HostRegistry(内存 · 每副本)
host_id → HostConnection(ws),外加 pending_launches / stops / stats。只保存本副本的活连接——所以它不是真相源,只是"我这台 server 现在连着谁"的快照。
resolve_host_launch
派发前的守门:校验请求者拥有该 host + host 在线 + 拥有该 session,否则 403 / 409。
3hosts 表:跨副本的唯一真相源
因为 HostRegistry 只知道本副本的连接,多副本部署下"这个 host 到底在不在线"必须落到数据库。
hosts 表字段
host_id / owner / status / updated_at
token_hash / sandbox_id (managed 专用)
存活判定:status = online 且 updated_at ≥ now - 90s
updated_at 即视为掉线,即使某副本内存里还挂着连接。4两类 Host 对照
① 自注册 Host — host 连上来
- 用户机器上的
host daemon (connect.py)主动 outbound 建 WS 隧道,server 从不启动它们。 - 一个 host 可挂多个 runner(
self._runners{}),每个 runner 服务一个 session、各占独立 git worktree。 - runner 跑在同一 OS 用户下(如 alice),靠凭证白名单注入,不泄漏个人密钥。
- host = owner 的信任边界:bob 只能看到 / 派发自己的 host。
② Managed Host — server 起云沙箱
- server 按需在 Modal / Daytona 上 provision 一个隔离 VM / 容器,一个 session 一个沙箱、无池化。
- 注入 per-launch token(server 只存
SHA-256哈希)、host_id、server_url;沙箱内 daemon 用 token WS 连回并upsert_on_connect。 - 生命周期绑定 session:session 删除 → 沙箱销毁;沙箱挂了 relaunch 时复用 host_id、换新 token。
- 对用户透明——不进 host picker。
5一次 launch 的端到端时序
- 客户端 → REST:New Chat 建会话,并在 host picker 里选一台机器。
- REST → resolve_host_launch:起 session → 选 host → 发起 launch,先过所有权 / 在线校验。
- 分叉:自注册 host —— 取内存里的活连接,通过 WS 隧道发
launch_runner帧给 host daemon。 - 分叉:managed host ——
managed_hosts.launch① provision 沙箱 + 起 omnigent host(注入 token / host_id / server_url),写库register_managed_host。 - host / 沙箱 → server:daemon 建立(自注册)或 ② 用 token 连回(managed)WS 隧道,
upsert进 hosts 表,状态 online。 - runner 起来:host daemon 在独立 git worktree 里拉起 runner 子进程,session 开始跑,客户端订阅
SSE /stream看输出。