niceeval 0.1.0 → 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (133) hide show
  1. package/README.md +9 -9
  2. package/README.zh.md +14 -14
  3. package/docs/README.md +119 -0
  4. package/docs/adapters/README.md +60 -0
  5. package/docs/adapters/authoring.md +179 -0
  6. package/docs/adapters/coding-agent-skills-plugins.md +324 -0
  7. package/docs/adapters/collection.md +128 -0
  8. package/docs/adapters/contract.md +263 -0
  9. package/docs/adapters/reference/agent-eval.md +215 -0
  10. package/docs/adapters/reference/agent-loop-apis.md +69 -0
  11. package/docs/adapters/reference/claude-code-otel-telemetry.md +100 -0
  12. package/docs/adapters/reference/eve-protocol.md +127 -0
  13. package/docs/adapters/reference/otel-genai.md +107 -0
  14. package/docs/adapters/reference/otel-instrumentation.md +65 -0
  15. package/docs/adapters/targets.md +99 -0
  16. package/docs/architecture.md +140 -0
  17. package/docs/assertions.md +388 -0
  18. package/docs/capabilities-by-construction.md +48 -0
  19. package/docs/cli.md +171 -0
  20. package/docs/concepts.md +106 -0
  21. package/docs/e2e-ci.md +295 -0
  22. package/docs/eval-authoring.md +319 -0
  23. package/docs/experiments.md +154 -0
  24. package/docs/getting-started.md +224 -0
  25. package/docs/multi-agent.md +145 -0
  26. package/docs/observability.md +333 -0
  27. package/docs/origin-integration.md +195 -0
  28. package/docs/references.md +35 -0
  29. package/docs/results-format.md +228 -0
  30. package/docs/runner.md +104 -0
  31. package/docs/sandbox.md +276 -0
  32. package/docs/scoring.md +119 -0
  33. package/docs/source-map.md +106 -0
  34. package/docs/tier-sync.md +177 -0
  35. package/docs/view.md +157 -0
  36. package/docs/vision.md +88 -0
  37. package/package.json +46 -17
  38. package/src/agents/ai-sdk-otel.ts +0 -0
  39. package/src/agents/ai-sdk.test.ts +377 -0
  40. package/src/agents/ai-sdk.ts +577 -0
  41. package/src/agents/bub.ts +30 -37
  42. package/src/agents/claude-code.ts +7 -4
  43. package/src/agents/codex.ts +15 -10
  44. package/src/agents/index.ts +43 -1
  45. package/src/agents/sdk-streams.test.ts +145 -0
  46. package/src/agents/sdk-streams.ts +457 -0
  47. package/src/agents/shared.ts +77 -39
  48. package/src/agents/streaming.test.ts +152 -0
  49. package/src/agents/streaming.ts +195 -0
  50. package/src/agents/types.ts +218 -0
  51. package/src/agents/ui-message-stream.test.ts +249 -0
  52. package/src/agents/ui-message-stream.ts +372 -0
  53. package/src/cli.ts +124 -77
  54. package/src/context/context.test.ts +203 -7
  55. package/src/context/context.ts +158 -49
  56. package/src/context/session.test.ts +96 -0
  57. package/src/context/session.ts +119 -9
  58. package/src/context/types.ts +205 -0
  59. package/src/define.ts +4 -14
  60. package/src/expect/index.ts +8 -71
  61. package/src/i18n/core.ts +28 -0
  62. package/src/i18n/en.ts +47 -5
  63. package/src/i18n/index.ts +5 -17
  64. package/src/i18n/zh-CN.ts +47 -5
  65. package/src/index.ts +12 -0
  66. package/src/loaders/index.ts +8 -39
  67. package/src/o11y/otlp/canonical.ts +7 -6
  68. package/src/o11y/otlp/mappers/codex.ts +10 -8
  69. package/src/o11y/otlp/mappers/index.ts +9 -21
  70. package/src/o11y/otlp/receiver.ts +25 -7
  71. package/src/o11y/otlp/sandbox-receiver.ts +57 -21
  72. package/src/o11y/otlp/turn-otel.test.ts +110 -0
  73. package/src/o11y/otlp/turn-otel.ts +125 -0
  74. package/src/o11y/parsers/bub.ts +13 -11
  75. package/src/o11y/parsers/claude-code.ts +27 -51
  76. package/src/o11y/parsers/codex.ts +29 -46
  77. package/src/o11y/parsers/index.ts +5 -14
  78. package/src/o11y/tool-names.test.ts +61 -0
  79. package/src/o11y/tool-names.ts +74 -0
  80. package/src/o11y/types.ts +135 -0
  81. package/src/runner/attempt.ts +456 -0
  82. package/src/runner/fingerprint.ts +59 -0
  83. package/src/runner/remote-sandbox.ts +53 -0
  84. package/src/runner/report.ts +53 -0
  85. package/src/runner/reporters/artifacts.ts +25 -4
  86. package/src/runner/reporters/console.ts +2 -8
  87. package/src/runner/reporters/live.ts +2 -8
  88. package/src/runner/reporters/shared.ts +15 -0
  89. package/src/runner/reporters/table.ts +10 -62
  90. package/src/runner/run.ts +114 -619
  91. package/src/runner/types.ts +237 -0
  92. package/src/sandbox/checkpoint.ts +15 -13
  93. package/src/sandbox/docker-stream.ts +87 -0
  94. package/src/sandbox/docker.ts +42 -120
  95. package/src/sandbox/e2b.ts +24 -75
  96. package/src/sandbox/local-files.ts +33 -0
  97. package/src/sandbox/paths.test.ts +85 -0
  98. package/src/sandbox/paths.ts +45 -0
  99. package/src/sandbox/resolve.ts +10 -34
  100. package/src/sandbox/shell.ts +17 -0
  101. package/src/sandbox/source-files.ts +42 -2
  102. package/src/sandbox/types.ts +158 -0
  103. package/src/sandbox/vercel.ts +55 -71
  104. package/src/scoring/collector.ts +3 -2
  105. package/src/scoring/judge.ts +72 -146
  106. package/src/scoring/match.ts +79 -0
  107. package/src/scoring/types.ts +76 -0
  108. package/src/shared/aggregate.ts +48 -0
  109. package/src/shared/format.ts +20 -0
  110. package/src/shared/outcome.ts +48 -0
  111. package/src/shared/types.ts +37 -0
  112. package/src/types.ts +20 -911
  113. package/src/view/aggregate.ts +103 -0
  114. package/src/view/app/App.tsx +26 -5
  115. package/src/view/app/components/AttemptModal.tsx +12 -3
  116. package/src/view/app/components/CodeView.tsx +9 -5
  117. package/src/view/app/components/CopyControls.tsx +4 -4
  118. package/src/view/app/components/ExperimentTable.tsx +5 -5
  119. package/src/view/app/i18n.ts +31 -7
  120. package/src/view/app/lib/format.ts +17 -20
  121. package/src/view/app/lib/outcome.ts +4 -16
  122. package/src/view/app/main.tsx +3 -5
  123. package/src/view/app/pages/RunsPage.tsx +2 -2
  124. package/src/view/app/pages/TracesPage.tsx +2 -2
  125. package/src/view/app/shared.ts +2 -1
  126. package/src/view/app/types.ts +6 -43
  127. package/src/view/client-dist/app.css +1 -1
  128. package/src/view/client-dist/app.js +18 -18
  129. package/src/view/index.ts +24 -401
  130. package/src/view/loader.ts +234 -0
  131. package/src/view/server.ts +136 -0
  132. package/src/view/shared/types.ts +64 -0
  133. package/src/view/styles.css +60 -9
@@ -0,0 +1,48 @@
1
+ // CLI 表格(runner/reporters/table.ts)与 view 榜单(view/aggregate.ts)共用的聚合小工具。
2
+ // 实验标签推导、token/成本求和、outcome 排序各只有一份 —— 否则同一个实验在终端和网页上
3
+ // 会显示成两个名字 / 两组数。保持环境无关(纯函数,只 type import)。
4
+
5
+ import type { Usage } from "../o11y/types.ts";
6
+ import type { EvalResult, ExperimentRunInfo } from "../runner/types.ts";
7
+ import type { ResultOutcome } from "../scoring/types.ts";
8
+
9
+ /** 明细行排序:失败最靠前(failed > errored > skipped > passed 的紧急程度)。 */
10
+ export const OUTCOME_ORDER: Record<ResultOutcome, number> = {
11
+ failed: 0,
12
+ errored: 1,
13
+ skipped: 2,
14
+ passed: 3,
15
+ };
16
+
17
+ export function totalTokens(items: Array<Usage | undefined>): number {
18
+ return items.reduce((n, u) => n + (u?.inputTokens ?? 0) + (u?.outputTokens ?? 0), 0);
19
+ }
20
+
21
+ /** 求和,但「全都没报」时返回 undefined(区别于真 0 成本)。 */
22
+ export function sumMaybe(items: Array<number | undefined>): number | undefined {
23
+ const known = items.filter((n): n is number => n !== undefined);
24
+ return known.length ? known.reduce((sum, n) => sum + n, 0) : undefined;
25
+ }
26
+
27
+ export function avg(items: number[]): number {
28
+ return items.length ? items.reduce((sum, n) => sum + n, 0) / items.length : 0;
29
+ }
30
+
31
+ /** 实验 id 的展示名:取路径最后一段(exp 分组用目录表达)。 */
32
+ export function displayExperimentName(id: string | undefined): string | undefined {
33
+ if (!id) return undefined;
34
+ return id.split("/").filter(Boolean).at(-1) ?? id;
35
+ }
36
+
37
+ /** 无 experimentId 时的兜底标签。 */
38
+ export function fallbackExperimentLabel(result: {
39
+ experiment?: ExperimentRunInfo;
40
+ agent: string;
41
+ model?: string;
42
+ }): string {
43
+ if (result.experiment?.id) return displayExperimentName(result.experiment.id) ?? result.experiment.id;
44
+ if (result.model) return `${result.agent}/${result.model}`;
45
+ return result.agent || "ad hoc run";
46
+ }
47
+
48
+ export type { EvalResult };
@@ -0,0 +1,20 @@
1
+ // server 与前端共用的数值格式化;两边展示口径(取整/单位切换阈值)必须一致,所以单独成模块。
2
+ // 保持环境无关:不 import node/browser API。日期格式化不在这里 —— 它按前端当前 locale 做,
3
+ // 留在 app/lib/format.ts(见 formatDateTime)。
4
+
5
+ export function formatPercent(value?: number): string {
6
+ if (typeof value !== "number" || !Number.isFinite(value)) return "0%";
7
+ return Math.round(value * 100) + "%";
8
+ }
9
+
10
+ export function formatDuration(ms?: number): string {
11
+ if (typeof ms !== "number" || !Number.isFinite(ms) || ms <= 0) return "0ms";
12
+ if (ms >= 60_000) return (ms / 60_000).toFixed(1) + "m";
13
+ if (ms >= 1000) return (ms / 1000).toFixed(2) + "s";
14
+ return Math.round(ms) + "ms";
15
+ }
16
+
17
+ export function formatCost(value?: number): string {
18
+ if (typeof value !== "number" || !Number.isFinite(value) || value <= 0) return "$0";
19
+ return "$" + value.toFixed(value < 1 ? 3 : 2);
20
+ }
@@ -0,0 +1,48 @@
1
+ // server(aggregate.ts)与前端(app/lib/outcome.ts)共用的判决折叠口径。
2
+ // 必须保持环境无关且只依赖 type import,vite 前端会直接打包它。
3
+ // 单独成模块的原因:折叠/计票口径两边必须逐字一致,否则折叠行状态会和 KPI / 成功率对不上。
4
+
5
+ import type { ResultOutcome } from "../types.ts";
6
+
7
+ /** 折叠/计票只需要 outcome 字段;server 传 EvalResult,前端传 ViewResult 都满足。 */
8
+ export interface OutcomeLike {
9
+ outcome: ResultOutcome;
10
+ }
11
+
12
+ /**
13
+ * 把同一个 eval 的多轮 attempt 折叠成单一判决:任一轮通过 → 该 eval 通过(对齐 earlyExit
14
+ * 「先过一次即停」语义),否则按 failed > errored > skipped 取最严重的一个。
15
+ */
16
+ export function foldEvalOutcome(attempts: OutcomeLike[]): ResultOutcome {
17
+ const outcomes = attempts.map((a) => a.outcome);
18
+ if (outcomes.some((o) => o === "passed")) return "passed";
19
+ if (outcomes.some((o) => o === "failed")) return "failed";
20
+ if (outcomes.some((o) => o === "errored")) return "errored";
21
+ return "skipped";
22
+ }
23
+
24
+ export interface EvalLevelStats {
25
+ /** 去重后的 eval 数(成功率分母的口径)。 */
26
+ evals: number;
27
+ passed: number;
28
+ failed: number;
29
+ errored: number;
30
+ skipped: number;
31
+ passRate: number;
32
+ }
33
+
34
+ /**
35
+ * 通过率与 passed/failed 一律按 eval 计票,不按 attempt:每个 eval 不管跑几轮都只占一票,先把它
36
+ * 的多轮折叠成单一判决再计数。否则 runs>1 时同一 eval 的 N 次 attempt 各算一票 —— 尤其 earlyExit
37
+ * 开时通过的 eval 只留 1 次、失败的 eval 跑满 N 次,失败 eval 被重复计入分母,把通过率拉低
38
+ * (见 docs/runner.md、docs/scoring.md)。keyOf 决定「一个 eval」的粒度:单实验按 eval id,
39
+ * 跨实验组按 experimentId|eval id。
40
+ */
41
+ export function evalLevelStats<T extends OutcomeLike>(results: T[], keyOf: (r: T) => string): EvalLevelStats {
42
+ const byEval = new Map<string, T[]>();
43
+ for (const r of results) byEval.set(keyOf(r), [...(byEval.get(keyOf(r)) ?? []), r]);
44
+ const counts = { passed: 0, failed: 0, errored: 0, skipped: 0 };
45
+ for (const group of byEval.values()) counts[foldEvalOutcome(group)] += 1;
46
+ const ran = counts.passed + counts.failed + counts.errored; // skipped 不进分母
47
+ return { evals: byEval.size, ...counts, passRate: ran ? counts.passed / ran : 0 };
48
+ }
@@ -0,0 +1,37 @@
1
+ // 真正跨域的原子类型:序列化 / 严重级 / 源码位置 / 生命周期。
2
+ // 各域的类型住在各自目录的 types.ts(o11y / sandbox / agents / scoring / context / runner),
3
+ // src/types.ts 是聚合 facade —— 模块代码统一从那里 import,不必记住每个类型的家。
4
+
5
+ export type JsonValue =
6
+ | string
7
+ | number
8
+ | boolean
9
+ | null
10
+ | JsonValue[]
11
+ | { [key: string]: JsonValue };
12
+
13
+ export type Severity = "gate" | "soft";
14
+
15
+ /**
16
+ * eval 源码里一次调用的位置(`t.send` / 各断言),运行期从栈回溯抠出来(见 src/source-loc.ts)。
17
+ * view 据此把运行结果叠回真实源码行(github-diff 式代码视图)。`file` 为相对项目根的路径。
18
+ */
19
+ export interface SourceLoc {
20
+ file: string;
21
+ line: number;
22
+ column?: number;
23
+ }
24
+
25
+ /** 随结果回传的一份 eval 源码(相对项目根的路径 + 文本),供 view 渲染代码视图。 */
26
+ export interface SourceArtifact {
27
+ path: string;
28
+ content: string;
29
+ }
30
+
31
+ export type Cleanup = () => Promise<void> | void;
32
+
33
+ /**
34
+ * 可本地化文案:纯字符串,或按 locale 代码(如 "en"、"zh-CN")映射多语言。
35
+ * view 按当前界面语言挑一条,挑不到回退到 en / 第一条。
36
+ */
37
+ export type LocalizedText = string | Record<string, string>;