niceeval 0.6.1 → 0.6.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.
- package/dist/agents/types.d.ts +67 -5
- package/dist/context/types.d.ts +32 -12
- package/dist/i18n/en.d.ts +54 -0
- package/dist/i18n/zh-CN.d.ts +55 -1
- package/dist/o11y/types.d.ts +16 -2
- package/dist/report/aggregate.d.ts +5 -3
- package/dist/report/aggregate.js +32 -5
- package/dist/report/built-ins/experiment-comparison.d.ts +39 -1
- package/dist/report/built-ins/experiment-comparison.js +116 -10
- package/dist/report/built-ins/index.d.ts +1 -0
- package/dist/report/built-ins/index.js +1 -1
- package/dist/report/components.d.ts +8 -2
- package/dist/report/components.js +3 -3
- package/dist/report/compute.d.ts +11 -18
- package/dist/report/compute.js +54 -34
- package/dist/report/flag.d.ts +16 -1
- package/dist/report/flag.js +19 -1
- package/dist/report/format.d.ts +16 -8
- package/dist/report/format.js +27 -12
- package/dist/report/index.d.ts +4 -3
- package/dist/report/index.js +5 -4
- package/dist/report/locale.d.ts +11 -2
- package/dist/report/locale.js +23 -5
- package/dist/report/metrics.d.ts +13 -1
- package/dist/report/metrics.js +65 -14
- package/dist/report/primitives.d.ts +6 -0
- package/dist/report/react/AttemptList.d.ts +2 -2
- package/dist/report/react/AttemptList.js +5 -6
- package/dist/report/react/EvalList.d.ts +1 -1
- package/dist/report/react/EvalList.js +0 -0
- package/dist/report/react/ExperimentComparison.d.ts +8 -0
- package/dist/report/react/ExperimentComparison.js +11 -0
- package/dist/report/react/ExperimentList.d.ts +2 -1
- package/dist/report/react/ExperimentList.js +8 -10
- package/dist/report/react/MetricScatter.js +5 -11
- 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 +3 -3
- package/dist/report/react/fixtures.js +21 -14
- package/dist/report/report.d.ts +5 -1
- package/dist/report/report.js +6 -2
- package/dist/report/text/faces.d.ts +1 -1
- package/dist/report/text/faces.js +42 -41
- package/dist/report/text/table.js +36 -5
- package/dist/report/types.d.ts +39 -21
- package/dist/results/types.d.ts +11 -0
- 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 +1 -0
- package/dist/shared/aggregate.js +3 -3
- 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/concepts/adapter.mdx +22 -4
- package/docs-site/zh/concepts/experiment.mdx +1 -1
- package/docs-site/zh/concepts/overview.mdx +6 -6
- package/docs-site/zh/guides/agent-feedback-loop.mdx +28 -26
- package/docs-site/zh/guides/authoring.mdx +33 -0
- package/docs-site/zh/guides/ci-integration.mdx +23 -12
- package/docs-site/zh/guides/connect-your-agent.mdx +29 -3
- package/docs-site/zh/guides/custom-reports.mdx +29 -34
- package/docs-site/zh/guides/dataset-fanout.mdx +25 -3
- package/docs-site/zh/guides/debug-sandbox.mdx +57 -0
- package/docs-site/zh/guides/debugging.mdx +210 -0
- package/docs-site/zh/guides/experiments.mdx +10 -3
- package/docs-site/zh/guides/official-adapters.mdx +26 -2
- package/docs-site/zh/guides/publish-report.mdx +30 -16
- package/docs-site/zh/guides/report-components.mdx +42 -30
- package/docs-site/zh/guides/reporters.mdx +2 -2
- package/docs-site/zh/guides/results-data.mdx +17 -9
- package/docs-site/zh/guides/runner.mdx +17 -7
- package/docs-site/zh/guides/sandbox-agent.mdx +56 -7
- package/docs-site/zh/guides/sandbox-providers.mdx +257 -9
- package/docs-site/zh/guides/scoring-guide.mdx +4 -4
- package/docs-site/zh/guides/viewing-results.mdx +79 -36
- package/docs-site/zh/guides/write-experiment.mdx +5 -3
- package/docs-site/zh/guides/write-send.mdx +17 -1
- package/docs-site/zh/index.mdx +1 -1
- package/docs-site/zh/reference/builtin-agents.mdx +27 -0
- package/docs-site/zh/reference/capabilities.mdx +2 -2
- package/docs-site/zh/reference/cli.mdx +33 -7
- package/docs-site/zh/reference/define-agent.mdx +57 -4
- 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/expect.mdx +26 -1
- package/package.json +5 -1
- 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 +11 -0
- 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/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/types.ts +68 -5
- package/src/agents/ui-message-stream.test.ts +3 -0
- package/src/cli.ts +411 -108
- package/src/context/context.test.ts +51 -12
- package/src/context/context.ts +161 -29
- package/src/context/session.test.ts +1 -0
- package/src/context/session.ts +114 -6
- 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 +64 -2
- package/src/i18n/zh-CN.ts +65 -3
- 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 +34 -5
- package/src/report/built-in-user-parity.test.tsx +110 -153
- package/src/report/built-ins/experiment-comparison.tsx +173 -13
- package/src/report/built-ins/index.ts +6 -1
- package/src/report/components.tsx +9 -3
- package/src/report/compute.ts +70 -40
- package/src/report/dual-render.test.tsx +194 -67
- package/src/report/flag.ts +30 -2
- package/src/report/format.ts +35 -11
- package/src/report/index.ts +22 -4
- package/src/report/locale.ts +25 -5
- package/src/report/metrics.ts +67 -14
- package/src/report/primitives.tsx +6 -0
- package/src/report/react/AttemptList.tsx +6 -31
- package/src/report/react/EvalList.tsx +0 -0
- package/src/report/react/ExperimentComparison.tsx +68 -0
- package/src/report/react/ExperimentList.tsx +15 -9
- package/src/report/react/MetricScatter.tsx +12 -14
- 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 +33 -1
- package/src/report/react/fixtures.ts +24 -17
- package/src/report/react/render.test.tsx +9 -64
- package/src/report/react/styles.css +73 -2
- package/src/report/report.test.ts +306 -98
- package/src/report/report.ts +6 -2
- package/src/report/text/faces.ts +47 -43
- package/src/report/text/table.ts +42 -5
- package/src/report/types.ts +41 -21
- package/src/results/annotated-source.test.ts +62 -9
- package/src/results/annotated-source.ts +64 -6
- package/src/results/attempt-evidence.test.ts +9 -7
- package/src/results/attempt-evidence.ts +15 -8
- package/src/results/attempt-source.ts +6 -3
- package/src/results/copy.ts +145 -55
- package/src/results/host-equivalence.test.ts +8 -6
- package/src/results/index.ts +2 -0
- package/src/results/locator.test.ts +1 -22
- package/src/results/open.ts +7 -1
- package/src/results/publish.ts +149 -0
- package/src/results/results.test.ts +85 -51
- package/src/results/truncate.ts +90 -0
- package/src/results/types.ts +7 -0
- 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 +242 -36
- 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 +3 -2
- package/src/shared/types.ts +31 -0
- package/src/show/compose.ts +2 -2
- package/src/show/index.ts +21 -1
- package/src/show/render.ts +619 -104
- package/src/show/show.test.ts +235 -19
- package/src/tty-line.ts +8 -26
- package/src/util.test.ts +1 -0
- package/src/util.ts +41 -0
- package/src/view/app/components/AttemptModal.tsx +153 -2
- package/src/view/app/components/CodeView.tsx +32 -11
- package/src/view/app/components/CopyControls.tsx +2 -2
- package/src/view/app/i18n.ts +6 -0
- package/src/view/app/lib/attempt-route.test.ts +1 -0
- package/src/view/app/lib/verdict.ts +7 -9
- 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 +1 -0
- package/src/view/data.ts +11 -1
- package/src/view/index.ts +11 -0
- package/src/view/server.ts +2 -0
- package/src/view/styles.css +3 -0
- package/src/view/view-report.test.ts +6 -5
- 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
|
@@ -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/guides/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/guides/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。
|
|
@@ -4,7 +4,7 @@ sidebarTitle: "沙箱 provider"
|
|
|
4
4
|
description: "NiceEval 在 Docker 或 Vercel sandbox 中运行 coding agents。了解如何选择 provider、配置权限,并通过 warm pools 改善性能。"
|
|
5
5
|
---
|
|
6
6
|
|
|
7
|
-
Sandbox
|
|
7
|
+
Sandbox Provider 是创建和管理隔离运行环境的基础设施。[NiceEval](https://niceeval.com/) 把它们包装成同一个 `Sandbox` 接口,所以 Adapter 不需要知道当前用的是本地 Docker、Vercel micro-VM、E2B 还是第三方云服务。
|
|
8
8
|
|
|
9
9
|
## `Sandbox` 接口
|
|
10
10
|
|
|
@@ -51,13 +51,21 @@ export default defineExperiment({
|
|
|
51
51
|
|
|
52
52
|
## 环境钩子
|
|
53
53
|
|
|
54
|
-
`dockerSandbox()` / `vercelSandbox()` / `e2bSandbox()` 返回的 spec 上有两个链式方法:`.setup(fn)` 和 `.teardown(fn)
|
|
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 检查。
|
|
55
63
|
|
|
56
64
|
```ts
|
|
57
65
|
export default defineExperiment({
|
|
58
66
|
agent: codexAgent({ mcpServers: [mempalMcp] }),
|
|
59
|
-
sandbox: e2bSandbox({ template: "fasteval-agents" })
|
|
60
|
-
.setup(mempalSetup("codex")) //
|
|
67
|
+
sandbox: e2bSandbox({ template: "fasteval-agents-mempal" }) // 已包含二进制和模型缓存
|
|
68
|
+
.setup(mempalSetup("codex")) // 预检、写 hook、载入状态
|
|
61
69
|
.teardown(mempalTeardown("codex")), // 回存状态
|
|
62
70
|
maxConcurrency: 1, // 载入和回存之间不能并发,声明串行
|
|
63
71
|
});
|
|
@@ -65,17 +73,230 @@ export default defineExperiment({
|
|
|
65
73
|
|
|
66
74
|
规则一览:
|
|
67
75
|
|
|
68
|
-
-
|
|
76
|
+
- **签名**:钩子函数是 `(sandbox, ctx)`;`setup` 可以返回一个清理函数。这里的 `ctx` 是窄的 Sandbox Hook Context,只有 experiment 身份、取消信号和反馈方法,不带 Agent 会话或 telemetry。
|
|
69
77
|
- **不可变**:每次 `.setup()` / `.teardown()` 都返回一个新 spec,原对象不变,可以继续链。
|
|
70
78
|
- **多个钩子**:多个 `.setup()` 按追加顺序执行;多个 `.teardown()` 按追加的逆序执行。
|
|
71
79
|
- **执行时机**:`setup` 钩子在 sandbox 创建后、git 基线之前最先跑——它写下的文件会进基线,不会被算进 agent 产出的 diff;`teardown` 钩子在 Adapter 的 `teardown` 之后、sandbox 销毁之前最后跑——把状态回存到外部正好用这个时机。
|
|
72
|
-
- **失败语义**:`setup` 钩子抛错,这次
|
|
80
|
+
- **失败语义**:`setup` 钩子抛错,这次 Attempt 记为 `errored`(环境问题,不是 Agent 做错题);`teardown` 钩子可以报告 diagnostic,默认不改变已经得到的判定。某个收尾动作是结果成立的必要条件时应抛错,由 runner 明确记录为致命错误。
|
|
73
81
|
- **不带 sandbox 的 Agent**:`defineAgent` 构造的 Agent 没有 sandbox,`sandbox` 字段对它不生效,钩子自然不会跑。
|
|
74
82
|
|
|
75
83
|
钩子里可以用 `ctx.experimentId`(路径推导的实验 id)当状态隔离的键,比如不同实验各自维护一份跨 attempt 的缓存。跨 attempt 状态的载入和回存是你自己在钩子里写的普通代码——[NiceEval](https://niceeval.com/) 不提供状态存储;要保证同一实验的 attempt 不并发读写同一份状态,在 experiment 上声明 `maxConcurrency: 1`。
|
|
76
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
|
+
|
|
77
112
|
和另外两处 setup 的分工:Adapter 的 `setup` 管"怎么连被测 agent"(装 CLI、写鉴权配置);eval 里 `test(t)` 开头的代码管"这道题需要哪些起始文件";sandbox 的 `.setup()` 管"这次实验的环境里要多装什么"。三层各写各的,互相不知道对方的内容。MCP server、Skill、model 这些被测 agent 的配置仍然只从 Adapter 工厂参数进——环境钩子不做 Adapter 的事。
|
|
78
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
|
+
|
|
79
300
|
## Docker
|
|
80
301
|
|
|
81
302
|
Docker 适合本地开发和标准 CI。优点是简单、可控、无云端依赖;缺点是机器资源有限,冷启动和安装依赖可能较慢。
|
|
@@ -84,9 +305,35 @@ Docker 适合本地开发和标准 CI。优点是简单、可控、无云端依
|
|
|
84
305
|
|
|
85
306
|
Vercel Sandbox 适合需要云端隔离、更多资源或更稳定环境的任务。需要相应 token 或 OIDC 配置。
|
|
86
307
|
|
|
87
|
-
##
|
|
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
|
+
```
|
|
88
335
|
|
|
89
|
-
|
|
336
|
+
返回值实现 `Sandbox` 接口即可。Provider SDK 的原始日志不要直接写宿主进程的 `stdout` / `stderr`;短期状态走 `feedback.progress`,需要保留的问题走 `feedback.diagnostic`,无法创建环境时抛错。这样 Human dashboard 不会被日志打散,CI 也能保持单一有序输出。
|
|
90
337
|
|
|
91
338
|
## 权限和 root
|
|
92
339
|
|
|
@@ -94,8 +341,9 @@ Vercel Sandbox 适合需要云端隔离、更多资源或更稳定环境的任
|
|
|
94
341
|
|
|
95
342
|
## 性能建议
|
|
96
343
|
|
|
344
|
+
- 把稳定重依赖做进 image/template/snapshot,不在每个 Attempt 的 `.setup()` 重装。
|
|
97
345
|
- 减少 fixture 依赖体积。
|
|
98
|
-
-
|
|
346
|
+
- 对动态内容使用小而明确的缓存或预检。
|
|
99
347
|
- 控制 `maxConcurrency`(experiment 字段或 `--max-concurrency`),避免本地 Docker 资源耗尽。
|
|
100
348
|
- 把慢测试拆成必要的 gate 和可选的 soft 检查。
|
|
101
349
|
|
|
@@ -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
|
|