niceeval 0.8.1 → 0.9.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 +77 -45
- package/dist/agents/types.d.ts +28 -6
- package/dist/i18n/en.d.ts +2 -0
- package/dist/i18n/zh-CN.d.ts +2 -0
- package/dist/report/built-in/index.d.ts +3 -2
- package/dist/report/built-in/index.js +7 -8
- package/dist/report/built-in/standard.d.ts +1 -0
- package/dist/report/built-in/standard.js +30 -0
- package/dist/report/components.d.ts +69 -2
- package/dist/report/components.js +152 -3
- package/dist/report/compute.d.ts +28 -1
- package/dist/report/compute.js +123 -0
- package/dist/report/index.d.ts +4 -4
- package/dist/report/index.js +3 -2
- package/dist/report/locale.d.ts +39 -1
- package/dist/report/locale.js +69 -0
- package/dist/report/react/AttemptList.d.ts +3 -1
- package/dist/report/react/AttemptList.js +3 -3
- package/dist/report/react/CopyFixPrompt.d.ts +12 -0
- package/dist/report/react/CopyFixPrompt.js +12 -0
- package/dist/report/react/HeroCard.d.ts +13 -0
- package/dist/report/react/HeroCard.js +35 -0
- package/dist/report/react/PoweredBy.d.ts +5 -0
- package/dist/report/react/PoweredBy.js +7 -0
- package/dist/report/react/ScopeWarnings.d.ts +12 -0
- package/dist/report/react/ScopeWarnings.js +18 -0
- package/dist/report/react/TraceWaterfall.d.ts +14 -0
- package/dist/report/react/TraceWaterfall.js +22 -0
- package/dist/report/react/index.d.ts +6 -1
- package/dist/report/react/index.js +6 -0
- package/dist/report/report.d.ts +22 -6
- package/dist/report/report.js +66 -53
- package/dist/report/scope-warnings.d.ts +28 -0
- package/dist/report/scope-warnings.js +101 -0
- package/dist/report/text/faces.d.ts +19 -1
- package/dist/report/text/faces.js +61 -0
- package/dist/report/tree.js +6 -1
- package/dist/report/types.d.ts +45 -0
- package/dist/report/web.d.ts +5 -4
- package/dist/report/web.js +7 -22
- package/dist/results/select.d.ts +15 -2
- package/dist/results/select.js +75 -10
- package/dist/results/types.d.ts +26 -0
- package/dist/runner/fingerprint.d.ts +3 -3
- package/dist/runner/sandbox-selection.d.ts +12 -0
- package/dist/runner/types.d.ts +18 -6
- package/dist/sandbox/types.d.ts +12 -0
- package/docs-site/zh/explanation/evals.mdx +2 -1
- package/docs-site/zh/explanation/experiment.mdx +2 -0
- package/docs-site/zh/how-to/custom-reports.mdx +22 -6
- package/docs-site/zh/how-to/publish-report.mdx +5 -4
- package/docs-site/zh/how-to/viewing-results.mdx +3 -3
- package/docs-site/zh/how-to/write-experiment.mdx +40 -1
- package/docs-site/zh/reference/builtin-agents.mdx +40 -3
- package/docs-site/zh/reference/cli.mdx +1 -1
- package/docs-site/zh/reference/define-eval.mdx +8 -0
- package/docs-site/zh/reference/official-adapters.mdx +10 -5
- package/package.json +2 -1
- package/src/agents/bub.ts +13 -1
- package/src/agents/claude-code.test.ts +43 -1
- package/src/agents/claude-code.ts +32 -14
- package/src/agents/codex.test.ts +168 -1
- package/src/agents/codex.ts +51 -15
- package/src/agents/mcp.ts +31 -0
- package/src/agents/post-setup.ts +33 -0
- package/src/agents/types.ts +28 -7
- package/src/cli.ts +8 -6
- package/src/define.ts +3 -0
- package/src/i18n/en.ts +5 -2
- package/src/i18n/zh-CN.ts +5 -1
- package/src/index.ts +1 -0
- package/src/report/built-in/index.tsx +8 -7
- package/src/report/built-in/standard.tsx +59 -0
- package/src/report/components.tsx +218 -2
- package/src/report/compute.ts +138 -1
- package/src/report/dual-render.test.tsx +139 -12
- package/src/report/index.ts +20 -0
- package/src/report/locale.ts +83 -1
- package/src/report/react/AttemptList.tsx +13 -1
- package/src/report/react/CopyFixPrompt.tsx +37 -0
- package/src/report/react/HeroCard.tsx +59 -0
- package/src/report/react/PoweredBy.tsx +20 -0
- package/src/report/react/ScopeWarnings.tsx +74 -0
- package/src/report/react/TraceWaterfall.tsx +78 -0
- package/src/report/react/enhance.js +14 -0
- package/src/report/react/index.tsx +11 -0
- package/src/report/react/styles.css +187 -7
- package/src/report/report.ts +97 -62
- package/src/report/scope-warnings.ts +155 -0
- package/src/report/site-components.test.tsx +526 -0
- package/src/report/text/faces.ts +66 -0
- package/src/report/tree.ts +8 -1
- package/src/report/types.ts +51 -0
- package/src/report/web.ts +7 -40
- package/src/results/host-equivalence.test.ts +5 -1
- package/src/results/open.ts +5 -4
- package/src/results/results.test.ts +78 -1
- package/src/results/select.ts +78 -10
- package/src/results/types.ts +27 -0
- package/src/runner/attempt.ts +10 -9
- package/src/runner/discover.test.ts +9 -1
- package/src/runner/discover.ts +3 -3
- package/src/runner/fingerprint.ts +9 -4
- package/src/runner/ledger.test.ts +30 -1
- package/src/runner/ledger.ts +26 -4
- package/src/runner/run.ts +5 -1
- package/src/runner/sandbox-selection.test.ts +131 -0
- package/src/runner/sandbox-selection.ts +110 -0
- package/src/runner/types.ts +19 -2
- package/src/sandbox/types.ts +6 -0
- package/src/show/index.ts +17 -10
- package/src/show/render.ts +11 -11
- package/src/show/report-host.test.ts +32 -15
- package/src/show/report-host.ts +5 -4
- package/src/show/show.test.ts +140 -3
- package/src/view/app/App.test.tsx +78 -17
- package/src/view/app/App.tsx +17 -78
- package/src/view/app/components/CopyControls.tsx +4 -42
- package/src/view/app/i18n.ts +5 -227
- package/src/view/app/lib/rows.ts +3 -21
- package/src/view/app/shared.ts +1 -3
- package/src/view/app/types.ts +2 -2
- package/src/view/client-dist/app.css +1 -1
- package/src/view/client-dist/app.js +20 -20
- package/src/view/data.ts +2 -2
- package/src/view/shared/types.ts +11 -6
- package/src/view/styles.css +6 -266
- package/src/view/view-report.test.ts +59 -22
- package/src/view/app/components/LazyArtifact.tsx +0 -51
- package/src/view/app/components/SkippedRunsBanner.tsx +0 -140
- package/src/view/app/pages/AttemptsPage.tsx +0 -80
- package/src/view/app/pages/TracesPage.tsx +0 -35
package/dist/report/compute.js
CHANGED
|
@@ -774,3 +774,126 @@ function deltaOutcome(metric, delta) {
|
|
|
774
774
|
const better = metric.better ?? "higher";
|
|
775
775
|
return (delta > 0) === (better === "higher") ? "improved" : "regressed";
|
|
776
776
|
}
|
|
777
|
+
// ───────────────────────── 站点组件的计算函数(hero / warnings / fix prompt / trace)─────────────────────────
|
|
778
|
+
/**
|
|
779
|
+
* `heroData(input)`:站点标题区的运行 meta——`latestStartedAt` 取范围内最新快照的开始时间
|
|
780
|
+
* (空范围为 null,不编造当前时间),`snapshots` 计贡献当前水位的快照数
|
|
781
|
+
* (docs/feature/reports/library/site-components.md「HeroCard」)。
|
|
782
|
+
*/
|
|
783
|
+
export async function heroData(input) {
|
|
784
|
+
const { snapshots } = resolveInput(input);
|
|
785
|
+
let latest = null;
|
|
786
|
+
for (const snapshot of snapshots) {
|
|
787
|
+
if (latest === null || snapshot.startedAt > latest)
|
|
788
|
+
latest = snapshot.startedAt;
|
|
789
|
+
}
|
|
790
|
+
return { latestStartedAt: latest, snapshots: snapshots.length };
|
|
791
|
+
}
|
|
792
|
+
/**
|
|
793
|
+
* `scopeWarningsData(input)`:Scope 携带的挑选警告原样透出;`input` 是裸 `Snapshot[]` 时
|
|
794
|
+
* 没有挑选过程、没有警告,返回空数组,也如实
|
|
795
|
+
* (docs/feature/reports/library/site-components.md「ScopeWarnings」)。
|
|
796
|
+
*/
|
|
797
|
+
export async function scopeWarningsData(input) {
|
|
798
|
+
return resolveInput(input).warnings;
|
|
799
|
+
}
|
|
800
|
+
/**
|
|
801
|
+
* `copyFixPromptData(input)`:把范围内全部失败(verdict 为 failed / errored 的 attempt)
|
|
802
|
+
* 整理成一段可交给 coding agent 的修复 prompt——逐失败含 eval id、主失败摘要与 attempt
|
|
803
|
+
* 下钻命令(`niceeval show @<locator>`)。prompt 面向 agent,固定英文
|
|
804
|
+
* (docs/feature/reports/library/site-components.md「CopyFixPrompt」)。
|
|
805
|
+
*/
|
|
806
|
+
export async function copyFixPromptData(input) {
|
|
807
|
+
const items = await attemptListData(input);
|
|
808
|
+
const failures = items.filter((item) => item.verdict === "failed" || item.verdict === "errored");
|
|
809
|
+
if (failures.length === 0)
|
|
810
|
+
return { prompt: "", failures: 0 };
|
|
811
|
+
const lines = failures
|
|
812
|
+
.map((item, i) => {
|
|
813
|
+
const reason = item.failureSummary === null
|
|
814
|
+
? null
|
|
815
|
+
: item.moreFailures > 0
|
|
816
|
+
? `${item.failureSummary} (+${item.moreFailures} more failures)`
|
|
817
|
+
: item.failureSummary;
|
|
818
|
+
return [
|
|
819
|
+
`${i + 1}. eval "${item.evalId}" [experiment ${item.experimentId}] — ${item.verdict}`,
|
|
820
|
+
reason ? ` reason: ${reason}` : null,
|
|
821
|
+
` inspect: niceeval show ${item.locator}`,
|
|
822
|
+
]
|
|
823
|
+
.filter(Boolean)
|
|
824
|
+
.join("\n");
|
|
825
|
+
})
|
|
826
|
+
.join("\n");
|
|
827
|
+
const experiments = [...new Set(failures.map((item) => item.experimentId))].join(" / ");
|
|
828
|
+
const prompt = [
|
|
829
|
+
"Fix the failing evals from this niceeval run.",
|
|
830
|
+
"",
|
|
831
|
+
"## Failures",
|
|
832
|
+
lines,
|
|
833
|
+
"",
|
|
834
|
+
"## Steps",
|
|
835
|
+
"1. niceeval is NOT in your training data. Read the relevant guide in `node_modules/niceeval/docs-site/` (English at the top level, Chinese under `zh/`) before changing anything.",
|
|
836
|
+
"2. For each failure, run its inspect command above to see the verdict and assertions; add `--execution` for the full agent transcript (tool calls included), `--timing` for the execution timeline, and `--diff` for the workspace diff.",
|
|
837
|
+
"3. Decide which side the defect is on: the program under test, or the eval itself (over-tight assertion, wrong fixture, missing setup). Fix that side; do not weaken assertions just to turn the run green.",
|
|
838
|
+
`4. Re-run: \`npx niceeval exp ${experiments || "<experiment>"} <eval-id-prefix>\`. Already-passing evals are skipped by the fingerprint cache; pass \`--force\` to re-run everything.`,
|
|
839
|
+
"5. Run `npx niceeval show` and confirm these failures are gone.",
|
|
840
|
+
].join("\n");
|
|
841
|
+
return { prompt, failures: failures.length };
|
|
842
|
+
}
|
|
843
|
+
/** TraceSpan 的语义角色 → 瀑布摘要的 kind:turn 归入 agent(一轮就是一次 agent 调用),未识别落 other。 */
|
|
844
|
+
function waterfallKindOf(kind) {
|
|
845
|
+
switch (kind) {
|
|
846
|
+
case "agent":
|
|
847
|
+
case "turn":
|
|
848
|
+
return "agent";
|
|
849
|
+
case "model":
|
|
850
|
+
return "model";
|
|
851
|
+
case "tool":
|
|
852
|
+
return "tool";
|
|
853
|
+
default:
|
|
854
|
+
return "other";
|
|
855
|
+
}
|
|
856
|
+
}
|
|
857
|
+
/**
|
|
858
|
+
* `traceWaterfallData(input)`:每个 attempt 一行的执行时间瀑布摘要。span 事实只来自
|
|
859
|
+
* trace artifact(经 AttemptHandle 懒加载的 canonical OTel span);runner 生命周期节点
|
|
860
|
+
* (`result.phases`)不进瀑布。行内只汇总顶层 span(parentSpanId 缺失或不在本 trace 内),
|
|
861
|
+
* 按 startOffsetMs 升序;trace 缺失或为空时 `durationMs` 为 null、行照常出现
|
|
862
|
+
* (docs/feature/reports/library/site-components.md「TraceWaterfall」)。
|
|
863
|
+
*/
|
|
864
|
+
export async function traceWaterfallData(input) {
|
|
865
|
+
const { snapshots } = resolveInput(input);
|
|
866
|
+
const items = collectItems(snapshots);
|
|
867
|
+
return Promise.all(items.map(async (item) => {
|
|
868
|
+
const spans = await item.attempt.trace();
|
|
869
|
+
if (spans === null || spans.length === 0) {
|
|
870
|
+
return {
|
|
871
|
+
experimentId: experimentIdOf(item),
|
|
872
|
+
evalId: evalIdOf(item),
|
|
873
|
+
locator: locatorOf(item),
|
|
874
|
+
durationMs: null,
|
|
875
|
+
spans: [],
|
|
876
|
+
};
|
|
877
|
+
}
|
|
878
|
+
const t0 = Math.min(...spans.map((s) => s.startMs));
|
|
879
|
+
const t1 = Math.max(...spans.map((s) => s.endMs));
|
|
880
|
+
const ids = new Set(spans.map((s) => s.spanId));
|
|
881
|
+
const topLevel = spans.filter((s) => s.parentSpanId === undefined || !ids.has(s.parentSpanId));
|
|
882
|
+
const summaries = topLevel
|
|
883
|
+
.map((s) => ({
|
|
884
|
+
name: s.name,
|
|
885
|
+
kind: waterfallKindOf(s.kind),
|
|
886
|
+
startOffsetMs: s.startMs - t0,
|
|
887
|
+
durationMs: s.endMs - s.startMs,
|
|
888
|
+
failed: s.status === "error",
|
|
889
|
+
}))
|
|
890
|
+
.sort((a, b) => a.startOffsetMs - b.startOffsetMs);
|
|
891
|
+
return {
|
|
892
|
+
experimentId: experimentIdOf(item),
|
|
893
|
+
evalId: evalIdOf(item),
|
|
894
|
+
locator: locatorOf(item),
|
|
895
|
+
durationMs: Math.max(0, t1 - t0),
|
|
896
|
+
spans: summaries,
|
|
897
|
+
};
|
|
898
|
+
}));
|
|
899
|
+
}
|
package/dist/report/index.d.ts
CHANGED
|
@@ -10,10 +10,10 @@ export { stringWidth, padDisplay as padEnd, padStartDisplay as padStart, wrapDis
|
|
|
10
10
|
export type { ColumnAlign } from "./text/layout.ts";
|
|
11
11
|
export { DEFAULT_REPORT_LOCALE, localizedTextEquals, resolveLocalizedText, resolveMetricLabel } from "./locale.ts";
|
|
12
12
|
export type { LocalizedText, ReportLocale } from "./locale.ts";
|
|
13
|
-
export { AttemptList, DeltaTable, EvalList, ExperimentComparison, ExperimentList, FailureList, MetricBars, MetricLine, MetricMatrix, MetricScatter, MetricTable, Scoreboard, ScopeSummary, } from "./components.tsx";
|
|
14
|
-
export type { AttemptListProps, DataProps, DeltaTableProps, EvalListProps, ExperimentComparisonProps, ExperimentListProps, FailureListProps, MetricBarsProps, MetricLineProps, MetricMatrixProps, MetricScatterProps, MetricTableProps, ScoreboardProps, ScopeSummaryProps, } from "./components.tsx";
|
|
15
|
-
export { attemptListData, deltaTableData, evalListData, experimentComparisonData, experimentListData, metricLineData, metricMatrixData, metricScatterData, metricTableData, pairsByFlag, scopeSummaryData, scoreboardData, } from "./compute.ts";
|
|
13
|
+
export { AttemptList, CopyFixPrompt, DeltaTable, EvalList, ExperimentComparison, ExperimentList, FailureList, Hero, HeroCard, MetricBars, MetricLine, MetricMatrix, MetricScatter, MetricTable, PoweredBy, Scoreboard, ScopeSummary, ScopeWarnings, TraceWaterfall, } from "./components.tsx";
|
|
14
|
+
export type { AttemptListProps, CopyFixPromptProps, DataProps, DeltaTableProps, EvalListProps, ExperimentComparisonProps, ExperimentListProps, FailureListProps, HeroCardProps, HeroProps, MetricBarsProps, MetricLineProps, MetricMatrixProps, MetricScatterProps, MetricTableProps, ScoreboardProps, ScopeSummaryProps, ScopeWarningsProps, TraceWaterfallProps, } from "./components.tsx";
|
|
15
|
+
export { attemptListData, copyFixPromptData, deltaTableData, evalListData, experimentComparisonData, experimentListData, heroData, metricLineData, metricMatrixData, metricScatterData, metricTableData, pairsByFlag, scopeSummaryData, scopeWarningsData, scoreboardData, traceWaterfallData, } from "./compute.ts";
|
|
16
16
|
export type { DeltaTableOptions, MetricLineOptions, MetricMatrixOptions, MetricScatterOptions, MetricTableOptions, ScoreboardOptions, } from "./compute.ts";
|
|
17
|
-
export type { Aggregator, AttemptListItem, AttemptLocator, BuiltInDimension, CustomDimension, DeltaData, DeltaPair, DimensionInput, DimensionOptions, DimensionRef, EvalListItem, ExperimentComparisonData, ExperimentComparisonGroupData, ExperimentListEvalRow, ExperimentListItem, FlagPairs, LineData, MatrixData, Metric, MetricAggregate, MetricCell, MetricColumn, NumericAxis, NumericAxisOptions, NumericRunConfigAxisOptions, ReportInput, RunConfigKey, ScatterData, ScopeSummaryData, ScopeWarning, ScoreboardData, TableData, VerdictTally, } from "./types.ts";
|
|
17
|
+
export type { Aggregator, AttemptListItem, AttemptLocator, BuiltInDimension, CopyFixPromptData, CustomDimension, DeltaData, DeltaPair, DimensionInput, DimensionOptions, DimensionRef, EvalListItem, ExperimentComparisonData, ExperimentComparisonGroupData, ExperimentListEvalRow, ExperimentListItem, FlagPairs, HeroData, LineData, MatrixData, Metric, MetricAggregate, MetricCell, MetricColumn, NumericAxis, NumericAxisOptions, NumericRunConfigAxisOptions, ReportInput, RunConfigKey, ScatterData, ScopeSummaryData, ScopeWarning, ScoreboardData, TableData, TraceSpanSummary, TraceWaterfallRow, VerdictTally, } from "./types.ts";
|
|
18
18
|
export type { AttemptHandle, Results, Scope, Snapshot } from "../results/types.ts";
|
|
19
19
|
export { experimentGroupOf } from "../shared/aggregate.ts";
|
package/dist/report/index.js
CHANGED
|
@@ -20,10 +20,11 @@ export { stringWidth, padDisplay as padEnd, padStartDisplay as padStart, wrapDis
|
|
|
20
20
|
// locale:官方组件 chrome 文案的语言(内置词典覆盖 en / zh-CN,其它 locale 走回退)
|
|
21
21
|
export { DEFAULT_REPORT_LOCALE, localizedTextEquals, resolveLocalizedText, resolveMetricLabel } from "./locale.js";
|
|
22
22
|
// 官方双面组件(spec / data 双形态;配套 *Data 计算函数在下面成对导出)
|
|
23
|
-
|
|
23
|
+
// 与站点组件(Hero / HeroCard / PoweredBy / ScopeWarnings / CopyFixPrompt / TraceWaterfall)
|
|
24
|
+
export { AttemptList, CopyFixPrompt, DeltaTable, EvalList, ExperimentComparison, ExperimentList, FailureList, Hero, HeroCard, MetricBars, MetricLine, MetricMatrix, MetricScatter, MetricTable, PoweredBy, Scoreboard, ScopeSummary, ScopeWarnings, TraceWaterfall, } from "./components.js";
|
|
24
25
|
// 计算函数(组件解析面的具名形式,与组件成对;spec 形态下由管线代调,data 形态与
|
|
25
26
|
// 嵌入场景下由作者手工调)
|
|
26
|
-
export { attemptListData, deltaTableData, evalListData, experimentComparisonData, experimentListData, metricLineData, metricMatrixData, metricScatterData, metricTableData, pairsByFlag, scopeSummaryData, scoreboardData, } from "./compute.js";
|
|
27
|
+
export { attemptListData, copyFixPromptData, deltaTableData, evalListData, experimentComparisonData, experimentListData, heroData, metricLineData, metricMatrixData, metricScatterData, metricTableData, pairsByFlag, scopeSummaryData, scopeWarningsData, scoreboardData, traceWaterfallData, } from "./compute.js";
|
|
27
28
|
// experiment id 的组键推导(id 的目录前缀,如 `compare/bub-low` 的 `compare`)。
|
|
28
29
|
// 重新导出,让自定义报告能按同一份口径把 experiment 分组,不必自己重写这两行逻辑。
|
|
29
30
|
export { experimentGroupOf } from "../shared/aggregate.js";
|
package/dist/report/locale.d.ts
CHANGED
|
@@ -104,13 +104,51 @@ declare const en: {
|
|
|
104
104
|
readonly "scoreboard.subjectTitle": "{questions} evals, weighted {earned} of {possible}";
|
|
105
105
|
readonly "delta.pairHeader": "pair (A → B)";
|
|
106
106
|
readonly "delta.empty": "{experiments} experiments, 0 comparable pairs";
|
|
107
|
+
/** ScopeWarnings 聚合层的 chrome:汇总行、kind 徽标、组头与明细折叠标签;message 本体不经字典。 */
|
|
108
|
+
readonly "warnings.summary.experiments.one": "{n} experiment flagged";
|
|
109
|
+
readonly "warnings.summary.experiments.other": "{n} experiments flagged";
|
|
110
|
+
readonly "warnings.group.unreadableSnapshot.one": "{n} snapshot skipped";
|
|
111
|
+
readonly "warnings.group.unreadableSnapshot.other": "{n} snapshots skipped";
|
|
112
|
+
readonly "warnings.details.one": "{n} warning";
|
|
113
|
+
readonly "warnings.details.other": "{n} warnings";
|
|
114
|
+
readonly "warnings.badge.partialCoverage": "coverage {covered}/{total}";
|
|
115
|
+
readonly "warnings.badge.staleSnapshot": "{gap} behind";
|
|
116
|
+
readonly "warnings.badge.unfinishedSnapshot": "unfinished";
|
|
117
|
+
readonly "warnings.gap.second.one": "{n} second";
|
|
118
|
+
readonly "warnings.gap.second.other": "{n} seconds";
|
|
119
|
+
readonly "warnings.gap.minute.one": "{n} minute";
|
|
120
|
+
readonly "warnings.gap.minute.other": "{n} minutes";
|
|
121
|
+
readonly "warnings.gap.hour.one": "{n} hour";
|
|
122
|
+
readonly "warnings.gap.hour.other": "{n} hours";
|
|
123
|
+
readonly "warnings.gap.day.one": "{n} day";
|
|
124
|
+
readonly "warnings.gap.day.other": "{n} days";
|
|
125
|
+
/** Hero / HeroCard 的运行 meta(hero.noRuns 是 latestStartedAt 为 null 时的内置文案)。 */
|
|
126
|
+
readonly "hero.lastRun": "Last run {time}";
|
|
127
|
+
readonly "hero.noRuns": "No runs yet";
|
|
128
|
+
/** web 面的合成来源标注(仅 snapshots > 1 时显示)。 */
|
|
129
|
+
readonly "hero.composedRuns": "composed from {n} runs";
|
|
130
|
+
/** text 面的合成来源标注(show 页首 meta 行,仅 snapshots > 1 时显示)。 */
|
|
131
|
+
readonly "hero.composedSnapshots": "composed from {n} snapshots";
|
|
132
|
+
/** CopyFixPrompt 的 web 面 chrome(prompt 本身面向 agent、固定英文,不经词典)。 */
|
|
133
|
+
readonly "copyFixPrompt.summary.one": "Fix prompt · {n} failure";
|
|
134
|
+
readonly "copyFixPrompt.summary.other": "Fix prompt · {n} failures";
|
|
135
|
+
readonly "copyFixPrompt.copy": "Copy fix prompt";
|
|
136
|
+
/** TraceWaterfall 的 chrome。 */
|
|
137
|
+
readonly "traceWaterfall.empty": "No attempts";
|
|
138
|
+
readonly "traceWaterfall.noTrace": "no trace";
|
|
139
|
+
readonly "traceWaterfall.spans.one": "{n} span";
|
|
140
|
+
readonly "traceWaterfall.spans.other": "{n} spans";
|
|
141
|
+
readonly "traceWaterfall.failedSpans.one": "{n} failed";
|
|
142
|
+
readonly "traceWaterfall.failedSpans.other": "{n} failed";
|
|
143
|
+
/** AttemptList 的 web 面过滤框占位符(filter 渐进增强)。 */
|
|
144
|
+
readonly "attemptList.filterPlaceholder": "Filter attempts…";
|
|
107
145
|
readonly "tabs.tab": "Tab";
|
|
108
146
|
};
|
|
109
147
|
export type ReportMessageKey = keyof typeof en;
|
|
110
148
|
/** 查字典 + 简单插值({name} 占位符)。内置词典未覆盖的 locale 回退 en。 */
|
|
111
149
|
export declare function localeText(locale: ReportLocale, key: ReportMessageKey, vars?: Record<string, string | number>): string;
|
|
112
150
|
/** 带单复数的计数文案:n === 1 用 `<base>.one`,其余 `<base>.other`(zh-CN 两键同值)。 */
|
|
113
|
-
export declare function countText(locale: ReportLocale, base: "overview.experiments" | "pointsMissing" | "scoreboard.notRun" | "scoreboard.unscorable" | "scoreboard.ignored" | "entityList.moreFailures" | "table.columnsHidden", n: number): string;
|
|
151
|
+
export declare function countText(locale: ReportLocale, base: "overview.experiments" | "pointsMissing" | "scoreboard.notRun" | "scoreboard.unscorable" | "scoreboard.ignored" | "entityList.moreFailures" | "table.columnsHidden" | "copyFixPrompt.summary" | "traceWaterfall.spans" | "traceWaterfall.failedSpans", n: number): string;
|
|
114
152
|
/**
|
|
115
153
|
* 按 locale 解析指标 / 列 label:字符串原样;字典按 LocalizedText 回退规则取值;
|
|
116
154
|
* undefined 回退 fallback(= metric.name)。渲染面(web / text)共用。
|
package/dist/report/locale.js
CHANGED
|
@@ -129,6 +129,44 @@ const en = {
|
|
|
129
129
|
"scoreboard.subjectTitle": "{questions} evals, weighted {earned} of {possible}",
|
|
130
130
|
"delta.pairHeader": "pair (A → B)",
|
|
131
131
|
"delta.empty": "{experiments} experiments, 0 comparable pairs",
|
|
132
|
+
/** ScopeWarnings 聚合层的 chrome:汇总行、kind 徽标、组头与明细折叠标签;message 本体不经字典。 */
|
|
133
|
+
"warnings.summary.experiments.one": "{n} experiment flagged",
|
|
134
|
+
"warnings.summary.experiments.other": "{n} experiments flagged",
|
|
135
|
+
"warnings.group.unreadableSnapshot.one": "{n} snapshot skipped",
|
|
136
|
+
"warnings.group.unreadableSnapshot.other": "{n} snapshots skipped",
|
|
137
|
+
"warnings.details.one": "{n} warning",
|
|
138
|
+
"warnings.details.other": "{n} warnings",
|
|
139
|
+
"warnings.badge.partialCoverage": "coverage {covered}/{total}",
|
|
140
|
+
"warnings.badge.staleSnapshot": "{gap} behind",
|
|
141
|
+
"warnings.badge.unfinishedSnapshot": "unfinished",
|
|
142
|
+
"warnings.gap.second.one": "{n} second",
|
|
143
|
+
"warnings.gap.second.other": "{n} seconds",
|
|
144
|
+
"warnings.gap.minute.one": "{n} minute",
|
|
145
|
+
"warnings.gap.minute.other": "{n} minutes",
|
|
146
|
+
"warnings.gap.hour.one": "{n} hour",
|
|
147
|
+
"warnings.gap.hour.other": "{n} hours",
|
|
148
|
+
"warnings.gap.day.one": "{n} day",
|
|
149
|
+
"warnings.gap.day.other": "{n} days",
|
|
150
|
+
/** Hero / HeroCard 的运行 meta(hero.noRuns 是 latestStartedAt 为 null 时的内置文案)。 */
|
|
151
|
+
"hero.lastRun": "Last run {time}",
|
|
152
|
+
"hero.noRuns": "No runs yet",
|
|
153
|
+
/** web 面的合成来源标注(仅 snapshots > 1 时显示)。 */
|
|
154
|
+
"hero.composedRuns": "composed from {n} runs",
|
|
155
|
+
/** text 面的合成来源标注(show 页首 meta 行,仅 snapshots > 1 时显示)。 */
|
|
156
|
+
"hero.composedSnapshots": "composed from {n} snapshots",
|
|
157
|
+
/** CopyFixPrompt 的 web 面 chrome(prompt 本身面向 agent、固定英文,不经词典)。 */
|
|
158
|
+
"copyFixPrompt.summary.one": "Fix prompt · {n} failure",
|
|
159
|
+
"copyFixPrompt.summary.other": "Fix prompt · {n} failures",
|
|
160
|
+
"copyFixPrompt.copy": "Copy fix prompt",
|
|
161
|
+
/** TraceWaterfall 的 chrome。 */
|
|
162
|
+
"traceWaterfall.empty": "No attempts",
|
|
163
|
+
"traceWaterfall.noTrace": "no trace",
|
|
164
|
+
"traceWaterfall.spans.one": "{n} span",
|
|
165
|
+
"traceWaterfall.spans.other": "{n} spans",
|
|
166
|
+
"traceWaterfall.failedSpans.one": "{n} failed",
|
|
167
|
+
"traceWaterfall.failedSpans.other": "{n} failed",
|
|
168
|
+
/** AttemptList 的 web 面过滤框占位符(filter 渐进增强)。 */
|
|
169
|
+
"attemptList.filterPlaceholder": "Filter attempts…",
|
|
132
170
|
"tabs.tab": "Tab",
|
|
133
171
|
};
|
|
134
172
|
const zhCN = {
|
|
@@ -216,6 +254,37 @@ const zhCN = {
|
|
|
216
254
|
"scoreboard.subjectTitle": "{questions} 道题,加权得分 {earned}/{possible}",
|
|
217
255
|
"delta.pairHeader": "对比 (A → B)",
|
|
218
256
|
"delta.empty": "{experiments} 个实验、0 个可配对",
|
|
257
|
+
"warnings.summary.experiments.one": "{n} 个实验的数字带警告",
|
|
258
|
+
"warnings.summary.experiments.other": "{n} 个实验的数字带警告",
|
|
259
|
+
"warnings.group.unreadableSnapshot.one": "{n} 个快照被跳过",
|
|
260
|
+
"warnings.group.unreadableSnapshot.other": "{n} 个快照被跳过",
|
|
261
|
+
"warnings.details.one": "{n} 条原始警告",
|
|
262
|
+
"warnings.details.other": "{n} 条原始警告",
|
|
263
|
+
"warnings.badge.partialCoverage": "覆盖 {covered}/{total}",
|
|
264
|
+
"warnings.badge.staleSnapshot": "落后 {gap}",
|
|
265
|
+
"warnings.badge.unfinishedSnapshot": "未收尾",
|
|
266
|
+
"warnings.gap.second.one": "{n} 秒",
|
|
267
|
+
"warnings.gap.second.other": "{n} 秒",
|
|
268
|
+
"warnings.gap.minute.one": "{n} 分钟",
|
|
269
|
+
"warnings.gap.minute.other": "{n} 分钟",
|
|
270
|
+
"warnings.gap.hour.one": "{n} 小时",
|
|
271
|
+
"warnings.gap.hour.other": "{n} 小时",
|
|
272
|
+
"warnings.gap.day.one": "{n} 天",
|
|
273
|
+
"warnings.gap.day.other": "{n} 天",
|
|
274
|
+
"hero.lastRun": "最后运行 {time}",
|
|
275
|
+
"hero.noRuns": "暂无运行",
|
|
276
|
+
"hero.composedRuns": "由 {n} 次运行合成",
|
|
277
|
+
"hero.composedSnapshots": "由 {n} 份快照合成",
|
|
278
|
+
"copyFixPrompt.summary.one": "修复 prompt · {n} 个失败",
|
|
279
|
+
"copyFixPrompt.summary.other": "修复 prompt · {n} 个失败",
|
|
280
|
+
"copyFixPrompt.copy": "复制修复 prompt",
|
|
281
|
+
"traceWaterfall.empty": "没有 attempt",
|
|
282
|
+
"traceWaterfall.noTrace": "无 trace",
|
|
283
|
+
"traceWaterfall.spans.one": "{n} 个 span",
|
|
284
|
+
"traceWaterfall.spans.other": "{n} 个 span",
|
|
285
|
+
"traceWaterfall.failedSpans.one": "{n} 个失败",
|
|
286
|
+
"traceWaterfall.failedSpans.other": "{n} 个失败",
|
|
287
|
+
"attemptList.filterPlaceholder": "筛选 attempt…",
|
|
219
288
|
"tabs.tab": "Tab",
|
|
220
289
|
};
|
|
221
290
|
const dictionaries = {
|
|
@@ -15,10 +15,12 @@ export declare function AttemptRow({ item, attemptHref, locale, }: {
|
|
|
15
15
|
attemptHref?: (locator: AttemptLocator) => string;
|
|
16
16
|
locale?: ReportLocale;
|
|
17
17
|
}): ReactElement;
|
|
18
|
-
export declare function AttemptList({ data, total, attemptHref, className, locale, }: {
|
|
18
|
+
export declare function AttemptList({ data, total, filter, attemptHref, className, locale, }: {
|
|
19
19
|
data: readonly AttemptListItem[];
|
|
20
20
|
/** data 被 slice 时的原始数量;如实显示还剩多少条没展示。 */
|
|
21
21
|
total?: number;
|
|
22
|
+
/** web 面加过滤输入框(按 experiment、eval、agent、verdict 或摘要文本收窄行);渐进增强,不改变数据。 */
|
|
23
|
+
filter?: boolean;
|
|
22
24
|
attemptHref?: (locator: AttemptLocator) => string;
|
|
23
25
|
className?: string;
|
|
24
26
|
locale?: ReportLocale;
|
|
@@ -18,9 +18,9 @@ export function failureSummaryText(item, locale) {
|
|
|
18
18
|
/** 一条 Attempt 的比较卡片;完整 assertions 通过 locator 下钻,不在列表内展开。 */
|
|
19
19
|
export function AttemptRow({ item, attemptHref = DEFAULT_ATTEMPT_HREF, locale = DEFAULT_REPORT_LOCALE, }) {
|
|
20
20
|
const reason = failureSummaryText(item, locale);
|
|
21
|
-
return (_jsxs("li", { className: cx("nre-attempt", `nre-attempt-${item.verdict}`), children: [_jsxs("div", { className: "nre-attempt-head", children: [_jsx(AttemptLocatorBadge, { item: item, attemptHref: attemptHref }), _jsx("span", { className: "nre-attempt-eval", children: item.evalId }), _jsx("span", { className: "nre-attempt-experiment", children: item.experimentId }), _jsx("span", { className: cx("nre-attempt-agent", "nre-key", colorClassForKey(item.agent)), children: item.agent }), _jsx("span", { className: "nre-attempt-duration", children: formatDurationMs(item.durationMs) }), item.costUSD !== null && _jsx("span", { className: "nre-attempt-cost", children: formatUSD(item.costUSD) })] }), reason && _jsx("p", { className: "nre-attempt-result", children: reason })] }));
|
|
21
|
+
return (_jsxs("li", { className: cx("nre-attempt", `nre-attempt-${item.verdict}`), "data-nre-verdict": item.verdict, children: [_jsxs("div", { className: "nre-attempt-head", children: [_jsx(AttemptLocatorBadge, { item: item, attemptHref: attemptHref }), _jsx("span", { className: "nre-attempt-eval", children: item.evalId }), _jsx("span", { className: "nre-attempt-experiment", children: item.experimentId }), _jsx("span", { className: cx("nre-attempt-agent", "nre-key", colorClassForKey(item.agent)), children: item.agent }), _jsx("span", { className: "nre-attempt-duration", children: formatDurationMs(item.durationMs) }), item.costUSD !== null && _jsx("span", { className: "nre-attempt-cost", children: formatUSD(item.costUSD) })] }), reason && _jsx("p", { className: "nre-attempt-result", children: reason })] }));
|
|
22
22
|
}
|
|
23
|
-
export function AttemptList({ data, total, attemptHref = DEFAULT_ATTEMPT_HREF, className, locale = DEFAULT_REPORT_LOCALE, }) {
|
|
23
|
+
export function AttemptList({ data, total, filter = false, attemptHref = DEFAULT_ATTEMPT_HREF, className, locale = DEFAULT_REPORT_LOCALE, }) {
|
|
24
24
|
const remaining = (total ?? data.length) - data.length;
|
|
25
|
-
return (_jsxs("section", { className: cx("nre", "nre-attempt-list", className), children: [data.length === 0 && _jsx("p", { className: "nre-attempt-list-empty", children: localeText(locale, "attemptList.empty") }), _jsx("ul", { className: "nre-attempts", children: data.map((item) => (_jsx(AttemptRow, { item: item, attemptHref: attemptHref, locale: locale }, item.locator))) }), remaining > 0 && (_jsx("p", { className: "nre-truncated", children: localeText(locale, "attemptList.truncated", { n: remaining }) }))] }));
|
|
25
|
+
return (_jsxs("section", { className: cx("nre", "nre-attempt-list", className), children: [filter && (_jsx("input", { className: "nre-filter", "data-nre-attempt-filter": "", type: "search", placeholder: localeText(locale, "attemptList.filterPlaceholder") })), data.length === 0 && _jsx("p", { className: "nre-attempt-list-empty", children: localeText(locale, "attemptList.empty") }), _jsx("ul", { className: "nre-attempts", children: data.map((item) => (_jsx(AttemptRow, { item: item, attemptHref: attemptHref, locale: locale }, item.locator))) }), remaining > 0 && (_jsx("p", { className: "nre-truncated", children: localeText(locale, "attemptList.truncated", { n: remaining }) }))] }));
|
|
26
26
|
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { ReactElement } from "react";
|
|
2
|
+
import type { CopyFixPromptData } from "../types.ts";
|
|
3
|
+
import { type ReportLocale } from "../locale.ts";
|
|
4
|
+
/**
|
|
5
|
+
* 批量修复 prompt(纯 web 渲染面):折叠块内完整 prompt 文本 + 复制按钮(增强层)。
|
|
6
|
+
* 嵌入自有 React 页面时配合 `copyFixPromptData()` 使用;failures 为 0 返回 null。
|
|
7
|
+
*/
|
|
8
|
+
export declare function CopyFixPrompt({ data, className, locale, }: {
|
|
9
|
+
data: CopyFixPromptData;
|
|
10
|
+
className?: string;
|
|
11
|
+
locale?: ReportLocale;
|
|
12
|
+
}): ReactElement | null;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { DEFAULT_REPORT_LOCALE, countText, localeText } from "../locale.js";
|
|
3
|
+
import { cx } from "./format.js";
|
|
4
|
+
/**
|
|
5
|
+
* 批量修复 prompt(纯 web 渲染面):折叠块内完整 prompt 文本 + 复制按钮(增强层)。
|
|
6
|
+
* 嵌入自有 React 页面时配合 `copyFixPromptData()` 使用;failures 为 0 返回 null。
|
|
7
|
+
*/
|
|
8
|
+
export function CopyFixPrompt({ data, className, locale = DEFAULT_REPORT_LOCALE, }) {
|
|
9
|
+
if (data.failures === 0)
|
|
10
|
+
return null;
|
|
11
|
+
return (_jsxs("details", { className: cx("nre", "nre-copy-fix-prompt", className), children: [_jsx("summary", { className: "nre-copy-fix-prompt-summary", children: countText(locale, "copyFixPrompt.summary", data.failures) }), _jsx("button", { type: "button", className: "nre-copy-fix-prompt-copy", "data-nre-copy": data.prompt, children: localeText(locale, "copyFixPrompt.copy") }), _jsx("pre", { className: "nre-copy-fix-prompt-text", children: data.prompt })] }));
|
|
12
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { ReactElement } from "react";
|
|
2
|
+
import type { HeroData } from "../types.ts";
|
|
3
|
+
import { type LocalizedText, type ReportLocale } from "../locale.ts";
|
|
4
|
+
/**
|
|
5
|
+
* 站点标题区(纯 web 渲染面):`<h1>` 标题 + meta 行 + 品牌行。
|
|
6
|
+
* 嵌入自有 React 页面时配合 `heroData()` 使用。
|
|
7
|
+
*/
|
|
8
|
+
export declare function HeroCard({ title, data, className, locale, }: {
|
|
9
|
+
title: LocalizedText;
|
|
10
|
+
data: HeroData;
|
|
11
|
+
className?: string;
|
|
12
|
+
locale?: ReportLocale;
|
|
13
|
+
}): ReactElement;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { DEFAULT_REPORT_LOCALE, localeText, resolveLocalizedText } from "../locale.js";
|
|
3
|
+
import { cx } from "./format.js";
|
|
4
|
+
import { PoweredBy } from "./PoweredBy.js";
|
|
5
|
+
/** ISO 时间 → 按 locale 的「最后运行」显示(年月日 时:分);不可解析原样返回。 */
|
|
6
|
+
function formatLastRun(iso, locale) {
|
|
7
|
+
const date = new Date(iso);
|
|
8
|
+
if (Number.isNaN(date.valueOf()))
|
|
9
|
+
return iso;
|
|
10
|
+
try {
|
|
11
|
+
return new Intl.DateTimeFormat(locale, {
|
|
12
|
+
year: "numeric",
|
|
13
|
+
month: "short",
|
|
14
|
+
day: "numeric",
|
|
15
|
+
hour: "2-digit",
|
|
16
|
+
minute: "2-digit",
|
|
17
|
+
}).format(date);
|
|
18
|
+
}
|
|
19
|
+
catch {
|
|
20
|
+
return iso;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* 站点标题区(纯 web 渲染面):`<h1>` 标题 + meta 行 + 品牌行。
|
|
25
|
+
* 嵌入自有 React 页面时配合 `heroData()` 使用。
|
|
26
|
+
*/
|
|
27
|
+
export function HeroCard({ title, data, className, locale = DEFAULT_REPORT_LOCALE, }) {
|
|
28
|
+
const meta = data.latestStartedAt === null
|
|
29
|
+
? localeText(locale, "hero.noRuns")
|
|
30
|
+
: [
|
|
31
|
+
localeText(locale, "hero.lastRun", { time: formatLastRun(data.latestStartedAt, locale) }),
|
|
32
|
+
...(data.snapshots > 1 ? [localeText(locale, "hero.composedRuns", { n: data.snapshots })] : []),
|
|
33
|
+
].join(" · ");
|
|
34
|
+
return (_jsxs("header", { className: cx("nre", "nre-hero", className), children: [_jsx("h1", { className: "nre-hero-title", children: resolveLocalizedText(title, locale) }), _jsx("p", { className: "nre-hero-meta", children: meta }), _jsx(PoweredBy, {})] }));
|
|
35
|
+
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { ReactElement } from "react";
|
|
2
|
+
/** 品牌行的固定去处:niceeval 官网,utm 标记「来自报告的品牌行」。 */
|
|
3
|
+
export declare const POWERED_BY_HREF = "https://niceeval.com/?utm_source=report&utm_medium=powered-by";
|
|
4
|
+
/** 一行品牌色小字 `Powered by NiceEval`,链接官网;HeroCard 的品牌行与它同一渲染。 */
|
|
5
|
+
export declare function PoweredBy(): ReactElement;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
/** 品牌行的固定去处:niceeval 官网,utm 标记「来自报告的品牌行」。 */
|
|
3
|
+
export const POWERED_BY_HREF = "https://niceeval.com/?utm_source=report&utm_medium=powered-by";
|
|
4
|
+
/** 一行品牌色小字 `Powered by NiceEval`,链接官网;HeroCard 的品牌行与它同一渲染。 */
|
|
5
|
+
export function PoweredBy() {
|
|
6
|
+
return (_jsx("p", { className: "nre nre-powered-by", children: _jsx("a", { href: POWERED_BY_HREF, target: "_blank", rel: "noopener", children: "Powered by NiceEval" }) }));
|
|
7
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { ReactElement } from "react";
|
|
2
|
+
import type { ScopeWarning } from "../types.ts";
|
|
3
|
+
import { type ReportLocale } from "../locale.ts";
|
|
4
|
+
/**
|
|
5
|
+
* 选择警告区(纯 web 渲染面):按动作聚合的警告组。嵌入自有 React 页面时传
|
|
6
|
+
* `data={scope.warnings}`;空集返回 null,不渲染空容器。
|
|
7
|
+
*/
|
|
8
|
+
export declare function ScopeWarnings({ data, className, locale, }: {
|
|
9
|
+
data: readonly ScopeWarning[];
|
|
10
|
+
className?: string;
|
|
11
|
+
locale?: ReportLocale;
|
|
12
|
+
}): ReactElement | null;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { DEFAULT_REPORT_LOCALE } from "../locale.js";
|
|
3
|
+
import { groupScopeWarnings, warningDetailsLabel } from "../scope-warnings.js";
|
|
4
|
+
import { cx } from "./format.js";
|
|
5
|
+
/** 命令的可复制块:无 JS 时点击全选(user-select: all),enhance.js 在场时点击复制。 */
|
|
6
|
+
function CommandBlock({ command }) {
|
|
7
|
+
return (_jsx("code", { className: "nre-warning-command", "data-nre-copy": command, children: command }));
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* 选择警告区(纯 web 渲染面):按动作聚合的警告组。嵌入自有 React 页面时传
|
|
11
|
+
* `data={scope.warnings}`;空集返回 null,不渲染空容器。
|
|
12
|
+
*/
|
|
13
|
+
export function ScopeWarnings({ data, className, locale = DEFAULT_REPORT_LOCALE, }) {
|
|
14
|
+
if (data.length === 0)
|
|
15
|
+
return null;
|
|
16
|
+
const { summary, groups, detailsOpen } = groupScopeWarnings(data, locale);
|
|
17
|
+
return (_jsx("div", { className: cx("nre", "nre-scope-warnings", className), children: _jsxs("details", { className: "nre-warnings", children: [_jsx("summary", { className: "nre-warnings-summary", children: summary }), _jsx("ul", { className: "nre-warning-groups", children: groups.map((group, i) => (_jsxs("li", { className: "nre-warning-group", "data-category": group.category, children: [_jsxs("div", { className: "nre-warning-head", children: [_jsx("span", { className: "nre-warning-title", children: group.title }), group.badges.map((badge, j) => (_jsx("span", { className: "nre-warning-badge", "data-kind": badge.kind, children: badge.text }, j))), group.headCommand !== null && _jsx(CommandBlock, { command: group.headCommand })] }), _jsxs("details", { className: "nre-warning-details", open: detailsOpen || undefined, children: [_jsx("summary", { children: warningDetailsLabel(locale, group.warnings.length) }), _jsx("ul", { children: group.warnings.map((w, j) => (_jsxs("li", { className: "nre-warning", "data-kind": w.kind, children: [w.message, group.headCommand === null && "command" in w && w.command !== undefined && (_jsx(CommandBlock, { command: w.command }))] }, j))) })] })] }, i))) })] }) }));
|
|
18
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { ReactElement } from "react";
|
|
2
|
+
import type { TraceWaterfallRow } from "../types.ts";
|
|
3
|
+
import type { AttemptLocator } from "../../results/locator.ts";
|
|
4
|
+
import { type ReportLocale } from "../locale.ts";
|
|
5
|
+
/**
|
|
6
|
+
* 执行时间瀑布(纯 web 渲染面):嵌入自有 React 页面时配合 `traceWaterfallData()` 使用。
|
|
7
|
+
* 只画被测 agent 的原始 span;runner 生命周期节点不在 data 里,组合视图归 attempt 详情。
|
|
8
|
+
*/
|
|
9
|
+
export declare function TraceWaterfall({ data, attemptHref, className, locale, }: {
|
|
10
|
+
data: readonly TraceWaterfallRow[];
|
|
11
|
+
attemptHref?: (locator: AttemptLocator) => string;
|
|
12
|
+
className?: string;
|
|
13
|
+
locale?: ReportLocale;
|
|
14
|
+
}): ReactElement;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { DEFAULT_REPORT_LOCALE, countText, localeText } from "../locale.js";
|
|
3
|
+
import { cx, formatDurationMs } from "./format.js";
|
|
4
|
+
const DEFAULT_ATTEMPT_HREF = (locator) => `#/attempt/${locator}`;
|
|
5
|
+
function pct(part, total) {
|
|
6
|
+
if (total <= 0)
|
|
7
|
+
return "0%";
|
|
8
|
+
return `${Math.min(100, Math.max(0, (part / total) * 100)).toFixed(2)}%`;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* 执行时间瀑布(纯 web 渲染面):嵌入自有 React 页面时配合 `traceWaterfallData()` 使用。
|
|
12
|
+
* 只画被测 agent 的原始 span;runner 生命周期节点不在 data 里,组合视图归 attempt 详情。
|
|
13
|
+
*/
|
|
14
|
+
export function TraceWaterfall({ data, attemptHref = DEFAULT_ATTEMPT_HREF, className, locale = DEFAULT_REPORT_LOCALE, }) {
|
|
15
|
+
return (_jsxs("section", { className: cx("nre", "nre-trace-waterfall", className), children: [data.length === 0 && _jsx("p", { className: "nre-waterfall-empty", children: localeText(locale, "traceWaterfall.empty") }), _jsx("ul", { className: "nre-waterfall", children: data.map((row) => {
|
|
16
|
+
const failedSpans = row.spans.filter((span) => span.failed).length;
|
|
17
|
+
return (_jsxs("li", { className: "nre-waterfall-row", children: [_jsxs("div", { className: "nre-waterfall-head", children: [_jsx("a", { className: "nre-locator", href: attemptHref(row.locator), children: row.locator }), _jsx("span", { className: "nre-waterfall-eval", children: row.evalId }), _jsx("span", { className: "nre-waterfall-experiment", children: row.experimentId }), _jsx("span", { className: "nre-waterfall-duration", children: row.durationMs === null ? localeText(locale, "traceWaterfall.noTrace") : formatDurationMs(row.durationMs) }), _jsx("span", { className: "nre-waterfall-count", children: countText(locale, "traceWaterfall.spans", row.spans.length) }), failedSpans > 0 && (_jsxs("span", { className: "nre-waterfall-failed", children: ["\u2717 ", countText(locale, "traceWaterfall.failedSpans", failedSpans)] }))] }), row.durationMs !== null && row.spans.length > 0 && (_jsx("div", { className: "nre-waterfall-track", children: row.spans.map((span, i) => (_jsx("span", { className: cx("nre-waterfall-span", `nre-span-${span.kind}`, span.failed && "nre-span-failed"), style: {
|
|
18
|
+
left: pct(span.startOffsetMs, row.durationMs),
|
|
19
|
+
width: `max(${pct(span.durationMs, row.durationMs)}, 0.5%)`,
|
|
20
|
+
}, title: `${span.name} · ${formatDurationMs(span.durationMs)}${span.failed ? " · ✗" : ""}` }, i))) }))] }, row.locator));
|
|
21
|
+
}) })] }));
|
|
22
|
+
}
|
|
@@ -10,7 +10,12 @@ export { MetricScatter } from "./MetricScatter.tsx";
|
|
|
10
10
|
export { MetricLine } from "./MetricLine.tsx";
|
|
11
11
|
export { DeltaTable } from "./DeltaTable.tsx";
|
|
12
12
|
export { Scoreboard } from "./Scoreboard.tsx";
|
|
13
|
-
export
|
|
13
|
+
export { HeroCard } from "./HeroCard.tsx";
|
|
14
|
+
export { PoweredBy } from "./PoweredBy.tsx";
|
|
15
|
+
export { ScopeWarnings } from "./ScopeWarnings.tsx";
|
|
16
|
+
export { CopyFixPrompt } from "./CopyFixPrompt.tsx";
|
|
17
|
+
export { TraceWaterfall } from "./TraceWaterfall.tsx";
|
|
18
|
+
export type { AttemptListItem, AttemptLocator, CopyFixPromptData, DeltaData, EvalListItem, ExperimentComparisonData, ExperimentComparisonGroupData, ExperimentListEvalRow, ExperimentListItem, HeroData, LineData, MatrixData, MetricCell, MetricColumn, ScatterData, ScopeSummaryData, ScopeWarning, ScoreboardData, TableData, TraceSpanSummary, TraceWaterfallRow, VerdictTally, } from "../types.ts";
|
|
14
19
|
export { DEFAULT_REPORT_LOCALE, resolveLocalizedText, resolveMetricLabel } from "../locale.ts";
|
|
15
20
|
export type { LocalizedText, ReportLocale } from "../locale.ts";
|
|
16
21
|
export { NRE_PALETTE, colorClassForKey, colorHexForKey, colorIndexForKey, seriesClassForKey } from "./colors.ts";
|
|
@@ -19,6 +19,12 @@ export { MetricScatter } from "./MetricScatter.js";
|
|
|
19
19
|
export { MetricLine } from "./MetricLine.js";
|
|
20
20
|
export { DeltaTable } from "./DeltaTable.js";
|
|
21
21
|
export { Scoreboard } from "./Scoreboard.js";
|
|
22
|
+
// 站点组件的纯 web 面(data 形态;Hero 是组合组件,只住 niceeval/report)
|
|
23
|
+
export { HeroCard } from "./HeroCard.js";
|
|
24
|
+
export { PoweredBy } from "./PoweredBy.js";
|
|
25
|
+
export { ScopeWarnings } from "./ScopeWarnings.js";
|
|
26
|
+
export { CopyFixPrompt } from "./CopyFixPrompt.js";
|
|
27
|
+
export { TraceWaterfall } from "./TraceWaterfall.js";
|
|
22
28
|
// locale(官方组件 chrome 文案;LocalizedText 的按 locale 解析也用它)
|
|
23
29
|
export { DEFAULT_REPORT_LOCALE, resolveLocalizedText, resolveMetricLabel } from "../locale.js";
|
|
24
30
|
// 稳定配色(自定义组件想与官方组件同键同色时用;seriesClassForKey 配 CSS 的 --nre-series)
|
package/dist/report/report.d.ts
CHANGED
|
@@ -37,11 +37,11 @@ export type HeadTag = {
|
|
|
37
37
|
children?: string;
|
|
38
38
|
};
|
|
39
39
|
export interface ReportShell {
|
|
40
|
-
/**
|
|
40
|
+
/** 站点标题:浏览器标题、show 页索引标题行与 `ctx.report.title` 的取值源;`Hero` 组件缺省消费它。回退链 def.title → 唯一快照 name → 内置文案「Eval 运行结果 / Eval Results」。 */
|
|
41
41
|
title?: LocalizedText;
|
|
42
42
|
/** 页头右侧的外部链接,如 GitHub、文档、CI。 */
|
|
43
43
|
links?: ReportLink[];
|
|
44
|
-
/** 每页页脚的一段文字;省略时不渲染页脚(
|
|
44
|
+
/** 每页页脚的一段文字;省略时不渲染页脚(品牌行归 PoweredBy 组件,不占页脚)。 */
|
|
45
45
|
footer?: LocalizedText;
|
|
46
46
|
/**
|
|
47
47
|
* 注入每页 `<head>` 的结构化标签,在官方与外壳样式之后按声明顺序渲染。
|
|
@@ -63,13 +63,27 @@ export interface ReportPage {
|
|
|
63
63
|
/** 这一页的报告树;ReportDefinition 不是 ReportNode,页装不进外壳。 */
|
|
64
64
|
content: ReportNode;
|
|
65
65
|
}
|
|
66
|
-
/** content / pages
|
|
66
|
+
/** content / pages / extends 三选一由类型表达,不把非法状态留到运行期。 */
|
|
67
67
|
export type ReportDef = ReportShell & ({
|
|
68
|
+
/** 单页缩写,等价于只含 id `report` 的页列表。 */
|
|
68
69
|
content: ReportNode;
|
|
69
70
|
pages?: never;
|
|
71
|
+
extends?: never;
|
|
70
72
|
} | {
|
|
73
|
+
/** 非空页列表;导航按数组顺序显示。 */
|
|
71
74
|
pages: NonEmptyArray<ReportPage>;
|
|
72
75
|
content?: never;
|
|
76
|
+
extends?: never;
|
|
77
|
+
} | {
|
|
78
|
+
/**
|
|
79
|
+
* 在另一份报告上叠外壳:页列表取 base 的页列表;本对象声明的外壳字段整字段覆盖
|
|
80
|
+
* base 的同名字段,未声明的沿用 base——没有数组拼接、没有深合并。base 是任何
|
|
81
|
+
* `defineReport` 产物(内建视图或自己别的报告文件的具名导出);合并在
|
|
82
|
+
* `defineReport` 调用时折叠完成,产物仍是普通 ReportDefinition,可以再被 extends。
|
|
83
|
+
*/
|
|
84
|
+
extends: ReportDefinition;
|
|
85
|
+
content?: never;
|
|
86
|
+
pages?: never;
|
|
73
87
|
});
|
|
74
88
|
/**
|
|
75
89
|
* defineReport 的唯一产物:只作 --report 文件的默认导出,交给宿主装载。
|
|
@@ -136,7 +150,9 @@ export interface RenderReportTextOptions extends TextRenderOptions {
|
|
|
136
150
|
}
|
|
137
151
|
/**
|
|
138
152
|
* text 宿主的装载语义:选页 → resolve(组合展开 + spec 取数,唯一的 await 边界)→ 树校验 →
|
|
139
|
-
* 遍历渲染 text
|
|
153
|
+
* 遍历渲染 text 面。不需要 react-dom。宿主不在报告树外另设警告通道——挑选警告的呈现件是
|
|
154
|
+
* `ScopeWarnings` 组件,内建报告每页都放它,自定义报告放不放是作者义务
|
|
155
|
+
* (docs/feature/reports/architecture.md「Scope 是计算入口」)。
|
|
140
156
|
*/
|
|
141
157
|
export declare function renderReportToText(definition: ReportDefinition, ctx: ReportHostContext, options?: RenderReportTextOptions): Promise<string>;
|
|
142
158
|
/** 页索引标题行(show 多页索引 / view 导航共用的解析结果):按 locale 解析的标题字符串。 */
|
|
@@ -161,7 +177,7 @@ export interface RenderTreeTextOptions extends TextRenderOptions {
|
|
|
161
177
|
}
|
|
162
178
|
/**
|
|
163
179
|
* 渲染一页报告树的 text 面(宿主逐页调用;页选择归宿主):
|
|
164
|
-
* resolve(组合展开 + spec 取数)→ validate → render
|
|
165
|
-
*
|
|
180
|
+
* resolve(组合展开 + spec 取数)→ validate → render。宿主不在报告树外另设警告通道,
|
|
181
|
+
* 挑选警告由页内的 `ScopeWarnings` 组件呈现(内建报告每页都放它)。
|
|
166
182
|
*/
|
|
167
183
|
export declare function renderReportTreeToText(tree: ReportNode, ctx: ReportTreeHostContext, options?: RenderTreeTextOptions): Promise<string>;
|