Files
pikasTech-agentrun/docs/reference/architecture.md
T
2026-05-29 10:35:33 +08:00

237 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.
# AgentRun 架构参考
AgentRun 是面向 UniDesk 与 HWLAB 的共享 Agent 执行面。它不是 UniDesk Code Queue 的改名,也不能默认替换现有 Code Queue 行为。Code Queue 仍是当前 UniDesk 任务队列;AgentRun 是新的基础设施线,重点是 Agent run 生命周期、runner 隔离和可插拔执行 backend。
## 产品边界
AgentRun 负责通用执行基础设施:
- 创建和跟踪 run
- 接收 `turn``steer``interrupt``resume` 等 durable command
- 将 run 分配给短生命周期 runner
- 归一化 backend event、stdout/stderr、assistant message、tool call 和 terminal status
- 管理 lease、heartbeat、基础设施恢复导致的 retry 语义和 run 可观测性;
- 注册 backend capability,并定义 credential 注入边界。
UniDesk 与 HWLAB 是 tenant/client。UniDesk 负责平台入口、provider 清单、CLI/frontend 集成和现有 Code Queue 兼容。HWLAB 负责实验室任务 policy、设备/硬件语义、operation/audit/evidence 模型和 HWLAB workspace 规则。AgentRun 不判断某个 HWLAB live device mutation 是否被授权,也不判断某个 UniDesk production deployment 是否允许执行;它只执行 tenant policy 已授权的 run。
每个 run 都必须显式携带隔离字段:
- `tenantId`,例如 `unidesk``hwlab`
- `projectId`,例如 `pikasTech/unidesk``pikasTech/HWLAB`
- `workspaceRef`,用于定位 source/worktree/workspace
- `providerId`,例如 `G14``D601`
- `backendProfile`,例如 `codex``opencode``claudecode``host-native``windows-native`
- `executionPolicy`,包含 sandbox、approval、timeout、network 和 secret scope
- `traceSink`,说明标准化 event 镜像到哪里。
## 服务形态
AgentRun 应构建为小型服务族:
```text
agentrun-mgr
公共 RESTful API、durable facts、tenant/policy/idempotency 检查
agentrun-runner
短生命周期 per-run 或 per-attempt executorclaim 一个 run,连接一个 backend,写回 events/status
agentrun-backend-*
Codex、Claude Code、OpenCode、host-native 或 Windows-native 执行适配器
agentrun-scheduler
后续自动 dispatcher;扫描 pending runs,选择 backend/profile/capacity,创建 runner Jobs
```
Manager 是稳定 API 和审计点。Runner 是执行者,不应成为业务客户端直接调用的公共 API。MVP 阶段 operator 可以人工启动 runner 进程或 Kubernetes Job,但 runner 仍必须从 `agentrun-mgr` claim run,并把所有事实写回 manager。
Backend adapter 隐藏具体工具协议。Codex stdio JSON-RPC、OpenCode JSON events、Claude Code、host-native process 和 Windows-native execution 可以使用不同内部协议,但 AgentRun 公共 API 必须保持稳定且与 backend 无关。
## v0.1 实现技术栈
AgentRun `v0.1` 自研 runtime 优先使用 Bun + TypeScriptmanager、runner、backend adapter、Codex backend、CLI 和后续 scheduler 都按这一技术栈实现。`scripts/agentrun-cli.ts` 是官方 CLI 入口;复杂 CLI 逻辑进入 `scripts/src/`,服务和 runner 逻辑进入 `src/`。YAML manifest、Tekton/Argo CD 配置、Postgres 和 Kubernetes 仍按各自原生生态管理。
Codex backend 固定采用 Codex CLI app-server JSON-RPC over stdio。实现必须启动受控 `codex app-server --listen stdio://`,执行 `initialize``thread/start``thread/resume``turn/start`,并把 stdout/stderr、notification、tool lifecycle、assistant output 和 terminal/error 状态归一化为 AgentRun events。直接 Responses HTTP、OpenAI SDK wrapper、`codex exec` 一次性输出或文本 fallback 不能作为 `v0.1` Codex backend 的正式执行路径。
实现参考优先级:UniDesk Code Queue 的 `src/components/microservices/code-queue/src/code-agent/codex.ts``common.ts`,以及 HWLAB v0.2 的 `internal/cloud/codex-stdio-session.mjs``scripts/code-agent-chat-smoke.mjs`。AgentRun 复用其协议、trace、redaction、Secret projection 和 failure 分类经验,但不复制 tenant 业务规则、环境专用路径或密钥材料。
## MVP 顺序
AgentRun 必须按纵向切片推进,不要一开始大规模并行开发。
### M0: 契约骨架
只定义最小资源模型和状态机:
- `Run`
- `Command`
- `Event`
- `Runner`
- `Backend`
第一切片只要求 `turn``interrupt``status` 和分页 `events`。不要一开始就做 `steer``resume`、judge/retry、UI、多 backend 路由或自动调度。
### M1: 最小 Runner 加一个 Backend
第一份可执行证明不依赖 manager 或 scheduler。Runner 读取本地 run spec,调用一个 backend,并输出标准化 events。
验收标准:
- 一个 `turn` 能通过 backend 执行;
- assistant/output/error events 被归一化;
- terminal status 被写出;
- interrupt 至少有 durable cancellation 路径,backend 支持时再传播到真实进程中断。
第一个 backend 固定选择 Codex app-server stdio,用最窄实现证明真实 Agent 原语。如果 Codex 上游或凭据短暂不可用,可以用 controlled process 或 fake app-server 做自测试,但不能替代综合联调,也不能据此宣称 `v0.1` backend 通过。
### M2: Manager 加 Runner Claim
加入 `agentrun-mgr` 作为 durable fact store 和公共 API。Client 创建 runoperator 或 CLI 用 run id 人工启动 runnerrunner claim、poll commands、append events、heartbeat 并退出。
验收标准:
- run create/query 是 durable 的;
- runner claim 幂等,并拒绝双 owner
- events 是 append-only,并按 seq 分页;
- command ack state 可见;
- heartbeat expiration 可观察。
### M3: 手动 Dispatch CLI
增加 CLI,为指定 run 启动本地 runner process 或 Kubernetes Job。这是 manual dispatch,不是 manager 侧同步编排。Manager 仍拥有事实,runner 仍拥有执行。
验收标准:
- CLI 快速返回 JSON
- job/process identity 和 log path 可见;
- run status 可从 manager 轮询;
- runner 启动失败被报告为基础设施失败,不能静默写成任务成功。
### M4: 自动 Scheduler
只有 M1-M3 稳定后才加入 `agentrun-scheduler`。Scheduler 扫描 pending runs,应用 policy/capacity/backend selection,创建 runner Jobs,并处理 stale lease recovery。Scheduler 不直接执行 backend。
验收标准:
- pending run 自动变为 running
- scheduler restart 不影响已经运行的 runner
- stale lease recovery 留下显式 audit event
- scheduler rollout 不等同于 active run failure。
### M5: Tenant Canary 集成
核心生命周期证明后,再接入 UniDesk 和 HWLAB canary
- UniDesk 可以新增 `agentrun` CLI/API route,同时保持现有 Code Queue 不变。
- HWLAB 可以把一个窄范围 Code Agent canary 路由到 AgentRun。
- 每个 run 都必须显式带 tenant policy、workspace、secret scope 和 trace sink。
## RESTful MVP 契约
MVP 只使用短 RESTful HTTP/JSON 请求。长时间 Agent 工作用 durable command resource、run status 和分页 event polling 表示。不要让一个 HTTP 请求等待完整模型 turn。
Manager 公共 API
```http
POST /api/v1/runs
GET /api/v1/runs/:runId
GET /api/v1/runs/:runId/events?afterSeq=0&limit=100
POST /api/v1/runs/:runId/commands
GET /api/v1/runs/:runId/commands/:commandId
GET /api/v1/backends
```
Runner 到 manager 的私有 API
```http
POST /api/v1/runners/register
POST /api/v1/runs/:runId/claim
PATCH /api/v1/runs/:runId/lease
GET /api/v1/runs/:runId/commands?afterSeq=0&limit=20
POST /api/v1/runs/:runId/events
PATCH /api/v1/runs/:runId/status
POST /api/v1/commands/:commandId/ack
```
Runner inbound API 应保持本地/私有且最小:
```http
GET /health
GET /debug/status
```
不要依赖客户端调用短生命周期 runner Pod 地址。该方式在 Job、namespace、host-native backend 和重启场景下都会变脆。
## Command 状态
Command 是 durable resource。`turn``steer``interrupt``resume` 不能实现为 client 到 runner 的同步进程调用。
初始 command 状态机:
```text
accepted -> delivered -> confirmed
accepted -> delivered -> failed
accepted -> expired
```
所有 command 写入都应支持 idempotency key。相同 idempotency key 且 payload hash 相同的重复请求返回既有 command;相同 key 但 payload hash 不同必须显式失败。
## Event 模型
Event 是 append-only,并按 seq 分页:
- `seq` 在单个 run 内单调递增。
- `eventId``(runId, seq)` 支持幂等去重。
- `GET /events?afterSeq=N&limit=M` 是第一阶段观察 API。
- 后续 SSE 可以流式传输相同 event resource,但不能替代 REST polling contract。
最小 event 类别:
- `system`
- `assistant_message`
- `tool_call`
- `command_output`
- `diff`
- `error`
- `backend_status`
- `terminal_status`
## 数据模型方向
`v0.1` 使用 Postgres 作为唯一 durable storefile、sqlite、JSONL 或 Pod 本地目录只能用于临时测试或日志,不作为运行面事实来源。第一版实现可以使用紧凑 schema,但不应把所有事实都隐藏在一个 JSON blob 中。稳定方向是:
- `agentrun_schema_migrations`migration id、checksum 和 applied timestamp
- `agentrun_runs`run identity、tenant/project/workspace/backend policy、status 和 timestamps
- `agentrun_commands`command type、idempotency key、payload hash、state 和 ack timestamps
- `agentrun_events`:按 run 和 seq 索引的 append-only event records
- `agentrun_runners`registered runner identity、placement 和 heartbeat
- `agentrun_backends`backend profile、capabilities、capacity 和 health
- `agentrun_leases`:当前 ownership 和 expiry。
Postgres DSN、provider credential 和未来 tenant credential 的分发边界见 [spec-v01-secret-distribution.md](spec-v01-secret-distribution.md)Codex 测试凭据通过 Kubernetes Secret projection 注入 `~/.codex/auth.json``~/.codex/config.toml`source、GitOps、event、trace、日志和 CLI 输出都不得保存 Secret 明文。
## 部署方向
AgentRun 从 `v0.1` 开始按版本 lane 滚动,废弃 `dev/prod` 管理口径。`v0.1` 的固定 source workspace 是 `G14:/root/agentrun-v01`,固定 source branch 是 `v0.1`,固定运行目标是 G14 原生 k3s namespace `agentrun-v01`。后续 `v0.2``v0.3` 必须拥有自己的 branch、workspace、namespace、GitOps branch、runtime path 和发布验收。
Control-plane service 应是长驻服务;runner 应是短生命周期 Job 或受控 host-native process。Backend adapter 可以作为 pod 或 host-native service 运行,但必须通过 AgentRun 注册 capability 和 health,不能通过临时地址被 ad hoc 调用。
广泛 tenant 使用前,需要先设计 namespace isolation、RBAC、Secret scope、NetworkPolicy 和 ResourceQuota。独立 cluster 是后续成熟选项;第一版应优先在 `agentrun-v01` namespace 内证明服务,除非出现明确隔离 blocker。`agentrun_dev``agentrun_prod` 不再作为当前架构规格或验收目标。
## MVP 非目标
第一版 MVP 不包含:
- 迁移 UniDesk Code Queue
- 全局替换 HWLAB Code Agent
- 多 backend 路由;
- 最小诊断之外的 UI
- judge/retry 自动化;
- 自动扩缩容;
- 跨集群调度;
- SSE/WebSocket 流式输出;
- 完整权限系统;
- production rollout 自动化。
第一目标是稳定跑通一条纵向 run 生命周期:create run、人工启动 runner、执行一个 backend turn、append events、观察 final status,并能发出可见的 interrupt/cancel command。