204 lines
11 KiB
Markdown
204 lines
11 KiB
Markdown
# 规划方案 · 通过桌面客户端接入 Agent CLI
|
||||
|
|
|
|||
|
|
> **类型**:规划方案(待排期,非执行棒)
|
|||
|
|
> **产出**:让 DSH 平台支持「dsh 实例经覆盖网络拨号到用户电脑上的 Agent CLI」,与接入模型 API 同构
|
|||
|
|
> **状态**:调研完成 · 待排期
|
|||
|
|
> **创建**:2026-09-23
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## §1 目标
|
|||
|
|
|
|||
|
|
**一句话**:用户在桌面客户端内启动 Agent CLI(Claude Code / Aider / Gemini CLI 等),dsh 实例经覆盖网络 dialer 拨号到桌面客户端上的 agent 端口,实现「平台只管接入、agent 在用户侧跑」的集成模式。
|
|||
|
|
|
|||
|
|
与接入模型 API 的同构性:
|
|||
|
|
|
|||
|
|
| | 模型 API(现状) | Agent CLI(本方案) |
|
|||
|
|
|---|---|---|
|
|||
|
|
| 谁连谁 | dsh 实例 → 模型 API | dsh 实例 → 桌面客户端上的 agent |
|
|||
|
|
| 传输 | 公网 HTTP | 覆盖网络(dialer + relay) |
|
|||
|
|
| 平台角色 | 配置入口 + 注入凭据 | 配置入口 + 注入 agent endpoint |
|
|||
|
|
| 用户侧 | 填 API Key | 装桌面客户端 + 启动 agent |
|
|||
|
|
|
|||
|
|
四条可验收子目标:
|
|||
|
|
|
|||
|
|
1. **agent 适配层**:桌面客户端内嵌一个轻量 HTTP/WS 服务,把 dsh 实例发来的请求转成 agent CLI 的 stdin,把 agent stdout 回传给 dsh 实例。
|
|||
|
|
2. **dsh 实例侧调用**:在现有「调模型 API」的代码路径旁,新增「调覆盖网络里的 agent endpoint」分支,按 provider 类型分发。
|
|||
|
|
3. **管理面配置**:credential_vault 扩一个 `kind=agent` 类型,用户填 agent 名称 + 选择已注册的桌面设备,平台写入实例 env。
|
|||
|
|
4. **端到端验证**:用户在浏览器 chat 里发消息 → dsh 实例经覆盖网络拨到桌面客户端 → agent 处理 → 结果回传浏览器。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## §2 前置条件(已就位 · ⛔ 不重做)
|
|||
|
|
|
|||
|
|
| 能力 | 现状 | 代码位置 |
|
|||
|
|
|---|---|---|
|
|||
|
|
| **覆盖网络 relay** | relay server + relay client(WebSocket 长连接拨出,NAT 穿透) | `src/net/relay/server.ts` / `client.ts` |
|
|||
|
|
| **dialer 拨号** | dsh 实例侧经 `RelayDialer` 主动拨号到同网设备 `(hostId, port)` | `src/net/relay/dialer.ts` |
|
|||
|
|
| **用户网隔离** | `u:<userId>` 网络,用户设备与自己的实例同网 | `src/net/relay/network.ts` |
|
|||
|
|
| **桌面设备注册** | `OverlayDeviceKind='desktop'`,私钥本机生成、公钥上送 | `src/net/relay/device-grant.ts` |
|
|||
|
|
| **多端同时登录** | 序47 S1 落地:`sessions.kind` 区分 `browser`/`desktop`,`maxSessionsPerUser=20`,不再无条件驱逐旧会话 | `src/web/routes/auth.ts` L321-343 |
|
|||
|
|
| **会话/设备管理 API** | `GET /api/auth/sessions` + `POST /api/auth/sessions/revoke` + `GET /api/overlay/my-devices` | `src/web/routes/sessions.ts` |
|
|||
|
|
| **凭据注入机制** | spawn 时按 credential_vault 写 `settings.yaml` + `.credentials.yaml` + env | `src/db/types.ts` CredentialKey |
|
|||
|
|
|
|||
|
|
**结论**:覆盖网络 + 多端登录 + 设备台账 + 凭据注入四层基础设施全部就位,本方案只做适配层 + 调用分支 + 管理面扩展。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## §3 范围
|
|||
|
|
|
|||
|
|
### 本方案含
|
|||
|
|
|
|||
|
|
1. 桌面客户端内嵌 agent 适配层(HTTP/WS 服务 + PTY 桥)
|
|||
|
|
2. dsh 实例侧新增 agent provider 调用分支
|
|||
|
|
3. credential_vault 扩 `kind=agent` 类型
|
|||
|
|
4. 管理面 UI(选择已注册设备 + 启动/停止 agent)
|
|||
|
|
5. 审计日志(agent 调用记录)
|
|||
|
|
|
|||
|
|
### 本方案不含
|
|||
|
|
|
|||
|
|
- 改 dsh 官方包主程序(⛔ 红线:不改官方 dsh 主程序与缓存)
|
|||
|
|
- 在平台沙箱内跑 agent(agent 跑在用户电脑上,不受 bwrap 限制)
|
|||
|
|
- 覆盖网络本身改造(relay / dialer / 网络隔离已就位)
|
|||
|
|
- 多端登录改造(序47 已落地)
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## §4 决策点
|
|||
|
|
|
|||
|
|
### D1:agent 适配层协议(待拍板)
|
|||
|
|
|
|||
|
|
dsh 实例用什么协议调 agent?三个候选:
|
|||
|
|
|
|||
|
|
**A. HTTP 请求/响应(类 OpenAI API 格式)**
|
|||
|
|
- 优点:与模型 API 调用路径同构,dsh 实例侧改动最小;无状态,简单
|
|||
|
|
- 缺点:agent CLI 多为有状态长会话(工具循环),无状态 HTTP 需要适配层维护会话状态映射;不能实时看到 agent 的中间输出
|
|||
|
|
|
|||
|
|
**B. WebSocket 双向流(PTY over WS)**
|
|||
|
|
- 优点:支持实时交互(agent 中间思考、工具调用过程可见);天然适配 CLI 的 stdin/stdout 模型
|
|||
|
|
- 缺点:dsh 实例侧需新增 WS 客户端能力(现有只做 HTTP);连接管理更复杂
|
|||
|
|
|
|||
|
|
**C. MCP(Model Context Protocol)**
|
|||
|
|
- 优点:Anthropic 开放标准(2024.11 发布,2025.12 移交 Linux Foundation),已有大量开源实现;Claude Code / Cursor / VS Code / Gemini CLI 等已支持或正在支持;标准化资源发现 + 工具调用 + 提示模板
|
|||
|
|
- 缺点:MCP 是「agent 作为 server 暴露工具」的协议,不是「agent 作为 agent 跑」的协议——方向不完全匹配;标准化程度仍在快速演进(2025.10 三大平台才统一)
|
|||
|
|
|
|||
|
|
**倾向 A 起步**:最小改动跑通链路,后续按 agent 生态收敛情况再升级到 B 或 C。
|
|||
|
|
|
|||
|
|
### D2:agent 适配层实现位置
|
|||
|
|
|
|||
|
|
**A. 桌面客户端内嵌**(推荐)
|
|||
|
|
- agent 适配层作为桌面客户端的一个模块,与 relay client 同进程
|
|||
|
|
- 优点:复用 relay 连接;agent 进程由客户端管理(启停/崩溃恢复)
|
|||
|
|
- 缺点:桌面客户端需扩展(目前是纯文件管理 + 登录)
|
|||
|
|
|
|||
|
|
**B. 独立 sidecar 进程**
|
|||
|
|
- agent 适配层作为独立进程跑,客户端只负责拉起它
|
|||
|
|
- 优点:解耦,适配层崩溃不影响客户端
|
|||
|
|
- 缺点:多一层进程管理
|
|||
|
|
|
|||
|
|
**倾向 A**:桌面客户端本来就在用户电脑上,内嵌适配层最自然。
|
|||
|
|
|
|||
|
|
### D3:agent 进程管理
|
|||
|
|
|
|||
|
|
用户启动 agent 的方式:
|
|||
|
|
|
|||
|
|
**A. 客户端 UI 一键启动**:客户端界面提供「启动 Agent」按钮,用户选 agent 类型 + 模型,客户端拉起 agent 进程并绑定端口
|
|||
|
|
**B. 用户自行启动**:用户自己在终端跑 agent(如 `claude code --port 8080`),客户端只负责把那个端口暴露到覆盖网络
|
|||
|
|
|
|||
|
|
**倾向 B 起步**:最小改动,用户自主控制 agent;后续再做 A。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## §5 步骤(建议分三阶段)
|
|||
|
|
|
|||
|
|
### 阶段 1:最小链路打通(MVP)
|
|||
|
|
|
|||
|
|
| 步骤 | 内容 | 产出 |
|
|||
|
|
|---|---|---|
|
|||
|
|
| 1.1 | 桌面客户端加 agent 适配层:监听本地 HTTP 端口,收到请求 → spawn agent CLI → stdin 投递 → stdout 回传 | `src/desktop/agent-bridge.ts` |
|
|||
|
|
| 1.2 | 客户端启动时把 agent 端口注册到 relay(类似 worker 注册实例端口) | 复用 `RelayClient` 的 `ports` 白名单 |
|
|||
|
|
| 1.3 | dsh 实例侧加 agent provider 调用分支:检测到 `kind=agent` 的凭据 → 经 dialer 拨到设备 hostId:agentPort → HTTP 请求/响应 | `src/supervisor/` 新增 agent-call 分支 |
|
|||
|
|
| 1.4 | 端到端测试:浏览器 chat → dsh 实例 → dialer → 客户端 agent 适配层 → agent CLI → 回传 | 手动验收 |
|
|||
|
|
|
|||
|
|
### 阶段 2:管理面 + 多 agent 类型
|
|||
|
|
|
|||
|
|
| 步骤 | 内容 | 产出 |
|
|||
|
|
|---|---|---|
|
|||
|
|
| 2.1 | credential_vault 加 `kind` 列(`model` / `agent`),agent 类型存设备 hostId + 端口而非 API key | DB 迁移 v14 |
|
|||
|
|
| 2.2 | 管理面 UI:agent provider 配置页(选设备 + 填端口 + 选 agent 类型) | `portal.html` 新增 section |
|
|||
|
|
| 2.3 | 多 agent 类型适配:Claude Code / Aider / Gemini CLI 各自的启动参数 + stdin/stdout 格式适配 | 适配层配置文件 |
|
|||
|
|
| 2.4 | 审计日志:agent 调用记录(时间 / 用户 / agent 类型 / 设备) | `audit_log` |
|
|||
|
|
|
|||
|
|
### 阶段 3:实时交互 + MCP(按生态收敛情况排期)
|
|||
|
|
|
|||
|
|
| 步骤 | 内容 | 产出 |
|
|||
|
|
|---|---|---|
|
|||
|
|
| 3.1 | 适配层升级到 WebSocket(PTY over WS),dsh 实例侧 WS 客户端 | 支持实时中间输出 |
|
|||
|
|
| 3.2 | 评估 MCP 接入:如果 agent 生态收敛到 MCP 标准,适配层改为 MCP client | 跟随生态 |
|
|||
|
|
| 3.3 | 客户端 UI 一键启动 agent(D3-A) | 桌面客户端新功能 |
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## §6 验收
|
|||
|
|
|
|||
|
|
### 阶段 1 验收
|
|||
|
|
|
|||
|
|
1. 用户在桌面客户端登录(`kind=desktop` 会话),客户端 relay 连接 up
|
|||
|
|
2. 用户在本地终端启动 agent CLI(如 `aider --port 9090`)
|
|||
|
|
3. 客户端 agent 适配层监听 9090,并注册到 relay
|
|||
|
|
4. 用户在浏览器 chat 里发消息,dsh 实例经 dialer 拨到客户端 9090
|
|||
|
|
5. agent 处理消息,结果回传浏览器 chat
|
|||
|
|
6. dsh 实例同时仍可正常调模型 API(两条路径并存)
|
|||
|
|
|
|||
|
|
### 阶段 2 验收
|
|||
|
|
|
|||
|
|
7. 管理面可配置 agent provider(选设备 + 填端口)
|
|||
|
|
8. 多种 agent 类型可切换(Claude Code / Aider / Gemini CLI)
|
|||
|
|
9. agent 调用有审计日志
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## §7 回滚
|
|||
|
|
|
|||
|
|
| 场景 | 回滚动作 |
|
|||
|
|
|---|---|
|
|||
|
|
| agent 适配层出问题 | 客户端停掉 agent 适配层进程;dsh 实例侧回退到只调模型 API(agent provider 不启用即可) |
|
|||
|
|
| DB 迁移 v14 出问题 | 回滚迁移(删 `kind` 列);credential_vault 退回只有 model 类型 |
|
|||
|
|
| 覆盖网络拨号失败 | 不影响模型 API 路径;agent 不可用但 dsh 实例正常 |
|
|||
|
|
|
|||
|
|
**核心安全约束**:agent provider 的 endpoint **恒为覆盖网络内的 hostId**,不接受公网地址(与 relay client 的「目标恒为 127.0.0.1」同纪律)—— 防止把 dsh 实例变成任意公网请求转发器。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## §8 技术附录
|
|||
|
|
|
|||
|
|
### 8.1 已查证的关键代码位置
|
|||
|
|
|
|||
|
|
| 文件 | 关键行 | 内容 |
|
|||
|
|
|---|---|---|
|
|||
|
|
| `src/net/relay/dialer.ts` | L9-17 | dialer 拨号机制:Manager 侧预绑口池,有连接 → `client.openStream(hostId, port)` → mux 流对接 |
|
|||
|
|
| `src/net/relay/client.ts` | L4-14 | relay client 安全模型:端口白名单 + 目标恒为 127.0.0.1 |
|
|||
|
|
| `src/net/relay/network.ts` | L17 | 用户网 `u:<userId>`,设备与实例同网 |
|
|||
|
|
| `src/net/relay/device-grant.ts` | L18 | `desktop` 设备:私钥本机生成、公钥上送 |
|
|||
|
|
| `src/web/routes/auth.ts` | L321-343 | 序47 S1:多端登录不驱逐旧会话,超限淘汰最旧 |
|
|||
|
|
| `src/web/routes/sessions.ts` | L59-72 | 会话列表 API(含 kind 标签) |
|
|||
|
|
| `src/db/types.ts` | L158-183 | CredentialKey 类型(route / baseUrl / api / models) |
|
|||
|
|
| `src/db/schema.ts` | L97-104 | credential_vault 表结构 |
|
|||
|
|
| `src/config.ts` | L383 | `DEFAULT_MAX_SESSIONS_PER_USER = 20` |
|
|||
|
|
|
|||
|
|
### 8.2 MCP 生态现状(2026-09 查证)
|
|||
|
|
|
|||
|
|
- MCP(Model Context Protocol)由 Anthropic 于 2024.11 发布,2025.12 移交 Linux Foundation
|
|||
|
|
- 已有开源实现:5ire(Electron 桌面 GUI)、ChatMCP(Flutter 桌面)、Goose(Rust CLI agent)、HyperChat
|
|||
|
|
- 三大 CLI 平台(Google Gemini CLI / OpenAI / Anthropic Claude Code)已基于 MCP 构建插件生态
|
|||
|
|
- MCP 定义 client-server 架构,JSON-RPC 2.0 over stdio 或 HTTP+SSE
|
|||
|
|
- 核心概念:Resources(数据可读)、Tools(函数可执行)、Prompts(模板)
|
|||
|
|
- 安全注意:2025.06 发现约 2000 个 MCP server 暴露无认证;spec 已加 OAuth 2.0 + RFC 8707
|
|||
|
|
|
|||
|
|
### 8.3 与之前讨论的路径对比
|
|||
|
|
|
|||
|
|
| 路径 | 评估 |
|
|||
|
|
|---|---|
|
|||
|
|
| 在 dsh 沙箱内跑 agent CLI | ❌ 碰红线(不改官方 dsh 主程序);沙箱封 loopback + 资源限;无终端层 |
|
|||
|
|
| 平台侧新增 agent runner 实例类型 | ⚠️ 架构级改造,工作量大;用户需公网服务器 |
|
|||
|
|
| **桌面客户端集成 agent(本方案)** | ✅ 覆盖网络已就位;agent 在用户侧跑不受沙箱限制;改动量=适配层 |
|