feat: dual execution model (SSH CLI + HTTP pull)
- 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
This commit is contained in:
parent
1bc7580ecc
commit
e39a16498c
34 changed files with 2541 additions and 1555 deletions
107
openspec/changes/adapter-cross-machine-revision/design.md
Normal file
107
openspec/changes/adapter-cross-machine-revision/design.md
Normal file
|
|
@ -0,0 +1,107 @@
|
|||
## Context
|
||||
|
||||
当前 adapter interface 基于 spawn 本地进程模式,无法满足跨机协同的核心目标。实际使用中暴露了通知机制不可靠的问题(Codex 完成任务后 Jeeves 收不到通知)。
|
||||
|
||||
核心认知转变:
|
||||
- **Orchestrator 不调用 Agent,Agent 调用 Orchestrator**(pull 模型)
|
||||
- **Git/Forgejo 是状态追踪的 source of truth**(PR 生命周期 = 任务生命周期)
|
||||
- **通知 = Git 事件**(push → 进度信号,PR opened → 完成通知,PR merged → receipt 验证)
|
||||
|
||||
## Goals / Non-Goals
|
||||
|
||||
**Goals:**
|
||||
- Agent 通过 HTTP API 主动拉取任务、更新状态、提交 receipt(任何机器、任何语言)
|
||||
- 利用 Forgejo PR webhook 作为可靠的状态追踪和通知机制
|
||||
- 消除"Agent 完成但无人知道"的问题
|
||||
- Agent client 可以是任何语言实现(curl 就能交互)
|
||||
|
||||
**Non-Goals:**
|
||||
- 不实现 Agent 侧的 client SDK(Agent 自己决定用什么语言/方式调用 HTTP API)
|
||||
- 不实现 Orchestrator → Agent 的主动推送(pull 模型足够,Phase 2 可加 SSE)
|
||||
- 不修改 Forgejo webhook 已有的实现(复用现有 `POST /api/v1/webhooks/forgejo`)
|
||||
|
||||
## Decisions
|
||||
|
||||
### Decision 1: Pull 模型(Agent 主动拉取任务)
|
||||
|
||||
**选择**: Agent 通过 `POST /api/v1/tasks/dequeue` 主动拉取
|
||||
|
||||
**理由**:
|
||||
- 跨机场景下 Orchestrator 无法主动连接 Agent(防火墙、NAT、离线)
|
||||
- Agent 最清楚自己什么时候有空
|
||||
- Pull 模型天然负载均衡——空闲 Agent 自然拉更多任务
|
||||
- 无需长连接、无需消息队列
|
||||
|
||||
**替代方案**:
|
||||
- Push 模型(Orchestrator 推送):需要 Agent 暴露端点,复杂度高
|
||||
- 消息队列(NATS/Redis):增加基础设施依赖
|
||||
|
||||
### Decision 2: Forgejo PR lifecycle 作为通知机制
|
||||
|
||||
**选择**: 利用 Git 事件(push → PR opened → PR merged)作为任务状态追踪
|
||||
|
||||
**理由**:
|
||||
- Forgejo webhook 已经实现,可靠性由 Forgejo 保证
|
||||
- PR 本身就是 code review 流程——天然对应任务的"完成→验证"流程
|
||||
- 解决了实际遇到的通知丢失问题:即使 Agent 直接通知失败,Forgejo webhook 仍然会触发
|
||||
- PR merged = 自动 receipt 验证(PR 存在且被 merge = 代码确实被接受)
|
||||
|
||||
**替代方案**:
|
||||
- SSE/WebSocket 推送:需要保持长连接,跨网络不可靠
|
||||
- Agent 回调 URL:需要 Agent 暴露端点
|
||||
- 轮询:可行但延迟高,且不解决"Agent 完成后通知谁"的问题
|
||||
|
||||
### Decision 3: Registry token 认证
|
||||
|
||||
**选择**: Agent 注册后获得 token,后续请求需携带
|
||||
|
||||
**理由**:
|
||||
- 轻量级,不需要 OAuth 或 JWT
|
||||
- 防止未授权的 Agent 领取任务
|
||||
- token 在重新注册时刷新
|
||||
|
||||
## Risks / Trade-offs
|
||||
|
||||
- **[Pull 延迟] Agent 需要定期 dequeue 轮询** → Agent 可以在 heartbeat 周期内顺便 dequeue,不增加额外开销
|
||||
- **[PR 必需] 强制要求 Agent 创建 PR** → 非 PR 任务通过 `/complete` 端点完成,两条路径在 receipt 验证层汇合
|
||||
- **[Forgejo 单点] Forgejo 挂了通知就断了** → Forgejo 本身是 Git source of truth,挂了整个流程都停,可接受
|
||||
- **[死循环] Review 循环可能无限** → max_retries 限制 + review_count 跟踪
|
||||
|
||||
## Key Design Principles (from community best practices)
|
||||
|
||||
基于 ChatGPT 讨论和社区最佳实践的几个核心原则:
|
||||
|
||||
1. **Agent 是纯函数 worker**:输入 task + artifact,输出 artifact + state change。不保留跨任务状态。
|
||||
2. **状态机驱动,不对话驱动**:所有 Agent 只对共享状态(SQLite + Forgejo)读写,由 Orchestrator loop 推进流程
|
||||
3. **结构化 handoff**:Agent 之间不传 chat history,只传结构化 artifact(receipt、plan、review)
|
||||
4. **Git worktree 隔离**:每个 task 独立分支,避免并发冲突
|
||||
5. **Deterministic verification**:不依赖 Agent 自我判断,用 `cargo test` / `npm test` 等确定性验证
|
||||
6. **80/20 原则**:80% 自动运行,20% 人类介入(失败、架构决策、优先级调整)
|
||||
7. **外部调度 + 内部自治**:agent-fleet 只管理任务状态和 artifact 流转,Agent 的执行 runtime(hooks、compaction、sandbox、tool loop、session 管理)由 Agent 自己负责。agent-fleet 是 Kubernetes,Agent 是 Pod。
|
||||
8. **不替代 Agent runtime**:Claude Code / Codex / OpenCode 的价值在于它们的 runtime,不是模型本身。agent-fleet 不重新实现 tool loop、context compaction、patch management 等。
|
||||
|
||||
基于 ChatGPT 讨论和社区最佳实践的几个核心原则:
|
||||
|
||||
1. **Agent 是纯函数 worker**:输入 task + artifact,输出 artifact + state change。不保留跨任务状态。
|
||||
2. **状态机驱动,不对话驱动**:所有 Agent 只对共享状态(SQLite + Forgejo)读写,由 Orchestrator loop 推进流程
|
||||
3. **结构化 handoff**:Agent 之间不传 chat history,只传结构化 artifact(receipt、plan、review)
|
||||
4. **Git worktree 隔离**:每个 task 独立分支,避免并发冲突
|
||||
5. **Deterministic verification**:不依赖 Agent 自我判断,用 `cargo test` / `npm test` 等确定性验证
|
||||
6. **80/20 原则**:80% 自动运行,20% 人类介入(失败、架构决策、优先级调整)
|
||||
|
||||
## Migration Plan
|
||||
|
||||
1. 新增 `POST /api/v1/tasks/dequeue` 端点
|
||||
2. 新增 `POST /api/v1/tasks/{task_id}/status` 端点
|
||||
3. 新增 `GET /api/v1/tasks/{task_id}` 端点
|
||||
4. 扩展 Forgejo webhook 处理:支持 `pull_request` 和 `push` 事件
|
||||
5. 重写 `src/adapters/mod.rs`:从 AgentAdapter trait 改为 Agent Protocol 描述文档
|
||||
6. 新增 token 认证中间件
|
||||
7. 更新测试
|
||||
|
||||
## Open Questions
|
||||
|
||||
_(resolved — 见下方)_
|
||||
|
||||
- ~~非 PR 任务(research、review)如何触发完成通知?~~ → 使用 `POST /api/v1/tasks/{id}/complete` + receipt,与 PR 路径在 receipt 验证层汇合
|
||||
- ~~Token 认证是否需要在 Phase 1 实现?~~ → 必须在 Phase 1 实现,否则无法安全对接远程 Agent
|
||||
Loading…
Add table
Add a link
Reference in a new issue