niceeval 0.6.0 → 0.6.2

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.
Files changed (314) hide show
  1. package/dist/agents/types.d.ts +72 -6
  2. package/dist/context/types.d.ts +32 -12
  3. package/dist/i18n/en.d.ts +54 -0
  4. package/dist/i18n/zh-CN.d.ts +55 -1
  5. package/dist/o11y/types.d.ts +16 -2
  6. package/dist/report/aggregate.d.ts +5 -3
  7. package/dist/report/aggregate.js +32 -5
  8. package/dist/report/built-ins/experiment-comparison.d.ts +39 -0
  9. package/dist/report/built-ins/experiment-comparison.js +119 -0
  10. package/dist/report/built-ins/index.d.ts +2 -1
  11. package/dist/report/built-ins/index.js +2 -2
  12. package/dist/report/components.d.ts +10 -2
  13. package/dist/report/components.js +3 -3
  14. package/dist/report/compute.d.ts +11 -18
  15. package/dist/report/compute.js +68 -66
  16. package/dist/report/flag.d.ts +16 -1
  17. package/dist/report/flag.js +19 -1
  18. package/dist/report/format.d.ts +16 -14
  19. package/dist/report/format.js +28 -30
  20. package/dist/report/index.d.ts +5 -4
  21. package/dist/report/index.js +6 -5
  22. package/dist/report/locale.d.ts +23 -3
  23. package/dist/report/locale.js +47 -6
  24. package/dist/report/metrics.d.ts +13 -1
  25. package/dist/report/metrics.js +66 -15
  26. package/dist/report/primitives.d.ts +6 -0
  27. package/dist/report/react/AttemptList.d.ts +4 -4
  28. package/dist/report/react/AttemptList.js +8 -10
  29. package/dist/report/react/EvalList.d.ts +1 -1
  30. package/dist/report/react/EvalList.js +0 -0
  31. package/dist/report/react/ExperimentComparison.d.ts +8 -0
  32. package/dist/report/react/ExperimentComparison.js +11 -0
  33. package/dist/report/react/ExperimentList.d.ts +4 -2
  34. package/dist/report/react/ExperimentList.js +57 -7
  35. package/dist/report/react/MetricScatter.js +6 -16
  36. package/dist/report/react/chart-math.d.ts +23 -6
  37. package/dist/report/react/chart-math.js +71 -19
  38. package/dist/report/react/fixtures.d.ts +3 -3
  39. package/dist/report/react/fixtures.js +30 -18
  40. package/dist/report/react/format.d.ts +1 -1
  41. package/dist/report/react/format.js +1 -1
  42. package/dist/report/react/index.d.ts +1 -1
  43. package/dist/report/report.d.ts +5 -1
  44. package/dist/report/report.js +6 -2
  45. package/dist/report/text/faces.d.ts +1 -1
  46. package/dist/report/text/faces.js +100 -61
  47. package/dist/report/text/table.js +36 -5
  48. package/dist/report/types.d.ts +40 -34
  49. package/dist/results/types.d.ts +11 -0
  50. package/dist/runner/feedback/sink.d.ts +110 -0
  51. package/dist/runner/types.d.ts +513 -22
  52. package/dist/sandbox/docker.d.ts +23 -2
  53. package/dist/sandbox/e2b.d.ts +15 -1
  54. package/dist/sandbox/errors.d.ts +30 -3
  55. package/dist/sandbox/io-retry.d.ts +17 -0
  56. package/dist/sandbox/registry.d.ts +2 -0
  57. package/dist/sandbox/resolve.d.ts +18 -5
  58. package/dist/sandbox/retry.d.ts +11 -1
  59. package/dist/sandbox/types.d.ts +39 -5
  60. package/dist/sandbox/vercel.d.ts +7 -1
  61. package/dist/scoring/coverage.d.ts +30 -0
  62. package/dist/scoring/display.d.ts +21 -0
  63. package/dist/scoring/display.js +120 -0
  64. package/dist/scoring/types.d.ts +103 -20
  65. package/dist/shared/aggregate.d.ts +1 -0
  66. package/dist/shared/aggregate.js +3 -3
  67. package/dist/shared/types.d.ts +28 -0
  68. package/dist/tty-line.d.ts +0 -4
  69. package/dist/util.d.ts +23 -0
  70. package/docs-site/zh/concepts/adapter.mdx +24 -6
  71. package/docs-site/zh/concepts/assert.mdx +11 -10
  72. package/docs-site/zh/concepts/evals.mdx +7 -6
  73. package/docs-site/zh/concepts/experiment.mdx +1 -1
  74. package/docs-site/zh/concepts/overview.mdx +7 -7
  75. package/docs-site/zh/guides/agent-feedback-loop.mdx +35 -31
  76. package/docs-site/zh/guides/authoring.mdx +33 -0
  77. package/docs-site/zh/guides/ci-integration.mdx +23 -12
  78. package/docs-site/zh/guides/connect-your-agent.mdx +29 -3
  79. package/docs-site/zh/guides/custom-reports.mdx +29 -34
  80. package/docs-site/zh/guides/dataset-fanout.mdx +25 -3
  81. package/docs-site/zh/guides/debug-sandbox.mdx +57 -0
  82. package/docs-site/zh/guides/debugging.mdx +210 -0
  83. package/docs-site/zh/guides/experiments.mdx +10 -3
  84. package/docs-site/zh/guides/fixtures.mdx +3 -1
  85. package/docs-site/zh/guides/official-adapters.mdx +27 -3
  86. package/docs-site/zh/guides/publish-report.mdx +30 -16
  87. package/docs-site/zh/guides/report-components.mdx +49 -37
  88. package/docs-site/zh/guides/reporters.mdx +2 -2
  89. package/docs-site/zh/guides/results-data.mdx +42 -8
  90. package/docs-site/zh/guides/runner.mdx +17 -7
  91. package/docs-site/zh/guides/sandbox-agent.mdx +57 -7
  92. package/docs-site/zh/guides/sandbox-providers.mdx +258 -10
  93. package/docs-site/zh/guides/scoring-guide.mdx +4 -4
  94. package/docs-site/zh/guides/viewing-results.mdx +85 -41
  95. package/docs-site/zh/guides/write-experiment.mdx +5 -3
  96. package/docs-site/zh/guides/write-send.mdx +19 -2
  97. package/docs-site/zh/index.mdx +1 -1
  98. package/docs-site/zh/reference/builtin-agents.mdx +27 -0
  99. package/docs-site/zh/reference/capabilities.mdx +2 -2
  100. package/docs-site/zh/reference/cli.mdx +35 -9
  101. package/docs-site/zh/reference/define-agent.mdx +60 -5
  102. package/docs-site/zh/reference/define-config.mdx +1 -1
  103. package/docs-site/zh/reference/define-eval.mdx +42 -9
  104. package/docs-site/zh/reference/events.mdx +2 -2
  105. package/docs-site/zh/reference/expect.mdx +36 -6
  106. package/package.json +5 -1
  107. package/src/agents/ai-sdk-otel.test.ts +1 -0
  108. package/src/agents/ai-sdk.test.ts +3 -0
  109. package/src/agents/ai-sdk.ts +3 -0
  110. package/src/agents/bub-install-spec.test.ts +34 -0
  111. package/src/agents/bub-install-spec.ts +32 -0
  112. package/src/agents/bub.ts +31 -32
  113. package/src/agents/claude-code.test.ts +130 -9
  114. package/src/agents/claude-code.ts +76 -4
  115. package/src/agents/codex.test.ts +189 -40
  116. package/src/agents/codex.ts +155 -14
  117. package/src/agents/coding-cli-versions.test.ts +15 -0
  118. package/src/agents/coding-cli-versions.ts +3 -0
  119. package/src/agents/index.ts +11 -0
  120. package/src/agents/langgraph.test.ts +204 -0
  121. package/src/agents/langgraph.ts +495 -0
  122. package/src/agents/marketplace.ts +85 -0
  123. package/src/agents/native-config.test.ts +179 -0
  124. package/src/agents/native-config.ts +267 -0
  125. package/src/agents/openai-compat.test.ts +1 -0
  126. package/src/agents/openclaw.test.ts +31 -0
  127. package/src/agents/openclaw.ts +171 -0
  128. package/src/agents/plugin-config.test.ts +1 -0
  129. package/src/agents/sdk-streams.test.ts +79 -0
  130. package/src/agents/sdk-streams.ts +55 -10
  131. package/src/agents/skills.test.ts +1 -0
  132. package/src/agents/streaming.test.ts +3 -9
  133. package/src/agents/types.ts +73 -6
  134. package/src/agents/ui-message-stream.test.ts +3 -0
  135. package/src/cli.ts +411 -108
  136. package/src/context/context.test.ts +51 -12
  137. package/src/context/context.ts +161 -29
  138. package/src/context/session.test.ts +1 -0
  139. package/src/context/session.ts +114 -6
  140. package/src/context/types.ts +30 -12
  141. package/src/define.test.ts +13 -8
  142. package/src/define.ts +25 -4
  143. package/src/expect/index.ts +53 -23
  144. package/src/i18n/en.ts +65 -4
  145. package/src/i18n/zh-CN.ts +66 -4
  146. package/src/o11y/cost.test.ts +1 -0
  147. package/src/o11y/execution-tree.test.ts +1 -20
  148. package/src/o11y/otlp/mappers/claude-code.test.ts +1 -0
  149. package/src/o11y/otlp/parse.test.ts +1 -0
  150. package/src/o11y/otlp/turn-otel.test.ts +1 -0
  151. package/src/o11y/parsers/bub.test.ts +1 -0
  152. package/src/o11y/parsers/claude-code.test.ts +1 -34
  153. package/src/o11y/parsers/openclaw.test.ts +154 -0
  154. package/src/o11y/parsers/openclaw.ts +310 -0
  155. package/src/o11y/prices.json +746 -311
  156. package/src/o11y/tool-names.test.ts +1 -0
  157. package/src/o11y/types.ts +16 -2
  158. package/src/report/aggregate.ts +34 -5
  159. package/src/report/built-in-user-parity.test.tsx +127 -173
  160. package/src/report/built-ins/experiment-comparison.tsx +179 -0
  161. package/src/report/built-ins/index.ts +7 -2
  162. package/src/report/components.tsx +11 -3
  163. package/src/report/compute.ts +80 -74
  164. package/src/report/dual-render.test.tsx +222 -91
  165. package/src/report/flag.ts +30 -2
  166. package/src/report/format.ts +36 -27
  167. package/src/report/index.ts +23 -6
  168. package/src/report/locale.ts +49 -6
  169. package/src/report/metrics.ts +68 -15
  170. package/src/report/primitives.tsx +6 -0
  171. package/src/report/react/AttemptList.tsx +9 -36
  172. package/src/report/react/EvalList.tsx +0 -0
  173. package/src/report/react/ExperimentComparison.tsx +68 -0
  174. package/src/report/react/ExperimentList.tsx +173 -55
  175. package/src/report/react/MetricScatter.tsx +13 -25
  176. package/src/report/react/chart-math.test.ts +85 -0
  177. package/src/report/react/chart-math.ts +101 -22
  178. package/src/report/react/enhance.js +72 -1
  179. package/src/report/react/fixtures.ts +34 -21
  180. package/src/report/react/format.ts +1 -1
  181. package/src/report/react/index.tsx +0 -1
  182. package/src/report/react/render.test.tsx +30 -69
  183. package/src/report/react/styles.css +112 -14
  184. package/src/report/report.test.ts +308 -105
  185. package/src/report/report.ts +6 -2
  186. package/src/report/text/faces.ts +111 -67
  187. package/src/report/text/table.ts +42 -5
  188. package/src/report/types.ts +42 -34
  189. package/src/results/annotated-source.test.ts +62 -9
  190. package/src/results/annotated-source.ts +64 -6
  191. package/src/results/attempt-evidence.test.ts +9 -7
  192. package/src/results/attempt-evidence.ts +15 -8
  193. package/src/results/attempt-source.ts +6 -3
  194. package/src/results/copy.ts +145 -55
  195. package/src/results/host-equivalence.test.ts +11 -9
  196. package/src/results/index.ts +2 -0
  197. package/src/results/locator.test.ts +1 -22
  198. package/src/results/open.ts +7 -1
  199. package/src/results/publish.ts +149 -0
  200. package/src/results/results.test.ts +85 -51
  201. package/src/results/truncate.ts +90 -0
  202. package/src/results/types.ts +7 -0
  203. package/src/results/writer.ts +31 -13
  204. package/src/runner/attempt.test.ts +138 -7
  205. package/src/runner/attempt.ts +603 -104
  206. package/src/runner/discover.test.ts +47 -0
  207. package/src/runner/discover.ts +36 -2
  208. package/src/runner/eval-source.test.ts +1 -27
  209. package/src/runner/feedback/agent.test.ts +504 -0
  210. package/src/runner/feedback/agent.ts +409 -0
  211. package/src/runner/feedback/ci.test.ts +562 -0
  212. package/src/runner/feedback/ci.ts +401 -0
  213. package/src/runner/feedback/coordinator.test.ts +317 -0
  214. package/src/runner/feedback/coordinator.ts +397 -0
  215. package/src/runner/feedback/failure.ts +40 -0
  216. package/src/runner/feedback/human.test.ts +616 -0
  217. package/src/runner/feedback/human.ts +535 -0
  218. package/src/runner/feedback/index.ts +66 -0
  219. package/src/runner/feedback/io.ts +78 -0
  220. package/src/runner/feedback/profile.test.ts +50 -0
  221. package/src/runner/feedback/profile.ts +58 -0
  222. package/src/runner/feedback/reducer.test.ts +395 -0
  223. package/src/runner/feedback/reducer.ts +260 -0
  224. package/src/runner/feedback/renderer.ts +82 -0
  225. package/src/runner/feedback/sink.ts +203 -0
  226. package/src/runner/feedback/testing.ts +106 -0
  227. package/src/runner/ledger.test.ts +230 -0
  228. package/src/runner/ledger.ts +329 -0
  229. package/src/runner/report.test.ts +128 -3
  230. package/src/runner/report.ts +33 -9
  231. package/src/runner/reporters/artifacts.ts +8 -2
  232. package/src/runner/reporters/braintrust.test.ts +8 -7
  233. package/src/runner/reporters/braintrust.ts +9 -2
  234. package/src/runner/reporters/index.ts +2 -2
  235. package/src/runner/reporters/json.test.ts +162 -0
  236. package/src/runner/reporters/json.ts +35 -8
  237. package/src/runner/reporters/shared.ts +1 -5
  238. package/src/runner/run.test.ts +760 -3
  239. package/src/runner/run.ts +242 -36
  240. package/src/runner/sandbox-prep.ts +3 -42
  241. package/src/runner/timing.ts +158 -0
  242. package/src/runner/types.ts +518 -22
  243. package/src/sandbox/checkpoint.test.ts +55 -0
  244. package/src/sandbox/checkpoint.ts +29 -8
  245. package/src/sandbox/cli-commands.ts +407 -0
  246. package/src/sandbox/docker.ts +115 -16
  247. package/src/sandbox/e2b-agent-template.test.ts +56 -0
  248. package/src/sandbox/e2b-agent-template.ts +94 -0
  249. package/src/sandbox/e2b.ts +74 -9
  250. package/src/sandbox/errors.ts +111 -4
  251. package/src/sandbox/index.ts +2 -0
  252. package/src/sandbox/io-retry.test.ts +58 -0
  253. package/src/sandbox/io-retry.ts +45 -0
  254. package/src/sandbox/keep-registry.test.ts +86 -0
  255. package/src/sandbox/keep-registry.ts +142 -0
  256. package/src/sandbox/keep.ts +178 -0
  257. package/src/sandbox/paths.test.ts +1 -0
  258. package/src/sandbox/paths.ts +19 -8
  259. package/src/sandbox/registry.ts +20 -3
  260. package/src/sandbox/resolve.ts +76 -11
  261. package/src/sandbox/retry.test.ts +70 -0
  262. package/src/sandbox/retry.ts +46 -4
  263. package/src/sandbox/types.ts +44 -6
  264. package/src/sandbox/vercel.ts +43 -20
  265. package/src/scoring/collector.ts +60 -17
  266. package/src/scoring/coverage.ts +95 -0
  267. package/src/scoring/diff.ts +81 -0
  268. package/src/scoring/display.test.ts +121 -0
  269. package/src/scoring/display.ts +133 -0
  270. package/src/scoring/evidence.test.ts +189 -0
  271. package/src/scoring/judge.test.ts +142 -0
  272. package/src/scoring/judge.ts +15 -18
  273. package/src/scoring/scoped.ts +217 -50
  274. package/src/scoring/types.ts +117 -20
  275. package/src/scoring/verdict.ts +16 -4
  276. package/src/shared/aggregate.ts +3 -2
  277. package/src/shared/types.ts +31 -0
  278. package/src/show/compose.ts +2 -2
  279. package/src/show/index.ts +29 -16
  280. package/src/show/render.ts +626 -308
  281. package/src/show/show.test.ts +251 -36
  282. package/src/tty-line.ts +8 -26
  283. package/src/util.test.ts +1 -0
  284. package/src/util.ts +41 -0
  285. package/src/view/app/components/AttemptModal.tsx +153 -2
  286. package/src/view/app/components/CodeView.tsx +32 -11
  287. package/src/view/app/components/CopyControls.tsx +2 -2
  288. package/src/view/app/i18n.ts +6 -0
  289. package/src/view/app/lib/attempt-route.test.ts +1 -0
  290. package/src/view/app/lib/verdict.ts +7 -9
  291. package/src/view/artifact-serving.test.ts +2 -1
  292. package/src/view/client-dist/app.css +1 -1
  293. package/src/view/client-dist/app.js +17 -17
  294. package/src/view/data.test.ts +2 -1
  295. package/src/view/data.ts +17 -7
  296. package/src/view/index.ts +12 -1
  297. package/src/view/server.ts +2 -0
  298. package/src/view/shared/types.ts +1 -1
  299. package/src/view/styles.css +3 -0
  300. package/src/view/view-report.test.ts +11 -10
  301. package/dist/o11y/execution-tree.d.ts +0 -103
  302. package/dist/o11y/otlp/select.d.ts +0 -22
  303. package/dist/report/built-ins/cost-pass-rate-comparison.d.ts +0 -1
  304. package/dist/report/built-ins/cost-pass-rate-comparison.js +0 -17
  305. package/dist/results/annotated-source.d.ts +0 -61
  306. package/dist/results/attempt-evidence.d.ts +0 -69
  307. package/dist/results/attempt-source.d.ts +0 -15
  308. package/src/report/built-ins/cost-pass-rate-comparison.tsx +0 -23
  309. package/src/runner/reporters/console.ts +0 -70
  310. package/src/runner/reporters/live.test.ts +0 -56
  311. package/src/runner/reporters/live.ts +0 -247
  312. package/src/runner/reporters/quiet.test.ts +0 -66
  313. package/src/runner/reporters/quiet.ts +0 -49
  314. package/src/runner/reporters/table.ts +0 -277
@@ -1,10 +1,16 @@
1
1
  import type { Severity, SourceLoc } from "../shared/types.ts";
2
2
  import type { DerivedFacts, StreamEvent, Usage } from "../o11y/types.ts";
3
- /** 值断言(expect 匹配器)。纯函数 score + 可链式改严重度 / 阈值。 */
3
+ import type { ResolvedCoverage } from "./coverage.ts";
4
+ export type { CoverageChannel, ResolvedCoverage, ResolvedCoverageChannel, ResolvedCoverageStatus, } from "./coverage.ts";
5
+ /** 值断言(expect 匹配器)。纯函数 score + 可链式改严重度 / 阈值 / optional。 */
4
6
  export interface ValueAssertion {
5
7
  readonly name: string;
6
8
  readonly severity: Severity;
7
9
  readonly threshold?: number;
10
+ /** `.optional()` 链过的标记:评不了只记 unavailable,不把 attempt 拖成 errored。 */
11
+ readonly isOptional?: boolean;
12
+ /** 期望条件的有界文本描述(如 `contains "Brooklyn"`),失败时进 AssertionResult.expected。 */
13
+ readonly expected?: string;
8
14
  score(value: unknown): number | Promise<number>;
9
15
  /** 转成硬门槛断言:未达阈值(省略 threshold 则按 score > 0 判定)整条 eval 判为 failed。返回新实例,不改原对象。 */
10
16
  gate(threshold?: number): ValueAssertion;
@@ -13,34 +19,76 @@ export interface ValueAssertion {
13
19
  * `--strict` 运行下,软阈值失败也会把整条 eval 的 verdict 计为 failed。返回新实例,不改原对象。
14
20
  */
15
21
  atLeast(threshold: number): ValueAssertion;
22
+ /**
23
+ * 允许这条断言证据缺席:评不了时只记录 `outcome: "unavailable"`,不影响判定。
24
+ * 与 severity 正交(severity 说影不影响质量判定,optional 说证据允不允许缺席)。返回新实例,不改原对象。
25
+ */
26
+ optional(): ValueAssertion;
16
27
  }
17
- /** 收集到 collector 里的一条断言记录(评估前)。 */
18
- export interface AssertionSpec {
28
+ /**
29
+ * 断言记录的公共字段(见 docs/feature/scoring/architecture.md「断言记录」——字段契约的单点定义)。
30
+ */
31
+ export interface AssertionBase {
32
+ /** 断言标题:t.group 内是该断言自己的摘要,组外是 matcher 摘要或 judge 问题;show/view 失败行的标题。 */
19
33
  name: string;
34
+ /** 所属分组路径:外层在前的 t.group 标题数组;无分组省略。纯报告用,不影响判定。 */
35
+ groupPath?: string[];
20
36
  severity: Severity;
21
- threshold?: number;
22
- /** 延迟评估:final 时拿到完整运行结果再算分。 */
23
- evaluate(ctx: ScoringContext): Promise<number> | number;
37
+ /** 作者用 .optional() 显式允许该断言缺席;只改变 unavailable 的折叠方式(见 Severity 与 Verdict),不改变 severity 语义。 */
38
+ optional?: true;
39
+ /** matcher / judge 摘要,如 `equals(4)`、`closedQA("…")`;与 name 分开,供 show/view 同时展示分组标题与检查方式。 */
40
+ detail?: string;
41
+ /** 断言在 eval 源码中的调用点,`--eval` 把结果标回源码行的锚。 */
42
+ loc?: SourceLoc;
24
43
  }
25
- /** 断言评估完的结果(进判定 / 报告)。 */
26
- export interface AssertionResult {
27
- name: string;
28
- severity: Severity;
29
- threshold?: number;
44
+ /**
45
+ * 断言评估完的结果(进判定 / 报告)。判别键是 `outcome`——`unavailable` 是没有分数的独立态,
46
+ * 普通聚合代码按 `outcome` 分支就不可能把证据缺口算成零分。判定只消费
47
+ * `severity` / `outcome` / `optional` / `score` / `threshold`。
48
+ */
49
+ export type AssertionResult = (AssertionBase & {
50
+ outcome: "passed" | "failed";
51
+ /** 归一化得分:值断言 0/1,judge 等打分断言 0..1。 */
30
52
  score: number;
31
- passed: boolean;
32
- detail?: string;
33
- /** 这条分数是看着什么材料算出来的(judge 收到的输入,或 t.check 失败时实际被检查的值)。view 展开排查「为什么是这个分」,默认不展示。 */
53
+ /** soft 断言的 .atLeast(x) 阈值;没有设阈值则省略。 */
54
+ threshold?: number;
55
+ /** 失败证据摘要:期望值的有界文本预览,供 show/view 直接展示。 */
56
+ expected?: string;
57
+ /** 失败证据摘要:实际值的有界文本预览。 */
58
+ received?: string;
59
+ /** 这条分数看着什么材料算出(judge 输入或被检查值预览);view 展开排查用,默认不展示。 */
34
60
  evidence?: string;
35
- /** 所属分组(t.group 标题)。纯报告用,不影响 passed/score。 */
36
- group?: string;
37
- /** 断言在 eval 源码里的调用点(栈回溯抠出);view 把判定叠回这一行。 */
38
- loc?: SourceLoc;
61
+ }) | (AssertionBase & {
62
+ outcome: "unavailable";
63
+ /** 机器可读原因,如 "judge-model-unresolved"、"coverage:actions=partial"。 */
64
+ reason: string;
65
+ });
66
+ /**
67
+ * 摘要面从完整 `AssertionResult[]` 选出的一条主失败断言。它只负责展示,不参与 verdict;
68
+ * `show @locator` / view Attempt 详情仍读取完整断言数组。字段保持结构化,使 CI 不必解析
69
+ * Human 的 `gate: …` 文案。
70
+ */
71
+ export interface PrimaryAssertionSummary {
72
+ severity: Severity;
73
+ /** `groupPath.join(" > ")`,无 group 时回退到断言 name。 */
74
+ assertion: string;
75
+ /** `detail ?? name`;与 assertion 相同时省略,避免重复。 */
76
+ matcher?: string;
77
+ expected?: string;
78
+ received?: string;
79
+ score?: number;
80
+ threshold?: number;
81
+ /** unavailable 断言的结构化原因。 */
82
+ reason?: string;
83
+ /** 同类因果失败中除主失败外的条数。 */
84
+ additionalFailures: number;
39
85
  }
40
86
  /** eval 作者拿到的可链式句柄(t.judge.autoevals.closedQA(...).atLeast(0.7))。 */
41
87
  export interface AssertionHandle {
42
88
  atLeast(threshold: number): AssertionHandle;
43
89
  gate(threshold?: number): AssertionHandle;
90
+ /** 允许这条断言证据缺席:unavailable 只保留在记录里,不影响判定(见 Severity 与 Verdict)。 */
91
+ optional(): AssertionHandle;
44
92
  }
45
93
  /** scoped / judge 断言在 final 评估时拿到的运行结果。 */
46
94
  export interface ScoringContext {
@@ -50,6 +98,8 @@ export interface ScoringContext {
50
98
  readonly scripts: Record<string, ScriptResult>;
51
99
  readonly usage: Usage;
52
100
  readonly status: "completed" | "failed" | "waiting";
101
+ /** 当前作用域(turn / session / attempt)解析后的证据覆盖;断言按它做三值折叠(见 scoped.ts)。 */
102
+ readonly coverage: ResolvedCoverage;
53
103
  /** 读沙箱里某文件的最终内容(judge / file 断言用)。 */
54
104
  readFile(path: string): Promise<string | undefined>;
55
105
  }
@@ -57,9 +107,42 @@ export interface ScriptResult {
57
107
  success: boolean;
58
108
  output: string;
59
109
  }
110
+ /** diff.json 的落盘形状:按时序的窗口数组(逐窗口 delta 序列,不做跨窗口压缩)。 */
111
+ export type DiffArtifact = DiffWindow[];
112
+ export interface DiffWindow {
113
+ /** send 窗口标签,与时间树 turn 节点、--execution 轮次同源(如 "s1/t2")。 */
114
+ window: string;
115
+ /** 该窗口内 agent 改动的文件;窗口内没有 workspace 变化时窗口仍落一条、changes 为空对象。 */
116
+ changes: Record<string, WindowChange>;
117
+ }
118
+ export interface WindowChange {
119
+ status: "added" | "modified" | "deleted";
120
+ /** 窗口开始时的内容;added 无此字段。 */
121
+ before?: string;
122
+ /** 窗口结束时的内容;deleted 无此字段。 */
123
+ after?: string;
124
+ /** 二进制文件不内联内容,只记字节数。 */
125
+ binary?: {
126
+ beforeBytes?: number;
127
+ afterBytes?: number;
128
+ };
129
+ }
130
+ /** 读取面在窗口序列之上派生的文件级视图(派生物可随时重算,不落盘)。 */
131
+ export interface DiffFileSummary {
132
+ /** 净效果:首个触及窗口的起点 vs 最后触及窗口的终点;"none" = 动过但净无变化(创建又删除、改回原样)。 */
133
+ net: "added" | "modified" | "deleted" | "none";
134
+ /** 触及该文件的窗口标签,按时序。 */
135
+ windows: string[];
136
+ binary?: true;
137
+ }
138
+ /** agent 归因 diff 的消费视图:窗口序列(落盘事实)+ 派生的文件级摘要与终态读取。 */
60
139
  export interface DiffData {
61
- generatedFiles: Record<string, string>;
62
- deletedFiles: string[];
140
+ /** 落盘事实,原样。 */
141
+ windows: DiffWindow[];
142
+ /** 派生:每个被 agent 触及的文件一条。 */
143
+ files: Record<string, DiffFileSummary>;
144
+ /** 该文件最后一个触及窗口结束时的内容;净删除或从未触及返回 undefined。t.sandbox.diff.get 同一语义。 */
145
+ get(path: string): string | undefined;
63
146
  }
64
147
  export type Verdict = "passed" | "failed" | "errored" | "skipped";
65
148
  export interface JudgeConfig {
@@ -22,6 +22,7 @@ export declare function experimentGroupOf(experimentId: string): string | undefi
22
22
  export declare function evalPrefixPredicate(evals?: string | string[]): (id: string) => boolean;
23
23
  /** 无 experimentId 时的兜底标签。 */
24
24
  export declare function fallbackExperimentLabel(result: {
25
+ experimentId?: string;
25
26
  experiment?: ExperimentRunInfo;
26
27
  agent: string;
27
28
  model?: string;
@@ -1,4 +1,4 @@
1
- // CLI 表格(runner/reporters/table.ts)与 view 榜单(view/aggregate.ts)共用的聚合小工具。
1
+ // report 聚合(report/aggregate.ts)与 view 榜单(view/app/lib/rows.ts)共用的聚合小工具。
2
2
  // 实验标签推导、token/成本求和、verdict 排序各只有一份 —— 否则同一个实验在终端和网页上
3
3
  // 会显示成两个名字 / 两组数。保持环境无关(纯函数,只 type import)。
4
4
  /** 明细行排序:失败最靠前(failed > errored > skipped > passed 的紧急程度)。 */
@@ -47,8 +47,8 @@ export function evalPrefixPredicate(evals) {
47
47
  }
48
48
  /** 无 experimentId 时的兜底标签。 */
49
49
  export function fallbackExperimentLabel(result) {
50
- if (result.experiment?.id)
51
- return displayExperimentName(result.experiment.id) ?? result.experiment.id;
50
+ if (result.experimentId)
51
+ return displayExperimentName(result.experimentId) ?? result.experimentId;
52
52
  if (result.model)
53
53
  return `${result.agent}/${result.model}`;
54
54
  return result.agent || "ad hoc run";
@@ -20,6 +20,34 @@ export interface SourceArtifact {
20
20
  }
21
21
  /** 通用清理闭包(setup 返回值 / teardown 的形状),异步同步皆可,统一在 finally 里执行。 */
22
22
  export type Cleanup = () => Promise<void> | void;
23
+ /** `ScopedFeedback.progress` 的入参:此刻正在做什么(短命状态,可被后续更新覆盖)。 */
24
+ export interface ProgressUpdate {
25
+ message: string;
26
+ current?: number;
27
+ total?: number;
28
+ }
29
+ /** `ScopedFeedback.diagnostic` 的入参:运行结束后仍应保留的问题(永久事件)。 */
30
+ export interface DiagnosticInput {
31
+ code: string;
32
+ level: "warning" | "error";
33
+ message: string;
34
+ data?: Readonly<Record<string, JsonValue>>;
35
+ /** 并发 attempt 产生同一问题时的去重键;相同 key 折叠成一条并累计次数。 */
36
+ dedupeKey?: string;
37
+ }
38
+ /**
39
+ * 作用域反馈 API(见 docs/feature/experiments/library.md「生命周期代码怎样向这次运行反馈」):
40
+ * sandbox provider、sandbox hook、eval 与 Agent Adapter 从 runner 注入的上下文获得同一套入口。
41
+ * - `progress` 是短命状态:Human profile 更新 active 行,Agent/CI 不逐条打印,不进最终结果;
42
+ * - `diagnostic` 是永久事件:进 Human/Agent/CI 的永久输出流并落进 attempt 的 diagnostics;
43
+ * 即使 level 为 "error" 也不自动改变 verdict(要 errored 抛异常,要 failed 用断言)。
44
+ * 两个方法都不接受 phase / scope / 颜色 / 输出流——runner 知道当前回调属于哪个生命周期阶段,
45
+ * 调用方不能冒充其它阶段。
46
+ */
47
+ export interface ScopedFeedback {
48
+ progress(update: ProgressUpdate): void;
49
+ diagnostic(input: DiagnosticInput): void;
50
+ }
23
51
  /**
24
52
  * 可本地化文案:纯字符串,或按 locale 代码(如 "en"、"zh-CN")映射多语言。
25
53
  * view 按当前界面语言挑一条,挑不到回退到 en / 第一条。
@@ -1,6 +1,2 @@
1
- /** live.ts 用来订阅"即将有一行独立诊断消息落地"。返回取消订阅函数。 */
2
- export declare function onBeforeExternalTerminalWrite(fn: () => void): () => void;
3
- /** 任何要绕开 Reporter 直接往终端打一行独立诊断消息的地方,写之前都先调用这个。 */
4
- export declare function beforeExternalTerminalWrite(): void;
5
1
  /** process.stderr.write 的替代:文本需自带换行(沿用现有 i18n 字符串的约定)。 */
6
2
  export declare function writeStderrLine(text: string): void;
package/dist/util.d.ts CHANGED
@@ -10,6 +10,29 @@ export declare function stripComments(code: string): string;
10
10
  * `e instanceof Error ? e.message : String(e)`——那样用户永远看不出错误发生在哪一行。
11
11
  */
12
12
  export declare function formatThrown(e: unknown): string;
13
+ /**
14
+ * 截到第一个换行为止。`formatThrown()` 优先带完整 `.stack`(含本地绝对文件路径的多行调用栈)
15
+ * 给需要按 file:line 定位问题的落盘产物(`EvalResult.error`、`niceeval show`);但机器消费的
16
+ * 单行 envelope(`FailureNotice.reason`、reporter 失败诊断的 `message`……)只要「一层可行动摘要」
17
+ * ——`Error.stack` 的第一行恒为 `name: message`,不含栈帧,直接满足这个要求。完整栈仍然原样
18
+ * 留在调用方各自的落盘字段里,这个函数只负责第二次、更短的那份表达,不是唯一出口。
19
+ */
20
+ export declare function firstLine(text: string): string;
21
+ /**
22
+ * 把 catch 到的 e 拆成 `AttemptError` 的三段:`message`(一层原因,Error.message,不带 name 前缀、
23
+ * 不拼 stack)、`stack`(完整多行栈,供 `niceeval show` 展开)、`cause`(沿 `e.cause` 取一层结构化
24
+ * 摘要 `{ name?, code?, message }`)。Node 的 `Error.stack` 不展开 cause 链,所以 cause 只能从
25
+ * `e.cause` 单独取。非 Error 值只给 message。
26
+ */
27
+ export declare function describeError(e: unknown): {
28
+ message: string;
29
+ stack?: string;
30
+ cause?: {
31
+ name?: string;
32
+ code?: string;
33
+ message: string;
34
+ };
35
+ };
13
36
  /** 零填充到 4 位(数据集扇出的 id:sql/0000)。 */
14
37
  export declare function pad4(n: number): string;
15
38
  /**
@@ -37,6 +37,7 @@ export function webAgent(options: WebAgentOptions): Agent {
37
37
  return defineAgent({
38
38
  name: "web-agent",
39
39
  async send(input, ctx) {
40
+ ctx.progress({ message: "等待 Web Agent" });
40
41
  const response = await fetch(`${baseUrl}/api/turn`, {
41
42
  method: "POST",
42
43
  headers: {
@@ -54,6 +55,12 @@ export function webAgent(options: WebAgentOptions): Agent {
54
55
  });
55
56
 
56
57
  if (!response.ok) {
58
+ ctx.diagnostic({
59
+ code: "agent-http-error",
60
+ level: "error",
61
+ message: `Web Agent 返回 HTTP ${response.status}`,
62
+ data: { status: response.status },
63
+ });
57
64
  return {
58
65
  status: "failed",
59
66
  events: [{ type: "error", message: `HTTP ${response.status}` }],
@@ -107,10 +114,12 @@ interface Agent {
107
114
  }
108
115
  ```
109
116
 
117
+ `progress` 是运行中的短期状态,不落盘;`diagnostic` 是需要运行后回顾的有界 warning/error,会随 Attempt 保存。它们都不能指定 lifecycle phase,也不会自动改变 `Turn.status`。连接失败或响应无法解析时抛出异常;runner 会把它记录为 `errored`,并在终端给出可下钻的 locator。
118
+
110
119
  `send` 是唯一要实现的函数。它的签名里只有三个类型,分开看。
111
120
 
112
121
  <Note>
113
- 这里的 `setup` / `teardown` 是 Agent 自己"怎么连自己"的私事(装 CLI、写鉴权配置)。按实验变化的环境准备(装某个实验专属的二进制、预热、跨 attempt 保存状态)不写在 Agent 上,挂在 `sandbox` 字段那个 Sandbox spec 自己的 `.setup()` / `.teardown()` 链式方法上,见 [Sandbox 后端 · 环境钩子](/zh/guides/sandbox-providers#环境钩子)。
122
+ 这里的 `setup` / `teardown` 是 Agent 自己"怎么连自己"的私事(装 CLI、写鉴权配置)。按实验变化的环境准备(装某个实验专属的二进制、预热、跨 attempt 保存状态)不写在 Agent 上,挂在 `sandbox` 字段那个 Sandbox spec 自己的 `.setup()` / `.teardown()` 链式方法上,见 [沙箱 provider · 环境钩子](/zh/guides/sandbox-providers#环境钩子)。
114
123
  </Note>
115
124
 
116
125
  ### 传入:`TurnInput`
@@ -182,10 +191,17 @@ Adapter 侧的对应义务:按 `requestId` 把裁决交回应用(不要按
182
191
 
183
192
  ```ts
184
193
  interface AgentContext {
185
- // 每轮都在的三个
194
+ // 每轮都在的反馈与运行上下文
186
195
  readonly signal: AbortSignal; // 运行器的超时与取消:透传给你发出的每个请求
187
196
  readonly session: AgentSession; // 本条会话线的状态槽
188
- log(msg: string): void; // 写进本轮日志,niceeval view 里可见
197
+ progress(update: { message: string; current?: number; total?: number }): void;
198
+ diagnostic(input: {
199
+ code: string;
200
+ level: "warning" | "error";
201
+ message: string;
202
+ data?: Readonly<Record<string, JsonValue>>;
203
+ dedupeKey?: string;
204
+ }): void;
189
205
 
190
206
  // 按接入档位出现的三个(见「接入分三个 Tier」)
191
207
  readonly model?: string; // Tier 1 的模型对比:experiment.model 透传;应用接口收模型选择就转发
@@ -194,7 +210,7 @@ interface AgentContext {
194
210
  readonly flags: Readonly<Record<string, unknown>>; // Tier 3 的 feature A/B:experiment.flags 透传;没配时是 {}
195
211
  readonly experimentId?: string; // 路径推导的实验 id,与结果里的 experimentId 同源;不经 experiment 跑时是 undefined
196
212
 
197
- readonly sandbox?: Sandbox; // defineSandboxAgent 构造的 Agent 会拿到
213
+ readonly sandbox: Sandbox; // sandbox Agent 也会拿到一个 Sandbox(remote agent 是无操作的 stub)
198
214
  }
199
215
 
200
216
  interface AgentSession {
@@ -214,7 +230,9 @@ interface AgentSession {
214
230
  }
215
231
  ```
216
232
 
217
- `ctx` 里没有要你检查的标志位。三个档位字段都是"透传"语义:`model`、`flags` experiment 声明、运行器原样递过来,Adapter 只负责随请求转发给应用,不解释它们的含义;`telemetry` 仅在配置了 OTel 接入时出现,`send` 里只需要把 `headers` spread 进请求头——接收端点在 `defineConfig` 里固定、由应用启动时指向,不从这里传,见[OTel 接入](/zh/guides/connect-otel)。`experimentId` 是路径推导出的稳定标识,典型用途是在 Sandbox 的环境钩子里按实验隔离跨 attempt 的状态(缓存目录名、沙箱快照 tag 按它分区),见 [Sandbox 后端 · 环境钩子](/zh/guides/sandbox-providers#环境钩子)。
233
+ Runner Agent `setup`、每次 `send` `teardown` 分别绑定 lifecycle scope。Adapter 只报告当前回调内部的 progress/diagnostic,不能传 phase、颜色或输出流。`progress` 不落盘;diagnostic 会进入 Attempt `result.json`。无法继续时抛错,由 runner 保存结构化 error 并把 Attempt 标为 `errored`。
234
+
235
+ `ctx` 里没有要你检查的标志位。三个档位字段都是"透传"语义:`model`、`flags` 由 experiment 声明、运行器原样递过来,Adapter 只负责随请求转发给应用,不解释它们的含义;`telemetry` 仅在配置了 OTel 接入时出现,`send` 里只需要把 `headers` spread 进请求头——接收端点在 `defineConfig` 里固定、由应用启动时指向,不从这里传,见[OTel 接入](/zh/guides/connect-otel)。`experimentId` 是路径推导出的稳定标识,典型用途是在 Sandbox 的环境钩子里按实验隔离跨 attempt 的状态(缓存目录名、沙箱快照 tag 按它分区),见 [沙箱 provider · 环境钩子](/zh/guides/sandbox-providers#环境钩子)。
218
236
 
219
237
  `session` 是本条会话线的自有状态,[NiceEval](https://niceeval.com/) 对它只承诺一件事:**同一条会话线的每次 `send` 拿到同一个 `ctx.session`,新会话线(eval 的第一轮,或 `t.newSession()` 之后)拿到一个全新的。** 会话续接(`id`/`capture`、`history`)和 HITL 停轮现场(`hold`/`take`)的存取器都在它上面,"第一轮"就是新会话线的自然形态——`id` 是 `undefined`、`history.get()` 是空数组,没有要判断的分支;`state` 是这些存取器之外的逃生舱,框架从不往里写数据。
220
238
 
@@ -239,7 +257,7 @@ interface Turn {
239
257
  ]
240
258
  ```
241
259
 
242
- 对象统共九种类型(`message`、`action.*`、`input.requested`……完整清单见[事件流参考](/zh/reference/events))。断言读的就是这个数组:`t.calledTool("get_weather")` 数 `action.called`,`t.reply` 取最后一条 assistant `message`。注意 `send` 每次只返回**本轮**的数组——跨轮拼成整条会话线是运行器的事,见下一节。多数情况下你也不手写这些对象:官方转换器的返回值就是一个填好 `events`、`usage`、`status` 的完整 `Turn`,怎么选转换器见[写 send](/zh/guides/write-send)。
260
+ 对象统共十种类型(`message`、`action.*`、`input.requested`……完整清单见[事件流参考](/zh/reference/events))。断言读的就是这个数组:`t.calledTool("get_weather")` 数 `action.called`,`t.reply` 取最后一条 assistant `message`。注意 `send` 每次只返回**本轮**的数组——跨轮拼成整条会话线是运行器的事,见下一节。多数情况下你也不手写这些对象:官方转换器的返回值就是一个填好 `events`、`usage`、`status` 的完整 `Turn`,怎么选转换器见[写 send](/zh/guides/write-send)。
243
261
 
244
262
  `data` 不是"随便放点什么"的口袋,它只有一条规则:**要什么,由 eval 在 send 上用 schema 声明;声明了才有 data,拿到手就是声明的类型。**
245
263
 
@@ -52,25 +52,26 @@ t.maxTokens(80_000).atLeast(0.7); // 降为 soft 并带阈值
52
52
 
53
53
  ## 判定规则
54
54
 
55
- 所有断言收齐后,运行器按这个顺序折叠成一个结果:
55
+ 所有断言收齐后,运行器按固定优先级取第一个成立项,折叠成一个结果:
56
56
 
57
57
  ```
58
- 执行出错(超时 / 异常 / 作者错误) failed
59
- 显式调用了 t.skip(reason) skipped
60
- 任一 gate 断言失败 failed
61
- 所有 gate 都过,但至少一个 soft 低于阈值 → passed(--strict 下标红)
62
- 否则 → passed
58
+ 执行异常、超时或作者错误 errored
59
+ 任一 gate 断言失败,或 --strict 下 soft 低于阈值 failed
60
+ 显式调用了 t.skip(reason) skipped
61
+ 否则 → passed
63
62
  ```
64
63
 
64
+ `errored` 压过一切,因为执行证据已经不可信;`failed` 压过 `skipped`,避免 `t.skip()` 掩盖此前记录的硬失败。
65
+
65
66
  <CardGroup cols={2}>
66
67
  <Card title="passed" icon="circle-check" color="#22c55e">
67
- 没有错误,所有 gate 断言通过,所有 soft 断言都达到阈值。
68
+ 没有错误,所有 gate 断言通过,所有 soft 断言都达到阈值(或未开 `--strict`)。
68
69
  </Card>
69
70
  <Card title="failed" icon="circle-xmark" color="#ef4444">
70
- 执行出错,或至少一个 gate 断言没通过。硬失败。
71
+ 至少一个 gate 断言没通过,或 `--strict` 下有 soft 断言低于阈值。硬失败。
71
72
  </Card>
72
- <Card title="passed(计分)" icon="chart-bar" color="#f59e0b">
73
- 所有 gate 都过,但至少一个 soft 低于阈值。质量回归——默认不报红,`--strict` 下才报红。
73
+ <Card title="errored" icon="triangle-exclamation" color="#f59e0b">
74
+ 执行异常、超时或作者错误,本次执行无法形成可信结论——不伪装成断言失败。
74
75
  </Card>
75
76
  <Card title="skipped" icon="forward" color="#6b7280">
76
77
  调用了 `t.skip("reason")`。完全排除在通过率统计之外。
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  title: "NiceEval 中的 eval:生命周期、verdict 与文件"
3
3
  sidebarTitle: "评估"
4
- description: "eval 是一个测试用例:描述、agent 引用和 test 函数。了解 eval 如何被发现、调度、评分和报告。"
4
+ description: "eval 是一个测试用例:描述和 test 函数,agent-neutral。了解 eval 如何被发现、调度、评分和报告。"
5
5
  ---
6
6
 
7
7
  一个 eval 是一个可运行的测试用例。它通常由一个 `*.eval.ts` 文件导出,通过 `defineEval` 声明。
@@ -28,9 +28,10 @@ export default defineEval({
28
28
  | 字段 | 说明 |
29
29
  |---|---|
30
30
  | `description` | 给人看的描述,出现在报告里 |
31
- | `agent` | 使用哪个 Adapter,可由配置或 CLI 覆盖 |
32
31
  | `test(t)` | 交互和断言逻辑 |
33
32
 
33
+ eval 本身不声明用哪个 Agent——它默认保持 agent-neutral,同一个 eval 可以在不同 experiment 下跑不同 Agent。选哪个 Agent 是 experiment 的字段,不由 CLI 临时覆盖。
34
+
34
35
  <Note>
35
36
  不要手写 `id` 或 `name`。[NiceEval](https://niceeval.com/) 从文件路径推导 ID。
36
37
  </Note>
@@ -73,13 +74,13 @@ npx niceeval exp local weather/brooklyn
73
74
 
74
75
  <CardGroup cols={2}>
75
76
  <Card title="passed" icon="circle-check" color="#22c55e">
76
- 所有 gate 断言通过,并且没有未满足的硬失败。
77
+ 所有 gate 断言通过(`--strict` 下 soft 断言也都达到阈值),并且没有执行错误。
77
78
  </Card>
78
79
  <Card title="failed" icon="circle-xmark" color="#ef4444">
79
- 至少一个 gate 断言失败,或运行本身失败。
80
+ 至少一个 gate 断言失败,或 `--strict` 下有 soft 断言低于阈值。
80
81
  </Card>
81
- <Card title="passed" icon="chart-bar" color="#f59e0b">
82
- 没有 gate 失败,但 soft 分数需要保留为分值。
82
+ <Card title="errored" icon="triangle-exclamation" color="#f59e0b">
83
+ 执行异常、超时或作者错误,本次执行无法形成可信结论。
83
84
  </Card>
84
85
  <Card title="skipped" icon="forward" color="#6b7280">
85
86
  eval 主动跳过,通常通过 `t.skip(reason)`。
@@ -25,7 +25,7 @@ export default defineExperiment({
25
25
  - `model` / `flags`:透传语义。[NiceEval](https://niceeval.com/) 不解释它们的含义,原样经 `ctx` 递给 Adapter,由 Adapter 随请求转发、应用按需切换——这正是 [Tier](/zh/concepts/tier) 里模型对比(Tier 1)和 feature A/B(Tier 3)的通道。
26
26
  - `runs`、`budget`、并发、`sandbox` 等运行参数:怎么跑、跑多少。完整字段见[写实验](/zh/guides/write-experiment)。
27
27
 
28
- Experiment 是纯配置数据,没有 `setup` / `teardown` 这类生命周期字段。要按实验准备环境(装二进制、预热、跨 attempt 存取状态),挂在 `sandbox` 字段的 spec 上——`dockerSandbox()` 等工厂返回的对象可以链 `.setup()` / `.teardown()`,见 [Sandbox 后端 · 环境钩子](/zh/guides/sandbox-providers#环境钩子)。
28
+ Experiment 是纯配置数据,没有 `setup` / `teardown` 这类生命周期字段。要按实验准备环境(装二进制、预热、跨 attempt 存取状态),挂在 `sandbox` 字段的 spec 上——`dockerSandbox()` 等工厂返回的对象可以链 `.setup()` / `.teardown()`,见 [沙箱 provider · 环境钩子](/zh/guides/sandbox-providers#环境钩子)。
29
29
 
30
30
  ## 矩阵对比
31
31
 
@@ -1,10 +1,10 @@
1
1
  ---
2
2
  title: "NiceEval 架构:evals、agents 与 sandboxes"
3
3
  sidebarTitle: "概览"
4
- description: "理解 NiceEval、Adapter 和 Sandbox backend 如何配合,用统一 API 评估任意 AI agent。"
4
+ description: "理解 NiceEval、Adapter 和 Sandbox Provider 如何配合,用统一 API 评估任意 AI Agent。"
5
5
  ---
6
6
 
7
- [NiceEval](https://niceeval.com/) 的核心设计是把“评测逻辑”与“如何连接被测对象”分开。[NiceEval](https://niceeval.com/) 负责发现、调度、评分和报告;Adapter 负责调用被测系统;Sandbox backend 负责隔离文件系统。
7
+ [NiceEval](https://niceeval.com/) 的核心设计是把“评测逻辑”与“如何连接被测对象”分开。[NiceEval](https://niceeval.com/) 负责发现、调度、评分和报告;Adapter 负责调用被测系统;Sandbox Provider 负责隔离文件系统。
8
8
 
9
9
  ## 四层架构
10
10
 
@@ -15,7 +15,7 @@ NiceEval
15
15
 
16
16
  Adapter
17
17
 
18
- Subject under test / Sandbox backend
18
+ Subject under test / Sandbox Provider
19
19
  ```
20
20
 
21
21
  ## NiceEval 负责什么
@@ -53,12 +53,12 @@ Subject under test / Sandbox backend
53
53
 
54
54
  <Tabs>
55
55
  <Tab title="Docker">
56
- 本地容器后端,适合开发和 CI 中的 coding-agent eval。
56
+ 本地容器 Provider,适合开发和 CI 中的 coding-agent eval。
57
57
  </Tab>
58
58
  <Tab title="Vercel Sandbox">
59
- 云端 sandbox 后端,适合更强隔离或更大的运行资源。
59
+ 云端 Sandbox Provider,适合更强隔离或更大的运行资源。
60
60
  </Tab>
61
- <Tab title="第三方后端">
61
+ <Tab title="第三方 Provider">
62
62
  只要实现 `Sandbox` 接口,就可以接入其他沙箱服务。
63
63
  </Tab>
64
64
  </Tabs>
@@ -67,7 +67,7 @@ Subject under test / Sandbox backend
67
67
 
68
68
  <AccordionGroup>
69
69
  <Accordion title="Eval">
70
- 一个测试用例:描述、agent 引用和 `test(t)` 函数。
70
+ 一个测试用例:描述和 `test(t)` 函数,agent-neutral——用哪个 Agent 由 experiment 决定。
71
71
  </Accordion>
72
72
  <Accordion title="Agent">
73
73
  [NiceEval](https://niceeval.com/) 通过名字调用的一条连接,负责返回标准 `Turn`。