内置的三个 sandbox agent(claude-code、codex、bub)不是同一档实现。niceeval 把 adapter 能力拆成几档递进:档位越高,能写的断言越多。这篇按档位盘点三个内置 agent 各自做到哪,以及两个接 AI SDK 应用的内置件:进程内 agent 工厂 aiSdkAgent(含 HITL)和底层转换器 fromAiSdk。
分档速览
| 档位 | 解锁什么 |
|---|
| T0 · 收发消息 | t.send() 单发一轮、turn.outputEquals / outputMatches、按状态判断的 t.succeeded() |
T1 · 事件流(toolObservability) | calledTool / toolOrder / usedNoTools / maxToolCalls / messageIncludes / noFailedActions / event / eventOrder 等整套作用域断言;负断言(notCalledTool 等)从此才可信 |
T2 · 多轮会话(conversation) | t.send() 可多次调用、t.reply、t.newSession() |
| HITL(人工介入) | t.parked()、t.requireInputRequest()、t.respond() / t.respondAll() |
| T3 · tracing | EvalResult.trace、niceeval view 的调用瀑布图 |
三个内置 agent 分别做到哪
| Agent | T0 | T1 事件流 | T2 会话 | HITL | T3 tracing | 备注 |
|---|
claude-code | ✅ | ✅ | ✅(claude --resume <id>) | ❌ | ❌ | 额外声明 compactionObservability,t.event("compaction") 可用 |
codex | ✅ | ✅ | ✅(codex exec resume <id>) | ❌ | ✅(http/json → OTLP) | 额外声明 compactionObservability |
bub | ✅ | ✅ | ✅(--session-id + tape 续接) | ❌ | ✅(http/protobuf → OTLP) | 额外声明 compactionObservability |
三者都声明了 workspace 和 sandbox(defineSandboxAgent 默认开启),所以 t.sandbox.fileChanged() / diff 断言、文件 IO、命令执行在三个 agent 上都能用,不受这张表限制。
三个内置 sandbox agent 目前都不支持 HITL:send 只返回 "completed" / "failed",从不返回 "waiting",也不吐 input.requested 事件。需要 t.respond() / t.requireInputRequest() 时,可以用下文的内建 aiSdkAgent(AI SDK v7 tool approval 原生映射成 HITL),或自己写 adapter:实现 waiting 状态 + input.requested 事件 + resume 交回。
逐 agent 细节
claude-code
- 连接方式:沙箱里 spawn
claude --print --dangerously-skip-permissions,读回 ~/.claude/projects/**/*.jsonl 最新一份 transcript。
- 会话续接:
ctx.session.isNew 为 false 且有 id 时追加 --resume <id>。
- 鉴权:
ANTHROPIC_API_KEY(可用配置项 apiKey 覆盖),可选 ANTHROPIC_BASE_URL。
- 支持
mcpServers、skills(GitHub org/repo)配置项。
- 没有声明
tracing:不会起 OTLP 接收器,EvalResult.trace 为空。
codex
- 连接方式:沙箱里跑
codex exec --json(续接时是 codex exec resume <id> --json),stdout JSONL 当 transcript。
- 鉴权:
CODEX_API_KEY(不是 OPENAI_API_KEY),可选 CODEX_BASE_URL 接 OpenAI 兼容代理。
tracing 通过 ~/.codex/config.toml 的 [otel.trace_exporter.otlp-http] 段配置,协议 http/json。
- 支持
mcpServers、skills 配置项。
bub
- 连接方式:沙箱里跑
bub run + --session-id,从 ~/.bub/tapes/<hash>.jsonl 读 tape 当 transcript。
- 鉴权:
BUB_API_KEY + BUB_API_BASE(OpenAI 兼容代理)。
tracing 通过环境变量注入(OTEL_EXPORTER_OTLP_TRACES_ENDPOINT 等),协议 http/protobuf。
- 支持
pythonPlugins 配置项。
- 安装走
uv tool install(非 npm 包),首次安装带 checkpoint 缓存以加速后续沙箱。
aiSdkAgent:接 AI SDK 应用的内建 agent 工厂(含 HITL)
aiSdkAgent(niceeval/adapter 导出)把「一个 generateText 调用」变成完整的进程内 agent。应用只写 generate(怎么召模型:model / tools / system prompt 都在这里配),协议侧的活全部由工厂承担:
import { aiSdkAgent } from "niceeval/adapter";
import { generateText, isStepCount, type ModelMessage } from "ai";
export default defineExperiment({
agent: aiSdkAgent<ModelMessage>({
name: "my-assistant",
generate: ({ messages, model, signal }) =>
generateText({ model: resolveModel(model), system: SYSTEM_PROMPT,
tools, stopWhen: isStepCount(5), messages, abortSignal: signal }),
data: (result) => ({ reply: result.text }),
}),
model: "deepseek-v4-pro",
});
工厂承诺的档位:
- T0 / T1:结果经
fromAiSdk 直构——toolCallId 精确配对、时序保真、tool-error 映射成失败的 action.result、usage 聚合(v4 / v5 / v7 字段漂移都兜住)。
- T2 会话:
messages 历史由工厂管理,isNew 开新会话线、同 id 续接。
- HITL:AI SDK v7 的 tool approval(工具带
needsApproval: true)原生映射——模型决定调用被拦工具时,本轮返回 status: "waiting" + input.requested 事件(action = 工具名、options = approve / deny);t.respond("approve" / "deny") 由工厂翻译成 tool-approval-response 交回 SDK,拒绝的调用以 rejected(而非 failed)落进事件流,calledTool(..., { status: "rejected" }) 可精确断言。这是目前唯一原生支持 HITL 的内置件。
- T3 tracing:声明
capabilities: { tracing: true } 后,generate 能从 telemetry.endpoint 拿到本轮 OTLP 接收端点,自己把 span 发过去(参考示例里的手搓 OTLP/JSON 导出)。
workspace / sandbox 不适用(它评的是 AI SDK 应用,不是改文件的 coding agent)——这正是 Agent × Sandbox 正交的含义。完整可跑示例见仓库 examples/zh/ai-sdk-v7/(六条 eval 逐档演示:结构化输出、事件流断言、多轮隔离、HITL 批准 / 拒绝、多模态、trace)。
fromAiSdk:aiSdkAgent 底下的 T1+ 转换器
fromAiSdk(niceeval/adapter 导出)是 aiSdkAgent 内部用的转换函数,也可以在自己写的 adapter 里单独用(比如 HTTP web agent 的服务端直构,见 examples/zh/ai-sdk/)。它把 AI SDK 的 generateText / streamText 结果映射成 { events, usage, status },直接铺进 Turn:
import { defineAgent, fromAiSdk } from "niceeval/adapter";
export default defineAgent({
name: "my-ai-sdk-agent",
async send(input) {
const result = await generateText({ model, tools, prompt: input.text });
return { ...fromAiSdk(result), data: result.text };
},
});
status 由转换器给:有待人批准的 tool approval 时是 "waiting"(并附 input.requested 事件),否则 "completed"。要不要做到 T2(多轮 resume)、HITL 的裁决交回、T3(tracing)取决于你自己的 send 怎么写——这三样正是 aiSdkAgent 工厂替你写好的部分。
怎么选
- 被测对象是 AI SDK agent 应用(工具循环):直接用
aiSdkAgent,全档(T0 + T1 + T2 + HITL,tracing 可选)。
- 需要调用瀑布图(
niceeval view 的 trace):codex / bub / aiSdkAgent(自发 OTLP),claude-code 目前拿不到 trace。
- 需要人工审批 / 多步确认(HITL):目前只有
aiSdkAgent(AI SDK v7 tool approval);沙箱型三个都不支持,其它被测对象要自己写 adapter。
- 想跑一个 coding agent 改代码、看 diff、判断工具调用:
claude-code / codex / bub(T0 + T1 + T2 + workspace + sandbox)。
相关阅读