> ## Documentation Index
> Fetch the complete documentation index at: https://niceeval.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# 内置 Agent 能力参考

> NiceEval 内置的 claude-code、codex、bub 适配器分别做到了哪些能力，对应哪些断言，以及已知限制。

内置的三个 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 上都能用，不受这张表限制。

<Warning>
  三个内置 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 交回。
</Warning>

## 逐 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` 都替你做了：

```ts theme={null}
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`：

```ts theme={null}
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）。

## 相关阅读

* [接入你的 agent](/zh/guides/connect-your-agent) — 自己写 adapter 时每个能力怎么做、对应什么断言。
* [Sandbox Agent](/zh/guides/sandbox-agent) — 怎么运行内置 sandbox agent，以及怎么写自己的。
* [defineAgent 参考](/zh/reference/define-agent) — `defineAgent` / `defineSandboxAgent` 完整参数。
* [通过 OTel 接入](/zh/guides/connect-otel) — 已埋点应用的免映射接法。
