niceeval 0.11.4-canary.20 → 0.12.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/INDEX.md +1 -0
- package/dist/i18n/en.d.ts +9 -1
- package/dist/i18n/en.js +11 -2
- package/dist/i18n/zh-CN.d.ts +10 -2
- package/dist/i18n/zh-CN.js +11 -2
- package/dist/record/attempt-evidence.d.ts +1 -1
- package/dist/record/open.js +25 -0
- package/dist/report/assets/series-encoding.d.ts +36 -0
- package/dist/report/assets/series-encoding.js +104 -0
- package/dist/report/built-in/result-components.js +12 -2
- package/dist/report/components/attempt-detail/compute.d.ts +8 -1
- package/dist/report/components/attempt-detail/compute.js +19 -1
- package/dist/report/components/attempt-detail/index.js +25 -3
- package/dist/report/components/attempt-detail/validate.js +3 -2
- package/dist/report/components/entity-lists/compute.d.ts +6 -0
- package/dist/report/components/entity-lists/compute.js +55 -8
- package/dist/report/components/entity-lists/content.d.ts +2 -0
- package/dist/report/components/entity-lists/content.js +59 -6
- package/dist/report/components/entity-lists/index.d.ts +21 -1
- package/dist/report/components/entity-lists/index.js +40 -7
- package/dist/report/components/entity-lists/validate.js +21 -0
- package/dist/report/components/fixtures.js +2 -0
- package/dist/report/definition/cell.d.ts +22 -0
- package/dist/report/definition/cell.js +23 -9
- package/dist/report/definition/primitives/chart.js +125 -25
- package/dist/report/definition/primitives/conversation.d.ts +1 -1
- package/dist/report/definition/primitives/conversation.js +5 -3
- package/dist/report/definition/primitives.js +32 -7
- package/dist/report/definition/tree.d.ts +5 -2
- package/dist/report/definition/tree.js +1 -0
- package/dist/report/index.d.ts +5 -5
- package/dist/report/index.js +2 -2
- package/dist/report/model/aggregate.d.ts +14 -1
- package/dist/report/model/aggregate.js +34 -2
- package/dist/report/model/conversions.d.ts +1 -0
- package/dist/report/model/conversions.js +4 -1
- package/dist/report/model/format.d.ts +6 -5
- package/dist/report/model/format.js +30 -9
- package/dist/report/model/locale.d.ts +19 -3
- package/dist/report/model/locale.js +31 -5
- package/dist/report/model/types.d.ts +41 -4
- package/dist/report/presentation.d.ts +53 -6
- package/dist/report/presentation.js +40 -5
- package/dist/report/react/index.d.ts +3 -3
- package/dist/report/react/index.js +1 -1
- package/dist/report/slices/compute.js +52 -4
- package/dist/report/slices/content.d.ts +2 -1
- package/dist/report/slices/content.js +48 -15
- package/dist/report/slices/validate.js +23 -0
- package/dist/report/tasks.d.ts +7 -1
- package/dist/report/tasks.js +5 -3
- package/dist/runner/types.d.ts +30 -10
- package/dist/sample/index.d.ts +0 -9
- package/dist/sample/index.js +0 -18
- package/dist/sandbox/backend.d.ts +1 -1
- package/dist/sandbox/commands.d.ts +1 -1
- package/dist/sandbox/compose.d.ts +2 -1
- package/dist/sandbox/docker.d.ts +28 -7
- package/dist/sandbox/e2b.d.ts +11 -0
- package/dist/sandbox/identity.d.ts +6 -1
- package/dist/sandbox/layer.d.ts +36 -3
- package/dist/sandbox/local.d.ts +9 -0
- package/dist/sandbox/types.d.ts +14 -8
- package/dist/sandbox/vercel.d.ts +9 -0
- package/docs-site/zh/reference/builtin-agents.mdx +2 -0
- package/docs-site/zh/reference/cli.mdx +1 -0
- package/docs-site/zh/reference/define-agent.mdx +13 -9
- package/docs-site/zh/reference/define-config.mdx +8 -0
- package/docs-site/zh/reference/official-adapters.mdx +1 -1
- package/docs-site/zh/reference/results-data.mdx +1 -1
- package/docs-site/zh/tutorials/deploy-report-site.mdx +157 -0
- package/docs-site/zh/tutorials/publish-report.mdx +1 -1
- package/docs-site/zh/tutorials/rerun-and-cache.mdx +1 -1
- package/docs-site/zh/tutorials/sandbox-providers.mdx +19 -4
- package/package.json +1 -1
- package/src/agents/codex-env.test.ts +8 -1
- package/src/agents/codex.ts +8 -0
- package/src/agents/coding-cli-versions.ts +22 -6
- package/src/cli.ts +23 -1
- package/src/i18n/en.ts +14 -3
- package/src/i18n/zh-CN.ts +13 -2
- package/src/record/attempt-evidence.ts +1 -1
- package/src/record/open.ts +21 -0
- package/src/record/results.test.ts +74 -13
- package/src/record/truncate.ts +32 -7
- package/src/record/writer.ts +39 -8
- package/src/report/assets/series-encoding.tsx +177 -0
- package/src/report/assets/styles.css +97 -5
- package/src/report/built-in/result-components.tsx +23 -2
- package/src/report/components/attempt-detail/attempt-components.test.tsx +41 -0
- package/src/report/components/attempt-detail/compute.ts +20 -2
- package/src/report/components/attempt-detail/index.tsx +32 -2
- package/src/report/components/attempt-detail/validate.test.ts +1 -0
- package/src/report/components/attempt-detail/validate.tsx +3 -1
- package/src/report/components/compute.test.ts +196 -0
- package/src/report/components/entity-lists/compute.ts +73 -7
- package/src/report/components/entity-lists/content.test.ts +14 -8
- package/src/report/components/entity-lists/content.ts +63 -6
- package/src/report/components/entity-lists/index.tsx +93 -8
- package/src/report/components/entity-lists/validate.test.ts +9 -0
- package/src/report/components/entity-lists/validate.ts +16 -0
- package/src/report/components/fixtures.ts +2 -0
- package/src/report/definition/cell.ts +46 -11
- package/src/report/definition/conversation.test.tsx +5 -1
- package/src/report/definition/primitives/chart.tsx +197 -32
- package/src/report/definition/primitives/conversation.tsx +7 -4
- package/src/report/definition/primitives.tsx +81 -9
- package/src/report/definition/tree.ts +6 -2
- package/src/report/index.ts +15 -2
- package/src/report/model/aggregate.ts +40 -2
- package/src/report/model/conversions.ts +5 -0
- package/src/report/model/format.ts +32 -9
- package/src/report/model/locale.ts +35 -5
- package/src/report/model/presentation.test.ts +23 -1
- package/src/report/model/types.ts +40 -4
- package/src/report/presentation.test.tsx +179 -19
- package/src/report/presentation.ts +114 -11
- package/src/report/react/index.tsx +13 -2
- package/src/report/runtime/dual-render.test.tsx +38 -2
- package/src/report/slices/compute.ts +59 -4
- package/src/report/slices/content.ts +55 -16
- package/src/report/slices/delta-table.test.ts +138 -3
- package/src/report/slices/validate.test.ts +29 -0
- package/src/report/slices/validate.ts +16 -0
- package/src/report/tasks.ts +12 -2
- package/src/runner/accept.test.ts +328 -10
- package/src/runner/accept.ts +239 -72
- package/src/runner/attempt.test.ts +25 -13
- package/src/runner/attempt.ts +9 -9
- package/src/runner/config-identity.test.ts +25 -0
- package/src/runner/config-identity.ts +6 -7
- package/src/runner/feedback/coordinator.test.ts +51 -0
- package/src/runner/feedback/coordinator.ts +23 -0
- package/src/runner/feedback/failure.test.ts +15 -0
- package/src/runner/feedback/failure.ts +7 -0
- package/src/runner/feedback/human.test.ts +548 -27
- package/src/runner/feedback/human.ts +321 -47
- package/src/runner/feedback/index.ts +10 -0
- package/src/runner/feedback/input-guard.test.ts +251 -0
- package/src/runner/feedback/input-guard.ts +171 -0
- package/src/runner/feedback/reducer.ts +1 -0
- package/src/runner/fingerprint.test.ts +24 -0
- package/src/runner/gate-lease.test.ts +38 -14
- package/src/runner/ledger.test.ts +10 -7
- package/src/runner/ledger.ts +9 -2
- package/src/runner/lock.test.ts +40 -16
- package/src/runner/manifest.ts +8 -9
- package/src/runner/reporters/artifacts.ts +25 -3
- package/src/runner/run.test.ts +61 -0
- package/src/runner/run.ts +34 -9
- package/src/runner/sandbox-pool.test.ts +216 -12
- package/src/runner/sandbox-pool.ts +20 -2
- package/src/runner/types.ts +30 -10
- package/src/sample/index.ts +0 -16
- package/src/sample/sample.test.ts +78 -0
- package/src/sandbox/backend.ts +1 -1
- package/src/sandbox/commands.ts +4 -7
- package/src/sandbox/compose.test.ts +26 -1
- package/src/sandbox/compose.ts +7 -3
- package/src/sandbox/docker.test.ts +66 -1
- package/src/sandbox/docker.ts +89 -65
- package/src/sandbox/dockerfile-build.ts +4 -1
- package/src/sandbox/e2b-agent-template.test.ts +18 -1
- package/src/sandbox/e2b-agent-template.ts +22 -6
- package/src/sandbox/e2b.test.ts +64 -0
- package/src/sandbox/e2b.ts +27 -5
- package/src/sandbox/identity.ts +7 -2
- package/src/sandbox/layer.test.ts +23 -4
- package/src/sandbox/layer.ts +127 -43
- package/src/sandbox/link.test.ts +5 -2
- package/src/sandbox/local.test.ts +8 -8
- package/src/sandbox/local.ts +28 -6
- package/src/sandbox/operations.test.ts +4 -4
- package/src/sandbox/operations.ts +5 -5
- package/src/sandbox/runtime.ts +18 -3
- package/src/sandbox/types.ts +14 -8
- package/src/sandbox/vercel.test.ts +58 -3
- package/src/sandbox/vercel.ts +38 -6
- package/src/show/index.ts +11 -30
- package/src/show/render.test.ts +23 -1
- package/src/show/render.ts +6 -3
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { SeriesPatternDefs, seriesClassFromColorVar, seriesClassesFromFill, } from "../../assets/series-encoding.js";
|
|
2
3
|
import { defineComponent } from "../tree.js";
|
|
3
4
|
import { countText, localeText, resolveLocalizedText } from "../../model/locale.js";
|
|
4
5
|
import { formatAxisTick, formatMetricValue, shortestUniqueLabels } from "../../model/format.js";
|
|
@@ -91,7 +92,8 @@ function chartFieldLabel(field, meta, locale) {
|
|
|
91
92
|
const base = dictionary[field] ? localeText(locale, dictionary[field]) : field;
|
|
92
93
|
return meta.unit ? `${base}(${meta.unit})` : base;
|
|
93
94
|
}
|
|
94
|
-
|
|
95
|
+
/** 解析点所属 series 句柄与下标;单系列隐式图不声明视觉身份。 */
|
|
96
|
+
function seriesPresentationOf(mapped, series, point, ctx) {
|
|
95
97
|
let handle;
|
|
96
98
|
let index;
|
|
97
99
|
if (series.byField !== undefined && point.seriesValue !== undefined) {
|
|
@@ -101,12 +103,104 @@ function seriesClass(mapped, series, point, ctx) {
|
|
|
101
103
|
else {
|
|
102
104
|
const ids = mapped.filter((item) => !item.hidden && item.byField === undefined).map((item) => item.id);
|
|
103
105
|
if (ids.length < 2)
|
|
104
|
-
return
|
|
106
|
+
return undefined;
|
|
105
107
|
handle = IMPLICIT_SERIES_HANDLE;
|
|
106
108
|
index = ids.indexOf(series.id);
|
|
107
109
|
}
|
|
108
|
-
|
|
109
|
-
|
|
110
|
+
if (index < 0)
|
|
111
|
+
return undefined;
|
|
112
|
+
return ctx.dimension(handle).at(index);
|
|
113
|
+
}
|
|
114
|
+
/** SVG 路径:只挂 series-cN 设 --series;pattern 由 fill 属性 / style 承载。 */
|
|
115
|
+
function seriesColorClass(presentation) {
|
|
116
|
+
if (!presentation)
|
|
117
|
+
return "niceeval-series-none";
|
|
118
|
+
if (presentation.kind === "color")
|
|
119
|
+
return seriesClassFromColorVar(presentation.color);
|
|
120
|
+
if (presentation.kind !== "series")
|
|
121
|
+
return "niceeval-series-none";
|
|
122
|
+
// switch 按 mark 收窄;Fill 的 mark 是 "bar"|"area" 联合,if/|| 在部分 TS 版本下剔不干净。
|
|
123
|
+
switch (presentation.mark) {
|
|
124
|
+
case "bar":
|
|
125
|
+
case "area": {
|
|
126
|
+
// 只要色类,不要 HTML 专用的 fill-vN(SVG 用 url(#pattern))。
|
|
127
|
+
const classes = seriesClassesFromFill(presentation.fill).split(" ");
|
|
128
|
+
return classes.find((c) => c.startsWith("niceeval-series-c") || c === "niceeval-series-none") ?? "niceeval-series-none";
|
|
129
|
+
}
|
|
130
|
+
case "line":
|
|
131
|
+
return seriesClassFromColorVar(presentation.stroke);
|
|
132
|
+
case "scatter":
|
|
133
|
+
return seriesClassFromColorVar(presentation.marker.fill);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
/** HTML 横向柱:色类 + fill-vN 图案类(CSS repeating-linear-gradient 等效 SVG pattern)。 */
|
|
137
|
+
function seriesHtmlBarClass(presentation) {
|
|
138
|
+
if (!presentation)
|
|
139
|
+
return "niceeval-series-none";
|
|
140
|
+
if (presentation.kind === "series" && (presentation.mark === "bar" || presentation.mark === "area")) {
|
|
141
|
+
return seriesClassesFromFill(presentation.fill);
|
|
142
|
+
}
|
|
143
|
+
return seriesColorClass(presentation);
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* 作者在 `<Series line>` 上显式声明的 dashed/dotted **优先于** 页级 variant 的 strokeDasharray。
|
|
147
|
+
* 未声明时消费 LineSeriesPresentation / FillSeriesPresentation 的 strokeDasharray(空串 = 实线)。
|
|
148
|
+
*/
|
|
149
|
+
function resolveStrokeDasharray(series, presentation) {
|
|
150
|
+
if (series.line !== undefined)
|
|
151
|
+
return lineDash(series.line);
|
|
152
|
+
if (presentation?.kind === "series" && "strokeDasharray" in presentation) {
|
|
153
|
+
return presentation.strokeDasharray || undefined;
|
|
154
|
+
}
|
|
155
|
+
return undefined;
|
|
156
|
+
}
|
|
157
|
+
/** SVG 柱/面:pattern fill 必须用 style 压过 `.niceeval-chart-bar { fill: var(--series) }`。 */
|
|
158
|
+
function seriesSvgFillStyle(presentation) {
|
|
159
|
+
if (presentation?.kind !== "series")
|
|
160
|
+
return undefined;
|
|
161
|
+
if (presentation.mark !== "bar" && presentation.mark !== "area")
|
|
162
|
+
return undefined;
|
|
163
|
+
if (!presentation.fill.startsWith("url("))
|
|
164
|
+
return undefined;
|
|
165
|
+
return { fill: presentation.fill };
|
|
166
|
+
}
|
|
167
|
+
function renderMarkerShape(presentation, px, py, colorClass, title) {
|
|
168
|
+
const marker = presentation?.kind === "series" && (presentation.mark === "scatter" || presentation.mark === "line")
|
|
169
|
+
? presentation.marker
|
|
170
|
+
: undefined;
|
|
171
|
+
if (!marker) {
|
|
172
|
+
return (_jsx("circle", { className: cx("niceeval-chart-dot", colorClass), cx: px, cy: py, r: 4.5, children: title }));
|
|
173
|
+
}
|
|
174
|
+
// path 在 0..12 viewBox;缩放到 ~9px 并居中到 (px, py)。
|
|
175
|
+
return (_jsx("path", { className: cx("niceeval-chart-dot", colorClass), d: marker.path, transform: `translate(${px} ${py}) scale(0.75) translate(-6 -6)`, fill: marker.fill, stroke: "var(--panel)", strokeWidth: 1.6, children: title }));
|
|
176
|
+
}
|
|
177
|
+
function legendSwatch(presentation, mark) {
|
|
178
|
+
if (!presentation || presentation.kind !== "series") {
|
|
179
|
+
return _jsx("span", { className: cx("niceeval-chart-legend-swatch", "niceeval-series-none") });
|
|
180
|
+
}
|
|
181
|
+
// 图例方块跟 series mark 取义:柱/面用填充图案,线用 dash+marker,散点用 marker 形状。
|
|
182
|
+
if (mark === "bar" || mark === "area") {
|
|
183
|
+
const fillClass = presentation.mark === "bar" || presentation.mark === "area"
|
|
184
|
+
? seriesClassesFromFill(presentation.fill)
|
|
185
|
+
: seriesColorClass(presentation);
|
|
186
|
+
return _jsx("span", { className: cx("niceeval-chart-legend-swatch", fillClass) });
|
|
187
|
+
}
|
|
188
|
+
if (mark === "line") {
|
|
189
|
+
// 线系图例需要 stroke + marker;presentation 可能是 line 或 scatter(by 切分后 mark 对齐)。
|
|
190
|
+
if (presentation.mark === "line") {
|
|
191
|
+
return (_jsxs("svg", { className: "niceeval-chart-legend-swatch-svg", width: "16", height: "10", "aria-hidden": "true", children: [_jsx("line", { x1: "0", y1: "5", x2: "16", y2: "5", stroke: presentation.stroke, strokeWidth: 2, strokeDasharray: presentation.strokeDasharray || undefined }), _jsx("path", { d: presentation.marker.path, transform: "translate(8 5) scale(0.55) translate(-6 -6)", fill: presentation.marker.fill })] }));
|
|
192
|
+
}
|
|
193
|
+
if (presentation.mark === "scatter") {
|
|
194
|
+
return (_jsxs("svg", { className: "niceeval-chart-legend-swatch-svg", width: "16", height: "10", "aria-hidden": "true", children: [_jsx("line", { x1: "0", y1: "5", x2: "16", y2: "5", stroke: presentation.marker.fill, strokeWidth: 2 }), _jsx("path", { d: presentation.marker.path, transform: "translate(8 5) scale(0.55) translate(-6 -6)", fill: presentation.marker.fill })] }));
|
|
195
|
+
}
|
|
196
|
+
// fill presentation 配 line mark 的退化:只画色块。
|
|
197
|
+
return _jsx("span", { className: cx("niceeval-chart-legend-swatch", seriesColorClass(presentation)) });
|
|
198
|
+
}
|
|
199
|
+
// mark === "scatter"
|
|
200
|
+
if (presentation.mark === "scatter" || presentation.mark === "line") {
|
|
201
|
+
return (_jsx("svg", { className: "niceeval-chart-legend-swatch-svg", width: "10", height: "10", "aria-hidden": "true", children: _jsx("path", { d: presentation.marker.path, transform: "translate(5 5) scale(0.7) translate(-6 -6)", fill: presentation.marker.fill }) }));
|
|
202
|
+
}
|
|
203
|
+
return _jsx("span", { className: cx("niceeval-chart-legend-swatch", seriesColorClass(presentation)) });
|
|
110
204
|
}
|
|
111
205
|
function metricDisplay(point, axis, meta, locale) {
|
|
112
206
|
if (meta.kind === "dimension") {
|
|
@@ -129,10 +223,7 @@ function renderLegend(mapped, visible, locale, ctx) {
|
|
|
129
223
|
: implicitIds.indexOf(series.id);
|
|
130
224
|
const presentation = handle ? ctx.dimension(handle).at(index) : undefined;
|
|
131
225
|
const label = presentation?.label ?? (series.label ? resolveLocalizedText(series.label, locale) : series.id);
|
|
132
|
-
|
|
133
|
-
? "niceeval-series-none"
|
|
134
|
-
: `niceeval-series-c${presentation.colorIndex - 1}`;
|
|
135
|
-
return (_jsx("li", { className: cx("niceeval-chart-legend-item", colorClass), children: label }, `${series.id}:${value}`));
|
|
226
|
+
return (_jsxs("li", { className: "niceeval-chart-legend-item", children: [legendSwatch(presentation, series.mark), label] }, `${series.id}:${value}`));
|
|
136
227
|
});
|
|
137
228
|
}) }));
|
|
138
229
|
}
|
|
@@ -142,12 +233,13 @@ function renderHorizontalBarsWeb(mapped, visible, axes, locale, ctx, options) {
|
|
|
142
233
|
const values = entries.map(({ point }) => point.y);
|
|
143
234
|
const boundMax = axes.yMeta.kind === "metric" ? axes.yMeta.bounds?.max : undefined;
|
|
144
235
|
const max = boundMax !== undefined && boundMax > 0 ? boundMax : Math.max(0, ...values);
|
|
145
|
-
return (_jsxs("figure", { className: cx("niceeval-report", "niceeval-chart", "niceeval-chart--bars-horizontal", options.className), children: [_jsx("div", { className: "niceeval-chart-bars-heading", children: chartFieldLabel(axes.yField, axes.yMeta, locale) }), _jsx("ol", { className: "niceeval-chart-bars", children: entries.map(({ series, point }) => {
|
|
236
|
+
return (_jsxs("figure", { className: cx("niceeval-report", "niceeval-chart", "niceeval-chart--bars-horizontal", options.className), children: [_jsx(SeriesPatternDefs, {}), _jsx("div", { className: "niceeval-chart-bars-heading", children: chartFieldLabel(axes.yField, axes.yMeta, locale) }), _jsx("ol", { className: "niceeval-chart-bars", children: entries.map(({ series, point }) => {
|
|
146
237
|
const rawLabel = point.xLabel ?? point.pointLabel;
|
|
147
238
|
const label = labels.get(rawLabel) ?? rawLabel;
|
|
148
239
|
const display = metricDisplay(point, "y", axes.yMeta, locale);
|
|
149
240
|
const href = pointHref(point, ctx, options.pointTarget);
|
|
150
|
-
const
|
|
241
|
+
const presentation = seriesPresentationOf(mapped, series, point, ctx);
|
|
242
|
+
const colorClass = seriesHtmlBarClass(presentation);
|
|
151
243
|
const ratio = max > 0 ? Math.max(0, Math.min(1, point.y / max)) : 0;
|
|
152
244
|
const value = (_jsxs("span", { className: "niceeval-chart-bar-value", children: [display, point.yCell && point.yCell.samples < point.yCell.total ? (_jsxs("sup", { children: [point.yCell.samples, "/", point.yCell.total] })) : null] }));
|
|
153
245
|
return (_jsxs("li", { className: "niceeval-chart-bar-row", children: [_jsx("span", { className: "niceeval-chart-bar-label", title: rawLabel, children: label }), _jsx("span", { className: "niceeval-chart-bar-track", children: _jsx("span", { className: cx("niceeval-chart-bar-fill", colorClass), style: { width: `${ratio * 100}%` }, title: `${rawLabel}\n${axes.yField}: ${display}` }) }), href ? _jsx("a", { className: "niceeval-locator", href: href, children: value }) : value] }, `${series.id}:${point.key}`));
|
|
@@ -203,16 +295,20 @@ function renderChartWeb(mapped, axes, locale, ctx, options) {
|
|
|
203
295
|
const labelByKey = shortestUniqueLabels(allPoints.map((p) => p.pointLabel));
|
|
204
296
|
const xLabel = chartFieldLabel(axes.xField, axes.xMeta, locale);
|
|
205
297
|
const yLabel = chartFieldLabel(axes.yField, axes.yMeta, locale);
|
|
206
|
-
const drawable = visible.flatMap((series) => series.points.map((point) =>
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
298
|
+
const drawable = visible.flatMap((series) => series.points.map((point) => {
|
|
299
|
+
const presentation = seriesPresentationOf(mapped, series, point, ctx);
|
|
300
|
+
return {
|
|
301
|
+
...point,
|
|
302
|
+
sourceSeriesId: series.id,
|
|
303
|
+
label: labelByKey.get(point.pointLabel) ?? point.pointLabel,
|
|
304
|
+
px: xScale.scale(point.x),
|
|
305
|
+
py: yScale.scale(point.y),
|
|
306
|
+
presentation,
|
|
307
|
+
seriesClass: seriesColorClass(presentation),
|
|
308
|
+
};
|
|
309
|
+
}));
|
|
214
310
|
const labels = placePointLabels(drawable.map((p) => ({ cx: p.px, cy: p.py, width: p.label.length * 6.4 + 10 })), { x0: 2, y0: 2, x1: WIDTH - 2, y1: HEIGHT - 2 });
|
|
215
|
-
return (_jsxs("figure", { className: cx("niceeval-report", "niceeval-chart", "niceeval-chart--scatter", options.className), children: [_jsxs("svg", { className: "niceeval-chart-svg", viewBox: `0 0 ${WIDTH} ${HEIGHT}`, role: "img", "aria-label": `${axes.xField} × ${axes.yField}`, children: [options.grid !== false ? (_jsxs("g", { className: "niceeval-chart-grid", children: [yScale.ticks.map((tick) => (_jsx("line", { x1: MARGIN.left, x2: MARGIN.left + PLOT_W, y1: yScale.scale(tick), y2: yScale.scale(tick) }, `gy${tick}`))), xScale.ticks.map((tick) => (_jsx("line", { y1: MARGIN.top, y2: MARGIN.top + PLOT_H, x1: xScale.scale(tick), x2: xScale.scale(tick) }, `gx${tick}`)))] })) : null, _jsx("g", { className: "niceeval-chart-axis niceeval-chart-axis-y", children: (axes.yMeta.kind === "dimension"
|
|
311
|
+
return (_jsxs("figure", { className: cx("niceeval-report", "niceeval-chart", "niceeval-chart--scatter", options.className), children: [_jsx(SeriesPatternDefs, {}), _jsxs("svg", { className: "niceeval-chart-svg", viewBox: `0 0 ${WIDTH} ${HEIGHT}`, role: "img", "aria-label": `${axes.xField} × ${axes.yField}`, children: [options.grid !== false ? (_jsxs("g", { className: "niceeval-chart-grid", children: [yScale.ticks.map((tick) => (_jsx("line", { x1: MARGIN.left, x2: MARGIN.left + PLOT_W, y1: yScale.scale(tick), y2: yScale.scale(tick) }, `gy${tick}`))), xScale.ticks.map((tick) => (_jsx("line", { y1: MARGIN.top, y2: MARGIN.top + PLOT_H, x1: xScale.scale(tick), x2: xScale.scale(tick) }, `gx${tick}`)))] })) : null, _jsx("g", { className: "niceeval-chart-axis niceeval-chart-axis-y", children: (axes.yMeta.kind === "dimension"
|
|
216
312
|
? [...new Set(drawable.map((point) => point.y))]
|
|
217
313
|
: yScale.ticks).map((tick) => (_jsx("text", { className: "niceeval-chart-tick", x: MARGIN.left - 8, y: yScale.scale(tick) + 3, textAnchor: "end", children: axes.yMeta.kind === "dimension"
|
|
218
314
|
? drawable.find((point) => point.y === tick)?.yLabel
|
|
@@ -226,7 +322,8 @@ function renderChartWeb(mapped, axes, locale, ctx, options) {
|
|
|
226
322
|
const seriesPoints = drawable.filter((p) => p.sourceSeriesId === series.id &&
|
|
227
323
|
(series.byField === undefined || p.seriesValue === value));
|
|
228
324
|
const ordered = series.connect ? [...seriesPoints].sort((a, b) => a.x - b.x) : seriesPoints;
|
|
229
|
-
const
|
|
325
|
+
const seriesClassName = ordered[0]?.seriesClass ?? "niceeval-series-none";
|
|
326
|
+
const seriesPresentation = ordered[0]?.presentation;
|
|
230
327
|
const baseline = yScale.scale(0);
|
|
231
328
|
const barGroups = [...new Set(visible
|
|
232
329
|
.filter((item) => item.mark === "bar")
|
|
@@ -235,11 +332,13 @@ function renderChartWeb(mapped, axes, locale, ctx, options) {
|
|
|
235
332
|
const groupIndex = Math.max(0, barGroups.indexOf(barGroup));
|
|
236
333
|
const totalBarWidth = Math.max(8, Math.min(48, PLOT_W / Math.max(1, allPoints.length)));
|
|
237
334
|
const barWidth = totalBarWidth / Math.max(1, barGroups.length);
|
|
238
|
-
|
|
335
|
+
const dash = resolveStrokeDasharray(series, seriesPresentation);
|
|
336
|
+
const areaFillStyle = seriesSvgFillStyle(seriesPresentation);
|
|
337
|
+
return (_jsxs("g", { className: cx("niceeval-chart-series", seriesClassName), "data-series": `${series.id}:${value}`, children: [series.mark === "area" && ordered.length > 1 ? (_jsx("polygon", { className: "niceeval-chart-area", style: areaFillStyle, points: [
|
|
239
338
|
`${ordered[0].px},${baseline}`,
|
|
240
339
|
...ordered.map((point) => `${point.px},${point.py}`),
|
|
241
340
|
`${ordered[ordered.length - 1].px},${baseline}`,
|
|
242
|
-
].join(" ") })) : null, (series.mark === "line" || series.mark === "area" || series.connect) && ordered.length > 1 ? (_jsx("polyline", { className: "niceeval-chart-line", points: ordered.map((p) => `${p.px},${p.py}`).join(" "), strokeDasharray:
|
|
341
|
+
].join(" ") })) : null, (series.mark === "line" || series.mark === "area" || series.connect) && ordered.length > 1 ? (_jsx("polyline", { className: "niceeval-chart-line", points: ordered.map((p) => `${p.px},${p.py}`).join(" "), strokeDasharray: dash })) : null, ordered.map((p) => {
|
|
243
342
|
const placed = labels[drawable.indexOf(p)];
|
|
244
343
|
const href = pointHref(p, ctx, options.pointTarget);
|
|
245
344
|
let shape;
|
|
@@ -247,10 +346,10 @@ function renderChartWeb(mapped, axes, locale, ctx, options) {
|
|
|
247
346
|
const baseValue = stackedBarBase(visible, series, p.x);
|
|
248
347
|
const baseY = yScale.scale(baseValue);
|
|
249
348
|
const topY = yScale.scale(baseValue + p.y);
|
|
250
|
-
shape = (_jsx("rect", { className: cx("niceeval-chart-bar", p.seriesClass), x: p.px - totalBarWidth / 2 + groupIndex * barWidth, y: Math.min(topY, baseY), width: barWidth, height: Math.max(1, Math.abs(baseY - topY)), children: _jsx("title", { children: `${p.pointLabel}\n${series.id}: ${metricDisplay(p, "y", axes.yMeta, locale)}` }) }));
|
|
349
|
+
shape = (_jsx("rect", { className: cx("niceeval-chart-bar", p.seriesClass), style: seriesSvgFillStyle(p.presentation), x: p.px - totalBarWidth / 2 + groupIndex * barWidth, y: Math.min(topY, baseY), width: barWidth, height: Math.max(1, Math.abs(baseY - topY)), children: _jsx("title", { children: `${p.pointLabel}\n${series.id}: ${metricDisplay(p, "y", axes.yMeta, locale)}` }) }));
|
|
251
350
|
}
|
|
252
351
|
else {
|
|
253
|
-
shape = (
|
|
352
|
+
shape = renderMarkerShape(p.presentation, p.px, p.py, p.seriesClass, _jsx("title", { children: `${p.pointLabel}\n${axes.xField}: ${metricDisplay(p, "x", axes.xMeta, locale)}\n${axes.yField}: ${metricDisplay(p, "y", axes.yMeta, locale)}` }));
|
|
254
353
|
}
|
|
255
354
|
return (_jsxs("g", { className: "niceeval-chart-point", children: [href ? _jsx("a", { href: href, children: shape }) : shape, series.mark === "scatter" && placed ? (_jsx("text", { className: "niceeval-chart-point-label", x: placed.x, y: placed.y, textAnchor: placed.anchor, children: p.label })) : null] }, p.key));
|
|
256
355
|
})] }, `${series.id}:${value}`));
|
|
@@ -480,7 +579,8 @@ export const Chart = defineComponent({
|
|
|
480
579
|
continue;
|
|
481
580
|
decls[spec.by] = {
|
|
482
581
|
dimension: spec.by,
|
|
483
|
-
|
|
582
|
+
// area 是 FillSeriesPresentation(填充图案),不再折叠成 line。
|
|
583
|
+
encoding: { kind: "series", mark: spec.mark },
|
|
484
584
|
values,
|
|
485
585
|
};
|
|
486
586
|
}
|
|
@@ -110,7 +110,9 @@ function TurnCard({ turn, locale }) {
|
|
|
110
110
|
return (_jsxs("article", { className: cx("niceeval-conversation-turn", turn.verdict && `niceeval-conversation-turn--${turn.verdict}`), children: [_jsxs("header", { className: "niceeval-conversation-turn-head", children: [_jsx("span", { className: "niceeval-conversation-turn-label", children: resolveLocalizedText(turn.label, locale) }), turn.verdict ? _jsx("span", { className: "niceeval-conversation-turn-verdict", children: turn.verdict }) : null] }), _jsx(ConversationEntries, { entries: turn.entries, locale: locale })] }));
|
|
111
111
|
}
|
|
112
112
|
function commandEvidenceTitle(command) {
|
|
113
|
-
const title = command.classification === "
|
|
113
|
+
const title = command.classification === "succeeded" ? "COMMAND"
|
|
114
|
+
: command.classification === "failed" ? "FAILED COMMAND"
|
|
115
|
+
: "NON-ZERO COMMAND · observed";
|
|
114
116
|
return `${title} · ${command.phase} · exit ${command.exitCode}${command.durationMs === undefined ? "" : ` · ${command.durationMs}ms`}`;
|
|
115
117
|
}
|
|
116
118
|
function CommandEvidenceCard({ command }) {
|
|
@@ -147,8 +149,8 @@ function assertCommandEvidenceContent(data) {
|
|
|
147
149
|
throw dataShapeError("CommandEvidence", "commandEvidenceData", "CommandEvidenceContent", `"data.commands[${index}].display" must be a string`);
|
|
148
150
|
if (typeof command.exitCode !== "number")
|
|
149
151
|
throw dataShapeError("CommandEvidence", "commandEvidenceData", "CommandEvidenceContent", `"data.commands[${index}].exitCode" must be a number`);
|
|
150
|
-
if (command.classification !== "observed" && command.classification !== "failed") {
|
|
151
|
-
throw dataShapeError("CommandEvidence", "commandEvidenceData", "CommandEvidenceContent", `"data.commands[${index}].classification" must be observed | failed`);
|
|
152
|
+
if (command.classification !== "succeeded" && command.classification !== "observed" && command.classification !== "failed") {
|
|
153
|
+
throw dataShapeError("CommandEvidence", "commandEvidenceData", "CommandEvidenceContent", `"data.commands[${index}].classification" must be succeeded | observed | failed`);
|
|
152
154
|
}
|
|
153
155
|
if (command.durationMs !== undefined && typeof command.durationMs !== "number")
|
|
154
156
|
throw dataShapeError("CommandEvidence", "commandEvidenceData", "CommandEvidenceContent", `"data.commands[${index}].durationMs" must be a number`);
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
1
|
+
import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { COMPONENT_RAW_CHILDREN, COMPONENT_ROLE, defineComponent, } from "./tree.js";
|
|
3
3
|
import { hrefForLocator } from "../components/shared.js";
|
|
4
4
|
import { localeText, resolveLocalizedText } from "../model/locale.js";
|
|
@@ -10,7 +10,7 @@ import { datasetToTableContent, isDataset } from "../model/dataset.js";
|
|
|
10
10
|
import { isMetricValue } from "../model/calculation.js";
|
|
11
11
|
import { flattenTableContentForText, formatCellText, } from "./cell.js";
|
|
12
12
|
import { MetricCellView } from "../components/cell.js";
|
|
13
|
-
import { verdictMark } from "../model/format.js";
|
|
13
|
+
import { formatTimeDistance, missingText, verdictMark } from "../model/format.js";
|
|
14
14
|
function childArray(children) {
|
|
15
15
|
if (children === null || children === undefined || typeof children === "boolean")
|
|
16
16
|
return [];
|
|
@@ -548,18 +548,34 @@ function renderCellWeb(cell, ctx) {
|
|
|
548
548
|
switch (cell.kind) {
|
|
549
549
|
case "notApplicable":
|
|
550
550
|
return _jsx("span", { className: "niceeval-missing", children: MISSING_MARK });
|
|
551
|
-
case "missing":
|
|
552
|
-
|
|
551
|
+
case "missing": {
|
|
552
|
+
const reference = cell.reference;
|
|
553
|
+
let body;
|
|
554
|
+
if (reference) {
|
|
555
|
+
const mark = (_jsx("span", { className: "niceeval-locator-mark", "aria-hidden": "true", children: verdictMark(reference.verdict === "skipped" ? "skipped" : reference.verdict) }));
|
|
556
|
+
const distance = _jsx("span", { className: "niceeval-stale-distance", children: formatTimeDistance(reference.staleSinceMs, ctx.locale) });
|
|
557
|
+
const title = localeText(ctx.locale, "experimentList.staleReferenceTooltip");
|
|
558
|
+
const href = ctx.href(reference.locator);
|
|
559
|
+
body = href !== undefined ? (_jsxs("a", { className: "niceeval-locator niceeval-stale", href: href, title: title, children: [mark, reference.locator, distance] })) : (_jsxs("span", { className: "niceeval-locator niceeval-stale", title: title, children: [mark, reference.locator, distance] }));
|
|
560
|
+
}
|
|
561
|
+
else {
|
|
562
|
+
body = _jsx("span", { className: "niceeval-missing-reason", children: missingText(cell.code, ctx.locale) });
|
|
563
|
+
}
|
|
564
|
+
return (_jsxs("span", { className: "niceeval-missing", children: [body, cell.detail ? _jsx("small", { className: "niceeval-cell-detail", children: cell.detail }) : null] }));
|
|
565
|
+
}
|
|
553
566
|
case "text":
|
|
554
567
|
return (_jsxs("span", { className: "niceeval-cell-text", children: [_jsx("span", { children: cell.text }), cell.detail ? _jsx("small", { className: "niceeval-cell-detail", children: cell.detail }) : null] }));
|
|
555
568
|
case "locator": {
|
|
556
569
|
// 判定长在 locator 上:判定符与语义色同场,不靠颜色单独表意
|
|
557
570
|
// (docs/feature/reports/components/summaries/experiment-table.md)。
|
|
558
571
|
const verdict = cell.verdict;
|
|
559
|
-
const
|
|
572
|
+
const stale = cell.staleSinceMs !== undefined;
|
|
573
|
+
const className = cx("niceeval-locator", verdict !== undefined ? `niceeval-verdict-${verdict}` : undefined, stale ? "niceeval-stale" : undefined);
|
|
560
574
|
const mark = verdict === undefined ? null : (_jsx("span", { className: "niceeval-locator-mark", "aria-hidden": "true", children: verdictMark(verdict === "skipped" ? "skipped" : verdict) }));
|
|
575
|
+
const distance = stale ? (_jsx("span", { className: "niceeval-stale-distance", children: formatTimeDistance(cell.staleSinceMs, ctx.locale) })) : null;
|
|
576
|
+
const title = stale ? localeText(ctx.locale, "experimentList.historicalTooltip") : undefined;
|
|
561
577
|
const href = ctx.href(cell.locator);
|
|
562
|
-
return href !== undefined ? (_jsxs("a", { className: className, href: href, children: [mark, cell.locator] })) : (
|
|
578
|
+
return href !== undefined ? (_jsxs("a", { className: className, href: href, title: title, children: [mark, cell.locator, distance] })) : (_jsxs("span", { className: className, title: title, children: [mark, cell.locator, distance] }));
|
|
563
579
|
}
|
|
564
580
|
case "summary":
|
|
565
581
|
case "score":
|
|
@@ -570,11 +586,20 @@ function renderCellWeb(cell, ctx) {
|
|
|
570
586
|
return (_jsxs("span", { className: "niceeval-verdict-tally", children: [parts.map((kind) => (_jsxs("span", { className: `niceeval-verdict-${kind}`, children: [cell.counts[kind], " ", localeText(ctx.locale, `verdict.${kind === "skipped" ? "skipped" : kind}`)] }, kind))), parts.length === 0 ? _jsx("span", { className: "niceeval-missing", children: MISSING_MARK }) : null] }));
|
|
571
587
|
}
|
|
572
588
|
const verdict = cell.verdict ?? "skipped";
|
|
589
|
+
const stale = cell.staleSinceMs !== undefined;
|
|
573
590
|
// 判定符走 verdictMark 单源,与 locator 格同一张表(errored 是 `!`,不并到 `✗`)。
|
|
574
|
-
return (_jsxs("span", { className:
|
|
591
|
+
return (_jsxs("span", { className: cx("niceeval-verdict", `niceeval-verdict-${verdict}`, stale ? "niceeval-stale" : undefined), title: stale ? localeText(ctx.locale, "experimentList.historicalTooltip") : undefined, children: [verdictMark(verdict === "skipped" ? "skipped" : verdict), !cell.bare ? _jsxs(_Fragment, { children: [" ", localeText(ctx.locale, `verdict.${verdict === "skipped" ? "skipped" : verdict}`)] }) : null, stale ? _jsx("span", { className: "niceeval-stale-distance", children: formatTimeDistance(cell.staleSinceMs, ctx.locale) }) : null] }));
|
|
575
592
|
}
|
|
576
593
|
case "metric":
|
|
577
594
|
return (_jsx(MetricCellView, { cell: cell.metric, href: ctx.showMeasureRefs === false ? undefined : ctx.href, locale: ctx.locale }));
|
|
595
|
+
case "composition": {
|
|
596
|
+
// web 面画成一条分段条,hover 一段给出它的名字与计数;段的业务含义住在投影里,
|
|
597
|
+
// 这里只按声明序给一条位置驱动的渐隐色阶(docs/feature/reports/components/primitives/table.md「构成格」)。
|
|
598
|
+
const total = cell.segments.reduce((sum, segment) => sum + segment.count, 0);
|
|
599
|
+
if (total === 0)
|
|
600
|
+
return _jsx("span", { className: "niceeval-missing", children: MISSING_MARK });
|
|
601
|
+
return (_jsx("span", { className: "niceeval-composition", children: cell.segments.map((segment, i) => segment.count > 0 ? (_jsx("span", { className: "niceeval-composition-segment", style: { width: `${(segment.count / total) * 100}%`, "--composition-step": i }, title: `${resolveLocalizedText(segment.label, ctx.locale)}: ${segment.count}` }, i)) : null) }));
|
|
602
|
+
}
|
|
578
603
|
default: {
|
|
579
604
|
const _e = cell;
|
|
580
605
|
return _e;
|
|
@@ -92,8 +92,9 @@ export interface WebContext {
|
|
|
92
92
|
/** chrome 文案的 locale;官方组件渲染面经上下文读取,宿主外默认 "en"。 */
|
|
93
93
|
locale: ReportLocale;
|
|
94
94
|
/**
|
|
95
|
-
* 取本组件 `dimensions()` 声明的某个句柄在这一页的呈现面(
|
|
96
|
-
*
|
|
95
|
+
* 取本组件 `dimensions()` 声明的某个句柄在这一页的呈现面(label / color / series 的
|
|
96
|
+
* fill·stroke·marker 等可直接使用的值)。查别的组件的句柄或没声明的句柄抛
|
|
97
|
+
* `UndeclaredDimensionValueError`。
|
|
97
98
|
*/
|
|
98
99
|
dimension(handle: string): PresentedDimension;
|
|
99
100
|
}
|
|
@@ -152,6 +153,8 @@ export type ReportComponent<P extends object> = ((props: P) => ReactNode) & {
|
|
|
152
153
|
*/
|
|
153
154
|
export interface PageDimensions {
|
|
154
155
|
dimension(props: object, handle: string): PresentedDimension;
|
|
156
|
+
/** 维度 name → 值 → seriesSlot;测试与调试观察槽位分配,组件渲染不读槽号。 */
|
|
157
|
+
readonly slotsByDimension: ReadonlyMap<string, ReadonlyMap<string, number>>;
|
|
155
158
|
}
|
|
156
159
|
/** 宿主渲染前把这一页的分配结果挂到渲染上下文上(text 与 web 同一条通道)。 */
|
|
157
160
|
export declare function withPageDimensions<C extends object>(ctx: C, plan: PageDimensions | undefined): C;
|
|
@@ -142,6 +142,7 @@ export function collectPageDimensions(node, pins = {}, face = "web") {
|
|
|
142
142
|
visit(node);
|
|
143
143
|
const plan = allocatePageDimensions(handles, pins, { face });
|
|
144
144
|
return {
|
|
145
|
+
slotsByDimension: plan.slotsByDimension,
|
|
145
146
|
dimension(props, handle) {
|
|
146
147
|
const entry = byProps.get(props);
|
|
147
148
|
const key = entry?.keys.get(handle);
|
package/dist/report/index.d.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
export { aggregate, agent, costUSD, dedupeLocators, durationMs, evalId, evidenceRow, experiment, isCalculation, isMetricValue, max, mean, metricValue, min, model, parseEvidenceRow, parseEvidenceRows, passRate, percentile, rollup, sum, tokens, totalScore, } from "./model/calculation.ts";
|
|
2
2
|
export type { AggregateRow, AggregationSubject, Calculation, EvidenceRow, GroupFunction, MetricBasis, MetricFormat, MetricValue, Reducer, RollupOptions, } from "./model/calculation.ts";
|
|
3
|
-
export { toAttemptAssertions, toAttemptFixPrompt, toAttemptListRows, toAttemptNotices, toAttemptRows, toAttemptSource, toAttemptSummary, toAttemptUsage, toConversationTurns, toDiffFiles, toEvalRows, toExperimentDetails, toExperimentRows, toHeroData, toRunNotices, toSampleFixPrompt, toSampleNotices, toSummaryItems, toTimelineNodes, toTraceNodes, } from "./model/conversions.ts";
|
|
3
|
+
export { toAttemptAssertions, toAttemptFacts, toAttemptFixPrompt, toAttemptListRows, toAttemptNotices, toAttemptRows, toAttemptSource, toAttemptSummary, toAttemptUsage, toConversationTurns, toDiffFiles, toEvalRows, toExperimentDetails, toExperimentRows, toHeroData, toRunNotices, toSampleFixPrompt, toSampleNotices, toSummaryItems, toTimelineNodes, toTraceNodes, } from "./model/conversions.ts";
|
|
4
4
|
export { presentDimension, shortestUniqueLabels } from "./presentation.ts";
|
|
5
|
-
export type { DimensionDeclaration, DimensionEncoding, PresentedDimension } from "./presentation.ts";
|
|
5
|
+
export type { ColorPresentation, DimensionDeclaration, DimensionEncoding, DimensionPresentation, FillSeriesPresentation, LabelPresentation, LineSeriesPresentation, PresentedDimension, ScatterSeriesPresentation, } from "./presentation.ts";
|
|
6
6
|
export { flag, label, numericFlag, numericLabel, numericRunConfig, runConfig } from "./model/flag.ts";
|
|
7
7
|
export { evaluationKindComposition } from "./model/evaluation-kind.ts";
|
|
8
8
|
export { annotatedSourceResult, attemptDetailsResult, comparisonResult, conversationResult, diffResult, historyResult, stabilityResult, standardOverviewResult, timingResult, usageResult, } from "./tasks.ts";
|
|
@@ -22,7 +22,7 @@ export { Area, Bars, Callouts, Chart, Col, CommandEvidence, Conversation, CopyBl
|
|
|
22
22
|
export type { AreaProps, BarsProps, BarsSort, EvidenceAxisKey, EvidenceDimensionKey, CalloutGroup, CalloutItem, CalloutLevel, CalloutsProps, ChartPresentation, ChartProps, ChartAxisBinding, ChartFieldBinding, ChartSeriesOverride, ColProps, ConversationContent, ConversationEntry, ConversationProps, ConversationTurn, CopyBlockContent, CopyBlockProps, DiffChange, DiffContent, DiffFile, DiffFileWindow, DiffViewProps, ExternalAreaProps, ExternalAxisKey, ExternalBarsProps, ExternalLineProps, ExternalScatterProps, CommandEvidenceContent, CommandEvidenceItem, CommandEvidenceProps, GridProps, LayoutProps, LineProps, MarkdownProps, PlainTableColumn, RowProps, ScatterProps, SectionProps, SeriesProps, SourceBlockContent, SourceCallContent, SourceContent, SourceLine, SourceViewProps, StatProps, StatTone, StyleProps, TabProps, TableProps, TabsProps, TextProps, WaterfallContent, WaterfallNode, WaterfallProps, WaterfallRow, } from "./definition/primitives.tsx";
|
|
23
23
|
export type { Cell, VerdictCounts } from "./definition/cell.ts";
|
|
24
24
|
export { formatCellText } from "./definition/cell.ts";
|
|
25
|
-
export { formatAxisTick, formatInstant, formatMetricValue, missingText } from "./model/format.ts";
|
|
25
|
+
export { formatAxisTick, formatInstant, formatMetricValue, formatTimeDistance, missingText } from "./model/format.ts";
|
|
26
26
|
export { stringWidth, padDisplay as padEnd, padStartDisplay as padStart, wrapDisplay as wrapText, indentBlock as indent, textBar as bar, joinColumns as columns, } from "./model/text-layout.ts";
|
|
27
27
|
export type { ColumnAlign } from "./model/text-layout.ts";
|
|
28
28
|
export { DEFAULT_REPORT_LOCALE, localizedTextEquals, resolveLocalizedText, resolveMetricLabel, } from "./model/locale.ts";
|
|
@@ -38,6 +38,6 @@ export { AttemptAssessment, AttemptDetails, AttemptSummary, } from "./components
|
|
|
38
38
|
export type { AttemptDetailsProps } from "./components/attempt-detail/index.tsx";
|
|
39
39
|
export { ExperimentDetails } from "./components/experiment-detail/index.tsx";
|
|
40
40
|
export type { ExperimentDetailsProps } from "./components/experiment-detail/index.tsx";
|
|
41
|
-
export type { Aggregator, AttemptListItem, AttemptLocator, BuiltInDimension, CopyFixPromptData, CustomDimension, DeltaCell, DeltaData, DimensionInput, DimensionOptions, DimensionRef, EvalListItem, ExperimentDetailsData, ExperimentListEvalRow, ExperimentListItem, FlagConditions, HeroData, NumericAxis, NumericAxisOptions, NumericRunConfigAxisOptions, ReportInput, RunConfigKey, SampleSummaryContent, SampleIssue, EvaluationKindComposition, SeriesInput, SnapshotDiagnosticsData, SnapshotDiagnosticsItem, TraceSpanSummary, TraceWaterfallRow, VerdictTally, } from "./model/types.ts";
|
|
42
|
-
export type { AttemptAssertionsData, AttemptConversationData, AttemptConversationReply, AttemptConversationRound, AttemptDiagnosticsData, AttemptDiffData, AttemptErrorData, AttemptFixPromptData, AttemptSummaryData, AttemptTimelineData, AttemptTraceData, UsageTableData, } from "./model/types.ts";
|
|
41
|
+
export type { Aggregator, AttemptListItem, AttemptLocator, BuiltInDimension, CopyFixPromptData, CustomDimension, DeltaCell, DeltaData, DimensionInput, DimensionOptions, DimensionRef, EvalListItem, ExperimentDetailsData, ExperimentListEvalRow, ExperimentListItem, FlagConditions, HeroData, NumericAxis, NumericAxisOptions, NumericRunConfigAxisOptions, ReportInput, RunConfigKey, SampleSummaryContent, SampleIssue, EvaluationKindComposition, SeriesInput, SnapshotDiagnosticsData, SnapshotDiagnosticsItem, StaleConclusionReference, TraceSpanSummary, TraceWaterfallRow, VerdictTally, } from "./model/types.ts";
|
|
42
|
+
export type { AttemptAssertionsData, AttemptConversationData, AttemptConversationReply, AttemptConversationRound, AttemptDiagnosticsData, AttemptDiffData, AttemptErrorData, AttemptFactsData, AttemptFixPromptData, AttemptSummaryData, AttemptTimelineData, AttemptTraceData, UsageTableData, } from "./model/types.ts";
|
|
43
43
|
export type { AttemptHandle, Record, Sample, Run } from "../record/types.ts";
|
package/dist/report/index.js
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
// 官方 Calculation(普通值作者模型);内部切片仍可用 AttemptMetric 字面量,不导出 defineMeasure。
|
|
9
9
|
// 普通值计算内核
|
|
10
10
|
export { aggregate, agent, costUSD, dedupeLocators, durationMs, evalId, evidenceRow, experiment, isCalculation, isMetricValue, max, mean, metricValue, min, model, parseEvidenceRow, parseEvidenceRows, passRate, percentile, rollup, sum, tokens, totalScore, } from "./model/calculation.js";
|
|
11
|
-
export { toAttemptAssertions, toAttemptFixPrompt, toAttemptListRows, toAttemptNotices, toAttemptRows, toAttemptSource, toAttemptSummary, toAttemptUsage, toConversationTurns, toDiffFiles, toEvalRows, toExperimentDetails, toExperimentRows, toHeroData, toRunNotices, toSampleFixPrompt, toSampleNotices, toSummaryItems, toTimelineNodes, toTraceNodes, } from "./model/conversions.js";
|
|
11
|
+
export { toAttemptAssertions, toAttemptFacts, toAttemptFixPrompt, toAttemptListRows, toAttemptNotices, toAttemptRows, toAttemptSource, toAttemptSummary, toAttemptUsage, toConversationTurns, toDiffFiles, toEvalRows, toExperimentDetails, toExperimentRows, toHeroData, toRunNotices, toSampleFixPrompt, toSampleNotices, toSummaryItems, toTimelineNodes, toTraceNodes, } from "./model/conversions.js";
|
|
12
12
|
export { presentDimension, shortestUniqueLabels } from "./presentation.js";
|
|
13
13
|
export { flag, label, numericFlag, numericLabel, numericRunConfig, runConfig } from "./model/flag.js";
|
|
14
14
|
export { evaluationKindComposition } from "./model/evaluation-kind.js";
|
|
@@ -24,7 +24,7 @@ export { defineComponent, createTextContext, renderNodeToText, resolveReportTree
|
|
|
24
24
|
export { Area, Bars, Callouts, Chart, Col, CommandEvidence, Conversation, CopyBlock, DiffView, Grid, Line, Markdown, Row, Scatter, Section, Series, SourceView, Stat, Style, Tab, Table, Tabs, Text, Waterfall, applyBarsSortLimit, } from "./definition/primitives.js";
|
|
25
25
|
export { formatCellText } from "./definition/cell.js";
|
|
26
26
|
// 格式化与呈现工具箱(docs/feature/reports/library/presentation.md):渲染侧单点入口。
|
|
27
|
-
export { formatAxisTick, formatInstant, formatMetricValue, missingText } from "./model/format.js";
|
|
27
|
+
export { formatAxisTick, formatInstant, formatMetricValue, formatTimeDistance, missingText } from "./model/format.js";
|
|
28
28
|
// 文本排版工具箱:自定义组件的 text 面用的就是官方组件那把尺子。
|
|
29
29
|
// 表格有 <Table> 承担,这里只给表以外的形态用 —— 尤其别拿 String.prototype.padEnd 对齐:
|
|
30
30
|
// 它数 UTF-16 码元不数显示列宽,一带中文列就撕歪。renderAlignedRows 刻意不导出。
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { AttemptHandle, SampleCoverage, SampleIssue, Run } from "../../record/types.ts";
|
|
2
2
|
import { type AttemptLocator } from "../../record/locator.ts";
|
|
3
|
-
import type { Aggregator, DimensionInput, AttemptMetric, MetricValue, MetricColumn, NumericAxis, ReportInput, SeriesInput } from "./types.ts";
|
|
3
|
+
import type { Aggregator, DimensionInput, AttemptMetric, MetricValue, MetricColumn, NumericAxis, ReportInput, SeriesInput, StaleConclusionReference } from "./types.ts";
|
|
4
4
|
import { type LocalizedText } from "./locale.ts";
|
|
5
5
|
import { evalPrefixPredicate } from "../../shared/aggregate.ts";
|
|
6
6
|
import type { JsonValue } from "../../shared/types.ts";
|
|
@@ -15,6 +15,10 @@ export declare function resolveInput(input: ReportInput): {
|
|
|
15
15
|
attempts: readonly AttemptHandle[];
|
|
16
16
|
issues: readonly SampleIssue[];
|
|
17
17
|
coverage: readonly SampleCoverage[];
|
|
18
|
+
/** 同一总体内按 locator 去重的完整历史 attempt;裸 `Run[]` 没有挑选过程,取全部。 */
|
|
19
|
+
historyAttempts: readonly AttemptHandle[];
|
|
20
|
+
/** 是否只保留新执行的 attempt;裸 `Run[]` 没有这个口径,恒为 false。 */
|
|
21
|
+
fresh: boolean;
|
|
18
22
|
};
|
|
19
23
|
/**
|
|
20
24
|
* 展平后的一条样本:`run` 始终是 attempt 的真实来源(= `attempt.run`,快照维度/
|
|
@@ -37,6 +41,15 @@ export declare function evalIdOf(item: Item): string;
|
|
|
37
41
|
* 来源可能有多个,水位基准是其中 startedAt 最新的一个。
|
|
38
42
|
*/
|
|
39
43
|
export declare function historicalOf(item: Item): boolean;
|
|
44
|
+
/** 一个 ISO 时刻距渲染时刻(`Date.now()`)的毫秒数,恒不小于 0。 */
|
|
45
|
+
export declare function msSince(iso: string): number;
|
|
46
|
+
/**
|
|
47
|
+
* 覆盖缺口 / 对照矩阵缺席格的「过期结论」参考(docs/feature/reports/components/summaries/
|
|
48
|
+
* experiment-table.md「覆盖缺口的两档占位行」、show/compare.md 同一套口径):候选已经是与
|
|
49
|
+
* 当前基准 configHash 不可比的那些,取其中最近一条;两个消费方(entity-lists 的占位行、
|
|
50
|
+
* DeltaTable 的缺席格)共用同一份「取最新」判据,不各自实现一遍。
|
|
51
|
+
*/
|
|
52
|
+
export declare function staleReferenceOf(candidates: readonly AttemptHandle[]): StaleConclusionReference | undefined;
|
|
40
53
|
/** 快照键:"<experimentId> @ <startedAt>"("run" 维度与手挑快照数组的对比用)。 */
|
|
41
54
|
export declare function snapshotKeyOf(run: Run): string;
|
|
42
55
|
/** 一组 Item 的 eval 全身份键:experimentId + eval id(聚合中的题级身份始终是这一对)。 */
|
|
@@ -22,10 +22,18 @@ const KEY_SEP = "\u0000";
|
|
|
22
22
|
export function resolveInput(input) {
|
|
23
23
|
if (Array.isArray(input)) {
|
|
24
24
|
const runs = input;
|
|
25
|
-
|
|
25
|
+
const attempts = runs.flatMap((s) => s.attempts);
|
|
26
|
+
return { runs, attempts, issues: [], coverage: [], historyAttempts: attempts, fresh: false };
|
|
26
27
|
}
|
|
27
28
|
const scope = input;
|
|
28
|
-
return {
|
|
29
|
+
return {
|
|
30
|
+
runs: scope.runs,
|
|
31
|
+
attempts: scope.attempts,
|
|
32
|
+
issues: scope.issues,
|
|
33
|
+
coverage: scope.coverage,
|
|
34
|
+
historyAttempts: scope.historyAttempts,
|
|
35
|
+
fresh: scope.fresh,
|
|
36
|
+
};
|
|
29
37
|
}
|
|
30
38
|
export function experimentIdOf(item) {
|
|
31
39
|
return item.attempt.experimentId || item.run.experimentId;
|
|
@@ -42,6 +50,30 @@ export function evalIdOf(item) {
|
|
|
42
50
|
export function historicalOf(item) {
|
|
43
51
|
return item.attempt.carried || item.run.startedAt < item.watermark.startedAt;
|
|
44
52
|
}
|
|
53
|
+
/** 一个 ISO 时刻距渲染时刻(`Date.now()`)的毫秒数,恒不小于 0。 */
|
|
54
|
+
export function msSince(iso) {
|
|
55
|
+
return Math.max(0, Date.now() - Date.parse(iso));
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* 覆盖缺口 / 对照矩阵缺席格的「过期结论」参考(docs/feature/reports/components/summaries/
|
|
59
|
+
* experiment-table.md「覆盖缺口的两档占位行」、show/compare.md 同一套口径):候选已经是与
|
|
60
|
+
* 当前基准 configHash 不可比的那些,取其中最近一条;两个消费方(entity-lists 的占位行、
|
|
61
|
+
* DeltaTable 的缺席格)共用同一份「取最新」判据,不各自实现一遍。
|
|
62
|
+
*/
|
|
63
|
+
export function staleReferenceOf(candidates) {
|
|
64
|
+
if (candidates.length === 0)
|
|
65
|
+
return undefined;
|
|
66
|
+
const newest = candidates.reduce((a, b) => ((a.result.startedAt ?? "") >= (b.result.startedAt ?? "") ? a : b));
|
|
67
|
+
const startedAt = newest.result.startedAt;
|
|
68
|
+
if (!startedAt)
|
|
69
|
+
return undefined; // 无时刻的 legacy 落盘算不出时距,不伪造参考
|
|
70
|
+
return {
|
|
71
|
+
locator: newest.locator ??
|
|
72
|
+
encodeAttemptLocator({ runId: newest.run.runId, evalId: newest.evalId, attempt: newest.result.attempt }),
|
|
73
|
+
verdict: newest.result.verdict,
|
|
74
|
+
staleSinceMs: msSince(startedAt),
|
|
75
|
+
};
|
|
76
|
+
}
|
|
45
77
|
/** 快照键:"<experimentId> @ <startedAt>"("run" 维度与手挑快照数组的对比用)。 */
|
|
46
78
|
export function snapshotKeyOf(run) {
|
|
47
79
|
return `${run.experimentId} @ ${run.startedAt}`;
|
|
@@ -37,3 +37,4 @@ export declare function toAttemptSource(attempt: AttemptEvidence): Promise<impor
|
|
|
37
37
|
export declare function toAttemptAssertions(attempt: AttemptEvidence): Promise<import("../definition/cell.ts").TableContent | null>;
|
|
38
38
|
export declare function toAttemptFixPrompt(attempt: AttemptEvidence): Promise<CopyBlockContent | null>;
|
|
39
39
|
export declare function toAttemptUsage(attempt: AttemptEvidence): Promise<import("./types.ts").UsageTableData | null>;
|
|
40
|
+
export declare function toAttemptFacts(attempt: AttemptEvidence): Promise<import("./types.ts").AttemptFactsData | null>;
|
|
@@ -6,7 +6,7 @@ import { sampleSummary } from "../components/summaries/compute.js";
|
|
|
6
6
|
import { runNoticesContent, sampleFixPromptContent, sampleNoticesContent, sampleTracesContent, } from "../components/site-components/projections.js";
|
|
7
7
|
import { heroData } from "../components/site-components/compute.js";
|
|
8
8
|
import { attemptAssertionsContent, attemptCommandEvidenceContent, attemptConversationContent, attemptDiffContent, attemptFixPromptContent, attemptNoticesContent, projectedSourceContent, attemptTimelineContent, } from "../components/attempt-detail/content.js";
|
|
9
|
-
import { attemptAssertionsData, attemptCommandEvidenceData, attemptConversationData, attemptDiagnosticsData, attemptDiffData, attemptErrorData, attemptFixPromptData, attemptSummaryData, attemptTimelineData, usageTableData, } from "../components/attempt-detail/compute.js";
|
|
9
|
+
import { attemptAssertionsData, attemptCommandEvidenceData, attemptConversationData, attemptDiagnosticsData, attemptDiffData, attemptErrorData, attemptFactsData, attemptFixPromptData, attemptSummaryData, attemptTimelineData, usageTableData, } from "../components/attempt-detail/compute.js";
|
|
10
10
|
/** Sample 挑选警告 → Callouts items。 */
|
|
11
11
|
export function toSampleNotices(sample) {
|
|
12
12
|
return sampleNoticesContent(sample);
|
|
@@ -83,3 +83,6 @@ export async function toAttemptFixPrompt(attempt) {
|
|
|
83
83
|
export async function toAttemptUsage(attempt) {
|
|
84
84
|
return usageTableData(attempt);
|
|
85
85
|
}
|
|
86
|
+
export async function toAttemptFacts(attempt) {
|
|
87
|
+
return attemptFactsData(attempt);
|
|
88
|
+
}
|
|
@@ -68,12 +68,13 @@ export declare function formatReportDateTimeRange(fromIso: string, toIso: string
|
|
|
68
68
|
to: string;
|
|
69
69
|
};
|
|
70
70
|
/**
|
|
71
|
-
*
|
|
72
|
-
*
|
|
73
|
-
*
|
|
74
|
-
*
|
|
71
|
+
* 一段时长(毫秒) → 当前 locale 的紧凑相对时距("12d" / "12 天")。按区间选粒度最大的单位
|
|
72
|
+
* 取整,结果恒不小于一个单位(docs/feature/reports/library/presentation.md「相对时距是数据,
|
|
73
|
+
* 不是文案」):不足 1 小时→分钟,不足 1 天→小时,不足 30 天→天,30 天及以上→月。
|
|
74
|
+
* `locator` 格与占位行参考的 `staleSinceMs` 都经这一个入口,不各写各的措辞;不加箭头、回环
|
|
75
|
+
* 之类的装饰记号——记号不携带时长,读者还要先学会它。
|
|
75
76
|
*/
|
|
76
|
-
export declare function
|
|
77
|
+
export declare function formatTimeDistance(ms: number, locale?: ReportLocale): string;
|
|
77
78
|
/** passed / failed / errored / skipped 的判定符。 */
|
|
78
79
|
export declare function verdictMark(verdict: Verdict): string;
|
|
79
80
|
/**
|