Skip to content

Commit 95cec27

Browse files
committed
docs: document v2 protocol as primary contract with v1 removal plan
- protocols.md rewritten around the unified WebSocket+Protobuf links, v1 kept as a deprecated appendix; gateway/webui/gui/overview updated - new protocol-v2-migration.md: skew matrix, zero-traffic criteria, step-by-step v1 removal checklist - development.md: gateway layering map, capability-addition walkthrough, deprecation conventions, lint/proto-check commands
1 parent bb5e315 commit 95cec27

8 files changed

Lines changed: 264 additions & 100 deletions

File tree

docs/architecture/gateway.md

Lines changed: 33 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -2,36 +2,35 @@
22

33
## 职责边界
44

5-
Gateway 是远程访问中继,不是 Agent 执行环境。它同时面对桌面 Agent 和浏览器 WebUI:
5+
Gateway 是远程访问中继,不是 Agent 执行环境。它同时面对桌面 Agent 和浏览器 WebUI,
6+
v2 起两端统一走 WebSocket+Protobuf(v1 gRPC 与 JSON WebSocket 已弃用、仅为旧客户端保留):
67

78
| 方向 | 协议 | 作用 |
89
|---|---|---|
9-
| Desktop Agent -> Gateway | gRPC `AgentGateway.AgentConnect` 双向流 | 桌面端注册在线 session,接收 WebUI 请求,返回 chat/history/settings/memory/skills 等响应与事件。 |
10-
| Desktop Agent -> Gateway | gRPC `AgentGateway.AgentTerminalConnect` 双向流 | 专用终端字节流,承载 attach snapshot、input、resize、output,不与普通控制面共享队列。 |
11-
| WebUI -> Gateway | WebSocket `/ws` | 浏览器端发起 chat(command/subscribe)、history、settings、skills、memory、cron 等 request,并订阅 `chat.event` 与同步广播。 |
12-
| WebUI -> Gateway | WebSocket `/ws/terminal` | 专用二进制终端流;输入 fire-and-forget,输出按 session interest 推送轻量 bytes frame。 |
10+
| Desktop Agent -> Gateway | WebSocket `/ws/v2/agent`(Protobuf 帧) | 桌面端注册在线 session,接收 WebUI 请求(`GatewayEnvelope`),返回 chat/history/settings/memory/skills 等响应与事件(`AgentEnvelope`)。 |
11+
| Desktop/Browser -> Gateway | WebSocket `/ws/v2/terminal`(Protobuf 帧) | 专用终端字节流(角色由 hello 区分),承载 attach snapshot、input、resize、output,不与普通控制面共享队列。 |
12+
| WebUI -> Gateway | WebSocket `/ws/v2`(Protobuf 帧) | 浏览器端发起 chat(command/subscribe)、直通 history/settings/skills/memory/cron 等请求,并订阅 `chat_event` 与同步广播。 |
1313
| WebUI -> Gateway | HTTP `/api/*` | 状态检查、文件上传、公网分享页、图片代理、静态资源。 |
14+
| ~~Desktop -> Gateway~~ | gRPC `AgentGateway.*` | **已弃用**,服务旧版桌面端。 |
15+
| ~~WebUI -> Gateway~~ | WebSocket `/ws``/ws/terminal` | **已弃用**,服务未刷新的旧标签页。 |
1416

1517
## 入口与服务启动
1618

1719
| 文件 | 作用 |
1820
|---|---|
19-
| `cmd/gateway/main.go` | 读取 config,创建 `session.Manager`,启动 gRPC server 与 HTTP server,处理 shutdown。 |
21+
| `cmd/gateway/main.go` | 读取 config,创建 `session.Manager`,启动 gRPC server(弃用,兼容旧桌面端)与 HTTP server,处理 shutdown。 |
2022
| `cmd/gateway/shutdown.go` | gRPC graceful stop 超时后强制 stop。 |
2123
| `internal/config/config.go` | 地址、token、TLS、静态资源、请求大小、超时等配置。 |
22-
| `internal/auth/grpc_interceptor.go` | gRPC token 校验。 |
23-
| `internal/auth/http_middleware.go` | HTTP API token 校验。 |
24-
| `internal/server/grpc.go` | `AgentGateway` gRPC 服务实现。 |
25-
| `internal/server/http.go` | HTTP mux、WebSocket、API、静态 WebUI 与 public share route。 |
26-
| `internal/server/websocket_chat_handlers.go``websocket_chat_queue_handlers.go``chat_commands.go` | WS `chat.prepare`/`chat.command`/`chat.subscribe`/`chat.cancel`/chat queue handler、原生 Runtime 往返探测、订阅 replay 与实时 forward、Gateway -> Desktop `ChatCommandRequest` 下发与事件 payload 映射。 |
27-
| `internal/server/websocket.go` | WebUI WebSocket 连接生命周期、鉴权、订阅 forwarder。 |
28-
| `internal/server/websocket_routes.go` | WebSocket request type 到 domain handler 的路由表。 |
29-
| `internal/server/websocket_*_handlers.go` | fs/history/settings/terminal/git/skills/memory/cron/provider 等非 Chat domain handler。 |
30-
| `internal/server/websocket_payloads.go` | WebSocket 响应 payload 组装与 JSON helper。 |
31-
| `internal/server/websocket_roundtrip.go` | payload 严格解码、Agent unary round-trip 和错误文案归一。 |
32-
| `internal/server/websocket_writer.go` | WebSocket 并发写锁、write deadline 与 envelope 发送。 |
33-
| `internal/server/websocket_connection_state.go` | 单条 WebSocket 连接内的 terminal interest 状态。 |
34-
| `internal/session/manager.go` | `session.Manager` façade 和核心公开类型。 |
24+
| `internal/observability/` | slog 初始化与 v1/v2 协议使用计数(`/api/status``protocol_usage`)。 |
25+
| `internal/transport/wscore/` | v1/v2 共用的 WebSocket 连接运行时:控制优先双队列写泵、拥塞掉帧、有限重试、心跳与空闲驱逐。 |
26+
| `internal/protocol/pbws/` | **v2 协议层**:三链路握手/编解码、直通白名单(`guard.go`)、关联 id 命名空间化、事件扇出与快照回放。 |
27+
| `internal/protocol/shared/` | 两代协议共用的域逻辑:Origin 校验、终端权限门控与响应后处理、终端兴趣跟踪。 |
28+
| `internal/chatcmd/` | chat 命令编排(归一化、探活、投递、启动看门狗),v1/v2 共用。 |
29+
| `internal/auth/` | HTTP/WS token 校验;gRPC 拦截器(弃用)。 |
30+
| `internal/server/grpc.go` | v1 `AgentGateway` gRPC 服务实现(弃用)。 |
31+
| `internal/server/http.go` | HTTP mux、v1/v2 WebSocket 路由、API、静态 WebUI 与 public share route。 |
32+
| `internal/server/websocket*.go` | v1 JSON 协议实现(弃用):连接生命周期、字符串路由表、约 90 个 domain handler 与 payload 塑形。 |
33+
| `internal/session/manager.go` | `session.Manager` façade 和核心公开类型(transport 无关,两代协议共用)。 |
3534
| `internal/session/manager_state.go` | session registry、sync hub、chat run store 的内部状态定义。 |
3635
| `internal/session/manager_registry.go` | 当前 Agent session、认证快照、per-request stream 注册。 |
3736
| `internal/session/manager_*_sync.go``manager_terminal.go``conversation_stream.go``conversation_ingress.go` | history/settings/terminal sync、进程内 Chat 事件窗口、实时 fan-out、replay 与 command dedupe。 |
@@ -40,25 +39,30 @@ Gateway 是远程访问中继,不是 Agent 执行环境。它同时面对桌
4039

4140
| 路由 | 认证 | 说明 |
4241
|---|---|---|
43-
| `GET /ws` | token | WebUI 主 WebSocket 协议。 |
44-
| `GET /ws/terminal` | token | WebUI 终端专用 WebSocket;首帧 JSON auth,后续使用 `version + kind + headerLength + JSON header + bytes` 的二进制 frame。 |
45-
| `GET /api/status` | token | Gateway 当前 Agent 在线状态。 |
42+
| `GET /ws/v2` | hello token | **v2** WebUI 主链路(Protobuf 帧,子协议 `liveagent.v2.pb`)。 |
43+
| `GET /ws/v2/agent` | hello token | **v2** 桌面端信封流(取代 gRPC)。 |
44+
| `GET /ws/v2/terminal` | hello token | **v2** 终端数据面(两端共用,角色在 hello)。 |
45+
| `GET /ws` | token | v1 WebUI JSON 协议(弃用)。 |
46+
| `GET /ws/terminal` | token | v1 终端二进制流(弃用);首帧 JSON auth,后续 `version + kind + headerLength + JSON header + bytes`|
47+
| `GET /api/status` | token | Agent 在线状态 + `protocol_usage` 协议使用计数。 |
4648
| `POST /api/files/import` | token | WebUI 上传可读文件,Gateway 转发给桌面端导入 workspace uploads。 |
4749
| `GET /api/public/history-shares/{token}` | public token | 公开只读历史分享数据。 |
4850
| `GET /image-proxy` | 视配置/实现而定 | 图片代理,带 URL 安全校验。 |
4951
| `/` | 无或按静态资源策略 | 嵌入/构建后的 WebUI 静态资源与 SPA fallback。 |
5052

51-
Chat 走 `/ws` 且是严格新协议:`chat.prepare` 用关联 Ping/Pong 探测并唤醒桌面 Chat Runtime;`chat.command` 必须是 `{ type, payload }` envelope,`chat.subscribe``conversation_id` 订阅,不接受旧 `command` 字段、顶层裸 payload 或 `request_id` 别名。旧 HTTP SSE 路由 `GET /api/chat/events` 已下线。
53+
Chat 走 `/ws/v2` 且是严格新协议:`chat_prepare` 用关联 Ping/Pong 探测并唤醒桌面 Chat Runtime;`chat_command` 携带 proto `ChatCommandRequest``chat_subscribe``conversation_id` 订阅。旧 HTTP SSE 路由 `GET /api/chat/events` 已下线。
5254

53-
## gRPC 服务
55+
## gRPC 服务(已弃用)
56+
57+
仅为旧版桌面端保留;新桌面端走 `/ws/v2/agent`,握手失败时自动回退到本服务。
5458

5559
| RPC | 类型 | 用途 |
5660
|---|---|---|
57-
| `Authenticate(AuthRequest) -> AuthResponse` | unary | 桌面端认证探活,返回 session 信息。 |
58-
| `AgentConnect(stream AgentEnvelope) -> stream GatewayEnvelope` | bidirectional stream | 桌面端常驻连接,WebUI request 下发为 `GatewayEnvelope`,桌面端 response/event 回传为 `AgentEnvelope`|
59-
| `AgentTerminalConnect(stream TerminalStreamFrame) -> stream TerminalStreamFrame` | bidirectional stream | 终端专用字节流;attach 返回 snapshot,input/resize 不返回 session metadata,output 只携带 session、offset 与 bytes|
61+
| `Authenticate(AuthRequest) -> AuthResponse` | unary | 桌面端认证探活,返回 session 信息(v2 由 hello 承担)|
62+
| `AgentConnect(stream AgentEnvelope) -> stream GatewayEnvelope` | bidirectional stream | 桌面端常驻连接(v2 由 `/ws/v2/agent` 承担,信封同构)|
63+
| `AgentTerminalConnect(stream TerminalStreamFrame) -> stream TerminalStreamFrame` | bidirectional stream | 终端专用字节流(v2 由 `/ws/v2/terminal` 承担)|
6064

61-
`proto/v1/gateway.proto` 是 Desktop 与 Gateway 的权威协议定义;Go 侧生成文件位于 `internal/proto/v1/*`
65+
`proto/v1/gateway.proto` 是三端共享的权威业务消息定义(Go 生成于 `internal/proto/v1/*`);v2 帧壳定义于 `proto/v2/gateway_ws.proto`Go 生成于 `internal/proto/v2/*`)。代码生成统一由 `buf` 驱动(`make proto`),CI 有生成物漂移与 breaking 检查门禁
6266

6367
## Session Manager
6468

@@ -91,7 +95,7 @@ Chat 走 `/ws` 且是严格新协议:`chat.prepare` 用关联 Ping/Pong 探测
9195
| chat command | 提交/编辑/取消走 WS `chat.command`;新 command 在 accepted 前必须有原生往返 probe,紧随成功 prepare 的 command 可复用同一 session 2 秒内的新鲜结果,旧客户端或过期结果仍现场探测。accepted ACK 走控制优先队列,避免被 token 数据积压阻塞。流式事件走按 conversation 持久订阅 `chat.subscribe`,经 `chat.event` 推送(订阅缓冲溢出时发 `chat.subscription_reset` 提示客户端按游标重订阅)。 |
9296
| terminal stream | 不走普通 `/ws` request;attach/input/resize/detach 走 `/ws/terminal` 二进制 frame,页面侧 `BrowserGatewayTerminalStreamClient` 为同一 token 复用一条 terminal stream 并按 session fan-out。 |
9397

94-
WebSocket server 的实现按三层组织:`websocket.go` 管连接生命周期和订阅 forwarder;`websocket_routes.go` 管 request 路由;`websocket_*_handlers.go`domain handler。handler 只做 payload 校验、调用 Gateway/Desktop service、组装 WebUI 响应。连接内的可变状态不再直接铺在 `websocketConnection` 上,而是通过 terminal tracker 管理
98+
WebSocket server 的实现分层:`internal/transport/wscore` 管写泵/背压/心跳(两代共用);v2 在 `internal/protocol/pbws`(帧编解码、直通白名单、事件扇出);v1 在 `internal/server/websocket*.go`(弃用:连接生命周期 + 字符串路由 + domain handler)。域逻辑(终端门控/响应后处理、chat 编排)在 `internal/protocol/shared``internal/chatcmd`,两代协议调用同一份实现
9599

96100
Terminal metadata 事件仍通过普通 `/ws` 广播,用于同步 `created``exit``closed``renamed`、SSH prompt 和 SSH tab 状态;terminal output 不再进入 React session state,也不再附带完整 session。输出 bytes 只通过 `/ws/terminal``AgentTerminalConnect` 推送,慢客户端只阻塞自己的 terminal stream。
97101

docs/architecture/gui.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -79,9 +79,9 @@
7979
| 机制 | 当前实现 |
8080
|---|---|
8181
| 稳定 WebView listener | `useGatewayBridgeListeners` 用 ref 保存 worker id 和最新回调,effect 只在组件挂载/卸载时注册或销毁;普通 React render 不再重建 listener、制造接收空窗或重复上报 `suspended`|
82-
| 原生往返唤醒 | Rust 收到 `chat-runtime-wake-` 前缀的关联 Ping 后 emit `gateway:chat-runtime-wake`;所有 Pong(唤醒与心跳)经专用出站控制通道(64 深,与数据队列 merge 进同一 gRPC stream`try_send` 返回,token 流打满数据队列时探测仍可被应答,且绝不阻塞 inbound receive loop。 |
82+
| 原生往返唤醒 | Rust 收到 `chat-runtime-wake-` 前缀的关联 Ping 后 emit `gateway:chat-runtime-wake`;所有 Pong(唤醒与心跳)经专用出站控制通道(64 深,与数据队列 merge 进同一信封流(v2 WebSocket;旧网关回退 gRPC)`try_send` 返回,token 流打满数据队列时探测仍可被应答,且绝不阻塞 inbound receive loop。 |
8383
| 生命周期 nudge | `online``focus``pageshow``visibilitychange`、WebView `resume` 与 Tauri `RunEvent::Resumed` 会唤醒 runtime;`online`/focus 类事件经 `gateway_nudge_connection` 走 offline/stale-heartbeat 健康检查后才重建连接(不强制),仅 `RunEvent::Resumed` 保留强制重连。 |
84-
| 快速重连 | gRPC 自动重连从 250ms 指数退避到 5s,稳定连接 30s 后重置;stale 判断使用 heartbeat interval 加 20s(最多 60s)。 |
84+
| 快速重连 | 信封流自动重连从 250ms 指数退避到 5s(每次重连先试 v2 `/ws/v2/agent`,握手失败回退 gRPC),稳定连接 30s 后重置;stale 判断使用 heartbeat interval 加 20s(最多 60s)。 |
8585
| inbound 优先 | `AgentConnect` 建立后立即进入 inbound receive loop。Runtime status 先恢复,settings、terminal、tunnel、process 与 run ledger 延迟 200ms 后在可中止后台任务中低优先级 replay,并在批次间 yield。 |
8686
| 启动空窗消除 | WebView 在 Tauri listener 异步注册完成前就先 heartbeat + drain 一次;native wake、request-ready 与 Gateway online 事件都会继续触发 drain。 |
8787

@@ -101,7 +101,7 @@
101101
| 取舍 | 原因 |
102102
|---|---|
103103
| ChatPage 仍是总编排层 | 对话运行时跨模型、工具、历史、压缩、记忆、Gateway、上传和 UI 状态,保留一个编排中心能减少跨模块隐式状态。 |
104-
| 高权限能力放 Rust | 文件系统、Shell、MCP 进程、SQLite、Gateway gRPC、Cron 更适合在 Tauri 后端做权限与生命周期控制。 |
104+
| 高权限能力放 Rust | 文件系统、Shell、MCP 进程、SQLite、Gateway 连接、Cron 更适合在 Tauri 后端做权限与生命周期控制。 |
105105
| GUI 与 WebUI 复制部分 UI | 两端运行环境不同,WebUI 不能直接调用 Tauri,但需要维持体验 parity,因此复制 settings/hub/chat 组件并接入 shims。 |
106106
| Settings 按域保存 | provider secret、remote、cron、memory 等域有不同验证和同步策略,分域保存便于限制泄露与减少误覆盖。 |
107107
| Gateway 控制面优先 | 远程首条 Chat command 与 Ping/Pong 必须先于大体积状态 reconciliation;后台 snapshot replay 只负责最终一致性,不阻塞 inbound。 |

0 commit comments

Comments
 (0)