niceeval 0.9.1 → 0.10.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (432) hide show
  1. package/INDEX.md +31 -33
  2. package/dist/agents/types.d.ts +20 -17
  3. package/dist/context/types.d.ts +21 -21
  4. package/dist/i18n/en.d.ts +10 -2
  5. package/dist/i18n/zh-CN.d.ts +14 -6
  6. package/dist/o11y/execution-tree.d.ts +103 -0
  7. package/dist/o11y/otlp/select.d.ts +22 -0
  8. package/dist/report/{react → assets}/colors.d.ts +8 -0
  9. package/dist/report/{react → assets}/colors.js +23 -0
  10. package/dist/report/built-in/index.d.ts +2 -2
  11. package/dist/report/built-in/index.js +2 -2
  12. package/dist/report/built-in/standard.d.ts +8 -1
  13. package/dist/report/built-in/standard.js +17 -7
  14. package/dist/report/components/attempt-detail/AttemptAssertions.d.ts +6 -0
  15. package/dist/report/components/attempt-detail/AttemptAssertions.js +17 -0
  16. package/dist/report/components/attempt-detail/AttemptConversation.d.ts +10 -0
  17. package/dist/report/components/attempt-detail/AttemptConversation.js +74 -0
  18. package/dist/report/components/attempt-detail/AttemptDiagnostics.d.ts +6 -0
  19. package/dist/report/components/attempt-detail/AttemptDiagnostics.js +7 -0
  20. package/dist/report/components/attempt-detail/AttemptDiff.d.ts +6 -0
  21. package/dist/report/components/attempt-detail/AttemptDiff.js +11 -0
  22. package/dist/report/components/attempt-detail/AttemptError.d.ts +6 -0
  23. package/dist/report/components/attempt-detail/AttemptError.js +16 -0
  24. package/dist/report/components/attempt-detail/AttemptFixPrompt.d.ts +6 -0
  25. package/dist/report/components/attempt-detail/AttemptFixPrompt.js +7 -0
  26. package/dist/report/components/attempt-detail/AttemptSource.d.ts +6 -0
  27. package/dist/report/components/attempt-detail/AttemptSource.js +97 -0
  28. package/dist/report/components/attempt-detail/AttemptSummary.d.ts +8 -0
  29. package/dist/report/components/attempt-detail/AttemptSummary.js +20 -0
  30. package/dist/report/components/attempt-detail/AttemptTimeline.d.ts +6 -0
  31. package/dist/report/components/attempt-detail/AttemptTimeline.js +28 -0
  32. package/dist/report/components/attempt-detail/AttemptTrace.d.ts +6 -0
  33. package/dist/report/components/attempt-detail/AttemptTrace.js +29 -0
  34. package/dist/report/components/attempt-detail/AttemptUsage.d.ts +6 -0
  35. package/dist/report/components/attempt-detail/AttemptUsage.js +20 -0
  36. package/dist/report/components/attempt-detail/compute.d.ts +24 -0
  37. package/dist/report/components/attempt-detail/compute.js +297 -0
  38. package/dist/report/components/attempt-detail/faces.d.ts +14 -0
  39. package/dist/report/components/attempt-detail/faces.js +239 -0
  40. package/dist/report/components/attempt-detail/index.d.ts +38 -0
  41. package/dist/report/components/attempt-detail/index.js +547 -0
  42. package/dist/report/{react → components}/cell.d.ts +5 -3
  43. package/dist/report/{react → components}/cell.js +3 -3
  44. package/dist/report/{react → components/entity-lists}/AttemptList.d.ts +8 -4
  45. package/dist/report/{react → components/entity-lists}/AttemptList.js +16 -10
  46. package/dist/report/{react → components/entity-lists}/EvalList.d.ts +3 -3
  47. package/dist/report/{react → components/entity-lists}/EvalList.js +0 -0
  48. package/dist/report/{react → components/entity-lists}/ExperimentList.d.ts +4 -5
  49. package/dist/report/{react → components/entity-lists}/ExperimentList.js +12 -11
  50. package/dist/report/components/entity-lists/compute.d.ts +23 -0
  51. package/dist/report/components/entity-lists/compute.js +171 -0
  52. package/dist/report/components/entity-lists/faces.d.ts +5 -0
  53. package/dist/report/components/entity-lists/faces.js +175 -0
  54. package/dist/report/components/entity-lists/index.d.ts +49 -0
  55. package/dist/report/components/entity-lists/index.js +169 -0
  56. package/dist/report/{react → components}/fixtures.d.ts +2 -2
  57. package/dist/report/{react → components}/fixtures.js +1 -1
  58. package/dist/report/{react → components/metric-views}/DeltaTable.d.ts +2 -2
  59. package/dist/report/{react → components/metric-views}/DeltaTable.js +4 -4
  60. package/dist/report/{react → components/metric-views}/MetricBars.d.ts +3 -3
  61. package/dist/report/{react → components/metric-views}/MetricBars.js +3 -3
  62. package/dist/report/{react → components/metric-views}/MetricLine.d.ts +2 -2
  63. package/dist/report/{react → components/metric-views}/MetricLine.js +8 -5
  64. package/dist/report/{react → components/metric-views}/MetricMatrix.d.ts +3 -3
  65. package/dist/report/{react → components/metric-views}/MetricMatrix.js +4 -4
  66. package/dist/report/components/metric-views/MetricScatter.d.ts +11 -0
  67. package/dist/report/{react → components/metric-views}/MetricScatter.js +27 -60
  68. package/dist/report/{react → components/metric-views}/MetricTable.d.ts +3 -3
  69. package/dist/report/{react → components/metric-views}/MetricTable.js +4 -4
  70. package/dist/report/{react → components/metric-views}/Scoreboard.d.ts +2 -2
  71. package/dist/report/{react → components/metric-views}/Scoreboard.js +3 -3
  72. package/dist/report/components/metric-views/compute.d.ts +89 -0
  73. package/dist/report/{compute.js → components/metric-views/compute.js} +32 -415
  74. package/dist/report/components/metric-views/faces.d.ts +13 -0
  75. package/dist/report/components/metric-views/faces.js +381 -0
  76. package/dist/report/components/metric-views/index.d.ts +50 -0
  77. package/dist/report/components/metric-views/index.js +273 -0
  78. package/dist/report/{text → components/metric-views}/plot.js +1 -1
  79. package/dist/report/components/shared-compute.d.ts +22 -0
  80. package/dist/report/components/shared-compute.js +47 -0
  81. package/dist/report/components/shared-faces.d.ts +9 -0
  82. package/dist/report/components/shared-faces.js +26 -0
  83. package/dist/report/components/shared.d.ts +68 -0
  84. package/dist/report/components/shared.js +125 -0
  85. package/dist/report/{react → components/site-components}/CopyFixPrompt.d.ts +2 -2
  86. package/dist/report/{react → components/site-components}/CopyFixPrompt.js +2 -2
  87. package/dist/report/{react → components/site-components}/HeroCard.d.ts +2 -2
  88. package/dist/report/{react → components/site-components}/HeroCard.js +2 -2
  89. package/dist/report/{react → components/site-components}/ScopeWarnings.d.ts +2 -2
  90. package/dist/report/{react → components/site-components}/ScopeWarnings.js +3 -3
  91. package/dist/report/{react → components/site-components}/TraceWaterfall.d.ts +3 -3
  92. package/dist/report/{react → components/site-components}/TraceWaterfall.js +5 -5
  93. package/dist/report/components/site-components/compute.d.ts +28 -0
  94. package/dist/report/components/site-components/compute.js +132 -0
  95. package/dist/report/components/site-components/faces.d.ts +21 -0
  96. package/dist/report/components/site-components/faces.js +75 -0
  97. package/dist/report/components/site-components/index.d.ts +74 -0
  98. package/dist/report/components/site-components/index.js +220 -0
  99. package/dist/report/{scope-warnings.d.ts → components/site-components/scope-warnings.d.ts} +2 -2
  100. package/dist/report/{scope-warnings.js → components/site-components/scope-warnings.js} +2 -2
  101. package/dist/report/{react → components/summaries}/ScopeSummary.d.ts +2 -2
  102. package/dist/report/{react → components/summaries}/ScopeSummary.js +17 -8
  103. package/dist/report/components/summaries/compute.d.ts +7 -0
  104. package/dist/report/components/summaries/compute.js +51 -0
  105. package/dist/report/components/summaries/faces.d.ts +7 -0
  106. package/dist/report/components/summaries/faces.js +38 -0
  107. package/dist/report/components/summaries/index.d.ts +27 -0
  108. package/dist/report/components/summaries/index.js +78 -0
  109. package/dist/report/definition/grid-layout.d.ts +50 -0
  110. package/dist/report/definition/grid-layout.js +89 -0
  111. package/dist/report/{primitives.d.ts → definition/primitives.d.ts} +34 -4
  112. package/dist/report/{primitives.js → definition/primitives.js} +101 -10
  113. package/dist/report/{report.d.ts → definition/report.d.ts} +36 -65
  114. package/dist/report/{report.js → definition/report.js} +58 -90
  115. package/dist/report/{text/table.d.ts → definition/table-text.d.ts} +2 -2
  116. package/dist/report/{text/table.js → definition/table-text.js} +2 -2
  117. package/dist/report/{tree.d.ts → definition/tree.d.ts} +43 -11
  118. package/dist/report/{tree.js → definition/tree.js} +9 -11
  119. package/dist/report/index.d.ts +33 -18
  120. package/dist/report/index.js +23 -14
  121. package/dist/report/{aggregate.d.ts → model/aggregate.d.ts} +12 -4
  122. package/dist/report/{aggregate.js → model/aggregate.js} +28 -8
  123. package/dist/report/{flag.d.ts → model/flag.d.ts} +14 -1
  124. package/dist/report/{flag.js → model/flag.js} +35 -0
  125. package/dist/report/{format.d.ts → model/format.d.ts} +13 -7
  126. package/dist/report/{format.js → model/format.js} +79 -9
  127. package/dist/report/{locale.d.ts → model/locale.d.ts} +17 -17
  128. package/dist/report/{locale.js → model/locale.js} +31 -33
  129. package/dist/report/{metrics.d.ts → model/metrics.d.ts} +2 -2
  130. package/dist/report/{metrics.js → model/metrics.js} +2 -2
  131. package/dist/report/{types.d.ts → model/types.d.ts} +154 -20
  132. package/dist/report/react/index.d.ts +32 -21
  133. package/dist/report/react/index.js +33 -21
  134. package/dist/report/{load.d.ts → runtime/load.d.ts} +1 -1
  135. package/dist/report/{load.js → runtime/load.js} +1 -1
  136. package/dist/report/runtime/text.d.ts +67 -0
  137. package/dist/report/runtime/text.js +114 -0
  138. package/dist/report/runtime/web.d.ts +35 -0
  139. package/dist/report/runtime/web.js +70 -0
  140. package/dist/results/annotated-source.d.ts +87 -0
  141. package/dist/results/attempt-evidence.d.ts +74 -0
  142. package/dist/results/attempt-source.d.ts +15 -0
  143. package/dist/results/select.d.ts +11 -1
  144. package/dist/results/select.js +27 -5
  145. package/dist/runner/eval-selection.d.ts +26 -0
  146. package/dist/runner/feedback/sink.d.ts +26 -1
  147. package/dist/runner/types.d.ts +151 -24
  148. package/dist/sandbox/docker.d.ts +6 -0
  149. package/dist/sandbox/e2b.d.ts +0 -1
  150. package/dist/sandbox/types.d.ts +23 -21
  151. package/dist/scoring/display.d.ts +7 -2
  152. package/dist/scoring/display.js +42 -4
  153. package/dist/scoring/types.d.ts +3 -3
  154. package/dist/shared/aggregate.d.ts +14 -0
  155. package/dist/shared/aggregate.js +31 -0
  156. package/dist/shared/types.d.ts +6 -1
  157. package/docs-site/images/logo-dark.svg +7 -0
  158. package/docs-site/images/logo.svg +6 -5
  159. package/docs-site/zh/README.md +8 -7
  160. package/docs-site/zh/examples/ai-agent-application.mdx +5 -5
  161. package/docs-site/zh/examples/coding-agent-extensions.mdx +4 -4
  162. package/docs-site/zh/examples/index.mdx +3 -3
  163. package/docs-site/zh/examples/integrations/ai-sdk-v7.mdx +6 -6
  164. package/docs-site/zh/examples/integrations/claude-sdk.mdx +3 -3
  165. package/docs-site/zh/examples/integrations/codex-sdk.mdx +3 -3
  166. package/docs-site/zh/examples/integrations/langgraph.mdx +3 -3
  167. package/docs-site/zh/examples/integrations/pi-sdk.mdx +2 -2
  168. package/docs-site/zh/explanation/adapter.mdx +19 -19
  169. package/docs-site/zh/explanation/assert.mdx +9 -9
  170. package/docs-site/zh/explanation/drive.mdx +4 -4
  171. package/docs-site/zh/explanation/evals.mdx +8 -8
  172. package/docs-site/zh/explanation/experiment.mdx +8 -8
  173. package/docs-site/zh/explanation/hitl.mdx +13 -13
  174. package/docs-site/zh/explanation/judge.mdx +3 -3
  175. package/docs-site/zh/explanation/overview.mdx +7 -7
  176. package/docs-site/zh/explanation/runner.mdx +17 -13
  177. package/docs-site/zh/explanation/tier.mdx +6 -6
  178. package/docs-site/zh/index.mdx +14 -14
  179. package/docs-site/zh/introduction.mdx +13 -16
  180. package/docs-site/zh/reference/builtin-agents.mdx +61 -28
  181. package/docs-site/zh/reference/capabilities.mdx +7 -27
  182. package/docs-site/zh/reference/cli.mdx +36 -33
  183. package/docs-site/zh/reference/define-agent.mdx +32 -31
  184. package/docs-site/zh/reference/define-config.mdx +6 -6
  185. package/docs-site/zh/reference/define-eval.mdx +33 -20
  186. package/docs-site/zh/reference/events.mdx +4 -4
  187. package/docs-site/zh/reference/expect.mdx +3 -3
  188. package/docs-site/zh/reference/official-adapters.mdx +17 -17
  189. package/docs-site/zh/reference/report-components.mdx +195 -121
  190. package/docs-site/zh/reference/results-data.mdx +13 -13
  191. package/docs-site/zh/troubleshooting/debug-sandbox.mdx +11 -11
  192. package/docs-site/zh/troubleshooting/debugging.mdx +40 -16
  193. package/docs-site/zh/{how-to → tutorials}/agent-feedback-loop.mdx +38 -38
  194. package/docs-site/zh/tutorials/agent-onboarding.mdx +100 -0
  195. package/docs-site/zh/tutorials/authoring.mdx +211 -0
  196. package/docs-site/zh/{how-to → tutorials}/ci-integration.mdx +8 -8
  197. package/docs-site/zh/{how-to → tutorials}/connect-otel.mdx +22 -22
  198. package/docs-site/zh/{how-to → tutorials}/connect-your-agent.mdx +58 -63
  199. package/docs-site/zh/tutorials/custom-reports.mdx +453 -0
  200. package/docs-site/zh/{how-to → tutorials}/dataset-fanout.mdx +4 -4
  201. package/docs-site/zh/tutorials/experiments.mdx +102 -0
  202. package/docs-site/zh/{how-to → tutorials}/fixtures.mdx +9 -9
  203. package/docs-site/zh/{how-to → tutorials}/publish-report.mdx +6 -6
  204. package/docs-site/zh/tutorials/quickstart.mdx +18 -18
  205. package/docs-site/zh/{how-to → tutorials}/reporters.mdx +6 -6
  206. package/docs-site/zh/{how-to → tutorials}/sandbox-agent.mdx +6 -6
  207. package/docs-site/zh/{how-to → tutorials}/sandbox-providers.mdx +41 -19
  208. package/docs-site/zh/{how-to → tutorials}/scoring-guide.mdx +4 -4
  209. package/docs-site/zh/{how-to → tutorials}/viewing-results.mdx +60 -57
  210. package/docs-site/zh/tutorials/write-experiment.mdx +353 -0
  211. package/docs-site/zh/{how-to → tutorials}/write-send.mdx +40 -40
  212. package/package.json +10 -7
  213. package/src/agents/bub.ts +21 -8
  214. package/src/agents/claude-code.ts +23 -10
  215. package/src/agents/codex.test.ts +22 -7
  216. package/src/agents/codex.ts +22 -9
  217. package/src/agents/index.ts +2 -2
  218. package/src/agents/openai-compat.ts +1 -1
  219. package/src/agents/post-setup.ts +45 -22
  220. package/src/agents/streaming.ts +1 -1
  221. package/src/agents/types.ts +20 -17
  222. package/src/agents/ui-message-stream.test.ts +10 -0
  223. package/src/agents/ui-message-stream.ts +12 -1
  224. package/src/cli.ts +75 -59
  225. package/src/context/types.ts +21 -21
  226. package/src/define.ts +13 -0
  227. package/src/i18n/en.ts +27 -12
  228. package/src/i18n/zh-CN.ts +27 -12
  229. package/src/index.ts +2 -0
  230. package/src/o11y/prices.json +176 -99
  231. package/src/report/{react → assets}/colors.ts +22 -0
  232. package/src/report/{react → assets}/enhance.js +1 -33
  233. package/src/report/assets/styles.css +1785 -0
  234. package/src/report/built-in/index.tsx +2 -2
  235. package/src/report/built-in/standard.tsx +18 -6
  236. package/src/report/components/attempt-detail/AttemptAssertions.tsx +67 -0
  237. package/src/report/components/attempt-detail/AttemptConversation.tsx +158 -0
  238. package/src/report/components/attempt-detail/AttemptDiagnostics.tsx +38 -0
  239. package/src/report/components/attempt-detail/AttemptDiff.tsx +35 -0
  240. package/src/report/components/attempt-detail/AttemptError.tsx +31 -0
  241. package/src/report/components/attempt-detail/AttemptFixPrompt.tsx +26 -0
  242. package/src/report/components/attempt-detail/AttemptSource.tsx +224 -0
  243. package/src/report/components/attempt-detail/AttemptSummary.tsx +74 -0
  244. package/src/report/components/attempt-detail/AttemptTimeline.tsx +108 -0
  245. package/src/report/components/attempt-detail/AttemptTrace.tsx +63 -0
  246. package/src/report/components/attempt-detail/AttemptUsage.tsx +29 -0
  247. package/src/report/components/attempt-detail/attempt-components.test.tsx +758 -0
  248. package/src/report/components/attempt-detail/compute.ts +336 -0
  249. package/src/report/components/attempt-detail/faces.ts +260 -0
  250. package/src/report/components/attempt-detail/index.tsx +600 -0
  251. package/src/report/components/attempt-detail/validate.test.ts +252 -0
  252. package/src/report/{react → components}/cell.tsx +6 -3
  253. package/src/report/{report.test.ts → components/compute.test.ts} +316 -46
  254. package/src/report/{react → components/entity-lists}/AttemptList.tsx +24 -16
  255. package/src/report/{react → components/entity-lists}/EvalList.tsx +0 -0
  256. package/src/report/{react → components/entity-lists}/ExperimentList.tsx +33 -27
  257. package/src/report/components/entity-lists/compute.ts +196 -0
  258. package/src/report/components/entity-lists/faces.ts +208 -0
  259. package/src/report/components/entity-lists/index.tsx +238 -0
  260. package/src/report/components/entity-lists/validate.test.ts +114 -0
  261. package/src/report/{react → components}/fixtures.ts +2 -2
  262. package/src/report/{react → components/metric-views}/DeltaTable.tsx +5 -5
  263. package/src/report/{react → components/metric-views}/MetricBars.tsx +5 -5
  264. package/src/report/{react → components/metric-views}/MetricLine.tsx +9 -6
  265. package/src/report/{react → components/metric-views}/MetricMatrix.tsx +6 -6
  266. package/src/report/{react → components/metric-views}/MetricScatter.tsx +42 -70
  267. package/src/report/{react → components/metric-views}/MetricTable.tsx +6 -6
  268. package/src/report/{react → components/metric-views}/Scoreboard.tsx +4 -4
  269. package/src/report/{compute.ts → components/metric-views/compute.ts} +51 -477
  270. package/src/report/components/metric-views/faces.ts +423 -0
  271. package/src/report/components/metric-views/index.tsx +352 -0
  272. package/src/report/{text → components/metric-views}/plot.ts +1 -1
  273. package/src/report/components/metric-views/validate.test.ts +211 -0
  274. package/src/report/{react → components}/render.test.tsx +66 -26
  275. package/src/report/components/shared-compute.ts +59 -0
  276. package/src/report/components/shared-faces.ts +30 -0
  277. package/src/report/components/shared.ts +192 -0
  278. package/src/report/{react → components/site-components}/CopyFixPrompt.tsx +3 -3
  279. package/src/report/{react → components/site-components}/HeroCard.tsx +3 -3
  280. package/src/report/{react → components/site-components}/ScopeWarnings.tsx +4 -4
  281. package/src/report/{react → components/site-components}/TraceWaterfall.tsx +13 -10
  282. package/src/report/components/site-components/compute.ts +144 -0
  283. package/src/report/components/site-components/faces.ts +80 -0
  284. package/src/report/components/site-components/index.tsx +265 -0
  285. package/src/report/{scope-warnings.ts → components/site-components/scope-warnings.ts} +3 -3
  286. package/src/report/{site-components.test.tsx → components/site-components/site-components.test.tsx} +23 -21
  287. package/src/report/components/site-components/validate.test.ts +89 -0
  288. package/src/report/{react → components/summaries}/ScopeSummary.tsx +26 -11
  289. package/src/report/components/summaries/compute.ts +56 -0
  290. package/src/report/components/summaries/faces.ts +48 -0
  291. package/src/report/components/summaries/index.tsx +127 -0
  292. package/src/report/components/summaries/validate.test.ts +49 -0
  293. package/src/report/definition/grid-layout.test.ts +124 -0
  294. package/src/report/definition/grid-layout.ts +146 -0
  295. package/src/report/{primitives.tsx → definition/primitives.tsx} +168 -18
  296. package/src/report/{report.ts → definition/report.ts} +98 -165
  297. package/src/report/{shell-head.test.ts → definition/shell-head.test.ts} +2 -2
  298. package/src/report/{text/table.ts → definition/table-text.ts} +4 -4
  299. package/src/report/{tree.ts → definition/tree.ts} +56 -20
  300. package/src/report/index.ts +128 -66
  301. package/src/report/{aggregate.ts → model/aggregate.ts} +31 -9
  302. package/src/report/{flag.ts → model/flag.ts} +39 -1
  303. package/src/report/{format.ts → model/format.ts} +89 -10
  304. package/src/report/{locale.ts → model/locale.ts} +34 -36
  305. package/src/report/{metrics.ts → model/metrics.ts} +3 -3
  306. package/src/report/{types.ts → model/types.ts} +159 -22
  307. package/src/report/react/index.tsx +54 -26
  308. package/src/report/{dual-render.test.tsx → runtime/dual-render.test.tsx} +601 -53
  309. package/src/report/runtime/host.test.ts +44 -0
  310. package/src/report/runtime/host.ts +138 -0
  311. package/src/report/{load.ts → runtime/load.ts} +1 -1
  312. package/src/report/runtime/text.ts +192 -0
  313. package/src/report/runtime/web.ts +106 -0
  314. package/src/results/attempt-evidence.ts +5 -1
  315. package/src/results/host-equivalence.test.ts +53 -2
  316. package/src/results/select.ts +29 -5
  317. package/src/runner/attempt.test.ts +48 -1
  318. package/src/runner/attempt.ts +62 -42
  319. package/src/runner/cleanup-timeout.test.ts +16 -0
  320. package/src/runner/cleanup-timeout.ts +23 -0
  321. package/src/runner/discover.ts +1 -2
  322. package/src/runner/eval-selection.test.ts +187 -0
  323. package/src/runner/eval-selection.ts +109 -0
  324. package/src/runner/experiment-cleanup-registry.test.ts +89 -0
  325. package/src/runner/experiment-cleanup-registry.ts +39 -0
  326. package/src/runner/experiment-labels.test.ts +71 -0
  327. package/src/runner/feedback/agent.test.ts +33 -1
  328. package/src/runner/feedback/agent.ts +12 -16
  329. package/src/runner/feedback/ci.test.ts +35 -1
  330. package/src/runner/feedback/ci.ts +16 -18
  331. package/src/runner/feedback/coordinator.ts +28 -0
  332. package/src/runner/feedback/human.test.ts +108 -1
  333. package/src/runner/feedback/human.ts +71 -21
  334. package/src/runner/feedback/reducer.test.ts +64 -0
  335. package/src/runner/feedback/reducer.ts +26 -0
  336. package/src/runner/feedback/sink.ts +40 -1
  337. package/src/runner/fingerprint.ts +2 -1
  338. package/src/runner/report.test.ts +14 -0
  339. package/src/runner/report.ts +3 -1
  340. package/src/runner/run.test.ts +390 -12
  341. package/src/runner/run.ts +259 -26
  342. package/src/runner/sandbox-selection.test.ts +13 -3
  343. package/src/runner/sandbox-selection.ts +4 -2
  344. package/src/runner/types.ts +160 -24
  345. package/src/sandbox/docker.ts +7 -0
  346. package/src/sandbox/e2b-reconcile.test.ts +125 -0
  347. package/src/sandbox/e2b.ts +47 -12
  348. package/src/sandbox/types.ts +23 -21
  349. package/src/scoring/display.test.ts +28 -2
  350. package/src/scoring/display.ts +38 -5
  351. package/src/scoring/types.ts +3 -3
  352. package/src/shared/aggregate.test.ts +52 -0
  353. package/src/shared/aggregate.ts +29 -0
  354. package/src/shared/types.ts +6 -1
  355. package/src/show/command.test.ts +34 -0
  356. package/src/show/command.ts +16 -0
  357. package/src/show/compose.ts +1 -1
  358. package/src/show/index.ts +56 -20
  359. package/src/show/render.ts +15 -239
  360. package/src/show/show.test.ts +127 -34
  361. package/src/view/app/App.test.tsx +1 -1
  362. package/src/view/app/App.tsx +119 -47
  363. package/src/view/app/i18n.ts +7 -147
  364. package/src/view/app/lib/attempt-dialog.test.ts +65 -0
  365. package/src/view/app/lib/attempt-dialog.ts +69 -0
  366. package/src/view/app/main.tsx +0 -1
  367. package/src/view/app/types.ts +3 -86
  368. package/src/view/artifact-serving.test.ts +22 -38
  369. package/src/view/client-dist/app.css +1 -1
  370. package/src/view/client-dist/app.js +15 -22
  371. package/src/view/data.test.ts +48 -36
  372. package/src/view/data.ts +105 -83
  373. package/src/view/index.ts +1 -1
  374. package/src/view/server.ts +32 -2
  375. package/src/view/shared/types.ts +6 -31
  376. package/src/view/site-parity.test.ts +24 -1
  377. package/src/view/site.ts +144 -17
  378. package/src/view/styles.css +0 -805
  379. package/src/view/view-report.test.ts +143 -22
  380. package/dist/report/components.d.ts +0 -179
  381. package/dist/report/components.js +0 -544
  382. package/dist/report/compute.d.ts +0 -139
  383. package/dist/report/react/ExperimentComparison.d.ts +0 -10
  384. package/dist/report/react/ExperimentComparison.js +0 -12
  385. package/dist/report/react/MetricScatter.d.ts +0 -9
  386. package/dist/report/react/format.d.ts +0 -3
  387. package/dist/report/react/format.js +0 -7
  388. package/dist/report/text/faces.d.ts +0 -45
  389. package/dist/report/text/faces.js +0 -671
  390. package/dist/report/web.d.ts +0 -32
  391. package/dist/report/web.js +0 -48
  392. package/docs-site/zh/how-to/authoring.mdx +0 -162
  393. package/docs-site/zh/how-to/custom-reports.mdx +0 -414
  394. package/docs-site/zh/how-to/experiments.mdx +0 -86
  395. package/docs-site/zh/how-to/write-experiment.mdx +0 -164
  396. package/src/report/components.tsx +0 -925
  397. package/src/report/react/ExperimentComparison.tsx +0 -73
  398. package/src/report/react/format.ts +0 -9
  399. package/src/report/react/styles.css +0 -945
  400. package/src/report/text/faces.ts +0 -767
  401. package/src/report/web.ts +0 -77
  402. package/src/show/report-host.test.ts +0 -205
  403. package/src/show/report-host.ts +0 -389
  404. package/src/view/app/components/AttemptModal.tsx +0 -496
  405. package/src/view/app/components/CodeView.test.tsx +0 -142
  406. package/src/view/app/components/CodeView.tsx +0 -310
  407. package/src/view/app/components/CopyControls.tsx +0 -106
  408. package/src/view/app/components/Trace.tsx +0 -100
  409. package/src/view/app/components/Transcript.tsx +0 -157
  410. package/src/view/app/components/ui/badge.tsx +0 -21
  411. package/src/view/app/lib/artifact-url.ts +0 -17
  412. package/src/view/app/lib/attempt-route.test.ts +0 -80
  413. package/src/view/app/lib/attempt-route.ts +0 -52
  414. package/src/view/app/lib/format.ts +0 -70
  415. package/src/view/app/lib/guards.test.ts +0 -108
  416. package/src/view/app/lib/guards.ts +0 -71
  417. package/src/view/app/lib/rows.ts +0 -22
  418. package/src/view/app/lib/transcript-data.tsx +0 -151
  419. package/src/view/app/lib/verdict.ts +0 -23
  420. package/src/view/app/shared.ts +0 -8
  421. /package/dist/report/{react → components/metric-views}/chart-math.d.ts +0 -0
  422. /package/dist/report/{react → components/metric-views}/chart-math.js +0 -0
  423. /package/dist/report/{text → components/metric-views}/plot.d.ts +0 -0
  424. /package/dist/report/{react → components/site-components}/PoweredBy.d.ts +0 -0
  425. /package/dist/report/{react → components/site-components}/PoweredBy.js +0 -0
  426. /package/dist/report/{text/layout.d.ts → model/text-layout.d.ts} +0 -0
  427. /package/dist/report/{text/layout.js → model/text-layout.js} +0 -0
  428. /package/dist/report/{types.js → model/types.js} +0 -0
  429. /package/src/report/{react → components/metric-views}/chart-math.test.ts +0 -0
  430. /package/src/report/{react → components/metric-views}/chart-math.ts +0 -0
  431. /package/src/report/{react → components/site-components}/PoweredBy.tsx +0 -0
  432. /package/src/report/{text/layout.ts → model/text-layout.ts} +0 -0
@@ -3,7 +3,7 @@
3
3
  //
4
4
  // import 边界即运行时边界:计算函数(*Data)会经句柄触碰文件系统(懒加载 artifact),
5
5
  // 只能进服务端 / 脚本;组件的渲染面纯同步零 IO。text 宿主遍历渲染不需要 react-dom
6
- // (renderReportToText);web 宿主的 renderReportToStaticHtml 在 ./web.ts,只有那一侧
6
+ // (renderReportToText);web 宿主的 renderReportToStaticHtml 在 ./runtime/web.ts,只有那一侧
7
7
  // import react-dom。写报告文件的项目要装 react(.tsx 编译产物 import react/jsx-runtime)。
8
8
 
9
9
  // 指标与维度读取器
@@ -18,59 +18,73 @@ export {
18
18
  repeatedFailedCommands,
19
19
  taskPassRate,
20
20
  tokens,
21
- } from "./metrics.ts";
22
- export { flag, numericFlag, numericRunConfig, runConfig } from "./flag.ts";
21
+ } from "./model/metrics.ts";
22
+ export { flag, label, numericFlag, numericLabel, numericRunConfig, runConfig } from "./model/flag.ts";
23
23
 
24
24
  // 报告定义与组件基座
25
25
  export {
26
26
  buildReportMeta,
27
27
  defineReport,
28
28
  isReportDefinition,
29
- pickReportPage,
30
- renderReportToText,
31
- renderReportTreeToText,
32
- reportTitleText,
33
29
  resolveReportTitle,
34
- ReportPageNotFoundError,
35
30
  DEFAULT_PAGE_ID,
36
- } from "./report.ts";
31
+ } from "./definition/report.ts";
37
32
  export type {
38
- HostCommandContext,
39
33
  NonEmptyArray,
40
- RenderReportTextOptions,
41
- RenderTreeTextOptions,
42
- ReportTreeHostContext,
43
34
  HeadTag,
44
35
  ReportAsset,
45
36
  ReportDef,
46
37
  ReportDefinition,
47
- ReportHostContext,
48
38
  ReportLink,
49
39
  ReportMeta,
40
+ ReportMetaPage,
50
41
  ReportPage,
42
+ ReportPageBase,
51
43
  ReportShell,
52
- } from "./report.ts";
53
- export { defineComponent, createTextContext, renderNodeToText, resolveReportTree, validateReportTree, ResolveMemo } from "./tree.ts";
44
+ } from "./definition/report.ts";
45
+ export {
46
+ pickReportPage,
47
+ renderReportToText,
48
+ renderReportTreeToText,
49
+ reportTitleText,
50
+ ReportPageNotFoundError,
51
+ ReportPageNeedsLocatorError,
52
+ } from "./runtime/text.ts";
53
+ export type {
54
+ HostCommandContext,
55
+ RenderReportTextOptions,
56
+ RenderTreeTextOptions,
57
+ ReportTreeHostContext,
58
+ ReportHostContext,
59
+ } from "./runtime/text.ts";
60
+ export { defineComponent, createTextContext, renderNodeToText, resolveReportTree, validateReportTree, ResolveMemo } from "./definition/tree.ts";
61
+ export type { AttemptEvidence, AttemptEvidenceCapabilities } from "../results/attempt-evidence.ts";
54
62
  export type {
63
+ AttemptPageContext,
55
64
  ComponentFaces,
56
65
  ComposeContext,
66
+ PageContext,
57
67
  ReportComponent,
58
68
  ReportElement,
59
69
  ReportNode,
60
70
  ResolveContext,
61
71
  ResolveEnv,
72
+ ScopePageContext,
62
73
  TextContext,
63
74
  TextRenderOptions,
64
75
  WebContext,
65
- } from "./tree.ts";
76
+ } from "./definition/tree.ts";
66
77
 
67
- // 排版原语(八个内置双面组件)
68
- export { Col, Row, Section, Style, Tab, Table, Tabs, Text } from "./primitives.tsx";
78
+ // 排版原语(十个内置双面组件)
79
+ export { Col, Grid, Row, Section, Stat, Style, Tab, Table, Tabs, Text } from "./definition/primitives.tsx";
69
80
  export type {
70
81
  ColProps,
82
+ GridProps,
71
83
  LayoutProps,
72
84
  RowProps,
73
85
  SectionProps,
86
+ StatProps,
87
+ StatTone,
74
88
  StyleProps,
75
89
  TabProps,
76
90
  TableColumn,
@@ -78,7 +92,7 @@ export type {
78
92
  TableRow,
79
93
  TabsProps,
80
94
  TextProps,
81
- } from "./primitives.tsx";
95
+ } from "./definition/primitives.tsx";
82
96
 
83
97
  // 文本排版工具箱:自定义组件的 text 面用的就是官方组件那把尺子。
84
98
  // 表格有 <Table> 承担,这里只给表以外的形态用 —— 尤其别拿 String.prototype.padEnd 对齐:
@@ -91,78 +105,90 @@ export {
91
105
  indentBlock as indent,
92
106
  textBar as bar,
93
107
  joinColumns as columns,
94
- } from "./text/layout.ts";
95
- export type { ColumnAlign } from "./text/layout.ts";
108
+ } from "./model/text-layout.ts";
109
+ export type { ColumnAlign } from "./model/text-layout.ts";
96
110
 
97
111
  // locale:官方组件 chrome 文案的语言(内置词典覆盖 en / zh-CN,其它 locale 走回退)
98
- export { DEFAULT_REPORT_LOCALE, localizedTextEquals, resolveLocalizedText, resolveMetricLabel } from "./locale.ts";
99
- export type { LocalizedText, ReportLocale } from "./locale.ts";
112
+ export { DEFAULT_REPORT_LOCALE, localizedTextEquals, resolveLocalizedText, resolveMetricLabel } from "./model/locale.ts";
113
+ export type { LocalizedText, ReportLocale } from "./model/locale.ts";
100
114
 
101
115
  // 官方双面组件(spec / data 双形态;配套 *Data 计算函数在下面成对导出)
102
116
  // 与站点组件(Hero / HeroCard / PoweredBy / ScopeWarnings / CopyFixPrompt / TraceWaterfall)
117
+ export { ScopeSummary, ExperimentComparison } from "./components/summaries/index.tsx";
118
+ export type { ScopeSummaryProps, ExperimentComparisonProps } from "./components/summaries/index.tsx";
119
+ export { AttemptList, EvalList, ExperimentList, FailureList } from "./components/entity-lists/index.tsx";
120
+ export type {
121
+ AttemptListProps,
122
+ EvalListProps,
123
+ ExperimentListProps,
124
+ FailureListProps,
125
+ } from "./components/entity-lists/index.tsx";
103
126
  export {
104
- AttemptList,
105
- CopyFixPrompt,
106
127
  DeltaTable,
107
- EvalList,
108
- ExperimentComparison,
109
- ExperimentList,
110
- FailureList,
111
- Hero,
112
- HeroCard,
113
128
  MetricBars,
114
129
  MetricLine,
115
130
  MetricMatrix,
116
131
  MetricScatter,
117
132
  MetricTable,
118
- PoweredBy,
119
133
  Scoreboard,
120
- ScopeSummary,
121
- ScopeWarnings,
122
- TraceWaterfall,
123
- } from "./components.tsx";
134
+ } from "./components/metric-views/index.tsx";
124
135
  export type {
125
- AttemptListProps,
126
- CopyFixPromptProps,
127
- DataProps,
128
136
  DeltaTableProps,
129
- EvalListProps,
130
- ExperimentComparisonProps,
131
- ExperimentListProps,
132
- FailureListProps,
133
- HeroCardProps,
134
- HeroProps,
135
137
  MetricBarsProps,
136
138
  MetricLineProps,
137
139
  MetricMatrixProps,
138
140
  MetricScatterProps,
139
141
  MetricTableProps,
140
142
  ScoreboardProps,
141
- ScopeSummaryProps,
143
+ } from "./components/metric-views/index.tsx";
144
+ export {
145
+ CopyFixPrompt,
146
+ Hero,
147
+ HeroCard,
148
+ PoweredBy,
149
+ ScopeWarnings,
150
+ TraceWaterfall,
151
+ } from "./components/site-components/index.tsx";
152
+ export type {
153
+ CopyFixPromptProps,
154
+ HeroCardProps,
155
+ HeroProps,
142
156
  ScopeWarningsProps,
143
157
  TraceWaterfallProps,
144
- } from "./components.tsx";
158
+ } from "./components/site-components/index.tsx";
159
+
160
+ // Attempt 详情组件族(docs/feature/reports/library/attempt-detail.md):11 个叶子 + 2 个
161
+ // 只装配叶子的组合组件(AttemptAssessment / AttemptDetail),都从 niceeval/report 导出。
162
+ export {
163
+ AttemptAssertions,
164
+ AttemptAssessment,
165
+ AttemptConversation,
166
+ AttemptDetail,
167
+ AttemptDiagnostics,
168
+ AttemptDiff,
169
+ AttemptError,
170
+ AttemptFixPrompt,
171
+ AttemptSource,
172
+ AttemptSummary,
173
+ AttemptTimeline,
174
+ AttemptTrace,
175
+ AttemptUsage,
176
+ } from "./components/attempt-detail/index.tsx";
177
+ export type { AttemptSectionProps } from "./components/attempt-detail/index.tsx";
145
178
 
146
179
  // 计算函数(组件解析面的具名形式,与组件成对;spec 形态下由管线代调,data 形态与
147
180
  // 嵌入场景下由作者手工调)
181
+ export { scopeSummaryData } from "./components/summaries/compute.ts";
182
+ export { attemptListData, evalListData, experimentListData } from "./components/entity-lists/compute.ts";
148
183
  export {
149
- attemptListData,
150
- copyFixPromptData,
151
184
  deltaTableData,
152
- evalListData,
153
- experimentComparisonData,
154
- experimentListData,
155
- heroData,
156
185
  metricLineData,
157
186
  metricMatrixData,
158
187
  metricScatterData,
159
188
  metricTableData,
160
189
  pairsByFlag,
161
- scopeSummaryData,
162
- scopeWarningsData,
163
190
  scoreboardData,
164
- traceWaterfallData,
165
- } from "./compute.ts";
191
+ } from "./components/metric-views/compute.ts";
166
192
  export type {
167
193
  DeltaTableOptions,
168
194
  MetricLineOptions,
@@ -170,7 +196,28 @@ export type {
170
196
  MetricScatterOptions,
171
197
  MetricTableOptions,
172
198
  ScoreboardOptions,
173
- } from "./compute.ts";
199
+ } from "./components/metric-views/compute.ts";
200
+ export {
201
+ copyFixPromptData,
202
+ heroData,
203
+ scopeWarningsData,
204
+ traceWaterfallData,
205
+ } from "./components/site-components/compute.ts";
206
+
207
+ // Attempt 详情组件族的计算函数:输入恒为单个 AttemptEvidence,同步纯派生(不读文件、不 fetch)。
208
+ export {
209
+ attemptAssertionsData,
210
+ attemptConversationData,
211
+ attemptDiagnosticsData,
212
+ attemptDiffData,
213
+ attemptErrorData,
214
+ attemptFixPromptData,
215
+ attemptSourceData,
216
+ attemptSummaryData,
217
+ attemptTimelineData,
218
+ attemptTraceData,
219
+ attemptUsageData,
220
+ } from "./components/attempt-detail/compute.ts";
174
221
 
175
222
  // 数据契约(组件的 data)
176
223
  export type {
@@ -186,8 +233,6 @@ export type {
186
233
  DimensionOptions,
187
234
  DimensionRef,
188
235
  EvalListItem,
189
- ExperimentComparisonData,
190
- ExperimentComparisonGroupData,
191
236
  ExperimentListEvalRow,
192
237
  ExperimentListItem,
193
238
  FlagPairs,
@@ -207,15 +252,32 @@ export type {
207
252
  ScopeSummaryData,
208
253
  ScopeWarning,
209
254
  ScoreboardData,
255
+ SeriesInput,
210
256
  TableData,
211
257
  TraceSpanSummary,
212
258
  TraceWaterfallRow,
213
259
  VerdictTally,
214
- } from "./types.ts";
260
+ } from "./model/types.ts";
261
+
262
+ // Attempt 详情组件族的数据契约
263
+ export type {
264
+ AttemptAssertionsData,
265
+ AttemptConversationData,
266
+ AttemptConversationReply,
267
+ AttemptConversationRound,
268
+ AttemptDiagnosticsData,
269
+ AttemptDiffData,
270
+ AttemptDiffFileEntry,
271
+ AttemptErrorData,
272
+ AttemptFixPromptData,
273
+ AttemptSourceData,
274
+ AttemptSourceLineData,
275
+ AttemptSourceTurn,
276
+ AttemptSummaryData,
277
+ AttemptTimelineData,
278
+ AttemptTraceData,
279
+ AttemptUsageData,
280
+ } from "./model/types.ts";
215
281
 
216
282
  // 数据层输入的类型(家在 niceeval/results,这里 re-export 方便写指标 / 报告)
217
283
  export type { AttemptHandle, Results, Scope, Snapshot } from "../results/types.ts";
218
-
219
- // experiment id 的组键推导(id 的目录前缀,如 `compare/bub-low` 的 `compare`)。
220
- // 重新导出,让自定义报告能按同一份口径把 experiment 分组,不必自己重写这两行逻辑。
221
- export { experimentGroupOf } from "../shared/aggregate.ts";
@@ -6,9 +6,9 @@
6
6
  // 和重试策略纠缠在一起(eval A=[1]、eval B=[0,0,0] 平铺 = 0.25,两级宏平均 = 0.5)。
7
7
  // 自定义维度把同一道题的 attempt 分进不同组时,第一级折叠发生在各组内部。
8
8
 
9
- import { dedupeAttempts } from "../results/select.ts";
10
- import type { AttemptHandle, Scope, ScopeWarning, Snapshot } from "../results/types.ts";
11
- import { encodeAttemptLocator, type AttemptLocator } from "../results/locator.ts";
9
+ import { dedupeAttempts } from "../../results/select.ts";
10
+ import type { AttemptHandle, Scope, ScopeWarning, Snapshot } from "../../results/types.ts";
11
+ import { encodeAttemptLocator, type AttemptLocator } from "../../results/locator.ts";
12
12
  import type {
13
13
  Aggregator,
14
14
  DimensionInput,
@@ -18,11 +18,12 @@ import type {
18
18
  MetricColumn,
19
19
  NumericAxis,
20
20
  ReportInput,
21
+ SeriesInput,
21
22
  } from "./types.ts";
22
- import { flagValueOf, runConfigValueOf } from "./flag.ts";
23
+ import { flagValueOf, labelValueOf, runConfigValueOf } from "./flag.ts";
23
24
  import { formatMetricValue, localizedDisplay } from "./format.ts";
24
25
  import { localeText, type LocalizedText } from "./locale.ts";
25
- import { evalPrefixPredicate } from "../shared/aggregate.ts";
26
+ import { evalPrefixPredicate } from "../../shared/aggregate.ts";
26
27
 
27
28
  // 复合键分隔符:NUL 不会出现在 eval id / experimentId / ISO 时间里,拼接键不会串味
28
29
  const KEY_SEP = "\u0000";
@@ -119,7 +120,9 @@ function isDimensionRef(dimension: DimensionInput): dimension is DimensionRef {
119
120
  return (
120
121
  typeof dimension === "object" &&
121
122
  "kind" in dimension &&
122
- ((dimension as DimensionRef).kind === "flag" || (dimension as DimensionRef).kind === "runConfig")
123
+ ((dimension as DimensionRef).kind === "flag" ||
124
+ (dimension as DimensionRef).kind === "runConfig" ||
125
+ (dimension as DimensionRef).kind === "label")
123
126
  );
124
127
  }
125
128
 
@@ -147,9 +150,9 @@ export function refDisplayKey(value: unknown): [display: string, canonical: stri
147
150
  }
148
151
 
149
152
  function refValueOf(ref: DimensionRef, item: Item): unknown {
150
- return ref.kind === "flag"
151
- ? flagValueOf(item.attempt, ref.name)
152
- : runConfigValueOf(item.attempt, ref.name as Parameters<typeof runConfigValueOf>[1]);
153
+ if (ref.kind === "flag") return flagValueOf(item.attempt, ref.name);
154
+ if (ref.kind === "label") return labelValueOf(item.attempt, ref.name);
155
+ return runConfigValueOf(item.attempt, ref.name as Parameters<typeof runConfigValueOf>[1]);
153
156
  }
154
157
 
155
158
  export function dimensionKey(dimension: DimensionInput, item: Item): string {
@@ -179,6 +182,25 @@ export function dimensionKey(dimension: DimensionInput, item: Item): string {
179
182
  }
180
183
  }
181
184
 
185
+ /**
186
+ * series 类选项(SeriesInput)的复合维度解析:数组形态的维度 name 依声明顺序以 ` × ` 连接,
187
+ * 每个 attempt 的维度值为各成员显示键以 ` · ` 连接(缺失成员沿用 `(missing)` 显示键参与
188
+ * 连接,与单维度缺失同一条规则)。单维度形态与 dimensionName / dimensionKey 严格等价。
189
+ */
190
+ export function seriesMembers(series: SeriesInput): readonly DimensionInput[] {
191
+ return Array.isArray(series) ? (series as readonly DimensionInput[]) : [series as DimensionInput];
192
+ }
193
+
194
+ export function seriesName(series: SeriesInput): string {
195
+ return seriesMembers(series).map(dimensionName).join(" × ");
196
+ }
197
+
198
+ export function seriesKey(series: SeriesInput, item: Item): string {
199
+ return seriesMembers(series)
200
+ .map((member) => dimensionKey(member, item))
201
+ .join(" · ");
202
+ }
203
+
182
204
  /**
183
205
  * 按维度分组;维度 domain 按稳定 key 字典序(Unicode)排列,不让文件扫描顺序渗进报告。
184
206
  * flag / runConfig 维度做显示键冲突检测:不同原始值生成同一显示键时报错并要求改用
@@ -4,7 +4,7 @@
4
4
  // flag() 只读 `ExperimentDef.flags` 里显式声明的 KV;model / reasoningEffort / budget / runs
5
5
  // 这类顶层运行配置不在 flags 里,用 runConfig() 读快照的 ExperimentRunInfo 投影。
6
6
 
7
- import type { AttemptHandle } from "../results/types.ts";
7
+ import type { AttemptHandle } from "../../results/types.ts";
8
8
  import type {
9
9
  DimensionOptions,
10
10
  DimensionRef,
@@ -20,6 +20,12 @@ export function flagValueOf(attempt: AttemptHandle, name: string): unknown {
20
20
  return info?.flags?.[name];
21
21
  }
22
22
 
23
+ /** experiment 声明的报告归类标注 labels(同 flags 的读取回退链;值域 string | number)。 */
24
+ export function labelValueOf(attempt: AttemptHandle, name: string): unknown {
25
+ const info = attempt.snapshot?.experiment ?? attempt.result.experiment;
26
+ return info?.labels?.[name];
27
+ }
28
+
23
29
  /**
24
30
  * runConfig() 的取值:读快照的 `ExperimentRunInfo` 投影,外加桥接到快照顶层权威字段的
25
31
  * `model` / `agent` 两个键(与 "model" / "agent" 内置维度同一读法,不另造第二套口径)。
@@ -54,6 +60,21 @@ export function flag(name: string, options?: DimensionOptions): DimensionRef {
54
60
  };
55
61
  }
56
62
 
63
+ /**
64
+ * 把 experiment 声明的一个报告标注(`ExperimentDef.labels` 的键)当分组维度,与 {@link flag}
65
+ * 同一套用法。labels 是纯报告侧的归类坐标:不透传运行时、不参与可比性配置;报告不从
66
+ * experiment id 字符串猜语义,归类只认声明(docs/feature/experiments/library.md「labels」)。
67
+ */
68
+ export function label(name: string, options?: DimensionOptions): DimensionRef {
69
+ assertName(name, "label", "the key declared in the experiment's labels");
70
+ return {
71
+ kind: "label",
72
+ name,
73
+ ...(options?.label !== undefined ? { label: options.label } : {}),
74
+ ...(options?.unit !== undefined ? { unit: options.unit } : {}),
75
+ };
76
+ }
77
+
57
78
  /**
58
79
  * 把一项顶层运行配置当分组维度,与 {@link flag} 同一套用法。读快照的 `ExperimentRunInfo`
59
80
  * 投影;可用键由 RunConfigKey 在类型层穷尽(那张接口的字段全集,外加桥接到快照顶层权威
@@ -86,6 +107,23 @@ export function numericFlag(name: string, options?: NumericAxisOptions): Numeric
86
107
  };
87
108
  }
88
109
 
110
+ /**
111
+ * MetricLine 的 x 轴:只接受 number 值的 label。labels 由作者亲手声明,要数值轴就直接
112
+ * 声明成 number,不设 map;字符串值返回 null(折线不绘该点并报告缺失)。
113
+ */
114
+ export function numericLabel(name: string, options?: NumericAxisOptions): NumericAxis {
115
+ assertName(name, "numericLabel", "the key declared in the experiment's labels");
116
+ return {
117
+ name,
118
+ ...(options?.label !== undefined ? { label: options.label } : {}),
119
+ ...(options?.unit !== undefined ? { unit: options.unit } : {}),
120
+ of(attempt) {
121
+ const value = labelValueOf(attempt, name);
122
+ return typeof value === "number" && Number.isFinite(value) ? value : null;
123
+ },
124
+ };
125
+ }
126
+
89
127
  /**
90
128
  * 顶层运行配置作数值轴:数值配置直接返回该值;字符串配置必须显式给 `map`
91
129
  * (如 { low: 1, medium: 2, high: 3 })。未声明、未投影、非数值或未命中 map 的值返回 null。
@@ -2,21 +2,45 @@
2
2
  // "%" → 87% "ms" → 1.2s "$" → $0.31 其余 → 1.2k 缩写(带 unit 后缀)
3
3
  // metric.display 可整体覆盖;这里只负责默认。
4
4
 
5
- import type { Verdict } from "../types.ts";
5
+ import type { Verdict } from "../../types.ts";
6
6
  import { DISPLAY_LOCALES, type LocalizedText, type ReportLocale } from "./locale.ts";
7
7
 
8
8
  /**
9
- * experiment 行的显示名:给了父路径 `relativeTo` 且它确是前缀,就去掉 `relativeTo + "/"`,
10
- * 只留 id 末段——用在已经以组为标题的上下文(如默认 `ExperimentComparison` 的每组面板)里,
11
- * 避免每行重复文件夹名。组键就是 experiment id 的父目录,因此这里的末段与 `MetricScatter`
12
- * 点标签取的末段同源。不给 `relativeTo`、或它不是前缀(如根目录单例组)时原样返回完整 id。
13
- * 完整 id 仍是排序 / 着色 / 折叠的键,调用方不要拿这个显示名当身份用。
9
+ * 一组 id 的显示名:每个 id 缩成在这组里唯一的最短路径后缀,重名逐步加长到能区分为止
10
+ * (与 `MetricScatter` 点标签同一算法,两处共用本函数以保证同一份 experiment id 在散点和
11
+ * 列表里缩成同一个显示名)。单个 id、或所有 id 深度不同时也照常缩到各自的最短唯一后缀。
12
+ * 完整 id 不受影响,调用方仍用它做排序 / 过滤 / 折叠的身份键,这里只产出显示名。
14
13
  */
15
- export function experimentDisplayName(experimentId: string, relativeTo?: string): string {
16
- if (relativeTo && experimentId.startsWith(`${relativeTo}/`)) {
17
- return experimentId.slice(relativeTo.length + 1);
14
+ export function shortestUniqueLabels(ids: readonly string[]): Map<string, string> {
15
+ const segsOf = (id: string) => id.split("/").filter(Boolean);
16
+ const depth = new Map<string, number>(ids.map((id) => [id, 1]));
17
+ for (;;) {
18
+ const byLabel = new Map<string, string[]>();
19
+ for (const id of ids) {
20
+ const segs = segsOf(id);
21
+ const label = segs.slice(-Math.min(depth.get(id)!, segs.length)).join("/") || id;
22
+ byLabel.set(label, [...(byLabel.get(label) ?? []), id]);
23
+ }
24
+ let grew = false;
25
+ for (const group of byLabel.values()) {
26
+ if (group.length < 2) continue;
27
+ for (const id of group) {
28
+ const segs = segsOf(id);
29
+ if (depth.get(id)! < segs.length) {
30
+ depth.set(id, depth.get(id)! + 1);
31
+ grew = true;
32
+ }
33
+ }
34
+ }
35
+ if (!grew) {
36
+ const out = new Map<string, string>();
37
+ for (const id of ids) {
38
+ const segs = segsOf(id);
39
+ out.set(id, segs.slice(-Math.min(depth.get(id)!, segs.length)).join("/") || id);
40
+ }
41
+ return out;
42
+ }
18
43
  }
19
- return experimentId;
20
44
  }
21
45
 
22
46
  /** 一位小数、去掉无意义的 ".0" 尾巴。 */
@@ -104,6 +128,61 @@ export function formatPercent(ratio: number): string {
104
128
  return `${Math.round(ratio * 100)}%`;
105
129
  }
106
130
 
131
+ type ReportDateTimeOptions = Intl.DateTimeFormatOptions;
132
+
133
+ function formatReportDate(date: Date, locale: ReportLocale, options: ReportDateTimeOptions): string {
134
+ try {
135
+ return new Intl.DateTimeFormat(locale, options).format(date);
136
+ } catch {
137
+ return new Intl.DateTimeFormat("en", options).format(date);
138
+ }
139
+ }
140
+
141
+ const FULL_REPORT_DATE_TIME: ReportDateTimeOptions = {
142
+ year: "numeric",
143
+ month: "short",
144
+ day: "numeric",
145
+ hour: "2-digit",
146
+ minute: "2-digit",
147
+ hourCycle: "h23",
148
+ };
149
+
150
+ /** ISO 时间 → 本地化到分钟的短日期时间;不可解析时原样返回。 */
151
+ export function formatReportDateTime(iso: string, locale: ReportLocale): string {
152
+ const date = new Date(iso);
153
+ return Number.isNaN(date.valueOf()) ? iso : formatReportDate(date, locale, FULL_REPORT_DATE_TIME);
154
+ }
155
+
156
+ /** 时间范围的两端;同日省略右侧日期,同年省略右侧年份,减少卡片中的重复噪音。 */
157
+ export function formatReportDateTimeRange(
158
+ fromIso: string,
159
+ toIso: string,
160
+ locale: ReportLocale,
161
+ ): { from: string; to: string } {
162
+ const fromDate = new Date(fromIso);
163
+ const toDate = new Date(toIso);
164
+ if (Number.isNaN(fromDate.valueOf()) || Number.isNaN(toDate.valueOf())) {
165
+ return { from: formatReportDateTime(fromIso, locale), to: formatReportDateTime(toIso, locale) };
166
+ }
167
+ const sameYear = fromDate.getFullYear() === toDate.getFullYear();
168
+ const sameDay =
169
+ sameYear && fromDate.getMonth() === toDate.getMonth() && fromDate.getDate() === toDate.getDate();
170
+ const toOptions: ReportDateTimeOptions = sameDay
171
+ ? { hour: "2-digit", minute: "2-digit", hourCycle: "h23" }
172
+ : {
173
+ month: "short",
174
+ day: "numeric",
175
+ hour: "2-digit",
176
+ minute: "2-digit",
177
+ hourCycle: "h23",
178
+ ...(!sameYear && { year: "numeric" }),
179
+ };
180
+ return {
181
+ from: formatReportDate(fromDate, locale, FULL_REPORT_DATE_TIME),
182
+ to: formatReportDate(toDate, locale, toOptions),
183
+ };
184
+ }
185
+
107
186
  // ── 实体列表(ExperimentList / EvalList / AttemptList)共用的判定符 ──
108
187
 
109
188
  /** passed / failed / errored / skipped 的判定符。 */