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
@@ -104,7 +104,7 @@ npx niceeval exp prompt-variants/concise
104
104
  | `timeoutMs` | 单个 attempt 的超时 |
105
105
  | `budget` | 这一格配置的预算上限 |
106
106
  | `maxConcurrency` | 这一格配置的并发上限 |
107
- | `sandbox` | sandbox agent 使用的后端,如 `dockerSandbox()` / `e2bSandbox()`;spec 上可以链 `.setup()` / `.teardown()` 挂按实验变化的环境钩子 |
107
+ | `sandbox` | sandbox agent 使用的 provider,如 `dockerSandbox()` / `e2bSandbox()`;spec 上可以链 `.setup()` / `.teardown()` 挂按实验变化的环境钩子 |
108
108
 
109
109
  Experiment 本身是纯配置数据,没有 `setup` / `teardown` 这类字段。要在跑 agent 前按实验准备环境(装二进制、预热、跨 attempt 载入和回存状态),挂在 `sandbox` 字段的 spec 上:
110
110
 
@@ -112,12 +112,14 @@ Experiment 本身是纯配置数据,没有 `setup` / `teardown` 这类字段
112
112
  export default defineExperiment({
113
113
  agent: codexAgent({ mcpServers: [mempalMcp] }),
114
114
  sandbox: e2bSandbox({ template: "fasteval-agents" })
115
- .setup(mempalSetup("codex")) // 装二进制、预热、写 hook、载入状态
115
+ .setup(mempalSetup("codex")) // 预检、写动态配置、预热、载入状态
116
116
  .teardown(mempalTeardown("codex")), // 回存状态
117
117
  maxConcurrency: 1, // 载入和回存之间不能并发,声明串行
118
118
  });
119
119
  ```
120
120
 
121
- 钩子的执行时机、多钩子顺序和失败语义见 [Sandbox 后端 · 环境钩子](/zh/guides/sandbox-providers#环境钩子)。
121
+ 固定的 Agent CLI、系统包和大模型缓存应先做进 image/template/snapshot;`.setup()` 不应在每个 Attempt 重建同一套环境。如何从官方 Docker 镜像、E2B 模板或 Vercel runtime 继续派生来提速,见 [沙箱 provider · 从官方基线继续构建以提速](/zh/guides/sandbox-providers#从官方基线继续构建以提速)。
122
+
123
+ 钩子的执行时机、多钩子顺序和失败语义见 [沙箱 provider · 环境钩子](/zh/guides/sandbox-providers#环境钩子)。
122
124
 
123
125
  跨配置比较的设计建议见[实验矩阵](/zh/guides/experiments)。adapter 如何消费 `ctx.model` 和 `ctx.flags` 见[Adapter](/zh/concepts/adapter)。
@@ -6,10 +6,11 @@ description: "手写 Adapter 的 send 函数,一条主线七步走:发消息
6
6
 
7
7
  [Adapter](/zh/concepts/adapter) 讲了契约:`send` 传入 `TurnInput` 和 `AgentContext`,返回 `Turn`。这一页讲怎么写它——从"发一条消息拿到回复"的最小形态起步,一步一步加到完整接入。每一步只在上一步的代码上多几行,前面已有的部分在代码里用 `// ……省略` 标出;每一步末尾说明这几行解锁了哪些断言。改完任何一步都能立刻验证:把新解锁的断言写进一条 eval 重跑 `npx niceeval exp`,`niceeval view` 里能看到这一步新增的数据——多轮轨迹、用量、工具事件、待回答请求。
8
8
 
9
- 两个贯穿全文的原则:
9
+ 三个贯穿全文的原则:
10
10
 
11
11
  - **接的位置永远是用户前端本来就在用的那个接口。** 页面调哪个端点、收什么格式,Adapter 就调哪个端点、收什么格式——不为 eval 开新接口,也不 import 应用内部代码直调函数(为什么,见[接入你的 Agent](/zh/guides/connect-your-agent))。
12
12
  - **你唯一真正手写的是 transport**——URL、鉴权、请求体每家本来就不一样。解析(原始返回 → 标准事件流)有官方转换器,从 `niceeval/adapter` 导出;编排(会话续接、HITL 暂停恢复)的状态槽就挂在 `ctx.session` 上,取用即可,不需要额外声明什么。
13
+ - **运行反馈走 `ctx`,不直接写终端。** 长步骤用 `ctx.progress(...)`;需要在运行后回顾的退化或异常上下文用 `ctx.diagnostic(...)`;无法继续时抛错。不要从 Adapter 调用 `console.log/error` 或写 `process.stdout/stderr`。
13
14
 
14
15
  ![一次 t.send 的完整往返:eval 调用 t.send,运行器组装 TurnInput 与 ctx,adapter 调用你的应用并返回标准事件流 Turn。](/images/agent-turn-roundtrip-zh.svg)
15
16
 
@@ -38,6 +39,7 @@ const BASE_URL = "http://localhost:8080"; // 要按 experiment 切换地址,
38
39
  export default defineAgent({
39
40
  name: "chat-app",
40
41
  async send(input, ctx) {
42
+ ctx.progress({ message: "等待 Chat API" });
41
43
  const res = await fetch(`${BASE_URL}/v1/chat/completions`, { // ← 前端本来就在用的接口
42
44
  method: "POST",
43
45
  headers: { "content-type": "application/json" },
@@ -56,6 +58,20 @@ export default defineAgent({
56
58
  });
57
59
  ```
58
60
 
61
+ 如果接口返回了可继续处理、但证据不完整的响应,报告 diagnostic 而不是把原始响应全部打印出来:
62
+
63
+ ```ts
64
+ if (!res.requestId) {
65
+ ctx.diagnostic({
66
+ code: "missing-request-id",
67
+ level: "warning",
68
+ message: "响应没有 request id,无法与服务端日志关联",
69
+ });
70
+ }
71
+ ```
72
+
73
+ `progress` 不落盘;diagnostic 会随 Attempt 保存并可通过 locator 回顾。HTTP 连接失败或响应无法解析时直接抛错,runner 会记录错误发生在 `agent.run`,并把 Attempt 标为 `errored`。
74
+
59
75
  **这一步解锁**:`t.reply`、`t.messageIncludes()`、judge 的全部对话材料,以及 experiment 侧的**模型对比**(`ctx.model` 就是 experiment 声明的 `model`,运行器原样递给你、Adapter 不解释含义,只转发——不需要等到后面的步骤,也不需要应用配合做任何改造,分档见 [Tier](/zh/concepts/tier))。
60
76
 
61
77
  它有两个明显的局限:每轮都是一场全新对话(第二次 `t.send` 接不上第一次),工具调用完全看不见。后面两步各解决一个。
@@ -137,7 +153,7 @@ export default defineAgent({
137
153
 
138
154
  ## 第四步:把工具解析成事件
139
155
 
140
- 应用的返回里不只有回复文本——Chat Completions 形返回的 `tool_calls` 记录了这轮调过什么工具。Adapter 最重要的工作就是**把接口的返回归一成标准事件流**:本轮发生的每件事一个对象,按真实发生顺序排进 `Turn.events`,对象是下面九种类型之一(各字段的实际值,[契约页有一轮的完整示例](/zh/concepts/adapter)):
156
+ 应用的返回里不只有回复文本——Chat Completions 形返回的 `tool_calls` 记录了这轮调过什么工具。Adapter 最重要的工作就是**把接口的返回归一成标准事件流**:本轮发生的每件事一个对象,按真实发生顺序排进 `Turn.events`,对象是下面十种类型之一(各字段的实际值,[契约页有一轮的完整示例](/zh/concepts/adapter)):
141
157
 
142
158
  ```ts
143
159
  type StreamEvent =
@@ -145,6 +161,7 @@ type StreamEvent =
145
161
  | { type: "action.called"; callId: string; name: string; input: JsonValue; tool?: ToolName }
146
162
  | { type: "action.result"; callId: string; output?: JsonValue;
147
163
  status: "completed" | "failed" | "rejected" }
164
+ | { type: "skill.loaded"; skill: string; callId?: string }
148
165
  | { type: "subagent.called"; callId: string; name: string; remoteUrl?: string }
149
166
  | { type: "subagent.completed"; callId: string; output?: JsonValue;
150
167
  status: "completed" | "failed" }
@@ -166,7 +166,7 @@ READ https://raw.githubusercontent.com/CorrectRoadH/niceeval/refs/heads/main/doc
166
166
 
167
167
  <AccordionGroup>
168
168
  <Accordion title="需要注册账号吗?">
169
- 不需要。跑 eval 和 `niceeval view` 看报告全在本地完成;只有被测对象本身是需要隔离工作区的 coding agent 时,才会用到 Docker 或 E2B 这类 sandbox 后端。
169
+ 不需要。跑 eval 和 `niceeval view` 看报告全在本地完成;只有被测对象本身是需要隔离工作区的 coding agent 时,才会用到 Docker 或 E2B 这类 sandbox provider。
170
170
  </Accordion>
171
171
  <Accordion title="我的 Agent 不是用 TypeScript / JavaScript 写的,能接吗?">
172
172
  能。Adapter 只是对着应用本来暴露的接口(HTTP、gRPC、WebSocket 都行)收发;应用本身用什么语言写、部署在哪里,[NiceEval](https://niceeval.com/) 不关心,见 [Adapter](/zh/concepts/adapter)。
@@ -112,6 +112,19 @@ plugins?: ClaudeCodePluginSpec[];
112
112
 
113
113
  Claude Code 原生 Plugin(先连 Marketplace,再从中装指定 Plugin)。
114
114
 
115
+ #### `settingsFile`
116
+
117
+ ```ts
118
+ settingsFile?: string;
119
+ ```
120
+
121
+ 一份完整的 Claude Code `settings.json`(官方格式)在本地项目里的路径 —— 相对运行
122
+ niceeval 的项目根(含 `niceeval.config.ts` 的目录)解析,不是 Sandbox 内路径;只接受
123
+ 项目根内的相对路径,包含 `..` 的路径、绝对路径、`~` 路径和解析后逃出项目根的符号链接
124
+ 都在 setup 阶段报错。原始字节原样上传为沙箱里原本为空的用户级 `~/.claude/settings.json`
125
+ (不继承宿主机配置、不拼接、不重新序列化);保留键 `model` 与 `env` 出现在文件里
126
+ setup 报错。manifest 只记项目相对路径与字节 SHA-256,不落正文。
127
+
115
128
  ### `CodexConfig`
116
129
 
117
130
  #### `apiKey`
@@ -157,6 +170,20 @@ plugins?: CodexPluginSpec[];
157
170
 
158
171
  Codex 原生 Plugin(先连 Marketplace,再从中装指定 Plugin)。
159
172
 
173
+ #### `configFile`
174
+
175
+ ```ts
176
+ configFile?: string;
177
+ ```
178
+
179
+ 一份完整的 Codex `config.toml`(官方 TOML 格式)在本地项目里的路径 —— 相对运行
180
+ niceeval 的项目根(含 `niceeval.config.ts` 的目录)解析,不是 Sandbox 内路径;只接受
181
+ 项目根内的相对路径,包含 `..` 的路径、绝对路径、`~` 路径和解析后逃出项目根的符号链接
182
+ 都在 setup 阶段报错。原始字节原样并入沙箱里原本为空的用户级 `~/.codex/config.toml`
183
+ (不继承宿主机配置、不解析后重写);保留键 `model`、`model_provider`、`model_providers`、
184
+ `model_reasoning_effort`、`mcp_servers`、`otel` 出现在文件里 setup 报错。manifest 只记
185
+ 项目相对路径与字节 SHA-256,不落正文。
186
+
160
187
  ### `BubConfig`
161
188
 
162
189
  #### `apiKey`
@@ -22,13 +22,13 @@ description: "NiceEval 怎么知道你的 adapter 做到了什么:没有声明
22
22
 
23
23
  ## 为什么没有声明这一层
24
24
 
25
- 上一版设计里有 `capabilities: { conversation, toolObservability }` 这类布尔声明,用来补"代码证明不了的部分"。这一层已经被拿掉,原因是它承诺的事情本身就不该由声明来担保:
25
+ NiceEval 不设 `capabilities: { conversation, toolObservability }` 这类布尔声明层来补"代码证明不了的部分",因为这类声明承诺的事情本身就不该由声明来担保:
26
26
 
27
27
  - **构造即证明**:用了 `defineSandboxAgent`,说明被测对象在沙箱里改文件——不需要再声明一遍 `workspace: true`。
28
28
  - **字段即证明**:写了 `tracing`(怎么把 OTLP 端点交给 CLI),tracing 就成立。字段本身就是使用凭证,不需要旁边再放一个布尔值重复一遍。
29
29
  - **来源即证明**:`fromAiSdk(result)` 消费的 `result.steps` 是 AI SDK 契约保证的**全量**工具循环记录,返回值自带"事件流完整"的证明;内置 CLI 的 parser 同理。手工映射时,事件完不完整取决于你的映射代码写没写全——这不是一个可以靠声明担保的东西,声明了也不会让代码更完整。
30
30
  - **行为即证明**:HITL 没有能力位——`send` 返回 `status: "waiting"` + `input.requested` 事件,行为本身可见。
31
- - **接了就续得上**:会话续接不再是"声明了才有"的开关。`ctx.session` 一直都在;用了 `id`/`capture` 或 `history` 存取器就会续接上下文,不用就每轮都是全新会话——两种都是正常状态,都不会报错,区别只在你的 adapter 实际怎么写。
31
+ - **接了就续得上**:会话续接没有"声明了才有"的开关。`ctx.session` 一直都在;用了 `id`/`capture` 或 `history` 存取器就会续接上下文,不用就每轮都是全新会话——两种都是正常状态,都不会报错,区别只在你的 adapter 实际怎么写。
32
32
 
33
33
  ```ts
34
34
  export default defineAgent({
@@ -25,7 +25,7 @@ description: "NiceEval CLI 参考:exp、show、view、init、list 和 clean
25
25
  在终端读取结果;用 `@<locator>` 或 eval ID 前缀下钻断言、Eval 源码、执行事件流、diff 和历史。
26
26
  </Card>
27
27
  <Card title="npx niceeval view" icon="eye">
28
- 打开网页结果查看器,读默认报告并交互浏览 Eval 源码、执行事件流、diff 与历史;默认范围与 `show` 相同。
28
+ 打开网页结果查看器,读默认报告并交互浏览 Eval 源码、执行事件流与 diff;默认范围与 `show` 相同。跨 run 时间轴(`--history`)是 `show` 专用的终端能力。
29
29
  </Card>
30
30
  </CardGroup>
31
31
 
@@ -64,7 +64,7 @@ npx niceeval exp compare-models weather
64
64
 
65
65
  ## 常用 flags
66
66
 
67
- 下表由 CLI 的 flag 解析表生成,表外的 flag 一律按未知 flag 报错并以非零状态退出。**没有**用于选择 sandbox 后端的 CLI flag:sandbox 后端只能写在代码里——在 experiment(`defineExperiment`)里设置 `sandbox`,或者在 `niceeval.config.ts`(`defineConfig`)里设置作为项目级兜底,值来自 `niceeval/sandbox` 的 `dockerSandbox()` / `vercelSandbox()` / `e2bSandbox()`。
67
+ 下表由 CLI 的 flag 解析表生成,表外的 flag 一律按未知 flag 报错并以非零状态退出。**没有**用于选择 sandbox provider CLI flag:sandbox provider 只能写在代码里——在 experiment(`defineExperiment`)里设置 `sandbox`,或者在 `niceeval.config.ts`(`defineConfig`)里设置作为项目级兜底,值来自 `niceeval/sandbox` 的 `dockerSandbox()` / `vercelSandbox()` / `e2bSandbox()`。
68
68
 
69
69
  {/* GENERATED:BEGIN cli-flags */}
70
70
 
@@ -78,20 +78,27 @@ npx niceeval exp compare-models weather
78
78
  | `--max-concurrency` | number | 设置同时运行的 eval 数量。 |
79
79
  | `--timeout` | number | 单个 attempt 的超时时间,单位毫秒。 |
80
80
  | `--budget` | number | 整次运行的预算上限(美元)。 |
81
+ | `--keep-sandbox` | boolean | `exp` 命令专用:跑完留下 failed/errored attempt 的沙箱现场(= `--keep-sandbox=failed`);`--keep-sandbox=all` 连 passed 也留。事后用 `niceeval sandbox list/enter/stop` 查看与销毁。 |
82
+ | `--all` | boolean | `sandbox stop` 专用:销毁全部留存沙箱。 |
83
+ | `--window` | string | `sandbox diff` 专用:只看某个 send 窗口(如 `--window s1/t2`);省略输出全部窗口的串联视图。 |
84
+ | `--path` | string | `sandbox diff` 专用:只看某个文件的 patch;省略输出该窗口的全部文件。 |
85
+ | `--leave-running` | boolean | `sandbox enter` 专用:shell 退出后让现场保持运行,不送回休眠。 |
81
86
  | `--tag` | string | 只运行带有该 tag 的 eval(见 `defineEval` 的 `tags`)。 |
82
87
  | `--junit` | string | 额外写一份 JUnit XML 报告到指定路径,供 CI 消费。 |
83
88
  | `--json` | string | 额外写一份 JSON 结果(`RunSummary` 原样序列化)到指定路径,供 CI 或下游脚本消费。 |
84
89
  | `--out` | string | `view` 命令专用:把结果查看器静态导出到指定目录。 |
85
90
  | `--port` | number | `view` 命令专用:指定本地服务器监听端口。 |
91
+ | `--allow-sensitive-artifacts` | boolean | `view --out` 专用:对非发布根(快照没有 publish:&#123;redaction:"applied"&#125; 标记)导出时的显式确认——静态站会原样携带未消毒的证据文件。 |
86
92
  | `--eval` | boolean | `show` 命令专用:该 attempt 运行时保存的 Eval 源码,gate/soft 断言标回源码行(证据切面)。 |
87
93
  | `--execution` | boolean | `show` 命令专用:该 attempt 的标准执行事件流(消息、thinking、Skill load、工具调用/结果);有 OTel 时同一节点补时间(证据切面)。 |
94
+ | `--timing` | boolean | `show` 命令专用:整个 Attempt 的统一时间树;裸 `--timing` 给有界诊断投影,`--timing=full` 逐节点展开全部 runner/已关联 OTel 节点。 |
88
95
  | `--diff` | boolean | `show` 命令专用:sandbox 里的文件改动摘要;`--diff=<文件路径>` 看单个文件的完整改动(路径必须 `=` 连写)。 |
89
96
  | `--history` | boolean | `show` 命令专用:跨 run 时间轴,只列真实执行;与 `--report` 互斥。 |
90
- | `--experiment` | string | `show` / `view` 命令专用:Selection 只留该实验。 |
97
+ | `--experiment` | string | `show` / `view` 命令专用:按路径段前缀收窄 experiment;组名会选中组内全部配置。 |
91
98
  | `--run` | string | `show` / `view` 命令专用:钉死看某一个结果目录(某次快照或 `copySnapshots` 产物)。 |
92
- | `--report` | string | `show` / `view` 命令专用:渲染你的报告文件(文件默认导出 `defineReport(...)`);show 用它替换 Attempt 索引,view 用它替换默认分析报告。 |
93
- | `--dry` | boolean | 只打印本次会匹配到的 eval × 运行配置,不实际执行。 |
94
- | `--quiet` | boolean | 关闭控制台 / live 的逐条结果与末尾汇总(attempt 进度行仍写 stderr);errored / failed 的结果各在 stderr 补一行摘要,passed / skipped 静默;reporter 仍会写 artifacts。 |
99
+ | `--report` | string | `show` / `view` 命令专用:用文件默认导出的 `defineReport(...)` 替换两者共用的默认报告。 |
100
+ | `--dry` | boolean | 只打印本次会匹配到的 eval × 运行配置,不实际执行(按下面 `--output` 选中的 profile 给出预览)。 |
101
+ | `--output` | string | 反馈 profile:`auto`(默认)按环境自动选择,`human` / `agent` / `ci` 强制指定;只改变终端展示,不改变选择、调度、判定、artifact 或退出码。`auto` 依次判定:stderr TTY human;否则 `CI`(或其它常见 CI 平台环境变量)存在 ci;否则 → agent。 |
95
102
  | `--force` | boolean | 忽略上次运行结果,不跳过已通过的 (experiment, eval) 组合,强制全部重跑。 |
96
103
  | `--strict` | boolean | CI 中推荐使用:让软阈值(`soft`)失败也计入整条 eval 的 verdict。 |
97
104
  | `--early-exit` / `--no-early-exit` | boolean | 某个 eval 的一次 attempt 通过后,停止该 eval 剩余的 attempts。 |
@@ -118,13 +125,32 @@ npx niceeval exp compare-models weather-tool
118
125
 
119
126
  运行命名 experiment,用矩阵比较 agents、models 或 flags。第二个参数开始是 eval ID 前缀过滤。
120
127
 
128
+ `show` 与 `view` 是顶层命令,应写成 `npx niceeval show`、`npx niceeval view`。误写成 `npx niceeval exp show` / `exp view` 且没有同名 experiment 时,CLI 会在“不存在的实验”错误后提示正确命令;仓库确实存在同名 experiment 时仍按合法 id 执行。
129
+
130
+ ## `--output`:human / agent / ci
131
+
132
+ `--output` 选一种终端反馈模型,只改变展示,不改变选择、调度、判定、artifact 或退出码;省略时的默认值 `auto` 按环境自动选择。三种消费者各有推荐命令:
133
+
134
+ ```bash
135
+ # 人在 TTY 前:动态 dashboard + 永久失败/诊断行
136
+ npx niceeval exp compare --output human
137
+
138
+ # coding agent / 自动修复循环:低频 checkpoint + 有界 handoff block
139
+ npx niceeval exp compare --output agent
140
+
141
+ # CI job:单一有序 stdout 事件流 + 退出码 + JSON/JUnit
142
+ npx niceeval exp compare --output ci --strict --json .niceeval/ci-summary.json --junit .niceeval/junit.xml
143
+ ```
144
+
145
+ 三种 profile 的完整对比见[运行器 · Reporter](/zh/guides/runner#reporter);人在终端里怎么读 dashboard 与结束摘要见上面的[常用 flags](#常用-flags)与本页各命令示例;AI 反馈闭环的完整用法(读输出、按 locator 下钻、局部重跑)见 [AI 反馈闭环](/zh/guides/agent-feedback-loop);CI 集成(GitHub Actions、退出码、JSON/JUnit)见 [CI 集成](/zh/guides/ci-integration)。
146
+
121
147
  ## `view`
122
148
 
123
149
  ```bash
124
150
  npx niceeval view
125
151
  ```
126
152
 
127
- 打开本地结果查看器。它和 `show` 共用同一份默认报告和同一套默认选择——对每个 experiment、每个 eval,取历次运行里最新的那份判定;只补跑部分 eval 时,其余 eval 从更早的运行补齐。`show` 输出终端文本,`view` 输出网页并提供可交互的证据浏览;eval ID 前缀、`--experiment`、`--run` 对两者的收窄一致。完整说明见[查看结果](/zh/guides/viewing-results)。
153
+ 打开本地结果查看器。它和 `show` 共用同一份默认报告和同一套默认选择——对每个 experiment、每个 eval,取历次运行里最新的那份判定;只补跑部分 eval 时,其余 eval 从更早的运行补齐。默认报告按 experiment id 的父目录分组,只在同组内比较。`show` 输出终端文本,`view` 输出网页并提供可交互的证据浏览;eval ID 前缀、`--experiment`、`--run` 对两者的收窄一致。完整说明见[查看结果](/zh/guides/viewing-results)。
128
154
 
129
155
  ## `show [id-prefix...]`
130
156
 
@@ -138,9 +164,9 @@ npx niceeval show fixtures/button --diff
138
164
  npx niceeval show weather/brooklyn --history
139
165
  ```
140
166
 
141
- `show` 是终端结果入口,适合人直接阅读,也适合 coding agent 在上下文窗口里逐级下钻。位置参数选「看哪些 eval」(ID 前缀)或直接用 `@<locator>` 精确选一个 attempt;不带位置参数时显示默认报告(每行带紧凑 attempt 索引),指定到单个 eval 时显示各 experiment 的 attempt、断言、错误与用量。
167
+ `show` 是终端结果入口,适合人直接阅读,也适合 coding agent 在上下文窗口里逐级下钻。位置参数选「看哪些 eval」(ID 前缀)或直接用 `@<locator>` 精确选一个 attempt;不带位置参数时显示按实验组分区的默认比较报告,指定 eval ID 前缀只收窄报告覆盖的 Eval,不改变组边界。
142
168
 
143
- `@<locator>` 不带证据 flag 时给出该 attempt 的紧凑全景(断言摘要、执行摘要、可选 OTel 时间、diff 摘要);`--eval`、`--execution`、`--diff` 是同一 attempt 的证据切面,分别展开运行时保存的 Eval 源码、标准执行事件流、工作区文件改动。`--eval`、`--execution`、`--diff` 也能配一个 eval ID 前缀使用,但要求最终只匹配一个 eval——多 experiment 或多 attempt 时默认选择最新一次失败的 attempt;用 `--experiment` 收窄实验,或直接用 `@<locator>` 精确指名。`--run` 钉住某次结果目录,`--history` 查看跨 run 趋势。完整的阅读顺序、输出示例和 artifact 说明见[查看结果](/zh/guides/viewing-results)。
169
+ `@<locator>` 不带证据 flag 时给出该 attempt 的紧凑全景(断言摘要、执行摘要、可选 OTel 时间、diff 摘要);`--eval`、`--execution`、`--diff` 是同一 attempt 的证据切面,分别展开运行时保存的 Eval 源码、标准执行事件流、工作区文件改动,因此必须搭配 `@<locator>` 精确指名一个 attempt。`--run` 钉住某次结果目录,`--history` 查看跨 run 趋势。完整的阅读顺序、输出示例和 artifact 说明见[查看结果](/zh/guides/viewing-results)。
144
170
 
145
171
  ## `--early-exit` 与 `--strict`
146
172
 
@@ -92,6 +92,14 @@ name: string;
92
92
 
93
93
  agent 的显示名/标识,原样进入 `Agent.name`——不是注册表查找 key,只用于展示、结果归属与去重指纹。
94
94
 
95
+ #### `coverage`
96
+
97
+ ```ts
98
+ coverage?: EvidenceCoverage;
99
+ ```
100
+
101
+ 该 Adapter 的常态证据覆盖声明(完整采集的用 `completeCoverage` 常量);省略 = 全通道 unknown。
102
+
95
103
  #### `setup`
96
104
 
97
105
  ```ts
@@ -145,6 +153,14 @@ name: string;
145
153
 
146
154
  agent 的显示名/标识,原样进入 `Agent.name`——不是注册表查找 key,只用于展示、结果归属与去重指纹。
147
155
 
156
+ #### `coverage`
157
+
158
+ ```ts
159
+ coverage?: EvidenceCoverage;
160
+ ```
161
+
162
+ 该 Adapter 的常态证据覆盖声明(完整采集的用 `completeCoverage` 常量);省略 = 全通道 unknown。
163
+
148
164
  #### `setup`
149
165
 
150
166
  ```ts
@@ -245,7 +261,9 @@ experiment 跑(如脱离 CLI、直接构造 `AgentRun` 的场景)时为 undefine
245
261
  readonly sandbox: Sandbox;
246
262
  ```
247
263
 
248
- 仅沙箱型 agent 有(运行器按 --sandbox 备好)。
264
+ 所有 agent 都有:沙箱型是运行器按项目/experiment 配置备好的真实沙箱句柄,remote 型是
265
+ `createRemoteSandbox()` 产出的 stub(仅含 `workdir`/`sandboxId`/`otlpHost`/`stop` 等
266
+ 元信息,其余方法调用即抛错)。
249
267
 
250
268
  #### `session`
251
269
 
@@ -266,16 +284,35 @@ spread 进 send;file-based 的在 tracing.configure 里写配置。远程 HTTP
266
284
  只需要把 headers spread 进请求头(每轮一个新 traceparent);端点是启动期配置
267
285
  (defineConfig(&#123; telemetry: &#123; port &#125; &#125;))固定的,不从这里传。
268
286
 
287
+ #### `progress`
288
+
289
+ ```ts
290
+ progress(update: ProgressUpdate): void;
291
+ ```
292
+
293
+ 作用域反馈:报告此刻正在做什么(turn / tool / 安装进度)。短命状态——Human profile
294
+ 更新 active 行,`agent`/`ci` 不逐条打印,也不进最终结果;不要每个 token/delta 都调用。
295
+ runner 按当前回调所处的生命周期阶段(agent.setup / agent.run / agent.teardown)归因,
296
+ 调用方不能冒充其它阶段(见 docs/feature/experiments/library.md)。
297
+
298
+ #### `diagnostic`
299
+
300
+ ```ts
301
+ diagnostic(input: DiagnosticInput): void;
302
+ ```
303
+
304
+ 作用域反馈:报告运行结束后仍应保留的问题(协议降级、数据不完整、cleanup 问题)。
305
+ 永久事件,落进 attempt 的 diagnostics 并进各 profile 的永久输出;`dedupeKey` 去重。
306
+ 即使 level 为 "error" 也不改变 Turn.status / verdict——无法继续时抛异常。
307
+
269
308
  #### `log`
270
309
 
271
310
  ```ts
272
311
  log(msg: string): void;
273
312
  ```
274
313
 
275
- 写一行进运行器自身的进度日志( stderr,或调用方传入的 `onProgress` 回调)。
276
- 超时失败时,最近若干行会并入结果的 error 信息,方便定位卡在哪一步。
277
- 与 `Sandbox.appendLog` 是两回事:那个是把一行写进容器自己的原生日志
278
- (`docker logs` 能看到),这里只是运行器的观测通道。
314
+ `progress({ message: msg })` 的别名,不是第二条通道(见 docs/feature/experiments/cli.md
315
+ 「Attempt 阶段」)。超时失败时最近若干行会并入结果的 error 信息,方便定位卡在哪一步。
279
316
 
280
317
  {/* GENERATED:END agent-def */}
281
318
 
@@ -456,6 +493,24 @@ stream?: boolean;
456
493
  日志里看到 agent 的【原始输出】。provider 各自实现(docker:tee 到 PID1 tail 的文件;
457
494
  不支持的 provider 忽略)—— 日志怎么浮现是 provider 的事,adapter 只声明意图。
458
495
 
496
+ #### `onStdout`
497
+
498
+ ```ts
499
+ onStdout?: (chunk: string) => void | Promise<void>;
500
+ ```
501
+
502
+ 命令 stdout 每到一块就调用一次。回调只用于运行中的短命反馈;完整 stdout 仍会原样
503
+ 出现在返回的 `CommandResult` 里。provider 不支持真流时,至少会在命令结束后按完整
504
+ stdout 调用一次,不能静默丢掉。
505
+
506
+ #### `onStderr`
507
+
508
+ ```ts
509
+ onStderr?: (chunk: string) => void | Promise<void>;
510
+ ```
511
+
512
+ `onStdout` 的 stderr 对应物;完整 stderr 仍保留在 `CommandResult`。
513
+
459
514
  #### `root`
460
515
 
461
516
  ```ts
@@ -106,4 +106,4 @@ pricing?: Record<string, PriceOverride>;
106
106
 
107
107
  {/* GENERATED:END config-fields */}
108
108
 
109
- [NiceEval](https://niceeval.com/) 把环境准备放在普通代码里:eval 自己需要的文件写在 `test(t)`,agent 自己的准备写在 adapter 的 `setup`。sandbox 后端不再从环境变量自动探测,也没有对应的 CLI flag——用 `niceeval/sandbox` 里的 `dockerSandbox()` / `vercelSandbox()` / `e2bSandbox()` 构造后填进 `sandbox` 字段(可以直接写在 experiment 上,也可以只写在这里作为项目级兜底:`exp.sandbox ?? config.sandbox`)。
109
+ [NiceEval](https://niceeval.com/) 把环境准备放在普通代码里:eval 自己需要的文件写在 `test(t)`,agent 自己的准备写在 adapter 的 `setup`。sandbox provider 只来自代码里的 `sandbox` 字段,不做环境变量自动探测,也没有对应的 CLI flag——用 `niceeval/sandbox` 里的 `dockerSandbox()` / `vercelSandbox()` / `e2bSandbox()` 构造后填进 `sandbox` 字段(可以直接写在 experiment 上,也可以只写在这里作为项目级兜底:`exp.sandbox ?? config.sandbox`)。
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  title: "defineEval:声明、配置并运行 NiceEval eval"
3
3
  sidebarTitle: "defineEval"
4
- description: "defineEval 参考:选项、test context t、Turn 返回值、sandbox helper 和数据集数组导出。"
4
+ description: "defineEval 参考:选项、test context t、Turn 返回值、sandbox helper,以及数组和 keyed record 数据集导出。"
5
5
  ---
6
6
 
7
7
  `defineEval` 是编写 eval 的主要入口。每个 eval 文件调用一次,传入描述和 `test(t)`,并默认导出结果。
@@ -84,15 +84,28 @@ metadata?: Record<string, unknown>;
84
84
 
85
85
  任意附加元数据,原样透传进 EvalResult,不参与调度或打分;供自定义 reporter 消费。
86
86
 
87
+ #### `diff`
88
+
89
+ ```ts
90
+ diff?: { include?: string[]; ignore?: string[] };
91
+ ```
92
+
93
+ 调整 agent diff 的归因排除清单(仅沙箱型;见 docs/feature/eval/README.md):两个数组都是
94
+ gitignore 风格 glob(workdir 相对)。默认排除 .git/node_modules/构建产物/包管理器缓存;
95
+ `ignore` 在默认清单上追加排除;`include` 优先级最高,把匹配路径显式加回。
96
+ 合成规则固定为「默认 ∪ ignore,再被 include 打洞」,清单在分类账锚点时冻结。
97
+
87
98
  #### `setup`
88
99
 
89
100
  ```ts
90
- setup?: (sandbox: Sandbox) => Promise<void | Cleanup> | void | Cleanup;
101
+ setup?: (sandbox: Sandbox, ctx: SandboxHookContext) => Promise<void | Cleanup> | void | Cleanup;
91
102
  ```
92
103
 
93
104
  eval 级预置:拿到沙箱(已上传 workspace + git 基线 + 装好依赖前)。
94
105
  默认命令以非 root 跑(agent 的自然环境);装系统依赖时给 `runCommand` 传 `{ root: true }`
95
106
  (如 `runCommand("apt-get", ["install", …], { root: true })`),跨 provider 语义一致。
107
+ 第二个参数是绑定到 `eval.setup` 的窄上下文(`ctx.progress` / `ctx.diagnostic`,
108
+ 见 docs/feature/eval/README.md);可返回 cleanup 闭包,归因到 `eval.teardown`。
96
109
 
97
110
  #### `test`
98
111
 
@@ -115,10 +128,10 @@ eval 主体:拿到 TestContext,驱动对话 / 沙箱操作并就地断言。
115
128
  #### `send`
116
129
 
117
130
  ```ts
118
- send(text: string): Promise<TurnHandle>;
131
+ send(input: SendInput): Promise<TurnHandle>;
119
132
  ```
120
133
 
121
- 向默认会话发一条消息,返回该轮的 TurnHandle。事件同时累加进默认会话的累计事件流,供下面的作用域断言使用。
134
+ 向默认会话发一条消息(字符串或结构化消息),返回该轮的 TurnHandle。事件同时累加进默认会话的累计事件流,供下面的作用域断言使用。
122
135
 
123
136
  #### `sendFile`
124
137
 
@@ -219,13 +232,31 @@ readonly flags: Readonly<Record<string, unknown>>;
219
232
 
220
233
  本次 attempt 生效的实验 flags(experiment.flags 的只读视图;实验条件,非命令行开关)。
221
234
 
235
+ #### `progress`
236
+
237
+ ```ts
238
+ progress(update: ProgressUpdate): void;
239
+ ```
240
+
241
+ 作用域反馈:报告 eval 自己执行的长步骤(上传 fixture、跑构建……)。短命状态,scope 固定
242
+ 为 `eval.run`;只报告不断言(见 docs/feature/eval/library/context.md「向运行反馈长步骤」)。
243
+
244
+ #### `diagnostic`
245
+
246
+ ```ts
247
+ diagnostic(input: DiagnosticInput): void;
248
+ ```
249
+
250
+ 作用域反馈:报告运行结束后仍需保留的问题(永久事件,落 attempt diagnostics)。
251
+ 即使 level 为 "error" 也不自动改变 verdict——测试结论仍由断言决定。
252
+
222
253
  #### `log`
223
254
 
224
255
  ```ts
225
256
  log(msg: string): void;
226
257
  ```
227
258
 
228
- 打一行调试日志;有 live 进度回调时走该回调,否则落到 stderr,不出现在最终结果里。
259
+ `progress({ message: msg })` 的别名(调试日志),不出现在最终结果里。
229
260
 
230
261
  #### `skip`
231
262
 
@@ -380,10 +411,10 @@ eventOrder(types: StreamEvent["type"][]): AssertionHandle;
380
411
  #### `eventsSatisfy`
381
412
 
382
413
  ```ts
383
- eventsSatisfy(predicate: (events: readonly StreamEvent[]) => boolean, label?: string): AssertionHandle;
414
+ eventsSatisfy(label: string, predicate: (events: readonly StreamEvent[]) => boolean): AssertionHandle;
384
415
  ```
385
416
 
386
- 用自定义谓词对默认会话累计的整段事件流断言;失败时用 label 说明原因。
417
+ 用自定义谓词对默认会话累计的整段事件流断言;label 必填、进断言标题。
387
418
 
388
419
  #### `sandbox`
389
420
 
@@ -633,10 +664,10 @@ eventOrder(types: StreamEvent["type"][]): AssertionHandle;
633
664
  #### `eventsSatisfy`
634
665
 
635
666
  ```ts
636
- eventsSatisfy(predicate: (events: readonly StreamEvent[]) => boolean, label?: string): AssertionHandle;
667
+ eventsSatisfy(label: string, predicate: (events: readonly StreamEvent[]) => boolean): AssertionHandle;
637
668
  ```
638
669
 
639
- 用自定义谓词对本轮整段事件流断言;失败时用 label 说明原因。
670
+ 用自定义谓词对本轮整段事件流断言;label 必填、进断言标题(谓词不透明,解释责任在 label)。
640
671
 
641
672
  #### `maxTokens`
642
673
 
@@ -678,3 +709,5 @@ export default rows.map((row) =>
678
709
  ```
679
710
 
680
711
  数组导出会生成稳定 ID:`file/0000`、`file/0001` 等。
712
+
713
+ 已有稳定业务 key 时也可以默认导出 `Record<string, EvalDef>`。例如 key `15193` 在 `swelancer.eval.ts` 中生成 `swelancer/15193`。key 必须是非空单一路径片段,不能是 `.` / `..`,不能含 `/`、`\\` 或控制字符;发现顺序按 key 字典序固定。
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  title: "标准事件流参考"
3
3
  sidebarTitle: "事件流"
4
- description: "StreamEvent 的九种事件:每种的字段、什么时候吐、哪些断言消费它。adapter 的核心工作就是产出这条流。"
4
+ description: "StreamEvent 的十种事件:每种的字段、什么时候吐、哪些断言消费它。adapter 的核心工作就是产出这条流。"
5
5
  ---
6
6
 
7
7
  adapter 的 `send` 返回一个 `Turn`,其中 `events: StreamEvent[]` 是**断言的唯一数据源**:`t.calledTool()`、`t.reply`、`toolOrder`、`noFailedActions`……全部从这条流上读。把你的 agent"这一轮做了什么"翻成这条流,整套断言就都能用。
@@ -79,7 +79,7 @@ token 用量或 OTel span 反推得到)。存在时优先于按价格表(`define
79
79
 
80
80
  ## StreamEvent 变体一览
81
81
 
82
- `StreamEvent` 的九种变体,逐字段列出(消费它们的断言 / 使用细节见下面的「事件总表」和「逐事件说明」):
82
+ `StreamEvent` 的十种变体,逐字段列出(消费它们的断言 / 使用细节见下面的「事件总表」和「逐事件说明」):
83
83
 
84
84
  {/* GENERATED:BEGIN stream-events */}
85
85
 
@@ -136,7 +136,7 @@ export function makeAssertion(spec: {
136
136
  t.check(t.reply, includes("Paris"));
137
137
  t.check(t.reply, includes(/order #\d+/i));
138
138
  t.check(turn.data, equals({ intent: "refund" }));
139
- t.check(t.reply, matches(/#[A-Z0-9]{8}/));
139
+ t.check(turn.data, matches(OrderSchema)); // Standard Schema / Zod 结构校验;正则匹配用 includes
140
140
  t.check(t.reply, similarity("The answer explains the refund window").atLeast(0.8));
141
141
  t.check(turn.data, satisfies((value) => Array.isArray(value)));
142
142
  ```
@@ -172,6 +172,22 @@ readonly severity: Severity;
172
172
  readonly threshold?: number;
173
173
  ```
174
174
 
175
+ #### `isOptional`
176
+
177
+ ```ts
178
+ readonly isOptional?: boolean;
179
+ ```
180
+
181
+ `.optional()` 链过的标记:评不了只记 unavailable,不把 attempt 拖成 errored。
182
+
183
+ #### `expected`
184
+
185
+ ```ts
186
+ readonly expected?: string;
187
+ ```
188
+
189
+ 期望条件的有界文本描述(如 `contains "Brooklyn"`),失败时进 AssertionResult.expected。
190
+
175
191
  #### `score`
176
192
 
177
193
  ```ts
@@ -195,18 +211,32 @@ atLeast(threshold: number): ValueAssertion;
195
211
  转成软阈值断言:未达 threshold 时该条记为 failed,但默认不拖累整条 eval 的 verdict;
196
212
  `--strict` 运行下,软阈值失败也会把整条 eval 的 verdict 计为 failed。返回新实例,不改原对象。
197
213
 
214
+ #### `optional`
215
+
216
+ ```ts
217
+ optional(): ValueAssertion;
218
+ ```
219
+
220
+ 允许这条断言证据缺席:评不了时只记录 `outcome: "unavailable"`,不影响判定。
221
+ 与 severity 正交(severity 说影不影响质量判定,optional 说证据允不允许缺席)。返回新实例,不改原对象。
222
+
198
223
  {/* GENERATED:END value-assertion */}
199
224
 
200
225
  ## 自定义 matcher
201
226
 
202
227
  ```ts
203
- import { makeAssertion } from "niceeval/expect";
228
+ import { makeAssertion, type Assertion } from "niceeval/expect";
204
229
 
205
- const validEmail = makeAssertion("valid email", (value) => {
206
- return typeof value === "string" && value.includes("@") ? 1 : 0;
207
- });
230
+ function validEmail(): Assertion {
231
+ return makeAssertion({
232
+ name: "valid email",
233
+ score(value) {
234
+ return typeof value === "string" && value.includes("@") ? 1 : 0;
235
+ },
236
+ });
237
+ }
208
238
 
209
239
  t.check(t.reply, validEmail());
210
240
  ```
211
241
 
212
- 自定义 matcher 应返回 0 1 之间的分数,并给出清晰名称。
242
+ `makeAssertion` 接受单个 spec 对象(`name`、可选 `severity`/`threshold`、`score`),直接返回一个 `Assertion`;按惯例用一个同名函数包一层再调用,而不是把 `makeAssertion` 本身当工厂调用。
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "niceeval",
3
- "version": "0.6.0",
3
+ "version": "0.6.2",
4
4
  "description": "Agent-native eval tool — eval agents, services, functions, and coding-agent fixtures",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -24,6 +24,10 @@
24
24
  "types": "./src/sandbox/index.ts",
25
25
  "import": "./src/sandbox/index.ts"
26
26
  },
27
+ "./sandbox/e2b-template": {
28
+ "types": "./src/sandbox/e2b-agent-template.ts",
29
+ "import": "./src/sandbox/e2b-agent-template.ts"
30
+ },
27
31
  "./adapter": {
28
32
  "types": "./src/agents/index.ts",
29
33
  "import": "./src/agents/index.ts"
@@ -1,3 +1,4 @@
1
+ // cases: docs/engineering/unit-tests/adapters/cases.md
1
2
  import { describe, expect, it } from "vitest";
2
3
 
3
4
  import { aiSdkOtel } from "./ai-sdk-otel.ts";
@@ -1,3 +1,4 @@
1
+ // cases: docs/engineering/unit-tests/adapters/cases.md
1
2
  import { describe, expect, it } from "vitest";
2
3
 
3
4
  import { aiSdkAgent, fromAiSdk } from "./ai-sdk.ts";
@@ -457,6 +458,8 @@ function fakeCtx(opts: { id?: string } = {}): AgentContext {
457
458
  flags: {},
458
459
  sandbox: undefined as unknown as AgentContext["sandbox"],
459
460
  session,
461
+ progress: () => {},
462
+ diagnostic: () => {},
460
463
  log: () => {},
461
464
  };
462
465
  }
@@ -13,6 +13,7 @@
13
13
  // (不在 steps 里),这里挖出来补成 `action.result` —— 拒绝(execution-denied)映射成
14
14
  // `status: "rejected"`,喂 `calledTool(..., { status: "rejected" })` 与 `noFailedActions()`。
15
15
 
16
+ import { completeCoverage } from "../scoring/coverage.ts";
16
17
  import { randomUUID } from "node:crypto";
17
18
 
18
19
  import { defineAgent } from "../define.ts";
@@ -466,6 +467,8 @@ export function aiSdkAgent<M = unknown>(options: AiSdkAgentOptions<M>): Agent {
466
467
 
467
468
  return defineAgent({
468
469
  name: options.name ?? "ai-sdk",
470
+ // 官方 SDK 完整 steps/output:全通道 complete(见 adapters/architecture/evidence.md)。
471
+ coverage: completeCoverage,
469
472
  // tracing 开了才让运行器为这个 agent 起 OTLP 接收器(ctx.telemetry 才会出现);
470
473
  // AgentTracing 的其余字段(env/configure/scope)这里都用不上,空对象即可。
471
474
  tracing: options.tracing ? {} : undefined,