niceeval 0.6.1 → 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 +67 -5
- 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 -1
- package/dist/report/built-ins/experiment-comparison.js +116 -10
- package/dist/report/built-ins/index.d.ts +1 -0
- package/dist/report/built-ins/index.js +1 -1
- package/dist/report/components.d.ts +8 -2
- package/dist/report/components.js +3 -3
- package/dist/report/compute.d.ts +11 -18
- package/dist/report/compute.js +54 -34
- package/dist/report/flag.d.ts +16 -1
- package/dist/report/flag.js +19 -1
- package/dist/report/format.d.ts +16 -8
- package/dist/report/format.js +27 -12
- package/dist/report/index.d.ts +4 -3
- package/dist/report/index.js +5 -4
- package/dist/report/locale.d.ts +11 -2
- package/dist/report/locale.js +23 -5
- package/dist/report/metrics.d.ts +13 -1
- package/dist/report/metrics.js +65 -14
- package/dist/report/primitives.d.ts +6 -0
- package/dist/report/react/AttemptList.d.ts +2 -2
- package/dist/report/react/AttemptList.js +5 -6
- 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 +2 -1
- package/dist/report/react/ExperimentList.js +8 -10
- package/dist/report/react/MetricScatter.js +5 -11
- 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 +21 -14
- 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 +42 -41
- package/dist/report/text/table.js +36 -5
- package/dist/report/types.d.ts +39 -21
- 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 +22 -4
- package/docs-site/zh/concepts/experiment.mdx +1 -1
- package/docs-site/zh/concepts/overview.mdx +6 -6
- package/docs-site/zh/guides/agent-feedback-loop.mdx +28 -26
- 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/official-adapters.mdx +26 -2
- package/docs-site/zh/guides/publish-report.mdx +30 -16
- package/docs-site/zh/guides/report-components.mdx +42 -30
- package/docs-site/zh/guides/reporters.mdx +2 -2
- package/docs-site/zh/guides/results-data.mdx +17 -9
- package/docs-site/zh/guides/runner.mdx +17 -7
- package/docs-site/zh/guides/sandbox-agent.mdx +56 -7
- package/docs-site/zh/guides/sandbox-providers.mdx +257 -9
- package/docs-site/zh/guides/scoring-guide.mdx +4 -4
- package/docs-site/zh/guides/viewing-results.mdx +79 -36
- package/docs-site/zh/guides/write-experiment.mdx +5 -3
- package/docs-site/zh/guides/write-send.mdx +17 -1
- 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 +33 -7
- package/docs-site/zh/reference/define-agent.mdx +57 -4
- 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/expect.mdx +26 -1
- 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 +68 -5
- 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 +64 -2
- package/src/i18n/zh-CN.ts +65 -3
- 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 +110 -153
- package/src/report/built-ins/experiment-comparison.tsx +173 -13
- package/src/report/built-ins/index.ts +6 -1
- package/src/report/components.tsx +9 -3
- package/src/report/compute.ts +70 -40
- package/src/report/dual-render.test.tsx +194 -67
- package/src/report/flag.ts +30 -2
- package/src/report/format.ts +35 -11
- package/src/report/index.ts +22 -4
- package/src/report/locale.ts +25 -5
- package/src/report/metrics.ts +67 -14
- package/src/report/primitives.tsx +6 -0
- package/src/report/react/AttemptList.tsx +6 -31
- package/src/report/react/EvalList.tsx +0 -0
- package/src/report/react/ExperimentComparison.tsx +68 -0
- package/src/report/react/ExperimentList.tsx +15 -9
- package/src/report/react/MetricScatter.tsx +12 -14
- 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 +33 -1
- package/src/report/react/fixtures.ts +24 -17
- package/src/report/react/render.test.tsx +9 -64
- package/src/report/react/styles.css +73 -2
- package/src/report/report.test.ts +306 -98
- package/src/report/report.ts +6 -2
- package/src/report/text/faces.ts +47 -43
- package/src/report/text/table.ts +42 -5
- package/src/report/types.ts +41 -21
- 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 +8 -6
- 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 +21 -1
- package/src/show/render.ts +619 -104
- package/src/show/show.test.ts +235 -19
- 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 +1 -0
- package/src/view/data.ts +11 -1
- package/src/view/index.ts +11 -0
- package/src/view/server.ts +2 -0
- package/src/view/styles.css +3 -0
- package/src/view/view-report.test.ts +6 -5
- 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,4 @@
|
|
|
1
|
-
// 通用图表数值工具:round-number
|
|
2
|
-
// 从 src/view/app/lib/chart.ts 迁来(view 侧从这里 re-export),报告组件与 view 共用同一份。
|
|
1
|
+
// 通用图表数值工具:round-number 刻度生成与点标签布局,零依赖纯函数。
|
|
3
2
|
|
|
4
3
|
function niceNumber(range: number, round: boolean): number {
|
|
5
4
|
if (range <= 0) return 1;
|
|
@@ -35,34 +34,114 @@ export function niceTicks(min: number, max: number, count = 5): number[] {
|
|
|
35
34
|
return ticks;
|
|
36
35
|
}
|
|
37
36
|
|
|
38
|
-
export interface
|
|
37
|
+
export interface PointLabelInput {
|
|
39
38
|
cx: number;
|
|
40
39
|
cy: number;
|
|
40
|
+
/** 标签文本的估算宽度(px)。 */
|
|
41
41
|
width: number;
|
|
42
|
-
|
|
43
|
-
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/** 标签允许占用的画布范围(含坐标轴边距,标签可以借用空白边距)。 */
|
|
45
|
+
export interface LabelBounds {
|
|
46
|
+
x0: number;
|
|
47
|
+
y0: number;
|
|
48
|
+
x1: number;
|
|
49
|
+
y1: number;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export interface PlacedPointLabel {
|
|
53
|
+
/** <text> 的锚点坐标(y 为文字基线)。 */
|
|
54
|
+
x: number;
|
|
55
|
+
y: number;
|
|
56
|
+
anchor: "start" | "end" | "middle";
|
|
57
|
+
/** 标签不在点左右紧邻位:渲染层补 leader line 连回原点。 */
|
|
58
|
+
leader: boolean;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/** 标签框高度(基线上方 10px、下方 2px,对应 11px 字号)。 */
|
|
62
|
+
const LABEL_ASCENT = 10;
|
|
63
|
+
const LABEL_DESCENT = 2;
|
|
64
|
+
/** 数据点视为边长 2×DOT_R 的方形障碍(点半径 4.5 + 命中余量)。 */
|
|
65
|
+
const DOT_R = 6;
|
|
66
|
+
/** 紧邻位与点的水平间距;候选环按它逐环外扩。 */
|
|
67
|
+
const NEAR = 10;
|
|
68
|
+
const RINGS = [NEAR, NEAR + 12, NEAR + 26];
|
|
69
|
+
|
|
70
|
+
interface Box {
|
|
71
|
+
x0: number;
|
|
72
|
+
y0: number;
|
|
73
|
+
x1: number;
|
|
74
|
+
y1: number;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function labelBoxAt(x: number, y: number, anchor: PlacedPointLabel["anchor"], width: number): Box {
|
|
78
|
+
const x0 = anchor === "start" ? x : anchor === "end" ? x - width : x - width / 2;
|
|
79
|
+
return { x0, y0: y - LABEL_ASCENT, x1: x0 + width, y1: y + LABEL_DESCENT };
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function overlapArea(a: Box, b: Box): number {
|
|
83
|
+
const w = Math.min(a.x1, b.x1) - Math.max(a.x0, b.x0);
|
|
84
|
+
const h = Math.min(a.y1, b.y1) - Math.max(a.y0, b.y0);
|
|
85
|
+
return w > 0 && h > 0 ? w * h : 0;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
function outOfBoundsArea(box: Box, bounds: LabelBounds): number {
|
|
89
|
+
const total = (box.x1 - box.x0) * (box.y1 - box.y0);
|
|
90
|
+
const w = Math.min(box.x1, bounds.x1) - Math.max(box.x0, bounds.x0);
|
|
91
|
+
const h = Math.min(box.y1, bounds.y1) - Math.max(box.y0, bounds.y0);
|
|
92
|
+
const inside = w > 0 && h > 0 ? w * h : 0;
|
|
93
|
+
return total - inside;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/** 一个点在距离 d 的候选环:左右紧邻、四个斜角、正上正下。顺序即同代价时的偏好序。 */
|
|
97
|
+
function ringCandidates(p: PointLabelInput, d: number): Omit<PlacedPointLabel, "leader">[] {
|
|
98
|
+
const diag = d * 0.75;
|
|
99
|
+
return [
|
|
100
|
+
{ x: p.cx + d, y: p.cy + 4, anchor: "start" },
|
|
101
|
+
{ x: p.cx - d, y: p.cy + 4, anchor: "end" },
|
|
102
|
+
{ x: p.cx + diag, y: p.cy - diag - 2, anchor: "start" },
|
|
103
|
+
{ x: p.cx - diag, y: p.cy - diag - 2, anchor: "end" },
|
|
104
|
+
{ x: p.cx, y: p.cy - d - LABEL_DESCENT - 2, anchor: "middle" },
|
|
105
|
+
{ x: p.cx + diag, y: p.cy + diag + LABEL_ASCENT, anchor: "start" },
|
|
106
|
+
{ x: p.cx - diag, y: p.cy + diag + LABEL_ASCENT, anchor: "end" },
|
|
107
|
+
{ x: p.cx, y: p.cy + d + LABEL_ASCENT + 2, anchor: "middle" },
|
|
108
|
+
];
|
|
44
109
|
}
|
|
45
110
|
|
|
46
111
|
/**
|
|
47
|
-
*
|
|
48
|
-
*
|
|
112
|
+
* 散点直接标签的候选位择优布局(docs/feature/reports/library.md「MetricScatter」):
|
|
113
|
+
* 每个标签在点四周由近及远的候选环上打分——与已放置标签的重叠、与任何数据点的重叠、
|
|
114
|
+
* 越出画布的面积、离点距离逐项累加,取代价最小的候选。存在无冲突候选时标签必不遮点、
|
|
115
|
+
* 不叠标签、不越界;全候选冲突时取重叠最小者,绝不丢标签。重合点簇因此向不同方向散开,
|
|
116
|
+
* 而不是单向堆叠压到下方的数据点上。
|
|
49
117
|
*/
|
|
50
|
-
export function
|
|
51
|
-
const
|
|
52
|
-
const
|
|
53
|
-
const
|
|
118
|
+
export function placePointLabels(points: PointLabelInput[], bounds: LabelBounds): PlacedPointLabel[] {
|
|
119
|
+
const dots: Box[] = points.map((p) => ({ x0: p.cx - DOT_R, y0: p.cy - DOT_R, x1: p.cx + DOT_R, y1: p.cy + DOT_R }));
|
|
120
|
+
const placedBoxes: Box[] = [];
|
|
121
|
+
const result: PlacedPointLabel[] = new Array(points.length);
|
|
122
|
+
// 由上到下、由左到右逐个放置,布局确定可复现
|
|
123
|
+
const order = [...points.keys()].sort((a, b) => points[a].cy - points[b].cy || points[a].cx - points[b].cx);
|
|
124
|
+
|
|
54
125
|
for (const i of order) {
|
|
55
|
-
const
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
126
|
+
const p = points[i];
|
|
127
|
+
let best: { candidate: Omit<PlacedPointLabel, "leader">; box: Box; cost: number; leader: boolean } | null = null;
|
|
128
|
+
for (let ring = 0; ring < RINGS.length; ring++) {
|
|
129
|
+
const candidates = ringCandidates(p, RINGS[ring]);
|
|
130
|
+
for (let c = 0; c < candidates.length; c++) {
|
|
131
|
+
const candidate = candidates[c];
|
|
132
|
+
const box = labelBoxAt(candidate.x, candidate.y, candidate.anchor, p.width);
|
|
133
|
+
let cost = 0;
|
|
134
|
+
for (const placed of placedBoxes) cost += overlapArea(box, placed) * 4;
|
|
135
|
+
for (const dot of dots) cost += overlapArea(box, dot) * 3;
|
|
136
|
+
cost += outOfBoundsArea(box, bounds) * 6;
|
|
137
|
+
cost += ring * 8 + c * 0.5; // 近环、偏好序靠前者优先,只作同冲突程度下的排序
|
|
138
|
+
if (best === null || cost < best.cost) {
|
|
139
|
+
best = { candidate, box, cost, leader: !(ring === 0 && c <= 1) };
|
|
140
|
+
}
|
|
141
|
+
}
|
|
63
142
|
}
|
|
64
|
-
|
|
65
|
-
|
|
143
|
+
placedBoxes.push(best!.box);
|
|
144
|
+
result[i] = { ...best!.candidate, leader: best!.leader };
|
|
66
145
|
}
|
|
67
|
-
return
|
|
146
|
+
return result;
|
|
68
147
|
}
|
|
@@ -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 类驱动。
|
|
@@ -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,8 +322,9 @@ 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
|
],
|
|
@@ -338,7 +339,17 @@ const erroredAttempt: AttemptListItem = {
|
|
|
338
339
|
attempt: 0,
|
|
339
340
|
agent: "codex",
|
|
340
341
|
verdict: "errored",
|
|
341
|
-
|
|
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
|
+
],
|
|
342
353
|
assertions: [],
|
|
343
354
|
durationMs: 4_500,
|
|
344
355
|
locator: locator("@1c1c1c1"),
|
|
@@ -358,7 +369,6 @@ export const evalListItems: EvalListItem[] = [
|
|
|
358
369
|
evalId: "algebra/quadratic",
|
|
359
370
|
experimentId: "compare/bub",
|
|
360
371
|
verdict: "failed",
|
|
361
|
-
reason: "roots-correct: expected x=2, got x=3",
|
|
362
372
|
score: { value: 0, display: "0%", samples: 1, total: 1, refs: [failedAttempt.locator] },
|
|
363
373
|
duration: { value: 32_000, display: "32.0s", samples: 1, total: 1, refs: [failedAttempt.locator] },
|
|
364
374
|
cost: { value: 0.12, display: "$0.12", samples: 1, total: 1, refs: [failedAttempt.locator] },
|
|
@@ -368,7 +378,6 @@ export const evalListItems: EvalListItem[] = [
|
|
|
368
378
|
evalId: "geometry/angles",
|
|
369
379
|
experimentId: "compare/codex",
|
|
370
380
|
verdict: "errored",
|
|
371
|
-
reason: erroredAttempt.error,
|
|
372
381
|
score: { value: 0, display: "0%", samples: 1, total: 1, refs: [erroredAttempt.locator] },
|
|
373
382
|
duration: { value: 4_500, display: "4.5s", samples: 1, total: 1, refs: [erroredAttempt.locator] },
|
|
374
383
|
cost: { value: null, display: "—", samples: 0, total: 1, refs: [] },
|
|
@@ -394,7 +403,6 @@ export const experimentListItems: ExperimentListItem[] = [
|
|
|
394
403
|
{
|
|
395
404
|
evalId: "algebra/quadratic",
|
|
396
405
|
verdict: "failed",
|
|
397
|
-
reason: "roots-correct: expected x=2, got x=3",
|
|
398
406
|
duration: { value: 32_000, display: "32.0s", samples: 1, total: 1, refs: [failedAttempt.locator] },
|
|
399
407
|
cost: { value: 0.12, display: "$0.12", samples: 1, total: 1, refs: [failedAttempt.locator] },
|
|
400
408
|
attempts: [failedAttempt, failedRetryAttempt],
|
|
@@ -423,7 +431,6 @@ export const experimentListItems: ExperimentListItem[] = [
|
|
|
423
431
|
{
|
|
424
432
|
evalId: "geometry/angles",
|
|
425
433
|
verdict: "errored",
|
|
426
|
-
reason: erroredAttempt.error,
|
|
427
434
|
duration: { value: 4_500, display: "4.5s", samples: 1, total: 1, refs: [erroredAttempt.locator] },
|
|
428
435
|
cost: { value: null, display: "—", samples: 0, total: 1, refs: [] },
|
|
429
436
|
attempts: [erroredAttempt],
|
|
@@ -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)");
|
|
@@ -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).not.toMatch(/\[[EXD⏱,]+\]/);
|
|
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");
|
|
@@ -377,7 +333,7 @@ describe("ExperimentList", () => {
|
|
|
377
333
|
|
|
378
334
|
it("web 面是带过滤框与八个固定列头的 experiment 比较表", () => {
|
|
379
335
|
expect(html).toContain('data-nre-experiment-filter=""');
|
|
380
|
-
for (const header of ["Experiment", "Model", "Agent", "Avg duration", "
|
|
336
|
+
for (const header of ["Experiment", "Model", "Agent", "Avg duration", "End-to-end pass rate", "Tokens", "Est. cost", "Result"]) {
|
|
381
337
|
expect(html).toContain(`>${header}</button>`);
|
|
382
338
|
}
|
|
383
339
|
expect(html).toContain('data-nre-experiment-sort="4" class="nre-sort-desc"');
|
|
@@ -438,15 +394,4 @@ describe("跨组件契约", () => {
|
|
|
438
394
|
].join("");
|
|
439
395
|
expect(all).not.toContain("<script");
|
|
440
396
|
});
|
|
441
|
-
|
|
442
|
-
it("组件源码零 hooks(本实验的「不 hydrate 也完整」用最笨的方式保证)", () => {
|
|
443
|
-
const dir = dirname(fileURLToPath(import.meta.url));
|
|
444
|
-
const sources = readdirSync(dir)
|
|
445
|
-
.filter((f) => (f.endsWith(".tsx") || f.endsWith(".ts")) && !f.includes(".test."))
|
|
446
|
-
.map((f) => readFileSync(join(dir, f), "utf8"));
|
|
447
|
-
expect(sources.length).toBeGreaterThanOrEqual(12);
|
|
448
|
-
for (const src of sources) {
|
|
449
|
-
expect(src).not.toMatch(/\buse[A-Z][A-Za-z]*\s*\(/);
|
|
450
|
-
}
|
|
451
|
-
});
|
|
452
397
|
});
|
|
@@ -61,6 +61,7 @@
|
|
|
61
61
|
.nre-attempt-list .nre-attempt-experiment,
|
|
62
62
|
.nre-attempt-list .nre-attempt-duration,
|
|
63
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; }
|
|
64
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; }
|
|
65
66
|
.nre-attempt-list .nre-assertions { list-style:none; margin:.4rem 0 0; padding:0; display:grid; gap:6px; }
|
|
66
67
|
.nre-attempt-list .nre-assertion { padding-left:.25rem; }
|
|
@@ -75,6 +76,77 @@
|
|
|
75
76
|
.nre-attempt-list .nre-truncated { color:var(--warn); font-size:.9em; }
|
|
76
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); }
|
|
77
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
|
+
|
|
78
150
|
/* ---- EvalList:实体列表的第二级,一条 <details> 一个 experimentId × evalId ---- */
|
|
79
151
|
.nre-eval-list .nre-evals { list-style:none; margin:0; padding:0; }
|
|
80
152
|
.nre-eval-list .nre-eval { border-bottom:1px solid var(--line); }
|
|
@@ -88,7 +160,6 @@
|
|
|
88
160
|
.nre-eval-list .nre-eval-attempts-count,
|
|
89
161
|
.nre-eval-list .nre-eval-duration,
|
|
90
162
|
.nre-eval-list .nre-eval-cost { color:var(--muted); font-size:.9em; font-variant-numeric:tabular-nums; }
|
|
91
|
-
.nre-eval-list .nre-eval-reason { color:color-mix(in oklch,var(--muted),var(--text) 6%); }
|
|
92
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%); }
|
|
93
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); }
|
|
94
165
|
|
|
@@ -132,7 +203,7 @@
|
|
|
132
203
|
.nre-experiment-list .nre-experiment-attempt-row { padding:5px 0 5px 20px; color:var(--muted); }
|
|
133
204
|
.nre-experiment-list .nre-eval-id { font-weight:560; overflow-wrap:anywhere; }
|
|
134
205
|
.nre-experiment-list .nre-eval-attempt-count { color:var(--soft); font-size:12px; }
|
|
135
|
-
.nre-experiment-list .nre-eval-
|
|
206
|
+
.nre-experiment-list .nre-eval-rollup { color:var(--muted); font-size:.92em; overflow-wrap:anywhere; }
|
|
136
207
|
.nre-experiment-list .nre-attempt-branch { color:var(--line-strong); font-variant-numeric:tabular-nums; }
|
|
137
208
|
.nre-experiment-list .nre-eval-attempt-badges { display:inline-flex; flex-wrap:wrap; gap:.6em; }
|
|
138
209
|
.nre-experiment-list .nre-eval-attempt-metrics,
|