agent-fleet/openspec/changes/adapter-cross-machine-revision/design.md
Zer4tul e39a16498c 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
2026-05-12 14:07:56 +08:00

107 lines
5.8 KiB
Markdown
Raw Permalink 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.

## Context
当前 adapter interface 基于 spawn 本地进程模式无法满足跨机协同的核心目标。实际使用中暴露了通知机制不可靠的问题Codex 完成任务后 Jeeves 收不到通知)。
核心认知转变:
- **Orchestrator 不调用 AgentAgent 调用 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 SDKAgent 自己决定用什么语言/方式调用 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只传结构化 artifactreceipt、plan、review
4. **Git worktree 隔离**:每个 task 独立分支,避免并发冲突
5. **Deterministic verification**:不依赖 Agent 自我判断,用 `cargo test` / `npm test` 等确定性验证
6. **80/20 原则**80% 自动运行20% 人类介入(失败、架构决策、优先级调整)
7. **外部调度 + 内部自治**agent-fleet 只管理任务状态和 artifact 流转Agent 的执行 runtimehooks、compaction、sandbox、tool loop、session 管理)由 Agent 自己负责。agent-fleet 是 KubernetesAgent 是 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只传结构化 artifactreceipt、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