niceeval 0.6.2 → 0.7.1
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.
- package/INDEX.md +23 -23
- package/README.zh.md +6 -6
- package/dist/agents/types.d.ts +2 -2
- package/dist/i18n/zh-CN.d.ts +3 -3
- package/dist/report/aggregate.d.ts +32 -26
- package/dist/report/aggregate.js +157 -76
- package/dist/report/built-in/index.d.ts +2 -0
- package/dist/report/built-in/index.js +8 -0
- package/dist/report/components.d.ts +91 -164
- package/dist/report/components.js +377 -114
- package/dist/report/compute.d.ts +86 -73
- package/dist/report/compute.js +592 -432
- package/dist/report/flag.d.ts +28 -17
- package/dist/report/flag.js +86 -16
- package/dist/report/format.d.ts +11 -11
- package/dist/report/format.js +17 -15
- package/dist/report/index.d.ts +16 -17
- package/dist/report/index.js +20 -22
- package/dist/report/load.js +3 -2
- package/dist/report/locale.d.ts +49 -34
- package/dist/report/locale.js +106 -58
- package/dist/report/metrics.d.ts +10 -3
- package/dist/report/metrics.js +46 -12
- package/dist/report/primitives.d.ts +42 -15
- package/dist/report/primitives.js +135 -26
- package/dist/report/react/AttemptList.d.ts +10 -8
- package/dist/report/react/AttemptList.js +18 -10
- package/dist/report/react/DeltaTable.js +19 -18
- package/dist/report/react/EvalList.d.ts +3 -3
- package/dist/report/react/EvalList.js +0 -0
- package/dist/report/react/ExperimentComparison.d.ts +4 -2
- package/dist/report/react/ExperimentComparison.js +5 -4
- package/dist/report/react/ExperimentList.d.ts +3 -3
- package/dist/report/react/ExperimentList.js +16 -15
- package/dist/report/react/MetricBars.js +5 -4
- package/dist/report/react/MetricLine.js +12 -5
- package/dist/report/react/MetricMatrix.js +1 -1
- package/dist/report/react/MetricScatter.js +54 -17
- package/dist/report/react/MetricTable.js +2 -12
- package/dist/report/react/ScopeSummary.d.ts +10 -0
- package/dist/report/react/ScopeSummary.js +17 -0
- package/dist/report/react/Scoreboard.js +6 -6
- package/dist/report/react/cell.js +2 -2
- package/dist/report/react/fixtures.d.ts +5 -9
- package/dist/report/react/fixtures.js +105 -149
- package/dist/report/react/index.d.ts +15 -5
- package/dist/report/react/index.js +18 -7
- package/dist/report/report.d.ts +137 -20
- package/dist/report/report.js +261 -34
- package/dist/report/text/faces.d.ts +17 -19
- package/dist/report/text/faces.js +225 -157
- package/dist/report/text/plot.js +1 -1
- package/dist/report/text/table.js +2 -2
- package/dist/report/tree.d.ts +90 -40
- package/dist/report/tree.js +252 -94
- package/dist/report/types.d.ts +245 -300
- package/dist/report/types.js +4 -3
- package/dist/report/web.d.ts +21 -5
- package/dist/report/web.js +42 -16
- package/dist/results/select.d.ts +38 -16
- package/dist/results/select.js +73 -25
- package/dist/results/types.d.ts +38 -14
- package/dist/shared/aggregate.d.ts +3 -2
- package/dist/shared/aggregate.js +5 -4
- package/docs-site/zh/README.md +44 -0
- package/docs-site/zh/examples/ai-agent-application.mdx +63 -0
- package/docs-site/zh/examples/coding-agent-extensions.mdx +57 -0
- package/docs-site/zh/examples/index.mdx +50 -0
- package/docs-site/zh/{concepts → explanation}/adapter.mdx +11 -11
- package/docs-site/zh/{concepts → explanation}/assert.mdx +7 -7
- package/docs-site/zh/{concepts → explanation}/drive.mdx +8 -8
- package/docs-site/zh/{concepts → explanation}/evals.mdx +4 -4
- package/docs-site/zh/{concepts → explanation}/experiment.mdx +8 -8
- package/docs-site/zh/{concepts → explanation}/hitl.mdx +8 -8
- package/docs-site/zh/{concepts → explanation}/judge.mdx +5 -5
- package/docs-site/zh/{concepts → explanation}/overview.mdx +5 -5
- package/docs-site/zh/{guides → explanation}/runner.mdx +1 -1
- package/docs-site/zh/{concepts → explanation}/tier.mdx +6 -6
- package/docs-site/zh/{guides → how-to}/agent-feedback-loop.mdx +7 -7
- package/docs-site/zh/{guides → how-to}/authoring.mdx +2 -2
- package/docs-site/zh/{guides → how-to}/connect-otel.mdx +6 -6
- package/docs-site/zh/{guides → how-to}/connect-your-agent.mdx +18 -18
- package/docs-site/zh/{guides → how-to}/custom-reports.mdx +6 -6
- package/docs-site/zh/{guides → how-to}/experiments.mdx +3 -3
- package/docs-site/zh/{guides → how-to}/publish-report.mdx +2 -2
- package/docs-site/zh/{guides → how-to}/sandbox-agent.mdx +2 -2
- package/docs-site/zh/{guides → how-to}/sandbox-providers.mdx +1 -1
- package/docs-site/zh/{guides → how-to}/viewing-results.mdx +6 -6
- package/docs-site/zh/{guides → how-to}/write-experiment.mdx +3 -3
- package/docs-site/zh/{guides → how-to}/write-send.mdx +13 -13
- package/docs-site/zh/index.mdx +23 -25
- package/docs-site/zh/introduction.mdx +8 -8
- package/docs-site/zh/reference/builtin-agents.mdx +5 -5
- package/docs-site/zh/reference/capabilities.mdx +6 -6
- package/docs-site/zh/reference/cli.mdx +9 -7
- package/docs-site/zh/reference/define-agent.mdx +1 -1
- package/docs-site/zh/reference/events.mdx +3 -3
- package/docs-site/zh/{guides → reference}/official-adapters.mdx +7 -7
- package/docs-site/zh/{guides → reference}/report-components.mdx +5 -5
- package/docs-site/zh/{guides → reference}/results-data.mdx +5 -5
- package/docs-site/zh/{guides → troubleshooting}/debug-sandbox.mdx +2 -2
- package/docs-site/zh/{guides → troubleshooting}/debugging.mdx +4 -2
- package/docs-site/zh/{quickstart.mdx → tutorials/quickstart.mdx} +5 -17
- package/package.json +6 -2
- package/src/agents/index.ts +2 -2
- package/src/agents/openai-compat.ts +1 -1
- package/src/agents/streaming.ts +2 -2
- package/src/agents/types.ts +3 -3
- package/src/cli.ts +42 -23
- package/src/context/context.ts +1 -1
- package/src/context/session.test.ts +1 -1
- package/src/context/session.ts +1 -1
- package/src/i18n/en.ts +18 -16
- package/src/i18n/zh-CN.ts +16 -15
- package/src/report/aggregate.ts +175 -87
- package/src/report/built-in/index.tsx +9 -0
- package/src/report/components.tsx +625 -285
- package/src/report/compute.ts +717 -515
- package/src/report/dual-render.test.tsx +738 -1148
- package/src/report/flag.ts +97 -33
- package/src/report/format.ts +18 -22
- package/src/report/index.ts +113 -58
- package/src/report/load.ts +3 -2
- package/src/report/locale.ts +120 -69
- package/src/report/metrics.ts +42 -12
- package/src/report/primitives.tsx +190 -45
- package/src/report/react/AttemptList.tsx +32 -20
- package/src/report/react/DeltaTable.tsx +63 -45
- package/src/report/react/EvalList.tsx +0 -0
- package/src/report/react/ExperimentComparison.tsx +12 -7
- package/src/report/react/ExperimentList.tsx +38 -26
- package/src/report/react/MetricBars.tsx +5 -4
- package/src/report/react/MetricLine.tsx +13 -8
- package/src/report/react/MetricMatrix.tsx +2 -2
- package/src/report/react/MetricScatter.tsx +74 -20
- package/src/report/react/MetricTable.tsx +4 -76
- package/src/report/react/ScopeSummary.tsx +86 -0
- package/src/report/react/Scoreboard.tsx +28 -10
- package/src/report/react/cell.tsx +2 -2
- package/src/report/react/enhance.js +57 -5
- package/src/report/react/fixtures.ts +109 -156
- package/src/report/react/index.tsx +24 -39
- package/src/report/react/render.test.tsx +139 -104
- package/src/report/react/styles.css +181 -91
- package/src/report/report.test.ts +761 -1031
- package/src/report/report.ts +425 -47
- package/src/report/text/faces.ts +257 -164
- package/src/report/text/plot.ts +1 -1
- package/src/report/text/table.ts +2 -2
- package/src/report/tree.ts +362 -104
- package/src/report/types.ts +257 -287
- package/src/report/web.ts +63 -20
- package/src/results/attempt-evidence.test.ts +4 -4
- package/src/results/attempt-evidence.ts +5 -5
- package/src/results/copy.ts +6 -6
- package/src/results/host-equivalence.test.ts +26 -14
- package/src/results/index.ts +10 -4
- package/src/results/open.ts +8 -4
- package/src/results/results.test.ts +4 -3
- package/src/results/select.ts +104 -34
- package/src/results/types.ts +36 -14
- package/src/runner/feedback/human.test.ts +1 -1
- package/src/runner/run.ts +1 -1
- package/src/sandbox/cli-commands.ts +2 -2
- package/src/scoring/judge.test.ts +1 -1
- package/src/shared/aggregate.ts +5 -4
- package/src/show/compose.ts +50 -67
- package/src/show/index.ts +107 -56
- package/src/show/render.ts +43 -27
- package/src/show/report-host.test.ts +188 -0
- package/src/show/report-host.ts +375 -0
- package/src/show/show.test.ts +86 -36
- package/src/view/app/App.test.tsx +69 -0
- package/src/view/app/App.tsx +144 -48
- package/src/view/app/components/AttemptModal.tsx +324 -63
- package/src/view/app/components/CodeView.tsx +10 -4
- package/src/view/app/i18n.ts +31 -17
- package/src/view/app/lib/artifact-url.ts +14 -3
- package/src/view/app/main.tsx +13 -8
- package/src/view/app/pages/{RunsPage.tsx → AttemptsPage.tsx} +6 -6
- package/src/view/app/types.ts +4 -1
- package/src/view/artifact-serving.test.ts +21 -1
- package/src/view/client-dist/app.css +1 -1
- package/src/view/client-dist/app.js +6 -6
- package/src/view/data.test.ts +9 -3
- package/src/view/data.ts +145 -49
- package/src/view/index.ts +48 -44
- package/src/view/server.ts +35 -15
- package/src/view/shared/types.ts +34 -5
- package/src/view/styles.css +224 -0
- package/src/view/view-report.test.ts +161 -57
- package/dist/report/built-ins/experiment-comparison.d.ts +0 -39
- package/dist/report/built-ins/experiment-comparison.js +0 -119
- package/dist/report/built-ins/index.d.ts +0 -2
- package/dist/report/built-ins/index.js +0 -2
- package/dist/report/react/GroupSummary.d.ts +0 -8
- package/dist/report/react/GroupSummary.js +0 -8
- package/dist/report/react/RunOverview.d.ts +0 -8
- package/dist/report/react/RunOverview.js +0 -12
- package/docs-site/zh/example/ai-agent-application.mdx +0 -152
- package/docs-site/zh/example/claude-code-codex-plugin.mdx +0 -167
- package/docs-site/zh/example/claude-code-codex-skill.mdx +0 -152
- package/docs-site/zh/example/showcase.mdx +0 -39
- package/src/report/built-in-user-parity.test.tsx +0 -597
- package/src/report/built-ins/experiment-comparison.tsx +0 -179
- package/src/report/built-ins/index.ts +0 -7
- package/src/report/react/GroupSummary.tsx +0 -66
- package/src/report/react/RunOverview.tsx +0 -109
- /package/docs-site/zh/{example/tier1-ai-sdk-v7.mdx → examples/integrations/ai-sdk-v7.mdx} +0 -0
- /package/docs-site/zh/{example/tier1-claude-sdk.mdx → examples/integrations/claude-sdk.mdx} +0 -0
- /package/docs-site/zh/{example/tier1-codex-sdk.mdx → examples/integrations/codex-sdk.mdx} +0 -0
- /package/docs-site/zh/{example/tier1-langgraph.mdx → examples/integrations/langgraph.mdx} +0 -0
- /package/docs-site/zh/{example/tier1-pi-sdk.mdx → examples/integrations/pi-sdk.mdx} +0 -0
- /package/docs-site/zh/{guides → how-to}/ci-integration.mdx +0 -0
- /package/docs-site/zh/{guides → how-to}/dataset-fanout.mdx +0 -0
- /package/docs-site/zh/{guides → how-to}/fixtures.mdx +0 -0
- /package/docs-site/zh/{guides → how-to}/reporters.mdx +0 -0
- /package/docs-site/zh/{guides → how-to}/scoring-guide.mdx +0 -0
|
@@ -1,40 +1,25 @@
|
|
|
1
|
-
// niceeval/report/react ——
|
|
2
|
-
// import
|
|
3
|
-
//
|
|
4
|
-
// 不是另一套报告系统 —— 报告的家在官方宿主(--report)。
|
|
1
|
+
// niceeval/report/react —— 纯 web 渲染面的导出点:把某一块指标表嵌进已有 React 页面时
|
|
2
|
+
// 从这里 import。组件只收算好的可序列化 `data`(data 形态),不含任何读盘 / artifact
|
|
3
|
+
// 计算代码;计算函数、spec 形态与组合组件只住在 niceeval/report。
|
|
5
4
|
//
|
|
6
5
|
// 契约:
|
|
7
6
|
// - 组件只认「算好的可序列化数据」:零 hooks、零数据操作;
|
|
8
7
|
// - 样式随包发布:配套 ./styles.css(nre-* 稳定类名),使用者在其后加载覆盖即可;
|
|
8
|
+
// - 渐进增强脚本 ./enhance.js 可选加载,初始静态 HTML 无 JS 完整可读;
|
|
9
9
|
// - 跨块配色一致:维度键 → 稳定散列 → 固定调色板下标(colors.ts)。
|
|
10
10
|
|
|
11
|
-
export {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
Scoreboard,
|
|
24
|
-
} from "../components.tsx";
|
|
25
|
-
export type {
|
|
26
|
-
AttemptListProps,
|
|
27
|
-
DeltaTableProps,
|
|
28
|
-
EvalListProps,
|
|
29
|
-
ExperimentListProps,
|
|
30
|
-
GroupSummaryProps,
|
|
31
|
-
MetricLineProps,
|
|
32
|
-
MetricMatrixProps,
|
|
33
|
-
MetricScatterProps,
|
|
34
|
-
MetricTableProps,
|
|
35
|
-
RunOverviewProps,
|
|
36
|
-
ScoreboardProps,
|
|
37
|
-
} from "../components.tsx";
|
|
11
|
+
export { AttemptList } from "./AttemptList.tsx";
|
|
12
|
+
export { EvalList } from "./EvalList.tsx";
|
|
13
|
+
export { ExperimentList } from "./ExperimentList.tsx";
|
|
14
|
+
export { ScopeSummary } from "./ScopeSummary.tsx";
|
|
15
|
+
export { ExperimentComparisonView as ExperimentComparison } from "./ExperimentComparison.tsx";
|
|
16
|
+
export { MetricTable } from "./MetricTable.tsx";
|
|
17
|
+
export { MetricMatrix } from "./MetricMatrix.tsx";
|
|
18
|
+
export { MetricBars } from "./MetricBars.tsx";
|
|
19
|
+
export { MetricScatter } from "./MetricScatter.tsx";
|
|
20
|
+
export { MetricLine } from "./MetricLine.tsx";
|
|
21
|
+
export { DeltaTable } from "./DeltaTable.tsx";
|
|
22
|
+
export { Scoreboard } from "./Scoreboard.tsx";
|
|
38
23
|
|
|
39
24
|
// 数据契约类型(家在 ../types.ts,「算」与「画」两侧共用同一份)
|
|
40
25
|
export type {
|
|
@@ -42,25 +27,25 @@ export type {
|
|
|
42
27
|
AttemptLocator,
|
|
43
28
|
DeltaData,
|
|
44
29
|
EvalListItem,
|
|
30
|
+
ExperimentComparisonData,
|
|
31
|
+
ExperimentComparisonGroupData,
|
|
45
32
|
ExperimentListEvalRow,
|
|
46
33
|
ExperimentListItem,
|
|
47
|
-
GroupSummaryData,
|
|
48
|
-
LineAxis,
|
|
49
34
|
LineData,
|
|
50
35
|
MatrixData,
|
|
51
36
|
MetricCell,
|
|
52
37
|
MetricColumn,
|
|
53
|
-
OverviewData,
|
|
54
38
|
ScatterData,
|
|
39
|
+
ScopeSummaryData,
|
|
40
|
+
ScopeWarning,
|
|
55
41
|
ScoreboardData,
|
|
56
|
-
SelectionWarning,
|
|
57
42
|
TableData,
|
|
58
|
-
|
|
43
|
+
VerdictTally,
|
|
59
44
|
} from "../types.ts";
|
|
60
45
|
|
|
61
|
-
// locale(官方组件 chrome
|
|
62
|
-
export { DEFAULT_REPORT_LOCALE, resolveMetricLabel } from "../locale.ts";
|
|
63
|
-
export type {
|
|
46
|
+
// locale(官方组件 chrome 文案;LocalizedText 的按 locale 解析也用它)
|
|
47
|
+
export { DEFAULT_REPORT_LOCALE, resolveLocalizedText, resolveMetricLabel } from "../locale.ts";
|
|
48
|
+
export type { LocalizedText, ReportLocale } from "../locale.ts";
|
|
64
49
|
|
|
65
50
|
// 稳定配色(自定义组件想与官方组件同键同色时用;seriesClassForKey 配 CSS 的 --nre-series)
|
|
66
51
|
export { NRE_PALETTE, colorClassForKey, colorHexForKey, colorIndexForKey, seriesClassForKey } from "./colors.ts";
|
|
@@ -16,8 +16,8 @@ import {
|
|
|
16
16
|
MetricMatrix,
|
|
17
17
|
MetricScatter,
|
|
18
18
|
MetricTable,
|
|
19
|
-
RunOverview,
|
|
20
19
|
Scoreboard,
|
|
20
|
+
ScopeSummary,
|
|
21
21
|
} from "./index.tsx";
|
|
22
22
|
import { colorClassForKey, seriesClassForKey } from "./colors.ts";
|
|
23
23
|
import {
|
|
@@ -26,56 +26,53 @@ import {
|
|
|
26
26
|
evalListItems,
|
|
27
27
|
experimentListItems,
|
|
28
28
|
matrixData,
|
|
29
|
-
overviewData,
|
|
30
|
-
overviewWithCost,
|
|
31
29
|
scatterData,
|
|
30
|
+
scopeSummaryData,
|
|
32
31
|
scoreboardData,
|
|
33
32
|
tableData,
|
|
34
|
-
tableDataWithMeta,
|
|
35
33
|
} from "./fixtures.ts";
|
|
36
34
|
|
|
37
35
|
const attemptHref = (locator: AttemptLocator) => `/attempts/${locator}`;
|
|
38
36
|
|
|
39
|
-
describe("
|
|
40
|
-
const html = renderToStaticMarkup(<
|
|
37
|
+
describe("ScopeSummary", () => {
|
|
38
|
+
const html = renderToStaticMarkup(<ScopeSummary data={scopeSummaryData} />);
|
|
41
39
|
|
|
42
|
-
it("KPI
|
|
43
|
-
expect(html).toContain("nre-
|
|
44
|
-
expect(html).toContain("<dd>
|
|
45
|
-
expect(html).toContain("<dd>
|
|
46
|
-
|
|
47
|
-
//
|
|
48
|
-
|
|
49
|
-
expect(html).
|
|
50
|
-
expect(html).toContain("
|
|
51
|
-
expect(html).toContain("
|
|
40
|
+
it("KPI:experiment/eval/attempt 数、成功率与总成本原样渲染(不从计票重算)", () => {
|
|
41
|
+
expect(html).toContain("nre-scope-summary");
|
|
42
|
+
expect(html).toContain("<dd>2</dd>"); // experiments
|
|
43
|
+
expect(html).toContain("<dd>6</dd>"); // evals
|
|
44
|
+
expect(html).toContain("<dd>9</dd>"); // attempts
|
|
45
|
+
// endToEndPassRate.display 原样渲染(两级聚合 60%),不是 eval 计票 3/5 = 60% 巧合之外的重算;
|
|
46
|
+
// attempt 计票 4/9 ≈ 44% 也不该出现
|
|
47
|
+
expect(html).toContain("60%");
|
|
48
|
+
expect(html).not.toContain("44%");
|
|
49
|
+
expect(html).toContain("$1.50");
|
|
52
50
|
});
|
|
53
51
|
|
|
54
|
-
it("
|
|
55
|
-
expect(html).toContain("
|
|
56
|
-
expect(html).
|
|
57
|
-
const
|
|
58
|
-
expect(
|
|
52
|
+
it("votes 默认 eval 级计票;votes='attempt' 切换显示但 data 不变", () => {
|
|
53
|
+
expect(html).toContain("3 passed");
|
|
54
|
+
expect(html).toContain('data-votes="eval"');
|
|
55
|
+
const attempts = renderToStaticMarkup(<ScopeSummary data={scopeSummaryData} votes="attempt" />);
|
|
56
|
+
expect(attempts).toContain("4 passed");
|
|
57
|
+
expect(attempts).toContain('data-votes="attempt"');
|
|
59
58
|
});
|
|
60
59
|
|
|
61
|
-
it("
|
|
62
|
-
expect(html).toContain("2 snapshots");
|
|
63
|
-
expect(html).toContain("compare/bub");
|
|
60
|
+
it("时间窗来自 range,不编造当前时间", () => {
|
|
64
61
|
expect(html).toContain("2026-07-01T10:00:00Z");
|
|
65
|
-
expect(html).toContain("
|
|
66
|
-
expect(html).toContain("nre-warnings");
|
|
62
|
+
expect(html).toContain("2026-07-01T11:30:00Z");
|
|
67
63
|
});
|
|
68
64
|
});
|
|
69
65
|
|
|
70
66
|
describe("MetricTable", () => {
|
|
71
67
|
const html = renderToStaticMarkup(<MetricTable data={tableData} attemptHref={attemptHref} />);
|
|
72
68
|
|
|
73
|
-
it("列头带 label、unit 与 better
|
|
69
|
+
it("列头带 label、unit 与 better 方向,首列是 rowDimension", () => {
|
|
74
70
|
expect(html).toContain("pass rate");
|
|
75
71
|
expect(html).toContain("(%)");
|
|
76
72
|
expect(html).toContain("code lines");
|
|
77
73
|
expect(html).toContain("↑");
|
|
78
74
|
expect(html).toContain("↓");
|
|
75
|
+
expect(html).toContain(">agent</th>");
|
|
79
76
|
});
|
|
80
77
|
|
|
81
78
|
it("数字与覆盖率角标:samples < total 如实标出", () => {
|
|
@@ -90,7 +87,7 @@ describe("MetricTable", () => {
|
|
|
90
87
|
});
|
|
91
88
|
|
|
92
89
|
it("refs + attemptHref 出普通 <a>", () => {
|
|
93
|
-
expect(html).toContain('href="/attempts/@
|
|
90
|
+
expect(html).toContain('href="/attempts/@1a0a0a0a"');
|
|
94
91
|
});
|
|
95
92
|
|
|
96
93
|
it("渐进增强的 data 属性:所有表头 data-nre-sort、格子 data-sort-value(无 JS 时纯属性,内容完整)", () => {
|
|
@@ -100,30 +97,9 @@ describe("MetricTable", () => {
|
|
|
100
97
|
// 缺数据格子的排序值为空串:enhance.js 排序时恒沉底
|
|
101
98
|
expect(html).toContain('data-sort-value=""');
|
|
102
99
|
});
|
|
103
|
-
});
|
|
104
|
-
|
|
105
|
-
describe("MetricTable:meta 榜单 parity 与 filter", () => {
|
|
106
|
-
const html = renderToStaticMarkup(<MetricTable data={tableDataWithMeta} />);
|
|
107
|
-
|
|
108
|
-
it("meta 在场补 Model / Agent 列,列序 experiment、model、agent、指标、verdicts", () => {
|
|
109
|
-
expect(html).toContain(">Model</th>");
|
|
110
|
-
expect(html).toContain(">Agent</th>");
|
|
111
|
-
expect(html).toContain(">Verdicts</th>");
|
|
112
|
-
expect(html.indexOf(">Model</th>")).toBeLessThan(html.indexOf(">Agent</th>"));
|
|
113
|
-
expect(html.indexOf(">Agent</th>")).toBeLessThan(html.indexOf("pass rate"));
|
|
114
|
-
expect(html).toContain("gpt-5.4");
|
|
115
|
-
});
|
|
116
|
-
|
|
117
|
-
it("verdict 计票列:eval 级折叠口径的 pill,零计数不出 pill", () => {
|
|
118
|
-
expect(html).toContain("nre-verdict-pill");
|
|
119
|
-
expect(html).toContain("1 passed");
|
|
120
|
-
expect(html).toContain("1 failed");
|
|
121
|
-
expect(html).toContain("2 passed");
|
|
122
|
-
expect(html).not.toContain("0 errored");
|
|
123
|
-
});
|
|
124
100
|
|
|
125
101
|
it("filter 开:表格前渲染 data-nre-filter 输入框(无 JS 静默无功能),仍无 <script>", () => {
|
|
126
|
-
const filtered = renderToStaticMarkup(<MetricTable data={
|
|
102
|
+
const filtered = renderToStaticMarkup(<MetricTable data={tableData} filter />);
|
|
127
103
|
expect(filtered).toContain("data-nre-filter");
|
|
128
104
|
expect(filtered).toContain('class="nre-filter"');
|
|
129
105
|
expect(filtered.indexOf("nre-filter")).toBeLessThan(filtered.indexOf("<table"));
|
|
@@ -131,11 +107,8 @@ describe("MetricTable:meta 榜单 parity 与 filter", () => {
|
|
|
131
107
|
expect(filtered).not.toContain("<script");
|
|
132
108
|
});
|
|
133
109
|
|
|
134
|
-
it("locale=zh-CN:chrome
|
|
135
|
-
const zh = renderToStaticMarkup(<MetricTable data={
|
|
136
|
-
expect(zh).toContain(">模型</th>");
|
|
137
|
-
expect(zh).toContain(">结果</th>");
|
|
138
|
-
expect(zh).toContain("1 通过");
|
|
110
|
+
it("locale=zh-CN:chrome 文案走字典;display 不本地化", () => {
|
|
111
|
+
const zh = renderToStaticMarkup(<MetricTable data={tableData} filter locale="zh-CN" />);
|
|
139
112
|
expect(zh).toContain('placeholder="筛选行…"');
|
|
140
113
|
expect(zh).toContain("50%"); // display 是 format 产物,不本地化
|
|
141
114
|
});
|
|
@@ -144,16 +117,17 @@ describe("MetricTable:meta 榜单 parity 与 filter", () => {
|
|
|
144
117
|
describe("MetricMatrix", () => {
|
|
145
118
|
const html = renderToStaticMarkup(<MetricMatrix data={matrixData} attemptHref={attemptHref} />);
|
|
146
119
|
|
|
147
|
-
it("caption 标出指标与行列维度", () => {
|
|
120
|
+
it("caption 标出指标与行列维度(rowDimension × columnDimension)", () => {
|
|
148
121
|
expect(html).toContain("pass rate");
|
|
149
122
|
expect(html).toContain("eval × agent");
|
|
150
123
|
});
|
|
151
124
|
|
|
152
|
-
it("格子数字与 refs
|
|
125
|
+
it("格子数字与 refs 下钻链接;稀疏格子空着不补 0", () => {
|
|
153
126
|
expect(html).toContain("100%");
|
|
154
127
|
expect(html).toContain("0%");
|
|
155
|
-
expect(html).toContain('href="/attempts/@
|
|
156
|
-
expect(html).toContain('href="/attempts/@
|
|
128
|
+
expect(html).toContain('href="/attempts/@1b3b3b3b"');
|
|
129
|
+
expect(html).toContain('href="/attempts/@1b7b7b7b"');
|
|
130
|
+
expect(html).toContain("nre-td-empty");
|
|
157
131
|
});
|
|
158
132
|
});
|
|
159
133
|
|
|
@@ -166,19 +140,20 @@ describe("Scoreboard", () => {
|
|
|
166
140
|
expect(html).toContain("/ 100");
|
|
167
141
|
});
|
|
168
142
|
|
|
169
|
-
it("分科小计 earned/possible", () => {
|
|
170
|
-
expect(html).toContain("14/16");
|
|
171
|
-
expect(html).toContain("3/4");
|
|
143
|
+
it("分科小计 display(earned/possible 与同尺度百分比)", () => {
|
|
144
|
+
expect(html).toContain("14/16 (87.5%)");
|
|
145
|
+
expect(html).toContain("3/4 (75%)");
|
|
172
146
|
});
|
|
173
147
|
|
|
174
|
-
it("
|
|
175
|
-
expect(html).toContain("1 eval
|
|
176
|
-
expect(html).toContain("2 evals
|
|
148
|
+
it("notRun 与 unscorable 分开注脚,不合并成一个笼统的缺失数", () => {
|
|
149
|
+
expect(html).toContain("1 eval not run, scored 0");
|
|
150
|
+
expect(html).toContain("2 evals unscorable, scored 0");
|
|
177
151
|
});
|
|
178
152
|
|
|
179
|
-
it("
|
|
153
|
+
it("实际生效的权重表可审计;题集外被忽略的 eval 如实报数", () => {
|
|
180
154
|
expect(html).toContain("algebra/ ×2");
|
|
181
155
|
expect(html).toContain("others ×1");
|
|
156
|
+
expect(html).toContain("1 eval outside the question set ignored");
|
|
182
157
|
});
|
|
183
158
|
});
|
|
184
159
|
|
|
@@ -203,10 +178,37 @@ describe("MetricScatter", () => {
|
|
|
203
178
|
expect(html).toContain("pass rate(%)");
|
|
204
179
|
});
|
|
205
180
|
|
|
206
|
-
it("better
|
|
181
|
+
it("轴方向跟随 better:成本轴(lower)反向,便宜($5)在贵($10)右边;提示恒为「越靠右上越好」", () => {
|
|
207
182
|
expect(cxOf("compare/bub-low")).toBeGreaterThan(cxOf("compare/bub-high"));
|
|
208
|
-
// y 轴
|
|
183
|
+
// y 轴(higher)正向:通过率高(90%)在低(50%)上方(SVG y 向下增长)
|
|
209
184
|
expect(cyOf("compare/bub-high")).toBeLessThan(cyOf("compare/bub-low"));
|
|
185
|
+
expect(html).toContain("better → upper right");
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
it("反向轴的刻度显示真实值:x 刻度从左到右数值递减(值大在左),数字不变", () => {
|
|
189
|
+
// x 轴刻度 <text class="nre-scatter-tick" x="…">$N</text>:抓出 (x, 值) 对,按 x 升序后值应递减。
|
|
190
|
+
const ticks = [...html.matchAll(/nre-scatter-tick" x="([\d.]+)" y="[\d.]+" text-anchor="middle">\$([\d.]+)/g)].map(
|
|
191
|
+
(m) => ({ px: Number(m[1]), value: Number(m[2]) }),
|
|
192
|
+
);
|
|
193
|
+
expect(ticks.length).toBeGreaterThanOrEqual(2);
|
|
194
|
+
const byPx = [...ticks].sort((a, b) => a.px - b.px);
|
|
195
|
+
for (let i = 1; i < byPx.length; i++) {
|
|
196
|
+
expect(byPx[i]!.value).toBeLessThan(byPx[i - 1]!.value);
|
|
197
|
+
}
|
|
198
|
+
});
|
|
199
|
+
|
|
200
|
+
it("任一轴未声明 better:该轴正向渲染且整图无方向提示(组件不猜「更好」朝哪边)", () => {
|
|
201
|
+
const noBetter = renderToStaticMarkup(
|
|
202
|
+
<MetricScatter data={{ ...scatterData, x: { key: "cost", label: "cost", unit: "$" } }} />,
|
|
203
|
+
);
|
|
204
|
+
expect(noBetter).not.toContain("better →");
|
|
205
|
+
// x 正向:便宜($5)回到贵($10)左边。
|
|
206
|
+
const cx = (key: string): number => {
|
|
207
|
+
const m = noBetter.match(new RegExp(`data-key="${key}"[\\s\\S]*?\\bcx="([\\d.]+)"`));
|
|
208
|
+
expect(m, `circle for ${key}`).toBeTruthy();
|
|
209
|
+
return Number(m![1]);
|
|
210
|
+
};
|
|
211
|
+
expect(cx("compare/bub-low")).toBeLessThan(cx("compare/bub-high"));
|
|
210
212
|
});
|
|
211
213
|
|
|
212
214
|
it("同系列点连线,系列色走类名(nre-series-cN,CSS 上色跟随深浅主题),图例列系列名", () => {
|
|
@@ -214,18 +216,33 @@ describe("MetricScatter", () => {
|
|
|
214
216
|
expect(html).toContain(`nre-scatter-line ${seriesClassForKey("bub")}`);
|
|
215
217
|
// 渲染面零内联 hex:深色主题下由 CSS 变量切换
|
|
216
218
|
expect(html).not.toMatch(/#[0-9a-f]{6}/i);
|
|
217
|
-
// 图例:codex 只有 1 个可画点、不出线,但系列名仍在图例里
|
|
218
219
|
expect(html).toContain(">bub</span>");
|
|
219
220
|
expect(html).toContain(">codex</span>");
|
|
220
221
|
});
|
|
221
222
|
|
|
222
|
-
it("niceTicks 网格与每点直接标签(
|
|
223
|
+
it("niceTicks 网格与每点直接标签(末段唯一时缩成末段)", () => {
|
|
223
224
|
expect(html).toContain("nre-scatter-grid");
|
|
224
225
|
expect(html.match(/nre-scatter-tick/g)!.length).toBeGreaterThanOrEqual(6);
|
|
225
226
|
expect(html).toContain(">bub-low</text>");
|
|
226
227
|
expect(html).toContain(">codex-mid</text>");
|
|
227
228
|
});
|
|
228
229
|
|
|
230
|
+
it("末段重名的点使用能区分它们的最短路径后缀", () => {
|
|
231
|
+
const dupes = renderToStaticMarkup(
|
|
232
|
+
<MetricScatter
|
|
233
|
+
data={{
|
|
234
|
+
...scatterData,
|
|
235
|
+
rows: [
|
|
236
|
+
{ ...scatterData.rows[0]!, key: "compare/a/run" },
|
|
237
|
+
{ ...scatterData.rows[1]!, key: "compare/b/run" },
|
|
238
|
+
],
|
|
239
|
+
}}
|
|
240
|
+
/>,
|
|
241
|
+
);
|
|
242
|
+
expect(dupes).toContain(">a/run</text>");
|
|
243
|
+
expect(dupes).toContain(">b/run</text>");
|
|
244
|
+
});
|
|
245
|
+
|
|
229
246
|
it("hover 退化为 <title>:display 与 samples/total", () => {
|
|
230
247
|
expect(html).toContain("<title>");
|
|
231
248
|
expect(html).toContain("50%(6/6)");
|
|
@@ -276,49 +293,57 @@ describe("DeltaTable", () => {
|
|
|
276
293
|
expect(html).toContain(">Δ</span>");
|
|
277
294
|
});
|
|
278
295
|
|
|
279
|
-
it("
|
|
296
|
+
it("涨跌好坏按数据侧算好的 outcome 配色:improved / regressed / unchanged / unavailable", () => {
|
|
280
297
|
expect(html).toContain("nre-delta-good");
|
|
281
298
|
expect(html).toContain("nre-delta-bad");
|
|
282
299
|
expect(html).toContain("nre-delta-flat");
|
|
300
|
+
expect(html).toContain('data-outcome="unavailable"');
|
|
283
301
|
});
|
|
284
302
|
|
|
285
|
-
it("
|
|
303
|
+
it("每行显示作者声明的 pair label 与 A → B 的维度键", () => {
|
|
304
|
+
expect(html).toContain(">bub</span>");
|
|
286
305
|
expect(html).toContain("compare/bub → compare/bub--agents-md");
|
|
287
306
|
});
|
|
288
|
-
});
|
|
289
307
|
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
308
|
+
it("0 对显示明确空态并报告配对域实验数", () => {
|
|
309
|
+
const empty = renderToStaticMarkup(<DeltaTable data={{ ...deltaData, experiments: 3, rows: [] }} />);
|
|
310
|
+
expect(empty).not.toContain("<table");
|
|
311
|
+
expect(empty).toContain("3 experiments, 0 comparable pairs");
|
|
312
|
+
});
|
|
313
|
+
});
|
|
294
314
|
|
|
295
315
|
describe("AttemptList", () => {
|
|
296
|
-
const html = renderToStaticMarkup(<AttemptList
|
|
316
|
+
const html = renderToStaticMarkup(<AttemptList data={attemptListItems} />);
|
|
297
317
|
|
|
298
|
-
it("
|
|
299
|
-
expect(html).toContain("roots-correct");
|
|
300
|
-
expect(html).toContain("
|
|
301
|
-
|
|
302
|
-
expect(html).
|
|
318
|
+
it("显示算好的 failureSummary 与 +N more failures 计数,不重算摘要", () => {
|
|
319
|
+
expect(html).toContain("gate: roots-correct · expected x=2 · received x=3");
|
|
320
|
+
expect(html).toContain("+1 more failure");
|
|
321
|
+
// errored 的一层摘要(phase · code · message)
|
|
322
|
+
expect(html).toContain("eval.run · unexpected-error · TypeError");
|
|
303
323
|
});
|
|
304
324
|
|
|
305
|
-
it("total >
|
|
306
|
-
const html2 = renderToStaticMarkup(<AttemptList
|
|
325
|
+
it("total > data.length 时如实报「还有 n 条没列」", () => {
|
|
326
|
+
const html2 = renderToStaticMarkup(<AttemptList data={attemptListItems} total={attemptListItems.length + 2} />);
|
|
307
327
|
expect(html2).toContain("and 2 more not shown");
|
|
308
|
-
// 不传 total(或 total ===
|
|
328
|
+
// 不传 total(或 total === data.length)不产出截断文案
|
|
309
329
|
expect(html).not.toContain("more not shown");
|
|
310
330
|
});
|
|
311
331
|
|
|
332
|
+
it("costUSD 为 null 时不显示成本,也不伪造 $0", () => {
|
|
333
|
+
expect(html).toContain("$0.12");
|
|
334
|
+
expect(html.match(/nre-attempt-cost/g)).toHaveLength(1); // errored 那条 costUSD: null
|
|
335
|
+
});
|
|
336
|
+
|
|
312
337
|
it("AttemptList 自身不展开断言详情", () => {
|
|
313
338
|
expect(html).not.toContain("<details");
|
|
314
339
|
});
|
|
315
340
|
});
|
|
316
341
|
|
|
317
342
|
describe("EvalList", () => {
|
|
318
|
-
const html = renderToStaticMarkup(<EvalList
|
|
343
|
+
const html = renderToStaticMarkup(<EvalList data={evalListItems} />);
|
|
319
344
|
|
|
320
345
|
it("展开到这道题的 Attempt(与 AttemptList 同一套 AttemptRow 渲染)", () => {
|
|
321
|
-
expect(html).toContain('href="#/attempt/@
|
|
346
|
+
expect(html).toContain('href="#/attempt/@1a4a4a4a"');
|
|
322
347
|
expect(html).toContain("roots-correct");
|
|
323
348
|
});
|
|
324
349
|
|
|
@@ -329,34 +354,45 @@ describe("EvalList", () => {
|
|
|
329
354
|
});
|
|
330
355
|
|
|
331
356
|
describe("ExperimentList", () => {
|
|
332
|
-
const html = renderToStaticMarkup(<ExperimentList
|
|
357
|
+
const html = renderToStaticMarkup(<ExperimentList data={experimentListItems} filter />);
|
|
333
358
|
|
|
334
|
-
it("web 面是带过滤框与八个固定列头的 experiment 比较表", () => {
|
|
359
|
+
it("web 面是带过滤框与八个固定列头的 experiment 比较表(成本列头是 Cost)", () => {
|
|
335
360
|
expect(html).toContain('data-nre-experiment-filter=""');
|
|
336
|
-
for (const header of ["Experiment", "Model", "Agent", "Avg duration", "End-to-end pass rate", "Tokens", "
|
|
361
|
+
for (const header of ["Experiment", "Model", "Agent", "Avg duration", "End-to-end pass rate", "Tokens", "Cost", "Result"]) {
|
|
337
362
|
expect(html).toContain(`>${header}</button>`);
|
|
338
363
|
}
|
|
364
|
+
expect(html).not.toContain("Est. cost");
|
|
339
365
|
expect(html).toContain('data-nre-experiment-sort="4" class="nre-sort-desc"');
|
|
340
366
|
});
|
|
341
367
|
|
|
342
|
-
it("主行:身份、agent/model
|
|
368
|
+
it("主行:身份、agent/model、官方两级聚合指标与 eval 级判定构成", () => {
|
|
343
369
|
expect(html).toContain("compare/bub");
|
|
344
370
|
expect(html).toContain("compare/codex");
|
|
345
371
|
expect(html).toContain("gpt-5.4");
|
|
346
|
-
expect(html).toContain("50%"); //
|
|
372
|
+
expect(html).toContain("50%"); // endToEndPassRate.display
|
|
347
373
|
expect(html).toContain("1 passed / 1 failed");
|
|
348
374
|
expect(html).toContain("memory=true");
|
|
349
375
|
});
|
|
350
376
|
|
|
351
|
-
it("展开到 Eval
|
|
377
|
+
it("展开到 Eval:父行只有折叠判定与题级聚合,失败摘要只在 Attempt 子行", () => {
|
|
352
378
|
expect(html).toContain("algebra/quadratic");
|
|
353
|
-
expect(html).toContain('href="#/attempt/@
|
|
354
|
-
expect(html).toContain('href="#/attempt/@
|
|
379
|
+
expect(html).toContain('href="#/attempt/@1a4a4a4a"');
|
|
380
|
+
expect(html).toContain('href="#/attempt/@1b5b5b5b"');
|
|
355
381
|
expect(html.match(/algebra\/quadratic/g)).toHaveLength(1);
|
|
356
382
|
expect(html).toContain("nre-experiment-eval-header");
|
|
357
|
-
expect(html.match(/nre-experiment-attempt-row/g)).toHaveLength(
|
|
383
|
+
expect(html.match(/nre-experiment-attempt-row/g)).toHaveLength(4);
|
|
358
384
|
expect(html).toContain("├─");
|
|
359
385
|
expect(html).toContain("└─");
|
|
386
|
+
// 主失败摘要只出现在 attempt 子行:两次(同一 eval 的两轮 attempt 各自的摘要),不在父行重复
|
|
387
|
+
expect(html.match(/gate: roots-correct/g)).toHaveLength(2);
|
|
388
|
+
});
|
|
389
|
+
|
|
390
|
+
it("relativeTo 去掉组前缀只显示末段;data-sort-value 仍是完整 id", () => {
|
|
391
|
+
const relative = renderToStaticMarkup(<ExperimentList data={experimentListItems} relativeTo="compare" />);
|
|
392
|
+
expect(relative).toContain(">bub</b>");
|
|
393
|
+
expect(relative).toContain('data-sort-value="compare/bub"');
|
|
394
|
+
// 不传 relativeTo 显示完整 id
|
|
395
|
+
expect(html).toContain(">compare/bub</b>");
|
|
360
396
|
});
|
|
361
397
|
|
|
362
398
|
it("零 JS 靠原生 <details>,无 <script>", () => {
|
|
@@ -371,9 +407,8 @@ describe("跨组件契约", () => {
|
|
|
371
407
|
const table = renderToStaticMarkup(<MetricTable data={tableData} />);
|
|
372
408
|
const matrix = renderToStaticMarkup(<MetricMatrix data={matrixData} />);
|
|
373
409
|
const board = renderToStaticMarkup(<Scoreboard data={scoreboardData} />);
|
|
374
|
-
const
|
|
375
|
-
const
|
|
376
|
-
for (const html of [table, matrix, board, delta, attempts]) {
|
|
410
|
+
const attempts = renderToStaticMarkup(<AttemptList data={attemptListItems} />);
|
|
411
|
+
for (const html of [table, matrix, board, attempts]) {
|
|
377
412
|
expect(html).toContain(cls);
|
|
378
413
|
}
|
|
379
414
|
const scatter = renderToStaticMarkup(<MetricScatter data={scatterData} />);
|
|
@@ -382,15 +417,15 @@ describe("跨组件契约", () => {
|
|
|
382
417
|
|
|
383
418
|
it("静态输出不含 <script>:交互只靠 <a>/<details>/CSS", () => {
|
|
384
419
|
const all = [
|
|
385
|
-
renderToStaticMarkup(<
|
|
420
|
+
renderToStaticMarkup(<ScopeSummary data={scopeSummaryData} />),
|
|
386
421
|
renderToStaticMarkup(<MetricTable data={tableData} attemptHref={attemptHref} />),
|
|
387
422
|
renderToStaticMarkup(<MetricMatrix data={matrixData} attemptHref={attemptHref} />),
|
|
388
423
|
renderToStaticMarkup(<Scoreboard data={scoreboardData} />),
|
|
389
424
|
renderToStaticMarkup(<MetricScatter data={scatterData} />),
|
|
390
425
|
renderToStaticMarkup(<DeltaTable data={deltaData} />),
|
|
391
|
-
renderToStaticMarkup(<AttemptList
|
|
392
|
-
renderToStaticMarkup(<EvalList
|
|
393
|
-
renderToStaticMarkup(<ExperimentList
|
|
426
|
+
renderToStaticMarkup(<AttemptList data={attemptListItems} />),
|
|
427
|
+
renderToStaticMarkup(<EvalList data={evalListItems} />),
|
|
428
|
+
renderToStaticMarkup(<ExperimentList data={experimentListItems} />),
|
|
394
429
|
].join("");
|
|
395
430
|
expect(all).not.toContain("<script");
|
|
396
431
|
});
|