- ExecutionMode enum: SshCli (orchestrator dispatches) | HttpPull (agent pulls) - SSH CLI executor: spawn remote agents via ssh + CLI template - Local subprocess as SSH special case (localhost) - HostConfig with capability matching and load-based selection - Dispatch loop: scan created tasks → select host → execute → update - CliAdapterConfig: CLI templates for Codex and Claude Code - Structured prompt construction (Issue → goal/constraints/validation) - Output parsers: Codex JSON, Claude Code JSON, raw fallback - TaskStatus::ReviewPending + review_count loop limit - Forgejo webhook: pull_request (opened→review_pending, merged→completed) - Forgejo webhook: push events (task/* branch → last_activity_at) - HTTP API: dequeue only returns http_pull tasks - HTTP API: status update only for http_pull mode - Token auth config for http_pull agents - Adapter module rewritten: AgentAdapter trait removed → config-driven CLI templates - New fields: execution_mode, assigned_host, branch_name, pr_title, last_activity_at, review_count - 30/30 tests pass
83 lines
3.2 KiB
Markdown
83 lines
3.2 KiB
Markdown
## 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(通过跳板机连接目标机器)?
|