## Context `adapter-cross-machine-revision` change 设计了纯 Pull 模型(Agent 主动调 HTTP API),但分析后发现 Pull 模型不是 subprocess CLI 的跨机等价——控制权、上下文传递、生命周期管理都不同。 真正的跨机等价是 **SSH + CLI**:Orchestrator 通过 SSH 在远程主机上 spawn Agent CLI,与本地 subprocess 完全一致的执行模型。 同时,HTTP Pull 对外部 Agent(OpenClaw/Jeeves、Hermes)仍有价值。因此需要双执行模型。 ## Goals / Non-Goals **Goals:** - SSH + CLI 作为主执行模式(Orchestrator 主动调度、构造上下文、控制生命周期) - HTTP API 保留给外部 Agent 自主接入 - 每种 Agent 类型定义为 CLI 模板 + 输出解析器 - 远程主机管理(SSH 连接、CLI 可用性检查) **Non-Goals:** - 不实现 Agent daemon(Phase 1 用 SSH + CLI 足够) - 不实现动态主机发现(Phase 1 静态配置) - 不实现容器化执行(不用 Docker/Kubernetes) ## Decisions ### Decision 1: SSH + CLI 是 subprocess 的跨机等价 **选择**: Orchestrator 通过 SSH 执行远程 Agent CLI **理由**: - 控制流与本地 subprocess 完全一致 - 上下文由 Orchestrator 构造,通过 CLI 参数传入 - Agent 不需要预运行,不需要 daemon - 唯一前提:SSH 免密登录 + 目标机器装了 CLI **替代方案**: - HTTP Pull:控制权反转,上下文传递难解决 - Agent daemon:复杂度高,每台机器多一个服务 - 容器化:更复杂,需要 container runtime ### Decision 2: HTTP Pull 作为补充模式 **选择**: 保留 HTTP API 给外部 Agent **理由**: - OpenClaw/Jeeves、Hermes 有自己的调度,不需要 Orchestrator 启动 - 它们只需要查询/更新任务状态 - 两种模式通过 `execution_mode` 字段区分 ### Decision 3: Adapter = CLI 模板 + 输出解析器 **选择**: 不实现 AgentAdapter trait,而是配置驱动 **理由**: - CLI 模板可以通过配置文件定义,无需编译 - 不同 Agent 的差异主要在 CLI 参数和输出格式 - 新增 Agent 类型只需要加配置,不需要写代码 ### Decision 4: 本地执行作为 SSH 的特例 **选择**: Orchestrator 所在机器的 Agent 用本地 subprocess,不经过 SSH **理由**: - 避免 SSH loopback 的开销和配置 - subprocess 是 SSH 的本地特例,逻辑统一 ## Risks / Trade-offs - **[SSH 密钥管理] 需要配置免密 SSH** → 用 SSH agent forwarding 或 deploy key,标准运维实践 - **[长时间运行] SSH 连接可能超时** → 用 `ssh -o ServerAliveInterval=60`,或改用 SSH multiplexing - **[CLI 版本差异] 不同机器可能装不同版本** → health check 时验证版本 ## Migration Plan 1. 新增 `src/execution/` 模块(SSH executor、CLI template、output parser) 2. Task 模型添加 `execution_mode`、`assigned_host` 字段 3. 新增 `[hosts]` 配置 section 4. 实现 Orchestrator dispatch loop(ssh_cli → SSH 执行,http_pull → 等待 Agent dequeue) 5. 保留并调整 HTTP API 端点(dequeue 仅限 http_pull 任务) 6. 更新测试 ## Open Questions - SSH 库选择:`ssh2` crate vs `tokio::process::Command` + 系统 `ssh` 命令? - 是否需要支持 SSH jump host(通过跳板机连接目标机器)?