162 lines
12 KiB
Markdown
162 lines
12 KiB
Markdown
# v0.1 AipodSpec 规格
|
||
|
||
`AipodSpec` 是 AgentRun `v0.1` 的声明式 agent 装配规格。它把已有的 `imageRef`、`backendProfile`、`executionPolicy.secretScope`、`ResourceBundleRef.kind="gitbundle"`、Queue task 和 Session turn 装配入口集中到 YAML 文件中,避免把某个 agent 的 work-ready env image、模型、SecretRef、gitbundle、skill 或 tool 写死在 manager、runner 或 CLI 源码里。
|
||
|
||
## 设计边界
|
||
|
||
- `AipodSpec` 只声明装配意图,不保存 API key、SSH private key、token、`auth.json`、`config.toml` 或其他 Secret 明文。
|
||
- manager 通过 `/api/v1/aipod-specs` 对 YAML 做增删改查;默认目录为仓库 `config/aipods/`,可用 `AGENTRUN_AIPOD_SPEC_DIR` 覆盖。
|
||
- CLI 通过 `aipod-specs list|show|render|apply|delete` 管理规格,通过 `queue submit --aipod <name>` 或 `sessions turn --aipod <name>` 使用规格。
|
||
- `render` 只把规格展开为标准 Queue task / Session turn 输入,输出必须脱敏,只显示 imageRef source 摘要、SecretRef 名称、key、projection、gitbundle 摘要和 `valuesPrinted=false`。
|
||
- `AipodSpec` 不引入第二套 scheduler、runner、backend adapter 或 Code Queue;最终执行仍走 AgentRun Queue、Sessions、runner Job 和 Codex app-server stdio backend。
|
||
|
||
## YAML 结构
|
||
|
||
最小结构:
|
||
|
||
```yaml
|
||
apiVersion: agentrun.pikastech.local/v0.1
|
||
kind: AipodSpec
|
||
metadata:
|
||
name: Artificer
|
||
spec:
|
||
imageRef:
|
||
kind: env-image-dockerfile
|
||
repoUrl: git@github.com:pikasTech/agentrun.git
|
||
commitId: 0000000000000000000000000000000000000000
|
||
dockerfilePath: deploy/container/Containerfile
|
||
backendProfile: sub2api
|
||
executionPolicy:
|
||
sandbox: workspace-write
|
||
approval: never
|
||
timeoutMs: 1800000
|
||
network: enabled
|
||
secretScope:
|
||
allowCredentialEcho: false
|
||
providerCredentials:
|
||
- profile: sub2api
|
||
secretRef:
|
||
name: agentrun-v01-provider-sub2api
|
||
keys: [auth.json, config.toml]
|
||
resourceBundleRef:
|
||
kind: gitbundle
|
||
repoUrl: git@github.com:pikasTech/unidesk.git
|
||
ref: master
|
||
bundles:
|
||
- subpath: .agents/skills
|
||
targetPath: .agents/skills
|
||
```
|
||
|
||
字段规则:
|
||
|
||
- `apiVersion` 固定为 `agentrun.pikastech.local/v0.1`,`kind` 固定为 `AipodSpec`。
|
||
- `metadata.name` 是 CLI/API 查找名,允许大小写,但文件落盘名会归一为安全 YAML 文件名。
|
||
- `spec.imageRef` 描述该 Aipod 的 work-ready env image 来源。`kind` 固定为 `env-image-dockerfile`,最小字段为 `repoUrl`、完整 40 位 `commitId` 和仓库内相对 `dockerfilePath`;不得用可变 image tag 代替 source 引用。
|
||
- `spec.backendProfile` 使用 AgentRun 已注册或动态的 Codex-compatible profile slug,例如 `codex`、`deepseek`、`minimax-m3`、`dsflash-go` 或 `sub2api`。
|
||
- `spec.model.model` 会展开为 command payload 的 `model` 字段;完整 `spec.model` 同时进入 `payload.modelConfig`,用于保留 `reasoningEffort` 等声明但不作为 Secret 输出。
|
||
- `spec.executionPolicy` 复用 run 的执行策略校验,且必须恰好包含一个匹配 `backendProfile` 的 provider credential SecretRef。
|
||
- `spec.resourceBundleRef` 复用 RuntimeAssembly 的 gitbundle 规则,可为 `null`,但需要注入 skill/tool 时必须使用 gitbundle。
|
||
- `spec.payloadDefaults` 与 CLI render 输入合并;用户 prompt 通过 `--prompt`、`--prompt-file` 或 `--prompt-stdin` 覆盖或补充。
|
||
|
||
## imageRef 与 env image reuse
|
||
|
||
`imageRef` 是 Aipod work-ready 环境的声明式 source,不是最终 Kubernetes image 字符串。它回答“这个 Aipod 的基础执行镜像由哪个 Git commit 中的哪个 Dockerfile/Containerfile 构建”。
|
||
|
||
本决策来自 `#146` 主线和 `#156` work-ready runner 收口:Aipod 装配完成后必须已经具备基础执行环境,`apt`、`apk`、`bun install`、`npm install` 或等价基础依赖安装不能成为普通任务运行时的默认前置。`imageRef` 必须先固化到 AipodSpec YAML,再由 dispatch/runner 解析为 env identity 和 digest-pinned image;不得用 prompt、payload、临时 CLI 参数或 dispatcher 当前 rollout commit 替代。
|
||
|
||
最小结构:
|
||
|
||
```yaml
|
||
imageRef:
|
||
kind: env-image-dockerfile
|
||
repoUrl: git@github.com:pikasTech/agentrun.git
|
||
commitId: 0000000000000000000000000000000000000000
|
||
dockerfilePath: deploy/container/Containerfile
|
||
```
|
||
|
||
规则:
|
||
|
||
- `repoUrl` 必须是无明文 credential 的 Git URL;credential 只能通过受控 Git/mirror 运行面获取。
|
||
- `commitId` 必须是完整 commit SHA,不能是 branch、tag、short SHA 或 dispatcher 当前 rollout hint。
|
||
- `dockerfilePath` 必须是 repo 内相对路径,不能包含 `..`,不能是绝对路径。
|
||
- Aipod 启动或 Queue dispatch 时必须先按 `imageRef` 解析 env image identity,并优先查询 artifact catalog / registry 复用已有 digest-pinned env image。
|
||
- catalog/registry 未命中时只允许进入受控 CI/CD 构建路径;普通 Aipod 启动不得在任务内部临时 `apt`、`apk`、`bun install`、`npm install` 或等价命令补基础环境。
|
||
- runner job 最终只接受解析后的 digest-pinned image;response、event 和 result 必须输出 `imageRef` source、env identity、reuse/build 状态和 digest 摘要,不输出 Secret。
|
||
|
||
## Artificer 默认规格
|
||
|
||
仓库内置 `config/aipods/artificer.yaml`,名称为 `Artificer`。它的长期目标是承接 UniDesk 分布式开发任务:
|
||
|
||
- 使用 `backendProfile=sub2api`,模型声明为 `gpt-5.5`,reasoning effort 为 `xhigh`。
|
||
- 通过 `imageRef` 引用 AgentRun `v0.1` env image Dockerfile source;当前默认值是 `repoUrl=git@github.com:pikasTech/agentrun.git`、`commitId=6601b4afb4870ecec62f14459e14202e5ccca7ec`、`dockerfilePath=deploy/container/Containerfile`。启动时必须复用已物化的 digest-pinned env image,不能把依赖安装留给任务运行时。
|
||
- 通过 provider SecretRef `agentrun-v01-provider-sub2api` 获取 `auth.json` 与 `config.toml`。
|
||
- 通过 `toolCredentials` 获取 GitHub Issue/PR 写入 token:`agentrun-v01-tool-github-pr` -> env `GH_TOKEN`。
|
||
- 通过 `toolCredentials` 获取 UniDesk SSH 透传 token:`agentrun-v01-tool-unidesk-ssh` -> env `UNIDESK_SSH_CLIENT_TOKEN`。
|
||
- 通过 `toolCredentials` 获取 GitHub SSH 凭据:`agentrun-v01-tool-github-ssh` -> volume `/home/agentrun/.ssh`。
|
||
- 通过声明 GitHub repo URL 的多仓库 gitbundle,装配 UniDesk repo 中的 `unidesk-*` skills、AgentRun repo 中的 `tools/trans`、`tools/tran`、`tools/apply_patch`,以及 `agent_skills` repo 中的 `dad-dev`、`cli-spec`、`docs-spec`、`git-spec`;runner 物化阶段自动把 GitHub URL 改写到 G14 git mirror,Artificer 规格本身不声明 mirror 开关或 mirror base URL。
|
||
- 通过 `requiredSkills[]` 在 runner 启动 backend 前校验 `dad-dev` 与 UniDesk 关键 skills 已被 materialize;缺失时必须 `required-skill-unavailable`,不得使用模型默认 skill 猜测。
|
||
- Artificer 默认是 session-capable agent。`render`/`queue submit --aipod Artificer` 在调用方没有显式传入 `sessionRef` 时,必须生成稳定的默认 `SessionRef`,`sessionId` 使用 `sess_artificer_<24 hex>` 形态,`conversationId` 默认等于 `sessionId`,并把该引用写入 Queue task/run 装配输入;后续 follow-up、补测、reviewer feedback 和 manager recovery 优先继续同一个 session,而不是每次新开 session。
|
||
|
||
## Git mirror
|
||
|
||
Git mirror 是 AgentRun/G14 基础设施能力,不是 AipodSpec 或 Queue task 规格能力。`AipodSpec.spec.resourceBundleRef` 必须继续声明无明文 credential 的 GitHub repo URL;不得在 AipodSpec、Queue task、prompt 或业务 adapter 中声明 `gitMirror`、mirror base URL、direct/mirror 开关或 per-agent mirror 策略。
|
||
|
||
规则:
|
||
|
||
- runner 在 materialization 阶段自动把 GitHub URL 改写为 G14 git mirror read URL;基础 URL 来自 `AGENTRUN_GIT_MIRROR_BASE_URL`,缺省为 `http://git-mirror-http.devops-infra.svc.cluster.local`。
|
||
- 支持 `git@github.com:owner/repo.git`、`ssh://git@github.com/owner/repo.git`、`ssh://git@ssh.github.com:443/owner/repo.git` 和 `https://github.com/owner/repo.git`。
|
||
- 非 GitHub URL 不改写,仍按原 `repoUrl` fetch。
|
||
- devops-infra mirror cache 必须覆盖 Artificer 默认 bundle 使用的 `pikasTech/unidesk`、`pikasTech/agentrun` 和 `pikasTech/agent_skills`;缺 cache 是基础设施缺口,不能通过修改 AipodSpec 直连 GitHub 来绕过。
|
||
- materialization event 必须输出原始 `repoUrl`、实际 `fetchRepoUrl`、`mirrorUsed`、`mirrorBaseUrl`、requested ref/commit 和实际 commit;不得输出 credential 值。
|
||
|
||
## Tool credential projection
|
||
|
||
`toolCredentials[]` 支持两类 projection:
|
||
|
||
- `env`:把 Secret key 作为环境变量注入 runner,例如 `UNIDESK_SSH_CLIENT_TOKEN`。
|
||
- `volume`:把 Secret keys 作为只读文件挂载到 `/home/agentrun/` 下,例如 GitHub SSH 的 `/home/agentrun/.ssh`。
|
||
|
||
约束:
|
||
|
||
- `unidesk-ssh` 必须使用 env projection,且 env/key 都必须是 `UNIDESK_SSH_CLIENT_TOKEN`。
|
||
- volume projection 的 `mountPath` 必须位于 `/home/agentrun/` 下,不能包含 `..`。
|
||
- runner Job response、dry-run manifest、event 和日志只能显示 SecretRef 名称、key、projection kind 与 mount path,不得显示 Secret value。
|
||
|
||
## API 与 CLI
|
||
|
||
REST API:
|
||
|
||
- `GET /api/v1/aipod-specs`:列出可用规格。
|
||
- `POST /api/v1/aipod-specs`:从 `{ yaml }` 或 `{ spec }` 创建/更新规格。
|
||
- `GET /api/v1/aipod-specs/:name`:查看规格和摘要。
|
||
- `PUT /api/v1/aipod-specs/:name`:按 URL 名称更新规格,URL name 必须匹配 `metadata.name`。
|
||
- `DELETE /api/v1/aipod-specs/:name`:删除规格文件。
|
||
- `POST /api/v1/aipod-specs/:name/render`:把规格和本次输入展开为 Queue task。
|
||
|
||
Artificer 依赖的 GitHub SSH Secret 由 `tool-credentials set-github-ssh` 单独 bootstrap。`AipodSpec` 只引用 SecretRef,不读取或保存 SSH private key。
|
||
|
||
CLI:
|
||
|
||
```bash
|
||
./scripts/agentrun aipod-specs list
|
||
./scripts/agentrun aipod-specs show Artificer
|
||
./scripts/agentrun aipod-specs render Artificer --prompt-stdin
|
||
./scripts/agentrun aipod-specs apply --yaml-stdin
|
||
./scripts/agentrun aipod-specs delete Artificer
|
||
./scripts/agentrun queue submit --aipod Artificer --prompt-stdin --idempotency-key <key>
|
||
./scripts/agentrun sessions turn --aipod Artificer --prompt-stdin
|
||
./scripts/agentrun tool-credentials set-github-ssh --private-key-file <id_ed25519> --known-hosts-file <known_hosts> [--config-file <ssh_config>]
|
||
```
|
||
|
||
所有 mutating CLI 必须短返回 JSON;`--dry-run` 只输出 mutation plan 和确认命令,不写 manager。
|
||
|
||
## 测试规格
|
||
|
||
- A1:`config/aipods/artificer.yaml` 能被 manager list/show/render,render 结果包含 `imageRef.kind=env-image-dockerfile`、`repoUrl`、`commitId`、`dockerfilePath`、`backendProfile=sub2api`、`model=gpt-5.5`、`reasoningEffort=xhigh`、provider SecretRef、GitHub PR token env projection、UniDesk SSH env projection、GitHub SSH volume projection、无 `resourceBundleRef.gitMirror` 字段、AgentRun runner tools gitbundle 和 gitbundle requiredSkills。
|
||
- A2:`queue submit --aipod Artificer --dry-run` 输出标准 `queue-submit-plan`,且 `idempotencyKey`、prompt 与 metadata 被保留。
|
||
- A2b:`queue submit --aipod Artificer --dry-run` 或 `render Artificer` 在没有显式 `sessionRef` 时必须输出默认 `sessionRef.sessionId` / `conversationId`;显式传入 `sessionRef` 时不得覆盖。
|
||
- A3:Artificer 规格只声明 GitHub URL,不声明 `gitMirror`;runner 默认把 GitHub URL 改写到 mirror base URL,非 GitHub URL 不改写。请求体显式携带 `resourceBundleRef.gitMirror` 必须 schema-invalid,避免把基础设施策略下放到 AipodSpec。
|
||
- A4:Aipod 启动/dispatch 能基于 `imageRef` 命中 artifact catalog / registry 并复用 digest-pinned env image;未命中时返回明确 build-required 或进入受控 CI/CD,不在 runner 任务内补装依赖。
|
||
- A5:runner Job dry-run 支持 tool credential volume mount,并且 response/manifest/event 不泄漏 Secret 明文。
|
||
- A6:`bun run check` 和 `bun run self-test` 必须覆盖 A1-A5。
|