115 lines
7.2 KiB
Markdown
115 lines
7.2 KiB
Markdown
# v0.1 agentrun-mgr 服务规格
|
||
|
||
`agentrun-mgr` 是 AgentRun `v0.1` 的长驻管理服务。它是公共 RESTful API、durable facts、tenant policy boundary、runner claim、event append 和 terminal status 的 authority;业务客户端、CLI 和 runner 都不能绕过它直接写 Postgres。
|
||
|
||
## 在系统中的职责划分
|
||
|
||
- 提供 Manager 公共 API:创建和查询 run、提交 command、分页读取 events、查询 backend capability。
|
||
- 提供 Runner 私有 API:runner register、claim run、lease heartbeat、poll commands、append events、ack command、上报 status。
|
||
- 校验并持久化 `tenantId`、`projectId`、`workspaceRef`、`providerId`、`backendProfile`、`executionPolicy` 和 `traceSink`。
|
||
- 执行最小 tenant policy boundary:只做 schema、allowlist、idempotency、secret scope 和 executionPolicy 范围检查;不内建 UniDesk/HWLAB 的业务授权。
|
||
- 使用 Postgres 保存 runs、commands、events、runners、backends、leases 和 migration ledger。
|
||
- 输出结构化 health/readiness、failureKind、redacted SecretRef 和 trace correlation。
|
||
|
||
## 内部架构
|
||
|
||
`agentrun-mgr` 运行在 `agentrun-v01` namespace,长驻 Deployment/Service 名称使用 `agentrun-mgr`。`v0.1` 自研服务实现优先使用 Bun + TypeScript;具体 HTTP 框架不是规格边界,但源码必须保持可被 Bun 运行、测试和打包。服务必须保持以下边界:
|
||
|
||
- HTTP JSON API 是稳定跨服务边界;不使用 SSE、WebSocket、long-polling 或长同步 `turn` 请求作为 `v0.1` 必备能力。
|
||
- Postgres adapter 是唯一 durable store adapter;file、sqlite、JSONL 或内存状态只能用于自测试。
|
||
- Migration 必须在 readiness 前完成或显式 fail fast,不能以空 schema 静默启动。
|
||
- Provider credential、Codex auth/config、Postgres DSN 明文不进数据库、event、trace、日志或 CLI 输出。
|
||
- Manager 可以保存 SecretRef 和 credential source reference,但不得读取 provider Secret 值后存库。
|
||
|
||
## API 接口说明
|
||
|
||
公共 API 的 `v0.1` 范围:
|
||
|
||
```http
|
||
GET /health
|
||
GET /health/live
|
||
GET /health/readiness
|
||
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 私有 API 的 `v0.1` 范围:
|
||
|
||
```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
|
||
```
|
||
|
||
所有 API 成功和失败响应都必须是 JSON。失败响应至少包含 `failureKind`、`message` 和 trace correlation;不得出现空 stdout/空 response 被误判为成功的情况。
|
||
|
||
## Run 与 Command 合同
|
||
|
||
`POST /api/v1/runs` 必须持久化以下字段:
|
||
|
||
| 字段 | v0.1 规则 |
|
||
| --- | --- |
|
||
| `tenantId` | 必填,只做 allowlist/schema 校验,默认候选为 `unidesk`、`hwlab`。 |
|
||
| `projectId` | 必填,例如 `pikasTech/unidesk`、`pikasTech/HWLAB`。 |
|
||
| `workspaceRef` | 必填,描述 source/worktree/workspace,不由 runner 猜测。 |
|
||
| `providerId` | 必填,例如 `G14`、`D601`;只表示目标 provider,不直接授予业务权限。 |
|
||
| `backendProfile` | 必填,`v0.1` 默认真实 backend 为 `codex`。 |
|
||
| `executionPolicy` | 必填或由 manager 显式补齐默认值,至少包含 sandbox、approval、timeout、network 和 secretScope。 |
|
||
| `traceSink` | 字段必须存在;可以为 `null` 或显式 sink。 |
|
||
|
||
`POST /api/v1/runs/:runId/commands` 必须支持 idempotency key。相同 key 且 payload hash 相同应返回既有 command;相同 key 但 payload hash 不同必须结构化失败。
|
||
|
||
## Tenant Policy Boundary
|
||
|
||
`v0.1` 不实现独立 policy engine。Manager 只做基础边界收敛:
|
||
|
||
- 校验 tenant/project/provider/backend 是否在 `v0.1` 允许集合内。
|
||
- 校验 workspaceRef 形态存在且与 tenant 请求一致;不替 tenant 判断某个 repo 操作是否业务授权。
|
||
- 校验 executionPolicy 不扩大 sandbox、network、approval、timeout 和 secretScope。
|
||
- 校验 secretScope 只引用 [spec-v01-secret-distribution.md](spec-v01-secret-distribution.md) 中允许的 SecretRef。
|
||
- 对 HWLAB live device mutation、UniDesk production deploy、GitHub issue/PR 写入等业务授权,Manager 只记录字段和审计事件,不把业务规则硬编码成通用门禁。
|
||
|
||
## 最小 Observability 合同
|
||
|
||
- events append-only,单 run 内 `seq` 单调递增。
|
||
- 每个 run 必须最终出现 `terminal_status`,或保持明确 non-terminal status 并可查询 lease/heartbeat。
|
||
- failureKind 至少能区分 `schema-invalid`、`tenant-policy-denied`、`secret-unavailable`、`runner-lease-conflict`、`backend-failed`、`provider-auth-failed`、`infra-failed`、`cancelled`。
|
||
- health/readiness 必须返回 Postgres reachable、schema migration ready、SecretRef redacted 状态和 build/source metadata。
|
||
- 日志、event、trace、health 和 diagnostics 不得输出 provider credential、Codex auth/config 内容、DSN password、token 或 URL credential。
|
||
|
||
## 测试规格
|
||
|
||
### T1 Manager health/readiness
|
||
|
||
阅读 `AGENTS.md`、本文和 [spec-v01-postgres.md](spec-v01-postgres.md),然后用 RESTful API 手动测试 `agentrun-mgr` 的 `/health/live` 和 `/health/readiness`。确认响应为 JSON,包含 serviceId、Postgres readiness、migration 状态、source commit、SecretRef redacted 状态;不得输出任何 Secret value。
|
||
|
||
### T2 Run schema 与 tenant boundary
|
||
|
||
阅读本文和 [spec-v01-services.md](spec-v01-services.md),然后调用 `POST /api/v1/runs` 创建包含 tenant/project/workspace/provider/backend/execution/trace 字段的 run。确认缺失字段、非法 tenant、非法 backend 或扩大 secretScope 都返回结构化 failureKind,合法请求持久化后可用 `GET /api/v1/runs/:runId` 查询。
|
||
|
||
### T3 Command idempotency
|
||
|
||
阅读本文,然后对同一个 run 使用相同 idempotency key 提交相同 command 两次,再提交 payload hash 不同的第三次。确认前两次返回同一个 command,第三次结构化失败,且所有响应为 JSON。
|
||
|
||
### T4 Runner claim 与 event pagination
|
||
|
||
阅读本文和 [spec-v01-agentrun-runner.md](spec-v01-agentrun-runner.md),然后让两个真实 runner 尝试 claim 同一个 run。确认只有一个 owner 成功,另一个返回 `runner-lease-conflict` 或等价 failureKind;随后分页读取 events,确认 `seq` 单调、不重复、不丢失。
|
||
|
||
## 规格的实现情况
|
||
|
||
| 规格项 | 状态 | 说明 |
|
||
| --- | --- | --- |
|
||
| `agentrun-mgr` 服务规格 | 已定义 | 本文为 v0.1 manager 权威。 |
|
||
| Manager REST API | 部分实现 | 内存 self-test server 已覆盖公共 run/command/event/backends 和 runner register/claim/lease/poll/ack/event/status 骨架;生产 Postgres durable adapter 尚未接入。 |
|
||
| Tenant policy boundary | 已定义/未实现 | v0.1 只做最小 schema/allowlist/secretScope 边界。 |
|
||
| Postgres durable adapter | 未实现 | 见 [spec-v01-postgres.md](spec-v01-postgres.md)。 |
|
||
| Observability 最小合同 | 部分实现 | 内存路径已输出非空 JSON、runner claim/lease/backend/terminal events、failureKind 和 Secret redaction 自测试;持久化和集群日志联调待补齐。 |
|