niceeval 0.2.1 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +34 -34
- package/README.zh.md +29 -15
- package/docs/README.md +2 -1
- package/docs/adapters/collection.md +1 -1
- package/docs/adapters/contract.md +6 -5
- package/docs/adapters/reference/claude-code-otel-telemetry.md +1 -1
- package/docs/architecture.md +20 -20
- package/docs/assertions.md +0 -1
- package/docs/capabilities-by-construction.md +2 -2
- package/docs/cli.md +2 -2
- package/docs/concepts.md +2 -2
- package/docs/e2e-ci.md +135 -98
- package/docs/eval-authoring.md +3 -3
- package/docs/experiments.md +7 -4
- package/docs/observability.md +9 -5
- package/docs/origin-integration.md +18 -18
- package/docs/references.md +1 -1
- package/docs/reports.md +551 -0
- package/docs/results-format.md +3 -3
- package/docs/results-lib.md +191 -0
- package/docs/runner.md +1 -1
- package/docs/sandbox.md +1 -1
- package/docs/source-map.md +22 -2
- package/docs/tier-sync.md +74 -58
- package/docs/view.md +41 -4
- package/package.json +29 -3
- package/src/agents/ai-sdk.ts +3 -0
- package/src/agents/claude-code.ts +18 -1
- package/src/agents/codex.ts +3 -2
- package/src/agents/index.ts +16 -0
- package/src/agents/openai-compat.test.ts +56 -0
- package/src/agents/openai-compat.ts +151 -0
- package/src/agents/types.ts +3 -1
- package/src/cli.ts +2 -1
- package/src/context/context.test.ts +78 -1
- package/src/context/context.ts +19 -11
- package/src/context/session.ts +2 -0
- package/src/context/types.ts +11 -5
- package/src/i18n/en.ts +8 -4
- package/src/i18n/zh-CN.ts +6 -3
- package/src/o11y/cost.test.ts +40 -0
- package/src/o11y/cost.ts +27 -5
- package/src/o11y/derive.ts +2 -2
- package/src/o11y/otlp/mappers/claude-code.test.ts +31 -0
- package/src/o11y/otlp/mappers/claude-code.ts +24 -0
- package/src/o11y/otlp/mappers/index.ts +1 -0
- package/src/o11y/otlp/parse.test.ts +127 -0
- package/src/o11y/prices.json +176 -119
- package/src/o11y/types.ts +2 -1
- package/src/report/aggregate.ts +215 -0
- package/src/report/compute.ts +405 -0
- package/src/report/format.ts +47 -0
- package/src/report/index.ts +40 -0
- package/src/report/metrics.ts +96 -0
- package/src/report/react/CaseList.tsx +70 -0
- package/src/report/react/DeltaTable.tsx +79 -0
- package/src/report/react/MetricMatrix.tsx +75 -0
- package/src/report/react/MetricScatter.tsx +217 -0
- package/src/report/react/MetricTable.tsx +71 -0
- package/src/report/react/RunOverview.tsx +87 -0
- package/src/report/react/Scoreboard.tsx +87 -0
- package/src/report/react/cell.tsx +49 -0
- package/src/report/react/colors.ts +42 -0
- package/src/report/react/data.ts +17 -0
- package/src/report/react/fixtures.ts +236 -0
- package/src/report/react/format.ts +34 -0
- package/src/report/react/index.tsx +34 -0
- package/src/report/react/render.test.tsx +303 -0
- package/src/report/react/styles.css +302 -0
- package/src/report/report.test.ts +667 -0
- package/src/report/types.ts +210 -0
- package/src/results/copy.ts +200 -0
- package/src/results/format.ts +75 -0
- package/src/results/index.ts +27 -0
- package/src/results/open.ts +207 -0
- package/src/results/results.test.ts +359 -0
- package/src/results/select.ts +101 -0
- package/src/results/types.ts +98 -0
- package/src/runner/attempt.ts +3 -1
- package/src/runner/report.test.ts +111 -0
- package/src/runner/report.ts +52 -1
- package/src/runner/reporters/artifacts.ts +1 -1
- package/src/runner/reporters/braintrust.test.ts +106 -0
- package/src/runner/reporters/braintrust.ts +197 -0
- package/src/runner/reporters/console.ts +3 -3
- package/src/runner/reporters/index.ts +3 -1
- package/src/runner/reporters/live.ts +17 -5
- package/src/runner/reporters/shared.ts +3 -0
- package/src/runner/reporters/table.ts +1 -0
- package/src/runner/run.ts +31 -18
- package/src/runner/types.ts +20 -1
- package/src/sandbox/types.ts +3 -3
- package/src/shared/format.ts +8 -2
- package/src/view/app/App.tsx +82 -17
- package/src/view/app/components/AttemptModal.tsx +9 -2
- package/src/view/app/components/CodeView.tsx +2 -2
- package/src/view/app/components/CostScoreChart.tsx +127 -0
- package/src/view/app/components/LazyArtifact.tsx +2 -1
- package/src/view/app/i18n.ts +13 -1
- package/src/view/app/lib/artifact-url.ts +6 -0
- package/src/view/app/lib/attempt-route.test.ts +89 -0
- package/src/view/app/lib/attempt-route.ts +52 -0
- package/src/view/app/lib/chart.ts +72 -0
- package/src/view/app/lib/outcome.ts +1 -1
- package/src/view/app/types.ts +4 -5
- package/src/view/client-dist/app.css +1 -1
- package/src/view/client-dist/app.js +18 -18
- package/src/view/index.ts +36 -7
- package/src/view/loader.ts +14 -7
- package/src/view/server.ts +7 -0
- package/src/view/shared/types.ts +14 -1
- package/src/view/styles.css +43 -0
- package/src/view/template.html +0 -1
package/README.md
CHANGED
|
@@ -12,13 +12,17 @@
|
|
|
12
12
|
|
|
13
13
|
</div>
|
|
14
14
|
|
|
15
|
-
NiceEval is an
|
|
15
|
+
NiceEval is an Agent-Native eval tool inspired by [eve](https://eve.dev), built for the best possible DX.
|
|
16
16
|
|
|
17
|
-
|
|
17
|
+
Thanks to its universal design, NiceEval can evaluate almost any agent application.
|
|
18
|
+
Whether you need to evaluate coding agent plugins, Hooks, and Skills written for Claude Code / Codex, or your own AI agent application — both plug in easily.
|
|
19
|
+
|
|
20
|
+
After the eval completes, it generates readable reports and lets you view agent behavior details. Convenient for debugging and understanding agent behavior.
|
|
18
21
|
|
|
19
22
|
## Why NiceEval when DeepEval, LangFuse, and BrainTrust already exist
|
|
20
23
|
|
|
21
|
-
NiceEval is an
|
|
24
|
+
NiceEval is an Agent-Native eval tool. The Dataset / golden pattern of building an Input and an Expected Output doesn't fit real agent evaluation.
|
|
25
|
+
Agents today need to be evaluated at a finer grain — multi-turn conversations, multi-agent collaboration, tool calls, skill loading — and NiceEval does this better.
|
|
22
26
|
|
|
23
27
|
It also coexists with LangFuse and BrainTrust: use them for tracing, or upload eval results to both (in progress).
|
|
24
28
|
|
|
@@ -32,19 +36,19 @@ NiceEval supports two integration modes, depending on whether the agent under te
|
|
|
32
36
|
evals/*.eval.ts
|
|
33
37
|
│
|
|
34
38
|
▼
|
|
35
|
-
|
|
36
|
-
│
|
|
37
|
-
|
|
39
|
+
┌────────────┐
|
|
40
|
+
│ NiceEval │
|
|
41
|
+
└────────────┘
|
|
38
42
|
│
|
|
39
43
|
│ Agent adapter (official)
|
|
40
44
|
▼
|
|
41
|
-
|
|
42
|
-
│
|
|
43
|
-
│
|
|
44
|
-
│
|
|
45
|
-
│
|
|
46
|
-
│
|
|
47
|
-
|
|
45
|
+
┌────────────────────────────────┐
|
|
46
|
+
│ Docker Sandbox │
|
|
47
|
+
│ ┌────────────────────────┐ │
|
|
48
|
+
│ │ Codex / Claude Code │ │
|
|
49
|
+
│ │ apps needing isolation │ │
|
|
50
|
+
│ └────────────────────────┘ │
|
|
51
|
+
└────────────────────────────────┘
|
|
48
52
|
```
|
|
49
53
|
|
|
50
54
|
**Mode 2: Direct — connect straight to your own AI Agent**
|
|
@@ -53,18 +57,16 @@ NiceEval supports two integration modes, depending on whether the agent under te
|
|
|
53
57
|
evals/*.eval.ts
|
|
54
58
|
│
|
|
55
59
|
▼
|
|
56
|
-
|
|
57
|
-
│
|
|
58
|
-
|
|
60
|
+
┌────────────┐
|
|
61
|
+
│ NiceEval │
|
|
62
|
+
└────────────┘
|
|
59
63
|
│
|
|
60
64
|
│ Agent adapter (official, or your own implementation)
|
|
61
65
|
▼
|
|
62
|
-
|
|
63
|
-
│
|
|
64
|
-
│ (AI SDK·LangGraph·Pi
|
|
65
|
-
|
|
66
|
-
│ no Docker needed) │
|
|
67
|
-
└──────────────────────────────┘
|
|
66
|
+
┌──────────────────────────┐
|
|
67
|
+
│ your own AI Agent │
|
|
68
|
+
│ (AI SDK·LangGraph·Pi) │
|
|
69
|
+
└──────────────────────────┘
|
|
68
70
|
```
|
|
69
71
|
|
|
70
72
|
- **NiceEval core** owns discovery, scheduling, scoring, reporting, and artifacts.
|
|
@@ -74,8 +76,6 @@ NiceEval supports two integration modes, depending on whether the agent under te
|
|
|
74
76
|
|
|
75
77
|
## Example
|
|
76
78
|
|
|
77
|
-
Running an eval takes two files: the eval itself (what to check) and an experiment (which agent to run it against). The CLI won't run a bare eval id — the experiment in `niceeval exp <experiment> <eval prefix>` is what picks the system under test. Here's a real eval against a directly-connected web agent (full project in [`examples/zh/ai-sdk/`](examples/zh/ai-sdk/)), checking that the agent calls a tool for live weather questions and answers from the tool result instead of making it up:
|
|
78
|
-
|
|
79
79
|
```ts
|
|
80
80
|
// evals/eval-tool-call.eval.ts
|
|
81
81
|
import { defineEval } from "niceeval";
|
|
@@ -109,16 +109,15 @@ import { webAgent } from "./adapter"; // your agent adapter, pointed at the syst
|
|
|
109
109
|
|
|
110
110
|
export default defineExperiment({
|
|
111
111
|
agent: webAgent({ baseUrl: "http://127.0.0.1:5188" }),
|
|
112
|
+
model: "gpt-5.5"
|
|
112
113
|
});
|
|
113
114
|
```
|
|
114
115
|
|
|
115
116
|
```sh
|
|
116
|
-
|
|
117
|
-
|
|
117
|
+
pnpm exec niceeval exp local eval-tool-call // run only eval-tool-call under the local experiment
|
|
118
|
+
pnpm exec niceeval view // view eval results
|
|
118
119
|
```
|
|
119
120
|
|
|
120
|
-
For coding agents that need an isolated workspace (Codex, Claude Code plugins/skills), see [`examples/zh/coding-agent-skill/`](examples/zh/coding-agent-skill/): evals there use `t.sandbox.uploadDirectory()` to seed the workspace, `t.fileChanged()` / `t.file()` to check what changed, and `t.sandbox.runCommand()` to run tests.
|
|
121
|
-
|
|
122
121
|
## Quick Start
|
|
123
122
|
|
|
124
123
|
```text
|
|
@@ -135,19 +134,20 @@ Start from the scenario that matches what you need to evaluate:
|
|
|
135
134
|
## Roadmap
|
|
136
135
|
Official Adapters
|
|
137
136
|
- [ ] Agent Software
|
|
138
|
-
- [
|
|
139
|
-
- [
|
|
140
|
-
- [
|
|
137
|
+
- [x] Claude Code
|
|
138
|
+
- [x] Codex
|
|
139
|
+
- [x] Bub
|
|
141
140
|
- [ ] OpenClaw
|
|
142
141
|
- [ ] Hermess Agent
|
|
143
142
|
- [ ] Alma
|
|
144
143
|
- [ ] ...
|
|
145
144
|
|
|
146
145
|
- [ ] Agent Frameworks
|
|
147
|
-
- [
|
|
146
|
+
- [x] AI SDK
|
|
147
|
+
- [x] Claude SDK
|
|
148
|
+
- [x] Codex SDK
|
|
149
|
+
- [x] Pi Agent SDK
|
|
148
150
|
- [ ] LangGraph
|
|
149
|
-
- [ ] Claude SDK
|
|
150
|
-
- [ ] Codex SDK
|
|
151
151
|
- [ ] vm0
|
|
152
152
|
- [ ] Cursor Agent SDK
|
|
153
153
|
|
package/README.zh.md
CHANGED
|
@@ -12,12 +12,16 @@
|
|
|
12
12
|
|
|
13
13
|
</div>
|
|
14
14
|
|
|
15
|
-
NiceEval 是一个受 [eve](https://eve.dev) 启发的
|
|
15
|
+
NiceEval 是一个受 [eve](https://eve.dev) 启发的 Agent-Native eval 工具,追求极致的DX。
|
|
16
|
+
|
|
17
|
+
通过通用式的设计,使 NiceEval 可以为几乎所有 Agent 应用进行评估。
|
|
18
|
+
无论你是需要评估为 Claude Code / Codex 写的 coding agent 插件、Hook 和 Skill,还是可以评估你自己的 AI Agent 应用都能轻松接入。
|
|
16
19
|
|
|
17
20
|
在 eval 完成之后可以生成易读的报告与查看 Agent 的行为细节。方便 Debug 与理解 Agent 行为。
|
|
18
21
|
|
|
19
22
|
## 为什么有了 DeepEval、LangFuse、BrainTrust 还需要 NiceEval
|
|
20
|
-
NiceEval 是一个
|
|
23
|
+
NiceEval 是一个 Agent-Native 的评估工具。Dataset / golden 那一套「构建 Input 与 Expected Output」的模式,并不适合真实的 Agent 评估。
|
|
24
|
+
现在 Agent 需要在多轮对话、多 agent 协作、工具调用、Skill 加载等细粒度场景下进行评估,NiceEval 能做得更好。
|
|
21
25
|
|
|
22
26
|
同时,NiceEval 也能与 LangFuse、BrainTrust 共存:可以用它们做 tracing,或者把评估结果上传到两者(这部分功能还在开发中)。
|
|
23
27
|
|
|
@@ -40,8 +44,8 @@ NiceEval 支持两种接入方式,取决于被测 agent 是否需要隔离的
|
|
|
40
44
|
┌──────────────────────────────┐
|
|
41
45
|
│ Docker Sandbox │
|
|
42
46
|
│ ┌────────────────────────┐ │
|
|
43
|
-
│ │ Codex / Claude Code
|
|
44
|
-
│ │ 需要隔离文件系统的应用
|
|
47
|
+
│ │ Codex / Claude Code │ │
|
|
48
|
+
│ │ 需要隔离文件系统的应用 │ │
|
|
45
49
|
│ └────────────────────────┘ │
|
|
46
50
|
└──────────────────────────────┘
|
|
47
51
|
```
|
|
@@ -59,9 +63,8 @@ NiceEval 支持两种接入方式,取决于被测 agent 是否需要隔离的
|
|
|
59
63
|
│ Agent 适配器(官方,或者自己实现)
|
|
60
64
|
▼
|
|
61
65
|
┌──────────────────────────────┐
|
|
62
|
-
│ 你自己的 AI Agent
|
|
63
|
-
│ (AI SDK·LangGraph·Pi
|
|
64
|
-
│ agent 框架,无需 Docker) │
|
|
66
|
+
│ 你自己的 AI Agent │
|
|
67
|
+
│ (AI SDK·LangGraph·Pi ) │
|
|
65
68
|
└──────────────────────────────┘
|
|
66
69
|
```
|
|
67
70
|
|
|
@@ -69,10 +72,19 @@ NiceEval 支持两种接入方式,取决于被测 agent 是否需要隔离的
|
|
|
69
72
|
- **Agent 适配器** 是开放的边界:你来决定如何调用被测系统。
|
|
70
73
|
- 需要文件系统隔离的 coding agent 走 **Docker Sandbox**;自有的 AI Agent 可以直连,无需 Docker。
|
|
71
74
|
|
|
75
|
+
## 核心概念一览
|
|
72
76
|
|
|
73
|
-
|
|
77
|
+
| 概念 | 一句话 |
|
|
78
|
+
|---|---|
|
|
79
|
+
| Eval | 一个测试用例:写在 `evals/*.eval.ts` 里,描述测什么。 |
|
|
80
|
+
| Experiment | 可签入的运行配置:决定连哪个 Adapter、什么 model、什么 flags。 |
|
|
81
|
+
| Adapter | 连接被测系统的适配层:实现一个 `send`,把返回翻译成标准事件流。 |
|
|
82
|
+
| Sandbox | 需要隔离工作区的 coding agent 才用得到;直连 Web Agent 不需要。 |
|
|
83
|
+
| Tier | 接入 Adapter 的三档投入:Tier 1 只接 send,Tier 2 加 OTel 换调用瀑布图,Tier 3 侵入改造做 feature A/B。 |
|
|
74
84
|
|
|
75
|
-
|
|
85
|
+
完整术语表见[架构概览](https://niceeval.com/docs/zh/concepts/overview)。
|
|
86
|
+
|
|
87
|
+
## 示例
|
|
76
88
|
|
|
77
89
|
```ts
|
|
78
90
|
// evals/eval-tool-call.eval.ts
|
|
@@ -107,6 +119,7 @@ import { webAgent } from "./adapter"; // 你自己写的 agent adapter,接被
|
|
|
107
119
|
|
|
108
120
|
export default defineExperiment({
|
|
109
121
|
agent: webAgent({ baseUrl: "http://127.0.0.1:5188" }),
|
|
122
|
+
model: "gpt-5.5"
|
|
110
123
|
});
|
|
111
124
|
```
|
|
112
125
|
|
|
@@ -131,19 +144,20 @@ READ https://niceeval.com/INIT.md and install niceeval for this repo.
|
|
|
131
144
|
## Roadmap
|
|
132
145
|
官方适配器
|
|
133
146
|
- [ ] Agent 软件
|
|
134
|
-
- [
|
|
135
|
-
- [
|
|
136
|
-
- [
|
|
147
|
+
- [x] Claude Code
|
|
148
|
+
- [x] Codex
|
|
149
|
+
- [x] Bub
|
|
137
150
|
- [ ] OpenClaw
|
|
138
151
|
- [ ] Hermess Agent
|
|
139
152
|
- [ ] Alma
|
|
140
153
|
- [ ] ...
|
|
141
154
|
|
|
142
155
|
- [ ] Agent 框架
|
|
143
|
-
- [
|
|
156
|
+
- [x] AI SDK
|
|
157
|
+
- [x] Claude SDK
|
|
158
|
+
- [x] Codex SDK
|
|
159
|
+
- [x] Pi Agent SDK
|
|
144
160
|
- [ ] LangGraph
|
|
145
|
-
- [ ] Claude SDK
|
|
146
|
-
- [ ] Codex SDK
|
|
147
161
|
- [ ] vm0
|
|
148
162
|
- [ ] Cursor Agent SDK
|
|
149
163
|
|
package/docs/README.md
CHANGED
|
@@ -110,7 +110,8 @@ npx niceeval exp local fixtures/button
|
|
|
110
110
|
- **建立心智模型:** [Vision](vision.md)、[Concepts(术语表)](concepts.md)、[Architecture](architecture.md)。
|
|
111
111
|
- **写 eval:** [Eval Authoring(编写 eval)](eval-authoring.md)、[Assertions(断言参考:作用域 + 来源)](assertions.md)、[Scoring(评分器)](scoring.md)。
|
|
112
112
|
- **连 AI / 接 agent:** [Agents 与 Adapters(定位与导航)](adapters/README.md)、[Origin 应用接入手册(五个应用的接入记录)](origin-integration.md)、[Tier Sync(examples origin→tier 同步维护工具)](tier-sync.md)、[Adapter 契约(逐 API 适配义务)](adapters/contract.md)、[Adapter 写法(递进式写法)](adapters/authoring.md)、[Capabilities by Construction(能力由构造证明)](capabilities-by-construction.md)、[采集设计(三条外部路线对比)](adapters/collection.md)、[接入目标矩阵(12 个被测对象调研)](adapters/targets.md)、[Coding Agent Skills / Plugins DX](adapters/coding-agent-skills-plugins.md)、[Sandbox](sandbox.md)、[Observability(含 OTel trace 瀑布图)](observability.md)。
|
|
113
|
-
- **设计提案(未实现):** [Multi-Agent(多 agent eval 的三种场景)](multi-agent.md)、[
|
|
113
|
+
- **设计提案(未实现):** [Multi-Agent(多 agent eval 的三种场景)](multi-agent.md)、[Reports(自己搭报告页:React 组件 × 查询模型两档积木)](reports.md)、[Results Lib(结果数据的读写库,Reports 的数据层)](results-lib.md)。
|
|
114
|
+
- **框架自测:** [E2E CI(全链路 e2e 测试方案;`e2e/` 的 tier1 矩阵已落地,workflow 未建)](e2e-ci.md)。
|
|
114
115
|
- **跑与看:** [Experiments(实验/运行矩阵)](experiments.md)、[Runner(执行引擎)](runner.md)、[CLI 参考](cli.md)、[Observability(可观测性)](observability.md)、[Results Format(结果保存格式)](results-format.md)、[View(本地查看器)](view.md)。
|
|
115
116
|
- **背景调研:** [References(从其它项目学到什么)](references.md)、[agent-eval 是怎么做适配的](adapters/reference/agent-eval.md)、[OTel GenAI 等「行为怎么记」标准](adapters/reference/otel-genai.md)、[四个主流 agent loop 接入面调研](adapters/reference/agent-loop-apis.md)、[应用侧 OTel 埋点生态调研](adapters/reference/otel-instrumentation.md)、[eve 的协议机制](adapters/reference/eve-protocol.md)、[Claude Code 自带 OTel 遥测能不能提前拿结果](adapters/reference/claude-code-otel-telemetry.md)。
|
|
116
117
|
|
|
@@ -46,7 +46,7 @@
|
|
|
46
46
|
| **usage** | assistant 行 `message.usage`(含 cache read) | 防御式多路径:`data/payload/item/turn/response.usage`,兼容 `input/output_tokens` 与 `prompt/completion_tokens` 两套命名 | `event(name=="run")` 的 `data.usage`(`prompt/completion_tokens`,**`cost` 直接有**) |
|
|
47
47
|
| **session id(resume 用)** | transcript 首个 `sessionId` 字段(`shared.sessionIdFromClaudeTranscript`) | `thread.started.thread_id`(`shared.codexThreadId`) | tape 文件名含 session hash;adapter 自管 |
|
|
48
48
|
| **实际模型** | transcript 行内有 | 网关场景要第二通道读 `~/.codex/sessions` 的 `turn_context.payload.model`(agent-eval 的做法;niceeval 未接,记为已知缺口) | tape 内 run 事件 |
|
|
49
|
-
| **时间轨** |
|
|
49
|
+
| **时间轨** | beta 版原生 OTLP trace 导出,已接进 adapter 的 `tracing.env`(`CLAUDE_CODE_ENHANCED_TELEMETRY_BETA=1` 等一串 env;span 只有结构与计时、内容默认脱敏,内容仍由 transcript 旁读补全,详见 [reference/claude-code-otel-telemetry.md](reference/claude-code-otel-telemetry.md)) | 原生 OTLP/JSON(`config.toml [otel]`,走 `tracing.configure`) | 原生 OTLP/protobuf(env-based `OTEL_*`,走 `tracing.env`) |
|
|
50
50
|
|
|
51
51
|
remote agent(通道 0)不在表里——它没有"采集",字段来源就是你自己代码里的返回值,见下节示例。
|
|
52
52
|
|
|
@@ -72,10 +72,10 @@ interface AgentSession {
|
|
|
72
72
|
| `t.respond()` / `t.parked()` 等 HITL | send 返回过 `"waiting"` + `input.requested` 事件——做到了就是有 |
|
|
73
73
|
| `t.calledTool()` / `t.toolOrder()` 等正断言 | events 里有 `action.*` |
|
|
74
74
|
| `t.notCalledTool()` / `t.usedNoTools()` 等负断言**可信** | 事件来自带完整性证明的官方转换器(SDK 原生事件流透传、`fromAiSdk` 的 `result.steps`、Responses 的 `output`);手写映射没有这份证明,负断言可信度按来源判断,不按作者的自觉 |
|
|
75
|
-
| `t.sandbox`、`t.fileChanged()` 等 | `defineSandboxAgent` 构造(`kind: "sandbox"`) |
|
|
75
|
+
| `t.sandbox`、`t.sandbox.fileChanged()` 等 | `defineSandboxAgent` 构造(`kind: "sandbox"`) |
|
|
76
76
|
| `EvalResult.trace`、`niceeval view` 瀑布图 | 配置了 OTel 接入(agent 的 `tracing` 块,或 remote agent + `defineConfig({ telemetry })`)——只画瀑布图,不影响任何断言,详见[观测性](../observability.md#otlp-traces--统一瀑布图) |
|
|
77
77
|
|
|
78
|
-
唯一仍然存在的运行时守卫是**沙箱能力**:`t.sandbox` / `t.file` / `t.fileChanged()` 等直接读沙箱文件系统,非沙箱型 agent(`kind !== "sandbox"`)调用这些方法会立即得到清晰报错(`src/context/context.ts` 的 `capabilityGuard`)——没有沙箱就没有东西可读,不报错会静默返回空结果。其余能力(多轮对话、工具观测……)不设运行时守卫:没接会话存取器的 agent 每轮各是新对话(不报错,只是断言看不到历史);没吐 `action.*` 事件的 agent 上正断言自然不命中;负断言的可信度靠事件来源判断,不靠拦截调用。
|
|
78
|
+
唯一仍然存在的运行时守卫是**沙箱能力**:`t.sandbox` / `t.sandbox.file()` / `t.sandbox.fileChanged()` 等直接读沙箱文件系统,非沙箱型 agent(`kind !== "sandbox"`)调用这些方法会立即得到清晰报错(`src/context/context.ts` 的 `capabilityGuard`)——没有沙箱就没有东西可读,不报错会静默返回空结果。其余能力(多轮对话、工具观测……)不设运行时守卫:没接会话存取器的 agent 每轮各是新对话(不报错,只是断言看不到历史);没吐 `action.*` 事件的 agent 上正断言自然不命中;负断言的可信度靠事件来源判断,不靠拦截调用。
|
|
79
79
|
|
|
80
80
|
## 标准事件流
|
|
81
81
|
|
|
@@ -182,7 +182,7 @@ interface InputRequest {
|
|
|
182
182
|
|
|
183
183
|
| 断言族 | 读什么 | adapter 义务 | 数据缺失时 |
|
|
184
184
|
|---|---|---|---|
|
|
185
|
-
| `succeeded()` / `parked()`
|
|
185
|
+
| `succeeded()` / `parked()` | `Turn.status` + 事件流(`parked` 看最后有意义事件是否 `input.requested`) | `status` 如实;HITL 停留吐 `input.requested` | `status` 恒 completed → `succeeded` **假通过(静默)** |
|
|
186
186
|
| `messageIncludes()` / `t.reply` / `turn.message` | `message` 且 `role: "assistant"` 的事件文本 | 每段助手文本吐一条 `message`(工具结果**不是**助手消息,别混,见[参考笔记的踩坑记录](reference/agent-eval.md#claude-code-怎么转换)) | 断言 fail(响) |
|
|
187
187
|
| `outputEquals()` / `outputMatches()` | `turn.data` | 结构化输出放 `data`,不要序列化塞进 `events` | fail(响) |
|
|
188
188
|
| `calledTool()` / `toolOrder()` / `loadedSkill()` / `calledSubagent()` | 派生 `toolCalls` / `subagentCalls` | 每次调用吐 `called` + `result`(callId 配对);`name` 原始名 + `tool` 规范名;result `status` 如实 | fail(响) |
|
|
@@ -230,10 +230,11 @@ t.succeeded() ✓
|
|
|
230
230
|
| 鉴权(API key / token / base url) | **agent 本地** —— 它怎么连自己,是私事 | 在定义里读 env / 闭包,不经 ctx |
|
|
231
231
|
| CLI 细节(装什么包、参数形状、transcript 在哪) | **agent 本地** | 写死在 `send` / `setup` 里 |
|
|
232
232
|
| **model** | **实验决定(留空)** | `ctx.model`(省略 → agent 原生默认) |
|
|
233
|
-
| **
|
|
233
|
+
| **reasoningEffort** | **实验决定(留空)** | `ctx.reasoningEffort`(省略 → agent 原生默认) |
|
|
234
|
+
| **feature flags**(webResearch、注入哪个 skill…) | **实验决定** | `ctx.flags.*` —— agent 的 `send` 与 eval 的 `t.flags` 都能读 |
|
|
234
235
|
| runs / earlyExit / evals / sandbox / budget | **实验决定** | 运行器据此调度 |
|
|
235
236
|
|
|
236
|
-
一句话:**agent 只配「怎么连我自己」,不配「跑哪个模型、开哪些开关」**;后者全留给 [experiment](../experiments.md),经 `ctx`(eval 里是 `t`)透传。这样同一个 agent 能被不同实验以不同 model / flags 复用,不必改 agent。
|
|
237
|
+
一句话:**agent 只配「怎么连我自己」,不配「跑哪个模型、开哪些开关」**;后者全留给 [experiment](../experiments.md),经 `ctx`(eval 里是 `t`)透传。这样同一个 agent 能被不同实验以不同 model / reasoningEffort / flags 复用,不必改 agent。
|
|
237
238
|
|
|
238
239
|
## `ctx`(agent 侧)与 `t`(eval 侧):同一份东西,两个名字
|
|
239
240
|
|
|
@@ -79,7 +79,7 @@ OTEL_TRACES_EXPORT_INTERVAL=1000 # 拉到近实时,eval 场
|
|
|
79
79
|
|
|
80
80
|
## 跟现有采集矩阵的关系
|
|
81
81
|
|
|
82
|
-
[
|
|
82
|
+
**已落地(2026-07)**:下文"升级档"描述的接线已经实现——`claudeCodeAgent` 的 `tracing.env` 注入本页这组 env,与 bub/codex 一样默认开启(见 `src/agents/claude-code.ts`),[采集矩阵](../collection.md#采集矩阵现状与-src-对齐)的时间轨一行已同步。span 只有结构与计时(未开内容 flag),行为轨与断言仍走 transcript 旁读,与下文结论一致。
|
|
83
83
|
|
|
84
84
|
## 结论:这条路径值不值得接
|
|
85
85
|
|
package/docs/architecture.md
CHANGED
|
@@ -7,26 +7,26 @@ niceeval 把一个评测过程拆成四段职责:**发现**要跑什么、**驱
|
|
|
7
7
|
## 系统总览
|
|
8
8
|
|
|
9
9
|
```text
|
|
10
|
-
|
|
11
|
-
evals/ │
|
|
12
|
-
└─ *.eval.ts ──────────►│
|
|
13
|
-
│
|
|
14
|
-
│
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
│
|
|
20
|
-
│
|
|
21
|
-
│
|
|
22
|
-
│
|
|
23
|
-
│
|
|
24
|
-
│
|
|
25
|
-
│
|
|
26
|
-
│
|
|
27
|
-
│
|
|
28
|
-
│
|
|
29
|
-
|
|
10
|
+
┌─────────────────────────── core ───────────────────────────┐
|
|
11
|
+
evals/ │ │
|
|
12
|
+
└─ *.eval.ts ──────────►│ Discovery ──► Runner ──► Scoring ──► Outcome ──► Reporters │
|
|
13
|
+
│ (发现) (调度) (评分) (判决) (报告) │
|
|
14
|
+
│ │ 驱动 │ │
|
|
15
|
+
└──────────────┼──────────────────────────────────┼──────────┘
|
|
16
|
+
│ ▼
|
|
17
|
+
▼ 对接口分发,不按名字分支 .niceeval/<run>/
|
|
18
|
+
┌────── Agent(自实现 Adapter) ──────┐
|
|
19
|
+
│ 远程 adapter 沙箱 adapter │
|
|
20
|
+
│ (你的服务) ┌───────────────┐ │
|
|
21
|
+
│ │ claude-code │ │
|
|
22
|
+
│ │ codex / bub │ │
|
|
23
|
+
│ └───────────────┘ │
|
|
24
|
+
│ ▼ │
|
|
25
|
+
│ ┌─── Sandbox ───┐ │
|
|
26
|
+
│ │ docker │ │
|
|
27
|
+
│ │ vercel / 三方 │ │
|
|
28
|
+
│ └───────────────┘ │
|
|
29
|
+
└───────────────────────────────────┘
|
|
30
30
|
```
|
|
31
31
|
|
|
32
32
|
四段职责是**单向数据流**:发现产出一批 `Eval`,运行器逐个对 Agent `send` 得到 `Turn`,评分器把 `Turn` 折叠成 `Assertion[]`,再把全部断言折叠成一个互斥的 `Outcome`;报告器消费 `Outcome` + 工件。没有反向耦合 —— 评分器不知道 agent 的 transport 是 HTTP 还是沙箱 CLI,它只看 `Turn`。
|
package/docs/assertions.md
CHANGED
|
@@ -158,7 +158,6 @@ export default defineEval({
|
|
|
158
158
|
| `t` | `check` / `require` / `skip` / `log` | 记录 eval run 级断言或控制流,不属于某个 session / turn |
|
|
159
159
|
| `t` | `newSession()` | 只有 run 主上下文负责创建额外 session |
|
|
160
160
|
| `t` | `sandbox.*` | 沙箱是 attempt / run 资源,不是某条会话或某一轮的资源 |
|
|
161
|
-
| `turn` | `expectOk()` | 只对一次 `send` 的返回状态有意义 |
|
|
162
161
|
| `turn` | `outputEquals(value)` / `outputMatches(schema)` | 只对这一轮的 `turn.data` 有意义 |
|
|
163
162
|
|
|
164
163
|
### 值级断言
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
|
|
9
9
|
| 能力 | 证据 | 用户要写什么 |
|
|
10
10
|
|---|---|---|
|
|
11
|
-
| `t.sandbox`、`t.fileChanged()` 等文件系统断言 | `defineSandboxAgent` 构造(`kind: "sandbox"`) | 无——`defineAgent` 构造的 agent(`kind: "remote"`)调用这些方法会立即得到清晰报错,这是唯一仍需要运行时守卫的能力(`src/context/context.ts` 的 `capabilityGuard`) |
|
|
11
|
+
| `t.sandbox`、`t.sandbox.fileChanged()` 等文件系统断言 | `defineSandboxAgent` 构造(`kind: "sandbox"`) | 无——`defineAgent` 构造的 agent(`kind: "remote"`)调用这些方法会立即得到清晰报错,这是唯一仍需要运行时守卫的能力(`src/context/context.ts` 的 `capabilityGuard`) |
|
|
12
12
|
| 多次 `t.send()`、`t.reply`、`t.newSession()` | `send` 里接了 `ctx.session` 的续接存取器(`history<TMsg>()` 或 `id` + `capture(id)`) | 无——没接就每轮各是新对话,不报错,只是断言看不到跨轮历史 |
|
|
13
13
|
| `t.calledTool()` 等正断言 | `send` 返回的 events 里有 `action.*` | 无——有事件就能断,没有就是断言 fail(响,不静默) |
|
|
14
14
|
| `t.notCalledTool()` / `usedNoTools()` 等负断言的**可信度** | 事件来源是否有完整性契约(SDK 原生事件流透传、`fromAiSdk` 的 `result.steps`、Responses 的 `output`) | 无——但手写映射时如果知道自己漏了工具层,应在 eval README 里如实说明这条 eval 的负断言不可信,而不是假装它和正断言一样可靠 |
|
|
@@ -38,7 +38,7 @@ export default defineAgent({
|
|
|
38
38
|
## 边界
|
|
39
39
|
|
|
40
40
|
- **默认值问题已经不存在。** 提案担心的"`defineAgent` 默认给 `conversation: true, toolObservability: true`,教程第一步要写一行反悔"——这个问题连同整个 `capabilities` 字段一起消失了,不需要保留"opt-out 默认值"这个概念。
|
|
41
|
-
- **`workspace` 对远程 agent 依然不放开。** 文件系统断言(`t.sandbox`、`t.fileChanged()`)只在 `kind: "sandbox"` 上解锁,远程 agent 即便自己改了文件,也没有 sandbox 提供的 diff 基线,这条边界和提案设想的一致。
|
|
41
|
+
- **`workspace` 对远程 agent 依然不放开。** 文件系统断言(`t.sandbox`、`t.sandbox.fileChanged()`)只在 `kind: "sandbox"` 上解锁,远程 agent 即便自己改了文件,也没有 sandbox 提供的 diff 基线,这条边界和提案设想的一致。
|
|
42
42
|
- **`t.newSession()` 在没有接会话续接存取器时依然可以调用。** 新会话线的第一轮就是存取器的自然空态,不需要判断"这个 agent 支不支持多轮"。
|
|
43
43
|
|
|
44
44
|
## 相关阅读
|
package/docs/cli.md
CHANGED
|
@@ -58,7 +58,7 @@ niceeval exp compare --no-early-exit # 关掉,要完整通过率分布
|
|
|
58
58
|
niceeval exp compare --max-concurrency <n> # 并发上限
|
|
59
59
|
niceeval exp compare --timeout <ms> # 单 eval 超时
|
|
60
60
|
niceeval exp compare --force # 忽略指纹缓存,全量重跑
|
|
61
|
-
niceeval exp compare --tag <tag> #
|
|
61
|
+
niceeval exp compare --tag <tag> # 按单个标签过滤
|
|
62
62
|
```
|
|
63
63
|
|
|
64
64
|
## 评分与退出
|
|
@@ -81,7 +81,7 @@ niceeval view # 起本地 web,自动打开浏览器,读
|
|
|
81
81
|
niceeval view .niceeval/<run>/summary.json
|
|
82
82
|
niceeval view --port 4317 # 固定端口;被占用时向后找可用端口
|
|
83
83
|
niceeval view --no-open # 只启动服务并打印 URL(适合远端 shell / CI)
|
|
84
|
-
niceeval view --out .
|
|
84
|
+
niceeval view --out site # 目录式静态导出,不启动服务(index.html + 查看器工件)
|
|
85
85
|
niceeval clean # 清掉这些历史运行结果
|
|
86
86
|
```
|
|
87
87
|
|
package/docs/concepts.md
CHANGED
|
@@ -40,7 +40,7 @@
|
|
|
40
40
|
|
|
41
41
|
**Integration tier** / **接入 Tier** —— 按「Adapter 接到哪里、额外拿到什么观测数据」给接入方式分的三档(和下面的**模型档**是两回事,后者说的是给 agent 指定哪个模型)。**Tier 1(只接 send)**:应用代码一行不改——adapter 适配应用现有对外接口实现 `send`,靠手写事件映射或官方转换器拿到工具断言;应用接口本身暴露模型选择的话,**模型对比**类 [Experiment](#experiment) 也在这一档(`model` 经 `ctx.model` 透传)。**Tier 2(send + OTel)**:还是同一个 `send`,事件来源换成应用发给 niceeval 的 OTel span(应用已埋点则零代码,未埋点补一段通用 OTel 初始化)——买到的是观测质量的跃升:事件流免手写映射、负断言带完整性证明、trace 瀑布图。**Tier 3(侵入改造 + experiment flags)**:改应用内部代码,把内部可变点(prompt、工具集、feature flag)暴露成 experiment 可选的配置(经 `flags` → `ctx.flags` 透传),解锁**完整的 feature A/B test**——对照的不再只是模型,而是应用内部的功能变体。前两档都是**无侵入**的:应用按自己的方式启动,eval 侧不 spawn 应用进程、不另开端口,Adapter 只对着用户前端本来就在用的那个接口收发。三档递进不互斥,详见 [docs-site · Tier](../docs-site/zh/concepts/tier.mdx)。
|
|
42
42
|
|
|
43
|
-
**Model tier** / **模型档** —— 给 agent 指定模型的标识(如 `opus
|
|
43
|
+
**Model tier** / **模型档** —— 给 agent 指定模型的标识(如 `opus`)。由 [Experiment](#experiment) 的 `model` 字段指定;省略则用 agent 原生默认,不经额外的策略层决定。推理努力程度(如 `low`/`medium`/`high`,取值由具体模型定义)是独立的 `reasoningEffort` 字段,经 `ctx.reasoningEffort`/`t.reasoningEffort` 透传,归属与 `model` 一致——都是实验决定、agent 留空。
|
|
44
44
|
|
|
45
45
|
## 数据集与发现
|
|
46
46
|
|
|
@@ -62,7 +62,7 @@
|
|
|
62
62
|
|
|
63
63
|
**Session** —— 一条会话线。`t` 驱动主 session;`t.newSession()` 返回独立 session,用于并行或隔离的多会话测试。`session.*` 作用域断言只看这条 session 已经发生的事件;这些事件仍会汇入 `t.*` run 级断言。
|
|
64
64
|
|
|
65
|
-
**Turn** —— `t.send()` 的一次返回值,对应这一轮的标准事件流片段。带 `message` / `data` / `toolCalls` / `status` / `usage` / `events`
|
|
65
|
+
**Turn** —— `t.send()` 的一次返回值,对应这一轮的标准事件流片段。带 `message` / `data` / `toolCalls` / `status` / `usage` / `events` 等只读字段,以及一套与 `t` 同名的作用域断言(`turn.calledTool`/`turn.succeeded`/…),作用域收窄成只看这一轮,详见 [Assertions](assertions.md#作用域规则)。
|
|
66
66
|
|
|
67
67
|
**EarlyExit** / **早停** —— 一个 eval 取通过率时,先过一次即中止其余 attempt 的策略(可关)。
|
|
68
68
|
|