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,9 +1,43 @@
1
- // 官方组件 chrome 文案的 locale 字典(en / zh-CN 两份)。
1
+ // 官方组件 chrome 文案的 locale 字典与 LocalizedText 解析。
2
+ // ReportLocale 是开放的 BCP 47 标签(数据协议不封语言上限);官方内置文案与
3
+ // MetricCell.display 生成面当前覆盖 en / zh-CN,其它 locale 走 LocalizedText 回退规则。
2
4
  // 只覆盖组件自带的固定文案(verdict 词、缺数据、覆盖率角标、注脚、占位符等);
3
- // 数据本身(display、维度键、warnings 的 message)不经这里。
4
- // 刻意不 import src/i18n/(CLI 专用字典,locale 来源与 key 面完全不同);
5
- // zh-CN 译法与 src/view/app/i18n.ts 现有词保持一致(成功率/平均耗时/预估成本…)。
5
+ // 维度键、warnings 的 message 不经这里。
6
+ // 刻意不 import src/i18n/(CLI 专用字典,locale 来源与 key 面完全不同)
6
7
  export const DEFAULT_REPORT_LOCALE = "en";
8
+ /** MetricCell.display 生成面覆盖的 locale 全集;其它 locale 按 LocalizedText 回退取 en。 */
9
+ export const DISPLAY_LOCALES = ["en", "zh-CN"];
10
+ /**
11
+ * LocalizedText 的确定回退:取当前 locale;缺失时取 en;仍缺失时取按 locale 键字典序的
12
+ * 第一个非空值。对象没有任何非空值时报错,不渲染空文案
13
+ * (docs/feature/reports/library/shell.md「行为约束」)。
14
+ */
15
+ export function resolveLocalizedText(text, locale) {
16
+ if (typeof text === "string")
17
+ return text;
18
+ const direct = text[locale];
19
+ if (direct !== undefined && direct !== "")
20
+ return direct;
21
+ const en = text.en;
22
+ if (en !== undefined && en !== "")
23
+ return en;
24
+ for (const key of Object.keys(text).sort()) {
25
+ const value = text[key];
26
+ if (value !== undefined && value !== "")
27
+ return value;
28
+ }
29
+ throw new Error("LocalizedText object has no non-empty value. Provide at least one locale entry, e.g. { en: \"…\" }.");
30
+ }
31
+ /** LocalizedText 按字段值深相等(键顺序无关;标题回退链的「唯一且相同」判定用)。 */
32
+ export function localizedTextEquals(a, b) {
33
+ if (typeof a === "string" || typeof b === "string")
34
+ return a === b;
35
+ const keysA = Object.keys(a).sort();
36
+ const keysB = Object.keys(b).sort();
37
+ if (keysA.length !== keysB.length)
38
+ return false;
39
+ return keysA.every((key, i) => key === keysB[i] && a[key] === b[key]);
40
+ }
7
41
  const en = {
8
42
  "verdict.passed": "passed",
9
43
  "verdict.failed": "failed",
@@ -14,6 +48,7 @@ const en = {
14
48
  "cell.measuredTitle": "{samples}/{total} attempts measured",
15
49
  "cell.noneMeasurableTitle": "0/{total} attempts measurable",
16
50
  "cell.coverageTitle": "coverage {samples}/{total}: this metric is null for the remaining attempts",
51
+ "cell.missingValue": "(missing)",
17
52
  "table.higherBetter": "higher is better",
18
53
  "table.lowerBetter": "lower is better",
19
54
  "table.model": "Model",
@@ -27,39 +62,47 @@ const en = {
27
62
  "table.attempt": "attempt",
28
63
  "experimentList.experiment": "Experiment",
29
64
  "experimentList.avgDuration": "Avg duration",
30
- "experimentList.passRate": "Pass rate",
65
+ "experimentList.passRate": "End-to-end pass rate",
31
66
  "experimentList.tokens": "Tokens",
32
- "experimentList.estimatedCost": "Est. cost",
67
+ "experimentList.cost": "Cost",
33
68
  "experimentList.result": "Result",
34
69
  "experimentList.status": "Status",
35
70
  "experimentList.evalAttempt": "Eval / Attempt",
36
71
  "experimentList.duration": "Duration",
37
- "experimentList.cost": "Cost",
38
72
  "experimentList.filterPlaceholder": "Filter experiments…",
39
73
  "experimentList.defaultModel": "default",
40
74
  "experimentList.flags": "Flags",
75
+ "entityList.average": "{value} avg",
76
+ "entityList.moreFailures.one": "+{n} more failure",
77
+ "entityList.moreFailures.other": "+{n} more failures",
41
78
  /** <Table> 压到下限仍放不下时,从右侧丢列并如实报数。 */
42
79
  "table.columnsHidden.one": "({n} more column not shown)",
43
80
  "table.columnsHidden.other": "({n} more columns not shown)",
44
- "overview.snapshots": "Snapshots",
45
- "overview.evals": "Evals",
46
- "overview.attempts": "attempts",
47
- "overview.passRate": "Pass rate",
48
- "overview.totalCost": "Total cost",
49
- "overview.totalDuration": "Total duration",
50
- "overview.source": "Source: {n} snapshots",
81
+ /** ScopeSummary 的 KPI 标签。 */
82
+ "scopeSummary.experiments": "Experiments",
83
+ "scopeSummary.evals": "Evals",
84
+ "scopeSummary.attempts": "attempts",
85
+ "scopeSummary.passRate": "End-to-end pass rate",
86
+ "scopeSummary.totalCost": "Total cost",
87
+ "scopeSummary.range": "{from} {to}",
88
+ "scopeSummary.votesEval": "eval verdicts",
89
+ "scopeSummary.votesAttempt": "attempt verdicts",
51
90
  "overview.experiments.one": "{n} experiment",
52
91
  "overview.experiments.other": "{n} experiments",
53
92
  "overview.evalsCount": "{n} evals",
54
93
  "overview.attemptsCount": "{n} attempts",
55
- /** GroupSummary 的 KPI dt 标签(其余字段复用 verdict.* / overview.* 已有 key)。 */
56
- "groupSummary.experiments": "Experiments",
57
- "composedFrom.one": "composed from {n} run",
58
- "composedFrom.other": "composed from {n} runs",
59
- "latestRun": "latest {run}",
60
- "scatter.betterHint": "better ",
94
+ "overview.evals": "Evals",
95
+ "overview.passRate": "End-to-end pass rate",
96
+ "overview.totalCost": "Cost",
97
+ "experimentComparison.groups": "Experiment groups",
98
+ "experimentComparison.group": "Experiment group",
99
+ "experimentComparison.results": "Eval results",
100
+ "experimentComparison.lastRun": "Last run",
101
+ "experimentComparison.selectGroup": "Select experiment group {group}",
102
+ "experimentComparison.commandsHead": "Group details:",
103
+ "experimentComparison.empty": "No experiment groups",
104
+ /** 方向提示唯一文案:轴向已随 better 反正,「更好」恒指向右上(两轴都声明 better 时才显示)。 */
61
105
  "scatter.betterUpperRight": "better → upper right",
62
- "scatter.axisReversed": "(axis reversed: right = better)",
63
106
  /** 0 个可画点:x/y 指标没有可用数据。 */
64
107
  "scatter.noData": "No data to plot {x} × {y}",
65
108
  "pointsMissing.one": "{n} point missing data",
@@ -68,19 +111,25 @@ const en = {
68
111
  "attemptList.truncated": "and {n} more not shown",
69
112
  "attemptList.truncatedText": "({n} more not shown)",
70
113
  "attemptList.score": "score {score}",
114
+ "attemptList.unavailable": "unavailable",
71
115
  "attemptList.details": "details",
72
116
  "scoreboard.total": "Total",
73
117
  "scoreboard.totalText": "total",
74
- "scoreboard.missing.one": "{n} eval missing, scored 0",
75
- "scoreboard.missing.other": "{n} evals missing, scored 0",
76
- "scoreboard.missingText": "({n} missing)",
118
+ "scoreboard.notRun.one": "{n} eval not run, scored 0",
119
+ "scoreboard.notRun.other": "{n} evals not run, scored 0",
120
+ "scoreboard.unscorable.one": "{n} eval unscorable, scored 0",
121
+ "scoreboard.unscorable.other": "{n} evals unscorable, scored 0",
122
+ "scoreboard.notRunText": "({n} not run)",
123
+ "scoreboard.unscorableText": "({n} unscorable)",
124
+ "scoreboard.ignored.one": "{n} eval outside the question set ignored",
125
+ "scoreboard.ignored.other": "{n} evals outside the question set ignored",
77
126
  "scoreboard.weights": "weights:",
78
127
  "scoreboard.allWeights": "all evals ×1",
79
128
  "scoreboard.othersWeight": "others ×1",
80
- "scoreboard.subjectTitle": "{evals} evals, weighted {earned} of {possible}",
129
+ "scoreboard.subjectTitle": "{questions} evals, weighted {earned} of {possible}",
81
130
  "delta.pairHeader": "pair (A → B)",
82
- "board.currentVerdicts": "Current verdicts",
83
- "board.failing": "Failing:",
131
+ "delta.empty": "{experiments} experiments, 0 comparable pairs",
132
+ "tabs.tab": "Tab",
84
133
  };
85
134
  const zhCN = {
86
135
  "verdict.passed": "通过",
@@ -91,6 +140,7 @@ const zhCN = {
91
140
  "cell.measuredTitle": "{samples}/{total} 次 attempt 测得",
92
141
  "cell.noneMeasurableTitle": "0/{total} 次 attempt 可测",
93
142
  "cell.coverageTitle": "覆盖率 {samples}/{total}:其余 attempt 测不了这个指标",
143
+ "cell.missingValue": "(missing)",
94
144
  "table.higherBetter": "越高越好",
95
145
  "table.lowerBetter": "越低越好",
96
146
  "table.model": "模型",
@@ -103,37 +153,44 @@ const zhCN = {
103
153
  "table.attempt": "Attempt",
104
154
  "experimentList.experiment": "实验",
105
155
  "experimentList.avgDuration": "平均耗时",
106
- "experimentList.passRate": "成功率",
156
+ "experimentList.passRate": "端到端成功率",
107
157
  "experimentList.tokens": "Tokens",
108
- "experimentList.estimatedCost": "预估成本",
158
+ "experimentList.cost": "成本",
109
159
  "experimentList.result": "结果",
110
160
  "experimentList.status": "状态",
111
161
  "experimentList.evalAttempt": "题目 / Attempt",
112
162
  "experimentList.duration": "耗时",
113
- "experimentList.cost": "成本",
114
163
  "experimentList.filterPlaceholder": "筛选实验…",
115
164
  "experimentList.defaultModel": "默认",
116
165
  "experimentList.flags": "Flags",
166
+ "entityList.average": "平均 {value}",
167
+ "entityList.moreFailures.one": "+{n} 条其它失败",
168
+ "entityList.moreFailures.other": "+{n} 条其它失败",
117
169
  "table.columnsHidden.one": "(还有 {n} 列未列出)",
118
170
  "table.columnsHidden.other": "(还有 {n} 列未列出)",
119
- "overview.snapshots": "快照",
120
- "overview.evals": "题目",
121
- "overview.attempts": "尝试",
122
- "overview.passRate": "通过率",
123
- "overview.totalCost": "总成本",
124
- "overview.totalDuration": "总耗时",
125
- "overview.source": "数据来源:{n} 个快照",
171
+ "scopeSummary.experiments": "实验数",
172
+ "scopeSummary.evals": "题目",
173
+ "scopeSummary.attempts": "次 attempt",
174
+ "scopeSummary.passRate": "端到端成功率",
175
+ "scopeSummary.totalCost": "总成本",
176
+ "scopeSummary.range": "{from} – {to}",
177
+ "scopeSummary.votesEval": "Eval 计票",
178
+ "scopeSummary.votesAttempt": "Attempt 计票",
126
179
  "overview.experiments.one": "{n} 个实验",
127
180
  "overview.experiments.other": "{n} 个实验",
128
181
  "overview.evalsCount": "{n} 道题",
129
182
  "overview.attemptsCount": "{n} 次 attempt",
130
- "groupSummary.experiments": "实验数",
131
- "composedFrom.one": "合成自 {n} 个 run",
132
- "composedFrom.other": "合成自 {n} 个 run",
133
- "latestRun": "最新 {run}",
134
- "scatter.betterHint": "更好 ↗",
135
- "scatter.betterUpperRight": "更好 → 右上",
136
- "scatter.axisReversed": "(轴反向:右 = 更好)",
183
+ "overview.evals": "Eval",
184
+ "overview.passRate": "端到端成功率",
185
+ "overview.totalCost": "成本",
186
+ "experimentComparison.groups": "实验组",
187
+ "experimentComparison.group": "实验组",
188
+ "experimentComparison.results": "Eval 结果",
189
+ "experimentComparison.lastRun": "最后运行",
190
+ "experimentComparison.selectGroup": "选择实验组 {group}",
191
+ "experimentComparison.commandsHead": "查看组内详情:",
192
+ "experimentComparison.empty": "没有实验组",
193
+ "scatter.betterUpperRight": "越靠右上越好",
137
194
  "scatter.noData": "{x} × {y} 没有可绘制的数据",
138
195
  "pointsMissing.one": "{n} 个点缺数据",
139
196
  "pointsMissing.other": "{n} 个点缺数据",
@@ -141,25 +198,31 @@ const zhCN = {
141
198
  "attemptList.truncated": "还有 {n} 条未列出",
142
199
  "attemptList.truncatedText": "(还有 {n} 条未列出)",
143
200
  "attemptList.score": "得分 {score}",
201
+ "attemptList.unavailable": "评不了",
144
202
  "attemptList.details": "详情",
145
203
  "scoreboard.total": "总分",
146
204
  "scoreboard.totalText": "总分",
147
- "scoreboard.missing.one": "{n} 道题缺席,按 0 计",
148
- "scoreboard.missing.other": "{n} 道题缺席,按 0 计",
149
- "scoreboard.missingText": "(缺 {n} 题)",
205
+ "scoreboard.notRun.one": "{n} 道题没跑,按 0 计",
206
+ "scoreboard.notRun.other": "{n} 道题没跑,按 0 计",
207
+ "scoreboard.unscorable.one": "{n} 道题测不了,按 0 计",
208
+ "scoreboard.unscorable.other": "{n} 道题测不了,按 0 计",
209
+ "scoreboard.notRunText": "(没跑 {n} 题)",
210
+ "scoreboard.unscorableText": "(测不了 {n} 题)",
211
+ "scoreboard.ignored.one": "题集之外的 {n} 道题已忽略",
212
+ "scoreboard.ignored.other": "题集之外的 {n} 道题已忽略",
150
213
  "scoreboard.weights": "权重:",
151
214
  "scoreboard.allWeights": "全部题 ×1",
152
215
  "scoreboard.othersWeight": "其余 ×1",
153
- "scoreboard.subjectTitle": "{evals} 道题,加权得分 {earned}/{possible}",
216
+ "scoreboard.subjectTitle": "{questions} 道题,加权得分 {earned}/{possible}",
154
217
  "delta.pairHeader": "对比 (A → B)",
155
- "board.currentVerdicts": "现刻判定",
156
- "board.failing": "失败清单:",
218
+ "delta.empty": "{experiments} 个实验、0 个可配对",
219
+ "tabs.tab": "Tab",
157
220
  };
158
221
  const dictionaries = {
159
222
  en,
160
223
  "zh-CN": zhCN,
161
224
  };
162
- /** 查字典 + 简单插值({name} 占位符)。缺 locale 回退 en。 */
225
+ /** 查字典 + 简单插值({name} 占位符)。内置词典未覆盖的 locale 回退 en。 */
163
226
  export function localeText(locale, key, vars) {
164
227
  const template = dictionaries[locale]?.[key] ?? dictionaries.en[key];
165
228
  if (!vars)
@@ -171,13 +234,16 @@ export function countText(locale, base, n) {
171
234
  return localeText(locale, `${base}.${n === 1 ? "one" : "other"}`, { n });
172
235
  }
173
236
  /**
174
- * 按 locale 解析指标 label:字符串原样;字典取当前 locale,缺项回退 en,
175
- * 再回退字典里任一值;全空回退 fallback(= metric.name)。渲染面(web / text)共用。
237
+ * 按 locale 解析指标 / 列 label:字符串原样;字典按 LocalizedText 回退规则取值;
238
+ * undefined 回退 fallback(= metric.name)。渲染面(web / text)共用。
176
239
  */
177
240
  export function resolveMetricLabel(label, locale, fallback) {
178
241
  if (label === undefined)
179
242
  return fallback;
180
- if (typeof label === "string")
181
- return label;
182
- return label[locale] ?? label.en ?? Object.values(label).find((v) => v !== undefined) ?? fallback;
243
+ try {
244
+ return resolveLocalizedText(label, locale);
245
+ }
246
+ catch {
247
+ return fallback;
248
+ }
183
249
  }
@@ -8,14 +8,33 @@ import type { Metric } from "./types.ts";
8
8
  export declare function defineMetric<const Name extends string>(def: Metric<Name>): Metric<Name>;
9
9
  /** 单 attempt 成本:网关实测(usage.costUSD)优先于价格表估算(estimatedCostUSD);都缺 → null,不编 0。 */
10
10
  export declare function attemptCostUSD(result: EvalResult): number | null;
11
- export declare const passRate: Metric<"pass-rate">;
11
+ /**
12
+ * 条件答题质量:passed = 1,failed = 0,errored 记 null 不进分母。
13
+ * 这是「已形成可信判定」条件下的诊断指标,不能简称默认成功率
14
+ * (docs/feature/reports/library.md「内置指标」)。
15
+ */
16
+ export declare const taskPassRate: Metric<"task-pass-rate">;
17
+ /** 执行可靠性:跑到可判定(passed / failed)= 1,errored = 0;skipped → null。 */
18
+ export declare const executionReliability: Metric<"execution-reliability">;
19
+ /**
20
+ * 端到端合成:passed = 1,failed / errored = 0;哪边拖累用
21
+ * taskPassRate / executionReliability 拆开看。
22
+ */
23
+ export declare const endToEndPassRate: Metric<"end-to-end-pass-rate">;
12
24
  export declare const examScore: Metric<"exam-score">;
13
25
  export declare const durationMs: Metric<"duration">;
14
26
  export declare const tokens: Metric<"tokens">;
15
27
  export declare const costUSD: Metric<"cost">;
16
28
  /**
17
- * 唯一读 artifact(o11y,懒加载)的内置指标——其余五个只读瘦身字段。
29
+ * artifact(o11y,懒加载)的内置指标之一——其余只读瘦身字段。
18
30
  * 发布时若该 attempt 没带 o11y(如 copySnapshots 的 artifacts 选项漏了它),
19
- * value 如实返回 null,渲染成「—」,不冒充 0——见 docs/feature/reports/library.md「内置指标」。
31
+ * value 如实返回 null,渲染成「—」,不冒充 0。名字带限定词:o11y 事件流中的 assistant
32
+ * turn 数与 `t.send` 的 `s<session>/t<turn>` 轮次是两个计数。
33
+ */
34
+ export declare const assistantTurns: Metric<"assistant-turns">;
35
+ /**
36
+ * 同一 attempt 内同一条 shell 命令的重复失败数:每条命令失败 n 次(n > 1)记 n − 1,求和。
37
+ * 成功执行与只失败一次的命令不计。回答 agent 是否在反复撞同一个已知失败的命令。
38
+ * 读 o11y.json;skipped 与缺 o11y 返回 null(docs/feature/reports/library/metrics.md「内置指标」)。
20
39
  */
21
- export declare const turns: Metric<"turns">;
40
+ export declare const repeatedFailedCommands: Metric<"repeated-failed-commands">;
@@ -1,20 +1,25 @@
1
1
  // defineMetric 与内置指标。
2
2
  //
3
3
  // null ≠ 0:null = 此 attempt 测不了这个指标(不进聚合);0 = 测了,结果是零(照常进)。
4
- // 哪个 verdict 落哪边必须显式表态,内置指标按 docs/feature/reports/library.md「内置指标」的表格:
4
+ // 哪个 verdict 落哪边必须显式表态,内置指标按 docs/feature/reports/library.md「内置指标」的表格。
5
+ // 三个通过率指标把「Agent 答错」与「基建没跑起来」拆开,不互相伪装:
5
6
  //
6
- // 指标(name) skipped errored failed passed better
7
- // passRate(pass-rate) null 0 0 1 higher
8
- // examScore(exam-score) null 0 0 soft 均分 higher
9
- // durationMs(duration) null 实测 实测 实测 lower
10
- // tokens(tokens) null 实测;无 usage→null 同左 同左 lower
11
- // costUSD(cost) null 同上 同左 同左 lower
12
- // turns(turns) null 实测;o11y 缺失→null 同左 同左 lower
7
+ // 指标(name) skipped errored failed passed better
8
+ // taskPassRate(task-pass-rate) null null 0 1 higher
9
+ // executionReliability(execution-reliability) null 0 1 1 higher
10
+ // endToEndPassRate(end-to-end-pass-rate) null 0 0 1 higher
11
+ // examScore(exam-score) null 0 0 soft 均分 higher
12
+ // durationMs(duration) null 实测 实测 实测 lower
13
+ // tokens(tokens) null 实测;无 usage→null 同左 同左 lower
14
+ // costUSD(cost) null 同上 同左 同左 lower
15
+ // assistantTurns(assistant-turns) null 实测;o11y 缺失→null 同左 同左 lower
16
+ // repeatedFailedCommands(repeated-failed-commands) null 实测;o11y 缺失→null 同左 同左 lower
13
17
  //
14
- // 两档指标(docs/feature/reports/library.md「内置指标」):以上除 turns 外全部只读 attempt.result
15
- // 的瘦身字段——任何 producer、任何 copySnapshots artifacts 选择都算得出,内置报告
16
- // ExperimentComparison 只用这一档。turns attempt.o11y()(懒加载 artifact),发布时若
17
- // o11y 没随行就诚实渲染缺数据「—」,不算 0——报告作者自己摆时心里要有这根弦,内置报告不用它。
18
+ // 两档指标(docs/feature/reports/library/metrics.md「内置指标」):以上除 assistantTurns
19
+ // repeatedFailedCommands 外全部只读 attempt.result 的瘦身字段——任何 producer、任何
20
+ // copySnapshots artifacts 选择都算得出,内置报告 ExperimentComparison 只用这一档。
21
+ // 后两个读 attempt.o11y()(懒加载 artifact),发布时若 o11y 没随行就诚实渲染缺数据「—」,
22
+ // 不算 0——报告作者自己摆时心里要有这根弦,内置报告不用它们。
18
23
  /**
19
24
  * 定义一个指标。内置指标与自定义指标是同一个类型,没有特权;
20
25
  * 校验只管「能进计算」的最低要求,聚合语义见 docs/feature/reports/architecture.md「指标聚合不变量」。
@@ -33,10 +38,56 @@ export function defineMetric(def) {
33
38
  export function attemptCostUSD(result) {
34
39
  return result.usage?.costUSD ?? result.estimatedCostUSD ?? null;
35
40
  }
36
- export const passRate = defineMetric({
37
- name: "pass-rate",
38
- label: { en: "Pass rate", "zh-CN": "成功率" },
39
- description: "Share of evals that passed (skipped attempts excluded).",
41
+ /**
42
+ * 条件答题质量:passed = 1,failed = 0,errored 记 null 不进分母。
43
+ * 这是「已形成可信判定」条件下的诊断指标,不能简称默认成功率
44
+ * (docs/feature/reports/library.md「内置指标」)
45
+ */
46
+ export const taskPassRate = defineMetric({
47
+ name: "task-pass-rate",
48
+ label: { en: "Task pass rate", "zh-CN": "可判定任务通过率" },
49
+ description: "Conditional task quality among attempts that formed a trustworthy verdict: passed = 1, failed = 0; errored is null.",
50
+ better: "higher",
51
+ unit: "%",
52
+ value(a) {
53
+ switch (a.result.verdict) {
54
+ case "passed":
55
+ return 1;
56
+ case "failed":
57
+ return 0;
58
+ default:
59
+ // errored = 没形成可信判定 → null 不进这个条件指标;skipped 同为 null。
60
+ return null;
61
+ }
62
+ },
63
+ });
64
+ /** 执行可靠性:跑到可判定(passed / failed)= 1,errored = 0;skipped → null。 */
65
+ export const executionReliability = defineMetric({
66
+ name: "execution-reliability",
67
+ label: { en: "Execution reliability", "zh-CN": "执行可靠性" },
68
+ description: "Execution reliability: reached a trustworthy verdict (passed / failed) = 1, errored = 0.",
69
+ better: "higher",
70
+ unit: "%",
71
+ value(a) {
72
+ switch (a.result.verdict) {
73
+ case "passed":
74
+ case "failed":
75
+ return 1;
76
+ case "errored":
77
+ return 0;
78
+ default:
79
+ return null; // skipped
80
+ }
81
+ },
82
+ });
83
+ /**
84
+ * 端到端合成:passed = 1,failed / errored = 0;哪边拖累用
85
+ * taskPassRate / executionReliability 拆开看。
86
+ */
87
+ export const endToEndPassRate = defineMetric({
88
+ name: "end-to-end-pass-rate",
89
+ label: { en: "End-to-end pass rate", "zh-CN": "端到端成功率" },
90
+ description: "End-to-end composite: passed = 1, failed / errored = 0. Split blame with taskPassRate and executionReliability.",
40
91
  better: "higher",
41
92
  unit: "%",
42
93
  value: (a) => a.result.verdict === "skipped" ? null : a.result.verdict === "passed" ? 1 : 0,
@@ -56,10 +107,12 @@ export const examScore = defineMetric({
56
107
  // failed 同理得 0:--strict 下被翻成 failed 的哪怕 soft 分不低也是 0(报告不重新判卷)。
57
108
  if (verdict !== "passed")
58
109
  return 0;
59
- const soft = assertions.filter((x) => x.severity === "soft");
110
+ // unavailable 没有分数:不计入均分分母(评不了 0 分;非 optional 的 unavailable
111
+ // 早已把 verdict 拖成 errored,走不到这个分支)。
112
+ const soft = assertions.filter((x) => x.severity === "soft" && x.outcome !== "unavailable");
60
113
  if (soft.length === 0)
61
114
  return 1;
62
- return soft.reduce((sum, x) => sum + x.score, 0) / soft.length;
115
+ return soft.reduce((sum, x) => sum + (x.outcome === "unavailable" ? 0 : x.score), 0) / soft.length;
63
116
  },
64
117
  });
65
118
  export const durationMs = defineMetric({
@@ -89,21 +142,22 @@ export const tokens = defineMetric({
89
142
  });
90
143
  export const costUSD = defineMetric({
91
144
  name: "cost",
92
- label: { en: "Cost", "zh-CN": "预估成本" },
145
+ label: { en: "Cost", "zh-CN": "成本" },
93
146
  description: "USD cost per attempt (gateway-measured beats estimated).",
94
147
  better: "lower",
95
148
  unit: "$",
96
149
  value: (a) => (a.result.verdict === "skipped" ? null : attemptCostUSD(a.result)),
97
150
  });
98
151
  /**
99
- * 唯一读 artifact(o11y,懒加载)的内置指标——其余五个只读瘦身字段。
152
+ * artifact(o11y,懒加载)的内置指标之一——其余只读瘦身字段。
100
153
  * 发布时若该 attempt 没带 o11y(如 copySnapshots 的 artifacts 选项漏了它),
101
- * value 如实返回 null,渲染成「—」,不冒充 0——见 docs/feature/reports/library.md「内置指标」。
154
+ * value 如实返回 null,渲染成「—」,不冒充 0。名字带限定词:o11y 事件流中的 assistant
155
+ * turn 数与 `t.send` 的 `s<session>/t<turn>` 轮次是两个计数。
102
156
  */
103
- export const turns = defineMetric({
104
- name: "turns",
105
- label: { en: "Turns", "zh-CN": "轮次" },
106
- description: "Total agent turns (assistant replies) per attempt. Reads o11y — “—” if not published alongside this attempt.",
157
+ export const assistantTurns = defineMetric({
158
+ name: "assistant-turns",
159
+ label: { en: "Assistant turns", "zh-CN": "Assistant 轮次" },
160
+ description: "Assistant turns in the o11y event stream per attempt. Reads o11y — “—” if not published alongside this attempt.",
107
161
  better: "lower",
108
162
  unit: "turns",
109
163
  async value(a) {
@@ -113,3 +167,34 @@ export const turns = defineMetric({
113
167
  return o11y?.totalTurns ?? null;
114
168
  },
115
169
  });
170
+ /**
171
+ * 同一 attempt 内同一条 shell 命令的重复失败数:每条命令失败 n 次(n > 1)记 n − 1,求和。
172
+ * 成功执行与只失败一次的命令不计。回答 agent 是否在反复撞同一个已知失败的命令。
173
+ * 读 o11y.json;skipped 与缺 o11y 返回 null(docs/feature/reports/library/metrics.md「内置指标」)。
174
+ */
175
+ export const repeatedFailedCommands = defineMetric({
176
+ name: "repeated-failed-commands",
177
+ label: { en: "Repeated failed commands", "zh-CN": "重复失败命令" },
178
+ description: "Per attempt: for each shell command failing n > 1 times, count n − 1, summed. Reads o11y — “—” if not published alongside this attempt.",
179
+ better: "lower",
180
+ unit: "cmds",
181
+ async value(a) {
182
+ if (a.result.verdict === "skipped")
183
+ return null;
184
+ const o11y = await a.o11y();
185
+ if (!o11y)
186
+ return null;
187
+ const failures = new Map();
188
+ for (const entry of o11y.shellCommands) {
189
+ const failed = entry.success === false || (entry.success === undefined && entry.exitCode !== undefined && entry.exitCode !== 0);
190
+ if (!failed)
191
+ continue;
192
+ failures.set(entry.command, (failures.get(entry.command) ?? 0) + 1);
193
+ }
194
+ let repeated = 0;
195
+ for (const n of failures.values())
196
+ if (n > 1)
197
+ repeated += n - 1;
198
+ return repeated;
199
+ },
200
+ });
@@ -1,50 +1,83 @@
1
1
  import type { AttemptLocator } from "../results/locator.ts";
2
2
  import { type ReportNode } from "./tree.ts";
3
- import { type ReportLocale } from "./locale.ts";
4
- import { type ColumnAlign } from "./text/layout.ts";
3
+ import { type LocalizedText, type ReportLocale } from "./locale.ts";
4
+ import type { ColumnAlign } from "./text/layout.ts";
5
5
  export interface LayoutProps {
6
6
  children?: ReportNode;
7
7
  className?: string;
8
8
  }
9
- /** 纵向依次排列:网页是块级堆叠,终端是逐块输出(块间空一行)。 */
9
+ export type RowProps = LayoutProps;
10
+ export type ColProps = LayoutProps;
11
+ /** 纵向依次排列:网页是块级堆叠,终端是逐块输出(块间空一行)。两面都按声明序。 */
10
12
  export declare const Col: import("./tree.ts").ReportComponent<LayoutProps>;
11
- /** 并排:网页横向排布,终端字符分栏;终端宽度不够时自动降级为纵向。 */
13
+ /**
14
+ * 并排:web 面横排;text 面在可用宽度装得下全部子块时按显示宽度并排(与 `columns` 工具
15
+ * 同一把尺),装不下时整块退化为纵向堆叠——不截断、不隐藏任何子块。
16
+ */
12
17
  export declare const Row: import("./tree.ts").ReportComponent<LayoutProps>;
13
18
  export interface SectionProps extends LayoutProps {
14
- title: string;
19
+ title: LocalizedText;
15
20
  }
16
21
  /** 带标题的块:网页是标题层级,终端是标题行加缩进。 */
17
22
  export declare const Section: import("./tree.ts").ReportComponent<SectionProps>;
18
- /** 说明文字:网页是段落,终端是折行文本。 */
19
- export declare const Text: import("./tree.ts").ReportComponent<LayoutProps>;
23
+ export interface TextProps {
24
+ /** 自由正文原样渲染,不随 locale 自动翻译。 */
25
+ children: string | number;
26
+ className?: string;
27
+ }
28
+ /** 自由文本的显式载体:web 面负责转义,text 面按显示宽度折行。 */
29
+ export declare const Text: import("./tree.ts").ReportComponent<TextProps>;
20
30
  export interface StyleProps {
21
- children?: string;
31
+ children: string;
22
32
  }
23
- /** 自定义组件的样式随树带走:web 面吐 <style> 标签,text 面渲染为空。 */
33
+ /**
34
+ * 注入页级全局 CSS:树位置只决定声明顺序,不限定作用域;text 面零输出。
35
+ * 配置对象形态的报告要全站样式优先用外壳 styles,两条通道注入同一增强层。
36
+ */
24
37
  export declare const Style: import("./tree.ts").ReportComponent<StyleProps>;
38
+ export interface TabsProps extends LayoutProps {
39
+ }
40
+ export interface TabProps extends LayoutProps {
41
+ title: LocalizedText;
42
+ }
43
+ /**
44
+ * 页内并列视图的可切换块。tab 是页内浏览状态,不是数据边界,也不是宿主寻址单位——
45
+ * 两个渲染面都输出全部 tab 的完整内容:web 静态 HTML 每 tab 一个 <details>(首个默认展开,
46
+ * 渐进增强升级成单选 tab 条,切换不改变数据);text 面按声明序输出带标题分节,不折成索引
47
+ * 也不省略(tab 没有选择器,索引只能是死路)。
48
+ */
49
+ export declare const Tabs: import("./tree.ts").ReportComponent<TabsProps>;
50
+ /** 只能直接放在 <Tabs> 下;除通用 children / className 外只有 title。不参与路由,没有 id。 */
51
+ export declare const Tab: import("./tree.ts").ReportComponent<TabProps>;
25
52
  /** 一列的定义:取哪个 cells 键、表头写什么、往哪边对齐。 */
26
53
  export interface TableColumn {
27
54
  /** 取 `row.cells[key]` 的键。 */
28
55
  key: string;
29
- /** 表头文案,两个面都原样渲染。 */
30
- header: string;
56
+ /** 表头文案,按渲染 locale 选择。 */
57
+ header: LocalizedText;
31
58
  /** 对齐方向,默认 `"left"`;`"right"` 按显示宽度右对齐,数字列用。 */
32
59
  align?: ColumnAlign;
60
+ /**
61
+ * text 面:单元格折行后的最大物理行数,放不下的部分以 `…` 收口;省略则不限行数。
62
+ * 摘要类列(如比较列表的 Result)用它保证「格子是可扫读的预览」;完整值在下钻面。
63
+ * web 面不消费——网页的高度约束是组件自己的 CSS 决定。
64
+ */
65
+ maxLines?: number;
33
66
  }
34
67
  /** 一行的数据:身份键、已格式化的格子、可选的 attempt locator。 */
35
68
  export interface TableRow {
36
69
  /** 行身份。 */
37
70
  key: string;
38
71
  /** 已格式化的显示值;`null`(或缺这个键)渲染成 `—`,不补 0。 */
39
- cells: Record<string, string | null>;
72
+ cells: Readonly<Record<string, string | null>>;
40
73
  /** 带上就多一列 attempt:web 面链到证据室,text 面列出 locator。 */
41
74
  locator?: AttemptLocator;
42
75
  }
43
76
  export interface TableProps {
44
- /** 列定义;数组顺序即渲染顺序。 */
45
- columns: TableColumn[];
77
+ /** 非空列定义;数组顺序即渲染顺序。 */
78
+ columns: readonly [TableColumn, ...TableColumn[]];
46
79
  /** 行数据;数组顺序即渲染顺序,组件不重排也不过滤。 */
47
- rows: TableRow[];
80
+ rows: readonly TableRow[];
48
81
  /** 组件自带文案(attempt 表头、丢列提示)的语言;省略时随宿主。 */
49
82
  locale?: ReportLocale;
50
83
  /** web 面挂到 `<table>` 上。 */