niceeval 0.1.1 → 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 +8 -8
  2. package/README.zh.md +13 -13
  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 +35 -5
  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
@@ -3,13 +3,7 @@
3
3
  import type { EvalResult, Reporter, RunSummary } from "../../types.ts";
4
4
  import { t } from "../../i18n/index.ts";
5
5
  import { formatDuration, formatTokens, renderRunReport } from "./table.ts";
6
-
7
- const SYMBOL: Record<string, string> = {
8
- passed: "✓",
9
- failed: "✗",
10
- errored: "!",
11
- skipped: "○",
12
- };
6
+ import { outcomeSymbol } from "./shared.ts";
13
7
 
14
8
  export function Console(): Reporter {
15
9
  return {
@@ -24,7 +18,7 @@ export function Console(): Reporter {
24
18
  process.stdout.write(t("report.runStart", { count: n, extra }));
25
19
  },
26
20
  onEvalComplete(result: EvalResult) {
27
- const sym = SYMBOL[result.outcome] ?? "?";
21
+ const sym = outcomeSymbol(result.outcome);
28
22
  const tok = (result.usage?.inputTokens ?? 0) + (result.usage?.outputTokens ?? 0);
29
23
  // requests > 0 但 tokens = 0 → agent 跑了但不上报用量(如 bub);显示 — 而非误导性的 0
30
24
  const tokStr = tok > 0 ? `${formatTokens(tok)} tok` : (result.usage?.requests ?? 0) > 0 ? `— tok` : `0 tok`;
@@ -5,16 +5,10 @@
5
5
  import type { Reporter, RunShape, RunSummary } from "../../types.ts";
6
6
  import { t } from "../../i18n/index.ts";
7
7
  import { renderRunReport } from "./table.ts";
8
+ import { outcomeSymbol } from "./shared.ts";
8
9
 
9
10
  const SPINNER = ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"];
10
11
 
11
- const OUTCOME_SYM: Record<string, string> = {
12
- passed: "✓",
13
- failed: "✗",
14
- errored: "!",
15
- skipped: "○",
16
- };
17
-
18
12
  // 进度日志里的基础设施噪声:OTLP 端口、remote-agent 启动提示、trace span 计数。
19
13
  // 这些在行尾显示毫无意义,直接丢弃。
20
14
  const NOISE_PATTERNS = [
@@ -76,7 +70,7 @@ export function Live(rows: LiveRow[], totalAttempts: number): LiveReporter {
76
70
  function renderRow(state: RowState, frame: number): string {
77
71
  const done = state.completed >= state.total;
78
72
  const sym = done
79
- ? (OUTCOME_SYM[state.dominantOutcome ?? ""] ?? "?")
73
+ ? outcomeSymbol(state.dominantOutcome ?? "")
80
74
  : SPINNER[frame % SPINNER.length];
81
75
 
82
76
  const evalCol = state.evalId.slice(0, 24).padEnd(24);
@@ -0,0 +1,15 @@
1
+ // reporter 共用的展示常量。符号表只此一份 —— console/live/table 各抄一份时,
2
+ // 改一个符号要同步三处且不报错。
3
+
4
+ import type { ResultOutcome } from "../../types.ts";
5
+
6
+ export const OUTCOME_SYM: Record<ResultOutcome, string> = {
7
+ passed: "✓",
8
+ failed: "✗",
9
+ errored: "!",
10
+ skipped: "○",
11
+ };
12
+
13
+ export function outcomeSymbol(outcome: string): string {
14
+ return OUTCOME_SYM[outcome as ResultOutcome] ?? "?";
15
+ }
@@ -1,19 +1,13 @@
1
1
  import type { EvalResult, RunSummary, Usage } from "../../types.ts";
2
2
  import { t } from "../../i18n/index.ts";
3
+ import { outcomeSymbol } from "./shared.ts";
4
+ import { foldEvalOutcome, evalLevelStats as sharedEvalLevelStats } from "../../shared/outcome.ts";
5
+ // 展示口径(耗时/成本/百分比)与聚合小工具(标签/求和/排序)与 view 共用一份实现;
6
+ // console.ts 经这里 re-export formatDuration。
7
+ import { formatCost, formatDuration, formatPercent } from "../../shared/format.ts";
8
+ import { OUTCOME_ORDER, avg, displayExperimentName, fallbackExperimentLabel, sumMaybe, totalTokens } from "../../shared/aggregate.ts";
3
9
 
4
- const OUTCOME_ORDER: Record<string, number> = {
5
- failed: 0,
6
- errored: 1,
7
- skipped: 2,
8
- passed: 3,
9
- };
10
-
11
- const OUTCOME_SYM: Record<string, string> = {
12
- passed: "✓",
13
- failed: "✗",
14
- errored: "!",
15
- skipped: "○",
16
- };
10
+ export { formatCost, formatDuration } from "../../shared/format.ts";
17
11
 
18
12
  interface ExperimentRow {
19
13
  key: string;
@@ -119,20 +113,8 @@ export function formatTokens(n: number): string {
119
113
  return String(n);
120
114
  }
121
115
 
122
- export function formatDuration(ms: number): string {
123
- if (!Number.isFinite(ms) || ms <= 0) return "0ms";
124
- if (ms >= 60_000) return `${(ms / 60_000).toFixed(1)}m`;
125
- if (ms >= 1000) return `${(ms / 1000).toFixed(2)}s`;
126
- return `${Math.round(ms)}ms`;
127
- }
128
-
129
- export function formatCost(n: number | undefined): string {
130
- if (n === undefined || n <= 0) return "$0";
131
- return `$${n.toFixed(n < 1 ? 3 : 2)}`;
132
- }
133
-
134
116
  export function formatOutcome(outcome: string): string {
135
- const sym = OUTCOME_SYM[outcome] ?? "?";
117
+ const sym = outcomeSymbol(outcome);
136
118
  switch (outcome) {
137
119
  case "passed": return `${sym} ${t("report.passed")}`;
138
120
  case "failed": return `${sym} ${t("report.failed")}`;
@@ -198,21 +180,9 @@ function aggregateEvalRows(results: EvalResult[]): EvalRow[] {
198
180
  .sort((a, b) => OUTCOME_ORDER[a.outcome] - OUTCOME_ORDER[b.outcome] || a.id.localeCompare(b.id));
199
181
  }
200
182
 
183
+ // 折叠 / 计票口径与 view 同一份实现(src/shared/outcome.ts),CLI 表格和网页榜单永不打架。
201
184
  function evalLevelStats(results: EvalResult[]) {
202
- const byEval = new Map<string, EvalResult[]>();
203
- for (const r of results) byEval.set(r.id, [...(byEval.get(r.id) ?? []), r]);
204
- const counts = { passed: 0, failed: 0, errored: 0, skipped: 0 };
205
- for (const group of byEval.values()) counts[foldEvalOutcome(group)] += 1;
206
- const ran = counts.passed + counts.failed + counts.errored;
207
- return { evals: byEval.size, ...counts, passRate: ran ? counts.passed / ran : 0 };
208
- }
209
-
210
- function foldEvalOutcome(results: EvalResult[]): EvalResult["outcome"] {
211
- const outcomes = results.map((r) => r.outcome);
212
- if (outcomes.some((o) => o === "passed")) return "passed";
213
- if (outcomes.some((o) => o === "failed")) return "failed";
214
- if (outcomes.some((o) => o === "errored")) return "errored";
215
- return "skipped";
185
+ return sharedEvalLevelStats(results, (r) => r.id);
216
186
  }
217
187
 
218
188
  function reasonFor(result: EvalResult): string {
@@ -238,33 +208,11 @@ function formatResult(row: ExperimentRow): string {
238
208
  return `${row.passed}/${row.evals} ${t("report.passed")} · ${failures} ${t("report.failed")}${suffix}`;
239
209
  }
240
210
 
241
- function displayExperimentName(id: string | undefined): string | undefined {
242
- if (!id) return undefined;
243
- return id.split("/").filter(Boolean).at(-1) ?? id;
244
- }
245
211
 
246
- function fallbackExperimentLabel(result: EvalResult): string {
247
- if (result.experiment?.id) return displayExperimentName(result.experiment.id) ?? result.experiment.id;
248
- if (result.model) return `${result.agent}/${result.model}`;
249
- return result.agent || "ad hoc run";
250
- }
251
212
 
252
- function totalTokens(items: Array<Usage | undefined>): number {
253
- return items.reduce((n, u) => n + (u?.inputTokens ?? 0) + (u?.outputTokens ?? 0), 0);
254
- }
255
213
 
256
- function sumMaybe(items: Array<number | undefined>): number | undefined {
257
- const known = items.filter((n): n is number => n !== undefined);
258
- return known.length ? known.reduce((sum, n) => sum + n, 0) : undefined;
259
- }
260
214
 
261
- function avg(items: number[]): number {
262
- return items.length ? items.reduce((sum, n) => sum + n, 0) / items.length : 0;
263
- }
264
215
 
265
- function formatPercent(v: number): string {
266
- return `${Math.round(v * 100)}%`;
267
- }
268
216
 
269
217
  function renderTable(headers: string[], rows: string[][], opts: { maxWidth?: number; flexibleColumn?: number } = {}): string {
270
218
  const rawRows = [headers, ...rows];