niceeval 0.6.2 → 0.7.1

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.
Files changed (218) hide show
  1. package/INDEX.md +23 -23
  2. package/README.zh.md +6 -6
  3. package/dist/agents/types.d.ts +2 -2
  4. package/dist/i18n/zh-CN.d.ts +3 -3
  5. package/dist/report/aggregate.d.ts +32 -26
  6. package/dist/report/aggregate.js +157 -76
  7. package/dist/report/built-in/index.d.ts +2 -0
  8. package/dist/report/built-in/index.js +8 -0
  9. package/dist/report/components.d.ts +91 -164
  10. package/dist/report/components.js +377 -114
  11. package/dist/report/compute.d.ts +86 -73
  12. package/dist/report/compute.js +592 -432
  13. package/dist/report/flag.d.ts +28 -17
  14. package/dist/report/flag.js +86 -16
  15. package/dist/report/format.d.ts +11 -11
  16. package/dist/report/format.js +17 -15
  17. package/dist/report/index.d.ts +16 -17
  18. package/dist/report/index.js +20 -22
  19. package/dist/report/load.js +3 -2
  20. package/dist/report/locale.d.ts +49 -34
  21. package/dist/report/locale.js +106 -58
  22. package/dist/report/metrics.d.ts +10 -3
  23. package/dist/report/metrics.js +46 -12
  24. package/dist/report/primitives.d.ts +42 -15
  25. package/dist/report/primitives.js +135 -26
  26. package/dist/report/react/AttemptList.d.ts +10 -8
  27. package/dist/report/react/AttemptList.js +18 -10
  28. package/dist/report/react/DeltaTable.js +19 -18
  29. package/dist/report/react/EvalList.d.ts +3 -3
  30. package/dist/report/react/EvalList.js +0 -0
  31. package/dist/report/react/ExperimentComparison.d.ts +4 -2
  32. package/dist/report/react/ExperimentComparison.js +5 -4
  33. package/dist/report/react/ExperimentList.d.ts +3 -3
  34. package/dist/report/react/ExperimentList.js +16 -15
  35. package/dist/report/react/MetricBars.js +5 -4
  36. package/dist/report/react/MetricLine.js +12 -5
  37. package/dist/report/react/MetricMatrix.js +1 -1
  38. package/dist/report/react/MetricScatter.js +54 -17
  39. package/dist/report/react/MetricTable.js +2 -12
  40. package/dist/report/react/ScopeSummary.d.ts +10 -0
  41. package/dist/report/react/ScopeSummary.js +17 -0
  42. package/dist/report/react/Scoreboard.js +6 -6
  43. package/dist/report/react/cell.js +2 -2
  44. package/dist/report/react/fixtures.d.ts +5 -9
  45. package/dist/report/react/fixtures.js +105 -149
  46. package/dist/report/react/index.d.ts +15 -5
  47. package/dist/report/react/index.js +18 -7
  48. package/dist/report/report.d.ts +137 -20
  49. package/dist/report/report.js +261 -34
  50. package/dist/report/text/faces.d.ts +17 -19
  51. package/dist/report/text/faces.js +225 -157
  52. package/dist/report/text/plot.js +1 -1
  53. package/dist/report/text/table.js +2 -2
  54. package/dist/report/tree.d.ts +90 -40
  55. package/dist/report/tree.js +252 -94
  56. package/dist/report/types.d.ts +245 -300
  57. package/dist/report/types.js +4 -3
  58. package/dist/report/web.d.ts +21 -5
  59. package/dist/report/web.js +42 -16
  60. package/dist/results/select.d.ts +38 -16
  61. package/dist/results/select.js +73 -25
  62. package/dist/results/types.d.ts +38 -14
  63. package/dist/shared/aggregate.d.ts +3 -2
  64. package/dist/shared/aggregate.js +5 -4
  65. package/docs-site/zh/README.md +44 -0
  66. package/docs-site/zh/examples/ai-agent-application.mdx +63 -0
  67. package/docs-site/zh/examples/coding-agent-extensions.mdx +57 -0
  68. package/docs-site/zh/examples/index.mdx +50 -0
  69. package/docs-site/zh/{concepts → explanation}/adapter.mdx +11 -11
  70. package/docs-site/zh/{concepts → explanation}/assert.mdx +7 -7
  71. package/docs-site/zh/{concepts → explanation}/drive.mdx +8 -8
  72. package/docs-site/zh/{concepts → explanation}/evals.mdx +4 -4
  73. package/docs-site/zh/{concepts → explanation}/experiment.mdx +8 -8
  74. package/docs-site/zh/{concepts → explanation}/hitl.mdx +8 -8
  75. package/docs-site/zh/{concepts → explanation}/judge.mdx +5 -5
  76. package/docs-site/zh/{concepts → explanation}/overview.mdx +5 -5
  77. package/docs-site/zh/{guides → explanation}/runner.mdx +1 -1
  78. package/docs-site/zh/{concepts → explanation}/tier.mdx +6 -6
  79. package/docs-site/zh/{guides → how-to}/agent-feedback-loop.mdx +7 -7
  80. package/docs-site/zh/{guides → how-to}/authoring.mdx +2 -2
  81. package/docs-site/zh/{guides → how-to}/connect-otel.mdx +6 -6
  82. package/docs-site/zh/{guides → how-to}/connect-your-agent.mdx +18 -18
  83. package/docs-site/zh/{guides → how-to}/custom-reports.mdx +6 -6
  84. package/docs-site/zh/{guides → how-to}/experiments.mdx +3 -3
  85. package/docs-site/zh/{guides → how-to}/publish-report.mdx +2 -2
  86. package/docs-site/zh/{guides → how-to}/sandbox-agent.mdx +2 -2
  87. package/docs-site/zh/{guides → how-to}/sandbox-providers.mdx +1 -1
  88. package/docs-site/zh/{guides → how-to}/viewing-results.mdx +6 -6
  89. package/docs-site/zh/{guides → how-to}/write-experiment.mdx +3 -3
  90. package/docs-site/zh/{guides → how-to}/write-send.mdx +13 -13
  91. package/docs-site/zh/index.mdx +23 -25
  92. package/docs-site/zh/introduction.mdx +8 -8
  93. package/docs-site/zh/reference/builtin-agents.mdx +5 -5
  94. package/docs-site/zh/reference/capabilities.mdx +6 -6
  95. package/docs-site/zh/reference/cli.mdx +9 -7
  96. package/docs-site/zh/reference/define-agent.mdx +1 -1
  97. package/docs-site/zh/reference/events.mdx +3 -3
  98. package/docs-site/zh/{guides → reference}/official-adapters.mdx +7 -7
  99. package/docs-site/zh/{guides → reference}/report-components.mdx +5 -5
  100. package/docs-site/zh/{guides → reference}/results-data.mdx +5 -5
  101. package/docs-site/zh/{guides → troubleshooting}/debug-sandbox.mdx +2 -2
  102. package/docs-site/zh/{guides → troubleshooting}/debugging.mdx +4 -2
  103. package/docs-site/zh/{quickstart.mdx → tutorials/quickstart.mdx} +5 -17
  104. package/package.json +6 -2
  105. package/src/agents/index.ts +2 -2
  106. package/src/agents/openai-compat.ts +1 -1
  107. package/src/agents/streaming.ts +2 -2
  108. package/src/agents/types.ts +3 -3
  109. package/src/cli.ts +42 -23
  110. package/src/context/context.ts +1 -1
  111. package/src/context/session.test.ts +1 -1
  112. package/src/context/session.ts +1 -1
  113. package/src/i18n/en.ts +18 -16
  114. package/src/i18n/zh-CN.ts +16 -15
  115. package/src/report/aggregate.ts +175 -87
  116. package/src/report/built-in/index.tsx +9 -0
  117. package/src/report/components.tsx +625 -285
  118. package/src/report/compute.ts +717 -515
  119. package/src/report/dual-render.test.tsx +738 -1148
  120. package/src/report/flag.ts +97 -33
  121. package/src/report/format.ts +18 -22
  122. package/src/report/index.ts +113 -58
  123. package/src/report/load.ts +3 -2
  124. package/src/report/locale.ts +120 -69
  125. package/src/report/metrics.ts +42 -12
  126. package/src/report/primitives.tsx +190 -45
  127. package/src/report/react/AttemptList.tsx +32 -20
  128. package/src/report/react/DeltaTable.tsx +63 -45
  129. package/src/report/react/EvalList.tsx +0 -0
  130. package/src/report/react/ExperimentComparison.tsx +12 -7
  131. package/src/report/react/ExperimentList.tsx +38 -26
  132. package/src/report/react/MetricBars.tsx +5 -4
  133. package/src/report/react/MetricLine.tsx +13 -8
  134. package/src/report/react/MetricMatrix.tsx +2 -2
  135. package/src/report/react/MetricScatter.tsx +74 -20
  136. package/src/report/react/MetricTable.tsx +4 -76
  137. package/src/report/react/ScopeSummary.tsx +86 -0
  138. package/src/report/react/Scoreboard.tsx +28 -10
  139. package/src/report/react/cell.tsx +2 -2
  140. package/src/report/react/enhance.js +57 -5
  141. package/src/report/react/fixtures.ts +109 -156
  142. package/src/report/react/index.tsx +24 -39
  143. package/src/report/react/render.test.tsx +139 -104
  144. package/src/report/react/styles.css +181 -91
  145. package/src/report/report.test.ts +761 -1031
  146. package/src/report/report.ts +425 -47
  147. package/src/report/text/faces.ts +257 -164
  148. package/src/report/text/plot.ts +1 -1
  149. package/src/report/text/table.ts +2 -2
  150. package/src/report/tree.ts +362 -104
  151. package/src/report/types.ts +257 -287
  152. package/src/report/web.ts +63 -20
  153. package/src/results/attempt-evidence.test.ts +4 -4
  154. package/src/results/attempt-evidence.ts +5 -5
  155. package/src/results/copy.ts +6 -6
  156. package/src/results/host-equivalence.test.ts +26 -14
  157. package/src/results/index.ts +10 -4
  158. package/src/results/open.ts +8 -4
  159. package/src/results/results.test.ts +4 -3
  160. package/src/results/select.ts +104 -34
  161. package/src/results/types.ts +36 -14
  162. package/src/runner/feedback/human.test.ts +1 -1
  163. package/src/runner/run.ts +1 -1
  164. package/src/sandbox/cli-commands.ts +2 -2
  165. package/src/scoring/judge.test.ts +1 -1
  166. package/src/shared/aggregate.ts +5 -4
  167. package/src/show/compose.ts +50 -67
  168. package/src/show/index.ts +107 -56
  169. package/src/show/render.ts +43 -27
  170. package/src/show/report-host.test.ts +188 -0
  171. package/src/show/report-host.ts +375 -0
  172. package/src/show/show.test.ts +86 -36
  173. package/src/view/app/App.test.tsx +69 -0
  174. package/src/view/app/App.tsx +144 -48
  175. package/src/view/app/components/AttemptModal.tsx +324 -63
  176. package/src/view/app/components/CodeView.tsx +10 -4
  177. package/src/view/app/i18n.ts +31 -17
  178. package/src/view/app/lib/artifact-url.ts +14 -3
  179. package/src/view/app/main.tsx +13 -8
  180. package/src/view/app/pages/{RunsPage.tsx → AttemptsPage.tsx} +6 -6
  181. package/src/view/app/types.ts +4 -1
  182. package/src/view/artifact-serving.test.ts +21 -1
  183. package/src/view/client-dist/app.css +1 -1
  184. package/src/view/client-dist/app.js +6 -6
  185. package/src/view/data.test.ts +9 -3
  186. package/src/view/data.ts +145 -49
  187. package/src/view/index.ts +48 -44
  188. package/src/view/server.ts +35 -15
  189. package/src/view/shared/types.ts +34 -5
  190. package/src/view/styles.css +224 -0
  191. package/src/view/view-report.test.ts +161 -57
  192. package/dist/report/built-ins/experiment-comparison.d.ts +0 -39
  193. package/dist/report/built-ins/experiment-comparison.js +0 -119
  194. package/dist/report/built-ins/index.d.ts +0 -2
  195. package/dist/report/built-ins/index.js +0 -2
  196. package/dist/report/react/GroupSummary.d.ts +0 -8
  197. package/dist/report/react/GroupSummary.js +0 -8
  198. package/dist/report/react/RunOverview.d.ts +0 -8
  199. package/dist/report/react/RunOverview.js +0 -12
  200. package/docs-site/zh/example/ai-agent-application.mdx +0 -152
  201. package/docs-site/zh/example/claude-code-codex-plugin.mdx +0 -167
  202. package/docs-site/zh/example/claude-code-codex-skill.mdx +0 -152
  203. package/docs-site/zh/example/showcase.mdx +0 -39
  204. package/src/report/built-in-user-parity.test.tsx +0 -597
  205. package/src/report/built-ins/experiment-comparison.tsx +0 -179
  206. package/src/report/built-ins/index.ts +0 -7
  207. package/src/report/react/GroupSummary.tsx +0 -66
  208. package/src/report/react/RunOverview.tsx +0 -109
  209. /package/docs-site/zh/{example/tier1-ai-sdk-v7.mdx → examples/integrations/ai-sdk-v7.mdx} +0 -0
  210. /package/docs-site/zh/{example/tier1-claude-sdk.mdx → examples/integrations/claude-sdk.mdx} +0 -0
  211. /package/docs-site/zh/{example/tier1-codex-sdk.mdx → examples/integrations/codex-sdk.mdx} +0 -0
  212. /package/docs-site/zh/{example/tier1-langgraph.mdx → examples/integrations/langgraph.mdx} +0 -0
  213. /package/docs-site/zh/{example/tier1-pi-sdk.mdx → examples/integrations/pi-sdk.mdx} +0 -0
  214. /package/docs-site/zh/{guides → how-to}/ci-integration.mdx +0 -0
  215. /package/docs-site/zh/{guides → how-to}/dataset-fanout.mdx +0 -0
  216. /package/docs-site/zh/{guides → how-to}/fixtures.mdx +0 -0
  217. /package/docs-site/zh/{guides → how-to}/reporters.mdx +0 -0
  218. /package/docs-site/zh/{guides → how-to}/scoring-guide.mdx +0 -0
@@ -1,46 +1,110 @@
1
- // flag() / config():把 experiment 声明的变量当维度或轴(docs/feature/reports/library.md「维度与 flags」)
1
+ // flag() / runConfig() / numericFlag() / numericRunConfig():把 experiment 声明的变量当
2
+ // 分组维度或数值轴(docs/feature/reports/library/metrics.md「维度与数值轴」)。
2
3
  // 变量来自配置,不来自命名 —— 报告不解析 experiment id 字符串抠变量。
3
4
  // flag() 只读 `ExperimentDef.flags` 里显式声明的 KV;model / reasoningEffort / budget / runs
4
- // 这类顶层运行配置不在 flags 里,用 config() 读快照的 ExperimentRunInfo 投影。
5
+ // 这类顶层运行配置不在 flags 里,用 runConfig() 读快照的 ExperimentRunInfo 投影。
5
6
 
6
- import type { ConfigRef, FlagRef } from "./types.ts";
7
+ import type { AttemptHandle } from "../results/types.ts";
8
+ import type {
9
+ DimensionOptions,
10
+ DimensionRef,
11
+ NumericAxis,
12
+ NumericAxisOptions,
13
+ NumericRunConfigAxisOptions,
14
+ RunConfigKey,
15
+ } from "./types.ts";
16
+
17
+ /** experiment 声明的 flags(快照级投影优先;第三方落盘只拼在条目上时回退 result.experiment)。 */
18
+ export function flagValueOf(attempt: AttemptHandle, name: string): unknown {
19
+ const info = attempt.snapshot?.experiment ?? attempt.result.experiment;
20
+ return info?.flags?.[name];
21
+ }
7
22
 
8
23
  /**
9
- * 把 experiment 声明的一个 flag 当分组维度(series / rows / columns / points 槽)或数值轴
10
- * (MetricLine x 槽)。只读 `ExperimentDef.flags` 里显式声明的 KV;未声明的 experiment
11
- * 分组归 `(unset)`,作轴不画点并报告缺失。
24
+ * runConfig() 的取值:读快照的 `ExperimentRunInfo` 投影,外加桥接到快照顶层权威字段的
25
+ * `model` / `agent` 两个键(与 "model" / "agent" 内置维度同一读法,不另造第二套口径)。
26
+ * 未投影 → undefined。
12
27
  */
13
- export function flag(
14
- name: string,
15
- opts?: {
16
- /** 组标签 / 轴标签;函数形态把声明值折成组名(如 `(v) => \`${v} agents\``)。 */
17
- label?: string | ((value: string | number | boolean) => string);
18
- unit?: string;
19
- },
20
- ): FlagRef {
28
+ export function runConfigValueOf(attempt: AttemptHandle, name: RunConfigKey): unknown {
29
+ if (name === "model") return attempt.result.model ?? attempt.snapshot?.model;
30
+ if (name === "agent") return attempt.result.agent || attempt.snapshot?.agent;
31
+ const info = attempt.snapshot?.experiment ?? attempt.result.experiment;
32
+ // ExperimentRunInfo 是穷尽可序列化投影;按字段名取值,新增投影字段无需改这里
33
+ return (info as Record<string, unknown> | undefined)?.[name];
34
+ }
35
+
36
+ function assertName(name: unknown, fn: string, hint: string): asserts name is string {
21
37
  if (typeof name !== "string" || name.length === 0) {
22
- throw new Error("flag: name must be a non-empty string (the key declared in the experiment's flags).");
38
+ throw new Error(`${fn}: name must be a non-empty string (${hint}).`);
23
39
  }
24
- return { kind: "flag", name, label: opts?.label, unit: opts?.unit };
25
40
  }
26
41
 
27
42
  /**
28
- * 把一项顶层运行配置当分组维度或数值轴,与 {@link flag} 同一套用法。读快照的
29
- * `ExperimentRunInfo` 投影(可用键是那张接口的字段全集),外加桥接到快照顶层权威字段的
30
- * `model` / `agent` 两个键。未投影的值分组归 `(unset)`,作轴不画点并报告缺失。
43
+ * experiment 声明的一个 flag 当分组维度(rows / columns / points / series / by 槽)。
44
+ * 分组显示键按稳定 JSON 规则生成(字符串直接显示,其它值用键递归排序后的 JSON),
45
+ * 缺失值显示内置文案 `(missing)`;显示键冲突时计算报错并要求改用 CustomDimension。
31
46
  */
32
- export function config(
33
- name: string,
34
- opts?: {
35
- /** 组标签 / 轴标签;函数形态把投影值折成组名(如 `(v) => \`effort ${v}\``)。 */
36
- label?: string | ((value: string | number | boolean) => string);
37
- unit?: string;
38
- },
39
- ): ConfigRef {
40
- if (typeof name !== "string" || name.length === 0) {
41
- throw new Error(
42
- "config: name must be a non-empty string (an ExperimentRunInfo field, or the bridged \"model\" / \"agent\" keys).",
43
- );
44
- }
45
- return { kind: "config", name, label: opts?.label, unit: opts?.unit };
47
+ export function flag(name: string, options?: DimensionOptions): DimensionRef {
48
+ assertName(name, "flag", "the key declared in the experiment's flags");
49
+ return {
50
+ kind: "flag",
51
+ name,
52
+ ...(options?.label !== undefined ? { label: options.label } : {}),
53
+ ...(options?.unit !== undefined ? { unit: options.unit } : {}),
54
+ };
55
+ }
56
+
57
+ /**
58
+ * 把一项顶层运行配置当分组维度,与 {@link flag} 同一套用法。读快照的 `ExperimentRunInfo`
59
+ * 投影;可用键由 RunConfigKey 在类型层穷尽(那张接口的字段全集,外加桥接到快照顶层权威
60
+ * 字段的 `model` / `agent`),拼错键在编译期就被拒绝。
61
+ */
62
+ export function runConfig(name: RunConfigKey, options?: DimensionOptions): DimensionRef {
63
+ assertName(name, "runConfig", 'an ExperimentRunInfo field, or the bridged "model" / "agent" keys');
64
+ return {
65
+ kind: "runConfig",
66
+ name,
67
+ ...(options?.label !== undefined ? { label: options.label } : {}),
68
+ ...(options?.unit !== undefined ? { unit: options.unit } : {}),
69
+ };
70
+ }
71
+
72
+ /**
73
+ * MetricLine 的 x 轴:只接受落盘值为 number 的 flag。未声明或非数值的 attempt 返回 null
74
+ * (折线不绘该点并报告缺失),不猜 `low < medium < high`。
75
+ */
76
+ export function numericFlag(name: string, options?: NumericAxisOptions): NumericAxis {
77
+ assertName(name, "numericFlag", "the key declared in the experiment's flags");
78
+ return {
79
+ name,
80
+ ...(options?.label !== undefined ? { label: options.label } : {}),
81
+ ...(options?.unit !== undefined ? { unit: options.unit } : {}),
82
+ of(attempt) {
83
+ const value = flagValueOf(attempt, name);
84
+ return typeof value === "number" && Number.isFinite(value) ? value : null;
85
+ },
86
+ };
87
+ }
88
+
89
+ /**
90
+ * 顶层运行配置作数值轴:数值配置直接返回该值;字符串配置必须显式给 `map`
91
+ * (如 { low: 1, medium: 2, high: 3 })。未声明、未投影、非数值或未命中 map 的值返回 null。
92
+ */
93
+ export function numericRunConfig(name: RunConfigKey, options?: NumericRunConfigAxisOptions): NumericAxis {
94
+ assertName(name, "numericRunConfig", 'an ExperimentRunInfo field, or the bridged "model" / "agent" keys');
95
+ const map = options?.map;
96
+ return {
97
+ name,
98
+ ...(options?.label !== undefined ? { label: options.label } : {}),
99
+ ...(options?.unit !== undefined ? { unit: options.unit } : {}),
100
+ of(attempt) {
101
+ const value = runConfigValueOf(attempt, name);
102
+ if (typeof value === "number" && Number.isFinite(value)) return value;
103
+ if (typeof value === "string" && map !== undefined) {
104
+ const mapped = map[value];
105
+ return typeof mapped === "number" && Number.isFinite(mapped) ? mapped : null;
106
+ }
107
+ return null;
108
+ },
109
+ };
46
110
  }
@@ -2,8 +2,8 @@
2
2
  // "%" → 87% "ms" → 1.2s "$" → $0.31 其余 → 1.2k 缩写(带 unit 后缀)
3
3
  // metric.display 可整体覆盖;这里只负责默认。
4
4
 
5
- import type { AssertionResult, Verdict } from "../types.ts";
6
- import { compactAssertionSummary, fitCompactAssertionSummary, primaryAssertionSummary } from "../scoring/display.ts";
5
+ import type { Verdict } from "../types.ts";
6
+ import { DISPLAY_LOCALES, type LocalizedText, type ReportLocale } from "./locale.ts";
7
7
 
8
8
  /**
9
9
  * experiment 行的显示名:给了父路径 `relativeTo` 且它确是前缀,就去掉 `relativeTo + "/"`,
@@ -57,6 +57,18 @@ export function formatMetricValue(value: number, unit?: string): string {
57
57
  return unit ? `${sign}${n} ${unit}` : `${sign}${n}`;
58
58
  }
59
59
 
60
+ /**
61
+ * MetricCell.display 的生成:为官方生成面覆盖的每个 locale(DISPLAY_LOCALES)各生成一份;
62
+ * 全部相同(内置 unit 格式化都是 locale 无关的)时折叠成单个字符串,renderer 按
63
+ * LocalizedText 回退规则选择。`make` 抛错由调用方(computeCell)带 metric 上下文包装。
64
+ */
65
+ export function localizedDisplay(make: (locale: ReportLocale) => string): LocalizedText {
66
+ const entries = DISPLAY_LOCALES.map((locale) => [locale, make(locale)] as const);
67
+ const first = entries[0]![1];
68
+ if (entries.every(([, text]) => text === first)) return first;
69
+ return Object.fromEntries(entries);
70
+ }
71
+
60
72
  /** 无单位纯数字(scoreboard 总分等):一位小数,去尾零。 */
61
73
  export function formatPlainNumber(value: number): string {
62
74
  const sign = value < 0 ? "-" : "";
@@ -109,25 +121,9 @@ export function verdictMark(verdict: Verdict): string {
109
121
  }
110
122
 
111
123
  /**
112
- * Attempt 比较项的一层结果摘要;完整 assertions 只在 locator 详情里展开。
113
- * maxChars(可选)是渲染面的宽度收口预算(如两行单元格 = 2 × 列宽):断言摘要按
114
- * fitCompactAssertionSummary 的优先级让位,error 摘要折单行后尾截。
124
+ * `AttemptListItem.failureSummary` 的宽度收口:摘要已在计算侧按 Scoring display 契约折好,
125
+ * 渲染面只做尾截,不重算摘要。maxChars 是渲染面的宽度预算(如两行单元格 = 2 × 列宽)
115
126
  */
116
- export function attemptItemReason(
117
- item: {
118
- verdict: Verdict;
119
- error?: { message: string };
120
- assertions: AssertionResult[];
121
- },
122
- maxChars?: number,
123
- ): string | undefined {
124
- if (item.error !== undefined) {
125
- const message = item.error.message.replace(/\s+/g, " ").trim();
126
- return maxChars !== undefined && message.length > maxChars
127
- ? `${message.slice(0, Math.max(0, maxChars - 1))}…`
128
- : message;
129
- }
130
- const summary = primaryAssertionSummary(item.assertions, item.verdict);
131
- if (summary === undefined) return undefined;
132
- return maxChars === undefined ? compactAssertionSummary(summary) : fitCompactAssertionSummary(summary, maxChars);
127
+ export function fitFailureSummary(summary: string, maxChars: number): string {
128
+ return summary.length <= maxChars ? summary : `${summary.slice(0, Math.max(0, maxChars - 1))}…`;
133
129
  }
@@ -1,44 +1,83 @@
1
1
  // niceeval/report —— 报告积木:指标 × 计算函数 × 双面组件 × defineReport。
2
- // 契约见 docs/feature/reports/README.md;公开叙事的准绳是 docs-site/zh/guides/custom-reports.mdx
3
- // 与 report-components.mdx。
2
+ // 契约见 docs/feature/reports/README.md docs/feature/reports/library/ 分篇。
4
3
  //
5
- // import 边界即运行时边界:计算函数(挂在组件上的 .data)会经句柄触碰文件系统
6
- // (懒加载 artifact),只能进服务端 / 脚本;组件的渲染面纯同步零 IO。text 宿主遍历渲染
7
- // 不需要 react-dom(renderReportToText);web 宿主的 renderReportToStaticHtml 在
8
- // ./web.ts,只有那一侧 import react-dom。写报告文件的项目要装 react(.tsx 编译产物
9
- // import react/jsx-runtime)。
4
+ // import 边界即运行时边界:计算函数(*Data)会经句柄触碰文件系统(懒加载 artifact),
5
+ // 只能进服务端 / 脚本;组件的渲染面纯同步零 IO。text 宿主遍历渲染不需要 react-dom
6
+ // (renderReportToText);web 宿主的 renderReportToStaticHtml 在 ./web.ts,只有那一侧
7
+ // import react-dom。写报告文件的项目要装 react(.tsx 编译产物 import react/jsx-runtime)。
10
8
 
11
- // 指标与维度读取器(flag / config)
9
+ // 指标与维度读取器
12
10
  export {
11
+ assistantTurns,
12
+ costUSD,
13
13
  defineMetric,
14
- taskPassRate,
15
- executionReliability,
14
+ durationMs,
16
15
  endToEndPassRate,
17
16
  examScore,
18
- durationMs,
17
+ executionReliability,
18
+ repeatedFailedCommands,
19
+ taskPassRate,
19
20
  tokens,
20
- costUSD,
21
- turns,
22
21
  } from "./metrics.ts";
23
- export { flag, config } from "./flag.ts";
22
+ export { flag, numericFlag, numericRunConfig, runConfig } from "./flag.ts";
24
23
 
25
- // 报告基座与双面组件基座
26
- export { defineReport, isReportDefinition, renderReportToText } from "./report.ts";
27
- export type { ReportContext, ReportDefinition } from "./report.ts";
28
- export { defineComponent } from "./tree.ts";
24
+ // 报告定义与组件基座
25
+ export {
26
+ buildReportMeta,
27
+ defineReport,
28
+ isReportDefinition,
29
+ pickReportPage,
30
+ renderReportToText,
31
+ renderReportTreeToText,
32
+ reportTitleText,
33
+ resolveReportTitle,
34
+ ReportPageNotFoundError,
35
+ DEFAULT_PAGE_ID,
36
+ } from "./report.ts";
37
+ export type {
38
+ HostCommandContext,
39
+ NonEmptyArray,
40
+ RenderReportTextOptions,
41
+ RenderTreeTextOptions,
42
+ ReportTreeHostContext,
43
+ ReportAsset,
44
+ ReportDef,
45
+ ReportDefinition,
46
+ ReportHostContext,
47
+ ReportLink,
48
+ ReportMeta,
49
+ ReportPage,
50
+ ReportShell,
51
+ } from "./report.ts";
52
+ export { defineComponent, createTextContext, renderNodeToText, resolveReportTree, validateReportTree, ResolveMemo } from "./tree.ts";
29
53
  export type {
30
54
  ComponentFaces,
55
+ ComposeContext,
31
56
  ReportComponent,
32
57
  ReportElement,
33
58
  ReportNode,
59
+ ResolveContext,
60
+ ResolveEnv,
34
61
  TextContext,
35
62
  TextRenderOptions,
36
63
  WebContext,
37
64
  } from "./tree.ts";
38
65
 
39
- // 排版原语(六个内置双面组件)
40
- export { Row, Col, Section, Text, Style, Table } from "./primitives.tsx";
41
- export type { LayoutProps, SectionProps, StyleProps, TableColumn, TableProps, TableRow } from "./primitives.tsx";
66
+ // 排版原语(八个内置双面组件)
67
+ export { Col, Row, Section, Style, Tab, Table, Tabs, Text } from "./primitives.tsx";
68
+ export type {
69
+ ColProps,
70
+ LayoutProps,
71
+ RowProps,
72
+ SectionProps,
73
+ StyleProps,
74
+ TabProps,
75
+ TableColumn,
76
+ TableProps,
77
+ TableRow,
78
+ TabsProps,
79
+ TextProps,
80
+ } from "./primitives.tsx";
42
81
 
43
82
  // 文本排版工具箱:自定义组件的 text 面用的就是官方组件那把尺子。
44
83
  // 表格有 <Table> 承担,这里只给表以外的形态用 —— 尤其别拿 String.prototype.padEnd 对齐:
@@ -54,92 +93,108 @@ export {
54
93
  } from "./text/layout.ts";
55
94
  export type { ColumnAlign } from "./text/layout.ts";
56
95
 
57
- // 内置报告兼组合件(show / view 裸跑时报告槽的出厂填充;也可作组件整体引用,
58
- // `<ExperimentComparison data={await ExperimentComparison.data(selection)} />`),无 renderer 特权
59
- export { ExperimentComparison } from "./built-ins/index.ts";
60
- export type {
61
- ExperimentComparisonData,
62
- ExperimentComparisonGroupData,
63
- ExperimentComparisonProps,
64
- } from "./built-ins/index.ts";
96
+ // locale:官方组件 chrome 文案的语言(内置词典覆盖 en / zh-CN,其它 locale 走回退)
97
+ export { DEFAULT_REPORT_LOCALE, localizedTextEquals, resolveLocalizedText, resolveMetricLabel } from "./locale.ts";
98
+ export type { LocalizedText, ReportLocale } from "./locale.ts";
65
99
 
66
- // locale:官方组件 chrome 文案的语言(en / zh-CN);指标 label 可按 locale 给字典
67
- export { DEFAULT_REPORT_LOCALE, resolveMetricLabel } from "./locale.ts";
68
- export type { LocalizedLabel, ReportLocale } from "./locale.ts";
69
-
70
- // 官方双面组件(各自带 data 计算函数;MetricBars.data = MetricMatrix.data)
100
+ // 官方双面组件(spec / data 双形态;配套 *Data 计算函数在下面成对导出)
71
101
  export {
72
102
  AttemptList,
73
103
  DeltaTable,
74
104
  EvalList,
105
+ ExperimentComparison,
75
106
  ExperimentList,
76
- GroupSummary,
107
+ FailureList,
77
108
  MetricBars,
78
109
  MetricLine,
79
110
  MetricMatrix,
80
111
  MetricScatter,
81
112
  MetricTable,
82
- RunOverview,
83
113
  Scoreboard,
114
+ ScopeSummary,
84
115
  } from "./components.tsx";
85
116
  export type {
86
117
  AttemptListProps,
118
+ DataProps,
87
119
  DeltaTableProps,
88
120
  EvalListProps,
121
+ ExperimentComparisonProps,
89
122
  ExperimentListProps,
90
- GroupSummaryProps,
123
+ FailureListProps,
124
+ MetricBarsProps,
91
125
  MetricLineProps,
92
126
  MetricMatrixProps,
93
127
  MetricScatterProps,
94
128
  MetricTableProps,
95
- RunOverviewProps,
96
129
  ScoreboardProps,
130
+ ScopeSummaryProps,
97
131
  } from "./components.tsx";
98
132
 
99
- // 计算函数的选项类型(函数本体挂在组件上,不做顶层导出)
133
+ // 计算函数(组件解析面的具名形式,与组件成对;spec 形态下由管线代调,data 形态与
134
+ // 嵌入场景下由作者手工调)
135
+ export {
136
+ attemptListData,
137
+ deltaTableData,
138
+ evalListData,
139
+ experimentComparisonData,
140
+ experimentListData,
141
+ metricLineData,
142
+ metricMatrixData,
143
+ metricScatterData,
144
+ metricTableData,
145
+ pairsByFlag,
146
+ scopeSummaryData,
147
+ scoreboardData,
148
+ } from "./compute.ts";
100
149
  export type {
101
- AttemptListDataOptions,
102
- DeltaDataOptions,
103
- DeltaPair,
104
- LineDataOptions,
105
- MatrixDataOptions,
106
- ScatterDataOptions,
107
- ScoreboardDataOptions,
108
- TableDataOptions,
150
+ DeltaTableOptions,
151
+ MetricLineOptions,
152
+ MetricMatrixOptions,
153
+ MetricScatterOptions,
154
+ MetricTableOptions,
155
+ ScoreboardOptions,
109
156
  } from "./compute.ts";
110
157
 
111
- // 数据契约(组件的 data props)
158
+ // 数据契约(组件的 data)
112
159
  export type {
113
160
  Aggregator,
114
161
  AttemptListItem,
115
162
  AttemptLocator,
116
- AxisInput,
117
- ConfigRef,
163
+ BuiltInDimension,
164
+ CustomDimension,
118
165
  DeltaData,
119
- Dimension,
166
+ DeltaPair,
120
167
  DimensionInput,
168
+ DimensionOptions,
169
+ DimensionRef,
170
+ EntityListDataOptions,
121
171
  EvalListItem,
172
+ ExperimentComparisonData,
173
+ ExperimentComparisonGroupData,
122
174
  ExperimentListEvalRow,
123
175
  ExperimentListItem,
124
- GroupSummaryData,
125
- LineAxis,
176
+ FlagPairs,
126
177
  LineData,
127
178
  MatrixData,
128
179
  Metric,
129
180
  MetricAggregate,
130
181
  MetricCell,
131
182
  MetricColumn,
132
- OverviewData,
133
- FlagRef,
183
+ NumericAxis,
184
+ NumericAxisOptions,
185
+ NumericRunConfigAxisOptions,
186
+ ReportInput,
187
+ RunConfigKey,
134
188
  ScatterData,
189
+ ScopeSummaryData,
190
+ ScopeWarning,
135
191
  ScoreboardData,
136
- SelectionWarning,
137
192
  TableData,
138
- TableRowMeta,
193
+ VerdictTally,
139
194
  } from "./types.ts";
140
195
 
141
196
  // 数据层输入的类型(家在 niceeval/results,这里 re-export 方便写指标 / 报告)
142
- export type { AttemptHandle, Results, Selection, Snapshot } from "../results/types.ts";
197
+ export type { AttemptHandle, Results, Scope, Snapshot } from "../results/types.ts";
143
198
 
144
199
  // experiment id 的组键推导(id 的目录前缀,如 `compare/bub-low` 的 `compare`)。
145
200
  // 重新导出,让自定义报告能按同一份口径把 experiment 分组,不必自己重写这两行逻辑。
@@ -28,7 +28,7 @@ export async function loadReportFile(
28
28
  const abs = resolve(cwd, path);
29
29
  if (!existsSync(abs)) {
30
30
  throw new ReportLoadError(
31
- `Report file not found: ${abs}. Pass --report an explicit path to a module whose default export is defineReport(...).`,
31
+ `Report file not found: ${abs}. Pass --report an explicit path to a module whose default export is a defineReport(...) product.`,
32
32
  );
33
33
  }
34
34
  const plain = pathToFileURL(abs);
@@ -60,7 +60,8 @@ export async function loadReportFile(
60
60
  }
61
61
  if (!isReportDefinition(mod.default)) {
62
62
  throw new ReportLoadError(
63
- `${path} does not default-export a report. Export default defineReport(async ({ selection, results }) => ...) from "niceeval/report".`,
63
+ `${path} does not default-export a report. Export the product of defineReport(...) from "niceeval/report" as the default export — ` +
64
+ `a tree (defineReport(<ExperimentComparison />)) or a config object (defineReport({ title, content | pages, … })).`,
64
65
  );
65
66
  }
66
67
  return mod.default;