niceeval 0.6.0 → 0.6.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.
- package/dist/agents/types.d.ts +72 -6
- package/dist/context/types.d.ts +32 -12
- package/dist/i18n/en.d.ts +54 -0
- package/dist/i18n/zh-CN.d.ts +55 -1
- package/dist/o11y/types.d.ts +16 -2
- package/dist/report/aggregate.d.ts +5 -3
- package/dist/report/aggregate.js +32 -5
- package/dist/report/built-ins/experiment-comparison.d.ts +39 -0
- package/dist/report/built-ins/experiment-comparison.js +119 -0
- package/dist/report/built-ins/index.d.ts +2 -1
- package/dist/report/built-ins/index.js +2 -2
- package/dist/report/components.d.ts +10 -2
- package/dist/report/components.js +3 -3
- package/dist/report/compute.d.ts +11 -18
- package/dist/report/compute.js +68 -66
- package/dist/report/flag.d.ts +16 -1
- package/dist/report/flag.js +19 -1
- package/dist/report/format.d.ts +16 -14
- package/dist/report/format.js +28 -30
- package/dist/report/index.d.ts +5 -4
- package/dist/report/index.js +6 -5
- package/dist/report/locale.d.ts +23 -3
- package/dist/report/locale.js +47 -6
- package/dist/report/metrics.d.ts +13 -1
- package/dist/report/metrics.js +66 -15
- package/dist/report/primitives.d.ts +6 -0
- package/dist/report/react/AttemptList.d.ts +4 -4
- package/dist/report/react/AttemptList.js +8 -10
- package/dist/report/react/EvalList.d.ts +1 -1
- package/dist/report/react/EvalList.js +0 -0
- package/dist/report/react/ExperimentComparison.d.ts +8 -0
- package/dist/report/react/ExperimentComparison.js +11 -0
- package/dist/report/react/ExperimentList.d.ts +4 -2
- package/dist/report/react/ExperimentList.js +57 -7
- package/dist/report/react/MetricScatter.js +6 -16
- package/dist/report/react/chart-math.d.ts +23 -6
- package/dist/report/react/chart-math.js +71 -19
- package/dist/report/react/fixtures.d.ts +3 -3
- package/dist/report/react/fixtures.js +30 -18
- package/dist/report/react/format.d.ts +1 -1
- package/dist/report/react/format.js +1 -1
- package/dist/report/react/index.d.ts +1 -1
- package/dist/report/report.d.ts +5 -1
- package/dist/report/report.js +6 -2
- package/dist/report/text/faces.d.ts +1 -1
- package/dist/report/text/faces.js +100 -61
- package/dist/report/text/table.js +36 -5
- package/dist/report/types.d.ts +40 -34
- package/dist/results/types.d.ts +11 -0
- package/dist/runner/feedback/sink.d.ts +110 -0
- package/dist/runner/types.d.ts +513 -22
- package/dist/sandbox/docker.d.ts +23 -2
- package/dist/sandbox/e2b.d.ts +15 -1
- package/dist/sandbox/errors.d.ts +30 -3
- package/dist/sandbox/io-retry.d.ts +17 -0
- package/dist/sandbox/registry.d.ts +2 -0
- package/dist/sandbox/resolve.d.ts +18 -5
- package/dist/sandbox/retry.d.ts +11 -1
- package/dist/sandbox/types.d.ts +39 -5
- package/dist/sandbox/vercel.d.ts +7 -1
- package/dist/scoring/coverage.d.ts +30 -0
- package/dist/scoring/display.d.ts +21 -0
- package/dist/scoring/display.js +120 -0
- package/dist/scoring/types.d.ts +103 -20
- package/dist/shared/aggregate.d.ts +1 -0
- package/dist/shared/aggregate.js +3 -3
- package/dist/shared/types.d.ts +28 -0
- package/dist/tty-line.d.ts +0 -4
- package/dist/util.d.ts +23 -0
- package/docs-site/zh/concepts/adapter.mdx +24 -6
- package/docs-site/zh/concepts/assert.mdx +11 -10
- package/docs-site/zh/concepts/evals.mdx +7 -6
- package/docs-site/zh/concepts/experiment.mdx +1 -1
- package/docs-site/zh/concepts/overview.mdx +7 -7
- package/docs-site/zh/guides/agent-feedback-loop.mdx +35 -31
- package/docs-site/zh/guides/authoring.mdx +33 -0
- package/docs-site/zh/guides/ci-integration.mdx +23 -12
- package/docs-site/zh/guides/connect-your-agent.mdx +29 -3
- package/docs-site/zh/guides/custom-reports.mdx +29 -34
- package/docs-site/zh/guides/dataset-fanout.mdx +25 -3
- package/docs-site/zh/guides/debug-sandbox.mdx +57 -0
- package/docs-site/zh/guides/debugging.mdx +210 -0
- package/docs-site/zh/guides/experiments.mdx +10 -3
- package/docs-site/zh/guides/fixtures.mdx +3 -1
- package/docs-site/zh/guides/official-adapters.mdx +27 -3
- package/docs-site/zh/guides/publish-report.mdx +30 -16
- package/docs-site/zh/guides/report-components.mdx +49 -37
- package/docs-site/zh/guides/reporters.mdx +2 -2
- package/docs-site/zh/guides/results-data.mdx +42 -8
- package/docs-site/zh/guides/runner.mdx +17 -7
- package/docs-site/zh/guides/sandbox-agent.mdx +57 -7
- package/docs-site/zh/guides/sandbox-providers.mdx +258 -10
- package/docs-site/zh/guides/scoring-guide.mdx +4 -4
- package/docs-site/zh/guides/viewing-results.mdx +85 -41
- package/docs-site/zh/guides/write-experiment.mdx +5 -3
- package/docs-site/zh/guides/write-send.mdx +19 -2
- package/docs-site/zh/index.mdx +1 -1
- package/docs-site/zh/reference/builtin-agents.mdx +27 -0
- package/docs-site/zh/reference/capabilities.mdx +2 -2
- package/docs-site/zh/reference/cli.mdx +35 -9
- package/docs-site/zh/reference/define-agent.mdx +60 -5
- package/docs-site/zh/reference/define-config.mdx +1 -1
- package/docs-site/zh/reference/define-eval.mdx +42 -9
- package/docs-site/zh/reference/events.mdx +2 -2
- package/docs-site/zh/reference/expect.mdx +36 -6
- package/package.json +5 -1
- package/src/agents/ai-sdk-otel.test.ts +1 -0
- package/src/agents/ai-sdk.test.ts +3 -0
- package/src/agents/ai-sdk.ts +3 -0
- package/src/agents/bub-install-spec.test.ts +34 -0
- package/src/agents/bub-install-spec.ts +32 -0
- package/src/agents/bub.ts +31 -32
- package/src/agents/claude-code.test.ts +130 -9
- package/src/agents/claude-code.ts +76 -4
- package/src/agents/codex.test.ts +189 -40
- package/src/agents/codex.ts +155 -14
- package/src/agents/coding-cli-versions.test.ts +15 -0
- package/src/agents/coding-cli-versions.ts +3 -0
- package/src/agents/index.ts +11 -0
- package/src/agents/langgraph.test.ts +204 -0
- package/src/agents/langgraph.ts +495 -0
- package/src/agents/marketplace.ts +85 -0
- package/src/agents/native-config.test.ts +179 -0
- package/src/agents/native-config.ts +267 -0
- package/src/agents/openai-compat.test.ts +1 -0
- package/src/agents/openclaw.test.ts +31 -0
- package/src/agents/openclaw.ts +171 -0
- package/src/agents/plugin-config.test.ts +1 -0
- package/src/agents/sdk-streams.test.ts +79 -0
- package/src/agents/sdk-streams.ts +55 -10
- package/src/agents/skills.test.ts +1 -0
- package/src/agents/streaming.test.ts +3 -9
- package/src/agents/types.ts +73 -6
- package/src/agents/ui-message-stream.test.ts +3 -0
- package/src/cli.ts +411 -108
- package/src/context/context.test.ts +51 -12
- package/src/context/context.ts +161 -29
- package/src/context/session.test.ts +1 -0
- package/src/context/session.ts +114 -6
- package/src/context/types.ts +30 -12
- package/src/define.test.ts +13 -8
- package/src/define.ts +25 -4
- package/src/expect/index.ts +53 -23
- package/src/i18n/en.ts +65 -4
- package/src/i18n/zh-CN.ts +66 -4
- package/src/o11y/cost.test.ts +1 -0
- package/src/o11y/execution-tree.test.ts +1 -20
- package/src/o11y/otlp/mappers/claude-code.test.ts +1 -0
- package/src/o11y/otlp/parse.test.ts +1 -0
- package/src/o11y/otlp/turn-otel.test.ts +1 -0
- package/src/o11y/parsers/bub.test.ts +1 -0
- package/src/o11y/parsers/claude-code.test.ts +1 -34
- package/src/o11y/parsers/openclaw.test.ts +154 -0
- package/src/o11y/parsers/openclaw.ts +310 -0
- package/src/o11y/prices.json +746 -311
- package/src/o11y/tool-names.test.ts +1 -0
- package/src/o11y/types.ts +16 -2
- package/src/report/aggregate.ts +34 -5
- package/src/report/built-in-user-parity.test.tsx +127 -173
- package/src/report/built-ins/experiment-comparison.tsx +179 -0
- package/src/report/built-ins/index.ts +7 -2
- package/src/report/components.tsx +11 -3
- package/src/report/compute.ts +80 -74
- package/src/report/dual-render.test.tsx +222 -91
- package/src/report/flag.ts +30 -2
- package/src/report/format.ts +36 -27
- package/src/report/index.ts +23 -6
- package/src/report/locale.ts +49 -6
- package/src/report/metrics.ts +68 -15
- package/src/report/primitives.tsx +6 -0
- package/src/report/react/AttemptList.tsx +9 -36
- package/src/report/react/EvalList.tsx +0 -0
- package/src/report/react/ExperimentComparison.tsx +68 -0
- package/src/report/react/ExperimentList.tsx +173 -55
- package/src/report/react/MetricScatter.tsx +13 -25
- package/src/report/react/chart-math.test.ts +85 -0
- package/src/report/react/chart-math.ts +101 -22
- package/src/report/react/enhance.js +72 -1
- package/src/report/react/fixtures.ts +34 -21
- package/src/report/react/format.ts +1 -1
- package/src/report/react/index.tsx +0 -1
- package/src/report/react/render.test.tsx +30 -69
- package/src/report/react/styles.css +112 -14
- package/src/report/report.test.ts +308 -105
- package/src/report/report.ts +6 -2
- package/src/report/text/faces.ts +111 -67
- package/src/report/text/table.ts +42 -5
- package/src/report/types.ts +42 -34
- package/src/results/annotated-source.test.ts +62 -9
- package/src/results/annotated-source.ts +64 -6
- package/src/results/attempt-evidence.test.ts +9 -7
- package/src/results/attempt-evidence.ts +15 -8
- package/src/results/attempt-source.ts +6 -3
- package/src/results/copy.ts +145 -55
- package/src/results/host-equivalence.test.ts +11 -9
- package/src/results/index.ts +2 -0
- package/src/results/locator.test.ts +1 -22
- package/src/results/open.ts +7 -1
- package/src/results/publish.ts +149 -0
- package/src/results/results.test.ts +85 -51
- package/src/results/truncate.ts +90 -0
- package/src/results/types.ts +7 -0
- package/src/results/writer.ts +31 -13
- package/src/runner/attempt.test.ts +138 -7
- package/src/runner/attempt.ts +603 -104
- package/src/runner/discover.test.ts +47 -0
- package/src/runner/discover.ts +36 -2
- package/src/runner/eval-source.test.ts +1 -27
- package/src/runner/feedback/agent.test.ts +504 -0
- package/src/runner/feedback/agent.ts +409 -0
- package/src/runner/feedback/ci.test.ts +562 -0
- package/src/runner/feedback/ci.ts +401 -0
- package/src/runner/feedback/coordinator.test.ts +317 -0
- package/src/runner/feedback/coordinator.ts +397 -0
- package/src/runner/feedback/failure.ts +40 -0
- package/src/runner/feedback/human.test.ts +616 -0
- package/src/runner/feedback/human.ts +535 -0
- package/src/runner/feedback/index.ts +66 -0
- package/src/runner/feedback/io.ts +78 -0
- package/src/runner/feedback/profile.test.ts +50 -0
- package/src/runner/feedback/profile.ts +58 -0
- package/src/runner/feedback/reducer.test.ts +395 -0
- package/src/runner/feedback/reducer.ts +260 -0
- package/src/runner/feedback/renderer.ts +82 -0
- package/src/runner/feedback/sink.ts +203 -0
- package/src/runner/feedback/testing.ts +106 -0
- package/src/runner/ledger.test.ts +230 -0
- package/src/runner/ledger.ts +329 -0
- package/src/runner/report.test.ts +128 -3
- package/src/runner/report.ts +33 -9
- package/src/runner/reporters/artifacts.ts +8 -2
- package/src/runner/reporters/braintrust.test.ts +8 -7
- package/src/runner/reporters/braintrust.ts +9 -2
- package/src/runner/reporters/index.ts +2 -2
- package/src/runner/reporters/json.test.ts +162 -0
- package/src/runner/reporters/json.ts +35 -8
- package/src/runner/reporters/shared.ts +1 -5
- package/src/runner/run.test.ts +760 -3
- package/src/runner/run.ts +242 -36
- package/src/runner/sandbox-prep.ts +3 -42
- package/src/runner/timing.ts +158 -0
- package/src/runner/types.ts +518 -22
- package/src/sandbox/checkpoint.test.ts +55 -0
- package/src/sandbox/checkpoint.ts +29 -8
- package/src/sandbox/cli-commands.ts +407 -0
- package/src/sandbox/docker.ts +115 -16
- package/src/sandbox/e2b-agent-template.test.ts +56 -0
- package/src/sandbox/e2b-agent-template.ts +94 -0
- package/src/sandbox/e2b.ts +74 -9
- package/src/sandbox/errors.ts +111 -4
- package/src/sandbox/index.ts +2 -0
- package/src/sandbox/io-retry.test.ts +58 -0
- package/src/sandbox/io-retry.ts +45 -0
- package/src/sandbox/keep-registry.test.ts +86 -0
- package/src/sandbox/keep-registry.ts +142 -0
- package/src/sandbox/keep.ts +178 -0
- package/src/sandbox/paths.test.ts +1 -0
- package/src/sandbox/paths.ts +19 -8
- package/src/sandbox/registry.ts +20 -3
- package/src/sandbox/resolve.ts +76 -11
- package/src/sandbox/retry.test.ts +70 -0
- package/src/sandbox/retry.ts +46 -4
- package/src/sandbox/types.ts +44 -6
- package/src/sandbox/vercel.ts +43 -20
- package/src/scoring/collector.ts +60 -17
- package/src/scoring/coverage.ts +95 -0
- package/src/scoring/diff.ts +81 -0
- package/src/scoring/display.test.ts +121 -0
- package/src/scoring/display.ts +133 -0
- package/src/scoring/evidence.test.ts +189 -0
- package/src/scoring/judge.test.ts +142 -0
- package/src/scoring/judge.ts +15 -18
- package/src/scoring/scoped.ts +217 -50
- package/src/scoring/types.ts +117 -20
- package/src/scoring/verdict.ts +16 -4
- package/src/shared/aggregate.ts +3 -2
- package/src/shared/types.ts +31 -0
- package/src/show/compose.ts +2 -2
- package/src/show/index.ts +29 -16
- package/src/show/render.ts +626 -308
- package/src/show/show.test.ts +251 -36
- package/src/tty-line.ts +8 -26
- package/src/util.test.ts +1 -0
- package/src/util.ts +41 -0
- package/src/view/app/components/AttemptModal.tsx +153 -2
- package/src/view/app/components/CodeView.tsx +32 -11
- package/src/view/app/components/CopyControls.tsx +2 -2
- package/src/view/app/i18n.ts +6 -0
- package/src/view/app/lib/attempt-route.test.ts +1 -0
- package/src/view/app/lib/verdict.ts +7 -9
- package/src/view/artifact-serving.test.ts +2 -1
- package/src/view/client-dist/app.css +1 -1
- package/src/view/client-dist/app.js +17 -17
- package/src/view/data.test.ts +2 -1
- package/src/view/data.ts +17 -7
- package/src/view/index.ts +12 -1
- package/src/view/server.ts +2 -0
- package/src/view/shared/types.ts +1 -1
- package/src/view/styles.css +3 -0
- package/src/view/view-report.test.ts +11 -10
- package/dist/o11y/execution-tree.d.ts +0 -103
- package/dist/o11y/otlp/select.d.ts +0 -22
- package/dist/report/built-ins/cost-pass-rate-comparison.d.ts +0 -1
- package/dist/report/built-ins/cost-pass-rate-comparison.js +0 -17
- package/dist/results/annotated-source.d.ts +0 -61
- package/dist/results/attempt-evidence.d.ts +0 -69
- package/dist/results/attempt-source.d.ts +0 -15
- package/src/report/built-ins/cost-pass-rate-comparison.tsx +0 -23
- package/src/runner/reporters/console.ts +0 -70
- package/src/runner/reporters/live.test.ts +0 -56
- package/src/runner/reporters/live.ts +0 -247
- package/src/runner/reporters/quiet.test.ts +0 -66
- package/src/runner/reporters/quiet.ts +0 -49
- package/src/runner/reporters/table.ts +0 -277
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// niceeval 报告的渐进增强 runtime:纯 vanilla JS、零依赖、IIFE、幂等。
|
|
2
|
-
// 只作用于 .nre DOM 与 data-nre-*
|
|
2
|
+
// 只作用于 .nre DOM 与 data-nre-* 属性;四个行为——实验组切换、表格排序、行过滤、SVG 点 tooltip。
|
|
3
3
|
// 静态 HTML 无 JS 时内容完整可读是硬约束:排序有数据侧预排、tooltip 退化为原生
|
|
4
4
|
// <title>、过滤输入框静默无功能。全部经 document 级事件委托绑定,重复注入本文件
|
|
5
5
|
// 只在首次生效(window.__nreEnhanced 守卫),DOM 被搬动(如 view 把 <template> 内容
|
|
@@ -14,6 +14,38 @@
|
|
|
14
14
|
return target && target.closest ? target.closest(selector) : null;
|
|
15
15
|
}
|
|
16
16
|
|
|
17
|
+
// ───────────────────────── 实验组:[data-nre-experiment-group-select] ─────────────────────────
|
|
18
|
+
// 数据侧已经把每组的摘要、散点和列表分别算好;这里仅在同一报告节点内切换 <details>,
|
|
19
|
+
// 不重新请求、不重算,也不触碰 Runs / Traces / Attempt 证据室。
|
|
20
|
+
|
|
21
|
+
function selectExperimentGroup(control) {
|
|
22
|
+
var root = control.closest("[data-nre-experiment-groups]");
|
|
23
|
+
if (!root) return;
|
|
24
|
+
var selected = control.getAttribute("data-nre-experiment-group-select");
|
|
25
|
+
var controls = root.querySelectorAll("[data-nre-experiment-group-select]");
|
|
26
|
+
var panels = root.querySelectorAll("[data-nre-experiment-group-panel]");
|
|
27
|
+
for (var i = 0; i < controls.length; i++) {
|
|
28
|
+
var active = controls[i].getAttribute("data-nre-experiment-group-select") === selected;
|
|
29
|
+
controls[i].setAttribute("aria-selected", active ? "true" : "false");
|
|
30
|
+
controls[i].tabIndex = active ? 0 : -1;
|
|
31
|
+
}
|
|
32
|
+
for (var j = 0; j < panels.length; j++) {
|
|
33
|
+
panels[j].open = panels[j].getAttribute("data-nre-experiment-group-panel") === selected;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
document.addEventListener("click", function (e) {
|
|
38
|
+
var control = closest(e.target, "[data-nre-experiment-group-select]");
|
|
39
|
+
if (control) selectExperimentGroup(control);
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
document.addEventListener("keydown", function (e) {
|
|
43
|
+
var control = closest(e.target, "[data-nre-experiment-group-select]");
|
|
44
|
+
if (!control || (e.key !== "Enter" && e.key !== " ")) return;
|
|
45
|
+
e.preventDefault();
|
|
46
|
+
selectExperimentGroup(control);
|
|
47
|
+
});
|
|
48
|
+
|
|
17
49
|
// ───────────────────────── 排序:th[data-nre-sort] ─────────────────────────
|
|
18
50
|
// 点击按该列排序 tbody 行(td/th 的 data-sort-value,数值优先、退回字符串;
|
|
19
51
|
// 空值恒沉底),再点反向;方向指示由 th 上的 nre-sort-asc / nre-sort-desc 类驱动。
|
|
@@ -73,6 +105,45 @@
|
|
|
73
105
|
}
|
|
74
106
|
});
|
|
75
107
|
|
|
108
|
+
// ExperimentList 的 web 面以原生 details 表达「八列主行 + 展开明细」,不是 table/tbody。
|
|
109
|
+
// 单独按 summary 的列排序、按整条 details 文本过滤;无 JS 时保持数据侧成功率降序。
|
|
110
|
+
document.addEventListener("click", function (e) {
|
|
111
|
+
var control = closest(e.target, "[data-nre-experiment-sort]");
|
|
112
|
+
if (!control) return;
|
|
113
|
+
var board = control.closest(".nre-experiment-table");
|
|
114
|
+
if (!board) return;
|
|
115
|
+
var index = Number(control.getAttribute("data-nre-experiment-sort"));
|
|
116
|
+
var dir = control.classList.contains("nre-sort-asc") ? "desc" : "asc";
|
|
117
|
+
var controls = board.querySelectorAll("[data-nre-experiment-sort]");
|
|
118
|
+
for (var i = 0; i < controls.length; i++) controls[i].classList.remove("nre-sort-asc", "nre-sort-desc");
|
|
119
|
+
control.classList.add(dir === "asc" ? "nre-sort-asc" : "nre-sort-desc");
|
|
120
|
+
var entries = Array.prototype.slice.call(board.querySelectorAll(":scope > .nre-experiment-entry"));
|
|
121
|
+
entries.sort(function (a, b) {
|
|
122
|
+
var ac = a.querySelector(".nre-experiment-summary").children[index];
|
|
123
|
+
var bc = b.querySelector(".nre-experiment-summary").children[index];
|
|
124
|
+
var av = ac ? ac.getAttribute("data-sort-value") || ac.textContent.trim() : "";
|
|
125
|
+
var bv = bc ? bc.getAttribute("data-sort-value") || bc.textContent.trim() : "";
|
|
126
|
+
if (av === "" && bv === "") return 0;
|
|
127
|
+
if (av === "") return 1;
|
|
128
|
+
if (bv === "") return -1;
|
|
129
|
+
var an = Number(av), bn = Number(bv);
|
|
130
|
+
var out = !isNaN(an) && !isNaN(bn) ? an - bn : String(av).localeCompare(String(bv));
|
|
131
|
+
return dir === "asc" ? out : -out;
|
|
132
|
+
});
|
|
133
|
+
for (var j = 0; j < entries.length; j++) board.appendChild(entries[j]);
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
document.addEventListener("input", function (e) {
|
|
137
|
+
var input = closest(e.target, "input[data-nre-experiment-filter]");
|
|
138
|
+
if (!input) return;
|
|
139
|
+
var scope = input.parentElement;
|
|
140
|
+
var entries = scope ? scope.querySelectorAll(".nre-experiment-entry") : [];
|
|
141
|
+
var query = input.value.trim().toLowerCase();
|
|
142
|
+
for (var i = 0; i < entries.length; i++) {
|
|
143
|
+
entries[i].classList.toggle("nre-row-hidden", query !== "" && entries[i].textContent.toLowerCase().indexOf(query) === -1);
|
|
144
|
+
}
|
|
145
|
+
});
|
|
146
|
+
|
|
76
147
|
// ───────────────────────── tooltip:.nre-scatter-point / .nre-line-point ─────────────────────────
|
|
77
148
|
// 首次 hover 时把点内 <title> 的内容搬进 data-nre-title(避免与原生 tooltip 重影),
|
|
78
149
|
// 渲染样式化 tooltip div(定位在点上方,挂在所属 figure 里)。无 JS 时 <title> 原样生效。
|
|
@@ -21,7 +21,7 @@ import type { AttemptLocator } from "../../results/locator.ts";
|
|
|
21
21
|
|
|
22
22
|
const locator = (s: string): AttemptLocator => s as AttemptLocator;
|
|
23
23
|
|
|
24
|
-
export const passRateColumn: MetricColumn = { key: "pass-rate", label: "pass rate", unit: "%", better: "higher" };
|
|
24
|
+
export const passRateColumn: MetricColumn = { key: "task-pass-rate", label: "pass rate", unit: "%", better: "higher" };
|
|
25
25
|
export const codeLinesColumn: MetricColumn = { key: "code-lines", label: "code lines", unit: "lines", better: "lower" };
|
|
26
26
|
export const costColumn: MetricColumn = { key: "cost", label: "cost", unit: "$", better: "lower" };
|
|
27
27
|
|
|
@@ -73,7 +73,7 @@ export const groupSummaryData: GroupSummaryData = {
|
|
|
73
73
|
lastRunAt: "2026-07-01T11:30:00Z",
|
|
74
74
|
};
|
|
75
75
|
|
|
76
|
-
export const tableData: TableData<"pass-rate" | "code-lines"> = {
|
|
76
|
+
export const tableData: TableData<"task-pass-rate" | "code-lines"> = {
|
|
77
77
|
dimension: "agent",
|
|
78
78
|
// 行顺序故意不按 passRate 排:组件必须按传入顺序渲染,不重排
|
|
79
79
|
columns: [passRateColumn, codeLinesColumn],
|
|
@@ -81,7 +81,7 @@ export const tableData: TableData<"pass-rate" | "code-lines"> = {
|
|
|
81
81
|
{
|
|
82
82
|
key: "codex",
|
|
83
83
|
cells: {
|
|
84
|
-
"pass-rate": { value: 0.5, display: "50%", samples: 6, total: 6, refs: [] },
|
|
84
|
+
"task-pass-rate": { value: 0.5, display: "50%", samples: 6, total: 6, refs: [] },
|
|
85
85
|
// 全 null:一个有效样本都没有 → 缺数据文案,绝不画 0
|
|
86
86
|
"code-lines": { value: null, display: "—", samples: 0, total: 6, refs: [] },
|
|
87
87
|
},
|
|
@@ -89,7 +89,7 @@ export const tableData: TableData<"pass-rate" | "code-lines"> = {
|
|
|
89
89
|
{
|
|
90
90
|
key: "bub",
|
|
91
91
|
cells: {
|
|
92
|
-
"pass-rate": {
|
|
92
|
+
"task-pass-rate": {
|
|
93
93
|
value: 0.87,
|
|
94
94
|
display: "87%",
|
|
95
95
|
samples: 6,
|
|
@@ -104,13 +104,13 @@ export const tableData: TableData<"pass-rate" | "code-lines"> = {
|
|
|
104
104
|
};
|
|
105
105
|
|
|
106
106
|
/** rows: "experiment" 的榜单形态:行携带 agent/model 元信息与 eval 级折叠计票。 */
|
|
107
|
-
export const tableDataWithMeta: TableData<"pass-rate"> = {
|
|
107
|
+
export const tableDataWithMeta: TableData<"task-pass-rate"> = {
|
|
108
108
|
dimension: "experiment",
|
|
109
109
|
columns: [passRateColumn],
|
|
110
110
|
rows: [
|
|
111
111
|
{
|
|
112
112
|
key: "compare/bub",
|
|
113
|
-
cells: { "pass-rate": { value: 0.5, display: "50%", samples: 2, total: 2, refs: [] } },
|
|
113
|
+
cells: { "task-pass-rate": { value: 0.5, display: "50%", samples: 2, total: 2, refs: [] } },
|
|
114
114
|
meta: {
|
|
115
115
|
agent: "bub",
|
|
116
116
|
model: "gpt-5.4",
|
|
@@ -119,7 +119,7 @@ export const tableDataWithMeta: TableData<"pass-rate"> = {
|
|
|
119
119
|
},
|
|
120
120
|
{
|
|
121
121
|
key: "compare/codex",
|
|
122
|
-
cells: { "pass-rate": { value: 1, display: "100%", samples: 2, total: 2, refs: [] } },
|
|
122
|
+
cells: { "task-pass-rate": { value: 1, display: "100%", samples: 2, total: 2, refs: [] } },
|
|
123
123
|
meta: {
|
|
124
124
|
agent: "codex",
|
|
125
125
|
verdicts: { passed: 2, failed: 0, errored: 0, skipped: 0 },
|
|
@@ -261,7 +261,7 @@ export const lineData: LineData = {
|
|
|
261
261
|
],
|
|
262
262
|
};
|
|
263
263
|
|
|
264
|
-
export const deltaData: DeltaData<"pass-rate" | "cost"> = {
|
|
264
|
+
export const deltaData: DeltaData<"task-pass-rate" | "cost"> = {
|
|
265
265
|
columns: [passRateColumn, costColumn],
|
|
266
266
|
rows: [
|
|
267
267
|
{
|
|
@@ -270,7 +270,7 @@ export const deltaData: DeltaData<"pass-rate" | "cost"> = {
|
|
|
270
270
|
b: { experimentId: "compare/bub--agents-md" },
|
|
271
271
|
cells: {
|
|
272
272
|
// 通过率 +12pp:better higher → 好(绿)
|
|
273
|
-
"pass-rate": {
|
|
273
|
+
"task-pass-rate": {
|
|
274
274
|
a: { value: 0.5, display: "50%", samples: 6, total: 6, refs: [] },
|
|
275
275
|
b: { value: 0.62, display: "62%", samples: 6, total: 6, refs: [] },
|
|
276
276
|
delta: 0.12,
|
|
@@ -290,7 +290,7 @@ export const deltaData: DeltaData<"pass-rate" | "cost"> = {
|
|
|
290
290
|
a: { experimentId: "compare/codex" },
|
|
291
291
|
b: { experimentId: "compare/codex--agents-md" },
|
|
292
292
|
cells: {
|
|
293
|
-
"pass-rate": {
|
|
293
|
+
"task-pass-rate": {
|
|
294
294
|
a: { value: 0.4, display: "40%", samples: 6, total: 6, refs: [] },
|
|
295
295
|
b: { value: 0.4, display: "40%", samples: 6, total: 6, refs: [] },
|
|
296
296
|
delta: 0,
|
|
@@ -322,15 +322,15 @@ const failedAttempt: AttemptListItem = {
|
|
|
322
322
|
name: "roots-correct",
|
|
323
323
|
severity: "gate",
|
|
324
324
|
score: 0,
|
|
325
|
-
|
|
326
|
-
|
|
325
|
+
outcome: "failed" as const,
|
|
326
|
+
expected: "x=2",
|
|
327
|
+
received: "x=3",
|
|
327
328
|
evidence: "judge: sign flipped when substituting into the quadratic formula",
|
|
328
329
|
},
|
|
329
330
|
],
|
|
330
331
|
durationMs: 32_000,
|
|
331
332
|
costUSD: 0.12,
|
|
332
333
|
locator: locator("@1a4a4a4"),
|
|
333
|
-
capabilities: { eval: true, execution: true, timing: true, diff: false },
|
|
334
334
|
};
|
|
335
335
|
|
|
336
336
|
const erroredAttempt: AttemptListItem = {
|
|
@@ -339,11 +339,27 @@ const erroredAttempt: AttemptListItem = {
|
|
|
339
339
|
attempt: 0,
|
|
340
340
|
agent: "codex",
|
|
341
341
|
verdict: "errored",
|
|
342
|
-
|
|
342
|
+
// 结构化 error:列表只渲染 message 一层摘要;cause/stack 与 diagnostics 是下钻详情,随数据携带
|
|
343
|
+
error: {
|
|
344
|
+
code: "unexpected-error",
|
|
345
|
+
message: "TypeError: cannot read properties of undefined (reading 'foo')",
|
|
346
|
+
phase: "eval.run",
|
|
347
|
+
stack: "TypeError: cannot read properties of undefined (reading 'foo')\n at run (adapter.ts:42:7)",
|
|
348
|
+
cause: { name: "TypeError", message: "cannot read properties of undefined (reading 'foo')" },
|
|
349
|
+
},
|
|
350
|
+
diagnostics: [
|
|
351
|
+
{ code: "sandbox-teardown-failed", level: "warning", message: "sandbox teardown timed out", phase: "sandbox.teardown" },
|
|
352
|
+
],
|
|
343
353
|
assertions: [],
|
|
344
354
|
durationMs: 4_500,
|
|
345
355
|
locator: locator("@1c1c1c1"),
|
|
346
|
-
|
|
356
|
+
};
|
|
357
|
+
|
|
358
|
+
const failedRetryAttempt: AttemptListItem = {
|
|
359
|
+
...failedAttempt,
|
|
360
|
+
attempt: 4,
|
|
361
|
+
durationMs: 35_000,
|
|
362
|
+
locator: locator("@1b5b5b5"),
|
|
347
363
|
};
|
|
348
364
|
|
|
349
365
|
export const attemptListItems: AttemptListItem[] = [failedAttempt, erroredAttempt];
|
|
@@ -353,7 +369,6 @@ export const evalListItems: EvalListItem[] = [
|
|
|
353
369
|
evalId: "algebra/quadratic",
|
|
354
370
|
experimentId: "compare/bub",
|
|
355
371
|
verdict: "failed",
|
|
356
|
-
reason: "roots-correct: expected x=2, got x=3",
|
|
357
372
|
score: { value: 0, display: "0%", samples: 1, total: 1, refs: [failedAttempt.locator] },
|
|
358
373
|
duration: { value: 32_000, display: "32.0s", samples: 1, total: 1, refs: [failedAttempt.locator] },
|
|
359
374
|
cost: { value: 0.12, display: "$0.12", samples: 1, total: 1, refs: [failedAttempt.locator] },
|
|
@@ -363,7 +378,6 @@ export const evalListItems: EvalListItem[] = [
|
|
|
363
378
|
evalId: "geometry/angles",
|
|
364
379
|
experimentId: "compare/codex",
|
|
365
380
|
verdict: "errored",
|
|
366
|
-
reason: erroredAttempt.error,
|
|
367
381
|
score: { value: 0, display: "0%", samples: 1, total: 1, refs: [erroredAttempt.locator] },
|
|
368
382
|
duration: { value: 4_500, display: "4.5s", samples: 1, total: 1, refs: [erroredAttempt.locator] },
|
|
369
383
|
cost: { value: null, display: "—", samples: 0, total: 1, refs: [] },
|
|
@@ -376,22 +390,22 @@ export const experimentListItems: ExperimentListItem[] = [
|
|
|
376
390
|
experimentId: "compare/bub",
|
|
377
391
|
agent: "bub",
|
|
378
392
|
model: "gpt-5.4",
|
|
393
|
+
flags: { memory: true },
|
|
379
394
|
verdicts: { passed: 1, failed: 1, errored: 0, skipped: 0 },
|
|
380
395
|
passRate: { value: 0.5, display: "50%", samples: 2, total: 2, refs: [] },
|
|
381
396
|
cost: { value: 0.12, display: "$0.12", samples: 1, total: 2, refs: [failedAttempt.locator] },
|
|
382
397
|
duration: { value: 32_000, display: "32.0s", samples: 2, total: 2, refs: [] },
|
|
383
398
|
tokens: { value: null, display: "—", samples: 0, total: 2, refs: [] },
|
|
384
399
|
evals: 2,
|
|
385
|
-
attempts:
|
|
400
|
+
attempts: 3,
|
|
386
401
|
lastRunAt: "2026-07-01T10:00:00Z",
|
|
387
402
|
evalRows: [
|
|
388
403
|
{
|
|
389
404
|
evalId: "algebra/quadratic",
|
|
390
405
|
verdict: "failed",
|
|
391
|
-
reason: "roots-correct: expected x=2, got x=3",
|
|
392
406
|
duration: { value: 32_000, display: "32.0s", samples: 1, total: 1, refs: [failedAttempt.locator] },
|
|
393
407
|
cost: { value: 0.12, display: "$0.12", samples: 1, total: 1, refs: [failedAttempt.locator] },
|
|
394
|
-
attempts: [failedAttempt],
|
|
408
|
+
attempts: [failedAttempt, failedRetryAttempt],
|
|
395
409
|
},
|
|
396
410
|
{
|
|
397
411
|
evalId: "algebra/simple",
|
|
@@ -417,7 +431,6 @@ export const experimentListItems: ExperimentListItem[] = [
|
|
|
417
431
|
{
|
|
418
432
|
evalId: "geometry/angles",
|
|
419
433
|
verdict: "errored",
|
|
420
|
-
reason: erroredAttempt.error,
|
|
421
434
|
duration: { value: 4_500, display: "4.5s", samples: 1, total: 1, refs: [erroredAttempt.locator] },
|
|
422
435
|
cost: { value: null, display: "—", samples: 0, total: 1, refs: [] },
|
|
423
436
|
attempts: [erroredAttempt],
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// web 面的小工具:展示格式化统一住在计算侧的 ../format.ts(两个渲染面同一份),
|
|
2
2
|
// 这里 re-export 并补 class 名拼接。MetricCell 一律自带 display,组件不重算。
|
|
3
3
|
|
|
4
|
-
export { MISSING_TEXT,
|
|
4
|
+
export { MISSING_TEXT, formatDurationMs, formatPercent, formatUSD, verdictMark } from "../format.ts";
|
|
5
5
|
|
|
6
6
|
/** 拼 class 名:过滤空值,末尾接使用者透传的 className。 */
|
|
7
7
|
export function cx(...parts: (string | undefined | false)[]): string {
|
|
@@ -1,11 +1,9 @@
|
|
|
1
|
+
// cases: docs/engineering/unit-tests/reports/cases.md
|
|
1
2
|
// 「不 hydrate 也完整」的验收测试:每个组件过 renderToStaticMarkup,
|
|
2
3
|
// 断言纯静态 HTML 里就有全部关键内容——数字、覆盖率角标、缺数据文案、
|
|
3
4
|
// 散点的 SVG 与系列名、truncated 行、attemptHref 链接。
|
|
4
|
-
//
|
|
5
|
+
// 另外锁一条契约:维度键跨组件同色。
|
|
5
6
|
|
|
6
|
-
import { readFileSync, readdirSync } from "node:fs";
|
|
7
|
-
import { dirname, join } from "node:path";
|
|
8
|
-
import { fileURLToPath } from "node:url";
|
|
9
7
|
import { renderToStaticMarkup } from "react-dom/server";
|
|
10
8
|
import { describe, expect, it } from "vitest";
|
|
11
9
|
import type { AttemptLocator } from "../../results/locator.ts";
|
|
@@ -72,12 +70,6 @@ describe("RunOverview", () => {
|
|
|
72
70
|
describe("MetricTable", () => {
|
|
73
71
|
const html = renderToStaticMarkup(<MetricTable data={tableData} attemptHref={attemptHref} />);
|
|
74
72
|
|
|
75
|
-
it("按传入顺序渲染行,不重排(排序在数据侧)", () => {
|
|
76
|
-
// fixture 里 codex(50%)在 bub(87%)前面,输出必须保持
|
|
77
|
-
expect(html.indexOf(">codex<")).toBeGreaterThan(-1);
|
|
78
|
-
expect(html.indexOf(">codex<")).toBeLessThan(html.indexOf(">bub<"));
|
|
79
|
-
});
|
|
80
|
-
|
|
81
73
|
it("列头带 label、unit 与 better 方向", () => {
|
|
82
74
|
expect(html).toContain("pass rate");
|
|
83
75
|
expect(html).toContain("(%)");
|
|
@@ -157,21 +149,12 @@ describe("MetricMatrix", () => {
|
|
|
157
149
|
expect(html).toContain("eval × agent");
|
|
158
150
|
});
|
|
159
151
|
|
|
160
|
-
it("稀疏格子:没有样本的格子空着(恰好一个)", () => {
|
|
161
|
-
expect(html.match(/nre-td-empty/g)).toHaveLength(1);
|
|
162
|
-
});
|
|
163
|
-
|
|
164
152
|
it("格子数字与 refs 下钻链接", () => {
|
|
165
153
|
expect(html).toContain("100%");
|
|
166
154
|
expect(html).toContain("0%");
|
|
167
155
|
expect(html).toContain('href="/attempts/@1b3b3b3"');
|
|
168
156
|
expect(html).toContain('href="/attempts/@1b7b7b7"');
|
|
169
157
|
});
|
|
170
|
-
|
|
171
|
-
it("列头(维度键)带稳定散列配色 class", () => {
|
|
172
|
-
expect(html).toContain(colorClassForKey("bub"));
|
|
173
|
-
expect(html).toContain(colorClassForKey("codex"));
|
|
174
|
-
});
|
|
175
158
|
});
|
|
176
159
|
|
|
177
160
|
describe("Scoreboard", () => {
|
|
@@ -243,11 +226,6 @@ describe("MetricScatter", () => {
|
|
|
243
226
|
expect(html).toContain(">codex-mid</text>");
|
|
244
227
|
});
|
|
245
228
|
|
|
246
|
-
it("null 点不画,底部注脚如实报数", () => {
|
|
247
|
-
expect(html).not.toContain('data-key="compare/codex-broken"');
|
|
248
|
-
expect(html).toContain("1 point missing data");
|
|
249
|
-
});
|
|
250
|
-
|
|
251
229
|
it("hover 退化为 <title>:display 与 samples/total", () => {
|
|
252
230
|
expect(html).toContain("<title>");
|
|
253
231
|
expect(html).toContain("50%(6/6)");
|
|
@@ -271,7 +249,7 @@ describe("MetricScatter", () => {
|
|
|
271
249
|
expect(empty).toContain("4 points missing data");
|
|
272
250
|
});
|
|
273
251
|
|
|
274
|
-
it("恰好 1
|
|
252
|
+
it("恰好 1 个可画点:照常画出单点", () => {
|
|
275
253
|
const single = renderToStaticMarkup(
|
|
276
254
|
<MetricScatter
|
|
277
255
|
data={{
|
|
@@ -281,8 +259,8 @@ describe("MetricScatter", () => {
|
|
|
281
259
|
}}
|
|
282
260
|
/>,
|
|
283
261
|
);
|
|
284
|
-
expect(single).
|
|
285
|
-
expect(single).toContain("
|
|
262
|
+
expect(single).toContain("<svg");
|
|
263
|
+
expect(single).toContain("nre-scatter-point");
|
|
286
264
|
});
|
|
287
265
|
});
|
|
288
266
|
|
|
@@ -304,11 +282,6 @@ describe("DeltaTable", () => {
|
|
|
304
282
|
expect(html).toContain("nre-delta-flat");
|
|
305
283
|
});
|
|
306
284
|
|
|
307
|
-
it("任一侧缺数据:Δ 显示为缺,不硬算", () => {
|
|
308
|
-
expect(html).toContain("nre-delta-missing");
|
|
309
|
-
expect(html).toContain("no data");
|
|
310
|
-
});
|
|
311
|
-
|
|
312
285
|
it("每行标出 A → B 的 experimentId", () => {
|
|
313
286
|
expect(html).toContain("compare/bub → compare/bub--agents-md");
|
|
314
287
|
});
|
|
@@ -322,14 +295,11 @@ describe("DeltaTable", () => {
|
|
|
322
295
|
describe("AttemptList", () => {
|
|
323
296
|
const html = renderToStaticMarkup(<AttemptList items={attemptListItems} />);
|
|
324
297
|
|
|
325
|
-
it("
|
|
298
|
+
it("只显示一条主失败摘要,不内联完整 evidence", () => {
|
|
326
299
|
expect(html).toContain("roots-correct");
|
|
327
|
-
expect(html).toContain("expected x=2
|
|
328
|
-
expect(html).toContain("
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
it("errored 的 error 摘要", () => {
|
|
332
|
-
expect(html).toContain("TypeError: cannot read properties of undefined");
|
|
300
|
+
expect(html).toContain("expected x=2");
|
|
301
|
+
expect(html).toContain("received x=3");
|
|
302
|
+
expect(html).not.toContain("judge: sign flipped when substituting into the quadratic formula");
|
|
333
303
|
});
|
|
334
304
|
|
|
335
305
|
it("total > items.length 时如实报「还有 n 条没列」", () => {
|
|
@@ -339,28 +309,14 @@ describe("AttemptList", () => {
|
|
|
339
309
|
expect(html).not.toContain("more not shown");
|
|
340
310
|
});
|
|
341
311
|
|
|
342
|
-
it("
|
|
343
|
-
expect(html).toContain(
|
|
344
|
-
expect(html).toContain('href="#/attempt/@1c1c1c1"');
|
|
345
|
-
expect(html).toContain("[E,X,⏱]"); // failedAttempt: eval + execution + timing
|
|
346
|
-
});
|
|
347
|
-
|
|
348
|
-
it("长文本(evidence)收进 <details>,零 JS 可展开", () => {
|
|
349
|
-
expect(html).toContain("<details");
|
|
350
|
-
expect(html).toContain("<summary>");
|
|
312
|
+
it("AttemptList 自身不展开断言详情", () => {
|
|
313
|
+
expect(html).not.toContain("<details");
|
|
351
314
|
});
|
|
352
315
|
});
|
|
353
316
|
|
|
354
317
|
describe("EvalList", () => {
|
|
355
318
|
const html = renderToStaticMarkup(<EvalList items={evalListItems} />);
|
|
356
319
|
|
|
357
|
-
it("每项一个 experimentId + evalId,判定与分数在场", () => {
|
|
358
|
-
expect(html).toContain("algebra/quadratic");
|
|
359
|
-
expect(html).toContain("geometry/angles");
|
|
360
|
-
expect(html).toContain("compare/bub");
|
|
361
|
-
expect(html).toContain("compare/codex");
|
|
362
|
-
});
|
|
363
|
-
|
|
364
320
|
it("展开到这道题的 Attempt(与 AttemptList 同一套 AttemptRow 渲染)", () => {
|
|
365
321
|
expect(html).toContain('href="#/attempt/@1a4a4a4"');
|
|
366
322
|
expect(html).toContain("roots-correct");
|
|
@@ -373,18 +329,34 @@ describe("EvalList", () => {
|
|
|
373
329
|
});
|
|
374
330
|
|
|
375
331
|
describe("ExperimentList", () => {
|
|
376
|
-
const html = renderToStaticMarkup(<ExperimentList items={experimentListItems} />);
|
|
332
|
+
const html = renderToStaticMarkup(<ExperimentList items={experimentListItems} filter />);
|
|
333
|
+
|
|
334
|
+
it("web 面是带过滤框与八个固定列头的 experiment 比较表", () => {
|
|
335
|
+
expect(html).toContain('data-nre-experiment-filter=""');
|
|
336
|
+
for (const header of ["Experiment", "Model", "Agent", "Avg duration", "End-to-end pass rate", "Tokens", "Est. cost", "Result"]) {
|
|
337
|
+
expect(html).toContain(`>${header}</button>`);
|
|
338
|
+
}
|
|
339
|
+
expect(html).toContain('data-nre-experiment-sort="4" class="nre-sort-desc"');
|
|
340
|
+
});
|
|
377
341
|
|
|
378
|
-
it("主行:身份、agent/model
|
|
342
|
+
it("主行:身份、agent/model、官方两级聚合指标与判定构成", () => {
|
|
379
343
|
expect(html).toContain("compare/bub");
|
|
380
344
|
expect(html).toContain("compare/codex");
|
|
381
345
|
expect(html).toContain("gpt-5.4");
|
|
382
346
|
expect(html).toContain("50%"); // passRate.display
|
|
347
|
+
expect(html).toContain("1 passed / 1 failed");
|
|
348
|
+
expect(html).toContain("memory=true");
|
|
383
349
|
});
|
|
384
350
|
|
|
385
|
-
it("展开到 Eval
|
|
351
|
+
it("展开到 Eval:同一道题的全部 Attempt 逐条显示", () => {
|
|
386
352
|
expect(html).toContain("algebra/quadratic");
|
|
387
353
|
expect(html).toContain('href="#/attempt/@1a4a4a4"');
|
|
354
|
+
expect(html).toContain('href="#/attempt/@1b5b5b5"');
|
|
355
|
+
expect(html.match(/algebra\/quadratic/g)).toHaveLength(1);
|
|
356
|
+
expect(html).toContain("nre-experiment-eval-header");
|
|
357
|
+
expect(html.match(/nre-experiment-attempt-row/g)).toHaveLength(3);
|
|
358
|
+
expect(html).toContain("├─");
|
|
359
|
+
expect(html).toContain("└─");
|
|
388
360
|
});
|
|
389
361
|
|
|
390
362
|
it("零 JS 靠原生 <details>,无 <script>", () => {
|
|
@@ -422,15 +394,4 @@ describe("跨组件契约", () => {
|
|
|
422
394
|
].join("");
|
|
423
395
|
expect(all).not.toContain("<script");
|
|
424
396
|
});
|
|
425
|
-
|
|
426
|
-
it("组件源码零 hooks(本实验的「不 hydrate 也完整」用最笨的方式保证)", () => {
|
|
427
|
-
const dir = dirname(fileURLToPath(import.meta.url));
|
|
428
|
-
const sources = readdirSync(dir)
|
|
429
|
-
.filter((f) => (f.endsWith(".tsx") || f.endsWith(".ts")) && !f.includes(".test."))
|
|
430
|
-
.map((f) => readFileSync(join(dir, f), "utf8"));
|
|
431
|
-
expect(sources.length).toBeGreaterThanOrEqual(12);
|
|
432
|
-
for (const src of sources) {
|
|
433
|
-
expect(src).not.toMatch(/\buse[A-Z][A-Za-z]*\s*\(/);
|
|
434
|
-
}
|
|
435
|
-
});
|
|
436
397
|
});
|
|
@@ -42,7 +42,7 @@
|
|
|
42
42
|
margin: 1rem 0;
|
|
43
43
|
}
|
|
44
44
|
|
|
45
|
-
/* ----
|
|
45
|
+
/* ---- locator 与判定符:AttemptList / EvalList / ExperimentList 共用的最小单元 ---- */
|
|
46
46
|
.nre .nre-locator { display:inline-flex; align-items:center; gap:4px; color:var(--nre-c0); font-variant-numeric:tabular-nums; text-decoration:none; white-space:nowrap; }
|
|
47
47
|
.nre .nre-locator:hover { text-decoration:underline; }
|
|
48
48
|
.nre .nre-locator-mark { font-weight:700; }
|
|
@@ -50,7 +50,6 @@
|
|
|
50
50
|
.nre .nre-locator.nre-verdict-failed .nre-locator-mark,
|
|
51
51
|
.nre .nre-locator.nre-verdict-errored .nre-locator-mark { color:var(--bad); }
|
|
52
52
|
.nre .nre-locator.nre-verdict-skipped .nre-locator-mark { color:var(--soft); }
|
|
53
|
-
.nre .nre-locator-caps { color:var(--muted); font-size:.85em; }
|
|
54
53
|
|
|
55
54
|
/* ---- AttemptList:实体列表的叶子层,一条卡片一个 Attempt ---- */
|
|
56
55
|
.nre-attempt-list .nre-attempts { list-style:none; margin:0; padding:0; }
|
|
@@ -62,6 +61,7 @@
|
|
|
62
61
|
.nre-attempt-list .nre-attempt-experiment,
|
|
63
62
|
.nre-attempt-list .nre-attempt-duration,
|
|
64
63
|
.nre-attempt-list .nre-attempt-cost { color:var(--muted); font-size:.9em; font-variant-numeric:tabular-nums; }
|
|
64
|
+
.nre-attempt-list .nre-attempt-result { display:-webkit-box; overflow:hidden; -webkit-box-orient:vertical; -webkit-line-clamp:2; margin:.4rem 0 0; color:color-mix(in oklch,var(--muted),var(--text) 12%); overflow-wrap:anywhere; }
|
|
65
65
|
.nre-attempt-list .nre-attempt-error { margin:.4rem 0 0; padding:6px 10px; border:1px solid color-mix(in oklch,var(--bad),var(--line) 50%); border-radius:7px; background:color-mix(in oklch,var(--bad),var(--panel) 92%); color:var(--bad); font-family:ui-monospace,SFMono-Regular,Menlo,monospace; font-size:.85em; white-space:pre-wrap; word-break:break-word; }
|
|
66
66
|
.nre-attempt-list .nre-assertions { list-style:none; margin:.4rem 0 0; padding:0; display:grid; gap:6px; }
|
|
67
67
|
.nre-attempt-list .nre-assertion { padding-left:.25rem; }
|
|
@@ -76,6 +76,77 @@
|
|
|
76
76
|
.nre-attempt-list .nre-truncated { color:var(--warn); font-size:.9em; }
|
|
77
77
|
.nre-attempt-list .nre-attempt-list-empty { border:1px dashed var(--line-strong); border-radius:8px; padding:18px; color:var(--muted); text-align:center; background:var(--panel); }
|
|
78
78
|
|
|
79
|
+
/* ---- ExperimentComparison:完整组索引 + 当前组独立 panel ---- */
|
|
80
|
+
.nre-experiment-comparison .nre-experiment-group-tabs {
|
|
81
|
+
display:grid;
|
|
82
|
+
grid-template-columns:repeat(auto-fit,minmax(320px,1fr));
|
|
83
|
+
gap:12px;
|
|
84
|
+
margin-bottom:20px;
|
|
85
|
+
}
|
|
86
|
+
.nre-experiment-comparison .nre-experiment-group-tab {
|
|
87
|
+
min-width:0;
|
|
88
|
+
border:1px solid var(--line);
|
|
89
|
+
border-radius:9px;
|
|
90
|
+
padding:14px 16px 8px;
|
|
91
|
+
background:var(--panel);
|
|
92
|
+
cursor:pointer;
|
|
93
|
+
transition:border-color .12s,background .12s;
|
|
94
|
+
}
|
|
95
|
+
.nre-experiment-comparison .nre-experiment-group-tab:hover {
|
|
96
|
+
border-color:var(--line-strong);
|
|
97
|
+
background:color-mix(in oklch,var(--panel-2),var(--panel) 35%);
|
|
98
|
+
}
|
|
99
|
+
.nre-experiment-comparison .nre-experiment-group-tab:focus-visible {
|
|
100
|
+
outline:2px solid var(--nre-c0);
|
|
101
|
+
outline-offset:2px;
|
|
102
|
+
}
|
|
103
|
+
.nre-experiment-comparison .nre-experiment-group-tab[aria-selected="true"] {
|
|
104
|
+
border-color:var(--nre-c0);
|
|
105
|
+
box-shadow:inset 3px 0 0 var(--nre-c0);
|
|
106
|
+
}
|
|
107
|
+
.nre-experiment-comparison .nre-experiment-group-name {
|
|
108
|
+
display:block;
|
|
109
|
+
margin-bottom:10px;
|
|
110
|
+
color:var(--text);
|
|
111
|
+
font-size:15px;
|
|
112
|
+
overflow-wrap:anywhere;
|
|
113
|
+
}
|
|
114
|
+
.nre-experiment-comparison .nre-experiment-group-tab .nre-group-kpis {
|
|
115
|
+
column-gap:16px;
|
|
116
|
+
}
|
|
117
|
+
.nre-experiment-comparison .nre-experiment-group-tab .nre-group-kpi {
|
|
118
|
+
min-width:58px;
|
|
119
|
+
}
|
|
120
|
+
.nre-experiment-comparison .nre-experiment-group-panel {
|
|
121
|
+
border:1px solid var(--line);
|
|
122
|
+
border-radius:9px;
|
|
123
|
+
padding:16px;
|
|
124
|
+
background:var(--panel);
|
|
125
|
+
}
|
|
126
|
+
.nre-experiment-comparison .nre-experiment-group-panel > summary {
|
|
127
|
+
cursor:pointer;
|
|
128
|
+
font-size:16px;
|
|
129
|
+
font-weight:700;
|
|
130
|
+
overflow-wrap:anywhere;
|
|
131
|
+
}
|
|
132
|
+
.nre-experiment-comparison .nre-experiment-group-panel[open] > summary {
|
|
133
|
+
margin-bottom:16px;
|
|
134
|
+
}
|
|
135
|
+
.nre-experiment-comparison .nre-experiment-group-panel > .nre {
|
|
136
|
+
margin:0 0 18px;
|
|
137
|
+
}
|
|
138
|
+
.nre-experiment-comparison .nre-experiment-group-panel > .nre:last-child {
|
|
139
|
+
margin-bottom:0;
|
|
140
|
+
}
|
|
141
|
+
.nre-experiment-comparison .nre-experiment-groups-empty {
|
|
142
|
+
border:1px dashed var(--line-strong);
|
|
143
|
+
border-radius:8px;
|
|
144
|
+
padding:18px;
|
|
145
|
+
color:var(--muted);
|
|
146
|
+
text-align:center;
|
|
147
|
+
background:var(--panel);
|
|
148
|
+
}
|
|
149
|
+
|
|
79
150
|
/* ---- EvalList:实体列表的第二级,一条 <details> 一个 experimentId × evalId ---- */
|
|
80
151
|
.nre-eval-list .nre-evals { list-style:none; margin:0; padding:0; }
|
|
81
152
|
.nre-eval-list .nre-eval { border-bottom:1px solid var(--line); }
|
|
@@ -89,29 +160,56 @@
|
|
|
89
160
|
.nre-eval-list .nre-eval-attempts-count,
|
|
90
161
|
.nre-eval-list .nre-eval-duration,
|
|
91
162
|
.nre-eval-list .nre-eval-cost { color:var(--muted); font-size:.9em; font-variant-numeric:tabular-nums; }
|
|
92
|
-
.nre-eval-list .nre-eval-reason { color:color-mix(in oklch,var(--muted),var(--text) 6%); }
|
|
93
163
|
.nre-eval-list .nre-attempts { list-style:none; margin:0 0 12px; padding:0 0 0 20px; border-left:2px solid color-mix(in oklch,var(--nre-c0),transparent 55%); }
|
|
94
164
|
.nre-eval-list .nre-eval-list-empty { border:1px dashed var(--line-strong); border-radius:8px; padding:18px; color:var(--muted); text-align:center; background:var(--panel); }
|
|
95
165
|
|
|
96
|
-
/* ---- ExperimentList
|
|
97
|
-
.nre-experiment-
|
|
166
|
+
/* ---- ExperimentList:web 面固定八列比较表,一条 <details> 一个 experiment ---- */
|
|
167
|
+
.nre-experiment-table { border:1px solid var(--line); border-radius:9px; overflow:hidden; background:var(--panel); }
|
|
168
|
+
.nre-experiment-head,
|
|
169
|
+
.nre-experiment-summary { display:grid; grid-template-columns:minmax(220px,1.25fr) minmax(120px,.8fr) minmax(90px,.6fr) minmax(100px,.65fr) minmax(90px,.55fr) minmax(110px,.7fr) minmax(90px,.6fr) minmax(160px,.9fr); column-gap:16px; align-items:center; }
|
|
170
|
+
.nre-experiment-head { padding:12px 20px; color:var(--muted); font-size:12px; font-weight:560; text-transform:uppercase; letter-spacing:.05em; border-bottom:1px solid var(--line); }
|
|
171
|
+
.nre-experiment-head button { appearance:none; border:0; padding:0; background:transparent; color:inherit; font:inherit; text-transform:inherit; letter-spacing:inherit; text-align:left; cursor:pointer; }
|
|
172
|
+
.nre-experiment-head button::after { content:"↕"; margin-left:6px; color:var(--soft); font-size:11px; }
|
|
173
|
+
.nre-experiment-head button.nre-sort-asc::after { content:"↑"; color:var(--text); }
|
|
174
|
+
.nre-experiment-head button.nre-sort-desc::after { content:"↓"; color:var(--text); }
|
|
175
|
+
.nre-experiment-table-wrap > .nre-filter { height:34px; min-width:260px; margin-bottom:16px; border:1px solid var(--line); border-radius:7px; padding:0 11px; background:var(--panel); color:var(--text); font:inherit; }
|
|
98
176
|
.nre-experiment-list .nre-experiment-entry { border-bottom:1px solid var(--line); }
|
|
99
177
|
.nre-experiment-list .nre-experiment-entry:last-child { border-bottom:0; }
|
|
100
|
-
.nre-experiment-list .nre-experiment-summary {
|
|
178
|
+
.nre-experiment-list .nre-experiment-summary { padding:13px 20px; cursor:pointer; list-style:none; transition:background .12s; }
|
|
101
179
|
.nre-experiment-list .nre-experiment-summary::-webkit-details-marker { display:none; }
|
|
102
180
|
.nre-experiment-list .nre-experiment-summary:hover { background:color-mix(in oklch,var(--panel-2),var(--panel) 25%); }
|
|
103
|
-
.nre-experiment-list .nre-experiment-
|
|
104
|
-
.nre-experiment-list .nre-experiment-
|
|
105
|
-
.nre-experiment-list .nre-experiment-
|
|
106
|
-
.nre-experiment-list .nre-experiment-
|
|
107
|
-
.nre-experiment-list .nre-experiment-
|
|
108
|
-
.nre-experiment-list .nre-experiment-
|
|
109
|
-
.nre-experiment-list .nre-
|
|
181
|
+
.nre-experiment-list .nre-experiment-summary > span { min-width:0; }
|
|
182
|
+
.nre-experiment-list .nre-experiment-name { position:relative; padding-left:30px; }
|
|
183
|
+
.nre-experiment-list .nre-experiment-name::before { content:""; position:absolute; left:5px; top:6px; width:7px; height:7px; border-right:1.5px solid var(--muted); border-bottom:1.5px solid var(--muted); transform:rotate(-45deg); transition:transform .15s; }
|
|
184
|
+
.nre-experiment-list .nre-experiment-entry[open] .nre-experiment-name::before { transform:rotate(45deg); }
|
|
185
|
+
.nre-experiment-list .nre-experiment-id { display:block; overflow-wrap:anywhere; font-weight:650; }
|
|
186
|
+
.nre-experiment-list .nre-experiment-name small { display:block; margin-top:3px; color:var(--muted); font-size:12px; font-weight:400; }
|
|
187
|
+
.nre-experiment-list .nre-num { font-variant-numeric:tabular-nums; font-feature-settings:"tnum"; white-space:nowrap; }
|
|
188
|
+
.nre-experiment-list .nre-good { color:var(--good); }
|
|
189
|
+
.nre-experiment-list .nre-warn { color:var(--warn); }
|
|
190
|
+
.nre-experiment-list .nre-bad { color:var(--bad); }
|
|
191
|
+
.nre-experiment-list .nre-experiment-pill { display:inline-flex; min-height:22px; align-items:center; border:1px solid var(--line); border-radius:999px; padding:0 8px; color:var(--muted); font-size:12px; white-space:nowrap; }
|
|
192
|
+
.nre-experiment-list .nre-experiment-detail { padding:18px 30px 22px; background:color-mix(in oklch,var(--panel-2),var(--panel) 24%); border-top:1px solid var(--line); }
|
|
193
|
+
.nre-experiment-list .nre-experiment-flags { display:flex; flex-wrap:wrap; gap:8px; margin:0 0 14px; color:var(--soft); font-size:12px; }
|
|
194
|
+
.nre-experiment-list .nre-experiment-flags b { border:1px solid color-mix(in oklch,var(--line),transparent 16%); border-radius:999px; padding:3px 8px; color:var(--text); font-weight:560; }
|
|
195
|
+
.nre-experiment-list .nre-experiment-evals { list-style:none; margin:0; padding:0; display:grid; gap:6px; }
|
|
196
|
+
.nre-experiment-list .nre-experiment-eval,
|
|
197
|
+
.nre-experiment-list .nre-experiment-attempts { list-style:none; margin:0; padding:0; }
|
|
198
|
+
.nre-experiment-list .nre-experiment-eval { padding:4px 0 9px; border-bottom:1px solid color-mix(in oklch,var(--line),transparent 28%); }
|
|
199
|
+
.nre-experiment-list .nre-experiment-eval:last-child { border-bottom:0; }
|
|
200
|
+
.nre-experiment-list .nre-experiment-eval-header,
|
|
201
|
+
.nre-experiment-list .nre-experiment-attempt-row { display:grid; grid-template-columns:20px minmax(220px,1fr) minmax(150px,.7fr) minmax(260px,1fr); column-gap:12px; align-items:baseline; font-size:13px; }
|
|
202
|
+
.nre-experiment-list .nre-experiment-eval-header { padding:7px 0 5px; }
|
|
203
|
+
.nre-experiment-list .nre-experiment-attempt-row { padding:5px 0 5px 20px; color:var(--muted); }
|
|
110
204
|
.nre-experiment-list .nre-eval-id { font-weight:560; overflow-wrap:anywhere; }
|
|
205
|
+
.nre-experiment-list .nre-eval-attempt-count { color:var(--soft); font-size:12px; }
|
|
206
|
+
.nre-experiment-list .nre-eval-rollup { color:var(--muted); font-size:.92em; overflow-wrap:anywhere; }
|
|
207
|
+
.nre-experiment-list .nre-attempt-branch { color:var(--line-strong); font-variant-numeric:tabular-nums; }
|
|
111
208
|
.nre-experiment-list .nre-eval-attempt-badges { display:inline-flex; flex-wrap:wrap; gap:.6em; }
|
|
112
|
-
.nre-experiment-list .nre-eval-
|
|
209
|
+
.nre-experiment-list .nre-eval-attempt-metrics,
|
|
113
210
|
.nre-experiment-list .nre-eval-reason { color:var(--muted); font-size:.92em; }
|
|
114
211
|
.nre-experiment-list .nre-experiment-list-empty { border:1px dashed var(--line-strong); border-radius:8px; padding:18px; color:var(--muted); text-align:center; background:var(--panel); }
|
|
212
|
+
@media(max-width:1000px){.nre-experiment-table{overflow-x:auto}.nre-experiment-head,.nre-experiment-summary{min-width:1040px}.nre-experiment-detail{min-width:1040px}}
|
|
115
213
|
|
|
116
214
|
/* ---- verdict 判定色(AttemptList/EvalList/ExperimentList 的 verdict 文字与判定符共用) ---- */
|
|
117
215
|
.nre .nre-verdict-passed { color:var(--good); }
|