24 KiB
v0.1 装配 SPEC(RuntimeAssembly)
本文是 AgentRun v0.1 runner/backend 启动前的权威装配 SPEC。所有会进入运行时容器、进程、文件系统或环境变量的执行输入,都必须先落到本文定义的装配模型,再由 manager/runner 渲染为受控 Job 输入;不得在 CLI、Queue、runner Job、issue 过程或临时热补丁中绕过装配模型直接拼接 credential、host path 或隐式环境。
RuntimeAssembly 只回答一个问题:一次 run 到底用哪份 backend 镜像、哪个 profile/credential scope、哪份 session、哪份代码、初始 prompt、skill 和工具 credential。BackendImageRef、ProfileRef、SessionRef、ResourceBundleRef 仍是四个一等运行时要素;credential 注入不是第五个杂项要素,而是挂在 ProfileRef、ResourceBundleRef 或 tool scope 上的 SecretRef 装配引用。初始 prompt 与 skill 注入也不是第五条运行时路径,它们属于 ResourceBundleRef 指向的 Git-only 非敏感内容。
最简四要素
v0.1 只保留四个一等要素:
| 要素 | 最小字段 | v0.1 含义 | 不包含 |
|---|---|---|---|
BackendImageRef |
image |
digest-pinned backend/runner 镜像。 | API KEY、profile config、用户代码、session 文件。 |
ProfileRef |
profile、secretRef |
provider profile 和 API KEY/配置 SecretRef。 | backend 镜像、session、repo 文件、GitHub/业务工具 credential。 |
SessionRef |
sessionId 或 null |
backend 会话文件持久化引用;P0 可以为 null。 |
API KEY、完整 CODEX_HOME、Git workspace。 |
ResourceBundleRef |
kind="gitbundle"、repoUrl、commitId、bundles[]、可选 promptRefs |
初始代码/文件输入、工具目录、skill 目录和同一 commit 下的稳定初始 prompt;P0 固定 Git-only gitbundle。 | 上传文件、对象存储 artifact、inline env、Secret value、会话历史、旧 inline seed。 |
P0 最小 JSON 形态:
{
"backendImageRef": {
"image": "127.0.0.1:5000/agentrun/agentrun-mgr@sha256:..."
},
"profileRef": {
"profile": "codex",
"secretRef": { "name": "agentrun-v01-provider-codex", "keys": ["auth.json", "config.toml"] }
},
"sessionRef": null,
"resourceBundleRef": {
"kind": "gitbundle",
"repoUrl": "git@github.com:pikasTech/unidesk.git",
"commitId": "<full commit sha>",
"bundles": [
{ "name": "tools", "subpath": "tools", "target_path": "tools" },
{ "name": "skills", "subpath": "skills", "target_path": ".agents/skills" }
],
"promptRefs": []
}
}
executionPolicy、observabilityPolicy、tenant identity、network、GC、failureKind、provenance、resource limit、tool credential scope、初始 prompt 装配和 skill 装配都不是新的运行时要素;它们分别挂在四要素或 run policy 上,并且必须能追溯到 SecretRef、Git commit/path/hash、配置引用或显式 null/deferred 状态。
装配对象与 credential 归属
任何 credential 注入都必须先归类,再进入对应装配路径:
| credential 类别 | 装配归属 | 运行时投影 | 规则 |
|---|---|---|---|
| Provider credential | ProfileRef / executionPolicy.secretScope.providerCredentials[] |
profile-scoped 只读 Secret projection,再复制到 per-run writable CODEX_HOME |
只服务 codex/deepseek/minimax-m3 backend profile;缺失为 secret-unavailable,不得 fallback。 |
| Git resource credential | ResourceBundleRef.credentialRef |
只服务 resource materialization 的 Git fetch/checkout | 只能用于拉取 ResourceBundleRef.repoUrl 对应代码,不得暴露给 agent shell 作为通用 GitHub token。 |
| Tool credential | executionPolicy.secretScope.toolCredentials[] |
由 runner 按 tool scope 投影为文件或 env,并只暴露给当前 run/command 允许的工具 | 用于 GitHub PR、issue、UniDesk SSH passthrough、artifact registry 等 agent shell 工具能力;不等同于 AgentRun integration,不触发 GitHub sink/OA/Event 之类外部动作记录。 |
| Short-lived execution context | runner-job transientEnv |
单次 Job env,response/dry-run/event 只显示 name/hash | 只用于业务 dispatcher 生成的短期或 owner-scoped runtime context,例如 HWLAB HWPOD runtime API key、runtime URL 和非敏感服务地址;不得承载 provider credential、GitHub token、UniDesk SSH client token 或长期 SSH key。 |
toolCredentials 是装配 SPEC 中的受控扩展槽位,用于把 agent 运行时需要的外部工具授权从“临时 env”收敛为 SecretRef。v0.1 支持 GitHub PR/issue 与 UniDesk SSH passthrough 所需的最小 env projection,例如:
{
"toolCredentials": [
{
"tool": "github",
"purpose": "pull-request",
"secretRef": {
"namespace": "agentrun-v01",
"name": "agentrun-v01-tool-github-pr",
"keys": ["GH_TOKEN"]
},
"projection": { "kind": "env", "envName": "GH_TOKEN" }
},
{
"tool": "unidesk-ssh",
"purpose": "ssh-passthrough",
"secretRef": {
"namespace": "agentrun-v01",
"name": "agentrun-v01-tool-unidesk-ssh",
"keys": ["UNIDESK_SSH_CLIENT_TOKEN"]
},
"projection": { "kind": "env", "envName": "UNIDESK_SSH_CLIENT_TOKEN" }
}
]
}
规则:
toolCredentials只能保存 SecretRef、tool、purpose、projection intent 和 redacted metadata,不保存 Secret value。- manager 只校验引用形态和 tenant/policy 边界,不读取 Secret value 后存库。
- runner 渲染 Job 时只能按当前 run 的
secretScope投影被授权的 tool credential;不能枚举 namespace 内所有 Secret。 - dry-run manifest、runner job record、event、trace、日志和 CLI 输出只能显示 tool、purpose、SecretRef 名称/key、projection kind 和
valuesPrinted=false。 - GitHub PR 能力属于 agent shell/tool 运行能力,不是 AgentRun Queue integration,也不要求新增 GitHub sink、OA sink、notification 或 Event Flow。
tool=unidesk-ssh只允许投影 Secret keyUNIDESK_SSH_CLIENT_TOKEN到同名 env。该 token 是 UniDesk frontend/ws/ssh的 scoped client token,route allowlist 由 UniDesk frontend 配置约束;它不得携带 provider token、主 server SSH key 或完整 frontend 登录态。- 发现 agent shell 缺少
gh、curl、UniDesk SSH passthrough token 或其他工具凭证时,只能记录为装配能力缺口;不得用transientEnv或 issue 评论里的明文 token 绕过。
HWLAB v0.2 承接口径
HWLAB v0.2 原有 Code Agent 已经验证了 profile、session、workspace 和 Secret 的基本边界。RuntimeAssembly 需要把这些边界固化为 AgentRun 自身四要素,避免 runner 继续依赖 HWLAB cloud-api Pod 内路径或本地进程状态。
| HWLAB v0.2 基线能力 | HWLAB 参考入口 | RuntimeAssembly 承接字段 | 承接规则 |
|---|---|---|---|
| provider profile 可切换 | internal/cloud/code-agent-contract.ts |
ProfileRef.profile、ProfileRef.secretRef |
deepseek、minimax-m3 与 codex 只选择 profile/config/SecretRef,不复制 backend 协议;缺失 Secret 必须失败,不 fallback。 |
| Codex app-server thread 复用 | internal/cloud/codex-stdio-session.ts、internal/cloud/code-agent-session-registry.ts |
SessionRef.sessionId、conversationId、threadId |
AgentRun 保存 backend thread/session 摘要;不保存 API KEY、auth.json、config.toml 或完整 CODEX_HOME。 |
固定 /workspace/hwlab 代码上下文 |
internal/cloud/code-agent-contract.ts |
ResourceBundleRef.repoUrl、commitId |
用 Git-only full commit 取代 HWLAB Pod 内固定路径;runner checkout 到隔离 workspace。 |
writable CODEX_HOME 与 Secret 投影分离 |
docs/reference/code-agent-chat-readiness.md |
ProfileRef + runner runtime home |
Secret 只读投影,复制到当前 run/profile writable runtime home;profile 间不共享。 |
| runner/image 可追溯 | HWLAB live build/source metadata | BackendImageRef.image |
runner/backend image 必须可追溯 digest/source commit,不能由调用方任意传未受控镜像。 |
HWLAB Workbench 的 project/workspace 不属于 RuntimeAssembly 四要素,也不是 AgentRun projectId。这些业务字段只能作为 metadata 或 workspaceRef 的 HWLAB 子字段进入 run;AgentRun policy 字段仍以 tenantId / projectId / providerId / backendProfile 为准。HWLAB providerProfile 在 RuntimeAssembly 中只映射为 ProfileRef.profile 和 run backendProfile,并应由显式 HWLAB session 继承,不能从 stale workspace fallback 覆盖。
四要素边界
BackendImageRef
image必须是 digest-pinned image。- image 来源必须是 CI/CD artifact catalog、GitOps manifest 或 manager allowlist;客户端不能在 run payload 中传任意镜像。
- v0.1 可以继续使用现有 agentrun runner 镜像,不要求立即拆独立 backend image。
- 验收时只需要能追溯实际 Deployment/Job image digest 和 source commit。
ProfileRef
profile在 v0.1 只允许codex、deepseek或minimax-m3。secretRef只保存 Secret 名称和 key,不保存值。- 当前 profile 只能读取当前 profile 的 SecretRef;缺失必须
secret-unavailable,不能 fallback 到另一个 profile。 - profile Secret 只读投影,backend 需要可写目录时复制到 per-run/profile runtime home。
SessionRef
- P0 允许
sessionRef=null,表示不持久化 backend session 文件。 - 面向 HWLAB v0.2 原有长会话能力,SessionRef 是承接 Code Agent thread 复用的核心字段:需要支持
conversationId/sessionId/threadId到 backend session identity 的稳定映射。 - thread 复用只认标准
threadId:单个 command 显式提供payload.threadId时优先使用,否则使用SessionRef.threadId。协议字段、events、result 和 session record 都以该字段为唯一 thread identity;缺失标准threadId就按新 thread 启动并在 result/sessionRef 中回写标准字段。 - 一旦启用 session,必须只保存 backend session/cache,不保存 API KEY、
auth.json、config.toml或完整CODEX_HOME。 - session 文件目录必须和 profile credential、Git workspace 分开。
- runner 启动时,有 SessionRef 则执行
thread/resume,没有 SessionRef 则执行thread/start;profile 切换不得复用另一 profile 的 session。 - v0.1 先定义边界;持久 session store、TTL、GC 和 resume 验收按 spec-v01-hwlab-manual-dispatch.md 分阶段推进。
v0.1.1 SessionRef 持久化(per-session RWO PVC 直接挂载)
v0.1 的 P0 把 SessionRef 收敛为「只持久化 sessionId/threadId/metadata」。v0.1.1 必须把 SessionRef 升级为真正持久化,让 codex app-server thread / resume 跨 runner pod 重建继续成功,且「PVC 不删就随时 resume」是硬验收。
边界:
- 每个 session 绑定一个 RWO PVC:
agentrun-v01-session-<sessionId>,固定 namespaceagentrun-v01、StorageClass 走AGENTRUN_SESSION_STORAGE_CLASS(默认local-path)、默认容量 1Gi。 - runner Job 必须在
${CODEX_HOME}/<codex_rollout_subdir>位置把 PVC 直接挂载到 runner pod;auth.json、config.toml、state_*.sqlite、memories/、tmp/、skills/仍由emptyDir父目录提供,不持久化。 - 完整 CODEX_HOME 不进入 PVC,profile Secret 投影仍走
agentrun-v01-runner-secret-reader,与 session 持久化路径分离。 - runner 启动时把 PVC 名、namespace、mount path、codex rollout subdir 写入 env(
AGENTRUN_SESSION_PVC_NAME、AGENTRUN_SESSION_PVC_NAMESPACE、AGENTRUN_SESSION_PVC_MOUNT_PATH、AGENTRUN_CODEX_ROLLOUT_SUBDIR),backend adapter 不需要直接读 k8s API。 codex_rollout_subdir走 env,默认sessions,codex CLI 升级改子目录时只改该 env,不改 runner/backend 装配。POST /api/v1/sessions创建 session 时同步创建 PVC;POST /api/v1/runs/:runId/commands命中已有 session 且storage_kind='evicted'时短路返回session-store-evicted,不创建 runner Job。- runner pod 删除或旧 lease 过期后的 replacement runner 只改变执行尝试 identity,不改变 RuntimeAssembly 的
SessionRef、ProfileRef或ResourceBundleRef。验收时应证明 replacement run/job 仍使用同一SessionRef.sessionId、threadId、ProfileRef.profile和 PVC;不能通过新 session、新 profile 或历史 prompt 拼接来制造 resume 表象。 - GC 循环(默认 5min,可调
AGENTRUN_SESSION_GC_INTERVAL_MS)扫到expires_at过 + 无 active run 的 session 删 PVC。 - runner Job 启动后把 PVC 摘要(
pvcName/pvcPhase/storage_size_bytes/storage_files_count/storage_sha256/storage_updated_at)通过POST /api/v1/sessions/:id/storage/refresh写回 manager;manager 不读 PVC 内容,只读摘要。
禁止路径:
- 不引入「runner 启动后 copy/restore」path,撤掉的 copy 方案不允许复活(PR #78 已回退 replacement 逻辑,本节同样禁止任何「持久化卷 + 热修脚手架」变体)。
- 不允许 fake
thread/resume:completed,PVC 真的存在且 codex 真的能 resume 才算通过。 - 不写 fallback、不写 replacement、不拼接历史。
thread/resume失败时按 spec-v01-backend-codex.md T7 直接失败;只有AGENTRUN_SESSION_PVC_NAME已设 + codex 报no rollout found for thread id时升级为session-store-evicted,用于上层区分「PVC 被删」与「真协议错误」。
ResourceBundleRef
- P0 固定
kind="gitbundle",由repoUrl + full commitId + bundles[]决定内容身份。 commitId必须是不可变 full commit sha,不能是 branch、tag 或HEAD。bundles[]每一项只允许{ name?, repoUrl?, commitId?, subpath, target_path };缺省 repo/commit 继承顶层。subpath必须留在 checkout 内,target_path必须留在 runner workspace 内;runner 按subpath -> target_path复制文件或目录。credentialRef只用于拉取私有 Git repo,不等同于 backend API KEY。- 不支持上传文件、对象存储 artifact、任意 ConfigMap 文件袋、inline seed 或旧字段;旧
toolAliases、skillRefs、workspaceFiles、subdir、sparsePaths输入必须直接 schema-invalid。 - 面向 HWLAB 手动调度 canary,默认 bundle 把 repo 的
tools/复制到 workspacetools/,把skills/复制到 workspace.agents/skills/;event/result 必须记录 repo、full commit、checkout tree、bundle 列表、workspace 摘要、tools 和 skillDirs 摘要。
tools 目录
runner 对 workspace tools/ 做统一装配:顶层带 shebang 的脚本会被 chmod +x,tools/ 目录会追加到 PATH。非 shebang 文件是随 bundle 复制的源码、测试或辅助文件,不作为可执行工具发现,也不触发 schema-invalid。短命令名称来自 repo 内真实文件,例如 tools/hwpod,不再由 runner 生成 wrapper。
promptRefs
promptRefs 用于按 repoUrl + full commitId + path 装配初始 prompt。它承载业务域稳定 runtime/developer instruction,例如某个项目的标准入口、禁止路径和工具使用纪律;它不承载用户本轮 message,也不承载历史会话。
最小形态:
{
"name": "hwlab-v02-runtime",
"path": "internal/agent/prompts/hwlab-v02-runtime.md",
"inject": "thread-start",
"required": true
}
规则:
path只能是 bundle 内相对路径,不能是绝对路径,不能包含..。inject的 v0.1 默认和唯一正式语义是thread-start:只有没有既有threadId、runner 执行thread/start的第一条 turn 会注入;已有SessionRef.threadId或 commandpayload.threadId并执行thread/resume时不得再次注入。- 多个
promptRefs按数组顺序拼装;单个 prompt 和总 assembled prompt 必须有大小上限,超限返回prompt-unavailable或prompt-too-large,不能静默截断成新语义。 - prompt 文件内容进入 Codex turn input,但 event/result 只输出
name、path、sha256、bytes、inject、required和injected=true/false,不得默认输出全文。 promptRefs不得读取 Secret、env、token、profile config 或 session 文件;需要 credential 的内容必须通过ProfileRef、toolCredentials或transientEnv的正式路径装配。promptRefs缺失且required=true时,run/command 必须 blocked;不得 fallback 到用户 prompt、旧硬编码 prompt、模型默认 system prompt 或历史上下文拼接。
skill 目录
skill 只来自 gitbundle 复制进 workspace 的 .agents/skills/<name>/SKILL.md。runner 发现直接子目录中的 SKILL.md 后,把 .agents/skills 暴露给 backend,并在 initial prompt 中加入有界 skill facts。多文件 skill 的 references/、scripts/ 和后续新增文件跟随目录一起复制;event/result 只输出 skill name、manifest path 摘要、hash、bytes 和 summary,不输出大段 manifest 正文。runner 不读取镜像默认 skill、host path、ConfigMap、用户长 prompt 或旧 skillRefs。
初始 prompt 与 session 边界
初始 prompt 装配只发生在新 thread 的首轮 turn。后续 turn 的历史上下文必须由 Codex stdio 原生 thread/resume 恢复;AgentRun 不得为了补 prompt、补 skill facts 或修复 stale thread 而拼接旧用户消息、旧 assistant 回复、旧 skill 列表或旧业务事实。thread/resume 失败时按 spec-v01-backend-codex.md 直接失败,不启动替代 thread/start。
最简装配顺序
- Manager 根据 run 解析四要素引用。
- Manager 根据
executionPolicy.secretScope解析 provider/tool SecretRef 和 resource credential 引用;只保存引用,不读取值。 - Manager 或 runner Job render 只使用解析后的 image、SecretRef、sessionRef、Git commit 和 projection intent。
- Runner materialize profile Secret 到 writable runtime home。
- Runner materialize tool credential 到该 run 允许的 env/file projection;未实现的 tool scope 必须显式 failed/blocked,不能静默跳过后让 agent 自己猜凭据。
- Runner materialize
kind="gitbundle"resource bundle 到 workspace;P0 未实现时必须显式 blocked,不能猜测 host path。 - Runner 按
bundles[]复制目录或文件,准备 workspacetools/、发现.agents/skills,读取并校验promptRefs,写入有界 assembly event。 - Runner 启动 backend,并在 event 中记录 image digest、profile、SecretRef 名称/key、tool credential scope、sessionRef、repoUrl/commitId、bundles、promptRefs、tools 和 skillDirs 摘要。
任何一个要素缺失或不合法,都必须按该要素失败;不得静默 fallback。
v0.1 验收标准
A1 BackendImageRef 验收
- 实际 manager Deployment 和 runner Job 使用 digest-pinned image。
- event、CLI 或诊断输出能看到 image digest 或可追溯到 GitOps/catalog。
- run payload 不能传任意 image 字符串。
A2 ProfileRef 验收
codexrun 只挂载agentrun-v01-provider-codex。deepseekrun 只挂载agentrun-v01-provider-deepseek。minimax-m3run 只挂载agentrun-v01-provider-minimax-m3。codex -> deepseek -> minimax-m3 -> codex切换后,CODEX_HOME、SecretRef、backend_status 不互相污染。- 删除或缺失
deepseek/minimax-m3SecretRef 时必须secret-unavailable,不能 fallback 到codex。 - 所有输出不得包含 Secret value、
auth.json或config.toml明文。
A2b Tool credential 验收
- GitHub PR、issue、UniDesk SSH passthrough 或其他 shell/tool 授权只能通过
executionPolicy.secretScope.toolCredentials[]的 SecretRef 装配进入 runner。 - CLI、Queue task、runner job response、dry-run manifest、event 和日志不得输出 token、SSH private key 或 credential 文件正文。
- 缺少 tool credential 时,run/command 必须返回可判定的
secret-unavailable、tenant-policy-denied或明确 blocker,不能伪装成 agent 业务失败。 transientEnv不得用于 GitHub token、UniDesk SSH client token、长期 SSH key、provider API key 或其他 provider/tool 可复用 credential。HWLAB dispatcher 生成并限定 owner/HWPOD/runtime scope 的HWLAB_API_KEY可以作为单次 runner Job runtime context 进入transientEnv,但 AgentRun 不保存、不解释、不回显其明文。
A3 SessionRef 验收
- P0 若未启用 session,run/manifest 必须显式表现为
sessionRef=null或 equivalent deferred 状态。 - runner Job 不得把完整
CODEX_HOME、Secret projection 或 host path 当成 session store。 - 后续启用 session 前,必须补充真实验收:session 目录不包含 API KEY 或 profile credential。
A4 ResourceBundleRef 验收
- P0 ResourceBundle 只能是
kind="gitbundle":repoUrl + full commitId + bundles[]。 commitId不是 branch/tag/HEAD。- checkout 只能进入允许 workspace 前缀,不能覆盖
/app、Secret projection、profile runtime home 或 session 目录。 - run payload 不携带文件正文、env dump、Secret value 或大型 artifact。
- 若提供
bundles[],必须能看到每个subpath -> target_path的复制摘要;旧字段输入必须 schema-invalid。 - 若提供
promptRefs���必须能看到每个 prompt 的name/path/sha256/bytes/inject,新 thread 首轮initialPromptInjected=true,resume turninitialPromptInjected=false。 - 若 bundle 复制了
.agents/skills,必须能看到 skillDirs 聚合摘要、skill 名称和 manifest hash;不能显示模型默认 skill 列表当作业务 skill。
A5 综合验收
一次真实 runner Job 或 dry-run manifest 必须能同时回答:
- 用哪一个 image digest。
- 用哪一个 profile 和 SecretRef。
- 是否使用 session;若不用,必须明确为
null/deferred。 - 使用哪一个 Git repo 和 full commit;若 P0 尚未 materialize,必须明确为 deferred,不能隐式使用 host path。
- 是否装配 gitbundle bundles、workspace tools、初始 prompt 和 skillDirs;若提供,必须能回答 name/path/hash/inject/required 和是否注入,不能只依赖模型默认 prompt 或默认 skill registry。
- 是否装配 tool credential;若需要 GitHub PR 能力,必须能回答 tool、purpose、SecretRef 和 projection kind,不能只在运行时 shell 中偶然存在 token。
实现状态
| 要素 | v0.1 状态 | 说明 |
|---|---|---|
BackendImageRef |
部分实现 | CI/CD 已使用 digest-pinned runtime image;当前 runner/backend 仍复用 agentrun 镜像。 |
ProfileRef |
已实现/已通过 HWLAB v0.2 原入口复测 | codex、deepseek 与 minimax-m3 已通过 SecretRef、writable runtime home 和真实 stdio turn 验证;MiniMax-M3 已通过 HWLAB 显式 session 原入口复测,后续只允许作为 profile/config/SecretRef 选择,不新增直连 backend。 |
SessionRef |
已实现最小持久化 | manager 持久化 sessionId/conversationId/threadId,run 创建会解析既有 session,runner 按 threadId resume;session 不保存 credential 文件,TTL/GC 后续细化。 |
SessionRef |
v0.1.1 已实现/已通过 HWLAB v0.2 原入口复测 | manager 持久化 sessionId/conversationId/threadId + 每个 session 绑 RWO PVC(agentrun-v01-session-<sessionId>),runner Job 把 PVC 直接挂到 ${CODEX_HOME}/<codex_rollout_subdir>,codex app-server 自己落盘;runner pod 删除后 replacement runner 仍复用同一 SessionRef/PVC/thread,禁止 copy/restore、replacement threadId 和 fake resume。 |
ResourceBundleRef |
已实现 kind="gitbundle" materialization/promptRefs/tools/skillDirs 装配 |
repoUrl + full commitId + bundles[] 已进入 run schema 和 runner checkout,workspace 受 AGENTRUN_WORKSPACE_ROOT 限制,event/result 记录 commit/tree/workspace/bundles 摘要;tools/ PATH、promptRefs thread-start 注入和 .agents/skills 目录发现已实现。 |
toolCredentials |
已实现最小 env projection | GitHub PR 和 UniDesk SSH passthrough 等 agent shell/tool 授权通过装配 SPEC 的 SecretRef 进入 runner;v0.1 支持 tool=github 与 tool=unidesk-ssh、projection.kind=env,runner Job 使用 valueFrom.secretKeyRef 注入,不用 transientEnv 绕过。 |