Co-authored-by: Codex <codex@pikas.tech>
13 KiB
v0.1 Backend Adapter 规格
Backend adapter 是 runner 与具体 Code Agent 工具之间的适配层。v0.1 的正式执行路径只保留 Codex/Codex-compatible backend profile;旧 MiniMax/OpenCode 直连路线废弃,不作为 fallback、judge backend 或 Queue 首版能力。Adapter 把输入、事件、错误和 terminal status 归一化为 AgentRun 公共模型。
在系统中的职责划分
- 根据
backendProfile选择具体 backend profile;v0.1必须支持codex、deepseek与minimax-m3,三者共享同一个codex-app-server-stdiobackend kind。 - 接收 manager 持久化后的 run、command 和 executionPolicy;不得自行扩大 workspace、network、approval 或 secret scope。
- 调用具体 backend,并把 backend 输出归一化为 AgentRun events。
- 负责 provider/auth/backend/protocol 错误到 failureKind 的映射。
- 负责 backend 输出和错误中的 credential redaction。
- 暴露 backend capability 给 manager,用于
GET /api/v1/backends。
Adapter 合同
第一版可以把 adapter 实现为 runner 进程内 Bun/TypeScript 模块,不要求独立 Deployment。无论实现形态如何,对 runner 的逻辑合同必须稳定:
resolveProfile(profile) -> capability
prepare(run, command, secretProjection) -> executionContext
startTurn(executionContext) -> normalized event stream
interrupt(executionContext, command) -> backend interrupt attempt
finalize(executionContext) -> terminal status
redact(value) -> redacted value
Adapter 输入必须来自 manager 保存的 run/command 和 Kubernetes Secret projection;不得从 CLI 参数、临时环境变量或 Git 文件读取 provider credential 明文。resolveProfile(profile) 必须返回 profile、backendKind、protocol、transport、command、requiredSecretKeys 和 isolation policy;不得把 unknown profile 静默映射到默认 codex。
Backend adapter 消费 RuntimeAssembly 中的 BackendImageRef 和 ProfileRef 结果,但不定义四要素字段;四要素权威见 spec-v01-runtime-assembly.md。
v0.1 的第一真实 adapter 是 Codex stdio adapter。它必须走 Codex CLI app-server JSON-RPC over stdio;adapter 合同把 Codex 的 thread、turn、notification、tool lifecycle 和 stderr/exit 信息归一化为 AgentRun 标准 events。codex、deepseek 与 minimax-m3 只是该 adapter 的 profile/config/SecretRef 选择,不允许复制多套协议实现。
HWLAB v0.2 Code Agent 能力吸收
Backend adapter 的第一阶段实现应吸收 HWLAB v0.2 已验证的 Codex stdio 行为,而不是另写一套不兼容协议。吸收只限通用 backend 执行能力,HWLAB 的自然语言业务路由、device-pod 授权和 Workbench 展示不进入 adapter。
| HWLAB v0.2 基线 | 参考入口 | Adapter 固化规则 |
|---|---|---|
| Codex app-server JSON-RPC stdio | internal/cloud/codex-stdio-session.ts、internal/cloud/codex-stdio-session-turn-state.ts |
支持 initialize、thread/start、thread/resume、turn/start,并处理 app-server client request;未知请求要记录 unsupported error,不能静默等待。 |
| completed 判定 | docs/reference/code-agent-chat-readiness.md |
只有 Codex turn terminal completed 且 assistant reply 可聚合时才输出 completed;assistant delta、item completed、stdout 或 transport close 不能单独完成。 |
| assistant stream 和 trace | internal/cloud/code-agent-trace-store.ts、internal/cloud/codex-stdio-session-turn-state.ts |
assistant delta 只能作为 stream/progress 证据;每个非空 completed agentMessage item 必须输出一个 assistant_message event,保留 itemId 和顺序;item/agentMessage:started、item/agentMessage:completed 这类 lifecycle 不得额外持久化为 backend_status,避免同一消息在 Web/CLI trace 中重复渲染;最终 result reply 必须优先来自最后一个 completed agentMessage item,不能把 commentary/progress delta 与 final response 直接串接。event 必须保留 threadId、turnId、session 摘要和 redacted backend metadata。 |
| command/tool output bounded | docs/reference/code-agent-chat-readiness.md、web/hwlab-cloud-web/app-trace.ts |
tool_call 和 command_output 必须记录状态、摘要、字节数、截断标记;完整大输出只能通过后续 log/artifact 引用。 |
| provider/profile 隔离 | internal/cloud/code-agent-contract.ts |
codex、deepseek 与 minimax-m3 共享同一 backend kind,但必须使用 profile-scoped SecretRef、model/base-url/config 和 writable runtime home。 |
| Secret redaction | internal/cloud/code-agent-trace-store.ts |
OPENAI_API_KEY、auth/config、token、password、kubeconfig、URL credential 不得进入 event、result、log 或 health。 |
Backend Profile Registry
GET /api/v1/backends 和 adapter 内部 registry 至少报告以下 profile:
| profile | backendKind | protocol | transport | command | v0.1 状态 |
|---|---|---|---|---|---|
codex |
codex-app-server-stdio |
codex-app-server-jsonrpc-stdio |
stdio |
codex app-server --listen stdio:// |
已有主闭环,必须保持默认兼容。 |
deepseek |
codex-app-server-stdio |
codex-app-server-jsonrpc-stdio |
stdio |
codex app-server --listen stdio:// |
已实现 profile;必须用独立 SecretRef 和 profile-scoped CODEX_HOME 完成真实联调。 |
minimax-m3 |
codex-app-server-stdio |
codex-app-server-jsonrpc-stdio |
stdio |
codex app-server --listen stdio:// |
已实现 profile;必须用独立 SecretRef 和 profile-scoped CODEX_HOME 完成真实联调。 |
Registry 只表达能力和选择边界,不读取 Secret 值。Manager 负责校验 backendProfile 是否在 allowlist 内,并校验 executionPolicy.secretScope.providerCredentials 是否存在匹配 profile 的 SecretRef;runner 只为当前 run 选择的 profile 准备 Secret projection 和 runtime home。
标准事件
Adapter 输出给 runner 的 event 类型至少包括:
backend_status:backend 启动、模型/profile、能力和阶段状态,不包含 Secret 值。assistant_message:模型输出的用户可见 assistant 文本。Codex app-server 的item/agentMessage/delta只能作为流式过程证据或缺少 completed item 时的兜底;一旦收到 completedagentMessageitem,adapter 必须为每个非空 completed item 输出一条assistant_message,并用itemId、messageIndex、messageCount、replyAuthority和final标明顺序与最终 reply authority。最终 result reply 必须以最后一个replyAuthority=true/final=true的assistant_message为准,避免把 commentary/status/progress 堆入 final response。tool_call:工具调用摘要和 redacted 参数。command_output:stdout/stderr 或命令输出摘要。diff:代码变更摘要或 patch 片段;必须受长度限制。error:结构化错误和 failureKind。terminal_status:completed、failed、cancelled、blocked 等终态。
事件必须有上限和分页友好形态。大型日志、完整 stdout 或完整 trace 应进入 logPath 或后续 artifact,不得一次性塞入单个 event 造成输出爆炸。
Codex app-server 的低价值内部 notification 必须在 AgentRun adapter 层收敛,不得要求 HWLAB Web/CLI 或其他消费侧自行过滤。以下事件默认不作为 durable trace event 持久化:item/reasoning/textDelta、纯 reasoning item 的 item/started|item/completed、非 commandExecution item 的通用 item/started|item/completed、thread/tokenUsage/updated、account/rateLimits/updated、普通 warning 和 configWarning。adapter 可以输出一条有界 backend_status.phase=codex-app-server-notifications-suppressed 摘要,只包含计数、method 和 item type,不包含 reasoning 文本、Secret、token 或 env value。真实 agentMessage、commandExecution、command_output、error、terminal 和关键生命周期事件必须继续保留。
commandExecution 的 tool_call event 只能输出面向人和消费侧的扁平字段,例如 method、itemId、toolName、type、command、cwd、status、processId 和 valuesPrinted=false。不得把 Codex app-server 的原始 item JSON、itemPreview 或嵌套协议摘要写入 message、outputSummary、stdoutSummary 或 payload;命令实际 stdout/stderr 只通过 command_output 或 completed commandExecution 摘要输出。
Failure Mapping
Adapter 必须把 backend 错误映射为稳定 failureKind:
| failureKind | 典型来源 |
|---|---|
secret-unavailable |
Secret projection 缺失、文件不存在、权限不可读。 |
provider-auth-failed |
provider credential 或 auth file 无效、上游返回 401/403。 |
provider-rate-limited |
上游限流或 quota 错误。 |
provider-unavailable |
上游 provider availability/transient 失败,包括 HTTP 5xx/503、Service Unavailable、responseStreamDisconnected 携带 5xx 状态码、明确 provider unavailable 或 temporary unavailable 文案。 |
backend-protocol-error |
backend 输出无法解析、协议字段缺失。 |
backend-json-parse-error |
backend stdout 不是合法 JSON-RPC 行。 |
backend-response-invalid |
backend JSON-RPC response/terminal notification 缺少必需字段。 |
backend-spawn-failed |
backend app-server 进程无法启动。 |
backend-failed |
backend 进程非零退出或 terminal error。 |
backend-timeout |
executionPolicy timeout 触发。 |
cancelled |
interrupt/cancel 生效。 |
Credential Boundary
- Adapter 只能看到运行时投影出来的最小 Secret 文件或 env;不得枚举整个 namespace Secret。
- Adapter 不得把 Secret 值写入 event、trace、日志、CLI 输出、health 或 Postgres。
- Codex backend 的
auth.json和config.toml整体按敏感文件处理,即使其中包含非敏感配置,也不得输出原文。 - Provider base URL、model 名称和 profile 名称可以输出,但 URL credential、Authorization header、token、api_key、password 必须 redacted。
测试规格
T1 Adapter 自测试
阅读本文,然后用 mock backend 做组件自测试,确认 adapter 能把 assistant/output/error/terminal 输出归一化为标准 events,并能对 token、Authorization header、URL credential 和 Secret 文件内容做 redaction。该测试属于自测试,不作为综合联调通过证据。
T2 Failure mapping 自测试
阅读本文,然后用 mock 错误覆盖 missing secret、provider auth failure、rate limit、provider availability/transient failure、protocol error、timeout 和 cancel。provider availability/transient 样例必须至少包含 HTTP 503 Service Unavailable 或携带 5xx 的 responseStreamDisconnected,并确认不会被归类为 backend-failed。确认每类错误都映射到稳定 failureKind,且输出为 JSON 或结构化 event。
T3 真实 backend 联调
阅读本文、spec-v01-backend-codex.md 和 spec-v01-validation.md,然后分别用 backendProfile=codex、backendProfile=deepseek 与 backendProfile=minimax-m3 完成真实最短 turn。确认 adapter 输出真实 assistant/backend_status/terminal_status events,事件中包含 profile/backendKind/protocol 摘要,且没有 Secret 泄露。
T4 Profile isolation 自测试
阅读本文,然后用 fake Codex app-server 和多个不同的 profile Secret fixture 做自测试。确认 adapter 只选择 run 指定 profile 的 SecretRef 和 CODEX_HOME,deepseek 或 minimax-m3 缺失时失败为 secret-unavailable,不会 fallback 到 codex。
规格的实现情况
| 规格项 | 状态 | 说明 |
|---|---|---|
| Backend adapter 合同 | 已定义 | 本文为 v0.1 adapter 权威。 |
| 通用 adapter 模块 | 已实现 profile 形态 | src/backend/adapter.ts 作为 runner 进程内 adapter 入口;codex、deepseek 与 minimax-m3 均路由到同一 Codex stdio backend kind,不复制第二套协议实现。 |
| event normalization | 已实现主路径 | Codex backend 已把 backend_status、assistant_message、tool_call、command_output、error 和 terminal_status 归一化为 manager events;复杂事件审计按人工验收抽查。 |
| failure mapping | 已实现主路径 | Codex backend 已覆盖 missing secret、auth/rate/availability、protocol、JSON parse、invalid response、spawn、timeout 和 cancel 分类;真实负向场景按 spec-v01-validation.md T7 手动验收。 |
deepseek profile |
已实现/已通过主闭环 | 已进入 registry、validation、runner Secret selection、backend_status metadata、CLI secret render 和 fake stdio 自测试;真实综合联调已按 spec-v01-validation.md T8 覆盖 codex -> deepseek -> codex 切换。 |
minimax-m3 profile |
已实现/待真实主闭环 | 已进入 registry、validation、runner Secret selection、backend_status metadata、CLI secret render 和 fake stdio 自测试;真实综合联调需要按 spec-v01-validation.md T8 覆盖 codex -> deepseek -> minimax-m3 -> codex 切换。 |
| 多 backend 路由 | Deferred | 跨 backend kind 的自动路由和 scheduler capacity selection 不进入 v0.1。 |