niceeval 0.4.6 → 0.5.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/docs-site/zh/concepts/adapter.mdx +6 -6
- package/docs-site/zh/concepts/experiment.mdx +7 -7
- package/docs-site/zh/concepts/overview.mdx +1 -1
- package/docs-site/zh/concepts/tier.mdx +6 -6
- package/docs-site/zh/guides/agent-feedback-loop.mdx +63 -20
- package/docs-site/zh/guides/connect-your-agent.mdx +7 -7
- package/docs-site/zh/guides/custom-reports.mdx +243 -0
- package/docs-site/zh/guides/experiments.mdx +3 -3
- package/docs-site/zh/guides/report-components.mdx +252 -0
- package/docs-site/zh/guides/reporters.mdx +1 -1
- package/docs-site/zh/guides/results-data.mdx +224 -0
- package/docs-site/zh/guides/runner.mdx +1 -1
- package/docs-site/zh/guides/sandbox-agent.mdx +2 -2
- package/docs-site/zh/guides/viewing-results.mdx +147 -77
- package/docs-site/zh/guides/write-experiment.mdx +9 -9
- package/docs-site/zh/guides/write-send.mdx +6 -6
- package/docs-site/zh/index.mdx +1 -1
- package/docs-site/zh/introduction.mdx +1 -1
- package/docs-site/zh/reference/cli.mdx +10 -2
- package/docs-site/zh/reference/define-agent.mdx +5 -5
- package/docs-site/zh/reference/define-config.mdx +1 -1
- package/docs-site/zh/reference/define-eval.mdx +3 -3
- package/package.json +3 -2
- package/src/agents/ai-sdk.test.ts +1 -1
- package/src/agents/ai-sdk.ts +2 -2
- package/src/agents/claude-code.ts +1 -1
- package/src/agents/codex.ts +2 -2
- package/src/agents/streaming.test.ts +1 -1
- package/src/agents/types.ts +4 -4
- package/src/agents/ui-message-stream.test.ts +1 -1
- package/src/cli.ts +104 -14
- package/src/context/context.test.ts +1 -1
- package/src/context/context.ts +3 -3
- package/src/context/session.ts +2 -2
- package/src/context/types.ts +2 -2
- package/src/i18n/en.ts +29 -7
- package/src/i18n/zh-CN.ts +24 -2
- package/src/report/aggregate.ts +79 -50
- package/src/report/components.tsx +190 -0
- package/src/report/compute.ts +149 -84
- package/src/report/default-report.tsx +222 -0
- package/src/report/dual-face.test.tsx +527 -0
- package/src/report/format.ts +29 -0
- package/src/report/index.ts +79 -24
- package/src/report/load.ts +67 -0
- package/src/report/metrics.ts +2 -1
- package/src/report/param.ts +18 -0
- package/src/report/primitives.tsx +117 -0
- package/src/report/react/CaseList.tsx +2 -2
- package/src/report/react/DeltaTable.tsx +2 -2
- package/src/report/react/MetricBars.tsx +109 -0
- package/src/report/react/MetricLine.tsx +200 -0
- package/src/report/react/MetricMatrix.tsx +1 -1
- package/src/report/react/MetricScatter.tsx +1 -1
- package/src/report/react/MetricTable.tsx +1 -1
- package/src/report/react/RunOverview.tsx +4 -4
- package/src/report/react/Scoreboard.tsx +3 -3
- package/src/report/react/cell.tsx +1 -1
- package/src/report/react/fixtures.ts +98 -36
- package/src/report/react/format.ts +3 -28
- package/src/report/react/index.tsx +41 -24
- package/src/report/react/render.test.tsx +8 -8
- package/src/report/react/styles.css +77 -0
- package/src/report/report.test.ts +248 -128
- package/src/report/report.ts +69 -0
- package/src/report/text/faces.ts +356 -0
- package/src/report/text/layout.ts +125 -0
- package/src/report/text/plot.ts +127 -0
- package/src/report/tree.ts +220 -0
- package/src/report/types.ts +75 -27
- package/src/report/web.ts +40 -0
- package/src/results/copy.ts +95 -41
- package/src/results/format.ts +12 -11
- package/src/results/index.ts +34 -17
- package/src/results/open.ts +201 -81
- package/src/results/results.test.ts +595 -191
- package/src/results/select.ts +107 -55
- package/src/results/types.ts +137 -45
- package/src/results/writer.ts +258 -0
- package/src/runner/attempt.ts +3 -3
- package/src/runner/fingerprint.ts +1 -1
- package/src/runner/reporters/artifacts.ts +38 -78
- package/src/runner/reporters/braintrust.test.ts +2 -2
- package/src/runner/reporters/braintrust.ts +3 -3
- package/src/runner/run.ts +1 -1
- package/src/runner/types.ts +18 -12
- package/src/show/compose.ts +215 -0
- package/src/show/index.ts +263 -0
- package/src/show/render.ts +456 -0
- package/src/show/show.test.ts +505 -0
- package/src/view/app/App.tsx +85 -24
- package/src/view/app/components/CostScoreChart.tsx +29 -10
- package/src/view/app/components/ExperimentTable.tsx +27 -9
- package/src/view/app/components/GroupSelector.tsx +1 -1
- package/src/view/app/i18n.ts +18 -3
- package/src/view/app/lib/attempt-route.test.ts +9 -9
- package/src/view/app/lib/attempt-route.ts +5 -5
- package/src/view/app/lib/outcome.ts +1 -3
- package/src/view/app/lib/rows.ts +95 -15
- package/src/view/app/main.tsx +18 -6
- package/src/view/app/pages/RunsPage.tsx +4 -7
- package/src/view/app/pages/TracesPage.tsx +3 -8
- package/src/view/app/types.ts +50 -6
- package/src/view/client-dist/app.css +1 -1
- package/src/view/client-dist/app.js +20 -20
- package/src/view/data.test.ts +254 -0
- package/src/view/data.ts +336 -0
- package/src/view/index.ts +64 -10
- package/src/view/server.ts +31 -9
- package/src/view/shared/types.ts +47 -41
- package/src/view/styles.css +5 -0
- package/src/view/template.html +1 -0
- package/src/view/view-report.test.ts +308 -0
- package/docs-site/.mintignore +0 -13
- package/docs-site/AGENTS.md +0 -46
- package/docs-site/concepts/adapter.mdx +0 -287
- package/docs-site/concepts/assert.mdx +0 -243
- package/docs-site/concepts/drive.mdx +0 -118
- package/docs-site/concepts/evals.mdx +0 -108
- package/docs-site/concepts/experiment.mdx +0 -37
- package/docs-site/concepts/hitl.mdx +0 -83
- package/docs-site/concepts/judge.mdx +0 -129
- package/docs-site/concepts/overview.mdx +0 -98
- package/docs-site/concepts/tier.mdx +0 -42
- package/docs-site/docs-ref/00-index.md +0 -23
- package/docs-site/docs-ref/01-page-types.md +0 -43
- package/docs-site/docs-ref/03-style-rules.md +0 -45
- package/docs-site/docs-ref/04-code-examples.md +0 -37
- package/docs-site/docs-ref/05-dx-failure-paths.md +0 -45
- package/docs-site/docs-ref/06-checklists.md +0 -53
- package/docs-site/docs.json +0 -256
- package/docs-site/example/ai-agent-application.mdx +0 -148
- package/docs-site/example/claude-code-codex-plugin.mdx +0 -162
- package/docs-site/example/claude-code-codex-skill.mdx +0 -147
- package/docs-site/example/showcase.mdx +0 -39
- package/docs-site/example/tier1-ai-sdk-v7.mdx +0 -136
- package/docs-site/example/tier1-claude-sdk.mdx +0 -119
- package/docs-site/example/tier1-codex-sdk.mdx +0 -111
- package/docs-site/example/tier1-langgraph.mdx +0 -119
- package/docs-site/example/tier1-pi-sdk.mdx +0 -119
- package/docs-site/favicon.svg +0 -5
- package/docs-site/github-diff.css +0 -135
- package/docs-site/github-diff.js +0 -11
- package/docs-site/guides/authoring.mdx +0 -129
- package/docs-site/guides/ci-integration.mdx +0 -97
- package/docs-site/guides/connect-otel.mdx +0 -209
- package/docs-site/guides/connect-your-agent.mdx +0 -221
- package/docs-site/guides/dataset-fanout.mdx +0 -98
- package/docs-site/guides/experiments.mdx +0 -71
- package/docs-site/guides/fixtures.mdx +0 -147
- package/docs-site/guides/reporters.mdx +0 -113
- package/docs-site/guides/runner.mdx +0 -79
- package/docs-site/guides/sandbox-agent.mdx +0 -138
- package/docs-site/guides/sandbox-backends.mdx +0 -64
- package/docs-site/guides/scoring-guide.mdx +0 -92
- package/docs-site/guides/viewing-results.mdx +0 -195
- package/docs-site/guides/write-experiment.mdx +0 -81
- package/docs-site/guides/write-send.mdx +0 -347
- package/docs-site/index.mdx +0 -181
- package/docs-site/introduction.mdx +0 -141
- package/docs-site/quickstart.mdx +0 -136
- package/docs-site/reference/builtin-agents.mdx +0 -161
- package/docs-site/reference/capabilities.mdx +0 -76
- package/docs-site/reference/cli.mdx +0 -120
- package/docs-site/reference/define-agent.mdx +0 -168
- package/docs-site/reference/define-config.mdx +0 -41
- package/docs-site/reference/define-eval.mdx +0 -160
- package/docs-site/reference/events.mdx +0 -131
- package/docs-site/reference/expect.mdx +0 -112
- package/docs-site/tracker.js +0 -8
- package/src/report/react/data.ts +0 -17
- package/src/view/aggregate.ts +0 -103
- package/src/view/loader.test.ts +0 -61
- package/src/view/loader.ts +0 -257
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
// DefaultReport:官方水位整块 —— 官方两扇门裸跑时渲染的就是它,零 props、纯声明。
|
|
2
|
+
// 「渲染面纯同步」与它不冲突,靠的是一个数据事实:官方水位(overview、榜单、失败清单)
|
|
3
|
+
// 只读瘦身条目、不碰任何懒加载工件,宿主对着已挑好的选集总是把这份数据备好、经上下文
|
|
4
|
+
// 注入(renderReportToText / renderReportToStaticHtml 里 prepareDefaultReportData)。
|
|
5
|
+
// 它渲染的口径钉死为宿主注入的那份选集 —— 零 props 意味着没有跟随的通道,这是锚点语义:
|
|
6
|
+
// 官方口径与自定义口径并排对照。默认无特权:数据全部来自公开计算函数。
|
|
7
|
+
//
|
|
8
|
+
// text 面即 `niceeval show` 的榜单(docs-site/zh/guides/viewing-results.mdx 的示例块是
|
|
9
|
+
// 行为规范):`Current verdicts` 头标注合成自几个 run、experiment 表带 eval 级折叠的
|
|
10
|
+
// evals 列、Failing 清单每条带判决时间与下钻命令。
|
|
11
|
+
|
|
12
|
+
import { basename } from "node:path";
|
|
13
|
+
import type { Selection } from "../results/index.ts";
|
|
14
|
+
import { foldEvalOutcome } from "../shared/outcome.ts";
|
|
15
|
+
import { defineComponent } from "./tree.ts";
|
|
16
|
+
import type { CaseListData, OverviewData, TableData } from "./types.ts";
|
|
17
|
+
import { caseListData, overviewData, tableData } from "./compute.ts";
|
|
18
|
+
import { attemptCostUSD, costUSD, durationMs, passRate } from "./metrics.ts";
|
|
19
|
+
import { RunOverview, MetricTable, CaseList } from "./components.tsx";
|
|
20
|
+
import { cellText } from "./text/faces.ts";
|
|
21
|
+
import { renderAlignedRows } from "./text/layout.ts";
|
|
22
|
+
|
|
23
|
+
/** 榜单的合成标注与 eval 级折叠(text 面用;与 verdicts/cases 出自同一选集)。 */
|
|
24
|
+
export interface VerdictBoardData {
|
|
25
|
+
/** 判决合成自几个物理 run。 */
|
|
26
|
+
composedFromRuns: number;
|
|
27
|
+
/** 参与合成的最新 run(目录名,即时间戳)。 */
|
|
28
|
+
latestRun?: string;
|
|
29
|
+
/** experiment → eval 级折叠计票(evals 列的 13/15)。 */
|
|
30
|
+
tallies: Record<string, { passedEvals: number; totalEvals: number }>;
|
|
31
|
+
/** eval 级折叠后失败/出错的题,带判决时间;新失败在前。 */
|
|
32
|
+
failing: {
|
|
33
|
+
evalId: string;
|
|
34
|
+
experimentId: string;
|
|
35
|
+
outcome: "failed" | "errored";
|
|
36
|
+
/** 最新 attempt 的第一条失败断言("gate calledTool(...)")或错误摘要。 */
|
|
37
|
+
reason?: string;
|
|
38
|
+
/** 判决产生的时刻(最新 attempt 的 startedAt,缺失退快照时刻)。 */
|
|
39
|
+
verdictAt?: string;
|
|
40
|
+
}[];
|
|
41
|
+
/** limit 之外还有几条,如实报。 */
|
|
42
|
+
failingTruncated: number;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export interface DefaultReportData {
|
|
46
|
+
overview: OverviewData;
|
|
47
|
+
/** 现刻榜单:experiment × (passRate, costUSD, durationMs)。 */
|
|
48
|
+
verdicts: TableData;
|
|
49
|
+
cases: CaseListData;
|
|
50
|
+
board: VerdictBoardData;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/** 失败清单的出厂截断;完整清单自己摆 <CaseList>(截断如实报剩余)。 */
|
|
54
|
+
const DEFAULT_CASE_LIMIT = 10;
|
|
55
|
+
|
|
56
|
+
function buildBoard(selection: Selection): VerdictBoardData {
|
|
57
|
+
const tallies: VerdictBoardData["tallies"] = {};
|
|
58
|
+
const failing: VerdictBoardData["failing"] = [];
|
|
59
|
+
const runs = new Set<string>();
|
|
60
|
+
let latestRunDir = "";
|
|
61
|
+
|
|
62
|
+
for (const snapshot of selection.snapshots) {
|
|
63
|
+
let passedEvals = 0;
|
|
64
|
+
for (const ev of snapshot.evals) {
|
|
65
|
+
for (const attempt of ev.attempts) {
|
|
66
|
+
runs.add(attempt.runDir.dir);
|
|
67
|
+
if (attempt.runDir.dir > latestRunDir) latestRunDir = attempt.runDir.dir;
|
|
68
|
+
}
|
|
69
|
+
const outcome = foldEvalOutcome(ev.attempts.map((a) => a.result));
|
|
70
|
+
if (outcome === "passed") {
|
|
71
|
+
passedEvals += 1;
|
|
72
|
+
continue;
|
|
73
|
+
}
|
|
74
|
+
if (outcome !== "failed" && outcome !== "errored") continue;
|
|
75
|
+
const latest = ev.attempts.reduce((a, b) => (b.result.attempt >= a.result.attempt ? b : a));
|
|
76
|
+
const failedAssertion = latest.result.assertions.find((a) => !a.passed);
|
|
77
|
+
const reason = failedAssertion
|
|
78
|
+
? `${failedAssertion.severity} ${failedAssertion.name}`
|
|
79
|
+
: latest.result.error !== undefined
|
|
80
|
+
? `error: ${latest.result.error}`
|
|
81
|
+
: undefined;
|
|
82
|
+
failing.push({
|
|
83
|
+
evalId: ev.id,
|
|
84
|
+
experimentId: snapshot.experimentId,
|
|
85
|
+
outcome,
|
|
86
|
+
...(reason !== undefined ? { reason } : {}),
|
|
87
|
+
...(latest.result.startedAt !== undefined || snapshot.startedAt
|
|
88
|
+
? { verdictAt: latest.result.startedAt ?? snapshot.startedAt }
|
|
89
|
+
: {}),
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
tallies[snapshot.experimentId] = { passedEvals, totalEvals: snapshot.evals.length };
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
failing.sort((a, b) => (b.verdictAt ?? "").localeCompare(a.verdictAt ?? ""));
|
|
96
|
+
const shown = failing.slice(0, DEFAULT_CASE_LIMIT);
|
|
97
|
+
return {
|
|
98
|
+
composedFromRuns: runs.size,
|
|
99
|
+
...(latestRunDir ? { latestRun: basename(latestRunDir) } : {}),
|
|
100
|
+
tallies,
|
|
101
|
+
failing: shown,
|
|
102
|
+
failingTruncated: failing.length - shown.length,
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/** 宿主渲染前备好官方水位:只读瘦身条目,代价可忽略。 */
|
|
107
|
+
export async function prepareDefaultReportData(selection: Selection): Promise<DefaultReportData> {
|
|
108
|
+
return {
|
|
109
|
+
overview: await overviewData(selection),
|
|
110
|
+
verdicts: await tableData(selection, {
|
|
111
|
+
rows: "experiment",
|
|
112
|
+
columns: [passRate, costUSD, durationMs],
|
|
113
|
+
sort: passRate,
|
|
114
|
+
}),
|
|
115
|
+
cases: await caseListData(selection, { limit: DEFAULT_CASE_LIMIT }),
|
|
116
|
+
board: buildBoard(selection),
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
let activeData: DefaultReportData | null = null;
|
|
121
|
+
|
|
122
|
+
/** 宿主(与渲染入口)用:在注入好的官方水位下同步渲染。 */
|
|
123
|
+
export function runWithDefaultReportData<T>(data: DefaultReportData, fn: () => T): T {
|
|
124
|
+
const prev = activeData;
|
|
125
|
+
activeData = data;
|
|
126
|
+
try {
|
|
127
|
+
return fn();
|
|
128
|
+
} finally {
|
|
129
|
+
activeData = prev;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
function requireData(): DefaultReportData {
|
|
134
|
+
if (!activeData) {
|
|
135
|
+
throw new Error(
|
|
136
|
+
"<DefaultReport /> renders the host-injected selection; render the report via " +
|
|
137
|
+
"`niceeval show --report` / `niceeval view --report` (or renderReportToText / renderReportToStaticHtml). " +
|
|
138
|
+
"Outside a host, compose the same blocks yourself: RunOverview, MetricTable, CaseList.",
|
|
139
|
+
);
|
|
140
|
+
}
|
|
141
|
+
return activeData;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/** 判决时间的相对标注(text 面的 "41s ago";渲染面纯同步,Date.now 不算 IO)。 */
|
|
145
|
+
function agoText(iso: string | undefined, now: number): string {
|
|
146
|
+
if (!iso) return "";
|
|
147
|
+
const ms = now - Date.parse(iso);
|
|
148
|
+
if (!Number.isFinite(ms) || ms < 10_000) return "just now";
|
|
149
|
+
const seconds = Math.floor(ms / 1000);
|
|
150
|
+
if (seconds < 120) return `${seconds}s ago`;
|
|
151
|
+
const minutes = Math.floor(seconds / 60);
|
|
152
|
+
if (minutes < 120) return `${minutes}m ago`;
|
|
153
|
+
const hours = Math.floor(minutes / 60);
|
|
154
|
+
if (hours < 48) return `${hours}h ago`;
|
|
155
|
+
return `${Math.floor(hours / 24)}d ago`;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/** show 榜单(viewing-results.mdx「榜单」块):头 + experiment 表 + Failing 清单。 */
|
|
159
|
+
function boardText(data: DefaultReportData): string {
|
|
160
|
+
const { verdicts, board, overview } = data;
|
|
161
|
+
const experiments = verdicts.rows.length;
|
|
162
|
+
const head = [
|
|
163
|
+
"Current verdicts",
|
|
164
|
+
`${experiments} ${experiments === 1 ? "experiment" : "experiments"}`,
|
|
165
|
+
`composed from ${board.composedFromRuns} ${board.composedFromRuns === 1 ? "run" : "runs"}`,
|
|
166
|
+
...(board.latestRun ? [`latest ${board.latestRun}`] : []),
|
|
167
|
+
].join(" · ");
|
|
168
|
+
const headBlock = [head, ...overview.warnings.map((w) => `! ${w.message}`)].join("\n");
|
|
169
|
+
|
|
170
|
+
// 表:experiment | evals(eval 级折叠计票)| pass | cost | duration(顺序随 verdicts 预排)
|
|
171
|
+
const header = [verdicts.dimension, "evals", "pass", "cost", "duration"];
|
|
172
|
+
const rows = verdicts.rows.map((row) => {
|
|
173
|
+
const tally = board.tallies[row.key];
|
|
174
|
+
const cells = row.cells as Record<string, TableData["rows"][number]["cells"][string]>;
|
|
175
|
+
return [
|
|
176
|
+
row.key,
|
|
177
|
+
tally ? `${tally.passedEvals}/${tally.totalEvals}` : "—",
|
|
178
|
+
cells[passRate.name] ? cellText(cells[passRate.name]) : "—",
|
|
179
|
+
cells[costUSD.name] ? cellText(cells[costUSD.name]) : "—",
|
|
180
|
+
cells[durationMs.name] ? cellText(cells[durationMs.name]) : "—",
|
|
181
|
+
];
|
|
182
|
+
});
|
|
183
|
+
const table = renderAlignedRows([header, ...rows]);
|
|
184
|
+
|
|
185
|
+
const blocks = [headBlock, table];
|
|
186
|
+
if (board.failing.length > 0) {
|
|
187
|
+
const now = Date.now();
|
|
188
|
+
const aligned = renderAlignedRows(
|
|
189
|
+
board.failing.map((f) => [
|
|
190
|
+
`✗ ${f.evalId}`,
|
|
191
|
+
f.experimentId,
|
|
192
|
+
f.reason ?? f.outcome,
|
|
193
|
+
agoText(f.verdictAt, now),
|
|
194
|
+
]),
|
|
195
|
+
).split("\n");
|
|
196
|
+
const lines: string[] = ["Failing:"];
|
|
197
|
+
board.failing.forEach((f, i) => {
|
|
198
|
+
lines.push(` ${aligned[i]}`);
|
|
199
|
+
lines.push(` → niceeval show ${f.evalId}`);
|
|
200
|
+
});
|
|
201
|
+
if (board.failingTruncated > 0) lines.push(` (${board.failingTruncated} more not shown)`);
|
|
202
|
+
blocks.push(lines.join("\n"));
|
|
203
|
+
}
|
|
204
|
+
return blocks.join("\n\n");
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
export const DefaultReport = defineComponent<Record<string, never>>({
|
|
208
|
+
web() {
|
|
209
|
+
const data = requireData();
|
|
210
|
+
return (
|
|
211
|
+
<div className="nre nre-default-report">
|
|
212
|
+
<RunOverview data={data.overview} />
|
|
213
|
+
<MetricTable data={data.verdicts} />
|
|
214
|
+
{data.cases.rows.length > 0 && <CaseList data={data.cases} />}
|
|
215
|
+
</div>
|
|
216
|
+
);
|
|
217
|
+
},
|
|
218
|
+
text() {
|
|
219
|
+
return boardText(requireData());
|
|
220
|
+
},
|
|
221
|
+
});
|
|
222
|
+
DefaultReport.displayName = "DefaultReport";
|