156 lines
15 KiB
Markdown
156 lines
15 KiB
Markdown
# v0.1 HWLAB 手动调度接入规格
|
||
|
||
本文定义 AgentRun `v0.1` 面向 HWLAB v0.2 的下一阶段服务目标:不以前置自动 scheduler 为条件,而是通过 `agentrun-mgr` 的手动调度 API 为 HWLAB 提供 canary Code Agent 执行服务。实施跟踪见 [pikasTech/agentrun#31](https://github.com/pikasTech/agentrun/issues/31)。
|
||
|
||
## 在系统中的职责划分
|
||
|
||
- HWLAB `hwlab-cloud-api` 是业务 dispatcher:继续负责用户登录、session owner、device-pod 授权、Workbench `/v1/agent/chat` 合同、result/trace/cancel 对外接口和业务权限判断。
|
||
- AgentRun `agentrun-mgr` 是执行事实 authority:负责 run、command、event、runner job、backend profile、SecretRef、terminal status 和手动调度 API。
|
||
- `agentrun-runner` 是短生命周期执行者:从 manager claim run、poll command、调用 backend adapter、append events、ack command、上报 terminal status。
|
||
- HWLAB 不直接写 AgentRun Postgres、不读取 AgentRun Secret、不直接创建 Kubernetes Job;所有跨服务操作只走 AgentRun RESTful API。
|
||
- AgentRun 不内建 HWLAB device-pod/gateway 业务授权;涉及硬件、用户授权或 device lease 的判断仍由 HWLAB 自己完成。
|
||
|
||
## 非目标
|
||
|
||
- 本阶段不要求自动 scheduler、pending scan、capacity selection 或长驻调度器。
|
||
- 不改变 HWLAB 对外 `/v1/agent/chat`、`/result`、`/trace`、`/cancel` 用户合同。
|
||
- 不使用 SSE、WebSocket、long-polling 或长同步 `turn` 请求替代 durable resource 模型。
|
||
- 不把 HWLAB 的 provider Secret、device token、gateway route 或 kubeconfig 复制给业务客户端。
|
||
- 不把 mock、fixture、source-only smoke 或 dry-run 结果当作 HWLAB canary 通过证据。
|
||
|
||
## 目标调用链
|
||
|
||
```text
|
||
HWLAB Workbench
|
||
-> hwlab-cloud-api /v1/agent/chat
|
||
-> HWLAB 用户/session/device 权限判断
|
||
-> AgentRun POST /api/v1/runs
|
||
-> AgentRun POST /api/v1/runs/:runId/commands
|
||
-> AgentRun POST /api/v1/runs/:runId/runner-jobs
|
||
-> agentrun-runner claim/poll/report
|
||
-> AgentRun events/command status/terminal_status
|
||
-> hwlab-cloud-api 映射为 HWLAB result/trace
|
||
```
|
||
|
||
HWLAB 应保存 `traceId -> runId/commandId/attemptId/jobName` 映射。用户轮询 HWLAB result/trace 时,HWLAB 从 AgentRun command status 与 run events 读取进展,再转换为 HWLAB 自己的前端 schema;浏览器不直接理解 AgentRun 内部 event schema。
|
||
|
||
## HWLAB v0.2 Code Agent 能力吸收基线
|
||
|
||
AgentRun `v0.1` 承接 HWLAB v0.2 时,只吸收原有 Code Agent 的通用执行能力,不吸收 HWLAB 的用户鉴权、device-pod 授权、Workbench UI 或业务 trace schema。下表是后续实现时的代码追溯入口,目的是复用 HWLAB 已验证的边界和判定标准,而不是重新发明一套 Agent 行为。
|
||
|
||
| HWLAB v0.2 原有能力 | HWLAB 代码/文档追溯入口 | AgentRun 自身承接点 | SPEC 归属 |
|
||
| --- | --- | --- | --- |
|
||
| 短连接 submit + result/trace 轮询 | `internal/cloud/server-code-agent-http.ts`、`docs/reference/spec-v02-hwlab-cloud-api.md` | `run + command + runner-job` 三段式手动调度,所有写操作短返回 JSON | [spec-v01-agentrun-mgr.md](spec-v01-agentrun-mgr.md) |
|
||
| 只有真实 terminal completed + 非空 reply 才算通过 | `docs/reference/code-agent-chat-readiness.md`、`internal/cloud/code-agent-chat.ts` | result envelope 和 terminal status 规则;partial、stdout、transport close 不升级为 completed | [spec-v01-agentrun-mgr.md](spec-v01-agentrun-mgr.md)、[spec-v01-backend-adapter.md](spec-v01-backend-adapter.md) |
|
||
| runnerTrace 可见,能展示请求、工具、输出、错误和终态 | `internal/cloud/code-agent-trace-store.ts`、`web/hwlab-cloud-web/app-trace.ts` | 标准 event schema、单 run 内 seq 单调、bounded payload、Secret redaction | [spec-v01-backend-adapter.md](spec-v01-backend-adapter.md)、[spec-v01-agentrun-runner.md](spec-v01-agentrun-runner.md) |
|
||
| 取消正在执行的 turn | `internal/cloud/server-code-agent-http.ts`、`internal/cloud/codex-stdio-session.ts` | durable run/command cancel、pending 阻止启动、running interrupt、terminal 幂等返回 | [spec-v01-agentrun-mgr.md](spec-v01-agentrun-mgr.md)、[spec-v01-agentrun-runner.md](spec-v01-agentrun-runner.md) |
|
||
| conversation/session/thread 复用 | `internal/cloud/codex-stdio-session.ts`、`internal/cloud/code-agent-session-registry.ts` | `SessionRef` 保存 session/thread 摘要,runner 有 thread 则 resume,无 thread 则 start | [spec-v01-runtime-assembly.md](spec-v01-runtime-assembly.md) |
|
||
| 固定 repo workspace 执行 | `internal/cloud/code-agent-contract.ts`、`docs/reference/code-agent-chat-readiness.md` | `ResourceBundleRef` 使用 Git-only `repoUrl + full commitId` checkout 到隔离 workspace | [spec-v01-runtime-assembly.md](spec-v01-runtime-assembly.md)、[spec-v01-agentrun-runner.md](spec-v01-agentrun-runner.md) |
|
||
| provider profile 隔离和 Secret 不泄露 | `internal/cloud/code-agent-contract.ts`、`docs/reference/code-agent-chat-readiness.md` | `ProfileRef/SecretRef` profile-scoped 投影、缺失为 `secret-unavailable`、禁止 fallback 和泄露值 | [spec-v01-runtime-assembly.md](spec-v01-runtime-assembly.md)、[spec-v01-backend-adapter.md](spec-v01-backend-adapter.md) |
|
||
| provider/backend/cancel 等失败可区分 | `scripts/src/code-agent-response-contract.mjs`、`internal/cloud/code-agent-chat.ts` | failureKind 最小矩阵和 JSON 错误响应 | [spec-v01-agentrun-mgr.md](spec-v01-agentrun-mgr.md)、[spec-v01-backend-adapter.md](spec-v01-backend-adapter.md) |
|
||
| stdout/stderr/tool 输出必须有界 | `docs/reference/code-agent-chat-readiness.md`、`internal/cloud/code-agent-trace-store.ts` | `command_output`/`tool_call` 记录摘要、字节数、截断标记和必要引用 | [spec-v01-backend-adapter.md](spec-v01-backend-adapter.md) |
|
||
| runner/job 失败需要定位证据 | `internal/cloud/server-code-agent-http.ts` 的 trace/result 可见性 | runner job identity、attempt、jobName、pod/log identity 和最小 phase/exit 摘要 | [spec-v01-agentrun-runner.md](spec-v01-agentrun-runner.md)、[spec-v01-agentrun-mgr.md](spec-v01-agentrun-mgr.md) |
|
||
|
||
## 手动调度 API
|
||
|
||
`POST /api/v1/runs/:runId/runner-jobs` 是 HWLAB canary 的正式手动调度入口。它只负责为一个已存在 run 和 command 显式创建 runner Job,不负责扫描 pending queue。
|
||
|
||
请求最小字段:
|
||
|
||
| 字段 | 规则 |
|
||
| --- | --- |
|
||
| `commandId` | 必填,必须属于 `runId`。 |
|
||
| `attemptId` | 可选;未提供时由 manager 生成,返回值必须可持久查询。 |
|
||
| `idempotencyKey` | HWLAB 必须用 `traceId`、`messageId` 或等价稳定 key;相同 key 和相同 payload 返回既有 job/attempt。 |
|
||
| `image` / `backendImageRef` | 只能来自 manager allowlist、GitOps/catalog 或受控默认值;客户端不能传任意镜像扩大执行面。 |
|
||
| `retention` / `ttlSecondsAfterFinished` | 可选;默认遵循 runner Job TTL 规格。 |
|
||
|
||
响应必须短返回 JSON,不等待完整模型 turn,至少包含:`runId`、`commandId`、`attemptId`、`jobName`、`namespace`、`runnerId`、`logPath` 或 `podIdentity`、后续 `commands show` 与 `events` 轮询入口。重复提交若 payload 不同,必须结构化失败,不能创建第二个同名业务 attempt。
|
||
|
||
## Run / Command 映射
|
||
|
||
HWLAB canary 创建 run 时应使用以下字段口径:
|
||
|
||
| 字段 | HWLAB canary 口径 |
|
||
| --- | --- |
|
||
| `tenantId` | `hwlab`。 |
|
||
| `projectId` | `pikasTech/HWLAB`。 |
|
||
| `providerId` | `G14`,只表示目标 provider,不授予 HWLAB 业务权限。 |
|
||
| `backendProfile` | `deepseek` 或 `codex`,由 HWLAB 显式选择;缺少 matching SecretRef 必须失败,不 fallback。 |
|
||
| `workspaceRef` | 必须引用 ResourceBundleRef 中的 Git-only full commit;不得由 runner 猜 host path。 |
|
||
| `executionPolicy` | sandbox、network、timeout、secretScope 必须显式,不得由 HWLAB 扩大 AgentRun Secret 范围。 |
|
||
| `traceSink` | 可指向 HWLAB trace adapter;为 `null` 时 HWLAB 仍可通过 AgentRun events 轮询。 |
|
||
|
||
Command 第一阶段只要求 `type=turn`。用户原始 prompt、conversation metadata、profile 选择和 HWLAB trace correlation 必须作为 command payload 的非敏感字段保存;不得把 cookie、session token、provider credential、device internal token 或 Secret value 写入 payload。
|
||
|
||
## 需要补齐的能力
|
||
|
||
### P0 trace/result 元语
|
||
|
||
AgentRun 标准 events 必须稳定到足以被 HWLAB 转换:
|
||
|
||
- `backend_status`:profile、backendKind、protocol、attempt、resource/session 摘要,不包含 Secret 值。
|
||
- `assistant_message`:用户可见 assistant 文本,允许分片但必须能聚合为最终 reply。
|
||
- `tool_call`:工具名、状态、bounded 参数摘要和 redacted correlation。
|
||
- `command_output`:stdout/stderr/diff 的 bounded summary、原始字节数、截断标记和 artifact/log 引用。
|
||
- `error`:`failureKind`、message、retryable、provider/infra/backend 分类和 redacted details。
|
||
- `terminal_status`:`completed`、`failed`、`blocked` 或 `cancelled`,是 completed 的唯一终态来源。
|
||
|
||
面向 HWLAB 的 result envelope 至少应能回答:`status`、`terminalStatus`、`reply`、`failureKind`、`blocker`、`lastSeq`、`eventCount`、`artifactSummary`、`runId`、`commandId` 和 `attemptId`。partial assistant 文本、transport close、idle timeout 或 stdout 存在都不能单独升级为 `completed`。
|
||
|
||
### P0 cancel
|
||
|
||
AgentRun 需要提供 durable cancel 能力,建议形态为 `POST /api/v1/runs/:runId/cancel` 或 `POST /api/v1/commands/:commandId/cancel`。cancel 必须幂等;已 terminal 的对象返回当前终态。pending command 被 cancel 后不得再创建 runner Job。running runner 必须通过 poll、lease 或 heartbeat 观察 cancel,并传播到 backend interrupt;backend 不支持 interrupt 时终止受控进程组。cancel 最终必须写入 event、command state 和 run status,`failureKind` 使用 `cancelled`。
|
||
|
||
### P1 SessionRef 持久化
|
||
|
||
`SessionRef` 需要从 `null/deferred` 升级为可选持久会话引用,支持 HWLAB `conversationId/sessionId/threadId` 到 AgentRun session identity 的映射。session 只能保存 backend thread/session/cache,不保存 API KEY、`auth.json`、`config.toml` 或完整 `CODEX_HOME`。session store 必须与 Secret projection、writable runtime home、Git workspace 分离。runner 启动时,有 SessionRef 则执行 `thread/resume`,没有则执行 `thread/start`;profile 隔离、TTL、GC 和跨 profile 污染防护必须可见。
|
||
|
||
### P1 ResourceBundleRef / bundle materialization
|
||
|
||
`ResourceBundleRef` 必须按 Git-only 模型落地:`repoUrl + full commitId` 是唯一内容身份。runner 只能 checkout 到允许 workspace 前缀,不能覆盖 `/app`、Secret projection、profile runtime home 或 session 目录。第一阶段支持 `subdir`、`sparsePaths`、`submodules=false`、`lfs=false`、`credentialRef` 的最小字段即可。HWLAB canary 只需要 `pikasTech/HWLAB` 固定 full commit 的普通 checkout;用户上传文件和对象存储 artifact 不进入 `v0.1`。
|
||
|
||
## 分阶段增强计划
|
||
|
||
| 阶段 | 目标 | 主要交付 | 验收重点 |
|
||
| --- | --- | --- | --- |
|
||
| 1 | 手动调度 API 固化 | `runner-jobs` request/response schema、idempotency、job identity、CLI 调同一 REST API | 重复 key 不重复创建;短返回;manager 重启后可查。 |
|
||
| 2 | trace/result 元语 | 标准 event 子集、terminal result envelope、bounded output metadata | HWLAB 可由 events 稳定生成 result/trace;partial 不误报 completed。 |
|
||
| 3 | cancel 闭环 | durable cancel API、runner cancel poll、backend interrupt/process group stop | pending/running/terminal 后 cancel 均幂等且可见。 |
|
||
| 4 | ResourceBundleRef materialization | Git-only checkout、workspace 前缀、commit/tree 摘要、failureKind | 使用 full commit;不接受 branch/tag/HEAD;不覆盖 Secret/session/runtime home。 |
|
||
| 5 | SessionRef 持久化 | session record/store、thread resume、TTL/GC、profile 隔离 | 同一 conversation 连续两轮可复用;不同 profile 不污染。 |
|
||
| 6 | HWLAB v0.2 canary | HWLAB dispatcher adapter、traceId 映射、result/trace 转换 | 普通自然语言最短 turn 真实 completed 且 reply 非空;device-pod 仍由 HWLAB 授权。 |
|
||
|
||
## 测试规格
|
||
|
||
### T1 手动调度 API
|
||
|
||
阅读本文和 [spec-v01-agentrun-mgr.md](spec-v01-agentrun-mgr.md),然后在真实 `agentrun-v01` runtime 中用 RESTful API 创建 `tenantId=hwlab` 的 run、提交 `turn` command、调用 `POST /api/v1/runs/:runId/runner-jobs`。确认每个 API 返回 JSON、60 秒内返回、不等待完整 turn,并返回 job identity 与后续 poll 入口。
|
||
|
||
### T2 幂等和重复提交
|
||
|
||
阅读本文,然后用相同 `idempotencyKey` 重复调用 runner job API。相同 payload 必须返回同一 attempt/job;不同 payload 必须结构化失败,且不能创建第二个 runner Job。
|
||
|
||
### T3 trace/result 映射
|
||
|
||
阅读本文和 [spec-v01-backend-adapter.md](spec-v01-backend-adapter.md),然后执行真实 Codex stdio turn,确认 events 中存在可转换为 HWLAB result/trace 的 `backend_status`、assistant 或 error、`terminal_status`,且 bounded output metadata 足够判断截断和 artifact 引用。
|
||
|
||
### T4 cancel
|
||
|
||
阅读本文,然后分别验证 pending cancel、running cancel、重复 cancel 和 terminal 后 cancel。确认 command/run 终态、events 和 failureKind 均为 `cancelled` 或当前既有 terminal 状态,日志不泄露 Secret。
|
||
|
||
### T5 SessionRef 与 ResourceBundleRef
|
||
|
||
阅读本文和 [spec-v01-runtime-assembly.md](spec-v01-runtime-assembly.md),然后验证一次带 SessionRef 和 Git-only ResourceBundleRef 的 runner Job。确认 session 不含 credential 文件,bundle 使用 full commit checkout 到允许 workspace,event/result 能回答 session id、repo、commit 和 checkout 摘要。
|
||
|
||
## 实现状态
|
||
|
||
| 能力 | v0.1 状态 | 说明 |
|
||
| --- | --- | --- |
|
||
| 手动 runner Job API | 已实现 | `runner job` 通过 manager REST 创建 Kubernetes Job,支持 `idempotencyKey`、持久 runner job record、job identity、attempt/runner/jobName 返回和重复 payload 冲突保护。 |
|
||
| trace/result 元语 | 已实现最小合同 | 新增 run/command result envelope,聚合 terminal status、reply、failureKind、event cursor、artifact summary、attempt、SessionRef 和 ResourceBundleRef 摘要。 |
|
||
| cancel | 已实现最小闭环 | 已提供 run/command cancel API;pending cancel 会阻止新 runner Job,running runner 通过轮询触发 backend abort,终态写入 event、command state 和 run status。 |
|
||
| SessionRef | 已实现最小持久化 | run 可携带 `sessionRef`,manager 保存 session/thread,runner 会按 threadId resume,result envelope 暴露脱敏 session 摘要;TTL/GC 仍按后续运维策略细化。 |
|
||
| ResourceBundleRef | 已实现 Git-only materialization | run 可携带 `repoUrl + full commitId`,runner checkout 到 `AGENTRUN_WORKSPACE_ROOT` 下的隔离目录并记录 commit/tree/workspace 摘要;上传文件和对象存储仍不进入 v0.1。 |
|
||
| HWLAB v0.2 canary | 待实现 | 需要 HWLAB dispatcher adapter 调 AgentRun 手动调度 API,并转换 result/trace。 |
|