niceeval 0.6.1 → 0.7.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 +23 -23
- package/README.zh.md +6 -6
- package/dist/agents/types.d.ts +69 -7
- package/dist/context/types.d.ts +32 -12
- package/dist/i18n/en.d.ts +54 -0
- package/dist/i18n/zh-CN.d.ts +57 -3
- package/dist/o11y/types.d.ts +16 -2
- package/dist/report/aggregate.d.ts +32 -24
- package/dist/report/aggregate.js +158 -50
- package/dist/report/built-in/index.d.ts +2 -0
- package/dist/report/built-in/index.js +8 -0
- package/dist/report/components.d.ts +93 -160
- package/dist/report/components.js +377 -114
- package/dist/report/compute.d.ts +87 -81
- package/dist/report/compute.js +597 -417
- package/dist/report/flag.d.ts +32 -6
- package/dist/report/flag.js +92 -4
- package/dist/report/format.d.ts +19 -11
- package/dist/report/format.js +30 -13
- package/dist/report/index.d.ts +16 -16
- package/dist/report/index.js +20 -21
- package/dist/report/load.js +3 -2
- package/dist/report/locale.d.ts +57 -33
- package/dist/report/locale.js +122 -56
- package/dist/report/metrics.d.ts +23 -4
- package/dist/report/metrics.js +110 -25
- package/dist/report/primitives.d.ts +48 -15
- package/dist/report/primitives.js +135 -26
- package/dist/report/react/AttemptList.d.ts +9 -7
- package/dist/report/react/AttemptList.js +17 -10
- package/dist/report/react/DeltaTable.js +19 -18
- package/dist/report/react/EvalList.d.ts +4 -4
- package/dist/report/react/EvalList.js +0 -0
- package/dist/report/react/ExperimentComparison.d.ts +10 -0
- package/dist/report/react/ExperimentComparison.js +12 -0
- package/dist/report/react/ExperimentList.d.ts +4 -3
- package/dist/report/react/ExperimentList.js +17 -18
- package/dist/report/react/MetricBars.js +5 -4
- package/dist/report/react/MetricLine.js +12 -5
- package/dist/report/react/MetricMatrix.js +1 -1
- package/dist/report/react/MetricScatter.js +59 -28
- package/dist/report/react/MetricTable.js +2 -12
- package/dist/report/react/ScopeSummary.d.ts +10 -0
- package/dist/report/react/ScopeSummary.js +17 -0
- package/dist/report/react/Scoreboard.js +6 -6
- package/dist/report/react/cell.js +2 -2
- package/dist/report/react/chart-math.d.ts +23 -6
- package/dist/report/react/chart-math.js +71 -19
- package/dist/report/react/fixtures.d.ts +5 -9
- package/dist/report/react/fixtures.js +110 -147
- package/dist/report/react/index.d.ts +15 -5
- package/dist/report/react/index.js +18 -7
- package/dist/report/report.d.ts +137 -16
- package/dist/report/report.js +259 -28
- package/dist/report/text/faces.d.ts +17 -19
- package/dist/report/text/faces.js +253 -184
- package/dist/report/text/plot.js +1 -1
- package/dist/report/text/table.js +38 -7
- package/dist/report/tree.d.ts +90 -40
- package/dist/report/tree.js +252 -94
- package/dist/report/types.d.ts +247 -284
- package/dist/report/types.js +4 -3
- package/dist/report/web.d.ts +21 -5
- package/dist/report/web.js +42 -16
- package/dist/results/select.d.ts +38 -16
- package/dist/results/select.js +73 -25
- package/dist/results/types.d.ts +49 -14
- package/dist/runner/feedback/sink.d.ts +110 -0
- package/dist/runner/types.d.ts +513 -22
- package/dist/sandbox/docker.d.ts +23 -2
- package/dist/sandbox/e2b.d.ts +15 -1
- package/dist/sandbox/errors.d.ts +30 -3
- package/dist/sandbox/io-retry.d.ts +17 -0
- package/dist/sandbox/registry.d.ts +2 -0
- package/dist/sandbox/resolve.d.ts +18 -5
- package/dist/sandbox/retry.d.ts +11 -1
- package/dist/sandbox/types.d.ts +39 -5
- package/dist/sandbox/vercel.d.ts +7 -1
- package/dist/scoring/coverage.d.ts +30 -0
- package/dist/scoring/display.d.ts +21 -0
- package/dist/scoring/display.js +120 -0
- package/dist/scoring/types.d.ts +103 -20
- package/dist/shared/aggregate.d.ts +4 -2
- package/dist/shared/aggregate.js +8 -7
- package/dist/shared/types.d.ts +28 -0
- package/dist/tty-line.d.ts +0 -4
- package/dist/util.d.ts +23 -0
- package/docs-site/zh/README.md +44 -0
- package/docs-site/zh/examples/ai-agent-application.mdx +63 -0
- package/docs-site/zh/examples/coding-agent-extensions.mdx +57 -0
- package/docs-site/zh/examples/index.mdx +50 -0
- package/docs-site/zh/{concepts → explanation}/adapter.mdx +31 -13
- package/docs-site/zh/{concepts → explanation}/assert.mdx +7 -7
- package/docs-site/zh/{concepts → explanation}/drive.mdx +8 -8
- package/docs-site/zh/{concepts → explanation}/evals.mdx +4 -4
- package/docs-site/zh/{concepts → explanation}/experiment.mdx +8 -8
- package/docs-site/zh/{concepts → explanation}/hitl.mdx +8 -8
- package/docs-site/zh/{concepts → explanation}/judge.mdx +5 -5
- package/docs-site/zh/{concepts → explanation}/overview.mdx +11 -11
- package/docs-site/zh/{guides → explanation}/runner.mdx +18 -8
- package/docs-site/zh/{concepts → explanation}/tier.mdx +6 -6
- package/docs-site/zh/{guides → how-to}/agent-feedback-loop.mdx +35 -33
- package/docs-site/zh/{guides → how-to}/authoring.mdx +35 -2
- package/docs-site/zh/{guides → how-to}/ci-integration.mdx +23 -12
- package/docs-site/zh/{guides → how-to}/connect-otel.mdx +6 -6
- package/docs-site/zh/{guides → how-to}/connect-your-agent.mdx +47 -21
- package/docs-site/zh/{guides → how-to}/custom-reports.mdx +34 -39
- package/docs-site/zh/{guides → how-to}/dataset-fanout.mdx +25 -3
- package/docs-site/zh/{guides → how-to}/experiments.mdx +12 -5
- package/docs-site/zh/how-to/publish-report.mdx +105 -0
- package/docs-site/zh/{guides → how-to}/reporters.mdx +2 -2
- package/docs-site/zh/{guides → how-to}/sandbox-agent.mdx +56 -7
- package/docs-site/zh/how-to/sandbox-providers.mdx +350 -0
- package/docs-site/zh/{guides → how-to}/scoring-guide.mdx +4 -4
- package/docs-site/zh/{guides → how-to}/viewing-results.mdx +82 -39
- package/docs-site/zh/{guides → how-to}/write-experiment.mdx +6 -4
- package/docs-site/zh/{guides → how-to}/write-send.mdx +30 -14
- package/docs-site/zh/index.mdx +24 -26
- package/docs-site/zh/introduction.mdx +8 -8
- package/docs-site/zh/reference/builtin-agents.mdx +32 -5
- package/docs-site/zh/reference/capabilities.mdx +8 -8
- package/docs-site/zh/reference/cli.mdx +40 -12
- package/docs-site/zh/reference/define-agent.mdx +58 -5
- package/docs-site/zh/reference/define-config.mdx +1 -1
- package/docs-site/zh/reference/define-eval.mdx +42 -9
- package/docs-site/zh/reference/events.mdx +3 -3
- package/docs-site/zh/reference/expect.mdx +26 -1
- package/docs-site/zh/{guides → reference}/official-adapters.mdx +32 -8
- package/docs-site/zh/{guides → reference}/report-components.mdx +45 -33
- package/docs-site/zh/{guides → reference}/results-data.mdx +21 -13
- package/docs-site/zh/troubleshooting/debug-sandbox.mdx +57 -0
- package/docs-site/zh/troubleshooting/debugging.mdx +212 -0
- package/docs-site/zh/{quickstart.mdx → tutorials/quickstart.mdx} +5 -17
- package/package.json +10 -2
- package/src/agents/ai-sdk-otel.test.ts +1 -0
- package/src/agents/ai-sdk.test.ts +3 -0
- package/src/agents/ai-sdk.ts +3 -0
- package/src/agents/bub-install-spec.test.ts +34 -0
- package/src/agents/bub-install-spec.ts +32 -0
- package/src/agents/bub.ts +31 -32
- package/src/agents/claude-code.test.ts +130 -9
- package/src/agents/claude-code.ts +76 -4
- package/src/agents/codex.test.ts +189 -40
- package/src/agents/codex.ts +155 -14
- package/src/agents/coding-cli-versions.test.ts +15 -0
- package/src/agents/coding-cli-versions.ts +3 -0
- package/src/agents/index.ts +13 -2
- package/src/agents/langgraph.test.ts +204 -0
- package/src/agents/langgraph.ts +495 -0
- package/src/agents/marketplace.ts +85 -0
- package/src/agents/native-config.test.ts +179 -0
- package/src/agents/native-config.ts +267 -0
- package/src/agents/openai-compat.test.ts +1 -0
- package/src/agents/openai-compat.ts +1 -1
- package/src/agents/openclaw.test.ts +31 -0
- package/src/agents/openclaw.ts +171 -0
- package/src/agents/plugin-config.test.ts +1 -0
- package/src/agents/sdk-streams.test.ts +79 -0
- package/src/agents/sdk-streams.ts +55 -10
- package/src/agents/skills.test.ts +1 -0
- package/src/agents/streaming.test.ts +3 -9
- package/src/agents/streaming.ts +2 -2
- package/src/agents/types.ts +71 -8
- package/src/agents/ui-message-stream.test.ts +3 -0
- package/src/cli.ts +446 -124
- package/src/context/context.test.ts +51 -12
- package/src/context/context.ts +162 -30
- package/src/context/session.test.ts +2 -1
- package/src/context/session.ts +115 -7
- package/src/context/types.ts +30 -12
- package/src/define.test.ts +13 -8
- package/src/define.ts +25 -4
- package/src/expect/index.ts +53 -23
- package/src/i18n/en.ts +81 -17
- package/src/i18n/zh-CN.ts +80 -17
- package/src/o11y/cost.test.ts +1 -0
- package/src/o11y/execution-tree.test.ts +1 -20
- package/src/o11y/otlp/mappers/claude-code.test.ts +1 -0
- package/src/o11y/otlp/parse.test.ts +1 -0
- package/src/o11y/otlp/turn-otel.test.ts +1 -0
- package/src/o11y/parsers/bub.test.ts +1 -0
- package/src/o11y/parsers/claude-code.test.ts +1 -34
- package/src/o11y/parsers/openclaw.test.ts +154 -0
- package/src/o11y/parsers/openclaw.ts +310 -0
- package/src/o11y/prices.json +746 -311
- package/src/o11y/tool-names.test.ts +1 -0
- package/src/o11y/types.ts +16 -2
- package/src/report/aggregate.ts +178 -61
- package/src/report/built-in/index.tsx +9 -0
- package/src/report/components.tsx +625 -279
- package/src/report/compute.ts +723 -491
- package/src/report/dual-render.test.tsx +741 -1024
- package/src/report/flag.ts +104 -12
- package/src/report/format.ts +32 -12
- package/src/report/index.ts +119 -46
- package/src/report/load.ts +3 -2
- package/src/report/locale.ts +136 -65
- package/src/report/metrics.ts +108 -25
- package/src/report/primitives.tsx +196 -45
- package/src/report/react/AttemptList.tsx +30 -43
- package/src/report/react/DeltaTable.tsx +63 -45
- package/src/report/react/EvalList.tsx +0 -0
- package/src/report/react/ExperimentComparison.tsx +73 -0
- package/src/report/react/ExperimentList.tsx +50 -32
- package/src/report/react/MetricBars.tsx +5 -4
- package/src/report/react/MetricLine.tsx +13 -8
- package/src/report/react/MetricMatrix.tsx +2 -2
- package/src/report/react/MetricScatter.tsx +86 -34
- package/src/report/react/MetricTable.tsx +4 -76
- package/src/report/react/ScopeSummary.tsx +86 -0
- package/src/report/react/Scoreboard.tsx +28 -10
- package/src/report/react/cell.tsx +2 -2
- package/src/report/react/chart-math.test.ts +85 -0
- package/src/report/react/chart-math.ts +101 -22
- package/src/report/react/enhance.js +89 -5
- package/src/report/react/fixtures.ts +114 -154
- package/src/report/react/index.tsx +24 -39
- package/src/report/react/render.test.tsx +138 -158
- package/src/report/react/styles.css +243 -82
- package/src/report/report.test.ts +779 -841
- package/src/report/report.ts +423 -41
- package/src/report/text/faces.ts +290 -193
- package/src/report/text/plot.ts +1 -1
- package/src/report/text/table.ts +44 -7
- package/src/report/tree.ts +362 -104
- package/src/report/types.ts +261 -271
- package/src/report/web.ts +63 -20
- package/src/results/annotated-source.test.ts +62 -9
- package/src/results/annotated-source.ts +64 -6
- package/src/results/attempt-evidence.test.ts +13 -11
- package/src/results/attempt-evidence.ts +20 -13
- package/src/results/attempt-source.ts +6 -3
- package/src/results/copy.ts +150 -60
- package/src/results/host-equivalence.test.ts +34 -20
- package/src/results/index.ts +12 -4
- package/src/results/locator.test.ts +1 -22
- package/src/results/open.ts +15 -5
- package/src/results/publish.ts +149 -0
- package/src/results/results.test.ts +89 -54
- package/src/results/select.ts +104 -34
- package/src/results/truncate.ts +90 -0
- package/src/results/types.ts +43 -14
- package/src/results/writer.ts +31 -13
- package/src/runner/attempt.test.ts +138 -7
- package/src/runner/attempt.ts +603 -104
- package/src/runner/discover.test.ts +47 -0
- package/src/runner/discover.ts +36 -2
- package/src/runner/eval-source.test.ts +1 -27
- package/src/runner/feedback/agent.test.ts +504 -0
- package/src/runner/feedback/agent.ts +409 -0
- package/src/runner/feedback/ci.test.ts +562 -0
- package/src/runner/feedback/ci.ts +401 -0
- package/src/runner/feedback/coordinator.test.ts +317 -0
- package/src/runner/feedback/coordinator.ts +397 -0
- package/src/runner/feedback/failure.ts +40 -0
- package/src/runner/feedback/human.test.ts +616 -0
- package/src/runner/feedback/human.ts +535 -0
- package/src/runner/feedback/index.ts +66 -0
- package/src/runner/feedback/io.ts +78 -0
- package/src/runner/feedback/profile.test.ts +50 -0
- package/src/runner/feedback/profile.ts +58 -0
- package/src/runner/feedback/reducer.test.ts +395 -0
- package/src/runner/feedback/reducer.ts +260 -0
- package/src/runner/feedback/renderer.ts +82 -0
- package/src/runner/feedback/sink.ts +203 -0
- package/src/runner/feedback/testing.ts +106 -0
- package/src/runner/ledger.test.ts +230 -0
- package/src/runner/ledger.ts +329 -0
- package/src/runner/report.test.ts +128 -3
- package/src/runner/report.ts +33 -9
- package/src/runner/reporters/artifacts.ts +8 -2
- package/src/runner/reporters/braintrust.test.ts +8 -7
- package/src/runner/reporters/braintrust.ts +9 -2
- package/src/runner/reporters/index.ts +2 -2
- package/src/runner/reporters/json.test.ts +162 -0
- package/src/runner/reporters/json.ts +35 -8
- package/src/runner/reporters/shared.ts +1 -5
- package/src/runner/run.test.ts +760 -3
- package/src/runner/run.ts +243 -37
- package/src/runner/sandbox-prep.ts +3 -42
- package/src/runner/timing.ts +158 -0
- package/src/runner/types.ts +518 -22
- package/src/sandbox/checkpoint.test.ts +55 -0
- package/src/sandbox/checkpoint.ts +29 -8
- package/src/sandbox/cli-commands.ts +407 -0
- package/src/sandbox/docker.ts +115 -16
- package/src/sandbox/e2b-agent-template.test.ts +56 -0
- package/src/sandbox/e2b-agent-template.ts +94 -0
- package/src/sandbox/e2b.ts +74 -9
- package/src/sandbox/errors.ts +111 -4
- package/src/sandbox/index.ts +2 -0
- package/src/sandbox/io-retry.test.ts +58 -0
- package/src/sandbox/io-retry.ts +45 -0
- package/src/sandbox/keep-registry.test.ts +86 -0
- package/src/sandbox/keep-registry.ts +142 -0
- package/src/sandbox/keep.ts +178 -0
- package/src/sandbox/paths.test.ts +1 -0
- package/src/sandbox/paths.ts +19 -8
- package/src/sandbox/registry.ts +20 -3
- package/src/sandbox/resolve.ts +76 -11
- package/src/sandbox/retry.test.ts +70 -0
- package/src/sandbox/retry.ts +46 -4
- package/src/sandbox/types.ts +44 -6
- package/src/sandbox/vercel.ts +43 -20
- package/src/scoring/collector.ts +60 -17
- package/src/scoring/coverage.ts +95 -0
- package/src/scoring/diff.ts +81 -0
- package/src/scoring/display.test.ts +121 -0
- package/src/scoring/display.ts +133 -0
- package/src/scoring/evidence.test.ts +189 -0
- package/src/scoring/judge.test.ts +142 -0
- package/src/scoring/judge.ts +15 -18
- package/src/scoring/scoped.ts +217 -50
- package/src/scoring/types.ts +117 -20
- package/src/scoring/verdict.ts +16 -4
- package/src/shared/aggregate.ts +8 -6
- package/src/shared/types.ts +31 -0
- package/src/show/compose.ts +50 -67
- package/src/show/index.ts +127 -56
- package/src/show/render.ts +662 -131
- package/src/show/report-host.test.ts +188 -0
- package/src/show/report-host.ts +375 -0
- package/src/show/show.test.ts +320 -54
- package/src/tty-line.ts +8 -26
- package/src/util.test.ts +1 -0
- package/src/util.ts +41 -0
- package/src/view/app/App.test.tsx +69 -0
- package/src/view/app/App.tsx +144 -48
- package/src/view/app/components/AttemptModal.tsx +423 -11
- package/src/view/app/components/CodeView.tsx +41 -14
- package/src/view/app/components/CopyControls.tsx +2 -2
- package/src/view/app/i18n.ts +37 -17
- package/src/view/app/lib/attempt-route.test.ts +1 -0
- package/src/view/app/lib/verdict.ts +7 -9
- package/src/view/app/main.tsx +13 -8
- package/src/view/app/pages/{RunsPage.tsx → AttemptsPage.tsx} +6 -6
- package/src/view/app/types.ts +4 -1
- package/src/view/artifact-serving.test.ts +2 -1
- package/src/view/client-dist/app.css +1 -1
- package/src/view/client-dist/app.js +17 -17
- package/src/view/data.test.ts +10 -3
- package/src/view/data.ts +155 -49
- package/src/view/index.ts +56 -41
- package/src/view/server.ts +37 -15
- package/src/view/shared/types.ts +34 -5
- package/src/view/styles.css +227 -0
- package/src/view/view-report.test.ts +167 -62
- package/dist/report/built-ins/experiment-comparison.d.ts +0 -1
- package/dist/report/built-ins/experiment-comparison.js +0 -13
- package/dist/report/built-ins/index.d.ts +0 -1
- package/dist/report/built-ins/index.js +0 -2
- package/dist/report/react/GroupSummary.d.ts +0 -8
- package/dist/report/react/GroupSummary.js +0 -8
- package/dist/report/react/RunOverview.d.ts +0 -8
- package/dist/report/react/RunOverview.js +0 -12
- package/docs-site/zh/example/ai-agent-application.mdx +0 -152
- package/docs-site/zh/example/claude-code-codex-plugin.mdx +0 -167
- package/docs-site/zh/example/claude-code-codex-skill.mdx +0 -152
- package/docs-site/zh/example/showcase.mdx +0 -39
- package/docs-site/zh/guides/publish-report.mdx +0 -91
- package/docs-site/zh/guides/sandbox-providers.mdx +0 -102
- package/src/report/built-in-user-parity.test.tsx +0 -640
- package/src/report/built-ins/experiment-comparison.tsx +0 -19
- package/src/report/built-ins/index.ts +0 -2
- package/src/report/react/GroupSummary.tsx +0 -66
- package/src/report/react/RunOverview.tsx +0 -109
- package/src/runner/reporters/console.ts +0 -70
- package/src/runner/reporters/live.test.ts +0 -56
- package/src/runner/reporters/live.ts +0 -247
- package/src/runner/reporters/quiet.test.ts +0 -66
- package/src/runner/reporters/quiet.ts +0 -49
- package/src/runner/reporters/table.ts +0 -277
- /package/docs-site/zh/{example/tier1-ai-sdk-v7.mdx → examples/integrations/ai-sdk-v7.mdx} +0 -0
- /package/docs-site/zh/{example/tier1-claude-sdk.mdx → examples/integrations/claude-sdk.mdx} +0 -0
- /package/docs-site/zh/{example/tier1-codex-sdk.mdx → examples/integrations/codex-sdk.mdx} +0 -0
- /package/docs-site/zh/{example/tier1-langgraph.mdx → examples/integrations/langgraph.mdx} +0 -0
- /package/docs-site/zh/{example/tier1-pi-sdk.mdx → examples/integrations/pi-sdk.mdx} +0 -0
- /package/docs-site/zh/{guides → how-to}/fixtures.mdx +0 -0
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: "通过 CI 发布报告"
|
|
3
|
+
sidebarTitle: "CI 发布报告"
|
|
4
|
+
description: "把经过 copySnapshots 大小预检的结果目录提交进仓库,CI 用一行 view --run 导出报告站;超大文件在 commit 前就会得到可执行错误。"
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
`niceeval view --out <目录>` 把查看器导出成一个纯静态目录:报告、结果快照列表、transcript、trace 瀑布,和本地 `niceeval view` 看到的完全一样(导出行为见[查看结果 · 导出与静态托管](/zh/how-to/viewing-results#导出与静态托管))。CI 发布只需要让结果数据到构建机手里,但不要直接提交本地事实根 `.niceeval/`:逐字符串截断能防一条失控输出膨胀,不能保证整个文件小于 Git host 的限制。先用 `copySnapshots` 生成经过 50 MiB 单文件预检的发布结果根,再提交这个目录。
|
|
8
|
+
|
|
9
|
+
## 生成可提交的结果目录
|
|
10
|
+
|
|
11
|
+
新建 `scripts/publish-results.ts`(项目里 eval 和配置本来就是 TypeScript,脚本也用 `.ts`,由 `tsx` 直接运行):
|
|
12
|
+
|
|
13
|
+
```javascript
|
|
14
|
+
import { rm } from "node:fs/promises";
|
|
15
|
+
import { copySnapshots, openResults } from "niceeval/results";
|
|
16
|
+
|
|
17
|
+
const output = "report-data";
|
|
18
|
+
const results = await openResults(".niceeval");
|
|
19
|
+
|
|
20
|
+
await rm(output, { recursive: true, force: true });
|
|
21
|
+
await copySnapshots(results.latest(), output, {
|
|
22
|
+
artifacts: ["sources", "events", "trace", "o11y", "agentSetup"],
|
|
23
|
+
redact: (text) => text.replaceAll(/sk-[A-Za-z0-9]+/g, "[redacted]"),
|
|
24
|
+
});
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
`redact` 是必填项:给一个函数改写待发布文件里的自由文本,或者确认这批数据可以原文公开、显式传 `redact: false`。要发布的站点谁都能翻到 prompt 和工具输出,这个选择必须写在脚本里。
|
|
28
|
+
|
|
29
|
+
运行 `npx tsx scripts/publish-results.ts`,然后提交 `report-data/`。`copySnapshots` 在创建目录前检查所有待发布文件;任何文件超过 50 MiB 时整体失败并列出路径、大小和处理建议,不会留下半份目录。`diff` 缺省不发布;需要 diff 时显式加进 `artifacts`,它也受同一个预算约束。历史版本留下的超大 events / trace 不会被悄悄改写,预检会要求你排除这类证据或用当前版本重跑。
|
|
30
|
+
|
|
31
|
+
## 构建命令就是导出命令
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
npx niceeval view --run report-data --out site
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
`view` 对零可读结果直接报错、非零退出,不会导出一张空报告——`report-data/` checkout 坏掉,或所有落盘与当前 niceeval 的 schemaVersion 不兼容被整批跳过时,构建失败,Vercel / GitHub Pages 保留上一次部署。错误逐条列出被跳过的快照目录与原因,schemaVersion 场景还给出能直接查看旧落盘的 `npx niceeval@<版本> view` 命令。
|
|
38
|
+
|
|
39
|
+
## 发布自定义报告
|
|
40
|
+
|
|
41
|
+
不传 `--report` 时,发布出来的首页是默认报告。想让首页换成自己的报告,把 [`defineReport` 报告文件](/zh/how-to/custom-reports)传给 `--report` 就行——attempt 证据页(transcript、trace、代码视图)仍在同一个站里,报告里的每个数字点进去就是对应证据,和本地 `view --report` 看到的一模一样:
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
npx niceeval view --run report-data --report reports/exam.tsx --out site
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
报告文件和 `report-data/` 一样提交在仓库里,改完版面 push,线上就跟着更新。用下面的 `vercel.json` / workflow 时,把构建命令换成这一行即可,其余配置不用动。
|
|
48
|
+
|
|
49
|
+
## 接托管平台
|
|
50
|
+
|
|
51
|
+
**Vercel**:仓库根放一个 `vercel.json`,导入项目后 push 即部署。
|
|
52
|
+
|
|
53
|
+
```json
|
|
54
|
+
{
|
|
55
|
+
"installCommand": "pnpm install --frozen-lockfile",
|
|
56
|
+
"buildCommand": "npx niceeval view --run report-data --out site",
|
|
57
|
+
"outputDirectory": "site"
|
|
58
|
+
}
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
**GitHub Pages**:仓库 Settings → Pages 把 Source 设为 GitHub Actions,再加 workflow:
|
|
62
|
+
|
|
63
|
+
```yaml
|
|
64
|
+
# .github/workflows/report.yml
|
|
65
|
+
name: report
|
|
66
|
+
on:
|
|
67
|
+
push:
|
|
68
|
+
branches: [main]
|
|
69
|
+
|
|
70
|
+
permissions:
|
|
71
|
+
contents: read
|
|
72
|
+
pages: write
|
|
73
|
+
id-token: write
|
|
74
|
+
|
|
75
|
+
jobs:
|
|
76
|
+
build:
|
|
77
|
+
runs-on: ubuntu-latest
|
|
78
|
+
steps:
|
|
79
|
+
- uses: actions/checkout@v4
|
|
80
|
+
- uses: pnpm/action-setup@v4
|
|
81
|
+
- uses: actions/setup-node@v4
|
|
82
|
+
with:
|
|
83
|
+
node-version: 22
|
|
84
|
+
cache: pnpm
|
|
85
|
+
- run: pnpm install --frozen-lockfile
|
|
86
|
+
- run: npx niceeval view --run report-data --out site
|
|
87
|
+
- uses: actions/upload-pages-artifact@v3
|
|
88
|
+
with:
|
|
89
|
+
path: site
|
|
90
|
+
deploy:
|
|
91
|
+
needs: build
|
|
92
|
+
runs-on: ubuntu-latest
|
|
93
|
+
environment:
|
|
94
|
+
name: github-pages
|
|
95
|
+
url: ${{ steps.deployment.outputs.page_url }}
|
|
96
|
+
steps:
|
|
97
|
+
- id: deployment
|
|
98
|
+
uses: actions/deploy-pages@v4
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
日常循环是:本地跑 eval,运行 `npx tsx scripts/publish-results.ts`,提交更新后的 `report-data/` 并 push。发布目录只保留每个实验的最新结果快照;要发布其它选择策略,在脚本里替换 `results.latest()`。本地 `.niceeval/` 可以保留完整历史和 diff,不需要为了 Git 限制削掉调试证据。
|
|
102
|
+
|
|
103
|
+
## 发布的是选中的证据
|
|
104
|
+
|
|
105
|
+
整站导出会带上发布结果根里选中的 transcript、源码快照和 trace。新写入的超大 events / trace 字符串可能带结构化截断标记。`copySnapshots` 只在你给了消毒函数时改写自由文本(`redact` 是必填项,见上),其余只做选择和整文件大小预检;传 `redact: false` 的目录再导出时还要加 `--allow-sensitive-artifacts` 确认一次。发布到公网前确认结果里没有密钥或敏感数据。
|
|
@@ -4,7 +4,7 @@ sidebarTitle: "Reporter 上报"
|
|
|
4
4
|
description: "用内置 reporters 把 eval 结果送到 Braintrust 实验、JUnit XML 或自定义目的地。"
|
|
5
5
|
---
|
|
6
6
|
|
|
7
|
-
[NiceEval](https://niceeval.com/) 自己跑、自己判分;
|
|
7
|
+
[NiceEval](https://niceeval.com/) 自己跑、自己判分;Reporter 负责把完成结果送到其它目的地。运行中的 Human/Agent/CI 反馈由 `niceeval exp --output ...` 选择,不是用户配置的 Reporter;`.niceeval/` results artifacts 始终开启。其余 Reporter 从 `niceeval/reporters` 导入,按需挂载。
|
|
8
8
|
|
|
9
9
|
挂载位置有两个:
|
|
10
10
|
|
|
@@ -110,4 +110,4 @@ const notify: Reporter = {
|
|
|
110
110
|
- `onRunComplete(summary)`:运行结束,收到聚合汇总。
|
|
111
111
|
- `onEvent(event)`:更细粒度的事件流(`eval:start`、`run:budgetExceeded` 等)。
|
|
112
112
|
|
|
113
|
-
|
|
113
|
+
用户在 config/eval 中挂载的 Reporter 默认是 best-effort:抛错会形成永久 diagnostic,但不会中断在飞 Attempt。CLI 显式要求的 `--json` / `--junit` 与默认 results artifacts 是 required 输出,写失败会让最终运行判红。只有目的地没被内置覆盖时才需要自定义——`.niceeval/` 的 artifacts 已经记录了完整结果,事后分析直接读它(见[查看结果](./viewing-results))。
|
|
@@ -41,14 +41,31 @@ export default defineExperiment({
|
|
|
41
41
|
export ANTHROPIC_API_KEY=sk-ant-...
|
|
42
42
|
npx niceeval exp local fixtures/button
|
|
43
43
|
|
|
44
|
-
npx niceeval exp local fixtures/button --runs 10
|
|
44
|
+
npx niceeval exp local fixtures/button --runs 10
|
|
45
45
|
```
|
|
46
46
|
|
|
47
47
|
<Note>
|
|
48
|
-
没有对应的 CLI flag
|
|
48
|
+
没有对应的 CLI flag——provider 选择完全写在代码里。如果 experiment 和 `niceeval.config.ts` 都没设置 `sandbox`,[NiceEval](https://niceeval.com/) 在创建 sandbox 时会直接报错,不会自动探测。
|
|
49
49
|
</Note>
|
|
50
50
|
|
|
51
|
-
|
|
51
|
+
云端跑 coding agent 时,可以直接使用 NiceEval 已发布的 E2B 公共模板,避免每个 Attempt 安装 CLI:
|
|
52
|
+
|
|
53
|
+
```ts
|
|
54
|
+
import { codexAgent } from "niceeval/adapter";
|
|
55
|
+
import { e2bSandbox } from "niceeval/sandbox";
|
|
56
|
+
|
|
57
|
+
export default defineExperiment({
|
|
58
|
+
agent: codexAgent(),
|
|
59
|
+
model: "gpt-5.4",
|
|
60
|
+
sandbox: e2bSandbox({
|
|
61
|
+
template: "correctroads-default-team/niceeval-codex:v0.6.1",
|
|
62
|
+
}),
|
|
63
|
+
});
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
Claude Code 使用 `correctroads-default-team/niceeval-claude-code:v0.6.1`,Bub 使用 `correctroads-default-team/niceeval-bub:v0.6.1`。版本 tag 适合 CI;省略 tag 会跟随当前稳定构建。如何继续增加系统包、二进制或模型缓存,见 [沙箱 provider · 从官方基线继续构建以提速](/zh/how-to/sandbox-providers#从官方基线继续构建以提速)。
|
|
67
|
+
|
|
68
|
+
内置 agent 从 `niceeval/adapter` 导出的是工厂函数。需要配置鉴权、代理、MCP 或 GitHub skill 时,把这些写进工厂参数;模型仍然写在 experiment 的 `model` 字段,sandbox provider 仍然写在 `sandbox` 字段:
|
|
52
69
|
|
|
53
70
|
```ts
|
|
54
71
|
import { defineExperiment } from "niceeval";
|
|
@@ -87,13 +104,13 @@ export default defineExperiment({
|
|
|
87
104
|
```text
|
|
88
105
|
createSandbox
|
|
89
106
|
→ sandbox spec 的 .setup() 钩子? # 环境准备(按实验装东西);没挂就跳过
|
|
90
|
-
→ git init && git commit
|
|
91
107
|
→ eval 的 setup? # 这条 eval 的任务夹具(如果定义了)
|
|
92
108
|
→ adapter.setup? # 装 CLI / 写 agent 配置
|
|
93
109
|
→ test(t): uploadDirectory(...) # 写入这条 eval 的起始文件
|
|
94
|
-
→ adapter.send(input, ctx)
|
|
110
|
+
→ adapter.send(input, ctx) # agent 在这一步改动的文件才进 diff
|
|
95
111
|
→ test(t): runCommand(...) # 手工运行验证命令
|
|
96
|
-
→
|
|
112
|
+
→ 汇总 agent 改动的文件 # 供 t.sandbox.diff / fileChanged 使用
|
|
113
|
+
→ 评分与判定
|
|
97
114
|
→ adapter.teardown? # agent 收尾
|
|
98
115
|
→ sandbox spec 的 .teardown() 钩子? # 环境收尾(如回存状态),销毁前最后跑
|
|
99
116
|
→ sandbox.stop()
|
|
@@ -101,7 +118,9 @@ createSandbox
|
|
|
101
118
|
|
|
102
119
|
起始文件和验证命令都写在 `test(t)` 中。agent 执行阶段只能看到你已经写进 sandbox 的文件。
|
|
103
120
|
|
|
104
|
-
|
|
121
|
+
`t.sandbox.diff` 与 `t.sandbox.fileChanged()` 只包含 **agent 在 `t.send()` 期间改动的文件**:NiceEval 在每次 `t.send()` 前后记录一次工作区状态,把中间的变化记在 agent 名下。你上传的起始文件、`t.send()` 之后写入的验证材料都不会混进来,所以 `fileChanged("src/app.ts")` 只在 agent 真的动过这个文件时通过。
|
|
122
|
+
|
|
123
|
+
环境钩子(`.setup()` / `.teardown()`)挂在 experiment `sandbox` 字段的 spec 上,用来做"按实验变化的环境准备"——装某个实验专属的二进制、预热、跨 attempt 载入和回存状态。它写下的文件属于环境,不会被算进 agent 产出的 diff。写法和规则见 [沙箱 provider · 环境钩子](/zh/how-to/sandbox-providers#环境钩子)。
|
|
105
124
|
|
|
106
125
|
## 自定义 sandbox agent
|
|
107
126
|
|
|
@@ -110,9 +129,21 @@ import { defineSandboxAgent } from "niceeval/adapter";
|
|
|
110
129
|
|
|
111
130
|
export default defineSandboxAgent({
|
|
112
131
|
name: "my-agent",
|
|
132
|
+
async setup(sandbox, ctx) {
|
|
133
|
+
ctx.progress({ message: "检查 my-agent 安装" });
|
|
134
|
+
await sandbox.runCommand("npm", ["install", "-g", "my-agent"]);
|
|
135
|
+
},
|
|
113
136
|
async send(input, ctx) {
|
|
137
|
+
ctx.progress({ message: "运行 my-agent CLI" });
|
|
114
138
|
await ctx.sandbox.runCommand("my-agent", ["run", input.text, "--json-out", "agent-events.json"]);
|
|
115
139
|
const transcript = await ctx.sandbox.readFile("agent-events.json");
|
|
140
|
+
if (transcript.trim() === "") {
|
|
141
|
+
ctx.diagnostic({
|
|
142
|
+
code: "empty-transcript",
|
|
143
|
+
level: "warning",
|
|
144
|
+
message: "my-agent 没有写出 transcript,工具断言可能缺少证据",
|
|
145
|
+
});
|
|
146
|
+
}
|
|
116
147
|
return {
|
|
117
148
|
status: "completed",
|
|
118
149
|
events: parseTranscript(transcript),
|
|
@@ -121,6 +152,24 @@ export default defineSandboxAgent({
|
|
|
121
152
|
});
|
|
122
153
|
```
|
|
123
154
|
|
|
155
|
+
`setup`、每次 `send` 和 `teardown` 都拿到各自作用域的反馈方法:
|
|
156
|
+
|
|
157
|
+
- `ctx.progress({ message, current?, total? })` 更新当前短期状态,适合安装 CLI、运行 Turn、读取 transcript;不要逐 token 或逐 JSONL frame 调用。
|
|
158
|
+
- `ctx.diagnostic({ code, level, message, data?, dedupeKey? })` 保存协议退化、transcript 缺失和清理问题。它会进入终端永久事件和 `result.json`。
|
|
159
|
+
- 无法继续运行时抛出异常,runner 会把 Attempt 标为 `errored`,并保存发生阶段、错误码、message、cause 和 stack。
|
|
160
|
+
|
|
161
|
+
不要从 Adapter 直接调用 `console.log/error` 或写 `process.stdout/stderr`。它们会打散 Human dashboard,也会破坏 CI 日志顺序。
|
|
162
|
+
|
|
163
|
+
运行中看到 Sandbox 或 Adapter 错误时,终端会给出 Attempt locator:
|
|
164
|
+
|
|
165
|
+
```text
|
|
166
|
+
✗ @12h8m4k1 fixtures/button [local] errored · agent setup
|
|
167
|
+
agent-install-failed: npm install my-agent exited with code 1
|
|
168
|
+
Inspect: niceeval show @12h8m4k1
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
运行 `niceeval show @12h8m4k1` 可查看结构化错误、diagnostics 和已完成的生命周期阶段;`--timing` 给有界诊断时间树(排队、Sandbox 启动、setup/teardown hook 里的 shell、Agent CLI 安装与启动命令、每轮 send、可关联的 OTel model/tool、收尾),可直接看出错误或超时发生在哪一层、之前的时间花在哪里。树超过 80 个细节节点时会保留失败、慢点和首尾样本并提示省略数量;需要逐节点审计时使用 `--timing=full`。`--execution` 则以事件为骨架查看 agent 做了什么,有 OTel 时只把时间贴到能唯一关联的事件旁。Sandbox 创建失败可能发生在 telemetry 建立前,所以错误回顾不依赖 trace。
|
|
172
|
+
|
|
124
173
|
## `ctx.model` 与 `ctx.flags`
|
|
125
174
|
|
|
126
175
|
experiment 声明的 model 和 flags 会出现在 adapter context 中。adapter 可以决定如何把它们转成 CLI 参数或 HTTP payload。
|
|
@@ -0,0 +1,350 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: "Sandbox provider:Docker、Vercel 与第三方"
|
|
3
|
+
sidebarTitle: "沙箱 provider"
|
|
4
|
+
description: "NiceEval 在 Docker 或 Vercel sandbox 中运行 coding agents。了解如何选择 provider、配置权限,并通过 warm pools 改善性能。"
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
Sandbox Provider 是创建和管理隔离运行环境的基础设施。[NiceEval](https://niceeval.com/) 把它们包装成同一个 `Sandbox` 接口,所以 Adapter 不需要知道当前用的是本地 Docker、Vercel micro-VM、E2B 还是第三方云服务。
|
|
8
|
+
|
|
9
|
+
## `Sandbox` 接口
|
|
10
|
+
|
|
11
|
+
Adapter 常用操作包括:
|
|
12
|
+
|
|
13
|
+
| 方法 | 用途 |
|
|
14
|
+
|---|---|
|
|
15
|
+
| `runCommand(cmd, args)` | 运行命令 |
|
|
16
|
+
| `runShell(script)` | 运行 shell 脚本 |
|
|
17
|
+
| `readFile(path)` | 读取文件 |
|
|
18
|
+
| `writeFiles(files)` | 写入一组文件 |
|
|
19
|
+
| `uploadFiles(files)` | 上传 workspace 或测试文件 |
|
|
20
|
+
| `workdir` | provider 真实工作目录;省略的 `cwd` / `targetDir` 都解析到这里 |
|
|
21
|
+
| `runCommand(..., { cwd })` | 单条命令临时切换工作目录;相对路径按 `workdir` 解析 |
|
|
22
|
+
| `stop()` | 销毁环境 |
|
|
23
|
+
|
|
24
|
+
## 选择 provider
|
|
25
|
+
|
|
26
|
+
选择 provider 只能写在代码里——没有对应的 CLI flag,[NiceEval](https://niceeval.com/) 也不会自动探测 provider。在 experiment 里设置 `sandbox` 字段(或者在 `niceeval.config.ts` 里设置作为项目级兜底),三选一:
|
|
27
|
+
|
|
28
|
+
```ts
|
|
29
|
+
// experiments/local.ts
|
|
30
|
+
import { defineExperiment } from "niceeval";
|
|
31
|
+
import { dockerSandbox } from "niceeval/sandbox";
|
|
32
|
+
|
|
33
|
+
export default defineExperiment({
|
|
34
|
+
agent: myCodingAgent,
|
|
35
|
+
model: "claude-sonnet-4-6",
|
|
36
|
+
sandbox: dockerSandbox(), // 或 vercelSandbox() / e2bSandbox()
|
|
37
|
+
});
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
如果 experiment 和 `niceeval.config.ts` 都没有设置 `sandbox`,[NiceEval](https://niceeval.com/) 在创建 sandbox 时会直接报错,而不会猜一个 provider。
|
|
41
|
+
|
|
42
|
+
三个内置 provider 的 SDK 不随 NiceEval 一起安装——用哪个就装哪个,避免把用不到的依赖(以及它们的原生构建脚本)带进你的项目:
|
|
43
|
+
|
|
44
|
+
| provider | 安装命令 |
|
|
45
|
+
|---|---|
|
|
46
|
+
| `dockerSandbox()` | `pnpm add dockerode @types/dockerode` |
|
|
47
|
+
| `vercelSandbox()` | `pnpm add @vercel/sandbox` |
|
|
48
|
+
| `e2bSandbox()` | `pnpm add e2b` |
|
|
49
|
+
|
|
50
|
+
漏装时不会静默失败:NiceEval 在创建 sandbox 的那一刻报错并直接给出上面的安装命令,例如 `Docker sandbox requires 'dockerode'. Install it with: pnpm add dockerode @types/dockerode`。
|
|
51
|
+
|
|
52
|
+
## 环境钩子
|
|
53
|
+
|
|
54
|
+
`dockerSandbox()` / `vercelSandbox()` / `e2bSandbox()` 返回的 spec 上有两个链式方法:`.setup(fn)` 和 `.teardown(fn)`。它们处理只有运行时才知道的环境内容,例如按实验写小配置、检查预制工具是否可用、安装 hook,或在多次 Attempt 之间载入和回存状态。
|
|
55
|
+
|
|
56
|
+
共享 helper 需要显式标注回调类型时,从公开入口导入,不要从某个 provider 的 spec 反推:
|
|
57
|
+
|
|
58
|
+
```ts
|
|
59
|
+
import type { SandboxHook, SandboxHookContext } from "niceeval/sandbox";
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
稳定且体积大的依赖不要在这里重复安装。系统包、Agent CLI、编译好的二进制和大模型缓存应该先做进 Docker image、Vercel 沙箱快照或 E2B template。每个 Attempt 从预制环境启动,`.setup()` 只做薄薄的一层动态配置和 fail-fast 检查。
|
|
63
|
+
|
|
64
|
+
```ts
|
|
65
|
+
export default defineExperiment({
|
|
66
|
+
agent: codexAgent({ mcpServers: [mempalMcp] }),
|
|
67
|
+
sandbox: e2bSandbox({ template: "fasteval-agents-mempal" }) // 已包含二进制和模型缓存
|
|
68
|
+
.setup(mempalSetup("codex")) // 预检、写 hook、载入状态
|
|
69
|
+
.teardown(mempalTeardown("codex")), // 回存状态
|
|
70
|
+
maxConcurrency: 1, // 载入和回存之间不能并发,声明串行
|
|
71
|
+
});
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
规则一览:
|
|
75
|
+
|
|
76
|
+
- **签名**:钩子函数是 `(sandbox, ctx)`;`setup` 可以返回一个清理函数。这里的 `ctx` 是窄的 Sandbox Hook Context,只有 experiment 身份、取消信号和反馈方法,不带 Agent 会话或 telemetry。
|
|
77
|
+
- **不可变**:每次 `.setup()` / `.teardown()` 都返回一个新 spec,原对象不变,可以继续链。
|
|
78
|
+
- **多个钩子**:多个 `.setup()` 按追加顺序执行;多个 `.teardown()` 按追加的逆序执行。
|
|
79
|
+
- **执行时机**:`setup` 钩子在 sandbox 创建后、git 基线之前最先跑——它写下的文件会进基线,不会被算进 agent 产出的 diff;`teardown` 钩子在 Adapter 的 `teardown` 之后、sandbox 销毁之前最后跑——把状态回存到外部正好用这个时机。
|
|
80
|
+
- **失败语义**:`setup` 钩子抛错,这次 Attempt 记为 `errored`(环境问题,不是 Agent 做错题);`teardown` 钩子可以报告 diagnostic,默认不改变已经得到的判定。某个收尾动作是结果成立的必要条件时应抛错,由 runner 明确记录为致命错误。
|
|
81
|
+
- **不带 sandbox 的 Agent**:`defineAgent` 构造的 Agent 没有 sandbox,`sandbox` 字段对它不生效,钩子自然不会跑。
|
|
82
|
+
|
|
83
|
+
钩子里可以用 `ctx.experimentId`(路径推导的实验 id)当状态隔离的键,比如不同实验各自维护一份跨 attempt 的缓存。跨 attempt 状态的载入和回存是你自己在钩子里写的普通代码——[NiceEval](https://niceeval.com/) 不提供状态存储;要保证同一实验的 attempt 不并发读写同一份状态,在 experiment 上声明 `maxConcurrency: 1`。
|
|
84
|
+
|
|
85
|
+
### 从环境钩子报告进度和问题
|
|
86
|
+
|
|
87
|
+
长时间安装、预热和状态恢复可以调用 `ctx.progress(...)`。它只更新当前 Attempt 的短期状态,不会把每一步都写进结果。需要运行结束后仍能看到的问题使用 `ctx.diagnostic(...)`:
|
|
88
|
+
|
|
89
|
+
```ts
|
|
90
|
+
const sandbox = e2bSandbox({ template: "niceeval-agents" })
|
|
91
|
+
.setup(async (sandbox, ctx) => {
|
|
92
|
+
ctx.progress({ message: "安装 memory helper", current: 1, total: 2 });
|
|
93
|
+
await sandbox.runCommand("npm", ["install", "-g", "memory-helper"]);
|
|
94
|
+
|
|
95
|
+
ctx.progress({ message: "预热 memory index", current: 2, total: 2 });
|
|
96
|
+
try {
|
|
97
|
+
await warmIndex(sandbox);
|
|
98
|
+
} catch (error) {
|
|
99
|
+
ctx.diagnostic({
|
|
100
|
+
code: "memory-warmup-degraded",
|
|
101
|
+
level: "warning",
|
|
102
|
+
message: "预热失败,本次使用冷索引继续运行",
|
|
103
|
+
data: { reason: String(error) },
|
|
104
|
+
dedupeKey: "memory-warmup-degraded",
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
});
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
`progress` 和 `diagnostic` 都不能指定全局阶段、颜色或输出流。Runner 知道当前回调属于 `sandbox.setup`,会把 Human 终端中的阶段显示为 sandbox setup。`diagnostic` 会随 Attempt 写入 `result.json`,之后可用 `niceeval show @<locator>` 回顾;它本身不会改变判定。环境无法继续时直接抛出异常。
|
|
111
|
+
|
|
112
|
+
和另外两处 setup 的分工:Adapter 的 `setup` 管"怎么连被测 agent"(装 CLI、写鉴权配置);eval 里 `test(t)` 开头的代码管"这道题需要哪些起始文件";sandbox 的 `.setup()` 管"这次实验的环境里要多装什么"。三层各写各的,互相不知道对方的内容。MCP server、Skill、model 这些被测 agent 的配置仍然只从 Adapter 工厂参数进——环境钩子不做 Adapter 的事。
|
|
113
|
+
|
|
114
|
+
## 预制环境与运行时 checkpoint
|
|
115
|
+
|
|
116
|
+
NiceEval 用 typed spec 统一引用预制环境,但不提供一个假的通用构建命令:
|
|
117
|
+
|
|
118
|
+
```ts
|
|
119
|
+
dockerSandbox({ image: "my-evals:node24" })
|
|
120
|
+
vercelSandbox({ snapshotId: "snap_abc123" })
|
|
121
|
+
e2bSandbox({ template: "my-evals" })
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
Docker image、Vercel 沙箱快照和 E2B template 的凭据、构建上下文、发布和过期方式不同。项目应使用 provider 的官方工具维护构建脚本,把最终 ID 或名字放进 experiment。适合预制的判断很简单:如果所有 Attempt 都要下载或安装同一份内容,而且它稳定、昂贵或体积大,就把它移到预制环境。
|
|
125
|
+
|
|
126
|
+
### 从官方基线继续构建以提速
|
|
127
|
+
|
|
128
|
+
稳定、体积大、每个 Attempt 都相同的内容——系统包、Agent CLI、编译好的二进制、大模型缓存——应在跑 eval 之前烘焙进 provider 的可发布制品,让每个 Attempt 从预制环境启动、跳过运行时安装。三个内置 provider 都能从官方基线继续派生,不必从空白环境装 Agent;但它们的构建工具、凭据和发布语义不同,NiceEval 只统一**消费**产物 ID(`image` / `snapshotId` / `template`),不伪造跨 provider 的构建 DSL。
|
|
129
|
+
|
|
130
|
+
Adapter 与 Sandbox 不互相猜配置:Adapter 负责检查所需 CLI,Sandbox spec 负责选择 provider 和制品。Claude Code 与 Codex 缺少 CLI 时会回退到运行时安装,所以烘焙纯粹是提速;Bub 还会核对版本、OTel 插件和 Python 插件集合的安装指纹,不能仅凭 `command -v bub` 跳过安装,必须用预制环境。三个 provider 的构建都只在环境依赖变化时跑一次,产物换一个版本化名字,不要塞进每个 Attempt 的 `.setup()`。
|
|
131
|
+
|
|
132
|
+
#### E2B:从官方与公共模板派生
|
|
133
|
+
|
|
134
|
+
E2B 已提供 Claude Code 的 `claude` template 和 Codex 的 `codex` template。NiceEval 提供一个 E2B 专属的薄封装,让你从这两个官方起点继续链原生 E2B API。E2B 暂无 Bub 官方 template,因此 Bub 分支使用 NiceEval 固定到不可变 commit 的安装配方:
|
|
135
|
+
|
|
136
|
+
NiceEval 同时发布了三份任何 E2B Team 都能引用的公共模板。完整 namespace 与经过验证的 release
|
|
137
|
+
tag 由 NiceEval 自己维护,下游直接取完整引用:
|
|
138
|
+
|
|
139
|
+
```ts
|
|
140
|
+
import {
|
|
141
|
+
NICEEVAL_CLAUDE_CODE_E2B_TEMPLATE,
|
|
142
|
+
NICEEVAL_CODEX_E2B_TEMPLATE,
|
|
143
|
+
NICEEVAL_BUB_E2B_TEMPLATE,
|
|
144
|
+
} from "niceeval/sandbox/e2b-template";
|
|
145
|
+
|
|
146
|
+
e2bSandbox({ template: NICEEVAL_CLAUDE_CODE_E2B_TEMPLATE })
|
|
147
|
+
e2bSandbox({ template: NICEEVAL_CODEX_E2B_TEMPLATE })
|
|
148
|
+
e2bSandbox({ template: NICEEVAL_BUB_E2B_TEMPLATE })
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
这些基线已实际启动验证:Claude Code `2.1.207`、Codex `0.144.1`,Bub 安装指纹 `83770925b77a`。每个值都是带 tag 的完整跨 Team 引用;业务仓库不应复制这些字符串,也不应维护或读取另一份 NiceEval release 常量。派生模板需要记录 base 身份时,直接使用所选的完整 template ref。
|
|
152
|
+
|
|
153
|
+
```ts title="scripts/build-e2b-template.ts"
|
|
154
|
+
import { Template } from "e2b";
|
|
155
|
+
import { e2bCodingAgentTemplate } from "niceeval/sandbox/e2b-template";
|
|
156
|
+
|
|
157
|
+
const template = e2bCodingAgentTemplate("codex")
|
|
158
|
+
.aptInstall(["ripgrep", "jq"])
|
|
159
|
+
.runCmd("corepack enable && pnpm --version")
|
|
160
|
+
.copy("fixtures/toolchain.lock", "/opt/evals/toolchain.lock");
|
|
161
|
+
|
|
162
|
+
await Template.build(template, "acme-codex-evals:2026-07-13", {
|
|
163
|
+
cpuCount: 2,
|
|
164
|
+
memoryMB: 4096,
|
|
165
|
+
});
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
```bash
|
|
169
|
+
e2b auth login
|
|
170
|
+
pnpm tsx scripts/build-e2b-template.ts
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
然后在 Experiment 里只引用构建结果:
|
|
174
|
+
|
|
175
|
+
```ts
|
|
176
|
+
import { e2bSandbox } from "niceeval/sandbox";
|
|
177
|
+
|
|
178
|
+
sandbox: e2bSandbox({ template: "acme-codex-evals:2026-07-13" })
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
也可以直接从 NiceEval 公共模板继续派生,只支付项目依赖的构建成本:
|
|
182
|
+
|
|
183
|
+
```ts
|
|
184
|
+
import { NICEEVAL_CODEX_E2B_TEMPLATE } from "niceeval/sandbox/e2b-template";
|
|
185
|
+
|
|
186
|
+
const template = Template()
|
|
187
|
+
.fromTemplate(NICEEVAL_CODEX_E2B_TEMPLATE)
|
|
188
|
+
.aptInstall(["ripgrep", "jq"])
|
|
189
|
+
.runCmd("corepack enable");
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
`e2bCodingAgentTemplate("claude-code" | "codex" | "bub")` 返回原生 `TemplateBuilder`,不是 NiceEval 私有构建 DSL。你可以继续使用 `.aptInstall()`、`.runCmd()`、`.copy()` 等 E2B 能力。构建自己的 alias 会把官方起点和项目依赖冻结在同一个可复现制品里;依赖变更时重建并换一个版本化 alias。
|
|
193
|
+
|
|
194
|
+
若 Bub Adapter 配了 `pythonPlugins`,构建模板时把同一组 package 传给 factory,插件集合才会进入兼容性指纹并真正命中预装环境:
|
|
195
|
+
|
|
196
|
+
```ts
|
|
197
|
+
e2bCodingAgentTemplate("bub", {
|
|
198
|
+
bubPythonPackages: ["bub-plugin-memory==1.3.0"],
|
|
199
|
+
})
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
#### Docker:使用 NiceEval 维护的镜像,或从官方 node 基础镜像派生
|
|
203
|
+
|
|
204
|
+
要直接运行 NiceEval 内置的 `claude-code`、`codex` 或 `bub` Adapter,可以使用对应的公开镜像:
|
|
205
|
+
[`niceeval/claude-code`](https://hub.docker.com/r/niceeval/claude-code)、
|
|
206
|
+
[`niceeval/codex`](https://hub.docker.com/r/niceeval/codex) 或
|
|
207
|
+
[`niceeval/bub`](https://hub.docker.com/r/niceeval/bub)。每个镜像只包含自己的 Agent CLI,并为
|
|
208
|
+
`linux/amd64` 和 `linux/arm64` 发布 manifest;每个 NiceEval release 都有同名 tag。稳定 CI 要固定
|
|
209
|
+
release tag 或 digest,不要依赖会移动的 `latest`:
|
|
210
|
+
|
|
211
|
+
```ts
|
|
212
|
+
import { dockerSandbox } from "niceeval/sandbox";
|
|
213
|
+
|
|
214
|
+
sandbox: dockerSandbox({ image: "niceeval/codex:v0.6.1" })
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
这个镜像是 NiceEval 维护的公开镜像,不是 Docker 的 `library/*` Official Image。它随 NiceEval
|
|
218
|
+
release 更新,里面的 Agent CLI 版本由该 release 的构建配方固定。
|
|
219
|
+
|
|
220
|
+
如果只需要一个 Agent,或还要加入项目专有依赖,写 Dockerfile 从 Docker 的官方基线
|
|
221
|
+
`node:24-slim` 派生。省略 `image` 时,NiceEval 也会按 runtime 使用该默认镜像:
|
|
222
|
+
|
|
223
|
+
```dockerfile title="Dockerfile"
|
|
224
|
+
FROM node:24-slim
|
|
225
|
+
# slim 镜像不带 ca-certificates / git,Agent 和 npm 都要用
|
|
226
|
+
RUN apt-get update \
|
|
227
|
+
&& apt-get install -y --no-install-recommends ca-certificates git \
|
|
228
|
+
&& rm -rf /var/lib/apt/lists/*
|
|
229
|
+
# npm 全局装进 /usr/local/bin,正好落在沙箱注入的 PATH 上
|
|
230
|
+
RUN npm install -g @openai/codex@0.144.1
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
```bash
|
|
234
|
+
docker build -t acme-codex-evals:2026-07-13 .
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
然后在 Experiment 里只引用构建结果:
|
|
238
|
+
|
|
239
|
+
```ts
|
|
240
|
+
import { dockerSandbox } from "niceeval/sandbox";
|
|
241
|
+
|
|
242
|
+
sandbox: dockerSandbox({ image: "acme-codex-evals:2026-07-13" })
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
Docker 沙箱默认以非 root 的 `node` 用户(UID 1000)跑命令,并把 `/usr/local/bin` 放进 PATH,所以 `npm install -g` 装的全局二进制天然可见;要装到别处的 Agent(如落在 `~/.local/bin`)记得让它进 PATH。本地快速迭代可以直接省略 `image` 用默认 `node:*-slim`,稳定 CI 引用不可变 tag。
|
|
246
|
+
|
|
247
|
+
#### Vercel:从官方 runtime 拍快照
|
|
248
|
+
|
|
249
|
+
Vercel 没有 E2B 式的 template registry,也没有 Dockerfile;沙箱快照是从一台跑起来的 microVM 拍出来的。用 Vercel SDK 从官方 runtime(`node24`)起一台沙箱,装好 Agent CLI,调 `.snapshot()` 拿到 `snap_...`,再把它交给 `vercelSandbox({ snapshotId })`:
|
|
250
|
+
|
|
251
|
+
```ts title="scripts/build-vercel-snapshot.ts"
|
|
252
|
+
import { Sandbox } from "@vercel/sandbox";
|
|
253
|
+
|
|
254
|
+
const sandbox = await Sandbox.create({ runtime: "node24" }); // 官方 runtime 起 microVM
|
|
255
|
+
await sandbox.runCommand({
|
|
256
|
+
cmd: "npm",
|
|
257
|
+
args: ["install", "-g", "@openai/codex@0.144.1"],
|
|
258
|
+
sudo: true, // 全局装进 /usr/local/bin,落在沙箱 PATH 上
|
|
259
|
+
});
|
|
260
|
+
const { snapshotId } = await sandbox.snapshot();
|
|
261
|
+
console.log(snapshotId); // snap_...
|
|
262
|
+
await sandbox.stop();
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
```bash
|
|
266
|
+
pnpm tsx scripts/build-vercel-snapshot.ts
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
然后在 Experiment 里引用打印出的 ID:
|
|
270
|
+
|
|
271
|
+
```ts
|
|
272
|
+
import { vercelSandbox } from "niceeval/sandbox";
|
|
273
|
+
|
|
274
|
+
sandbox: vercelSandbox({ snapshotId: "snap_xxx" })
|
|
275
|
+
```
|
|
276
|
+
|
|
277
|
+
Vercel snapshot 不支持 E2B 式公共发布:snapshot ID 受创建它的 Team/Project 权限控制,同项目成员可以复用,外部用户必须在自己的 Vercel Project 重拍一份。NiceEval 维护项目当前验证过的永不过期 snapshot 是 `snap_7sIjfs71xfmVly0WEUTGhTBoMGeL`,但它不是跨账号公共 ID。
|
|
278
|
+
|
|
279
|
+
### 运行时 checkpoint
|
|
280
|
+
|
|
281
|
+
`createCheckpoint()` / `restoreCheckpoint()` 是另一件事。它们把指定的 Linux 路径打包成 `Buffer`,可以在已创建的 Sandbox 之间恢复文件系统片段:
|
|
282
|
+
|
|
283
|
+
```ts
|
|
284
|
+
import { createCheckpoint, restoreCheckpoint } from "niceeval/sandbox";
|
|
285
|
+
|
|
286
|
+
const data = await createCheckpoint(sandbox, ["/home/user/.cache/tool"]);
|
|
287
|
+
await restoreCheckpoint(nextSandbox, data);
|
|
288
|
+
```
|
|
289
|
+
|
|
290
|
+
这适合运行时缓存,不会创建可发布的 image/template/snapshot,也不管理共享、版本和过期。归档或恢复失败会直接抛错。
|
|
291
|
+
|
|
292
|
+
## 瞬时错误重试
|
|
293
|
+
|
|
294
|
+
内置 Provider 创建沙箱时,限流、`fetch failed`、连接重置、5xx、临时网络不可达这类瞬时失败会自动做指数退避重试;模板不存在、凭据缺失这类配置错误第一次就报错。重试用尽后该 Attempt 记为 errored。`defineSandbox` 自定义 Provider 的 `create` 是你自己的函数,NiceEval 不替它重试。
|
|
295
|
+
|
|
296
|
+
`readFile`、`downloadFile`、`uploadFile`、批量写入和目录上传会对 429、5xx、`fetch failed`、连接重置等瞬时传输错误自动做有限重试。文件不存在、权限错误、取消和 Sandbox terminated 不重试。
|
|
297
|
+
|
|
298
|
+
`runCommand` 与 `runShell` 不自动重试。命令可能已经产生副作用,只有你能确认它可安全重复时,才在 hook 或 eval 中显式重试。
|
|
299
|
+
|
|
300
|
+
## Docker
|
|
301
|
+
|
|
302
|
+
Docker 适合本地开发和标准 CI。优点是简单、可控、无云端依赖;缺点是机器资源有限,冷启动和安装依赖可能较慢。
|
|
303
|
+
|
|
304
|
+
## Vercel Sandbox
|
|
305
|
+
|
|
306
|
+
Vercel Sandbox 适合需要云端隔离、更多资源或更稳定环境的任务。需要相应 token 或 OIDC 配置。
|
|
307
|
+
|
|
308
|
+
## 自定义 Provider
|
|
309
|
+
|
|
310
|
+
用 `defineSandbox` 接入其它服务。`create` 的 `feedback` 已绑定到 `sandbox.create` 阶段,可以报告分配实例、拉镜像或恢复沙箱快照的状态:
|
|
311
|
+
|
|
312
|
+
```ts
|
|
313
|
+
import { defineSandbox } from "niceeval/sandbox";
|
|
314
|
+
|
|
315
|
+
export default defineSandbox({
|
|
316
|
+
name: "modal",
|
|
317
|
+
recommendedConcurrency: 8,
|
|
318
|
+
async create({ timeout, runtime, feedback }) {
|
|
319
|
+
feedback.progress({ message: "分配 Modal Sandbox" });
|
|
320
|
+
const instance = await allocateModal({ timeout, runtime });
|
|
321
|
+
|
|
322
|
+
if (instance.usedFallbackRegion) {
|
|
323
|
+
feedback.diagnostic({
|
|
324
|
+
code: "modal-fallback-region",
|
|
325
|
+
level: "warning",
|
|
326
|
+
message: `主区域不可用,使用 ${instance.region}`,
|
|
327
|
+
data: { region: instance.region },
|
|
328
|
+
});
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
return new ModalSandbox(instance);
|
|
332
|
+
},
|
|
333
|
+
});
|
|
334
|
+
```
|
|
335
|
+
|
|
336
|
+
返回值实现 `Sandbox` 接口即可。Provider SDK 的原始日志不要直接写宿主进程的 `stdout` / `stderr`;短期状态走 `feedback.progress`,需要保留的问题走 `feedback.diagnostic`,无法创建环境时抛错。这样 Human dashboard 不会被日志打散,CI 也能保持单一有序输出。
|
|
337
|
+
|
|
338
|
+
## 权限和 root
|
|
339
|
+
|
|
340
|
+
不同 provider 对 root 权限、网络、文件系统和进程生命周期的约束不同。编写 fixture 时尽量避免依赖宿主机环境,把依赖写进 `package.json` 或 fixture setup。
|
|
341
|
+
|
|
342
|
+
## 性能建议
|
|
343
|
+
|
|
344
|
+
- 把稳定重依赖做进 image/template/snapshot,不在每个 Attempt 的 `.setup()` 重装。
|
|
345
|
+
- 减少 fixture 依赖体积。
|
|
346
|
+
- 对动态内容使用小而明确的缓存或预检。
|
|
347
|
+
- 控制 `maxConcurrency`(experiment 字段或 `--max-concurrency`),避免本地 Docker 资源耗尽。
|
|
348
|
+
- 把慢测试拆成必要的 gate 和可选的 soft 检查。
|
|
349
|
+
|
|
350
|
+
Warm pools 和复用属于 runner / scheduler 层面的能力,详见 [Runner](/zh/explanation/runner)。
|
|
@@ -10,7 +10,7 @@ description: "用 NiceEval 的五种评分机制评估任意 eval:值断言、
|
|
|
10
10
|
|
|
11
11
|
| 目标 | 推荐机制 |
|
|
12
12
|
|---|---|
|
|
13
|
-
|
|
|
13
|
+
| 回复包含固定子串或命中正则 | `includes` |
|
|
14
14
|
| 结构化 JSON 完全匹配 | `equals` |
|
|
15
15
|
| 工具调用是否发生 | `t.calledTool` / `t.notCalledTool` |
|
|
16
16
|
| 输出是否语义正确 | `t.judge.*` |
|
|
@@ -20,14 +20,14 @@ description: "用 NiceEval 的五种评分机制评估任意 eval:值断言、
|
|
|
20
20
|
## 值断言
|
|
21
21
|
|
|
22
22
|
```ts
|
|
23
|
-
import { includes, equals
|
|
23
|
+
import { includes, equals } from "niceeval/expect";
|
|
24
24
|
|
|
25
25
|
t.check(t.reply, includes("refund"));
|
|
26
26
|
t.check(turn.data, equals({ intent: "refund" }));
|
|
27
|
-
t.check(t.reply,
|
|
27
|
+
t.check(t.reply, includes(/order #\d+/));
|
|
28
28
|
```
|
|
29
29
|
|
|
30
|
-
|
|
30
|
+
`includes` 同时接受子串和正则;`matches` 只接受 Standard Schema / Zod schema,用于结构校验,不做正则匹配。值断言适合精确、稳定、低歧义的结果。
|
|
31
31
|
|
|
32
32
|
## 作用域断言
|
|
33
33
|
|