niceeval 0.6.1 → 0.7.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.
Files changed (378) hide show
  1. package/INDEX.md +23 -23
  2. package/README.zh.md +6 -6
  3. package/dist/agents/types.d.ts +69 -7
  4. package/dist/context/types.d.ts +32 -12
  5. package/dist/i18n/en.d.ts +54 -0
  6. package/dist/i18n/zh-CN.d.ts +57 -3
  7. package/dist/o11y/types.d.ts +16 -2
  8. package/dist/report/aggregate.d.ts +32 -24
  9. package/dist/report/aggregate.js +158 -50
  10. package/dist/report/built-in/index.d.ts +2 -0
  11. package/dist/report/built-in/index.js +8 -0
  12. package/dist/report/components.d.ts +93 -160
  13. package/dist/report/components.js +377 -114
  14. package/dist/report/compute.d.ts +87 -81
  15. package/dist/report/compute.js +597 -417
  16. package/dist/report/flag.d.ts +32 -6
  17. package/dist/report/flag.js +92 -4
  18. package/dist/report/format.d.ts +19 -11
  19. package/dist/report/format.js +30 -13
  20. package/dist/report/index.d.ts +16 -16
  21. package/dist/report/index.js +20 -21
  22. package/dist/report/load.js +3 -2
  23. package/dist/report/locale.d.ts +57 -33
  24. package/dist/report/locale.js +122 -56
  25. package/dist/report/metrics.d.ts +23 -4
  26. package/dist/report/metrics.js +110 -25
  27. package/dist/report/primitives.d.ts +48 -15
  28. package/dist/report/primitives.js +135 -26
  29. package/dist/report/react/AttemptList.d.ts +9 -7
  30. package/dist/report/react/AttemptList.js +17 -10
  31. package/dist/report/react/DeltaTable.js +19 -18
  32. package/dist/report/react/EvalList.d.ts +4 -4
  33. package/dist/report/react/EvalList.js +0 -0
  34. package/dist/report/react/ExperimentComparison.d.ts +10 -0
  35. package/dist/report/react/ExperimentComparison.js +12 -0
  36. package/dist/report/react/ExperimentList.d.ts +4 -3
  37. package/dist/report/react/ExperimentList.js +17 -18
  38. package/dist/report/react/MetricBars.js +5 -4
  39. package/dist/report/react/MetricLine.js +12 -5
  40. package/dist/report/react/MetricMatrix.js +1 -1
  41. package/dist/report/react/MetricScatter.js +59 -28
  42. package/dist/report/react/MetricTable.js +2 -12
  43. package/dist/report/react/ScopeSummary.d.ts +10 -0
  44. package/dist/report/react/ScopeSummary.js +17 -0
  45. package/dist/report/react/Scoreboard.js +6 -6
  46. package/dist/report/react/cell.js +2 -2
  47. package/dist/report/react/chart-math.d.ts +23 -6
  48. package/dist/report/react/chart-math.js +71 -19
  49. package/dist/report/react/fixtures.d.ts +5 -9
  50. package/dist/report/react/fixtures.js +110 -147
  51. package/dist/report/react/index.d.ts +15 -5
  52. package/dist/report/react/index.js +18 -7
  53. package/dist/report/report.d.ts +137 -16
  54. package/dist/report/report.js +259 -28
  55. package/dist/report/text/faces.d.ts +17 -19
  56. package/dist/report/text/faces.js +253 -184
  57. package/dist/report/text/plot.js +1 -1
  58. package/dist/report/text/table.js +38 -7
  59. package/dist/report/tree.d.ts +90 -40
  60. package/dist/report/tree.js +252 -94
  61. package/dist/report/types.d.ts +247 -284
  62. package/dist/report/types.js +4 -3
  63. package/dist/report/web.d.ts +21 -5
  64. package/dist/report/web.js +42 -16
  65. package/dist/results/select.d.ts +38 -16
  66. package/dist/results/select.js +73 -25
  67. package/dist/results/types.d.ts +49 -14
  68. package/dist/runner/feedback/sink.d.ts +110 -0
  69. package/dist/runner/types.d.ts +513 -22
  70. package/dist/sandbox/docker.d.ts +23 -2
  71. package/dist/sandbox/e2b.d.ts +15 -1
  72. package/dist/sandbox/errors.d.ts +30 -3
  73. package/dist/sandbox/io-retry.d.ts +17 -0
  74. package/dist/sandbox/registry.d.ts +2 -0
  75. package/dist/sandbox/resolve.d.ts +18 -5
  76. package/dist/sandbox/retry.d.ts +11 -1
  77. package/dist/sandbox/types.d.ts +39 -5
  78. package/dist/sandbox/vercel.d.ts +7 -1
  79. package/dist/scoring/coverage.d.ts +30 -0
  80. package/dist/scoring/display.d.ts +21 -0
  81. package/dist/scoring/display.js +120 -0
  82. package/dist/scoring/types.d.ts +103 -20
  83. package/dist/shared/aggregate.d.ts +4 -2
  84. package/dist/shared/aggregate.js +8 -7
  85. package/dist/shared/types.d.ts +28 -0
  86. package/dist/tty-line.d.ts +0 -4
  87. package/dist/util.d.ts +23 -0
  88. package/docs-site/zh/README.md +44 -0
  89. package/docs-site/zh/examples/ai-agent-application.mdx +63 -0
  90. package/docs-site/zh/examples/coding-agent-extensions.mdx +57 -0
  91. package/docs-site/zh/examples/index.mdx +50 -0
  92. package/docs-site/zh/{concepts → explanation}/adapter.mdx +31 -13
  93. package/docs-site/zh/{concepts → explanation}/assert.mdx +7 -7
  94. package/docs-site/zh/{concepts → explanation}/drive.mdx +8 -8
  95. package/docs-site/zh/{concepts → explanation}/evals.mdx +4 -4
  96. package/docs-site/zh/{concepts → explanation}/experiment.mdx +8 -8
  97. package/docs-site/zh/{concepts → explanation}/hitl.mdx +8 -8
  98. package/docs-site/zh/{concepts → explanation}/judge.mdx +5 -5
  99. package/docs-site/zh/{concepts → explanation}/overview.mdx +11 -11
  100. package/docs-site/zh/{guides → explanation}/runner.mdx +18 -8
  101. package/docs-site/zh/{concepts → explanation}/tier.mdx +6 -6
  102. package/docs-site/zh/{guides → how-to}/agent-feedback-loop.mdx +35 -33
  103. package/docs-site/zh/{guides → how-to}/authoring.mdx +35 -2
  104. package/docs-site/zh/{guides → how-to}/ci-integration.mdx +23 -12
  105. package/docs-site/zh/{guides → how-to}/connect-otel.mdx +6 -6
  106. package/docs-site/zh/{guides → how-to}/connect-your-agent.mdx +47 -21
  107. package/docs-site/zh/{guides → how-to}/custom-reports.mdx +34 -39
  108. package/docs-site/zh/{guides → how-to}/dataset-fanout.mdx +25 -3
  109. package/docs-site/zh/{guides → how-to}/experiments.mdx +12 -5
  110. package/docs-site/zh/how-to/publish-report.mdx +105 -0
  111. package/docs-site/zh/{guides → how-to}/reporters.mdx +2 -2
  112. package/docs-site/zh/{guides → how-to}/sandbox-agent.mdx +56 -7
  113. package/docs-site/zh/how-to/sandbox-providers.mdx +350 -0
  114. package/docs-site/zh/{guides → how-to}/scoring-guide.mdx +4 -4
  115. package/docs-site/zh/{guides → how-to}/viewing-results.mdx +82 -39
  116. package/docs-site/zh/{guides → how-to}/write-experiment.mdx +6 -4
  117. package/docs-site/zh/{guides → how-to}/write-send.mdx +30 -14
  118. package/docs-site/zh/index.mdx +24 -26
  119. package/docs-site/zh/introduction.mdx +8 -8
  120. package/docs-site/zh/reference/builtin-agents.mdx +32 -5
  121. package/docs-site/zh/reference/capabilities.mdx +8 -8
  122. package/docs-site/zh/reference/cli.mdx +40 -12
  123. package/docs-site/zh/reference/define-agent.mdx +58 -5
  124. package/docs-site/zh/reference/define-config.mdx +1 -1
  125. package/docs-site/zh/reference/define-eval.mdx +42 -9
  126. package/docs-site/zh/reference/events.mdx +3 -3
  127. package/docs-site/zh/reference/expect.mdx +26 -1
  128. package/docs-site/zh/{guides → reference}/official-adapters.mdx +32 -8
  129. package/docs-site/zh/{guides → reference}/report-components.mdx +45 -33
  130. package/docs-site/zh/{guides → reference}/results-data.mdx +21 -13
  131. package/docs-site/zh/troubleshooting/debug-sandbox.mdx +57 -0
  132. package/docs-site/zh/troubleshooting/debugging.mdx +212 -0
  133. package/docs-site/zh/{quickstart.mdx → tutorials/quickstart.mdx} +5 -17
  134. package/package.json +10 -2
  135. package/src/agents/ai-sdk-otel.test.ts +1 -0
  136. package/src/agents/ai-sdk.test.ts +3 -0
  137. package/src/agents/ai-sdk.ts +3 -0
  138. package/src/agents/bub-install-spec.test.ts +34 -0
  139. package/src/agents/bub-install-spec.ts +32 -0
  140. package/src/agents/bub.ts +31 -32
  141. package/src/agents/claude-code.test.ts +130 -9
  142. package/src/agents/claude-code.ts +76 -4
  143. package/src/agents/codex.test.ts +189 -40
  144. package/src/agents/codex.ts +155 -14
  145. package/src/agents/coding-cli-versions.test.ts +15 -0
  146. package/src/agents/coding-cli-versions.ts +3 -0
  147. package/src/agents/index.ts +13 -2
  148. package/src/agents/langgraph.test.ts +204 -0
  149. package/src/agents/langgraph.ts +495 -0
  150. package/src/agents/marketplace.ts +85 -0
  151. package/src/agents/native-config.test.ts +179 -0
  152. package/src/agents/native-config.ts +267 -0
  153. package/src/agents/openai-compat.test.ts +1 -0
  154. package/src/agents/openai-compat.ts +1 -1
  155. package/src/agents/openclaw.test.ts +31 -0
  156. package/src/agents/openclaw.ts +171 -0
  157. package/src/agents/plugin-config.test.ts +1 -0
  158. package/src/agents/sdk-streams.test.ts +79 -0
  159. package/src/agents/sdk-streams.ts +55 -10
  160. package/src/agents/skills.test.ts +1 -0
  161. package/src/agents/streaming.test.ts +3 -9
  162. package/src/agents/streaming.ts +2 -2
  163. package/src/agents/types.ts +71 -8
  164. package/src/agents/ui-message-stream.test.ts +3 -0
  165. package/src/cli.ts +446 -124
  166. package/src/context/context.test.ts +51 -12
  167. package/src/context/context.ts +162 -30
  168. package/src/context/session.test.ts +2 -1
  169. package/src/context/session.ts +115 -7
  170. package/src/context/types.ts +30 -12
  171. package/src/define.test.ts +13 -8
  172. package/src/define.ts +25 -4
  173. package/src/expect/index.ts +53 -23
  174. package/src/i18n/en.ts +81 -17
  175. package/src/i18n/zh-CN.ts +80 -17
  176. package/src/o11y/cost.test.ts +1 -0
  177. package/src/o11y/execution-tree.test.ts +1 -20
  178. package/src/o11y/otlp/mappers/claude-code.test.ts +1 -0
  179. package/src/o11y/otlp/parse.test.ts +1 -0
  180. package/src/o11y/otlp/turn-otel.test.ts +1 -0
  181. package/src/o11y/parsers/bub.test.ts +1 -0
  182. package/src/o11y/parsers/claude-code.test.ts +1 -34
  183. package/src/o11y/parsers/openclaw.test.ts +154 -0
  184. package/src/o11y/parsers/openclaw.ts +310 -0
  185. package/src/o11y/prices.json +746 -311
  186. package/src/o11y/tool-names.test.ts +1 -0
  187. package/src/o11y/types.ts +16 -2
  188. package/src/report/aggregate.ts +178 -61
  189. package/src/report/built-in/index.tsx +9 -0
  190. package/src/report/components.tsx +625 -279
  191. package/src/report/compute.ts +723 -491
  192. package/src/report/dual-render.test.tsx +741 -1024
  193. package/src/report/flag.ts +104 -12
  194. package/src/report/format.ts +32 -12
  195. package/src/report/index.ts +119 -46
  196. package/src/report/load.ts +3 -2
  197. package/src/report/locale.ts +136 -65
  198. package/src/report/metrics.ts +108 -25
  199. package/src/report/primitives.tsx +196 -45
  200. package/src/report/react/AttemptList.tsx +30 -43
  201. package/src/report/react/DeltaTable.tsx +63 -45
  202. package/src/report/react/EvalList.tsx +0 -0
  203. package/src/report/react/ExperimentComparison.tsx +73 -0
  204. package/src/report/react/ExperimentList.tsx +50 -32
  205. package/src/report/react/MetricBars.tsx +5 -4
  206. package/src/report/react/MetricLine.tsx +13 -8
  207. package/src/report/react/MetricMatrix.tsx +2 -2
  208. package/src/report/react/MetricScatter.tsx +86 -34
  209. package/src/report/react/MetricTable.tsx +4 -76
  210. package/src/report/react/ScopeSummary.tsx +86 -0
  211. package/src/report/react/Scoreboard.tsx +28 -10
  212. package/src/report/react/cell.tsx +2 -2
  213. package/src/report/react/chart-math.test.ts +85 -0
  214. package/src/report/react/chart-math.ts +101 -22
  215. package/src/report/react/enhance.js +89 -5
  216. package/src/report/react/fixtures.ts +114 -154
  217. package/src/report/react/index.tsx +24 -39
  218. package/src/report/react/render.test.tsx +138 -158
  219. package/src/report/react/styles.css +243 -82
  220. package/src/report/report.test.ts +779 -841
  221. package/src/report/report.ts +423 -41
  222. package/src/report/text/faces.ts +290 -193
  223. package/src/report/text/plot.ts +1 -1
  224. package/src/report/text/table.ts +44 -7
  225. package/src/report/tree.ts +362 -104
  226. package/src/report/types.ts +261 -271
  227. package/src/report/web.ts +63 -20
  228. package/src/results/annotated-source.test.ts +62 -9
  229. package/src/results/annotated-source.ts +64 -6
  230. package/src/results/attempt-evidence.test.ts +13 -11
  231. package/src/results/attempt-evidence.ts +20 -13
  232. package/src/results/attempt-source.ts +6 -3
  233. package/src/results/copy.ts +150 -60
  234. package/src/results/host-equivalence.test.ts +34 -20
  235. package/src/results/index.ts +12 -4
  236. package/src/results/locator.test.ts +1 -22
  237. package/src/results/open.ts +15 -5
  238. package/src/results/publish.ts +149 -0
  239. package/src/results/results.test.ts +89 -54
  240. package/src/results/select.ts +104 -34
  241. package/src/results/truncate.ts +90 -0
  242. package/src/results/types.ts +43 -14
  243. package/src/results/writer.ts +31 -13
  244. package/src/runner/attempt.test.ts +138 -7
  245. package/src/runner/attempt.ts +603 -104
  246. package/src/runner/discover.test.ts +47 -0
  247. package/src/runner/discover.ts +36 -2
  248. package/src/runner/eval-source.test.ts +1 -27
  249. package/src/runner/feedback/agent.test.ts +504 -0
  250. package/src/runner/feedback/agent.ts +409 -0
  251. package/src/runner/feedback/ci.test.ts +562 -0
  252. package/src/runner/feedback/ci.ts +401 -0
  253. package/src/runner/feedback/coordinator.test.ts +317 -0
  254. package/src/runner/feedback/coordinator.ts +397 -0
  255. package/src/runner/feedback/failure.ts +40 -0
  256. package/src/runner/feedback/human.test.ts +616 -0
  257. package/src/runner/feedback/human.ts +535 -0
  258. package/src/runner/feedback/index.ts +66 -0
  259. package/src/runner/feedback/io.ts +78 -0
  260. package/src/runner/feedback/profile.test.ts +50 -0
  261. package/src/runner/feedback/profile.ts +58 -0
  262. package/src/runner/feedback/reducer.test.ts +395 -0
  263. package/src/runner/feedback/reducer.ts +260 -0
  264. package/src/runner/feedback/renderer.ts +82 -0
  265. package/src/runner/feedback/sink.ts +203 -0
  266. package/src/runner/feedback/testing.ts +106 -0
  267. package/src/runner/ledger.test.ts +230 -0
  268. package/src/runner/ledger.ts +329 -0
  269. package/src/runner/report.test.ts +128 -3
  270. package/src/runner/report.ts +33 -9
  271. package/src/runner/reporters/artifacts.ts +8 -2
  272. package/src/runner/reporters/braintrust.test.ts +8 -7
  273. package/src/runner/reporters/braintrust.ts +9 -2
  274. package/src/runner/reporters/index.ts +2 -2
  275. package/src/runner/reporters/json.test.ts +162 -0
  276. package/src/runner/reporters/json.ts +35 -8
  277. package/src/runner/reporters/shared.ts +1 -5
  278. package/src/runner/run.test.ts +760 -3
  279. package/src/runner/run.ts +243 -37
  280. package/src/runner/sandbox-prep.ts +3 -42
  281. package/src/runner/timing.ts +158 -0
  282. package/src/runner/types.ts +518 -22
  283. package/src/sandbox/checkpoint.test.ts +55 -0
  284. package/src/sandbox/checkpoint.ts +29 -8
  285. package/src/sandbox/cli-commands.ts +407 -0
  286. package/src/sandbox/docker.ts +115 -16
  287. package/src/sandbox/e2b-agent-template.test.ts +56 -0
  288. package/src/sandbox/e2b-agent-template.ts +94 -0
  289. package/src/sandbox/e2b.ts +74 -9
  290. package/src/sandbox/errors.ts +111 -4
  291. package/src/sandbox/index.ts +2 -0
  292. package/src/sandbox/io-retry.test.ts +58 -0
  293. package/src/sandbox/io-retry.ts +45 -0
  294. package/src/sandbox/keep-registry.test.ts +86 -0
  295. package/src/sandbox/keep-registry.ts +142 -0
  296. package/src/sandbox/keep.ts +178 -0
  297. package/src/sandbox/paths.test.ts +1 -0
  298. package/src/sandbox/paths.ts +19 -8
  299. package/src/sandbox/registry.ts +20 -3
  300. package/src/sandbox/resolve.ts +76 -11
  301. package/src/sandbox/retry.test.ts +70 -0
  302. package/src/sandbox/retry.ts +46 -4
  303. package/src/sandbox/types.ts +44 -6
  304. package/src/sandbox/vercel.ts +43 -20
  305. package/src/scoring/collector.ts +60 -17
  306. package/src/scoring/coverage.ts +95 -0
  307. package/src/scoring/diff.ts +81 -0
  308. package/src/scoring/display.test.ts +121 -0
  309. package/src/scoring/display.ts +133 -0
  310. package/src/scoring/evidence.test.ts +189 -0
  311. package/src/scoring/judge.test.ts +142 -0
  312. package/src/scoring/judge.ts +15 -18
  313. package/src/scoring/scoped.ts +217 -50
  314. package/src/scoring/types.ts +117 -20
  315. package/src/scoring/verdict.ts +16 -4
  316. package/src/shared/aggregate.ts +8 -6
  317. package/src/shared/types.ts +31 -0
  318. package/src/show/compose.ts +50 -67
  319. package/src/show/index.ts +127 -56
  320. package/src/show/render.ts +662 -131
  321. package/src/show/report-host.test.ts +188 -0
  322. package/src/show/report-host.ts +375 -0
  323. package/src/show/show.test.ts +320 -54
  324. package/src/tty-line.ts +8 -26
  325. package/src/util.test.ts +1 -0
  326. package/src/util.ts +41 -0
  327. package/src/view/app/App.test.tsx +69 -0
  328. package/src/view/app/App.tsx +144 -48
  329. package/src/view/app/components/AttemptModal.tsx +423 -11
  330. package/src/view/app/components/CodeView.tsx +41 -14
  331. package/src/view/app/components/CopyControls.tsx +2 -2
  332. package/src/view/app/i18n.ts +37 -17
  333. package/src/view/app/lib/attempt-route.test.ts +1 -0
  334. package/src/view/app/lib/verdict.ts +7 -9
  335. package/src/view/app/main.tsx +13 -8
  336. package/src/view/app/pages/{RunsPage.tsx → AttemptsPage.tsx} +6 -6
  337. package/src/view/app/types.ts +4 -1
  338. package/src/view/artifact-serving.test.ts +2 -1
  339. package/src/view/client-dist/app.css +1 -1
  340. package/src/view/client-dist/app.js +17 -17
  341. package/src/view/data.test.ts +10 -3
  342. package/src/view/data.ts +155 -49
  343. package/src/view/index.ts +56 -41
  344. package/src/view/server.ts +37 -15
  345. package/src/view/shared/types.ts +34 -5
  346. package/src/view/styles.css +227 -0
  347. package/src/view/view-report.test.ts +167 -62
  348. package/dist/report/built-ins/experiment-comparison.d.ts +0 -1
  349. package/dist/report/built-ins/experiment-comparison.js +0 -13
  350. package/dist/report/built-ins/index.d.ts +0 -1
  351. package/dist/report/built-ins/index.js +0 -2
  352. package/dist/report/react/GroupSummary.d.ts +0 -8
  353. package/dist/report/react/GroupSummary.js +0 -8
  354. package/dist/report/react/RunOverview.d.ts +0 -8
  355. package/dist/report/react/RunOverview.js +0 -12
  356. package/docs-site/zh/example/ai-agent-application.mdx +0 -152
  357. package/docs-site/zh/example/claude-code-codex-plugin.mdx +0 -167
  358. package/docs-site/zh/example/claude-code-codex-skill.mdx +0 -152
  359. package/docs-site/zh/example/showcase.mdx +0 -39
  360. package/docs-site/zh/guides/publish-report.mdx +0 -91
  361. package/docs-site/zh/guides/sandbox-providers.mdx +0 -102
  362. package/src/report/built-in-user-parity.test.tsx +0 -640
  363. package/src/report/built-ins/experiment-comparison.tsx +0 -19
  364. package/src/report/built-ins/index.ts +0 -2
  365. package/src/report/react/GroupSummary.tsx +0 -66
  366. package/src/report/react/RunOverview.tsx +0 -109
  367. package/src/runner/reporters/console.ts +0 -70
  368. package/src/runner/reporters/live.test.ts +0 -56
  369. package/src/runner/reporters/live.ts +0 -247
  370. package/src/runner/reporters/quiet.test.ts +0 -66
  371. package/src/runner/reporters/quiet.ts +0 -49
  372. package/src/runner/reporters/table.ts +0 -277
  373. /package/docs-site/zh/{example/tier1-ai-sdk-v7.mdx → examples/integrations/ai-sdk-v7.mdx} +0 -0
  374. /package/docs-site/zh/{example/tier1-claude-sdk.mdx → examples/integrations/claude-sdk.mdx} +0 -0
  375. /package/docs-site/zh/{example/tier1-codex-sdk.mdx → examples/integrations/codex-sdk.mdx} +0 -0
  376. /package/docs-site/zh/{example/tier1-langgraph.mdx → examples/integrations/langgraph.mdx} +0 -0
  377. /package/docs-site/zh/{example/tier1-pi-sdk.mdx → examples/integrations/pi-sdk.mdx} +0 -0
  378. /package/docs-site/zh/{guides → how-to}/fixtures.mdx +0 -0
@@ -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 {
@@ -16,12 +16,14 @@ export declare function displayExperimentName(id: string | undefined): string |
16
16
  */
17
17
  export declare function experimentGroupOf(experimentId: string): string | undefined;
18
18
  /**
19
- * eval id 前缀过滤,同 CLI 位置参数的分段语义(src/runner/discover.ts):
20
- * "algebra" 匹配自身与 "algebra/..." 子级,不误配 "algebra2";允许 "algebra/" 尾斜杠写法,等价。
19
+ * eval id 前缀过滤,同 CLI 位置参数语义(docs/feature/reports/show.md「打开与收窄」):
20
+ * eval 位置参数是收窄过滤,按**裸前缀宽松匹配**——"algebra" 命中 "algebra""algebra/..."
21
+ * 也命中 "algebra2",多命中正是它的用途(与 `--experiment` 的按路径段匹配有意不同)。
21
22
  */
22
23
  export declare function evalPrefixPredicate(evals?: string | string[]): (id: string) => boolean;
23
24
  /** 无 experimentId 时的兜底标签。 */
24
25
  export declare function fallbackExperimentLabel(result: {
26
+ experimentId?: string;
25
27
  experiment?: ExperimentRunInfo;
26
28
  agent: string;
27
29
  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 的紧急程度)。 */
@@ -36,19 +36,20 @@ export function experimentGroupOf(experimentId) {
36
36
  return experimentId.split("/").slice(0, -1).join("/");
37
37
  }
38
38
  /**
39
- * eval id 前缀过滤,同 CLI 位置参数的分段语义(src/runner/discover.ts):
40
- * "algebra" 匹配自身与 "algebra/..." 子级,不误配 "algebra2";允许 "algebra/" 尾斜杠写法,等价。
39
+ * eval id 前缀过滤,同 CLI 位置参数语义(docs/feature/reports/show.md「打开与收窄」):
40
+ * eval 位置参数是收窄过滤,按**裸前缀宽松匹配**——"algebra" 命中 "algebra""algebra/..."
41
+ * 也命中 "algebra2",多命中正是它的用途(与 `--experiment` 的按路径段匹配有意不同)。
41
42
  */
42
43
  export function evalPrefixPredicate(evals) {
43
44
  if (evals === undefined)
44
45
  return () => true;
45
- const prefixes = (Array.isArray(evals) ? evals : [evals]).map((p) => p.replace(/\/+$/, ""));
46
- return (id) => prefixes.some((prefix) => id === prefix || id.startsWith(prefix + "/"));
46
+ const prefixes = Array.isArray(evals) ? evals : [evals];
47
+ return (id) => prefixes.some((prefix) => id.startsWith(prefix));
47
48
  }
48
49
  /** 无 experimentId 时的兜底标签。 */
49
50
  export function fallbackExperimentLabel(result) {
50
- if (result.experiment?.id)
51
- return displayExperimentName(result.experiment.id) ?? result.experiment.id;
51
+ if (result.experimentId)
52
+ return displayExperimentName(result.experimentId) ?? result.experimentId;
52
53
  if (result.model)
53
54
  return `${result.agent}/${result.model}`;
54
55
  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
  /**
@@ -0,0 +1,44 @@
1
+ # 中文公开文档信息架构
2
+
3
+ `zh/` 按读者此刻的需求组织,不按 NiceEval 的内部模块组织。判断一页放在哪里时,先问读者是在学习、完成任务、查事实、理解原理,还是修复问题。
4
+
5
+ ## 五个正文分区
6
+
7
+ | 目录 | 页面类型 | 读者要什么 | 本站边界 |
8
+ | --- | --- | --- | --- |
9
+ | `tutorials/` | Tutorial | 跟着一条安全路径拿到第一次成功 | 当前只有 `quickstart.mdx`。不为凑齐目录增加第二条入门路径 |
10
+ | `how-to/` | How-to | 完成一个现实任务 | 标题用任务表述;步骤、验证方式和失败后的下一步要清楚 |
11
+ | `explanation/` | Explanation | 理解概念、边界和运行原理 | 不承担完整操作步骤或字段罗列 |
12
+ | `reference/` | Technical Reference | 快速查准确、完整的事实 | API 签名、字段、类型和 CLI flags 以源码为权威来源 |
13
+ | `troubleshooting/` | Troubleshooting | 从可见症状定位并修复问题 | 按症状组织,不按内部模块组织 |
14
+
15
+ `index.mdx` 和 `introduction.mdx` 是站点入口,不硬归入正文类型。`examples/` 是独立资源入口,不属于 Diátaxis 的四种正文类型。
16
+
17
+ ## Examples 的收录标准
18
+
19
+ `examples/` 只收录有真实可运行源码的项目。一个案例页只回答四件事:被测对象是什么、这个项目证明什么、源码在哪里、怎么运行。操作步骤的通用版本链接 How-to,字段和配置全集链接 Reference,不在案例页复制。
20
+
21
+ - 接入前后能从仓库源码计算时,由生成器产出 diff 页面,不手抄代码。
22
+ - 同一个可运行项目只保留一张案例页。Skill、Plugin 等相邻主题共享实验设计时合并,不复制两份近似正文。
23
+ - 只有一个条目的 Showcase 不单独成页,真实项目直接列在 `examples/index.mdx`。
24
+ - 没有可运行源码、只有片段或设想的内容不进 Examples。片段进入对应 How-to,未实现方向留在 Roadmap。
25
+
26
+ ## Reference 的生成边界
27
+
28
+ Technical Reference 不等于整页都由生成器拼出来。页面仍可手写短导语、最小示例和去往 How-to 的链接,但代码形状不能手抄:
29
+
30
+ - `{/* GENERATED:BEGIN ... */}` 与 `{/* GENERATED:END ... */}` 之间的 API 成员、字段和 CLI flags 由 `pnpm docs:reference` 从源码紧邻注释生成。
31
+ - 新增需要穷举的接口字段、函数、联合类型或 CLI flag 时,扩展 `scripts/generate-reference.ts` 的 region 映射,不在 MDX 里另写一份字段全集。
32
+ - 能力矩阵、选择表和行为约束暂时由手写 Reference 承担;它们必须只描述当前实现,并避免重复已经生成的类型签名。
33
+ - `reference/` 中没有生成区块的页面不因此成为 API 事实的第二来源。出现代码形状时,优先链接已有生成页;确实缺少生成入口时先补生成器。
34
+
35
+ 运行 `pnpm docs:reference` 后,生成器只改 `zh/reference/` 中已登记的 region。`test/reference-consistency.test.ts` 会拦截源码与生成区块的漂移。
36
+
37
+ ## 当前页面归类
38
+
39
+ - `explanation/runner.mdx` 解释执行引擎如何发现、调度、缓存和产出结果,不是一步一任务的操作指南。
40
+ - `reference/official-adapters.mdx`、`reference/report-components.mdx` 和 `reference/results-data.mdx` 用于查能力、组件或数据 API,不能留在 How-to。
41
+ - `troubleshooting/debugging.mdx` 与 `troubleshooting/debug-sandbox.mdx` 从失败症状出发,目录独立,在导航中归入 How-to Guides。
42
+ - `how-to/sandbox-providers.mdx` 目前保留在 How-to,因为主问题是选择并配置 Provider;若以后字段表继续增长,再拆出独立 Provider Reference。
43
+
44
+ 新增或移动页面时,同时更新 `docs-site/docs.json` 和旧路径 redirect。校验命令以 [`../AGENTS.md`](../AGENTS.md) 为准。
@@ -0,0 +1,63 @@
1
+ ---
2
+ title: "自写 Adapter 评估 AI Agent 应用"
3
+ sidebarTitle: "AI Agent 应用"
4
+ description: "一个可运行的 AI SDK v6 Web Agent 评测项目,覆盖自写 Adapter、工具调用、图片理解、多轮会话、模型对比和双路可观测。"
5
+ ---
6
+
7
+ 这个项目演示如何用 `defineAgent` 把已有 HTTP Agent 接入 NiceEval。它适合需要控制自有协议和事件映射的应用。
8
+
9
+ - [查看完整源码](https://github.com/CorrectRoadH/niceeval/tree/main/examples/zh/ai-sdk)
10
+ - 本地目录:`examples/zh/ai-sdk/`
11
+
12
+ <Note>
13
+ 如果应用使用 AI SDK v7 的 UI Message Stream,优先使用内置 `uiMessageStreamAgent`。对应的无侵入示例见 [AI SDK v7](/zh/examples/integrations/ai-sdk-v7)。
14
+ </Note>
15
+
16
+ ## 这个项目证明什么
17
+
18
+ | 部分 | 实现 |
19
+ | --- | --- |
20
+ | 被测应用 | AI SDK v6 Web Agent,HTTP `POST /api/turn` |
21
+ | Adapter | `defineAgent` + 自定义 `AgentEvent` → `StreamEvent` 映射 |
22
+ | Eval | 天气工具、图片理解、多轮文本、多轮图片上下文 |
23
+ | Experiment | 每个文件固定一个模型,同组比较 DeepSeek 与 GPT |
24
+ | 可观测 | 应用继续上报 Langfuse,同时把本轮 OTLP 数据发给 NiceEval |
25
+
26
+ Adapter 只负责连接和翻译。URL 与模型属于 Experiment;Eval 只描述交互与好结果。这个分层让同一批 Eval 可以复用到不同模型和部署实例。
27
+
28
+ ## 目录
29
+
30
+ ```text
31
+ examples/zh/ai-sdk/
32
+ ├── src/ # 被测 Web Agent
33
+ ├── adapter/adapter.ts # 自写 NiceEval Adapter
34
+ ├── evals/ # 工具、图片和多轮 Eval
35
+ ├── experiments/ # 模型对比
36
+ └── niceeval.config.ts
37
+ ```
38
+
39
+ ## 跑起来
40
+
41
+ 这个示例调用真实模型,没有 Mock 模式。先复制环境变量并填入 OpenAI 兼容服务的凭据:
42
+
43
+ ```bash
44
+ cd examples/zh/ai-sdk
45
+ pnpm install
46
+ cp .env.example .env
47
+ pnpm dev
48
+ ```
49
+
50
+ 另开一个终端运行:
51
+
52
+ ```bash
53
+ cd examples/zh/ai-sdk
54
+ pnpm exec niceeval list
55
+ pnpm exec niceeval exp compare-models weather-tool
56
+ pnpm exec niceeval view
57
+ ```
58
+
59
+ ## 继续阅读
60
+
61
+ - [接入你的 Agent](/zh/how-to/connect-your-agent):从最小 Adapter 开始接入自己的协议。
62
+ - [如何写好 Send](/zh/how-to/write-send):逐步补齐会话、工具、HITL 和 OTel。
63
+ - [实验矩阵](/zh/how-to/experiments):组织模型和配置对比。
@@ -0,0 +1,57 @@
1
+ ---
2
+ title: "评估 Coding Agent 扩展"
3
+ sidebarTitle: "Coding Agent 扩展"
4
+ description: "用真实 Workspace、基线实验和自定义报告,评估 Skill、提示词与 Plugin Benchmark 是否改善 Coding Agent 的任务结果。"
5
+ ---
6
+
7
+ 这个案例把扩展内容作为 Experiment 变量,让同一个 Coding Agent 在同一批真实开发任务上运行,再比较任务成功率、成本、耗时和行为差异。
8
+
9
+ - [查看完整源码](https://github.com/CorrectRoadH/coding-agent-skill)
10
+ - [查看 Fixtures 指南](/zh/how-to/fixtures)
11
+
12
+ ## 两组实验
13
+
14
+ | 实验 | 对照 | 测什么 |
15
+ | --- | --- | --- |
16
+ | Zod Skill | `with-skill` vs `baseline` | Skill 是否让 Agent 稳定使用 `z.object().safeParse()`,而不是退回手写校验 |
17
+ | Ponytail Benchmark | Baseline / Caveman / Ponytail / YAGNI One-liner | 完整决策 Skill 是否比裸 Agent、简短风格 Skill 或一句提示更有效 |
18
+
19
+ Ponytail 这一组迁移自第三方 Plugin 的 Agentic Benchmark,但这个仓库实际比较的是注入给 Agent 的内容与提示。它不用于证明某个原生 Plugin 包装或安装协议是否正确。原生 Skill / Plugin 的安装配置见 [官方适配器](/zh/reference/official-adapters)。
20
+
21
+ ## 实验设计
22
+
23
+ 每个 Arm 固定相同的模型、Sandbox、任务集、Runs 和预算,只改变注入内容。Eval 不读取“当前是哪个 Arm”,也不为实验组降低验收标准。
24
+
25
+ ```text
26
+ coding-agent-skill/
27
+ ├── skills/ # 各 Arm 注入的内容
28
+ ├── workspaces/ts-starter/ # 每个 Eval 的初始项目
29
+ ├── evals/ # 真实开发任务与验证
30
+ ├── experiments/ # Baseline 和实验 Arm
31
+ └── reports/benchmark.tsx # Arm × Metric 自定义报告
32
+ ```
33
+
34
+ 验证优先看最终产物:项目测试、隐藏探针、源码和 Diff。只有事件稳定且完整时,才把 Skill Load 或工具调用作为 Gate。
35
+
36
+ ## 跑起来
37
+
38
+ ```bash
39
+ git clone https://github.com/CorrectRoadH/coding-agent-skill.git
40
+ cd coding-agent-skill
41
+ pnpm install
42
+ cp .env.example .env
43
+ docker info
44
+
45
+ pnpm exec niceeval exp ponytail-baseline
46
+ pnpm exec niceeval exp caveman
47
+ pnpm exec niceeval exp ponytail
48
+ pnpm exec niceeval exp yagni-oneliner
49
+ pnpm exec niceeval view --report reports/benchmark.tsx
50
+ ```
51
+
52
+ ## 从这个案例复用什么
53
+
54
+ - 用 Experiment 表达有扩展和无扩展的对照,不让 Eval 知道实验条件。
55
+ - Prompt 不泄露答案;验证阶段再检查测试、源码、Diff 和行为证据。
56
+ - 把任务成功率作为主指标,把 Token、成本、耗时和行为作为解释指标。
57
+ - [评分指南](/zh/how-to/scoring-guide) 负责选择 Gate、Soft 和 Judge;本页不复制评分 API。
@@ -0,0 +1,50 @@
1
+ ---
2
+ title: "NiceEval Examples"
3
+ sidebarTitle: "选择示例"
4
+ description: "按被测对象选择可运行的 NiceEval 示例:Agent Framework 接入、完整 AI Agent 评测、Coding Agent 扩展 benchmark 和真实项目。"
5
+ ---
6
+
7
+ 这里的每个示例都有真实可运行源码。先按被测对象选择,不必从头依次阅读。
8
+
9
+ 如果你还没有跑通过第一条 Eval,先读 [Quickstart](/zh/tutorials/quickstart)。如果你已经知道要完成什么,直接进入对应的 [How-to Guides](/zh/how-to/connect-your-agent)。
10
+
11
+ ## 接入已有 Agent Framework
12
+
13
+ 下面五组示例都保留接入前的普通应用和接入 NiceEval 后的完整项目。页面中的代码 diff 从这两份源码生成。
14
+
15
+ | 被测对象 | 接入方式 | 示例覆盖 |
16
+ | --- | --- | --- |
17
+ | [AI SDK v7](/zh/examples/integrations/ai-sdk-v7) | 内置 `uiMessageStreamAgent` | UI Message Stream、多轮、工具、HITL |
18
+ | [Claude Agent SDK](/zh/examples/integrations/claude-sdk) | `fromClaudeSdkMessages` | 原生事件流、多轮、工具、HITL |
19
+ | [Codex SDK](/zh/examples/integrations/codex-sdk) | `fromCodexThreadEvents` | 编码任务、文件和命令、usage;SDK 不支持 HITL |
20
+ | [pi-agent-core](/zh/examples/integrations/pi-sdk) | `fromPiAgentEvents` | 原生事件流、多轮、工具、HITL;SDK 没有 OTel |
21
+ | [LangGraph](/zh/examples/integrations/langgraph) | 手写自定义 SSE 帧映射 | Python 应用、多轮、工具、HITL |
22
+
23
+ 每组源码都位于 [`examples/zh/origin/`](https://github.com/CorrectRoadH/niceeval/tree/main/examples/zh/origin) 和 [`examples/zh/tier1/`](https://github.com/CorrectRoadH/niceeval/tree/main/examples/zh/tier1)。需要 OTel 或 Experiment Flags 时,再沿相同项目进入 `tier2/` 和 `tier3/`。
24
+
25
+ ## 完整评测项目
26
+
27
+ <CardGroup cols={2}>
28
+ <Card title="自写 Adapter 评估 AI Agent 应用" icon="robot" href="/zh/examples/ai-agent-application">
29
+ 一个 AI SDK v6 Web Agent,覆盖工具调用、图片理解、多轮会话、模型对比和双路可观测。
30
+ </Card>
31
+ <Card title="评估 Coding Agent 扩展" icon="wand-magic-sparkles" href="/zh/examples/coding-agent-extensions">
32
+ 用真实 Workspace 和对照实验衡量 Skill、提示词与 Plugin Benchmark 对任务结果的影响。
33
+ </Card>
34
+ </CardGroup>
35
+
36
+ ## 真实项目
37
+
38
+ ### Coding Agent Memory Evals
39
+
40
+ [coding-agent-memory-evals](https://github.com/CorrectRoadH/coding-agent-memory-evals) 用同一批开发任务和同一个模型,对比 Coding Agent 是否带持久记忆时的任务成功率、成本、耗时和行为差异。
41
+
42
+ - [查看在线报告](https://niceeval.com/showcase/memory)
43
+ - [查看项目源码](https://github.com/CorrectRoadH/coding-agent-memory-evals)
44
+
45
+ ## 什么不放在 Examples
46
+
47
+ - 单段 API 用法放进 How-to 或 Reference。
48
+ - 没有可运行源码的伪项目不收录。
49
+ - Roadmap 和尚未实现的接入不收录。
50
+ - 同一个项目不为 Skill、Plugin、Hook 等相邻叫法复制多张案例页。
@@ -6,7 +6,7 @@ description: "Adapter 是你写的适配器。本文讲清楚 send 函数传入
6
6
 
7
7
  在 [NiceEval](https://niceeval.com/) 里,`Adapter` 是连接运行器和被测系统的适配层。Adapter 需要实现 `send` 函数:把 `t.send()` 等 eval 侧动作发给你的应用,再把应用返回翻译成 [NiceEval](https://niceeval.com/) 的标准 `Turn`。
8
8
 
9
- 后续阅读[写 send](/zh/guides/write-send)
9
+ 后续阅读[写 send](/zh/how-to/write-send)
10
10
 
11
11
  ## 适配器
12
12
  如果被测系统使用标准的 OpenAI Chat Completions 或 Responses 协议,可以直接用官方适配器。自己实现的前后端协议(HTTP、gRPC、WebSocket 都行)则写一个 Adapter:它知道怎么鉴权、怎么调用你的应用、怎么把返回翻译成标准事件流。
@@ -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}` }],
@@ -87,12 +94,12 @@ export default defineExperiment({
87
94
 
88
95
  ## 接入等级
89
96
 
90
- 按「Adapter 接到哪里、额外拿到什么观测数据」,接入分三级:**Tier 1 只接 send**(应用代码一行不改,全套断言在这一级就齐了)、**Tier 2 send + OTel**(应用把 span 发给 [NiceEval](https://niceeval.com/),换 `niceeval view` 的调用瀑布图)、**Tier 3 侵入改造 + experiment flags**(feature A/B)。每档投入什么、买到什么、什么时候升级,见 [Tier](/zh/concepts/tier)。
97
+ 按「Adapter 接到哪里、额外拿到什么观测数据」,接入分三级:**Tier 1 只接 send**(应用代码一行不改,全套断言在这一级就齐了)、**Tier 2 send + OTel**(应用把 span 发给 [NiceEval](https://niceeval.com/),换 `niceeval view` 的调用瀑布图)、**Tier 3 侵入改造 + experiment flags**(feature A/B)。每档投入什么、买到什么、什么时候升级,见 [Tier](/zh/explanation/tier)。
91
98
 
92
99
  eval 侧的驱动 API——`t.send()`、`t.sendFile()`、`t.newSession()`、HITL 的 `t.respond()` / `t.respondAll()`
93
100
  统一都是调用 Adapter 的 `send`。
94
101
 
95
- 怎么收敛、send 里怎么接,见[写 send](/zh/guides/write-send)。
102
+ 怎么收敛、send 里怎么接,见[写 send](/zh/how-to/write-send)。
96
103
 
97
104
  ## send 函数
98
105
 
@@ -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/how-to/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 透传;应用接口收模型选择就转发
@@ -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/how-to/connect-otel)。`experimentId` 是路径推导出的稳定标识,典型用途是在 Sandbox 的环境钩子里按实验隔离跨 attempt 的状态(缓存目录名、沙箱快照 tag 按它分区),见 [沙箱 provider · 环境钩子](/zh/how-to/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/how-to/write-send)。
243
261
 
244
262
  `data` 不是"随便放点什么"的口袋,它只有一条规则:**要什么,由 eval 在 send 上用 schema 声明;声明了才有 data,拿到手就是声明的类型。**
245
263
 
@@ -284,8 +302,8 @@ turn.data.amount; // 类型是 number——不是 unknown,不用手动收窄
284
302
 
285
303
  ## 相关阅读
286
304
 
287
- - [写 send](/zh/guides/write-send) — 实操教程:从发一条消息到完整接入,七步递进,每步解锁一组断言。
288
- - [接入你的 Agent](/zh/guides/connect-your-agent) — 接入全景:最小接入、参数通道与增量地图。
289
- - [Drive](/zh/concepts/drive) — eval 侧视角:`t.send()`、`t.newSession()` 与 HITL 怎么用。
290
- - [Assert](/zh/concepts/assert) — 标准事件流驱动的完整断言词汇。
291
- - [架构概览](/zh/concepts/overview) — 四层架构和边界。
305
+ - [写 send](/zh/how-to/write-send) — 实操教程:从发一条消息到完整接入,七步递进,每步解锁一组断言。
306
+ - [接入你的 Agent](/zh/how-to/connect-your-agent) — 接入全景:最小接入、参数通道与增量地图。
307
+ - [Drive](/zh/explanation/drive) — eval 侧视角:`t.send()`、`t.newSession()` 与 HITL 怎么用。
308
+ - [Assert](/zh/explanation/assert) — 标准事件流驱动的完整断言词汇。
309
+ - [架构概览](/zh/explanation/overview) — 四层架构和边界。