内置的三个 sandbox agent(claude-code、codex、bub)做到的能力不完全相同。adapter 的能力是正交的组合,每个能力对应一组断言。这篇按能力盘点三个内置 agent 各自做到哪,以及两个接 AI SDK 应用的内置件:进程内 agent 工厂 aiSdkAgent(含 HITL)和底层转换器 fromAiSdk。
能力速览
| 能力 | 对应的断言 / API |
|---|
| 收发消息(基础契约) | t.send()(可多次调用)、t.reply、turn.outputEquals / outputMatches、按状态判断的 t.succeeded() |
toolObservability · 事件流 | calledTool / toolOrder / usedNoTools / maxToolCalls / messageIncludes / noFailedActions / event / eventOrder 等整套作用域断言;负断言(notCalledTool 等)有完整事件流才可信 |
conversation · 会话续接 | 跨轮记忆断言、t.newSession() 会话隔离 |
| HITL(人工介入) | t.parked()、t.requireInputRequest()、t.respond() / t.respondAll() |
tracing | EvalResult.trace、niceeval view 的调用瀑布图 |
三个内置 agent 分别做到哪
| Agent | 收发 | 事件流 | 会话续接 | HITL | 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 都在这里配),协议侧的活 aiSdkAgent 都替你做了:
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",
});
它替你做好的能力:
- 收发 + 事件流:结果经
fromAiSdk 直构——toolCallId 精确配对、时序保真、tool-error 映射成失败的 action.result、usage 聚合(v4 / v5 / v7 字段漂移都兜住)。
- 会话续接:
messages 历史由 aiSdkAgent 管理,isNew 开新会话线、同 id 续接。
- HITL:AI SDK v7 的 tool approval(工具带
needsApproval: true)原生映射——模型决定调用被拦工具时,本轮返回 status: "waiting" + input.requested 事件(action = 工具名、options = approve / deny);t.respond("approve" / "deny") 由 aiSdkAgent 翻译成 tool-approval-response 交回 SDK,拒绝的调用以 rejected(而非 failed)落进事件流,calledTool(..., { status: "rejected" }) 可精确断言。这是目前唯一原生支持 HITL 的内置件。
- tracing:声明
capabilities: { tracing: true } 后,OTel 管线全由工厂承担——每轮把绑定 NiceEval 接收端点的 @ai-sdk/otel 集成经 telemetry 交给 generate(原样透传给 generateText 的 telemetry 选项即可),轮末自动 flush;并行 attempt 各用各的出口,不串流。设 otlpBackendUrl 可把同一批 span 双发到你自己的观测后端。需要在项目里安装 @ai-sdk/otel、@opentelemetry/sdk-trace-node、@opentelemetry/exporter-trace-otlp-http(NiceEval 的可选 peer 依赖,只有 tracing 用到)。
workspace / sandbox 不适用(它评的是 AI SDK 应用,不是改文件的 coding agent)——这正是 Agent × Sandbox 正交的含义。完整可跑示例见仓库 examples/zh/ai-sdk-v7/(六条 eval 逐项演示:结构化输出、事件流断言、多轮隔离、HITL 批准 / 拒绝、多模态、trace)。
fromAiSdk:aiSdkAgent 底下的事件流转换器
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"。会话续接(多轮 resume)、HITL 的裁决交回、tracing 取决于你自己的 send 怎么写——这三样正是 aiSdkAgent 替你写好的部分。
怎么选
- 被测对象是 AI SDK agent 应用(工具循环):直接用
aiSdkAgent,所有能力都已做好(含 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(收发 + 事件流 + 会话续接 + workspace + sandbox)。
相关阅读