VibeAround
架构

工作原理

本页跟随定义 VibeAround 的两段旅程:一条 IM 消息抵达编程 Agent,和一个 Agent CLI 在你的终端里被启动。术语不熟悉的话,先看核心概念。

文档提示:当前文档全部由 Codex 生成,正在积极审阅、扩充和优化中。

本页跟随定义 VibeAround 的两段旅程:一条 IM 消息抵达编程 Agent,和一个 Agent CLI 在你的终端里被启动。术语不熟悉的话,先看核心概念

运行时一览

 web SPA ───────────────┐       TUI / CLI (va)          desktop-ui (React)
  │HTTP   │WS ×3        │             │ HTTP + WS            │ Tauri IPC
  │/api/* │/ws (pty)    │             │ (va-client)          ▼
  │       │/ws/chat     │             │                desktop (Tauri shell)
  │       │/ws/* state  │             │                      │ 进程内嵌入
  ▼       ▼             ▼             ▼                      ▼
   ┌───────────────────────────────────────────────────────────────┐
   │              vibearound-server (axum daemon)                  │
   │  REST /api/* · WS (pty, chat, live state) · MCP /mcp          │
   │  api_bridge /va/local-api · preview 反向代理 · 配对           │
   ├───────────────────────────────────────────────────────────────┤
   │  core 运行时                                                  │
   │  channels · workspace threads · process supervisor ·          │
   │  profiles · pty · previews · tunnels · auth · search          │
   └──┬──────────────┬──────────────┬───────────────┬──────────────┘
      │ stdio        │ stdio        │ pseudo-tty    │ 子进程 / SDK
      │ JSON-RPC     │ JSON-RPC     ▼               ▼
      │ (ACP)        │ (ACP)    shell / agent   隧道进程
      ▼              ▼          CLI 会话        (cloudflared, npx
  渠道插件进程    agent CLI     (web terminal)  localtunnel; ngrok
  (telegram, …)   进程                          走进程内 SDK)

                     │ HTTP 回环(Bridge 化的 Profile)

             /va/local-api bridge ──HTTPS──► 上游模型 API

一切都是一个进程加受监督的子进程。桌面应用内嵌的就是独立 va serve 跑的那个守护进程;每个 UI 都是它的客户端。

通信路径

图中每一条边,及其传输方式和负载形状:

传输协议 / 负载
web SPA → server(REST)HTTP /api/*JSON,bearer token
web SPA ↔ server(终端)WebSocket /ws?session_id=原始终端字节 + JSON resize 消息
web SPA ↔ server(聊天)WebSocket /ws/chatJSON 聊天事件:类型化输入、流式输出、权限卡片
web SPA ↔ server(实时状态)WebSocket /ws/channels/ws/tunnels/ws/sessions/ws/agents/runtime每次变化重发全量快照("最后一条消息就是状态")
TUI / va CLI → serverHTTP + /ws/chat同一套契约,经 va-client 协议 crate
desktop-ui → 桌面外壳Tauri IPC原生命令(窗口、启动、配置页面)
桌面外壳 → 守护进程进程内直接嵌入 ServerDaemon
守护进程 ↔ 渠道插件子进程 stdio换行分隔的 JSON-RPC(ACP 帧):信封进;输出、权限卡片、_va/heartbeat
守护进程 ↔ agent CLI子进程 stdioACP(JSON-RPC):初始化、会话、提示、通知、权限请求
守护进程 ↔ web 终端会话pseudo-tty经 PTY 注册表的字节流
agents → 守护进程(工具)HTTP /mcpMCP:streamable HTTP 上的 JSON-RPC(+ SSE)
启动的 CLI → 守护进程(模型)HTTP 回环 /va/local-api/…客户端的供应商方言(OpenAI / Anthropic / Gemini 形状)
守护进程 → 模型供应商HTTPSBridge 转换后的供应商方言
守护进程 → 隧道进程内 SDK(ngrok)或子进程(cloudflarednpx localtunnel供应商特定
守护进程 → 被预览的 dev serverHTTP 反向代理透传 + iframe 工具栏注入

模块地图

每项职责的归属。每个运行时模块在 modules/ 下都有深入页面,每条端到端路径在 flows/ 下都有走读:

core —— 运行时库(没有 HTTP 服务,没有 UI):

模块负责
channels插件宿主、stdio/websocket 传输、输入分发、outbox、监控
workspaceWorkspace、Thread、Route 附着、交接码(事件溯源状态 + 内存 pickup codes)
process监督器(拉起/重启/看门狗)、子进程注册表、ACP 传输、环境增强
agentACP agent 句柄、启动渲染、MCP/技能配置注入
profilesProfile schema、目录、渲染、Bridge 启动 URL、供应商连接
ptyPTY 会话注册表与运行时 —— Web 终端的后端
previews实时预览注册表、owner/share URL、端口清理
tunnelsngrok / localtunnel / cloudflare 各供应商
auth守护进程 token、配对码
launch_sessions原生 CLI 会话发现与归档
plugins插件发现与清单
search宿主侧网页搜索运行时
configstoragestateroutingresources设置、JSONL 事件存储、StateSource 契约、route key、Agent 注册表

server —— core 之上的 axum 外壳: web_server/api(REST)、ws_pty / ws_chat / ws_domains(三族 WebSocket)、mcp(工具端点)、api_bridge(方言转换、模型映射、内容策略、上游)、preview(反向代理、markdown 渲染)、auth + pair(token 中间件、配对)、boot(守护进程装配)。

其他 crate: client(HTTP/WS 契约的纯 Rust 协议库)、clitui(它的消费者)、desktop(Tauri 外壳 + IPC 命令)、launcherva-launch 原生启动二进制)。

旅程一:一条 IM 消息变成 Agent 回复

  1. 平台到插件。 Telegram/飞书/Slack 插件 —— 由守护进程监督的独立 Node.js 进程 —— 接收平台的 webhook 或长轮询事件,归一化为渠道信封:route key、消息 id、文本、附件。

  2. 插件到守护进程。 信封经插件的 stdio ACP 连接进入守护进程,落到渠道输入队列。

  3. 有序分发。 输入按 route key 分片到 worker 任务:同一聊天的消息严格按序处理,不同聊天并行。这就是连珠炮消息不会互相竞态的原因。

  4. 命令还是提示。 文本先对照斜杠命令语法检查(/new/close/switch/pickup……)。命令由 workspace-thread 层直接处理;其余都成为提示。

  5. Route 到 Thread。 Route 解析到它附着的开启 Thread。某 Route 首次联系会在默认 Workspace 创建 Thread 并附着 —— 不需要任何设置步骤。

  6. Thread 到 Agent。 Thread 确保宿主 Agent 活着:需要时监督器在 Workspace 目录里拉起该 Agent 的 ACP 适配器,绑定 Profile 的环境已就位(凭据、Bridge base URL),VibeAround 的 MCP 端点和技能注入 Agent 配置。Thread 已有 CLI Session 就恢复它;否则新建一个。

  7. 提示与流式回传。 提示经 ACP 发给 Agent。通知流回来 —— 文本块、工具调用摘要、权限请求 —— 并扇出到附着在该 Thread 上的每条 Route。权限请求渲染为交互卡片;点按以回调返回,解除 Agent 的等待。

  8. 闲时收尾。 回合结束后启动 10 分钟闲置计时。到期关停 Agent 进程;Thread 保持开启,下一条消息重新拉起 Agent 并恢复同一个 Session。

旅程二:在你的终端里启动 Agent CLI

Agent Launch 是另一条路 —— 不把 Agent 托管在守护进程里,而是在你自己的终端里打开它:

  1. 你选 Agent、Workspace 和模型 Profile(桌面 UI 或 va launch --profile <name>)。
  2. Profile 被渲染成一次具体启动:环境变量、按 Agent 的配置覆盖,以及 —— 当 Profile 指向 Bridge 化的供应商时 —— 指向守护进程本地 API 的 base URL(http://127.0.0.1:12358/va/local-api/…)。
  3. 原生启动器(va-launch,随桌面应用和 CLI 一起发行的独立二进制)校验计划,守护进程在运行时安装项目级 MCP/技能集成,然后在你的终端应用里打开 Agent(Terminal.app、iTerm2、PowerShell 或某个 Linux 终端)。
  4. 启动的 CLI 的模型请求走 Bridge,所以一份 Kimi 或 DeepSeek 订阅可以原生驱动 Codex 或 Claude Code。这样创建的会话会被守护进程发现并显示为可恢复 —— 这就是终端会话后来能从 IM 接续的原理。

状态放在哪

状态位置重启后保留?
Workspace、Thread、Route 附着~/.vibearound/ 里的 JSONL 事件日志保留
Agent CLI 会话(对话记录)各 Agent 自己的存储保留(归 Agent 所有)
模型 Profile、设置~/.vibearound/settings.json + Profile 存储保留
运行中的 Agent/插件进程内存中,受监督不保留 —— 按需重新拉起
控制台认证 token~/.vibearound/auth.json每次守护进程启动重新生成

监督器给每个子进程(渠道插件、Agent 适配器)提供崩溃重启,插件另有心跳看门狗;守护进程关停时级联清理,不留孤儿进程。


Source anchors: src/server/src/lib.rs (daemon boot, input sharding), src/server/src/web_server/mod.rs + ws_pty.rs / ws_chat.rs / ws_domains.rs (WebSocket families), src/core/src/lib.rs (module map), src/core/src/channels/ (plugin transport, dispatch), src/core/src/workspace/ (threads, attachments), src/core/src/process/supervisor.rs + acp_transport.rs (ACP framing), src/core/src/tunnels/providers/ (tunnel process forms), src/core/src/profiles/bridge_launch.rs (local API URLs), src/launcher/ (va-launch). Last verified: v0.7.11