niceeval 0.5.4 → 0.6.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/INDEX.md +55 -0
- package/dist/agents/types.d.ts +321 -0
- package/dist/context/types.d.ts +335 -0
- package/dist/i18n/core.d.ts +11 -0
- package/dist/i18n/en.d.ts +181 -0
- package/dist/i18n/index.d.ts +5 -0
- package/dist/i18n/zh-CN.d.ts +183 -0
- package/dist/o11y/otlp/parse.d.ts +3 -0
- package/dist/o11y/otlp/receiver.d.ts +21 -0
- package/dist/o11y/otlp/turn-otel.d.ts +43 -0
- package/dist/o11y/types.d.ts +190 -0
- package/dist/report/aggregate.d.ts +57 -0
- package/dist/report/aggregate.js +212 -0
- package/dist/report/built-ins/experiment-comparison.d.ts +1 -0
- package/dist/report/built-ins/experiment-comparison.js +13 -0
- package/dist/report/built-ins/index.d.ts +1 -0
- package/dist/report/built-ins/index.js +2 -0
- package/dist/report/components.d.ts +180 -0
- package/dist/report/components.js +132 -0
- package/dist/report/compute.d.ts +106 -0
- package/dist/report/compute.js +600 -0
- package/dist/report/flag.d.ts +6 -0
- package/dist/report/flag.js +8 -0
- package/dist/report/format.d.ts +26 -0
- package/dist/report/format.js +109 -0
- package/dist/report/index.d.ts +19 -0
- package/dist/report/index.js +30 -0
- package/dist/report/load.d.ts +12 -0
- package/dist/report/load.js +56 -0
- package/dist/report/locale.d.ts +94 -0
- package/dist/report/locale.js +183 -0
- package/dist/report/metrics.d.ts +21 -0
- package/dist/report/metrics.js +115 -0
- package/dist/report/primitives.d.ts +64 -0
- package/dist/report/primitives.js +113 -0
- package/dist/report/react/AttemptList.d.ts +23 -0
- package/dist/report/react/AttemptList.js +19 -0
- package/dist/report/react/DeltaTable.d.ts +8 -0
- package/dist/report/react/DeltaTable.js +24 -0
- package/dist/report/react/EvalList.d.ts +10 -0
- package/dist/report/react/EvalList.js +0 -0
- package/dist/report/react/ExperimentList.d.ts +11 -0
- package/dist/report/react/ExperimentList.js +67 -0
- package/dist/report/react/GroupSummary.d.ts +8 -0
- package/dist/report/react/GroupSummary.js +8 -0
- package/dist/report/react/MetricBars.d.ts +10 -0
- package/dist/report/react/MetricBars.js +48 -0
- package/dist/report/react/MetricLine.d.ts +9 -0
- package/dist/report/react/MetricLine.js +68 -0
- package/dist/report/react/MetricMatrix.d.ts +10 -0
- package/dist/report/react/MetricMatrix.js +23 -0
- package/dist/report/react/MetricScatter.d.ts +9 -0
- package/dist/report/react/MetricScatter.js +96 -0
- package/dist/report/react/MetricTable.d.ts +11 -0
- package/dist/report/react/MetricTable.js +26 -0
- package/dist/report/react/RunOverview.d.ts +8 -0
- package/dist/report/react/RunOverview.js +12 -0
- package/dist/report/react/Scoreboard.d.ts +8 -0
- package/dist/report/react/Scoreboard.js +26 -0
- package/dist/report/react/cell.d.ts +9 -0
- package/dist/report/react/cell.js +9 -0
- package/dist/report/react/chart-math.d.ts +14 -0
- package/dist/report/react/chart-math.js +68 -0
- package/dist/report/react/colors.d.ts +14 -0
- package/dist/report/react/colors.js +45 -0
- package/dist/report/react/fixtures.d.ts +19 -0
- package/dist/report/react/fixtures.js +398 -0
- package/dist/report/react/format.d.ts +3 -0
- package/dist/report/react/format.js +7 -0
- package/dist/report/react/index.d.ts +6 -0
- package/dist/report/react/index.js +14 -0
- package/dist/report/report.d.ts +24 -0
- package/dist/report/report.js +49 -0
- package/dist/report/text/faces.d.ts +29 -0
- package/dist/report/text/faces.js +541 -0
- package/dist/report/text/layout.d.ts +75 -0
- package/dist/report/text/layout.js +173 -0
- package/dist/report/text/plot.d.ts +37 -0
- package/dist/report/text/plot.js +81 -0
- package/dist/report/text/table.d.ts +8 -0
- package/dist/report/text/table.js +86 -0
- package/dist/report/tree.d.ts +99 -0
- package/dist/report/tree.js +228 -0
- package/dist/report/types.d.ts +408 -0
- package/dist/report/types.js +4 -0
- package/dist/report/web.d.ts +15 -0
- package/dist/report/web.js +37 -0
- package/dist/results/locator.d.ts +75 -0
- package/dist/results/locator.js +0 -0
- package/dist/results/select.d.ts +45 -0
- package/dist/results/select.js +230 -0
- package/dist/results/source-hash.d.ts +9 -0
- package/dist/results/types.d.ts +204 -0
- package/dist/runner/eval-source.d.ts +22 -0
- package/dist/runner/fingerprint.d.ts +23 -0
- package/dist/runner/types.d.ts +332 -0
- package/dist/sandbox/docker-stream.d.ts +24 -0
- package/dist/sandbox/docker.d.ts +84 -0
- package/dist/sandbox/e2b.d.ts +31 -0
- package/dist/sandbox/errors.d.ts +4 -0
- package/dist/sandbox/local-files.d.ts +6 -0
- package/dist/sandbox/paths.d.ts +4 -0
- package/dist/sandbox/registry.d.ts +13 -0
- package/dist/sandbox/resolve.d.ts +40 -0
- package/dist/sandbox/retry.d.ts +10 -0
- package/dist/sandbox/shell.d.ts +11 -0
- package/dist/sandbox/source-files.d.ts +13 -0
- package/dist/sandbox/types.d.ts +203 -0
- package/dist/sandbox/vercel.d.ts +37 -0
- package/dist/scoring/types.d.ts +70 -0
- package/dist/shared/aggregate.d.ts +29 -0
- package/dist/shared/aggregate.js +55 -0
- package/dist/shared/types.d.ts +27 -0
- package/dist/shared/verdict.d.ts +27 -0
- package/dist/shared/verdict.js +34 -0
- package/dist/tty-line.d.ts +6 -0
- package/dist/types.d.ts +7 -0
- package/dist/util.d.ts +22 -0
- package/docs-site/zh/concepts/adapter.mdx +7 -7
- package/docs-site/zh/concepts/assert.mdx +19 -18
- package/docs-site/zh/concepts/evals.mdx +12 -11
- package/docs-site/zh/concepts/experiment.mdx +2 -2
- package/docs-site/zh/concepts/judge.mdx +9 -9
- package/docs-site/zh/concepts/overview.mdx +3 -3
- package/docs-site/zh/concepts/tier.mdx +6 -6
- package/docs-site/zh/example/claude-code-codex-plugin.mdx +9 -5
- package/docs-site/zh/example/claude-code-codex-skill.mdx +12 -7
- package/docs-site/zh/guides/agent-feedback-loop.mdx +237 -78
- package/docs-site/zh/guides/connect-otel.mdx +3 -3
- package/docs-site/zh/guides/connect-your-agent.mdx +2 -2
- package/docs-site/zh/guides/custom-reports.mdx +196 -36
- package/docs-site/zh/guides/experiments.mdx +7 -1
- package/docs-site/zh/guides/fixtures.mdx +4 -2
- package/docs-site/zh/guides/official-adapters.mdx +31 -9
- package/docs-site/zh/guides/publish-report.mdx +4 -4
- package/docs-site/zh/guides/report-components.mdx +194 -55
- package/docs-site/zh/guides/reporters.mdx +2 -2
- package/docs-site/zh/guides/results-data.mdx +61 -34
- package/docs-site/zh/guides/runner.mdx +2 -2
- package/docs-site/zh/guides/sandbox-agent.mdx +3 -2
- package/docs-site/zh/guides/{sandbox-backends.mdx → sandbox-providers.mdx} +12 -12
- package/docs-site/zh/guides/viewing-results.mdx +200 -79
- package/docs-site/zh/guides/write-experiment.mdx +9 -1
- package/docs-site/zh/guides/write-send.mdx +4 -3
- package/docs-site/zh/index.mdx +4 -3
- package/docs-site/zh/introduction.mdx +2 -1
- package/docs-site/zh/quickstart.mdx +5 -3
- package/docs-site/zh/reference/builtin-agents.mdx +38 -13
- package/docs-site/zh/reference/capabilities.mdx +1 -1
- package/docs-site/zh/reference/cli.mdx +36 -13
- package/docs-site/zh/reference/define-agent.mdx +15 -13
- package/docs-site/zh/reference/define-config.mdx +1 -1
- package/docs-site/zh/reference/define-eval.mdx +3 -3
- package/docs-site/zh/reference/events.mdx +9 -3
- package/docs-site/zh/reference/expect.mdx +13 -8
- package/package.json +10 -6
- package/src/agents/bub.ts +129 -42
- package/src/agents/claude-code.test.ts +152 -0
- package/src/agents/claude-code.ts +127 -13
- package/src/agents/codex.test.ts +192 -0
- package/src/agents/codex.ts +151 -12
- package/src/agents/index.ts +9 -3
- package/src/agents/manifest.ts +41 -0
- package/src/agents/plugin-config.test.ts +94 -0
- package/src/agents/shared.ts +33 -2
- package/src/agents/skills.test.ts +214 -0
- package/src/agents/skills.ts +304 -0
- package/src/agents/streaming.ts +5 -5
- package/src/agents/types.ts +59 -3
- package/src/cli.ts +74 -47
- package/src/context/context.test.ts +20 -2
- package/src/context/control-flow.ts +1 -1
- package/src/context/session.test.ts +92 -1
- package/src/context/session.ts +23 -1
- package/src/context/types.ts +4 -4
- package/src/define.test.ts +8 -8
- package/src/define.ts +11 -11
- package/src/expect/index.ts +5 -5
- package/src/i18n/en.ts +33 -15
- package/src/i18n/zh-CN.ts +37 -21
- package/src/index.ts +1 -1
- package/src/o11y/execution-tree.test.ts +452 -0
- package/src/o11y/execution-tree.ts +367 -0
- package/src/o11y/otlp/receiver.ts +1 -1
- package/src/o11y/otlp/select.ts +7 -3
- package/src/o11y/parsers/claude-code.test.ts +175 -0
- package/src/o11y/parsers/claude-code.ts +32 -0
- package/src/o11y/types.ts +6 -1
- package/src/report/aggregate.ts +26 -20
- package/src/report/built-in-user-parity.test.tsx +640 -0
- package/src/report/built-ins/experiment-comparison.tsx +19 -0
- package/src/report/built-ins/index.ts +2 -0
- package/src/report/components.tsx +225 -50
- package/src/report/compute.ts +335 -54
- package/src/report/dual-render.test.tsx +1129 -0
- package/src/report/flag.ts +1 -1
- package/src/report/format.ts +35 -2
- package/src/report/index.ts +47 -14
- package/src/report/load.ts +1 -1
- package/src/report/locale.ts +229 -0
- package/src/report/metrics.ts +39 -15
- package/src/report/primitives.tsx +100 -2
- package/src/report/react/AttemptList.tsx +113 -0
- package/src/report/react/DeltaTable.tsx +9 -6
- package/src/report/react/EvalList.tsx +0 -0
- package/src/report/react/ExperimentList.tsx +220 -0
- package/src/report/react/GroupSummary.tsx +66 -0
- package/src/report/react/MetricBars.tsx +24 -13
- package/src/report/react/MetricLine.tsx +21 -21
- package/src/report/react/MetricMatrix.tsx +8 -4
- package/src/report/react/MetricScatter.tsx +126 -96
- package/src/report/react/MetricTable.tsx +115 -15
- package/src/report/react/RunOverview.tsx +48 -26
- package/src/report/react/Scoreboard.tsx +15 -7
- package/src/report/react/cell.tsx +18 -9
- package/src/{view/app/lib/chart.ts → report/react/chart-math.ts} +2 -6
- package/src/report/react/colors.ts +24 -15
- package/src/report/react/enhance.js +168 -0
- package/src/report/react/fixtures.ts +169 -34
- package/src/report/react/format.ts +1 -1
- package/src/report/react/index.tsx +21 -6
- package/src/report/react/render.test.tsx +180 -31
- package/src/report/react/styles.css +432 -213
- package/src/report/report.test.ts +398 -94
- package/src/report/report.ts +29 -11
- package/src/report/text/faces.ts +344 -96
- package/src/report/text/layout.ts +76 -11
- package/src/report/text/table.ts +98 -0
- package/src/report/tree.ts +103 -20
- package/src/report/types.ts +184 -25
- package/src/report/web.ts +46 -19
- package/src/results/annotated-source.test.ts +146 -0
- package/src/results/annotated-source.ts +128 -0
- package/src/results/attempt-evidence.test.ts +158 -0
- package/src/results/attempt-evidence.ts +158 -0
- package/src/results/attempt-source.ts +48 -0
- package/src/results/copy.ts +154 -139
- package/src/results/format.ts +54 -47
- package/src/results/host-equivalence.test.ts +527 -0
- package/src/results/index.ts +56 -14
- package/src/results/locator.test.ts +198 -0
- package/src/results/locator.ts +0 -0
- package/src/results/open.ts +392 -175
- package/src/results/results.test.ts +943 -494
- package/src/results/select.ts +129 -23
- package/src/results/skipped-notice.ts +0 -0
- package/src/results/source-hash.ts +28 -0
- package/src/results/types.ts +98 -62
- package/src/results/writer.ts +304 -176
- package/src/runner/attempt.test.ts +170 -0
- package/src/runner/attempt.ts +48 -13
- package/src/runner/discover.test.ts +65 -0
- package/src/runner/discover.ts +6 -2
- package/src/runner/eval-source.test.ts +121 -0
- package/src/runner/eval-source.ts +45 -0
- package/src/runner/fingerprint.ts +54 -1
- package/src/runner/remote-sandbox.ts +1 -1
- package/src/runner/report.test.ts +6 -8
- package/src/runner/report.ts +5 -4
- package/src/runner/reporters/artifacts.ts +27 -41
- package/src/runner/reporters/braintrust.test.ts +3 -3
- package/src/runner/reporters/braintrust.ts +1 -1
- package/src/runner/reporters/console.ts +6 -6
- package/src/runner/reporters/json.ts +4 -4
- package/src/runner/reporters/live.test.ts +56 -0
- package/src/runner/reporters/live.ts +36 -10
- package/src/runner/reporters/quiet.test.ts +66 -0
- package/src/runner/reporters/quiet.ts +49 -0
- package/src/runner/reporters/shared.ts +5 -5
- package/src/runner/reporters/table.ts +17 -17
- package/src/runner/run.ts +61 -102
- package/src/runner/types.ts +43 -32
- package/src/sandbox/checkpoint.ts +1 -1
- package/src/sandbox/docker.ts +15 -2
- package/src/sandbox/e2b.ts +11 -5
- package/src/sandbox/errors.ts +13 -0
- package/src/sandbox/index.ts +3 -3
- package/src/sandbox/local-files.ts +1 -1
- package/src/sandbox/registry.ts +6 -5
- package/src/sandbox/resolve.ts +38 -23
- package/src/sandbox/retry.test.ts +68 -0
- package/src/sandbox/retry.ts +44 -0
- package/src/sandbox/types.ts +24 -24
- package/src/sandbox/vercel.ts +17 -3
- package/src/scoring/collector.ts +3 -3
- package/src/scoring/judge.ts +2 -2
- package/src/scoring/scoped.ts +13 -1
- package/src/scoring/types.ts +7 -7
- package/src/scoring/verdict.ts +4 -4
- package/src/shared/aggregate.ts +23 -3
- package/src/shared/types.ts +2 -2
- package/src/shared/{outcome.ts → verdict.ts} +15 -15
- package/src/show/compose.ts +12 -132
- package/src/show/index.ts +119 -95
- package/src/show/render.ts +462 -159
- package/src/show/show.test.ts +471 -253
- package/src/source-loc.ts +1 -1
- package/src/tty-line.ts +32 -0
- package/src/types.ts +2 -2
- package/src/util.test.ts +21 -1
- package/src/util.ts +5 -1
- package/src/view/app/App.tsx +33 -198
- package/src/view/app/components/AttemptModal.tsx +6 -6
- package/src/view/app/components/CodeView.tsx +2 -2
- package/src/view/app/components/CopyControls.tsx +32 -36
- package/src/view/app/components/SkippedRunsBanner.tsx +140 -0
- package/src/view/app/components/ui/badge.tsx +1 -1
- package/src/view/app/components/ui/dialog.tsx +2 -2
- package/src/view/app/i18n.ts +40 -31
- package/src/view/app/lib/artifact-url.ts +1 -1
- package/src/view/app/lib/attempt-route.test.ts +37 -47
- package/src/view/app/lib/attempt-route.ts +26 -26
- package/src/view/app/lib/rows.ts +9 -112
- package/src/view/app/lib/verdict.ts +25 -0
- package/src/view/app/main.tsx +9 -12
- package/src/view/app/pages/RunsPage.tsx +4 -4
- package/src/view/app/pages/TracesPage.tsx +3 -3
- package/src/view/app/shared.ts +0 -1
- package/src/view/app/types.ts +6 -51
- package/src/view/artifact-serving.test.ts +136 -0
- package/src/view/client-dist/app.css +1 -1
- package/src/view/client-dist/app.js +21 -21
- package/src/view/data.test.ts +214 -143
- package/src/view/data.ts +166 -120
- package/src/view/index.ts +23 -11
- package/src/view/server.ts +52 -17
- package/src/view/shared/types.ts +22 -31
- package/src/view/styles.css +117 -327
- package/src/view/view-report.test.ts +146 -98
- package/src/report/default-report.tsx +0 -222
- package/src/report/dual-face.test.tsx +0 -527
- package/src/report/react/CaseList.tsx +0 -70
- package/src/view/app/components/CostScoreChart.tsx +0 -147
- package/src/view/app/components/ExperimentTable.tsx +0 -284
- package/src/view/app/components/GroupSelector.tsx +0 -61
- package/src/view/app/components/primitives.tsx +0 -43
- package/src/view/app/lib/outcome.ts +0 -82
|
@@ -0,0 +1,332 @@
|
|
|
1
|
+
import type { Cleanup, LocalizedText, SourceArtifact } from "../shared/types.ts";
|
|
2
|
+
import type { O11ySummary, StreamEvent, TraceSpan, Usage } from "../o11y/types.ts";
|
|
3
|
+
import type { Agent, AgentSetupManifest } from "../agents/types.ts";
|
|
4
|
+
import type { Sandbox, SandboxOption } from "../sandbox/types.ts";
|
|
5
|
+
import type { AssertionResult, DiffData, JudgeConfig, Verdict } from "../scoring/types.ts";
|
|
6
|
+
import type { TestContext } from "../context/types.ts";
|
|
7
|
+
import type { CapturedEvalSource } from "./eval-source.ts";
|
|
8
|
+
export interface ExperimentRunInfo {
|
|
9
|
+
id?: string;
|
|
10
|
+
flags?: Record<string, unknown>;
|
|
11
|
+
runs?: number;
|
|
12
|
+
earlyExit?: boolean;
|
|
13
|
+
sandbox?: string;
|
|
14
|
+
timeoutMs?: number;
|
|
15
|
+
budget?: number;
|
|
16
|
+
}
|
|
17
|
+
export interface EvalResult {
|
|
18
|
+
id: string;
|
|
19
|
+
description?: string;
|
|
20
|
+
experimentId?: string;
|
|
21
|
+
experiment?: ExperimentRunInfo;
|
|
22
|
+
agent: string;
|
|
23
|
+
model?: string;
|
|
24
|
+
verdict: Verdict;
|
|
25
|
+
fingerprint?: string;
|
|
26
|
+
attempt: number;
|
|
27
|
+
/** 本 attempt 开始的墙钟时刻(ISO);view 按 eval 粒度展示「何时跑的」。 */
|
|
28
|
+
startedAt?: string;
|
|
29
|
+
/**
|
|
30
|
+
* 不透明的 Attempt 定位符(`@` 前缀短确定性编码,见 `src/results/locator.ts` 的 AttemptLocator),
|
|
31
|
+
* 由 {experimentId, 快照 startedAt, evalId, attempt} 身份元组派生。非携带条目由 writer 在落盘时
|
|
32
|
+
* 算出;携带条目(`--resume` 合入)原样复制上一轮的值,从不重算——原快照的 startedAt 已经不在
|
|
33
|
+
* 当前快照里,重算会算出不同的字符串,详见 writer.ts 对携带分支的说明。省略时读取面按当前
|
|
34
|
+
* 已知身份兜底算出(第三方 harness 未实现 locator 时的降级,不保证跨 --resume 稳定)。
|
|
35
|
+
*/
|
|
36
|
+
locator?: string;
|
|
37
|
+
durationMs: number;
|
|
38
|
+
assertions: AssertionResult[];
|
|
39
|
+
usage?: Usage;
|
|
40
|
+
estimatedCostUSD?: number;
|
|
41
|
+
error?: string;
|
|
42
|
+
skipReason?: string;
|
|
43
|
+
events?: StreamEvent[];
|
|
44
|
+
/** test 引用到的 eval 源码(按 loc 收集),供 view 渲染 github-diff 式代码视图。 */
|
|
45
|
+
sources?: SourceArtifact[];
|
|
46
|
+
o11y?: O11ySummary;
|
|
47
|
+
/** agent 经 OpenTelemetry 导出的运行追踪(有 tracing 能力且收到 span 时)。 */
|
|
48
|
+
trace?: TraceSpan[];
|
|
49
|
+
/** 本 attempt 的 agent setup 实际装了什么(Skill / native plugin / MCP / Python plugin);不参与评分。 */
|
|
50
|
+
agentSetup?: AgentSetupManifest;
|
|
51
|
+
diff?: DiffData;
|
|
52
|
+
rawTranscript?: string;
|
|
53
|
+
/** 携带条目(--resume 合入)专用:artifact 目录(相对结果根目录),指向原快照里的落盘。 */
|
|
54
|
+
artifactBase?: string;
|
|
55
|
+
hasTrace?: boolean;
|
|
56
|
+
hasEvents?: boolean;
|
|
57
|
+
hasSources?: boolean;
|
|
58
|
+
}
|
|
59
|
+
/** `snapshot.json` 的格式标记;把 niceeval 报告和其它工具的同名文件区分开。 */
|
|
60
|
+
export declare const RESULTS_FORMAT = "niceeval.results";
|
|
61
|
+
/**
|
|
62
|
+
* 结果格式版本,只在破坏兼容读取时递增;读取器只认相同版本。见 docs/feature/results/architecture.md。
|
|
63
|
+
* `5`(见 memory 的 attempt-locator-and-source-dedup 条目)= result.json 新增 `locator` 字段;
|
|
64
|
+
* `sources.json` 从逐 attempt 内联全量内容改为「attempt 级引用 + 快照级 `sources/<sha256>.json`
|
|
65
|
+
* 去重仓库」,`AttemptHandle.sources()` 的公开返回形状不变(仍是 `SourceArtifact[] | null`)。
|
|
66
|
+
*/
|
|
67
|
+
export declare const RESULTS_SCHEMA_VERSION = 5;
|
|
68
|
+
/** 一次运行的纯运行时内存聚合(reporter 契约用);落盘格式契约在 niceeval/results 的 SnapshotMeta / AttemptRecord,见 docs/feature/results/architecture.md。 */
|
|
69
|
+
export interface RunSummary {
|
|
70
|
+
/** 项目名(来自 config.name),透传给 `niceeval view` 顶部 hero 显示。 */
|
|
71
|
+
name?: LocalizedText;
|
|
72
|
+
agent: string;
|
|
73
|
+
model?: string;
|
|
74
|
+
startedAt: string;
|
|
75
|
+
completedAt: string;
|
|
76
|
+
passed: number;
|
|
77
|
+
/** 断言不通过的数量;不包含 errored。 */
|
|
78
|
+
failed: number;
|
|
79
|
+
skipped: number;
|
|
80
|
+
/** 环境、超时、adapter、agent runtime 等执行错误数量;与 failed 互斥。 */
|
|
81
|
+
errored: number;
|
|
82
|
+
durationMs: number;
|
|
83
|
+
usage?: Usage;
|
|
84
|
+
estimatedCostUSD?: number;
|
|
85
|
+
results: EvalResult[];
|
|
86
|
+
}
|
|
87
|
+
/** onRunStart 的运行规模:去重后 eval 数 × 配置(agent×model×flags)数 → 总运行(attempt)数。 */
|
|
88
|
+
export interface RunShape {
|
|
89
|
+
/** 去重后实际要跑的 eval 数(= evals.length)。 */
|
|
90
|
+
evals: number;
|
|
91
|
+
/** (agent, model, flags) 配置组合数;compare 多 agent 时 > 1。 */
|
|
92
|
+
configs: number;
|
|
93
|
+
/** 总 attempt 数(evals × configs × runs);逐行输出与汇总计数都按它。 */
|
|
94
|
+
totalRuns: number;
|
|
95
|
+
/** 本次运行实际生效的全局并发数(flag/env/config/sandbox 默认值解析后的结果);
|
|
96
|
+
* 实验级 maxConcurrency 只在该实验内部限流,不改这个全局值。 */
|
|
97
|
+
maxConcurrency: number;
|
|
98
|
+
}
|
|
99
|
+
export interface Reporter {
|
|
100
|
+
onEvent?(event: ReporterEvent): void | Promise<void>;
|
|
101
|
+
onRunStart?(evals: {
|
|
102
|
+
id: string;
|
|
103
|
+
}[], agent: Agent, shape?: RunShape): void | Promise<void>;
|
|
104
|
+
onEvalComplete?(result: EvalResult): void | Promise<void>;
|
|
105
|
+
onRunComplete?(summary: RunSummary): void | Promise<void>;
|
|
106
|
+
}
|
|
107
|
+
export type ReporterEvent = {
|
|
108
|
+
type: "run:start";
|
|
109
|
+
evals: {
|
|
110
|
+
id: string;
|
|
111
|
+
}[];
|
|
112
|
+
agent: Agent;
|
|
113
|
+
shape: RunShape;
|
|
114
|
+
} | {
|
|
115
|
+
type: "eval:start";
|
|
116
|
+
eval: {
|
|
117
|
+
id: string;
|
|
118
|
+
};
|
|
119
|
+
agent: Agent;
|
|
120
|
+
model?: string;
|
|
121
|
+
attempt: number;
|
|
122
|
+
experimentId?: string;
|
|
123
|
+
} | {
|
|
124
|
+
type: "eval:complete";
|
|
125
|
+
result: EvalResult;
|
|
126
|
+
} | {
|
|
127
|
+
type: "run:earlyExit";
|
|
128
|
+
evalId: string;
|
|
129
|
+
experimentId?: string;
|
|
130
|
+
} | {
|
|
131
|
+
type: "run:budgetExceeded";
|
|
132
|
+
budget: number;
|
|
133
|
+
spent: number;
|
|
134
|
+
} | {
|
|
135
|
+
type: "run:saved";
|
|
136
|
+
summary: RunSummary;
|
|
137
|
+
} | {
|
|
138
|
+
type: "run:summary";
|
|
139
|
+
summary: RunSummary;
|
|
140
|
+
};
|
|
141
|
+
export interface EvalDef {
|
|
142
|
+
/** 路径推导,定义里禁止手写。 */
|
|
143
|
+
id?: string;
|
|
144
|
+
/** 一句话描述,展示在 `niceeval list` 和 view 里;纯说明,不影响调度或打分。 */
|
|
145
|
+
description?: string;
|
|
146
|
+
/** 标签,供 CLI `--tag` 过滤和 view 分类;与 id 前缀过滤是两套独立的筛选维度。 */
|
|
147
|
+
tags?: string[];
|
|
148
|
+
/** 覆盖项目级 Config.judge,只对这一个 eval 生效(如换个更贵的评审模型)。 */
|
|
149
|
+
judge?: JudgeConfig;
|
|
150
|
+
/** 覆盖 / 追加项目级 Config.reporters,只对这一个 eval 生效。 */
|
|
151
|
+
reporters?: Reporter[];
|
|
152
|
+
/** 覆盖项目级 / CLI 的单次 attempt 超时(毫秒),只对这一个 eval 生效。 */
|
|
153
|
+
timeoutMs?: number;
|
|
154
|
+
/** 任意附加元数据,原样透传进 EvalResult,不参与调度或打分;供自定义 reporter 消费。 */
|
|
155
|
+
metadata?: Record<string, unknown>;
|
|
156
|
+
/**
|
|
157
|
+
* eval 级预置:拿到沙箱(已上传 workspace + git 基线 + 装好依赖前)。
|
|
158
|
+
* 默认命令以非 root 跑(agent 的自然环境);装系统依赖时给 `runCommand` 传 `{ root: true }`
|
|
159
|
+
* (如 `runCommand("apt-get", ["install", …], { root: true })`),跨 provider 语义一致。
|
|
160
|
+
*/
|
|
161
|
+
setup?: (sandbox: Sandbox) => Promise<void | Cleanup> | void | Cleanup;
|
|
162
|
+
/** eval 主体:拿到 TestContext,驱动对话 / 沙箱操作并就地断言。 */
|
|
163
|
+
test(t: TestContext): Promise<void> | void;
|
|
164
|
+
}
|
|
165
|
+
/** 内部:发现后带上 id 的 eval。 */
|
|
166
|
+
export interface DiscoveredEval extends EvalDef {
|
|
167
|
+
id: string;
|
|
168
|
+
/** 定义文件所在目录(解析相对 workspace 用)。 */
|
|
169
|
+
baseDir: string;
|
|
170
|
+
/** 定义文件绝对路径,用于内容指纹缓存。 */
|
|
171
|
+
sourcePath: string;
|
|
172
|
+
/**
|
|
173
|
+
* discovery 时捕获的规范化源码(归一化文本 + 项目相对路径 + SHA-256),见 `eval-source.ts`。
|
|
174
|
+
* 同一文件里多个 eval(数组默认导出)共享同一份引用——哈希与内容天然相同,不重复读盘。
|
|
175
|
+
*/
|
|
176
|
+
source: CapturedEvalSource;
|
|
177
|
+
}
|
|
178
|
+
export interface ExperimentDef {
|
|
179
|
+
/** 路径推导,定义里禁止手写(defineExperiment 会拒绝显式传入)。 */
|
|
180
|
+
id?: string;
|
|
181
|
+
/** 一句话描述,展示在 view / CLI 里;纯说明,不影响调度或打分。 */
|
|
182
|
+
description?: string;
|
|
183
|
+
/**
|
|
184
|
+
* 必填:这个实验跑哪个 agent(defineSandboxAgent / defineAgent 的产物)。运行配置的
|
|
185
|
+
* agent 归属完全由这里决定——EvalDef.agent 不参与(见其字段注释)。
|
|
186
|
+
*/
|
|
187
|
+
agent: Agent;
|
|
188
|
+
/** 单个模型(agent 留空时实验决定);省略=用 agent 原生默认。跨模型对比写多个实验文件,别用数组。 */
|
|
189
|
+
model?: string;
|
|
190
|
+
/** 模型推理努力程度(如 "low"/"medium"/"high",取值由具体模型/adapter 决定);省略=用 agent 原生默认。经 ctx.reasoningEffort 透给 adapter 与 eval。 */
|
|
191
|
+
reasoningEffort?: string;
|
|
192
|
+
/** 实验条件(A/B 里的 feature flag),由实验文件声明;经 ctx.flags 透传给 adapter、t.flags 暴露给 eval。 */
|
|
193
|
+
flags?: Record<string, unknown>;
|
|
194
|
+
/** 同一 eval 重复跑几次(结果各计一条 attempt);省略/CLI `--runs` 覆盖时默认 1。 */
|
|
195
|
+
runs?: number;
|
|
196
|
+
/** 一次重复(runs > 1)里某次 attempt 失败后是否跳过剩余重复;省略默认 true(提前退出省钱)。 */
|
|
197
|
+
earlyExit?: boolean;
|
|
198
|
+
/** 这个实验覆盖哪些 eval:"*" 全部、字符串数组按 id 前缀、或自定义谓词;省略等价于 "*"。 */
|
|
199
|
+
evals?: "*" | string[] | ((id: string) => boolean);
|
|
200
|
+
/** 覆盖项目级 / CLI 的单次 attempt 超时(毫秒),只对这个实验生效。 */
|
|
201
|
+
timeoutMs?: number;
|
|
202
|
+
/** 覆盖项目级 Config.sandbox,只对这个实验生效。 */
|
|
203
|
+
sandbox?: SandboxOption;
|
|
204
|
+
/**
|
|
205
|
+
* 本实验的花费上限(USD)。调度器按「已花 + 在飞预估」的护栏口径逼近上限时限流,
|
|
206
|
+
* 累计花费到顶后跳过这个实验剩下未起飞的 attempt 并上报一次 `run:budgetExceeded`
|
|
207
|
+
* (已在飞的 attempt 仍会跑完)。
|
|
208
|
+
*/
|
|
209
|
+
budget?: number;
|
|
210
|
+
/**
|
|
211
|
+
* 本实验自己的并发上限:调度器只对这个实验的 attempt 限流,同批其它实验不受影响,
|
|
212
|
+
* 仍按全局并发(CLI / env / config / 沙箱默认)跑。用于串行化有共享状态的实验
|
|
213
|
+
* (如跨 eval 累积记忆:`maxConcurrency: 1` 保证 attempt 按 eval 顺序一个个跑),
|
|
214
|
+
* 或给撞 provider 限额的实验单独降速。
|
|
215
|
+
*/
|
|
216
|
+
maxConcurrency?: number;
|
|
217
|
+
}
|
|
218
|
+
export interface DiscoveredExperiment extends ExperimentDef {
|
|
219
|
+
id: string;
|
|
220
|
+
group: string;
|
|
221
|
+
}
|
|
222
|
+
export interface Config {
|
|
223
|
+
/**
|
|
224
|
+
* 项目名,显示在 `niceeval view` 顶部 hero(`<h1>`),省略则回退到通用标题。
|
|
225
|
+
* 可传字符串,或按 locale 提供多语言(如 `{ en: "...", "zh-CN": "..." }`),随 view 语言切换。
|
|
226
|
+
*/
|
|
227
|
+
name?: LocalizedText;
|
|
228
|
+
/** 项目级默认沙箱 provider(docker / vercel / e2b / custom);experiment 可覆盖。 */
|
|
229
|
+
sandbox?: SandboxOption;
|
|
230
|
+
/** 上传进沙箱的工作区根目录,省略则用项目根;eval 的 sandbox 视图从这里起步。 */
|
|
231
|
+
workspace?: string;
|
|
232
|
+
/** 项目级默认 judge 配置(model / baseUrl / apiKeyEnv);EvalDef.judge 可按 eval 覆盖。 */
|
|
233
|
+
judge?: JudgeConfig;
|
|
234
|
+
/** 项目级默认 reporter 列表(如落盘 / 上传结果);EvalDef.reporters 会与它合并。 */
|
|
235
|
+
reporters?: Reporter[];
|
|
236
|
+
/** 项目级默认并发上限;CLI flag / env / experiment 的同名设置优先级更高。 */
|
|
237
|
+
maxConcurrency?: number;
|
|
238
|
+
/** 项目级默认单次 attempt 超时(毫秒);CLI flag / experiment / EvalDef 的同名设置优先级更高。 */
|
|
239
|
+
timeoutMs?: number;
|
|
240
|
+
/**
|
|
241
|
+
* OTLP 接收配置,niceeval 项目内唯一入口(不读 NICEEVAL_OTLP_* 环境变量)。
|
|
242
|
+
* `port` 钉住接收端口(固定端口模式:长驻服务把 OTEL_EXPORTER_OTLP_ENDPOINT 一次性指到
|
|
243
|
+
* http://localhost:<port>/v1/traces,跑多少次 eval 都不用改)。省略 = 每次运行动态分配
|
|
244
|
+
* 临时端口(经 ctx.telemetry 交给 adapter)。代价:固定端口下同机同时只能跑一个 niceeval 进程,
|
|
245
|
+
* 且该端口被别的进程占用时会报错——换一个空闲端口写回这里即可。
|
|
246
|
+
* `host` 是报给 adapter 的接收端 hostname(而非监听地址,监听地址恒为 0.0.0.0):默认
|
|
247
|
+
* "127.0.0.1";docker 沙箱型 tracing 需要 "host.docker.internal" 之类的场景,或配了隧道
|
|
248
|
+
* 的远程接入,在这里覆盖。
|
|
249
|
+
*/
|
|
250
|
+
telemetry?: {
|
|
251
|
+
host?: string;
|
|
252
|
+
port?: number;
|
|
253
|
+
};
|
|
254
|
+
/**
|
|
255
|
+
* 内置价格表(`o11y/prices.json`)之上的用户覆盖 / 补充,按 model 查(见 Observability
|
|
256
|
+
* · 用量与成本)。key 支持精确 model 名或 `provider/*` 通配(自托管/网关折扣按 provider 批量覆盖);
|
|
257
|
+
* 精确 key 优先于通配。只在没有网关实测成本(`usage.costUSD`)时才会用到——实测优先于估算恒成立。
|
|
258
|
+
*/
|
|
259
|
+
pricing?: Record<string, PriceOverride>;
|
|
260
|
+
}
|
|
261
|
+
/** 每百万 token 的美元单价;省略的桶退回 `inputPerMTok`(cache token 本质也是 input)。 */
|
|
262
|
+
export interface PriceOverride {
|
|
263
|
+
/** 普通输入 token 单价。 */
|
|
264
|
+
inputPerMTok: number;
|
|
265
|
+
/** 输出 token 单价。 */
|
|
266
|
+
outputPerMTok: number;
|
|
267
|
+
/** cache 命中(读)token 单价,省略则退回 inputPerMTok。 */
|
|
268
|
+
cacheReadPerMTok?: number;
|
|
269
|
+
/** cache 写入 token 单价,省略则退回 inputPerMTok。 */
|
|
270
|
+
cacheWritePerMTok?: number;
|
|
271
|
+
}
|
|
272
|
+
/**
|
|
273
|
+
* 进度行 / 日志里标识一个 run 配置的短名。有 experiment 时用其 basename(唯一,
|
|
274
|
+
* 能区分同 agent 同 model 的实验变体,如 xxx 与 xxx--agents-md;与汇总表口径一致);
|
|
275
|
+
* 无 experiment 时退回 agent/model。live display 以它作行聚合 key,两处必须同源。
|
|
276
|
+
*/
|
|
277
|
+
export declare function runWho(run: {
|
|
278
|
+
agentName: string;
|
|
279
|
+
model?: string;
|
|
280
|
+
experimentId?: string;
|
|
281
|
+
}): string;
|
|
282
|
+
/** 一个 (agent, model, flags) 的运行配置 —— 由 CLI / 实验展开。 */
|
|
283
|
+
export interface AgentRun {
|
|
284
|
+
agent: Agent;
|
|
285
|
+
model?: string;
|
|
286
|
+
reasoningEffort?: string;
|
|
287
|
+
flags: Record<string, unknown>;
|
|
288
|
+
runs: number;
|
|
289
|
+
earlyExit: boolean;
|
|
290
|
+
sandbox?: SandboxOption;
|
|
291
|
+
timeoutMs?: number;
|
|
292
|
+
budget?: number;
|
|
293
|
+
evalFilter: (id: string) => boolean;
|
|
294
|
+
experimentId?: string;
|
|
295
|
+
strict?: boolean;
|
|
296
|
+
/** 本配置自己的并发上限(来自 ExperimentDef.maxConcurrency):调度器为它单建信号量,
|
|
297
|
+
* attempt 先过这道闸再占全局并发位;省略则只受全局并发约束。 */
|
|
298
|
+
maxConcurrency?: number;
|
|
299
|
+
}
|
|
300
|
+
export interface RunOptions {
|
|
301
|
+
config: Config;
|
|
302
|
+
evals: DiscoveredEval[];
|
|
303
|
+
agentRuns: AgentRun[];
|
|
304
|
+
reporters: Reporter[];
|
|
305
|
+
maxConcurrency: number;
|
|
306
|
+
signal?: AbortSignal;
|
|
307
|
+
/** TTY live display 的进度回调;设置后 attempt 的 log 消息路由到它而不是 stderr。 */
|
|
308
|
+
onProgress?: (evalId: string, who: string, msg: string) => void;
|
|
309
|
+
/** 上次运行的结果。verdict 为 passed/failed 的 (experimentId, evalId) 组合跳过重跑,结果直接合入本次汇总。 */
|
|
310
|
+
priorResults?: EvalResult[];
|
|
311
|
+
/**
|
|
312
|
+
* 预算好的携入计划(见 fingerprint.ts 的 planCarry)。cli.ts 为了让 live 表格提前知道
|
|
313
|
+
* 哪些行会被携入,必须在构建 liveRows 之前算一次;传进来后 runEvals 直接复用,不重算
|
|
314
|
+
* 一遍(否则两处各自算一次,不仅重复 I/O,还留下"两边判断可能不一致"的隐患)。
|
|
315
|
+
* 省略时 runEvals 自己算(测试直调等场景)。
|
|
316
|
+
*/
|
|
317
|
+
carryPlan?: import("./fingerprint.ts").CarryPlan;
|
|
318
|
+
/**
|
|
319
|
+
* 非沙箱 tracing agent 的 run 级共享 OTLP 接收池(runEvals 创建并回收;
|
|
320
|
+
* 每个 agent 一个 receiver,attempt 之间共享 —— 被测应用是长驻进程,端点不能随 attempt 换)。
|
|
321
|
+
*/
|
|
322
|
+
otelPool?: import("../o11y/otlp/turn-otel.ts").OtelReceiverPool;
|
|
323
|
+
}
|
|
324
|
+
/** 调度器内部的一次尝试:eval × run × 第几轮。 */
|
|
325
|
+
export interface Attempt {
|
|
326
|
+
evalDef: DiscoveredEval;
|
|
327
|
+
run: AgentRun;
|
|
328
|
+
attempt: number;
|
|
329
|
+
/** agent+model+evalId,用于首过即停。 */
|
|
330
|
+
key: string;
|
|
331
|
+
fingerprint: string;
|
|
332
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import * as tar from "tar-stream";
|
|
2
|
+
/**
|
|
3
|
+
* Docker exec 复用流(8 字节头 + 载荷)的增量解析器。
|
|
4
|
+
* 头:[stream_type(1B), 0, 0, 0, size(4B 大端)];stream_type:1=stdout,2=stderr。
|
|
5
|
+
*
|
|
6
|
+
* 关键:一帧可能被 Node 的可读流切到【多个 data 事件】里(尤其大输出,如 cat 一个
|
|
7
|
+
* ~100KB 的文件),帧头 / 载荷都可能跨 chunk。所以必须跨 data 累积一个 leftover,
|
|
8
|
+
* 只消费「已到齐的完整帧」,残帧留到下个 data —— 否则会在 chunk 边界丢字节 / 串帧,
|
|
9
|
+
* 表现为 transcript 里随机损坏的行(曾导致 bub tape 的 tool_result/tool_call 被吞)。
|
|
10
|
+
*/
|
|
11
|
+
export declare function createExecDemuxer(): {
|
|
12
|
+
push(chunk: Buffer): void;
|
|
13
|
+
stdout(): string;
|
|
14
|
+
stderr(): string;
|
|
15
|
+
};
|
|
16
|
+
/** Readable stream → Buffer。 */
|
|
17
|
+
export declare function readableToBuffer(stream: NodeJS.ReadableStream): Promise<Buffer>;
|
|
18
|
+
/** 从单文件 tar 包里提取第一个 entry 的内容。 */
|
|
19
|
+
export declare function extractFileFromTar(tarBuf: Buffer): Promise<Buffer>;
|
|
20
|
+
/** 把若干文件打成 tar 流(putArchive 用)。 */
|
|
21
|
+
export declare function packFilesToTar(entries: readonly {
|
|
22
|
+
name: string;
|
|
23
|
+
content: Buffer;
|
|
24
|
+
}[]): tar.Pack;
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import type { Sandbox, CommandResult, CommandOptions, SandboxFile, SourceFiles, ReadSourceFilesOptions } from "../types.ts";
|
|
2
|
+
import type { SandboxProvisionErrorKind } from "./errors.ts";
|
|
3
|
+
/**
|
|
4
|
+
* dockerode 对镜像拉取限流没有专门的错误类型;Docker Hub 429 体现在错误 message 里
|
|
5
|
+
* (如 "toomanyrequests: You have reached your pull rate limit")。
|
|
6
|
+
*/
|
|
7
|
+
export declare function classifyProvisionError(e: unknown): SandboxProvisionErrorKind;
|
|
8
|
+
/** 创建 Docker 沙箱的选项。 */
|
|
9
|
+
export interface DockerSandboxOptions {
|
|
10
|
+
/** 单条命令超时(毫秒)。 */
|
|
11
|
+
timeout?: number;
|
|
12
|
+
/** Node 运行时。 */
|
|
13
|
+
runtime?: "node20" | "node24";
|
|
14
|
+
/** 覆盖默认镜像(默认按 runtime 选 `node:*-slim`)。预制模板:烘焙好 agent CLI 的镜像名。 */
|
|
15
|
+
image?: string;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Docker 沙箱:为每次运行起一个隔离容器。
|
|
19
|
+
* 实现 ../types.ts 的 Sandbox 接口。
|
|
20
|
+
*/
|
|
21
|
+
export declare class DockerSandbox implements Sandbox {
|
|
22
|
+
readonly workdir = "/home/sandbox/workspace";
|
|
23
|
+
readonly otlpHost = "host.docker.internal";
|
|
24
|
+
private docker;
|
|
25
|
+
private container;
|
|
26
|
+
private _containerId;
|
|
27
|
+
private timeout;
|
|
28
|
+
private runtime;
|
|
29
|
+
private image?;
|
|
30
|
+
constructor(options?: DockerSandboxOptions);
|
|
31
|
+
/** 创建并启动一个 Docker 沙箱。 */
|
|
32
|
+
static create(options?: DockerSandboxOptions): Promise<DockerSandbox>;
|
|
33
|
+
/** 拉镜像、起容器、装基础工具、备好工作区与 npm 前缀。 */
|
|
34
|
+
private initialize;
|
|
35
|
+
/** 确保镜像在本地,缺了就拉。 */
|
|
36
|
+
private ensureImage;
|
|
37
|
+
/** 拉取镜像并跟进度。 */
|
|
38
|
+
private pullImage;
|
|
39
|
+
/** 容器短 ID(像 Docker CLI 那样取前 12 位)。 */
|
|
40
|
+
get sandboxId(): string;
|
|
41
|
+
/**
|
|
42
|
+
* 在容器里跑一条命令。默认以非 root 的 node 用户跑;`opts.root` 为真则以 root 跑
|
|
43
|
+
* (setup 装系统依赖用)。
|
|
44
|
+
*/
|
|
45
|
+
runCommand(cmd: string, args?: string[], opts?: CommandOptions): Promise<CommandResult>;
|
|
46
|
+
/** 以 root 跑命令(provider 内部用:容器初始化、属主收敛)。 */
|
|
47
|
+
private runCommandAsRoot;
|
|
48
|
+
/** 把目录属主收敛回非 root 的沙箱用户(putArchive 以 root 解包后用)。 */
|
|
49
|
+
private chownToSandboxUser;
|
|
50
|
+
/** 真正在容器里 exec 一条命令,demux stdout/stderr 并带超时。 */
|
|
51
|
+
private execCommand;
|
|
52
|
+
/** 经 bash -c 跑一段 shell 脚本。opts 为选项对象。 */
|
|
53
|
+
runShell(script: string, opts?: CommandOptions): Promise<CommandResult>;
|
|
54
|
+
/** 追加一行到容器主日志(PID1 在 tail)→ Docker 的 Logs 标签页实时可见。 */
|
|
55
|
+
appendLog(line: string): Promise<void>;
|
|
56
|
+
/** 读容器里的文件。 */
|
|
57
|
+
readFile(path: string): Promise<string>;
|
|
58
|
+
/** 判断容器里某文件是否存在。 */
|
|
59
|
+
fileExists(path: string): Promise<boolean>;
|
|
60
|
+
/**
|
|
61
|
+
* 一次 shell 往返读全部源码文件。find 按目录名(任意深度)剪枝、按扩展名收,
|
|
62
|
+
* 每份文件前打一行哨兵 + 相对路径,再 cat 内容;在宿主侧按哨兵切分。
|
|
63
|
+
*/
|
|
64
|
+
readSourceFiles(opts?: ReadSourceFilesOptions): Promise<SourceFiles>;
|
|
65
|
+
/** 批量写文件(路径 -> 文本内容)。 */
|
|
66
|
+
writeFiles(files: Record<string, string>, targetDir?: string): Promise<void>;
|
|
67
|
+
/** 用 tar 归档把文件灌进容器。 */
|
|
68
|
+
uploadFiles(files: SandboxFile[], targetDir?: string): Promise<void>;
|
|
69
|
+
uploadDirectory(localDir: string, targetDir?: string, opts?: {
|
|
70
|
+
ignore?: string[];
|
|
71
|
+
}): Promise<void>;
|
|
72
|
+
/**
|
|
73
|
+
* 从容器任意路径读文件 → Buffer。
|
|
74
|
+
* 用 Docker getArchive API(原生二进制,无 base64 开销);tar 只有一个 entry,直接解包取内容。
|
|
75
|
+
*/
|
|
76
|
+
downloadFile(path: string): Promise<Buffer>;
|
|
77
|
+
/**
|
|
78
|
+
* 向容器任意路径写文件(二进制)。
|
|
79
|
+
* 打成单文件 tar → putArchive 到目标目录,与 uploadFiles 同一机制但目标路径自由。
|
|
80
|
+
*/
|
|
81
|
+
uploadFile(destPath: string, content: Buffer): Promise<void>;
|
|
82
|
+
/** 停止并清理容器(AutoRemove 负责销毁)。 */
|
|
83
|
+
stop(): Promise<void>;
|
|
84
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import type { Sandbox, CommandResult, CommandOptions, SandboxFile, SourceFiles, ReadSourceFilesOptions } from "../types.ts";
|
|
2
|
+
import type { SandboxProvisionErrorKind } from "./errors.ts";
|
|
3
|
+
/** e2b 的限流错误是 SDK 原生的 RateLimitError(HTTP 429 映射而来);见 resolve.ts 的 withProvisionRetry。 */
|
|
4
|
+
export declare function classifyProvisionError(e: unknown): SandboxProvisionErrorKind;
|
|
5
|
+
export declare class E2BSandbox implements Sandbox {
|
|
6
|
+
readonly workdir = "/home/user/workspace";
|
|
7
|
+
readonly otlpHost: null;
|
|
8
|
+
private sbx;
|
|
9
|
+
private commandTimeoutMs;
|
|
10
|
+
readonly sandboxId: string;
|
|
11
|
+
private constructor();
|
|
12
|
+
static create(opts?: {
|
|
13
|
+
timeout?: number;
|
|
14
|
+
runtime?: "node20" | "node24";
|
|
15
|
+
template?: string;
|
|
16
|
+
}): Promise<E2BSandbox>;
|
|
17
|
+
runCommand(cmd: string, args?: string[], opts?: CommandOptions): Promise<CommandResult>;
|
|
18
|
+
runShell(script: string, opts?: CommandOptions): Promise<CommandResult>;
|
|
19
|
+
private abs;
|
|
20
|
+
readFile(path: string): Promise<string>;
|
|
21
|
+
fileExists(path: string): Promise<boolean>;
|
|
22
|
+
readSourceFiles(opts?: ReadSourceFilesOptions): Promise<SourceFiles>;
|
|
23
|
+
writeFiles(files: Record<string, string>, targetDir?: string): Promise<void>;
|
|
24
|
+
uploadFiles(files: SandboxFile[], targetDir?: string): Promise<void>;
|
|
25
|
+
uploadDirectory(localDir: string, targetDir?: string, opts?: {
|
|
26
|
+
ignore?: string[];
|
|
27
|
+
}): Promise<void>;
|
|
28
|
+
stop(): Promise<void>;
|
|
29
|
+
downloadFile(path: string): Promise<Buffer>;
|
|
30
|
+
uploadFile(path: string, content: Buffer): Promise<void>;
|
|
31
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { SandboxFile } from "../types.ts";
|
|
2
|
+
export declare const DEFAULT_SOURCE_EXTENSIONS: string[];
|
|
3
|
+
export declare const DEFAULT_IGNORE_DIRS: string[];
|
|
4
|
+
export declare const DEFAULT_IGNORE_FILES: string[];
|
|
5
|
+
/** 递归收集本地目录下的全部文件;路径统一转成 POSIX 分隔的相对路径,供上传沙箱用。 */
|
|
6
|
+
export declare function collectLocalFiles(localDir: string, ignore?: readonly string[]): Promise<SandboxFile[]>;
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { Sandbox } from "../types.ts";
|
|
2
|
+
export declare function resolveSandboxPath(workdir: string, path?: string): string;
|
|
3
|
+
export declare function resolveLocalPath(baseDir: string | undefined, path: string): string;
|
|
4
|
+
export declare function normalizeSandboxPaths(sandbox: Sandbox): Sandbox;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { Sandbox } from "../types.ts";
|
|
2
|
+
export declare function registerSandbox(sb: Sandbox): void;
|
|
3
|
+
export declare function liveSandboxCount(): number;
|
|
4
|
+
/**
|
|
5
|
+
* 带超时地停单个沙箱。成功 / 失败 / 超时都从登记表移除(失败的靠 provider 过期兜底),
|
|
6
|
+
* 异常打到 stderr 不再静默吞。供 Scope finalizer 与兜底强清共用,避免重复实现 stop 语义。
|
|
7
|
+
*/
|
|
8
|
+
export declare function stopSandbox(sb: Sandbox, timeoutMs?: number): Promise<void>;
|
|
9
|
+
/**
|
|
10
|
+
* 兜底强清:并发停掉所有还登记着的沙箱(各自带超时、各自兜错,绝不抛)。返回尝试停的数量。
|
|
11
|
+
* cli 在二次中断 / graceful 清理超时 / 正常返回后调用 —— 正常跑完时登记表已空,是个 no-op。
|
|
12
|
+
*/
|
|
13
|
+
export declare function stopAllSandboxes(timeoutMs?: number): Promise<number>;
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { Effect } from "effect";
|
|
2
|
+
import type { CustomSandboxSpec, Sandbox, SandboxOption, SandboxRuntime } from "../types.ts";
|
|
3
|
+
import { type ProvisionSlot } from "./retry.ts";
|
|
4
|
+
/** 归一化后的沙箱描述:确定的 provider + 各 provider 参数(只有对应 provider 用得上的会有值)。 */
|
|
5
|
+
export interface ResolvedSandbox {
|
|
6
|
+
provider: string;
|
|
7
|
+
runtime?: SandboxRuntime;
|
|
8
|
+
/** docker */
|
|
9
|
+
image?: string;
|
|
10
|
+
/** vercel */
|
|
11
|
+
snapshotId?: string;
|
|
12
|
+
/** e2b */
|
|
13
|
+
template?: string;
|
|
14
|
+
/** 自定义 provider(defineSandbox):有它就直接调用,跳过下面的内置 provider switch。 */
|
|
15
|
+
create?: CustomSandboxSpec["create"];
|
|
16
|
+
recommendedConcurrency?: number;
|
|
17
|
+
}
|
|
18
|
+
/** 把 spec 数据结构归一化成 ResolvedSandbox;省略(undefined)直接报错——没有默认 provider。 */
|
|
19
|
+
export declare function resolveSandbox(opt: SandboxOption | undefined, runtimeDefault?: SandboxRuntime): ResolvedSandbox;
|
|
20
|
+
/**
|
|
21
|
+
* 各 provider 的推荐默认并发数。反映的是 provider 侧约束(daemon 容量、API quota、session 池大小),
|
|
22
|
+
* 不是用户侧的 agent API 限速——后者由用户通过 --max-concurrency 或 config.maxConcurrency 设置。
|
|
23
|
+
* docker:本地 daemon 创建容器有开销,10 是经验上稳健的上限。
|
|
24
|
+
* e2b:云服务,20 是默认账户并发配额的保守估计。
|
|
25
|
+
* vercel:sandbox session 有严格的并发限制,1 避免 429。
|
|
26
|
+
*/
|
|
27
|
+
export declare function sandboxRecommendedConcurrency(opt: SandboxOption | undefined): number;
|
|
28
|
+
/** 报告 / 日志用的简短标签:provider 名,带上区分性的参数(镜像 / 快照 / 模板)。 */
|
|
29
|
+
export declare function sandboxLabel(opt: SandboxOption | undefined): string;
|
|
30
|
+
/**
|
|
31
|
+
* 按解析出的 provider + 参数创建沙箱,并把 stop() 注册为 Scope 回收动作。
|
|
32
|
+
* 在 Effect.scoped / Effect.gen 里 yield* 即可;成功/失败/中断都保证 stop。
|
|
33
|
+
*/
|
|
34
|
+
export declare function createSandbox(opts: {
|
|
35
|
+
sandbox?: SandboxOption;
|
|
36
|
+
timeout?: number;
|
|
37
|
+
runtime?: SandboxRuntime;
|
|
38
|
+
/** 调用方并发槽位的临时归还/收回,传给 withProvisionRetry 在退避睡眠期间释放(见 retry.ts)。 */
|
|
39
|
+
provisionSlot?: ProvisionSlot;
|
|
40
|
+
}): Effect.Effect<Sandbox, never, import("effect/Scope").Scope>;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { type SandboxProvisionErrorKind } from "./errors.ts";
|
|
2
|
+
/**
|
|
3
|
+
* 调用方(resolve.ts)持有的并发槽位的临时归还/收回。不认调用方用的是不是 Effect —— 只要求
|
|
4
|
+
* 两个 async 方法,保持这层 provider 无关。
|
|
5
|
+
*/
|
|
6
|
+
export interface ProvisionSlot {
|
|
7
|
+
release(): Promise<void>;
|
|
8
|
+
reacquire(): Promise<void>;
|
|
9
|
+
}
|
|
10
|
+
export declare function withProvisionRetry<T>(create: () => Promise<T>, classify: (e: unknown) => SandboxProvisionErrorKind, slot?: ProvisionSlot): Promise<T>;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/** 单引号包裹 + 转义,把一个参数安全嵌进 shell 命令串。 */
|
|
2
|
+
export declare function shellQuote(s: string): string;
|
|
3
|
+
/**
|
|
4
|
+
* 构造 readSourceFiles 用的 find 脚本:按目录名(任意深度)剪枝、按扩展名收文件,
|
|
5
|
+
* 输出 `./` 前缀的相对路径。ignoreDirs / extensions 可能来自 eval 作者输入,
|
|
6
|
+
* 一律走 shellQuote 转义后再拼进脚本,防止特殊字符破坏脚本结构。
|
|
7
|
+
*/
|
|
8
|
+
export declare function buildFindScript(opts: {
|
|
9
|
+
extensions: readonly string[];
|
|
10
|
+
ignoreDirs: readonly string[];
|
|
11
|
+
}): string;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { CommandResult, ReadSourceFilesOptions, SourceFile, SourceFiles } from "../types.ts";
|
|
2
|
+
export declare function makeSourceFiles(files: SourceFile[]): SourceFiles;
|
|
3
|
+
/**
|
|
4
|
+
* 两阶段 readSourceFiles 模板(vercel / e2b 共用):
|
|
5
|
+
* Phase 1 只做 find(列路径,短命令快速结束);Phase 2 经 readOne 逐文件独立读取,
|
|
6
|
+
* 不依赖长命令输出流 —— 即使 session 快到平台上限,后半段读取也不会被截断。
|
|
7
|
+
* readOne 返回 null 表示该文件跳过(二进制、无权限等)。
|
|
8
|
+
*/
|
|
9
|
+
export declare function readSourceFilesByList(opts: {
|
|
10
|
+
options: ReadSourceFilesOptions;
|
|
11
|
+
runShell: (script: string) => Promise<CommandResult>;
|
|
12
|
+
readOne: (path: string) => Promise<string | null>;
|
|
13
|
+
}): Promise<SourceFiles>;
|