# 规划方案 · 通过桌面客户端接入 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:` 网络,用户设备与自己的实例同网 | `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:`,设备与实例同网 | | `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 在用户侧跑不受沙箱限制;改动量=适配层 |