niceeval 0.4.6 → 0.5.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 (174) hide show
  1. package/docs-site/zh/concepts/adapter.mdx +6 -6
  2. package/docs-site/zh/concepts/experiment.mdx +7 -7
  3. package/docs-site/zh/concepts/overview.mdx +1 -1
  4. package/docs-site/zh/concepts/tier.mdx +6 -6
  5. package/docs-site/zh/guides/agent-feedback-loop.mdx +63 -20
  6. package/docs-site/zh/guides/connect-your-agent.mdx +7 -7
  7. package/docs-site/zh/guides/custom-reports.mdx +243 -0
  8. package/docs-site/zh/guides/experiments.mdx +3 -3
  9. package/docs-site/zh/guides/report-components.mdx +252 -0
  10. package/docs-site/zh/guides/reporters.mdx +1 -1
  11. package/docs-site/zh/guides/results-data.mdx +224 -0
  12. package/docs-site/zh/guides/runner.mdx +1 -1
  13. package/docs-site/zh/guides/sandbox-agent.mdx +2 -2
  14. package/docs-site/zh/guides/viewing-results.mdx +147 -77
  15. package/docs-site/zh/guides/write-experiment.mdx +9 -9
  16. package/docs-site/zh/guides/write-send.mdx +6 -6
  17. package/docs-site/zh/index.mdx +1 -1
  18. package/docs-site/zh/introduction.mdx +1 -1
  19. package/docs-site/zh/reference/cli.mdx +10 -2
  20. package/docs-site/zh/reference/define-agent.mdx +5 -5
  21. package/docs-site/zh/reference/define-config.mdx +1 -1
  22. package/docs-site/zh/reference/define-eval.mdx +3 -3
  23. package/package.json +3 -2
  24. package/src/agents/ai-sdk.test.ts +1 -1
  25. package/src/agents/ai-sdk.ts +2 -2
  26. package/src/agents/claude-code.ts +1 -1
  27. package/src/agents/codex.ts +2 -2
  28. package/src/agents/streaming.test.ts +1 -1
  29. package/src/agents/types.ts +4 -4
  30. package/src/agents/ui-message-stream.test.ts +1 -1
  31. package/src/cli.ts +104 -14
  32. package/src/context/context.test.ts +1 -1
  33. package/src/context/context.ts +3 -3
  34. package/src/context/session.ts +2 -2
  35. package/src/context/types.ts +2 -2
  36. package/src/i18n/en.ts +29 -7
  37. package/src/i18n/zh-CN.ts +24 -2
  38. package/src/report/aggregate.ts +79 -50
  39. package/src/report/components.tsx +190 -0
  40. package/src/report/compute.ts +149 -84
  41. package/src/report/default-report.tsx +222 -0
  42. package/src/report/dual-face.test.tsx +527 -0
  43. package/src/report/format.ts +29 -0
  44. package/src/report/index.ts +79 -24
  45. package/src/report/load.ts +67 -0
  46. package/src/report/metrics.ts +2 -1
  47. package/src/report/param.ts +18 -0
  48. package/src/report/primitives.tsx +117 -0
  49. package/src/report/react/CaseList.tsx +2 -2
  50. package/src/report/react/DeltaTable.tsx +2 -2
  51. package/src/report/react/MetricBars.tsx +109 -0
  52. package/src/report/react/MetricLine.tsx +200 -0
  53. package/src/report/react/MetricMatrix.tsx +1 -1
  54. package/src/report/react/MetricScatter.tsx +1 -1
  55. package/src/report/react/MetricTable.tsx +1 -1
  56. package/src/report/react/RunOverview.tsx +4 -4
  57. package/src/report/react/Scoreboard.tsx +3 -3
  58. package/src/report/react/cell.tsx +1 -1
  59. package/src/report/react/fixtures.ts +98 -36
  60. package/src/report/react/format.ts +3 -28
  61. package/src/report/react/index.tsx +41 -24
  62. package/src/report/react/render.test.tsx +8 -8
  63. package/src/report/react/styles.css +77 -0
  64. package/src/report/report.test.ts +248 -128
  65. package/src/report/report.ts +69 -0
  66. package/src/report/text/faces.ts +356 -0
  67. package/src/report/text/layout.ts +125 -0
  68. package/src/report/text/plot.ts +127 -0
  69. package/src/report/tree.ts +220 -0
  70. package/src/report/types.ts +75 -27
  71. package/src/report/web.ts +40 -0
  72. package/src/results/copy.ts +95 -41
  73. package/src/results/format.ts +12 -11
  74. package/src/results/index.ts +34 -17
  75. package/src/results/open.ts +201 -81
  76. package/src/results/results.test.ts +595 -191
  77. package/src/results/select.ts +107 -55
  78. package/src/results/types.ts +137 -45
  79. package/src/results/writer.ts +258 -0
  80. package/src/runner/attempt.ts +3 -3
  81. package/src/runner/fingerprint.ts +1 -1
  82. package/src/runner/reporters/artifacts.ts +38 -78
  83. package/src/runner/reporters/braintrust.test.ts +2 -2
  84. package/src/runner/reporters/braintrust.ts +3 -3
  85. package/src/runner/run.ts +1 -1
  86. package/src/runner/types.ts +18 -12
  87. package/src/show/compose.ts +215 -0
  88. package/src/show/index.ts +263 -0
  89. package/src/show/render.ts +456 -0
  90. package/src/show/show.test.ts +505 -0
  91. package/src/view/app/App.tsx +85 -24
  92. package/src/view/app/components/CostScoreChart.tsx +29 -10
  93. package/src/view/app/components/ExperimentTable.tsx +27 -9
  94. package/src/view/app/components/GroupSelector.tsx +1 -1
  95. package/src/view/app/i18n.ts +18 -3
  96. package/src/view/app/lib/attempt-route.test.ts +9 -9
  97. package/src/view/app/lib/attempt-route.ts +5 -5
  98. package/src/view/app/lib/outcome.ts +1 -3
  99. package/src/view/app/lib/rows.ts +95 -15
  100. package/src/view/app/main.tsx +18 -6
  101. package/src/view/app/pages/RunsPage.tsx +4 -7
  102. package/src/view/app/pages/TracesPage.tsx +3 -8
  103. package/src/view/app/types.ts +50 -6
  104. package/src/view/client-dist/app.css +1 -1
  105. package/src/view/client-dist/app.js +20 -20
  106. package/src/view/data.test.ts +254 -0
  107. package/src/view/data.ts +336 -0
  108. package/src/view/index.ts +64 -10
  109. package/src/view/server.ts +31 -9
  110. package/src/view/shared/types.ts +47 -41
  111. package/src/view/styles.css +5 -0
  112. package/src/view/template.html +1 -0
  113. package/src/view/view-report.test.ts +308 -0
  114. package/docs-site/.mintignore +0 -13
  115. package/docs-site/AGENTS.md +0 -46
  116. package/docs-site/concepts/adapter.mdx +0 -287
  117. package/docs-site/concepts/assert.mdx +0 -243
  118. package/docs-site/concepts/drive.mdx +0 -118
  119. package/docs-site/concepts/evals.mdx +0 -108
  120. package/docs-site/concepts/experiment.mdx +0 -37
  121. package/docs-site/concepts/hitl.mdx +0 -83
  122. package/docs-site/concepts/judge.mdx +0 -129
  123. package/docs-site/concepts/overview.mdx +0 -98
  124. package/docs-site/concepts/tier.mdx +0 -42
  125. package/docs-site/docs-ref/00-index.md +0 -23
  126. package/docs-site/docs-ref/01-page-types.md +0 -43
  127. package/docs-site/docs-ref/03-style-rules.md +0 -45
  128. package/docs-site/docs-ref/04-code-examples.md +0 -37
  129. package/docs-site/docs-ref/05-dx-failure-paths.md +0 -45
  130. package/docs-site/docs-ref/06-checklists.md +0 -53
  131. package/docs-site/docs.json +0 -256
  132. package/docs-site/example/ai-agent-application.mdx +0 -148
  133. package/docs-site/example/claude-code-codex-plugin.mdx +0 -162
  134. package/docs-site/example/claude-code-codex-skill.mdx +0 -147
  135. package/docs-site/example/showcase.mdx +0 -39
  136. package/docs-site/example/tier1-ai-sdk-v7.mdx +0 -136
  137. package/docs-site/example/tier1-claude-sdk.mdx +0 -119
  138. package/docs-site/example/tier1-codex-sdk.mdx +0 -111
  139. package/docs-site/example/tier1-langgraph.mdx +0 -119
  140. package/docs-site/example/tier1-pi-sdk.mdx +0 -119
  141. package/docs-site/favicon.svg +0 -5
  142. package/docs-site/github-diff.css +0 -135
  143. package/docs-site/github-diff.js +0 -11
  144. package/docs-site/guides/authoring.mdx +0 -129
  145. package/docs-site/guides/ci-integration.mdx +0 -97
  146. package/docs-site/guides/connect-otel.mdx +0 -209
  147. package/docs-site/guides/connect-your-agent.mdx +0 -221
  148. package/docs-site/guides/dataset-fanout.mdx +0 -98
  149. package/docs-site/guides/experiments.mdx +0 -71
  150. package/docs-site/guides/fixtures.mdx +0 -147
  151. package/docs-site/guides/reporters.mdx +0 -113
  152. package/docs-site/guides/runner.mdx +0 -79
  153. package/docs-site/guides/sandbox-agent.mdx +0 -138
  154. package/docs-site/guides/sandbox-backends.mdx +0 -64
  155. package/docs-site/guides/scoring-guide.mdx +0 -92
  156. package/docs-site/guides/viewing-results.mdx +0 -195
  157. package/docs-site/guides/write-experiment.mdx +0 -81
  158. package/docs-site/guides/write-send.mdx +0 -347
  159. package/docs-site/index.mdx +0 -181
  160. package/docs-site/introduction.mdx +0 -141
  161. package/docs-site/quickstart.mdx +0 -136
  162. package/docs-site/reference/builtin-agents.mdx +0 -161
  163. package/docs-site/reference/capabilities.mdx +0 -76
  164. package/docs-site/reference/cli.mdx +0 -120
  165. package/docs-site/reference/define-agent.mdx +0 -168
  166. package/docs-site/reference/define-config.mdx +0 -41
  167. package/docs-site/reference/define-eval.mdx +0 -160
  168. package/docs-site/reference/events.mdx +0 -131
  169. package/docs-site/reference/expect.mdx +0 -112
  170. package/docs-site/tracker.js +0 -8
  171. package/src/report/react/data.ts +0 -17
  172. package/src/view/aggregate.ts +0 -103
  173. package/src/view/loader.test.ts +0 -61
  174. package/src/view/loader.ts +0 -257
@@ -1,22 +1,23 @@
1
- // 手工 fixture:模拟计算层(niceeval/report table()/matrix()/… )的产物。
2
- // 仅供 render.test.tsx 与 scripts/report-react-demo.tsx 使用,不从入口导出。
1
+ // 手工 fixture:模拟计算函数(MetricTable.data / MetricMatrix.data / )的产物。
2
+ // 仅供渲染测试与 scripts/report-react-demo.tsx 使用,不从入口导出。
3
3
  // 数字刻意覆盖诚实细节:coverage 角标(samples<total)、全 null 格子、
4
4
  // 稀疏矩阵、缺数据的散点、delta 的 null 不硬算、truncated 计数。
5
5
 
6
6
  import type {
7
7
  CaseListData,
8
8
  DeltaData,
9
+ LineData,
9
10
  MatrixData,
10
11
  MetricColumn,
11
12
  OverviewData,
12
13
  ScatterData,
13
14
  ScoreboardData,
14
15
  TableData,
15
- } from "./data.ts";
16
+ } from "../types.ts";
16
17
 
17
- export const passRateColumn: MetricColumn = { key: "pass-rate", label: "通过率", unit: "%", better: "higher" };
18
- export const codeLinesColumn: MetricColumn = { key: "code-lines", label: "代码行数", unit: "lines", better: "lower" };
19
- export const costColumn: MetricColumn = { key: "cost", label: "成本", unit: "$", better: "lower" };
18
+ export const passRateColumn: MetricColumn = { key: "pass-rate", label: "pass rate", unit: "%", better: "higher" };
19
+ export const codeLinesColumn: MetricColumn = { key: "code-lines", label: "code lines", unit: "lines", better: "lower" };
20
+ export const costColumn: MetricColumn = { key: "cost", label: "cost", unit: "$", better: "lower" };
20
21
 
21
22
  export const overviewData: OverviewData = {
22
23
  snapshots: [
@@ -33,7 +34,15 @@ export const overviewData: OverviewData = {
33
34
  costUSD: null, // 全部 attempt 都没报成本:null,组件必须显示缺数据而不是 $0
34
35
  durationMs: 261_000,
35
36
  },
36
- warnings: ["compare/bub 快照缺 3 个 eval 的结果"],
37
+ warnings: [
38
+ {
39
+ kind: "partial-coverage",
40
+ experimentId: "compare/bub",
41
+ covered: 9,
42
+ total: 12,
43
+ message: "snapshot covers 9 of 12 evals seen in history; re-run `niceeval exp compare/bub` for a full snapshot",
44
+ },
45
+ ],
37
46
  };
38
47
 
39
48
  export const overviewWithCost: OverviewData = {
@@ -42,7 +51,7 @@ export const overviewWithCost: OverviewData = {
42
51
  warnings: [],
43
52
  };
44
53
 
45
- export const tableData: TableData = {
54
+ export const tableData: TableData<"pass-rate" | "code-lines"> = {
46
55
  dimension: "agent",
47
56
  // 行顺序故意不按 passRate 排:组件必须按传入顺序渲染,不重排
48
57
  columns: [passRateColumn, codeLinesColumn],
@@ -50,9 +59,9 @@ export const tableData: TableData = {
50
59
  {
51
60
  key: "codex",
52
61
  cells: {
53
- "pass-rate": { value: 0.5, display: "50%", samples: 6, total: 6 },
62
+ "pass-rate": { value: 0.5, display: "50%", samples: 6, total: 6, refs: [] },
54
63
  // 全 null:一个有效样本都没有 → 缺数据文案,绝不画 0
55
- "code-lines": { value: null, display: "", samples: 0, total: 6 },
64
+ "code-lines": { value: null, display: "", samples: 0, total: 6, refs: [] },
56
65
  },
57
66
  },
58
67
  {
@@ -66,7 +75,7 @@ export const tableData: TableData = {
66
75
  refs: [{ run: "run-a", result: 0 }],
67
76
  },
68
77
  // samples < total:有 attempt 测不了 → 覆盖率角标 5/6
69
- "code-lines": { value: 120, display: "120 lines", samples: 5, total: 6 },
78
+ "code-lines": { value: 120, display: "120 lines", samples: 5, total: 6, refs: [] },
70
79
  },
71
80
  },
72
81
  ],
@@ -81,23 +90,32 @@ export const matrixData: MatrixData = {
81
90
  {
82
91
  row: "algebra/quadratic",
83
92
  column: "bub",
84
- cell: { value: 1, display: "100%", samples: 2, total: 2, refs: [{ run: "run-b", result: 3 }, { run: "run-b", result: 7 }] },
93
+ cell: {
94
+ value: 1,
95
+ display: "100%",
96
+ samples: 2,
97
+ total: 2,
98
+ refs: [
99
+ { run: "run-b", result: 3 },
100
+ { run: "run-b", result: 7 },
101
+ ],
102
+ },
85
103
  },
86
104
  {
87
105
  row: "algebra/quadratic",
88
106
  column: "codex",
89
- cell: { value: 0, display: "0%", samples: 3, total: 3 },
107
+ cell: { value: 0, display: "0%", samples: 3, total: 3, refs: [] },
90
108
  },
91
109
  {
92
110
  row: "geometry/angles",
93
111
  column: "bub",
94
- cell: { value: 0.5, display: "50%", samples: 2, total: 2 },
112
+ cell: { value: 0.5, display: "50%", samples: 2, total: 2, refs: [] },
95
113
  },
96
114
  ],
97
115
  };
98
116
 
99
117
  export const scoreboardData: ScoreboardData = {
100
- of: "agent",
118
+ dimension: "agent",
101
119
  fullMarks: 100,
102
120
  weights: [{ prefix: "algebra/", weight: 2 }],
103
121
  rows: [
@@ -130,32 +148,76 @@ export const scatterData: ScatterData = {
130
148
  {
131
149
  key: "compare/bub-low",
132
150
  series: "bub",
133
- x: { value: 5, display: "$5.00", samples: 6, total: 6 },
134
- y: { value: 0.5, display: "50%", samples: 6, total: 6 },
151
+ x: { value: 5, display: "$5.00", samples: 6, total: 6, refs: [] },
152
+ y: { value: 0.5, display: "50%", samples: 6, total: 6, refs: [] },
135
153
  },
136
154
  {
137
155
  key: "compare/bub-high",
138
156
  series: "bub",
139
- x: { value: 10, display: "$10.00", samples: 6, total: 6 },
140
- y: { value: 0.9, display: "90%", samples: 6, total: 6 },
157
+ x: { value: 10, display: "$10.00", samples: 6, total: 6, refs: [] },
158
+ y: { value: 0.9, display: "90%", samples: 6, total: 6, refs: [] },
141
159
  },
142
160
  {
143
161
  key: "compare/codex-mid",
144
162
  series: "codex",
145
- x: { value: 7, display: "$7.00", samples: 6, total: 6 },
146
- y: { value: 0.6, display: "60%", samples: 6, total: 6 },
163
+ x: { value: 7, display: "$7.00", samples: 6, total: 6, refs: [] },
164
+ y: { value: 0.6, display: "60%", samples: 6, total: 6, refs: [] },
147
165
  },
148
166
  {
149
167
  // x 缺数据:这个点不画,注脚报 1 个点缺数据
150
168
  key: "compare/codex-broken",
151
169
  series: "codex",
152
- x: { value: null, display: "", samples: 0, total: 6 },
153
- y: { value: 0.7, display: "70%", samples: 6, total: 6 },
170
+ x: { value: null, display: "", samples: 0, total: 6, refs: [] },
171
+ y: { value: 0.7, display: "70%", samples: 6, total: 6, refs: [] },
172
+ },
173
+ ],
174
+ };
175
+
176
+ export const lineData: LineData = {
177
+ x: { key: "latencyMs", label: "Simulated latency", unit: "ms" },
178
+ series: "agents",
179
+ y: passRateColumn,
180
+ rows: [
181
+ {
182
+ key: "ultra/agents-1-lat-100",
183
+ series: "1 agents",
184
+ x: 100,
185
+ xDisplay: "100ms",
186
+ y: { value: 0.4, display: "40%", samples: 6, total: 6, refs: [] },
187
+ },
188
+ {
189
+ key: "ultra/agents-1-lat-300",
190
+ series: "1 agents",
191
+ x: 300,
192
+ xDisplay: "300ms",
193
+ y: { value: 0.3, display: "30%", samples: 6, total: 6, refs: [] },
194
+ },
195
+ {
196
+ key: "ultra/agents-16-lat-100",
197
+ series: "16 agents",
198
+ x: 100,
199
+ xDisplay: "100ms",
200
+ y: { value: 0.8, display: "80%", samples: 6, total: 6, refs: [] },
201
+ },
202
+ {
203
+ key: "ultra/agents-16-lat-300",
204
+ series: "16 agents",
205
+ x: 300,
206
+ xDisplay: "300ms",
207
+ y: { value: 0.7, display: "70%", samples: 6, total: 6, refs: [] },
208
+ },
209
+ {
210
+ // 未声明 param 的 experiment:作轴不画点,注脚报数
211
+ key: "ultra/legacy",
212
+ series: "1 agents",
213
+ x: null,
214
+ xDisplay: "",
215
+ y: { value: 0.5, display: "50%", samples: 6, total: 6, refs: [] },
154
216
  },
155
217
  ],
156
218
  };
157
219
 
158
- export const deltaData: DeltaData = {
220
+ export const deltaData: DeltaData<"pass-rate" | "cost"> = {
159
221
  columns: [passRateColumn, costColumn],
160
222
  rows: [
161
223
  {
@@ -165,15 +227,15 @@ export const deltaData: DeltaData = {
165
227
  cells: {
166
228
  // 通过率 +12pp:better higher → 好(绿)
167
229
  "pass-rate": {
168
- a: { value: 0.5, display: "50%", samples: 6, total: 6 },
169
- b: { value: 0.62, display: "62%", samples: 6, total: 6 },
230
+ a: { value: 0.5, display: "50%", samples: 6, total: 6, refs: [] },
231
+ b: { value: 0.62, display: "62%", samples: 6, total: 6, refs: [] },
170
232
  delta: 0.12,
171
233
  display: "+12pp",
172
234
  },
173
235
  // 成本 +$0.15:better lower → 坏(红)
174
236
  cost: {
175
- a: { value: 0.2, display: "$0.20", samples: 6, total: 6 },
176
- b: { value: 0.35, display: "$0.35", samples: 6, total: 6 },
237
+ a: { value: 0.2, display: "$0.20", samples: 6, total: 6, refs: [] },
238
+ b: { value: 0.35, display: "$0.35", samples: 6, total: 6, refs: [] },
177
239
  delta: 0.15,
178
240
  display: "+$0.15",
179
241
  },
@@ -185,17 +247,17 @@ export const deltaData: DeltaData = {
185
247
  b: { experimentId: "compare/codex--agents-md" },
186
248
  cells: {
187
249
  "pass-rate": {
188
- a: { value: 0.4, display: "40%", samples: 6, total: 6 },
189
- b: { value: 0.4, display: "40%", samples: 6, total: 6 },
250
+ a: { value: 0.4, display: "40%", samples: 6, total: 6, refs: [] },
251
+ b: { value: 0.4, display: "40%", samples: 6, total: 6, refs: [] },
190
252
  delta: 0,
191
- display: "±0pp",
253
+ display: "±0",
192
254
  },
193
255
  // A 侧缺数据 → delta null:显示缺,不硬算
194
256
  cost: {
195
- a: { value: null, display: "", samples: 0, total: 6 },
196
- b: { value: 0.3, display: "$0.30", samples: 6, total: 6 },
257
+ a: { value: null, display: "", samples: 0, total: 6, refs: [] },
258
+ b: { value: 0.3, display: "$0.30", samples: 6, total: 6, refs: [] },
197
259
  delta: null,
198
- display: "",
260
+ display: "",
199
261
  },
200
262
  },
201
263
  },
@@ -213,8 +275,8 @@ export const caseListData: CaseListData = {
213
275
  {
214
276
  name: "roots-correct",
215
277
  score: 0,
216
- detail: "期望 x=2,得到 x=3",
217
- evidence: "judge: 求根公式代入时符号写反",
278
+ detail: "expected x=2, got x=3",
279
+ evidence: "judge: sign flipped when substituting into the quadratic formula",
218
280
  },
219
281
  ],
220
282
  durationMs: 32_000,
@@ -1,34 +1,9 @@
1
- // 展示层的小格式化。注意边界:MetricCell 一律自带 display(格式化发生在计算侧),
2
- // 组件不重算;这里只服务 OverviewData 这类携带裸数字的字段(耗时、成本、比率),
3
- // 以及 class 名拼接。缺数据的统一文案也钉在这里,保证各组件同词。
1
+ // web 面的小工具:展示格式化统一住在计算侧的 ../format.ts(两个渲染面同一份),
2
+ // 这里 re-export 并补 class 名拼接。MetricCell 一律自带 display,组件不重算。
4
3
 
5
- /** null / 无样本的统一文案。绝不画 0(docs/reports.md「null 0」)。 */
6
- export const MISSING_TEXT = "no data";
4
+ export { MISSING_TEXT, formatDurationMs, formatPercent, formatUSD } from "../format.ts";
7
5
 
8
6
  /** 拼 class 名:过滤空值,末尾接使用者透传的 className。 */
9
7
  export function cx(...parts: (string | undefined | false)[]): string {
10
8
  return parts.filter(Boolean).join(" ");
11
9
  }
12
-
13
- /** 毫秒 → 人读耗时("850ms" / "1.2s" / "4m 20s" / "1h 4m")。 */
14
- export function formatDurationMs(ms: number): string {
15
- if (ms < 1000) return `${Math.round(ms)}ms`;
16
- const s = ms / 1000;
17
- if (s < 60) return `${s.toFixed(1)}s`;
18
- const m = Math.floor(s / 60);
19
- if (m < 60) return `${m}m ${Math.round(s % 60)}s`;
20
- const h = Math.floor(m / 60);
21
- return `${h}h ${m % 60}m`;
22
- }
23
-
24
- /** 美元金额;小额保留更多位数,不四舍五入成 $0.00 的假零。 */
25
- export function formatUSD(usd: number): string {
26
- if (usd === 0) return "$0";
27
- const digits = Math.abs(usd) >= 0.01 ? 2 : 4;
28
- return `$${usd.toFixed(digits)}`;
29
- }
30
-
31
- /** 0..1 的比率 → 整数百分比。 */
32
- export function formatPercent(ratio: number): string {
33
- return `${Math.round(ratio * 100)}%`;
34
- }
@@ -1,34 +1,51 @@
1
- // niceeval/report/react —— 纯渲染的报告积木(docs/reports.md 第一档,原型实现)。
1
+ // niceeval/report/react —— 零件复用的导出点:把某一块指标表嵌进已有内部面板时从这里
2
+ // import。导出的组件与 niceeval/report 是同一批双面组件(web 面即 React 渲染,零 IO、
3
+ // 可进 "use client",不 hydrate 也完整),都带自己的 data 计算函数;那是零件的复用,
4
+ // 不是另一套报告系统 —— 报告的家在官方宿主(--report)。
2
5
  //
3
6
  // 契约:
4
- // - 组件只认「算好的可序列化数据」:零 IO、零 hooks、零数据操作,可进 "use client";
5
- // - 不 hydrate 也完整:renderToStaticMarkup 的产物即成品——排序在数据侧预排,
6
- // hover 退化为 title,下钻是普通 <a>,展开折叠是 <details>;
7
+ // - 组件只认「算好的可序列化数据」:零 hooks、零数据操作;
7
8
  // - 样式随包发布:配套 ./styles.css(nre-* 稳定类名),使用者在其后加载覆盖即可;
8
9
  // - 跨块配色一致:维度键 → 稳定散列 → 固定调色板下标(colors.ts)。
9
- //
10
- // 数据从哪来:niceeval/report 的计算函数(table()/matrix()/scoreboard()/scatter()/
11
- // overview()/delta()/cases())。计算层在并行实验中实现;类型暂由 ./data.ts 声明,
12
- // 合并时切换为从计算层 re-export。
13
10
 
14
- export { RunOverview } from "./RunOverview.tsx";
15
- export { MetricTable } from "./MetricTable.tsx";
16
- export { MetricMatrix } from "./MetricMatrix.tsx";
17
- export { Scoreboard } from "./Scoreboard.tsx";
18
- export { MetricScatter } from "./MetricScatter.tsx";
19
- export { DeltaTable } from "./DeltaTable.tsx";
20
- export { CaseList } from "./CaseList.tsx";
11
+ export {
12
+ CaseList,
13
+ DeltaTable,
14
+ MetricBars,
15
+ MetricLine,
16
+ MetricMatrix,
17
+ MetricScatter,
18
+ MetricTable,
19
+ RunOverview,
20
+ Scoreboard,
21
+ } from "../components.tsx";
22
+ export type {
23
+ CaseListProps,
24
+ DeltaTableProps,
25
+ MetricLineProps,
26
+ MetricMatrixProps,
27
+ MetricScatterProps,
28
+ MetricTableProps,
29
+ RunOverviewProps,
30
+ ScoreboardProps,
31
+ } from "../components.tsx";
21
32
 
22
- // 数据契约类型(临时家在 ./data.ts,见该文件头部说明)
33
+ // 数据契约类型(家在 ../types.ts,「算」与「画」两侧共用同一份)
23
34
  export type {
24
35
  AttemptRef,
25
- MetricColumn,
26
- MetricCell,
27
- TableData,
36
+ CaseListData,
37
+ DeltaData,
38
+ LineAxis,
39
+ LineData,
28
40
  MatrixData,
29
- ScoreboardData,
30
- ScatterData,
41
+ MetricCell,
42
+ MetricColumn,
31
43
  OverviewData,
32
- DeltaData,
33
- CaseListData,
34
- } from "./data.ts";
44
+ ScatterData,
45
+ ScoreboardData,
46
+ SelectionWarning,
47
+ TableData,
48
+ } from "../types.ts";
49
+
50
+ // 稳定配色(自定义组件想与官方组件同键同色时用)
51
+ export { NRE_PALETTE, colorClassForKey, colorHexForKey, colorIndexForKey } from "./colors.ts";
@@ -54,7 +54,7 @@ describe("RunOverview", () => {
54
54
  expect(html).toContain("2 snapshots");
55
55
  expect(html).toContain("compare/bub");
56
56
  expect(html).toContain("2026-07-01T10:00:00Z");
57
- expect(html).toContain("compare/bub 快照缺 3 eval 的结果");
57
+ expect(html).toContain("snapshot covers 9 of 12 evals seen in history");
58
58
  expect(html).toContain("nre-warnings");
59
59
  });
60
60
  });
@@ -69,9 +69,9 @@ describe("MetricTable", () => {
69
69
  });
70
70
 
71
71
  it("列头带 label、unit 与 better 方向", () => {
72
- expect(html).toContain("通过率");
72
+ expect(html).toContain("pass rate");
73
73
  expect(html).toContain("(%)");
74
- expect(html).toContain("代码行数");
74
+ expect(html).toContain("code lines");
75
75
  expect(html).toContain("↑");
76
76
  expect(html).toContain("↓");
77
77
  });
@@ -96,7 +96,7 @@ describe("MetricMatrix", () => {
96
96
  const html = renderToStaticMarkup(<MetricMatrix data={matrixData} attemptHref={attemptHref} />);
97
97
 
98
98
  it("caption 标出指标与行列维度", () => {
99
- expect(html).toContain("通过率");
99
+ expect(html).toContain("pass rate");
100
100
  expect(html).toContain("eval × agent");
101
101
  });
102
102
 
@@ -158,8 +158,8 @@ describe("MetricScatter", () => {
158
158
 
159
159
  it("内联 SVG + 轴标签", () => {
160
160
  expect(html).toContain("<svg");
161
- expect(html).toContain("成本($)");
162
- expect(html).toContain("通过率(%)");
161
+ expect(html).toContain("cost($)");
162
+ expect(html).toContain("pass rate(%)");
163
163
  });
164
164
 
165
165
  it("better:lower 的 x 轴反向:便宜($5)在贵($10)右边,好的角落恒在右上", () => {
@@ -239,8 +239,8 @@ describe("CaseList", () => {
239
239
  it("逐条失败断言:name、score、detail、evidence", () => {
240
240
  expect(html).toContain("roots-correct");
241
241
  expect(html).toContain("score 0");
242
- expect(html).toContain("期望 x=2,得到 x=3");
243
- expect(html).toContain("judge: 求根公式代入时符号写反");
242
+ expect(html).toContain("expected x=2, got x=3");
243
+ expect(html).toContain("judge: sign flipped when substituting into the quadratic formula");
244
244
  });
245
245
 
246
246
  it("errored 的 error 摘要", () => {
@@ -300,3 +300,80 @@ table.nre,
300
300
  .nre-case-list .nre-case-empty {
301
301
  color: #737373;
302
302
  }
303
+
304
+ /* ---- MetricBars ---- */
305
+ .nre-metric-bars {
306
+ margin: 1rem 0;
307
+ }
308
+ .nre-metric-bars .nre-bars-svg {
309
+ max-width: 640px;
310
+ width: 100%;
311
+ height: auto;
312
+ display: block;
313
+ }
314
+ .nre-metric-bars .nre-bars-legend {
315
+ color: #737373;
316
+ font-size: 0.85em;
317
+ margin-top: 0.25rem;
318
+ }
319
+ .nre-metric-bars .nre-bars-metric {
320
+ margin-right: 1em;
321
+ font-weight: 600;
322
+ color: #171717;
323
+ }
324
+ .nre-metric-bars .nre-legend-key {
325
+ margin-right: 0.75em;
326
+ }
327
+
328
+ /* ---- MetricLine ---- */
329
+ .nre-metric-line {
330
+ margin: 1rem 0;
331
+ }
332
+ .nre-metric-line .nre-line-svg {
333
+ max-width: 640px;
334
+ width: 100%;
335
+ height: auto;
336
+ display: block;
337
+ }
338
+ .nre-metric-line .nre-line-missing {
339
+ color: #b45309;
340
+ font-size: 0.85em;
341
+ margin: 0.25rem 0 0;
342
+ }
343
+ .nre-metric-line .nre-line-point-link circle:hover {
344
+ stroke: #171717;
345
+ stroke-width: 1.5;
346
+ }
347
+
348
+ /* ---- 排版原语 Row / Col / Section / Text ---- */
349
+ .nre-col {
350
+ display: flex;
351
+ flex-direction: column;
352
+ gap: 1rem;
353
+ }
354
+ .nre-row {
355
+ display: flex;
356
+ flex-wrap: wrap;
357
+ gap: 1.5rem;
358
+ align-items: flex-start;
359
+ }
360
+ .nre-row > * {
361
+ flex: 1 1 20rem;
362
+ min-width: 0;
363
+ }
364
+ .nre-section .nre-section-title {
365
+ font-size: 1.1em;
366
+ font-weight: 700;
367
+ margin: 0 0 0.5rem;
368
+ }
369
+ .nre-text {
370
+ color: #525252;
371
+ margin: 0.25rem 0;
372
+ }
373
+
374
+ /* ---- DefaultReport(官方水位整块)---- */
375
+ .nre-default-report {
376
+ display: flex;
377
+ flex-direction: column;
378
+ gap: 1rem;
379
+ }