Files
dsh_ai1net_server/交接单/规划方案_AgentCLI接入_20260923.md
T
admin ce8e6ceed9 chore(工作区): 纳入版本控制基线(回收 411 MB 过程产物)
回收 411 MB(470 M → 58.8 M),全部经回收站,可恢复:
- 待清理/(146.2 M,含 relay 分片 128 M 与 42 项过程目录)
- tmp/(32.4 M,按接续棒命名的过程临时区)
- .workbuddy/tmp/(39.5 M)
- 4 份 workbuddy.db 冗余副本(101 M,09-23 事故的坏副本 / 抢救产物)
- tmp/im16/gw/centrifugo 二进制(63.9 M,可重下)+ 缓存残留

入库范围:常驻规则(CODEBUDDY.md / README.md / state.py)、在途接续入口与
接续包、docs/、交付物/、交接单/、归档/、scripts/、.codebuddy/、
.workbuddy/memory/;共 398 件,其中 >60 KB 的 26 件全为文档。

排除(.gitignore):tmp/、待清理/、运行态日志与缓存、*.db 与 DB 备份整目录、
打包二进制(*.tar.gz / *.tgz)、记忆修复前备份。
2026-09-24 07:51:03 +08:00

205 lines
11 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 规划方案 · 通过桌面客户端接入 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 在用户侧跑不受沙箱限制;改动量=适配层 |