Files
pikasTech-agentrun/docs/reference/spec-v01-agentrun-runner.md
T
2026-06-02 10:16:03 +08:00

15 KiB
Raw Blame History

v0.1 agentrun-runner 服务规格

agentrun-runner 是 AgentRun v0.1 的手动启动执行入口。它以 per-run runner Job 方式运行,必须从 agentrun-mgr claim run,调用 backend adapter,并把 events、heartbeat、command ack 和 command terminal status 写回 manager。同一 runner Job 在 idle timeout 内必须继续 poll 同一 run 的后续 command,不得把每个 turn 都变成重新 bundle 和新 runner Job。

在系统中的职责划分

  • 作为 Kubernetes Job 或受控 host process 启动;不作为普通业务客户端直接调用的长驻公共服务。
  • 从 manager register、claim run、续租 lease、poll commands、ack command、append events、patch command status;只有 runner 级不可恢复失败或显式 run terminal 时才 patch run status。
  • 根据 run 中的 backendProfileexecutionPolicy.secretScope 调用 backend adapter。
  • 根据 manager 解析出的 RuntimeAssembly materialize backend image、profile Secret、session 和初始资源;四要素字段权威见 spec-v01-runtime-assembly.md,本文只规定 runner 消费边界。
  • 将 backend stdout/stderr、assistant message、tool call、error 和 command terminal status 归一化为 manager event。
  • 提供可定位的 job/process identity、logPath、attempt id 和 failureKind。
  • 不直连 Postgres,不扩大 workspace、network、approval 或 secret scope。

内部架构

v0.1 默认 runner 形态是 agentrun-v01 namespace 中的短生命周期 Job,Job 名称建议使用 agentrun-v01-runner-<runId>-<attempt>。短生命周期指 Job 不作为公共长驻服务;Job 内部必须支持同一 run 的多 command loop,直到 run 被 cancel/terminal、lease 冲突或 idle timeout。MVP 允许 CLI 启动受控本地 process,但该 process 仍必须通过 manager API claim/report。

Runner 自研代码优先使用 Bun + TypeScript。Kubernetes Job 和 CLI 启动的 host process 必须进入同一套 TS runner 模块,避免一套 Job 逻辑和一套本地调试逻辑分叉;容器镜像可以直接运行 TS 入口或运行由同一源码构建出的 JS artifact。

Runner 启动参数必须显式包含:

  • manager API base URL。
  • runId 和 attemptId。
  • backendProfile。
  • logPath 或 Kubernetes job/pod identity。
  • source commit/build metadata。

Runner Secret 只能通过 Kubernetes Secret projection、ServiceAccount/RBAC 或受控 Secret API 读取获得。Codex 测试凭据投影规则见 spec-v01-secret-distribution.mdspec-v01-backend-codex.md

Kubernetes Job runner 必须把 credential source 与 runtime home 分开:Secret volume 只读挂在 /var/run/agentrun/secrets/.../home/agentrunemptyDir 提供可写空间,CODEX_HOME 指向当前 run/profile 的 writable runtime homeAGENTRUN_CODEX_SECRET_HOME 指向当前 backendProfile 对应的只读 projection。runner/backend 在启动 provider 前只复制授权文件,不打印内容。codexdeepseekminimax-m3 profile 不得共享同一个可写 runtime home,除非它们运行在不同的 per-run Kubernetes Job 且该目录由 Job 独占 emptyDir 提供。

RuntimeAssembly P0 中 SessionRef 可以显式为 nullrunner 不得把完整 CODEX_HOME、Secret projection 或节点 host path 当作 session store。ResourceBundleRef P0 收敛为 Git-onlyrunner 已支持把 repoUrl + full commitId checkout 到 AGENTRUN_WORKSPACE_ROOT 下的隔离目录,并记录 commit/tree 摘要,不能把用户上传文件或 env dump 混入 Git-only bundle。

HWLAB v0.2 执行经验承接

Runner 承接的是 HWLAB v0.2 原有 Code Agent 的执行层经验,不承接 HWLAB cloud-api 的业务路由和权限判断。实现时优先参考 HWLAB 已验证的代码路径,而不是重新定义 Codex session、trace 和输出裁剪语义:

HWLAB v0.2 参考能力 参考入口 Runner 承接规则
Codex app-server stdio thread/turn 生命周期 internal/cloud/codex-stdio-session.ts 有 command payload.threadIdSessionRef.threadId 时执行 resume,再 start turn;无标准 threadId 时 start threadevents、result 和 session record 都以 threadId 为唯一 thread identityturn terminal 才能上报 completed。
cancel/interrupt internal/cloud/server-code-agent-http.tsinternal/cloud/codex-stdio-session.ts runner 必须轮询 manager cancel 状态并中止 backendbackend 不支持精确 interrupt 时终止受控进程组。
runnerTrace 事件可见性 internal/cloud/code-agent-trace-store.ts backend 输出必须转成 manager events;每个 terminal/错误/取消都要有事件和 final status。
workspace-write 边界 internal/cloud/code-agent-contract.ts runner 只使用 ResourceBundleRef materialized workspace,不猜 HWLAB Pod 的 /workspace/hwlab 或 host path。
Secret 与 writable CODEX_HOME 分离 internal/cloud/code-agent-contract.tsdocs/reference/code-agent-chat-readiness.md profile Secret 只读投影,复制到当前 run/profile writable runtime home;不同 profile 不共享 runtime home。
bounded stdout/stderr docs/reference/code-agent-chat-readiness.md command_output 记录摘要、字节数、截断标记和必要引用;不得把大输出直接塞进单个 event/result。

Kubernetes Job runner 必须设置有限保留时间。v0.1 默认 ttlSecondsAfterFinished=86400,用于保留最近完成 Job 的调试窗口,同时避免长期堆积 Completed runner Job 污染运行面观察。该 TTL 是 Job manifest 的运行面属性,不是 CI/CD 门禁;需要延长保留时间时必须通过受控 Job render/input 显式覆盖,并在 issue 或 PR 中说明原因。

Runner 生命周期

标准状态方向:

starting -> registered -> claimed -> running -> terminal
starting -> registered -> claim_failed
claimed -> running -> backend_failed
claimed -> running -> cancelled
claimed -> lease_lost

规则:

  • runner 必须先 register,再 claim runclaim 失败不能继续调用 backend。
  • lease heartbeat 必须通过 manager lease/status 可观察;不得把周期性心跳或 backend running tick 写成 durable trace event 刷屏。长 turn 只在 backend-turn-finished 中输出有界 progress 摘要;过期或冲突时写入 failure event 或明确退出原因。
  • command 只能从 manager poll;不得从本地文件或临时参数伪造正式 command。
  • runner 的普通 poll 只选择 pending turn;当 backend adapter 暴露 active turn control 后,runner 才在同 run 内轮询 pending steer commandack 后调用 backend 的 steer 能力并单独终结该 steer command。active turn 结束后到达的 steer 必须结构化 blocked,不得启动新 turn,也不得把 run 标为 terminal。
  • backend 产生的所有可见输出必须先经过 adapter normalization 和 redaction,再 append 到 managerbackend_status 至少包含 redacted profile/backendKind/protocol 摘要。
  • 单个 command terminal 上报后 runner 不应立即退出,而应继续 poll 同一 run 的 pending command,直到 idle timeout、lease 冲突或 run terminal。退出码与 runner loop 终态必须一致或在日志中可解释。

Manager API 交互

Runner 只使用 manager 私有 API

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
PATCH /api/v1/commands/:commandId/status

PATCH /api/v1/commands/:commandId/status 是普通 turn 完成的权威上报入口;它只能终结 command,并可更新 run 的 SessionRef/thread 摘要。PATCH /api/v1/runs/:runId/status 只用于 runner 级不可恢复失败或显式 run terminal,不得在每个成功 turn 后调用。

Runner inbound HTTP 不是业务 API。若实现本地诊断端点,只允许 GET /healthGET /debug/status,并且只能暴露在本地或 pod 内部调试面。

Failure 与 Redaction

Runner 必须把以下失败归类为结构化 failureKind

  • secret-unavailableSecretRef 缺失、RBAC 拒绝或 Secret projection 不完整。
  • provider-auth-failed:上游 provider 鉴权失败。
  • provider-unavailable:上游 provider 返回 HTTP 5xx/503、Service Unavailable、携带 5xx 的 responseStreamDisconnected 或明确 temporary/provider unavailable 文案;这是外部 provider availability blocker,不得归为本地 backend-failed
  • backend-failed:backend 进程退出、协议错误或返回 terminal error。
  • runner-lease-conflictclaim/lease 被其他 runner 持有。
  • infra-failedJob 启动、网络、manager API 或文件系统基础设施失败。
  • cancelled:收到 interrupt/cancel 且已停止执行。

Runner 日志必须实时 flush 到文件或 pod logCLI 启动 runner 时必须返回 logPath 或 job/pod identity。日志、event、trace 和 CLI 输出不得出现 provider credential、auth.jsonconfig.toml 内容、DSN password、token 或 URL credential。

Runner Job 最小状态

HWLAB v0.2 原有 Code Agent 在 cloud-api 进程内执行,失败时依赖本地 trace 定位;AgentRun 将执行迁到 runner Job 后,runner 必须把最小定位事实交回 manager。runner-jobs 创建响应和后续查询至少包含:

字段 规则
attemptId 同一 command 的一次执行尝试;重复 idempotency key 和相同 payload 返回同一 attempt。
jobName / namespace Kubernetes Job identity;不得要求业务客户端自己构造名称。
runnerId runner register 后的执行者身份。
podIdentity / logPath 至少提供一种可定位 runner 日志的 redacted 引用。
phase / exitCode 若可用,返回 Job/Pod/container 的最小状态摘要;不可用时必须说明 waitingFor 或 failureKind。
startedAt / finishedAt 用于区分 pending、running、terminal 和 TTL retention 窗口。

这些字段只用于可观测性,不授予调用方直接操作 Kubernetes Job 或读取 Secret 的权限。

测试规格

T1 Runner 启动可见性

阅读 AGENTS.md、本文和 spec-v01-cli.md,然后用正式 AgentRun CLI 为一个真实 run 启动 runner。确认 CLI 立即返回 JSON,包含 runId、attemptId、job/process identity、logPath 和后续 poll command;不得等待完整模型 turn。

T2 Claim 与 lease 冲突

阅读本文和 spec-v01-agentrun-mgr.md,然后对同一个 run 启动两个 runner。确认只有一个 runner claim 成功,失败方输出结构化 failureKind,并且 manager events 中能看到冲突或拒绝原因。

T3 Backend event round-trip

阅读本文和 spec-v01-backend-adapter.md,然后用真实 backend 执行一个最短 turn。确认 runner append assistant/output/error/backend_status/terminal_status 中的必要 eventsevent seq 单调,terminal status 可通过 manager 查询。

T4 Missing Secret failure

阅读本文和 spec-v01-secret-distribution.md,然后分别用缺失 codex SecretRef、缺失 deepseek SecretRef 与缺失 minimax-m3 SecretRef 的 run 启动 runner。确认 runner 不调用 providerrun 失败为 secret-unavailable 或等价 failureKind,不 fallback 到另一个 profile,日志和事件不泄露 Secret 值。

T5 Profile switching

阅读本文和 spec-v01-backend-codex.md,然后按 codex -> deepseek -> minimax-m3 -> codex 顺序启动四个真实 runner Job。确认每个 Job 只挂载和复制当前 profile 的 SecretRefCODEX_HOME 互相隔离,且前后两个 codex run 不受 deepseekminimax-m3 run 的 config/model/upstream 影响。

T6 Same-run runner command loop

阅读本文和 spec-v01-hwlab-manual-dispatch.md,然后在同一 run 中提交两条 turn command,只启动一次 runner Job。确认第一条 completed 后 run 仍为 non-terminalrunner 在 idle timeout 内处理第二条 commandresource-bundle-materialized 只记录一次,两个 command result 按 commandId 独立返回 reply/terminal。

规格的实现情况

规格项 状态 说明
agentrun-runner 服务规格 已定义 本文为 v0.1 runner 权威。
Kubernetes Job runner 已实现/已通过主闭环 runner job 通过 manager REST 创建 Kubernetes Job,固定使用 agentrun-v01-runner ServiceAccount、manager URL、runId/commandId/attemptId、executionPolicy、SecretRef 文件投影、writable Codex runtime home、idle timeout 和有限 TTL;真实 agentrun-v01 runner Job 已完成 Codex turn。
host process runner 已实现 runner startsrc/runner/main.ts 进入同一套 runOnce,可通过 manager register/claim/poll/report 执行自测试,并支持 --one-shot 或 idle timeout 控制。
claim/lease/report client 已实现 已拆出 runner manager API client,覆盖 register、claim、lease heartbeat、poll command、ack、append event、command status 和必要 run statuslive runtime 通过 manager 写入 Postgres durable store。
cancel observation 已实现最小闭环 runner 在 backend 执行期间轮询 run/command cancel,触发 AbortController 中止 Codex stdio backend,并按 cancelled 上报 command/run 终态。
SessionRef/ResourceBundleRef 消费 已实现最小闭环 runner 会使用 run 中的 SessionRef threadId 执行 resume,并 materialize Git-only ResourceBundleRef 到隔离 workspace 后再启动 backend。
同 run/runner 多 turn 已实现最小闭环 runner 在同一 Job 中 materialize bundle 一次后循环 poll command;普通 turn completed 只终结 commandrun 保持可继续接后续 turn,直到 idle timeout 或 run terminal。
runner redaction 已实现主路径 runner/backend event 和 Job 输出使用 redaction;复杂审计仍按 spec-v01-validation.md 的人工验收抽查。
deepseek profile runner selection 已实现/已通过主闭环 Runner Job 和 host runner 已按 run backendProfile 选择 matching SecretRef、projection、CODEX_HOME 和 backend metadata;真实 Kubernetes Job 已完成 codex -> deepseek -> codex 切换联调。
minimax-m3 profile runner selection 已实现/待真实主闭环 Runner Job 和 host runner 已按 run backendProfile=minimax-m3 选择 matching SecretRef、projection、CODEX_HOME 和 backend metadata;真实 Kubernetes Job 需要完成 MiniMax-M3 CLI 手动联调后收口。